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