1 /* $NetBSD: puffs_vnops.c,v 1.153 2011/06/12 03:35:54 rmind 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.153 2011/06/12 03:35:54 rmind 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 }, /* 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 1108 if (notifyserver) 1109 callreclaim(MPTOPUFFSMP(vp->v_mount), VPTOPNC(vp)); 1110 1111 puffs_putvnode(vp); 1112 vp->v_data = NULL; 1113 1114 return 0; 1115 } 1116 1117 #define CSIZE sizeof(**ap->a_cookies) 1118 int 1119 puffs_vnop_readdir(void *v) 1120 { 1121 struct vop_readdir_args /* { 1122 const struct vnodeop_desc *a_desc; 1123 struct vnode *a_vp; 1124 struct uio *a_uio; 1125 kauth_cred_t a_cred; 1126 int *a_eofflag; 1127 off_t **a_cookies; 1128 int *a_ncookies; 1129 } */ *ap = v; 1130 PUFFS_MSG_VARS(vn, readdir); 1131 struct vnode *vp = ap->a_vp; 1132 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 1133 size_t argsize, tomove, cookiemem, cookiesmax; 1134 struct uio *uio = ap->a_uio; 1135 size_t howmuch, resid; 1136 int error; 1137 1138 /* 1139 * ok, so we need: resid + cookiemem = maxreq 1140 * => resid + cookiesize * (resid/minsize) = maxreq 1141 * => resid + cookiesize/minsize * resid = maxreq 1142 * => (cookiesize/minsize + 1) * resid = maxreq 1143 * => resid = maxreq / (cookiesize/minsize + 1) 1144 * 1145 * Since cookiesize <= minsize and we're not very big on floats, 1146 * we approximate that to be 1. Therefore: 1147 * 1148 * resid = maxreq / 2; 1149 * 1150 * Well, at least we didn't have to use differential equations 1151 * or the Gram-Schmidt process. 1152 * 1153 * (yes, I'm very afraid of this) 1154 */ 1155 KASSERT(CSIZE <= _DIRENT_MINSIZE((struct dirent *)0)); 1156 1157 if (ap->a_cookies) { 1158 KASSERT(ap->a_ncookies != NULL); 1159 if (pmp->pmp_args.pa_fhsize == 0) 1160 return EOPNOTSUPP; 1161 resid = PUFFS_TOMOVE(uio->uio_resid, pmp) / 2; 1162 cookiesmax = resid/_DIRENT_MINSIZE((struct dirent *)0); 1163 cookiemem = ALIGN(cookiesmax*CSIZE); /* play safe */ 1164 } else { 1165 resid = PUFFS_TOMOVE(uio->uio_resid, pmp); 1166 cookiesmax = 0; 1167 cookiemem = 0; 1168 } 1169 1170 argsize = sizeof(struct puffs_vnmsg_readdir); 1171 tomove = resid + cookiemem; 1172 puffs_msgmem_alloc(argsize + tomove, &park_readdir, 1173 (void *)&readdir_msg, 1); 1174 1175 puffs_credcvt(&readdir_msg->pvnr_cred, ap->a_cred); 1176 readdir_msg->pvnr_offset = uio->uio_offset; 1177 readdir_msg->pvnr_resid = resid; 1178 readdir_msg->pvnr_ncookies = cookiesmax; 1179 readdir_msg->pvnr_eofflag = 0; 1180 readdir_msg->pvnr_dentoff = cookiemem; 1181 puffs_msg_setinfo(park_readdir, PUFFSOP_VN, 1182 PUFFS_VN_READDIR, VPTOPNC(vp)); 1183 puffs_msg_setdelta(park_readdir, tomove); 1184 1185 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_readdir, vp->v_data, NULL, error); 1186 error = checkerr(pmp, error, __func__); 1187 if (error) 1188 goto out; 1189 1190 /* userspace is cheating? */ 1191 if (readdir_msg->pvnr_resid > resid) { 1192 puffs_senderr(pmp, PUFFS_ERR_READDIR, E2BIG, 1193 "resid grew", VPTOPNC(vp)); 1194 ERROUT(EPROTO); 1195 } 1196 if (readdir_msg->pvnr_ncookies > cookiesmax) { 1197 puffs_senderr(pmp, PUFFS_ERR_READDIR, E2BIG, 1198 "too many cookies", VPTOPNC(vp)); 1199 ERROUT(EPROTO); 1200 } 1201 1202 /* check eof */ 1203 if (readdir_msg->pvnr_eofflag) 1204 *ap->a_eofflag = 1; 1205 1206 /* bouncy-wouncy with the directory data */ 1207 howmuch = resid - readdir_msg->pvnr_resid; 1208 1209 /* force eof if no data was returned (getcwd() needs this) */ 1210 if (howmuch == 0) { 1211 *ap->a_eofflag = 1; 1212 goto out; 1213 } 1214 1215 error = uiomove(readdir_msg->pvnr_data + cookiemem, howmuch, uio); 1216 if (error) 1217 goto out; 1218 1219 /* provide cookies to caller if so desired */ 1220 if (ap->a_cookies) { 1221 *ap->a_cookies = malloc(readdir_msg->pvnr_ncookies*CSIZE, 1222 M_TEMP, M_WAITOK); 1223 *ap->a_ncookies = readdir_msg->pvnr_ncookies; 1224 memcpy(*ap->a_cookies, readdir_msg->pvnr_data, 1225 *ap->a_ncookies*CSIZE); 1226 } 1227 1228 /* next readdir starts here */ 1229 uio->uio_offset = readdir_msg->pvnr_offset; 1230 1231 out: 1232 puffs_msgmem_release(park_readdir); 1233 return error; 1234 } 1235 #undef CSIZE 1236 1237 /* 1238 * poll works by consuming the bitmask in pn_revents. If there are 1239 * events available, poll returns immediately. If not, it issues a 1240 * poll to userspace, selrecords itself and returns with no available 1241 * events. When the file server returns, it executes puffs_parkdone_poll(), 1242 * where available events are added to the bitmask. selnotify() is 1243 * then also executed by that function causing us to enter here again 1244 * and hopefully find the missing bits (unless someone got them first, 1245 * in which case it starts all over again). 1246 */ 1247 int 1248 puffs_vnop_poll(void *v) 1249 { 1250 struct vop_poll_args /* { 1251 const struct vnodeop_desc *a_desc; 1252 struct vnode *a_vp; 1253 int a_events; 1254 } */ *ap = v; 1255 PUFFS_MSG_VARS(vn, poll); 1256 struct vnode *vp = ap->a_vp; 1257 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 1258 struct puffs_node *pn = vp->v_data; 1259 int events, error; 1260 1261 if (EXISTSOP(pmp, POLL)) { 1262 mutex_enter(&pn->pn_mtx); 1263 events = pn->pn_revents & ap->a_events; 1264 if (events & ap->a_events) { 1265 pn->pn_revents &= ~ap->a_events; 1266 mutex_exit(&pn->pn_mtx); 1267 1268 return events; 1269 } else { 1270 puffs_referencenode(pn); 1271 mutex_exit(&pn->pn_mtx); 1272 1273 PUFFS_MSG_ALLOC(vn, poll); 1274 poll_msg->pvnr_events = ap->a_events; 1275 puffs_msg_setinfo(park_poll, PUFFSOP_VN, 1276 PUFFS_VN_POLL, VPTOPNC(vp)); 1277 puffs_msg_setcall(park_poll, puffs_parkdone_poll, pn); 1278 selrecord(curlwp, &pn->pn_sel); 1279 1280 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_poll, vp->v_data, 1281 NULL, error); 1282 PUFFS_MSG_RELEASE(poll); 1283 1284 return 0; 1285 } 1286 } else { 1287 return genfs_poll(v); 1288 } 1289 } 1290 1291 static int 1292 flushvncache(struct vnode *vp, off_t offlo, off_t offhi, bool wait) 1293 { 1294 struct puffs_node *pn = VPTOPP(vp); 1295 struct vattr va; 1296 int pflags, error; 1297 1298 /* flush out information from our metacache, see vop_setattr */ 1299 if (pn->pn_stat & PNODE_METACACHE_MASK 1300 && (pn->pn_stat & PNODE_DYING) == 0) { 1301 vattr_null(&va); 1302 error = dosetattr(vp, &va, FSCRED, 1303 SETATTR_CHSIZE | (wait ? 0 : SETATTR_ASYNC)); 1304 if (error) 1305 return error; 1306 } 1307 1308 /* 1309 * flush pages to avoid being overly dirty 1310 */ 1311 pflags = PGO_CLEANIT; 1312 if (wait) 1313 pflags |= PGO_SYNCIO; 1314 mutex_enter(vp->v_interlock); 1315 return VOP_PUTPAGES(vp, trunc_page(offlo), round_page(offhi), pflags); 1316 } 1317 1318 int 1319 puffs_vnop_fsync(void *v) 1320 { 1321 struct vop_fsync_args /* { 1322 const struct vnodeop_desc *a_desc; 1323 struct vnode *a_vp; 1324 kauth_cred_t a_cred; 1325 int a_flags; 1326 off_t a_offlo; 1327 off_t a_offhi; 1328 } */ *ap = v; 1329 PUFFS_MSG_VARS(vn, fsync); 1330 struct vnode *vp = ap->a_vp; 1331 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 1332 struct puffs_node *pn = VPTOPP(vp); 1333 int error, dofaf; 1334 1335 error = flushvncache(vp, ap->a_offlo, ap->a_offhi, 1336 (ap->a_flags & FSYNC_WAIT) == FSYNC_WAIT); 1337 if (error) 1338 return error; 1339 1340 /* 1341 * HELLO! We exit already here if the user server does not 1342 * support fsync OR if we should call fsync for a node which 1343 * has references neither in the kernel or the fs server. 1344 * Otherwise we continue to issue fsync() forward. 1345 */ 1346 if (!EXISTSOP(pmp, FSYNC) || (pn->pn_stat & PNODE_DYING)) 1347 return 0; 1348 1349 dofaf = (ap->a_flags & FSYNC_WAIT) == 0 || ap->a_flags == FSYNC_LAZY; 1350 /* 1351 * We abuse VXLOCK to mean "vnode is going to die", so we issue 1352 * only FAFs for those. Otherwise there's a danger of deadlock, 1353 * since the execution context here might be the user server 1354 * doing some operation on another fs, which in turn caused a 1355 * vnode to be reclaimed from the freelist for this fs. 1356 */ 1357 if (dofaf == 0) { 1358 mutex_enter(vp->v_interlock); 1359 if (vp->v_iflag & VI_XLOCK) 1360 dofaf = 1; 1361 mutex_exit(vp->v_interlock); 1362 } 1363 1364 PUFFS_MSG_ALLOC(vn, fsync); 1365 if (dofaf) 1366 puffs_msg_setfaf(park_fsync); 1367 1368 puffs_credcvt(&fsync_msg->pvnr_cred, ap->a_cred); 1369 fsync_msg->pvnr_flags = ap->a_flags; 1370 fsync_msg->pvnr_offlo = ap->a_offlo; 1371 fsync_msg->pvnr_offhi = ap->a_offhi; 1372 puffs_msg_setinfo(park_fsync, PUFFSOP_VN, 1373 PUFFS_VN_FSYNC, VPTOPNC(vp)); 1374 1375 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_fsync, vp->v_data, NULL, error); 1376 PUFFS_MSG_RELEASE(fsync); 1377 1378 error = checkerr(pmp, error, __func__); 1379 1380 return error; 1381 } 1382 1383 int 1384 puffs_vnop_seek(void *v) 1385 { 1386 struct vop_seek_args /* { 1387 const struct vnodeop_desc *a_desc; 1388 struct vnode *a_vp; 1389 off_t a_oldoff; 1390 off_t a_newoff; 1391 kauth_cred_t a_cred; 1392 } */ *ap = v; 1393 PUFFS_MSG_VARS(vn, seek); 1394 struct vnode *vp = ap->a_vp; 1395 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 1396 int error; 1397 1398 PUFFS_MSG_ALLOC(vn, seek); 1399 seek_msg->pvnr_oldoff = ap->a_oldoff; 1400 seek_msg->pvnr_newoff = ap->a_newoff; 1401 puffs_credcvt(&seek_msg->pvnr_cred, ap->a_cred); 1402 puffs_msg_setinfo(park_seek, PUFFSOP_VN, 1403 PUFFS_VN_SEEK, VPTOPNC(vp)); 1404 1405 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_seek, vp->v_data, NULL, error); 1406 PUFFS_MSG_RELEASE(seek); 1407 return checkerr(pmp, error, __func__); 1408 } 1409 1410 static int 1411 callremove(struct puffs_mount *pmp, puffs_cookie_t dck, puffs_cookie_t ck, 1412 struct componentname *cnp) 1413 { 1414 PUFFS_MSG_VARS(vn, remove); 1415 int error; 1416 1417 PUFFS_MSG_ALLOC(vn, remove); 1418 remove_msg->pvnr_cookie_targ = ck; 1419 puffs_makecn(&remove_msg->pvnr_cn, &remove_msg->pvnr_cn_cred, 1420 cnp, PUFFS_USE_FULLPNBUF(pmp)); 1421 puffs_msg_setinfo(park_remove, PUFFSOP_VN, PUFFS_VN_REMOVE, dck); 1422 1423 PUFFS_MSG_ENQUEUEWAIT(pmp, park_remove, error); 1424 PUFFS_MSG_RELEASE(remove); 1425 1426 return checkerr(pmp, error, __func__); 1427 } 1428 1429 /* 1430 * XXX: can't use callremove now because can't catch setbacks with 1431 * it due to lack of a pnode argument. 1432 */ 1433 int 1434 puffs_vnop_remove(void *v) 1435 { 1436 struct vop_remove_args /* { 1437 const struct vnodeop_desc *a_desc; 1438 struct vnode *a_dvp; 1439 struct vnode *a_vp; 1440 struct componentname *a_cnp; 1441 } */ *ap = v; 1442 PUFFS_MSG_VARS(vn, remove); 1443 struct vnode *dvp = ap->a_dvp; 1444 struct vnode *vp = ap->a_vp; 1445 struct puffs_node *dpn = VPTOPP(dvp); 1446 struct puffs_node *pn = VPTOPP(vp); 1447 struct componentname *cnp = ap->a_cnp; 1448 struct mount *mp = dvp->v_mount; 1449 struct puffs_mount *pmp = MPTOPUFFSMP(mp); 1450 int error; 1451 1452 PUFFS_MSG_ALLOC(vn, remove); 1453 remove_msg->pvnr_cookie_targ = VPTOPNC(vp); 1454 puffs_makecn(&remove_msg->pvnr_cn, &remove_msg->pvnr_cn_cred, 1455 cnp, PUFFS_USE_FULLPNBUF(pmp)); 1456 puffs_msg_setinfo(park_remove, PUFFSOP_VN, 1457 PUFFS_VN_REMOVE, VPTOPNC(dvp)); 1458 1459 puffs_msg_enqueue(pmp, park_remove); 1460 REFPN_AND_UNLOCKVP(dvp, dpn); 1461 if (dvp == vp) 1462 REFPN(pn); 1463 else 1464 REFPN_AND_UNLOCKVP(vp, pn); 1465 error = puffs_msg_wait2(pmp, park_remove, dpn, pn); 1466 1467 PUFFS_MSG_RELEASE(remove); 1468 1469 RELEPN_AND_VP(dvp, dpn); 1470 RELEPN_AND_VP(vp, pn); 1471 1472 error = checkerr(pmp, error, __func__); 1473 return error; 1474 } 1475 1476 int 1477 puffs_vnop_mkdir(void *v) 1478 { 1479 struct vop_mkdir_args /* { 1480 const struct vnodeop_desc *a_desc; 1481 struct vnode *a_dvp; 1482 struct vnode **a_vpp; 1483 struct componentname *a_cnp; 1484 struct vattr *a_vap; 1485 } */ *ap = v; 1486 PUFFS_MSG_VARS(vn, mkdir); 1487 struct vnode *dvp = ap->a_dvp; 1488 struct puffs_node *dpn = VPTOPP(dvp); 1489 struct componentname *cnp = ap->a_cnp; 1490 struct mount *mp = dvp->v_mount; 1491 struct puffs_mount *pmp = MPTOPUFFSMP(mp); 1492 int error; 1493 1494 PUFFS_MSG_ALLOC(vn, mkdir); 1495 puffs_makecn(&mkdir_msg->pvnr_cn, &mkdir_msg->pvnr_cn_cred, 1496 cnp, PUFFS_USE_FULLPNBUF(pmp)); 1497 mkdir_msg->pvnr_va = *ap->a_vap; 1498 puffs_msg_setinfo(park_mkdir, PUFFSOP_VN, 1499 PUFFS_VN_MKDIR, VPTOPNC(dvp)); 1500 1501 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_mkdir, dvp->v_data, NULL, error); 1502 1503 error = checkerr(pmp, error, __func__); 1504 if (error) 1505 goto out; 1506 1507 error = puffs_newnode(mp, dvp, ap->a_vpp, 1508 mkdir_msg->pvnr_newnode, cnp, VDIR, 0); 1509 if (error) 1510 puffs_abortbutton(pmp, PUFFS_ABORT_MKDIR, dpn->pn_cookie, 1511 mkdir_msg->pvnr_newnode, cnp); 1512 1513 out: 1514 vput(dvp); 1515 PUFFS_MSG_RELEASE(mkdir); 1516 return error; 1517 } 1518 1519 static int 1520 callrmdir(struct puffs_mount *pmp, puffs_cookie_t dck, puffs_cookie_t ck, 1521 struct componentname *cnp) 1522 { 1523 PUFFS_MSG_VARS(vn, rmdir); 1524 int error; 1525 1526 PUFFS_MSG_ALLOC(vn, rmdir); 1527 rmdir_msg->pvnr_cookie_targ = ck; 1528 puffs_makecn(&rmdir_msg->pvnr_cn, &rmdir_msg->pvnr_cn_cred, 1529 cnp, PUFFS_USE_FULLPNBUF(pmp)); 1530 puffs_msg_setinfo(park_rmdir, PUFFSOP_VN, PUFFS_VN_RMDIR, dck); 1531 1532 PUFFS_MSG_ENQUEUEWAIT(pmp, park_rmdir, error); 1533 PUFFS_MSG_RELEASE(rmdir); 1534 1535 return checkerr(pmp, error, __func__); 1536 } 1537 1538 int 1539 puffs_vnop_rmdir(void *v) 1540 { 1541 struct vop_rmdir_args /* { 1542 const struct vnodeop_desc *a_desc; 1543 struct vnode *a_dvp; 1544 struct vnode *a_vp; 1545 struct componentname *a_cnp; 1546 } */ *ap = v; 1547 PUFFS_MSG_VARS(vn, rmdir); 1548 struct vnode *dvp = ap->a_dvp; 1549 struct vnode *vp = ap->a_vp; 1550 struct puffs_node *dpn = VPTOPP(dvp); 1551 struct puffs_node *pn = VPTOPP(vp); 1552 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount); 1553 struct componentname *cnp = ap->a_cnp; 1554 int error; 1555 1556 PUFFS_MSG_ALLOC(vn, rmdir); 1557 rmdir_msg->pvnr_cookie_targ = VPTOPNC(vp); 1558 puffs_makecn(&rmdir_msg->pvnr_cn, &rmdir_msg->pvnr_cn_cred, 1559 cnp, PUFFS_USE_FULLPNBUF(pmp)); 1560 puffs_msg_setinfo(park_rmdir, PUFFSOP_VN, 1561 PUFFS_VN_RMDIR, VPTOPNC(dvp)); 1562 1563 puffs_msg_enqueue(pmp, park_rmdir); 1564 REFPN_AND_UNLOCKVP(dvp, dpn); 1565 REFPN_AND_UNLOCKVP(vp, pn); 1566 error = puffs_msg_wait2(pmp, park_rmdir, dpn, pn); 1567 1568 PUFFS_MSG_RELEASE(rmdir); 1569 1570 /* XXX: some call cache_purge() *for both vnodes* here, investigate */ 1571 RELEPN_AND_VP(dvp, dpn); 1572 RELEPN_AND_VP(vp, pn); 1573 1574 return error; 1575 } 1576 1577 int 1578 puffs_vnop_link(void *v) 1579 { 1580 struct vop_link_args /* { 1581 const struct vnodeop_desc *a_desc; 1582 struct vnode *a_dvp; 1583 struct vnode *a_vp; 1584 struct componentname *a_cnp; 1585 } */ *ap = v; 1586 PUFFS_MSG_VARS(vn, link); 1587 struct vnode *dvp = ap->a_dvp; 1588 struct vnode *vp = ap->a_vp; 1589 struct puffs_node *dpn = VPTOPP(dvp); 1590 struct puffs_node *pn = VPTOPP(vp); 1591 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount); 1592 struct componentname *cnp = ap->a_cnp; 1593 int error; 1594 1595 PUFFS_MSG_ALLOC(vn, link); 1596 link_msg->pvnr_cookie_targ = VPTOPNC(vp); 1597 puffs_makecn(&link_msg->pvnr_cn, &link_msg->pvnr_cn_cred, 1598 cnp, PUFFS_USE_FULLPNBUF(pmp)); 1599 puffs_msg_setinfo(park_link, PUFFSOP_VN, 1600 PUFFS_VN_LINK, VPTOPNC(dvp)); 1601 1602 puffs_msg_enqueue(pmp, park_link); 1603 REFPN_AND_UNLOCKVP(dvp, dpn); 1604 REFPN(pn); 1605 error = puffs_msg_wait2(pmp, park_link, dpn, pn); 1606 1607 PUFFS_MSG_RELEASE(link); 1608 1609 error = checkerr(pmp, error, __func__); 1610 1611 /* 1612 * XXX: stay in touch with the cache. I don't like this, but 1613 * don't have a better solution either. See also puffs_rename(). 1614 */ 1615 if (error == 0) 1616 puffs_updatenode(pn, PUFFS_UPDATECTIME, 0); 1617 1618 RELEPN_AND_VP(dvp, dpn); 1619 puffs_releasenode(pn); 1620 1621 return error; 1622 } 1623 1624 int 1625 puffs_vnop_symlink(void *v) 1626 { 1627 struct vop_symlink_args /* { 1628 const struct vnodeop_desc *a_desc; 1629 struct vnode *a_dvp; 1630 struct vnode **a_vpp; 1631 struct componentname *a_cnp; 1632 struct vattr *a_vap; 1633 char *a_target; 1634 } */ *ap = v; 1635 PUFFS_MSG_VARS(vn, symlink); 1636 struct vnode *dvp = ap->a_dvp; 1637 struct puffs_node *dpn = VPTOPP(dvp); 1638 struct mount *mp = dvp->v_mount; 1639 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount); 1640 struct componentname *cnp = ap->a_cnp; 1641 int error; 1642 1643 *ap->a_vpp = NULL; 1644 1645 PUFFS_MSG_ALLOC(vn, symlink); 1646 puffs_makecn(&symlink_msg->pvnr_cn, &symlink_msg->pvnr_cn_cred, 1647 cnp, PUFFS_USE_FULLPNBUF(pmp)); 1648 symlink_msg->pvnr_va = *ap->a_vap; 1649 (void)strlcpy(symlink_msg->pvnr_link, ap->a_target, 1650 sizeof(symlink_msg->pvnr_link)); 1651 puffs_msg_setinfo(park_symlink, PUFFSOP_VN, 1652 PUFFS_VN_SYMLINK, VPTOPNC(dvp)); 1653 1654 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_symlink, dvp->v_data, NULL, error); 1655 1656 error = checkerr(pmp, error, __func__); 1657 if (error) 1658 goto out; 1659 1660 error = puffs_newnode(mp, dvp, ap->a_vpp, 1661 symlink_msg->pvnr_newnode, cnp, VLNK, 0); 1662 if (error) 1663 puffs_abortbutton(pmp, PUFFS_ABORT_SYMLINK, dpn->pn_cookie, 1664 symlink_msg->pvnr_newnode, cnp); 1665 1666 out: 1667 vput(dvp); 1668 PUFFS_MSG_RELEASE(symlink); 1669 1670 return error; 1671 } 1672 1673 int 1674 puffs_vnop_readlink(void *v) 1675 { 1676 struct vop_readlink_args /* { 1677 const struct vnodeop_desc *a_desc; 1678 struct vnode *a_vp; 1679 struct uio *a_uio; 1680 kauth_cred_t a_cred; 1681 } */ *ap = v; 1682 PUFFS_MSG_VARS(vn, readlink); 1683 struct vnode *vp = ap->a_vp; 1684 struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_vp->v_mount); 1685 size_t linklen; 1686 int error; 1687 1688 PUFFS_MSG_ALLOC(vn, readlink); 1689 puffs_credcvt(&readlink_msg->pvnr_cred, ap->a_cred); 1690 linklen = sizeof(readlink_msg->pvnr_link); 1691 readlink_msg->pvnr_linklen = linklen; 1692 puffs_msg_setinfo(park_readlink, PUFFSOP_VN, 1693 PUFFS_VN_READLINK, VPTOPNC(vp)); 1694 1695 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_readlink, vp->v_data, NULL, error); 1696 error = checkerr(pmp, error, __func__); 1697 if (error) 1698 goto out; 1699 1700 /* bad bad user file server */ 1701 if (readlink_msg->pvnr_linklen > linklen) { 1702 puffs_senderr(pmp, PUFFS_ERR_READLINK, E2BIG, 1703 "linklen too big", VPTOPNC(ap->a_vp)); 1704 error = EPROTO; 1705 goto out; 1706 } 1707 1708 error = uiomove(&readlink_msg->pvnr_link, readlink_msg->pvnr_linklen, 1709 ap->a_uio); 1710 out: 1711 PUFFS_MSG_RELEASE(readlink); 1712 return error; 1713 } 1714 1715 int 1716 puffs_vnop_rename(void *v) 1717 { 1718 struct vop_rename_args /* { 1719 const struct vnodeop_desc *a_desc; 1720 struct vnode *a_fdvp; 1721 struct vnode *a_fvp; 1722 struct componentname *a_fcnp; 1723 struct vnode *a_tdvp; 1724 struct vnode *a_tvp; 1725 struct componentname *a_tcnp; 1726 } */ *ap = v; 1727 PUFFS_MSG_VARS(vn, rename); 1728 struct vnode *fdvp = ap->a_fdvp, *fvp = ap->a_fvp; 1729 struct vnode *tdvp = ap->a_tdvp, *tvp = ap->a_tvp; 1730 struct puffs_node *fpn = ap->a_fvp->v_data; 1731 struct puffs_mount *pmp = MPTOPUFFSMP(fdvp->v_mount); 1732 int error; 1733 bool doabort = true; 1734 1735 if ((fvp->v_mount != tdvp->v_mount) || 1736 (tvp && (fvp->v_mount != tvp->v_mount))) { 1737 ERROUT(EXDEV); 1738 } 1739 1740 PUFFS_MSG_ALLOC(vn, rename); 1741 rename_msg->pvnr_cookie_src = VPTOPNC(fvp); 1742 rename_msg->pvnr_cookie_targdir = VPTOPNC(tdvp); 1743 if (tvp) 1744 rename_msg->pvnr_cookie_targ = VPTOPNC(tvp); 1745 else 1746 rename_msg->pvnr_cookie_targ = NULL; 1747 puffs_makecn(&rename_msg->pvnr_cn_src, &rename_msg->pvnr_cn_src_cred, 1748 ap->a_fcnp, PUFFS_USE_FULLPNBUF(pmp)); 1749 puffs_makecn(&rename_msg->pvnr_cn_targ, &rename_msg->pvnr_cn_targ_cred, 1750 ap->a_tcnp, PUFFS_USE_FULLPNBUF(pmp)); 1751 puffs_msg_setinfo(park_rename, PUFFSOP_VN, 1752 PUFFS_VN_RENAME, VPTOPNC(fdvp)); 1753 1754 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_rename, fdvp->v_data, NULL, error); 1755 doabort = false; 1756 PUFFS_MSG_RELEASE(rename); 1757 error = checkerr(pmp, error, __func__); 1758 1759 /* 1760 * XXX: stay in touch with the cache. I don't like this, but 1761 * don't have a better solution either. See also puffs_link(). 1762 */ 1763 if (error == 0) 1764 puffs_updatenode(fpn, PUFFS_UPDATECTIME, 0); 1765 1766 out: 1767 if (doabort) 1768 VOP_ABORTOP(tdvp, ap->a_tcnp); 1769 if (tvp != NULL) 1770 vput(tvp); 1771 if (tdvp == tvp) 1772 vrele(tdvp); 1773 else 1774 vput(tdvp); 1775 1776 if (doabort) 1777 VOP_ABORTOP(fdvp, ap->a_fcnp); 1778 vrele(fdvp); 1779 vrele(fvp); 1780 1781 return error; 1782 } 1783 1784 #define RWARGS(cont, iofl, move, offset, creds) \ 1785 (cont)->pvnr_ioflag = (iofl); \ 1786 (cont)->pvnr_resid = (move); \ 1787 (cont)->pvnr_offset = (offset); \ 1788 puffs_credcvt(&(cont)->pvnr_cred, creds) 1789 1790 int 1791 puffs_vnop_read(void *v) 1792 { 1793 struct vop_read_args /* { 1794 const struct vnodeop_desc *a_desc; 1795 struct vnode *a_vp; 1796 struct uio *a_uio; 1797 int a_ioflag; 1798 kauth_cred_t a_cred; 1799 } */ *ap = v; 1800 PUFFS_MSG_VARS(vn, read); 1801 struct vnode *vp = ap->a_vp; 1802 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 1803 struct uio *uio = ap->a_uio; 1804 size_t tomove, argsize; 1805 vsize_t bytelen; 1806 int error; 1807 1808 read_msg = NULL; 1809 error = 0; 1810 1811 /* std sanity */ 1812 if (uio->uio_resid == 0) 1813 return 0; 1814 if (uio->uio_offset < 0) 1815 return EINVAL; 1816 1817 if (vp->v_type == VREG && PUFFS_USE_PAGECACHE(pmp)) { 1818 const int advice = IO_ADV_DECODE(ap->a_ioflag); 1819 1820 while (uio->uio_resid > 0) { 1821 bytelen = MIN(uio->uio_resid, 1822 vp->v_size - uio->uio_offset); 1823 if (bytelen == 0) 1824 break; 1825 1826 error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice, 1827 UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp)); 1828 if (error) 1829 break; 1830 } 1831 1832 if ((vp->v_mount->mnt_flag & MNT_NOATIME) == 0) 1833 puffs_updatenode(VPTOPP(vp), PUFFS_UPDATEATIME, 0); 1834 } else { 1835 /* 1836 * in case it's not a regular file or we're operating 1837 * uncached, do read in the old-fashioned style, 1838 * i.e. explicit read operations 1839 */ 1840 1841 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp); 1842 argsize = sizeof(struct puffs_vnmsg_read); 1843 puffs_msgmem_alloc(argsize + tomove, &park_read, 1844 (void *)&read_msg, 1); 1845 1846 error = 0; 1847 while (uio->uio_resid > 0) { 1848 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp); 1849 memset(read_msg, 0, argsize); /* XXX: touser KASSERT */ 1850 RWARGS(read_msg, ap->a_ioflag, tomove, 1851 uio->uio_offset, ap->a_cred); 1852 puffs_msg_setinfo(park_read, PUFFSOP_VN, 1853 PUFFS_VN_READ, VPTOPNC(vp)); 1854 puffs_msg_setdelta(park_read, tomove); 1855 1856 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_read, vp->v_data, 1857 NULL, error); 1858 error = checkerr(pmp, error, __func__); 1859 if (error) 1860 break; 1861 1862 if (read_msg->pvnr_resid > tomove) { 1863 puffs_senderr(pmp, PUFFS_ERR_READ, 1864 E2BIG, "resid grew", VPTOPNC(ap->a_vp)); 1865 error = EPROTO; 1866 break; 1867 } 1868 1869 error = uiomove(read_msg->pvnr_data, 1870 tomove - read_msg->pvnr_resid, uio); 1871 1872 /* 1873 * in case the file is out of juice, resid from 1874 * userspace is != 0. and the error-case is 1875 * quite obvious 1876 */ 1877 if (error || read_msg->pvnr_resid) 1878 break; 1879 } 1880 1881 puffs_msgmem_release(park_read); 1882 } 1883 1884 return error; 1885 } 1886 1887 /* 1888 * XXX: in case of a failure, this leaves uio in a bad state. 1889 * We could theoretically copy the uio and iovecs and "replay" 1890 * them the right amount after the userspace trip, but don't 1891 * bother for now. 1892 */ 1893 int 1894 puffs_vnop_write(void *v) 1895 { 1896 struct vop_write_args /* { 1897 const struct vnodeop_desc *a_desc; 1898 struct vnode *a_vp; 1899 struct uio *a_uio; 1900 int a_ioflag; 1901 kauth_cred_t a_cred; 1902 } */ *ap = v; 1903 PUFFS_MSG_VARS(vn, write); 1904 struct vnode *vp = ap->a_vp; 1905 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 1906 struct uio *uio = ap->a_uio; 1907 size_t tomove, argsize; 1908 off_t oldoff, newoff, origoff; 1909 vsize_t bytelen; 1910 int error, uflags; 1911 int ubcflags; 1912 1913 error = uflags = 0; 1914 write_msg = NULL; 1915 1916 if (vp->v_type == VREG && PUFFS_USE_PAGECACHE(pmp)) { 1917 ubcflags = UBC_WRITE | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp); 1918 1919 /* 1920 * userspace *should* be allowed to control this, 1921 * but with UBC it's a bit unclear how to handle it 1922 */ 1923 if (ap->a_ioflag & IO_APPEND) 1924 uio->uio_offset = vp->v_size; 1925 1926 origoff = uio->uio_offset; 1927 while (uio->uio_resid > 0) { 1928 uflags |= PUFFS_UPDATECTIME; 1929 uflags |= PUFFS_UPDATEMTIME; 1930 oldoff = uio->uio_offset; 1931 bytelen = uio->uio_resid; 1932 1933 newoff = oldoff + bytelen; 1934 if (vp->v_size < newoff) { 1935 uvm_vnp_setwritesize(vp, newoff); 1936 } 1937 error = ubc_uiomove(&vp->v_uobj, uio, bytelen, 1938 UVM_ADV_RANDOM, ubcflags); 1939 1940 /* 1941 * In case of a ubc_uiomove() error, 1942 * opt to not extend the file at all and 1943 * return an error. Otherwise, if we attempt 1944 * to clear the memory we couldn't fault to, 1945 * we might generate a kernel page fault. 1946 */ 1947 if (vp->v_size < newoff) { 1948 if (error == 0) { 1949 uflags |= PUFFS_UPDATESIZE; 1950 uvm_vnp_setsize(vp, newoff); 1951 } else { 1952 uvm_vnp_setwritesize(vp, vp->v_size); 1953 } 1954 } 1955 if (error) 1956 break; 1957 1958 /* 1959 * If we're writing large files, flush to file server 1960 * every 64k. Otherwise we can very easily exhaust 1961 * kernel and user memory, as the file server cannot 1962 * really keep up with our writing speed. 1963 * 1964 * Note: this does *NOT* honor MNT_ASYNC, because 1965 * that gives userland too much say in the kernel. 1966 */ 1967 if (oldoff >> 16 != uio->uio_offset >> 16) { 1968 mutex_enter(vp->v_interlock); 1969 error = VOP_PUTPAGES(vp, oldoff & ~0xffff, 1970 uio->uio_offset & ~0xffff, 1971 PGO_CLEANIT | PGO_SYNCIO); 1972 if (error) 1973 break; 1974 } 1975 } 1976 1977 /* synchronous I/O? */ 1978 if (error == 0 && ap->a_ioflag & IO_SYNC) { 1979 mutex_enter(vp->v_interlock); 1980 error = VOP_PUTPAGES(vp, trunc_page(origoff), 1981 round_page(uio->uio_offset), 1982 PGO_CLEANIT | PGO_SYNCIO); 1983 1984 /* write through page cache? */ 1985 } else if (error == 0 && pmp->pmp_flags & PUFFS_KFLAG_WTCACHE) { 1986 mutex_enter(vp->v_interlock); 1987 error = VOP_PUTPAGES(vp, trunc_page(origoff), 1988 round_page(uio->uio_offset), PGO_CLEANIT); 1989 } 1990 1991 puffs_updatenode(VPTOPP(vp), uflags, vp->v_size); 1992 } else { 1993 /* tomove is non-increasing */ 1994 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp); 1995 argsize = sizeof(struct puffs_vnmsg_write) + tomove; 1996 puffs_msgmem_alloc(argsize, &park_write, (void *)&write_msg,1); 1997 1998 while (uio->uio_resid > 0) { 1999 /* move data to buffer */ 2000 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp); 2001 memset(write_msg, 0, argsize); /* XXX: touser KASSERT */ 2002 RWARGS(write_msg, ap->a_ioflag, tomove, 2003 uio->uio_offset, ap->a_cred); 2004 error = uiomove(write_msg->pvnr_data, tomove, uio); 2005 if (error) 2006 break; 2007 2008 /* move buffer to userspace */ 2009 puffs_msg_setinfo(park_write, PUFFSOP_VN, 2010 PUFFS_VN_WRITE, VPTOPNC(vp)); 2011 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_write, vp->v_data, 2012 NULL, error); 2013 error = checkerr(pmp, error, __func__); 2014 if (error) 2015 break; 2016 2017 if (write_msg->pvnr_resid > tomove) { 2018 puffs_senderr(pmp, PUFFS_ERR_WRITE, 2019 E2BIG, "resid grew", VPTOPNC(ap->a_vp)); 2020 error = EPROTO; 2021 break; 2022 } 2023 2024 /* adjust file size */ 2025 if (vp->v_size < uio->uio_offset) 2026 uvm_vnp_setsize(vp, uio->uio_offset); 2027 2028 /* didn't move everything? bad userspace. bail */ 2029 if (write_msg->pvnr_resid != 0) { 2030 error = EIO; 2031 break; 2032 } 2033 } 2034 puffs_msgmem_release(park_write); 2035 } 2036 2037 return error; 2038 } 2039 2040 int 2041 puffs_vnop_print(void *v) 2042 { 2043 struct vop_print_args /* { 2044 struct vnode *a_vp; 2045 } */ *ap = v; 2046 PUFFS_MSG_VARS(vn, print); 2047 struct vnode *vp = ap->a_vp; 2048 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 2049 struct puffs_node *pn = vp->v_data; 2050 int error; 2051 2052 /* kernel portion */ 2053 printf("tag VT_PUFFS, vnode %p, puffs node: %p,\n" 2054 "\tuserspace cookie: %p", vp, pn, pn->pn_cookie); 2055 if (vp->v_type == VFIFO) 2056 VOCALL(fifo_vnodeop_p, VOFFSET(vop_print), v); 2057 printf("\n"); 2058 2059 /* userspace portion */ 2060 if (EXISTSOP(pmp, PRINT)) { 2061 PUFFS_MSG_ALLOC(vn, print); 2062 puffs_msg_setinfo(park_print, PUFFSOP_VN, 2063 PUFFS_VN_PRINT, VPTOPNC(vp)); 2064 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_print, vp->v_data, 2065 NULL, error); 2066 PUFFS_MSG_RELEASE(print); 2067 } 2068 2069 return 0; 2070 } 2071 2072 int 2073 puffs_vnop_pathconf(void *v) 2074 { 2075 struct vop_pathconf_args /* { 2076 const struct vnodeop_desc *a_desc; 2077 struct vnode *a_vp; 2078 int a_name; 2079 register_t *a_retval; 2080 } */ *ap = v; 2081 PUFFS_MSG_VARS(vn, pathconf); 2082 struct vnode *vp = ap->a_vp; 2083 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 2084 int error; 2085 2086 PUFFS_MSG_ALLOC(vn, pathconf); 2087 pathconf_msg->pvnr_name = ap->a_name; 2088 puffs_msg_setinfo(park_pathconf, PUFFSOP_VN, 2089 PUFFS_VN_PATHCONF, VPTOPNC(vp)); 2090 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_pathconf, vp->v_data, NULL, error); 2091 error = checkerr(pmp, error, __func__); 2092 if (!error) 2093 *ap->a_retval = pathconf_msg->pvnr_retval; 2094 PUFFS_MSG_RELEASE(pathconf); 2095 2096 return error; 2097 } 2098 2099 int 2100 puffs_vnop_advlock(void *v) 2101 { 2102 struct vop_advlock_args /* { 2103 const struct vnodeop_desc *a_desc; 2104 struct vnode *a_vp; 2105 void *a_id; 2106 int a_op; 2107 struct flock *a_fl; 2108 int a_flags; 2109 } */ *ap = v; 2110 PUFFS_MSG_VARS(vn, advlock); 2111 struct vnode *vp = ap->a_vp; 2112 struct puffs_node *pn = VPTOPP(vp); 2113 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 2114 int error; 2115 2116 if (!EXISTSOP(pmp, ADVLOCK)) 2117 return lf_advlock(ap, &pn->pn_lockf, vp->v_size); 2118 2119 PUFFS_MSG_ALLOC(vn, advlock); 2120 (void)memcpy(&advlock_msg->pvnr_fl, ap->a_fl, 2121 sizeof(advlock_msg->pvnr_fl)); 2122 advlock_msg->pvnr_id = ap->a_id; 2123 advlock_msg->pvnr_op = ap->a_op; 2124 advlock_msg->pvnr_flags = ap->a_flags; 2125 puffs_msg_setinfo(park_advlock, PUFFSOP_VN, 2126 PUFFS_VN_ADVLOCK, VPTOPNC(vp)); 2127 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_advlock, vp->v_data, NULL, error); 2128 error = checkerr(pmp, error, __func__); 2129 PUFFS_MSG_RELEASE(advlock); 2130 2131 return error; 2132 } 2133 2134 int 2135 puffs_vnop_abortop(void *v) 2136 { 2137 struct vop_abortop_args /* { 2138 struct vnode *a_dvp; 2139 struct componentname *a_cnp; 2140 }; */ *ap = v; 2141 PUFFS_MSG_VARS(vn, abortop); 2142 struct vnode *dvp = ap->a_dvp; 2143 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount); 2144 struct componentname *cnp = ap->a_cnp; 2145 2146 if (EXISTSOP(pmp, ABORTOP)) { 2147 PUFFS_MSG_ALLOC(vn, abortop); 2148 puffs_makecn(&abortop_msg->pvnr_cn, &abortop_msg->pvnr_cn_cred, 2149 cnp, PUFFS_USE_FULLPNBUF(pmp)); 2150 puffs_msg_setfaf(park_abortop); 2151 puffs_msg_setinfo(park_abortop, PUFFSOP_VN, 2152 PUFFS_VN_ABORTOP, VPTOPNC(dvp)); 2153 2154 puffs_msg_enqueue(pmp, park_abortop); 2155 PUFFS_MSG_RELEASE(abortop); 2156 } 2157 2158 return genfs_abortop(v); 2159 } 2160 2161 #define BIOASYNC(bp) (bp->b_flags & B_ASYNC) 2162 2163 /* 2164 * This maps itself to PUFFS_VN_READ/WRITE for data transfer. 2165 */ 2166 int 2167 puffs_vnop_strategy(void *v) 2168 { 2169 struct vop_strategy_args /* { 2170 const struct vnodeop_desc *a_desc; 2171 struct vnode *a_vp; 2172 struct buf *a_bp; 2173 } */ *ap = v; 2174 PUFFS_MSG_VARS(vn, rw); 2175 struct vnode *vp = ap->a_vp; 2176 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 2177 struct puffs_node *pn; 2178 struct buf *bp; 2179 size_t argsize; 2180 size_t tomove, moved; 2181 int error, dofaf, dobiodone; 2182 2183 pmp = MPTOPUFFSMP(vp->v_mount); 2184 bp = ap->a_bp; 2185 error = 0; 2186 dofaf = 0; 2187 pn = VPTOPP(vp); 2188 park_rw = NULL; /* explicit */ 2189 dobiodone = 1; 2190 2191 if ((BUF_ISREAD(bp) && !EXISTSOP(pmp, READ)) 2192 || (BUF_ISWRITE(bp) && !EXISTSOP(pmp, WRITE))) 2193 ERROUT(EOPNOTSUPP); 2194 2195 /* 2196 * Short-circuit optimization: don't flush buffer in between 2197 * VOP_INACTIVE and VOP_RECLAIM in case the node has no references. 2198 */ 2199 if (pn->pn_stat & PNODE_DYING) { 2200 KASSERT(BUF_ISWRITE(bp)); 2201 bp->b_resid = 0; 2202 goto out; 2203 } 2204 2205 #ifdef DIAGNOSTIC 2206 if (bp->b_bcount > pmp->pmp_msg_maxsize - PUFFS_MSGSTRUCT_MAX) 2207 panic("puffs_strategy: wildly inappropriate buf bcount %d", 2208 bp->b_bcount); 2209 #endif 2210 2211 /* 2212 * See explanation for the necessity of a FAF in puffs_fsync. 2213 * 2214 * Also, do FAF in case we're suspending. 2215 * See puffs_vfsops.c:pageflush() 2216 */ 2217 if (BUF_ISWRITE(bp)) { 2218 mutex_enter(vp->v_interlock); 2219 if (vp->v_iflag & VI_XLOCK) 2220 dofaf = 1; 2221 if (pn->pn_stat & PNODE_FAF) 2222 dofaf = 1; 2223 mutex_exit(vp->v_interlock); 2224 } 2225 2226 #ifdef DIAGNOSTIC 2227 if (curlwp == uvm.pagedaemon_lwp) 2228 KASSERT(dofaf || BIOASYNC(bp)); 2229 #endif 2230 2231 /* allocate transport structure */ 2232 tomove = PUFFS_TOMOVE(bp->b_bcount, pmp); 2233 argsize = sizeof(struct puffs_vnmsg_rw); 2234 error = puffs_msgmem_alloc(argsize + tomove, &park_rw, 2235 (void *)&rw_msg, dofaf ? 0 : 1); 2236 if (error) 2237 goto out; 2238 RWARGS(rw_msg, 0, tomove, bp->b_blkno << DEV_BSHIFT, FSCRED); 2239 2240 /* 2x2 cases: read/write, faf/nofaf */ 2241 if (BUF_ISREAD(bp)) { 2242 puffs_msg_setinfo(park_rw, PUFFSOP_VN, 2243 PUFFS_VN_READ, VPTOPNC(vp)); 2244 puffs_msg_setdelta(park_rw, tomove); 2245 if (BIOASYNC(bp)) { 2246 puffs_msg_setcall(park_rw, 2247 puffs_parkdone_asyncbioread, bp); 2248 puffs_msg_enqueue(pmp, park_rw); 2249 dobiodone = 0; 2250 } else { 2251 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_rw, vp->v_data, 2252 NULL, error); 2253 error = checkerr(pmp, error, __func__); 2254 if (error) 2255 goto out; 2256 2257 if (rw_msg->pvnr_resid > tomove) { 2258 puffs_senderr(pmp, PUFFS_ERR_READ, 2259 E2BIG, "resid grew", VPTOPNC(vp)); 2260 ERROUT(EPROTO); 2261 } 2262 2263 moved = tomove - rw_msg->pvnr_resid; 2264 2265 (void)memcpy(bp->b_data, rw_msg->pvnr_data, moved); 2266 bp->b_resid = bp->b_bcount - moved; 2267 } 2268 } else { 2269 puffs_msg_setinfo(park_rw, PUFFSOP_VN, 2270 PUFFS_VN_WRITE, VPTOPNC(vp)); 2271 /* 2272 * make pages read-only before we write them if we want 2273 * write caching info 2274 */ 2275 if (PUFFS_WCACHEINFO(pmp)) { 2276 struct uvm_object *uobj = &vp->v_uobj; 2277 int npages = (bp->b_bcount + PAGE_SIZE-1) >> PAGE_SHIFT; 2278 struct vm_page *vmp; 2279 int i; 2280 2281 for (i = 0; i < npages; i++) { 2282 vmp= uvm_pageratop((vaddr_t)bp->b_data 2283 + (i << PAGE_SHIFT)); 2284 DPRINTF(("puffs_strategy: write-protecting " 2285 "vp %p page %p, offset %" PRId64"\n", 2286 vp, vmp, vmp->offset)); 2287 mutex_enter(uobj->vmobjlock); 2288 vmp->flags |= PG_RDONLY; 2289 pmap_page_protect(vmp, VM_PROT_READ); 2290 mutex_exit(uobj->vmobjlock); 2291 } 2292 } 2293 2294 (void)memcpy(&rw_msg->pvnr_data, bp->b_data, tomove); 2295 if (dofaf) { 2296 puffs_msg_setfaf(park_rw); 2297 } else if (BIOASYNC(bp)) { 2298 puffs_msg_setcall(park_rw, 2299 puffs_parkdone_asyncbiowrite, bp); 2300 dobiodone = 0; 2301 } 2302 2303 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_rw, vp->v_data, NULL, error); 2304 2305 if (dobiodone == 0) 2306 goto out; 2307 2308 /* 2309 * XXXXXXXX: wrong, but kernel can't survive strategy 2310 * failure currently. Here, have one more X: X. 2311 */ 2312 if (error != ENOMEM) 2313 error = 0; 2314 2315 error = checkerr(pmp, error, __func__); 2316 if (error) 2317 goto out; 2318 2319 if (rw_msg->pvnr_resid > tomove) { 2320 puffs_senderr(pmp, PUFFS_ERR_WRITE, 2321 E2BIG, "resid grew", VPTOPNC(vp)); 2322 ERROUT(EPROTO); 2323 } 2324 2325 /* 2326 * FAF moved everything. Frankly, we don't 2327 * really have a choice. 2328 */ 2329 if (dofaf && error == 0) 2330 moved = tomove; 2331 else 2332 moved = tomove - rw_msg->pvnr_resid; 2333 2334 bp->b_resid = bp->b_bcount - moved; 2335 if (bp->b_resid != 0) { 2336 ERROUT(EIO); 2337 } 2338 } 2339 2340 out: 2341 if (park_rw) 2342 puffs_msgmem_release(park_rw); 2343 2344 if (error) 2345 bp->b_error = error; 2346 2347 if (error || dobiodone) 2348 biodone(bp); 2349 2350 return error; 2351 } 2352 2353 int 2354 puffs_vnop_mmap(void *v) 2355 { 2356 struct vop_mmap_args /* { 2357 const struct vnodeop_desc *a_desc; 2358 struct vnode *a_vp; 2359 vm_prot_t a_prot; 2360 kauth_cred_t a_cred; 2361 } */ *ap = v; 2362 PUFFS_MSG_VARS(vn, mmap); 2363 struct vnode *vp = ap->a_vp; 2364 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 2365 int error; 2366 2367 if (!PUFFS_USE_PAGECACHE(pmp)) 2368 return genfs_eopnotsupp(v); 2369 2370 if (EXISTSOP(pmp, MMAP)) { 2371 PUFFS_MSG_ALLOC(vn, mmap); 2372 mmap_msg->pvnr_prot = ap->a_prot; 2373 puffs_credcvt(&mmap_msg->pvnr_cred, ap->a_cred); 2374 puffs_msg_setinfo(park_mmap, PUFFSOP_VN, 2375 PUFFS_VN_MMAP, VPTOPNC(vp)); 2376 2377 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_mmap, vp->v_data, NULL, error); 2378 error = checkerr(pmp, error, __func__); 2379 PUFFS_MSG_RELEASE(mmap); 2380 } else { 2381 error = genfs_mmap(v); 2382 } 2383 2384 return error; 2385 } 2386 2387 2388 /* 2389 * The rest don't get a free trip to userspace and back, they 2390 * have to stay within the kernel. 2391 */ 2392 2393 /* 2394 * bmap doesn't really make any sense for puffs, so just 1:1 map it. 2395 * well, maybe somehow, somewhere, some day .... 2396 */ 2397 int 2398 puffs_vnop_bmap(void *v) 2399 { 2400 struct vop_bmap_args /* { 2401 const struct vnodeop_desc *a_desc; 2402 struct vnode *a_vp; 2403 daddr_t a_bn; 2404 struct vnode **a_vpp; 2405 daddr_t *a_bnp; 2406 int *a_runp; 2407 } */ *ap = v; 2408 struct puffs_mount *pmp; 2409 2410 pmp = MPTOPUFFSMP(ap->a_vp->v_mount); 2411 2412 if (ap->a_vpp) 2413 *ap->a_vpp = ap->a_vp; 2414 if (ap->a_bnp) 2415 *ap->a_bnp = ap->a_bn; 2416 if (ap->a_runp) 2417 *ap->a_runp 2418 = (PUFFS_TOMOVE(pmp->pmp_msg_maxsize, pmp)>>DEV_BSHIFT) - 1; 2419 2420 return 0; 2421 } 2422 2423 /* 2424 * Handle getpages faults in puffs. We let genfs_getpages() do most 2425 * of the dirty work, but we come in this route to do accounting tasks. 2426 * If the user server has specified functions for cache notifications 2427 * about reads and/or writes, we record which type of operation we got, 2428 * for which page range, and proceed to issue a FAF notification to the 2429 * server about it. 2430 */ 2431 int 2432 puffs_vnop_getpages(void *v) 2433 { 2434 struct vop_getpages_args /* { 2435 const struct vnodeop_desc *a_desc; 2436 struct vnode *a_vp; 2437 voff_t a_offset; 2438 struct vm_page **a_m; 2439 int *a_count; 2440 int a_centeridx; 2441 vm_prot_t a_access_type; 2442 int a_advice; 2443 int a_flags; 2444 } */ *ap = v; 2445 struct puffs_mount *pmp; 2446 struct puffs_node *pn; 2447 struct vnode *vp; 2448 struct vm_page **pgs; 2449 struct puffs_cacheinfo *pcinfo = NULL; 2450 struct puffs_cacherun *pcrun; 2451 void *parkmem = NULL; 2452 size_t runsizes; 2453 int i, npages, si, streakon; 2454 int error, locked, write; 2455 2456 pmp = MPTOPUFFSMP(ap->a_vp->v_mount); 2457 npages = *ap->a_count; 2458 pgs = ap->a_m; 2459 vp = ap->a_vp; 2460 pn = vp->v_data; 2461 locked = (ap->a_flags & PGO_LOCKED) != 0; 2462 write = (ap->a_access_type & VM_PROT_WRITE) != 0; 2463 2464 /* ccg xnaht - gets Wuninitialized wrong */ 2465 pcrun = NULL; 2466 runsizes = 0; 2467 2468 /* 2469 * Check that we aren't trying to fault in pages which our file 2470 * server doesn't know about. This happens if we extend a file by 2471 * skipping some pages and later try to fault in pages which 2472 * are between pn_serversize and vp_size. This check optimizes 2473 * away the common case where a file is being extended. 2474 */ 2475 if (ap->a_offset >= pn->pn_serversize && ap->a_offset < vp->v_size) { 2476 struct vattr va; 2477 2478 /* try again later when we can block */ 2479 if (locked) 2480 ERROUT(EBUSY); 2481 2482 mutex_exit(vp->v_interlock); 2483 vattr_null(&va); 2484 va.va_size = vp->v_size; 2485 error = dosetattr(vp, &va, FSCRED, 0); 2486 if (error) 2487 ERROUT(error); 2488 mutex_enter(vp->v_interlock); 2489 } 2490 2491 if (write && PUFFS_WCACHEINFO(pmp)) { 2492 #ifdef notnowjohn 2493 /* allocate worst-case memory */ 2494 runsizes = ((npages / 2) + 1) * sizeof(struct puffs_cacherun); 2495 pcinfo = kmem_zalloc(sizeof(struct puffs_cacheinfo) + runsize, 2496 locked ? KM_NOSLEEP : KM_SLEEP); 2497 2498 /* 2499 * can't block if we're locked and can't mess up caching 2500 * information for fs server. so come back later, please 2501 */ 2502 if (pcinfo == NULL) 2503 ERROUT(ENOMEM); 2504 2505 parkmem = puffs_park_alloc(locked == 0); 2506 if (parkmem == NULL) 2507 ERROUT(ENOMEM); 2508 2509 pcrun = pcinfo->pcache_runs; 2510 #else 2511 (void)parkmem; 2512 #endif 2513 } 2514 2515 error = genfs_getpages(v); 2516 if (error) 2517 goto out; 2518 2519 if (PUFFS_WCACHEINFO(pmp) == 0) 2520 goto out; 2521 2522 /* 2523 * Let's see whose fault it was and inform the user server of 2524 * possibly read/written pages. Map pages from read faults 2525 * strictly read-only, since otherwise we might miss info on 2526 * when the page is actually write-faulted to. 2527 */ 2528 if (!locked) 2529 mutex_enter(vp->v_uobj.vmobjlock); 2530 for (i = 0, si = 0, streakon = 0; i < npages; i++) { 2531 if (pgs[i] == NULL || pgs[i] == PGO_DONTCARE) { 2532 if (streakon && write) { 2533 streakon = 0; 2534 pcrun[si].pcache_runend 2535 = trunc_page(pgs[i]->offset) + PAGE_MASK; 2536 si++; 2537 } 2538 continue; 2539 } 2540 if (streakon == 0 && write) { 2541 streakon = 1; 2542 pcrun[si].pcache_runstart = pgs[i]->offset; 2543 } 2544 2545 if (!write) 2546 pgs[i]->flags |= PG_RDONLY; 2547 } 2548 /* was the last page part of our streak? */ 2549 if (streakon) { 2550 pcrun[si].pcache_runend 2551 = trunc_page(pgs[i-1]->offset) + PAGE_MASK; 2552 si++; 2553 } 2554 if (!locked) 2555 mutex_exit(vp->v_uobj.vmobjlock); 2556 2557 KASSERT(si <= (npages / 2) + 1); 2558 2559 #ifdef notnowjohn 2560 /* send results to userspace */ 2561 if (write) 2562 puffs_cacheop(pmp, parkmem, pcinfo, 2563 sizeof(struct puffs_cacheinfo) + runsizes, VPTOPNC(vp)); 2564 #endif 2565 2566 out: 2567 if (error) { 2568 if (pcinfo != NULL) 2569 kmem_free(pcinfo, 2570 sizeof(struct puffs_cacheinfo) + runsizes); 2571 #ifdef notnowjohn 2572 if (parkmem != NULL) 2573 puffs_park_release(parkmem, 1); 2574 #endif 2575 } 2576 2577 return error; 2578 } 2579 2580 /* 2581 * Extended attribute support. 2582 */ 2583 2584 int 2585 puffs_vnop_getextattr(void *v) 2586 { 2587 struct vop_getextattr_args /* 2588 struct vnode *a_vp; 2589 int a_attrnamespace; 2590 const char *a_name; 2591 struct uio *a_uio; 2592 size_t *a_size; 2593 kauth_cred_t a_cred; 2594 }; */ *ap = v; 2595 PUFFS_MSG_VARS(vn, getextattr); 2596 struct vnode *vp = ap->a_vp; 2597 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 2598 int attrnamespace = ap->a_attrnamespace; 2599 const char *name = ap->a_name; 2600 struct uio *uio = ap->a_uio; 2601 size_t *sizep = ap->a_size; 2602 size_t tomove, resid; 2603 int error; 2604 2605 if (uio) 2606 resid = uio->uio_resid; 2607 else 2608 resid = 0; 2609 2610 tomove = PUFFS_TOMOVE(resid, pmp); 2611 if (tomove != resid) { 2612 error = E2BIG; 2613 goto out; 2614 } 2615 2616 puffs_msgmem_alloc(sizeof(struct puffs_vnmsg_getextattr) + tomove, 2617 &park_getextattr, (void *)&getextattr_msg, 1); 2618 2619 getextattr_msg->pvnr_attrnamespace = attrnamespace; 2620 strlcpy(getextattr_msg->pvnr_attrname, name, 2621 sizeof(getextattr_msg->pvnr_attrname)); 2622 puffs_credcvt(&getextattr_msg->pvnr_cred, ap->a_cred); 2623 if (sizep) 2624 getextattr_msg->pvnr_datasize = 1; 2625 getextattr_msg->pvnr_resid = tomove; 2626 2627 puffs_msg_setinfo(park_getextattr, 2628 PUFFSOP_VN, PUFFS_VN_GETEXTATTR, VPTOPNC(vp)); 2629 puffs_msg_setdelta(park_getextattr, tomove); 2630 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_getextattr, vp->v_data, NULL, error); 2631 2632 error = checkerr(pmp, error, __func__); 2633 if (error) 2634 goto out; 2635 2636 resid = getextattr_msg->pvnr_resid; 2637 if (resid > tomove) { 2638 puffs_senderr(pmp, PUFFS_ERR_GETEXTATTR, E2BIG, 2639 "resid grew", VPTOPNC(vp)); 2640 error = EPROTO; 2641 goto out; 2642 } 2643 2644 if (sizep) 2645 *sizep = getextattr_msg->pvnr_datasize; 2646 if (uio) 2647 error = uiomove(getextattr_msg->pvnr_data, tomove - resid, uio); 2648 2649 out: 2650 PUFFS_MSG_RELEASE(getextattr); 2651 return error; 2652 } 2653 2654 int 2655 puffs_vnop_setextattr(void *v) 2656 { 2657 struct vop_setextattr_args /* { 2658 struct vnode *a_vp; 2659 int a_attrnamespace; 2660 const char *a_name; 2661 struct uio *a_uio; 2662 kauth_cred_t a_cred; 2663 }; */ *ap = v; 2664 PUFFS_MSG_VARS(vn, setextattr); 2665 struct vnode *vp = ap->a_vp; 2666 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 2667 int attrnamespace = ap->a_attrnamespace; 2668 const char *name = ap->a_name; 2669 struct uio *uio = ap->a_uio; 2670 size_t tomove, resid; 2671 int error; 2672 2673 if (uio) 2674 resid = uio->uio_resid; 2675 else 2676 resid = 0; 2677 2678 tomove = PUFFS_TOMOVE(resid, pmp); 2679 if (tomove != resid) { 2680 error = E2BIG; 2681 goto out; 2682 } 2683 2684 puffs_msgmem_alloc(sizeof(struct puffs_vnmsg_setextattr) + tomove, 2685 &park_setextattr, (void *)&setextattr_msg, 1); 2686 2687 setextattr_msg->pvnr_attrnamespace = attrnamespace; 2688 strlcpy(setextattr_msg->pvnr_attrname, name, 2689 sizeof(setextattr_msg->pvnr_attrname)); 2690 puffs_credcvt(&setextattr_msg->pvnr_cred, ap->a_cred); 2691 setextattr_msg->pvnr_resid = tomove; 2692 2693 if (uio) { 2694 error = uiomove(setextattr_msg->pvnr_data, tomove, uio); 2695 if (error) 2696 goto out; 2697 } 2698 2699 puffs_msg_setinfo(park_setextattr, 2700 PUFFSOP_VN, PUFFS_VN_SETEXTATTR, VPTOPNC(vp)); 2701 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_setextattr, vp->v_data, NULL, error); 2702 2703 error = checkerr(pmp, error, __func__); 2704 if (error) 2705 goto out; 2706 2707 if (setextattr_msg->pvnr_resid != 0) 2708 error = EIO; 2709 2710 out: 2711 PUFFS_MSG_RELEASE(setextattr); 2712 2713 return error; 2714 } 2715 2716 int 2717 puffs_vnop_listextattr(void *v) 2718 { 2719 struct vop_listextattr_args /* { 2720 struct vnode *a_vp; 2721 int a_attrnamespace; 2722 struct uio *a_uio; 2723 size_t *a_size; 2724 kauth_cred_t a_cred; 2725 }; */ *ap = v; 2726 PUFFS_MSG_VARS(vn, listextattr); 2727 struct vnode *vp = ap->a_vp; 2728 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 2729 int attrnamespace = ap->a_attrnamespace; 2730 struct uio *uio = ap->a_uio; 2731 size_t *sizep = ap->a_size; 2732 size_t tomove, resid; 2733 int error; 2734 2735 if (uio) 2736 resid = uio->uio_resid; 2737 else 2738 resid = 0; 2739 2740 tomove = PUFFS_TOMOVE(resid, pmp); 2741 if (tomove != resid) { 2742 error = E2BIG; 2743 goto out; 2744 } 2745 2746 puffs_msgmem_alloc(sizeof(struct puffs_vnmsg_listextattr) + tomove, 2747 &park_listextattr, (void *)&listextattr_msg, 1); 2748 2749 listextattr_msg->pvnr_attrnamespace = attrnamespace; 2750 puffs_credcvt(&listextattr_msg->pvnr_cred, ap->a_cred); 2751 listextattr_msg->pvnr_resid = tomove; 2752 if (sizep) 2753 listextattr_msg->pvnr_datasize = 1; 2754 2755 puffs_msg_setinfo(park_listextattr, 2756 PUFFSOP_VN, PUFFS_VN_LISTEXTATTR, VPTOPNC(vp)); 2757 puffs_msg_setdelta(park_listextattr, tomove); 2758 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_listextattr, vp->v_data, NULL, error); 2759 2760 error = checkerr(pmp, error, __func__); 2761 if (error) 2762 goto out; 2763 2764 resid = listextattr_msg->pvnr_resid; 2765 if (resid > tomove) { 2766 puffs_senderr(pmp, PUFFS_ERR_LISTEXTATTR, E2BIG, 2767 "resid grew", VPTOPNC(vp)); 2768 error = EPROTO; 2769 goto out; 2770 } 2771 2772 if (sizep) 2773 *sizep = listextattr_msg->pvnr_datasize; 2774 if (uio) 2775 error = uiomove(listextattr_msg->pvnr_data, tomove-resid, uio); 2776 2777 out: 2778 PUFFS_MSG_RELEASE(listextattr); 2779 return error; 2780 } 2781 2782 int 2783 puffs_vnop_deleteextattr(void *v) 2784 { 2785 struct vop_deleteextattr_args /* { 2786 struct vnode *a_vp; 2787 int a_attrnamespace; 2788 const char *a_name; 2789 kauth_cred_t a_cred; 2790 }; */ *ap = v; 2791 PUFFS_MSG_VARS(vn, deleteextattr); 2792 struct vnode *vp = ap->a_vp; 2793 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 2794 int attrnamespace = ap->a_attrnamespace; 2795 const char *name = ap->a_name; 2796 int error; 2797 2798 PUFFS_MSG_ALLOC(vn, deleteextattr); 2799 deleteextattr_msg->pvnr_attrnamespace = attrnamespace; 2800 strlcpy(deleteextattr_msg->pvnr_attrname, name, 2801 sizeof(deleteextattr_msg->pvnr_attrname)); 2802 puffs_credcvt(&deleteextattr_msg->pvnr_cred, ap->a_cred); 2803 2804 puffs_msg_setinfo(park_deleteextattr, 2805 PUFFSOP_VN, PUFFS_VN_DELETEEXTATTR, VPTOPNC(vp)); 2806 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_deleteextattr, 2807 vp->v_data, NULL, error); 2808 2809 error = checkerr(pmp, error, __func__); 2810 2811 PUFFS_MSG_RELEASE(deleteextattr); 2812 return error; 2813 } 2814 2815 /* 2816 * spec & fifo. These call the miscfs spec and fifo vectors, but issue 2817 * FAF update information for the puffs node first. 2818 */ 2819 int 2820 puffs_vnop_spec_read(void *v) 2821 { 2822 struct vop_read_args /* { 2823 const struct vnodeop_desc *a_desc; 2824 struct vnode *a_vp; 2825 struct uio *a_uio; 2826 int a_ioflag; 2827 kauth_cred_t a_cred; 2828 } */ *ap = v; 2829 2830 puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEATIME, 0); 2831 return VOCALL(spec_vnodeop_p, VOFFSET(vop_read), v); 2832 } 2833 2834 int 2835 puffs_vnop_spec_write(void *v) 2836 { 2837 struct vop_write_args /* { 2838 const struct vnodeop_desc *a_desc; 2839 struct vnode *a_vp; 2840 struct uio *a_uio; 2841 int a_ioflag; 2842 kauth_cred_t a_cred; 2843 } */ *ap = v; 2844 2845 puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEMTIME, 0); 2846 return VOCALL(spec_vnodeop_p, VOFFSET(vop_write), v); 2847 } 2848 2849 int 2850 puffs_vnop_fifo_read(void *v) 2851 { 2852 struct vop_read_args /* { 2853 const struct vnodeop_desc *a_desc; 2854 struct vnode *a_vp; 2855 struct uio *a_uio; 2856 int a_ioflag; 2857 kauth_cred_t a_cred; 2858 } */ *ap = v; 2859 2860 puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEATIME, 0); 2861 return VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), v); 2862 } 2863 2864 int 2865 puffs_vnop_fifo_write(void *v) 2866 { 2867 struct vop_write_args /* { 2868 const struct vnodeop_desc *a_desc; 2869 struct vnode *a_vp; 2870 struct uio *a_uio; 2871 int a_ioflag; 2872 kauth_cred_t a_cred; 2873 } */ *ap = v; 2874 2875 puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEMTIME, 0); 2876 return VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), v); 2877 } 2878