1 /* 2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)ffs_balloc.c 7.25 (Berkeley) 02/02/93 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, bn, size, cred, bpp, flags) 32 register struct inode *ip; 33 register daddr_t bn; 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 int osize, nsize, num, j, error; 45 daddr_t newb, lbn, *bap, pref; 46 47 *bpp = (struct buf *)0; 48 if (bn < 0) 49 return (EFBIG); 50 fs = ip->i_fs; 51 lbn = bn; 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 < bn) { 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 |= IUPD|ICHG; 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 (bn < NDADDR) { 81 nb = ip->i_db[bn]; 82 if (nb != 0 && ip->i_size >= (bn + 1) * fs->fs_bsize) { 83 error = bread(vp, bn, 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, bn, osize, NOCRED, &bp); 99 if (error) { 100 brelse(bp); 101 return (error); 102 } 103 } else { 104 error = ffs_realloccg(ip, bn, 105 ffs_blkpref(ip, bn, (int)bn, &ip->i_db[0]), 106 osize, nsize, cred, &bp); 107 if (error) 108 return (error); 109 } 110 } else { 111 if (ip->i_size < (bn + 1) * fs->fs_bsize) 112 nsize = fragroundup(fs, size); 113 else 114 nsize = fs->fs_bsize; 115 error = ffs_alloc(ip, bn, 116 ffs_blkpref(ip, bn, (int)bn, &ip->i_db[0]), 117 nsize, cred, &newb); 118 if (error) 119 return (error); 120 bp = getblk(vp, bn, nsize, 0, 0); 121 bp->b_blkno = fsbtodb(fs, newb); 122 if (flags & B_CLRBUF) 123 clrbuf(bp); 124 } 125 ip->i_db[bn] = dbtofsb(fs, bp->b_blkno); 126 ip->i_flag |= IUPD|ICHG; 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, bn, 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 if (nb == 0) { 146 pref = ffs_blkpref(ip, lbn, 0, (daddr_t *)0); 147 if (error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, 148 cred, &newb)) 149 return (error); 150 nb = newb; 151 bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0); 152 bp->b_blkno = fsbtodb(fs, newb); 153 clrbuf(bp); 154 /* 155 * Write synchronously so that indirect blocks 156 * never point at garbage. 157 */ 158 if (error = bwrite(bp)) { 159 ffs_blkfree(ip, nb, fs->fs_bsize); 160 return (error); 161 } 162 ip->i_ib[indirs[0].in_off] = newb; 163 ip->i_flag |= IUPD|ICHG; 164 } 165 /* 166 * Fetch through the indirect blocks, allocating as necessary. 167 */ 168 for (j = 1; ; ) { 169 error = bread(vp, indirs[j].in_lbn, (int)fs->fs_bsize, NOCRED, 170 &bp); 171 if (error) { 172 brelse(bp); 173 return (error); 174 } 175 bap = bp->b_un.b_daddr; 176 nb = bap[indirs[j].in_off]; 177 if (j == num) 178 break; 179 j += 1; 180 if (nb != 0) { 181 brelse(bp); 182 continue; 183 } 184 if (pref == 0) 185 pref = ffs_blkpref(ip, lbn, 0, (daddr_t *)0); 186 if (error = 187 ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb)) { 188 brelse(bp); 189 return (error); 190 } 191 nb = newb; 192 nbp = getblk(vp, indirs[j].in_lbn, fs->fs_bsize, 0, 0); 193 nbp->b_blkno = fsbtodb(fs, nb); 194 clrbuf(nbp); 195 /* 196 * Write synchronously so that indirect blocks 197 * never point at garbage. 198 */ 199 if (error = bwrite(nbp)) { 200 ffs_blkfree(ip, nb, fs->fs_bsize); 201 brelse(bp); 202 return (error); 203 } 204 bap[indirs[j - 1].in_off] = nb; 205 /* 206 * If required, write synchronously, otherwise use 207 * delayed write. 208 */ 209 if (flags & B_SYNC) { 210 bwrite(bp); 211 } else { 212 bdwrite(bp); 213 } 214 } 215 /* 216 * Get the data block, allocating if necessary. 217 */ 218 if (nb == 0) { 219 pref = ffs_blkpref(ip, lbn, indirs[j].in_off, &bap[0]); 220 if (error = 221 ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb)) { 222 brelse(bp); 223 return (error); 224 } 225 nb = newb; 226 nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); 227 nbp->b_blkno = fsbtodb(fs, nb); 228 if (flags & B_CLRBUF) 229 clrbuf(nbp); 230 bap[indirs[j].in_off] = nb; 231 /* 232 * If required, write synchronously, otherwise use 233 * delayed write. 234 */ 235 if (flags & B_SYNC) { 236 bwrite(bp); 237 } else { 238 bdwrite(bp); 239 } 240 *bpp = nbp; 241 return (0); 242 } 243 brelse(bp); 244 if (flags & B_CLRBUF) { 245 error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp); 246 if (error) { 247 brelse(nbp); 248 return (error); 249 } 250 } else { 251 nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); 252 nbp->b_blkno = fsbtodb(fs, nb); 253 } 254 *bpp = nbp; 255 return (0); 256 } 257