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