xref: /csrg-svn/sys/ufs/lfs/lfs_balloc.c (revision 51183)
1 /*
2  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)lfs_balloc.c	7.15 (Berkeley) 09/25/91
8  */
9 
10 #include "param.h"
11 #include "systm.h"
12 #include "buf.h"
13 #include "time.h"
14 #include "resource.h"
15 #include "resourcevar.h"
16 #include "proc.h"
17 #include "file.h"
18 #include "vnode.h"
19 #include "mount.h"
20 #include "specdev.h"
21 
22 #include "../ufs/quota.h"
23 #include "../ufs/inode.h"
24 #include "../ufs/ufsmount.h"
25 #include "trace.h"
26 #include "lfs.h"
27 #include "lfs_extern.h"
28 
29 /*
30  * Bmap converts a the logical block number of a file
31  * to its physical block number on the disk. The conversion
32  * is done by using the logical block number to index into
33  * the array of block pointers described by the dinode.
34  */
35 lfs_bmap(ip, bn, bnp)
36 	register struct inode *ip;
37 	register daddr_t bn;
38 	daddr_t	*bnp;
39 {
40 	register LFS *fs;					/* LFS */
41 	register daddr_t nb;
42 	struct vnode *devvp, *vp;
43 	struct buf *bp;
44 	daddr_t *bap, daddr;
45 	daddr_t lbn_ind;
46 	int i, j, off, sh;
47 	int error;
48 
49 printf("lfs_bmap: block number %d, inode %d\n", bn, ip->i_number);
50 	fs = ip->i_lfs;						/* LFS */
51 
52 	/*
53 	 * We access all blocks in the cache, even indirect blocks by means of
54 	 * a logical address. Indirect blocks (single, double, triple) all have
55 	 * negative block numbers. The first NDADDR blocks are direct blocks,
56 	 * the first NIADDR negative blocks are the indirect block pointers.
57 	 * The single, double and triple indirect blocks in the inode
58 	 * are addressed: -1, -2 and -3 respectively.
59 	 * XXX we don't handle triple indirect at all.
60 	 */
61 	if (bn < 0) {
62 		/* Shouldn't be here -- we don't think */
63 		printf("lfs_bmap: NEGATIVE indirect block number %d\n", bn);
64 		panic("negative indirect block number");
65 	}
66 
67 	/*
68 	 * The first NDADDR blocks are direct blocks
69 	 */
70 	if (bn < NDADDR) {
71 		nb = ip->i_db[bn];
72 		if (nb == 0) {
73 			*bnp = (daddr_t)-1;
74 			return (0);
75 		}
76 		*bnp = nb;
77 		return (0);
78 	}
79 	/*
80 	 * Determine the number of levels of indirection.
81 	 */
82 	sh = 1;
83 	bn -= NDADDR;
84 	lbn_ind = 0;
85 	for (j = NIADDR; j > 0; j--) {
86 		lbn_ind--;
87 		sh *= NINDIR(fs);
88 		if (bn < sh)
89 			break;
90 		bn -= sh;
91 	}
92 	if (j == 0)
93 		return (EFBIG);
94 	/*
95 	 * Fetch through the indirect blocks.
96 	 */
97 
98 	vp = ITOV(ip);
99 	devvp = VFSTOUFS(vp->v_mount)->um_devvp;
100 	for (off = NIADDR - j, bap = ip->i_ib; j <= NIADDR; j++) {
101 		if((daddr = bap[off]) == 0) {
102 			daddr = (daddr_t)-1;
103 			break;
104 		}
105 		if (bp)
106 			brelse(bp);
107 		bp = getblk(vp, lbn_ind, fs->lfs_bsize);
108 		if (bp->b_flags & (B_DONE | B_DELWRI)) {
109 			trace(TR_BREADHIT, pack(vp, size), lbn_ind);
110 		} else {
111 			trace(TR_BREADMISS, pack(vp, size), lbn_ind);
112 			bp->b_blkno = daddr;
113 			bp->b_flags |= B_READ;
114 			bp->b_dev = devvp->v_rdev;
115 			(*(devvp->v_op->vop_strategy))(bp);
116 			curproc->p_stats->p_ru.ru_inblock++;	/* XXX */
117 			if (error = biowait(bp)) {
118 				brelse(bp);
119 				return (error);
120 			}
121 		}
122 		bap = bp->b_un.b_daddr;
123 		sh /= NINDIR(fs);
124 		off = (bn / sh) % NINDIR(fs);
125 		lbn_ind  = -(NIADDR + 1 + off);
126 	}
127 	if (bp)
128 		brelse(bp);
129 
130 	*bnp = daddr;
131 	return (0);
132 }
133