1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * (c) UNIX System Laboratories, Inc. 7 * All or some portions of this file are derived from material licensed 8 * to the University of California by American Telephone and Telegraph 9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10 * the permission of UNIX System Laboratories, Inc. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)ufs_lookup.c 8.15 (Berkeley) 6/16/95 37 */ 38 39 #include <sys/cdefs.h> 40 #include "opt_ufs.h" 41 #include "opt_quota.h" 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/kernel.h> 46 #include <sys/namei.h> 47 #include <sys/bio.h> 48 #include <sys/buf.h> 49 #include <sys/proc.h> 50 #include <sys/stat.h> 51 #include <sys/mount.h> 52 #include <sys/vnode.h> 53 #include <sys/sysctl.h> 54 55 #include <vm/vm.h> 56 #include <vm/vm_extern.h> 57 58 #include <ufs/ufs/extattr.h> 59 #include <ufs/ufs/quota.h> 60 #include <ufs/ufs/inode.h> 61 #include <ufs/ufs/dir.h> 62 #ifdef UFS_DIRHASH 63 #include <ufs/ufs/dirhash.h> 64 #endif 65 #include <ufs/ufs/ufsmount.h> 66 #include <ufs/ufs/ufs_extern.h> 67 #include <ufs/ffs/ffs_extern.h> 68 69 #ifdef DIAGNOSTIC 70 static int dirchk = 1; 71 #else 72 static int dirchk = 0; 73 #endif 74 75 SYSCTL_INT(_debug, OID_AUTO, dircheck, CTLFLAG_RW, &dirchk, 0, ""); 76 77 static int 78 ufs_delete_denied(struct vnode *vdp, struct vnode *tdp, struct ucred *cred, 79 struct thread *td) 80 { 81 int error; 82 83 #ifdef UFS_ACL 84 /* 85 * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt 86 * 87 * 3.16.2.1. ACE4_DELETE vs. ACE4_DELETE_CHILD 88 */ 89 90 /* 91 * XXX: Is this check required? 92 */ 93 error = VOP_ACCESS(vdp, VEXEC, cred, td); 94 if (error) 95 return (error); 96 97 error = VOP_ACCESSX(tdp, VDELETE, cred, td); 98 if (error == 0) 99 return (0); 100 101 error = VOP_ACCESSX(vdp, VDELETE_CHILD, cred, td); 102 if (error == 0) 103 return (0); 104 105 error = VOP_ACCESSX(vdp, VEXPLICIT_DENY | VDELETE_CHILD, cred, td); 106 if (error) 107 return (error); 108 109 #endif /* !UFS_ACL */ 110 111 /* 112 * Standard Unix access control - delete access requires VWRITE. 113 */ 114 error = VOP_ACCESS(vdp, VWRITE, cred, td); 115 if (error) 116 return (error); 117 118 /* 119 * If directory is "sticky", then user must own 120 * the directory, or the file in it, else she 121 * may not delete it (unless she's root). This 122 * implements append-only directories. 123 */ 124 if ((VTOI(vdp)->i_mode & ISVTX) && 125 VOP_ACCESS(vdp, VADMIN, cred, td) && 126 VOP_ACCESS(tdp, VADMIN, cred, td)) 127 return (EPERM); 128 129 return (0); 130 } 131 132 /* 133 * Convert a component of a pathname into a pointer to a locked inode. 134 * This is a very central and rather complicated routine. 135 * If the filesystem is not maintained in a strict tree hierarchy, 136 * this can result in a deadlock situation (see comments in code below). 137 * 138 * The cnp->cn_nameiop argument is LOOKUP, CREATE, RENAME, or DELETE depending 139 * on whether the name is to be looked up, created, renamed, or deleted. 140 * When CREATE, RENAME, or DELETE is specified, information usable in 141 * creating, renaming, or deleting a directory entry may be calculated. 142 * If flag has LOCKPARENT or'ed into it and the target of the pathname 143 * exists, lookup returns both the target and its parent directory locked. 144 * When creating or renaming and LOCKPARENT is specified, the target may 145 * not be ".". When deleting and LOCKPARENT is specified, the target may 146 * be "."., but the caller must check to ensure it does an vrele and vput 147 * instead of two vputs. 148 * 149 * This routine is actually used as VOP_CACHEDLOOKUP method, and the 150 * filesystem employs the generic vfs_cache_lookup() as VOP_LOOKUP 151 * method. 152 * 153 * vfs_cache_lookup() performs the following for us: 154 * check that it is a directory 155 * check accessibility of directory 156 * check for modification attempts on read-only mounts 157 * if name found in cache 158 * if at end of path and deleting or creating 159 * drop it 160 * else 161 * return name. 162 * return VOP_CACHEDLOOKUP() 163 * 164 * Overall outline of ufs_lookup: 165 * 166 * search for name in directory, to found or notfound 167 * notfound: 168 * if creating, return locked directory, leaving info on available slots 169 * else return error 170 * found: 171 * if at end of path and deleting, return information to allow delete 172 * if at end of path and rewriting (RENAME and LOCKPARENT), lock target 173 * inode and return info to allow rewrite 174 * if not at end, add name to cache; if at end and neither creating 175 * nor deleting, add name to cache 176 */ 177 int 178 ufs_lookup( 179 struct vop_cachedlookup_args /* { 180 struct vnode *a_dvp; 181 struct vnode **a_vpp; 182 struct componentname *a_cnp; 183 } */ *ap) 184 { 185 186 return (ufs_lookup_ino(ap->a_dvp, ap->a_vpp, ap->a_cnp, NULL)); 187 } 188 189 int 190 ufs_lookup_ino(struct vnode *vdp, struct vnode **vpp, struct componentname *cnp, 191 ino_t *dd_ino) 192 { 193 struct inode *dp; /* inode for directory being searched */ 194 struct buf *bp; /* a buffer of directory entries */ 195 struct direct *ep; /* the current directory entry */ 196 int entryoffsetinblock; /* offset of ep in bp's buffer */ 197 enum {NONE, COMPACT, FOUND} slotstatus; 198 doff_t slotoffset; /* offset of area with free space */ 199 doff_t i_diroff; /* cached i_diroff value. */ 200 doff_t i_offset; /* cached i_offset value. */ 201 int slotsize; /* size of area at slotoffset */ 202 int slotfreespace; /* amount of space free in slot */ 203 int slotneeded; /* size of the entry we're seeking */ 204 int numdirpasses; /* strategy for directory search */ 205 doff_t endsearch; /* offset to end directory search */ 206 doff_t prevoff; /* prev entry dp->i_offset */ 207 struct vnode *pdp; /* saved dp during symlink work */ 208 struct vnode *tdp; /* returned by VFS_VGET */ 209 doff_t enduseful; /* pointer past last used dir slot */ 210 uint64_t bmask; /* block offset mask */ 211 int namlen, error; 212 struct ucred *cred = cnp->cn_cred; 213 int flags = cnp->cn_flags; 214 int nameiop = cnp->cn_nameiop; 215 ino_t ino, ino1; 216 int ltype; 217 218 if (vpp != NULL) 219 *vpp = NULL; 220 221 dp = VTOI(vdp); 222 if (dp->i_effnlink == 0) 223 return (ENOENT); 224 225 /* 226 * Create a vm object if vmiodirenable is enabled. 227 * Alternatively we could call vnode_create_vobject 228 * in VFS_VGET but we could end up creating objects 229 * that are never used. 230 */ 231 vnode_create_vobject(vdp, DIP(dp, i_size), curthread); 232 233 bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1; 234 235 #ifdef DEBUG_VFS_LOCKS 236 /* 237 * Assert that the directory vnode is locked, and locked 238 * exclusively for the last component lookup for modifying 239 * operations. 240 * 241 * The directory-modifying operations need to save 242 * intermediate state in the inode between namei() call and 243 * actual directory manipulations. See fields in the struct 244 * inode marked as 'used during directory lookup'. We must 245 * ensure that upgrade in namei() does not happen, since 246 * upgrade might need to unlock vdp. If quotas are enabled, 247 * getinoquota() also requires exclusive lock to modify inode. 248 */ 249 ASSERT_VOP_LOCKED(vdp, "ufs_lookup1"); 250 if ((nameiop == CREATE || nameiop == DELETE || nameiop == RENAME) && 251 (flags & (LOCKPARENT | ISLASTCN)) == (LOCKPARENT | ISLASTCN)) 252 ASSERT_VOP_ELOCKED(vdp, "ufs_lookup2"); 253 #endif 254 255 restart: 256 bp = NULL; 257 slotoffset = -1; 258 259 /* 260 * We now have a segment name to search for, and a directory to search. 261 * 262 * Suppress search for slots unless creating 263 * file and at end of pathname, in which case 264 * we watch for a place to put the new file in 265 * case it doesn't already exist. 266 */ 267 ino = 0; 268 i_diroff = dp->i_diroff; 269 slotstatus = FOUND; 270 slotfreespace = slotsize = slotneeded = 0; 271 if ((nameiop == CREATE || nameiop == RENAME) && 272 (flags & ISLASTCN)) { 273 slotstatus = NONE; 274 slotneeded = DIRECTSIZ(cnp->cn_namelen); 275 } 276 277 #ifdef UFS_DIRHASH 278 /* 279 * Use dirhash for fast operations on large directories. The logic 280 * to determine whether to hash the directory is contained within 281 * ufsdirhash_build(); a zero return means that it decided to hash 282 * this directory and it successfully built up the hash table. 283 */ 284 if (ufsdirhash_build(dp) == 0) { 285 /* Look for a free slot if needed. */ 286 enduseful = dp->i_size; 287 if (slotstatus != FOUND) { 288 slotoffset = ufsdirhash_findfree(dp, slotneeded, 289 &slotsize); 290 if (slotoffset >= 0) { 291 slotstatus = COMPACT; 292 enduseful = ufsdirhash_enduseful(dp); 293 if (enduseful < 0) 294 enduseful = dp->i_size; 295 } 296 } 297 /* Look up the component. */ 298 numdirpasses = 1; 299 entryoffsetinblock = 0; /* silence compiler warning */ 300 switch (ufsdirhash_lookup(dp, cnp->cn_nameptr, cnp->cn_namelen, 301 &i_offset, &bp, nameiop == DELETE ? &prevoff : NULL)) { 302 case 0: 303 ep = (struct direct *)((char *)bp->b_data + 304 (i_offset & bmask)); 305 goto foundentry; 306 case ENOENT: 307 i_offset = roundup2(dp->i_size, DIRBLKSIZ); 308 goto notfound; 309 default: 310 /* Something failed; just do a linear search. */ 311 break; 312 } 313 } 314 #endif /* UFS_DIRHASH */ 315 /* 316 * If there is cached information on a previous search of 317 * this directory, pick up where we last left off. 318 * We cache only lookups as these are the most common 319 * and have the greatest payoff. Caching CREATE has little 320 * benefit as it usually must search the entire directory 321 * to determine that the entry does not exist. Caching the 322 * location of the last DELETE or RENAME has not reduced 323 * profiling time and hence has been removed in the interest 324 * of simplicity. 325 */ 326 if (nameiop != LOOKUP || i_diroff == 0 || i_diroff >= dp->i_size) { 327 entryoffsetinblock = 0; 328 i_offset = 0; 329 numdirpasses = 1; 330 } else { 331 i_offset = i_diroff; 332 if ((entryoffsetinblock = i_offset & bmask) && 333 (error = UFS_BLKATOFF(vdp, (off_t)i_offset, NULL, &bp))) 334 return (error); 335 numdirpasses = 2; 336 nchstats.ncs_2passes++; 337 } 338 prevoff = i_offset; 339 endsearch = roundup2(dp->i_size, DIRBLKSIZ); 340 enduseful = 0; 341 342 searchloop: 343 while (i_offset < endsearch) { 344 /* 345 * If necessary, get the next directory block. 346 */ 347 if ((i_offset & bmask) == 0) { 348 if (bp != NULL) 349 brelse(bp); 350 error = 351 UFS_BLKATOFF(vdp, (off_t)i_offset, NULL, &bp); 352 if (error) 353 return (error); 354 entryoffsetinblock = 0; 355 } 356 /* 357 * If still looking for a slot, and at a DIRBLKSIZE 358 * boundary, have to start looking for free space again. 359 */ 360 if (slotstatus == NONE && 361 (entryoffsetinblock & (DIRBLKSIZ - 1)) == 0) { 362 slotoffset = -1; 363 slotfreespace = 0; 364 } 365 /* 366 * Get pointer to next entry. 367 * Full validation checks are slow, so we only check 368 * enough to insure forward progress through the 369 * directory. Complete checks can be run by patching 370 * "dirchk" to be true. 371 */ 372 ep = (struct direct *)((char *)bp->b_data + entryoffsetinblock); 373 if (ep->d_reclen == 0 || ep->d_reclen > 374 DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) || 375 (dirchk && ufs_dirbadentry(vdp, ep, entryoffsetinblock))) { 376 int i; 377 378 ufs_dirbad(dp, i_offset, "mangled entry"); 379 i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)); 380 i_offset += i; 381 entryoffsetinblock += i; 382 continue; 383 } 384 385 /* 386 * If an appropriate sized slot has not yet been found, 387 * check to see if one is available. Also accumulate space 388 * in the current block so that we can determine if 389 * compaction is viable. 390 */ 391 if (slotstatus != FOUND) { 392 int size = ep->d_reclen; 393 394 if (ep->d_ino != 0) 395 size -= DIRSIZ(OFSFMT(vdp), ep); 396 if (size > 0) { 397 if (size >= slotneeded) { 398 slotstatus = FOUND; 399 slotoffset = i_offset; 400 slotsize = ep->d_reclen; 401 } else if (slotstatus == NONE) { 402 slotfreespace += size; 403 if (slotoffset == -1) 404 slotoffset = i_offset; 405 if (slotfreespace >= slotneeded) { 406 slotstatus = COMPACT; 407 slotsize = i_offset + 408 ep->d_reclen - slotoffset; 409 } 410 } 411 } 412 } 413 414 /* 415 * Check for a name match. 416 */ 417 if (ep->d_ino) { 418 # if (BYTE_ORDER == LITTLE_ENDIAN) 419 if (OFSFMT(vdp)) 420 namlen = ep->d_type; 421 else 422 namlen = ep->d_namlen; 423 # else 424 namlen = ep->d_namlen; 425 # endif 426 if (namlen == cnp->cn_namelen && 427 (cnp->cn_nameptr[0] == ep->d_name[0]) && 428 !bcmp(cnp->cn_nameptr, ep->d_name, 429 (unsigned)namlen)) { 430 #ifdef UFS_DIRHASH 431 foundentry: 432 #endif 433 /* 434 * Save directory entry's inode number and 435 * reclen in ndp->ni_ufs area, and release 436 * directory buffer. 437 */ 438 if (!OFSFMT(vdp) && ep->d_type == DT_WHT) { 439 slotstatus = FOUND; 440 slotoffset = i_offset; 441 slotsize = ep->d_reclen; 442 enduseful = dp->i_size; 443 cnp->cn_flags |= ISWHITEOUT; 444 numdirpasses--; 445 goto notfound; 446 } 447 ino = ep->d_ino; 448 goto found; 449 } 450 } 451 prevoff = i_offset; 452 i_offset += ep->d_reclen; 453 entryoffsetinblock += ep->d_reclen; 454 if (ep->d_ino) 455 enduseful = i_offset; 456 } 457 notfound: 458 /* 459 * If we started in the middle of the directory and failed 460 * to find our target, we must check the beginning as well. 461 */ 462 if (numdirpasses == 2) { 463 numdirpasses--; 464 i_offset = 0; 465 endsearch = i_diroff; 466 goto searchloop; 467 } 468 if (bp != NULL) 469 brelse(bp); 470 /* 471 * If creating, and at end of pathname and current 472 * directory has not been removed, then can consider 473 * allowing file to be created. 474 */ 475 if ((nameiop == CREATE || nameiop == RENAME || 476 (nameiop == DELETE && 477 (cnp->cn_flags & DOWHITEOUT) && 478 (cnp->cn_flags & ISWHITEOUT))) && 479 (flags & ISLASTCN) && dp->i_effnlink != 0) { 480 /* 481 * Access for write is interpreted as allowing 482 * creation of files in the directory. 483 * 484 * XXX: Fix the comment above. 485 */ 486 if (flags & WILLBEDIR) 487 error = VOP_ACCESSX(vdp, VWRITE | VAPPEND, cred, curthread); 488 else 489 error = VOP_ACCESS(vdp, VWRITE, cred, curthread); 490 if (error) 491 return (error); 492 /* 493 * Return an indication of where the new directory 494 * entry should be put. If we didn't find a slot, 495 * then set dp->i_count to 0 indicating 496 * that the new slot belongs at the end of the 497 * directory. If we found a slot, then the new entry 498 * can be put in the range from dp->i_offset to 499 * dp->i_offset + dp->i_count. 500 */ 501 if (slotstatus == NONE) { 502 SET_I_OFFSET(dp, roundup2(dp->i_size, DIRBLKSIZ)); 503 SET_I_COUNT(dp, 0); 504 enduseful = I_OFFSET(dp); 505 } else if (nameiop == DELETE) { 506 SET_I_OFFSET(dp, slotoffset); 507 if ((I_OFFSET(dp) & (DIRBLKSIZ - 1)) == 0) 508 SET_I_COUNT(dp, 0); 509 else 510 SET_I_COUNT(dp, I_OFFSET(dp) - prevoff); 511 } else { 512 SET_I_OFFSET(dp, slotoffset); 513 SET_I_COUNT(dp, slotsize); 514 if (enduseful < slotoffset + slotsize) 515 enduseful = slotoffset + slotsize; 516 } 517 SET_I_ENDOFF(dp, roundup2(enduseful, DIRBLKSIZ)); 518 /* 519 * We return with the directory locked, so that 520 * the parameters we set up above will still be 521 * valid if we actually decide to do a direnter(). 522 * We return ni_vp == NULL to indicate that the entry 523 * does not currently exist; we leave a pointer to 524 * the (locked) directory inode in ndp->ni_dvp. 525 * 526 * NB - if the directory is unlocked, then this 527 * information cannot be used. 528 */ 529 return (EJUSTRETURN); 530 } 531 /* 532 * Insert name into cache (as non-existent) if appropriate. 533 */ 534 if ((cnp->cn_flags & MAKEENTRY) != 0) 535 cache_enter(vdp, NULL, cnp); 536 return (ENOENT); 537 538 found: 539 if (dd_ino != NULL) 540 *dd_ino = ino; 541 if (numdirpasses == 2) 542 nchstats.ncs_pass2++; 543 /* 544 * Check that directory length properly reflects presence 545 * of this entry. 546 */ 547 if (i_offset + DIRSIZ(OFSFMT(vdp), ep) > dp->i_size) { 548 ufs_dirbad(dp, i_offset, "i_size too small"); 549 brelse(bp); 550 return (EIO); 551 } 552 brelse(bp); 553 554 /* 555 * Found component in pathname. 556 * If the final component of path name, save information 557 * in the cache as to where the entry was found. 558 */ 559 if ((flags & ISLASTCN) && nameiop == LOOKUP) 560 dp->i_diroff = rounddown2(i_offset, DIRBLKSIZ); 561 562 /* 563 * If deleting, and at end of pathname, return 564 * parameters which can be used to remove file. 565 */ 566 if (nameiop == DELETE && (flags & ISLASTCN)) { 567 if (flags & LOCKPARENT) 568 ASSERT_VOP_ELOCKED(vdp, __FUNCTION__); 569 570 if (VOP_ISLOCKED(vdp) == LK_EXCLUSIVE) { 571 /* 572 * Return pointer to current entry in 573 * dp->i_offset, and distance past previous 574 * entry (if there is a previous entry in this 575 * block) in dp->i_count. 576 * 577 * We shouldn't be setting these in the 578 * WANTPARENT case (first lookup in rename()), but any 579 * lookups that will result in directory changes will 580 * overwrite these. 581 */ 582 SET_I_OFFSET(dp, i_offset); 583 if ((I_OFFSET(dp) & (DIRBLKSIZ - 1)) == 0) 584 SET_I_COUNT(dp, 0); 585 else 586 SET_I_COUNT(dp, I_OFFSET(dp) - prevoff); 587 } 588 if (dd_ino != NULL) 589 return (0); 590 591 /* 592 * Save directory inode pointer in ndp->ni_dvp for 593 * dirremove(). 594 */ 595 if ((error = VFS_VGET(vdp->v_mount, ino, 596 LK_EXCLUSIVE, &tdp)) != 0) 597 return (error); 598 error = ufs_delete_denied(vdp, tdp, cred, curthread); 599 if (error) { 600 vput(tdp); 601 return (error); 602 } 603 if (dp->i_number == ino) { 604 VREF(vdp); 605 *vpp = vdp; 606 vput(tdp); 607 return (0); 608 } 609 610 *vpp = tdp; 611 return (0); 612 } 613 614 /* 615 * If rewriting (RENAME), return the inode and the 616 * information required to rewrite the present directory 617 * Must get inode of directory entry to verify it's a 618 * regular file, or empty directory. 619 */ 620 if (nameiop == RENAME && (flags & ISLASTCN)) { 621 if (flags & WILLBEDIR) 622 error = VOP_ACCESSX(vdp, VWRITE | VAPPEND, cred, curthread); 623 else 624 error = VOP_ACCESS(vdp, VWRITE, cred, curthread); 625 if (error) 626 return (error); 627 /* 628 * Careful about locking second inode. 629 * This can only occur if the target is ".". 630 */ 631 SET_I_OFFSET(dp, i_offset); 632 if (dp->i_number == ino) 633 return (EISDIR); 634 if (dd_ino != NULL) 635 return (0); 636 if ((error = VFS_VGET(vdp->v_mount, ino, 637 LK_EXCLUSIVE, &tdp)) != 0) 638 return (error); 639 640 error = ufs_delete_denied(vdp, tdp, cred, curthread); 641 if (error) { 642 vput(tdp); 643 return (error); 644 } 645 646 #ifdef SunOS_doesnt_do_that 647 /* 648 * The only purpose of this check is to return the correct 649 * error. Assume that we want to rename directory "a" 650 * to a file "b", and that we have no ACL_WRITE_DATA on 651 * a containing directory, but we _do_ have ACL_APPEND_DATA. 652 * In that case, the VOP_ACCESS check above will return 0, 653 * and the operation will fail with ENOTDIR instead 654 * of EACCESS. 655 */ 656 if (tdp->v_type == VDIR) 657 error = VOP_ACCESSX(vdp, VWRITE | VAPPEND, cred, curthread); 658 else 659 error = VOP_ACCESS(vdp, VWRITE, cred, curthread); 660 if (error) { 661 vput(tdp); 662 return (error); 663 } 664 #endif 665 666 *vpp = tdp; 667 return (0); 668 } 669 if (dd_ino != NULL) 670 return (0); 671 672 /* 673 * Step through the translation in the name. We do not `vput' the 674 * directory because we may need it again if a symbolic link 675 * is relative to the current directory. Instead we save it 676 * unlocked as "pdp". We must get the target inode before unlocking 677 * the directory to insure that the inode will not be removed 678 * before we get it. We prevent deadlock by always fetching 679 * inodes from the root, moving down the directory tree. Thus 680 * when following backward pointers ".." we must unlock the 681 * parent directory before getting the requested directory. 682 * There is a potential race condition here if both the current 683 * and parent directories are removed before the VFS_VGET for the 684 * inode associated with ".." returns. We hope that this occurs 685 * infrequently since we cannot avoid this race condition without 686 * implementing a sophisticated deadlock detection algorithm. 687 * Note also that this simple deadlock detection scheme will not 688 * work if the filesystem has any hard links other than ".." 689 * that point backwards in the directory structure. 690 */ 691 pdp = vdp; 692 if (flags & ISDOTDOT) { 693 error = vn_vget_ino(pdp, ino, cnp->cn_lkflags, &tdp); 694 if (error) 695 return (error); 696 697 /* 698 * Recheck that ".." entry in the vdp directory points 699 * to the inode we looked up before vdp lock was 700 * dropped. 701 */ 702 error = ufs_lookup_ino(pdp, NULL, cnp, &ino1); 703 if (error) { 704 vput(tdp); 705 return (error); 706 } 707 if (ino1 != ino) { 708 vput(tdp); 709 goto restart; 710 } 711 712 *vpp = tdp; 713 } else if (dp->i_number == ino) { 714 VREF(vdp); /* we want ourself, ie "." */ 715 /* 716 * When we lookup "." we still can be asked to lock it 717 * differently. 718 */ 719 ltype = cnp->cn_lkflags & LK_TYPE_MASK; 720 if (ltype != VOP_ISLOCKED(vdp)) { 721 if (ltype == LK_EXCLUSIVE) 722 vn_lock(vdp, LK_UPGRADE | LK_RETRY); 723 else /* if (ltype == LK_SHARED) */ 724 vn_lock(vdp, LK_DOWNGRADE | LK_RETRY); 725 /* 726 * Relock for the "." case may left us with 727 * reclaimed vnode. 728 */ 729 if (VN_IS_DOOMED(vdp)) { 730 vrele(vdp); 731 return (ENOENT); 732 } 733 } 734 *vpp = vdp; 735 } else { 736 error = VFS_VGET(pdp->v_mount, ino, cnp->cn_lkflags, &tdp); 737 if (error == 0 && VTOI(tdp)->i_mode == 0) { 738 vgone(tdp); 739 vput(tdp); 740 error = ENOENT; 741 } 742 if (error) 743 return (error); 744 *vpp = tdp; 745 } 746 747 /* 748 * Insert name into cache if appropriate. 749 */ 750 if (cnp->cn_flags & MAKEENTRY) 751 cache_enter(vdp, *vpp, cnp); 752 return (0); 753 } 754 755 void 756 ufs_dirbad(struct inode *ip, doff_t offset, char *how) 757 { 758 759 (void)printf("%s: bad dir ino %ju at offset %ld: %s\n", 760 ITOV(ip)->v_mount->mnt_stat.f_mntonname, (uintmax_t)ip->i_number, 761 (long)offset, how); 762 } 763 764 /* 765 * Do consistency checking on a directory entry: 766 * record length must be multiple of 4 767 * entry must fit in rest of its DIRBLKSIZ block 768 * record must be large enough to contain entry 769 * name is not longer than UFS_MAXNAMLEN 770 * name must be as long as advertised, and null terminated 771 */ 772 int 773 ufs_dirbadentry(struct vnode *dp, struct direct *ep, int entryoffsetinblock) 774 { 775 int i, namlen; 776 777 # if (BYTE_ORDER == LITTLE_ENDIAN) 778 if (OFSFMT(dp)) 779 namlen = ep->d_type; 780 else 781 namlen = ep->d_namlen; 782 # else 783 namlen = ep->d_namlen; 784 # endif 785 if ((ep->d_reclen & 0x3) != 0 || 786 ep->d_reclen > DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) || 787 ep->d_reclen < DIRSIZ(OFSFMT(dp), ep) || namlen > UFS_MAXNAMLEN) { 788 /*return (1); */ 789 printf("First bad\n"); 790 goto bad; 791 } 792 if (ep->d_ino == 0) 793 return (0); 794 for (i = 0; i < namlen; i++) 795 if (ep->d_name[i] == '\0') { 796 /*return (1); */ 797 printf("Second bad\n"); 798 goto bad; 799 } 800 if (ep->d_name[i]) 801 goto bad; 802 return (0); 803 bad: 804 return (1); 805 } 806 807 /* 808 * Construct a new directory entry after a call to namei, using the 809 * parameters that it left in the componentname argument cnp. The 810 * argument ip is the inode to which the new directory entry will refer. 811 */ 812 void 813 ufs_makedirentry(struct inode *ip, struct componentname *cnp, 814 struct direct *newdirp) 815 { 816 uint64_t namelen; 817 818 namelen = (unsigned)cnp->cn_namelen; 819 KASSERT(namelen <= UFS_MAXNAMLEN, 820 ("ufs_makedirentry: name too long")); 821 newdirp->d_ino = ip->i_number; 822 newdirp->d_namlen = namelen; 823 824 /* Zero out after-name padding */ 825 *(uint32_t *)(&newdirp->d_name[namelen & ~(DIR_ROUNDUP - 1)]) = 0; 826 827 bcopy(cnp->cn_nameptr, newdirp->d_name, namelen); 828 829 if (!OFSFMT(ITOV(ip))) 830 newdirp->d_type = IFTODT(ip->i_mode); 831 else { 832 newdirp->d_type = 0; 833 # if (BYTE_ORDER == LITTLE_ENDIAN) 834 { uint8_t tmp = newdirp->d_namlen; 835 newdirp->d_namlen = newdirp->d_type; 836 newdirp->d_type = tmp; } 837 # endif 838 } 839 } 840 841 /* 842 * Write a directory entry after a call to namei, using the parameters 843 * that it left in nameidata. The argument dirp is the new directory 844 * entry contents. Dvp is a pointer to the directory to be written, 845 * which was left locked by namei. Remaining parameters (dp->i_offset, 846 * dp->i_count) indicate how the space for the new entry is to be obtained. 847 * Non-null bp indicates that a directory is being created (for the 848 * soft dependency code). 849 */ 850 int 851 ufs_direnter(struct vnode *dvp, struct vnode *tvp, struct direct *dirp, 852 struct componentname *cnp, struct buf *newdirbp) 853 { 854 struct ucred *cr; 855 struct thread *td; 856 int newentrysize; 857 struct inode *dp; 858 struct buf *bp; 859 uint64_t dsize; 860 struct direct *ep, *nep; 861 uint64_t old_isize; 862 int error, ret, blkoff, loc, spacefree, flags, namlen; 863 char *dirbuf; 864 865 td = curthread; /* XXX */ 866 cr = td->td_ucred; 867 868 dp = VTOI(dvp); 869 newentrysize = DIRSIZ(OFSFMT(dvp), dirp); 870 871 if (I_COUNT(dp) == 0) { 872 /* 873 * If dp->i_count is 0, then namei could find no 874 * space in the directory. Here, dp->i_offset will 875 * be on a directory block boundary and we will write the 876 * new entry into a fresh block. 877 */ 878 if (I_OFFSET(dp) & (DIRBLKSIZ - 1)) 879 panic("ufs_direnter: newblk"); 880 flags = BA_CLRBUF; 881 if (!DOINGSOFTDEP(dvp) && !DOINGASYNC(dvp)) 882 flags |= IO_SYNC; 883 #ifdef QUOTA 884 if ((error = getinoquota(dp)) != 0) { 885 if (DOINGSOFTDEP(dvp) && newdirbp != NULL) 886 bdwrite(newdirbp); 887 return (error); 888 } 889 #endif 890 old_isize = dp->i_size; 891 vnode_pager_setsize(dvp, 892 (vm_ooffset_t)I_OFFSET(dp) + DIRBLKSIZ); 893 if ((error = UFS_BALLOC(dvp, (off_t)I_OFFSET(dp), DIRBLKSIZ, 894 cr, flags, &bp)) != 0) { 895 if (DOINGSOFTDEP(dvp) && newdirbp != NULL) 896 bdwrite(newdirbp); 897 vnode_pager_setsize(dvp, (vm_ooffset_t)old_isize); 898 return (error); 899 } 900 dp->i_size = I_OFFSET(dp) + DIRBLKSIZ; 901 DIP_SET(dp, i_size, dp->i_size); 902 SET_I_ENDOFF(dp, dp->i_size); 903 UFS_INODE_SET_FLAG(dp, IN_SIZEMOD | IN_CHANGE | IN_UPDATE); 904 dirp->d_reclen = DIRBLKSIZ; 905 blkoff = I_OFFSET(dp) & 906 (VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_iosize - 1); 907 bcopy((caddr_t)dirp, (caddr_t)bp->b_data + blkoff,newentrysize); 908 #ifdef UFS_DIRHASH 909 if (dp->i_dirhash != NULL) { 910 ufsdirhash_newblk(dp, I_OFFSET(dp)); 911 ufsdirhash_add(dp, dirp, I_OFFSET(dp)); 912 ufsdirhash_checkblock(dp, (char *)bp->b_data + blkoff, 913 I_OFFSET(dp)); 914 } 915 #endif 916 if (DOINGSOFTDEP(dvp)) { 917 /* 918 * Ensure that the entire newly allocated block is a 919 * valid directory so that future growth within the 920 * block does not have to ensure that the block is 921 * written before the inode. 922 */ 923 blkoff += DIRBLKSIZ; 924 while (blkoff < bp->b_bcount) { 925 ((struct direct *) 926 (bp->b_data + blkoff))->d_reclen = DIRBLKSIZ; 927 blkoff += DIRBLKSIZ; 928 } 929 if (softdep_setup_directory_add(bp, dp, I_OFFSET(dp), 930 dirp->d_ino, newdirbp, 1)) 931 UFS_INODE_SET_FLAG(dp, IN_NEEDSYNC); 932 if (newdirbp) 933 bdwrite(newdirbp); 934 bdwrite(bp); 935 return (UFS_UPDATE(dvp, 0)); 936 } 937 if (DOINGASYNC(dvp)) { 938 bdwrite(bp); 939 return (UFS_UPDATE(dvp, 0)); 940 } 941 error = bwrite(bp); 942 ret = UFS_UPDATE(dvp, 1); 943 if (error == 0) 944 return (ret); 945 return (error); 946 } 947 948 /* 949 * If dp->i_count is non-zero, then namei found space for the new 950 * entry in the range dp->i_offset to dp->i_offset + dp->i_count 951 * in the directory. To use this space, we may have to compact 952 * the entries located there, by copying them together towards the 953 * beginning of the block, leaving the free space in one usable 954 * chunk at the end. 955 */ 956 957 /* 958 * Increase size of directory if entry eats into new space. 959 * This should never push the size past a new multiple of 960 * DIRBLKSIZE. 961 * 962 * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN. 963 */ 964 if (I_OFFSET(dp) + I_COUNT(dp) > dp->i_size) { 965 dp->i_size = I_OFFSET(dp) + I_COUNT(dp); 966 DIP_SET(dp, i_size, dp->i_size); 967 UFS_INODE_SET_FLAG(dp, IN_SIZEMOD | IN_MODIFIED); 968 } 969 /* 970 * Get the block containing the space for the new directory entry. 971 */ 972 error = UFS_BLKATOFF(dvp, (off_t)I_OFFSET(dp), &dirbuf, &bp); 973 if (error) { 974 if (DOINGSOFTDEP(dvp) && newdirbp != NULL) 975 bdwrite(newdirbp); 976 return (error); 977 } 978 /* 979 * Find space for the new entry. In the simple case, the entry at 980 * offset base will have the space. If it does not, then namei 981 * arranged that compacting the region dp->i_offset to 982 * dp->i_offset + dp->i_count would yield the space. 983 */ 984 ep = (struct direct *)dirbuf; 985 dsize = ep->d_ino ? DIRSIZ(OFSFMT(dvp), ep) : 0; 986 spacefree = ep->d_reclen - dsize; 987 for (loc = ep->d_reclen; loc < I_COUNT(dp); ) { 988 nep = (struct direct *)(dirbuf + loc); 989 990 /* Trim the existing slot (NB: dsize may be zero). */ 991 ep->d_reclen = dsize; 992 ep = (struct direct *)((char *)ep + dsize); 993 994 /* Read nep->d_reclen now as the bcopy() may clobber it. */ 995 loc += nep->d_reclen; 996 if (nep->d_ino == 0) { 997 /* 998 * A mid-block unused entry. Such entries are 999 * never created by the kernel, but fsck_ffs 1000 * can create them (and it doesn't fix them). 1001 * 1002 * Add up the free space, and initialise the 1003 * relocated entry since we don't bcopy it. 1004 */ 1005 spacefree += nep->d_reclen; 1006 ep->d_ino = 0; 1007 dsize = 0; 1008 continue; 1009 } 1010 dsize = DIRSIZ(OFSFMT(dvp), nep); 1011 spacefree += nep->d_reclen - dsize; 1012 #ifdef UFS_DIRHASH 1013 if (dp->i_dirhash != NULL) 1014 ufsdirhash_move(dp, nep, 1015 I_OFFSET(dp) + ((char *)nep - dirbuf), 1016 I_OFFSET(dp) + ((char *)ep - dirbuf)); 1017 #endif 1018 if (DOINGSOFTDEP(dvp)) 1019 softdep_change_directoryentry_offset(bp, dp, dirbuf, 1020 (caddr_t)nep, (caddr_t)ep, dsize); 1021 else 1022 bcopy((caddr_t)nep, (caddr_t)ep, dsize); 1023 } 1024 /* 1025 * Here, `ep' points to a directory entry containing `dsize' in-use 1026 * bytes followed by `spacefree' unused bytes. If ep->d_ino == 0, 1027 * then the entry is completely unused (dsize == 0). The value 1028 * of ep->d_reclen is always indeterminate. 1029 * 1030 * Update the pointer fields in the previous entry (if any), 1031 * copy in the new entry, and write out the block. 1032 */ 1033 # if (BYTE_ORDER == LITTLE_ENDIAN) 1034 if (OFSFMT(dvp)) 1035 namlen = ep->d_type; 1036 else 1037 namlen = ep->d_namlen; 1038 # else 1039 namlen = ep->d_namlen; 1040 # endif 1041 if (ep->d_ino == 0 || 1042 (ep->d_ino == UFS_WINO && namlen == dirp->d_namlen && 1043 bcmp(ep->d_name, dirp->d_name, dirp->d_namlen) == 0)) { 1044 if (spacefree + dsize < newentrysize) 1045 panic("ufs_direnter: compact1"); 1046 dirp->d_reclen = spacefree + dsize; 1047 } else { 1048 if (spacefree < newentrysize) 1049 panic("ufs_direnter: compact2"); 1050 dirp->d_reclen = spacefree; 1051 ep->d_reclen = dsize; 1052 ep = (struct direct *)((char *)ep + dsize); 1053 } 1054 #ifdef UFS_DIRHASH 1055 if (dp->i_dirhash != NULL && (ep->d_ino == 0 || 1056 dirp->d_reclen == spacefree)) 1057 ufsdirhash_add(dp, dirp, I_OFFSET(dp) + ((char *)ep - dirbuf)); 1058 #endif 1059 bcopy((caddr_t)dirp, (caddr_t)ep, (uint64_t)newentrysize); 1060 #ifdef UFS_DIRHASH 1061 if (dp->i_dirhash != NULL) 1062 ufsdirhash_checkblock(dp, dirbuf - 1063 (I_OFFSET(dp) & (DIRBLKSIZ - 1)), 1064 rounddown2(I_OFFSET(dp), DIRBLKSIZ)); 1065 #endif 1066 1067 if (DOINGSOFTDEP(dvp)) { 1068 (void) softdep_setup_directory_add(bp, dp, 1069 I_OFFSET(dp) + (caddr_t)ep - dirbuf, 1070 dirp->d_ino, newdirbp, 0); 1071 if (newdirbp != NULL) 1072 bdwrite(newdirbp); 1073 bdwrite(bp); 1074 } else { 1075 if (DOINGASYNC(dvp)) { 1076 bdwrite(bp); 1077 error = 0; 1078 } else { 1079 error = bwrite(bp); 1080 } 1081 } 1082 1083 /* 1084 * If all went well, and the directory can be shortened, 1085 * mark directory inode with the truncation request. 1086 */ 1087 UFS_INODE_SET_FLAG(dp, IN_CHANGE | IN_UPDATE | (error == 0 && 1088 I_ENDOFF(dp) != 0 && I_ENDOFF(dp) < dp->i_size ? IN_ENDOFF : 0)); 1089 1090 return (error); 1091 } 1092 1093 /* 1094 * Remove a directory entry after a call to namei, using 1095 * the parameters which it left in nameidata. The entry 1096 * dp->i_offset contains the offset into the directory of the 1097 * entry to be eliminated. The dp->i_count field contains the 1098 * size of the previous record in the directory. If this 1099 * is 0, the first entry is being deleted, so we need only 1100 * zero the inode number to mark the entry as free. If the 1101 * entry is not the first in the directory, we must reclaim 1102 * the space of the now empty record by adding the record size 1103 * to the size of the previous entry. 1104 */ 1105 int 1106 ufs_dirremove(struct vnode *dvp, struct inode *ip, int flags, int isrmdir) 1107 { 1108 struct inode *dp; 1109 struct direct *ep, *rep; 1110 struct buf *bp; 1111 off_t offset; 1112 int error; 1113 1114 dp = VTOI(dvp); 1115 1116 /* 1117 * Adjust the link count early so softdep can block if necessary. 1118 */ 1119 if (ip) { 1120 ip->i_effnlink--; 1121 UFS_INODE_SET_FLAG(ip, IN_CHANGE); 1122 if (DOINGSOFTDEP(dvp)) { 1123 softdep_setup_unlink(dp, ip); 1124 } else { 1125 ip->i_nlink--; 1126 DIP_SET(ip, i_nlink, ip->i_nlink); 1127 UFS_INODE_SET_FLAG(ip, IN_CHANGE); 1128 } 1129 } 1130 if (flags & DOWHITEOUT) 1131 offset = I_OFFSET(dp); 1132 else 1133 offset = I_OFFSET(dp) - I_COUNT(dp); 1134 if ((error = UFS_BLKATOFF(dvp, offset, (char **)&ep, &bp)) != 0) { 1135 if (ip) { 1136 ip->i_effnlink++; 1137 UFS_INODE_SET_FLAG(ip, IN_CHANGE); 1138 if (DOINGSOFTDEP(dvp)) { 1139 softdep_change_linkcnt(ip); 1140 } else { 1141 ip->i_nlink++; 1142 DIP_SET(ip, i_nlink, ip->i_nlink); 1143 UFS_INODE_SET_FLAG(ip, IN_CHANGE); 1144 } 1145 } 1146 return (error); 1147 } 1148 if (flags & DOWHITEOUT) { 1149 /* 1150 * Whiteout entry: set d_ino to UFS_WINO. 1151 */ 1152 ep->d_ino = UFS_WINO; 1153 ep->d_type = DT_WHT; 1154 goto out; 1155 } 1156 /* Set 'rep' to the entry being removed. */ 1157 if (I_COUNT(dp) == 0) 1158 rep = ep; 1159 else 1160 rep = (struct direct *)((char *)ep + ep->d_reclen); 1161 #ifdef UFS_DIRHASH 1162 /* 1163 * Remove the dirhash entry. This is complicated by the fact 1164 * that `ep' is the previous entry when dp->i_count != 0. 1165 */ 1166 if (dp->i_dirhash != NULL) 1167 ufsdirhash_remove(dp, rep, I_OFFSET(dp)); 1168 #endif 1169 if (ip && rep->d_ino != ip->i_number) 1170 panic("ufs_dirremove: ip %ju does not match dirent ino %ju\n", 1171 (uintmax_t)ip->i_number, (uintmax_t)rep->d_ino); 1172 /* 1173 * Zero out the file directory entry metadata to reduce disk 1174 * scavenging disclosure. 1175 */ 1176 bzero(&rep->d_name[0], rep->d_namlen); 1177 rep->d_namlen = 0; 1178 rep->d_type = 0; 1179 rep->d_ino = 0; 1180 1181 if (I_COUNT(dp) != 0) { 1182 /* 1183 * Collapse new free space into previous entry. 1184 */ 1185 ep->d_reclen += rep->d_reclen; 1186 rep->d_reclen = 0; 1187 } 1188 #ifdef UFS_DIRHASH 1189 if (dp->i_dirhash != NULL) 1190 ufsdirhash_checkblock(dp, (char *)ep - 1191 ((I_OFFSET(dp) - I_COUNT(dp)) & (DIRBLKSIZ - 1)), 1192 rounddown2(I_OFFSET(dp), DIRBLKSIZ)); 1193 #endif 1194 out: 1195 error = 0; 1196 if (DOINGSOFTDEP(dvp)) { 1197 if (ip) 1198 softdep_setup_remove(bp, dp, ip, isrmdir); 1199 if (softdep_slowdown(dvp)) 1200 error = bwrite(bp); 1201 else 1202 bdwrite(bp); 1203 } else { 1204 if (flags & DOWHITEOUT) 1205 error = bwrite(bp); 1206 else if (DOINGASYNC(dvp)) 1207 bdwrite(bp); 1208 else 1209 error = bwrite(bp); 1210 } 1211 UFS_INODE_SET_FLAG(dp, IN_CHANGE | IN_UPDATE); 1212 /* 1213 * If the last named reference to a snapshot goes away, 1214 * drop its snapshot reference so that it will be reclaimed 1215 * when last open reference goes away. 1216 */ 1217 if (ip != NULL && IS_SNAPSHOT(ip) && ip->i_effnlink == 0) 1218 UFS_SNAPGONE(ip); 1219 return (error); 1220 } 1221 1222 /* 1223 * Rewrite an existing directory entry to point at the inode 1224 * supplied. The parameters describing the directory entry are 1225 * set up by a call to namei. 1226 */ 1227 int 1228 ufs_dirrewrite(struct inode *dp, struct inode *oip, ino_t newinum, int newtype, 1229 int isrmdir) 1230 { 1231 struct buf *bp; 1232 struct direct *ep; 1233 struct vnode *vdp = ITOV(dp); 1234 int error; 1235 1236 /* 1237 * Drop the link before we lock the buf so softdep can block if 1238 * necessary. 1239 */ 1240 oip->i_effnlink--; 1241 UFS_INODE_SET_FLAG(oip, IN_CHANGE); 1242 if (DOINGSOFTDEP(vdp)) { 1243 softdep_setup_unlink(dp, oip); 1244 } else { 1245 oip->i_nlink--; 1246 DIP_SET(oip, i_nlink, oip->i_nlink); 1247 UFS_INODE_SET_FLAG(oip, IN_CHANGE); 1248 } 1249 1250 error = UFS_BLKATOFF(vdp, (off_t)I_OFFSET(dp), (char **)&ep, &bp); 1251 if (error == 0 && ep->d_namlen == 2 && ep->d_name[1] == '.' && 1252 ep->d_name[0] == '.' && ep->d_ino != oip->i_number) { 1253 brelse(bp); 1254 error = EIDRM; 1255 } 1256 if (error) { 1257 oip->i_effnlink++; 1258 UFS_INODE_SET_FLAG(oip, IN_CHANGE); 1259 if (DOINGSOFTDEP(vdp)) { 1260 softdep_change_linkcnt(oip); 1261 } else { 1262 oip->i_nlink++; 1263 DIP_SET(oip, i_nlink, oip->i_nlink); 1264 UFS_INODE_SET_FLAG(oip, IN_CHANGE); 1265 } 1266 return (error); 1267 } 1268 ep->d_ino = newinum; 1269 if (!OFSFMT(vdp)) 1270 ep->d_type = newtype; 1271 if (DOINGSOFTDEP(vdp)) { 1272 softdep_setup_directory_change(bp, dp, oip, newinum, isrmdir); 1273 bdwrite(bp); 1274 } else { 1275 if (DOINGASYNC(vdp)) { 1276 bdwrite(bp); 1277 error = 0; 1278 } else { 1279 error = bwrite(bp); 1280 } 1281 } 1282 UFS_INODE_SET_FLAG(dp, IN_CHANGE | IN_UPDATE); 1283 /* 1284 * If the last named reference to a snapshot goes away, 1285 * drop its snapshot reference so that it will be reclaimed 1286 * when last open reference goes away. 1287 */ 1288 if (IS_SNAPSHOT(oip) && oip->i_effnlink == 0) 1289 UFS_SNAPGONE(oip); 1290 return (error); 1291 } 1292 1293 /* 1294 * Check if a directory is empty or not. 1295 * Inode supplied must be locked. 1296 * 1297 * Using a struct dirtemplate here is not precisely 1298 * what we want, but better than using a struct direct. 1299 * 1300 * NB: does not handle corrupted directories. 1301 */ 1302 int 1303 ufs_dirempty(struct inode *ip, ino_t parentino, struct ucred *cred) 1304 { 1305 doff_t off; 1306 struct dirtemplate dbuf; 1307 struct direct *dp = (struct direct *)&dbuf; 1308 int error, namlen; 1309 ssize_t count; 1310 #define MINDIRSIZ (sizeof (struct dirtemplate) / 2) 1311 1312 for (off = 0; off < ip->i_size; off += dp->d_reclen) { 1313 error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ, 1314 off, UIO_SYSSPACE, IO_NODELOCKED | IO_NOMACCHECK, cred, 1315 NOCRED, &count, (struct thread *)0); 1316 /* 1317 * Since we read MINDIRSIZ, residual must 1318 * be 0 unless we're at end of file. 1319 */ 1320 if (error || count != 0) 1321 return (0); 1322 /* avoid infinite loops */ 1323 if (dp->d_reclen == 0) 1324 return (0); 1325 /* skip empty entries */ 1326 if (dp->d_ino == 0 || dp->d_ino == UFS_WINO) 1327 continue; 1328 /* accept only "." and ".." */ 1329 # if (BYTE_ORDER == LITTLE_ENDIAN) 1330 if (OFSFMT(ITOV(ip))) 1331 namlen = dp->d_type; 1332 else 1333 namlen = dp->d_namlen; 1334 # else 1335 namlen = dp->d_namlen; 1336 # endif 1337 if (namlen > 2) 1338 return (0); 1339 if (dp->d_name[0] != '.') 1340 return (0); 1341 /* 1342 * At this point namlen must be 1 or 2. 1343 * 1 implies ".", 2 implies ".." if second 1344 * char is also "." 1345 */ 1346 if (namlen == 1 && dp->d_ino == ip->i_number) 1347 continue; 1348 if (dp->d_name[1] == '.' && dp->d_ino == parentino) 1349 continue; 1350 return (0); 1351 } 1352 return (1); 1353 } 1354 1355 static int 1356 ufs_dir_dd_ino(struct vnode *vp, struct ucred *cred, ino_t *dd_ino, 1357 struct vnode **dd_vp) 1358 { 1359 struct dirtemplate dirbuf; 1360 struct vnode *ddvp; 1361 int error, namlen; 1362 1363 ASSERT_VOP_LOCKED(vp, "ufs_dir_dd_ino"); 1364 *dd_vp = NULL; 1365 if (vp->v_type != VDIR) 1366 return (ENOTDIR); 1367 /* 1368 * First check to see if we have it in the name cache. 1369 */ 1370 if ((ddvp = vn_dir_dd_ino(vp)) != NULL) { 1371 KASSERT(ddvp->v_mount == vp->v_mount, 1372 ("ufs_dir_dd_ino: Unexpected mount point crossing")); 1373 *dd_ino = VTOI(ddvp)->i_number; 1374 *dd_vp = ddvp; 1375 return (0); 1376 } 1377 /* 1378 * Have to read the directory. 1379 */ 1380 error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf, 1381 sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE, 1382 IO_NODELOCKED | IO_NOMACCHECK, cred, NOCRED, NULL, NULL); 1383 if (error != 0) 1384 return (error); 1385 #if (BYTE_ORDER == LITTLE_ENDIAN) 1386 if (OFSFMT(vp)) 1387 namlen = dirbuf.dotdot_type; 1388 else 1389 namlen = dirbuf.dotdot_namlen; 1390 #else 1391 namlen = dirbuf.dotdot_namlen; 1392 #endif 1393 if (namlen != 2 || dirbuf.dotdot_name[0] != '.' || 1394 dirbuf.dotdot_name[1] != '.') 1395 return (ENOTDIR); 1396 *dd_ino = dirbuf.dotdot_ino; 1397 return (0); 1398 } 1399 1400 /* 1401 * Check if source directory is in the path of the target directory. 1402 */ 1403 int 1404 ufs_checkpath(ino_t source_ino, ino_t parent_ino, struct inode *target, 1405 struct ucred *cred, ino_t *wait_ino) 1406 { 1407 struct mount *mp; 1408 struct vnode *tvp, *vp, *vp1; 1409 int error; 1410 ino_t dd_ino; 1411 1412 vp = tvp = ITOV(target); 1413 mp = vp->v_mount; 1414 *wait_ino = 0; 1415 sx_assert(&VFSTOUFS(mp)->um_checkpath_lock, SA_XLOCKED); 1416 1417 if (target->i_number == source_ino) 1418 return (EEXIST); 1419 if (target->i_number == parent_ino) 1420 return (0); 1421 if (target->i_number == UFS_ROOTINO) 1422 return (0); 1423 for (;;) { 1424 error = ufs_dir_dd_ino(vp, cred, &dd_ino, &vp1); 1425 if (error != 0) 1426 break; 1427 if (dd_ino == source_ino) { 1428 error = EINVAL; 1429 break; 1430 } 1431 if (dd_ino == UFS_ROOTINO) 1432 break; 1433 if (dd_ino == parent_ino) 1434 break; 1435 if (vp1 == NULL) { 1436 error = VFS_VGET(mp, dd_ino, LK_SHARED | LK_NOWAIT, 1437 &vp1); 1438 if (error != 0) { 1439 *wait_ino = dd_ino; 1440 break; 1441 } 1442 } 1443 KASSERT(dd_ino == VTOI(vp1)->i_number, 1444 ("directory %ju reparented\n", 1445 (uintmax_t)VTOI(vp1)->i_number)); 1446 if (vp != tvp) 1447 vput(vp); 1448 vp = vp1; 1449 } 1450 1451 if (error == ENOTDIR) 1452 panic("checkpath: .. not a directory\n"); 1453 if (vp1 != NULL) 1454 vput(vp1); 1455 if (vp != tvp) 1456 vput(vp); 1457 return (error); 1458 } 1459 1460 #ifdef DIAGNOSTIC 1461 static void 1462 ufs_assert_inode_offset_owner(struct inode *ip, struct iown_tracker *tr, 1463 const char *name, const char *file, int line) 1464 { 1465 char msg[128]; 1466 1467 snprintf(msg, sizeof(msg), "at %s@%d", file, line); 1468 ASSERT_VOP_ELOCKED(ITOV(ip), msg); 1469 MPASS((ip->i_mode & IFMT) == IFDIR); 1470 if (curthread == tr->tr_owner && ip->i_lock_gen == tr->tr_gen) 1471 return; 1472 printf("locked at\n"); 1473 stack_print(&tr->tr_st); 1474 printf("unlocked at\n"); 1475 stack_print(&tr->tr_unlock); 1476 panic("%s ip %p %jd offset owner %p %d gen %d " 1477 "curthread %p %d gen %d at %s@%d\n", 1478 name, ip, (uintmax_t)ip->i_number, tr->tr_owner, 1479 tr->tr_owner->td_tid, tr->tr_gen, 1480 curthread, curthread->td_tid, ip->i_lock_gen, 1481 file, line); 1482 } 1483 1484 static void 1485 ufs_set_inode_offset_owner(struct inode *ip, struct iown_tracker *tr, 1486 const char *file, int line) 1487 { 1488 char msg[128]; 1489 1490 snprintf(msg, sizeof(msg), "at %s@%d", file, line); 1491 ASSERT_VOP_ELOCKED(ITOV(ip), msg); 1492 MPASS((ip->i_mode & IFMT) == IFDIR); 1493 tr->tr_owner = curthread; 1494 tr->tr_gen = ip->i_lock_gen; 1495 stack_save(&tr->tr_st); 1496 } 1497 1498 static void 1499 ufs_init_one_tracker(struct iown_tracker *tr) 1500 { 1501 tr->tr_owner = NULL; 1502 stack_zero(&tr->tr_st); 1503 } 1504 1505 void 1506 ufs_init_trackers(struct inode *ip) 1507 { 1508 ufs_init_one_tracker(&ip->i_offset_tracker); 1509 ufs_init_one_tracker(&ip->i_count_tracker); 1510 ufs_init_one_tracker(&ip->i_endoff_tracker); 1511 } 1512 1513 void 1514 ufs_unlock_tracker(struct inode *ip) 1515 { 1516 if (ip->i_count_tracker.tr_gen == ip->i_lock_gen) 1517 stack_save(&ip->i_count_tracker.tr_unlock); 1518 if (ip->i_offset_tracker.tr_gen == ip->i_lock_gen) 1519 stack_save(&ip->i_offset_tracker.tr_unlock); 1520 if (ip->i_endoff_tracker.tr_gen == ip->i_lock_gen) 1521 stack_save(&ip->i_endoff_tracker.tr_unlock); 1522 ip->i_lock_gen++; 1523 } 1524 1525 doff_t 1526 ufs_get_i_offset(struct inode *ip, const char *file, int line) 1527 { 1528 ufs_assert_inode_offset_owner(ip, &ip->i_offset_tracker, "i_offset", 1529 file, line); 1530 return (ip->i_offset); 1531 } 1532 1533 void 1534 ufs_set_i_offset(struct inode *ip, doff_t off, const char *file, int line) 1535 { 1536 ufs_set_inode_offset_owner(ip, &ip->i_offset_tracker, file, line); 1537 ip->i_offset = off; 1538 } 1539 1540 int32_t 1541 ufs_get_i_count(struct inode *ip, const char *file, int line) 1542 { 1543 ufs_assert_inode_offset_owner(ip, &ip->i_count_tracker, "i_count", 1544 file, line); 1545 return (ip->i_count); 1546 } 1547 1548 void 1549 ufs_set_i_count(struct inode *ip, int32_t cnt, const char *file, int line) 1550 { 1551 ufs_set_inode_offset_owner(ip, &ip->i_count_tracker, file, line); 1552 ip->i_count = cnt; 1553 } 1554 1555 doff_t 1556 ufs_get_i_endoff(struct inode *ip, const char *file, int line) 1557 { 1558 ufs_assert_inode_offset_owner(ip, &ip->i_endoff_tracker, "i_endoff", 1559 file, line); 1560 return (ip->i_endoff); 1561 } 1562 1563 void 1564 ufs_set_i_endoff(struct inode *ip, doff_t off, const char *file, int line) 1565 { 1566 ufs_set_inode_offset_owner(ip, &ip->i_endoff_tracker, file, line); 1567 ip->i_endoff = off; 1568 } 1569 1570 #endif 1571