xref: /freebsd/usr.sbin/makefs/ffs/ffs_balloc.c (revision 99429157e8615dc3b7f11afbe3ed92de7476a5db)
1 /*	$NetBSD: ffs_balloc.c,v 1.13 2004/06/20 22:20:18 jmc Exp $	*/
2 /* From NetBSD: ffs_balloc.c,v 1.25 2001/08/08 08:36:36 lukem Exp */
3 
4 /*
5  * Copyright (c) 1982, 1986, 1989, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  *	@(#)ffs_balloc.c	8.8 (Berkeley) 6/16/95
33  */
34 
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37 
38 #include <sys/param.h>
39 #include <sys/time.h>
40 
41 #include <assert.h>
42 #include <errno.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 
47 #include "makefs.h"
48 
49 #include <ufs/ufs/dinode.h>
50 #include <ufs/ffs/fs.h>
51 
52 #include "ffs/ufs_bswap.h"
53 #include "ffs/buf.h"
54 #include "ffs/ufs_inode.h"
55 #include "ffs/ffs_extern.h"
56 
57 static int ffs_balloc_ufs1(struct inode *, off_t, int, struct buf **);
58 static int ffs_balloc_ufs2(struct inode *, off_t, int, struct buf **);
59 
60 /*
61  * Balloc defines the structure of file system storage
62  * by allocating the physical blocks on a device given
63  * the inode and the logical block number in a file.
64  *
65  * Assume: flags == B_SYNC | B_CLRBUF
66  */
67 
68 int
69 ffs_balloc(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
70 {
71 	if (ip->i_fs->fs_magic == FS_UFS2_MAGIC)
72 		return ffs_balloc_ufs2(ip, offset, bufsize, bpp);
73 	else
74 		return ffs_balloc_ufs1(ip, offset, bufsize, bpp);
75 }
76 
77 static int
78 ffs_balloc_ufs1(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
79 {
80 	daddr_t lbn, lastlbn;
81 	int size;
82 	int32_t nb;
83 	struct buf *bp, *nbp;
84 	struct fs *fs = ip->i_fs;
85 	struct indir indirs[UFS_NIADDR + 2];
86 	daddr_t newb, pref;
87 	int32_t *bap;
88 	int osize, nsize, num, i, error;
89 	int32_t *allocblk, allociblk[UFS_NIADDR + 1];
90 	int32_t *allocib;
91 	const int needswap = UFS_FSNEEDSWAP(fs);
92 	struct vnode vp = { ip->i_fd, ip->i_fs, NULL, 0 };
93 
94 	lbn = lblkno(fs, offset);
95 	size = blkoff(fs, offset) + bufsize;
96 	if (bpp != NULL) {
97 		*bpp = NULL;
98 	}
99 
100 	assert(size <= fs->fs_bsize);
101 	if (lbn < 0)
102 		return (EFBIG);
103 
104 	/*
105 	 * If the next write will extend the file into a new block,
106 	 * and the file is currently composed of a fragment
107 	 * this fragment has to be extended to be a full block.
108 	 */
109 
110 	lastlbn = lblkno(fs, ip->i_ffs1_size);
111 	if (lastlbn < UFS_NDADDR && lastlbn < lbn) {
112 		nb = lastlbn;
113 		osize = blksize(fs, ip, nb);
114 		if (osize < fs->fs_bsize && osize > 0) {
115 			warnx("need to ffs_realloccg; not supported!");
116 			abort();
117 		}
118 	}
119 
120 	/*
121 	 * The first UFS_NDADDR blocks are direct blocks
122 	 */
123 
124 	if (lbn < UFS_NDADDR) {
125 		nb = ufs_rw32(ip->i_ffs1_db[lbn], needswap);
126 		if (nb != 0 && ip->i_ffs1_size >=
127 		    (uint64_t)lblktosize(fs, lbn + 1)) {
128 
129 			/*
130 			 * The block is an already-allocated direct block
131 			 * and the file already extends past this block,
132 			 * thus this must be a whole block.
133 			 * Just read the block (if requested).
134 			 */
135 
136 			if (bpp != NULL) {
137 				error = bread(&vp, lbn, fs->fs_bsize, NULL,
138 				    bpp);
139 				if (error) {
140 					brelse(*bpp, 0);
141 					return (error);
142 				}
143 			}
144 			return (0);
145 		}
146 		if (nb != 0) {
147 
148 			/*
149 			 * Consider need to reallocate a fragment.
150 			 */
151 
152 			osize = fragroundup(fs, blkoff(fs, ip->i_ffs1_size));
153 			nsize = fragroundup(fs, size);
154 			if (nsize <= osize) {
155 
156 				/*
157 				 * The existing block is already
158 				 * at least as big as we want.
159 				 * Just read the block (if requested).
160 				 */
161 
162 				if (bpp != NULL) {
163 					error = bread(&vp, lbn, osize, NULL,
164 					    bpp);
165 					if (error) {
166 						brelse(*bpp, 0);
167 						return (error);
168 					}
169 				}
170 				return 0;
171 			} else {
172 				warnx("need to ffs_realloccg; not supported!");
173 				abort();
174 			}
175 		} else {
176 
177 			/*
178 			 * the block was not previously allocated,
179 			 * allocate a new block or fragment.
180 			 */
181 
182 			if (ip->i_ffs1_size < (uint64_t)lblktosize(fs, lbn + 1))
183 				nsize = fragroundup(fs, size);
184 			else
185 				nsize = fs->fs_bsize;
186 			error = ffs_alloc(ip, lbn,
187 			    ffs_blkpref_ufs1(ip, lbn, (int)lbn,
188 				&ip->i_ffs1_db[0]),
189 				nsize, &newb);
190 			if (error)
191 				return (error);
192 			if (bpp != NULL) {
193 				bp = getblk(&vp, lbn, nsize, 0, 0, 0);
194 				bp->b_blkno = fsbtodb(fs, newb);
195 				clrbuf(bp);
196 				*bpp = bp;
197 			}
198 		}
199 		ip->i_ffs1_db[lbn] = ufs_rw32((int32_t)newb, needswap);
200 		return (0);
201 	}
202 
203 	/*
204 	 * Determine the number of levels of indirection.
205 	 */
206 
207 	pref = 0;
208 	if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0)
209 		return (error);
210 
211 	if (num < 1) {
212 		warnx("ffs_balloc: ufs_getlbns returned indirect block");
213 		abort();
214 	}
215 
216 	/*
217 	 * Fetch the first indirect block allocating if necessary.
218 	 */
219 
220 	--num;
221 	nb = ufs_rw32(ip->i_ffs1_ib[indirs[0].in_off], needswap);
222 	allocib = NULL;
223 	allocblk = allociblk;
224 	if (nb == 0) {
225 		pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
226 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
227 		if (error)
228 			return error;
229 		nb = newb;
230 		*allocblk++ = nb;
231 		bp = getblk(&vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0, 0);
232 		bp->b_blkno = fsbtodb(fs, nb);
233 		clrbuf(bp);
234 		/*
235 		 * Write synchronously so that indirect blocks
236 		 * never point at garbage.
237 		 */
238 		if ((error = bwrite(bp)) != 0)
239 			return error;
240 		allocib = &ip->i_ffs1_ib[indirs[0].in_off];
241 		*allocib = ufs_rw32((int32_t)nb, needswap);
242 	}
243 
244 	/*
245 	 * Fetch through the indirect blocks, allocating as necessary.
246 	 */
247 
248 	for (i = 1;;) {
249 		error = bread(&vp, indirs[i].in_lbn, fs->fs_bsize, NULL, &bp);
250 		if (error) {
251 			brelse(bp, 0);
252 			return error;
253 		}
254 		bap = (int32_t *)bp->b_data;
255 		nb = ufs_rw32(bap[indirs[i].in_off], needswap);
256 		if (i == num)
257 			break;
258 		i++;
259 		if (nb != 0) {
260 			brelse(bp, 0);
261 			continue;
262 		}
263 		if (pref == 0)
264 			pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
265 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
266 		if (error) {
267 			brelse(bp, 0);
268 			return error;
269 		}
270 		nb = newb;
271 		*allocblk++ = nb;
272 		nbp = getblk(&vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0, 0);
273 		nbp->b_blkno = fsbtodb(fs, nb);
274 		clrbuf(nbp);
275 		/*
276 		 * Write synchronously so that indirect blocks
277 		 * never point at garbage.
278 		 */
279 
280 		if ((error = bwrite(nbp)) != 0) {
281 			brelse(bp, 0);
282 			return error;
283 		}
284 		bap[indirs[i - 1].in_off] = ufs_rw32(nb, needswap);
285 
286 		bwrite(bp);
287 	}
288 
289 	/*
290 	 * Get the data block, allocating if necessary.
291 	 */
292 
293 	if (nb == 0) {
294 		pref = ffs_blkpref_ufs1(ip, lbn, indirs[num].in_off, &bap[0]);
295 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
296 		if (error) {
297 			brelse(bp, 0);
298 			return error;
299 		}
300 		nb = newb;
301 		*allocblk++ = nb;
302 		if (bpp != NULL) {
303 			nbp = getblk(&vp, lbn, fs->fs_bsize, 0, 0, 0);
304 			nbp->b_blkno = fsbtodb(fs, nb);
305 			clrbuf(nbp);
306 			*bpp = nbp;
307 		}
308 		bap[indirs[num].in_off] = ufs_rw32(nb, needswap);
309 
310 		/*
311 		 * If required, write synchronously, otherwise use
312 		 * delayed write.
313 		 */
314 		bwrite(bp);
315 		return (0);
316 	}
317 	brelse(bp, 0);
318 	if (bpp != NULL) {
319 		error = bread(&vp, lbn, (int)fs->fs_bsize, NULL, &nbp);
320 		if (error) {
321 			brelse(nbp, 0);
322 			return error;
323 		}
324 		*bpp = nbp;
325 	}
326 	return (0);
327 }
328 
329 static int
330 ffs_balloc_ufs2(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
331 {
332 	daddr_t lbn, lastlbn;
333 	int size;
334 	struct buf *bp, *nbp;
335 	struct fs *fs = ip->i_fs;
336 	struct indir indirs[UFS_NIADDR + 2];
337 	daddr_t newb, pref, nb;
338 	int64_t *bap;
339 	int osize, nsize, num, i, error;
340 	int64_t *allocblk, allociblk[UFS_NIADDR + 1];
341 	int64_t *allocib;
342 	const int needswap = UFS_FSNEEDSWAP(fs);
343 	struct vnode vp = { ip->i_fd, ip->i_fs, NULL, 0 };
344 
345 	lbn = lblkno(fs, offset);
346 	size = blkoff(fs, offset) + bufsize;
347 	if (bpp != NULL) {
348 		*bpp = NULL;
349 	}
350 
351 	assert(size <= fs->fs_bsize);
352 	if (lbn < 0)
353 		return (EFBIG);
354 
355 	/*
356 	 * If the next write will extend the file into a new block,
357 	 * and the file is currently composed of a fragment
358 	 * this fragment has to be extended to be a full block.
359 	 */
360 
361 	lastlbn = lblkno(fs, ip->i_ffs2_size);
362 	if (lastlbn < UFS_NDADDR && lastlbn < lbn) {
363 		nb = lastlbn;
364 		osize = blksize(fs, ip, nb);
365 		if (osize < fs->fs_bsize && osize > 0) {
366 			warnx("need to ffs_realloccg; not supported!");
367 			abort();
368 		}
369 	}
370 
371 	/*
372 	 * The first UFS_NDADDR blocks are direct blocks
373 	 */
374 
375 	if (lbn < UFS_NDADDR) {
376 		nb = ufs_rw64(ip->i_ffs2_db[lbn], needswap);
377 		if (nb != 0 && ip->i_ffs2_size >=
378 		    (uint64_t)lblktosize(fs, lbn + 1)) {
379 
380 			/*
381 			 * The block is an already-allocated direct block
382 			 * and the file already extends past this block,
383 			 * thus this must be a whole block.
384 			 * Just read the block (if requested).
385 			 */
386 
387 			if (bpp != NULL) {
388 				error = bread(&vp, lbn, fs->fs_bsize, NULL,
389 				    bpp);
390 				if (error) {
391 					brelse(*bpp, 0);
392 					return (error);
393 				}
394 			}
395 			return (0);
396 		}
397 		if (nb != 0) {
398 
399 			/*
400 			 * Consider need to reallocate a fragment.
401 			 */
402 
403 			osize = fragroundup(fs, blkoff(fs, ip->i_ffs2_size));
404 			nsize = fragroundup(fs, size);
405 			if (nsize <= osize) {
406 
407 				/*
408 				 * The existing block is already
409 				 * at least as big as we want.
410 				 * Just read the block (if requested).
411 				 */
412 
413 				if (bpp != NULL) {
414 					error = bread(&vp, lbn, osize, NULL,
415 					    bpp);
416 					if (error) {
417 						brelse(*bpp, 0);
418 						return (error);
419 					}
420 				}
421 				return 0;
422 			} else {
423 				warnx("need to ffs_realloccg; not supported!");
424 				abort();
425 			}
426 		} else {
427 
428 			/*
429 			 * the block was not previously allocated,
430 			 * allocate a new block or fragment.
431 			 */
432 
433 			if (ip->i_ffs2_size < (uint64_t)lblktosize(fs, lbn + 1))
434 				nsize = fragroundup(fs, size);
435 			else
436 				nsize = fs->fs_bsize;
437 			error = ffs_alloc(ip, lbn,
438 			    ffs_blkpref_ufs2(ip, lbn, (int)lbn,
439 				&ip->i_ffs2_db[0]),
440 				nsize, &newb);
441 			if (error)
442 				return (error);
443 			if (bpp != NULL) {
444 				bp = getblk(&vp, lbn, nsize, 0, 0, 0);
445 				bp->b_blkno = fsbtodb(fs, newb);
446 				clrbuf(bp);
447 				*bpp = bp;
448 			}
449 		}
450 		ip->i_ffs2_db[lbn] = ufs_rw64(newb, needswap);
451 		return (0);
452 	}
453 
454 	/*
455 	 * Determine the number of levels of indirection.
456 	 */
457 
458 	pref = 0;
459 	if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0)
460 		return (error);
461 
462 	if (num < 1) {
463 		warnx("ffs_balloc: ufs_getlbns returned indirect block");
464 		abort();
465 	}
466 
467 	/*
468 	 * Fetch the first indirect block allocating if necessary.
469 	 */
470 
471 	--num;
472 	nb = ufs_rw64(ip->i_ffs2_ib[indirs[0].in_off], needswap);
473 	allocib = NULL;
474 	allocblk = allociblk;
475 	if (nb == 0) {
476 		pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
477 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
478 		if (error)
479 			return error;
480 		nb = newb;
481 		*allocblk++ = nb;
482 		bp = getblk(&vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0, 0);
483 		bp->b_blkno = fsbtodb(fs, nb);
484 		clrbuf(bp);
485 		/*
486 		 * Write synchronously so that indirect blocks
487 		 * never point at garbage.
488 		 */
489 		if ((error = bwrite(bp)) != 0)
490 			return error;
491 		allocib = &ip->i_ffs2_ib[indirs[0].in_off];
492 		*allocib = ufs_rw64(nb, needswap);
493 	}
494 
495 	/*
496 	 * Fetch through the indirect blocks, allocating as necessary.
497 	 */
498 
499 	for (i = 1;;) {
500 		error = bread(&vp, indirs[i].in_lbn, fs->fs_bsize, NULL, &bp);
501 		if (error) {
502 			brelse(bp, 0);
503 			return error;
504 		}
505 		bap = (int64_t *)bp->b_data;
506 		nb = ufs_rw64(bap[indirs[i].in_off], needswap);
507 		if (i == num)
508 			break;
509 		i++;
510 		if (nb != 0) {
511 			brelse(bp, 0);
512 			continue;
513 		}
514 		if (pref == 0)
515 			pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
516 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
517 		if (error) {
518 			brelse(bp, 0);
519 			return error;
520 		}
521 		nb = newb;
522 		*allocblk++ = nb;
523 		nbp = getblk(&vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0, 0);
524 		nbp->b_blkno = fsbtodb(fs, nb);
525 		clrbuf(nbp);
526 		/*
527 		 * Write synchronously so that indirect blocks
528 		 * never point at garbage.
529 		 */
530 
531 		if ((error = bwrite(nbp)) != 0) {
532 			brelse(bp, 0);
533 			return error;
534 		}
535 		bap[indirs[i - 1].in_off] = ufs_rw64(nb, needswap);
536 
537 		bwrite(bp);
538 	}
539 
540 	/*
541 	 * Get the data block, allocating if necessary.
542 	 */
543 
544 	if (nb == 0) {
545 		pref = ffs_blkpref_ufs2(ip, lbn, indirs[num].in_off, &bap[0]);
546 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
547 		if (error) {
548 			brelse(bp, 0);
549 			return error;
550 		}
551 		nb = newb;
552 		*allocblk++ = nb;
553 		if (bpp != NULL) {
554 			nbp = getblk(&vp, lbn, fs->fs_bsize, 0, 0, 0);
555 			nbp->b_blkno = fsbtodb(fs, nb);
556 			clrbuf(nbp);
557 			*bpp = nbp;
558 		}
559 		bap[indirs[num].in_off] = ufs_rw64(nb, needswap);
560 
561 		/*
562 		 * If required, write synchronously, otherwise use
563 		 * delayed write.
564 		 */
565 		bwrite(bp);
566 		return (0);
567 	}
568 	brelse(bp, 0);
569 	if (bpp != NULL) {
570 		error = bread(&vp, lbn, (int)fs->fs_bsize, NULL, &nbp);
571 		if (error) {
572 			brelse(nbp, 0);
573 			return error;
574 		}
575 		*bpp = nbp;
576 	}
577 	return (0);
578 }
579