xref: /csrg-svn/sys/ufs/lfs/lfs_balloc.c (revision 7443)
1*7443Sroot /*	lfs_balloc.c	5.1	82/07/15	*/
2*7443Sroot 
3*7443Sroot #include "../h/param.h"
4*7443Sroot #include "../h/systm.h"
5*7443Sroot #include "../h/conf.h"
6*7443Sroot #include "../h/inode.h"
7*7443Sroot #include "../h/dir.h"
8*7443Sroot #include "../h/user.h"
9*7443Sroot #include "../h/buf.h"
10*7443Sroot #include "../h/proc.h"
11*7443Sroot #include "../h/fs.h"
12*7443Sroot 
13*7443Sroot /*
14*7443Sroot  * Bmap defines the structure of file system storage
15*7443Sroot  * by returning the physical block number on a device given the
16*7443Sroot  * inode and the logical block number in a file.
17*7443Sroot  * When convenient, it also leaves the physical
18*7443Sroot  * block number of the next block of the file in rablock
19*7443Sroot  * for use in read-ahead.
20*7443Sroot  */
21*7443Sroot /*VARARGS3*/
22*7443Sroot daddr_t
23*7443Sroot bmap(ip, bn, rwflg, size)
24*7443Sroot 	register struct inode *ip;
25*7443Sroot 	daddr_t bn;
26*7443Sroot 	int rwflg;
27*7443Sroot 	int size;	/* supplied only when rwflg == B_WRITE */
28*7443Sroot {
29*7443Sroot 	register int i;
30*7443Sroot 	int osize, nsize;
31*7443Sroot 	struct buf *bp, *nbp;
32*7443Sroot 	struct fs *fs;
33*7443Sroot 	int j, sh;
34*7443Sroot 	daddr_t nb, *bap, pref, blkpref();
35*7443Sroot 
36*7443Sroot 	if (bn < 0) {
37*7443Sroot 		u.u_error = EFBIG;
38*7443Sroot 		return ((daddr_t)0);
39*7443Sroot 	}
40*7443Sroot 	fs = ip->i_fs;
41*7443Sroot 	rablock = 0;
42*7443Sroot 	rasize = 0;		/* conservative */
43*7443Sroot 
44*7443Sroot 	/*
45*7443Sroot 	 * If the next write will extend the file into a new block,
46*7443Sroot 	 * and the file is currently composed of a fragment
47*7443Sroot 	 * this fragment has to be extended to be a full block.
48*7443Sroot 	 */
49*7443Sroot 	nb = lblkno(fs, ip->i_size);
50*7443Sroot 	if (rwflg == B_WRITE && nb < NDADDR && nb < bn) {
51*7443Sroot 		osize = blksize(fs, ip, nb);
52*7443Sroot 		if (osize < fs->fs_bsize && osize > 0) {
53*7443Sroot 			bp = realloccg(ip, ip->i_db[nb],
54*7443Sroot 				nb == 0 ? 0 : ip->i_db[nb - 1] + fs->fs_frag,
55*7443Sroot 				osize, fs->fs_bsize);
56*7443Sroot 			ip->i_size = (nb + 1) * fs->fs_bsize;
57*7443Sroot 			ip->i_db[nb] = dbtofsb(fs, bp->b_blkno);
58*7443Sroot 			ip->i_flag |= IUPD|ICHG;
59*7443Sroot 			bdwrite(bp);
60*7443Sroot 		}
61*7443Sroot 	}
62*7443Sroot 	/*
63*7443Sroot 	 * The first NDADDR blocks are direct blocks
64*7443Sroot 	 */
65*7443Sroot 	if (bn < NDADDR) {
66*7443Sroot 		i = bn;
67*7443Sroot 		nb = ip->i_db[i];
68*7443Sroot 		if (rwflg == B_READ) {
69*7443Sroot 			if (nb == 0)
70*7443Sroot 				return ((daddr_t)-1);
71*7443Sroot 			goto gotit;
72*7443Sroot 		}
73*7443Sroot 		if (nb == 0 || ip->i_size < (i + 1) * fs->fs_bsize) {
74*7443Sroot 			if (nb != 0) {
75*7443Sroot 				/* consider need to reallocate a frag */
76*7443Sroot 				osize = fragroundup(fs, blkoff(fs, ip->i_size));
77*7443Sroot 				nsize = fragroundup(fs, size);
78*7443Sroot 				if (nsize <= osize)
79*7443Sroot 					goto gotit;
80*7443Sroot 				bp = realloccg(ip, nb, i == 0 ?
81*7443Sroot 					0 : ip->i_db[i - 1] + fs->fs_frag,
82*7443Sroot 					osize, nsize);
83*7443Sroot 			} else {
84*7443Sroot 				if (ip->i_size < (i + 1) * fs->fs_bsize)
85*7443Sroot 					nsize = fragroundup(fs, size);
86*7443Sroot 				else
87*7443Sroot 					nsize = fs->fs_bsize;
88*7443Sroot 				bp = alloc(ip, i > 0 ?
89*7443Sroot 					ip->i_db[i - 1] + fs->fs_frag : 0,
90*7443Sroot 					nsize);
91*7443Sroot 			}
92*7443Sroot 			if (bp == NULL)
93*7443Sroot 				return ((daddr_t)-1);
94*7443Sroot 			nb = dbtofsb(fs, bp->b_blkno);
95*7443Sroot 			if ((ip->i_mode&IFMT) == IFDIR)
96*7443Sroot 				/*
97*7443Sroot 				 * Write directory blocks synchronously
98*7443Sroot 				 * so they never appear with garbage in
99*7443Sroot 				 * them on the disk.
100*7443Sroot 				 */
101*7443Sroot 				bwrite(bp);
102*7443Sroot 			else
103*7443Sroot 				bdwrite(bp);
104*7443Sroot 			ip->i_db[i] = nb;
105*7443Sroot 			ip->i_flag |= IUPD|ICHG;
106*7443Sroot 		}
107*7443Sroot gotit:
108*7443Sroot 		if (i < NDADDR - 1) {
109*7443Sroot 			rablock = fsbtodb(fs, ip->i_db[i+1]);
110*7443Sroot 			rasize = blksize(fs, ip, i+1);
111*7443Sroot 		}
112*7443Sroot 		return (nb);
113*7443Sroot 	}
114*7443Sroot 
115*7443Sroot 	/*
116*7443Sroot 	 * Determine how many levels of indirection.
117*7443Sroot 	 */
118*7443Sroot 	sh = 1;
119*7443Sroot 	bn -= NDADDR;
120*7443Sroot 	for (j = NIADDR; j>0; j--) {
121*7443Sroot 		sh *= NINDIR(fs);
122*7443Sroot 		if (bn < sh)
123*7443Sroot 			break;
124*7443Sroot 		bn -= sh;
125*7443Sroot 	}
126*7443Sroot 	if (j == 0) {
127*7443Sroot 		u.u_error = EFBIG;
128*7443Sroot 		return ((daddr_t)0);
129*7443Sroot 	}
130*7443Sroot 
131*7443Sroot 	/*
132*7443Sroot 	 * fetch the first indirect block
133*7443Sroot 	 */
134*7443Sroot 	nb = ip->i_ib[NIADDR - j];
135*7443Sroot 	if (nb == 0) {
136*7443Sroot 		if (rwflg==B_READ ||
137*7443Sroot 		    (bp = alloc(ip, (daddr_t)0, fs->fs_bsize)) == NULL)
138*7443Sroot 			return ((daddr_t)-1);
139*7443Sroot 		nb = dbtofsb(fs, bp->b_blkno);
140*7443Sroot 		/*
141*7443Sroot 		 * Write synchronously so that indirect blocks
142*7443Sroot 		 * never point at garbage.
143*7443Sroot 		 */
144*7443Sroot 		bwrite(bp);
145*7443Sroot 		ip->i_ib[NIADDR - j] = nb;
146*7443Sroot 		ip->i_flag |= IUPD|ICHG;
147*7443Sroot 	}
148*7443Sroot 
149*7443Sroot 	/*
150*7443Sroot 	 * fetch through the indirect blocks
151*7443Sroot 	 */
152*7443Sroot 	for (; j <= NIADDR; j++) {
153*7443Sroot 		bp = bread(ip->i_dev, fsbtodb(fs, nb), fs->fs_bsize);
154*7443Sroot 		if (bp->b_flags & B_ERROR) {
155*7443Sroot 			brelse(bp);
156*7443Sroot 			return ((daddr_t)0);
157*7443Sroot 		}
158*7443Sroot 		bap = bp->b_un.b_daddr;
159*7443Sroot 		sh /= NINDIR(fs);
160*7443Sroot 		i = (bn / sh) % NINDIR(fs);
161*7443Sroot 		nb = bap[i];
162*7443Sroot 		if (nb == 0) {
163*7443Sroot 			if (rwflg==B_READ) {
164*7443Sroot 				brelse(bp);
165*7443Sroot 				return ((daddr_t)-1);
166*7443Sroot 			}
167*7443Sroot 			if (i % (fs->fs_fsize / sizeof(daddr_t)) == 0 ||
168*7443Sroot 			    bap[i - 1] == 0)
169*7443Sroot 				pref = blkpref(ip->i_fs);
170*7443Sroot 			else
171*7443Sroot 				pref = bap[i - 1] + fs->fs_frag;
172*7443Sroot 		        nbp = alloc(ip, pref, fs->fs_bsize);
173*7443Sroot 			if (nbp == NULL) {
174*7443Sroot 				brelse(bp);
175*7443Sroot 				return ((daddr_t)-1);
176*7443Sroot 			}
177*7443Sroot 			nb = dbtofsb(fs, nbp->b_blkno);
178*7443Sroot 			if (j < NIADDR || (ip->i_mode&IFMT) == IFDIR)
179*7443Sroot 				/*
180*7443Sroot 				 * Write synchronously so indirect blocks
181*7443Sroot 				 * never point at garbage and blocks
182*7443Sroot 				 * in directories never contain garbage.
183*7443Sroot 				 */
184*7443Sroot 				bwrite(nbp);
185*7443Sroot 			else
186*7443Sroot 				bdwrite(nbp);
187*7443Sroot 			bap[i] = nb;
188*7443Sroot 			bdwrite(bp);
189*7443Sroot 		} else
190*7443Sroot 			brelse(bp);
191*7443Sroot 	}
192*7443Sroot 
193*7443Sroot 	/*
194*7443Sroot 	 * calculate read-ahead.
195*7443Sroot 	 */
196*7443Sroot 	if (i < NINDIR(fs) - 1) {
197*7443Sroot 		rablock = fsbtodb(fs, bap[i+1]);
198*7443Sroot 		rasize = fs->fs_bsize;
199*7443Sroot 	}
200*7443Sroot 	return (nb);
201*7443Sroot }
202