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