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