1 /* $NetBSD: ext2fs_balloc.c,v 1.19 2003/01/24 21:55:19 fvdl Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Manuel Bouyer. 5 * Copyright (c) 1982, 1986, 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)ffs_balloc.c 8.4 (Berkeley) 9/23/93 37 * Modified for ext2fs by Manuel Bouyer. 38 */ 39 40 #include <sys/cdefs.h> 41 __KERNEL_RCSID(0, "$NetBSD: ext2fs_balloc.c,v 1.19 2003/01/24 21:55:19 fvdl Exp $"); 42 43 #if defined(_KERNEL_OPT) 44 #include "opt_uvmhist.h" 45 #endif 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/buf.h> 50 #include <sys/proc.h> 51 #include <sys/file.h> 52 #include <sys/vnode.h> 53 #include <sys/mount.h> 54 55 #include <uvm/uvm.h> 56 57 #include <ufs/ufs/inode.h> 58 #include <ufs/ufs/ufs_extern.h> 59 60 #include <ufs/ext2fs/ext2fs.h> 61 #include <ufs/ext2fs/ext2fs_extern.h> 62 63 /* 64 * Balloc defines the structure of file system storage 65 * by allocating the physical blocks on a device given 66 * the inode and the logical block number in a file. 67 */ 68 int 69 ext2fs_balloc(ip, bn, size, cred, bpp, flags) 70 struct inode *ip; 71 daddr_t bn; 72 int size; 73 struct ucred *cred; 74 struct buf **bpp; 75 int flags; 76 { 77 struct m_ext2fs *fs; 78 daddr_t nb; 79 struct buf *bp, *nbp; 80 struct vnode *vp = ITOV(ip); 81 struct indir indirs[NIADDR + 2]; 82 daddr_t newb, lbn, pref; 83 int32_t *bap; /* XXX ondisk32 */ 84 int num, i, error; 85 u_int deallocated; 86 daddr_t *blkp, *allocblk, allociblk[NIADDR + 1]; 87 int32_t *allocib; /* XXX ondisk32 */ 88 int unwindidx = -1; 89 UVMHIST_FUNC("ext2fs_balloc"); UVMHIST_CALLED(ubchist); 90 91 UVMHIST_LOG(ubchist, "bn 0x%x", bn,0,0,0); 92 93 if (bpp != NULL) { 94 *bpp = NULL; 95 } 96 if (bn < 0) 97 return (EFBIG); 98 fs = ip->i_e2fs; 99 lbn = bn; 100 101 /* 102 * The first NDADDR blocks are direct blocks 103 */ 104 if (bn < NDADDR) { 105 /* XXX ondisk32 */ 106 nb = fs2h32(ip->i_e2fs_blocks[bn]); 107 if (nb != 0) { 108 109 /* 110 * the block is already allocated, just read it. 111 */ 112 113 if (bpp != NULL) { 114 error = bread(vp, bn, fs->e2fs_bsize, NOCRED, 115 &bp); 116 if (error) { 117 brelse(bp); 118 return (error); 119 } 120 *bpp = bp; 121 } 122 return (0); 123 } 124 125 /* 126 * allocate a new direct block. 127 */ 128 129 error = ext2fs_alloc(ip, bn, 130 ext2fs_blkpref(ip, bn, bn, &ip->i_e2fs_blocks[0]), 131 cred, &newb); 132 if (error) 133 return (error); 134 ip->i_e2fs_last_lblk = lbn; 135 ip->i_e2fs_last_blk = newb; 136 /* XXX ondisk32 */ 137 ip->i_e2fs_blocks[bn] = h2fs32((int32_t)newb); 138 ip->i_flag |= IN_CHANGE | IN_UPDATE; 139 if (bpp != NULL) { 140 bp = getblk(vp, bn, fs->e2fs_bsize, 0, 0); 141 bp->b_blkno = fsbtodb(fs, newb); 142 if (flags & B_CLRBUF) 143 clrbuf(bp); 144 *bpp = bp; 145 } 146 return (0); 147 } 148 /* 149 * Determine the number of levels of indirection. 150 */ 151 pref = 0; 152 if ((error = ufs_getlbns(vp, bn, indirs, &num)) != 0) 153 return(error); 154 #ifdef DIAGNOSTIC 155 if (num < 1) 156 panic ("ext2fs_balloc: ufs_getlbns returned indirect block\n"); 157 #endif 158 /* 159 * Fetch the first indirect block allocating if necessary. 160 */ 161 --num; 162 /* XXX ondisk32 */ 163 nb = fs2h32(ip->i_e2fs_blocks[NDADDR + indirs[0].in_off]); 164 allocib = NULL; 165 allocblk = allociblk; 166 if (nb == 0) { 167 pref = ext2fs_blkpref(ip, lbn, 0, (int32_t *)0); 168 error = ext2fs_alloc(ip, lbn, pref, cred, &newb); 169 if (error) 170 return (error); 171 nb = newb; 172 *allocblk++ = nb; 173 ip->i_e2fs_last_blk = newb; 174 bp = getblk(vp, indirs[1].in_lbn, fs->e2fs_bsize, 0, 0); 175 bp->b_blkno = fsbtodb(fs, newb); 176 clrbuf(bp); 177 /* 178 * Write synchronously so that indirect blocks 179 * never point at garbage. 180 */ 181 if ((error = bwrite(bp)) != 0) 182 goto fail; 183 unwindidx = 0; 184 allocib = &ip->i_e2fs_blocks[NDADDR + indirs[0].in_off]; 185 /* XXX ondisk32 */ 186 *allocib = h2fs32((int32_t)newb); 187 ip->i_flag |= IN_CHANGE | IN_UPDATE; 188 } 189 /* 190 * Fetch through the indirect blocks, allocating as necessary. 191 */ 192 for (i = 1;;) { 193 error = bread(vp, 194 indirs[i].in_lbn, (int)fs->e2fs_bsize, NOCRED, &bp); 195 if (error) { 196 brelse(bp); 197 goto fail; 198 } 199 bap = (int32_t *)bp->b_data; /* XXX ondisk32 */ 200 nb = fs2h32(bap[indirs[i].in_off]); 201 if (i == num) 202 break; 203 i++; 204 if (nb != 0) { 205 brelse(bp); 206 continue; 207 } 208 pref = ext2fs_blkpref(ip, lbn, 0, (int32_t *)0); 209 error = ext2fs_alloc(ip, lbn, pref, cred, &newb); 210 if (error) { 211 brelse(bp); 212 goto fail; 213 } 214 nb = newb; 215 *allocblk++ = nb; 216 ip->i_e2fs_last_blk = newb; 217 nbp = getblk(vp, indirs[i].in_lbn, fs->e2fs_bsize, 0, 0); 218 nbp->b_blkno = fsbtodb(fs, nb); 219 clrbuf(nbp); 220 /* 221 * Write synchronously so that indirect blocks 222 * never point at garbage. 223 */ 224 if ((error = bwrite(nbp)) != 0) { 225 brelse(bp); 226 goto fail; 227 } 228 if (unwindidx < 0) 229 unwindidx = i - 1; 230 /* XXX ondisk32 */ 231 bap[indirs[i - 1].in_off] = h2fs32((int32_t)nb); 232 /* 233 * If required, write synchronously, otherwise use 234 * delayed write. 235 */ 236 if (flags & B_SYNC) { 237 bwrite(bp); 238 } else { 239 bdwrite(bp); 240 } 241 } 242 /* 243 * Get the data block, allocating if necessary. 244 */ 245 if (nb == 0) { 246 pref = ext2fs_blkpref(ip, lbn, indirs[num].in_off, &bap[0]); 247 error = ext2fs_alloc(ip, lbn, pref, cred, &newb); 248 if (error) { 249 brelse(bp); 250 goto fail; 251 } 252 nb = newb; 253 *allocblk++ = nb; 254 ip->i_e2fs_last_lblk = lbn; 255 ip->i_e2fs_last_blk = newb; 256 /* XXX ondisk32 */ 257 bap[indirs[num].in_off] = h2fs32((int32_t)nb); 258 /* 259 * If required, write synchronously, otherwise use 260 * delayed write. 261 */ 262 if (flags & B_SYNC) { 263 bwrite(bp); 264 } else { 265 bdwrite(bp); 266 } 267 if (bpp != NULL) { 268 nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0); 269 nbp->b_blkno = fsbtodb(fs, nb); 270 if (flags & B_CLRBUF) 271 clrbuf(nbp); 272 *bpp = nbp; 273 } 274 return (0); 275 } 276 brelse(bp); 277 if (bpp != NULL) { 278 if (flags & B_CLRBUF) { 279 error = bread(vp, lbn, (int)fs->e2fs_bsize, NOCRED, 280 &nbp); 281 if (error) { 282 brelse(nbp); 283 goto fail; 284 } 285 } else { 286 nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0); 287 nbp->b_blkno = fsbtodb(fs, nb); 288 } 289 *bpp = nbp; 290 } 291 return (0); 292 fail: 293 /* 294 * If we have failed part way through block allocation, we 295 * have to deallocate any indirect blocks that we have allocated. 296 */ 297 for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) { 298 ext2fs_blkfree(ip, *blkp); 299 deallocated += fs->e2fs_bsize; 300 } 301 if (unwindidx >= 0) { 302 if (unwindidx == 0) { 303 *allocib = 0; 304 } else { 305 int r; 306 307 r = bread(vp, indirs[unwindidx].in_lbn, 308 (int)fs->e2fs_bsize, NOCRED, &bp); 309 if (r) { 310 panic("Could not unwind indirect block, error %d", r); 311 brelse(bp); 312 } else { 313 bap = (int32_t *)bp->b_data; /* XXX ondisk32 */ 314 bap[indirs[unwindidx].in_off] = 0; 315 if (flags & B_SYNC) 316 bwrite(bp); 317 else 318 bdwrite(bp); 319 } 320 } 321 for (i = unwindidx + 1; i <= num; i++) { 322 bp = getblk(vp, indirs[i].in_lbn, (int)fs->e2fs_bsize, 323 0, 0); 324 bp->b_flags |= B_INVAL; 325 brelse(bp); 326 } 327 } 328 if (deallocated) { 329 ip->i_e2fs_nblock -= btodb(deallocated); 330 ip->i_e2fs_flags |= IN_CHANGE | IN_UPDATE; 331 } 332 return error; 333 } 334 335 int 336 ext2fs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags, 337 struct ucred *cred) 338 { 339 struct inode *ip = VTOI(vp); 340 struct m_ext2fs *fs = ip->i_e2fs; 341 int error, delta, bshift, bsize; 342 UVMHIST_FUNC("ext2fs_gop_alloc"); UVMHIST_CALLED(ubchist); 343 344 bshift = fs->e2fs_bshift; 345 bsize = 1 << bshift; 346 347 delta = off & (bsize - 1); 348 off -= delta; 349 len += delta; 350 351 while (len > 0) { 352 bsize = min(bsize, len); 353 UVMHIST_LOG(ubchist, "off 0x%x len 0x%x bsize 0x%x", 354 off, len, bsize, 0); 355 356 error = ext2fs_balloc(ip, lblkno(fs, off), bsize, cred, 357 NULL, flags); 358 if (error) { 359 UVMHIST_LOG(ubchist, "error %d", error, 0,0,0); 360 return error; 361 } 362 363 /* 364 * increase file size now, VOP_BALLOC() requires that 365 * EOF be up-to-date before each call. 366 */ 367 368 if (ip->i_e2fs_size < off + bsize) { 369 UVMHIST_LOG(ubchist, "old 0x%x new 0x%x", 370 ip->i_e2fs_size, off + bsize,0,0); 371 ip->i_e2fs_size = off + bsize; 372 } 373 374 off += bsize; 375 len -= bsize; 376 } 377 return 0; 378 } 379