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