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