Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
9fc995cf | 2 | * Copyright (c) 1989, 1991 Regents of the University of California. |
7188ac27 | 3 | * All rights reserved. |
da7c5cc6 | 4 | * |
b702c21d | 5 | * %sccs.include.redist.c% |
7188ac27 | 6 | * |
ea67b335 | 7 | * @(#)lfs_balloc.c 7.28 (Berkeley) %G% |
da7c5cc6 | 8 | */ |
52212483 | 9 | |
f6437c6d KB |
10 | #include <sys/param.h> |
11 | #include <sys/buf.h> | |
12 | #include <sys/proc.h> | |
13 | #include <sys/vnode.h> | |
14 | #include <sys/mount.h> | |
15 | #include <sys/resourcevar.h> | |
16 | #include <sys/specdev.h> | |
17 | #include <sys/trace.h> | |
c6f5111d | 18 | |
9fc995cf KB |
19 | #include <ufs/ufs/quota.h> |
20 | #include <ufs/ufs/inode.h> | |
21 | #include <ufs/ufs/ufsmount.h> | |
f6437c6d | 22 | |
9fc995cf KB |
23 | #include <ufs/lfs/lfs.h> |
24 | #include <ufs/lfs/lfs_extern.h> | |
52212483 | 25 | |
bc375a66 | 26 | int lfs_getlbns __P((struct vnode *, daddr_t, INDIR *, int *)); |
1cc06455 | 27 | |
52212483 | 28 | /* |
f6437c6d KB |
29 | * Bmap converts a the logical block number of a file to its physical block |
30 | * number on the disk. The conversion is done by using the logical block | |
31 | * number to index into the array of block pointers described by the dinode. | |
1cc06455 KB |
32 | */ |
33 | int | |
9342689a JH |
34 | lfs_bmap (ap) |
35 | struct vop_bmap_args *ap; | |
36 | #define vp (ap->a_vp) | |
37 | #define bn (ap->a_bn) | |
38 | #define vpp (ap->a_vpp) | |
39 | #define bnp (ap->a_bnp) | |
1cc06455 KB |
40 | { |
41 | #ifdef VERBOSE | |
42 | printf("lfs_bmap\n"); | |
43 | #endif | |
44 | /* | |
45 | * Check for underlying vnode requests and ensure that logical | |
46 | * to physical mapping is requested. | |
47 | */ | |
48 | if (vpp != NULL) | |
49 | *vpp = VTOI(vp)->i_devvp; | |
50 | if (bnp == NULL) | |
51 | return (0); | |
52 | ||
53 | return (lfs_bmaparray(vp, bn, bnp, NULL, NULL)); | |
54 | } | |
9342689a JH |
55 | #undef vp |
56 | #undef bn | |
57 | #undef vpp | |
58 | #undef bnp | |
1cc06455 KB |
59 | |
60 | /* | |
fce00cda KB |
61 | * LFS has a different version of bmap from FFS because of a naming conflict. |
62 | * In FFS, meta blocks are given real disk addresses at allocation time, and | |
63 | * are linked into the device vnode, using a logical block number which is | |
64 | * the same as the physical block number. This can't be done by LFS because | |
65 | * blocks aren't given disk addresses until they're written, so there's no | |
66 | * way to distinguish the meta-data blocks for one file from any other file. | |
67 | * This means that meta-data blocks have to be on the vnode for the file so | |
68 | * they can be found, and have to have "names" different from the standard | |
69 | * data blocks. To do this, we divide the name space into positive and | |
70 | * negative block numbers, and give the meta-data blocks negative logical | |
175a033b KB |
71 | * numbers. Indirect blocks are addressed by the negative address of the |
72 | * first data block to which they point. Double indirect blocks are addressed | |
73 | * by one less than the address of the first indirect block to which they | |
74 | * point. Triple indirect blocks are addressed by one less than the address | |
75 | * of the first double indirect block to which they point. | |
52212483 | 76 | */ |
e3b6a940 | 77 | int |
1cc06455 | 78 | lfs_bmaparray(vp, bn, bnp, ap, nump) |
8ad16d99 | 79 | struct vnode *vp; |
7188ac27 | 80 | register daddr_t bn; |
8ad16d99 | 81 | daddr_t *bnp; |
1cc06455 KB |
82 | INDIR *ap; |
83 | int *nump; | |
52212483 | 84 | { |
8ad16d99 | 85 | register struct inode *ip; |
7188ac27 | 86 | struct buf *bp; |
1cc06455 | 87 | struct lfs *fs; |
fce00cda | 88 | struct vnode *devvp; |
1cc06455 KB |
89 | INDIR a[NIADDR], *xap; |
90 | daddr_t *bap, daddr; | |
91 | long metalbn; | |
92 | int error, num, off; | |
7188ac27 | 93 | |
d5075120 | 94 | |
1cc06455 | 95 | ip = VTOI(vp); |
fce00cda | 96 | #ifdef VERBOSE |
1cc06455 KB |
97 | printf("lfs_bmap: block number %d, inode %d\n", bn, ip->i_number); |
98 | #endif | |
99 | #ifdef DIAGNOSTIC | |
100 | if (ap != NULL && nump == NULL || ap == NULL && nump != NULL) | |
101 | panic("lfs_bmaparray: invalid arguments"); | |
fce00cda | 102 | #endif |
175a033b | 103 | |
1cc06455 KB |
104 | xap = ap == NULL ? a : ap; |
105 | if (error = lfs_getlbns(vp, bn, xap, nump)) | |
106 | return (error); | |
f6437c6d | 107 | |
1cc06455 | 108 | num = *nump; |
cb92c035 | 109 | |
1cc06455 KB |
110 | if (num == 0) { |
111 | *bnp = ip->i_db[bn]; | |
112 | if (*bnp == 0) | |
113 | *bnp = UNASSIGNED; | |
114 | return (0); | |
7188ac27 | 115 | } |
d5075120 | 116 | |
cb92c035 KB |
117 | |
118 | /* Get disk address out of indirect block array */ | |
119 | daddr = ip->i_ib[xap->in_off]; | |
120 | ||
1cc06455 | 121 | /* Fetch through the indirect blocks. */ |
cb92c035 | 122 | fs = ip->i_lfs; |
d5075120 | 123 | devvp = VFSTOUFS(vp->v_mount)->um_devvp; |
175a033b | 124 | |
cb92c035 KB |
125 | for (bp = NULL, ++xap; daddr && --num; ++xap) { |
126 | /* If looking for a meta-block, break out when we find it. */ | |
127 | metalbn = xap->in_lbn; | |
1cc06455 | 128 | if (metalbn == bn) |
175a033b KB |
129 | break; |
130 | ||
fce00cda KB |
131 | /* |
132 | * Read in the appropriate indirect block. LFS can't do a | |
133 | * bread because bread knows that FFS will hand it the device | |
134 | * vnode, not the file vnode, so the b_dev and b_blkno would | |
135 | * be wrong. | |
136 | * | |
137 | * XXX | |
138 | * This REALLY needs to be fixed, at the very least it needs | |
1cc06455 KB |
139 | * to be rethought when the buffer cache goes away. When it's |
140 | * fixed, change lfs_bmaparray and lfs_getlbns to take an ip, | |
141 | * not a vp. | |
fce00cda | 142 | */ |
d5075120 | 143 | if (bp) |
7188ac27 | 144 | brelse(bp); |
175a033b | 145 | bp = getblk(vp, metalbn, fs->lfs_bsize); |
d5075120 | 146 | if (bp->b_flags & (B_DONE | B_DELWRI)) { |
175a033b | 147 | trace(TR_BREADHIT, pack(vp, size), metalbn); |
d5075120 | 148 | } else { |
175a033b | 149 | trace(TR_BREADMISS, pack(vp, size), metalbn); |
fce00cda | 150 | bp->b_blkno = daddr; |
175a033b | 151 | bp->b_flags |= B_READ; |
d5075120 | 152 | bp->b_dev = devvp->v_rdev; |
275ca4f0 | 153 | (devvp->v_op->vop_strategy)(bp); |
d5075120 KB |
154 | curproc->p_stats->p_ru.ru_inblock++; /* XXX */ |
155 | if (error = biowait(bp)) { | |
156 | brelse(bp); | |
157 | return (error); | |
158 | } | |
7188ac27 | 159 | } |
cb92c035 | 160 | daddr = bp->b_un.b_daddr[xap->in_off]; |
7188ac27 | 161 | } |
d5075120 KB |
162 | if (bp) |
163 | brelse(bp); | |
164 | ||
cb92c035 | 165 | *bnp = daddr == 0 ? UNASSIGNED : daddr; |
7188ac27 | 166 | return (0); |
52212483 | 167 | } |
1cc06455 KB |
168 | |
169 | /* | |
170 | * Create an array of logical block number/offset pairs which represent the | |
171 | * path of indirect blocks required to access a data block. The first "pair" | |
172 | * contains the logical block number of the appropriate single, double or | |
173 | * triple indirect block and the offset into the inode indirect block array. | |
174 | * Note, the logical block number of the inode single/double/triple indirect | |
175 | * block appears twice in the array, once with the offset into the i_ib and | |
176 | * once with the offset into the page itself. | |
177 | */ | |
178 | int | |
179 | lfs_getlbns(vp, bn, ap, nump) | |
180 | struct vnode *vp; | |
181 | register daddr_t bn; | |
182 | INDIR *ap; | |
183 | int *nump; | |
184 | { | |
185 | struct lfs *fs; | |
186 | long metalbn, realbn; | |
187 | int j, off, sh; | |
188 | ||
189 | #ifdef VERBOSE | |
190 | printf("lfs_getlbns: bn %d, inode %d\n", bn, VTOI(vp)->i_number); | |
191 | #endif | |
192 | *nump = 0; | |
193 | realbn = bn; | |
194 | if ((long)bn < 0) | |
195 | bn = -(long)bn; | |
196 | ||
197 | /* The first NDADDR blocks are direct blocks. */ | |
198 | if (bn < NDADDR) | |
cb92c035 | 199 | return (0); |
1cc06455 KB |
200 | |
201 | /* | |
202 | * Determine the number of levels of indirection. After this loop | |
203 | * is done, sh indicates the number of data blocks possible at the | |
204 | * given level of indirection, and NIADDR - j is the number of levels | |
205 | * of indirection needed to locate the requested block. | |
206 | */ | |
207 | bn -= NDADDR; | |
208 | fs = VTOI(vp)->i_lfs; | |
209 | sh = 1; | |
210 | for (j = NIADDR; j > 0; j--) { | |
211 | sh *= NINDIR(fs); | |
212 | if (bn < sh) | |
213 | break; | |
214 | bn -= sh; | |
215 | } | |
216 | if (j == 0) | |
217 | return (EFBIG); | |
218 | ||
219 | /* Calculate the address of the first meta-block. */ | |
220 | if (realbn >= 0) | |
221 | metalbn = -(realbn - bn + NIADDR - j); | |
222 | else | |
223 | metalbn = -(-realbn - bn + NIADDR - j); | |
224 | ||
225 | /* | |
226 | * At each iteration, off is the offset into the bap array which is | |
227 | * an array of disk addresses at the current level of indirection. | |
228 | * The logical block number and the offset in that block are stored | |
229 | * into the argument array. | |
230 | */ | |
231 | ++*nump; | |
232 | ap->in_lbn = metalbn; | |
233 | ap->in_off = off = NIADDR - j; | |
234 | ap++; | |
235 | for (; j <= NIADDR; j++) { | |
236 | /* If searching for a meta-data block, quit when found. */ | |
237 | if (metalbn == realbn) | |
238 | break; | |
239 | ||
240 | sh /= NINDIR(fs); | |
241 | off = (bn / sh) % NINDIR(fs); | |
242 | ||
243 | ++*nump; | |
244 | ap->in_lbn = metalbn; | |
245 | ap->in_off = off; | |
246 | ++ap; | |
247 | ||
248 | metalbn -= -1 + off * sh; | |
249 | } | |
250 | return (0); | |
251 | } | |
ce90ef66 KB |
252 | |
253 | int | |
254 | lfs_balloc(vp, iosize, lbn, bpp) | |
255 | struct vnode *vp; | |
256 | u_long iosize; | |
257 | daddr_t lbn; | |
258 | struct buf **bpp; | |
259 | { | |
9342689a | 260 | USES_VOP_BMAP; |
ce90ef66 KB |
261 | struct buf *bp; |
262 | struct inode *ip; | |
263 | struct lfs *fs; | |
264 | daddr_t daddr; | |
265 | int error, newblock; | |
266 | ||
267 | ip = VTOI(vp); | |
268 | fs = ip->i_lfs; | |
269 | ||
270 | /* | |
271 | * Three cases: it's a block beyond the end of file, it's a block in | |
272 | * the file that may or may not have been assigned a disk address or | |
273 | * we're writing an entire block. Note, if the daddr is unassigned, | |
274 | * the block might still have existed in the cache. If it did, make | |
275 | * sure we don't count it as a new block or zero out its contents. | |
276 | */ | |
277 | newblock = ip->i_size <= lbn << fs->lfs_bshift; | |
9342689a | 278 | if (!newblock && (error = VOP_BMAP(vp, lbn, NULL, &daddr))) |
cb92c035 | 279 | return (error); |
ce90ef66 | 280 | |
843a1a76 | 281 | if (newblock || daddr == UNASSIGNED || iosize == fs->lfs_bsize) { |
ce90ef66 KB |
282 | *bpp = bp = getblk(vp, lbn, fs->lfs_bsize); |
283 | if (newblock || | |
843a1a76 | 284 | daddr == UNASSIGNED && !(bp->b_flags & B_CACHE)) { |
ce90ef66 KB |
285 | ++ip->i_blocks; |
286 | if (iosize != fs->lfs_bsize) | |
287 | clrbuf(bp); | |
288 | } | |
cb92c035 | 289 | return (0); |
ce90ef66 | 290 | } |
cb92c035 | 291 | return (bread(vp, lbn, fs->lfs_bsize, NOCRED, bpp)); |
ce90ef66 KB |
292 | |
293 | } |