xref: /csrg-svn/sys/ufs/lfs/lfs_balloc.c (revision 39679)
123396Smckusick /*
237736Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
337736Smckusick  * All rights reserved.
423396Smckusick  *
537736Smckusick  * Redistribution and use in source and binary forms are permitted
637736Smckusick  * provided that the above copyright notice and this paragraph are
737736Smckusick  * duplicated in all such forms and that any documentation,
837736Smckusick  * advertising materials, and other materials related to such
937736Smckusick  * distribution and use acknowledge that the software was developed
1037736Smckusick  * by the University of California, Berkeley.  The name of the
1137736Smckusick  * University may not be used to endorse or promote products derived
1237736Smckusick  * from this software without specific prior written permission.
1337736Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1437736Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1537736Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1637736Smckusick  *
17*39679Smckusick  *	@(#)lfs_balloc.c	7.6 (Berkeley) 11/30/89
1823396Smckusick  */
197443Sroot 
2017099Sbloom #include "param.h"
2117099Sbloom #include "systm.h"
2217099Sbloom #include "user.h"
2317099Sbloom #include "buf.h"
2417099Sbloom #include "proc.h"
2537736Smckusick #include "file.h"
2637736Smckusick #include "vnode.h"
2737736Smckusick #include "../ufs/inode.h"
2837736Smckusick #include "../ufs/fs.h"
297443Sroot 
307443Sroot /*
317443Sroot  * Bmap defines the structure of file system storage
32*39679Smckusick  * by returning the physical block number on a device
33*39679Smckusick  * given the inode and the logical block number in a file.
347443Sroot  */
35*39679Smckusick bmap(ip, bn, bnp)
367443Sroot 	register struct inode *ip;
3737736Smckusick 	register daddr_t bn;
3837736Smckusick 	daddr_t	*bnp;
397443Sroot {
4037736Smckusick 	register struct fs *fs;
4137736Smckusick 	register daddr_t nb;
4237736Smckusick 	struct buf *bp;
4337736Smckusick 	daddr_t *bap;
4437736Smckusick 	int i, j, sh;
4537736Smckusick 	int error;
4637736Smckusick 
4737736Smckusick 	if (bn < 0)
4837736Smckusick 		return (EFBIG);
4937736Smckusick 	fs = ip->i_fs;
5037736Smckusick 
5137736Smckusick 	/*
5237736Smckusick 	 * The first NDADDR blocks are direct blocks
5337736Smckusick 	 */
5437736Smckusick 	if (bn < NDADDR) {
5537736Smckusick 		nb = ip->i_db[bn];
5637736Smckusick 		if (nb == 0) {
5737736Smckusick 			*bnp = (daddr_t)-1;
5837736Smckusick 			return (0);
5937736Smckusick 		}
6037736Smckusick 		*bnp = fsbtodb(fs, nb);
6137736Smckusick 		return (0);
6237736Smckusick 	}
6337736Smckusick 	/*
64*39679Smckusick 	 * Determine the number of levels of indirection.
6537736Smckusick 	 */
6637736Smckusick 	sh = 1;
6737736Smckusick 	bn -= NDADDR;
6837736Smckusick 	for (j = NIADDR; j > 0; j--) {
6937736Smckusick 		sh *= NINDIR(fs);
7037736Smckusick 		if (bn < sh)
7137736Smckusick 			break;
7237736Smckusick 		bn -= sh;
7337736Smckusick 	}
7437736Smckusick 	if (j == 0)
7537736Smckusick 		return (EFBIG);
7637736Smckusick 	/*
77*39679Smckusick 	 * Fetch through the indirect blocks.
7837736Smckusick 	 */
7937736Smckusick 	nb = ip->i_ib[NIADDR - j];
8037736Smckusick 	if (nb == 0) {
8137736Smckusick 		*bnp = (daddr_t)-1;
8237736Smckusick 		return (0);
8337736Smckusick 	}
8437736Smckusick 	for (; j <= NIADDR; j++) {
8537736Smckusick 		if (error = bread(ip->i_devvp, fsbtodb(fs, nb),
8638776Smckusick 		    (int)fs->fs_bsize, NOCRED, &bp)) {
8737736Smckusick 			brelse(bp);
8837736Smckusick 			return (error);
8937736Smckusick 		}
90*39679Smckusick 		if ((bp->b_flags & B_CACHE) == 0)
91*39679Smckusick 			reassignbuf(bp, ITOV(ip));
9237736Smckusick 		bap = bp->b_un.b_daddr;
9337736Smckusick 		sh /= NINDIR(fs);
9437736Smckusick 		i = (bn / sh) % NINDIR(fs);
9537736Smckusick 		nb = bap[i];
9637736Smckusick 		if (nb == 0) {
9737736Smckusick 			*bnp = (daddr_t)-1;
9837736Smckusick 			brelse(bp);
9937736Smckusick 			return (0);
10037736Smckusick 		}
101*39679Smckusick 		brelse(bp);
10237736Smckusick 	}
10337736Smckusick 	*bnp = fsbtodb(fs, nb);
10437736Smckusick 	return (0);
10537736Smckusick }
10637736Smckusick 
10737736Smckusick /*
10837736Smckusick  * Balloc defines the structure of file system storage
109*39679Smckusick  * by allocating the physical blocks on a device given
110*39679Smckusick  * the inode and the logical block number in a file.
11137736Smckusick  */
112*39679Smckusick balloc(ip, bn, size, bpp, flags)
11337736Smckusick 	register struct inode *ip;
11437736Smckusick 	register daddr_t bn;
11537736Smckusick 	int size;
116*39679Smckusick 	struct buf **bpp;
11737736Smckusick 	int flags;
11837736Smckusick {
11937736Smckusick 	register struct fs *fs;
12037736Smckusick 	register daddr_t nb;
1217443Sroot 	struct buf *bp, *nbp;
122*39679Smckusick 	struct vnode *vp = ITOV(ip);
12337736Smckusick 	int osize, nsize, i, j, sh, error;
124*39679Smckusick 	daddr_t newb, lbn, *bap, pref, blkpref();
1257443Sroot 
126*39679Smckusick 	*bpp = (struct buf *)0;
12737736Smckusick 	if (bn < 0)
12837736Smckusick 		return (EFBIG);
1297443Sroot 	fs = ip->i_fs;
1307443Sroot 
1317443Sroot 	/*
1327443Sroot 	 * If the next write will extend the file into a new block,
1337443Sroot 	 * and the file is currently composed of a fragment
1347443Sroot 	 * this fragment has to be extended to be a full block.
1357443Sroot 	 */
1367443Sroot 	nb = lblkno(fs, ip->i_size);
13737736Smckusick 	if (nb < NDADDR && nb < bn) {
1387443Sroot 		osize = blksize(fs, ip, nb);
1397443Sroot 		if (osize < fs->fs_bsize && osize > 0) {
140*39679Smckusick 			error = realloccg(ip, nb,
1419165Ssam 				blkpref(ip, nb, (int)nb, &ip->i_db[0]),
14237736Smckusick 				osize, (int)fs->fs_bsize, &bp);
143*39679Smckusick 			if (error)
14437736Smckusick 				return (error);
1457443Sroot 			ip->i_size = (nb + 1) * fs->fs_bsize;
1467443Sroot 			ip->i_db[nb] = dbtofsb(fs, bp->b_blkno);
1477443Sroot 			ip->i_flag |= IUPD|ICHG;
148*39679Smckusick 			if (flags & B_SYNC)
149*39679Smckusick 				bwrite(bp);
150*39679Smckusick 			else
151*39679Smckusick 				bawrite(bp);
1527443Sroot 		}
1537443Sroot 	}
1547443Sroot 	/*
1557443Sroot 	 * The first NDADDR blocks are direct blocks
1567443Sroot 	 */
1577443Sroot 	if (bn < NDADDR) {
1588258Smckusick 		nb = ip->i_db[bn];
159*39679Smckusick 		if (nb != 0 && ip->i_size >= (bn + 1) * fs->fs_bsize) {
160*39679Smckusick 			error = bread(vp, bn, fs->fs_bsize, NOCRED, &bp);
161*39679Smckusick 			if (error) {
162*39679Smckusick 				brelse(bp);
163*39679Smckusick 				return (error);
164*39679Smckusick 			}
165*39679Smckusick 			*bpp = bp;
166*39679Smckusick 			return (0);
167*39679Smckusick 		}
168*39679Smckusick 		if (nb != 0) {
169*39679Smckusick 			/*
170*39679Smckusick 			 * Consider need to reallocate a fragment.
171*39679Smckusick 			 */
172*39679Smckusick 			osize = fragroundup(fs, blkoff(fs, ip->i_size));
173*39679Smckusick 			nsize = fragroundup(fs, size);
174*39679Smckusick 			if (nsize <= osize) {
175*39679Smckusick 				error = bread(vp, bn, osize, NOCRED, &bp);
176*39679Smckusick 				if (error) {
177*39679Smckusick 					brelse(bp);
178*39679Smckusick 					return (error);
179*39679Smckusick 				}
180*39679Smckusick 			} else {
181*39679Smckusick 				error = realloccg(ip, bn,
1829165Ssam 					blkpref(ip, bn, (int)bn, &ip->i_db[0]),
18337736Smckusick 					osize, nsize, &bp);
184*39679Smckusick 				if (error)
185*39679Smckusick 					return (error);
1867443Sroot 			}
187*39679Smckusick 		} else {
188*39679Smckusick 			if (ip->i_size < (bn + 1) * fs->fs_bsize)
189*39679Smckusick 				nsize = fragroundup(fs, size);
190*39679Smckusick 			else
191*39679Smckusick 				nsize = fs->fs_bsize;
192*39679Smckusick 			error = alloc(ip, bn,
193*39679Smckusick 				blkpref(ip, bn, (int)bn, &ip->i_db[0]),
194*39679Smckusick 				nsize, &newb);
195*39679Smckusick 			if (error)
19637736Smckusick 				return (error);
197*39679Smckusick 			bp = getblk(vp, bn, nsize);
198*39679Smckusick 			bp->b_blkno = fsbtodb(fs, newb);
199*39679Smckusick 			if (flags & B_CLRBUF)
200*39679Smckusick 				clrbuf(bp);
2017443Sroot 		}
202*39679Smckusick 		ip->i_db[bn] = dbtofsb(fs, bp->b_blkno);
203*39679Smckusick 		ip->i_flag |= IUPD|ICHG;
204*39679Smckusick 		*bpp = bp;
20537736Smckusick 		return (0);
2067443Sroot 	}
2077443Sroot 	/*
208*39679Smckusick 	 * Determine the number of levels of indirection.
2097443Sroot 	 */
2108258Smckusick 	pref = 0;
2117443Sroot 	sh = 1;
2128258Smckusick 	lbn = bn;
2137443Sroot 	bn -= NDADDR;
21437736Smckusick 	for (j = NIADDR; j > 0; j--) {
2157443Sroot 		sh *= NINDIR(fs);
2167443Sroot 		if (bn < sh)
2177443Sroot 			break;
2187443Sroot 		bn -= sh;
2197443Sroot 	}
22037736Smckusick 	if (j == 0)
22137736Smckusick 		return (EFBIG);
2227443Sroot 	/*
223*39679Smckusick 	 * Fetch the first indirect block allocating if necessary.
2247443Sroot 	 */
2257443Sroot 	nb = ip->i_ib[NIADDR - j];
2267443Sroot 	if (nb == 0) {
2279165Ssam 		pref = blkpref(ip, lbn, 0, (daddr_t *)0);
228*39679Smckusick 	        if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb))
22937736Smckusick 			return (error);
230*39679Smckusick 		nb = newb;
231*39679Smckusick 		bp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize);
232*39679Smckusick 		clrbuf(bp);
233*39679Smckusick 		if ((bp->b_flags & B_CACHE) == 0)
234*39679Smckusick 			reassignbuf(bp, vp);
2357443Sroot 		/*
2367443Sroot 		 * Write synchronously so that indirect blocks
2377443Sroot 		 * never point at garbage.
2387443Sroot 		 */
239*39679Smckusick 		if (error = bwrite(bp)) {
240*39679Smckusick 			blkfree(ip, nb, fs->fs_bsize);
241*39679Smckusick 			return (error);
242*39679Smckusick 		}
2437443Sroot 		ip->i_ib[NIADDR - j] = nb;
2447443Sroot 		ip->i_flag |= IUPD|ICHG;
2457443Sroot 	}
2467443Sroot 	/*
247*39679Smckusick 	 * Fetch through the indirect blocks, allocating as necessary.
2487443Sroot 	 */
249*39679Smckusick 	for (; ; j++) {
250*39679Smckusick 		error = bread(ip->i_devvp, fsbtodb(fs, nb),
251*39679Smckusick 		    (int)fs->fs_bsize, NOCRED, &bp);
252*39679Smckusick 		if (error) {
2537443Sroot 			brelse(bp);
25437736Smckusick 			return (error);
2557443Sroot 		}
256*39679Smckusick 		if ((bp->b_flags & B_CACHE) == 0)
257*39679Smckusick 			reassignbuf(bp, vp);
2587443Sroot 		bap = bp->b_un.b_daddr;
2597443Sroot 		sh /= NINDIR(fs);
2607443Sroot 		i = (bn / sh) % NINDIR(fs);
2617443Sroot 		nb = bap[i];
262*39679Smckusick 		if (j == NIADDR)
263*39679Smckusick 			break;
264*39679Smckusick 		if (nb != 0) {
265*39679Smckusick 			brelse(bp);
266*39679Smckusick 			continue;
267*39679Smckusick 		}
268*39679Smckusick 		if (pref == 0)
269*39679Smckusick 			pref = blkpref(ip, lbn, 0, (daddr_t *)0);
270*39679Smckusick 		if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) {
271*39679Smckusick 			brelse(bp);
272*39679Smckusick 			return (error);
273*39679Smckusick 		}
274*39679Smckusick 		nb = newb;
275*39679Smckusick 		nbp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize);
276*39679Smckusick 		clrbuf(nbp);
277*39679Smckusick 		if ((nbp->b_flags & B_CACHE) == 0)
278*39679Smckusick 			reassignbuf(nbp, vp);
279*39679Smckusick 		/*
280*39679Smckusick 		 * Write synchronously so that indirect blocks
281*39679Smckusick 		 * never point at garbage.
282*39679Smckusick 		 */
283*39679Smckusick 		if (error = bwrite(nbp)) {
284*39679Smckusick 			blkfree(ip, nb, fs->fs_bsize);
285*39679Smckusick 			brelse(bp);
286*39679Smckusick 			return (error);
287*39679Smckusick 		}
288*39679Smckusick 		bap[i] = nb;
289*39679Smckusick 		if (flags & B_SYNC)
290*39679Smckusick 			bwrite(bp);
291*39679Smckusick 		else
2927443Sroot 			bdwrite(bp);
293*39679Smckusick 	}
294*39679Smckusick 	/*
295*39679Smckusick 	 * Get the data block, allocating if necessary.
296*39679Smckusick 	 */
297*39679Smckusick 	if (nb == 0) {
298*39679Smckusick 		pref = blkpref(ip, lbn, i, &bap[0]);
299*39679Smckusick 		if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) {
3007443Sroot 			brelse(bp);
301*39679Smckusick 			return (error);
302*39679Smckusick 		}
303*39679Smckusick 		nb = newb;
304*39679Smckusick 		nbp = getblk(vp, lbn, fs->fs_bsize);
305*39679Smckusick 		nbp->b_blkno = fsbtodb(fs, nb);
306*39679Smckusick 		if (flags & B_CLRBUF)
307*39679Smckusick 			clrbuf(nbp);
308*39679Smckusick 		bap[i] = nb;
309*39679Smckusick 		if (flags & B_SYNC)
310*39679Smckusick 			bwrite(bp);
311*39679Smckusick 		else
312*39679Smckusick 			bdwrite(bp);
313*39679Smckusick 		*bpp = nbp;
314*39679Smckusick 		return (0);
3157443Sroot 	}
316*39679Smckusick 	brelse(bp);
317*39679Smckusick 	nbp = getblk(vp, lbn, fs->fs_bsize);
318*39679Smckusick 	nbp->b_blkno = fsbtodb(fs, nb);
319*39679Smckusick 	if ((flags & B_CLRBUF) && (nbp->b_flags & (B_DONE|B_DELWRI)) == 0) {
320*39679Smckusick 		brelse(nbp);
321*39679Smckusick 		error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp);
322*39679Smckusick 		if (error) {
323*39679Smckusick 			brelse(nbp);
324*39679Smckusick 			return (error);
325*39679Smckusick 		}
326*39679Smckusick 	}
327*39679Smckusick 	*bpp = nbp;
32837736Smckusick 	return (0);
3297443Sroot }
330