1 /* $NetBSD: puffs_vnops.c,v 1.150 2011/01/11 14:04:54 kefren Exp $ */ 2 3 /* 4 * Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved. 5 * 6 * Development of this software was supported by the 7 * Google Summer of Code program and the Ulla Tuominen Foundation. 8 * The Google SoC project was mentored by Bill Studenmund. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: puffs_vnops.c,v 1.150 2011/01/11 14:04:54 kefren Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/buf.h> 37 #include <sys/lockf.h> 38 #include <sys/malloc.h> 39 #include <sys/mount.h> 40 #include <sys/namei.h> 41 #include <sys/vnode.h> 42 #include <sys/proc.h> 43 44 #include <uvm/uvm.h> 45 46 #include <fs/puffs/puffs_msgif.h> 47 #include <fs/puffs/puffs_sys.h> 48 49 #include <miscfs/fifofs/fifo.h> 50 #include <miscfs/genfs/genfs.h> 51 #include <miscfs/specfs/specdev.h> 52 53 int puffs_vnop_lookup(void *); 54 int puffs_vnop_create(void *); 55 int puffs_vnop_access(void *); 56 int puffs_vnop_mknod(void *); 57 int puffs_vnop_open(void *); 58 int puffs_vnop_close(void *); 59 int puffs_vnop_getattr(void *); 60 int puffs_vnop_setattr(void *); 61 int puffs_vnop_reclaim(void *); 62 int puffs_vnop_readdir(void *); 63 int puffs_vnop_poll(void *); 64 int puffs_vnop_fsync(void *); 65 int puffs_vnop_seek(void *); 66 int puffs_vnop_remove(void *); 67 int puffs_vnop_mkdir(void *); 68 int puffs_vnop_rmdir(void *); 69 int puffs_vnop_link(void *); 70 int puffs_vnop_readlink(void *); 71 int puffs_vnop_symlink(void *); 72 int puffs_vnop_rename(void *); 73 int puffs_vnop_read(void *); 74 int puffs_vnop_write(void *); 75 int puffs_vnop_fcntl(void *); 76 int puffs_vnop_ioctl(void *); 77 int puffs_vnop_inactive(void *); 78 int puffs_vnop_print(void *); 79 int puffs_vnop_pathconf(void *); 80 int puffs_vnop_advlock(void *); 81 int puffs_vnop_strategy(void *); 82 int puffs_vnop_bmap(void *); 83 int puffs_vnop_mmap(void *); 84 int puffs_vnop_getpages(void *); 85 int puffs_vnop_abortop(void *); 86 int puffs_vnop_getextattr(void *); 87 int puffs_vnop_setextattr(void *); 88 int puffs_vnop_listextattr(void *); 89 int puffs_vnop_deleteextattr(void *); 90 91 int puffs_vnop_spec_read(void *); 92 int puffs_vnop_spec_write(void *); 93 int puffs_vnop_fifo_read(void *); 94 int puffs_vnop_fifo_write(void *); 95 96 int puffs_vnop_checkop(void *); 97 98 #define puffs_vnop_lock genfs_lock 99 #define puffs_vnop_unlock genfs_unlock 100 #define puffs_vnop_islocked genfs_islocked 101 102 int (**puffs_vnodeop_p)(void *); 103 const struct vnodeopv_entry_desc puffs_vnodeop_entries[] = { 104 { &vop_default_desc, vn_default_error }, 105 { &vop_lookup_desc, puffs_vnop_lookup }, /* REAL lookup */ 106 { &vop_create_desc, puffs_vnop_checkop }, /* create */ 107 { &vop_mknod_desc, puffs_vnop_checkop }, /* mknod */ 108 { &vop_open_desc, puffs_vnop_open }, /* REAL open */ 109 { &vop_close_desc, puffs_vnop_checkop }, /* close */ 110 { &vop_access_desc, puffs_vnop_access }, /* REAL access */ 111 { &vop_getattr_desc, puffs_vnop_checkop }, /* getattr */ 112 { &vop_setattr_desc, puffs_vnop_checkop }, /* setattr */ 113 { &vop_read_desc, puffs_vnop_checkop }, /* read */ 114 { &vop_write_desc, puffs_vnop_checkop }, /* write */ 115 { &vop_fsync_desc, puffs_vnop_fsync }, /* REAL fsync */ 116 { &vop_seek_desc, puffs_vnop_checkop }, /* seek */ 117 { &vop_remove_desc, puffs_vnop_checkop }, /* remove */ 118 { &vop_link_desc, puffs_vnop_checkop }, /* link */ 119 { &vop_rename_desc, puffs_vnop_checkop }, /* rename */ 120 { &vop_mkdir_desc, puffs_vnop_checkop }, /* mkdir */ 121 { &vop_rmdir_desc, puffs_vnop_checkop }, /* rmdir */ 122 { &vop_symlink_desc, puffs_vnop_checkop }, /* symlink */ 123 { &vop_readdir_desc, puffs_vnop_checkop }, /* readdir */ 124 { &vop_readlink_desc, puffs_vnop_checkop }, /* readlink */ 125 { &vop_getpages_desc, puffs_vnop_checkop }, /* getpages */ 126 { &vop_putpages_desc, genfs_putpages }, /* REAL putpages */ 127 { &vop_pathconf_desc, puffs_vnop_checkop }, /* pathconf */ 128 { &vop_advlock_desc, puffs_vnop_advlock }, /* REAL advlock */ 129 { &vop_strategy_desc, puffs_vnop_strategy }, /* REAL strategy */ 130 { &vop_revoke_desc, genfs_revoke }, /* REAL revoke */ 131 { &vop_abortop_desc, puffs_vnop_abortop }, /* REAL abortop */ 132 { &vop_inactive_desc, puffs_vnop_inactive }, /* REAL inactive */ 133 { &vop_reclaim_desc, puffs_vnop_reclaim }, /* REAL reclaim */ 134 { &vop_lock_desc, puffs_vnop_lock }, /* REAL lock */ 135 { &vop_unlock_desc, puffs_vnop_unlock }, /* REAL unlock */ 136 { &vop_bmap_desc, puffs_vnop_bmap }, /* REAL bmap */ 137 { &vop_print_desc, puffs_vnop_print }, /* REAL print */ 138 { &vop_islocked_desc, puffs_vnop_islocked }, /* REAL islocked */ 139 { &vop_bwrite_desc, genfs_nullop }, /* REAL bwrite */ 140 { &vop_mmap_desc, puffs_vnop_mmap }, /* REAL mmap */ 141 { &vop_poll_desc, puffs_vnop_poll }, /* REAL poll */ 142 { &vop_getextattr_desc, puffs_vnop_getextattr }, /* getextattr */ 143 { &vop_setextattr_desc, puffs_vnop_setextattr }, /* setextattr */ 144 { &vop_listextattr_desc, puffs_vnop_listextattr }, /* listextattr */ 145 { &vop_deleteextattr_desc, puffs_vnop_deleteextattr },/* deleteextattr */ 146 #if 0 147 { &vop_openextattr_desc, puffs_vnop_checkop }, /* openextattr */ 148 { &vop_closeextattr_desc, puffs_vnop_checkop }, /* closeextattr */ 149 #endif 150 { &vop_kqfilter_desc, genfs_eopnotsupp }, /* kqfilter XXX */ 151 { NULL, NULL } 152 }; 153 const struct vnodeopv_desc puffs_vnodeop_opv_desc = 154 { &puffs_vnodeop_p, puffs_vnodeop_entries }; 155 156 157 int (**puffs_specop_p)(void *); 158 const struct vnodeopv_entry_desc puffs_specop_entries[] = { 159 { &vop_default_desc, vn_default_error }, 160 { &vop_lookup_desc, spec_lookup }, /* lookup, ENOTDIR */ 161 { &vop_create_desc, spec_create }, /* genfs_badop */ 162 { &vop_mknod_desc, spec_mknod }, /* genfs_badop */ 163 { &vop_open_desc, spec_open }, /* spec_open */ 164 { &vop_close_desc, spec_close }, /* spec_close */ 165 { &vop_access_desc, puffs_vnop_checkop }, /* access */ 166 { &vop_getattr_desc, puffs_vnop_checkop }, /* getattr */ 167 { &vop_setattr_desc, puffs_vnop_checkop }, /* setattr */ 168 { &vop_read_desc, puffs_vnop_spec_read }, /* update, read */ 169 { &vop_write_desc, puffs_vnop_spec_write }, /* update, write */ 170 { &vop_ioctl_desc, spec_ioctl }, /* spec_ioctl */ 171 { &vop_fcntl_desc, genfs_fcntl }, /* dummy */ 172 { &vop_poll_desc, spec_poll }, /* spec_poll */ 173 { &vop_kqfilter_desc, spec_kqfilter }, /* spec_kqfilter */ 174 { &vop_revoke_desc, spec_revoke }, /* genfs_revoke */ 175 { &vop_mmap_desc, spec_mmap }, /* spec_mmap */ 176 { &vop_fsync_desc, spec_fsync }, /* vflushbuf */ 177 { &vop_seek_desc, spec_seek }, /* genfs_nullop */ 178 { &vop_remove_desc, spec_remove }, /* genfs_badop */ 179 { &vop_link_desc, spec_link }, /* genfs_badop */ 180 { &vop_rename_desc, spec_rename }, /* genfs_badop */ 181 { &vop_mkdir_desc, spec_mkdir }, /* genfs_badop */ 182 { &vop_rmdir_desc, spec_rmdir }, /* genfs_badop */ 183 { &vop_symlink_desc, spec_symlink }, /* genfs_badop */ 184 { &vop_readdir_desc, spec_readdir }, /* genfs_badop */ 185 { &vop_readlink_desc, spec_readlink }, /* genfs_badop */ 186 { &vop_abortop_desc, spec_abortop }, /* genfs_badop */ 187 { &vop_inactive_desc, puffs_vnop_inactive }, /* REAL inactive */ 188 { &vop_reclaim_desc, puffs_vnop_reclaim }, /* REAL reclaim */ 189 { &vop_lock_desc, puffs_vnop_lock }, /* REAL lock */ 190 { &vop_unlock_desc, puffs_vnop_unlock }, /* REAL unlock */ 191 { &vop_bmap_desc, spec_bmap }, /* dummy */ 192 { &vop_strategy_desc, spec_strategy }, /* dev strategy */ 193 { &vop_print_desc, puffs_vnop_print }, /* REAL print */ 194 { &vop_islocked_desc, puffs_vnop_islocked }, /* REAL islocked */ 195 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 196 { &vop_advlock_desc, spec_advlock }, /* lf_advlock */ 197 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 198 { &vop_getpages_desc, spec_getpages }, /* genfs_getpages */ 199 { &vop_putpages_desc, spec_putpages }, /* genfs_putpages */ 200 { &vop_getextattr_desc, puffs_vnop_checkop }, /* getextattr */ 201 { &vop_setextattr_desc, puffs_vnop_checkop }, /* setextattr */ 202 { &vop_listextattr_desc, puffs_vnop_checkop }, /* listextattr */ 203 { &vop_deleteextattr_desc, puffs_vnop_checkop },/* deleteextattr */ 204 #if 0 205 { &vop_openextattr_desc, _openextattr }, /* openextattr */ 206 { &vop_closeextattr_desc, _closeextattr }, /* closeextattr */ 207 #endif 208 { NULL, NULL } 209 }; 210 const struct vnodeopv_desc puffs_specop_opv_desc = 211 { &puffs_specop_p, puffs_specop_entries }; 212 213 214 int (**puffs_fifoop_p)(void *); 215 const struct vnodeopv_entry_desc puffs_fifoop_entries[] = { 216 { &vop_default_desc, vn_default_error }, 217 { &vop_lookup_desc, vn_fifo_bypass }, /* lookup, ENOTDIR */ 218 { &vop_create_desc, vn_fifo_bypass }, /* genfs_badop */ 219 { &vop_mknod_desc, vn_fifo_bypass }, /* genfs_badop */ 220 { &vop_open_desc, vn_fifo_bypass }, /* open */ 221 { &vop_close_desc, vn_fifo_bypass }, /* close */ 222 { &vop_access_desc, puffs_vnop_checkop }, /* access */ 223 { &vop_getattr_desc, puffs_vnop_checkop }, /* getattr */ 224 { &vop_setattr_desc, puffs_vnop_checkop }, /* setattr */ 225 { &vop_read_desc, puffs_vnop_fifo_read }, /* read, update */ 226 { &vop_write_desc, puffs_vnop_fifo_write }, /* write, update */ 227 { &vop_ioctl_desc, vn_fifo_bypass }, /* ioctl */ 228 { &vop_fcntl_desc, genfs_fcntl }, /* dummy */ 229 { &vop_poll_desc, vn_fifo_bypass }, /* poll */ 230 { &vop_kqfilter_desc, vn_fifo_bypass }, /* kqfilter */ 231 { &vop_revoke_desc, vn_fifo_bypass }, /* genfs_revoke */ 232 { &vop_mmap_desc, vn_fifo_bypass }, /* genfs_badop */ 233 { &vop_fsync_desc, vn_fifo_bypass }, /* genfs_nullop*/ 234 { &vop_seek_desc, vn_fifo_bypass }, /* genfs_badop */ 235 { &vop_remove_desc, vn_fifo_bypass }, /* genfs_badop */ 236 { &vop_link_desc, vn_fifo_bypass }, /* genfs_badop */ 237 { &vop_rename_desc, vn_fifo_bypass }, /* genfs_badop */ 238 { &vop_mkdir_desc, vn_fifo_bypass }, /* genfs_badop */ 239 { &vop_rmdir_desc, vn_fifo_bypass }, /* genfs_badop */ 240 { &vop_symlink_desc, vn_fifo_bypass }, /* genfs_badop */ 241 { &vop_readdir_desc, vn_fifo_bypass }, /* genfs_badop */ 242 { &vop_readlink_desc, vn_fifo_bypass }, /* genfs_badop */ 243 { &vop_abortop_desc, vn_fifo_bypass }, /* genfs_badop */ 244 { &vop_inactive_desc, puffs_vnop_inactive }, /* REAL inactive */ 245 { &vop_reclaim_desc, puffs_vnop_reclaim }, /* REAL reclaim */ 246 { &vop_lock_desc, puffs_vnop_lock }, /* REAL lock */ 247 { &vop_unlock_desc, puffs_vnop_unlock }, /* REAL unlock */ 248 { &vop_bmap_desc, vn_fifo_bypass }, /* dummy */ 249 { &vop_strategy_desc, vn_fifo_bypass }, /* genfs_badop */ 250 { &vop_print_desc, puffs_vnop_print }, /* REAL print */ 251 { &vop_islocked_desc, puffs_vnop_islocked }, /* REAL islocked */ 252 { &vop_pathconf_desc, vn_fifo_bypass }, /* pathconf */ 253 { &vop_advlock_desc, vn_fifo_bypass }, /* genfs_einval */ 254 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 255 { &vop_putpages_desc, vn_fifo_bypass }, /* genfs_null_putpages*/ 256 #if 0 257 { &vop_openextattr_desc, _openextattr }, /* openextattr */ 258 { &vop_closeextattr_desc, _closeextattr }, /* closeextattr */ 259 #endif 260 { &vop_getextattr_desc, puffs_vnop_checkop }, /* getextattr */ 261 { &vop_setextattr_desc, puffs_vnop_checkop }, /* setextattr */ 262 { &vop_listextattr_desc, puffs_vnop_checkop }, /* listextattr */ 263 { &vop_deleteextattr_desc, puffs_vnop_checkop }, /* deleteextattr */ 264 { NULL, NULL } 265 }; 266 const struct vnodeopv_desc puffs_fifoop_opv_desc = 267 { &puffs_fifoop_p, puffs_fifoop_entries }; 268 269 270 /* "real" vnode operations */ 271 int (**puffs_msgop_p)(void *); 272 const struct vnodeopv_entry_desc puffs_msgop_entries[] = { 273 { &vop_default_desc, vn_default_error }, 274 { &vop_create_desc, puffs_vnop_create }, /* create */ 275 { &vop_mknod_desc, puffs_vnop_mknod }, /* mknod */ 276 { &vop_open_desc, puffs_vnop_open }, /* open */ 277 { &vop_close_desc, puffs_vnop_close }, /* close */ 278 { &vop_access_desc, puffs_vnop_access }, /* access */ 279 { &vop_getattr_desc, puffs_vnop_getattr }, /* getattr */ 280 { &vop_setattr_desc, puffs_vnop_setattr }, /* setattr */ 281 { &vop_read_desc, puffs_vnop_read }, /* read */ 282 { &vop_write_desc, puffs_vnop_write }, /* write */ 283 { &vop_seek_desc, puffs_vnop_seek }, /* seek */ 284 { &vop_remove_desc, puffs_vnop_remove }, /* remove */ 285 { &vop_link_desc, puffs_vnop_link }, /* link */ 286 { &vop_rename_desc, puffs_vnop_rename }, /* rename */ 287 { &vop_mkdir_desc, puffs_vnop_mkdir }, /* mkdir */ 288 { &vop_rmdir_desc, puffs_vnop_rmdir }, /* rmdir */ 289 { &vop_symlink_desc, puffs_vnop_symlink }, /* symlink */ 290 { &vop_readdir_desc, puffs_vnop_readdir }, /* readdir */ 291 { &vop_readlink_desc, puffs_vnop_readlink }, /* readlink */ 292 { &vop_print_desc, puffs_vnop_print }, /* print */ 293 { &vop_islocked_desc, puffs_vnop_islocked }, /* islocked */ 294 { &vop_pathconf_desc, puffs_vnop_pathconf }, /* pathconf */ 295 { &vop_getpages_desc, puffs_vnop_getpages }, /* getpages */ 296 { NULL, NULL } 297 }; 298 const struct vnodeopv_desc puffs_msgop_opv_desc = 299 { &puffs_msgop_p, puffs_msgop_entries }; 300 301 302 #define ERROUT(err) \ 303 do { \ 304 error = err; \ 305 goto out; \ 306 } while (/*CONSTCOND*/0) 307 308 /* 309 * This is a generic vnode operation handler. It checks if the necessary 310 * operations for the called vnode operation are implemented by userspace 311 * and either returns a dummy return value or proceeds to call the real 312 * vnode operation from puffs_msgop_v. 313 * 314 * XXX: this should described elsewhere and autogenerated, the complexity 315 * of the vnode operations vectors and their interrelationships is also 316 * getting a bit out of hand. Another problem is that we need this same 317 * information in the fs server code, so keeping the two in sync manually 318 * is not a viable (long term) plan. 319 */ 320 321 /* not supported, handle locking protocol */ 322 #define CHECKOP_NOTSUPP(op) \ 323 case VOP_##op##_DESCOFFSET: \ 324 if (pmp->pmp_vnopmask[PUFFS_VN_##op] == 0) \ 325 return genfs_eopnotsupp(v); \ 326 break 327 328 /* always succeed, no locking */ 329 #define CHECKOP_SUCCESS(op) \ 330 case VOP_##op##_DESCOFFSET: \ 331 if (pmp->pmp_vnopmask[PUFFS_VN_##op] == 0) \ 332 return 0; \ 333 break 334 335 int 336 puffs_vnop_checkop(void *v) 337 { 338 struct vop_generic_args /* { 339 struct vnodeop_desc *a_desc; 340 spooky mystery contents; 341 } */ *ap = v; 342 struct vnodeop_desc *desc = ap->a_desc; 343 struct puffs_mount *pmp; 344 struct vnode *vp; 345 int offset, rv; 346 347 offset = ap->a_desc->vdesc_vp_offsets[0]; 348 #ifdef DIAGNOSTIC 349 if (offset == VDESC_NO_OFFSET) 350 panic("puffs_checkop: no vnode, why did you call me?"); 351 #endif 352 vp = *VOPARG_OFFSETTO(struct vnode **, offset, ap); 353 pmp = MPTOPUFFSMP(vp->v_mount); 354 355 DPRINTF_VERBOSE(("checkop call %s (%d), vp %p\n", 356 ap->a_desc->vdesc_name, ap->a_desc->vdesc_offset, vp)); 357 358 if (!ALLOPS(pmp)) { 359 switch (desc->vdesc_offset) { 360 CHECKOP_NOTSUPP(CREATE); 361 CHECKOP_NOTSUPP(MKNOD); 362 CHECKOP_NOTSUPP(GETATTR); 363 CHECKOP_NOTSUPP(SETATTR); 364 CHECKOP_NOTSUPP(READ); 365 CHECKOP_NOTSUPP(WRITE); 366 CHECKOP_NOTSUPP(FCNTL); 367 CHECKOP_NOTSUPP(IOCTL); 368 CHECKOP_NOTSUPP(REMOVE); 369 CHECKOP_NOTSUPP(LINK); 370 CHECKOP_NOTSUPP(RENAME); 371 CHECKOP_NOTSUPP(MKDIR); 372 CHECKOP_NOTSUPP(RMDIR); 373 CHECKOP_NOTSUPP(SYMLINK); 374 CHECKOP_NOTSUPP(READDIR); 375 CHECKOP_NOTSUPP(READLINK); 376 CHECKOP_NOTSUPP(PRINT); 377 CHECKOP_NOTSUPP(PATHCONF); 378 CHECKOP_NOTSUPP(GETEXTATTR); 379 CHECKOP_NOTSUPP(SETEXTATTR); 380 CHECKOP_NOTSUPP(LISTEXTATTR); 381 CHECKOP_NOTSUPP(DELETEEXTATTR); 382 383 CHECKOP_SUCCESS(ACCESS); 384 CHECKOP_SUCCESS(CLOSE); 385 CHECKOP_SUCCESS(SEEK); 386 387 case VOP_GETPAGES_DESCOFFSET: 388 if (!EXISTSOP(pmp, READ)) 389 return genfs_eopnotsupp(v); 390 break; 391 392 default: 393 panic("puffs_checkop: unhandled vnop %d", 394 desc->vdesc_offset); 395 } 396 } 397 398 rv = VOCALL(puffs_msgop_p, ap->a_desc->vdesc_offset, v); 399 400 DPRINTF_VERBOSE(("checkop return %s (%d), vp %p: %d\n", 401 ap->a_desc->vdesc_name, ap->a_desc->vdesc_offset, vp, rv)); 402 403 return rv; 404 } 405 406 static int callremove(struct puffs_mount *, puffs_cookie_t, puffs_cookie_t, 407 struct componentname *); 408 static int callrmdir(struct puffs_mount *, puffs_cookie_t, puffs_cookie_t, 409 struct componentname *); 410 static void callinactive(struct puffs_mount *, puffs_cookie_t, int); 411 static void callreclaim(struct puffs_mount *, puffs_cookie_t); 412 static int flushvncache(struct vnode *, off_t, off_t, bool); 413 414 415 #define PUFFS_ABORT_LOOKUP 1 416 #define PUFFS_ABORT_CREATE 2 417 #define PUFFS_ABORT_MKNOD 3 418 #define PUFFS_ABORT_MKDIR 4 419 #define PUFFS_ABORT_SYMLINK 5 420 421 /* 422 * Press the pani^Wabort button! Kernel resource allocation failed. 423 */ 424 static void 425 puffs_abortbutton(struct puffs_mount *pmp, int what, 426 puffs_cookie_t dck, puffs_cookie_t ck, struct componentname *cnp) 427 { 428 429 switch (what) { 430 case PUFFS_ABORT_CREATE: 431 case PUFFS_ABORT_MKNOD: 432 case PUFFS_ABORT_SYMLINK: 433 callremove(pmp, dck, ck, cnp); 434 break; 435 case PUFFS_ABORT_MKDIR: 436 callrmdir(pmp, dck, ck, cnp); 437 break; 438 } 439 440 callinactive(pmp, ck, 0); 441 callreclaim(pmp, ck); 442 } 443 444 /* 445 * Begin vnode operations. 446 * 447 * A word from the keymaster about locks: generally we don't want 448 * to use the vnode locks at all: it creates an ugly dependency between 449 * the userlandia file server and the kernel. But we'll play along with 450 * the kernel vnode locks for now. However, even currently we attempt 451 * to release locks as early as possible. This is possible for some 452 * operations which a) don't need a locked vnode after the userspace op 453 * and b) return with the vnode unlocked. Theoretically we could 454 * unlock-do op-lock for others and order the graph in userspace, but I 455 * don't want to think of the consequences for the time being. 456 */ 457 458 int 459 puffs_vnop_lookup(void *v) 460 { 461 struct vop_lookup_args /* { 462 const struct vnodeop_desc *a_desc; 463 struct vnode *a_dvp; 464 struct vnode **a_vpp; 465 struct componentname *a_cnp; 466 } */ *ap = v; 467 PUFFS_MSG_VARS(vn, lookup); 468 struct puffs_mount *pmp; 469 struct componentname *cnp; 470 struct vnode *vp, *dvp; 471 struct puffs_node *dpn; 472 int isdot; 473 int error; 474 475 pmp = MPTOPUFFSMP(ap->a_dvp->v_mount); 476 cnp = ap->a_cnp; 477 dvp = ap->a_dvp; 478 *ap->a_vpp = NULL; 479 480 /* r/o fs? we check create later to handle EEXIST */ 481 if ((cnp->cn_flags & ISLASTCN) 482 && (dvp->v_mount->mnt_flag & MNT_RDONLY) 483 && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 484 return EROFS; 485 486 isdot = cnp->cn_namelen == 1 && *cnp->cn_nameptr == '.'; 487 488 DPRINTF(("puffs_lookup: \"%s\", parent vnode %p, op: %x\n", 489 cnp->cn_nameptr, dvp, cnp->cn_nameiop)); 490 491 /* 492 * Check if someone fed it into the cache 493 */ 494 if (PUFFS_USE_NAMECACHE(pmp)) { 495 error = cache_lookup(dvp, ap->a_vpp, cnp); 496 497 if (error >= 0) 498 return error; 499 } 500 501 if (isdot) { 502 /* deal with rename lookup semantics */ 503 if (cnp->cn_nameiop == RENAME && (cnp->cn_flags & ISLASTCN)) 504 return EISDIR; 505 506 vp = ap->a_dvp; 507 vref(vp); 508 *ap->a_vpp = vp; 509 return 0; 510 } 511 512 PUFFS_MSG_ALLOC(vn, lookup); 513 puffs_makecn(&lookup_msg->pvnr_cn, &lookup_msg->pvnr_cn_cred, 514 cnp, PUFFS_USE_FULLPNBUF(pmp)); 515 516 if (cnp->cn_flags & ISDOTDOT) 517 VOP_UNLOCK(dvp); 518 519 puffs_msg_setinfo(park_lookup, PUFFSOP_VN, 520 PUFFS_VN_LOOKUP, VPTOPNC(dvp)); 521 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_lookup, dvp->v_data, NULL, error); 522 DPRINTF(("puffs_lookup: return of the userspace, part %d\n", error)); 523 524 /* 525 * In case of error, there is no new vnode to play with, so be 526 * happy with the NULL value given to vpp in the beginning. 527 * Also, check if this really was an error or the target was not 528 * present. Either treat it as a non-error for CREATE/RENAME or 529 * enter the component into the negative name cache (if desired). 530 */ 531 if (error) { 532 error = checkerr(pmp, error, __func__); 533 if (error == ENOENT) { 534 /* don't allow to create files on r/o fs */ 535 if ((dvp->v_mount->mnt_flag & MNT_RDONLY) 536 && cnp->cn_nameiop == CREATE) { 537 error = EROFS; 538 539 /* adjust values if we are creating */ 540 } else if ((cnp->cn_flags & ISLASTCN) 541 && (cnp->cn_nameiop == CREATE 542 || cnp->cn_nameiop == RENAME)) { 543 error = EJUSTRETURN; 544 545 /* save negative cache entry */ 546 } else { 547 if ((cnp->cn_flags & MAKEENTRY) 548 && PUFFS_USE_NAMECACHE(pmp)) 549 cache_enter(dvp, NULL, cnp); 550 } 551 } 552 goto out; 553 } 554 555 /* 556 * Check that we don't get our parent node back, that would cause 557 * a pretty obvious deadlock. 558 */ 559 dpn = dvp->v_data; 560 if (lookup_msg->pvnr_newnode == dpn->pn_cookie) { 561 puffs_senderr(pmp, PUFFS_ERR_LOOKUP, EINVAL, 562 "lookup produced parent cookie", lookup_msg->pvnr_newnode); 563 error = EPROTO; 564 goto out; 565 } 566 567 error = puffs_cookie2vnode(pmp, lookup_msg->pvnr_newnode, 1, 1, &vp); 568 if (error == PUFFS_NOSUCHCOOKIE) { 569 error = puffs_getvnode(dvp->v_mount, 570 lookup_msg->pvnr_newnode, lookup_msg->pvnr_vtype, 571 lookup_msg->pvnr_size, lookup_msg->pvnr_rdev, &vp); 572 if (error) { 573 puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp), 574 lookup_msg->pvnr_newnode, ap->a_cnp); 575 goto out; 576 } 577 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 578 } else if (error) { 579 puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp), 580 lookup_msg->pvnr_newnode, ap->a_cnp); 581 goto out; 582 } 583 584 *ap->a_vpp = vp; 585 586 if ((cnp->cn_flags & MAKEENTRY) != 0 && PUFFS_USE_NAMECACHE(pmp)) 587 cache_enter(dvp, vp, cnp); 588 589 /* XXX */ 590 if ((lookup_msg->pvnr_cn.pkcn_flags & REQUIREDIR) == 0) 591 cnp->cn_flags &= ~REQUIREDIR; 592 if (lookup_msg->pvnr_cn.pkcn_consume) 593 cnp->cn_consume = MIN(lookup_msg->pvnr_cn.pkcn_consume, 594 strlen(cnp->cn_nameptr) - cnp->cn_namelen); 595 596 out: 597 if (cnp->cn_flags & ISDOTDOT) 598 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 599 600 DPRINTF(("puffs_lookup: returning %d %p\n", error, *ap->a_vpp)); 601 PUFFS_MSG_RELEASE(lookup); 602 return error; 603 } 604 605 #define REFPN_AND_UNLOCKVP(a, b) \ 606 do { \ 607 mutex_enter(&b->pn_mtx); \ 608 puffs_referencenode(b); \ 609 mutex_exit(&b->pn_mtx); \ 610 VOP_UNLOCK(a); \ 611 } while (/*CONSTCOND*/0) 612 613 #define REFPN(b) \ 614 do { \ 615 mutex_enter(&b->pn_mtx); \ 616 puffs_referencenode(b); \ 617 mutex_exit(&b->pn_mtx); \ 618 } while (/*CONSTCOND*/0) 619 620 #define RELEPN_AND_VP(a, b) \ 621 do { \ 622 puffs_releasenode(b); \ 623 vrele(a); \ 624 } while (/*CONSTCOND*/0) 625 626 int 627 puffs_vnop_create(void *v) 628 { 629 struct vop_create_args /* { 630 const struct vnodeop_desc *a_desc; 631 struct vnode *a_dvp; 632 struct vnode **a_vpp; 633 struct componentname *a_cnp; 634 struct vattr *a_vap; 635 } */ *ap = v; 636 PUFFS_MSG_VARS(vn, create); 637 struct vnode *dvp = ap->a_dvp; 638 struct puffs_node *dpn = VPTOPP(dvp); 639 struct componentname *cnp = ap->a_cnp; 640 struct mount *mp = dvp->v_mount; 641 struct puffs_mount *pmp = MPTOPUFFSMP(mp); 642 int error; 643 644 DPRINTF(("puffs_create: dvp %p, cnp: %s\n", 645 dvp, ap->a_cnp->cn_nameptr)); 646 647 PUFFS_MSG_ALLOC(vn, create); 648 puffs_makecn(&create_msg->pvnr_cn, &create_msg->pvnr_cn_cred, 649 cnp, PUFFS_USE_FULLPNBUF(pmp)); 650 create_msg->pvnr_va = *ap->a_vap; 651 puffs_msg_setinfo(park_create, PUFFSOP_VN, 652 PUFFS_VN_CREATE, VPTOPNC(dvp)); 653 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_create, dvp->v_data, NULL, error); 654 655 error = checkerr(pmp, error, __func__); 656 if (error) 657 goto out; 658 659 error = puffs_newnode(mp, dvp, ap->a_vpp, 660 create_msg->pvnr_newnode, cnp, ap->a_vap->va_type, 0); 661 if (error) 662 puffs_abortbutton(pmp, PUFFS_ABORT_CREATE, dpn->pn_cookie, 663 create_msg->pvnr_newnode, cnp); 664 665 out: 666 vput(dvp); 667 668 DPRINTF(("puffs_create: return %d\n", error)); 669 PUFFS_MSG_RELEASE(create); 670 return error; 671 } 672 673 int 674 puffs_vnop_mknod(void *v) 675 { 676 struct vop_mknod_args /* { 677 const struct vnodeop_desc *a_desc; 678 struct vnode *a_dvp; 679 struct vnode **a_vpp; 680 struct componentname *a_cnp; 681 struct vattr *a_vap; 682 } */ *ap = v; 683 PUFFS_MSG_VARS(vn, mknod); 684 struct vnode *dvp = ap->a_dvp; 685 struct puffs_node *dpn = VPTOPP(dvp); 686 struct componentname *cnp = ap->a_cnp; 687 struct mount *mp = dvp->v_mount; 688 struct puffs_mount *pmp = MPTOPUFFSMP(mp); 689 int error; 690 691 PUFFS_MSG_ALLOC(vn, mknod); 692 puffs_makecn(&mknod_msg->pvnr_cn, &mknod_msg->pvnr_cn_cred, 693 cnp, PUFFS_USE_FULLPNBUF(pmp)); 694 mknod_msg->pvnr_va = *ap->a_vap; 695 puffs_msg_setinfo(park_mknod, PUFFSOP_VN, 696 PUFFS_VN_MKNOD, VPTOPNC(dvp)); 697 698 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_mknod, dvp->v_data, NULL, error); 699 700 error = checkerr(pmp, error, __func__); 701 if (error) 702 goto out; 703 704 error = puffs_newnode(mp, dvp, ap->a_vpp, 705 mknod_msg->pvnr_newnode, cnp, ap->a_vap->va_type, 706 ap->a_vap->va_rdev); 707 if (error) 708 puffs_abortbutton(pmp, PUFFS_ABORT_MKNOD, dpn->pn_cookie, 709 mknod_msg->pvnr_newnode, cnp); 710 711 out: 712 vput(dvp); 713 PUFFS_MSG_RELEASE(mknod); 714 return error; 715 } 716 717 int 718 puffs_vnop_open(void *v) 719 { 720 struct vop_open_args /* { 721 const struct vnodeop_desc *a_desc; 722 struct vnode *a_vp; 723 int a_mode; 724 kauth_cred_t a_cred; 725 } */ *ap = v; 726 PUFFS_MSG_VARS(vn, open); 727 struct vnode *vp = ap->a_vp; 728 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 729 int mode = ap->a_mode; 730 int error; 731 732 DPRINTF(("puffs_open: vp %p, mode 0x%x\n", vp, mode)); 733 734 if (vp->v_type == VREG && mode & FWRITE && !EXISTSOP(pmp, WRITE)) 735 ERROUT(EROFS); 736 737 if (!EXISTSOP(pmp, OPEN)) 738 ERROUT(0); 739 740 PUFFS_MSG_ALLOC(vn, open); 741 open_msg->pvnr_mode = mode; 742 puffs_credcvt(&open_msg->pvnr_cred, ap->a_cred); 743 puffs_msg_setinfo(park_open, PUFFSOP_VN, 744 PUFFS_VN_OPEN, VPTOPNC(vp)); 745 746 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_open, vp->v_data, NULL, error); 747 error = checkerr(pmp, error, __func__); 748 749 out: 750 DPRINTF(("puffs_open: returning %d\n", error)); 751 PUFFS_MSG_RELEASE(open); 752 return error; 753 } 754 755 int 756 puffs_vnop_close(void *v) 757 { 758 struct vop_close_args /* { 759 const struct vnodeop_desc *a_desc; 760 struct vnode *a_vp; 761 int a_fflag; 762 kauth_cred_t a_cred; 763 } */ *ap = v; 764 PUFFS_MSG_VARS(vn, close); 765 struct vnode *vp = ap->a_vp; 766 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 767 768 PUFFS_MSG_ALLOC(vn, close); 769 puffs_msg_setfaf(park_close); 770 close_msg->pvnr_fflag = ap->a_fflag; 771 puffs_credcvt(&close_msg->pvnr_cred, ap->a_cred); 772 puffs_msg_setinfo(park_close, PUFFSOP_VN, 773 PUFFS_VN_CLOSE, VPTOPNC(vp)); 774 775 puffs_msg_enqueue(pmp, park_close); 776 PUFFS_MSG_RELEASE(close); 777 return 0; 778 } 779 780 int 781 puffs_vnop_access(void *v) 782 { 783 struct vop_access_args /* { 784 const struct vnodeop_desc *a_desc; 785 struct vnode *a_vp; 786 int a_mode; 787 kauth_cred_t a_cred; 788 } */ *ap = v; 789 PUFFS_MSG_VARS(vn, access); 790 struct vnode *vp = ap->a_vp; 791 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 792 int mode = ap->a_mode; 793 int error; 794 795 if (mode & VWRITE) { 796 switch (vp->v_type) { 797 case VDIR: 798 case VLNK: 799 case VREG: 800 if ((vp->v_mount->mnt_flag & MNT_RDONLY) 801 || !EXISTSOP(pmp, WRITE)) 802 return EROFS; 803 break; 804 default: 805 break; 806 } 807 } 808 809 if (!EXISTSOP(pmp, ACCESS)) 810 return 0; 811 812 PUFFS_MSG_ALLOC(vn, access); 813 access_msg->pvnr_mode = ap->a_mode; 814 puffs_credcvt(&access_msg->pvnr_cred, ap->a_cred); 815 puffs_msg_setinfo(park_access, PUFFSOP_VN, 816 PUFFS_VN_ACCESS, VPTOPNC(vp)); 817 818 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_access, vp->v_data, NULL, error); 819 error = checkerr(pmp, error, __func__); 820 PUFFS_MSG_RELEASE(access); 821 822 return error; 823 } 824 825 int 826 puffs_vnop_getattr(void *v) 827 { 828 struct vop_getattr_args /* { 829 const struct vnodeop_desc *a_desc; 830 struct vnode *a_vp; 831 struct vattr *a_vap; 832 kauth_cred_t a_cred; 833 } */ *ap = v; 834 PUFFS_MSG_VARS(vn, getattr); 835 struct vnode *vp = ap->a_vp; 836 struct mount *mp = vp->v_mount; 837 struct puffs_mount *pmp = MPTOPUFFSMP(mp); 838 struct vattr *vap, *rvap; 839 struct puffs_node *pn = VPTOPP(vp); 840 int error = 0; 841 842 REFPN(pn); 843 vap = ap->a_vap; 844 845 PUFFS_MSG_ALLOC(vn, getattr); 846 vattr_null(&getattr_msg->pvnr_va); 847 puffs_credcvt(&getattr_msg->pvnr_cred, ap->a_cred); 848 puffs_msg_setinfo(park_getattr, PUFFSOP_VN, 849 PUFFS_VN_GETATTR, VPTOPNC(vp)); 850 851 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_getattr, vp->v_data, NULL, error); 852 error = checkerr(pmp, error, __func__); 853 if (error) 854 goto out; 855 856 rvap = &getattr_msg->pvnr_va; 857 /* 858 * Don't listen to the file server regarding special device 859 * size info, the file server doesn't know anything about them. 860 */ 861 if (vp->v_type == VBLK || vp->v_type == VCHR) 862 rvap->va_size = vp->v_size; 863 864 /* Ditto for blocksize (ufs comment: this doesn't belong here) */ 865 if (vp->v_type == VBLK) 866 rvap->va_blocksize = BLKDEV_IOSIZE; 867 else if (vp->v_type == VCHR) 868 rvap->va_blocksize = MAXBSIZE; 869 870 (void) memcpy(vap, rvap, sizeof(struct vattr)); 871 vap->va_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0]; 872 873 if (pn->pn_stat & PNODE_METACACHE_ATIME) 874 vap->va_atime = pn->pn_mc_atime; 875 if (pn->pn_stat & PNODE_METACACHE_CTIME) 876 vap->va_ctime = pn->pn_mc_ctime; 877 if (pn->pn_stat & PNODE_METACACHE_MTIME) 878 vap->va_mtime = pn->pn_mc_mtime; 879 if (pn->pn_stat & PNODE_METACACHE_SIZE) { 880 vap->va_size = pn->pn_mc_size; 881 } else { 882 if (rvap->va_size != VNOVAL 883 && vp->v_type != VBLK && vp->v_type != VCHR) { 884 uvm_vnp_setsize(vp, rvap->va_size); 885 pn->pn_serversize = rvap->va_size; 886 } 887 } 888 889 out: 890 puffs_releasenode(pn); 891 PUFFS_MSG_RELEASE(getattr); 892 return error; 893 } 894 895 #define SETATTR_CHSIZE 0x01 896 #define SETATTR_ASYNC 0x02 897 static int 898 dosetattr(struct vnode *vp, struct vattr *vap, kauth_cred_t cred, int flags) 899 { 900 PUFFS_MSG_VARS(vn, setattr); 901 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 902 struct puffs_node *pn = vp->v_data; 903 int error = 0; 904 905 if ((vp->v_mount->mnt_flag & MNT_RDONLY) && 906 (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL 907 || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL 908 || vap->va_mode != (mode_t)VNOVAL)) 909 return EROFS; 910 911 if ((vp->v_mount->mnt_flag & MNT_RDONLY) 912 && vp->v_type == VREG && vap->va_size != VNOVAL) 913 return EROFS; 914 915 /* 916 * Flush metacache first. If we are called with some explicit 917 * parameters, treat them as information overriding metacache 918 * information. 919 */ 920 if (pn->pn_stat & PNODE_METACACHE_MASK) { 921 if ((pn->pn_stat & PNODE_METACACHE_ATIME) 922 && vap->va_atime.tv_sec == VNOVAL) 923 vap->va_atime = pn->pn_mc_atime; 924 if ((pn->pn_stat & PNODE_METACACHE_CTIME) 925 && vap->va_ctime.tv_sec == VNOVAL) 926 vap->va_ctime = pn->pn_mc_ctime; 927 if ((pn->pn_stat & PNODE_METACACHE_MTIME) 928 && vap->va_mtime.tv_sec == VNOVAL) 929 vap->va_mtime = pn->pn_mc_mtime; 930 if ((pn->pn_stat & PNODE_METACACHE_SIZE) 931 && vap->va_size == VNOVAL) 932 vap->va_size = pn->pn_mc_size; 933 934 pn->pn_stat &= ~PNODE_METACACHE_MASK; 935 } 936 937 PUFFS_MSG_ALLOC(vn, setattr); 938 (void)memcpy(&setattr_msg->pvnr_va, vap, sizeof(struct vattr)); 939 puffs_credcvt(&setattr_msg->pvnr_cred, cred); 940 puffs_msg_setinfo(park_setattr, PUFFSOP_VN, 941 PUFFS_VN_SETATTR, VPTOPNC(vp)); 942 if (flags & SETATTR_ASYNC) 943 puffs_msg_setfaf(park_setattr); 944 945 puffs_msg_enqueue(pmp, park_setattr); 946 if ((flags & SETATTR_ASYNC) == 0) 947 error = puffs_msg_wait2(pmp, park_setattr, vp->v_data, NULL); 948 PUFFS_MSG_RELEASE(setattr); 949 if ((flags & SETATTR_ASYNC) == 0) { 950 error = checkerr(pmp, error, __func__); 951 if (error) 952 return error; 953 } else { 954 error = 0; 955 } 956 957 if (vap->va_size != VNOVAL) { 958 pn->pn_serversize = vap->va_size; 959 if (flags & SETATTR_CHSIZE) 960 uvm_vnp_setsize(vp, vap->va_size); 961 } 962 963 return 0; 964 } 965 966 int 967 puffs_vnop_setattr(void *v) 968 { 969 struct vop_getattr_args /* { 970 const struct vnodeop_desc *a_desc; 971 struct vnode *a_vp; 972 struct vattr *a_vap; 973 kauth_cred_t a_cred; 974 } */ *ap = v; 975 976 return dosetattr(ap->a_vp, ap->a_vap, ap->a_cred, SETATTR_CHSIZE); 977 } 978 979 static __inline int 980 doinact(struct puffs_mount *pmp, int iaflag) 981 { 982 983 if (EXISTSOP(pmp, INACTIVE)) 984 if (pmp->pmp_flags & PUFFS_KFLAG_IAONDEMAND) 985 if (iaflag || ALLOPS(pmp)) 986 return 1; 987 else 988 return 0; 989 else 990 return 1; 991 else 992 return 0; 993 } 994 995 static void 996 callinactive(struct puffs_mount *pmp, puffs_cookie_t ck, int iaflag) 997 { 998 int error; 999 PUFFS_MSG_VARS(vn, inactive); 1000 1001 if (doinact(pmp, iaflag)) { 1002 PUFFS_MSG_ALLOC(vn, inactive); 1003 puffs_msg_setinfo(park_inactive, PUFFSOP_VN, 1004 PUFFS_VN_INACTIVE, ck); 1005 1006 PUFFS_MSG_ENQUEUEWAIT(pmp, park_inactive, error); 1007 PUFFS_MSG_RELEASE(inactive); 1008 } 1009 } 1010 1011 /* XXX: callinactive can't setback */ 1012 int 1013 puffs_vnop_inactive(void *v) 1014 { 1015 struct vop_inactive_args /* { 1016 const struct vnodeop_desc *a_desc; 1017 struct vnode *a_vp; 1018 } */ *ap = v; 1019 PUFFS_MSG_VARS(vn, inactive); 1020 struct vnode *vp = ap->a_vp; 1021 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 1022 struct puffs_node *pnode; 1023 int error; 1024 1025 pnode = vp->v_data; 1026 1027 if (doinact(pmp, pnode->pn_stat & PNODE_DOINACT)) { 1028 flushvncache(vp, 0, 0, false); 1029 PUFFS_MSG_ALLOC(vn, inactive); 1030 puffs_msg_setinfo(park_inactive, PUFFSOP_VN, 1031 PUFFS_VN_INACTIVE, VPTOPNC(vp)); 1032 1033 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_inactive, vp->v_data, 1034 NULL, error); 1035 PUFFS_MSG_RELEASE(inactive); 1036 } 1037 pnode->pn_stat &= ~PNODE_DOINACT; 1038 1039 /* 1040 * file server thinks it's gone? then don't be afraid care, 1041 * node's life was already all it would ever be 1042 */ 1043 if (pnode->pn_stat & PNODE_NOREFS) { 1044 pnode->pn_stat |= PNODE_DYING; 1045 *ap->a_recycle = true; 1046 } 1047 1048 VOP_UNLOCK(vp); 1049 1050 return 0; 1051 } 1052 1053 static void 1054 callreclaim(struct puffs_mount *pmp, puffs_cookie_t ck) 1055 { 1056 PUFFS_MSG_VARS(vn, reclaim); 1057 1058 if (!EXISTSOP(pmp, RECLAIM)) 1059 return; 1060 1061 PUFFS_MSG_ALLOC(vn, reclaim); 1062 puffs_msg_setfaf(park_reclaim); 1063 puffs_msg_setinfo(park_reclaim, PUFFSOP_VN, PUFFS_VN_RECLAIM, ck); 1064 1065 puffs_msg_enqueue(pmp, park_reclaim); 1066 PUFFS_MSG_RELEASE(reclaim); 1067 } 1068 1069 /* 1070 * always FAF, we don't really care if the server wants to fail to 1071 * reclaim the node or not 1072 */ 1073 int 1074 puffs_vnop_reclaim(void *v) 1075 { 1076 struct vop_reclaim_args /* { 1077 const struct vnodeop_desc *a_desc; 1078 struct vnode *a_vp; 1079 } */ *ap = v; 1080 struct vnode *vp = ap->a_vp; 1081 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 1082 struct puffs_node *pnode = vp->v_data; 1083 bool notifyserver = true; 1084 1085 /* 1086 * first things first: check if someone is trying to reclaim the 1087 * root vnode. do not allow that to travel to userspace. 1088 * Note that we don't need to take the lock similarly to 1089 * puffs_root(), since there is only one of us. 1090 */ 1091 if (vp->v_vflag & VV_ROOT) { 1092 mutex_enter(&pmp->pmp_lock); 1093 KASSERT(pmp->pmp_root != NULL); 1094 pmp->pmp_root = NULL; 1095 mutex_exit(&pmp->pmp_lock); 1096 notifyserver = false; 1097 } 1098 1099 /* 1100 * purge info from kernel before issueing FAF, since we 1101 * don't really know when we'll get around to it after 1102 * that and someone might race us into node creation 1103 */ 1104 mutex_enter(&pmp->pmp_lock); 1105 LIST_REMOVE(pnode, pn_hashent); 1106 mutex_exit(&pmp->pmp_lock); 1107 if (PUFFS_USE_NAMECACHE(pmp)) 1108 cache_purge(vp); 1109 1110 if (notifyserver) 1111 callreclaim(MPTOPUFFSMP(vp->v_mount), VPTOPNC(vp)); 1112 1113 puffs_putvnode(vp); 1114 1115 return 0; 1116 } 1117 1118 #define CSIZE sizeof(**ap->a_cookies) 1119 int 1120 puffs_vnop_readdir(void *v) 1121 { 1122 struct vop_readdir_args /* { 1123 const struct vnodeop_desc *a_desc; 1124 struct vnode *a_vp; 1125 struct uio *a_uio; 1126 kauth_cred_t a_cred; 1127 int *a_eofflag; 1128 off_t **a_cookies; 1129 int *a_ncookies; 1130 } */ *ap = v; 1131 PUFFS_MSG_VARS(vn, readdir); 1132 struct vnode *vp = ap->a_vp; 1133 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 1134 size_t argsize, tomove, cookiemem, cookiesmax; 1135 struct uio *uio = ap->a_uio; 1136 size_t howmuch, resid; 1137 int error; 1138 1139 /* 1140 * ok, so we need: resid + cookiemem = maxreq 1141 * => resid + cookiesize * (resid/minsize) = maxreq 1142 * => resid + cookiesize/minsize * resid = maxreq 1143 * => (cookiesize/minsize + 1) * resid = maxreq 1144 * => resid = maxreq / (cookiesize/minsize + 1) 1145 * 1146 * Since cookiesize <= minsize and we're not very big on floats, 1147 * we approximate that to be 1. Therefore: 1148 * 1149 * resid = maxreq / 2; 1150 * 1151 * Well, at least we didn't have to use differential equations 1152 * or the Gram-Schmidt process. 1153 * 1154 * (yes, I'm very afraid of this) 1155 */ 1156 KASSERT(CSIZE <= _DIRENT_MINSIZE((struct dirent *)0)); 1157 1158 if (ap->a_cookies) { 1159 KASSERT(ap->a_ncookies != NULL); 1160 if (pmp->pmp_args.pa_fhsize == 0) 1161 return EOPNOTSUPP; 1162 resid = PUFFS_TOMOVE(uio->uio_resid, pmp) / 2; 1163 cookiesmax = resid/_DIRENT_MINSIZE((struct dirent *)0); 1164 cookiemem = ALIGN(cookiesmax*CSIZE); /* play safe */ 1165 } else { 1166 resid = PUFFS_TOMOVE(uio->uio_resid, pmp); 1167 cookiesmax = 0; 1168 cookiemem = 0; 1169 } 1170 1171 argsize = sizeof(struct puffs_vnmsg_readdir); 1172 tomove = resid + cookiemem; 1173 puffs_msgmem_alloc(argsize + tomove, &park_readdir, 1174 (void *)&readdir_msg, 1); 1175 1176 puffs_credcvt(&readdir_msg->pvnr_cred, ap->a_cred); 1177 readdir_msg->pvnr_offset = uio->uio_offset; 1178 readdir_msg->pvnr_resid = resid; 1179 readdir_msg->pvnr_ncookies = cookiesmax; 1180 readdir_msg->pvnr_eofflag = 0; 1181 readdir_msg->pvnr_dentoff = cookiemem; 1182 puffs_msg_setinfo(park_readdir, PUFFSOP_VN, 1183 PUFFS_VN_READDIR, VPTOPNC(vp)); 1184 puffs_msg_setdelta(park_readdir, tomove); 1185 1186 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_readdir, vp->v_data, NULL, error); 1187 error = checkerr(pmp, error, __func__); 1188 if (error) 1189 goto out; 1190 1191 /* userspace is cheating? */ 1192 if (readdir_msg->pvnr_resid > resid) { 1193 puffs_senderr(pmp, PUFFS_ERR_READDIR, E2BIG, 1194 "resid grew", VPTOPNC(vp)); 1195 ERROUT(EPROTO); 1196 } 1197 if (readdir_msg->pvnr_ncookies > cookiesmax) { 1198 puffs_senderr(pmp, PUFFS_ERR_READDIR, E2BIG, 1199 "too many cookies", VPTOPNC(vp)); 1200 ERROUT(EPROTO); 1201 } 1202 1203 /* check eof */ 1204 if (readdir_msg->pvnr_eofflag) 1205 *ap->a_eofflag = 1; 1206 1207 /* bouncy-wouncy with the directory data */ 1208 howmuch = resid - readdir_msg->pvnr_resid; 1209 1210 /* force eof if no data was returned (getcwd() needs this) */ 1211 if (howmuch == 0) { 1212 *ap->a_eofflag = 1; 1213 goto out; 1214 } 1215 1216 error = uiomove(readdir_msg->pvnr_data + cookiemem, howmuch, uio); 1217 if (error) 1218 goto out; 1219 1220 /* provide cookies to caller if so desired */ 1221 if (ap->a_cookies) { 1222 *ap->a_cookies = malloc(readdir_msg->pvnr_ncookies*CSIZE, 1223 M_TEMP, M_WAITOK); 1224 *ap->a_ncookies = readdir_msg->pvnr_ncookies; 1225 memcpy(*ap->a_cookies, readdir_msg->pvnr_data, 1226 *ap->a_ncookies*CSIZE); 1227 } 1228 1229 /* next readdir starts here */ 1230 uio->uio_offset = readdir_msg->pvnr_offset; 1231 1232 out: 1233 puffs_msgmem_release(park_readdir); 1234 return error; 1235 } 1236 #undef CSIZE 1237 1238 /* 1239 * poll works by consuming the bitmask in pn_revents. If there are 1240 * events available, poll returns immediately. If not, it issues a 1241 * poll to userspace, selrecords itself and returns with no available 1242 * events. When the file server returns, it executes puffs_parkdone_poll(), 1243 * where available events are added to the bitmask. selnotify() is 1244 * then also executed by that function causing us to enter here again 1245 * and hopefully find the missing bits (unless someone got them first, 1246 * in which case it starts all over again). 1247 */ 1248 int 1249 puffs_vnop_poll(void *v) 1250 { 1251 struct vop_poll_args /* { 1252 const struct vnodeop_desc *a_desc; 1253 struct vnode *a_vp; 1254 int a_events; 1255 } */ *ap = v; 1256 PUFFS_MSG_VARS(vn, poll); 1257 struct vnode *vp = ap->a_vp; 1258 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 1259 struct puffs_node *pn = vp->v_data; 1260 int events, error; 1261 1262 if (EXISTSOP(pmp, POLL)) { 1263 mutex_enter(&pn->pn_mtx); 1264 events = pn->pn_revents & ap->a_events; 1265 if (events & ap->a_events) { 1266 pn->pn_revents &= ~ap->a_events; 1267 mutex_exit(&pn->pn_mtx); 1268 1269 return events; 1270 } else { 1271 puffs_referencenode(pn); 1272 mutex_exit(&pn->pn_mtx); 1273 1274 PUFFS_MSG_ALLOC(vn, poll); 1275 poll_msg->pvnr_events = ap->a_events; 1276 puffs_msg_setinfo(park_poll, PUFFSOP_VN, 1277 PUFFS_VN_POLL, VPTOPNC(vp)); 1278 puffs_msg_setcall(park_poll, puffs_parkdone_poll, pn); 1279 selrecord(curlwp, &pn->pn_sel); 1280 1281 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_poll, vp->v_data, 1282 NULL, error); 1283 PUFFS_MSG_RELEASE(poll); 1284 1285 return 0; 1286 } 1287 } else { 1288 return genfs_poll(v); 1289 } 1290 } 1291 1292 static int 1293 flushvncache(struct vnode *vp, off_t offlo, off_t offhi, bool wait) 1294 { 1295 struct puffs_node *pn = VPTOPP(vp); 1296 struct vattr va; 1297 int pflags, error; 1298 1299 /* flush out information from our metacache, see vop_setattr */ 1300 if (pn->pn_stat & PNODE_METACACHE_MASK 1301 && (pn->pn_stat & PNODE_DYING) == 0) { 1302 vattr_null(&va); 1303 error = dosetattr(vp, &va, FSCRED, 1304 SETATTR_CHSIZE | (wait ? 0 : SETATTR_ASYNC)); 1305 if (error) 1306 return error; 1307 } 1308 1309 /* 1310 * flush pages to avoid being overly dirty 1311 */ 1312 pflags = PGO_CLEANIT; 1313 if (wait) 1314 pflags |= PGO_SYNCIO; 1315 mutex_enter(&vp->v_interlock); 1316 return VOP_PUTPAGES(vp, trunc_page(offlo), round_page(offhi), pflags); 1317 } 1318 1319 int 1320 puffs_vnop_fsync(void *v) 1321 { 1322 struct vop_fsync_args /* { 1323 const struct vnodeop_desc *a_desc; 1324 struct vnode *a_vp; 1325 kauth_cred_t a_cred; 1326 int a_flags; 1327 off_t a_offlo; 1328 off_t a_offhi; 1329 } */ *ap = v; 1330 PUFFS_MSG_VARS(vn, fsync); 1331 struct vnode *vp = ap->a_vp; 1332 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 1333 struct puffs_node *pn = VPTOPP(vp); 1334 int error, dofaf; 1335 1336 error = flushvncache(vp, ap->a_offlo, ap->a_offhi, 1337 (ap->a_flags & FSYNC_WAIT) == FSYNC_WAIT); 1338 if (error) 1339 return error; 1340 1341 /* 1342 * HELLO! We exit already here if the user server does not 1343 * support fsync OR if we should call fsync for a node which 1344 * has references neither in the kernel or the fs server. 1345 * Otherwise we continue to issue fsync() forward. 1346 */ 1347 if (!EXISTSOP(pmp, FSYNC) || (pn->pn_stat & PNODE_DYING)) 1348 return 0; 1349 1350 dofaf = (ap->a_flags & FSYNC_WAIT) == 0 || ap->a_flags == FSYNC_LAZY; 1351 /* 1352 * We abuse VXLOCK to mean "vnode is going to die", so we issue 1353 * only FAFs for those. Otherwise there's a danger of deadlock, 1354 * since the execution context here might be the user server 1355 * doing some operation on another fs, which in turn caused a 1356 * vnode to be reclaimed from the freelist for this fs. 1357 */ 1358 if (dofaf == 0) { 1359 mutex_enter(&vp->v_interlock); 1360 if (vp->v_iflag & VI_XLOCK) 1361 dofaf = 1; 1362 mutex_exit(&vp->v_interlock); 1363 } 1364 1365 PUFFS_MSG_ALLOC(vn, fsync); 1366 if (dofaf) 1367 puffs_msg_setfaf(park_fsync); 1368 1369 puffs_credcvt(&fsync_msg->pvnr_cred, ap->a_cred); 1370 fsync_msg->pvnr_flags = ap->a_flags; 1371 fsync_msg->pvnr_offlo = ap->a_offlo; 1372 fsync_msg->pvnr_offhi = ap->a_offhi; 1373 puffs_msg_setinfo(park_fsync, PUFFSOP_VN, 1374 PUFFS_VN_FSYNC, VPTOPNC(vp)); 1375 1376 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_fsync, vp->v_data, NULL, error); 1377 PUFFS_MSG_RELEASE(fsync); 1378 1379 error = checkerr(pmp, error, __func__); 1380 1381 return error; 1382 } 1383 1384 int 1385 puffs_vnop_seek(void *v) 1386 { 1387 struct vop_seek_args /* { 1388 const struct vnodeop_desc *a_desc; 1389 struct vnode *a_vp; 1390 off_t a_oldoff; 1391 off_t a_newoff; 1392 kauth_cred_t a_cred; 1393 } */ *ap = v; 1394 PUFFS_MSG_VARS(vn, seek); 1395 struct vnode *vp = ap->a_vp; 1396 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 1397 int error; 1398 1399 PUFFS_MSG_ALLOC(vn, seek); 1400 seek_msg->pvnr_oldoff = ap->a_oldoff; 1401 seek_msg->pvnr_newoff = ap->a_newoff; 1402 puffs_credcvt(&seek_msg->pvnr_cred, ap->a_cred); 1403 puffs_msg_setinfo(park_seek, PUFFSOP_VN, 1404 PUFFS_VN_SEEK, VPTOPNC(vp)); 1405 1406 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_seek, vp->v_data, NULL, error); 1407 PUFFS_MSG_RELEASE(seek); 1408 return checkerr(pmp, error, __func__); 1409 } 1410 1411 static int 1412 callremove(struct puffs_mount *pmp, puffs_cookie_t dck, puffs_cookie_t ck, 1413 struct componentname *cnp) 1414 { 1415 PUFFS_MSG_VARS(vn, remove); 1416 int error; 1417 1418 PUFFS_MSG_ALLOC(vn, remove); 1419 remove_msg->pvnr_cookie_targ = ck; 1420 puffs_makecn(&remove_msg->pvnr_cn, &remove_msg->pvnr_cn_cred, 1421 cnp, PUFFS_USE_FULLPNBUF(pmp)); 1422 puffs_msg_setinfo(park_remove, PUFFSOP_VN, PUFFS_VN_REMOVE, dck); 1423 1424 PUFFS_MSG_ENQUEUEWAIT(pmp, park_remove, error); 1425 PUFFS_MSG_RELEASE(remove); 1426 1427 return checkerr(pmp, error, __func__); 1428 } 1429 1430 /* 1431 * XXX: can't use callremove now because can't catch setbacks with 1432 * it due to lack of a pnode argument. 1433 */ 1434 int 1435 puffs_vnop_remove(void *v) 1436 { 1437 struct vop_remove_args /* { 1438 const struct vnodeop_desc *a_desc; 1439 struct vnode *a_dvp; 1440 struct vnode *a_vp; 1441 struct componentname *a_cnp; 1442 } */ *ap = v; 1443 PUFFS_MSG_VARS(vn, remove); 1444 struct vnode *dvp = ap->a_dvp; 1445 struct vnode *vp = ap->a_vp; 1446 struct puffs_node *dpn = VPTOPP(dvp); 1447 struct puffs_node *pn = VPTOPP(vp); 1448 struct componentname *cnp = ap->a_cnp; 1449 struct mount *mp = dvp->v_mount; 1450 struct puffs_mount *pmp = MPTOPUFFSMP(mp); 1451 int error; 1452 1453 PUFFS_MSG_ALLOC(vn, remove); 1454 remove_msg->pvnr_cookie_targ = VPTOPNC(vp); 1455 puffs_makecn(&remove_msg->pvnr_cn, &remove_msg->pvnr_cn_cred, 1456 cnp, PUFFS_USE_FULLPNBUF(pmp)); 1457 puffs_msg_setinfo(park_remove, PUFFSOP_VN, 1458 PUFFS_VN_REMOVE, VPTOPNC(dvp)); 1459 1460 puffs_msg_enqueue(pmp, park_remove); 1461 REFPN_AND_UNLOCKVP(dvp, dpn); 1462 if (dvp == vp) 1463 REFPN(pn); 1464 else 1465 REFPN_AND_UNLOCKVP(vp, pn); 1466 error = puffs_msg_wait2(pmp, park_remove, dpn, pn); 1467 1468 PUFFS_MSG_RELEASE(remove); 1469 1470 RELEPN_AND_VP(dvp, dpn); 1471 RELEPN_AND_VP(vp, pn); 1472 1473 error = checkerr(pmp, error, __func__); 1474 return error; 1475 } 1476 1477 int 1478 puffs_vnop_mkdir(void *v) 1479 { 1480 struct vop_mkdir_args /* { 1481 const struct vnodeop_desc *a_desc; 1482 struct vnode *a_dvp; 1483 struct vnode **a_vpp; 1484 struct componentname *a_cnp; 1485 struct vattr *a_vap; 1486 } */ *ap = v; 1487 PUFFS_MSG_VARS(vn, mkdir); 1488 struct vnode *dvp = ap->a_dvp; 1489 struct puffs_node *dpn = VPTOPP(dvp); 1490 struct componentname *cnp = ap->a_cnp; 1491 struct mount *mp = dvp->v_mount; 1492 struct puffs_mount *pmp = MPTOPUFFSMP(mp); 1493 int error; 1494 1495 PUFFS_MSG_ALLOC(vn, mkdir); 1496 puffs_makecn(&mkdir_msg->pvnr_cn, &mkdir_msg->pvnr_cn_cred, 1497 cnp, PUFFS_USE_FULLPNBUF(pmp)); 1498 mkdir_msg->pvnr_va = *ap->a_vap; 1499 puffs_msg_setinfo(park_mkdir, PUFFSOP_VN, 1500 PUFFS_VN_MKDIR, VPTOPNC(dvp)); 1501 1502 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_mkdir, dvp->v_data, NULL, error); 1503 1504 error = checkerr(pmp, error, __func__); 1505 if (error) 1506 goto out; 1507 1508 error = puffs_newnode(mp, dvp, ap->a_vpp, 1509 mkdir_msg->pvnr_newnode, cnp, VDIR, 0); 1510 if (error) 1511 puffs_abortbutton(pmp, PUFFS_ABORT_MKDIR, dpn->pn_cookie, 1512 mkdir_msg->pvnr_newnode, cnp); 1513 1514 out: 1515 vput(dvp); 1516 PUFFS_MSG_RELEASE(mkdir); 1517 return error; 1518 } 1519 1520 static int 1521 callrmdir(struct puffs_mount *pmp, puffs_cookie_t dck, puffs_cookie_t ck, 1522 struct componentname *cnp) 1523 { 1524 PUFFS_MSG_VARS(vn, rmdir); 1525 int error; 1526 1527 PUFFS_MSG_ALLOC(vn, rmdir); 1528 rmdir_msg->pvnr_cookie_targ = ck; 1529 puffs_makecn(&rmdir_msg->pvnr_cn, &rmdir_msg->pvnr_cn_cred, 1530 cnp, PUFFS_USE_FULLPNBUF(pmp)); 1531 puffs_msg_setinfo(park_rmdir, PUFFSOP_VN, PUFFS_VN_RMDIR, dck); 1532 1533 PUFFS_MSG_ENQUEUEWAIT(pmp, park_rmdir, error); 1534 PUFFS_MSG_RELEASE(rmdir); 1535 1536 return checkerr(pmp, error, __func__); 1537 } 1538 1539 int 1540 puffs_vnop_rmdir(void *v) 1541 { 1542 struct vop_rmdir_args /* { 1543 const struct vnodeop_desc *a_desc; 1544 struct vnode *a_dvp; 1545 struct vnode *a_vp; 1546 struct componentname *a_cnp; 1547 } */ *ap = v; 1548 PUFFS_MSG_VARS(vn, rmdir); 1549 struct vnode *dvp = ap->a_dvp; 1550 struct vnode *vp = ap->a_vp; 1551 struct puffs_node *dpn = VPTOPP(dvp); 1552 struct puffs_node *pn = VPTOPP(vp); 1553 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount); 1554 struct componentname *cnp = ap->a_cnp; 1555 int error; 1556 1557 PUFFS_MSG_ALLOC(vn, rmdir); 1558 rmdir_msg->pvnr_cookie_targ = VPTOPNC(vp); 1559 puffs_makecn(&rmdir_msg->pvnr_cn, &rmdir_msg->pvnr_cn_cred, 1560 cnp, PUFFS_USE_FULLPNBUF(pmp)); 1561 puffs_msg_setinfo(park_rmdir, PUFFSOP_VN, 1562 PUFFS_VN_RMDIR, VPTOPNC(dvp)); 1563 1564 puffs_msg_enqueue(pmp, park_rmdir); 1565 REFPN_AND_UNLOCKVP(dvp, dpn); 1566 REFPN_AND_UNLOCKVP(vp, pn); 1567 error = puffs_msg_wait2(pmp, park_rmdir, dpn, pn); 1568 1569 PUFFS_MSG_RELEASE(rmdir); 1570 1571 /* XXX: some call cache_purge() *for both vnodes* here, investigate */ 1572 RELEPN_AND_VP(dvp, dpn); 1573 RELEPN_AND_VP(vp, pn); 1574 1575 return error; 1576 } 1577 1578 int 1579 puffs_vnop_link(void *v) 1580 { 1581 struct vop_link_args /* { 1582 const struct vnodeop_desc *a_desc; 1583 struct vnode *a_dvp; 1584 struct vnode *a_vp; 1585 struct componentname *a_cnp; 1586 } */ *ap = v; 1587 PUFFS_MSG_VARS(vn, link); 1588 struct vnode *dvp = ap->a_dvp; 1589 struct vnode *vp = ap->a_vp; 1590 struct puffs_node *dpn = VPTOPP(dvp); 1591 struct puffs_node *pn = VPTOPP(vp); 1592 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount); 1593 struct componentname *cnp = ap->a_cnp; 1594 int error; 1595 1596 PUFFS_MSG_ALLOC(vn, link); 1597 link_msg->pvnr_cookie_targ = VPTOPNC(vp); 1598 puffs_makecn(&link_msg->pvnr_cn, &link_msg->pvnr_cn_cred, 1599 cnp, PUFFS_USE_FULLPNBUF(pmp)); 1600 puffs_msg_setinfo(park_link, PUFFSOP_VN, 1601 PUFFS_VN_LINK, VPTOPNC(dvp)); 1602 1603 puffs_msg_enqueue(pmp, park_link); 1604 REFPN_AND_UNLOCKVP(dvp, dpn); 1605 REFPN(pn); 1606 error = puffs_msg_wait2(pmp, park_link, dpn, pn); 1607 1608 PUFFS_MSG_RELEASE(link); 1609 1610 error = checkerr(pmp, error, __func__); 1611 1612 /* 1613 * XXX: stay in touch with the cache. I don't like this, but 1614 * don't have a better solution either. See also puffs_rename(). 1615 */ 1616 if (error == 0) 1617 puffs_updatenode(pn, PUFFS_UPDATECTIME, 0); 1618 1619 RELEPN_AND_VP(dvp, dpn); 1620 puffs_releasenode(pn); 1621 1622 return error; 1623 } 1624 1625 int 1626 puffs_vnop_symlink(void *v) 1627 { 1628 struct vop_symlink_args /* { 1629 const struct vnodeop_desc *a_desc; 1630 struct vnode *a_dvp; 1631 struct vnode **a_vpp; 1632 struct componentname *a_cnp; 1633 struct vattr *a_vap; 1634 char *a_target; 1635 } */ *ap = v; 1636 PUFFS_MSG_VARS(vn, symlink); 1637 struct vnode *dvp = ap->a_dvp; 1638 struct puffs_node *dpn = VPTOPP(dvp); 1639 struct mount *mp = dvp->v_mount; 1640 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount); 1641 struct componentname *cnp = ap->a_cnp; 1642 int error; 1643 1644 *ap->a_vpp = NULL; 1645 1646 PUFFS_MSG_ALLOC(vn, symlink); 1647 puffs_makecn(&symlink_msg->pvnr_cn, &symlink_msg->pvnr_cn_cred, 1648 cnp, PUFFS_USE_FULLPNBUF(pmp)); 1649 symlink_msg->pvnr_va = *ap->a_vap; 1650 (void)strlcpy(symlink_msg->pvnr_link, ap->a_target, 1651 sizeof(symlink_msg->pvnr_link)); 1652 puffs_msg_setinfo(park_symlink, PUFFSOP_VN, 1653 PUFFS_VN_SYMLINK, VPTOPNC(dvp)); 1654 1655 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_symlink, dvp->v_data, NULL, error); 1656 1657 error = checkerr(pmp, error, __func__); 1658 if (error) 1659 goto out; 1660 1661 error = puffs_newnode(mp, dvp, ap->a_vpp, 1662 symlink_msg->pvnr_newnode, cnp, VLNK, 0); 1663 if (error) 1664 puffs_abortbutton(pmp, PUFFS_ABORT_SYMLINK, dpn->pn_cookie, 1665 symlink_msg->pvnr_newnode, cnp); 1666 1667 out: 1668 vput(dvp); 1669 PUFFS_MSG_RELEASE(symlink); 1670 1671 return error; 1672 } 1673 1674 int 1675 puffs_vnop_readlink(void *v) 1676 { 1677 struct vop_readlink_args /* { 1678 const struct vnodeop_desc *a_desc; 1679 struct vnode *a_vp; 1680 struct uio *a_uio; 1681 kauth_cred_t a_cred; 1682 } */ *ap = v; 1683 PUFFS_MSG_VARS(vn, readlink); 1684 struct vnode *vp = ap->a_vp; 1685 struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_vp->v_mount); 1686 size_t linklen; 1687 int error; 1688 1689 PUFFS_MSG_ALLOC(vn, readlink); 1690 puffs_credcvt(&readlink_msg->pvnr_cred, ap->a_cred); 1691 linklen = sizeof(readlink_msg->pvnr_link); 1692 readlink_msg->pvnr_linklen = linklen; 1693 puffs_msg_setinfo(park_readlink, PUFFSOP_VN, 1694 PUFFS_VN_READLINK, VPTOPNC(vp)); 1695 1696 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_readlink, vp->v_data, NULL, error); 1697 error = checkerr(pmp, error, __func__); 1698 if (error) 1699 goto out; 1700 1701 /* bad bad user file server */ 1702 if (readlink_msg->pvnr_linklen > linklen) { 1703 puffs_senderr(pmp, PUFFS_ERR_READLINK, E2BIG, 1704 "linklen too big", VPTOPNC(ap->a_vp)); 1705 error = EPROTO; 1706 goto out; 1707 } 1708 1709 error = uiomove(&readlink_msg->pvnr_link, readlink_msg->pvnr_linklen, 1710 ap->a_uio); 1711 out: 1712 PUFFS_MSG_RELEASE(readlink); 1713 return error; 1714 } 1715 1716 int 1717 puffs_vnop_rename(void *v) 1718 { 1719 struct vop_rename_args /* { 1720 const struct vnodeop_desc *a_desc; 1721 struct vnode *a_fdvp; 1722 struct vnode *a_fvp; 1723 struct componentname *a_fcnp; 1724 struct vnode *a_tdvp; 1725 struct vnode *a_tvp; 1726 struct componentname *a_tcnp; 1727 } */ *ap = v; 1728 PUFFS_MSG_VARS(vn, rename); 1729 struct vnode *fdvp = ap->a_fdvp, *fvp = ap->a_fvp; 1730 struct vnode *tdvp = ap->a_tdvp, *tvp = ap->a_tvp; 1731 struct puffs_node *fpn = ap->a_fvp->v_data; 1732 struct puffs_mount *pmp = MPTOPUFFSMP(fdvp->v_mount); 1733 int error; 1734 bool doabort = true; 1735 1736 if ((fvp->v_mount != tdvp->v_mount) || 1737 (tvp && (fvp->v_mount != tvp->v_mount))) { 1738 ERROUT(EXDEV); 1739 } 1740 1741 PUFFS_MSG_ALLOC(vn, rename); 1742 rename_msg->pvnr_cookie_src = VPTOPNC(fvp); 1743 rename_msg->pvnr_cookie_targdir = VPTOPNC(tdvp); 1744 if (tvp) 1745 rename_msg->pvnr_cookie_targ = VPTOPNC(tvp); 1746 else 1747 rename_msg->pvnr_cookie_targ = NULL; 1748 puffs_makecn(&rename_msg->pvnr_cn_src, &rename_msg->pvnr_cn_src_cred, 1749 ap->a_fcnp, PUFFS_USE_FULLPNBUF(pmp)); 1750 puffs_makecn(&rename_msg->pvnr_cn_targ, &rename_msg->pvnr_cn_targ_cred, 1751 ap->a_tcnp, PUFFS_USE_FULLPNBUF(pmp)); 1752 puffs_msg_setinfo(park_rename, PUFFSOP_VN, 1753 PUFFS_VN_RENAME, VPTOPNC(fdvp)); 1754 1755 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_rename, fdvp->v_data, NULL, error); 1756 doabort = false; 1757 PUFFS_MSG_RELEASE(rename); 1758 error = checkerr(pmp, error, __func__); 1759 1760 /* 1761 * XXX: stay in touch with the cache. I don't like this, but 1762 * don't have a better solution either. See also puffs_link(). 1763 */ 1764 if (error == 0) 1765 puffs_updatenode(fpn, PUFFS_UPDATECTIME, 0); 1766 1767 out: 1768 if (doabort) 1769 VOP_ABORTOP(tdvp, ap->a_tcnp); 1770 if (tvp != NULL) 1771 vput(tvp); 1772 if (tdvp == tvp) 1773 vrele(tdvp); 1774 else 1775 vput(tdvp); 1776 1777 if (doabort) 1778 VOP_ABORTOP(fdvp, ap->a_fcnp); 1779 vrele(fdvp); 1780 vrele(fvp); 1781 1782 return error; 1783 } 1784 1785 #define RWARGS(cont, iofl, move, offset, creds) \ 1786 (cont)->pvnr_ioflag = (iofl); \ 1787 (cont)->pvnr_resid = (move); \ 1788 (cont)->pvnr_offset = (offset); \ 1789 puffs_credcvt(&(cont)->pvnr_cred, creds) 1790 1791 int 1792 puffs_vnop_read(void *v) 1793 { 1794 struct vop_read_args /* { 1795 const struct vnodeop_desc *a_desc; 1796 struct vnode *a_vp; 1797 struct uio *a_uio; 1798 int a_ioflag; 1799 kauth_cred_t a_cred; 1800 } */ *ap = v; 1801 PUFFS_MSG_VARS(vn, read); 1802 struct vnode *vp = ap->a_vp; 1803 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 1804 struct uio *uio = ap->a_uio; 1805 size_t tomove, argsize; 1806 vsize_t bytelen; 1807 int error; 1808 1809 read_msg = NULL; 1810 error = 0; 1811 1812 /* std sanity */ 1813 if (uio->uio_resid == 0) 1814 return 0; 1815 if (uio->uio_offset < 0) 1816 return EINVAL; 1817 1818 if (vp->v_type == VREG && PUFFS_USE_PAGECACHE(pmp)) { 1819 const int advice = IO_ADV_DECODE(ap->a_ioflag); 1820 1821 while (uio->uio_resid > 0) { 1822 bytelen = MIN(uio->uio_resid, 1823 vp->v_size - uio->uio_offset); 1824 if (bytelen == 0) 1825 break; 1826 1827 error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice, 1828 UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp)); 1829 if (error) 1830 break; 1831 } 1832 1833 if ((vp->v_mount->mnt_flag & MNT_NOATIME) == 0) 1834 puffs_updatenode(VPTOPP(vp), PUFFS_UPDATEATIME, 0); 1835 } else { 1836 /* 1837 * in case it's not a regular file or we're operating 1838 * uncached, do read in the old-fashioned style, 1839 * i.e. explicit read operations 1840 */ 1841 1842 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp); 1843 argsize = sizeof(struct puffs_vnmsg_read); 1844 puffs_msgmem_alloc(argsize + tomove, &park_read, 1845 (void *)&read_msg, 1); 1846 1847 error = 0; 1848 while (uio->uio_resid > 0) { 1849 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp); 1850 memset(read_msg, 0, argsize); /* XXX: touser KASSERT */ 1851 RWARGS(read_msg, ap->a_ioflag, tomove, 1852 uio->uio_offset, ap->a_cred); 1853 puffs_msg_setinfo(park_read, PUFFSOP_VN, 1854 PUFFS_VN_READ, VPTOPNC(vp)); 1855 puffs_msg_setdelta(park_read, tomove); 1856 1857 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_read, vp->v_data, 1858 NULL, error); 1859 error = checkerr(pmp, error, __func__); 1860 if (error) 1861 break; 1862 1863 if (read_msg->pvnr_resid > tomove) { 1864 puffs_senderr(pmp, PUFFS_ERR_READ, 1865 E2BIG, "resid grew", VPTOPNC(ap->a_vp)); 1866 error = EPROTO; 1867 break; 1868 } 1869 1870 error = uiomove(read_msg->pvnr_data, 1871 tomove - read_msg->pvnr_resid, uio); 1872 1873 /* 1874 * in case the file is out of juice, resid from 1875 * userspace is != 0. and the error-case is 1876 * quite obvious 1877 */ 1878 if (error || read_msg->pvnr_resid) 1879 break; 1880 } 1881 1882 puffs_msgmem_release(park_read); 1883 } 1884 1885 return error; 1886 } 1887 1888 /* 1889 * XXX: in case of a failure, this leaves uio in a bad state. 1890 * We could theoretically copy the uio and iovecs and "replay" 1891 * them the right amount after the userspace trip, but don't 1892 * bother for now. 1893 */ 1894 int 1895 puffs_vnop_write(void *v) 1896 { 1897 struct vop_write_args /* { 1898 const struct vnodeop_desc *a_desc; 1899 struct vnode *a_vp; 1900 struct uio *a_uio; 1901 int a_ioflag; 1902 kauth_cred_t a_cred; 1903 } */ *ap = v; 1904 PUFFS_MSG_VARS(vn, write); 1905 struct vnode *vp = ap->a_vp; 1906 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 1907 struct uio *uio = ap->a_uio; 1908 size_t tomove, argsize; 1909 off_t oldoff, newoff, origoff; 1910 vsize_t bytelen; 1911 int error, uflags; 1912 int ubcflags; 1913 1914 error = uflags = 0; 1915 write_msg = NULL; 1916 1917 if (vp->v_type == VREG && PUFFS_USE_PAGECACHE(pmp)) { 1918 ubcflags = UBC_WRITE | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp); 1919 1920 /* 1921 * userspace *should* be allowed to control this, 1922 * but with UBC it's a bit unclear how to handle it 1923 */ 1924 if (ap->a_ioflag & IO_APPEND) 1925 uio->uio_offset = vp->v_size; 1926 1927 origoff = uio->uio_offset; 1928 while (uio->uio_resid > 0) { 1929 uflags |= PUFFS_UPDATECTIME; 1930 uflags |= PUFFS_UPDATEMTIME; 1931 oldoff = uio->uio_offset; 1932 bytelen = uio->uio_resid; 1933 1934 newoff = oldoff + bytelen; 1935 if (vp->v_size < newoff) { 1936 uvm_vnp_setwritesize(vp, newoff); 1937 } 1938 error = ubc_uiomove(&vp->v_uobj, uio, bytelen, 1939 UVM_ADV_RANDOM, ubcflags); 1940 1941 /* 1942 * In case of a ubc_uiomove() error, 1943 * opt to not extend the file at all and 1944 * return an error. Otherwise, if we attempt 1945 * to clear the memory we couldn't fault to, 1946 * we might generate a kernel page fault. 1947 */ 1948 if (vp->v_size < newoff) { 1949 if (error == 0) { 1950 uflags |= PUFFS_UPDATESIZE; 1951 uvm_vnp_setsize(vp, newoff); 1952 } else { 1953 uvm_vnp_setwritesize(vp, vp->v_size); 1954 } 1955 } 1956 if (error) 1957 break; 1958 1959 /* 1960 * If we're writing large files, flush to file server 1961 * every 64k. Otherwise we can very easily exhaust 1962 * kernel and user memory, as the file server cannot 1963 * really keep up with our writing speed. 1964 * 1965 * Note: this does *NOT* honor MNT_ASYNC, because 1966 * that gives userland too much say in the kernel. 1967 */ 1968 if (oldoff >> 16 != uio->uio_offset >> 16) { 1969 mutex_enter(&vp->v_interlock); 1970 error = VOP_PUTPAGES(vp, oldoff & ~0xffff, 1971 uio->uio_offset & ~0xffff, 1972 PGO_CLEANIT | PGO_SYNCIO); 1973 if (error) 1974 break; 1975 } 1976 } 1977 1978 /* synchronous I/O? */ 1979 if (error == 0 && ap->a_ioflag & IO_SYNC) { 1980 mutex_enter(&vp->v_interlock); 1981 error = VOP_PUTPAGES(vp, trunc_page(origoff), 1982 round_page(uio->uio_offset), 1983 PGO_CLEANIT | PGO_SYNCIO); 1984 1985 /* write through page cache? */ 1986 } else if (error == 0 && pmp->pmp_flags & PUFFS_KFLAG_WTCACHE) { 1987 mutex_enter(&vp->v_interlock); 1988 error = VOP_PUTPAGES(vp, trunc_page(origoff), 1989 round_page(uio->uio_offset), PGO_CLEANIT); 1990 } 1991 1992 puffs_updatenode(VPTOPP(vp), uflags, vp->v_size); 1993 } else { 1994 /* tomove is non-increasing */ 1995 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp); 1996 argsize = sizeof(struct puffs_vnmsg_write) + tomove; 1997 puffs_msgmem_alloc(argsize, &park_write, (void *)&write_msg,1); 1998 1999 while (uio->uio_resid > 0) { 2000 /* move data to buffer */ 2001 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp); 2002 memset(write_msg, 0, argsize); /* XXX: touser KASSERT */ 2003 RWARGS(write_msg, ap->a_ioflag, tomove, 2004 uio->uio_offset, ap->a_cred); 2005 error = uiomove(write_msg->pvnr_data, tomove, uio); 2006 if (error) 2007 break; 2008 2009 /* move buffer to userspace */ 2010 puffs_msg_setinfo(park_write, PUFFSOP_VN, 2011 PUFFS_VN_WRITE, VPTOPNC(vp)); 2012 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_write, vp->v_data, 2013 NULL, error); 2014 error = checkerr(pmp, error, __func__); 2015 if (error) 2016 break; 2017 2018 if (write_msg->pvnr_resid > tomove) { 2019 puffs_senderr(pmp, PUFFS_ERR_WRITE, 2020 E2BIG, "resid grew", VPTOPNC(ap->a_vp)); 2021 error = EPROTO; 2022 break; 2023 } 2024 2025 /* adjust file size */ 2026 if (vp->v_size < uio->uio_offset) 2027 uvm_vnp_setsize(vp, uio->uio_offset); 2028 2029 /* didn't move everything? bad userspace. bail */ 2030 if (write_msg->pvnr_resid != 0) { 2031 error = EIO; 2032 break; 2033 } 2034 } 2035 puffs_msgmem_release(park_write); 2036 } 2037 2038 return error; 2039 } 2040 2041 int 2042 puffs_vnop_print(void *v) 2043 { 2044 struct vop_print_args /* { 2045 struct vnode *a_vp; 2046 } */ *ap = v; 2047 PUFFS_MSG_VARS(vn, print); 2048 struct vnode *vp = ap->a_vp; 2049 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 2050 struct puffs_node *pn = vp->v_data; 2051 int error; 2052 2053 /* kernel portion */ 2054 printf("tag VT_PUFFS, vnode %p, puffs node: %p,\n" 2055 "\tuserspace cookie: %p", vp, pn, pn->pn_cookie); 2056 if (vp->v_type == VFIFO) 2057 VOCALL(fifo_vnodeop_p, VOFFSET(vop_print), v); 2058 printf("\n"); 2059 2060 /* userspace portion */ 2061 if (EXISTSOP(pmp, PRINT)) { 2062 PUFFS_MSG_ALLOC(vn, print); 2063 puffs_msg_setinfo(park_print, PUFFSOP_VN, 2064 PUFFS_VN_PRINT, VPTOPNC(vp)); 2065 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_print, vp->v_data, 2066 NULL, error); 2067 PUFFS_MSG_RELEASE(print); 2068 } 2069 2070 return 0; 2071 } 2072 2073 int 2074 puffs_vnop_pathconf(void *v) 2075 { 2076 struct vop_pathconf_args /* { 2077 const struct vnodeop_desc *a_desc; 2078 struct vnode *a_vp; 2079 int a_name; 2080 register_t *a_retval; 2081 } */ *ap = v; 2082 PUFFS_MSG_VARS(vn, pathconf); 2083 struct vnode *vp = ap->a_vp; 2084 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 2085 int error; 2086 2087 PUFFS_MSG_ALLOC(vn, pathconf); 2088 pathconf_msg->pvnr_name = ap->a_name; 2089 puffs_msg_setinfo(park_pathconf, PUFFSOP_VN, 2090 PUFFS_VN_PATHCONF, VPTOPNC(vp)); 2091 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_pathconf, vp->v_data, NULL, error); 2092 error = checkerr(pmp, error, __func__); 2093 if (!error) 2094 *ap->a_retval = pathconf_msg->pvnr_retval; 2095 PUFFS_MSG_RELEASE(pathconf); 2096 2097 return error; 2098 } 2099 2100 int 2101 puffs_vnop_advlock(void *v) 2102 { 2103 struct vop_advlock_args /* { 2104 const struct vnodeop_desc *a_desc; 2105 struct vnode *a_vp; 2106 void *a_id; 2107 int a_op; 2108 struct flock *a_fl; 2109 int a_flags; 2110 } */ *ap = v; 2111 struct vnode *vp = ap->a_vp; 2112 struct puffs_node *pn = VPTOPP(vp); 2113 2114 return lf_advlock(ap, &pn->pn_lockf, vp->v_size); 2115 } 2116 2117 int 2118 puffs_vnop_abortop(void *v) 2119 { 2120 struct vop_abortop_args /* { 2121 struct vnode *a_dvp; 2122 struct componentname *a_cnp; 2123 }; */ *ap = v; 2124 PUFFS_MSG_VARS(vn, abortop); 2125 struct vnode *dvp = ap->a_dvp; 2126 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount); 2127 struct componentname *cnp = ap->a_cnp; 2128 2129 if (EXISTSOP(pmp, ABORTOP)) { 2130 PUFFS_MSG_ALLOC(vn, abortop); 2131 puffs_makecn(&abortop_msg->pvnr_cn, &abortop_msg->pvnr_cn_cred, 2132 cnp, PUFFS_USE_FULLPNBUF(pmp)); 2133 puffs_msg_setfaf(park_abortop); 2134 puffs_msg_setinfo(park_abortop, PUFFSOP_VN, 2135 PUFFS_VN_ABORTOP, VPTOPNC(dvp)); 2136 2137 puffs_msg_enqueue(pmp, park_abortop); 2138 PUFFS_MSG_RELEASE(abortop); 2139 } 2140 2141 return genfs_abortop(v); 2142 } 2143 2144 #define BIOASYNC(bp) (bp->b_flags & B_ASYNC) 2145 2146 /* 2147 * This maps itself to PUFFS_VN_READ/WRITE for data transfer. 2148 */ 2149 int 2150 puffs_vnop_strategy(void *v) 2151 { 2152 struct vop_strategy_args /* { 2153 const struct vnodeop_desc *a_desc; 2154 struct vnode *a_vp; 2155 struct buf *a_bp; 2156 } */ *ap = v; 2157 PUFFS_MSG_VARS(vn, rw); 2158 struct vnode *vp = ap->a_vp; 2159 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 2160 struct puffs_node *pn; 2161 struct buf *bp; 2162 size_t argsize; 2163 size_t tomove, moved; 2164 int error, dofaf, dobiodone; 2165 2166 pmp = MPTOPUFFSMP(vp->v_mount); 2167 bp = ap->a_bp; 2168 error = 0; 2169 dofaf = 0; 2170 pn = VPTOPP(vp); 2171 park_rw = NULL; /* explicit */ 2172 dobiodone = 1; 2173 2174 if ((BUF_ISREAD(bp) && !EXISTSOP(pmp, READ)) 2175 || (BUF_ISWRITE(bp) && !EXISTSOP(pmp, WRITE))) 2176 ERROUT(EOPNOTSUPP); 2177 2178 /* 2179 * Short-circuit optimization: don't flush buffer in between 2180 * VOP_INACTIVE and VOP_RECLAIM in case the node has no references. 2181 */ 2182 if (pn->pn_stat & PNODE_DYING) { 2183 KASSERT(BUF_ISWRITE(bp)); 2184 bp->b_resid = 0; 2185 goto out; 2186 } 2187 2188 #ifdef DIAGNOSTIC 2189 if (bp->b_bcount > pmp->pmp_msg_maxsize - PUFFS_MSGSTRUCT_MAX) 2190 panic("puffs_strategy: wildly inappropriate buf bcount %d", 2191 bp->b_bcount); 2192 #endif 2193 2194 /* 2195 * See explanation for the necessity of a FAF in puffs_fsync. 2196 * 2197 * Also, do FAF in case we're suspending. 2198 * See puffs_vfsops.c:pageflush() 2199 */ 2200 if (BUF_ISWRITE(bp)) { 2201 mutex_enter(&vp->v_interlock); 2202 if (vp->v_iflag & VI_XLOCK) 2203 dofaf = 1; 2204 if (pn->pn_stat & PNODE_FAF) 2205 dofaf = 1; 2206 mutex_exit(&vp->v_interlock); 2207 } 2208 2209 #ifdef DIAGNOSTIC 2210 if (curlwp == uvm.pagedaemon_lwp) 2211 KASSERT(dofaf || BIOASYNC(bp)); 2212 #endif 2213 2214 /* allocate transport structure */ 2215 tomove = PUFFS_TOMOVE(bp->b_bcount, pmp); 2216 argsize = sizeof(struct puffs_vnmsg_rw); 2217 error = puffs_msgmem_alloc(argsize + tomove, &park_rw, 2218 (void *)&rw_msg, dofaf ? 0 : 1); 2219 if (error) 2220 goto out; 2221 RWARGS(rw_msg, 0, tomove, bp->b_blkno << DEV_BSHIFT, FSCRED); 2222 2223 /* 2x2 cases: read/write, faf/nofaf */ 2224 if (BUF_ISREAD(bp)) { 2225 puffs_msg_setinfo(park_rw, PUFFSOP_VN, 2226 PUFFS_VN_READ, VPTOPNC(vp)); 2227 puffs_msg_setdelta(park_rw, tomove); 2228 if (BIOASYNC(bp)) { 2229 puffs_msg_setcall(park_rw, 2230 puffs_parkdone_asyncbioread, bp); 2231 puffs_msg_enqueue(pmp, park_rw); 2232 dobiodone = 0; 2233 } else { 2234 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_rw, vp->v_data, 2235 NULL, error); 2236 error = checkerr(pmp, error, __func__); 2237 if (error) 2238 goto out; 2239 2240 if (rw_msg->pvnr_resid > tomove) { 2241 puffs_senderr(pmp, PUFFS_ERR_READ, 2242 E2BIG, "resid grew", VPTOPNC(vp)); 2243 ERROUT(EPROTO); 2244 } 2245 2246 moved = tomove - rw_msg->pvnr_resid; 2247 2248 (void)memcpy(bp->b_data, rw_msg->pvnr_data, moved); 2249 bp->b_resid = bp->b_bcount - moved; 2250 } 2251 } else { 2252 puffs_msg_setinfo(park_rw, PUFFSOP_VN, 2253 PUFFS_VN_WRITE, VPTOPNC(vp)); 2254 /* 2255 * make pages read-only before we write them if we want 2256 * write caching info 2257 */ 2258 if (PUFFS_WCACHEINFO(pmp)) { 2259 struct uvm_object *uobj = &vp->v_uobj; 2260 int npages = (bp->b_bcount + PAGE_SIZE-1) >> PAGE_SHIFT; 2261 struct vm_page *vmp; 2262 int i; 2263 2264 for (i = 0; i < npages; i++) { 2265 vmp= uvm_pageratop((vaddr_t)bp->b_data 2266 + (i << PAGE_SHIFT)); 2267 DPRINTF(("puffs_strategy: write-protecting " 2268 "vp %p page %p, offset %" PRId64"\n", 2269 vp, vmp, vmp->offset)); 2270 mutex_enter(&uobj->vmobjlock); 2271 vmp->flags |= PG_RDONLY; 2272 pmap_page_protect(vmp, VM_PROT_READ); 2273 mutex_exit(&uobj->vmobjlock); 2274 } 2275 } 2276 2277 (void)memcpy(&rw_msg->pvnr_data, bp->b_data, tomove); 2278 if (dofaf) { 2279 puffs_msg_setfaf(park_rw); 2280 } else if (BIOASYNC(bp)) { 2281 puffs_msg_setcall(park_rw, 2282 puffs_parkdone_asyncbiowrite, bp); 2283 dobiodone = 0; 2284 } 2285 2286 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_rw, vp->v_data, NULL, error); 2287 2288 if (dobiodone == 0) 2289 goto out; 2290 2291 /* 2292 * XXXXXXXX: wrong, but kernel can't survive strategy 2293 * failure currently. Here, have one more X: X. 2294 */ 2295 if (error != ENOMEM) 2296 error = 0; 2297 2298 error = checkerr(pmp, error, __func__); 2299 if (error) 2300 goto out; 2301 2302 if (rw_msg->pvnr_resid > tomove) { 2303 puffs_senderr(pmp, PUFFS_ERR_WRITE, 2304 E2BIG, "resid grew", VPTOPNC(vp)); 2305 ERROUT(EPROTO); 2306 } 2307 2308 /* 2309 * FAF moved everything. Frankly, we don't 2310 * really have a choice. 2311 */ 2312 if (dofaf && error == 0) 2313 moved = tomove; 2314 else 2315 moved = tomove - rw_msg->pvnr_resid; 2316 2317 bp->b_resid = bp->b_bcount - moved; 2318 if (bp->b_resid != 0) { 2319 ERROUT(EIO); 2320 } 2321 } 2322 2323 out: 2324 if (park_rw) 2325 puffs_msgmem_release(park_rw); 2326 2327 if (error) 2328 bp->b_error = error; 2329 2330 if (error || dobiodone) 2331 biodone(bp); 2332 2333 return error; 2334 } 2335 2336 int 2337 puffs_vnop_mmap(void *v) 2338 { 2339 struct vop_mmap_args /* { 2340 const struct vnodeop_desc *a_desc; 2341 struct vnode *a_vp; 2342 vm_prot_t a_prot; 2343 kauth_cred_t a_cred; 2344 } */ *ap = v; 2345 PUFFS_MSG_VARS(vn, mmap); 2346 struct vnode *vp = ap->a_vp; 2347 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 2348 int error; 2349 2350 if (!PUFFS_USE_PAGECACHE(pmp)) 2351 return genfs_eopnotsupp(v); 2352 2353 if (EXISTSOP(pmp, MMAP)) { 2354 PUFFS_MSG_ALLOC(vn, mmap); 2355 mmap_msg->pvnr_prot = ap->a_prot; 2356 puffs_credcvt(&mmap_msg->pvnr_cred, ap->a_cred); 2357 puffs_msg_setinfo(park_mmap, PUFFSOP_VN, 2358 PUFFS_VN_MMAP, VPTOPNC(vp)); 2359 2360 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_mmap, vp->v_data, NULL, error); 2361 error = checkerr(pmp, error, __func__); 2362 PUFFS_MSG_RELEASE(mmap); 2363 } else { 2364 error = genfs_mmap(v); 2365 } 2366 2367 return error; 2368 } 2369 2370 2371 /* 2372 * The rest don't get a free trip to userspace and back, they 2373 * have to stay within the kernel. 2374 */ 2375 2376 /* 2377 * bmap doesn't really make any sense for puffs, so just 1:1 map it. 2378 * well, maybe somehow, somewhere, some day .... 2379 */ 2380 int 2381 puffs_vnop_bmap(void *v) 2382 { 2383 struct vop_bmap_args /* { 2384 const struct vnodeop_desc *a_desc; 2385 struct vnode *a_vp; 2386 daddr_t a_bn; 2387 struct vnode **a_vpp; 2388 daddr_t *a_bnp; 2389 int *a_runp; 2390 } */ *ap = v; 2391 struct puffs_mount *pmp; 2392 2393 pmp = MPTOPUFFSMP(ap->a_vp->v_mount); 2394 2395 if (ap->a_vpp) 2396 *ap->a_vpp = ap->a_vp; 2397 if (ap->a_bnp) 2398 *ap->a_bnp = ap->a_bn; 2399 if (ap->a_runp) 2400 *ap->a_runp 2401 = (PUFFS_TOMOVE(pmp->pmp_msg_maxsize, pmp)>>DEV_BSHIFT) - 1; 2402 2403 return 0; 2404 } 2405 2406 /* 2407 * Handle getpages faults in puffs. We let genfs_getpages() do most 2408 * of the dirty work, but we come in this route to do accounting tasks. 2409 * If the user server has specified functions for cache notifications 2410 * about reads and/or writes, we record which type of operation we got, 2411 * for which page range, and proceed to issue a FAF notification to the 2412 * server about it. 2413 */ 2414 int 2415 puffs_vnop_getpages(void *v) 2416 { 2417 struct vop_getpages_args /* { 2418 const struct vnodeop_desc *a_desc; 2419 struct vnode *a_vp; 2420 voff_t a_offset; 2421 struct vm_page **a_m; 2422 int *a_count; 2423 int a_centeridx; 2424 vm_prot_t a_access_type; 2425 int a_advice; 2426 int a_flags; 2427 } */ *ap = v; 2428 struct puffs_mount *pmp; 2429 struct puffs_node *pn; 2430 struct vnode *vp; 2431 struct vm_page **pgs; 2432 struct puffs_cacheinfo *pcinfo = NULL; 2433 struct puffs_cacherun *pcrun; 2434 void *parkmem = NULL; 2435 size_t runsizes; 2436 int i, npages, si, streakon; 2437 int error, locked, write; 2438 2439 pmp = MPTOPUFFSMP(ap->a_vp->v_mount); 2440 npages = *ap->a_count; 2441 pgs = ap->a_m; 2442 vp = ap->a_vp; 2443 pn = vp->v_data; 2444 locked = (ap->a_flags & PGO_LOCKED) != 0; 2445 write = (ap->a_access_type & VM_PROT_WRITE) != 0; 2446 2447 /* ccg xnaht - gets Wuninitialized wrong */ 2448 pcrun = NULL; 2449 runsizes = 0; 2450 2451 /* 2452 * Check that we aren't trying to fault in pages which our file 2453 * server doesn't know about. This happens if we extend a file by 2454 * skipping some pages and later try to fault in pages which 2455 * are between pn_serversize and vp_size. This check optimizes 2456 * away the common case where a file is being extended. 2457 */ 2458 if (ap->a_offset >= pn->pn_serversize && ap->a_offset < vp->v_size) { 2459 struct vattr va; 2460 2461 /* try again later when we can block */ 2462 if (locked) 2463 ERROUT(EBUSY); 2464 2465 mutex_exit(&vp->v_interlock); 2466 vattr_null(&va); 2467 va.va_size = vp->v_size; 2468 error = dosetattr(vp, &va, FSCRED, 0); 2469 if (error) 2470 ERROUT(error); 2471 mutex_enter(&vp->v_interlock); 2472 } 2473 2474 if (write && PUFFS_WCACHEINFO(pmp)) { 2475 #ifdef notnowjohn 2476 /* allocate worst-case memory */ 2477 runsizes = ((npages / 2) + 1) * sizeof(struct puffs_cacherun); 2478 pcinfo = kmem_zalloc(sizeof(struct puffs_cacheinfo) + runsize, 2479 locked ? KM_NOSLEEP : KM_SLEEP); 2480 2481 /* 2482 * can't block if we're locked and can't mess up caching 2483 * information for fs server. so come back later, please 2484 */ 2485 if (pcinfo == NULL) 2486 ERROUT(ENOMEM); 2487 2488 parkmem = puffs_park_alloc(locked == 0); 2489 if (parkmem == NULL) 2490 ERROUT(ENOMEM); 2491 2492 pcrun = pcinfo->pcache_runs; 2493 #else 2494 (void)parkmem; 2495 #endif 2496 } 2497 2498 error = genfs_getpages(v); 2499 if (error) 2500 goto out; 2501 2502 if (PUFFS_WCACHEINFO(pmp) == 0) 2503 goto out; 2504 2505 /* 2506 * Let's see whose fault it was and inform the user server of 2507 * possibly read/written pages. Map pages from read faults 2508 * strictly read-only, since otherwise we might miss info on 2509 * when the page is actually write-faulted to. 2510 */ 2511 if (!locked) 2512 mutex_enter(&vp->v_uobj.vmobjlock); 2513 for (i = 0, si = 0, streakon = 0; i < npages; i++) { 2514 if (pgs[i] == NULL || pgs[i] == PGO_DONTCARE) { 2515 if (streakon && write) { 2516 streakon = 0; 2517 pcrun[si].pcache_runend 2518 = trunc_page(pgs[i]->offset) + PAGE_MASK; 2519 si++; 2520 } 2521 continue; 2522 } 2523 if (streakon == 0 && write) { 2524 streakon = 1; 2525 pcrun[si].pcache_runstart = pgs[i]->offset; 2526 } 2527 2528 if (!write) 2529 pgs[i]->flags |= PG_RDONLY; 2530 } 2531 /* was the last page part of our streak? */ 2532 if (streakon) { 2533 pcrun[si].pcache_runend 2534 = trunc_page(pgs[i-1]->offset) + PAGE_MASK; 2535 si++; 2536 } 2537 if (!locked) 2538 mutex_exit(&vp->v_uobj.vmobjlock); 2539 2540 KASSERT(si <= (npages / 2) + 1); 2541 2542 #ifdef notnowjohn 2543 /* send results to userspace */ 2544 if (write) 2545 puffs_cacheop(pmp, parkmem, pcinfo, 2546 sizeof(struct puffs_cacheinfo) + runsizes, VPTOPNC(vp)); 2547 #endif 2548 2549 out: 2550 if (error) { 2551 if (pcinfo != NULL) 2552 kmem_free(pcinfo, 2553 sizeof(struct puffs_cacheinfo) + runsizes); 2554 #ifdef notnowjohn 2555 if (parkmem != NULL) 2556 puffs_park_release(parkmem, 1); 2557 #endif 2558 } 2559 2560 return error; 2561 } 2562 2563 /* 2564 * Extended attribute support. 2565 */ 2566 2567 int 2568 puffs_vnop_getextattr(void *v) 2569 { 2570 struct vop_getextattr_args /* 2571 struct vnode *a_vp; 2572 int a_attrnamespace; 2573 const char *a_name; 2574 struct uio *a_uio; 2575 size_t *a_size; 2576 kauth_cred_t a_cred; 2577 }; */ *ap = v; 2578 PUFFS_MSG_VARS(vn, getextattr); 2579 struct vnode *vp = ap->a_vp; 2580 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 2581 int attrnamespace = ap->a_attrnamespace; 2582 const char *name = ap->a_name; 2583 struct uio *uio = ap->a_uio; 2584 size_t *sizep = ap->a_size; 2585 size_t tomove, resid; 2586 int error; 2587 2588 if (uio) 2589 resid = uio->uio_resid; 2590 else 2591 resid = 0; 2592 2593 tomove = PUFFS_TOMOVE(resid, pmp); 2594 if (tomove != resid) { 2595 error = E2BIG; 2596 goto out; 2597 } 2598 2599 puffs_msgmem_alloc(sizeof(struct puffs_vnmsg_getextattr) + tomove, 2600 &park_getextattr, (void *)&getextattr_msg, 1); 2601 2602 getextattr_msg->pvnr_attrnamespace = attrnamespace; 2603 strlcpy(getextattr_msg->pvnr_attrname, name, 2604 sizeof(getextattr_msg->pvnr_attrname)); 2605 puffs_credcvt(&getextattr_msg->pvnr_cred, ap->a_cred); 2606 if (sizep) 2607 getextattr_msg->pvnr_datasize = 1; 2608 getextattr_msg->pvnr_resid = tomove; 2609 2610 puffs_msg_setinfo(park_getextattr, 2611 PUFFSOP_VN, PUFFS_VN_GETEXTATTR, VPTOPNC(vp)); 2612 puffs_msg_setdelta(park_getextattr, tomove); 2613 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_getextattr, vp->v_data, NULL, error); 2614 2615 error = checkerr(pmp, error, __func__); 2616 if (error) 2617 goto out; 2618 2619 resid = getextattr_msg->pvnr_resid; 2620 if (resid > tomove) { 2621 puffs_senderr(pmp, PUFFS_ERR_GETEXTATTR, E2BIG, 2622 "resid grew", VPTOPNC(vp)); 2623 error = EPROTO; 2624 goto out; 2625 } 2626 2627 if (sizep) 2628 *sizep = getextattr_msg->pvnr_datasize; 2629 if (uio) 2630 error = uiomove(getextattr_msg->pvnr_data, tomove - resid, uio); 2631 2632 out: 2633 PUFFS_MSG_RELEASE(getextattr); 2634 return error; 2635 } 2636 2637 int 2638 puffs_vnop_setextattr(void *v) 2639 { 2640 struct vop_setextattr_args /* { 2641 struct vnode *a_vp; 2642 int a_attrnamespace; 2643 const char *a_name; 2644 struct uio *a_uio; 2645 kauth_cred_t a_cred; 2646 }; */ *ap = v; 2647 PUFFS_MSG_VARS(vn, setextattr); 2648 struct vnode *vp = ap->a_vp; 2649 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 2650 int attrnamespace = ap->a_attrnamespace; 2651 const char *name = ap->a_name; 2652 struct uio *uio = ap->a_uio; 2653 size_t tomove, resid; 2654 int error; 2655 2656 if (uio) 2657 resid = uio->uio_resid; 2658 else 2659 resid = 0; 2660 2661 tomove = PUFFS_TOMOVE(resid, pmp); 2662 if (tomove != resid) { 2663 error = E2BIG; 2664 goto out; 2665 } 2666 2667 puffs_msgmem_alloc(sizeof(struct puffs_vnmsg_setextattr) + tomove, 2668 &park_setextattr, (void *)&setextattr_msg, 1); 2669 2670 setextattr_msg->pvnr_attrnamespace = attrnamespace; 2671 strlcpy(setextattr_msg->pvnr_attrname, name, 2672 sizeof(setextattr_msg->pvnr_attrname)); 2673 puffs_credcvt(&setextattr_msg->pvnr_cred, ap->a_cred); 2674 setextattr_msg->pvnr_resid = tomove; 2675 2676 if (uio) { 2677 error = uiomove(setextattr_msg->pvnr_data, tomove, uio); 2678 if (error) 2679 goto out; 2680 } 2681 2682 puffs_msg_setinfo(park_setextattr, 2683 PUFFSOP_VN, PUFFS_VN_SETEXTATTR, VPTOPNC(vp)); 2684 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_setextattr, vp->v_data, NULL, error); 2685 2686 error = checkerr(pmp, error, __func__); 2687 if (error) 2688 goto out; 2689 2690 if (setextattr_msg->pvnr_resid != 0) 2691 error = EIO; 2692 2693 out: 2694 PUFFS_MSG_RELEASE(setextattr); 2695 2696 return error; 2697 } 2698 2699 int 2700 puffs_vnop_listextattr(void *v) 2701 { 2702 struct vop_listextattr_args /* { 2703 struct vnode *a_vp; 2704 int a_attrnamespace; 2705 struct uio *a_uio; 2706 size_t *a_size; 2707 kauth_cred_t a_cred; 2708 }; */ *ap = v; 2709 PUFFS_MSG_VARS(vn, listextattr); 2710 struct vnode *vp = ap->a_vp; 2711 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 2712 int attrnamespace = ap->a_attrnamespace; 2713 struct uio *uio = ap->a_uio; 2714 size_t *sizep = ap->a_size; 2715 size_t tomove, resid; 2716 int error; 2717 2718 if (uio) 2719 resid = uio->uio_resid; 2720 else 2721 resid = 0; 2722 2723 tomove = PUFFS_TOMOVE(resid, pmp); 2724 if (tomove != resid) { 2725 error = E2BIG; 2726 goto out; 2727 } 2728 2729 puffs_msgmem_alloc(sizeof(struct puffs_vnmsg_listextattr) + tomove, 2730 &park_listextattr, (void *)&listextattr_msg, 1); 2731 2732 listextattr_msg->pvnr_attrnamespace = attrnamespace; 2733 puffs_credcvt(&listextattr_msg->pvnr_cred, ap->a_cred); 2734 listextattr_msg->pvnr_resid = tomove; 2735 if (sizep) 2736 listextattr_msg->pvnr_datasize = 1; 2737 2738 puffs_msg_setinfo(park_listextattr, 2739 PUFFSOP_VN, PUFFS_VN_LISTEXTATTR, VPTOPNC(vp)); 2740 puffs_msg_setdelta(park_listextattr, tomove); 2741 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_listextattr, vp->v_data, NULL, error); 2742 2743 error = checkerr(pmp, error, __func__); 2744 if (error) 2745 goto out; 2746 2747 resid = listextattr_msg->pvnr_resid; 2748 if (resid > tomove) { 2749 puffs_senderr(pmp, PUFFS_ERR_LISTEXTATTR, E2BIG, 2750 "resid grew", VPTOPNC(vp)); 2751 error = EPROTO; 2752 goto out; 2753 } 2754 2755 if (sizep) 2756 *sizep = listextattr_msg->pvnr_datasize; 2757 if (uio) 2758 error = uiomove(listextattr_msg->pvnr_data, tomove-resid, uio); 2759 2760 out: 2761 PUFFS_MSG_RELEASE(listextattr); 2762 return error; 2763 } 2764 2765 int 2766 puffs_vnop_deleteextattr(void *v) 2767 { 2768 struct vop_deleteextattr_args /* { 2769 struct vnode *a_vp; 2770 int a_attrnamespace; 2771 const char *a_name; 2772 kauth_cred_t a_cred; 2773 }; */ *ap = v; 2774 PUFFS_MSG_VARS(vn, deleteextattr); 2775 struct vnode *vp = ap->a_vp; 2776 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 2777 int attrnamespace = ap->a_attrnamespace; 2778 const char *name = ap->a_name; 2779 int error; 2780 2781 PUFFS_MSG_ALLOC(vn, deleteextattr); 2782 deleteextattr_msg->pvnr_attrnamespace = attrnamespace; 2783 strlcpy(deleteextattr_msg->pvnr_attrname, name, 2784 sizeof(deleteextattr_msg->pvnr_attrname)); 2785 puffs_credcvt(&deleteextattr_msg->pvnr_cred, ap->a_cred); 2786 2787 puffs_msg_setinfo(park_deleteextattr, 2788 PUFFSOP_VN, PUFFS_VN_DELETEEXTATTR, VPTOPNC(vp)); 2789 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_deleteextattr, 2790 vp->v_data, NULL, error); 2791 2792 error = checkerr(pmp, error, __func__); 2793 2794 PUFFS_MSG_RELEASE(deleteextattr); 2795 return error; 2796 } 2797 2798 /* 2799 * spec & fifo. These call the miscfs spec and fifo vectors, but issue 2800 * FAF update information for the puffs node first. 2801 */ 2802 int 2803 puffs_vnop_spec_read(void *v) 2804 { 2805 struct vop_read_args /* { 2806 const struct vnodeop_desc *a_desc; 2807 struct vnode *a_vp; 2808 struct uio *a_uio; 2809 int a_ioflag; 2810 kauth_cred_t a_cred; 2811 } */ *ap = v; 2812 2813 puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEATIME, 0); 2814 return VOCALL(spec_vnodeop_p, VOFFSET(vop_read), v); 2815 } 2816 2817 int 2818 puffs_vnop_spec_write(void *v) 2819 { 2820 struct vop_write_args /* { 2821 const struct vnodeop_desc *a_desc; 2822 struct vnode *a_vp; 2823 struct uio *a_uio; 2824 int a_ioflag; 2825 kauth_cred_t a_cred; 2826 } */ *ap = v; 2827 2828 puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEMTIME, 0); 2829 return VOCALL(spec_vnodeop_p, VOFFSET(vop_write), v); 2830 } 2831 2832 int 2833 puffs_vnop_fifo_read(void *v) 2834 { 2835 struct vop_read_args /* { 2836 const struct vnodeop_desc *a_desc; 2837 struct vnode *a_vp; 2838 struct uio *a_uio; 2839 int a_ioflag; 2840 kauth_cred_t a_cred; 2841 } */ *ap = v; 2842 2843 puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEATIME, 0); 2844 return VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), v); 2845 } 2846 2847 int 2848 puffs_vnop_fifo_write(void *v) 2849 { 2850 struct vop_write_args /* { 2851 const struct vnodeop_desc *a_desc; 2852 struct vnode *a_vp; 2853 struct uio *a_uio; 2854 int a_ioflag; 2855 kauth_cred_t a_cred; 2856 } */ *ap = v; 2857 2858 puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEMTIME, 0); 2859 return VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), v); 2860 } 2861