Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
7188ac27 KM |
2 | * Copyright (c) 1982, 1986, 1989 Regents of the University of California. |
3 | * All rights reserved. | |
da7c5cc6 | 4 | * |
b702c21d | 5 | * %sccs.include.redist.c% |
7188ac27 | 6 | * |
a3257f3c | 7 | * @(#)lfs_balloc.c 7.13 (Berkeley) %G% |
da7c5cc6 | 8 | */ |
52212483 | 9 | |
94368568 JB |
10 | #include "param.h" |
11 | #include "systm.h" | |
94368568 JB |
12 | #include "buf.h" |
13 | #include "proc.h" | |
7188ac27 KM |
14 | #include "file.h" |
15 | #include "vnode.h" | |
c6f5111d MK |
16 | |
17 | #include "quota.h" | |
18 | #include "inode.h" | |
19 | #include "fs.h" | |
52212483 BJ |
20 | |
21 | /* | |
a3257f3c KM |
22 | * Bmap converts a the logical block number of a file |
23 | * to its physical block number on the disk. The conversion | |
24 | * is done by using the logical block number to index into | |
25 | * the array of block pointers described by the dinode. | |
52212483 | 26 | */ |
9b392e39 | 27 | bmap(ip, bn, bnp) |
52212483 | 28 | register struct inode *ip; |
7188ac27 KM |
29 | register daddr_t bn; |
30 | daddr_t *bnp; | |
52212483 | 31 | { |
7188ac27 KM |
32 | register struct fs *fs; |
33 | register daddr_t nb; | |
34 | struct buf *bp; | |
35 | daddr_t *bap; | |
36 | int i, j, sh; | |
37 | int error; | |
38 | ||
39 | if (bn < 0) | |
40 | return (EFBIG); | |
41 | fs = ip->i_fs; | |
42 | ||
43 | /* | |
44 | * The first NDADDR blocks are direct blocks | |
45 | */ | |
46 | if (bn < NDADDR) { | |
47 | nb = ip->i_db[bn]; | |
48 | if (nb == 0) { | |
49 | *bnp = (daddr_t)-1; | |
50 | return (0); | |
51 | } | |
7188ac27 KM |
52 | *bnp = fsbtodb(fs, nb); |
53 | return (0); | |
54 | } | |
7188ac27 | 55 | /* |
9b392e39 | 56 | * Determine the number of levels of indirection. |
7188ac27 KM |
57 | */ |
58 | sh = 1; | |
59 | bn -= NDADDR; | |
60 | for (j = NIADDR; j > 0; j--) { | |
61 | sh *= NINDIR(fs); | |
62 | if (bn < sh) | |
63 | break; | |
64 | bn -= sh; | |
65 | } | |
66 | if (j == 0) | |
67 | return (EFBIG); | |
7188ac27 | 68 | /* |
9b392e39 | 69 | * Fetch through the indirect blocks. |
7188ac27 KM |
70 | */ |
71 | nb = ip->i_ib[NIADDR - j]; | |
72 | if (nb == 0) { | |
73 | *bnp = (daddr_t)-1; | |
74 | return (0); | |
52212483 | 75 | } |
7188ac27 KM |
76 | for (; j <= NIADDR; j++) { |
77 | if (error = bread(ip->i_devvp, fsbtodb(fs, nb), | |
a937f856 | 78 | (int)fs->fs_bsize, NOCRED, &bp)) { |
7188ac27 KM |
79 | brelse(bp); |
80 | return (error); | |
81 | } | |
82 | bap = bp->b_un.b_daddr; | |
83 | sh /= NINDIR(fs); | |
84 | i = (bn / sh) % NINDIR(fs); | |
85 | nb = bap[i]; | |
86 | if (nb == 0) { | |
87 | *bnp = (daddr_t)-1; | |
88 | brelse(bp); | |
89 | return (0); | |
90 | } | |
9b392e39 | 91 | brelse(bp); |
7188ac27 KM |
92 | } |
93 | *bnp = fsbtodb(fs, nb); | |
7188ac27 KM |
94 | return (0); |
95 | } | |
96 | ||
97 | /* | |
98 | * Balloc defines the structure of file system storage | |
9b392e39 KM |
99 | * by allocating the physical blocks on a device given |
100 | * the inode and the logical block number in a file. | |
7188ac27 | 101 | */ |
9b392e39 | 102 | balloc(ip, bn, size, bpp, flags) |
7188ac27 KM |
103 | register struct inode *ip; |
104 | register daddr_t bn; | |
105 | int size; | |
9b392e39 | 106 | struct buf **bpp; |
7188ac27 KM |
107 | int flags; |
108 | { | |
109 | register struct fs *fs; | |
110 | register daddr_t nb; | |
111 | struct buf *bp, *nbp; | |
9b392e39 | 112 | struct vnode *vp = ITOV(ip); |
7188ac27 | 113 | int osize, nsize, i, j, sh, error; |
9b392e39 | 114 | daddr_t newb, lbn, *bap, pref, blkpref(); |
7188ac27 | 115 | |
9b392e39 | 116 | *bpp = (struct buf *)0; |
7188ac27 KM |
117 | if (bn < 0) |
118 | return (EFBIG); | |
52212483 | 119 | fs = ip->i_fs; |
52212483 BJ |
120 | |
121 | /* | |
122 | * If the next write will extend the file into a new block, | |
123 | * and the file is currently composed of a fragment | |
124 | * this fragment has to be extended to be a full block. | |
125 | */ | |
126 | nb = lblkno(fs, ip->i_size); | |
7188ac27 | 127 | if (nb < NDADDR && nb < bn) { |
52212483 BJ |
128 | osize = blksize(fs, ip, nb); |
129 | if (osize < fs->fs_bsize && osize > 0) { | |
9b392e39 | 130 | error = realloccg(ip, nb, |
4f083fd7 | 131 | blkpref(ip, nb, (int)nb, &ip->i_db[0]), |
7188ac27 | 132 | osize, (int)fs->fs_bsize, &bp); |
9b392e39 | 133 | if (error) |
7188ac27 | 134 | return (error); |
52212483 | 135 | ip->i_size = (nb + 1) * fs->fs_bsize; |
8986c97c | 136 | vnode_pager_setsize(ITOV(ip), (u_long)ip->i_size); |
52212483 BJ |
137 | ip->i_db[nb] = dbtofsb(fs, bp->b_blkno); |
138 | ip->i_flag |= IUPD|ICHG; | |
9b392e39 KM |
139 | if (flags & B_SYNC) |
140 | bwrite(bp); | |
141 | else | |
142 | bawrite(bp); | |
52212483 BJ |
143 | } |
144 | } | |
145 | /* | |
146 | * The first NDADDR blocks are direct blocks | |
147 | */ | |
148 | if (bn < NDADDR) { | |
a6e7e3c6 | 149 | nb = ip->i_db[bn]; |
9b392e39 KM |
150 | if (nb != 0 && ip->i_size >= (bn + 1) * fs->fs_bsize) { |
151 | error = bread(vp, bn, fs->fs_bsize, NOCRED, &bp); | |
7188ac27 | 152 | if (error) { |
9b392e39 | 153 | brelse(bp); |
7188ac27 | 154 | return (error); |
52212483 | 155 | } |
9b392e39 KM |
156 | *bpp = bp; |
157 | return (0); | |
158 | } | |
159 | if (nb != 0) { | |
160 | /* | |
161 | * Consider need to reallocate a fragment. | |
162 | */ | |
163 | osize = fragroundup(fs, blkoff(fs, ip->i_size)); | |
164 | nsize = fragroundup(fs, size); | |
165 | if (nsize <= osize) { | |
166 | error = bread(vp, bn, osize, NOCRED, &bp); | |
167 | if (error) { | |
168 | brelse(bp); | |
169 | return (error); | |
170 | } | |
171 | } else { | |
172 | error = realloccg(ip, bn, | |
173 | blkpref(ip, bn, (int)bn, &ip->i_db[0]), | |
174 | osize, nsize, &bp); | |
175 | if (error) | |
176 | return (error); | |
177 | } | |
178 | } else { | |
179 | if (ip->i_size < (bn + 1) * fs->fs_bsize) | |
180 | nsize = fragroundup(fs, size); | |
52212483 | 181 | else |
9b392e39 KM |
182 | nsize = fs->fs_bsize; |
183 | error = alloc(ip, bn, | |
184 | blkpref(ip, bn, (int)bn, &ip->i_db[0]), | |
185 | nsize, &newb); | |
186 | if (error) | |
187 | return (error); | |
188 | bp = getblk(vp, bn, nsize); | |
189 | bp->b_blkno = fsbtodb(fs, newb); | |
190 | if (flags & B_CLRBUF) | |
191 | clrbuf(bp); | |
52212483 | 192 | } |
9b392e39 KM |
193 | ip->i_db[bn] = dbtofsb(fs, bp->b_blkno); |
194 | ip->i_flag |= IUPD|ICHG; | |
195 | *bpp = bp; | |
7188ac27 | 196 | return (0); |
52212483 | 197 | } |
52212483 | 198 | /* |
9b392e39 | 199 | * Determine the number of levels of indirection. |
52212483 | 200 | */ |
a6e7e3c6 | 201 | pref = 0; |
52212483 | 202 | sh = 1; |
a6e7e3c6 | 203 | lbn = bn; |
52212483 | 204 | bn -= NDADDR; |
7188ac27 | 205 | for (j = NIADDR; j > 0; j--) { |
52212483 BJ |
206 | sh *= NINDIR(fs); |
207 | if (bn < sh) | |
208 | break; | |
209 | bn -= sh; | |
210 | } | |
7188ac27 KM |
211 | if (j == 0) |
212 | return (EFBIG); | |
52212483 | 213 | /* |
9b392e39 | 214 | * Fetch the first indirect block allocating if necessary. |
52212483 BJ |
215 | */ |
216 | nb = ip->i_ib[NIADDR - j]; | |
217 | if (nb == 0) { | |
4f083fd7 | 218 | pref = blkpref(ip, lbn, 0, (daddr_t *)0); |
9b392e39 | 219 | if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) |
7188ac27 | 220 | return (error); |
9b392e39 KM |
221 | nb = newb; |
222 | bp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize); | |
223 | clrbuf(bp); | |
52212483 BJ |
224 | /* |
225 | * Write synchronously so that indirect blocks | |
226 | * never point at garbage. | |
227 | */ | |
9b392e39 KM |
228 | if (error = bwrite(bp)) { |
229 | blkfree(ip, nb, fs->fs_bsize); | |
230 | return (error); | |
231 | } | |
52212483 BJ |
232 | ip->i_ib[NIADDR - j] = nb; |
233 | ip->i_flag |= IUPD|ICHG; | |
234 | } | |
52212483 | 235 | /* |
9b392e39 | 236 | * Fetch through the indirect blocks, allocating as necessary. |
52212483 | 237 | */ |
9b392e39 KM |
238 | for (; ; j++) { |
239 | error = bread(ip->i_devvp, fsbtodb(fs, nb), | |
240 | (int)fs->fs_bsize, NOCRED, &bp); | |
241 | if (error) { | |
52212483 | 242 | brelse(bp); |
7188ac27 | 243 | return (error); |
52212483 BJ |
244 | } |
245 | bap = bp->b_un.b_daddr; | |
246 | sh /= NINDIR(fs); | |
247 | i = (bn / sh) % NINDIR(fs); | |
248 | nb = bap[i]; | |
9b392e39 KM |
249 | if (j == NIADDR) |
250 | break; | |
251 | if (nb != 0) { | |
252 | brelse(bp); | |
253 | continue; | |
254 | } | |
255 | if (pref == 0) | |
256 | pref = blkpref(ip, lbn, 0, (daddr_t *)0); | |
257 | if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) { | |
258 | brelse(bp); | |
259 | return (error); | |
260 | } | |
261 | nb = newb; | |
262 | nbp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize); | |
263 | clrbuf(nbp); | |
9b392e39 KM |
264 | /* |
265 | * Write synchronously so that indirect blocks | |
266 | * never point at garbage. | |
267 | */ | |
268 | if (error = bwrite(nbp)) { | |
269 | blkfree(ip, nb, fs->fs_bsize); | |
270 | brelse(bp); | |
271 | return (error); | |
272 | } | |
273 | bap[i] = nb; | |
3cf3d516 KM |
274 | /* |
275 | * If required, write synchronously, otherwise use | |
276 | * delayed write. If this is the first instance of | |
277 | * the delayed write, reassociate the buffer with the | |
278 | * file so it will be written if the file is sync'ed. | |
279 | */ | |
280 | if (flags & B_SYNC) { | |
9b392e39 | 281 | bwrite(bp); |
3cf3d516 | 282 | } else if (bp->b_flags & B_DELWRI) { |
52212483 | 283 | bdwrite(bp); |
3cf3d516 KM |
284 | } else { |
285 | bdwrite(bp); | |
286 | reassignbuf(bp, vp); | |
287 | } | |
9b392e39 KM |
288 | } |
289 | /* | |
290 | * Get the data block, allocating if necessary. | |
291 | */ | |
292 | if (nb == 0) { | |
293 | pref = blkpref(ip, lbn, i, &bap[0]); | |
294 | if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) { | |
52212483 | 295 | brelse(bp); |
9b392e39 KM |
296 | return (error); |
297 | } | |
298 | nb = newb; | |
299 | nbp = getblk(vp, lbn, fs->fs_bsize); | |
300 | nbp->b_blkno = fsbtodb(fs, nb); | |
301 | if (flags & B_CLRBUF) | |
302 | clrbuf(nbp); | |
303 | bap[i] = nb; | |
3cf3d516 KM |
304 | /* |
305 | * If required, write synchronously, otherwise use | |
306 | * delayed write. If this is the first instance of | |
307 | * the delayed write, reassociate the buffer with the | |
308 | * file so it will be written if the file is sync'ed. | |
309 | */ | |
310 | if (flags & B_SYNC) { | |
9b392e39 | 311 | bwrite(bp); |
3cf3d516 | 312 | } else if (bp->b_flags & B_DELWRI) { |
9b392e39 | 313 | bdwrite(bp); |
3cf3d516 KM |
314 | } else { |
315 | bdwrite(bp); | |
316 | reassignbuf(bp, vp); | |
317 | } | |
9b392e39 KM |
318 | *bpp = nbp; |
319 | return (0); | |
52212483 | 320 | } |
9b392e39 | 321 | brelse(bp); |
0b4c7ad8 | 322 | if (flags & B_CLRBUF) { |
9b392e39 KM |
323 | error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp); |
324 | if (error) { | |
325 | brelse(nbp); | |
326 | return (error); | |
327 | } | |
0b4c7ad8 KM |
328 | } else { |
329 | nbp = getblk(vp, lbn, fs->fs_bsize); | |
330 | nbp->b_blkno = fsbtodb(fs, nb); | |
9b392e39 KM |
331 | } |
332 | *bpp = nbp; | |
7188ac27 | 333 | return (0); |
52212483 | 334 | } |