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