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