1cfe60390STomohiro Kusumi /*- 2cfe60390STomohiro Kusumi * SPDX-License-Identifier: BSD-3-Clause 3cfe60390STomohiro Kusumi * 4cfe60390STomohiro Kusumi * Copyright (c) 1989, 1991, 1993 5cfe60390STomohiro Kusumi * The Regents of the University of California. All rights reserved. 6cfe60390STomohiro Kusumi * (c) UNIX System Laboratories, Inc. 7cfe60390STomohiro Kusumi * All or some portions of this file are derived from material licensed 8cfe60390STomohiro Kusumi * to the University of California by American Telephone and Telegraph 9cfe60390STomohiro Kusumi * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10cfe60390STomohiro Kusumi * the permission of UNIX System Laboratories, Inc. 11cfe60390STomohiro Kusumi * 12cfe60390STomohiro Kusumi * Redistribution and use in source and binary forms, with or without 13cfe60390STomohiro Kusumi * modification, are permitted provided that the following conditions 14cfe60390STomohiro Kusumi * are met: 15cfe60390STomohiro Kusumi * 1. Redistributions of source code must retain the above copyright 16cfe60390STomohiro Kusumi * notice, this list of conditions and the following disclaimer. 17cfe60390STomohiro Kusumi * 2. Redistributions in binary form must reproduce the above copyright 18cfe60390STomohiro Kusumi * notice, this list of conditions and the following disclaimer in the 19cfe60390STomohiro Kusumi * documentation and/or other materials provided with the distribution. 20cfe60390STomohiro Kusumi * 3. Neither the name of the University nor the names of its contributors 21cfe60390STomohiro Kusumi * may be used to endorse or promote products derived from this software 22cfe60390STomohiro Kusumi * without specific prior written permission. 23cfe60390STomohiro Kusumi * 24cfe60390STomohiro Kusumi * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25cfe60390STomohiro Kusumi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26cfe60390STomohiro Kusumi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27cfe60390STomohiro Kusumi * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28cfe60390STomohiro Kusumi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29cfe60390STomohiro Kusumi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30cfe60390STomohiro Kusumi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31cfe60390STomohiro Kusumi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32cfe60390STomohiro Kusumi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33cfe60390STomohiro Kusumi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34cfe60390STomohiro Kusumi * SUCH DAMAGE. 35cfe60390STomohiro Kusumi * 36cfe60390STomohiro Kusumi * @(#)ufs_bmap.c 8.7 (Berkeley) 3/21/95 37cfe60390STomohiro Kusumi * $FreeBSD$ 38cfe60390STomohiro Kusumi */ 39cfe60390STomohiro Kusumi 40cfe60390STomohiro Kusumi #include <sys/param.h> 41cfe60390STomohiro Kusumi #include <sys/systm.h> 42cfe60390STomohiro Kusumi #include <sys/bio.h> 43cfe60390STomohiro Kusumi #include <sys/buf.h> 44cfe60390STomohiro Kusumi #include <sys/endian.h> 45cfe60390STomohiro Kusumi #include <sys/proc.h> 46cfe60390STomohiro Kusumi #include <sys/vnode.h> 47cfe60390STomohiro Kusumi #include <sys/mount.h> 48cfe60390STomohiro Kusumi #include <sys/resourcevar.h> 49cfe60390STomohiro Kusumi #include <sys/stat.h> 50cfe60390STomohiro Kusumi 51cfe60390STomohiro Kusumi #include <vfs/ext2fs/fs.h> 52cfe60390STomohiro Kusumi #include <vfs/ext2fs/inode.h> 53cfe60390STomohiro Kusumi #include <vfs/ext2fs/ext2fs.h> 54cfe60390STomohiro Kusumi #include <vfs/ext2fs/ext2_dinode.h> 55cfe60390STomohiro Kusumi #include <vfs/ext2fs/ext2_extern.h> 56cfe60390STomohiro Kusumi #include <vfs/ext2fs/ext2_mount.h> 57cfe60390STomohiro Kusumi 58cfe60390STomohiro Kusumi /* 59cfe60390STomohiro Kusumi * Bmap converts the logical block number of a file to its physical block 60cfe60390STomohiro Kusumi * number on the disk. The conversion is done by using the logical block 61cfe60390STomohiro Kusumi * number to index into the array of block pointers described by the dinode. 62cfe60390STomohiro Kusumi * 63cfe60390STomohiro Kusumi * BMAP must return the contiguous before and after run in bytes, inclusive 64cfe60390STomohiro Kusumi * of the returned block. 65cfe60390STomohiro Kusumi */ 66cfe60390STomohiro Kusumi int 67cfe60390STomohiro Kusumi ext2_bmap(struct vop_bmap_args *ap) 68cfe60390STomohiro Kusumi { 69cfe60390STomohiro Kusumi struct m_ext2fs *fs; 70cfe60390STomohiro Kusumi daddr_t lbn, dbn; 71cfe60390STomohiro Kusumi int error; 72cfe60390STomohiro Kusumi 73cfe60390STomohiro Kusumi /* 74cfe60390STomohiro Kusumi * Check for underlying vnode requests and ensure that logical 75cfe60390STomohiro Kusumi * to physical mapping is requested. 76cfe60390STomohiro Kusumi */ 77cfe60390STomohiro Kusumi if (ap->a_doffsetp == NULL) 78cfe60390STomohiro Kusumi return (0); 79cfe60390STomohiro Kusumi 80cfe60390STomohiro Kusumi fs = VTOI(ap->a_vp)->i_e2fs; 81cfe60390STomohiro Kusumi KKASSERT(((int)ap->a_loffset & ((1 << fs->e2fs_bshift) - 1)) == 0); 82cfe60390STomohiro Kusumi lbn = ap->a_loffset >> fs->e2fs_bshift; 83cfe60390STomohiro Kusumi 84cfe60390STomohiro Kusumi if (VTOI(ap->a_vp)->i_flag & IN_E4EXTENTS) 85cfe60390STomohiro Kusumi error = ext4_bmapext(ap->a_vp, lbn, &dbn, ap->a_runp, 86cfe60390STomohiro Kusumi ap->a_runb); 87cfe60390STomohiro Kusumi else 88cfe60390STomohiro Kusumi error = ext2_bmaparray(ap->a_vp, lbn, &dbn, ap->a_runp, 89cfe60390STomohiro Kusumi ap->a_runb); 90cfe60390STomohiro Kusumi 91cfe60390STomohiro Kusumi if (error || dbn == (daddr_t)-1) { 92cfe60390STomohiro Kusumi *ap->a_doffsetp = NOOFFSET; 93cfe60390STomohiro Kusumi } else { 94cfe60390STomohiro Kusumi *ap->a_doffsetp = dbtodoff(fs, dbn); 95cfe60390STomohiro Kusumi if (ap->a_runp) 96cfe60390STomohiro Kusumi *ap->a_runp = (*ap->a_runp + 1) << fs->e2fs_bshift; 97cfe60390STomohiro Kusumi if (ap->a_runb) 98cfe60390STomohiro Kusumi *ap->a_runb = *ap->a_runb << fs->e2fs_bshift; 99cfe60390STomohiro Kusumi } 100cfe60390STomohiro Kusumi return (error); 101cfe60390STomohiro Kusumi } 102cfe60390STomohiro Kusumi 103cfe60390STomohiro Kusumi /* 104cfe60390STomohiro Kusumi * Convert the logical block number of a file to its physical block number 105cfe60390STomohiro Kusumi * on the disk within ext4 extents. 106cfe60390STomohiro Kusumi */ 107cfe60390STomohiro Kusumi int 108cfe60390STomohiro Kusumi ext4_bmapext(struct vnode *vp, int32_t bn, daddr_t/*int64_t*/ *bnp, int *runp, int *runb) 109cfe60390STomohiro Kusumi { 110cfe60390STomohiro Kusumi return (EINVAL); 111cfe60390STomohiro Kusumi } 112cfe60390STomohiro Kusumi 113cfe60390STomohiro Kusumi static int 114cfe60390STomohiro Kusumi readindir(struct vnode *vp, e2fs_lbn_t lbn, e2fs_daddr_t daddr, struct buf **bpp) 115cfe60390STomohiro Kusumi { 116cfe60390STomohiro Kusumi struct buf *bp; 117cfe60390STomohiro Kusumi struct mount *mp; 118cfe60390STomohiro Kusumi struct ext2mount *ump; 119cfe60390STomohiro Kusumi struct m_ext2fs *fs; 120cfe60390STomohiro Kusumi int error; 121cfe60390STomohiro Kusumi 122cfe60390STomohiro Kusumi mp = vp->v_mount; 123cfe60390STomohiro Kusumi ump = VFSTOEXT2(mp); 124cfe60390STomohiro Kusumi fs = VTOI(vp)->i_e2fs; 125cfe60390STomohiro Kusumi 126cfe60390STomohiro Kusumi bp = getblk(vp, lblktodoff(fs, lbn), mp->mnt_stat.f_iosize, 0, 0); 127cfe60390STomohiro Kusumi if ((bp->b_flags & B_CACHE) == 0) { 128cfe60390STomohiro Kusumi KASSERT(daddr != 0, 129cfe60390STomohiro Kusumi ("readindir: indirect block not in cache")); 130cfe60390STomohiro Kusumi /* 131cfe60390STomohiro Kusumi * This runs through ext2_strategy using bio2 to 132cfe60390STomohiro Kusumi * cache the disk offset, then comes back through 133cfe60390STomohiro Kusumi * bio1. So we want to wait on bio1. 134cfe60390STomohiro Kusumi */ 135cfe60390STomohiro Kusumi bp->b_bio1.bio_done = biodone_sync; 136cfe60390STomohiro Kusumi bp->b_bio1.bio_flags |= BIO_SYNC; 137cfe60390STomohiro Kusumi bp->b_bio2.bio_offset = fsbtodoff(fs, daddr); 138cfe60390STomohiro Kusumi bp->b_flags &= ~(B_INVAL | B_ERROR); 139cfe60390STomohiro Kusumi bp->b_cmd = BUF_CMD_READ; 140cfe60390STomohiro Kusumi vfs_busy_pages(bp->b_vp, bp); 141cfe60390STomohiro Kusumi vn_strategy(bp->b_vp, &bp->b_bio1); 142cfe60390STomohiro Kusumi #ifdef RACCT 143cfe60390STomohiro Kusumi if (racct_enable) { 144cfe60390STomohiro Kusumi PROC_LOCK(curproc); 145cfe60390STomohiro Kusumi racct_add_buf(curproc, bp, 0); 146cfe60390STomohiro Kusumi PROC_UNLOCK(curproc); 147cfe60390STomohiro Kusumi } 148cfe60390STomohiro Kusumi #endif 149cfe60390STomohiro Kusumi error = biowait(&bp->b_bio1, "biord"); 150cfe60390STomohiro Kusumi if (error) { 151*e5b38eb5STomohiro Kusumi brelse(bp); 152cfe60390STomohiro Kusumi return (error); 153cfe60390STomohiro Kusumi } 154cfe60390STomohiro Kusumi } 155cfe60390STomohiro Kusumi *bpp = bp; 156cfe60390STomohiro Kusumi return (0); 157cfe60390STomohiro Kusumi } 158cfe60390STomohiro Kusumi 159cfe60390STomohiro Kusumi /* 160cfe60390STomohiro Kusumi * Indirect blocks are now on the vnode for the file. They are given negative 161cfe60390STomohiro Kusumi * logical block numbers. Indirect blocks are addressed by the negative 162cfe60390STomohiro Kusumi * address of the first data block to which they point. Double indirect blocks 163cfe60390STomohiro Kusumi * are addressed by one less than the address of the first indirect block to 164cfe60390STomohiro Kusumi * which they point. Triple indirect blocks are addressed by one less than 165cfe60390STomohiro Kusumi * the address of the first double indirect block to which they point. 166cfe60390STomohiro Kusumi * 167cfe60390STomohiro Kusumi * ext2_bmaparray does the bmap conversion, and if requested returns the 168cfe60390STomohiro Kusumi * array of logical blocks which must be traversed to get to a block. 169cfe60390STomohiro Kusumi * Each entry contains the offset into that block that gets you to the 170cfe60390STomohiro Kusumi * next block and the disk address of the block (if it is assigned). 171cfe60390STomohiro Kusumi */ 172cfe60390STomohiro Kusumi 173cfe60390STomohiro Kusumi int 174cfe60390STomohiro Kusumi ext2_bmaparray(struct vnode *vp, daddr_t bn, daddr_t *bnp, int *runp, int *runb) 175cfe60390STomohiro Kusumi { 176cfe60390STomohiro Kusumi struct inode *ip; 177cfe60390STomohiro Kusumi struct buf *bp; 178cfe60390STomohiro Kusumi struct ext2mount *ump; 179cfe60390STomohiro Kusumi struct mount *mp; 180cfe60390STomohiro Kusumi struct m_ext2fs *fs; 181cfe60390STomohiro Kusumi struct indir a[EXT2_NIADDR + 1], *ap; 182cfe60390STomohiro Kusumi daddr_t daddr; 183cfe60390STomohiro Kusumi e2fs_lbn_t metalbn; 184cfe60390STomohiro Kusumi int error, num, maxrun = 0, bsize; 185cfe60390STomohiro Kusumi int *nump; 186cfe60390STomohiro Kusumi 187cfe60390STomohiro Kusumi ap = NULL; 188cfe60390STomohiro Kusumi ip = VTOI(vp); 189cfe60390STomohiro Kusumi mp = vp->v_mount; 190cfe60390STomohiro Kusumi ump = VFSTOEXT2(mp); 191cfe60390STomohiro Kusumi fs = ip->i_e2fs; 192cfe60390STomohiro Kusumi 193cfe60390STomohiro Kusumi bsize = EXT2_BLOCK_SIZE(ump->um_e2fs); 194cfe60390STomohiro Kusumi 195cfe60390STomohiro Kusumi if (runp) { 196cfe60390STomohiro Kusumi maxrun = mp->mnt_iosize_max / bsize - 1; 197cfe60390STomohiro Kusumi *runp = 0; 198cfe60390STomohiro Kusumi } 199cfe60390STomohiro Kusumi if (runb) 200cfe60390STomohiro Kusumi *runb = 0; 201cfe60390STomohiro Kusumi 202cfe60390STomohiro Kusumi 203cfe60390STomohiro Kusumi ap = a; 204cfe60390STomohiro Kusumi nump = # 205cfe60390STomohiro Kusumi error = ext2_getlbns(vp, bn, ap, nump); 206cfe60390STomohiro Kusumi if (error) 207cfe60390STomohiro Kusumi return (error); 208cfe60390STomohiro Kusumi 209cfe60390STomohiro Kusumi num = *nump; 210cfe60390STomohiro Kusumi if (num == 0) { 211cfe60390STomohiro Kusumi *bnp = blkptrtodb(ump, ip->i_db[bn]); 212cfe60390STomohiro Kusumi if (*bnp == 0) { 213cfe60390STomohiro Kusumi *bnp = -1; 214cfe60390STomohiro Kusumi } else if (runp) { 215cfe60390STomohiro Kusumi daddr_t bnb = bn; 216cfe60390STomohiro Kusumi 217cfe60390STomohiro Kusumi for (++bn; bn < EXT2_NDADDR && *runp < maxrun && 218cfe60390STomohiro Kusumi is_sequential(ump, ip->i_db[bn - 1], ip->i_db[bn]); 219cfe60390STomohiro Kusumi ++bn, ++*runp); 220cfe60390STomohiro Kusumi bn = bnb; 221cfe60390STomohiro Kusumi if (runb && (bn > 0)) { 222cfe60390STomohiro Kusumi for (--bn; (bn >= 0) && (*runb < maxrun) && 223cfe60390STomohiro Kusumi is_sequential(ump, ip->i_db[bn], 224cfe60390STomohiro Kusumi ip->i_db[bn + 1]); 225cfe60390STomohiro Kusumi --bn, ++*runb); 226cfe60390STomohiro Kusumi } 227cfe60390STomohiro Kusumi } 228cfe60390STomohiro Kusumi return (0); 229cfe60390STomohiro Kusumi } 230cfe60390STomohiro Kusumi 231cfe60390STomohiro Kusumi /* Get disk address out of indirect block array */ 232cfe60390STomohiro Kusumi daddr = ip->i_ib[ap->in_off]; 233cfe60390STomohiro Kusumi 234cfe60390STomohiro Kusumi for (bp = NULL, ++ap; --num; ++ap) { 235cfe60390STomohiro Kusumi /* 236cfe60390STomohiro Kusumi * Exit the loop if there is no disk address assigned yet and 237cfe60390STomohiro Kusumi * the indirect block isn't in the cache, or if we were 238cfe60390STomohiro Kusumi * looking for an indirect block and we've found it. 239cfe60390STomohiro Kusumi */ 240cfe60390STomohiro Kusumi 241cfe60390STomohiro Kusumi metalbn = ap->in_lbn; 242cfe60390STomohiro Kusumi if ((daddr == 0 && 243cfe60390STomohiro Kusumi !findblk(vp, dbtodoff(fs, metalbn), FINDBLK_TEST)) || 244cfe60390STomohiro Kusumi metalbn == bn) 245cfe60390STomohiro Kusumi break; 246cfe60390STomohiro Kusumi /* 247cfe60390STomohiro Kusumi * If we get here, we've either got the block in the cache 248cfe60390STomohiro Kusumi * or we have a disk address for it, go fetch it. 249cfe60390STomohiro Kusumi */ 250cfe60390STomohiro Kusumi if (bp) 251*e5b38eb5STomohiro Kusumi bqrelse(bp); 252cfe60390STomohiro Kusumi error = readindir(vp, metalbn, daddr, &bp); 253cfe60390STomohiro Kusumi if (error != 0) 254cfe60390STomohiro Kusumi return (error); 255cfe60390STomohiro Kusumi 256cfe60390STomohiro Kusumi daddr = le32toh(((e2fs_daddr_t *)bp->b_data)[ap->in_off]); 257cfe60390STomohiro Kusumi if (num == 1 && daddr && runp) { 258cfe60390STomohiro Kusumi for (bn = ap->in_off + 1; 259cfe60390STomohiro Kusumi bn < MNINDIR(ump) && *runp < maxrun && 260cfe60390STomohiro Kusumi is_sequential(ump, 261cfe60390STomohiro Kusumi ((e2fs_daddr_t *)bp->b_data)[bn - 1], 262cfe60390STomohiro Kusumi ((e2fs_daddr_t *)bp->b_data)[bn]); 263cfe60390STomohiro Kusumi ++bn, ++*runp); 264cfe60390STomohiro Kusumi bn = ap->in_off; 265cfe60390STomohiro Kusumi if (runb && bn) { 266cfe60390STomohiro Kusumi for (--bn; bn >= 0 && *runb < maxrun && 267cfe60390STomohiro Kusumi is_sequential(ump, 268cfe60390STomohiro Kusumi ((e2fs_daddr_t *)bp->b_data)[bn], 269cfe60390STomohiro Kusumi ((e2fs_daddr_t *)bp->b_data)[bn + 1]); 270cfe60390STomohiro Kusumi --bn, ++*runb); 271cfe60390STomohiro Kusumi } 272cfe60390STomohiro Kusumi } 273cfe60390STomohiro Kusumi } 274cfe60390STomohiro Kusumi if (bp) 275*e5b38eb5STomohiro Kusumi bqrelse(bp); 276cfe60390STomohiro Kusumi 277cfe60390STomohiro Kusumi *bnp = blkptrtodb(ump, daddr); 278cfe60390STomohiro Kusumi if (*bnp == 0) { 279cfe60390STomohiro Kusumi *bnp = -1; 280cfe60390STomohiro Kusumi } 281cfe60390STomohiro Kusumi return (0); 282cfe60390STomohiro Kusumi } 283cfe60390STomohiro Kusumi 284cfe60390STomohiro Kusumi /* 285cfe60390STomohiro Kusumi * Create an array of logical block number/offset pairs which represent the 286cfe60390STomohiro Kusumi * path of indirect blocks required to access a data block. The first "pair" 287cfe60390STomohiro Kusumi * contains the logical block number of the appropriate single, double or 288cfe60390STomohiro Kusumi * triple indirect block and the offset into the inode indirect block array. 289cfe60390STomohiro Kusumi * Note, the logical block number of the inode single/double/triple indirect 290cfe60390STomohiro Kusumi * block appears twice in the array, once with the offset into the i_ib and 291cfe60390STomohiro Kusumi * once with the offset into the page itself. 292cfe60390STomohiro Kusumi */ 293cfe60390STomohiro Kusumi int 294cfe60390STomohiro Kusumi ext2_getlbns(struct vnode *vp, daddr_t bn, struct indir *ap, int *nump) 295cfe60390STomohiro Kusumi { 296cfe60390STomohiro Kusumi long blockcnt; 297cfe60390STomohiro Kusumi e2fs_lbn_t metalbn, realbn; 298cfe60390STomohiro Kusumi struct ext2mount *ump; 299cfe60390STomohiro Kusumi int i, numlevels, off; 300cfe60390STomohiro Kusumi int64_t qblockcnt; 301cfe60390STomohiro Kusumi 302cfe60390STomohiro Kusumi ump = VFSTOEXT2(vp->v_mount); 303cfe60390STomohiro Kusumi if (nump) 304cfe60390STomohiro Kusumi *nump = 0; 305cfe60390STomohiro Kusumi numlevels = 0; 306cfe60390STomohiro Kusumi realbn = bn; 307cfe60390STomohiro Kusumi if ((long)bn < 0) 308cfe60390STomohiro Kusumi bn = -(long)bn; 309cfe60390STomohiro Kusumi 310cfe60390STomohiro Kusumi /* The first EXT2_NDADDR blocks are direct blocks. */ 311cfe60390STomohiro Kusumi if (bn < EXT2_NDADDR) 312cfe60390STomohiro Kusumi return (0); 313cfe60390STomohiro Kusumi 314cfe60390STomohiro Kusumi /* 315cfe60390STomohiro Kusumi * Determine the number of levels of indirection. After this loop 316cfe60390STomohiro Kusumi * is done, blockcnt indicates the number of data blocks possible 317cfe60390STomohiro Kusumi * at the previous level of indirection, and EXT2_NIADDR - i is the 318cfe60390STomohiro Kusumi * number of levels of indirection needed to locate the requested block. 319cfe60390STomohiro Kusumi */ 320cfe60390STomohiro Kusumi for (blockcnt = 1, i = EXT2_NIADDR, bn -= EXT2_NDADDR; ; 321cfe60390STomohiro Kusumi i--, bn -= blockcnt) { 322cfe60390STomohiro Kusumi if (i == 0) 323cfe60390STomohiro Kusumi return (EFBIG); 324cfe60390STomohiro Kusumi /* 325cfe60390STomohiro Kusumi * Use int64_t's here to avoid overflow for triple indirect 326cfe60390STomohiro Kusumi * blocks when longs have 32 bits and the block size is more 327cfe60390STomohiro Kusumi * than 4K. 328cfe60390STomohiro Kusumi */ 329cfe60390STomohiro Kusumi qblockcnt = (int64_t)blockcnt * MNINDIR(ump); 330cfe60390STomohiro Kusumi if (bn < qblockcnt) 331cfe60390STomohiro Kusumi break; 332cfe60390STomohiro Kusumi blockcnt = qblockcnt; 333cfe60390STomohiro Kusumi } 334cfe60390STomohiro Kusumi 335cfe60390STomohiro Kusumi /* Calculate the address of the first meta-block. */ 336cfe60390STomohiro Kusumi if (realbn >= 0) 337cfe60390STomohiro Kusumi metalbn = -(realbn - bn + EXT2_NIADDR - i); 338cfe60390STomohiro Kusumi else 339cfe60390STomohiro Kusumi metalbn = -(-realbn - bn + EXT2_NIADDR - i); 340cfe60390STomohiro Kusumi 341cfe60390STomohiro Kusumi /* 342cfe60390STomohiro Kusumi * At each iteration, off is the offset into the bap array which is 343cfe60390STomohiro Kusumi * an array of disk addresses at the current level of indirection. 344cfe60390STomohiro Kusumi * The logical block number and the offset in that block are stored 345cfe60390STomohiro Kusumi * into the argument array. 346cfe60390STomohiro Kusumi */ 347cfe60390STomohiro Kusumi ap->in_lbn = metalbn; 348cfe60390STomohiro Kusumi ap->in_off = off = EXT2_NIADDR - i; 349cfe60390STomohiro Kusumi ap++; 350cfe60390STomohiro Kusumi for (++numlevels; i <= EXT2_NIADDR; i++) { 351cfe60390STomohiro Kusumi /* If searching for a meta-data block, quit when found. */ 352cfe60390STomohiro Kusumi if (metalbn == realbn) 353cfe60390STomohiro Kusumi break; 354cfe60390STomohiro Kusumi 355cfe60390STomohiro Kusumi off = (bn / blockcnt) % MNINDIR(ump); 356cfe60390STomohiro Kusumi 357cfe60390STomohiro Kusumi ++numlevels; 358cfe60390STomohiro Kusumi ap->in_lbn = metalbn; 359cfe60390STomohiro Kusumi ap->in_off = off; 360cfe60390STomohiro Kusumi ++ap; 361cfe60390STomohiro Kusumi 362cfe60390STomohiro Kusumi metalbn -= -1 + off * blockcnt; 363cfe60390STomohiro Kusumi blockcnt /= MNINDIR(ump); 364cfe60390STomohiro Kusumi } 365cfe60390STomohiro Kusumi if (nump) 366cfe60390STomohiro Kusumi *nump = numlevels; 367cfe60390STomohiro Kusumi return (0); 368cfe60390STomohiro Kusumi } 369