1*8258Smckusick /* lfs_balloc.c 5.2 82/09/25 */ 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; 34*8258Smckusick 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*8258Smckusick blkpref(ip, nb, nb, &ip->i_db[0]), 557443Sroot osize, 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) { 66*8258Smckusick nb = ip->i_db[bn]; 677443Sroot if (rwflg == B_READ) { 687443Sroot if (nb == 0) 697443Sroot return ((daddr_t)-1); 707443Sroot goto gotit; 717443Sroot } 72*8258Smckusick 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; 79*8258Smckusick bp = realloccg(ip, nb, 80*8258Smckusick blkpref(ip, bn, bn, &ip->i_db[0]), 817443Sroot osize, nsize); 827443Sroot } else { 83*8258Smckusick if (ip->i_size < (bn + 1) * fs->fs_bsize) 847443Sroot nsize = fragroundup(fs, size); 857443Sroot else 867443Sroot nsize = fs->fs_bsize; 87*8258Smckusick bp = alloc(ip, 88*8258Smckusick blkpref(ip, bn, 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); 103*8258Smckusick ip->i_db[bn] = nb; 1047443Sroot ip->i_flag |= IUPD|ICHG; 1057443Sroot } 1067443Sroot gotit: 107*8258Smckusick if (bn < NDADDR - 1) { 108*8258Smckusick rablock = fsbtodb(fs, ip->i_db[bn + 1]); 109*8258Smckusick rasize = blksize(fs, ip, bn + 1); 1107443Sroot } 1117443Sroot return (nb); 1127443Sroot } 1137443Sroot 1147443Sroot /* 1157443Sroot * Determine how many levels of indirection. 1167443Sroot */ 117*8258Smckusick pref = 0; 1187443Sroot sh = 1; 119*8258Smckusick 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) { 137*8258Smckusick if (rwflg == B_READ) 1387443Sroot return ((daddr_t)-1); 139*8258Smckusick pref = blkpref(ip, lbn, 0, 0); 140*8258Smckusick bp = alloc(ip, pref, fs->fs_bsize); 141*8258Smckusick if (bp == NULL) 142*8258Smckusick 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++) { 1577443Sroot bp = bread(ip->i_dev, fsbtodb(fs, nb), 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 } 171*8258Smckusick if (pref == 0) 172*8258Smckusick if (j < NIADDR) 173*8258Smckusick pref = blkpref(ip, lbn, 0, 0); 174*8258Smckusick else 175*8258Smckusick pref = blkpref(ip, lbn, i, &bap[0]); 1767443Sroot nbp = alloc(ip, pref, fs->fs_bsize); 1777443Sroot if (nbp == NULL) { 1787443Sroot brelse(bp); 1797443Sroot return ((daddr_t)-1); 1807443Sroot } 1817443Sroot nb = dbtofsb(fs, nbp->b_blkno); 1827443Sroot if (j < NIADDR || (ip->i_mode&IFMT) == IFDIR) 1837443Sroot /* 1847443Sroot * Write synchronously so indirect blocks 1857443Sroot * never point at garbage and blocks 1867443Sroot * in directories never contain garbage. 1877443Sroot */ 1887443Sroot bwrite(nbp); 1897443Sroot else 1907443Sroot bdwrite(nbp); 1917443Sroot bap[i] = nb; 1927443Sroot bdwrite(bp); 1937443Sroot } else 1947443Sroot brelse(bp); 1957443Sroot } 1967443Sroot 1977443Sroot /* 1987443Sroot * calculate read-ahead. 1997443Sroot */ 2007443Sroot if (i < NINDIR(fs) - 1) { 2017443Sroot rablock = fsbtodb(fs, bap[i+1]); 2027443Sroot rasize = fs->fs_bsize; 2037443Sroot } 2047443Sroot return (nb); 2057443Sroot } 206