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