123396Smckusick /* 251494Sbostic * Copyright (c) 1989, 1991 Regents of the University of California. 337736Smckusick * All rights reserved. 423396Smckusick * 544537Sbostic * %sccs.include.redist.c% 637736Smckusick * 7*51855Sbostic * @(#)lfs_balloc.c 7.23 (Berkeley) 12/06/91 823396Smckusick */ 97443Sroot 1051486Sbostic #include <sys/param.h> 1151486Sbostic #include <sys/buf.h> 1251486Sbostic #include <sys/proc.h> 1351486Sbostic #include <sys/vnode.h> 1451486Sbostic #include <sys/mount.h> 1551486Sbostic #include <sys/resourcevar.h> 1651486Sbostic #include <sys/specdev.h> 1751486Sbostic #include <sys/trace.h> 187443Sroot 1951494Sbostic #include <ufs/ufs/quota.h> 2051494Sbostic #include <ufs/ufs/inode.h> 2151494Sbostic #include <ufs/ufs/ufsmount.h> 2247571Skarels 2351494Sbostic #include <ufs/lfs/lfs.h> 2451494Sbostic #include <ufs/lfs/lfs_extern.h> 2551486Sbostic 26*51855Sbostic static int lfs_getlbns __P((struct vnode *, daddr_t, INDIR *, int *)); 27*51855Sbostic 287443Sroot /* 2951486Sbostic * Bmap converts a the logical block number of a file to its physical block 3051486Sbostic * number on the disk. The conversion is done by using the logical block 3151486Sbostic * number to index into the array of block pointers described by the dinode. 32*51855Sbostic */ 33*51855Sbostic int 34*51855Sbostic lfs_bmap(vp, bn, vpp, bnp) 35*51855Sbostic struct vnode *vp; 36*51855Sbostic register daddr_t bn; 37*51855Sbostic struct vnode **vpp; 38*51855Sbostic daddr_t *bnp; 39*51855Sbostic { 40*51855Sbostic #ifdef VERBOSE 41*51855Sbostic printf("lfs_bmap\n"); 42*51855Sbostic #endif 43*51855Sbostic /* 44*51855Sbostic * Check for underlying vnode requests and ensure that logical 45*51855Sbostic * to physical mapping is requested. 46*51855Sbostic */ 47*51855Sbostic if (vpp != NULL) 48*51855Sbostic *vpp = VTOI(vp)->i_devvp; 49*51855Sbostic if (bnp == NULL) 50*51855Sbostic return (0); 51*51855Sbostic 52*51855Sbostic return (lfs_bmaparray(vp, bn, bnp, NULL, NULL)); 53*51855Sbostic } 54*51855Sbostic 55*51855Sbostic /* 5651846Sbostic * LFS has a different version of bmap from FFS because of a naming conflict. 5751846Sbostic * In FFS, meta blocks are given real disk addresses at allocation time, and 5851846Sbostic * are linked into the device vnode, using a logical block number which is 5951846Sbostic * the same as the physical block number. This can't be done by LFS because 6051846Sbostic * blocks aren't given disk addresses until they're written, so there's no 6151846Sbostic * way to distinguish the meta-data blocks for one file from any other file. 6251846Sbostic * This means that meta-data blocks have to be on the vnode for the file so 6351846Sbostic * they can be found, and have to have "names" different from the standard 6451846Sbostic * data blocks. To do this, we divide the name space into positive and 6551846Sbostic * negative block numbers, and give the meta-data blocks negative logical 6651847Sbostic * numbers. Indirect blocks are addressed by the negative address of the 6751847Sbostic * first data block to which they point. Double indirect blocks are addressed 6851847Sbostic * by one less than the address of the first indirect block to which they 6951847Sbostic * point. Triple indirect blocks are addressed by one less than the address 7051847Sbostic * of the first double indirect block to which they point. 717443Sroot */ 7251348Sroot int 73*51855Sbostic lfs_bmaparray(vp, bn, bnp, ap, nump) 7451561Smckusick struct vnode *vp; 7537736Smckusick register daddr_t bn; 7651561Smckusick daddr_t *bnp; 77*51855Sbostic INDIR *ap; 78*51855Sbostic int *nump; 797443Sroot { 8051561Smckusick register struct inode *ip; 8151846Sbostic struct buf *bp; 82*51855Sbostic struct lfs *fs; 8351561Smckusick struct vnode *devvp; 84*51855Sbostic INDIR a[NIADDR], *xap; 85*51855Sbostic daddr_t *bap, daddr; 86*51855Sbostic long metalbn; 87*51855Sbostic int error, num, off; 8837736Smckusick 89*51855Sbostic 9051561Smckusick ip = VTOI(vp); 9151846Sbostic #ifdef VERBOSE 92*51855Sbostic printf("lfs_bmap: block number %d, inode %d\n", bn, ip->i_number); 9351846Sbostic #endif 94*51855Sbostic #ifdef DIAGNOSTIC 95*51855Sbostic if (ap != NULL && nump == NULL || ap == NULL && nump != NULL) 96*51855Sbostic panic("lfs_bmaparray: invalid arguments"); 97*51855Sbostic #endif 9851847Sbostic 99*51855Sbostic xap = ap == NULL ? a : ap; 100*51855Sbostic if (error = lfs_getlbns(vp, bn, xap, nump)) 101*51855Sbostic return (error); 102*51855Sbostic 103*51855Sbostic num = *nump; 104*51855Sbostic fs = ip->i_lfs; 105*51855Sbostic if (num == 0) { 106*51855Sbostic *bnp = ip->i_db[bn]; 107*51855Sbostic if (*bnp == 0) 10851348Sroot *bnp = UNASSIGNED; 10937736Smckusick return (0); 11037736Smckusick } 11151486Sbostic 112*51855Sbostic /* Fetch through the indirect blocks. */ 11351846Sbostic bp = NULL; 11451183Sbostic devvp = VFSTOUFS(vp->v_mount)->um_devvp; 115*51855Sbostic for (bap = ip->i_ib; num--; off = xap->in_off, ++xap) { 116*51855Sbostic off = xap->in_off; 117*51855Sbostic metalbn = xap->in_lbn; 118*51855Sbostic 11951846Sbostic /* 12051846Sbostic * In LFS, it's possible to have a block appended to a file 12151846Sbostic * for which the meta-blocks have not yet been allocated. 12251846Sbostic * This is a win if the file never gets written or if the 12351846Sbostic * file's growing. 12451846Sbostic */ 12551846Sbostic if ((daddr = bap[off]) == 0) { 12651348Sroot daddr = UNASSIGNED; 12751183Sbostic break; 12851183Sbostic } 12951847Sbostic 13051847Sbostic /* If searching for a meta-data block, quit when found. */ 131*51855Sbostic if (metalbn == bn) 13251847Sbostic break; 13351847Sbostic 13451846Sbostic /* 13551846Sbostic * Read in the appropriate indirect block. LFS can't do a 13651846Sbostic * bread because bread knows that FFS will hand it the device 13751846Sbostic * vnode, not the file vnode, so the b_dev and b_blkno would 13851846Sbostic * be wrong. 13951846Sbostic * 14051846Sbostic * XXX 14151846Sbostic * This REALLY needs to be fixed, at the very least it needs 142*51855Sbostic * to be rethought when the buffer cache goes away. When it's 143*51855Sbostic * fixed, change lfs_bmaparray and lfs_getlbns to take an ip, 144*51855Sbostic * not a vp. 14551846Sbostic */ 14651183Sbostic if (bp) 14737736Smckusick brelse(bp); 14851847Sbostic bp = getblk(vp, metalbn, fs->lfs_bsize); 14951183Sbostic if (bp->b_flags & (B_DONE | B_DELWRI)) { 15051847Sbostic trace(TR_BREADHIT, pack(vp, size), metalbn); 15151183Sbostic } else { 15251847Sbostic trace(TR_BREADMISS, pack(vp, size), metalbn); 15351847Sbostic bp->b_blkno = daddr; 15451846Sbostic bp->b_flags |= B_READ; 15551183Sbostic bp->b_dev = devvp->v_rdev; 15651215Sbostic (devvp->v_op->vop_strategy)(bp); 15751183Sbostic curproc->p_stats->p_ru.ru_inblock++; /* XXX */ 15851183Sbostic if (error = biowait(bp)) { 15951183Sbostic brelse(bp); 16051183Sbostic return (error); 16151183Sbostic } 16237736Smckusick } 16337736Smckusick bap = bp->b_un.b_daddr; 16451183Sbostic } 16551183Sbostic if (bp) 16639679Smckusick brelse(bp); 16751183Sbostic 16851183Sbostic *bnp = daddr; 16937736Smckusick return (0); 17037736Smckusick } 171*51855Sbostic 172*51855Sbostic /* 173*51855Sbostic * Create an array of logical block number/offset pairs which represent the 174*51855Sbostic * path of indirect blocks required to access a data block. The first "pair" 175*51855Sbostic * contains the logical block number of the appropriate single, double or 176*51855Sbostic * triple indirect block and the offset into the inode indirect block array. 177*51855Sbostic * Note, the logical block number of the inode single/double/triple indirect 178*51855Sbostic * block appears twice in the array, once with the offset into the i_ib and 179*51855Sbostic * once with the offset into the page itself. 180*51855Sbostic */ 181*51855Sbostic int 182*51855Sbostic lfs_getlbns(vp, bn, ap, nump) 183*51855Sbostic struct vnode *vp; 184*51855Sbostic register daddr_t bn; 185*51855Sbostic INDIR *ap; 186*51855Sbostic int *nump; 187*51855Sbostic { 188*51855Sbostic struct lfs *fs; 189*51855Sbostic long metalbn, realbn; 190*51855Sbostic int j, off, sh; 191*51855Sbostic 192*51855Sbostic #ifdef VERBOSE 193*51855Sbostic printf("lfs_getlbns: bn %d, inode %d\n", bn, VTOI(vp)->i_number); 194*51855Sbostic #endif 195*51855Sbostic *nump = 0; 196*51855Sbostic realbn = bn; 197*51855Sbostic if ((long)bn < 0) 198*51855Sbostic bn = -(long)bn; 199*51855Sbostic 200*51855Sbostic /* The first NDADDR blocks are direct blocks. */ 201*51855Sbostic if (bn < NDADDR) 202*51855Sbostic return(0); 203*51855Sbostic 204*51855Sbostic /* 205*51855Sbostic * Determine the number of levels of indirection. After this loop 206*51855Sbostic * is done, sh indicates the number of data blocks possible at the 207*51855Sbostic * given level of indirection, and NIADDR - j is the number of levels 208*51855Sbostic * of indirection needed to locate the requested block. 209*51855Sbostic */ 210*51855Sbostic bn -= NDADDR; 211*51855Sbostic fs = VTOI(vp)->i_lfs; 212*51855Sbostic sh = 1; 213*51855Sbostic for (j = NIADDR; j > 0; j--) { 214*51855Sbostic sh *= NINDIR(fs); 215*51855Sbostic if (bn < sh) 216*51855Sbostic break; 217*51855Sbostic bn -= sh; 218*51855Sbostic } 219*51855Sbostic if (j == 0) 220*51855Sbostic return (EFBIG); 221*51855Sbostic 222*51855Sbostic /* Calculate the address of the first meta-block. */ 223*51855Sbostic if (realbn >= 0) 224*51855Sbostic metalbn = -(realbn - bn + NIADDR - j); 225*51855Sbostic else 226*51855Sbostic metalbn = -(-realbn - bn + NIADDR - j); 227*51855Sbostic 228*51855Sbostic /* 229*51855Sbostic * At each iteration, off is the offset into the bap array which is 230*51855Sbostic * an array of disk addresses at the current level of indirection. 231*51855Sbostic * The logical block number and the offset in that block are stored 232*51855Sbostic * into the argument array. 233*51855Sbostic */ 234*51855Sbostic ++*nump; 235*51855Sbostic ap->in_lbn = metalbn; 236*51855Sbostic ap->in_off = off = NIADDR - j; 237*51855Sbostic ap++; 238*51855Sbostic for (; j <= NIADDR; j++) { 239*51855Sbostic /* If searching for a meta-data block, quit when found. */ 240*51855Sbostic if (metalbn == realbn) 241*51855Sbostic break; 242*51855Sbostic 243*51855Sbostic sh /= NINDIR(fs); 244*51855Sbostic off = (bn / sh) % NINDIR(fs); 245*51855Sbostic 246*51855Sbostic ++*nump; 247*51855Sbostic ap->in_lbn = metalbn; 248*51855Sbostic ap->in_off = off; 249*51855Sbostic ++ap; 250*51855Sbostic 251*51855Sbostic metalbn -= -1 + off * sh; 252*51855Sbostic } 253*51855Sbostic return (0); 254*51855Sbostic } 255