1 /* 2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)ffs_balloc.c 7.9 (Berkeley) 05/03/90 18 */ 19 20 #include "param.h" 21 #include "systm.h" 22 #include "user.h" 23 #include "buf.h" 24 #include "proc.h" 25 #include "file.h" 26 #include "vnode.h" 27 #include "../ufs/quota.h" 28 #include "../ufs/inode.h" 29 #include "../ufs/fs.h" 30 31 /* 32 * Bmap defines the structure of file system storage 33 * by returning the physical block number on a device 34 * given the inode and the logical block number in a file. 35 */ 36 bmap(ip, bn, bnp) 37 register struct inode *ip; 38 register daddr_t bn; 39 daddr_t *bnp; 40 { 41 register struct fs *fs; 42 register daddr_t nb; 43 struct buf *bp; 44 daddr_t *bap; 45 int i, j, sh; 46 int error; 47 48 if (bn < 0) 49 return (EFBIG); 50 fs = ip->i_fs; 51 52 /* 53 * The first NDADDR blocks are direct blocks 54 */ 55 if (bn < NDADDR) { 56 nb = ip->i_db[bn]; 57 if (nb == 0) { 58 *bnp = (daddr_t)-1; 59 return (0); 60 } 61 *bnp = fsbtodb(fs, nb); 62 return (0); 63 } 64 /* 65 * Determine the number of levels of indirection. 66 */ 67 sh = 1; 68 bn -= NDADDR; 69 for (j = NIADDR; j > 0; j--) { 70 sh *= NINDIR(fs); 71 if (bn < sh) 72 break; 73 bn -= sh; 74 } 75 if (j == 0) 76 return (EFBIG); 77 /* 78 * Fetch through the indirect blocks. 79 */ 80 nb = ip->i_ib[NIADDR - j]; 81 if (nb == 0) { 82 *bnp = (daddr_t)-1; 83 return (0); 84 } 85 for (; j <= NIADDR; j++) { 86 if (error = bread(ip->i_devvp, fsbtodb(fs, nb), 87 (int)fs->fs_bsize, NOCRED, &bp)) { 88 brelse(bp); 89 return (error); 90 } 91 bap = bp->b_un.b_daddr; 92 sh /= NINDIR(fs); 93 i = (bn / sh) % NINDIR(fs); 94 nb = bap[i]; 95 if (nb == 0) { 96 *bnp = (daddr_t)-1; 97 brelse(bp); 98 return (0); 99 } 100 brelse(bp); 101 } 102 *bnp = fsbtodb(fs, nb); 103 return (0); 104 } 105 106 /* 107 * Balloc defines the structure of file system storage 108 * by allocating the physical blocks on a device given 109 * the inode and the logical block number in a file. 110 */ 111 balloc(ip, bn, size, bpp, flags) 112 register struct inode *ip; 113 register daddr_t bn; 114 int size; 115 struct buf **bpp; 116 int flags; 117 { 118 register struct fs *fs; 119 register daddr_t nb; 120 struct buf *bp, *nbp; 121 struct vnode *vp = ITOV(ip); 122 int osize, nsize, i, j, sh, error; 123 daddr_t newb, lbn, *bap, pref, blkpref(); 124 125 *bpp = (struct buf *)0; 126 if (bn < 0) 127 return (EFBIG); 128 fs = ip->i_fs; 129 130 /* 131 * If the next write will extend the file into a new block, 132 * and the file is currently composed of a fragment 133 * this fragment has to be extended to be a full block. 134 */ 135 nb = lblkno(fs, ip->i_size); 136 if (nb < NDADDR && nb < bn) { 137 osize = blksize(fs, ip, nb); 138 if (osize < fs->fs_bsize && osize > 0) { 139 error = realloccg(ip, nb, 140 blkpref(ip, nb, (int)nb, &ip->i_db[0]), 141 osize, (int)fs->fs_bsize, &bp); 142 if (error) 143 return (error); 144 ip->i_size = (nb + 1) * fs->fs_bsize; 145 ip->i_db[nb] = dbtofsb(fs, bp->b_blkno); 146 ip->i_flag |= IUPD|ICHG; 147 if (flags & B_SYNC) 148 bwrite(bp); 149 else 150 bawrite(bp); 151 } 152 } 153 /* 154 * The first NDADDR blocks are direct blocks 155 */ 156 if (bn < NDADDR) { 157 nb = ip->i_db[bn]; 158 if (nb != 0 && ip->i_size >= (bn + 1) * fs->fs_bsize) { 159 error = bread(vp, bn, fs->fs_bsize, NOCRED, &bp); 160 if (error) { 161 brelse(bp); 162 return (error); 163 } 164 *bpp = bp; 165 return (0); 166 } 167 if (nb != 0) { 168 /* 169 * Consider need to reallocate a fragment. 170 */ 171 osize = fragroundup(fs, blkoff(fs, ip->i_size)); 172 nsize = fragroundup(fs, size); 173 if (nsize <= osize) { 174 error = bread(vp, bn, osize, NOCRED, &bp); 175 if (error) { 176 brelse(bp); 177 return (error); 178 } 179 } else { 180 error = realloccg(ip, bn, 181 blkpref(ip, bn, (int)bn, &ip->i_db[0]), 182 osize, nsize, &bp); 183 if (error) 184 return (error); 185 } 186 } else { 187 if (ip->i_size < (bn + 1) * fs->fs_bsize) 188 nsize = fragroundup(fs, size); 189 else 190 nsize = fs->fs_bsize; 191 error = alloc(ip, bn, 192 blkpref(ip, bn, (int)bn, &ip->i_db[0]), 193 nsize, &newb); 194 if (error) 195 return (error); 196 bp = getblk(vp, bn, nsize); 197 bp->b_blkno = fsbtodb(fs, newb); 198 if (flags & B_CLRBUF) 199 clrbuf(bp); 200 } 201 ip->i_db[bn] = dbtofsb(fs, bp->b_blkno); 202 ip->i_flag |= IUPD|ICHG; 203 *bpp = bp; 204 return (0); 205 } 206 /* 207 * Determine the number of levels of indirection. 208 */ 209 pref = 0; 210 sh = 1; 211 lbn = bn; 212 bn -= NDADDR; 213 for (j = NIADDR; j > 0; j--) { 214 sh *= NINDIR(fs); 215 if (bn < sh) 216 break; 217 bn -= sh; 218 } 219 if (j == 0) 220 return (EFBIG); 221 /* 222 * Fetch the first indirect block allocating if necessary. 223 */ 224 nb = ip->i_ib[NIADDR - j]; 225 if (nb == 0) { 226 pref = blkpref(ip, lbn, 0, (daddr_t *)0); 227 if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) 228 return (error); 229 nb = newb; 230 bp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize); 231 clrbuf(bp); 232 /* 233 * Write synchronously so that indirect blocks 234 * never point at garbage. 235 */ 236 if (error = bwrite(bp)) { 237 blkfree(ip, nb, fs->fs_bsize); 238 return (error); 239 } 240 ip->i_ib[NIADDR - j] = nb; 241 ip->i_flag |= IUPD|ICHG; 242 } 243 /* 244 * Fetch through the indirect blocks, allocating as necessary. 245 */ 246 for (; ; j++) { 247 error = bread(ip->i_devvp, fsbtodb(fs, nb), 248 (int)fs->fs_bsize, NOCRED, &bp); 249 if (error) { 250 brelse(bp); 251 return (error); 252 } 253 bap = bp->b_un.b_daddr; 254 sh /= NINDIR(fs); 255 i = (bn / sh) % NINDIR(fs); 256 nb = bap[i]; 257 if (j == NIADDR) 258 break; 259 if (nb != 0) { 260 brelse(bp); 261 continue; 262 } 263 if (pref == 0) 264 pref = blkpref(ip, lbn, 0, (daddr_t *)0); 265 if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) { 266 brelse(bp); 267 return (error); 268 } 269 nb = newb; 270 nbp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize); 271 clrbuf(nbp); 272 /* 273 * Write synchronously so that indirect blocks 274 * never point at garbage. 275 */ 276 if (error = bwrite(nbp)) { 277 blkfree(ip, nb, fs->fs_bsize); 278 brelse(bp); 279 return (error); 280 } 281 bap[i] = nb; 282 /* 283 * If required, write synchronously, otherwise use 284 * delayed write. If this is the first instance of 285 * the delayed write, reassociate the buffer with the 286 * file so it will be written if the file is sync'ed. 287 */ 288 if (flags & B_SYNC) { 289 bwrite(bp); 290 } else if (bp->b_flags & B_DELWRI) { 291 bdwrite(bp); 292 } else { 293 bdwrite(bp); 294 reassignbuf(bp, vp); 295 } 296 } 297 /* 298 * Get the data block, allocating if necessary. 299 */ 300 if (nb == 0) { 301 pref = blkpref(ip, lbn, i, &bap[0]); 302 if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) { 303 brelse(bp); 304 return (error); 305 } 306 nb = newb; 307 nbp = getblk(vp, lbn, fs->fs_bsize); 308 nbp->b_blkno = fsbtodb(fs, nb); 309 if (flags & B_CLRBUF) 310 clrbuf(nbp); 311 bap[i] = nb; 312 /* 313 * If required, write synchronously, otherwise use 314 * delayed write. If this is the first instance of 315 * the delayed write, reassociate the buffer with the 316 * file so it will be written if the file is sync'ed. 317 */ 318 if (flags & B_SYNC) { 319 bwrite(bp); 320 } else if (bp->b_flags & B_DELWRI) { 321 bdwrite(bp); 322 } else { 323 bdwrite(bp); 324 reassignbuf(bp, vp); 325 } 326 *bpp = nbp; 327 return (0); 328 } 329 brelse(bp); 330 if (flags & B_CLRBUF) { 331 error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp); 332 if (error) { 333 brelse(nbp); 334 return (error); 335 } 336 } else { 337 nbp = getblk(vp, lbn, fs->fs_bsize); 338 nbp->b_blkno = fsbtodb(fs, nb); 339 } 340 *bpp = nbp; 341 return (0); 342 } 343