11541Srgrimes/*- 21541Srgrimes * Copyright (c) 1989, 1993, 1994 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * This code is derived from software contributed to Berkeley 61541Srgrimes * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension 71541Srgrimes * Support code is derived from software contributed to Berkeley 81541Srgrimes * by Atsushi Murai (amurai@spec.co.jp). 91541Srgrimes * 101541Srgrimes * Redistribution and use in source and binary forms, with or without 111541Srgrimes * modification, are permitted provided that the following conditions 121541Srgrimes * are met: 131541Srgrimes * 1. Redistributions of source code must retain the above copyright 141541Srgrimes * notice, this list of conditions and the following disclaimer. 151541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161541Srgrimes * notice, this list of conditions and the following disclaimer in the 171541Srgrimes * documentation and/or other materials provided with the distribution. 181541Srgrimes * 4. Neither the name of the University nor the names of its contributors 191541Srgrimes * may be used to endorse or promote products derived from this software 201541Srgrimes * without specific prior written permission. 211541Srgrimes * 221541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 231541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 241541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 251541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 261541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 271541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 281541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 291541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 301541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 311541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 321541Srgrimes * SUCH DAMAGE. 331541Srgrimes * 341541Srgrimes * from: @(#)ufs_lookup.c 7.33 (Berkeley) 5/19/91 351541Srgrimes * @(#)cd9660_lookup.c 8.2 (Berkeley) 1/23/94 361541Srgrimes */ 371541Srgrimes 38116181Sobrien#include <sys/cdefs.h> 39116181Sobrien__FBSDID("$FreeBSD$"); 40116181Sobrien 411541Srgrimes#include <sys/param.h> 422806Sbde#include <sys/systm.h> 431541Srgrimes#include <sys/namei.h> 4460041Sphk#include <sys/bio.h> 451541Srgrimes#include <sys/buf.h> 461541Srgrimes#include <sys/vnode.h> 471541Srgrimes#include <sys/mount.h> 481541Srgrimes 49166639Srodrigc#include <fs/cd9660/iso.h> 50166639Srodrigc#include <fs/cd9660/cd9660_node.h> 51166639Srodrigc#include <fs/cd9660/iso_rrip.h> 521541Srgrimes 531541Srgrimes/* 541541Srgrimes * Convert a component of a pathname into a pointer to a locked inode. 551541Srgrimes * This is a very central and rather complicated routine. 5696755Strhodes * If the filesystem is not maintained in a strict tree hierarchy, 571541Srgrimes * this can result in a deadlock situation (see comments in code below). 581541Srgrimes * 591541Srgrimes * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on 601541Srgrimes * whether the name is to be looked up, created, renamed, or deleted. 611541Srgrimes * When CREATE, RENAME, or DELETE is specified, information usable in 621541Srgrimes * creating, renaming, or deleting a directory entry may be calculated. 631541Srgrimes * If flag has LOCKPARENT or'ed into it and the target of the pathname 641541Srgrimes * exists, lookup returns both the target and its parent directory locked. 651541Srgrimes * When creating or renaming and LOCKPARENT is specified, the target may 661541Srgrimes * not be ".". When deleting and LOCKPARENT is specified, the target may 671541Srgrimes * be "."., but the caller must check to ensure it does an vrele and iput 681541Srgrimes * instead of two iputs. 691541Srgrimes * 701541Srgrimes * Overall outline of ufs_lookup: 711541Srgrimes * 721541Srgrimes * search for name in directory, to found or notfound 731541Srgrimes * notfound: 741541Srgrimes * if creating, return locked directory, leaving info on available slots 751541Srgrimes * else return error 761541Srgrimes * found: 771541Srgrimes * if at end of path and deleting, return information to allow delete 781541Srgrimes * if at end of path and rewriting (RENAME and LOCKPARENT), lock target 791541Srgrimes * inode and return info to allow rewrite 801541Srgrimes * if not at end, add name to cache; if at end and neither creating 811541Srgrimes * nor deleting, add name to cache 821541Srgrimes * 831541Srgrimes * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent inode unlocked. 841541Srgrimes */ 851549Srgrimesint 861541Srgrimescd9660_lookup(ap) 8728787Sphk struct vop_cachedlookup_args /* { 881541Srgrimes struct vnode *a_dvp; 891541Srgrimes struct vnode **a_vpp; 901541Srgrimes struct componentname *a_cnp; 911541Srgrimes } */ *ap; 921541Srgrimes{ 93131526Sphk struct vnode *vdp; /* vnode for directory being searched */ 94131526Sphk struct iso_node *dp; /* inode for directory being searched */ 95131526Sphk struct iso_mnt *imp; /* filesystem that directory is in */ 961541Srgrimes struct buf *bp; /* a buffer of directory entries */ 97187838Sjhb struct iso_directory_record *ep;/* the current directory entry */ 98187838Sjhb struct iso_directory_record *ep2;/* copy of current directory entry */ 991541Srgrimes int entryoffsetinblock; /* offset of ep in bp's buffer */ 1001549Srgrimes int saveoffset = 0; /* offset of last directory entry in dir */ 101187838Sjhb doff_t i_diroff; /* cached i_diroff value. */ 102187838Sjhb doff_t i_offset; /* cached i_offset value. */ 1031541Srgrimes int numdirpasses; /* strategy for directory search */ 1041541Srgrimes doff_t endsearch; /* offset to end directory search */ 10522521Sdyson struct vnode *pdp; /* saved dp during symlink work */ 10622521Sdyson struct vnode *tdp; /* returned by cd9660_vget_internal */ 10722521Sdyson u_long bmask; /* block offset mask */ 1081541Srgrimes int error; 109187838Sjhb ino_t ino, i_ino; 110187838Sjhb int ltype, reclen; 1111541Srgrimes u_short namelen; 1125651Sjoerg int isoflags; 1131541Srgrimes char altname[NAME_MAX]; 1141541Srgrimes int res; 1151541Srgrimes int assoc, len; 1161541Srgrimes char *name; 117187838Sjhb struct mount *mp; 1181541Srgrimes struct vnode **vpp = ap->a_vpp; 1191541Srgrimes struct componentname *cnp = ap->a_cnp; 1201541Srgrimes int flags = cnp->cn_flags; 1211541Srgrimes int nameiop = cnp->cn_nameiop; 1228876Srgrimes 123187838Sjhb ep2 = ep = NULL; 1241541Srgrimes bp = NULL; 1251541Srgrimes *vpp = NULL; 1261541Srgrimes vdp = ap->a_dvp; 1271541Srgrimes dp = VTOI(vdp); 1281541Srgrimes imp = dp->i_mnt; 1298876Srgrimes 1301541Srgrimes /* 1311541Srgrimes * We now have a segment name to search for, and a directory to search. 1321541Srgrimes */ 133187838Sjhb ino = reclen = 0; 134187838Sjhb i_diroff = dp->i_diroff; 1351541Srgrimes len = cnp->cn_namelen; 1361541Srgrimes name = cnp->cn_nameptr; 137187838Sjhb 1381541Srgrimes /* 1391541Srgrimes * A leading `=' means, we are looking for an associated file 1401541Srgrimes */ 1413106Sgpalmer if ((assoc = (imp->iso_ftype != ISO_FTYPE_RRIP && *name == ASSOCCHAR))) 1423106Sgpalmer { 1431541Srgrimes len--; 1441541Srgrimes name++; 1451541Srgrimes } 1468876Srgrimes 1471541Srgrimes /* 1481541Srgrimes * If there is cached information on a previous search of 1491541Srgrimes * this directory, pick up where we last left off. 1501541Srgrimes * We cache only lookups as these are the most common 1511541Srgrimes * and have the greatest payoff. Caching CREATE has little 1521541Srgrimes * benefit as it usually must search the entire directory 1531541Srgrimes * to determine that the entry does not exist. Caching the 1541541Srgrimes * location of the last DELETE or RENAME has not reduced 1551541Srgrimes * profiling time and hence has been removed in the interest 1561541Srgrimes * of simplicity. 1571541Srgrimes */ 15822521Sdyson bmask = imp->im_bmask; 159187838Sjhb if (nameiop != LOOKUP || i_diroff == 0 || i_diroff > dp->i_size) { 1601541Srgrimes entryoffsetinblock = 0; 161187838Sjhb i_offset = 0; 1621541Srgrimes numdirpasses = 1; 1631541Srgrimes } else { 164187838Sjhb i_offset = i_diroff; 165187838Sjhb if ((entryoffsetinblock = i_offset & bmask) && 166187838Sjhb (error = cd9660_blkatoff(vdp, (off_t)i_offset, NULL, &bp))) 1671541Srgrimes return (error); 1681541Srgrimes numdirpasses = 2; 16923527Sbde nchstats.ncs_2passes++; 1701541Srgrimes } 17122521Sdyson endsearch = dp->i_size; 172131526Sphk 1731541Srgrimessearchloop: 174187838Sjhb while (i_offset < endsearch) { 1751541Srgrimes /* 1761541Srgrimes * If offset is on a block boundary, 1771541Srgrimes * read the next directory block. 1781541Srgrimes * Release previous if it exists. 1791541Srgrimes */ 180187838Sjhb if ((i_offset & bmask) == 0) { 1811541Srgrimes if (bp != NULL) 1821541Srgrimes brelse(bp); 18343301Sdillon if ((error = 184187838Sjhb cd9660_blkatoff(vdp, (off_t)i_offset, NULL, &bp)) != 0) 1851541Srgrimes return (error); 1861541Srgrimes entryoffsetinblock = 0; 1871541Srgrimes } 1881541Srgrimes /* 1891541Srgrimes * Get pointer to next entry. 1901541Srgrimes */ 1911541Srgrimes ep = (struct iso_directory_record *) 19222521Sdyson ((char *)bp->b_data + entryoffsetinblock); 193131526Sphk 19422521Sdyson reclen = isonum_711(ep->length); 1951541Srgrimes if (reclen == 0) { 1961541Srgrimes /* skip to next block, if any */ 197187838Sjhb i_offset = 198187838Sjhb (i_offset & ~bmask) + imp->logical_block_size; 1991541Srgrimes continue; 2001541Srgrimes } 2018876Srgrimes 2021541Srgrimes if (reclen < ISO_DIRECTORY_RECORD_SIZE) 2031541Srgrimes /* illegal entry, stop */ 2041541Srgrimes break; 2058876Srgrimes 2061541Srgrimes if (entryoffsetinblock + reclen > imp->logical_block_size) 2071541Srgrimes /* entries are not allowed to cross boundaries */ 2081541Srgrimes break; 209131526Sphk 2101541Srgrimes namelen = isonum_711(ep->name_len); 2115651Sjoerg isoflags = isonum_711(imp->iso_ftype == ISO_FTYPE_HIGH_SIERRA? 2125651Sjoerg &ep->date[6]: ep->flags); 2138876Srgrimes 2141541Srgrimes if (reclen < ISO_DIRECTORY_RECORD_SIZE + namelen) 2151541Srgrimes /* illegal entry, stop */ 2161541Srgrimes break; 217131526Sphk 21822521Sdyson /* 21922521Sdyson * Check for a name match. 22022521Sdyson */ 2211541Srgrimes switch (imp->iso_ftype) { 2221541Srgrimes default: 2235651Sjoerg if (!(isoflags & 4) == !assoc) { 2241541Srgrimes if ((len == 1 2251541Srgrimes && *name == '.') 2261541Srgrimes || (flags & ISDOTDOT)) { 2271541Srgrimes if (namelen == 1 2281541Srgrimes && ep->name[0] == ((flags & ISDOTDOT) ? 1 : 0)) { 2291541Srgrimes /* 2301541Srgrimes * Save directory entry's inode number and 23122521Sdyson * release directory buffer. 2321541Srgrimes */ 233187838Sjhb i_ino = isodirino(ep, imp); 2341541Srgrimes goto found; 2351541Srgrimes } 2361541Srgrimes if (namelen != 1 2371541Srgrimes || ep->name[0] != 0) 2381541Srgrimes goto notfound; 239120492Sfjoe } else if (!(res = isofncmp(name, len, 240120492Sfjoe ep->name, namelen, 241120492Sfjoe imp->joliet_level, 242120492Sfjoe imp->im_flags, 243120492Sfjoe imp->im_d2l, 244120492Sfjoe imp->im_l2d))) { 24522566Sbde if (isoflags & 2) 24622521Sdyson ino = isodirino(ep, imp); 2471541Srgrimes else 2481541Srgrimes ino = dbtob(bp->b_blkno) 2491541Srgrimes + entryoffsetinblock; 250187838Sjhb saveoffset = i_offset; 2511541Srgrimes } else if (ino) 2521541Srgrimes goto foundino; 2531541Srgrimes#ifdef NOSORTBUG /* On some CDs directory entries are not sorted correctly */ 2541541Srgrimes else if (res < 0) 2551541Srgrimes goto notfound; 2561541Srgrimes else if (res > 0 && numdirpasses == 2) 2571541Srgrimes numdirpasses++; 2581541Srgrimes#endif 2591541Srgrimes } 2601541Srgrimes break; 2611541Srgrimes case ISO_FTYPE_RRIP: 2621541Srgrimes if (isonum_711(ep->flags)&2) 26322521Sdyson ino = isodirino(ep, imp); 2641541Srgrimes else 2651541Srgrimes ino = dbtob(bp->b_blkno) + entryoffsetinblock; 266187838Sjhb i_ino = ino; 267187838Sjhb cd9660_rrip_getname(ep, altname, &namelen, &i_ino, imp); 2681541Srgrimes if (namelen == cnp->cn_namelen 2691541Srgrimes && !bcmp(name,altname,namelen)) 2701541Srgrimes goto found; 2711541Srgrimes ino = 0; 2721541Srgrimes break; 2731541Srgrimes } 274187838Sjhb i_offset += reclen; 2751541Srgrimes entryoffsetinblock += reclen; 2761541Srgrimes } 2771541Srgrimes if (ino) { 2781541Srgrimesfoundino: 279187838Sjhb i_ino = ino; 280187838Sjhb if (saveoffset != i_offset) { 281187838Sjhb if (lblkno(imp, i_offset) != 28222521Sdyson lblkno(imp, saveoffset)) { 2831541Srgrimes if (bp != NULL) 2841541Srgrimes brelse(bp); 28543301Sdillon if ((error = cd9660_blkatoff(vdp, 28643301Sdillon (off_t)saveoffset, NULL, &bp)) != 0) 2871541Srgrimes return (error); 2881541Srgrimes } 28922521Sdyson entryoffsetinblock = saveoffset & bmask; 29022521Sdyson ep = (struct iso_directory_record *) 29122521Sdyson ((char *)bp->b_data + entryoffsetinblock); 292187838Sjhb reclen = isonum_711(ep->length); 293187838Sjhb i_offset = saveoffset; 2941541Srgrimes } 2951541Srgrimes goto found; 2961541Srgrimes } 2971541Srgrimesnotfound: 2981541Srgrimes /* 2991541Srgrimes * If we started in the middle of the directory and failed 3001541Srgrimes * to find our target, we must check the beginning as well. 3011541Srgrimes */ 3021541Srgrimes if (numdirpasses == 2) { 3031541Srgrimes numdirpasses--; 304187838Sjhb i_offset = 0; 305187838Sjhb endsearch = i_diroff; 3061541Srgrimes goto searchloop; 3071541Srgrimes } 3081541Srgrimes if (bp != NULL) 3091541Srgrimes brelse(bp); 31022521Sdyson 3111541Srgrimes /* 3121541Srgrimes * Insert name into cache (as non-existent) if appropriate. 3131541Srgrimes */ 3141541Srgrimes if (cnp->cn_flags & MAKEENTRY) 3151541Srgrimes cache_enter(vdp, *vpp, cnp); 3161541Srgrimes if (nameiop == CREATE || nameiop == RENAME) 31712228Sdg return (EROFS); 3181541Srgrimes return (ENOENT); 3198876Srgrimes 3201541Srgrimesfound: 3211541Srgrimes if (numdirpasses == 2) 32223527Sbde nchstats.ncs_pass2++; 323131526Sphk 3241541Srgrimes /* 3251541Srgrimes * Found component in pathname. 3261541Srgrimes * If the final component of path name, save information 3271541Srgrimes * in the cache as to where the entry was found. 3281541Srgrimes */ 3291541Srgrimes if ((flags & ISLASTCN) && nameiop == LOOKUP) 330187838Sjhb dp->i_diroff = i_offset; 3318876Srgrimes 3321541Srgrimes /* 333187838Sjhb * Step through the translation in the name. We do not `vput' the 3341541Srgrimes * directory because we may need it again if a symbolic link 3351541Srgrimes * is relative to the current directory. Instead we save it 3361541Srgrimes * unlocked as "pdp". We must get the target inode before unlocking 3371541Srgrimes * the directory to insure that the inode will not be removed 3381541Srgrimes * before we get it. We prevent deadlock by always fetching 3391541Srgrimes * inodes from the root, moving down the directory tree. Thus 3401541Srgrimes * when following backward pointers ".." we must unlock the 3411541Srgrimes * parent directory before getting the requested directory. 3421541Srgrimes * There is a potential race condition here if both the current 343187838Sjhb * and parent directories are removed before the `vget' for the 3441541Srgrimes * inode associated with ".." returns. We hope that this occurs 3451541Srgrimes * infrequently since we cannot avoid this race condition without 3461541Srgrimes * implementing a sophisticated deadlock detection algorithm. 3471541Srgrimes * Note also that this simple deadlock detection scheme will not 34896755Strhodes * work if the filesystem has any hard links other than ".." 3491541Srgrimes * that point backwards in the directory structure. 3501541Srgrimes */ 35122521Sdyson pdp = vdp; 352187838Sjhb 3531541Srgrimes /* 354187838Sjhb * Make a copy of the directory entry for non "." lookups so 355187838Sjhb * we can drop the buffer before calling vget() to avoid a 356187838Sjhb * lock order reversal between the vnode lock and the buffer 357187838Sjhb * lock. 358187838Sjhb */ 359187838Sjhb if (dp->i_number != i_ino) { 360187838Sjhb ep2 = malloc(reclen, M_TEMP, M_WAITOK); 361187838Sjhb bcopy(ep, ep2, reclen); 362187838Sjhb ep = ep2; 363187838Sjhb } 364187838Sjhb brelse(bp); 365187838Sjhb 366187838Sjhb /* 367187838Sjhb * If ino is different from i_ino, 3681541Srgrimes * it's a relocated directory. 3691541Srgrimes */ 3701541Srgrimes if (flags & ISDOTDOT) { 371187838Sjhb /* 372187838Sjhb * Expanded copy of vn_vget_ino() so that we can use 373187838Sjhb * cd9660_vget_internal(). 374187838Sjhb */ 375187838Sjhb mp = pdp->v_mount; 376187838Sjhb ltype = VOP_ISLOCKED(pdp); 377194078Sjhb error = vfs_busy(mp, MBF_NOWAIT); 378194078Sjhb if (error != 0) { 379195294Skib vfs_ref(mp); 380187838Sjhb VOP_UNLOCK(pdp, 0); 381194078Sjhb error = vfs_busy(mp, 0); 382187838Sjhb vn_lock(pdp, ltype | LK_RETRY); 383195294Skib vfs_rel(mp); 384194078Sjhb if (error) 385187838Sjhb return (ENOENT); 386194078Sjhb if (pdp->v_iflag & VI_DOOMED) { 387194078Sjhb vfs_unbusy(mp); 388194078Sjhb return (ENOENT); 389194078Sjhb } 390187838Sjhb } 391187838Sjhb VOP_UNLOCK(pdp, 0); 392187838Sjhb error = cd9660_vget_internal(vdp->v_mount, i_ino, 393187838Sjhb cnp->cn_lkflags, &tdp, 394187838Sjhb i_ino != ino, ep); 395187838Sjhb free(ep2, M_TEMP); 396187838Sjhb vfs_unbusy(mp); 397187838Sjhb vn_lock(pdp, ltype | LK_RETRY); 398187838Sjhb if (pdp->v_iflag & VI_DOOMED) { 399187838Sjhb if (error == 0) 400187838Sjhb vput(tdp); 401187838Sjhb error = ENOENT; 402187838Sjhb } 403145006Sjeff if (error) 4041541Srgrimes return (error); 40522521Sdyson *vpp = tdp; 406187838Sjhb } else if (dp->i_number == i_ino) { 4071541Srgrimes VREF(vdp); /* we want ourself, ie "." */ 408187838Sjhb /* 409187838Sjhb * When we lookup "." we still can be asked to lock it 410187838Sjhb * differently. 411187838Sjhb */ 412187838Sjhb ltype = cnp->cn_lkflags & LK_TYPE_MASK; 413187838Sjhb if (ltype != VOP_ISLOCKED(vdp)) { 414187838Sjhb if (ltype == LK_EXCLUSIVE) 415187838Sjhb vn_lock(vdp, LK_UPGRADE | LK_RETRY); 416187838Sjhb else /* if (ltype == LK_SHARED) */ 417187838Sjhb vn_lock(vdp, LK_DOWNGRADE | LK_RETRY); 418187838Sjhb } 4191541Srgrimes *vpp = vdp; 4201541Srgrimes } else { 421187838Sjhb error = cd9660_vget_internal(vdp->v_mount, i_ino, 422187838Sjhb cnp->cn_lkflags, &tdp, 423187838Sjhb i_ino != ino, ep); 424187838Sjhb free(ep2, M_TEMP); 42522521Sdyson if (error) 4261541Srgrimes return (error); 42722521Sdyson *vpp = tdp; 4281541Srgrimes } 4298876Srgrimes 4301541Srgrimes /* 4311541Srgrimes * Insert name into cache if appropriate. 4321541Srgrimes */ 4331541Srgrimes if (cnp->cn_flags & MAKEENTRY) 4341541Srgrimes cache_enter(vdp, *vpp, cnp); 4351541Srgrimes return (0); 4361541Srgrimes} 4371541Srgrimes 4381541Srgrimes/* 43922521Sdyson * Return buffer with the contents of block "offset" from the beginning of 44022521Sdyson * directory "ip". If "res" is non-zero, fill it in with a pointer to the 4411541Srgrimes * remaining space in the directory. 4421541Srgrimes */ 4431549Srgrimesint 44430474Sphkcd9660_blkatoff(vp, offset, res, bpp) 44530474Sphk struct vnode *vp; 44630474Sphk off_t offset; 44730474Sphk char **res; 44830474Sphk struct buf **bpp; 44922521Sdyson{ 4501541Srgrimes struct iso_node *ip; 451131526Sphk struct iso_mnt *imp; 4521541Srgrimes struct buf *bp; 45322521Sdyson daddr_t lbn; 454119055Sphk int bsize, bshift, error; 4558876Srgrimes 45630474Sphk ip = VTOI(vp); 45722521Sdyson imp = ip->i_mnt; 45830474Sphk lbn = lblkno(imp, offset); 45922521Sdyson bsize = blksize(imp, ip, lbn); 460119055Sphk bshift = imp->im_bshift; 46186003Sdillon 46243301Sdillon if ((error = bread(vp, lbn, bsize, NOCRED, &bp)) != 0) { 4631541Srgrimes brelse(bp); 46430474Sphk *bpp = NULL; 4651541Srgrimes return (error); 4661541Srgrimes } 46786003Sdillon 46886003Sdillon /* 46986003Sdillon * We must BMAP the buffer because the directory code may use b_blkno 47086003Sdillon * to calculate the inode for certain types of directory entries. 47186003Sdillon * We could get away with not doing it before we VMIO-backed the 47286003Sdillon * directories because the buffers would get freed atomically with 47386003Sdillon * the invalidation of their data. But with VMIO-backed buffers 47486003Sdillon * the buffers may be freed and then later reconstituted - and the 47586003Sdillon * reconstituted buffer will have no knowledge of b_blkno. 47686003Sdillon */ 47786003Sdillon if (bp->b_blkno == bp->b_lblkno) { 478119055Sphk bp->b_blkno = (ip->iso_start + bp->b_lblkno) << (bshift - DEV_BSHIFT); 47986003Sdillon } 48086003Sdillon 48130474Sphk if (res) 48230474Sphk *res = (char *)bp->b_data + blkoff(imp, offset); 48330474Sphk *bpp = bp; 4841541Srgrimes return (0); 4851541Srgrimes} 486