xref: /csrg-svn/sys/ufs/lfs/lfs_balloc.c (revision 17099)
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