1 /* $NetBSD: tmpfs_vnops.c,v 1.39 2007/07/23 15:41:01 jmmv Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-2-Clause-NetBSD 5 * 6 * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc. 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to The NetBSD Foundation 10 * by Julio M. Merino Vidal, developed as part of Google's Summer of Code 11 * 2005 program. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 /* 36 * tmpfs vnode interface. 37 */ 38 #include <sys/cdefs.h> 39 __FBSDID("$FreeBSD$"); 40 41 #include <sys/param.h> 42 #include <sys/fcntl.h> 43 #include <sys/lockf.h> 44 #include <sys/lock.h> 45 #include <sys/namei.h> 46 #include <sys/priv.h> 47 #include <sys/proc.h> 48 #include <sys/rwlock.h> 49 #include <sys/sched.h> 50 #include <sys/stat.h> 51 #include <sys/systm.h> 52 #include <sys/sysctl.h> 53 #include <sys/unistd.h> 54 #include <sys/vnode.h> 55 56 #include <vm/vm.h> 57 #include <vm/vm_param.h> 58 #include <vm/vm_object.h> 59 #include <vm/vm_page.h> 60 #include <vm/vm_pager.h> 61 62 #include <fs/tmpfs/tmpfs_vnops.h> 63 #include <fs/tmpfs/tmpfs.h> 64 65 SYSCTL_DECL(_vfs_tmpfs); 66 67 static volatile int tmpfs_rename_restarts; 68 SYSCTL_INT(_vfs_tmpfs, OID_AUTO, rename_restarts, CTLFLAG_RD, 69 __DEVOLATILE(int *, &tmpfs_rename_restarts), 0, 70 "Times rename had to restart due to lock contention"); 71 72 static int 73 tmpfs_vn_get_ino_alloc(struct mount *mp, void *arg, int lkflags, 74 struct vnode **rvp) 75 { 76 77 return (tmpfs_alloc_vp(mp, arg, lkflags, rvp)); 78 } 79 80 static int 81 tmpfs_lookup1(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp) 82 { 83 struct tmpfs_dirent *de; 84 struct tmpfs_node *dnode, *pnode; 85 struct tmpfs_mount *tm; 86 int error; 87 88 dnode = VP_TO_TMPFS_DIR(dvp); 89 *vpp = NULLVP; 90 91 /* Check accessibility of requested node as a first step. */ 92 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_thread); 93 if (error != 0) 94 goto out; 95 96 /* We cannot be requesting the parent directory of the root node. */ 97 MPASS(IMPLIES(dnode->tn_type == VDIR && 98 dnode->tn_dir.tn_parent == dnode, 99 !(cnp->cn_flags & ISDOTDOT))); 100 101 TMPFS_ASSERT_LOCKED(dnode); 102 if (dnode->tn_dir.tn_parent == NULL) { 103 error = ENOENT; 104 goto out; 105 } 106 if (cnp->cn_flags & ISDOTDOT) { 107 tm = VFS_TO_TMPFS(dvp->v_mount); 108 pnode = dnode->tn_dir.tn_parent; 109 tmpfs_ref_node(pnode); 110 error = vn_vget_ino_gen(dvp, tmpfs_vn_get_ino_alloc, 111 pnode, cnp->cn_lkflags, vpp); 112 tmpfs_free_node(tm, pnode); 113 if (error != 0) 114 goto out; 115 } else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { 116 VREF(dvp); 117 *vpp = dvp; 118 error = 0; 119 } else { 120 de = tmpfs_dir_lookup(dnode, NULL, cnp); 121 if (de != NULL && de->td_node == NULL) 122 cnp->cn_flags |= ISWHITEOUT; 123 if (de == NULL || de->td_node == NULL) { 124 /* 125 * The entry was not found in the directory. 126 * This is OK if we are creating or renaming an 127 * entry and are working on the last component of 128 * the path name. 129 */ 130 if ((cnp->cn_flags & ISLASTCN) && 131 (cnp->cn_nameiop == CREATE || \ 132 cnp->cn_nameiop == RENAME || 133 (cnp->cn_nameiop == DELETE && 134 cnp->cn_flags & DOWHITEOUT && 135 cnp->cn_flags & ISWHITEOUT))) { 136 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, 137 cnp->cn_thread); 138 if (error != 0) 139 goto out; 140 141 /* 142 * Keep the component name in the buffer for 143 * future uses. 144 */ 145 cnp->cn_flags |= SAVENAME; 146 147 error = EJUSTRETURN; 148 } else 149 error = ENOENT; 150 } else { 151 struct tmpfs_node *tnode; 152 153 /* 154 * The entry was found, so get its associated 155 * tmpfs_node. 156 */ 157 tnode = de->td_node; 158 159 /* 160 * If we are not at the last path component and 161 * found a non-directory or non-link entry (which 162 * may itself be pointing to a directory), raise 163 * an error. 164 */ 165 if ((tnode->tn_type != VDIR && 166 tnode->tn_type != VLNK) && 167 !(cnp->cn_flags & ISLASTCN)) { 168 error = ENOTDIR; 169 goto out; 170 } 171 172 /* 173 * If we are deleting or renaming the entry, keep 174 * track of its tmpfs_dirent so that it can be 175 * easily deleted later. 176 */ 177 if ((cnp->cn_flags & ISLASTCN) && 178 (cnp->cn_nameiop == DELETE || 179 cnp->cn_nameiop == RENAME)) { 180 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, 181 cnp->cn_thread); 182 if (error != 0) 183 goto out; 184 185 /* Allocate a new vnode on the matching entry. */ 186 error = tmpfs_alloc_vp(dvp->v_mount, tnode, 187 cnp->cn_lkflags, vpp); 188 if (error != 0) 189 goto out; 190 191 if ((dnode->tn_mode & S_ISTXT) && 192 VOP_ACCESS(dvp, VADMIN, cnp->cn_cred, 193 cnp->cn_thread) && VOP_ACCESS(*vpp, VADMIN, 194 cnp->cn_cred, cnp->cn_thread)) { 195 error = EPERM; 196 vput(*vpp); 197 *vpp = NULL; 198 goto out; 199 } 200 cnp->cn_flags |= SAVENAME; 201 } else { 202 error = tmpfs_alloc_vp(dvp->v_mount, tnode, 203 cnp->cn_lkflags, vpp); 204 if (error != 0) 205 goto out; 206 } 207 } 208 } 209 210 /* 211 * Store the result of this lookup in the cache. Avoid this if the 212 * request was for creation, as it does not improve timings on 213 * emprical tests. 214 */ 215 if ((cnp->cn_flags & MAKEENTRY) != 0 && tmpfs_use_nc(dvp)) 216 cache_enter(dvp, *vpp, cnp); 217 218 out: 219 /* 220 * If there were no errors, *vpp cannot be null and it must be 221 * locked. 222 */ 223 MPASS(IFF(error == 0, *vpp != NULLVP && VOP_ISLOCKED(*vpp))); 224 225 return (error); 226 } 227 228 static int 229 tmpfs_cached_lookup(struct vop_cachedlookup_args *v) 230 { 231 232 return (tmpfs_lookup1(v->a_dvp, v->a_vpp, v->a_cnp)); 233 } 234 235 static int 236 tmpfs_lookup(struct vop_lookup_args *v) 237 { 238 239 return (tmpfs_lookup1(v->a_dvp, v->a_vpp, v->a_cnp)); 240 } 241 242 static int 243 tmpfs_create(struct vop_create_args *v) 244 { 245 struct vnode *dvp = v->a_dvp; 246 struct vnode **vpp = v->a_vpp; 247 struct componentname *cnp = v->a_cnp; 248 struct vattr *vap = v->a_vap; 249 int error; 250 251 MPASS(vap->va_type == VREG || vap->va_type == VSOCK); 252 253 error = tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL); 254 if (error == 0 && (cnp->cn_flags & MAKEENTRY) != 0 && tmpfs_use_nc(dvp)) 255 cache_enter(dvp, *vpp, cnp); 256 return (error); 257 } 258 259 static int 260 tmpfs_mknod(struct vop_mknod_args *v) 261 { 262 struct vnode *dvp = v->a_dvp; 263 struct vnode **vpp = v->a_vpp; 264 struct componentname *cnp = v->a_cnp; 265 struct vattr *vap = v->a_vap; 266 267 if (vap->va_type != VBLK && vap->va_type != VCHR && 268 vap->va_type != VFIFO) 269 return EINVAL; 270 271 return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL); 272 } 273 274 static int 275 tmpfs_open(struct vop_open_args *v) 276 { 277 struct vnode *vp = v->a_vp; 278 int mode = v->a_mode; 279 280 int error; 281 struct tmpfs_node *node; 282 283 MPASS(VOP_ISLOCKED(vp)); 284 285 node = VP_TO_TMPFS_NODE(vp); 286 287 /* The file is still active but all its names have been removed 288 * (e.g. by a "rmdir $(pwd)"). It cannot be opened any more as 289 * it is about to die. */ 290 if (node->tn_links < 1) 291 return (ENOENT); 292 293 /* If the file is marked append-only, deny write requests. */ 294 if (node->tn_flags & APPEND && (mode & (FWRITE | O_APPEND)) == FWRITE) 295 error = EPERM; 296 else { 297 error = 0; 298 /* For regular files, the call below is nop. */ 299 KASSERT(vp->v_type != VREG || (node->tn_reg.tn_aobj->flags & 300 OBJ_DEAD) == 0, ("dead object")); 301 vnode_create_vobject(vp, node->tn_size, v->a_td); 302 } 303 304 MPASS(VOP_ISLOCKED(vp)); 305 return error; 306 } 307 308 static int 309 tmpfs_close(struct vop_close_args *v) 310 { 311 struct vnode *vp = v->a_vp; 312 313 /* Update node times. */ 314 tmpfs_update(vp); 315 316 return (0); 317 } 318 319 int 320 tmpfs_access(struct vop_access_args *v) 321 { 322 struct vnode *vp = v->a_vp; 323 accmode_t accmode = v->a_accmode; 324 struct ucred *cred = v->a_cred; 325 326 int error; 327 struct tmpfs_node *node; 328 329 MPASS(VOP_ISLOCKED(vp)); 330 331 node = VP_TO_TMPFS_NODE(vp); 332 333 switch (vp->v_type) { 334 case VDIR: 335 /* FALLTHROUGH */ 336 case VLNK: 337 /* FALLTHROUGH */ 338 case VREG: 339 if (accmode & VWRITE && vp->v_mount->mnt_flag & MNT_RDONLY) { 340 error = EROFS; 341 goto out; 342 } 343 break; 344 345 case VBLK: 346 /* FALLTHROUGH */ 347 case VCHR: 348 /* FALLTHROUGH */ 349 case VSOCK: 350 /* FALLTHROUGH */ 351 case VFIFO: 352 break; 353 354 default: 355 error = EINVAL; 356 goto out; 357 } 358 359 if (accmode & VWRITE && node->tn_flags & IMMUTABLE) { 360 error = EPERM; 361 goto out; 362 } 363 364 error = vaccess(vp->v_type, node->tn_mode, node->tn_uid, 365 node->tn_gid, accmode, cred, NULL); 366 367 out: 368 MPASS(VOP_ISLOCKED(vp)); 369 370 return error; 371 } 372 373 int 374 tmpfs_getattr(struct vop_getattr_args *v) 375 { 376 struct vnode *vp = v->a_vp; 377 struct vattr *vap = v->a_vap; 378 vm_object_t obj; 379 struct tmpfs_node *node; 380 381 node = VP_TO_TMPFS_NODE(vp); 382 383 tmpfs_update(vp); 384 385 vap->va_type = vp->v_type; 386 vap->va_mode = node->tn_mode; 387 vap->va_nlink = node->tn_links; 388 vap->va_uid = node->tn_uid; 389 vap->va_gid = node->tn_gid; 390 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 391 vap->va_fileid = node->tn_id; 392 vap->va_size = node->tn_size; 393 vap->va_blocksize = PAGE_SIZE; 394 vap->va_atime = node->tn_atime; 395 vap->va_mtime = node->tn_mtime; 396 vap->va_ctime = node->tn_ctime; 397 vap->va_birthtime = node->tn_birthtime; 398 vap->va_gen = node->tn_gen; 399 vap->va_flags = node->tn_flags; 400 vap->va_rdev = (vp->v_type == VBLK || vp->v_type == VCHR) ? 401 node->tn_rdev : NODEV; 402 if (vp->v_type == VREG) { 403 obj = node->tn_reg.tn_aobj; 404 vap->va_bytes = (u_quad_t)obj->resident_page_count * PAGE_SIZE; 405 } else 406 vap->va_bytes = node->tn_size; 407 vap->va_filerev = 0; 408 409 return 0; 410 } 411 412 int 413 tmpfs_setattr(struct vop_setattr_args *v) 414 { 415 struct vnode *vp = v->a_vp; 416 struct vattr *vap = v->a_vap; 417 struct ucred *cred = v->a_cred; 418 struct thread *td = curthread; 419 420 int error; 421 422 MPASS(VOP_ISLOCKED(vp)); 423 424 error = 0; 425 426 /* Abort if any unsettable attribute is given. */ 427 if (vap->va_type != VNON || 428 vap->va_nlink != VNOVAL || 429 vap->va_fsid != VNOVAL || 430 vap->va_fileid != VNOVAL || 431 vap->va_blocksize != VNOVAL || 432 vap->va_gen != VNOVAL || 433 vap->va_rdev != VNOVAL || 434 vap->va_bytes != VNOVAL) 435 error = EINVAL; 436 437 if (error == 0 && (vap->va_flags != VNOVAL)) 438 error = tmpfs_chflags(vp, vap->va_flags, cred, td); 439 440 if (error == 0 && (vap->va_size != VNOVAL)) 441 error = tmpfs_chsize(vp, vap->va_size, cred, td); 442 443 if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL)) 444 error = tmpfs_chown(vp, vap->va_uid, vap->va_gid, cred, td); 445 446 if (error == 0 && (vap->va_mode != (mode_t)VNOVAL)) 447 error = tmpfs_chmod(vp, vap->va_mode, cred, td); 448 449 if (error == 0 && ((vap->va_atime.tv_sec != VNOVAL && 450 vap->va_atime.tv_nsec != VNOVAL) || 451 (vap->va_mtime.tv_sec != VNOVAL && 452 vap->va_mtime.tv_nsec != VNOVAL) || 453 (vap->va_birthtime.tv_sec != VNOVAL && 454 vap->va_birthtime.tv_nsec != VNOVAL))) 455 error = tmpfs_chtimes(vp, vap, cred, td); 456 457 /* Update the node times. We give preference to the error codes 458 * generated by this function rather than the ones that may arise 459 * from tmpfs_update. */ 460 tmpfs_update(vp); 461 462 MPASS(VOP_ISLOCKED(vp)); 463 464 return error; 465 } 466 467 static int 468 tmpfs_read(struct vop_read_args *v) 469 { 470 struct vnode *vp; 471 struct uio *uio; 472 struct tmpfs_node *node; 473 474 vp = v->a_vp; 475 if (vp->v_type != VREG) 476 return (EISDIR); 477 uio = v->a_uio; 478 if (uio->uio_offset < 0) 479 return (EINVAL); 480 node = VP_TO_TMPFS_NODE(vp); 481 tmpfs_set_status(node, TMPFS_NODE_ACCESSED); 482 return (uiomove_object(node->tn_reg.tn_aobj, node->tn_size, uio)); 483 } 484 485 static int 486 tmpfs_write(struct vop_write_args *v) 487 { 488 struct vnode *vp; 489 struct uio *uio; 490 struct tmpfs_node *node; 491 off_t oldsize; 492 int error, ioflag; 493 494 vp = v->a_vp; 495 uio = v->a_uio; 496 ioflag = v->a_ioflag; 497 error = 0; 498 node = VP_TO_TMPFS_NODE(vp); 499 oldsize = node->tn_size; 500 501 if (uio->uio_offset < 0 || vp->v_type != VREG) 502 return (EINVAL); 503 if (uio->uio_resid == 0) 504 return (0); 505 if (ioflag & IO_APPEND) 506 uio->uio_offset = node->tn_size; 507 if (uio->uio_offset + uio->uio_resid > 508 VFS_TO_TMPFS(vp->v_mount)->tm_maxfilesize) 509 return (EFBIG); 510 if (vn_rlimit_fsize(vp, uio, uio->uio_td)) 511 return (EFBIG); 512 if (uio->uio_offset + uio->uio_resid > node->tn_size) { 513 error = tmpfs_reg_resize(vp, uio->uio_offset + uio->uio_resid, 514 FALSE); 515 if (error != 0) 516 goto out; 517 } 518 519 error = uiomove_object(node->tn_reg.tn_aobj, node->tn_size, uio); 520 node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | 521 TMPFS_NODE_CHANGED; 522 if (node->tn_mode & (S_ISUID | S_ISGID)) { 523 if (priv_check_cred(v->a_cred, PRIV_VFS_RETAINSUGID, 0)) 524 node->tn_mode &= ~(S_ISUID | S_ISGID); 525 } 526 if (error != 0) 527 (void)tmpfs_reg_resize(vp, oldsize, TRUE); 528 529 out: 530 MPASS(IMPLIES(error == 0, uio->uio_resid == 0)); 531 MPASS(IMPLIES(error != 0, oldsize == node->tn_size)); 532 533 return (error); 534 } 535 536 static int 537 tmpfs_fsync(struct vop_fsync_args *v) 538 { 539 struct vnode *vp = v->a_vp; 540 541 MPASS(VOP_ISLOCKED(vp)); 542 543 tmpfs_check_mtime(vp); 544 tmpfs_update(vp); 545 546 return 0; 547 } 548 549 static int 550 tmpfs_remove(struct vop_remove_args *v) 551 { 552 struct vnode *dvp = v->a_dvp; 553 struct vnode *vp = v->a_vp; 554 555 int error; 556 struct tmpfs_dirent *de; 557 struct tmpfs_mount *tmp; 558 struct tmpfs_node *dnode; 559 struct tmpfs_node *node; 560 561 MPASS(VOP_ISLOCKED(dvp)); 562 MPASS(VOP_ISLOCKED(vp)); 563 564 if (vp->v_type == VDIR) { 565 error = EISDIR; 566 goto out; 567 } 568 569 dnode = VP_TO_TMPFS_DIR(dvp); 570 node = VP_TO_TMPFS_NODE(vp); 571 tmp = VFS_TO_TMPFS(vp->v_mount); 572 de = tmpfs_dir_lookup(dnode, node, v->a_cnp); 573 MPASS(de != NULL); 574 575 /* Files marked as immutable or append-only cannot be deleted. */ 576 if ((node->tn_flags & (IMMUTABLE | APPEND | NOUNLINK)) || 577 (dnode->tn_flags & APPEND)) { 578 error = EPERM; 579 goto out; 580 } 581 582 /* Remove the entry from the directory; as it is a file, we do not 583 * have to change the number of hard links of the directory. */ 584 tmpfs_dir_detach(dvp, de); 585 if (v->a_cnp->cn_flags & DOWHITEOUT) 586 tmpfs_dir_whiteout_add(dvp, v->a_cnp); 587 588 /* Free the directory entry we just deleted. Note that the node 589 * referred by it will not be removed until the vnode is really 590 * reclaimed. */ 591 tmpfs_free_dirent(tmp, de); 592 593 node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED; 594 error = 0; 595 596 out: 597 598 return error; 599 } 600 601 static int 602 tmpfs_link(struct vop_link_args *v) 603 { 604 struct vnode *dvp = v->a_tdvp; 605 struct vnode *vp = v->a_vp; 606 struct componentname *cnp = v->a_cnp; 607 608 int error; 609 struct tmpfs_dirent *de; 610 struct tmpfs_node *node; 611 612 MPASS(VOP_ISLOCKED(dvp)); 613 MPASS(cnp->cn_flags & HASBUF); 614 MPASS(dvp != vp); /* XXX When can this be false? */ 615 node = VP_TO_TMPFS_NODE(vp); 616 617 /* Ensure that we do not overflow the maximum number of links imposed 618 * by the system. */ 619 MPASS(node->tn_links <= LINK_MAX); 620 if (node->tn_links == LINK_MAX) { 621 error = EMLINK; 622 goto out; 623 } 624 625 /* We cannot create links of files marked immutable or append-only. */ 626 if (node->tn_flags & (IMMUTABLE | APPEND)) { 627 error = EPERM; 628 goto out; 629 } 630 631 /* Allocate a new directory entry to represent the node. */ 632 error = tmpfs_alloc_dirent(VFS_TO_TMPFS(vp->v_mount), node, 633 cnp->cn_nameptr, cnp->cn_namelen, &de); 634 if (error != 0) 635 goto out; 636 637 /* Insert the new directory entry into the appropriate directory. */ 638 if (cnp->cn_flags & ISWHITEOUT) 639 tmpfs_dir_whiteout_remove(dvp, cnp); 640 tmpfs_dir_attach(dvp, de); 641 642 /* vp link count has changed, so update node times. */ 643 node->tn_status |= TMPFS_NODE_CHANGED; 644 tmpfs_update(vp); 645 646 error = 0; 647 648 out: 649 return error; 650 } 651 652 /* 653 * We acquire all but fdvp locks using non-blocking acquisitions. If we 654 * fail to acquire any lock in the path we will drop all held locks, 655 * acquire the new lock in a blocking fashion, and then release it and 656 * restart the rename. This acquire/release step ensures that we do not 657 * spin on a lock waiting for release. On error release all vnode locks 658 * and decrement references the way tmpfs_rename() would do. 659 */ 660 static int 661 tmpfs_rename_relock(struct vnode *fdvp, struct vnode **fvpp, 662 struct vnode *tdvp, struct vnode **tvpp, 663 struct componentname *fcnp, struct componentname *tcnp) 664 { 665 struct vnode *nvp; 666 struct mount *mp; 667 struct tmpfs_dirent *de; 668 int error, restarts = 0; 669 670 VOP_UNLOCK(tdvp, 0); 671 if (*tvpp != NULL && *tvpp != tdvp) 672 VOP_UNLOCK(*tvpp, 0); 673 mp = fdvp->v_mount; 674 675 relock: 676 restarts += 1; 677 error = vn_lock(fdvp, LK_EXCLUSIVE); 678 if (error) 679 goto releout; 680 if (vn_lock(tdvp, LK_EXCLUSIVE | LK_NOWAIT) != 0) { 681 VOP_UNLOCK(fdvp, 0); 682 error = vn_lock(tdvp, LK_EXCLUSIVE); 683 if (error) 684 goto releout; 685 VOP_UNLOCK(tdvp, 0); 686 goto relock; 687 } 688 /* 689 * Re-resolve fvp to be certain it still exists and fetch the 690 * correct vnode. 691 */ 692 de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(fdvp), NULL, fcnp); 693 if (de == NULL) { 694 VOP_UNLOCK(fdvp, 0); 695 VOP_UNLOCK(tdvp, 0); 696 if ((fcnp->cn_flags & ISDOTDOT) != 0 || 697 (fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.')) 698 error = EINVAL; 699 else 700 error = ENOENT; 701 goto releout; 702 } 703 error = tmpfs_alloc_vp(mp, de->td_node, LK_EXCLUSIVE | LK_NOWAIT, &nvp); 704 if (error != 0) { 705 VOP_UNLOCK(fdvp, 0); 706 VOP_UNLOCK(tdvp, 0); 707 if (error != EBUSY) 708 goto releout; 709 error = tmpfs_alloc_vp(mp, de->td_node, LK_EXCLUSIVE, &nvp); 710 if (error != 0) 711 goto releout; 712 VOP_UNLOCK(nvp, 0); 713 /* 714 * Concurrent rename race. 715 */ 716 if (nvp == tdvp) { 717 vrele(nvp); 718 error = EINVAL; 719 goto releout; 720 } 721 vrele(*fvpp); 722 *fvpp = nvp; 723 goto relock; 724 } 725 vrele(*fvpp); 726 *fvpp = nvp; 727 VOP_UNLOCK(*fvpp, 0); 728 /* 729 * Re-resolve tvp and acquire the vnode lock if present. 730 */ 731 de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(tdvp), NULL, tcnp); 732 /* 733 * If tvp disappeared we just carry on. 734 */ 735 if (de == NULL && *tvpp != NULL) { 736 vrele(*tvpp); 737 *tvpp = NULL; 738 } 739 /* 740 * Get the tvp ino if the lookup succeeded. We may have to restart 741 * if the non-blocking acquire fails. 742 */ 743 if (de != NULL) { 744 nvp = NULL; 745 error = tmpfs_alloc_vp(mp, de->td_node, 746 LK_EXCLUSIVE | LK_NOWAIT, &nvp); 747 if (*tvpp != NULL) 748 vrele(*tvpp); 749 *tvpp = nvp; 750 if (error != 0) { 751 VOP_UNLOCK(fdvp, 0); 752 VOP_UNLOCK(tdvp, 0); 753 if (error != EBUSY) 754 goto releout; 755 error = tmpfs_alloc_vp(mp, de->td_node, LK_EXCLUSIVE, 756 &nvp); 757 if (error != 0) 758 goto releout; 759 VOP_UNLOCK(nvp, 0); 760 /* 761 * fdvp contains fvp, thus tvp (=fdvp) is not empty. 762 */ 763 if (nvp == fdvp) { 764 error = ENOTEMPTY; 765 goto releout; 766 } 767 goto relock; 768 } 769 } 770 tmpfs_rename_restarts += restarts; 771 772 return (0); 773 774 releout: 775 vrele(fdvp); 776 vrele(*fvpp); 777 vrele(tdvp); 778 if (*tvpp != NULL) 779 vrele(*tvpp); 780 tmpfs_rename_restarts += restarts; 781 782 return (error); 783 } 784 785 static int 786 tmpfs_rename(struct vop_rename_args *v) 787 { 788 struct vnode *fdvp = v->a_fdvp; 789 struct vnode *fvp = v->a_fvp; 790 struct componentname *fcnp = v->a_fcnp; 791 struct vnode *tdvp = v->a_tdvp; 792 struct vnode *tvp = v->a_tvp; 793 struct componentname *tcnp = v->a_tcnp; 794 struct mount *mp = NULL; 795 796 char *newname; 797 int error; 798 struct tmpfs_dirent *de; 799 struct tmpfs_mount *tmp; 800 struct tmpfs_node *fdnode; 801 struct tmpfs_node *fnode; 802 struct tmpfs_node *tnode; 803 struct tmpfs_node *tdnode; 804 805 MPASS(VOP_ISLOCKED(tdvp)); 806 MPASS(IMPLIES(tvp != NULL, VOP_ISLOCKED(tvp))); 807 MPASS(fcnp->cn_flags & HASBUF); 808 MPASS(tcnp->cn_flags & HASBUF); 809 810 /* Disallow cross-device renames. 811 * XXX Why isn't this done by the caller? */ 812 if (fvp->v_mount != tdvp->v_mount || 813 (tvp != NULL && fvp->v_mount != tvp->v_mount)) { 814 error = EXDEV; 815 goto out; 816 } 817 818 /* If source and target are the same file, there is nothing to do. */ 819 if (fvp == tvp) { 820 error = 0; 821 goto out; 822 } 823 824 /* If we need to move the directory between entries, lock the 825 * source so that we can safely operate on it. */ 826 if (fdvp != tdvp && fdvp != tvp) { 827 if (vn_lock(fdvp, LK_EXCLUSIVE | LK_NOWAIT) != 0) { 828 mp = tdvp->v_mount; 829 error = vfs_busy(mp, 0); 830 if (error != 0) { 831 mp = NULL; 832 goto out; 833 } 834 error = tmpfs_rename_relock(fdvp, &fvp, tdvp, &tvp, 835 fcnp, tcnp); 836 if (error != 0) { 837 vfs_unbusy(mp); 838 return (error); 839 } 840 ASSERT_VOP_ELOCKED(fdvp, 841 "tmpfs_rename: fdvp not locked"); 842 ASSERT_VOP_ELOCKED(tdvp, 843 "tmpfs_rename: tdvp not locked"); 844 if (tvp != NULL) 845 ASSERT_VOP_ELOCKED(tvp, 846 "tmpfs_rename: tvp not locked"); 847 if (fvp == tvp) { 848 error = 0; 849 goto out_locked; 850 } 851 } 852 } 853 854 tmp = VFS_TO_TMPFS(tdvp->v_mount); 855 tdnode = VP_TO_TMPFS_DIR(tdvp); 856 tnode = (tvp == NULL) ? NULL : VP_TO_TMPFS_NODE(tvp); 857 fdnode = VP_TO_TMPFS_DIR(fdvp); 858 fnode = VP_TO_TMPFS_NODE(fvp); 859 de = tmpfs_dir_lookup(fdnode, fnode, fcnp); 860 861 /* Entry can disappear before we lock fdvp, 862 * also avoid manipulating '.' and '..' entries. */ 863 if (de == NULL) { 864 if ((fcnp->cn_flags & ISDOTDOT) != 0 || 865 (fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.')) 866 error = EINVAL; 867 else 868 error = ENOENT; 869 goto out_locked; 870 } 871 MPASS(de->td_node == fnode); 872 873 /* If re-naming a directory to another preexisting directory 874 * ensure that the target directory is empty so that its 875 * removal causes no side effects. 876 * Kern_rename guarantees the destination to be a directory 877 * if the source is one. */ 878 if (tvp != NULL) { 879 MPASS(tnode != NULL); 880 881 if ((tnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) || 882 (tdnode->tn_flags & (APPEND | IMMUTABLE))) { 883 error = EPERM; 884 goto out_locked; 885 } 886 887 if (fnode->tn_type == VDIR && tnode->tn_type == VDIR) { 888 if (tnode->tn_size > 0) { 889 error = ENOTEMPTY; 890 goto out_locked; 891 } 892 } else if (fnode->tn_type == VDIR && tnode->tn_type != VDIR) { 893 error = ENOTDIR; 894 goto out_locked; 895 } else if (fnode->tn_type != VDIR && tnode->tn_type == VDIR) { 896 error = EISDIR; 897 goto out_locked; 898 } else { 899 MPASS(fnode->tn_type != VDIR && 900 tnode->tn_type != VDIR); 901 } 902 } 903 904 if ((fnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) 905 || (fdnode->tn_flags & (APPEND | IMMUTABLE))) { 906 error = EPERM; 907 goto out_locked; 908 } 909 910 /* Ensure that we have enough memory to hold the new name, if it 911 * has to be changed. */ 912 if (fcnp->cn_namelen != tcnp->cn_namelen || 913 bcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fcnp->cn_namelen) != 0) { 914 newname = malloc(tcnp->cn_namelen, M_TMPFSNAME, M_WAITOK); 915 } else 916 newname = NULL; 917 918 /* If the node is being moved to another directory, we have to do 919 * the move. */ 920 if (fdnode != tdnode) { 921 /* In case we are moving a directory, we have to adjust its 922 * parent to point to the new parent. */ 923 if (de->td_node->tn_type == VDIR) { 924 struct tmpfs_node *n; 925 926 /* Ensure the target directory is not a child of the 927 * directory being moved. Otherwise, we'd end up 928 * with stale nodes. */ 929 n = tdnode; 930 /* TMPFS_LOCK garanties that no nodes are freed while 931 * traversing the list. Nodes can only be marked as 932 * removed: tn_parent == NULL. */ 933 TMPFS_LOCK(tmp); 934 TMPFS_NODE_LOCK(n); 935 while (n != n->tn_dir.tn_parent) { 936 struct tmpfs_node *parent; 937 938 if (n == fnode) { 939 TMPFS_NODE_UNLOCK(n); 940 TMPFS_UNLOCK(tmp); 941 error = EINVAL; 942 if (newname != NULL) 943 free(newname, M_TMPFSNAME); 944 goto out_locked; 945 } 946 parent = n->tn_dir.tn_parent; 947 TMPFS_NODE_UNLOCK(n); 948 if (parent == NULL) { 949 n = NULL; 950 break; 951 } 952 TMPFS_NODE_LOCK(parent); 953 if (parent->tn_dir.tn_parent == NULL) { 954 TMPFS_NODE_UNLOCK(parent); 955 n = NULL; 956 break; 957 } 958 n = parent; 959 } 960 TMPFS_UNLOCK(tmp); 961 if (n == NULL) { 962 error = EINVAL; 963 if (newname != NULL) 964 free(newname, M_TMPFSNAME); 965 goto out_locked; 966 } 967 TMPFS_NODE_UNLOCK(n); 968 969 /* Adjust the parent pointer. */ 970 TMPFS_VALIDATE_DIR(fnode); 971 TMPFS_NODE_LOCK(de->td_node); 972 de->td_node->tn_dir.tn_parent = tdnode; 973 TMPFS_NODE_UNLOCK(de->td_node); 974 975 /* As a result of changing the target of the '..' 976 * entry, the link count of the source and target 977 * directories has to be adjusted. */ 978 TMPFS_NODE_LOCK(tdnode); 979 TMPFS_ASSERT_LOCKED(tdnode); 980 tdnode->tn_links++; 981 TMPFS_NODE_UNLOCK(tdnode); 982 983 TMPFS_NODE_LOCK(fdnode); 984 TMPFS_ASSERT_LOCKED(fdnode); 985 fdnode->tn_links--; 986 TMPFS_NODE_UNLOCK(fdnode); 987 } 988 } 989 990 /* Do the move: just remove the entry from the source directory 991 * and insert it into the target one. */ 992 tmpfs_dir_detach(fdvp, de); 993 994 if (fcnp->cn_flags & DOWHITEOUT) 995 tmpfs_dir_whiteout_add(fdvp, fcnp); 996 if (tcnp->cn_flags & ISWHITEOUT) 997 tmpfs_dir_whiteout_remove(tdvp, tcnp); 998 999 /* If the name has changed, we need to make it effective by changing 1000 * it in the directory entry. */ 1001 if (newname != NULL) { 1002 MPASS(tcnp->cn_namelen <= MAXNAMLEN); 1003 1004 free(de->ud.td_name, M_TMPFSNAME); 1005 de->ud.td_name = newname; 1006 tmpfs_dirent_init(de, tcnp->cn_nameptr, tcnp->cn_namelen); 1007 1008 fnode->tn_status |= TMPFS_NODE_CHANGED; 1009 tdnode->tn_status |= TMPFS_NODE_MODIFIED; 1010 } 1011 1012 /* If we are overwriting an entry, we have to remove the old one 1013 * from the target directory. */ 1014 if (tvp != NULL) { 1015 struct tmpfs_dirent *tde; 1016 1017 /* Remove the old entry from the target directory. */ 1018 tde = tmpfs_dir_lookup(tdnode, tnode, tcnp); 1019 tmpfs_dir_detach(tdvp, tde); 1020 1021 /* Free the directory entry we just deleted. Note that the 1022 * node referred by it will not be removed until the vnode is 1023 * really reclaimed. */ 1024 tmpfs_free_dirent(VFS_TO_TMPFS(tvp->v_mount), tde); 1025 } 1026 1027 tmpfs_dir_attach(tdvp, de); 1028 1029 if (tmpfs_use_nc(fvp)) { 1030 cache_purge(fvp); 1031 if (tvp != NULL) 1032 cache_purge(tvp); 1033 cache_purge_negative(tdvp); 1034 } 1035 1036 error = 0; 1037 1038 out_locked: 1039 if (fdvp != tdvp && fdvp != tvp) 1040 VOP_UNLOCK(fdvp, 0); 1041 1042 out: 1043 /* Release target nodes. */ 1044 /* XXX: I don't understand when tdvp can be the same as tvp, but 1045 * other code takes care of this... */ 1046 if (tdvp == tvp) 1047 vrele(tdvp); 1048 else 1049 vput(tdvp); 1050 if (tvp != NULL) 1051 vput(tvp); 1052 1053 /* Release source nodes. */ 1054 vrele(fdvp); 1055 vrele(fvp); 1056 1057 if (mp != NULL) 1058 vfs_unbusy(mp); 1059 1060 return error; 1061 } 1062 1063 static int 1064 tmpfs_mkdir(struct vop_mkdir_args *v) 1065 { 1066 struct vnode *dvp = v->a_dvp; 1067 struct vnode **vpp = v->a_vpp; 1068 struct componentname *cnp = v->a_cnp; 1069 struct vattr *vap = v->a_vap; 1070 1071 MPASS(vap->va_type == VDIR); 1072 1073 return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL); 1074 } 1075 1076 static int 1077 tmpfs_rmdir(struct vop_rmdir_args *v) 1078 { 1079 struct vnode *dvp = v->a_dvp; 1080 struct vnode *vp = v->a_vp; 1081 1082 int error; 1083 struct tmpfs_dirent *de; 1084 struct tmpfs_mount *tmp; 1085 struct tmpfs_node *dnode; 1086 struct tmpfs_node *node; 1087 1088 MPASS(VOP_ISLOCKED(dvp)); 1089 MPASS(VOP_ISLOCKED(vp)); 1090 1091 tmp = VFS_TO_TMPFS(dvp->v_mount); 1092 dnode = VP_TO_TMPFS_DIR(dvp); 1093 node = VP_TO_TMPFS_DIR(vp); 1094 1095 /* Directories with more than two entries ('.' and '..') cannot be 1096 * removed. */ 1097 if (node->tn_size > 0) { 1098 error = ENOTEMPTY; 1099 goto out; 1100 } 1101 1102 if ((dnode->tn_flags & APPEND) 1103 || (node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND))) { 1104 error = EPERM; 1105 goto out; 1106 } 1107 1108 /* This invariant holds only if we are not trying to remove "..". 1109 * We checked for that above so this is safe now. */ 1110 MPASS(node->tn_dir.tn_parent == dnode); 1111 1112 /* Get the directory entry associated with node (vp). This was 1113 * filled by tmpfs_lookup while looking up the entry. */ 1114 de = tmpfs_dir_lookup(dnode, node, v->a_cnp); 1115 MPASS(TMPFS_DIRENT_MATCHES(de, 1116 v->a_cnp->cn_nameptr, 1117 v->a_cnp->cn_namelen)); 1118 1119 /* Check flags to see if we are allowed to remove the directory. */ 1120 if ((dnode->tn_flags & APPEND) != 0 || 1121 (node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) != 0) { 1122 error = EPERM; 1123 goto out; 1124 } 1125 1126 1127 /* Detach the directory entry from the directory (dnode). */ 1128 tmpfs_dir_detach(dvp, de); 1129 if (v->a_cnp->cn_flags & DOWHITEOUT) 1130 tmpfs_dir_whiteout_add(dvp, v->a_cnp); 1131 1132 /* No vnode should be allocated for this entry from this point */ 1133 TMPFS_NODE_LOCK(node); 1134 node->tn_links--; 1135 node->tn_dir.tn_parent = NULL; 1136 node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | 1137 TMPFS_NODE_MODIFIED; 1138 1139 TMPFS_NODE_UNLOCK(node); 1140 1141 TMPFS_NODE_LOCK(dnode); 1142 dnode->tn_links--; 1143 dnode->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | 1144 TMPFS_NODE_MODIFIED; 1145 TMPFS_NODE_UNLOCK(dnode); 1146 1147 if (tmpfs_use_nc(dvp)) { 1148 cache_purge(dvp); 1149 cache_purge(vp); 1150 } 1151 1152 /* Free the directory entry we just deleted. Note that the node 1153 * referred by it will not be removed until the vnode is really 1154 * reclaimed. */ 1155 tmpfs_free_dirent(tmp, de); 1156 1157 /* Release the deleted vnode (will destroy the node, notify 1158 * interested parties and clean it from the cache). */ 1159 1160 dnode->tn_status |= TMPFS_NODE_CHANGED; 1161 tmpfs_update(dvp); 1162 1163 error = 0; 1164 1165 out: 1166 return error; 1167 } 1168 1169 static int 1170 tmpfs_symlink(struct vop_symlink_args *v) 1171 { 1172 struct vnode *dvp = v->a_dvp; 1173 struct vnode **vpp = v->a_vpp; 1174 struct componentname *cnp = v->a_cnp; 1175 struct vattr *vap = v->a_vap; 1176 char *target = v->a_target; 1177 1178 #ifdef notyet /* XXX FreeBSD BUG: kern_symlink is not setting VLNK */ 1179 MPASS(vap->va_type == VLNK); 1180 #else 1181 vap->va_type = VLNK; 1182 #endif 1183 1184 return tmpfs_alloc_file(dvp, vpp, vap, cnp, target); 1185 } 1186 1187 static int 1188 tmpfs_readdir(struct vop_readdir_args *v) 1189 { 1190 struct vnode *vp = v->a_vp; 1191 struct uio *uio = v->a_uio; 1192 int *eofflag = v->a_eofflag; 1193 u_long **cookies = v->a_cookies; 1194 int *ncookies = v->a_ncookies; 1195 1196 int error; 1197 ssize_t startresid; 1198 int maxcookies; 1199 struct tmpfs_node *node; 1200 1201 /* This operation only makes sense on directory nodes. */ 1202 if (vp->v_type != VDIR) 1203 return ENOTDIR; 1204 1205 maxcookies = 0; 1206 node = VP_TO_TMPFS_DIR(vp); 1207 1208 startresid = uio->uio_resid; 1209 1210 /* Allocate cookies for NFS and compat modules. */ 1211 if (cookies != NULL && ncookies != NULL) { 1212 maxcookies = howmany(node->tn_size, 1213 sizeof(struct tmpfs_dirent)) + 2; 1214 *cookies = malloc(maxcookies * sizeof(**cookies), M_TEMP, 1215 M_WAITOK); 1216 *ncookies = 0; 1217 } 1218 1219 if (cookies == NULL) 1220 error = tmpfs_dir_getdents(node, uio, 0, NULL, NULL); 1221 else 1222 error = tmpfs_dir_getdents(node, uio, maxcookies, *cookies, 1223 ncookies); 1224 1225 /* Buffer was filled without hitting EOF. */ 1226 if (error == EJUSTRETURN) 1227 error = (uio->uio_resid != startresid) ? 0 : EINVAL; 1228 1229 if (error != 0 && cookies != NULL && ncookies != NULL) { 1230 free(*cookies, M_TEMP); 1231 *cookies = NULL; 1232 *ncookies = 0; 1233 } 1234 1235 if (eofflag != NULL) 1236 *eofflag = 1237 (error == 0 && uio->uio_offset == TMPFS_DIRCOOKIE_EOF); 1238 1239 return error; 1240 } 1241 1242 static int 1243 tmpfs_readlink(struct vop_readlink_args *v) 1244 { 1245 struct vnode *vp = v->a_vp; 1246 struct uio *uio = v->a_uio; 1247 1248 int error; 1249 struct tmpfs_node *node; 1250 1251 MPASS(uio->uio_offset == 0); 1252 MPASS(vp->v_type == VLNK); 1253 1254 node = VP_TO_TMPFS_NODE(vp); 1255 1256 error = uiomove(node->tn_link, MIN(node->tn_size, uio->uio_resid), 1257 uio); 1258 tmpfs_set_status(node, TMPFS_NODE_ACCESSED); 1259 1260 return (error); 1261 } 1262 1263 static int 1264 tmpfs_inactive(struct vop_inactive_args *v) 1265 { 1266 struct vnode *vp; 1267 struct tmpfs_node *node; 1268 1269 vp = v->a_vp; 1270 node = VP_TO_TMPFS_NODE(vp); 1271 if (node->tn_links == 0) 1272 vrecycle(vp); 1273 else 1274 tmpfs_check_mtime(vp); 1275 return (0); 1276 } 1277 1278 int 1279 tmpfs_reclaim(struct vop_reclaim_args *v) 1280 { 1281 struct vnode *vp = v->a_vp; 1282 1283 struct tmpfs_mount *tmp; 1284 struct tmpfs_node *node; 1285 1286 node = VP_TO_TMPFS_NODE(vp); 1287 tmp = VFS_TO_TMPFS(vp->v_mount); 1288 1289 if (vp->v_type == VREG) 1290 tmpfs_destroy_vobject(vp, node->tn_reg.tn_aobj); 1291 else 1292 vnode_destroy_vobject(vp); 1293 vp->v_object = NULL; 1294 if (tmpfs_use_nc(vp)) 1295 cache_purge(vp); 1296 1297 TMPFS_NODE_LOCK(node); 1298 tmpfs_free_vp(vp); 1299 1300 /* If the node referenced by this vnode was deleted by the user, 1301 * we must free its associated data structures (now that the vnode 1302 * is being reclaimed). */ 1303 if (node->tn_links == 0 && 1304 (node->tn_vpstate & TMPFS_VNODE_ALLOCATING) == 0) { 1305 node->tn_vpstate = TMPFS_VNODE_DOOMED; 1306 TMPFS_NODE_UNLOCK(node); 1307 tmpfs_free_node(tmp, node); 1308 } else 1309 TMPFS_NODE_UNLOCK(node); 1310 1311 MPASS(vp->v_data == NULL); 1312 return 0; 1313 } 1314 1315 int 1316 tmpfs_print(struct vop_print_args *v) 1317 { 1318 struct vnode *vp = v->a_vp; 1319 1320 struct tmpfs_node *node; 1321 1322 node = VP_TO_TMPFS_NODE(vp); 1323 1324 printf("tag VT_TMPFS, tmpfs_node %p, flags 0x%lx, links %jd\n", 1325 node, node->tn_flags, (uintmax_t)node->tn_links); 1326 printf("\tmode 0%o, owner %d, group %d, size %jd, status 0x%x\n", 1327 node->tn_mode, node->tn_uid, node->tn_gid, 1328 (intmax_t)node->tn_size, node->tn_status); 1329 1330 if (vp->v_type == VFIFO) 1331 fifo_printinfo(vp); 1332 1333 printf("\n"); 1334 1335 return 0; 1336 } 1337 1338 static int 1339 tmpfs_pathconf(struct vop_pathconf_args *v) 1340 { 1341 int name = v->a_name; 1342 register_t *retval = v->a_retval; 1343 1344 int error; 1345 1346 error = 0; 1347 1348 switch (name) { 1349 case _PC_NO_TRUNC: 1350 *retval = 1; 1351 break; 1352 1353 case _PC_SYNC_IO: 1354 *retval = 1; 1355 break; 1356 1357 case _PC_FILESIZEBITS: 1358 *retval = 64; 1359 break; 1360 1361 default: 1362 error = vop_stdpathconf(v); 1363 } 1364 1365 return error; 1366 } 1367 1368 static int 1369 tmpfs_vptofh(struct vop_vptofh_args *ap) 1370 { 1371 struct tmpfs_fid *tfhp; 1372 struct tmpfs_node *node; 1373 1374 tfhp = (struct tmpfs_fid *)ap->a_fhp; 1375 node = VP_TO_TMPFS_NODE(ap->a_vp); 1376 1377 tfhp->tf_len = sizeof(struct tmpfs_fid); 1378 tfhp->tf_id = node->tn_id; 1379 tfhp->tf_gen = node->tn_gen; 1380 1381 return (0); 1382 } 1383 1384 static int 1385 tmpfs_whiteout(struct vop_whiteout_args *ap) 1386 { 1387 struct vnode *dvp = ap->a_dvp; 1388 struct componentname *cnp = ap->a_cnp; 1389 struct tmpfs_dirent *de; 1390 1391 switch (ap->a_flags) { 1392 case LOOKUP: 1393 return (0); 1394 case CREATE: 1395 de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(dvp), NULL, cnp); 1396 if (de != NULL) 1397 return (de->td_node == NULL ? 0 : EEXIST); 1398 return (tmpfs_dir_whiteout_add(dvp, cnp)); 1399 case DELETE: 1400 tmpfs_dir_whiteout_remove(dvp, cnp); 1401 return (0); 1402 default: 1403 panic("tmpfs_whiteout: unknown op"); 1404 } 1405 } 1406 1407 static int 1408 tmpfs_vptocnp_dir(struct tmpfs_node *tn, struct tmpfs_node *tnp, 1409 struct tmpfs_dirent **pde) 1410 { 1411 struct tmpfs_dir_cursor dc; 1412 struct tmpfs_dirent *de; 1413 1414 for (de = tmpfs_dir_first(tnp, &dc); de != NULL; 1415 de = tmpfs_dir_next(tnp, &dc)) { 1416 if (de->td_node == tn) { 1417 *pde = de; 1418 return (0); 1419 } 1420 } 1421 return (ENOENT); 1422 } 1423 1424 static int 1425 tmpfs_vptocnp_fill(struct vnode *vp, struct tmpfs_node *tn, 1426 struct tmpfs_node *tnp, char *buf, int *buflen, struct vnode **dvp) 1427 { 1428 struct tmpfs_dirent *de; 1429 int error, i; 1430 1431 error = vn_vget_ino_gen(vp, tmpfs_vn_get_ino_alloc, tnp, LK_SHARED, 1432 dvp); 1433 if (error != 0) 1434 return (error); 1435 error = tmpfs_vptocnp_dir(tn, tnp, &de); 1436 if (error == 0) { 1437 i = *buflen; 1438 i -= de->td_namelen; 1439 if (i < 0) { 1440 error = ENOMEM; 1441 } else { 1442 bcopy(de->ud.td_name, buf + i, de->td_namelen); 1443 *buflen = i; 1444 } 1445 } 1446 if (error == 0) { 1447 if (vp != *dvp) 1448 VOP_UNLOCK(*dvp, 0); 1449 } else { 1450 if (vp != *dvp) 1451 vput(*dvp); 1452 else 1453 vrele(vp); 1454 } 1455 return (error); 1456 } 1457 1458 static int 1459 tmpfs_vptocnp(struct vop_vptocnp_args *ap) 1460 { 1461 struct vnode *vp, **dvp; 1462 struct tmpfs_node *tn, *tnp, *tnp1; 1463 struct tmpfs_dirent *de; 1464 struct tmpfs_mount *tm; 1465 char *buf; 1466 int *buflen; 1467 int error; 1468 1469 vp = ap->a_vp; 1470 dvp = ap->a_vpp; 1471 buf = ap->a_buf; 1472 buflen = ap->a_buflen; 1473 1474 tm = VFS_TO_TMPFS(vp->v_mount); 1475 tn = VP_TO_TMPFS_NODE(vp); 1476 if (tn->tn_type == VDIR) { 1477 tnp = tn->tn_dir.tn_parent; 1478 if (tnp == NULL) 1479 return (ENOENT); 1480 tmpfs_ref_node(tnp); 1481 error = tmpfs_vptocnp_fill(vp, tn, tn->tn_dir.tn_parent, buf, 1482 buflen, dvp); 1483 tmpfs_free_node(tm, tnp); 1484 return (error); 1485 } 1486 restart: 1487 TMPFS_LOCK(tm); 1488 LIST_FOREACH_SAFE(tnp, &tm->tm_nodes_used, tn_entries, tnp1) { 1489 if (tnp->tn_type != VDIR) 1490 continue; 1491 TMPFS_NODE_LOCK(tnp); 1492 tmpfs_ref_node_locked(tnp); 1493 1494 /* 1495 * tn_vnode cannot be instantiated while we hold the 1496 * node lock, so the directory cannot be changed while 1497 * we iterate over it. Do this to avoid instantiating 1498 * vnode for directories which cannot point to our 1499 * node. 1500 */ 1501 error = tnp->tn_vnode == NULL ? tmpfs_vptocnp_dir(tn, tnp, 1502 &de) : 0; 1503 1504 if (error == 0) { 1505 TMPFS_NODE_UNLOCK(tnp); 1506 TMPFS_UNLOCK(tm); 1507 error = tmpfs_vptocnp_fill(vp, tn, tnp, buf, buflen, 1508 dvp); 1509 if (error == 0) { 1510 tmpfs_free_node(tm, tnp); 1511 return (0); 1512 } 1513 if ((vp->v_iflag & VI_DOOMED) != 0) { 1514 tmpfs_free_node(tm, tnp); 1515 return (ENOENT); 1516 } 1517 TMPFS_LOCK(tm); 1518 TMPFS_NODE_LOCK(tnp); 1519 } 1520 if (tmpfs_free_node_locked(tm, tnp, false)) { 1521 goto restart; 1522 } else { 1523 KASSERT(tnp->tn_refcount > 0, 1524 ("node %p refcount zero", tnp)); 1525 tnp1 = LIST_NEXT(tnp, tn_entries); 1526 TMPFS_NODE_UNLOCK(tnp); 1527 } 1528 } 1529 TMPFS_UNLOCK(tm); 1530 return (ENOENT); 1531 } 1532 1533 /* 1534 * Vnode operations vector used for files stored in a tmpfs file system. 1535 */ 1536 struct vop_vector tmpfs_vnodeop_entries = { 1537 .vop_default = &default_vnodeops, 1538 .vop_lookup = vfs_cache_lookup, 1539 .vop_cachedlookup = tmpfs_cached_lookup, 1540 .vop_create = tmpfs_create, 1541 .vop_mknod = tmpfs_mknod, 1542 .vop_open = tmpfs_open, 1543 .vop_close = tmpfs_close, 1544 .vop_access = tmpfs_access, 1545 .vop_getattr = tmpfs_getattr, 1546 .vop_setattr = tmpfs_setattr, 1547 .vop_read = tmpfs_read, 1548 .vop_write = tmpfs_write, 1549 .vop_fsync = tmpfs_fsync, 1550 .vop_remove = tmpfs_remove, 1551 .vop_link = tmpfs_link, 1552 .vop_rename = tmpfs_rename, 1553 .vop_mkdir = tmpfs_mkdir, 1554 .vop_rmdir = tmpfs_rmdir, 1555 .vop_symlink = tmpfs_symlink, 1556 .vop_readdir = tmpfs_readdir, 1557 .vop_readlink = tmpfs_readlink, 1558 .vop_inactive = tmpfs_inactive, 1559 .vop_reclaim = tmpfs_reclaim, 1560 .vop_print = tmpfs_print, 1561 .vop_pathconf = tmpfs_pathconf, 1562 .vop_vptofh = tmpfs_vptofh, 1563 .vop_whiteout = tmpfs_whiteout, 1564 .vop_bmap = VOP_EOPNOTSUPP, 1565 .vop_vptocnp = tmpfs_vptocnp, 1566 }; 1567 1568 /* 1569 * Same vector for mounts which do not use namecache. 1570 */ 1571 struct vop_vector tmpfs_vnodeop_nonc_entries = { 1572 .vop_default = &tmpfs_vnodeop_entries, 1573 .vop_lookup = tmpfs_lookup, 1574 }; 1575