1*9165Ssam /* lfs_balloc.c 5.3 82/11/13 */ 27443Sroot 37443Sroot #include "../h/param.h" 47443Sroot #include "../h/systm.h" 57443Sroot #include "../h/conf.h" 67443Sroot #include "../h/inode.h" 77443Sroot #include "../h/dir.h" 87443Sroot #include "../h/user.h" 97443Sroot #include "../h/buf.h" 107443Sroot #include "../h/proc.h" 117443Sroot #include "../h/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], 54*9165Ssam blkpref(ip, nb, (int)nb, &ip->i_db[0]), 55*9165Ssam osize, (int)fs->fs_bsize); 567443Sroot ip->i_size = (nb + 1) * fs->fs_bsize; 577443Sroot ip->i_db[nb] = dbtofsb(fs, bp->b_blkno); 587443Sroot ip->i_flag |= IUPD|ICHG; 597443Sroot bdwrite(bp); 607443Sroot } 617443Sroot } 627443Sroot /* 637443Sroot * The first NDADDR blocks are direct blocks 647443Sroot */ 657443Sroot if (bn < NDADDR) { 668258Smckusick nb = ip->i_db[bn]; 677443Sroot if (rwflg == B_READ) { 687443Sroot if (nb == 0) 697443Sroot return ((daddr_t)-1); 707443Sroot goto gotit; 717443Sroot } 728258Smckusick if (nb == 0 || ip->i_size < (bn + 1) * fs->fs_bsize) { 737443Sroot if (nb != 0) { 747443Sroot /* consider need to reallocate a frag */ 757443Sroot osize = fragroundup(fs, blkoff(fs, ip->i_size)); 767443Sroot nsize = fragroundup(fs, size); 777443Sroot if (nsize <= osize) 787443Sroot goto gotit; 798258Smckusick bp = realloccg(ip, nb, 80*9165Ssam blkpref(ip, bn, (int)bn, &ip->i_db[0]), 817443Sroot osize, nsize); 827443Sroot } else { 838258Smckusick if (ip->i_size < (bn + 1) * fs->fs_bsize) 847443Sroot nsize = fragroundup(fs, size); 857443Sroot else 867443Sroot nsize = fs->fs_bsize; 878258Smckusick bp = alloc(ip, 88*9165Ssam blkpref(ip, bn, (int)bn, &ip->i_db[0]), 897443Sroot nsize); 907443Sroot } 917443Sroot if (bp == NULL) 927443Sroot return ((daddr_t)-1); 937443Sroot nb = dbtofsb(fs, bp->b_blkno); 947443Sroot if ((ip->i_mode&IFMT) == IFDIR) 957443Sroot /* 967443Sroot * Write directory blocks synchronously 977443Sroot * so they never appear with garbage in 987443Sroot * them on the disk. 997443Sroot */ 1007443Sroot bwrite(bp); 1017443Sroot else 1027443Sroot bdwrite(bp); 1038258Smckusick ip->i_db[bn] = nb; 1047443Sroot ip->i_flag |= IUPD|ICHG; 1057443Sroot } 1067443Sroot gotit: 1078258Smckusick if (bn < NDADDR - 1) { 1088258Smckusick rablock = fsbtodb(fs, ip->i_db[bn + 1]); 1098258Smckusick rasize = blksize(fs, ip, bn + 1); 1107443Sroot } 1117443Sroot return (nb); 1127443Sroot } 1137443Sroot 1147443Sroot /* 1157443Sroot * Determine how many levels of indirection. 1167443Sroot */ 1178258Smckusick pref = 0; 1187443Sroot sh = 1; 1198258Smckusick lbn = bn; 1207443Sroot bn -= NDADDR; 1217443Sroot for (j = NIADDR; j>0; j--) { 1227443Sroot sh *= NINDIR(fs); 1237443Sroot if (bn < sh) 1247443Sroot break; 1257443Sroot bn -= sh; 1267443Sroot } 1277443Sroot if (j == 0) { 1287443Sroot u.u_error = EFBIG; 1297443Sroot return ((daddr_t)0); 1307443Sroot } 1317443Sroot 1327443Sroot /* 1337443Sroot * fetch the first indirect block 1347443Sroot */ 1357443Sroot nb = ip->i_ib[NIADDR - j]; 1367443Sroot if (nb == 0) { 1378258Smckusick if (rwflg == B_READ) 1387443Sroot return ((daddr_t)-1); 139*9165Ssam pref = blkpref(ip, lbn, 0, (daddr_t *)0); 140*9165Ssam bp = alloc(ip, pref, (int)fs->fs_bsize); 1418258Smckusick if (bp == NULL) 1428258Smckusick return ((daddr_t)-1); 1437443Sroot nb = dbtofsb(fs, bp->b_blkno); 1447443Sroot /* 1457443Sroot * Write synchronously so that indirect blocks 1467443Sroot * never point at garbage. 1477443Sroot */ 1487443Sroot bwrite(bp); 1497443Sroot ip->i_ib[NIADDR - j] = nb; 1507443Sroot ip->i_flag |= IUPD|ICHG; 1517443Sroot } 1527443Sroot 1537443Sroot /* 1547443Sroot * fetch through the indirect blocks 1557443Sroot */ 1567443Sroot for (; j <= NIADDR; j++) { 157*9165Ssam bp = bread(ip->i_dev, fsbtodb(fs, nb), (int)fs->fs_bsize); 1587443Sroot if (bp->b_flags & B_ERROR) { 1597443Sroot brelse(bp); 1607443Sroot return ((daddr_t)0); 1617443Sroot } 1627443Sroot bap = bp->b_un.b_daddr; 1637443Sroot sh /= NINDIR(fs); 1647443Sroot i = (bn / sh) % NINDIR(fs); 1657443Sroot nb = bap[i]; 1667443Sroot if (nb == 0) { 1677443Sroot if (rwflg==B_READ) { 1687443Sroot brelse(bp); 1697443Sroot return ((daddr_t)-1); 1707443Sroot } 1718258Smckusick if (pref == 0) 1728258Smckusick if (j < NIADDR) 173*9165Ssam pref = blkpref(ip, lbn, 0, 174*9165Ssam (daddr_t *)0); 1758258Smckusick else 1768258Smckusick pref = blkpref(ip, lbn, i, &bap[0]); 177*9165Ssam nbp = alloc(ip, pref, (int)fs->fs_bsize); 1787443Sroot if (nbp == NULL) { 1797443Sroot brelse(bp); 1807443Sroot return ((daddr_t)-1); 1817443Sroot } 1827443Sroot nb = dbtofsb(fs, nbp->b_blkno); 1837443Sroot if (j < NIADDR || (ip->i_mode&IFMT) == IFDIR) 1847443Sroot /* 1857443Sroot * Write synchronously so indirect blocks 1867443Sroot * never point at garbage and blocks 1877443Sroot * in directories never contain garbage. 1887443Sroot */ 1897443Sroot bwrite(nbp); 1907443Sroot else 1917443Sroot bdwrite(nbp); 1927443Sroot bap[i] = nb; 1937443Sroot bdwrite(bp); 1947443Sroot } else 1957443Sroot brelse(bp); 1967443Sroot } 1977443Sroot 1987443Sroot /* 1997443Sroot * calculate read-ahead. 2007443Sroot */ 2017443Sroot if (i < NINDIR(fs) - 1) { 2027443Sroot rablock = fsbtodb(fs, bap[i+1]); 2037443Sroot rasize = fs->fs_bsize; 2047443Sroot } 2057443Sroot return (nb); 2067443Sroot } 207