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