1*17099Sbloom /* lfs_balloc.c 6.2 84/08/29 */ 27443Sroot 3*17099Sbloom #include "param.h" 4*17099Sbloom #include "systm.h" 5*17099Sbloom #include "conf.h" 6*17099Sbloom #include "inode.h" 7*17099Sbloom #include "dir.h" 8*17099Sbloom #include "user.h" 9*17099Sbloom #include "buf.h" 10*17099Sbloom #include "proc.h" 11*17099Sbloom #include "fs.h" 127443Sroot 137443Sroot /* 147443Sroot * Bmap defines the structure of file system storage 157443Sroot * by returning the physical block number on a device given the 167443Sroot * inode and the logical block number in a file. 177443Sroot * When convenient, it also leaves the physical 187443Sroot * block number of the next block of the file in rablock 197443Sroot * for use in read-ahead. 207443Sroot */ 217443Sroot /*VARARGS3*/ 227443Sroot daddr_t 237443Sroot bmap(ip, bn, rwflg, size) 247443Sroot register struct inode *ip; 257443Sroot daddr_t bn; 267443Sroot int rwflg; 277443Sroot int size; /* supplied only when rwflg == B_WRITE */ 287443Sroot { 297443Sroot register int i; 307443Sroot int osize, nsize; 317443Sroot struct buf *bp, *nbp; 327443Sroot struct fs *fs; 337443Sroot int j, sh; 348258Smckusick daddr_t nb, lbn, *bap, pref, blkpref(); 357443Sroot 367443Sroot if (bn < 0) { 377443Sroot u.u_error = EFBIG; 387443Sroot return ((daddr_t)0); 397443Sroot } 407443Sroot fs = ip->i_fs; 417443Sroot rablock = 0; 427443Sroot rasize = 0; /* conservative */ 437443Sroot 447443Sroot /* 457443Sroot * If the next write will extend the file into a new block, 467443Sroot * and the file is currently composed of a fragment 477443Sroot * this fragment has to be extended to be a full block. 487443Sroot */ 497443Sroot nb = lblkno(fs, ip->i_size); 507443Sroot if (rwflg == B_WRITE && nb < NDADDR && nb < bn) { 517443Sroot osize = blksize(fs, ip, nb); 527443Sroot if (osize < fs->fs_bsize && osize > 0) { 537443Sroot bp = realloccg(ip, ip->i_db[nb], 549165Ssam blkpref(ip, nb, (int)nb, &ip->i_db[0]), 559165Ssam osize, (int)fs->fs_bsize); 5611567Ssam if (bp == NULL) 5711567Ssam return ((daddr_t)-1); 587443Sroot ip->i_size = (nb + 1) * fs->fs_bsize; 597443Sroot ip->i_db[nb] = dbtofsb(fs, bp->b_blkno); 607443Sroot ip->i_flag |= IUPD|ICHG; 617443Sroot bdwrite(bp); 627443Sroot } 637443Sroot } 647443Sroot /* 657443Sroot * The first NDADDR blocks are direct blocks 667443Sroot */ 677443Sroot if (bn < NDADDR) { 688258Smckusick nb = ip->i_db[bn]; 697443Sroot if (rwflg == B_READ) { 707443Sroot if (nb == 0) 717443Sroot return ((daddr_t)-1); 727443Sroot goto gotit; 737443Sroot } 748258Smckusick if (nb == 0 || ip->i_size < (bn + 1) * fs->fs_bsize) { 757443Sroot if (nb != 0) { 767443Sroot /* consider need to reallocate a frag */ 777443Sroot osize = fragroundup(fs, blkoff(fs, ip->i_size)); 787443Sroot nsize = fragroundup(fs, size); 797443Sroot if (nsize <= osize) 807443Sroot goto gotit; 818258Smckusick bp = realloccg(ip, nb, 829165Ssam blkpref(ip, bn, (int)bn, &ip->i_db[0]), 837443Sroot osize, nsize); 847443Sroot } else { 858258Smckusick if (ip->i_size < (bn + 1) * fs->fs_bsize) 867443Sroot nsize = fragroundup(fs, size); 877443Sroot else 887443Sroot nsize = fs->fs_bsize; 898258Smckusick bp = alloc(ip, 909165Ssam blkpref(ip, bn, (int)bn, &ip->i_db[0]), 917443Sroot nsize); 927443Sroot } 937443Sroot if (bp == NULL) 947443Sroot return ((daddr_t)-1); 957443Sroot nb = dbtofsb(fs, bp->b_blkno); 967443Sroot if ((ip->i_mode&IFMT) == IFDIR) 977443Sroot /* 987443Sroot * Write directory blocks synchronously 997443Sroot * so they never appear with garbage in 1007443Sroot * them on the disk. 1017443Sroot */ 1027443Sroot bwrite(bp); 1037443Sroot else 1047443Sroot bdwrite(bp); 1058258Smckusick ip->i_db[bn] = nb; 1067443Sroot ip->i_flag |= IUPD|ICHG; 1077443Sroot } 1087443Sroot gotit: 1098258Smckusick if (bn < NDADDR - 1) { 1108258Smckusick rablock = fsbtodb(fs, ip->i_db[bn + 1]); 1118258Smckusick rasize = blksize(fs, ip, bn + 1); 1127443Sroot } 1137443Sroot return (nb); 1147443Sroot } 1157443Sroot 1167443Sroot /* 1177443Sroot * Determine how many levels of indirection. 1187443Sroot */ 1198258Smckusick pref = 0; 1207443Sroot sh = 1; 1218258Smckusick lbn = bn; 1227443Sroot bn -= NDADDR; 1237443Sroot for (j = NIADDR; j>0; j--) { 1247443Sroot sh *= NINDIR(fs); 1257443Sroot if (bn < sh) 1267443Sroot break; 1277443Sroot bn -= sh; 1287443Sroot } 1297443Sroot if (j == 0) { 1307443Sroot u.u_error = EFBIG; 1317443Sroot return ((daddr_t)0); 1327443Sroot } 1337443Sroot 1347443Sroot /* 1357443Sroot * fetch the first indirect block 1367443Sroot */ 1377443Sroot nb = ip->i_ib[NIADDR - j]; 1387443Sroot if (nb == 0) { 1398258Smckusick if (rwflg == B_READ) 1407443Sroot return ((daddr_t)-1); 1419165Ssam pref = blkpref(ip, lbn, 0, (daddr_t *)0); 1429165Ssam bp = alloc(ip, pref, (int)fs->fs_bsize); 1438258Smckusick if (bp == NULL) 1448258Smckusick return ((daddr_t)-1); 1457443Sroot nb = dbtofsb(fs, bp->b_blkno); 1467443Sroot /* 1477443Sroot * Write synchronously so that indirect blocks 1487443Sroot * never point at garbage. 1497443Sroot */ 1507443Sroot bwrite(bp); 1517443Sroot ip->i_ib[NIADDR - j] = nb; 1527443Sroot ip->i_flag |= IUPD|ICHG; 1537443Sroot } 1547443Sroot 1557443Sroot /* 1567443Sroot * fetch through the indirect blocks 1577443Sroot */ 1587443Sroot for (; j <= NIADDR; j++) { 1599165Ssam bp = bread(ip->i_dev, fsbtodb(fs, nb), (int)fs->fs_bsize); 1607443Sroot if (bp->b_flags & B_ERROR) { 1617443Sroot brelse(bp); 1627443Sroot return ((daddr_t)0); 1637443Sroot } 1647443Sroot bap = bp->b_un.b_daddr; 1657443Sroot sh /= NINDIR(fs); 1667443Sroot i = (bn / sh) % NINDIR(fs); 1677443Sroot nb = bap[i]; 1687443Sroot if (nb == 0) { 1697443Sroot if (rwflg==B_READ) { 1707443Sroot brelse(bp); 1717443Sroot return ((daddr_t)-1); 1727443Sroot } 1738258Smckusick if (pref == 0) 1748258Smckusick if (j < NIADDR) 1759165Ssam pref = blkpref(ip, lbn, 0, 1769165Ssam (daddr_t *)0); 1778258Smckusick else 1788258Smckusick pref = blkpref(ip, lbn, i, &bap[0]); 1799165Ssam nbp = alloc(ip, pref, (int)fs->fs_bsize); 1807443Sroot if (nbp == NULL) { 1817443Sroot brelse(bp); 1827443Sroot return ((daddr_t)-1); 1837443Sroot } 1847443Sroot nb = dbtofsb(fs, nbp->b_blkno); 1857443Sroot if (j < NIADDR || (ip->i_mode&IFMT) == IFDIR) 1867443Sroot /* 1877443Sroot * Write synchronously so indirect blocks 1887443Sroot * never point at garbage and blocks 1897443Sroot * in directories never contain garbage. 1907443Sroot */ 1917443Sroot bwrite(nbp); 1927443Sroot else 1937443Sroot bdwrite(nbp); 1947443Sroot bap[i] = nb; 1957443Sroot bdwrite(bp); 1967443Sroot } else 1977443Sroot brelse(bp); 1987443Sroot } 1997443Sroot 2007443Sroot /* 2017443Sroot * calculate read-ahead. 2027443Sroot */ 2037443Sroot if (i < NINDIR(fs) - 1) { 2047443Sroot rablock = fsbtodb(fs, bap[i+1]); 2057443Sroot rasize = fs->fs_bsize; 2067443Sroot } 2077443Sroot return (nb); 2087443Sroot } 209