ffs_balloc.c revision 1.14.4.5 1 /* $NetBSD: ffs_balloc.c,v 1.14.4.5 1999/07/31 18:47:38 chs Exp $ */
2
3 /*
4 * Copyright (c) 1982, 1986, 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)ffs_balloc.c 8.8 (Berkeley) 6/16/95
36 */
37
38 #if defined(_KERNEL) && !defined(_LKM)
39 #include "opt_quota.h"
40 #endif
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/buf.h>
45 #include <sys/proc.h>
46 #include <sys/file.h>
47 #include <sys/vnode.h>
48 #include <sys/mount.h>
49
50 #include <vm/vm.h>
51 #include <uvm/uvm_extern.h>
52 #include <uvm/uvm.h>
53
54 #include <ufs/ufs/quota.h>
55 #include <ufs/ufs/ufsmount.h>
56 #include <ufs/ufs/inode.h>
57 #include <ufs/ufs/ufs_extern.h>
58 #include <ufs/ufs/ufs_bswap.h>
59
60 #include <ufs/ffs/fs.h>
61 #include <ufs/ffs/ffs_extern.h>
62
63 /*
64 * Balloc defines the structure of file system storage
65 * by allocating the physical blocks on a device given
66 * the inode and the logical block number in a file.
67 */
68
69 int
70 ffs_balloc(v)
71 void *v;
72 {
73 struct vop_balloc_args /* {
74 struct vnode *a_vp;
75 off_t a_offset;
76 off_t a_length;
77 struct ucred *a_cred;
78 int a_flags;
79 } */ *ap = v;
80
81 off_t off, len;
82 struct vnode *vp = ap->a_vp;
83 struct inode *ip = VTOI(vp);
84 struct fs *fs = ip->i_fs;
85 int error, delta, bshift, bsize;
86
87 bshift = fs->fs_bshift;
88 bsize = 1 << bshift;
89
90 off = ap->a_offset;
91 len = ap->a_length;
92
93 delta = off & (bsize - 1);
94 off -= delta;
95 len += delta;
96
97 while (len > 0) {
98 bsize = min(bsize, len);
99
100 if ((error = ffs_balloc1(vp, lblkno(fs, off), bsize, ap->a_cred,
101 ap->a_flags, NULL))) {
102 return error;
103 }
104
105 /*
106 * increase file size now, VOP_BALLOC() requires that
107 * EOF be up-to-date before each call.
108 */
109
110 if (ip->i_ffs_size < off + bsize) {
111 ip->i_ffs_size = off + bsize;
112 uvm_vnp_setsize(vp, ip->i_ffs_size);
113 }
114
115 off += bsize;
116 len -= bsize;
117 }
118 return 0;
119 }
120
121 int
122 ffs_balloc1(vp, lbn, size, cred, flags, bpp)
123 struct vnode *vp;
124 ufs_daddr_t lbn;
125 int size;
126 struct ucred *cred;
127 int flags;
128 struct buf **bpp;
129 {
130 struct inode *ip = VTOI(vp);
131 struct fs *fs = ip->i_fs;
132 ufs_daddr_t nb;
133 struct buf *bp, *nbp;
134 struct indir indirs[NIADDR + 2];
135 ufs_daddr_t newb, *bap, pref;
136 int deallocated, osize, nsize, num, i, error;
137 ufs_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1];
138 UVMHIST_FUNC("ffs_balloc"); UVMHIST_CALLED(ubchist);
139
140 UVMHIST_LOG(ubchist, "vp %p lbn 0x%x size 0x%x", vp, lbn, size,0);
141 if (bpp != NULL) {
142 *bpp = NULL;
143 }
144 if (lbn < 0)
145 return (EFBIG);
146 fs = ip->i_fs;
147
148 /*
149 * If the file currently ends with a fragment and
150 * the block we're allocating now is after the current EOF,
151 * this fragment has to be extended to be a full block.
152 */
153
154 nb = lblkno(fs, ip->i_ffs_size);
155 if (nb < NDADDR && nb < lbn) {
156 osize = blksize(fs, ip, nb);
157 if (osize < fs->fs_bsize && osize > 0) {
158 error = ffs_realloccg(ip, nb,
159 ffs_blkpref(ip, nb, (int)nb, &ip->i_ffs_db[0]),
160 osize, (int)fs->fs_bsize, cred, bpp, &newb);
161 if (error)
162 return (error);
163 ip->i_ffs_size = lblktosize(fs, nb + 1);
164 uvm_vnp_setsize(vp, ip->i_ffs_size);
165 ip->i_ffs_db[nb] = ufs_rw32(newb,
166 UFS_MPNEEDSWAP(vp->v_mount));
167 ip->i_flag |= IN_CHANGE | IN_UPDATE;
168
169 if (bpp) {
170 if (flags & B_SYNC)
171 bwrite(*bpp);
172 else
173 bawrite(*bpp);
174 }
175 else {
176 /*
177 * XXX the data in the frag might be
178 * moving to a new disk location.
179 * we need to flush pages to the
180 * new disk locations.
181 * XXX we could do this in realloccg
182 * except for the sync flag.
183 */
184 (vp->v_uvm.u_obj.pgops->pgo_flush)
185 (&vp->v_uvm.u_obj, lblktosize(fs, nb),
186 lblktosize(fs, nb + 1),
187 flags & B_SYNC ? PGO_SYNCIO : 0);
188 }
189 }
190 }
191 /*
192 * The first NDADDR blocks are direct blocks
193 */
194 if (lbn < NDADDR) {
195
196 nb = ufs_rw32(ip->i_ffs_db[lbn], UFS_MPNEEDSWAP(vp->v_mount));
197 if (nb != 0 && ip->i_ffs_size >= lblktosize(fs, lbn + 1)) {
198
199 /*
200 * the block is an already-allocated direct block
201 * and the file already extends past this block,
202 * thus this must be a whole block.
203 * just read the block (if requested).
204 */
205
206 if (bpp != NULL) {
207 error = bread(vp, lbn, fs->fs_bsize, NOCRED,
208 &bp);
209 if (error) {
210 brelse(bp);
211 return (error);
212 }
213 *bpp = bp;
214 }
215 return (0);
216 }
217 if (nb != 0) {
218
219 /*
220 * Consider need to reallocate a fragment.
221 */
222
223 osize = fragroundup(fs, blkoff(fs, ip->i_ffs_size));
224 nsize = fragroundup(fs, size);
225 if (nsize <= osize) {
226
227 /*
228 * the existing block is already
229 * at least as big as we want.
230 * just read the block (if requested).
231 */
232
233 if (bpp != NULL) {
234 error = bread(vp, lbn, osize, NOCRED,
235 &bp);
236 if (error) {
237 brelse(bp);
238 return (error);
239 }
240 *bpp = bp;
241 }
242 return 0;
243 } else {
244
245 /*
246 * the existing block is smaller than we want,
247 * grow it.
248 */
249
250 error = ffs_realloccg(ip, lbn,
251 ffs_blkpref(ip, lbn, (int)lbn,
252 &ip->i_ffs_db[0]), osize, nsize, cred,
253 bpp, &newb);
254 if (error)
255 return (error);
256 }
257 } else {
258
259 /*
260 * the block was not previously allocated,
261 * allocate a new block or fragment.
262 */
263
264 if (ip->i_ffs_size < lblktosize(fs, lbn + 1))
265 nsize = fragroundup(fs, size);
266 else
267 nsize = fs->fs_bsize;
268 error = ffs_alloc(ip, lbn,
269 ffs_blkpref(ip, lbn, (int)lbn, &ip->i_ffs_db[0]),
270 nsize, cred, &newb);
271 if (error)
272 return (error);
273 if (bpp != NULL) {
274 bp = getblk(vp, lbn, nsize, 0, 0);
275 bp->b_blkno = fsbtodb(fs, newb);
276 if (flags & B_CLRBUF)
277 clrbuf(bp);
278 *bpp = bp;
279 }
280 }
281 ip->i_ffs_db[lbn] = ufs_rw32(newb, UFS_MPNEEDSWAP(vp->v_mount));
282 ip->i_flag |= IN_CHANGE | IN_UPDATE;
283 return (0);
284 }
285
286 /*
287 * Determine the number of levels of indirection.
288 */
289
290 pref = 0;
291 if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0)
292 return(error);
293 #ifdef DIAGNOSTIC
294 if (num < 1)
295 panic ("ffs_balloc: ufs_bmaparray returned indirect block\n");
296 #endif
297 /*
298 * Fetch the first indirect block allocating if necessary.
299 */
300 --num;
301 nb = ufs_rw32(ip->i_ffs_ib[indirs[0].in_off],
302 UFS_MPNEEDSWAP(vp->v_mount));
303 allocib = NULL;
304 allocblk = allociblk;
305 if (nb == 0) {
306 pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
307 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize,
308 cred, &newb);
309 if (error)
310 return (error);
311 nb = newb;
312 *allocblk++ = nb;
313 bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0);
314 bp->b_blkno = fsbtodb(fs, nb);
315 clrbuf(bp);
316 /*
317 * Write synchronously so that indirect blocks
318 * never point at garbage.
319 */
320 if ((error = bwrite(bp)) != 0)
321 goto fail;
322 allocib = &ip->i_ffs_ib[indirs[0].in_off];
323 *allocib = ufs_rw32(nb, UFS_MPNEEDSWAP(vp->v_mount));
324 ip->i_flag |= IN_CHANGE | IN_UPDATE;
325 }
326 /*
327 * Fetch through the indirect blocks, allocating as necessary.
328 */
329 for (i = 1;;) {
330 error = bread(vp,
331 indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp);
332 if (error) {
333 brelse(bp);
334 goto fail;
335 }
336 bap = (ufs_daddr_t *)bp->b_data;
337 nb = ufs_rw32(bap[indirs[i].in_off],
338 UFS_MPNEEDSWAP(vp->v_mount));
339 if (i == num)
340 break;
341 i += 1;
342 if (nb != 0) {
343 brelse(bp);
344 continue;
345 }
346 if (pref == 0)
347 pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
348 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
349 &newb);
350 if (error) {
351 brelse(bp);
352 goto fail;
353 }
354 nb = newb;
355 *allocblk++ = nb;
356 nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0);
357 nbp->b_blkno = fsbtodb(fs, nb);
358 clrbuf(nbp);
359 /*
360 * Write synchronously so that indirect blocks
361 * never point at garbage.
362 */
363 if ((error = bwrite(nbp)) != 0) {
364 brelse(bp);
365 goto fail;
366 }
367 bap[indirs[i - 1].in_off] = ufs_rw32(nb,
368 UFS_MPNEEDSWAP(vp->v_mount));
369 /*
370 * If required, write synchronously, otherwise use
371 * delayed write.
372 */
373 if (flags & B_SYNC) {
374 bwrite(bp);
375 } else {
376 bdwrite(bp);
377 }
378 }
379 /*
380 * Get the data block, allocating if necessary.
381 */
382 if (nb == 0) {
383 pref = ffs_blkpref(ip, lbn, indirs[i].in_off, &bap[0]);
384 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
385 &newb);
386 if (error) {
387 brelse(bp);
388 goto fail;
389 }
390 nb = newb;
391 *allocblk++ = nb;
392 bap[indirs[i].in_off] = ufs_rw32(nb,
393 UFS_MPNEEDSWAP(vp->v_mount));
394 /*
395 * If required, write synchronously, otherwise use
396 * delayed write.
397 */
398 if (flags & B_SYNC) {
399 bwrite(bp);
400 } else {
401 bdwrite(bp);
402 }
403 if (bpp != NULL) {
404 nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
405 nbp->b_blkno = fsbtodb(fs, nb);
406 if (flags & B_CLRBUF)
407 clrbuf(nbp);
408 *bpp = nbp;
409 }
410 return (0);
411 }
412
413 brelse(bp);
414
415 if (bpp != NULL) {
416 if (flags & B_CLRBUF) {
417 error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp);
418 if (error) {
419 brelse(nbp);
420 goto fail;
421 }
422 } else {
423 nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
424 nbp->b_blkno = fsbtodb(fs, nb);
425 clrbuf(nbp);
426 }
427 *bpp = nbp;
428 }
429 return (0);
430 fail:
431 /*
432 * If we have failed part way through block allocation, we
433 * have to deallocate any indirect blocks that we have allocated.
434 */
435 for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
436 ffs_blkfree(ip, *blkp, fs->fs_bsize);
437 deallocated += fs->fs_bsize;
438 }
439 if (allocib != NULL)
440 *allocib = 0;
441 if (deallocated) {
442 #ifdef QUOTA
443 /*
444 * Restore user's disk quota because allocation failed.
445 */
446 (void)chkdq(ip, (long)-btodb(deallocated), cred, FORCE);
447 #endif
448 ip->i_ffs_blocks -= btodb(deallocated);
449 ip->i_flag |= IN_CHANGE | IN_UPDATE;
450 }
451 return (error);
452 }
453