Home | History | Annotate | Line # | Download | only in ffs
ffs_balloc.c revision 1.13.2.5
      1 /*	$NetBSD: ffs_balloc.c,v 1.13.2.5 1999/05/30 15:01:26 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 #include "opt_uvm.h"
     41 #endif
     42 
     43 #include <sys/param.h>
     44 #include <sys/systm.h>
     45 #include <sys/buf.h>
     46 #include <sys/proc.h>
     47 #include <sys/file.h>
     48 #include <sys/vnode.h>
     49 #include <sys/mount.h>
     50 
     51 #include <vm/vm.h>
     52 
     53 #if defined(UVM)
     54 #include <uvm/uvm.h>
     55 #endif
     56 
     57 #include <ufs/ufs/quota.h>
     58 #include <ufs/ufs/ufsmount.h>
     59 #include <ufs/ufs/inode.h>
     60 #include <ufs/ufs/ufs_extern.h>
     61 #include <ufs/ufs/ufs_bswap.h>
     62 
     63 #include <ufs/ffs/fs.h>
     64 #include <ufs/ffs/ffs_extern.h>
     65 
     66 /*
     67  * Balloc defines the structure of file system storage
     68  * by allocating the physical blocks on a device given
     69  * the inode and the logical block number in a file.
     70  */
     71 int
     72 ffs_balloc(ip, lbn, size, cred, bpp, blknop, flags)
     73 	struct inode *ip;
     74 	ufs_daddr_t lbn;
     75 	int size;
     76 	struct ucred *cred;
     77 	struct buf **bpp;
     78 	daddr_t *blknop;
     79 	int flags;
     80 {
     81 	struct fs *fs;
     82 	ufs_daddr_t nb;
     83 	struct buf *bp, *nbp;
     84 	struct vnode *vp = ITOV(ip);
     85 	struct indir indirs[NIADDR + 2];
     86 	ufs_daddr_t newb, *bap, pref;
     87 	int deallocated, osize, nsize, num, i, error;
     88 	ufs_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1];
     89 
     90 	if (bpp != NULL) {
     91 		*bpp = NULL;
     92 	}
     93 	if (blknop != NULL) {
     94 		*blknop = (daddr_t)-1;
     95 	}
     96 
     97 	if (lbn < 0)
     98 		return (EFBIG);
     99 	fs = ip->i_fs;
    100 
    101 	/*
    102 	 * If the file currently ends with a fragment and
    103 	 * the block we're allocating now is after the current EOF,
    104 	 * this fragment has to be extended to be a full block.
    105 	 */
    106 	nb = lblkno(fs, ip->i_ffs_size);
    107 	if (nb < NDADDR && nb < lbn) {
    108 		osize = blksize(fs, ip, nb);
    109 		if (osize < fs->fs_bsize && osize > 0) {
    110 			error = ffs_realloccg(ip, nb,
    111 				ffs_blkpref(ip, nb, (int)nb, &ip->i_ffs_db[0]),
    112 				osize, (int)fs->fs_bsize, cred, bpp, &newb);
    113 			if (error)
    114 				return (error);
    115 			ip->i_ffs_size = lblktosize(fs, nb + 1);
    116 #if defined(UVM)
    117 			uvm_vnp_setsize(vp, ip->i_ffs_size);
    118 #else
    119 			vnode_pager_setsize(vp, ip->i_ffs_size);
    120 #endif
    121 			ip->i_ffs_db[nb] = ufs_rw32(newb,
    122 			    UFS_MPNEEDSWAP(vp->v_mount));
    123 			ip->i_flag |= IN_CHANGE | IN_UPDATE;
    124 
    125 			if (bpp) {
    126 				if (flags & B_SYNC)
    127 					bwrite(*bpp);
    128 				else
    129 					bawrite(*bpp);
    130 			}
    131 			else {
    132 				/*
    133 				 * XXX the data in the frag might be
    134 				 * moving to a new disk location.
    135 				 * we need to flush pages to the
    136 				 * new disk locations.
    137 				 * XXX we could do this in realloccg
    138 				 * except for the sync flag.
    139 				 */
    140 				(vp->v_uvm.u_obj.pgops->pgo_flush)
    141 					(&vp->v_uvm.u_obj, lblktosize(fs, nb),
    142 					 lblktosize(fs, nb + 1),
    143 					 flags & B_SYNC ? PGO_SYNCIO : 0);
    144 			}
    145 		}
    146 	}
    147 	/*
    148 	 * The first NDADDR blocks are direct blocks
    149 	 */
    150 	if (lbn < NDADDR) {
    151 
    152 		nb = ufs_rw32(ip->i_ffs_db[lbn], UFS_MPNEEDSWAP(vp->v_mount));
    153 		if (nb != 0 && ip->i_ffs_size >= lblktosize(fs, lbn + 1)) {
    154 
    155 			/*
    156 			 * the block is an already-allocated direct block
    157 			 * and the file already extends past this block,
    158 			 * thus this must be a whole block.
    159 			 * just read the block (if requested).
    160 			 */
    161 
    162 			if (bpp != NULL) {
    163 				error = bread(vp, lbn, fs->fs_bsize, NOCRED,
    164 					      &bp);
    165 				if (error) {
    166 					brelse(bp);
    167 					return (error);
    168 				}
    169 				*bpp = bp;
    170 			}
    171 			if (blknop) {
    172 				*blknop = fsbtodb(fs, nb);
    173 			}
    174 			return (0);
    175 		}
    176 		if (nb != 0) {
    177 			/*
    178 			 * Consider need to reallocate a fragment.
    179 			 */
    180 			osize = fragroundup(fs, blkoff(fs, ip->i_ffs_size));
    181 			nsize = fragroundup(fs, size);
    182 			if (nsize <= osize) {
    183 
    184 				/*
    185 				 * the existing block is already
    186 				 * at least as big as we want.
    187 				 * just read the block (if requested).
    188 				 */
    189 
    190 				if (bpp != NULL) {
    191 					error = bread(vp, lbn, osize, NOCRED,
    192 						      &bp);
    193 					if (error) {
    194 						brelse(bp);
    195 						return (error);
    196 					}
    197 					*bpp = bp;
    198 				}
    199 				if (blknop) {
    200 					*blknop = fsbtodb(fs, nb);
    201 				}
    202 				return 0;
    203 			} else {
    204 
    205 				/*
    206 				 * the existing block is smaller than we want,
    207 				 * grow it.
    208 				 */
    209 
    210 				error = ffs_realloccg(ip, lbn,
    211 				    ffs_blkpref(ip, lbn, (int)lbn,
    212 					&ip->i_ffs_db[0]), osize, nsize, cred,
    213 					bpp, &newb);
    214 				if (error)
    215 					return (error);
    216 			}
    217 		} else {
    218 
    219 			/*
    220 			 * the block was not previously allocated,
    221 			 * allocate a new block or fragment.
    222 			 */
    223 
    224 			if (ip->i_ffs_size < lblktosize(fs, lbn + 1))
    225 				nsize = fragroundup(fs, size);
    226 			else
    227 				nsize = fs->fs_bsize;
    228 			error = ffs_alloc(ip, lbn,
    229 			    ffs_blkpref(ip, lbn, (int)lbn, &ip->i_ffs_db[0]),
    230 				nsize, cred, &newb);
    231 			if (error)
    232 				return (error);
    233 			if (bpp != NULL) {
    234 				bp = getblk(vp, lbn, nsize, 0, 0);
    235 				bp->b_blkno = fsbtodb(fs, newb);
    236 				if (flags & B_CLRBUF)
    237 					clrbuf(bp);
    238 				*bpp = bp;
    239 			}
    240 		}
    241 		ip->i_ffs_db[lbn] = ufs_rw32(newb, UFS_MPNEEDSWAP(vp->v_mount));
    242 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
    243 
    244 		if (blknop != NULL) {
    245 			*blknop = fsbtodb(fs, newb);
    246 		}
    247 		return (0);
    248 	}
    249 
    250 	/*
    251 	 * Determine the number of levels of indirection.
    252 	 */
    253 
    254 	pref = 0;
    255 	if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0)
    256 		return(error);
    257 #ifdef DIAGNOSTIC
    258 	if (num < 1)
    259 		panic ("ffs_balloc: ufs_bmaparray returned indirect block\n");
    260 #endif
    261 	/*
    262 	 * Fetch the first indirect block allocating if necessary.
    263 	 */
    264 	--num;
    265 	nb = ufs_rw32(ip->i_ffs_ib[indirs[0].in_off],
    266 	    UFS_MPNEEDSWAP(vp->v_mount));
    267 	allocib = NULL;
    268 	allocblk = allociblk;
    269 	if (nb == 0) {
    270 		pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
    271 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize,
    272 			cred, &newb);
    273 		if (error)
    274 			return (error);
    275 		nb = newb;
    276 		*allocblk++ = nb;
    277 		bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0);
    278 		bp->b_blkno = fsbtodb(fs, nb);
    279 		clrbuf(bp);
    280 		/*
    281 		 * Write synchronously so that indirect blocks
    282 		 * never point at garbage.
    283 		 */
    284 		if ((error = bwrite(bp)) != 0)
    285 			goto fail;
    286 		allocib = &ip->i_ffs_ib[indirs[0].in_off];
    287 		*allocib = ufs_rw32(nb, UFS_MPNEEDSWAP(vp->v_mount));
    288 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
    289 	}
    290 	/*
    291 	 * Fetch through the indirect blocks, allocating as necessary.
    292 	 */
    293 	for (i = 1;;) {
    294 		error = bread(vp,
    295 		    indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp);
    296 		if (error) {
    297 			brelse(bp);
    298 			goto fail;
    299 		}
    300 		bap = (ufs_daddr_t *)bp->b_data;
    301 		nb = ufs_rw32(bap[indirs[i].in_off],
    302 		    UFS_MPNEEDSWAP(vp->v_mount));
    303 		if (i == num)
    304 			break;
    305 		i += 1;
    306 		if (nb != 0) {
    307 			brelse(bp);
    308 			continue;
    309 		}
    310 		if (pref == 0)
    311 			pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
    312 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
    313 				  &newb);
    314 		if (error) {
    315 			brelse(bp);
    316 			goto fail;
    317 		}
    318 		nb = newb;
    319 		*allocblk++ = nb;
    320 		nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0);
    321 		nbp->b_blkno = fsbtodb(fs, nb);
    322 		clrbuf(nbp);
    323 		/*
    324 		 * Write synchronously so that indirect blocks
    325 		 * never point at garbage.
    326 		 */
    327 		if ((error = bwrite(nbp)) != 0) {
    328 			brelse(bp);
    329 			goto fail;
    330 		}
    331 		bap[indirs[i - 1].in_off] = ufs_rw32(nb,
    332 		    UFS_MPNEEDSWAP(vp->v_mount));
    333 		/*
    334 		 * If required, write synchronously, otherwise use
    335 		 * delayed write.
    336 		 */
    337 		if (flags & B_SYNC) {
    338 			bwrite(bp);
    339 		} else {
    340 			bdwrite(bp);
    341 		}
    342 	}
    343 	/*
    344 	 * Get the data block, allocating if necessary.
    345 	 */
    346 	if (nb == 0) {
    347 		pref = ffs_blkpref(ip, lbn, indirs[i].in_off, &bap[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 		bap[indirs[i].in_off] = ufs_rw32(nb,
    357 		    UFS_MPNEEDSWAP(vp->v_mount));
    358 		/*
    359 		 * If required, write synchronously, otherwise use
    360 		 * delayed write.
    361 		 */
    362 		if (flags & B_SYNC) {
    363 			bwrite(bp);
    364 		} else {
    365 			bdwrite(bp);
    366 		}
    367 		if (bpp != NULL) {
    368 			nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
    369 			nbp->b_blkno = fsbtodb(fs, nb);
    370 			if (flags & B_CLRBUF)
    371 				clrbuf(nbp);
    372 			*bpp = nbp;
    373 		}
    374 		if (blknop != NULL) {
    375 			*blknop = fsbtodb(fs, nb);
    376 		}
    377 		return (0);
    378 	}
    379 
    380 	brelse(bp);
    381 
    382 	if (bpp != NULL) {
    383 		if (flags & B_CLRBUF) {
    384 			error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp);
    385 			if (error) {
    386 				brelse(nbp);
    387 				goto fail;
    388 			}
    389 		} else {
    390 			nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
    391 			nbp->b_blkno = fsbtodb(fs, nb);
    392 			clrbuf(nbp);
    393 		}
    394 		*bpp = nbp;
    395 	}
    396 	if (blknop != NULL) {
    397 		*blknop = fsbtodb(fs, nb);
    398 	}
    399 	return (0);
    400 fail:
    401 	/*
    402 	 * If we have failed part way through block allocation, we
    403 	 * have to deallocate any indirect blocks that we have allocated.
    404 	 */
    405 	for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
    406 		ffs_blkfree(ip, *blkp, fs->fs_bsize);
    407 		deallocated += fs->fs_bsize;
    408 	}
    409 	if (allocib != NULL)
    410 		*allocib = 0;
    411 	if (deallocated) {
    412 #ifdef QUOTA
    413 		/*
    414 		 * Restore user's disk quota because allocation failed.
    415 		 */
    416 		(void)chkdq(ip, (long)-btodb(deallocated), cred, FORCE);
    417 #endif
    418 		ip->i_ffs_blocks -= btodb(deallocated);
    419 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
    420 	}
    421 	return (error);
    422 }
    423 
    424 int
    425 ffs_balloc_range(ip, off, len, cred, flags)
    426 	struct inode *ip;
    427 	off_t off, len;
    428 	struct ucred *cred;
    429 	int flags;
    430 {
    431 	struct fs *fs = ip->i_fs;
    432 	int lbn, bsize, delta, error;
    433 	off_t pagestart, pageend;
    434 
    435 	/*
    436 	 * pagestart and pageend describe the range of pages that are
    437 	 * completely covered by the range of blocks being allocated.
    438 	 */
    439 
    440 	pagestart = round_page(off);
    441 	pageend = trunc_page(off + len);
    442 
    443 	/*
    444 	 * adjust off to be block-aligned.
    445 	 */
    446 
    447 	delta = off - lblktosize(fs, lblkno(fs, off));
    448 	off -= delta;
    449 	len += delta;
    450 
    451 	while (len > 0) {
    452 		lbn = lblkno(fs, off);
    453 		bsize = min(fs->fs_bsize, len);
    454 
    455 		if ((error = ffs_balloc(ip, lbn, bsize, cred, NULL, NULL,
    456 					flags))) {
    457 			return error;
    458 		}
    459 
    460 		/*
    461 		 * bump file size now.
    462 		 * ffs_balloc() needs to know in the case where we loop here.
    463 		 */
    464 
    465 		if (ip->i_ffs_size < lblktosize(fs, lbn) + bsize) {
    466 			ip->i_ffs_size = lblktosize(fs, lbn) + bsize;
    467 			uvm_vnp_setsize(ip->i_vnode, ip->i_ffs_size);
    468 		}
    469 
    470 		len -= bsize;
    471 		off += bsize;
    472 	}
    473 	return 0;
    474 }
    475