Home | History | Annotate | Line # | Download | only in ffs
ffs_balloc.c revision 1.12
      1 /*	$NetBSD: ffs_balloc.c,v 1.12 2003/08/07 11:25:33 agc 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 #if defined(__RCSID) && !defined(__lint)
     37 __RCSID("$NetBSD: ffs_balloc.c,v 1.12 2003/08/07 11:25:33 agc Exp $");
     38 #endif	/* !__lint */
     39 
     40 #include <sys/param.h>
     41 #include <sys/time.h>
     42 
     43 #include <assert.h>
     44 #include <errno.h>
     45 #include <stdio.h>
     46 #include <stdlib.h>
     47 #include <string.h>
     48 
     49 #include "makefs.h"
     50 
     51 #include <ufs/ufs/dinode.h>
     52 #include <ufs/ufs/ufs_bswap.h>
     53 #include <ufs/ffs/fs.h>
     54 
     55 #include "ffs/buf.h"
     56 #include "ffs/ufs_inode.h"
     57 #include "ffs/ffs_extern.h"
     58 
     59 static int ffs_balloc_ufs1(struct inode *, off_t, int, struct buf **);
     60 static int ffs_balloc_ufs2(struct inode *, off_t, int, struct buf **);
     61 
     62 /*
     63  * Balloc defines the structure of file system storage
     64  * by allocating the physical blocks on a device given
     65  * the inode and the logical block number in a file.
     66  *
     67  * Assume: flags == B_SYNC | B_CLRBUF
     68  */
     69 
     70 int
     71 ffs_balloc(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
     72 {
     73 	if (ip->i_fs->fs_magic == FS_UFS2_MAGIC)
     74 		return ffs_balloc_ufs2(ip, offset, bufsize, bpp);
     75 	else
     76 		return ffs_balloc_ufs1(ip, offset, bufsize, bpp);
     77 }
     78 
     79 static int
     80 ffs_balloc_ufs1(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
     81 {
     82 	daddr_t lbn, lastlbn;
     83 	int size;
     84 	int32_t nb;
     85 	struct buf *bp, *nbp;
     86 	struct fs *fs = ip->i_fs;
     87 	struct indir indirs[NIADDR + 2];
     88 	daddr_t newb, pref;
     89 	int32_t *bap;
     90 	int osize, nsize, num, i, error;
     91 	int32_t *allocblk, allociblk[NIADDR + 1];
     92 	int32_t *allocib;
     93 	const int needswap = UFS_FSNEEDSWAP(fs);
     94 
     95 	lbn = lblkno(fs, offset);
     96 	size = blkoff(fs, offset) + bufsize;
     97 	if (bpp != NULL) {
     98 		*bpp = NULL;
     99 	}
    100 
    101 	assert(size <= fs->fs_bsize);
    102 	if (lbn < 0)
    103 		return (EFBIG);
    104 
    105 	/*
    106 	 * If the next write will extend the file into a new block,
    107 	 * and the file is currently composed of a fragment
    108 	 * this fragment has to be extended to be a full block.
    109 	 */
    110 
    111 	lastlbn = lblkno(fs, ip->i_ffs1_size);
    112 	if (lastlbn < NDADDR && lastlbn < lbn) {
    113 		nb = lastlbn;
    114 		osize = blksize(fs, ip, nb);
    115 		if (osize < fs->fs_bsize && osize > 0) {
    116 			warnx("need to ffs_realloccg; not supported!");
    117 			abort();
    118 		}
    119 	}
    120 
    121 	/*
    122 	 * The first NDADDR blocks are direct blocks
    123 	 */
    124 
    125 	if (lbn < NDADDR) {
    126 		nb = ufs_rw32(ip->i_ffs1_db[lbn], needswap);
    127 		if (nb != 0 && ip->i_ffs1_size >= 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(ip->i_fd, ip->i_fs, lbn,
    138 				    fs->fs_bsize, bpp);
    139 				if (error) {
    140 					brelse(*bpp);
    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(ip->i_fd, ip->i_fs, lbn,
    164 					    osize, bpp);
    165 					if (error) {
    166 						brelse(*bpp);
    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 < 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(ip->i_fd, ip->i_fs, lbn, nsize);
    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(ip->i_fd, ip->i_fs, indirs[1].in_lbn, fs->fs_bsize);
    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(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
    250 		    fs->fs_bsize, &bp);
    251 		if (error) {
    252 			brelse(bp);
    253 			return error;
    254 		}
    255 		bap = (int32_t *)bp->b_data;
    256 		nb = ufs_rw32(bap[indirs[i].in_off], needswap);
    257 		if (i == num)
    258 			break;
    259 		i++;
    260 		if (nb != 0) {
    261 			brelse(bp);
    262 			continue;
    263 		}
    264 		if (pref == 0)
    265 			pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
    266 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
    267 		if (error) {
    268 			brelse(bp);
    269 			return error;
    270 		}
    271 		nb = newb;
    272 		*allocblk++ = nb;
    273 		nbp = getblk(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
    274 		    fs->fs_bsize);
    275 		nbp->b_blkno = fsbtodb(fs, nb);
    276 		clrbuf(nbp);
    277 		/*
    278 		 * Write synchronously so that indirect blocks
    279 		 * never point at garbage.
    280 		 */
    281 
    282 		if ((error = bwrite(nbp)) != 0) {
    283 			brelse(bp);
    284 			return error;
    285 		}
    286 		bap[indirs[i - 1].in_off] = ufs_rw32(nb, needswap);
    287 
    288 		bwrite(bp);
    289 	}
    290 
    291 	/*
    292 	 * Get the data block, allocating if necessary.
    293 	 */
    294 
    295 	if (nb == 0) {
    296 		pref = ffs_blkpref_ufs1(ip, lbn, indirs[num].in_off, &bap[0]);
    297 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
    298 		if (error) {
    299 			brelse(bp);
    300 			return error;
    301 		}
    302 		nb = newb;
    303 		*allocblk++ = nb;
    304 		if (bpp != NULL) {
    305 			nbp = getblk(ip->i_fd, ip->i_fs, lbn, fs->fs_bsize);
    306 			nbp->b_blkno = fsbtodb(fs, nb);
    307 			clrbuf(nbp);
    308 			*bpp = nbp;
    309 		}
    310 		bap[indirs[num].in_off] = ufs_rw32(nb, needswap);
    311 
    312 		/*
    313 		 * If required, write synchronously, otherwise use
    314 		 * delayed write.
    315 		 */
    316 		bwrite(bp);
    317 		return (0);
    318 	}
    319 	brelse(bp);
    320 	if (bpp != NULL) {
    321 		error = bread(ip->i_fd, ip->i_fs, lbn, (int)fs->fs_bsize, &nbp);
    322 		if (error) {
    323 			brelse(nbp);
    324 			return error;
    325 		}
    326 		*bpp = nbp;
    327 	}
    328 	return (0);
    329 }
    330 
    331 static int
    332 ffs_balloc_ufs2(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
    333 {
    334 	daddr_t lbn, lastlbn;
    335 	int size;
    336 	struct buf *bp, *nbp;
    337 	struct fs *fs = ip->i_fs;
    338 	struct indir indirs[NIADDR + 2];
    339 	daddr_t newb, pref, nb;
    340 	int64_t *bap;
    341 	int osize, nsize, num, i, error;
    342 	int64_t *allocblk, allociblk[NIADDR + 1];
    343 	int64_t *allocib;
    344 	const int needswap = UFS_FSNEEDSWAP(fs);
    345 
    346 	lbn = lblkno(fs, offset);
    347 	size = blkoff(fs, offset) + bufsize;
    348 	if (bpp != NULL) {
    349 		*bpp = NULL;
    350 	}
    351 
    352 	assert(size <= fs->fs_bsize);
    353 	if (lbn < 0)
    354 		return (EFBIG);
    355 
    356 	/*
    357 	 * If the next write will extend the file into a new block,
    358 	 * and the file is currently composed of a fragment
    359 	 * this fragment has to be extended to be a full block.
    360 	 */
    361 
    362 	lastlbn = lblkno(fs, ip->i_ffs2_size);
    363 	if (lastlbn < NDADDR && lastlbn < lbn) {
    364 		nb = lastlbn;
    365 		osize = blksize(fs, ip, nb);
    366 		if (osize < fs->fs_bsize && osize > 0) {
    367 			warnx("need to ffs_realloccg; not supported!");
    368 			abort();
    369 		}
    370 	}
    371 
    372 	/*
    373 	 * The first NDADDR blocks are direct blocks
    374 	 */
    375 
    376 	if (lbn < NDADDR) {
    377 		nb = ufs_rw64(ip->i_ffs2_db[lbn], needswap);
    378 		if (nb != 0 && ip->i_ffs2_size >= 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(ip->i_fd, ip->i_fs, lbn,
    389 				    fs->fs_bsize, bpp);
    390 				if (error) {
    391 					brelse(*bpp);
    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(ip->i_fd, ip->i_fs, lbn,
    415 					    osize, bpp);
    416 					if (error) {
    417 						brelse(*bpp);
    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 < 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(ip->i_fd, ip->i_fs, lbn, nsize);
    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(ip->i_fd, ip->i_fs, indirs[1].in_lbn, fs->fs_bsize);
    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(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
    501 		    fs->fs_bsize, &bp);
    502 		if (error) {
    503 			brelse(bp);
    504 			return error;
    505 		}
    506 		bap = (int64_t *)bp->b_data;
    507 		nb = ufs_rw64(bap[indirs[i].in_off], needswap);
    508 		if (i == num)
    509 			break;
    510 		i++;
    511 		if (nb != 0) {
    512 			brelse(bp);
    513 			continue;
    514 		}
    515 		if (pref == 0)
    516 			pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
    517 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
    518 		if (error) {
    519 			brelse(bp);
    520 			return error;
    521 		}
    522 		nb = newb;
    523 		*allocblk++ = nb;
    524 		nbp = getblk(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
    525 		    fs->fs_bsize);
    526 		nbp->b_blkno = fsbtodb(fs, nb);
    527 		clrbuf(nbp);
    528 		/*
    529 		 * Write synchronously so that indirect blocks
    530 		 * never point at garbage.
    531 		 */
    532 
    533 		if ((error = bwrite(nbp)) != 0) {
    534 			brelse(bp);
    535 			return error;
    536 		}
    537 		bap[indirs[i - 1].in_off] = ufs_rw64(nb, needswap);
    538 
    539 		bwrite(bp);
    540 	}
    541 
    542 	/*
    543 	 * Get the data block, allocating if necessary.
    544 	 */
    545 
    546 	if (nb == 0) {
    547 		pref = ffs_blkpref_ufs2(ip, lbn, indirs[num].in_off, &bap[0]);
    548 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
    549 		if (error) {
    550 			brelse(bp);
    551 			return error;
    552 		}
    553 		nb = newb;
    554 		*allocblk++ = nb;
    555 		if (bpp != NULL) {
    556 			nbp = getblk(ip->i_fd, ip->i_fs, lbn, fs->fs_bsize);
    557 			nbp->b_blkno = fsbtodb(fs, nb);
    558 			clrbuf(nbp);
    559 			*bpp = nbp;
    560 		}
    561 		bap[indirs[num].in_off] = ufs_rw64(nb, needswap);
    562 
    563 		/*
    564 		 * If required, write synchronously, otherwise use
    565 		 * delayed write.
    566 		 */
    567 		bwrite(bp);
    568 		return (0);
    569 	}
    570 	brelse(bp);
    571 	if (bpp != NULL) {
    572 		error = bread(ip->i_fd, ip->i_fs, lbn, (int)fs->fs_bsize, &nbp);
    573 		if (error) {
    574 			brelse(nbp);
    575 			return error;
    576 		}
    577 		*bpp = nbp;
    578 	}
    579 	return (0);
    580 }
    581