ffs_balloc.c revision 32286
1/* 2 * Copyright (c) 1982, 1986, 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)ffs_balloc.c 8.8 (Berkeley) 6/16/95 34 * $Id: ffs_balloc.c,v 1.16 1997/12/05 19:55:49 bde Exp $ 35 */ 36 37#include <sys/param.h> 38#include <sys/systm.h> 39#include <sys/buf.h> 40#include <sys/lock.h> 41#include <sys/vnode.h> 42 43#include <ufs/ufs/quota.h> 44#include <ufs/ufs/inode.h> 45#include <ufs/ufs/ufs_extern.h> 46 47#include <ufs/ffs/fs.h> 48#include <ufs/ffs/ffs_extern.h> 49 50/* 51 * Balloc defines the structure of file system storage 52 * by allocating the physical blocks on a device given 53 * the inode and the logical block number in a file. 54 */ 55int 56ffs_balloc(ip, lbn, size, cred, bpp, flags) 57 register struct inode *ip; 58 register ufs_daddr_t lbn; 59 int size; 60 struct ucred *cred; 61 struct buf **bpp; 62 int flags; 63{ 64 register struct fs *fs; 65 register ufs_daddr_t nb; 66 struct buf *bp, *nbp; 67 struct vnode *vp = ITOV(ip); 68 struct indir indirs[NIADDR + 2]; 69 ufs_daddr_t newb, *bap, pref; 70 int deallocated, osize, nsize, num, i, error; 71 ufs_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1]; 72 73 *bpp = NULL; 74 if (lbn < 0) 75 return (EFBIG); 76 fs = ip->i_fs; 77 78 /* 79 * If the next write will extend the file into a new block, 80 * and the file is currently composed of a fragment 81 * this fragment has to be extended to be a full block. 82 */ 83 nb = lblkno(fs, ip->i_size); 84 if (nb < NDADDR && nb < lbn) { 85 osize = blksize(fs, ip, nb); 86 if (osize < fs->fs_bsize && osize > 0) { 87 error = ffs_realloccg(ip, nb, 88 ffs_blkpref(ip, nb, (int)nb, &ip->i_db[0]), 89 osize, (int)fs->fs_bsize, cred, &bp); 90 if (error) 91 return (error); 92 ip->i_size = smalllblktosize(fs, nb + 1); 93 ip->i_db[nb] = dbtofsb(fs, bp->b_blkno); 94 ip->i_flag |= IN_CHANGE | IN_UPDATE; 95 if (flags & B_SYNC) 96 bwrite(bp); 97 else 98 bawrite(bp); 99 } 100 } 101 /* 102 * The first NDADDR blocks are direct blocks 103 */ 104 if (lbn < NDADDR) { 105 nb = ip->i_db[lbn]; 106 if (nb != 0 && ip->i_size >= smalllblktosize(fs, lbn + 1)) { 107 error = bread(vp, lbn, fs->fs_bsize, NOCRED, &bp); 108 if (error) { 109 brelse(bp); 110 return (error); 111 } 112 bp->b_blkno = fsbtodb(fs, nb); 113 *bpp = bp; 114 return (0); 115 } 116 if (nb != 0) { 117 /* 118 * Consider need to reallocate a fragment. 119 */ 120 osize = fragroundup(fs, blkoff(fs, ip->i_size)); 121 nsize = fragroundup(fs, size); 122 if (nsize <= osize) { 123 error = bread(vp, lbn, osize, NOCRED, &bp); 124 if (error) { 125 brelse(bp); 126 return (error); 127 } 128 bp->b_blkno = fsbtodb(fs, nb); 129 } else { 130 error = ffs_realloccg(ip, lbn, 131 ffs_blkpref(ip, lbn, (int)lbn, 132 &ip->i_db[0]), osize, nsize, cred, &bp); 133 if (error) 134 return (error); 135 } 136 } else { 137 if (ip->i_size < smalllblktosize(fs, lbn + 1)) 138 nsize = fragroundup(fs, size); 139 else 140 nsize = fs->fs_bsize; 141 error = ffs_alloc(ip, lbn, 142 ffs_blkpref(ip, lbn, (int)lbn, &ip->i_db[0]), 143 nsize, cred, &newb); 144 if (error) 145 return (error); 146 bp = getblk(vp, lbn, nsize, 0, 0); 147 bp->b_blkno = fsbtodb(fs, newb); 148 if (flags & B_CLRBUF) 149 vfs_bio_clrbuf(bp); 150 } 151 ip->i_db[lbn] = dbtofsb(fs, bp->b_blkno); 152 ip->i_flag |= IN_CHANGE | IN_UPDATE; 153 *bpp = bp; 154 return (0); 155 } 156 /* 157 * Determine the number of levels of indirection. 158 */ 159 pref = 0; 160 if (error = ufs_getlbns(vp, lbn, indirs, &num)) 161 return(error); 162#ifdef DIAGNOSTIC 163 if (num < 1) 164 panic ("ffs_balloc: ufs_bmaparray returned indirect block"); 165#endif 166 /* 167 * Fetch the first indirect block allocating if necessary. 168 */ 169 --num; 170 nb = ip->i_ib[indirs[0].in_off]; 171 allocib = NULL; 172 allocblk = allociblk; 173 if (nb == 0) { 174 pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0); 175 if (error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, 176 cred, &newb)) 177 return (error); 178 nb = newb; 179 *allocblk++ = nb; 180 bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0); 181 bp->b_blkno = fsbtodb(fs, nb); 182 vfs_bio_clrbuf(bp); 183 /* 184 * Write synchronously so that indirect blocks 185 * never point at garbage. 186 */ 187 if (error = bwrite(bp)) 188 goto fail; 189 allocib = &ip->i_ib[indirs[0].in_off]; 190 *allocib = nb; 191 ip->i_flag |= IN_CHANGE | IN_UPDATE; 192 } 193 /* 194 * Fetch through the indirect blocks, allocating as necessary. 195 */ 196 for (i = 1;;) { 197 error = bread(vp, 198 indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp); 199 if (error) { 200 brelse(bp); 201 goto fail; 202 } 203 bap = (ufs_daddr_t *)bp->b_data; 204 nb = bap[indirs[i].in_off]; 205 if (i == num) 206 break; 207 i += 1; 208 if (nb != 0) { 209 bqrelse(bp); 210 continue; 211 } 212 if (pref == 0) 213 pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0); 214 if (error = 215 ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb)) { 216 brelse(bp); 217 goto fail; 218 } 219 nb = newb; 220 *allocblk++ = nb; 221 nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0); 222 nbp->b_blkno = fsbtodb(fs, nb); 223 vfs_bio_clrbuf(nbp); 224 /* 225 * Write synchronously so that indirect blocks 226 * never point at garbage. 227 */ 228 if (error = bwrite(nbp)) { 229 brelse(bp); 230 goto fail; 231 } 232 bap[indirs[i - 1].in_off] = nb; 233 /* 234 * If required, write synchronously, otherwise use 235 * delayed write. 236 */ 237 if (flags & B_SYNC) { 238 bwrite(bp); 239 } else { 240 if (bp->b_bufsize == fs->fs_bsize) 241 bp->b_flags |= B_CLUSTEROK; 242 bdwrite(bp); 243 } 244 } 245 /* 246 * Get the data block, allocating if necessary. 247 */ 248 if (nb == 0) { 249 pref = ffs_blkpref(ip, lbn, indirs[i].in_off, &bap[0]); 250 error = ffs_alloc(ip, 251 lbn, pref, (int)fs->fs_bsize, cred, &newb); 252 if (error) { 253 brelse(bp); 254 goto fail; 255 } 256 nb = newb; 257 *allocblk++ = nb; 258 nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); 259 nbp->b_blkno = fsbtodb(fs, nb); 260 if (flags & B_CLRBUF) 261 vfs_bio_clrbuf(nbp); 262 bap[indirs[i].in_off] = nb; 263 /* 264 * If required, write synchronously, otherwise use 265 * delayed write. 266 */ 267 if (flags & B_SYNC) { 268 bwrite(bp); 269 } else { 270 if (bp->b_bufsize == fs->fs_bsize) 271 bp->b_flags |= B_CLUSTEROK; 272 bdwrite(bp); 273 } 274 *bpp = nbp; 275 return (0); 276 } 277 brelse(bp); 278 if (flags & B_CLRBUF) { 279 error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp); 280 if (error) { 281 brelse(nbp); 282 goto fail; 283 } 284 } else { 285 nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); 286 nbp->b_blkno = fsbtodb(fs, nb); 287 } 288 *bpp = nbp; 289 return (0); 290fail: 291 /* 292 * If we have failed part way through block allocation, we 293 * have to deallocate any indirect blocks that we have allocated. 294 */ 295 for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) { 296 ffs_blkfree(ip, *blkp, fs->fs_bsize); 297 deallocated += fs->fs_bsize; 298 } 299 if (allocib != NULL) 300 *allocib = 0; 301 if (deallocated) { 302#ifdef QUOTA 303 /* 304 * Restore user's disk quota because allocation failed. 305 */ 306 (void) chkdq(ip, (long)-btodb(deallocated), cred, FORCE); 307#endif 308 ip->i_blocks -= btodb(deallocated); 309 ip->i_flag |= IN_CHANGE | IN_UPDATE; 310 } 311 return (error); 312} 313