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 | * |
8986c97c | 7 | * @(#)ffs_balloc.c 7.11 (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 | 134 | ip->i_size = (nb + 1) * fs->fs_bsize; |
8986c97c | 135 | vnode_pager_setsize(ITOV(ip), (u_long)ip->i_size); |
52212483 BJ |
136 | ip->i_db[nb] = dbtofsb(fs, bp->b_blkno); |
137 | ip->i_flag |= IUPD|ICHG; | |
9b392e39 KM |
138 | if (flags & B_SYNC) |
139 | bwrite(bp); | |
140 | else | |
141 | bawrite(bp); | |
52212483 BJ |
142 | } |
143 | } | |
144 | /* | |
145 | * The first NDADDR blocks are direct blocks | |
146 | */ | |
147 | if (bn < NDADDR) { | |
a6e7e3c6 | 148 | nb = ip->i_db[bn]; |
9b392e39 KM |
149 | if (nb != 0 && ip->i_size >= (bn + 1) * fs->fs_bsize) { |
150 | error = bread(vp, bn, fs->fs_bsize, NOCRED, &bp); | |
7188ac27 | 151 | if (error) { |
9b392e39 | 152 | brelse(bp); |
7188ac27 | 153 | return (error); |
52212483 | 154 | } |
9b392e39 KM |
155 | *bpp = bp; |
156 | return (0); | |
157 | } | |
158 | if (nb != 0) { | |
159 | /* | |
160 | * Consider need to reallocate a fragment. | |
161 | */ | |
162 | osize = fragroundup(fs, blkoff(fs, ip->i_size)); | |
163 | nsize = fragroundup(fs, size); | |
164 | if (nsize <= osize) { | |
165 | error = bread(vp, bn, osize, NOCRED, &bp); | |
166 | if (error) { | |
167 | brelse(bp); | |
168 | return (error); | |
169 | } | |
170 | } else { | |
171 | error = realloccg(ip, bn, | |
172 | blkpref(ip, bn, (int)bn, &ip->i_db[0]), | |
173 | osize, nsize, &bp); | |
174 | if (error) | |
175 | return (error); | |
176 | } | |
177 | } else { | |
178 | if (ip->i_size < (bn + 1) * fs->fs_bsize) | |
179 | nsize = fragroundup(fs, size); | |
52212483 | 180 | else |
9b392e39 KM |
181 | nsize = fs->fs_bsize; |
182 | error = alloc(ip, bn, | |
183 | blkpref(ip, bn, (int)bn, &ip->i_db[0]), | |
184 | nsize, &newb); | |
185 | if (error) | |
186 | return (error); | |
187 | bp = getblk(vp, bn, nsize); | |
188 | bp->b_blkno = fsbtodb(fs, newb); | |
189 | if (flags & B_CLRBUF) | |
190 | clrbuf(bp); | |
52212483 | 191 | } |
9b392e39 KM |
192 | ip->i_db[bn] = dbtofsb(fs, bp->b_blkno); |
193 | ip->i_flag |= IUPD|ICHG; | |
194 | *bpp = bp; | |
7188ac27 | 195 | return (0); |
52212483 | 196 | } |
52212483 | 197 | /* |
9b392e39 | 198 | * Determine the number of levels of indirection. |
52212483 | 199 | */ |
a6e7e3c6 | 200 | pref = 0; |
52212483 | 201 | sh = 1; |
a6e7e3c6 | 202 | lbn = bn; |
52212483 | 203 | bn -= NDADDR; |
7188ac27 | 204 | for (j = NIADDR; j > 0; j--) { |
52212483 BJ |
205 | sh *= NINDIR(fs); |
206 | if (bn < sh) | |
207 | break; | |
208 | bn -= sh; | |
209 | } | |
7188ac27 KM |
210 | if (j == 0) |
211 | return (EFBIG); | |
52212483 | 212 | /* |
9b392e39 | 213 | * Fetch the first indirect block allocating if necessary. |
52212483 BJ |
214 | */ |
215 | nb = ip->i_ib[NIADDR - j]; | |
216 | if (nb == 0) { | |
4f083fd7 | 217 | pref = blkpref(ip, lbn, 0, (daddr_t *)0); |
9b392e39 | 218 | if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) |
7188ac27 | 219 | return (error); |
9b392e39 KM |
220 | nb = newb; |
221 | bp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize); | |
222 | clrbuf(bp); | |
52212483 BJ |
223 | /* |
224 | * Write synchronously so that indirect blocks | |
225 | * never point at garbage. | |
226 | */ | |
9b392e39 KM |
227 | if (error = bwrite(bp)) { |
228 | blkfree(ip, nb, fs->fs_bsize); | |
229 | return (error); | |
230 | } | |
52212483 BJ |
231 | ip->i_ib[NIADDR - j] = nb; |
232 | ip->i_flag |= IUPD|ICHG; | |
233 | } | |
52212483 | 234 | /* |
9b392e39 | 235 | * Fetch through the indirect blocks, allocating as necessary. |
52212483 | 236 | */ |
9b392e39 KM |
237 | for (; ; j++) { |
238 | error = bread(ip->i_devvp, fsbtodb(fs, nb), | |
239 | (int)fs->fs_bsize, NOCRED, &bp); | |
240 | if (error) { | |
52212483 | 241 | brelse(bp); |
7188ac27 | 242 | return (error); |
52212483 BJ |
243 | } |
244 | bap = bp->b_un.b_daddr; | |
245 | sh /= NINDIR(fs); | |
246 | i = (bn / sh) % NINDIR(fs); | |
247 | nb = bap[i]; | |
9b392e39 KM |
248 | if (j == NIADDR) |
249 | break; | |
250 | if (nb != 0) { | |
251 | brelse(bp); | |
252 | continue; | |
253 | } | |
254 | if (pref == 0) | |
255 | pref = blkpref(ip, lbn, 0, (daddr_t *)0); | |
256 | if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) { | |
257 | brelse(bp); | |
258 | return (error); | |
259 | } | |
260 | nb = newb; | |
261 | nbp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize); | |
262 | clrbuf(nbp); | |
9b392e39 KM |
263 | /* |
264 | * Write synchronously so that indirect blocks | |
265 | * never point at garbage. | |
266 | */ | |
267 | if (error = bwrite(nbp)) { | |
268 | blkfree(ip, nb, fs->fs_bsize); | |
269 | brelse(bp); | |
270 | return (error); | |
271 | } | |
272 | bap[i] = nb; | |
3cf3d516 KM |
273 | /* |
274 | * If required, write synchronously, otherwise use | |
275 | * delayed write. If this is the first instance of | |
276 | * the delayed write, reassociate the buffer with the | |
277 | * file so it will be written if the file is sync'ed. | |
278 | */ | |
279 | if (flags & B_SYNC) { | |
9b392e39 | 280 | bwrite(bp); |
3cf3d516 | 281 | } else if (bp->b_flags & B_DELWRI) { |
52212483 | 282 | bdwrite(bp); |
3cf3d516 KM |
283 | } else { |
284 | bdwrite(bp); | |
285 | reassignbuf(bp, vp); | |
286 | } | |
9b392e39 KM |
287 | } |
288 | /* | |
289 | * Get the data block, allocating if necessary. | |
290 | */ | |
291 | if (nb == 0) { | |
292 | pref = blkpref(ip, lbn, i, &bap[0]); | |
293 | if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) { | |
52212483 | 294 | brelse(bp); |
9b392e39 KM |
295 | return (error); |
296 | } | |
297 | nb = newb; | |
298 | nbp = getblk(vp, lbn, fs->fs_bsize); | |
299 | nbp->b_blkno = fsbtodb(fs, nb); | |
300 | if (flags & B_CLRBUF) | |
301 | clrbuf(nbp); | |
302 | bap[i] = nb; | |
3cf3d516 KM |
303 | /* |
304 | * If required, write synchronously, otherwise use | |
305 | * delayed write. If this is the first instance of | |
306 | * the delayed write, reassociate the buffer with the | |
307 | * file so it will be written if the file is sync'ed. | |
308 | */ | |
309 | if (flags & B_SYNC) { | |
9b392e39 | 310 | bwrite(bp); |
3cf3d516 | 311 | } else if (bp->b_flags & B_DELWRI) { |
9b392e39 | 312 | bdwrite(bp); |
3cf3d516 KM |
313 | } else { |
314 | bdwrite(bp); | |
315 | reassignbuf(bp, vp); | |
316 | } | |
9b392e39 KM |
317 | *bpp = nbp; |
318 | return (0); | |
52212483 | 319 | } |
9b392e39 | 320 | brelse(bp); |
0b4c7ad8 | 321 | if (flags & B_CLRBUF) { |
9b392e39 KM |
322 | error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp); |
323 | if (error) { | |
324 | brelse(nbp); | |
325 | return (error); | |
326 | } | |
0b4c7ad8 KM |
327 | } else { |
328 | nbp = getblk(vp, lbn, fs->fs_bsize); | |
329 | nbp->b_blkno = fsbtodb(fs, nb); | |
9b392e39 KM |
330 | } |
331 | *bpp = nbp; | |
7188ac27 | 332 | return (0); |
52212483 | 333 | } |