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