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