1/* $NetBSD: ext2fs_balloc.c,v 1.33 2008/05/16 09:22:00 hannken 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.33 2008/05/16 09:22:00 hannken 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 */ 91int 92ext2fs_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[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[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 NDADDR blocks are direct blocks 121 */ 122 if (bn < 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 brelse(bp, 0); 136 return (error); 137 } 138 *bpp = bp; 139 } 140 return (0); 141 } 142 143 /* 144 * allocate a new direct block. 145 */ 146 147 error = ext2fs_alloc(ip, bn, 148 ext2fs_blkpref(ip, bn, bn, &ip->i_e2fs_blocks[0]), 149 cred, &newb); 150 if (error) 151 return (error); 152 ip->i_e2fs_last_lblk = lbn; 153 ip->i_e2fs_last_blk = newb; 154 /* XXX ondisk32 */ 155 ip->i_e2fs_blocks[bn] = h2fs32((int32_t)newb); 156 ip->i_flag |= IN_CHANGE | IN_UPDATE; 157 if (bpp != NULL) { 158 bp = getblk(vp, bn, fs->e2fs_bsize, 0, 0); 159 bp->b_blkno = fsbtodb(fs, newb); 160 if (flags & B_CLRBUF) 161 clrbuf(bp); 162 *bpp = bp; 163 } 164 return (0); 165 } 166 /* 167 * Determine the number of levels of indirection. 168 */ 169 pref = 0; 170 if ((error = ufs_getlbns(vp, bn, indirs, &num)) != 0) 171 return(error); 172#ifdef DIAGNOSTIC 173 if (num < 1) 174 panic ("ext2fs_balloc: ufs_getlbns returned indirect block\n"); 175#endif 176 /* 177 * Fetch the first indirect block allocating if necessary. 178 */ 179 --num; 180 /* XXX ondisk32 */ 181 nb = fs2h32(ip->i_e2fs_blocks[NDADDR + indirs[0].in_off]); 182 allocib = NULL; 183 allocblk = allociblk; 184 if (nb == 0) { 185 pref = ext2fs_blkpref(ip, lbn, 0, (int32_t *)0); 186 error = ext2fs_alloc(ip, lbn, pref, cred, &newb); 187 if (error) 188 return (error); 189 nb = newb; 190 *allocblk++ = nb; 191 ip->i_e2fs_last_blk = newb; 192 bp = getblk(vp, indirs[1].in_lbn, fs->e2fs_bsize, 0, 0); 193 bp->b_blkno = fsbtodb(fs, newb); 194 clrbuf(bp); 195 /* 196 * Write synchronously so that indirect blocks 197 * never point at garbage. 198 */ 199 if ((error = bwrite(bp)) != 0) 200 goto fail; 201 unwindidx = 0; 202 allocib = &ip->i_e2fs_blocks[NDADDR + indirs[0].in_off]; 203 /* XXX ondisk32 */ 204 *allocib = h2fs32((int32_t)newb); 205 ip->i_flag |= IN_CHANGE | IN_UPDATE; 206 } 207 /* 208 * Fetch through the indirect blocks, allocating as necessary. 209 */ 210 for (i = 1;;) { 211 error = bread(vp, 212 indirs[i].in_lbn, (int)fs->e2fs_bsize, NOCRED, 0, &bp); 213 if (error) { 214 brelse(bp, 0); 215 goto fail; 216 } 217 bap = (int32_t *)bp->b_data; /* XXX ondisk32 */ 218 nb = fs2h32(bap[indirs[i].in_off]); 219 if (i == num) 220 break; 221 i++; 222 if (nb != 0) { 223 brelse(bp, 0); 224 continue; 225 } 226 pref = ext2fs_blkpref(ip, lbn, 0, (int32_t *)0); 227 error = ext2fs_alloc(ip, lbn, pref, cred, &newb); 228 if (error) { 229 brelse(bp, 0); 230 goto fail; 231 } 232 nb = newb; 233 *allocblk++ = nb; 234 ip->i_e2fs_last_blk = newb; 235 nbp = getblk(vp, indirs[i].in_lbn, fs->e2fs_bsize, 0, 0); 236 nbp->b_blkno = fsbtodb(fs, nb); 237 clrbuf(nbp); 238 /* 239 * Write synchronously so that indirect blocks 240 * never point at garbage. 241 */ 242 if ((error = bwrite(nbp)) != 0) { 243 brelse(bp, 0); 244 goto fail; 245 } 246 if (unwindidx < 0) 247 unwindidx = i - 1; 248 /* XXX ondisk32 */ 249 bap[indirs[i - 1].in_off] = h2fs32((int32_t)nb); 250 /* 251 * If required, write synchronously, otherwise use 252 * delayed write. 253 */ 254 if (flags & B_SYNC) { 255 bwrite(bp); 256 } else { 257 bdwrite(bp); 258 } 259 } 260 /* 261 * Get the data block, allocating if necessary. 262 */ 263 if (nb == 0) { 264 pref = ext2fs_blkpref(ip, lbn, indirs[num].in_off, &bap[0]); 265 error = ext2fs_alloc(ip, lbn, pref, cred, &newb); 266 if (error) { 267 brelse(bp, 0); 268 goto fail; 269 } 270 nb = newb; 271 *allocblk++ = nb; 272 ip->i_e2fs_last_lblk = lbn; 273 ip->i_e2fs_last_blk = newb; 274 /* XXX ondisk32 */ 275 bap[indirs[num].in_off] = h2fs32((int32_t)nb); 276 /* 277 * If required, write synchronously, otherwise use 278 * delayed write. 279 */ 280 if (flags & B_SYNC) { 281 bwrite(bp); 282 } else { 283 bdwrite(bp); 284 } 285 if (bpp != NULL) { 286 nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0); 287 nbp->b_blkno = fsbtodb(fs, nb); 288 if (flags & B_CLRBUF) 289 clrbuf(nbp); 290 *bpp = nbp; 291 } 292 return (0); 293 } 294 brelse(bp, 0); 295 if (bpp != NULL) { 296 if (flags & B_CLRBUF) { 297 error = bread(vp, lbn, (int)fs->e2fs_bsize, NOCRED, 298 B_MODIFY, &nbp); 299 if (error) { 300 brelse(nbp, 0); 301 goto fail; 302 } 303 } else { 304 nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0); 305 nbp->b_blkno = fsbtodb(fs, nb); 306 } 307 *bpp = nbp; 308 } 309 return (0); 310fail: 311 /* 312 * If we have failed part way through block allocation, we 313 * have to deallocate any indirect blocks that we have allocated. 314 */ 315 for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) { 316 ext2fs_blkfree(ip, *blkp); 317 deallocated += fs->e2fs_bsize; 318 } 319 if (unwindidx >= 0) { 320 if (unwindidx == 0) { 321 *allocib = 0; 322 } else { 323 int r; 324 325 r = bread(vp, indirs[unwindidx].in_lbn, 326 (int)fs->e2fs_bsize, NOCRED, B_MODIFY, &bp); 327 if (r) { 328 panic("Could not unwind indirect block, error %d", r); 329 brelse(bp, 0); 330 } else { 331 bap = (int32_t *)bp->b_data; /* XXX ondisk32 */ 332 bap[indirs[unwindidx].in_off] = 0; 333 if (flags & B_SYNC) 334 bwrite(bp); 335 else 336 bdwrite(bp); 337 } 338 } 339 for (i = unwindidx + 1; i <= num; i++) { 340 bp = getblk(vp, indirs[i].in_lbn, (int)fs->e2fs_bsize, 341 0, 0); 342 brelse(bp, BC_INVAL); 343 } 344 } 345 if (deallocated) { 346 ip->i_e2fs_nblock -= btodb(deallocated); 347 ip->i_e2fs_flags |= IN_CHANGE | IN_UPDATE; 348 } 349 return error; 350} 351 352int 353ext2fs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags, 354 kauth_cred_t cred) 355{ 356 struct inode *ip = VTOI(vp); 357 struct m_ext2fs *fs = ip->i_e2fs; 358 int error, delta, bshift, bsize; 359 UVMHIST_FUNC("ext2fs_gop_alloc"); UVMHIST_CALLED(ubchist); 360 361 bshift = fs->e2fs_bshift; 362 bsize = 1 << bshift; 363 364 delta = off & (bsize - 1); 365 off -= delta; 366 len += delta; 367 368 while (len > 0) { 369 bsize = min(bsize, len); 370 UVMHIST_LOG(ubchist, "off 0x%x len 0x%x bsize 0x%x", 371 off, len, bsize, 0); 372 373 error = ext2fs_balloc(ip, lblkno(fs, off), bsize, cred, 374 NULL, flags); 375 if (error) { 376 UVMHIST_LOG(ubchist, "error %d", error, 0,0,0); 377 return error; 378 } 379 380 /* 381 * increase file size now, ext2fs_balloc() requires that 382 * EOF be up-to-date before each call. 383 */ 384 385 if (ext2fs_size(ip) < off + bsize) { 386 UVMHIST_LOG(ubchist, "old 0x%lx%8lx new 0x%lx%8lx", 387 /* Note that arguments are always cast to u_long. */ 388 ext2fs_size(ip) >> 32, 389 ext2fs_size(ip) & 0xffffffff, 390 (off + bsize) >> 32, 391 (off + bsize) & 0xffffffff); 392 error = ext2fs_setsize(ip, off + bsize); 393 if (error) { 394 UVMHIST_LOG(ubchist, "error %d", error, 0,0,0); 395 return error; 396 } 397 } 398 399 off += bsize; 400 len -= bsize; 401 } 402 return 0; 403} 404