1 /* $NetBSD: ffs_balloc.c,v 1.9 2002/01/31 22:44:04 tv 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. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)ffs_balloc.c 8.8 (Berkeley) 6/16/95 37 */ 38 39 #include <sys/cdefs.h> 40 #if defined(__RCSID) && !defined(__lint) 41 __RCSID("$NetBSD: ffs_balloc.c,v 1.9 2002/01/31 22:44:04 tv Exp $"); 42 #endif /* !__lint */ 43 44 #include <sys/param.h> 45 #include <sys/time.h> 46 47 #include <assert.h> 48 #include <errno.h> 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <string.h> 52 53 #include "makefs.h" 54 55 #include <ufs/ufs/dinode.h> 56 #include <ufs/ufs/ufs_bswap.h> 57 #include <ufs/ffs/fs.h> 58 59 #include "ffs/buf.h" 60 #include "ffs/ufs_inode.h" 61 #include "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 * Assume: flags == B_SYNC | B_CLRBUF 69 */ 70 int 71 ffs_balloc(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) 72 { 73 ufs_daddr_t lbn; 74 int size; 75 ufs_daddr_t nb; 76 struct buf *bp, *nbp; 77 struct fs *fs = ip->i_fs; 78 struct indir indirs[NIADDR + 2]; 79 ufs_daddr_t newb, *bap, pref; 80 int osize, nsize, num, i, error; 81 ufs_daddr_t *allocib, *allocblk, allociblk[NIADDR + 1]; 82 const int needswap = UFS_FSNEEDSWAP(fs); 83 84 lbn = lblkno(fs, offset); 85 size = blkoff(fs, offset) + bufsize; 86 if (bpp != NULL) { 87 *bpp = NULL; 88 } 89 90 assert(size <= fs->fs_bsize); 91 if (lbn < 0) 92 return (EFBIG); 93 94 /* 95 * If the next write will extend the file into a new block, 96 * and the file is currently composed of a fragment 97 * this fragment has to be extended to be a full block. 98 */ 99 100 nb = lblkno(fs, ip->i_ffs_size); 101 if (nb < NDADDR && nb < lbn) { 102 osize = blksize(fs, ip, nb); 103 if (osize < fs->fs_bsize && osize > 0) { 104 warnx("need to ffs_realloccg; not supported!"); 105 abort(); 106 } 107 } 108 109 /* 110 * The first NDADDR blocks are direct blocks 111 */ 112 113 if (lbn < NDADDR) { 114 nb = ufs_rw32(ip->i_ffs_db[lbn], needswap); 115 if (nb != 0 && ip->i_ffs_size >= lblktosize(fs, lbn + 1)) { 116 117 /* 118 * The block is an already-allocated direct block 119 * and the file already extends past this block, 120 * thus this must be a whole block. 121 * Just read the block (if requested). 122 */ 123 124 if (bpp != NULL) { 125 error = bread(ip->i_fd, ip->i_fs, lbn, 126 fs->fs_bsize, bpp); 127 if (error) { 128 brelse(*bpp); 129 return (error); 130 } 131 } 132 return (0); 133 } 134 if (nb != 0) { 135 136 /* 137 * Consider need to reallocate a fragment. 138 */ 139 140 osize = fragroundup(fs, blkoff(fs, ip->i_ffs_size)); 141 nsize = fragroundup(fs, size); 142 if (nsize <= osize) { 143 144 /* 145 * The existing block is already 146 * at least as big as we want. 147 * Just read the block (if requested). 148 */ 149 150 if (bpp != NULL) { 151 error = bread(ip->i_fd, ip->i_fs, lbn, 152 osize, bpp); 153 if (error) { 154 brelse(*bpp); 155 return (error); 156 } 157 } 158 return 0; 159 } else { 160 warnx("need to ffs_realloccg; not supported!"); 161 abort(); 162 } 163 } else { 164 165 /* 166 * the block was not previously allocated, 167 * allocate a new block or fragment. 168 */ 169 170 if (ip->i_ffs_size < lblktosize(fs, lbn + 1)) 171 nsize = fragroundup(fs, size); 172 else 173 nsize = fs->fs_bsize; 174 error = ffs_alloc(ip, lbn, 175 ffs_blkpref(ip, lbn, (int)lbn, &ip->i_ffs_db[0]), 176 nsize, &newb); 177 if (error) 178 return (error); 179 if (bpp != NULL) { 180 bp = getblk(ip->i_fd, ip->i_fs, lbn, nsize); 181 bp->b_blkno = fsbtodb(fs, newb); 182 clrbuf(bp); 183 *bpp = bp; 184 } 185 } 186 ip->i_ffs_db[lbn] = ufs_rw32(newb, needswap); 187 return (0); 188 } 189 /* 190 * Determine the number of levels of indirection. 191 */ 192 pref = 0; 193 if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0) 194 return(error); 195 196 if (num < 1) { 197 warnx("ffs_balloc: ufs_getlbns returned indirect block"); 198 abort(); 199 } 200 /* 201 * Fetch the first indirect block allocating if necessary. 202 */ 203 --num; 204 nb = ufs_rw32(ip->i_ffs_ib[indirs[0].in_off], needswap); 205 allocib = NULL; 206 allocblk = allociblk; 207 if (nb == 0) { 208 pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0); 209 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb); 210 if (error) 211 return (error); 212 nb = newb; 213 *allocblk++ = nb; 214 bp = getblk(ip->i_fd, ip->i_fs, indirs[1].in_lbn, fs->fs_bsize); 215 bp->b_blkno = fsbtodb(fs, nb); 216 clrbuf(bp); 217 /* 218 * Write synchronously so that indirect blocks 219 * never point at garbage. 220 */ 221 if ((error = bwrite(bp)) != 0) 222 goto fail; 223 allocib = &ip->i_ffs_ib[indirs[0].in_off]; 224 *allocib = ufs_rw32(nb, needswap); 225 } 226 /* 227 * Fetch through the indirect blocks, allocating as necessary. 228 */ 229 for (i = 1;;) { 230 error = bread(ip->i_fd, ip->i_fs, indirs[i].in_lbn, 231 (int)fs->fs_bsize, &bp); 232 if (error) { 233 brelse(bp); 234 goto fail; 235 } 236 bap = (ufs_daddr_t *)bp->b_data; 237 nb = ufs_rw32(bap[indirs[i].in_off], needswap); 238 if (i == num) 239 break; 240 i++; 241 if (nb != 0) { 242 brelse(bp); 243 continue; 244 } 245 if (pref == 0) 246 pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0); 247 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb); 248 if (error) { 249 brelse(bp); 250 goto fail; 251 } 252 nb = newb; 253 *allocblk++ = nb; 254 nbp = getblk(ip->i_fd, ip->i_fs, indirs[i].in_lbn, 255 fs->fs_bsize); 256 nbp->b_blkno = fsbtodb(fs, nb); 257 clrbuf(nbp); 258 /* 259 * Write synchronously so that indirect blocks 260 * never point at garbage. 261 */ 262 if ((error = bwrite(nbp)) != 0) { 263 brelse(bp); 264 goto fail; 265 } 266 bap[indirs[i - 1].in_off] = ufs_rw32(nb, needswap); 267 /* 268 * If required, write synchronously, otherwise use 269 * delayed write. 270 */ 271 bwrite(bp); 272 } 273 /* 274 * Get the data block, allocating if necessary. 275 */ 276 if (nb == 0) { 277 pref = ffs_blkpref(ip, lbn, indirs[num].in_off, &bap[0]); 278 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb); 279 if (error) { 280 brelse(bp); 281 goto fail; 282 } 283 nb = newb; 284 *allocblk++ = nb; 285 if (bpp != NULL) { 286 nbp = getblk(ip->i_fd, ip->i_fs, lbn, fs->fs_bsize); 287 nbp->b_blkno = fsbtodb(fs, nb); 288 clrbuf(nbp); 289 *bpp = nbp; 290 } 291 bap[indirs[num].in_off] = ufs_rw32(nb, needswap); 292 /* 293 * If required, write synchronously, otherwise use 294 * delayed write. 295 */ 296 bwrite(bp); 297 return (0); 298 } 299 brelse(bp); 300 if (bpp != NULL) { 301 error = bread(ip->i_fd, ip->i_fs, lbn, 302 (int)fs->fs_bsize, &nbp); 303 if (error) { 304 brelse(nbp); 305 goto fail; 306 } 307 *bpp = nbp; 308 } 309 return (0); 310 fail: 311 return (error); 312 } 313