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.5 (Berkeley) 01/07/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 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 daddr_t nb; 41 struct buf *bp, *nbp; 42 struct vnode *vp = ITOV(ip); 43 struct indir indirs[NIADDR + 2]; 44 daddr_t newb, *bap, pref; 45 int osize, nsize, num, i, error; 46 47 *bpp = NULL; 48 if (lbn < 0) 49 return (EFBIG); 50 fs = ip->i_fs; 51 52 /* 53 * If the next write will extend the file into a new block, 54 * and the file is currently composed of a fragment 55 * this fragment has to be extended to be a full block. 56 */ 57 nb = lblkno(fs, ip->i_size); 58 if (nb < NDADDR && nb < lbn) { 59 osize = blksize(fs, ip, nb); 60 if (osize < fs->fs_bsize && osize > 0) { 61 error = ffs_realloccg(ip, nb, 62 ffs_blkpref(ip, nb, (int)nb, &ip->i_db[0]), 63 osize, (int)fs->fs_bsize, cred, &bp); 64 if (error) 65 return (error); 66 ip->i_size = (nb + 1) * fs->fs_bsize; 67 vnode_pager_setsize(vp, (u_long)ip->i_size); 68 ip->i_db[nb] = dbtofsb(fs, bp->b_blkno); 69 ip->i_flag |= IN_CHANGE | IN_UPDATE; 70 if (flags & B_SYNC) 71 bwrite(bp); 72 else 73 bawrite(bp); 74 } 75 } 76 /* 77 * The first NDADDR blocks are direct blocks 78 */ 79 if (lbn < NDADDR) { 80 nb = ip->i_db[lbn]; 81 if (nb != 0 && ip->i_size >= (lbn + 1) * fs->fs_bsize) { 82 error = bread(vp, lbn, fs->fs_bsize, NOCRED, &bp); 83 if (error) { 84 brelse(bp); 85 return (error); 86 } 87 *bpp = bp; 88 return (0); 89 } 90 if (nb != 0) { 91 /* 92 * Consider need to reallocate a fragment. 93 */ 94 osize = fragroundup(fs, blkoff(fs, ip->i_size)); 95 nsize = fragroundup(fs, size); 96 if (nsize <= osize) { 97 error = bread(vp, lbn, osize, NOCRED, &bp); 98 if (error) { 99 brelse(bp); 100 return (error); 101 } 102 } else { 103 error = ffs_realloccg(ip, lbn, 104 ffs_blkpref(ip, lbn, (int)lbn, 105 &ip->i_db[0]), osize, nsize, cred, &bp); 106 if (error) 107 return (error); 108 } 109 } else { 110 if (ip->i_size < (lbn + 1) * fs->fs_bsize) 111 nsize = fragroundup(fs, size); 112 else 113 nsize = fs->fs_bsize; 114 error = ffs_alloc(ip, lbn, 115 ffs_blkpref(ip, lbn, (int)lbn, &ip->i_db[0]), 116 nsize, cred, &newb); 117 if (error) 118 return (error); 119 bp = getblk(vp, lbn, nsize, 0, 0); 120 bp->b_blkno = fsbtodb(fs, newb); 121 if (flags & B_CLRBUF) 122 clrbuf(bp); 123 } 124 ip->i_db[lbn] = dbtofsb(fs, bp->b_blkno); 125 ip->i_flag |= IN_CHANGE | IN_UPDATE; 126 *bpp = bp; 127 return (0); 128 } 129 /* 130 * Determine the number of levels of indirection. 131 */ 132 pref = 0; 133 if (error = ufs_getlbns(vp, lbn, indirs, &num)) 134 return(error); 135 #ifdef DIAGNOSTIC 136 if (num < 1) 137 panic ("ffs_balloc: ufs_bmaparray returned indirect block\n"); 138 #endif 139 /* 140 * Fetch the first indirect block allocating if necessary. 141 */ 142 --num; 143 nb = ip->i_ib[indirs[0].in_off]; 144 if (nb == 0) { 145 pref = ffs_blkpref(ip, lbn, 0, (daddr_t *)0); 146 if (error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, 147 cred, &newb)) 148 return (error); 149 nb = newb; 150 bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0); 151 bp->b_blkno = fsbtodb(fs, newb); 152 clrbuf(bp); 153 /* 154 * Write synchronously so that indirect blocks 155 * never point at garbage. 156 */ 157 if (error = bwrite(bp)) { 158 ffs_blkfree(ip, nb, fs->fs_bsize); 159 return (error); 160 } 161 ip->i_ib[indirs[0].in_off] = newb; 162 ip->i_flag |= IN_CHANGE | IN_UPDATE; 163 } 164 /* 165 * Fetch through the indirect blocks, allocating as necessary. 166 */ 167 for (i = 1;;) { 168 error = bread(vp, 169 indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp); 170 if (error) { 171 brelse(bp); 172 return (error); 173 } 174 bap = (daddr_t *)bp->b_data; 175 nb = bap[indirs[i].in_off]; 176 if (i == num) 177 break; 178 i += 1; 179 if (nb != 0) { 180 brelse(bp); 181 continue; 182 } 183 if (pref == 0) 184 pref = ffs_blkpref(ip, lbn, 0, (daddr_t *)0); 185 if (error = 186 ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb)) { 187 brelse(bp); 188 return (error); 189 } 190 nb = newb; 191 nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0); 192 nbp->b_blkno = fsbtodb(fs, nb); 193 clrbuf(nbp); 194 /* 195 * Write synchronously so that indirect blocks 196 * never point at garbage. 197 */ 198 if (error = bwrite(nbp)) { 199 ffs_blkfree(ip, nb, fs->fs_bsize); 200 brelse(bp); 201 return (error); 202 } 203 bap[indirs[i - 1].in_off] = nb; 204 /* 205 * If required, write synchronously, otherwise use 206 * delayed write. 207 */ 208 if (flags & B_SYNC) { 209 bwrite(bp); 210 } else { 211 bdwrite(bp); 212 } 213 } 214 /* 215 * Get the data block, allocating if necessary. 216 */ 217 if (nb == 0) { 218 pref = ffs_blkpref(ip, lbn, indirs[i].in_off, &bap[0]); 219 if (error = ffs_alloc(ip, 220 lbn, pref, (int)fs->fs_bsize, cred, &newb)) { 221 brelse(bp); 222 return (error); 223 } 224 nb = newb; 225 nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); 226 nbp->b_blkno = fsbtodb(fs, nb); 227 if (flags & B_CLRBUF) 228 clrbuf(nbp); 229 bap[indirs[i].in_off] = nb; 230 /* 231 * If required, write synchronously, otherwise use 232 * delayed write. 233 */ 234 if (flags & B_SYNC) { 235 bwrite(bp); 236 } else { 237 bdwrite(bp); 238 } 239 *bpp = nbp; 240 return (0); 241 } 242 brelse(bp); 243 if (flags & B_CLRBUF) { 244 error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp); 245 if (error) { 246 brelse(nbp); 247 return (error); 248 } 249 } else { 250 nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); 251 nbp->b_blkno = fsbtodb(fs, nb); 252 } 253 *bpp = nbp; 254 return (0); 255 } 256