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.18 (Berkeley) 05/04/92 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 22 #include <ufs/ffs/fs.h> 23 #include <ufs/ffs/ffs_extern.h> 24 25 /* 26 * Bmap converts a the logical block number of a file 27 * to its physical block number on the disk. The conversion 28 * is done by using the logical block number to index into 29 * the array of block pointers described by the dinode. 30 */ 31 int 32 ffs_bmap(vp, bn, vpp, bnp) 33 struct vnode *vp; 34 register daddr_t bn; 35 struct vnode **vpp; 36 daddr_t *bnp; 37 { 38 register struct inode *ip; 39 register struct fs *fs; 40 register daddr_t nb; 41 struct buf *bp; 42 daddr_t *bap; 43 int i, j, sh; 44 int error; 45 46 /* 47 * Check for underlying vnode requests and ensure that logical 48 * to physical mapping is requested. 49 */ 50 ip = VTOI(vp); 51 if (vpp != NULL) 52 *vpp = ip->i_devvp; 53 if (bnp == NULL) 54 return (0); 55 if (bn < 0) 56 return (EFBIG); 57 fs = ip->i_fs; 58 59 /* 60 * The first NDADDR blocks are direct blocks 61 */ 62 if (bn < NDADDR) { 63 nb = ip->i_db[bn]; 64 if (nb == 0) { 65 *bnp = (daddr_t)-1; 66 return (0); 67 } 68 *bnp = fsbtodb(fs, nb); 69 return (0); 70 } 71 /* 72 * Determine the number of levels of indirection. 73 */ 74 sh = 1; 75 bn -= NDADDR; 76 for (j = NIADDR; j > 0; j--) { 77 sh *= NINDIR(fs); 78 if (bn < sh) 79 break; 80 bn -= sh; 81 } 82 if (j == 0) 83 return (EFBIG); 84 /* 85 * Fetch through the indirect blocks. 86 */ 87 nb = ip->i_ib[NIADDR - j]; 88 if (nb == 0) { 89 *bnp = (daddr_t)-1; 90 return (0); 91 } 92 for (; j <= NIADDR; j++) { 93 if (error = bread(ip->i_devvp, fsbtodb(fs, nb), 94 (int)fs->fs_bsize, NOCRED, &bp)) { 95 brelse(bp); 96 return (error); 97 } 98 bap = bp->b_un.b_daddr; 99 sh /= NINDIR(fs); 100 i = (bn / sh) % NINDIR(fs); 101 nb = bap[i]; 102 if (nb == 0) { 103 *bnp = (daddr_t)-1; 104 brelse(bp); 105 return (0); 106 } 107 brelse(bp); 108 } 109 *bnp = fsbtodb(fs, nb); 110 return (0); 111 } 112 113 /* 114 * Balloc defines the structure of file system storage 115 * by allocating the physical blocks on a device given 116 * the inode and the logical block number in a file. 117 */ 118 ffs_balloc(ip, bn, size, cred, bpp, flags) 119 register struct inode *ip; 120 register daddr_t bn; 121 int size; 122 struct ucred *cred; 123 struct buf **bpp; 124 int flags; 125 { 126 register struct fs *fs; 127 register daddr_t nb; 128 struct buf *bp, *nbp; 129 struct vnode *vp = ITOV(ip); 130 int osize, nsize, i, j, sh, error; 131 daddr_t newb, lbn, *bap, pref; 132 133 *bpp = (struct buf *)0; 134 if (bn < 0) 135 return (EFBIG); 136 fs = ip->i_fs; 137 138 /* 139 * If the next write will extend the file into a new block, 140 * and the file is currently composed of a fragment 141 * this fragment has to be extended to be a full block. 142 */ 143 nb = lblkno(fs, ip->i_size); 144 if (nb < NDADDR && nb < bn) { 145 osize = blksize(fs, ip, nb); 146 if (osize < fs->fs_bsize && osize > 0) { 147 error = ffs_realloccg(ip, nb, 148 ffs_blkpref(ip, nb, (int)nb, &ip->i_db[0]), 149 osize, (int)fs->fs_bsize, cred, &bp); 150 if (error) 151 return (error); 152 ip->i_size = (nb + 1) * fs->fs_bsize; 153 vnode_pager_setsize(vp, (u_long)ip->i_size); 154 ip->i_db[nb] = dbtofsb(fs, bp->b_blkno); 155 ip->i_flag |= IUPD|ICHG; 156 if (flags & B_SYNC) 157 bwrite(bp); 158 else 159 bawrite(bp); 160 } 161 } 162 /* 163 * The first NDADDR blocks are direct blocks 164 */ 165 if (bn < NDADDR) { 166 nb = ip->i_db[bn]; 167 if (nb != 0 && ip->i_size >= (bn + 1) * fs->fs_bsize) { 168 error = bread(vp, bn, fs->fs_bsize, NOCRED, &bp); 169 if (error) { 170 brelse(bp); 171 return (error); 172 } 173 *bpp = bp; 174 return (0); 175 } 176 if (nb != 0) { 177 /* 178 * Consider need to reallocate a fragment. 179 */ 180 osize = fragroundup(fs, blkoff(fs, ip->i_size)); 181 nsize = fragroundup(fs, size); 182 if (nsize <= osize) { 183 error = bread(vp, bn, osize, NOCRED, &bp); 184 if (error) { 185 brelse(bp); 186 return (error); 187 } 188 } else { 189 error = ffs_realloccg(ip, bn, 190 ffs_blkpref(ip, bn, (int)bn, &ip->i_db[0]), 191 osize, nsize, cred, &bp); 192 if (error) 193 return (error); 194 } 195 } else { 196 if (ip->i_size < (bn + 1) * fs->fs_bsize) 197 nsize = fragroundup(fs, size); 198 else 199 nsize = fs->fs_bsize; 200 error = ffs_alloc(ip, bn, 201 ffs_blkpref(ip, bn, (int)bn, &ip->i_db[0]), 202 nsize, cred, &newb); 203 if (error) 204 return (error); 205 bp = getblk(vp, bn, nsize); 206 bp->b_blkno = fsbtodb(fs, newb); 207 if (flags & B_CLRBUF) 208 clrbuf(bp); 209 } 210 ip->i_db[bn] = dbtofsb(fs, bp->b_blkno); 211 ip->i_flag |= IUPD|ICHG; 212 *bpp = bp; 213 return (0); 214 } 215 /* 216 * Determine the number of levels of indirection. 217 */ 218 pref = 0; 219 sh = 1; 220 lbn = bn; 221 bn -= NDADDR; 222 for (j = NIADDR; j > 0; j--) { 223 sh *= NINDIR(fs); 224 if (bn < sh) 225 break; 226 bn -= sh; 227 } 228 if (j == 0) 229 return (EFBIG); 230 /* 231 * Fetch the first indirect block allocating if necessary. 232 */ 233 nb = ip->i_ib[NIADDR - j]; 234 if (nb == 0) { 235 pref = ffs_blkpref(ip, lbn, 0, (daddr_t *)0); 236 if (error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, 237 cred, &newb)) 238 return (error); 239 nb = newb; 240 bp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize); 241 clrbuf(bp); 242 /* 243 * Write synchronously so that indirect blocks 244 * never point at garbage. 245 */ 246 if (error = bwrite(bp)) { 247 ffs_blkfree(ip, nb, fs->fs_bsize); 248 return (error); 249 } 250 ip->i_ib[NIADDR - j] = nb; 251 ip->i_flag |= IUPD|ICHG; 252 } 253 /* 254 * Fetch through the indirect blocks, allocating as necessary. 255 */ 256 for (; ; j++) { 257 error = bread(ip->i_devvp, fsbtodb(fs, nb), 258 (int)fs->fs_bsize, NOCRED, &bp); 259 if (error) { 260 brelse(bp); 261 return (error); 262 } 263 bap = bp->b_un.b_daddr; 264 sh /= NINDIR(fs); 265 i = (bn / sh) % NINDIR(fs); 266 nb = bap[i]; 267 if (j == NIADDR) 268 break; 269 if (nb != 0) { 270 brelse(bp); 271 continue; 272 } 273 if (pref == 0) 274 pref = ffs_blkpref(ip, lbn, 0, (daddr_t *)0); 275 if (error = 276 ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb)) { 277 brelse(bp); 278 return (error); 279 } 280 nb = newb; 281 nbp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize); 282 clrbuf(nbp); 283 /* 284 * Write synchronously so that indirect blocks 285 * never point at garbage. 286 */ 287 if (error = bwrite(nbp)) { 288 ffs_blkfree(ip, nb, fs->fs_bsize); 289 brelse(bp); 290 return (error); 291 } 292 bap[i] = nb; 293 /* 294 * If required, write synchronously, otherwise use 295 * delayed write. If this is the first instance of 296 * the delayed write, reassociate the buffer with the 297 * file so it will be written if the file is sync'ed. 298 */ 299 if (flags & B_SYNC) { 300 bwrite(bp); 301 } else if (bp->b_flags & B_DELWRI) { 302 bdwrite(bp); 303 } else { 304 bdwrite(bp); 305 reassignbuf(bp, vp); 306 } 307 } 308 /* 309 * Get the data block, allocating if necessary. 310 */ 311 if (nb == 0) { 312 pref = ffs_blkpref(ip, lbn, i, &bap[0]); 313 if (error = 314 ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb)) { 315 brelse(bp); 316 return (error); 317 } 318 nb = newb; 319 nbp = getblk(vp, lbn, fs->fs_bsize); 320 nbp->b_blkno = fsbtodb(fs, nb); 321 if (flags & B_CLRBUF) 322 clrbuf(nbp); 323 bap[i] = nb; 324 /* 325 * If required, write synchronously, otherwise use 326 * delayed write. If this is the first instance of 327 * the delayed write, reassociate the buffer with the 328 * file so it will be written if the file is sync'ed. 329 */ 330 if (flags & B_SYNC) { 331 bwrite(bp); 332 } else if (bp->b_flags & B_DELWRI) { 333 bdwrite(bp); 334 } else { 335 bdwrite(bp); 336 reassignbuf(bp, vp); 337 } 338 *bpp = nbp; 339 return (0); 340 } 341 brelse(bp); 342 if (flags & B_CLRBUF) { 343 error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp); 344 if (error) { 345 brelse(nbp); 346 return (error); 347 } 348 } else { 349 nbp = getblk(vp, lbn, fs->fs_bsize); 350 nbp->b_blkno = fsbtodb(fs, nb); 351 } 352 *bpp = nbp; 353 return (0); 354 } 355