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