xref: /csrg-svn/sys/ufs/lfs/lfs_balloc.c (revision 51855)
123396Smckusick /*
251494Sbostic  * Copyright (c) 1989, 1991 Regents of the University of California.
337736Smckusick  * All rights reserved.
423396Smckusick  *
544537Sbostic  * %sccs.include.redist.c%
637736Smckusick  *
7*51855Sbostic  *	@(#)lfs_balloc.c	7.23 (Berkeley) 12/06/91
823396Smckusick  */
97443Sroot 
1051486Sbostic #include <sys/param.h>
1151486Sbostic #include <sys/buf.h>
1251486Sbostic #include <sys/proc.h>
1351486Sbostic #include <sys/vnode.h>
1451486Sbostic #include <sys/mount.h>
1551486Sbostic #include <sys/resourcevar.h>
1651486Sbostic #include <sys/specdev.h>
1751486Sbostic #include <sys/trace.h>
187443Sroot 
1951494Sbostic #include <ufs/ufs/quota.h>
2051494Sbostic #include <ufs/ufs/inode.h>
2151494Sbostic #include <ufs/ufs/ufsmount.h>
2247571Skarels 
2351494Sbostic #include <ufs/lfs/lfs.h>
2451494Sbostic #include <ufs/lfs/lfs_extern.h>
2551486Sbostic 
26*51855Sbostic static int lfs_getlbns __P((struct vnode *, daddr_t, INDIR *, int *));
27*51855Sbostic 
287443Sroot /*
2951486Sbostic  * Bmap converts a the logical block number of a file to its physical block
3051486Sbostic  * number on the disk. The conversion is done by using the logical block
3151486Sbostic  * number to index into the array of block pointers described by the dinode.
32*51855Sbostic  */
33*51855Sbostic int
34*51855Sbostic lfs_bmap(vp, bn, vpp, bnp)
35*51855Sbostic 	struct vnode *vp;
36*51855Sbostic 	register daddr_t bn;
37*51855Sbostic 	struct vnode **vpp;
38*51855Sbostic 	daddr_t *bnp;
39*51855Sbostic {
40*51855Sbostic #ifdef VERBOSE
41*51855Sbostic 	printf("lfs_bmap\n");
42*51855Sbostic #endif
43*51855Sbostic 	/*
44*51855Sbostic 	 * Check for underlying vnode requests and ensure that logical
45*51855Sbostic 	 * to physical mapping is requested.
46*51855Sbostic 	 */
47*51855Sbostic 	if (vpp != NULL)
48*51855Sbostic 		*vpp = VTOI(vp)->i_devvp;
49*51855Sbostic 	if (bnp == NULL)
50*51855Sbostic 		return (0);
51*51855Sbostic 
52*51855Sbostic 	return (lfs_bmaparray(vp, bn, bnp, NULL, NULL));
53*51855Sbostic }
54*51855Sbostic 
55*51855Sbostic /*
5651846Sbostic  * LFS has a different version of bmap from FFS because of a naming conflict.
5751846Sbostic  * In FFS, meta blocks are given real disk addresses at allocation time, and
5851846Sbostic  * are linked into the device vnode, using a logical block number which is
5951846Sbostic  * the same as the physical block number.  This can't be done by LFS because
6051846Sbostic  * blocks aren't given disk addresses until they're written, so there's no
6151846Sbostic  * way to distinguish the meta-data blocks for one file from any other file.
6251846Sbostic  * This means that meta-data blocks have to be on the vnode for the file so
6351846Sbostic  * they can be found, and have to have "names" different from the standard
6451846Sbostic  * data blocks.  To do this, we divide the name space into positive and
6551846Sbostic  * negative block numbers, and give the meta-data blocks negative logical
6651847Sbostic  * numbers.  Indirect blocks are addressed by the negative address of the
6751847Sbostic  * first data block to which they point.  Double indirect blocks are addressed
6851847Sbostic  * by one less than the address of the first indirect block to which they
6951847Sbostic  * point.  Triple indirect blocks are addressed by one less than the address
7051847Sbostic  * of the first double indirect block to which they point.
717443Sroot  */
7251348Sroot int
73*51855Sbostic lfs_bmaparray(vp, bn, bnp, ap, nump)
7451561Smckusick 	struct vnode *vp;
7537736Smckusick 	register daddr_t bn;
7651561Smckusick 	daddr_t *bnp;
77*51855Sbostic 	INDIR *ap;
78*51855Sbostic 	int *nump;
797443Sroot {
8051561Smckusick 	register struct inode *ip;
8151846Sbostic 	struct buf *bp;
82*51855Sbostic 	struct lfs *fs;
8351561Smckusick 	struct vnode *devvp;
84*51855Sbostic 	INDIR a[NIADDR], *xap;
85*51855Sbostic 	daddr_t *bap, daddr;
86*51855Sbostic 	long metalbn;
87*51855Sbostic 	int error, num, off;
8837736Smckusick 
89*51855Sbostic 
9051561Smckusick 	ip = VTOI(vp);
9151846Sbostic #ifdef VERBOSE
92*51855Sbostic 	printf("lfs_bmap: block number %d, inode %d\n", bn, ip->i_number);
9351846Sbostic #endif
94*51855Sbostic #ifdef DIAGNOSTIC
95*51855Sbostic 	if (ap != NULL && nump == NULL || ap == NULL && nump != NULL)
96*51855Sbostic 		panic("lfs_bmaparray: invalid arguments");
97*51855Sbostic #endif
9851847Sbostic 
99*51855Sbostic 	xap = ap == NULL ? a : ap;
100*51855Sbostic 	if (error = lfs_getlbns(vp, bn, xap, nump))
101*51855Sbostic 		return (error);
102*51855Sbostic 
103*51855Sbostic 	num = *nump;
104*51855Sbostic 	fs = ip->i_lfs;
105*51855Sbostic 	if (num == 0) {
106*51855Sbostic 		*bnp = ip->i_db[bn];
107*51855Sbostic 		if (*bnp == 0)
10851348Sroot 			*bnp = UNASSIGNED;
10937736Smckusick 		return (0);
11037736Smckusick 	}
11151486Sbostic 
112*51855Sbostic 	/* Fetch through the indirect blocks. */
11351846Sbostic 	bp = NULL;
11451183Sbostic 	devvp = VFSTOUFS(vp->v_mount)->um_devvp;
115*51855Sbostic 	for (bap = ip->i_ib; num--; off = xap->in_off, ++xap) {
116*51855Sbostic 		off = xap->in_off;
117*51855Sbostic 		metalbn = xap->in_lbn;
118*51855Sbostic 
11951846Sbostic 		/*
12051846Sbostic 		 * In LFS, it's possible to have a block appended to a file
12151846Sbostic 		 * for which the meta-blocks have not yet been allocated.
12251846Sbostic 		 * This is a win if the file never gets written or if the
12351846Sbostic 		 * file's growing.
12451846Sbostic 		 */
12551846Sbostic 		if ((daddr = bap[off]) == 0) {
12651348Sroot 			daddr = UNASSIGNED;
12751183Sbostic 			break;
12851183Sbostic 		}
12951847Sbostic 
13051847Sbostic 		/* If searching for a meta-data block, quit when found. */
131*51855Sbostic 		if (metalbn == bn)
13251847Sbostic 			break;
13351847Sbostic 
13451846Sbostic 		/*
13551846Sbostic 		 * Read in the appropriate indirect block.  LFS can't do a
13651846Sbostic 		 * bread because bread knows that FFS will hand it the device
13751846Sbostic 		 * vnode, not the file vnode, so the b_dev and b_blkno would
13851846Sbostic 		 * be wrong.
13951846Sbostic 		 *
14051846Sbostic 		 * XXX
14151846Sbostic 		 * This REALLY needs to be fixed, at the very least it needs
142*51855Sbostic 		 * to be rethought when the buffer cache goes away.  When it's
143*51855Sbostic 		 * fixed, change lfs_bmaparray and lfs_getlbns to take an ip,
144*51855Sbostic 		 * not a vp.
14551846Sbostic 		 */
14651183Sbostic 		if (bp)
14737736Smckusick 			brelse(bp);
14851847Sbostic 		bp = getblk(vp, metalbn, fs->lfs_bsize);
14951183Sbostic 		if (bp->b_flags & (B_DONE | B_DELWRI)) {
15051847Sbostic 			trace(TR_BREADHIT, pack(vp, size), metalbn);
15151183Sbostic 		} else {
15251847Sbostic 			trace(TR_BREADMISS, pack(vp, size), metalbn);
15351847Sbostic 			bp->b_blkno = daddr;
15451846Sbostic 			bp->b_flags |= B_READ;
15551183Sbostic 			bp->b_dev = devvp->v_rdev;
15651215Sbostic 			(devvp->v_op->vop_strategy)(bp);
15751183Sbostic 			curproc->p_stats->p_ru.ru_inblock++;	/* XXX */
15851183Sbostic 			if (error = biowait(bp)) {
15951183Sbostic 				brelse(bp);
16051183Sbostic 				return (error);
16151183Sbostic 			}
16237736Smckusick 		}
16337736Smckusick 		bap = bp->b_un.b_daddr;
16451183Sbostic 	}
16551183Sbostic 	if (bp)
16639679Smckusick 		brelse(bp);
16751183Sbostic 
16851183Sbostic 	*bnp = daddr;
16937736Smckusick 	return (0);
17037736Smckusick }
171*51855Sbostic 
172*51855Sbostic /*
173*51855Sbostic  * Create an array of logical block number/offset pairs which represent the
174*51855Sbostic  * path of indirect blocks required to access a data block.  The first "pair"
175*51855Sbostic  * contains the logical block number of the appropriate single, double or
176*51855Sbostic  * triple indirect block and the offset into the inode indirect block array.
177*51855Sbostic  * Note, the logical block number of the inode single/double/triple indirect
178*51855Sbostic  * block appears twice in the array, once with the offset into the i_ib and
179*51855Sbostic  * once with the offset into the page itself.
180*51855Sbostic  */
181*51855Sbostic int
182*51855Sbostic lfs_getlbns(vp, bn, ap, nump)
183*51855Sbostic 	struct vnode *vp;
184*51855Sbostic 	register daddr_t bn;
185*51855Sbostic 	INDIR *ap;
186*51855Sbostic 	int *nump;
187*51855Sbostic {
188*51855Sbostic 	struct lfs *fs;
189*51855Sbostic 	long metalbn, realbn;
190*51855Sbostic 	int j, off, sh;
191*51855Sbostic 
192*51855Sbostic #ifdef VERBOSE
193*51855Sbostic 	printf("lfs_getlbns: bn %d, inode %d\n", bn, VTOI(vp)->i_number);
194*51855Sbostic #endif
195*51855Sbostic 	*nump = 0;
196*51855Sbostic 	realbn = bn;
197*51855Sbostic 	if ((long)bn < 0)
198*51855Sbostic 		bn = -(long)bn;
199*51855Sbostic 
200*51855Sbostic 	/* The first NDADDR blocks are direct blocks. */
201*51855Sbostic 	if (bn < NDADDR)
202*51855Sbostic 		return(0);
203*51855Sbostic 
204*51855Sbostic 	/*
205*51855Sbostic 	 * Determine the number of levels of indirection.  After this loop
206*51855Sbostic 	 * is done, sh indicates the number of data blocks possible at the
207*51855Sbostic 	 * given level of indirection, and NIADDR - j is the number of levels
208*51855Sbostic 	 * of indirection needed to locate the requested block.
209*51855Sbostic 	 */
210*51855Sbostic 	bn -= NDADDR;
211*51855Sbostic 	fs = VTOI(vp)->i_lfs;
212*51855Sbostic 	sh = 1;
213*51855Sbostic 	for (j = NIADDR; j > 0; j--) {
214*51855Sbostic 		sh *= NINDIR(fs);
215*51855Sbostic 		if (bn < sh)
216*51855Sbostic 			break;
217*51855Sbostic 		bn -= sh;
218*51855Sbostic 	}
219*51855Sbostic 	if (j == 0)
220*51855Sbostic 		return (EFBIG);
221*51855Sbostic 
222*51855Sbostic 	/* Calculate the address of the first meta-block. */
223*51855Sbostic 	if (realbn >= 0)
224*51855Sbostic 		metalbn = -(realbn - bn + NIADDR - j);
225*51855Sbostic 	else
226*51855Sbostic 		metalbn = -(-realbn - bn + NIADDR - j);
227*51855Sbostic 
228*51855Sbostic 	/*
229*51855Sbostic 	 * At each iteration, off is the offset into the bap array which is
230*51855Sbostic 	 * an array of disk addresses at the current level of indirection.
231*51855Sbostic 	 * The logical block number and the offset in that block are stored
232*51855Sbostic 	 * into the argument array.
233*51855Sbostic 	 */
234*51855Sbostic 	++*nump;
235*51855Sbostic 	ap->in_lbn = metalbn;
236*51855Sbostic 	ap->in_off = off = NIADDR - j;
237*51855Sbostic 	ap++;
238*51855Sbostic 	for (; j <= NIADDR; j++) {
239*51855Sbostic 		/* If searching for a meta-data block, quit when found. */
240*51855Sbostic 		if (metalbn == realbn)
241*51855Sbostic 			break;
242*51855Sbostic 
243*51855Sbostic 		sh /= NINDIR(fs);
244*51855Sbostic 		off = (bn / sh) % NINDIR(fs);
245*51855Sbostic 
246*51855Sbostic 		++*nump;
247*51855Sbostic 		ap->in_lbn = metalbn;
248*51855Sbostic 		ap->in_off = off;
249*51855Sbostic 		++ap;
250*51855Sbostic 
251*51855Sbostic 		metalbn -= -1 + off * sh;
252*51855Sbostic 	}
253*51855Sbostic 	return (0);
254*51855Sbostic }
255