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 | * |
8cfb9f42 | 7 | * @(#)lfs_balloc.c 7.29 (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 | { |
8cfb9f42 | 85 | USES_VOP_STRATEGY; |
8ad16d99 | 86 | register struct inode *ip; |
7188ac27 | 87 | struct buf *bp; |
1cc06455 | 88 | struct lfs *fs; |
fce00cda | 89 | struct vnode *devvp; |
1cc06455 KB |
90 | INDIR a[NIADDR], *xap; |
91 | daddr_t *bap, daddr; | |
92 | long metalbn; | |
93 | int error, num, off; | |
7188ac27 | 94 | |
d5075120 | 95 | |
1cc06455 | 96 | ip = VTOI(vp); |
fce00cda | 97 | #ifdef VERBOSE |
1cc06455 KB |
98 | printf("lfs_bmap: block number %d, inode %d\n", bn, ip->i_number); |
99 | #endif | |
100 | #ifdef DIAGNOSTIC | |
101 | if (ap != NULL && nump == NULL || ap == NULL && nump != NULL) | |
102 | panic("lfs_bmaparray: invalid arguments"); | |
fce00cda | 103 | #endif |
175a033b | 104 | |
1cc06455 KB |
105 | xap = ap == NULL ? a : ap; |
106 | if (error = lfs_getlbns(vp, bn, xap, nump)) | |
107 | return (error); | |
f6437c6d | 108 | |
1cc06455 | 109 | num = *nump; |
cb92c035 | 110 | |
1cc06455 KB |
111 | if (num == 0) { |
112 | *bnp = ip->i_db[bn]; | |
113 | if (*bnp == 0) | |
114 | *bnp = UNASSIGNED; | |
115 | return (0); | |
7188ac27 | 116 | } |
d5075120 | 117 | |
cb92c035 KB |
118 | |
119 | /* Get disk address out of indirect block array */ | |
120 | daddr = ip->i_ib[xap->in_off]; | |
121 | ||
1cc06455 | 122 | /* Fetch through the indirect blocks. */ |
cb92c035 | 123 | fs = ip->i_lfs; |
d5075120 | 124 | devvp = VFSTOUFS(vp->v_mount)->um_devvp; |
175a033b | 125 | |
cb92c035 KB |
126 | for (bp = NULL, ++xap; daddr && --num; ++xap) { |
127 | /* If looking for a meta-block, break out when we find it. */ | |
128 | metalbn = xap->in_lbn; | |
1cc06455 | 129 | if (metalbn == bn) |
175a033b KB |
130 | break; |
131 | ||
fce00cda KB |
132 | /* |
133 | * Read in the appropriate indirect block. LFS can't do a | |
134 | * bread because bread knows that FFS will hand it the device | |
135 | * vnode, not the file vnode, so the b_dev and b_blkno would | |
136 | * be wrong. | |
137 | * | |
138 | * XXX | |
139 | * This REALLY needs to be fixed, at the very least it needs | |
1cc06455 KB |
140 | * to be rethought when the buffer cache goes away. When it's |
141 | * fixed, change lfs_bmaparray and lfs_getlbns to take an ip, | |
142 | * not a vp. | |
fce00cda | 143 | */ |
d5075120 | 144 | if (bp) |
7188ac27 | 145 | brelse(bp); |
175a033b | 146 | bp = getblk(vp, metalbn, fs->lfs_bsize); |
d5075120 | 147 | if (bp->b_flags & (B_DONE | B_DELWRI)) { |
175a033b | 148 | trace(TR_BREADHIT, pack(vp, size), metalbn); |
d5075120 | 149 | } else { |
175a033b | 150 | trace(TR_BREADMISS, pack(vp, size), metalbn); |
fce00cda | 151 | bp->b_blkno = daddr; |
175a033b | 152 | bp->b_flags |= B_READ; |
d5075120 | 153 | bp->b_dev = devvp->v_rdev; |
8cfb9f42 JH |
154 | /* |
155 | * Call a strategy VOP by hand. | |
156 | */ | |
157 | vop_strategy_a.a_desc = VDESC(vop_strategy); | |
158 | vop_strategy_a.a_bp=bp; | |
159 | VOCALL(devvp->v_op, VOFFSET(vop_strategy), \ | |
160 | &vop_strategy_a); | |
d5075120 KB |
161 | curproc->p_stats->p_ru.ru_inblock++; /* XXX */ |
162 | if (error = biowait(bp)) { | |
163 | brelse(bp); | |
164 | return (error); | |
165 | } | |
7188ac27 | 166 | } |
cb92c035 | 167 | daddr = bp->b_un.b_daddr[xap->in_off]; |
7188ac27 | 168 | } |
d5075120 KB |
169 | if (bp) |
170 | brelse(bp); | |
171 | ||
cb92c035 | 172 | *bnp = daddr == 0 ? UNASSIGNED : daddr; |
7188ac27 | 173 | return (0); |
52212483 | 174 | } |
1cc06455 KB |
175 | |
176 | /* | |
177 | * Create an array of logical block number/offset pairs which represent the | |
178 | * path of indirect blocks required to access a data block. The first "pair" | |
179 | * contains the logical block number of the appropriate single, double or | |
180 | * triple indirect block and the offset into the inode indirect block array. | |
181 | * Note, the logical block number of the inode single/double/triple indirect | |
182 | * block appears twice in the array, once with the offset into the i_ib and | |
183 | * once with the offset into the page itself. | |
184 | */ | |
185 | int | |
186 | lfs_getlbns(vp, bn, ap, nump) | |
187 | struct vnode *vp; | |
188 | register daddr_t bn; | |
189 | INDIR *ap; | |
190 | int *nump; | |
191 | { | |
192 | struct lfs *fs; | |
193 | long metalbn, realbn; | |
194 | int j, off, sh; | |
195 | ||
196 | #ifdef VERBOSE | |
197 | printf("lfs_getlbns: bn %d, inode %d\n", bn, VTOI(vp)->i_number); | |
198 | #endif | |
199 | *nump = 0; | |
200 | realbn = bn; | |
201 | if ((long)bn < 0) | |
202 | bn = -(long)bn; | |
203 | ||
204 | /* The first NDADDR blocks are direct blocks. */ | |
205 | if (bn < NDADDR) | |
cb92c035 | 206 | return (0); |
1cc06455 KB |
207 | |
208 | /* | |
209 | * Determine the number of levels of indirection. After this loop | |
210 | * is done, sh indicates the number of data blocks possible at the | |
211 | * given level of indirection, and NIADDR - j is the number of levels | |
212 | * of indirection needed to locate the requested block. | |
213 | */ | |
214 | bn -= NDADDR; | |
215 | fs = VTOI(vp)->i_lfs; | |
216 | sh = 1; | |
217 | for (j = NIADDR; j > 0; j--) { | |
218 | sh *= NINDIR(fs); | |
219 | if (bn < sh) | |
220 | break; | |
221 | bn -= sh; | |
222 | } | |
223 | if (j == 0) | |
224 | return (EFBIG); | |
225 | ||
226 | /* Calculate the address of the first meta-block. */ | |
227 | if (realbn >= 0) | |
228 | metalbn = -(realbn - bn + NIADDR - j); | |
229 | else | |
230 | metalbn = -(-realbn - bn + NIADDR - j); | |
231 | ||
232 | /* | |
233 | * At each iteration, off is the offset into the bap array which is | |
234 | * an array of disk addresses at the current level of indirection. | |
235 | * The logical block number and the offset in that block are stored | |
236 | * into the argument array. | |
237 | */ | |
238 | ++*nump; | |
239 | ap->in_lbn = metalbn; | |
240 | ap->in_off = off = NIADDR - j; | |
241 | ap++; | |
242 | for (; j <= NIADDR; j++) { | |
243 | /* If searching for a meta-data block, quit when found. */ | |
244 | if (metalbn == realbn) | |
245 | break; | |
246 | ||
247 | sh /= NINDIR(fs); | |
248 | off = (bn / sh) % NINDIR(fs); | |
249 | ||
250 | ++*nump; | |
251 | ap->in_lbn = metalbn; | |
252 | ap->in_off = off; | |
253 | ++ap; | |
254 | ||
255 | metalbn -= -1 + off * sh; | |
256 | } | |
257 | return (0); | |
258 | } | |
ce90ef66 KB |
259 | |
260 | int | |
261 | lfs_balloc(vp, iosize, lbn, bpp) | |
262 | struct vnode *vp; | |
263 | u_long iosize; | |
264 | daddr_t lbn; | |
265 | struct buf **bpp; | |
266 | { | |
9342689a | 267 | USES_VOP_BMAP; |
ce90ef66 KB |
268 | struct buf *bp; |
269 | struct inode *ip; | |
270 | struct lfs *fs; | |
271 | daddr_t daddr; | |
272 | int error, newblock; | |
273 | ||
274 | ip = VTOI(vp); | |
275 | fs = ip->i_lfs; | |
276 | ||
277 | /* | |
278 | * Three cases: it's a block beyond the end of file, it's a block in | |
279 | * the file that may or may not have been assigned a disk address or | |
280 | * we're writing an entire block. Note, if the daddr is unassigned, | |
281 | * the block might still have existed in the cache. If it did, make | |
282 | * sure we don't count it as a new block or zero out its contents. | |
283 | */ | |
284 | newblock = ip->i_size <= lbn << fs->lfs_bshift; | |
9342689a | 285 | if (!newblock && (error = VOP_BMAP(vp, lbn, NULL, &daddr))) |
cb92c035 | 286 | return (error); |
ce90ef66 | 287 | |
843a1a76 | 288 | if (newblock || daddr == UNASSIGNED || iosize == fs->lfs_bsize) { |
ce90ef66 KB |
289 | *bpp = bp = getblk(vp, lbn, fs->lfs_bsize); |
290 | if (newblock || | |
843a1a76 | 291 | daddr == UNASSIGNED && !(bp->b_flags & B_CACHE)) { |
ce90ef66 KB |
292 | ++ip->i_blocks; |
293 | if (iosize != fs->lfs_bsize) | |
294 | clrbuf(bp); | |
295 | } | |
cb92c035 | 296 | return (0); |
ce90ef66 | 297 | } |
cb92c035 | 298 | return (bread(vp, lbn, fs->lfs_bsize, NOCRED, bpp)); |
ce90ef66 KB |
299 | |
300 | } |