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