1*7443Sroot /* lfs_balloc.c 5.1 82/07/15 */ 2*7443Sroot 3*7443Sroot #include "../h/param.h" 4*7443Sroot #include "../h/systm.h" 5*7443Sroot #include "../h/conf.h" 6*7443Sroot #include "../h/inode.h" 7*7443Sroot #include "../h/dir.h" 8*7443Sroot #include "../h/user.h" 9*7443Sroot #include "../h/buf.h" 10*7443Sroot #include "../h/proc.h" 11*7443Sroot #include "../h/fs.h" 12*7443Sroot 13*7443Sroot /* 14*7443Sroot * Bmap defines the structure of file system storage 15*7443Sroot * by returning the physical block number on a device given the 16*7443Sroot * inode and the logical block number in a file. 17*7443Sroot * When convenient, it also leaves the physical 18*7443Sroot * block number of the next block of the file in rablock 19*7443Sroot * for use in read-ahead. 20*7443Sroot */ 21*7443Sroot /*VARARGS3*/ 22*7443Sroot daddr_t 23*7443Sroot bmap(ip, bn, rwflg, size) 24*7443Sroot register struct inode *ip; 25*7443Sroot daddr_t bn; 26*7443Sroot int rwflg; 27*7443Sroot int size; /* supplied only when rwflg == B_WRITE */ 28*7443Sroot { 29*7443Sroot register int i; 30*7443Sroot int osize, nsize; 31*7443Sroot struct buf *bp, *nbp; 32*7443Sroot struct fs *fs; 33*7443Sroot int j, sh; 34*7443Sroot daddr_t nb, *bap, pref, blkpref(); 35*7443Sroot 36*7443Sroot if (bn < 0) { 37*7443Sroot u.u_error = EFBIG; 38*7443Sroot return ((daddr_t)0); 39*7443Sroot } 40*7443Sroot fs = ip->i_fs; 41*7443Sroot rablock = 0; 42*7443Sroot rasize = 0; /* conservative */ 43*7443Sroot 44*7443Sroot /* 45*7443Sroot * If the next write will extend the file into a new block, 46*7443Sroot * and the file is currently composed of a fragment 47*7443Sroot * this fragment has to be extended to be a full block. 48*7443Sroot */ 49*7443Sroot nb = lblkno(fs, ip->i_size); 50*7443Sroot if (rwflg == B_WRITE && nb < NDADDR && nb < bn) { 51*7443Sroot osize = blksize(fs, ip, nb); 52*7443Sroot if (osize < fs->fs_bsize && osize > 0) { 53*7443Sroot bp = realloccg(ip, ip->i_db[nb], 54*7443Sroot nb == 0 ? 0 : ip->i_db[nb - 1] + fs->fs_frag, 55*7443Sroot osize, fs->fs_bsize); 56*7443Sroot ip->i_size = (nb + 1) * fs->fs_bsize; 57*7443Sroot ip->i_db[nb] = dbtofsb(fs, bp->b_blkno); 58*7443Sroot ip->i_flag |= IUPD|ICHG; 59*7443Sroot bdwrite(bp); 60*7443Sroot } 61*7443Sroot } 62*7443Sroot /* 63*7443Sroot * The first NDADDR blocks are direct blocks 64*7443Sroot */ 65*7443Sroot if (bn < NDADDR) { 66*7443Sroot i = bn; 67*7443Sroot nb = ip->i_db[i]; 68*7443Sroot if (rwflg == B_READ) { 69*7443Sroot if (nb == 0) 70*7443Sroot return ((daddr_t)-1); 71*7443Sroot goto gotit; 72*7443Sroot } 73*7443Sroot if (nb == 0 || ip->i_size < (i + 1) * fs->fs_bsize) { 74*7443Sroot if (nb != 0) { 75*7443Sroot /* consider need to reallocate a frag */ 76*7443Sroot osize = fragroundup(fs, blkoff(fs, ip->i_size)); 77*7443Sroot nsize = fragroundup(fs, size); 78*7443Sroot if (nsize <= osize) 79*7443Sroot goto gotit; 80*7443Sroot bp = realloccg(ip, nb, i == 0 ? 81*7443Sroot 0 : ip->i_db[i - 1] + fs->fs_frag, 82*7443Sroot osize, nsize); 83*7443Sroot } else { 84*7443Sroot if (ip->i_size < (i + 1) * fs->fs_bsize) 85*7443Sroot nsize = fragroundup(fs, size); 86*7443Sroot else 87*7443Sroot nsize = fs->fs_bsize; 88*7443Sroot bp = alloc(ip, i > 0 ? 89*7443Sroot ip->i_db[i - 1] + fs->fs_frag : 0, 90*7443Sroot nsize); 91*7443Sroot } 92*7443Sroot if (bp == NULL) 93*7443Sroot return ((daddr_t)-1); 94*7443Sroot nb = dbtofsb(fs, bp->b_blkno); 95*7443Sroot if ((ip->i_mode&IFMT) == IFDIR) 96*7443Sroot /* 97*7443Sroot * Write directory blocks synchronously 98*7443Sroot * so they never appear with garbage in 99*7443Sroot * them on the disk. 100*7443Sroot */ 101*7443Sroot bwrite(bp); 102*7443Sroot else 103*7443Sroot bdwrite(bp); 104*7443Sroot ip->i_db[i] = nb; 105*7443Sroot ip->i_flag |= IUPD|ICHG; 106*7443Sroot } 107*7443Sroot gotit: 108*7443Sroot if (i < NDADDR - 1) { 109*7443Sroot rablock = fsbtodb(fs, ip->i_db[i+1]); 110*7443Sroot rasize = blksize(fs, ip, i+1); 111*7443Sroot } 112*7443Sroot return (nb); 113*7443Sroot } 114*7443Sroot 115*7443Sroot /* 116*7443Sroot * Determine how many levels of indirection. 117*7443Sroot */ 118*7443Sroot sh = 1; 119*7443Sroot bn -= NDADDR; 120*7443Sroot for (j = NIADDR; j>0; j--) { 121*7443Sroot sh *= NINDIR(fs); 122*7443Sroot if (bn < sh) 123*7443Sroot break; 124*7443Sroot bn -= sh; 125*7443Sroot } 126*7443Sroot if (j == 0) { 127*7443Sroot u.u_error = EFBIG; 128*7443Sroot return ((daddr_t)0); 129*7443Sroot } 130*7443Sroot 131*7443Sroot /* 132*7443Sroot * fetch the first indirect block 133*7443Sroot */ 134*7443Sroot nb = ip->i_ib[NIADDR - j]; 135*7443Sroot if (nb == 0) { 136*7443Sroot if (rwflg==B_READ || 137*7443Sroot (bp = alloc(ip, (daddr_t)0, fs->fs_bsize)) == NULL) 138*7443Sroot return ((daddr_t)-1); 139*7443Sroot nb = dbtofsb(fs, bp->b_blkno); 140*7443Sroot /* 141*7443Sroot * Write synchronously so that indirect blocks 142*7443Sroot * never point at garbage. 143*7443Sroot */ 144*7443Sroot bwrite(bp); 145*7443Sroot ip->i_ib[NIADDR - j] = nb; 146*7443Sroot ip->i_flag |= IUPD|ICHG; 147*7443Sroot } 148*7443Sroot 149*7443Sroot /* 150*7443Sroot * fetch through the indirect blocks 151*7443Sroot */ 152*7443Sroot for (; j <= NIADDR; j++) { 153*7443Sroot bp = bread(ip->i_dev, fsbtodb(fs, nb), fs->fs_bsize); 154*7443Sroot if (bp->b_flags & B_ERROR) { 155*7443Sroot brelse(bp); 156*7443Sroot return ((daddr_t)0); 157*7443Sroot } 158*7443Sroot bap = bp->b_un.b_daddr; 159*7443Sroot sh /= NINDIR(fs); 160*7443Sroot i = (bn / sh) % NINDIR(fs); 161*7443Sroot nb = bap[i]; 162*7443Sroot if (nb == 0) { 163*7443Sroot if (rwflg==B_READ) { 164*7443Sroot brelse(bp); 165*7443Sroot return ((daddr_t)-1); 166*7443Sroot } 167*7443Sroot if (i % (fs->fs_fsize / sizeof(daddr_t)) == 0 || 168*7443Sroot bap[i - 1] == 0) 169*7443Sroot pref = blkpref(ip->i_fs); 170*7443Sroot else 171*7443Sroot pref = bap[i - 1] + fs->fs_frag; 172*7443Sroot nbp = alloc(ip, pref, fs->fs_bsize); 173*7443Sroot if (nbp == NULL) { 174*7443Sroot brelse(bp); 175*7443Sroot return ((daddr_t)-1); 176*7443Sroot } 177*7443Sroot nb = dbtofsb(fs, nbp->b_blkno); 178*7443Sroot if (j < NIADDR || (ip->i_mode&IFMT) == IFDIR) 179*7443Sroot /* 180*7443Sroot * Write synchronously so indirect blocks 181*7443Sroot * never point at garbage and blocks 182*7443Sroot * in directories never contain garbage. 183*7443Sroot */ 184*7443Sroot bwrite(nbp); 185*7443Sroot else 186*7443Sroot bdwrite(nbp); 187*7443Sroot bap[i] = nb; 188*7443Sroot bdwrite(bp); 189*7443Sroot } else 190*7443Sroot brelse(bp); 191*7443Sroot } 192*7443Sroot 193*7443Sroot /* 194*7443Sroot * calculate read-ahead. 195*7443Sroot */ 196*7443Sroot if (i < NINDIR(fs) - 1) { 197*7443Sroot rablock = fsbtodb(fs, bap[i+1]); 198*7443Sroot rasize = fs->fs_bsize; 199*7443Sroot } 200*7443Sroot return (nb); 201*7443Sroot } 202