1 /* 2 * Copyright (c) 1982, 1986, 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)ffs_balloc.c 8.8 (Berkeley) 06/16/95 8 */ 9 10 #include <sys/param.h> 11 #include <sys/systm.h> 12 #include <sys/buf.h> 13 #include <sys/proc.h> 14 #include <sys/file.h> 15 #include <sys/vnode.h> 16 17 #include <vm/vm.h> 18 19 #include <ufs/ufs/quota.h> 20 #include <ufs/ufs/inode.h> 21 #include <ufs/ufs/ufs_extern.h> 22 23 #include <ufs/ffs/fs.h> 24 #include <ufs/ffs/ffs_extern.h> 25 26 /* 27 * Balloc defines the structure of file system storage 28 * by allocating the physical blocks on a device given 29 * the inode and the logical block number in a file. 30 */ 31 ffs_balloc(ip, lbn, size, cred, bpp, flags) 32 register struct inode *ip; 33 register ufs_daddr_t lbn; 34 int size; 35 struct ucred *cred; 36 struct buf **bpp; 37 int flags; 38 { 39 register struct fs *fs; 40 register ufs_daddr_t nb; 41 struct buf *bp, *nbp; 42 struct vnode *vp = ITOV(ip); 43 struct indir indirs[NIADDR + 2]; 44 ufs_daddr_t newb, *bap, pref; 45 int deallocated, osize, nsize, num, i, error; 46 ufs_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1]; 47 48 *bpp = NULL; 49 if (lbn < 0) 50 return (EFBIG); 51 fs = ip->i_fs; 52 53 /* 54 * If the next write will extend the file into a new block, 55 * and the file is currently composed of a fragment 56 * this fragment has to be extended to be a full block. 57 */ 58 nb = lblkno(fs, ip->i_size); 59 if (nb < NDADDR && nb < lbn) { 60 osize = blksize(fs, ip, nb); 61 if (osize < fs->fs_bsize && osize > 0) { 62 error = ffs_realloccg(ip, nb, 63 ffs_blkpref(ip, nb, (int)nb, &ip->i_db[0]), 64 osize, (int)fs->fs_bsize, cred, &bp); 65 if (error) 66 return (error); 67 ip->i_size = (nb + 1) * fs->fs_bsize; 68 vnode_pager_setsize(vp, (u_long)ip->i_size); 69 ip->i_db[nb] = dbtofsb(fs, bp->b_blkno); 70 ip->i_flag |= IN_CHANGE | IN_UPDATE; 71 if (flags & B_SYNC) 72 bwrite(bp); 73 else 74 bawrite(bp); 75 } 76 } 77 /* 78 * The first NDADDR blocks are direct blocks 79 */ 80 if (lbn < NDADDR) { 81 nb = ip->i_db[lbn]; 82 if (nb != 0 && ip->i_size >= (lbn + 1) * fs->fs_bsize) { 83 error = bread(vp, lbn, fs->fs_bsize, NOCRED, &bp); 84 if (error) { 85 brelse(bp); 86 return (error); 87 } 88 *bpp = bp; 89 return (0); 90 } 91 if (nb != 0) { 92 /* 93 * Consider need to reallocate a fragment. 94 */ 95 osize = fragroundup(fs, blkoff(fs, ip->i_size)); 96 nsize = fragroundup(fs, size); 97 if (nsize <= osize) { 98 error = bread(vp, lbn, osize, NOCRED, &bp); 99 if (error) { 100 brelse(bp); 101 return (error); 102 } 103 } else { 104 error = ffs_realloccg(ip, lbn, 105 ffs_blkpref(ip, lbn, (int)lbn, 106 &ip->i_db[0]), osize, nsize, cred, &bp); 107 if (error) 108 return (error); 109 } 110 } else { 111 if (ip->i_size < (lbn + 1) * fs->fs_bsize) 112 nsize = fragroundup(fs, size); 113 else 114 nsize = fs->fs_bsize; 115 error = ffs_alloc(ip, lbn, 116 ffs_blkpref(ip, lbn, (int)lbn, &ip->i_db[0]), 117 nsize, cred, &newb); 118 if (error) 119 return (error); 120 bp = getblk(vp, lbn, nsize, 0, 0); 121 bp->b_blkno = fsbtodb(fs, newb); 122 if (flags & B_CLRBUF) 123 clrbuf(bp); 124 } 125 ip->i_db[lbn] = dbtofsb(fs, bp->b_blkno); 126 ip->i_flag |= IN_CHANGE | IN_UPDATE; 127 *bpp = bp; 128 return (0); 129 } 130 /* 131 * Determine the number of levels of indirection. 132 */ 133 pref = 0; 134 if (error = ufs_getlbns(vp, lbn, indirs, &num)) 135 return(error); 136 #ifdef DIAGNOSTIC 137 if (num < 1) 138 panic ("ffs_balloc: ufs_bmaparray returned indirect block\n"); 139 #endif 140 /* 141 * Fetch the first indirect block allocating if necessary. 142 */ 143 --num; 144 nb = ip->i_ib[indirs[0].in_off]; 145 allocib = NULL; 146 allocblk = allociblk; 147 if (nb == 0) { 148 pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0); 149 if (error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, 150 cred, &newb)) 151 return (error); 152 nb = newb; 153 *allocblk++ = nb; 154 bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0); 155 bp->b_blkno = fsbtodb(fs, nb); 156 clrbuf(bp); 157 /* 158 * Write synchronously so that indirect blocks 159 * never point at garbage. 160 */ 161 if (error = bwrite(bp)) 162 goto fail; 163 allocib = &ip->i_ib[indirs[0].in_off]; 164 *allocib = nb; 165 ip->i_flag |= IN_CHANGE | IN_UPDATE; 166 } 167 /* 168 * Fetch through the indirect blocks, allocating as necessary. 169 */ 170 for (i = 1;;) { 171 error = bread(vp, 172 indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp); 173 if (error) { 174 brelse(bp); 175 goto fail; 176 } 177 bap = (ufs_daddr_t *)bp->b_data; 178 nb = bap[indirs[i].in_off]; 179 if (i == num) 180 break; 181 i += 1; 182 if (nb != 0) { 183 brelse(bp); 184 continue; 185 } 186 if (pref == 0) 187 pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0); 188 if (error = 189 ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb)) { 190 brelse(bp); 191 goto fail; 192 } 193 nb = newb; 194 *allocblk++ = nb; 195 nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0); 196 nbp->b_blkno = fsbtodb(fs, nb); 197 clrbuf(nbp); 198 /* 199 * Write synchronously so that indirect blocks 200 * never point at garbage. 201 */ 202 if (error = bwrite(nbp)) { 203 brelse(bp); 204 goto fail; 205 } 206 bap[indirs[i - 1].in_off] = nb; 207 /* 208 * If required, write synchronously, otherwise use 209 * delayed write. 210 */ 211 if (flags & B_SYNC) { 212 bwrite(bp); 213 } else { 214 bdwrite(bp); 215 } 216 } 217 /* 218 * Get the data block, allocating if necessary. 219 */ 220 if (nb == 0) { 221 pref = ffs_blkpref(ip, lbn, indirs[i].in_off, &bap[0]); 222 if (error = ffs_alloc(ip, 223 lbn, pref, (int)fs->fs_bsize, cred, &newb)) { 224 brelse(bp); 225 goto fail; 226 } 227 nb = newb; 228 *allocblk++ = nb; 229 nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); 230 nbp->b_blkno = fsbtodb(fs, nb); 231 if (flags & B_CLRBUF) 232 clrbuf(nbp); 233 bap[indirs[i].in_off] = nb; 234 /* 235 * If required, write synchronously, otherwise use 236 * delayed write. 237 */ 238 if (flags & B_SYNC) { 239 bwrite(bp); 240 } else { 241 bdwrite(bp); 242 } 243 *bpp = nbp; 244 return (0); 245 } 246 brelse(bp); 247 if (flags & B_CLRBUF) { 248 error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp); 249 if (error) { 250 brelse(nbp); 251 goto fail; 252 } 253 } else { 254 nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); 255 nbp->b_blkno = fsbtodb(fs, nb); 256 } 257 *bpp = nbp; 258 return (0); 259 fail: 260 /* 261 * If we have failed part way through block allocation, we 262 * have to deallocate any indirect blocks that we have allocated. 263 */ 264 for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) { 265 ffs_blkfree(ip, *blkp, fs->fs_bsize); 266 deallocated += fs->fs_bsize; 267 } 268 if (allocib != NULL) 269 *allocib = 0; 270 if (deallocated) { 271 #ifdef QUOTA 272 /* 273 * Restore user's disk quota because allocation failed. 274 */ 275 (void) chkdq(ip, (long)-btodb(deallocated), cred, FORCE); 276 #endif 277 ip->i_blocks -= btodb(deallocated); 278 ip->i_flag |= IN_CHANGE | IN_UPDATE; 279 } 280 return (error); 281 } 282