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