1*23396Smckusick /* 2*23396Smckusick * Copyright (c) 1982 Regents of the University of California. 3*23396Smckusick * All rights reserved. The Berkeley software License Agreement 4*23396Smckusick * specifies the terms and conditions for redistribution. 5*23396Smckusick * 6*23396Smckusick * @(#)lfs_balloc.c 6.4 (Berkeley) 06/08/85 7*23396Smckusick */ 87443Sroot 917099Sbloom #include "param.h" 1017099Sbloom #include "systm.h" 1117099Sbloom #include "inode.h" 1217099Sbloom #include "dir.h" 1317099Sbloom #include "user.h" 1417099Sbloom #include "buf.h" 1517099Sbloom #include "proc.h" 1617099Sbloom #include "fs.h" 177443Sroot 187443Sroot /* 197443Sroot * Bmap defines the structure of file system storage 207443Sroot * by returning the physical block number on a device given the 217443Sroot * inode and the logical block number in a file. 227443Sroot * When convenient, it also leaves the physical 237443Sroot * block number of the next block of the file in rablock 247443Sroot * for use in read-ahead. 257443Sroot */ 267443Sroot /*VARARGS3*/ 277443Sroot daddr_t 287443Sroot bmap(ip, bn, rwflg, size) 297443Sroot register struct inode *ip; 307443Sroot daddr_t bn; 317443Sroot int rwflg; 327443Sroot int size; /* supplied only when rwflg == B_WRITE */ 337443Sroot { 347443Sroot register int i; 357443Sroot int osize, nsize; 367443Sroot struct buf *bp, *nbp; 377443Sroot struct fs *fs; 387443Sroot int j, sh; 398258Smckusick daddr_t nb, lbn, *bap, pref, blkpref(); 407443Sroot 417443Sroot if (bn < 0) { 427443Sroot u.u_error = EFBIG; 437443Sroot return ((daddr_t)0); 447443Sroot } 457443Sroot fs = ip->i_fs; 467443Sroot rablock = 0; 477443Sroot rasize = 0; /* conservative */ 487443Sroot 497443Sroot /* 507443Sroot * If the next write will extend the file into a new block, 517443Sroot * and the file is currently composed of a fragment 527443Sroot * this fragment has to be extended to be a full block. 537443Sroot */ 547443Sroot nb = lblkno(fs, ip->i_size); 557443Sroot if (rwflg == B_WRITE && nb < NDADDR && nb < bn) { 567443Sroot osize = blksize(fs, ip, nb); 577443Sroot if (osize < fs->fs_bsize && osize > 0) { 587443Sroot bp = realloccg(ip, ip->i_db[nb], 599165Ssam blkpref(ip, nb, (int)nb, &ip->i_db[0]), 609165Ssam osize, (int)fs->fs_bsize); 6111567Ssam if (bp == NULL) 6211567Ssam return ((daddr_t)-1); 637443Sroot ip->i_size = (nb + 1) * fs->fs_bsize; 647443Sroot ip->i_db[nb] = dbtofsb(fs, bp->b_blkno); 657443Sroot ip->i_flag |= IUPD|ICHG; 667443Sroot bdwrite(bp); 677443Sroot } 687443Sroot } 697443Sroot /* 707443Sroot * The first NDADDR blocks are direct blocks 717443Sroot */ 727443Sroot if (bn < NDADDR) { 738258Smckusick nb = ip->i_db[bn]; 747443Sroot if (rwflg == B_READ) { 757443Sroot if (nb == 0) 767443Sroot return ((daddr_t)-1); 777443Sroot goto gotit; 787443Sroot } 798258Smckusick if (nb == 0 || ip->i_size < (bn + 1) * fs->fs_bsize) { 807443Sroot if (nb != 0) { 817443Sroot /* consider need to reallocate a frag */ 827443Sroot osize = fragroundup(fs, blkoff(fs, ip->i_size)); 837443Sroot nsize = fragroundup(fs, size); 847443Sroot if (nsize <= osize) 857443Sroot goto gotit; 868258Smckusick bp = realloccg(ip, nb, 879165Ssam blkpref(ip, bn, (int)bn, &ip->i_db[0]), 887443Sroot osize, nsize); 897443Sroot } else { 908258Smckusick if (ip->i_size < (bn + 1) * fs->fs_bsize) 917443Sroot nsize = fragroundup(fs, size); 927443Sroot else 937443Sroot nsize = fs->fs_bsize; 948258Smckusick bp = alloc(ip, 959165Ssam blkpref(ip, bn, (int)bn, &ip->i_db[0]), 967443Sroot nsize); 977443Sroot } 987443Sroot if (bp == NULL) 997443Sroot return ((daddr_t)-1); 1007443Sroot nb = dbtofsb(fs, bp->b_blkno); 1017443Sroot if ((ip->i_mode&IFMT) == IFDIR) 1027443Sroot /* 1037443Sroot * Write directory blocks synchronously 1047443Sroot * so they never appear with garbage in 1057443Sroot * them on the disk. 1067443Sroot */ 1077443Sroot bwrite(bp); 1087443Sroot else 1097443Sroot bdwrite(bp); 1108258Smckusick ip->i_db[bn] = nb; 1117443Sroot ip->i_flag |= IUPD|ICHG; 1127443Sroot } 1137443Sroot gotit: 1148258Smckusick if (bn < NDADDR - 1) { 1158258Smckusick rablock = fsbtodb(fs, ip->i_db[bn + 1]); 1168258Smckusick rasize = blksize(fs, ip, bn + 1); 1177443Sroot } 1187443Sroot return (nb); 1197443Sroot } 1207443Sroot 1217443Sroot /* 1227443Sroot * Determine how many levels of indirection. 1237443Sroot */ 1248258Smckusick pref = 0; 1257443Sroot sh = 1; 1268258Smckusick lbn = bn; 1277443Sroot bn -= NDADDR; 1287443Sroot for (j = NIADDR; j>0; j--) { 1297443Sroot sh *= NINDIR(fs); 1307443Sroot if (bn < sh) 1317443Sroot break; 1327443Sroot bn -= sh; 1337443Sroot } 1347443Sroot if (j == 0) { 1357443Sroot u.u_error = EFBIG; 1367443Sroot return ((daddr_t)0); 1377443Sroot } 1387443Sroot 1397443Sroot /* 1407443Sroot * fetch the first indirect block 1417443Sroot */ 1427443Sroot nb = ip->i_ib[NIADDR - j]; 1437443Sroot if (nb == 0) { 1448258Smckusick if (rwflg == B_READ) 1457443Sroot return ((daddr_t)-1); 1469165Ssam pref = blkpref(ip, lbn, 0, (daddr_t *)0); 1479165Ssam bp = alloc(ip, pref, (int)fs->fs_bsize); 1488258Smckusick if (bp == NULL) 1498258Smckusick return ((daddr_t)-1); 1507443Sroot nb = dbtofsb(fs, bp->b_blkno); 1517443Sroot /* 1527443Sroot * Write synchronously so that indirect blocks 1537443Sroot * never point at garbage. 1547443Sroot */ 1557443Sroot bwrite(bp); 1567443Sroot ip->i_ib[NIADDR - j] = nb; 1577443Sroot ip->i_flag |= IUPD|ICHG; 1587443Sroot } 1597443Sroot 1607443Sroot /* 1617443Sroot * fetch through the indirect blocks 1627443Sroot */ 1637443Sroot for (; j <= NIADDR; j++) { 1649165Ssam bp = bread(ip->i_dev, fsbtodb(fs, nb), (int)fs->fs_bsize); 1657443Sroot if (bp->b_flags & B_ERROR) { 1667443Sroot brelse(bp); 1677443Sroot return ((daddr_t)0); 1687443Sroot } 1697443Sroot bap = bp->b_un.b_daddr; 1707443Sroot sh /= NINDIR(fs); 1717443Sroot i = (bn / sh) % NINDIR(fs); 1727443Sroot nb = bap[i]; 1737443Sroot if (nb == 0) { 1747443Sroot if (rwflg==B_READ) { 1757443Sroot brelse(bp); 1767443Sroot return ((daddr_t)-1); 1777443Sroot } 1788258Smckusick if (pref == 0) 1798258Smckusick if (j < NIADDR) 1809165Ssam pref = blkpref(ip, lbn, 0, 1819165Ssam (daddr_t *)0); 1828258Smckusick else 1838258Smckusick pref = blkpref(ip, lbn, i, &bap[0]); 1849165Ssam nbp = alloc(ip, pref, (int)fs->fs_bsize); 1857443Sroot if (nbp == NULL) { 1867443Sroot brelse(bp); 1877443Sroot return ((daddr_t)-1); 1887443Sroot } 1897443Sroot nb = dbtofsb(fs, nbp->b_blkno); 1907443Sroot if (j < NIADDR || (ip->i_mode&IFMT) == IFDIR) 1917443Sroot /* 1927443Sroot * Write synchronously so indirect blocks 1937443Sroot * never point at garbage and blocks 1947443Sroot * in directories never contain garbage. 1957443Sroot */ 1967443Sroot bwrite(nbp); 1977443Sroot else 1987443Sroot bdwrite(nbp); 1997443Sroot bap[i] = nb; 2007443Sroot bdwrite(bp); 2017443Sroot } else 2027443Sroot brelse(bp); 2037443Sroot } 2047443Sroot 2057443Sroot /* 2067443Sroot * calculate read-ahead. 2077443Sroot */ 2087443Sroot if (i < NINDIR(fs) - 1) { 2097443Sroot rablock = fsbtodb(fs, bap[i+1]); 2107443Sroot rasize = fs->fs_bsize; 2117443Sroot } 2127443Sroot return (nb); 2137443Sroot } 214