1 /*- 2 * modified for Lites 1.1 3 * 4 * Aug 1995, Godmar Back (gback@cs.utah.edu) 5 * University of Utah, Department of Computer Science 6 */ 7 /*- 8 * SPDX-License-Identifier: BSD-3-Clause 9 * 10 * Copyright (c) 1982, 1986, 1989, 1993 11 * The Regents of the University of California. All rights reserved. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * @(#)ffs_balloc.c 8.4 (Berkeley) 9/23/93 38 * $FreeBSD$ 39 */ 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/bio.h> 44 #include <sys/buf.h> 45 #include <sys/lock.h> 46 #include <sys/mount.h> 47 #include <sys/vnode.h> 48 49 #include <fs/ext2fs/fs.h> 50 #include <fs/ext2fs/inode.h> 51 #include <fs/ext2fs/ext2fs.h> 52 #include <fs/ext2fs/ext2_dinode.h> 53 #include <fs/ext2fs/ext2_extern.h> 54 #include <fs/ext2fs/ext2_mount.h> 55 56 static int 57 ext2_ext_balloc(struct inode *ip, uint32_t lbn, int size, 58 struct ucred *cred, struct buf **bpp, int flags) 59 { 60 struct m_ext2fs *fs; 61 struct buf *bp = NULL; 62 struct vnode *vp = ITOV(ip); 63 uint32_t nb; 64 int osize, nsize, blks, error, allocated; 65 66 fs = ip->i_e2fs; 67 blks = howmany(size, fs->e2fs_bsize); 68 69 error = ext4_ext_get_blocks(ip, lbn, blks, cred, NULL, &allocated, &nb); 70 if (error) 71 return (error); 72 73 if (allocated) { 74 if (ip->i_size < (lbn + 1) * fs->e2fs_bsize) 75 nsize = fragroundup(fs, size); 76 else 77 nsize = fs->e2fs_bsize; 78 79 bp = getblk(vp, lbn, nsize, 0, 0, 0); 80 if(!bp) 81 return (EIO); 82 83 bp->b_blkno = fsbtodb(fs, nb); 84 if (flags & BA_CLRBUF) 85 vfs_bio_clrbuf(bp); 86 } else { 87 if (ip->i_size >= (lbn + 1) * fs->e2fs_bsize) { 88 89 error = bread(vp, lbn, fs->e2fs_bsize, NOCRED, &bp); 90 if (error) { 91 brelse(bp); 92 return (error); 93 } 94 bp->b_blkno = fsbtodb(fs, nb); 95 *bpp = bp; 96 return (0); 97 } 98 99 /* 100 * Consider need to reallocate a fragment. 101 */ 102 osize = fragroundup(fs, blkoff(fs, ip->i_size)); 103 nsize = fragroundup(fs, size); 104 if (nsize <= osize) { 105 error = bread(vp, lbn, osize, NOCRED, &bp); 106 if (error) { 107 brelse(bp); 108 return (error); 109 } 110 bp->b_blkno = fsbtodb(fs, nb); 111 } else { 112 error = bread(vp, lbn, fs->e2fs_bsize, NOCRED, &bp); 113 if (error) { 114 brelse(bp); 115 return (error); 116 } 117 bp->b_blkno = fsbtodb(fs, nb); 118 } 119 } 120 121 *bpp = bp; 122 123 return (error); 124 } 125 126 /* 127 * Balloc defines the structure of filesystem storage 128 * by allocating the physical blocks on a device given 129 * the inode and the logical block number in a file. 130 */ 131 int 132 ext2_balloc(struct inode *ip, e2fs_lbn_t lbn, int size, struct ucred *cred, 133 struct buf **bpp, int flags) 134 { 135 struct m_ext2fs *fs; 136 struct ext2mount *ump; 137 struct buf *bp, *nbp; 138 struct vnode *vp = ITOV(ip); 139 struct indir indirs[EXT2_NIADDR + 2]; 140 e4fs_daddr_t nb, newb; 141 e2fs_daddr_t *bap, pref; 142 int osize, nsize, num, i, error; 143 144 *bpp = NULL; 145 if (lbn < 0) 146 return (EFBIG); 147 fs = ip->i_e2fs; 148 ump = ip->i_ump; 149 150 /* 151 * check if this is a sequential block allocation. 152 * If so, increment next_alloc fields to allow ext2_blkpref 153 * to make a good guess 154 */ 155 if (lbn == ip->i_next_alloc_block + 1) { 156 ip->i_next_alloc_block++; 157 ip->i_next_alloc_goal++; 158 } 159 160 if (ip->i_flag & IN_E4EXTENTS) 161 return (ext2_ext_balloc(ip, lbn, size, cred, bpp, flags)); 162 163 /* 164 * The first EXT2_NDADDR blocks are direct blocks 165 */ 166 if (lbn < EXT2_NDADDR) { 167 nb = ip->i_db[lbn]; 168 /* 169 * no new block is to be allocated, and no need to expand 170 * the file 171 */ 172 if (nb != 0 && ip->i_size >= (lbn + 1) * fs->e2fs_bsize) { 173 error = bread(vp, lbn, fs->e2fs_bsize, NOCRED, &bp); 174 if (error) { 175 brelse(bp); 176 return (error); 177 } 178 bp->b_blkno = fsbtodb(fs, nb); 179 *bpp = bp; 180 return (0); 181 } 182 if (nb != 0) { 183 /* 184 * Consider need to reallocate a fragment. 185 */ 186 osize = fragroundup(fs, blkoff(fs, ip->i_size)); 187 nsize = fragroundup(fs, size); 188 if (nsize <= osize) { 189 error = bread(vp, lbn, osize, NOCRED, &bp); 190 if (error) { 191 brelse(bp); 192 return (error); 193 } 194 bp->b_blkno = fsbtodb(fs, nb); 195 } else { 196 /* 197 * Godmar thinks: this shouldn't happen w/o 198 * fragments 199 */ 200 printf("nsize %d(%d) > osize %d(%d) nb %d\n", 201 (int)nsize, (int)size, (int)osize, 202 (int)ip->i_size, (int)nb); 203 panic( 204 "ext2_balloc: Something is terribly wrong"); 205 /* 206 * please note there haven't been any changes from here on - 207 * FFS seems to work. 208 */ 209 } 210 } else { 211 if (ip->i_size < (lbn + 1) * fs->e2fs_bsize) 212 nsize = fragroundup(fs, size); 213 else 214 nsize = fs->e2fs_bsize; 215 EXT2_LOCK(ump); 216 error = ext2_alloc(ip, lbn, 217 ext2_blkpref(ip, lbn, (int)lbn, &ip->i_db[0], 0), 218 nsize, cred, &newb); 219 if (error) 220 return (error); 221 bp = getblk(vp, lbn, nsize, 0, 0, 0); 222 bp->b_blkno = fsbtodb(fs, newb); 223 if (flags & BA_CLRBUF) 224 vfs_bio_clrbuf(bp); 225 } 226 ip->i_db[lbn] = dbtofsb(fs, bp->b_blkno); 227 ip->i_flag |= IN_CHANGE | IN_UPDATE; 228 *bpp = bp; 229 return (0); 230 } 231 /* 232 * Determine the number of levels of indirection. 233 */ 234 pref = 0; 235 if ((error = ext2_getlbns(vp, lbn, indirs, &num)) != 0) 236 return (error); 237 #ifdef INVARIANTS 238 if (num < 1) 239 panic("ext2_balloc: ext2_getlbns returned indirect block"); 240 #endif 241 /* 242 * Fetch the first indirect block allocating if necessary. 243 */ 244 --num; 245 nb = ip->i_ib[indirs[0].in_off]; 246 if (nb == 0) { 247 EXT2_LOCK(ump); 248 pref = ext2_blkpref(ip, lbn, indirs[0].in_off + 249 EXT2_NDIR_BLOCKS, &ip->i_db[0], 0); 250 if ((error = ext2_alloc(ip, lbn, pref, fs->e2fs_bsize, cred, 251 &newb))) 252 return (error); 253 nb = newb; 254 bp = getblk(vp, indirs[1].in_lbn, fs->e2fs_bsize, 0, 0, 0); 255 bp->b_blkno = fsbtodb(fs, newb); 256 vfs_bio_clrbuf(bp); 257 /* 258 * Write synchronously so that indirect blocks 259 * never point at garbage. 260 */ 261 if ((error = bwrite(bp)) != 0) { 262 ext2_blkfree(ip, nb, fs->e2fs_bsize); 263 return (error); 264 } 265 ip->i_ib[indirs[0].in_off] = newb; 266 ip->i_flag |= IN_CHANGE | IN_UPDATE; 267 } 268 /* 269 * Fetch through the indirect blocks, allocating as necessary. 270 */ 271 for (i = 1;;) { 272 error = bread(vp, 273 indirs[i].in_lbn, (int)fs->e2fs_bsize, NOCRED, &bp); 274 if (error) { 275 brelse(bp); 276 return (error); 277 } 278 bap = (e2fs_daddr_t *)bp->b_data; 279 nb = bap[indirs[i].in_off]; 280 if (i == num) 281 break; 282 i += 1; 283 if (nb != 0) { 284 bqrelse(bp); 285 continue; 286 } 287 EXT2_LOCK(ump); 288 if (pref == 0) 289 pref = ext2_blkpref(ip, lbn, indirs[i].in_off, bap, 290 bp->b_lblkno); 291 error = ext2_alloc(ip, lbn, pref, (int)fs->e2fs_bsize, cred, &newb); 292 if (error) { 293 brelse(bp); 294 return (error); 295 } 296 nb = newb; 297 nbp = getblk(vp, indirs[i].in_lbn, fs->e2fs_bsize, 0, 0, 0); 298 nbp->b_blkno = fsbtodb(fs, nb); 299 vfs_bio_clrbuf(nbp); 300 /* 301 * Write synchronously so that indirect blocks 302 * never point at garbage. 303 */ 304 if ((error = bwrite(nbp)) != 0) { 305 ext2_blkfree(ip, nb, fs->e2fs_bsize); 306 EXT2_UNLOCK(ump); 307 brelse(bp); 308 return (error); 309 } 310 bap[indirs[i - 1].in_off] = nb; 311 /* 312 * If required, write synchronously, otherwise use 313 * delayed write. 314 */ 315 if (flags & IO_SYNC) { 316 bwrite(bp); 317 } else { 318 if (bp->b_bufsize == fs->e2fs_bsize) 319 bp->b_flags |= B_CLUSTEROK; 320 bdwrite(bp); 321 } 322 } 323 /* 324 * Get the data block, allocating if necessary. 325 */ 326 if (nb == 0) { 327 EXT2_LOCK(ump); 328 pref = ext2_blkpref(ip, lbn, indirs[i].in_off, &bap[0], 329 bp->b_lblkno); 330 if ((error = ext2_alloc(ip, 331 lbn, pref, (int)fs->e2fs_bsize, cred, &newb)) != 0) { 332 brelse(bp); 333 return (error); 334 } 335 nb = newb; 336 nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0, 0); 337 nbp->b_blkno = fsbtodb(fs, nb); 338 if (flags & BA_CLRBUF) 339 vfs_bio_clrbuf(nbp); 340 bap[indirs[i].in_off] = nb; 341 /* 342 * If required, write synchronously, otherwise use 343 * delayed write. 344 */ 345 if (flags & IO_SYNC) { 346 bwrite(bp); 347 } else { 348 if (bp->b_bufsize == fs->e2fs_bsize) 349 bp->b_flags |= B_CLUSTEROK; 350 bdwrite(bp); 351 } 352 *bpp = nbp; 353 return (0); 354 } 355 brelse(bp); 356 if (flags & BA_CLRBUF) { 357 int seqcount = (flags & BA_SEQMASK) >> BA_SEQSHIFT; 358 359 if (seqcount && (vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) { 360 error = cluster_read(vp, ip->i_size, lbn, 361 (int)fs->e2fs_bsize, NOCRED, 362 MAXBSIZE, seqcount, 0, &nbp); 363 } else { 364 error = bread(vp, lbn, (int)fs->e2fs_bsize, NOCRED, &nbp); 365 } 366 if (error) { 367 brelse(nbp); 368 return (error); 369 } 370 } else { 371 nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0, 0); 372 nbp->b_blkno = fsbtodb(fs, nb); 373 } 374 *bpp = nbp; 375 return (0); 376 } 377