1 /* $NetBSD: ulfs_lookup.c,v 1.39 2016/06/20 02:25:03 dholland Exp $ */ 2 /* from NetBSD: ufs_lookup.c,v 1.135 2015/07/11 11:04:48 mlelstv */ 3 4 /* 5 * Copyright (c) 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * (c) UNIX System Laboratories, Inc. 8 * All or some portions of this file are derived from material licensed 9 * to the University of California by American Telephone and Telegraph 10 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 11 * the permission of UNIX System Laboratories, Inc. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * @(#)ufs_lookup.c 8.9 (Berkeley) 8/11/94 38 */ 39 40 #include <sys/cdefs.h> 41 __KERNEL_RCSID(0, "$NetBSD: ulfs_lookup.c,v 1.39 2016/06/20 02:25:03 dholland Exp $"); 42 43 #ifdef _KERNEL_OPT 44 #include "opt_lfs.h" 45 #endif 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/namei.h> 50 #include <sys/buf.h> 51 #include <sys/file.h> 52 #include <sys/stat.h> 53 #include <sys/mount.h> 54 #include <sys/vnode.h> 55 #include <sys/kernel.h> 56 #include <sys/kauth.h> 57 #include <sys/fstrans.h> 58 #include <sys/proc.h> 59 #include <sys/kmem.h> 60 61 #include <ufs/lfs/lfs.h> 62 #include <ufs/lfs/lfs_accessors.h> 63 #include <ufs/lfs/lfs_extern.h> 64 65 #include <ufs/lfs/ulfs_inode.h> 66 #ifdef LFS_DIRHASH 67 #include <ufs/lfs/ulfs_dirhash.h> 68 #endif 69 #include <ufs/lfs/ulfsmount.h> 70 #include <ufs/lfs/ulfs_extern.h> 71 #include <ufs/lfs/ulfs_bswap.h> 72 73 #include <miscfs/genfs/genfs.h> 74 75 #ifdef DIAGNOSTIC 76 int lfs_dirchk = 1; 77 #else 78 int lfs_dirchk = 0; 79 #endif 80 81 /* 82 * Convert a component of a pathname into a pointer to a locked inode. 83 * This is a very central and rather complicated routine. 84 * If the file system is not maintained in a strict tree hierarchy, 85 * this can result in a deadlock situation (see comments in code below). 86 * 87 * The cnp->cn_nameiop argument is LOOKUP, CREATE, RENAME, or DELETE depending 88 * on whether the name is to be looked up, created, renamed, or deleted. 89 * When CREATE, RENAME, or DELETE is specified, information usable in 90 * creating, renaming, or deleting a directory entry may be calculated. 91 * If flag has LOCKPARENT or'ed into it and the target of the pathname 92 * exists, lookup returns both the target and its parent directory locked. 93 * When creating or renaming and LOCKPARENT is specified, the target may 94 * not be ".". When deleting and LOCKPARENT is specified, the target may 95 * be "."., but the caller must check to ensure it does an vrele and vput 96 * instead of two vputs. 97 * 98 * Overall outline of ulfs_lookup: 99 * 100 * check accessibility of directory 101 * look for name in cache, if found, then if at end of path 102 * and deleting or creating, drop it, else return name 103 * search for name in directory, to found or notfound 104 * notfound: 105 * if creating, return locked directory, leaving info on available slots 106 * else return error 107 * found: 108 * if at end of path and deleting, return information to allow delete 109 * if at end of path and rewriting (RENAME and LOCKPARENT), lock target 110 * inode and return info to allow rewrite 111 * if not at end, add name to cache; if at end and neither creating 112 * nor deleting, add name to cache 113 */ 114 int 115 ulfs_lookup(void *v) 116 { 117 struct vop_lookup_v2_args /* { 118 struct vnode *a_dvp; 119 struct vnode **a_vpp; 120 struct componentname *a_cnp; 121 } */ *ap = v; 122 struct vnode *vdp = ap->a_dvp; /* vnode for directory being searched */ 123 struct inode *dp = VTOI(vdp); /* inode for directory being searched */ 124 struct buf *bp; /* a buffer of directory entries */ 125 LFS_DIRHEADER *ep; /* the current directory entry */ 126 int entryoffsetinblock; /* offset of ep in bp's buffer */ 127 enum { 128 NONE, /* need to search a slot for our new entry */ 129 COMPACT, /* a compaction can make a slot in the current 130 DIRBLKSIZ block */ 131 FOUND, /* found a slot (or no need to search) */ 132 } slotstatus; 133 doff_t slotoffset; /* offset of area with free space. 134 a special value -1 for invalid */ 135 int slotsize; /* size of area at slotoffset */ 136 int slotfreespace; /* accumulated amount of space free in 137 the current DIRBLKSIZ block */ 138 int slotneeded; /* size of the entry we're seeking */ 139 int numdirpasses; /* strategy for directory search */ 140 doff_t endsearch; /* offset to end directory search */ 141 doff_t prevoff; /* previous value of ulr_offset */ 142 struct vnode *tdp; /* returned by vcache_get */ 143 doff_t enduseful; /* pointer past last used dir slot. 144 used for directory truncation. */ 145 u_long bmask; /* block offset mask */ 146 int error; 147 struct vnode **vpp = ap->a_vpp; 148 struct componentname *cnp = ap->a_cnp; 149 kauth_cred_t cred = cnp->cn_cred; 150 int flags; 151 int nameiop = cnp->cn_nameiop; 152 struct lfs *fs = dp->i_lfs; 153 int dirblksiz = fs->um_dirblksiz; 154 ino_t foundino; 155 struct ulfs_lookup_results *results; 156 int iswhiteout; /* temp result from cache_lookup() */ 157 158 flags = cnp->cn_flags; 159 160 bp = NULL; 161 slotoffset = -1; 162 *vpp = NULL; 163 endsearch = 0; /* silence compiler warning */ 164 165 /* 166 * Produce the auxiliary lookup results into i_crap. Increment 167 * its serial number so elsewhere we can tell if we're using 168 * stale results. This should not be done this way. XXX. 169 */ 170 results = &dp->i_crap; 171 dp->i_crapcounter++; 172 173 /* 174 * Check accessiblity of directory. 175 */ 176 if ((error = VOP_ACCESS(vdp, VEXEC, cred)) != 0) 177 return (error); 178 179 if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) && 180 (nameiop == DELETE || nameiop == RENAME)) 181 return (EROFS); 182 183 /* 184 * We now have a segment name to search for, and a directory to search. 185 * 186 * Before tediously performing a linear scan of the directory, 187 * check the name cache to see if the directory/name pair 188 * we are looking for is known already. 189 */ 190 if (cache_lookup(vdp, cnp->cn_nameptr, cnp->cn_namelen, 191 cnp->cn_nameiop, cnp->cn_flags, &iswhiteout, vpp)) { 192 if (iswhiteout) { 193 cnp->cn_flags |= ISWHITEOUT; 194 } 195 return *vpp == NULLVP ? ENOENT : 0; 196 } 197 if (iswhiteout) { 198 /* 199 * The namecache set iswhiteout without finding a 200 * cache entry. As of this writing (20121014), this 201 * can happen if there was a whiteout entry that has 202 * been invalidated by the lookup. It is not clear if 203 * it is correct to set ISWHITEOUT in this case or 204 * not; however, doing so retains the prior behavior, 205 * so we'll go with that until some clearer answer 206 * appears. XXX 207 */ 208 cnp->cn_flags |= ISWHITEOUT; 209 } 210 211 fstrans_start(vdp->v_mount, FSTRANS_SHARED); 212 213 /* 214 * Suppress search for slots unless creating 215 * file and at end of pathname, in which case 216 * we watch for a place to put the new file in 217 * case it doesn't already exist. 218 */ 219 slotstatus = FOUND; 220 slotfreespace = slotsize = slotneeded = 0; 221 if ((nameiop == CREATE || nameiop == RENAME) && (flags & ISLASTCN)) { 222 slotstatus = NONE; 223 slotneeded = LFS_DIRECTSIZ(fs, cnp->cn_namelen); 224 } 225 226 /* 227 * If there is cached information on a previous search of 228 * this directory, pick up where we last left off. 229 * We cache only lookups as these are the most common 230 * and have the greatest payoff. Caching CREATE has little 231 * benefit as it usually must search the entire directory 232 * to determine that the entry does not exist. Caching the 233 * location of the last DELETE or RENAME has not reduced 234 * profiling time and hence has been removed in the interest 235 * of simplicity. 236 */ 237 bmask = vdp->v_mount->mnt_stat.f_iosize - 1; 238 239 #ifdef LFS_DIRHASH 240 /* 241 * Use dirhash for fast operations on large directories. The logic 242 * to determine whether to hash the directory is contained within 243 * ulfsdirhash_build(); a zero return means that it decided to hash 244 * this directory and it successfully built up the hash table. 245 */ 246 if (ulfsdirhash_build(dp) == 0) { 247 /* Look for a free slot if needed. */ 248 enduseful = dp->i_size; 249 if (slotstatus != FOUND) { 250 slotoffset = ulfsdirhash_findfree(dp, slotneeded, 251 &slotsize); 252 if (slotoffset >= 0) { 253 slotstatus = COMPACT; 254 enduseful = ulfsdirhash_enduseful(dp); 255 if (enduseful < 0) 256 enduseful = dp->i_size; 257 } 258 } 259 /* Look up the component. */ 260 numdirpasses = 1; 261 entryoffsetinblock = 0; /* silence compiler warning */ 262 switch (ulfsdirhash_lookup(dp, cnp->cn_nameptr, cnp->cn_namelen, 263 &results->ulr_offset, &bp, nameiop == DELETE ? &prevoff : NULL)) { 264 case 0: 265 ep = (LFS_DIRHEADER *)((char *)bp->b_data + 266 (results->ulr_offset & bmask)); 267 goto foundentry; 268 case ENOENT: 269 results->ulr_offset = roundup(dp->i_size, dirblksiz); 270 goto notfound; 271 default: 272 /* Something failed; just do a linear search. */ 273 break; 274 } 275 } 276 #endif /* LFS_DIRHASH */ 277 278 if (nameiop != LOOKUP || results->ulr_diroff == 0 || 279 results->ulr_diroff >= dp->i_size) { 280 entryoffsetinblock = 0; 281 results->ulr_offset = 0; 282 numdirpasses = 1; 283 } else { 284 results->ulr_offset = results->ulr_diroff; 285 if ((entryoffsetinblock = results->ulr_offset & bmask) && 286 (error = ulfs_blkatoff(vdp, (off_t)results->ulr_offset, 287 NULL, &bp, false))) 288 goto out; 289 numdirpasses = 2; 290 namecache_count_2passes(); 291 } 292 prevoff = results->ulr_offset; 293 endsearch = roundup(dp->i_size, dirblksiz); 294 enduseful = 0; 295 296 searchloop: 297 while (results->ulr_offset < endsearch) { 298 if (curcpu()->ci_schedstate.spc_flags & SPCF_SHOULDYIELD) 299 preempt(); 300 /* 301 * If necessary, get the next directory block. 302 */ 303 if ((results->ulr_offset & bmask) == 0) { 304 if (bp != NULL) 305 brelse(bp, 0); 306 error = ulfs_blkatoff(vdp, (off_t)results->ulr_offset, 307 NULL, &bp, false); 308 if (error) 309 goto out; 310 entryoffsetinblock = 0; 311 } 312 /* 313 * If still looking for a slot, and at a DIRBLKSIZ 314 * boundary, have to start looking for free space again. 315 */ 316 if (slotstatus == NONE && 317 (entryoffsetinblock & (dirblksiz - 1)) == 0) { 318 slotoffset = -1; 319 slotfreespace = 0; 320 } 321 /* 322 * Get pointer to next entry. 323 * Full validation checks are slow, so we only check 324 * enough to insure forward progress through the 325 * directory. Complete checks can be run by patching 326 * "lfs_dirchk" to be true. 327 */ 328 KASSERT(bp != NULL); 329 ep = (LFS_DIRHEADER *)((char *)bp->b_data + entryoffsetinblock); 330 if (lfs_dir_getreclen(fs, ep) == 0 || 331 (lfs_dirchk && ulfs_dirbadentry(vdp, ep, entryoffsetinblock))) { 332 int i; 333 334 ulfs_dirbad(dp, results->ulr_offset, "mangled entry"); 335 i = dirblksiz - (entryoffsetinblock & (dirblksiz - 1)); 336 results->ulr_offset += i; 337 entryoffsetinblock += i; 338 continue; 339 } 340 341 /* 342 * If an appropriate sized slot has not yet been found, 343 * check to see if one is available. Also accumulate space 344 * in the current block so that we can determine if 345 * compaction is viable. 346 */ 347 if (slotstatus != FOUND) { 348 int size = lfs_dir_getreclen(fs, ep); 349 350 if (lfs_dir_getino(fs, ep) != 0) 351 size -= LFS_DIRSIZ(fs, ep); 352 if (size > 0) { 353 if (size >= slotneeded) { 354 slotstatus = FOUND; 355 slotoffset = results->ulr_offset; 356 slotsize = lfs_dir_getreclen(fs, ep); 357 } else if (slotstatus == NONE) { 358 slotfreespace += size; 359 if (slotoffset == -1) 360 slotoffset = results->ulr_offset; 361 if (slotfreespace >= slotneeded) { 362 slotstatus = COMPACT; 363 slotsize = results->ulr_offset + 364 lfs_dir_getreclen(fs, ep) - 365 slotoffset; 366 } 367 } 368 } 369 } 370 371 /* 372 * Check for a name match. 373 */ 374 if (lfs_dir_getino(fs, ep)) { 375 int namlen; 376 377 namlen = lfs_dir_getnamlen(fs, ep); 378 if (namlen == cnp->cn_namelen && 379 !memcmp(cnp->cn_nameptr, lfs_dir_nameptr(fs, ep), 380 (unsigned)namlen)) { 381 #ifdef LFS_DIRHASH 382 foundentry: 383 #endif 384 /* 385 * Save directory entry's inode number and 386 * reclen, and release directory buffer. 387 */ 388 if (!FSFMT(vdp) && lfs_dir_gettype(fs, ep) == LFS_DT_WHT) { 389 slotstatus = FOUND; 390 slotoffset = results->ulr_offset; 391 slotsize = lfs_dir_getreclen(fs, ep); 392 results->ulr_reclen = slotsize; 393 /* 394 * This is used to set 395 * results->ulr_endoff, 396 * which may be used by ulfs_direnter() 397 * as a length to truncate the 398 * directory to. Therefore, it must 399 * point past the end of the last 400 * non-empty directory entry. We don't 401 * know where that is in this case, so 402 * we effectively disable shrinking by 403 * using the existing size of the 404 * directory. 405 * 406 * Note that we wouldn't expect to 407 * shrink the directory while rewriting 408 * an existing entry anyway. 409 */ 410 enduseful = endsearch; 411 cnp->cn_flags |= ISWHITEOUT; 412 numdirpasses--; 413 goto notfound; 414 } 415 foundino = lfs_dir_getino(fs, ep); 416 results->ulr_reclen = lfs_dir_getreclen(fs, ep); 417 goto found; 418 } 419 } 420 prevoff = results->ulr_offset; 421 results->ulr_offset += lfs_dir_getreclen(fs, ep); 422 entryoffsetinblock += lfs_dir_getreclen(fs, ep); 423 if (lfs_dir_getino(fs, ep)) 424 enduseful = results->ulr_offset; 425 } 426 notfound: 427 /* 428 * If we started in the middle of the directory and failed 429 * to find our target, we must check the beginning as well. 430 */ 431 if (numdirpasses == 2) { 432 numdirpasses--; 433 results->ulr_offset = 0; 434 endsearch = results->ulr_diroff; 435 goto searchloop; 436 } 437 if (bp != NULL) 438 brelse(bp, 0); 439 /* 440 * If creating, and at end of pathname and current 441 * directory has not been removed, then can consider 442 * allowing file to be created. 443 */ 444 if ((nameiop == CREATE || nameiop == RENAME || 445 (nameiop == DELETE && 446 (cnp->cn_flags & DOWHITEOUT) && 447 (cnp->cn_flags & ISWHITEOUT))) && 448 (flags & ISLASTCN) && dp->i_nlink != 0) { 449 /* 450 * Access for write is interpreted as allowing 451 * creation of files in the directory. 452 */ 453 error = VOP_ACCESS(vdp, VWRITE, cred); 454 if (error) 455 goto out; 456 /* 457 * Return an indication of where the new directory 458 * entry should be put. If we didn't find a slot, 459 * then set results->ulr_count to 0 indicating 460 * that the new slot belongs at the end of the 461 * directory. If we found a slot, then the new entry 462 * can be put in the range from results->ulr_offset to 463 * results->ulr_offset + results->ulr_count. 464 */ 465 if (slotstatus == NONE) { 466 results->ulr_offset = roundup(dp->i_size, dirblksiz); 467 results->ulr_count = 0; 468 enduseful = results->ulr_offset; 469 } else if (nameiop == DELETE) { 470 results->ulr_offset = slotoffset; 471 if ((results->ulr_offset & (dirblksiz - 1)) == 0) 472 results->ulr_count = 0; 473 else 474 results->ulr_count = 475 results->ulr_offset - prevoff; 476 } else { 477 results->ulr_offset = slotoffset; 478 results->ulr_count = slotsize; 479 if (enduseful < slotoffset + slotsize) 480 enduseful = slotoffset + slotsize; 481 } 482 results->ulr_endoff = roundup(enduseful, dirblksiz); 483 #if 0 /* commented out by dbj. none of the on disk fields changed */ 484 dp->i_flag |= IN_CHANGE | IN_UPDATE; 485 #endif 486 /* 487 * We return with the directory locked, so that 488 * the parameters we set up above will still be 489 * valid if we actually decide to do a direnter(). 490 * We return ni_vp == NULL to indicate that the entry 491 * does not currently exist; we leave a pointer to 492 * the (locked) directory inode in ndp->ni_dvp. 493 * 494 * NB - if the directory is unlocked, then this 495 * information cannot be used. 496 */ 497 error = EJUSTRETURN; 498 goto out; 499 } 500 /* 501 * Insert name into cache (as non-existent) if appropriate. 502 */ 503 if (nameiop != CREATE) { 504 cache_enter(vdp, *vpp, cnp->cn_nameptr, cnp->cn_namelen, 505 cnp->cn_flags); 506 } 507 error = ENOENT; 508 goto out; 509 510 found: 511 if (numdirpasses == 2) 512 namecache_count_pass2(); 513 /* 514 * Check that directory length properly reflects presence 515 * of this entry. 516 */ 517 if (results->ulr_offset + LFS_DIRSIZ(fs, ep) > dp->i_size) { 518 ulfs_dirbad(dp, results->ulr_offset, "i_size too small"); 519 dp->i_size = 520 results->ulr_offset + LFS_DIRSIZ(fs, ep); 521 DIP_ASSIGN(dp, size, dp->i_size); 522 dp->i_flag |= IN_CHANGE | IN_UPDATE; 523 } 524 brelse(bp, 0); 525 526 /* 527 * Found component in pathname. 528 * If the final component of path name, save information 529 * in the cache as to where the entry was found. 530 */ 531 if ((flags & ISLASTCN) && nameiop == LOOKUP) 532 results->ulr_diroff = results->ulr_offset &~ (dirblksiz - 1); 533 534 /* 535 * If deleting, and at end of pathname, return 536 * parameters which can be used to remove file. 537 * Lock the inode, being careful with ".". 538 */ 539 if (nameiop == DELETE && (flags & ISLASTCN)) { 540 /* 541 * Return pointer to current entry in results->ulr_offset, 542 * and distance past previous entry (if there 543 * is a previous entry in this block) in results->ulr_count. 544 * Save directory inode pointer in ndp->ni_dvp for dirremove(). 545 */ 546 if ((results->ulr_offset & (dirblksiz - 1)) == 0) 547 results->ulr_count = 0; 548 else 549 results->ulr_count = results->ulr_offset - prevoff; 550 if (dp->i_number == foundino) { 551 vref(vdp); 552 tdp = vdp; 553 } else { 554 error = vcache_get(vdp->v_mount, 555 &foundino, sizeof(foundino), &tdp); 556 if (error) 557 goto out; 558 } 559 /* 560 * Write access to directory required to delete files. 561 */ 562 error = VOP_ACCESS(vdp, VWRITE, cred); 563 if (error) { 564 vrele(tdp); 565 goto out; 566 } 567 /* 568 * If directory is "sticky", then user must own 569 * the directory, or the file in it, else she 570 * may not delete it (unless she's root). This 571 * implements append-only directories. 572 */ 573 if (dp->i_mode & ISVTX) { 574 error = kauth_authorize_vnode(cred, KAUTH_VNODE_DELETE, 575 tdp, vdp, genfs_can_sticky(cred, dp->i_uid, 576 VTOI(tdp)->i_uid)); 577 if (error) { 578 vrele(tdp); 579 error = EPERM; 580 goto out; 581 } 582 } 583 *vpp = tdp; 584 error = 0; 585 goto out; 586 } 587 588 /* 589 * If rewriting (RENAME), return the inode and the 590 * information required to rewrite the present directory 591 * Must get inode of directory entry to verify it's a 592 * regular file, or empty directory. 593 */ 594 if (nameiop == RENAME && (flags & ISLASTCN)) { 595 error = VOP_ACCESS(vdp, VWRITE, cred); 596 if (error) 597 goto out; 598 /* 599 * Careful about locking second inode. 600 * This can only occur if the target is ".". 601 */ 602 if (dp->i_number == foundino) { 603 error = EISDIR; 604 goto out; 605 } 606 error = vcache_get(vdp->v_mount, 607 &foundino, sizeof(foundino), &tdp); 608 if (error) 609 goto out; 610 *vpp = tdp; 611 error = 0; 612 goto out; 613 } 614 615 if (dp->i_number == foundino) { 616 vref(vdp); /* we want ourself, ie "." */ 617 *vpp = vdp; 618 } else { 619 error = vcache_get(vdp->v_mount, 620 &foundino, sizeof(foundino), &tdp); 621 if (error) 622 goto out; 623 *vpp = tdp; 624 } 625 626 /* 627 * Insert name into cache if appropriate. 628 */ 629 cache_enter(vdp, *vpp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_flags); 630 error = 0; 631 632 out: 633 fstrans_done(vdp->v_mount); 634 return error; 635 } 636 637 void 638 ulfs_dirbad(struct inode *ip, doff_t offset, const char *how) 639 { 640 struct mount *mp; 641 642 mp = ITOV(ip)->v_mount; 643 printf("%s: bad dir ino %llu at offset %d: %s\n", 644 mp->mnt_stat.f_mntonname, (unsigned long long)ip->i_number, 645 offset, how); 646 if ((mp->mnt_flag & MNT_RDONLY) == 0) 647 panic("bad dir"); 648 } 649 650 /* 651 * Do consistency checking on a directory entry: 652 * record length must be multiple of 4 653 * entry must fit in rest of its DIRBLKSIZ block 654 * record must be large enough to contain entry 655 * name is not longer than LFS_MAXNAMLEN 656 * name must be as long as advertised, and null terminated 657 */ 658 int 659 ulfs_dirbadentry(struct vnode *dp, LFS_DIRHEADER *ep, int entryoffsetinblock) 660 { 661 int i; 662 int namlen; 663 unsigned reclen; 664 struct ulfsmount *ump = VFSTOULFS(dp->v_mount); 665 struct lfs *fs = ump->um_lfs; 666 int dirblksiz = fs->um_dirblksiz; 667 const char *name; 668 669 namlen = lfs_dir_getnamlen(fs, ep); 670 reclen = lfs_dir_getreclen(fs, ep); 671 if ((reclen & 0x3) != 0 || 672 reclen > dirblksiz - (entryoffsetinblock & (dirblksiz - 1)) || 673 reclen < LFS_DIRSIZ(fs, ep) || namlen > LFS_MAXNAMLEN) { 674 /*return (1); */ 675 printf("First bad, reclen=%#x, DIRSIZ=%lu, namlen=%d, " 676 "flags=%#x, entryoffsetinblock=%d, dirblksiz = %d\n", 677 lfs_dir_getreclen(fs, ep), 678 (u_long)LFS_DIRSIZ(fs, ep), 679 namlen, dp->v_mount->mnt_flag, entryoffsetinblock, 680 dirblksiz); 681 goto bad; 682 } 683 if (lfs_dir_getino(fs, ep) == 0) 684 return (0); 685 name = lfs_dir_nameptr(fs, ep); 686 for (i = 0; i < namlen; i++) 687 if (name[i] == '\0') { 688 /*return (1); */ 689 printf("Second bad\n"); 690 goto bad; 691 } 692 if (name[i]) 693 goto bad; 694 return (0); 695 bad: 696 return (1); 697 } 698 699 /* 700 * Assign the contents of directory entry DIRP, on volume FS. 701 * 702 * NAME/NAMLEN is the name, which is not necessarily null terminated. 703 * INUM is the inode number, and DTYPE is the type code (LFS_DT_*). 704 * 705 * Note that these values typically come from: 706 * cnp->cn_nameptr 707 * cnp->cn_namelen 708 * ip->i_number 709 * LFS_IFTODT(ip->i_mode) 710 * 711 * Does not set d_reclen. 712 */ 713 static void 714 ulfs_direntry_assign(struct lfs *fs, LFS_DIRHEADER *dirp, 715 const char *name, size_t namlen, 716 ino_t inum, unsigned dtype) 717 { 718 lfs_dir_setino(fs, dirp, inum); 719 lfs_dir_setnamlen(fs, dirp, namlen); 720 lfs_dir_settype(fs, dirp, dtype); 721 memcpy(lfs_dir_nameptr(fs, dirp), name, namlen); 722 lfs_dir_nameptr(fs, dirp)[namlen] = '\0'; 723 } 724 725 /* 726 * Write a directory entry after a call to namei, using the parameters 727 * that ulfs_lookup left in nameidata and in the ulfs_lookup_results. 728 * 729 * DVP is the directory to be updated. It must be locked. 730 * ULR is the ulfs_lookup_results structure from the final lookup step. 731 * TVP is not used. (XXX: why is it here? remove it) 732 * CNP is the componentname from the final lookup step. 733 * INUM is the inode number to insert into the new directory entry. 734 * DTYPE is the type code (LFS_DT_*) to insert into the new directory entry. 735 * NEWDIRBP is not used and (XXX) should be removed. The previous 736 * comment here said it was used by the now-removed softupdates code. 737 * 738 * The link count of the target inode is *not* incremented; the 739 * caller does that. 740 * 741 * If ulr->ulr_count is 0, ulfs_lookup did not find space to insert the 742 * directory entry. ulr_offset, which is the place to put the entry, 743 * should be on a block boundary (and should be at the end of the 744 * directory AFAIK) and a fresh block is allocated to put the new 745 * directory entry in. 746 * 747 * If ulr->ulr_count is not zero, ulfs_lookup found a slot to insert 748 * the entry into. This slot ranges from ulr_offset to ulr_offset + 749 * ulr_count. However, this slot may already be partially populated 750 * requiring compaction. See notes below. 751 * 752 * Furthermore, if ulr_count is not zero and ulr_endoff is not the 753 * same as i_size, the directory is truncated to size ulr_endoff. 754 */ 755 int 756 ulfs_direnter(struct vnode *dvp, const struct ulfs_lookup_results *ulr, 757 struct vnode *tvp, 758 struct componentname *cnp, ino_t inum, unsigned dtype, 759 struct buf *newdirbp) 760 { 761 kauth_cred_t cr; 762 int newentrysize; 763 struct inode *dp; 764 struct buf *bp; 765 u_int dsize; 766 LFS_DIRHEADER *ep, *nep; 767 int error, ret, lfs_blkoff, loc, spacefree; 768 char *dirbuf; 769 struct timespec ts; 770 struct ulfsmount *ump = VFSTOULFS(dvp->v_mount); 771 struct lfs *fs = ump->um_lfs; 772 int dirblksiz = fs->um_dirblksiz; 773 const char *name; 774 unsigned namlen, reclen; 775 #ifdef LFS_DIRHASH 776 int dohashadd; 777 #endif 778 779 error = 0; 780 name = cnp->cn_nameptr; /* note: not null-terminated */ 781 namlen = cnp->cn_namelen; 782 cr = cnp->cn_cred; 783 784 dp = VTOI(dvp); 785 newentrysize = LFS_DIRECTSIZ(fs, namlen); 786 787 if (ulr->ulr_count == 0) { 788 /* 789 * If ulr_count is 0, then namei could find no 790 * space in the directory. Here, ulr_offset will 791 * be on a directory block boundary and we will write the 792 * new entry into a fresh block. 793 */ 794 if (ulr->ulr_offset & (dirblksiz - 1)) 795 panic("ulfs_direnter: newblk"); 796 if ((error = lfs_balloc(dvp, (off_t)ulr->ulr_offset, dirblksiz, 797 cr, B_CLRBUF | B_SYNC, &bp)) != 0) { 798 return (error); 799 } 800 dp->i_size = ulr->ulr_offset + dirblksiz; 801 DIP_ASSIGN(dp, size, dp->i_size); 802 dp->i_flag |= IN_CHANGE | IN_UPDATE; 803 uvm_vnp_setsize(dvp, dp->i_size); 804 lfs_blkoff = ulr->ulr_offset & (ump->um_mountp->mnt_stat.f_iosize - 1); 805 ep = (LFS_DIRHEADER *)((char *)bp->b_data + lfs_blkoff); 806 ulfs_direntry_assign(fs, ep, name, namlen, inum, dtype); 807 lfs_dir_setreclen(fs, ep, dirblksiz); 808 #ifdef LFS_DIRHASH 809 if (dp->i_dirhash != NULL) { 810 ulfsdirhash_newblk(dp, ulr->ulr_offset); 811 ulfsdirhash_add(dp, ep, ulr->ulr_offset); 812 ulfsdirhash_checkblock(dp, (char *)bp->b_data + lfs_blkoff, 813 ulr->ulr_offset); 814 } 815 #endif 816 error = VOP_BWRITE(bp->b_vp, bp); 817 vfs_timestamp(&ts); 818 ret = lfs_update(dvp, &ts, &ts, UPDATE_DIROP); 819 if (error == 0) 820 return (ret); 821 return (error); 822 } 823 824 /* 825 * If ulr_count is non-zero, then namei found space for the new 826 * entry in the range ulr_offset to ulr_offset + ulr_count 827 * in the directory. To use this space, we may have to compact 828 * the entries located there, by copying them together towards the 829 * beginning of the block, leaving the free space in one usable 830 * chunk at the end. 831 */ 832 833 /* 834 * Increase size of directory if entry eats into new space. 835 * This should never push the size past a new multiple of 836 * DIRBLKSIZ. 837 * 838 * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN. 839 */ 840 if (ulr->ulr_offset + ulr->ulr_count > dp->i_size) { 841 #ifdef DIAGNOSTIC 842 printf("ulfs_direnter: reached 4.2-only block, " 843 "not supposed to happen\n"); 844 #endif 845 dp->i_size = ulr->ulr_offset + ulr->ulr_count; 846 DIP_ASSIGN(dp, size, dp->i_size); 847 dp->i_flag |= IN_CHANGE | IN_UPDATE; 848 } 849 /* 850 * Get the block containing the space for the new directory entry. 851 */ 852 error = ulfs_blkatoff(dvp, (off_t)ulr->ulr_offset, &dirbuf, &bp, true); 853 if (error) { 854 return (error); 855 } 856 /* 857 * Find space for the new entry. In the simple case, the entry at 858 * offset base will have the space. If it does not, then namei 859 * arranged that compacting the region ulr_offset to 860 * ulr_offset + ulr_count would yield the space. 861 */ 862 ep = (LFS_DIRHEADER *)dirbuf; 863 dsize = (lfs_dir_getino(fs, ep) != 0) ? LFS_DIRSIZ(fs, ep) : 0; 864 spacefree = lfs_dir_getreclen(fs, ep) - dsize; 865 for (loc = lfs_dir_getreclen(fs, ep); loc < ulr->ulr_count; ) { 866 nep = (LFS_DIRHEADER *)(dirbuf + loc); 867 868 /* Trim the existing slot (NB: dsize may be zero). */ 869 lfs_dir_setreclen(fs, ep, dsize); 870 ep = LFS_NEXTDIR(fs, ep); 871 872 reclen = lfs_dir_getreclen(fs, nep); 873 loc += reclen; 874 if (lfs_dir_getino(fs, nep) == 0) { 875 /* 876 * A mid-block unused entry. Such entries are 877 * never created by the kernel, but fsck_ffs 878 * can create them (and it doesn't fix them). 879 * 880 * Add up the free space, and initialise the 881 * relocated entry since we don't memcpy it. 882 */ 883 spacefree += reclen; 884 lfs_dir_setino(fs, ep, 0); 885 dsize = 0; 886 continue; 887 } 888 dsize = LFS_DIRSIZ(fs, nep); 889 spacefree += reclen - dsize; 890 #ifdef LFS_DIRHASH 891 if (dp->i_dirhash != NULL) 892 ulfsdirhash_move(dp, nep, 893 ulr->ulr_offset + ((char *)nep - dirbuf), 894 ulr->ulr_offset + ((char *)ep - dirbuf)); 895 #endif 896 memcpy((void *)ep, (void *)nep, dsize); 897 } 898 /* 899 * Here, `ep' points to a directory entry containing `dsize' in-use 900 * bytes followed by `spacefree' unused bytes. If ep->d_ino == 0, 901 * then the entry is completely unused (dsize == 0). The value 902 * of ep->d_reclen is always indeterminate. 903 * 904 * Update the pointer fields in the previous entry (if any), 905 * copy in the new entry, and write out the block. 906 */ 907 if (lfs_dir_getino(fs, ep) == 0 || 908 (lfs_dir_getino(fs, ep) == ULFS_WINO && 909 memcmp(lfs_dir_nameptr(fs, ep), name, namlen) == 0)) { 910 if (spacefree + dsize < newentrysize) 911 panic("ulfs_direnter: compact1"); 912 reclen = spacefree + dsize; 913 #ifdef LFS_DIRHASH 914 dohashadd = (lfs_dir_getino(fs, ep) == 0); 915 #endif 916 } else { 917 if (spacefree < newentrysize) 918 panic("ulfs_direnter: compact2"); 919 reclen = spacefree; 920 lfs_dir_setreclen(fs, ep, dsize); 921 ep = LFS_NEXTDIR(fs, ep); 922 #ifdef LFS_DIRHASH 923 dohashadd = 1; 924 #endif 925 } 926 927 ulfs_direntry_assign(fs, ep, name, namlen, inum, dtype); 928 lfs_dir_setreclen(fs, ep, reclen); 929 #ifdef LFS_DIRHASH 930 if (dp->i_dirhash != NULL && dohashadd) 931 ulfsdirhash_add(dp, ep, ulr->ulr_offset + ((char *)ep - dirbuf)); 932 if (dp->i_dirhash != NULL) 933 ulfsdirhash_checkblock(dp, dirbuf - 934 (ulr->ulr_offset & (dirblksiz - 1)), 935 ulr->ulr_offset & ~(dirblksiz - 1)); 936 #endif 937 error = VOP_BWRITE(bp->b_vp, bp); 938 dp->i_flag |= IN_CHANGE | IN_UPDATE; 939 /* 940 * If all went well, and the directory can be shortened, proceed 941 * with the truncation. Note that we have to unlock the inode for 942 * the entry that we just entered, as the truncation may need to 943 * lock other inodes which can lead to deadlock if we also hold a 944 * lock on the newly entered node. 945 */ 946 if (error == 0 && ulr->ulr_endoff && ulr->ulr_endoff < dp->i_size) { 947 #ifdef LFS_DIRHASH 948 if (dp->i_dirhash != NULL) 949 ulfsdirhash_dirtrunc(dp, ulr->ulr_endoff); 950 #endif 951 (void) lfs_truncate(dvp, (off_t)ulr->ulr_endoff, IO_SYNC, cr); 952 } 953 return (error); 954 } 955 956 /* 957 * Remove a directory entry after a call to namei, using the 958 * parameters that ulfs_lookup left in nameidata and in the 959 * ulfs_lookup_results. 960 * 961 * DVP is the directory to be updated. It must be locked. 962 * ULR is the ulfs_lookup_results structure from the final lookup step. 963 * IP, if not null, is the inode being unlinked. 964 * FLAGS may contain DOWHITEOUT. 965 * ISRMDIR is not used and (XXX) should be removed. 966 * 967 * If FLAGS contains DOWHITEOUT the entry is replaced with a whiteout 968 * instead of being cleared. 969 * 970 * ulr->ulr_offset contains the position of the directory entry 971 * to be removed. 972 * 973 * ulr->ulr_reclen contains the size of the directory entry to be 974 * removed. 975 * 976 * ulr->ulr_count contains the size of the *previous* directory 977 * entry. This allows finding it, for free space management. If 978 * ulr_count is 0, the target entry is at the beginning of the 979 * directory. (Does this ever happen? The first entry should be ".", 980 * which should only be removed at rmdir time. Does rmdir come here 981 * to clear out the "." and ".." entries? Perhaps, but I doubt it.) 982 * 983 * The space is marked free by adding it to the record length (not 984 * name length) of the preceding entry. If the first entry becomes 985 * free, it is marked free by setting the inode number to 0. 986 * 987 * The link count of IP is decremented. Note that this is not the 988 * inverse behavior of ulfs_direnter, which does not adjust link 989 * counts. Sigh. 990 */ 991 int 992 ulfs_dirremove(struct vnode *dvp, const struct ulfs_lookup_results *ulr, 993 struct inode *ip, int flags, int isrmdir) 994 { 995 struct inode *dp = VTOI(dvp); 996 struct lfs *fs = dp->i_lfs; 997 LFS_DIRHEADER *ep; 998 struct buf *bp; 999 int error; 1000 1001 if (flags & DOWHITEOUT) { 1002 /* 1003 * Whiteout entry: set d_ino to ULFS_WINO. 1004 */ 1005 error = ulfs_blkatoff(dvp, (off_t)ulr->ulr_offset, (void *)&ep, 1006 &bp, true); 1007 if (error) 1008 return (error); 1009 lfs_dir_setino(fs, ep, ULFS_WINO); 1010 lfs_dir_settype(fs, ep, LFS_DT_WHT); 1011 goto out; 1012 } 1013 1014 if ((error = ulfs_blkatoff(dvp, 1015 (off_t)(ulr->ulr_offset - ulr->ulr_count), (void *)&ep, &bp, true)) != 0) 1016 return (error); 1017 1018 #ifdef LFS_DIRHASH 1019 /* 1020 * Remove the dirhash entry. This is complicated by the fact 1021 * that `ep' is the previous entry when ulr_count != 0. 1022 */ 1023 if (dp->i_dirhash != NULL) 1024 ulfsdirhash_remove(dp, (ulr->ulr_count == 0) ? ep : 1025 LFS_NEXTDIR(fs, ep), ulr->ulr_offset); 1026 #endif 1027 1028 if (ulr->ulr_count == 0) { 1029 /* 1030 * First entry in block: set d_ino to zero. 1031 */ 1032 lfs_dir_setino(fs, ep, 0); 1033 } else { 1034 /* 1035 * Collapse new free space into previous entry. 1036 */ 1037 lfs_dir_setreclen(fs, ep, 1038 lfs_dir_getreclen(fs, ep) + ulr->ulr_reclen); 1039 } 1040 1041 #ifdef LFS_DIRHASH 1042 if (dp->i_dirhash != NULL) { 1043 int dirblksiz = ip->i_lfs->um_dirblksiz; 1044 ulfsdirhash_checkblock(dp, (char *)ep - 1045 ((ulr->ulr_offset - ulr->ulr_count) & (dirblksiz - 1)), 1046 ulr->ulr_offset & ~(dirblksiz - 1)); 1047 } 1048 #endif 1049 1050 out: 1051 if (ip) { 1052 ip->i_nlink--; 1053 DIP_ASSIGN(ip, nlink, ip->i_nlink); 1054 ip->i_flag |= IN_CHANGE; 1055 } 1056 /* 1057 * XXX did it ever occur to anyone that it might be a good 1058 * idea to restore ip->i_nlink if this fails? Or something? 1059 * Currently on error return from this function the state of 1060 * ip->i_nlink depends on what happened, and callers 1061 * definitely do not take this into account. 1062 */ 1063 error = VOP_BWRITE(bp->b_vp, bp); 1064 dp->i_flag |= IN_CHANGE | IN_UPDATE; 1065 /* 1066 * If the last named reference to a snapshot goes away, 1067 * drop its snapshot reference so that it will be reclaimed 1068 * when last open reference goes away. 1069 */ 1070 if (ip != 0 && (ip->i_flags & SF_SNAPSHOT) != 0 && 1071 ip->i_nlink == 0) 1072 ulfs_snapgone(ip); 1073 return (error); 1074 } 1075 1076 /* 1077 * Rewrite an existing directory entry to point at the inode supplied. 1078 * 1079 * DP is the directory to update. 1080 * OFFSET is the position of the entry in question. It may come 1081 * from ulr_offset of a ulfs_lookup_results. 1082 * OIP is the old inode the directory previously pointed to. 1083 * NEWINUM is the number of the new inode. 1084 * NEWTYPE is the new value for the type field of the directory entry. 1085 * (This is ignored if the fs doesn't support that.) 1086 * ISRMDIR is not used and (XXX) should be removed. 1087 * IFLAGS are added to DP's inode flags. 1088 * 1089 * The link count of OIP is decremented. Note that the link count of 1090 * the new inode is *not* incremented. Yay for symmetry. 1091 */ 1092 int 1093 ulfs_dirrewrite(struct inode *dp, off_t offset, 1094 struct inode *oip, ino_t newinum, int newtype, 1095 int isrmdir, int iflags) 1096 { 1097 struct lfs *fs = dp->i_lfs; 1098 struct buf *bp; 1099 LFS_DIRHEADER *ep; 1100 struct vnode *vdp = ITOV(dp); 1101 int error; 1102 1103 error = ulfs_blkatoff(vdp, offset, (void *)&ep, &bp, true); 1104 if (error) 1105 return (error); 1106 lfs_dir_setino(fs, ep, newinum); 1107 lfs_dir_settype(fs, ep, newtype); 1108 oip->i_nlink--; 1109 DIP_ASSIGN(oip, nlink, oip->i_nlink); 1110 oip->i_flag |= IN_CHANGE; 1111 error = VOP_BWRITE(bp->b_vp, bp); 1112 dp->i_flag |= iflags; 1113 /* 1114 * If the last named reference to a snapshot goes away, 1115 * drop its snapshot reference so that it will be reclaimed 1116 * when last open reference goes away. 1117 */ 1118 if ((oip->i_flags & SF_SNAPSHOT) != 0 && oip->i_nlink == 0) 1119 ulfs_snapgone(oip); 1120 return (error); 1121 } 1122 1123 /* 1124 * Check if a directory is empty or not. 1125 * Inode supplied must be locked. 1126 * 1127 * Using a struct lfs_dirtemplate here is not precisely 1128 * what we want, but better than using a struct lfs_direct. 1129 * 1130 * NB: does not handle corrupted directories. 1131 */ 1132 int 1133 ulfs_dirempty(struct inode *ip, ino_t parentino, kauth_cred_t cred) 1134 { 1135 struct lfs *fs = ip->i_lfs; 1136 doff_t off; 1137 union lfs_dirtemplate dbuf; 1138 LFS_DIRHEADER *dp = (LFS_DIRHEADER *)&dbuf; 1139 int error, namlen; 1140 const char *name; 1141 size_t count; 1142 /* XXX this should probably use LFS_DIRECTSIZ(fs, 2) */ 1143 #define MINDIRSIZ (sizeof (struct lfs_dirtemplate64) / 2) 1144 1145 for (off = 0; off < ip->i_size; off += lfs_dir_getreclen(fs, dp)) { 1146 error = ulfs_bufio(UIO_READ, ITOV(ip), (void *)dp, MINDIRSIZ, 1147 off, IO_NODELOCKED, cred, &count, NULL); 1148 /* 1149 * Since we read MINDIRSIZ, residual must 1150 * be 0 unless we're at end of file. 1151 */ 1152 if (error || count != 0) 1153 return (0); 1154 /* avoid infinite loops */ 1155 if (lfs_dir_getreclen(fs, dp) == 0) 1156 return (0); 1157 /* skip empty entries */ 1158 if (lfs_dir_getino(fs, dp) == 0 || 1159 lfs_dir_getino(fs, dp) == ULFS_WINO) 1160 continue; 1161 /* accept only "." and ".." */ 1162 namlen = lfs_dir_getnamlen(fs, dp); 1163 name = lfs_dir_nameptr(fs, dp); 1164 if (namlen > 2) 1165 return (0); 1166 if (name[0] != '.') 1167 return (0); 1168 /* 1169 * At this point namlen must be 1 or 2. 1170 * 1 implies ".", 2 implies ".." if second 1171 * char is also "." 1172 */ 1173 if (namlen == 1 && lfs_dir_getino(fs, dp) == ip->i_number) 1174 continue; 1175 if (name[1] == '.' && lfs_dir_getino(fs, dp) == parentino) 1176 continue; 1177 return (0); 1178 } 1179 return (1); 1180 } 1181 1182 #define ULFS_DIRRABLKS 0 1183 int ulfs_dirrablks = ULFS_DIRRABLKS; 1184 1185 /* 1186 * ulfs_blkatoff: Return buffer with the contents of block "offset" from 1187 * the beginning of directory "vp". If "res" is non-NULL, fill it in with 1188 * a pointer to the remaining space in the directory. If the caller intends 1189 * to modify the buffer returned, "modify" must be true. 1190 */ 1191 1192 int 1193 ulfs_blkatoff(struct vnode *vp, off_t offset, char **res, struct buf **bpp, 1194 bool modify) 1195 { 1196 struct inode *ip __diagused; 1197 struct buf *bp; 1198 daddr_t lbn; 1199 const int dirrablks = ulfs_dirrablks; 1200 daddr_t *blks; 1201 int *blksizes; 1202 int run, error; 1203 struct mount *mp = vp->v_mount; 1204 const int bshift = mp->mnt_fs_bshift; 1205 const int bsize = 1 << bshift; 1206 off_t eof; 1207 1208 blks = kmem_alloc((1 + dirrablks) * sizeof(daddr_t), KM_SLEEP); 1209 blksizes = kmem_alloc((1 + dirrablks) * sizeof(int), KM_SLEEP); 1210 ip = VTOI(vp); 1211 KASSERT(vp->v_size == ip->i_size); 1212 GOP_SIZE(vp, vp->v_size, &eof, 0); 1213 lbn = offset >> bshift; 1214 1215 for (run = 0; run <= dirrablks;) { 1216 const off_t curoff = lbn << bshift; 1217 const int size = MIN(eof - curoff, bsize); 1218 1219 if (size == 0) { 1220 break; 1221 } 1222 KASSERT(curoff < eof); 1223 blks[run] = lbn; 1224 blksizes[run] = size; 1225 lbn++; 1226 run++; 1227 if (size != bsize) { 1228 break; 1229 } 1230 } 1231 KASSERT(run >= 1); 1232 error = breadn(vp, blks[0], blksizes[0], &blks[1], &blksizes[1], 1233 run - 1, (modify ? B_MODIFY : 0), &bp); 1234 if (error != 0) { 1235 *bpp = NULL; 1236 goto out; 1237 } 1238 if (res) { 1239 *res = (char *)bp->b_data + (offset & (bsize - 1)); 1240 } 1241 *bpp = bp; 1242 1243 out: 1244 kmem_free(blks, (1 + dirrablks) * sizeof(daddr_t)); 1245 kmem_free(blksizes, (1 + dirrablks) * sizeof(int)); 1246 return error; 1247 } 1248