1/* $NetBSD: ext2fs_balloc.c,v 1.43 2020/09/05 16:30:13 riastradh 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.43 2020/09/05 16:30:13 riastradh 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#ifdef UVMHIST 79#include <uvm/uvm.h> 80#endif 81#include <uvm/uvm_stat.h> 82 83#include <ufs/ufs/inode.h> 84#include <ufs/ufs/ufs_extern.h> 85 86#include <ufs/ext2fs/ext2fs.h> 87#include <ufs/ext2fs/ext2fs_extern.h> 88 89/* 90 * Balloc defines the structure of file system storage 91 * by allocating the physical blocks on a device given 92 * the inode and the logical block number in a file. 93 */ 94int 95ext2fs_balloc(struct inode *ip, daddr_t bn, int size, 96 kauth_cred_t cred, struct buf **bpp, int flags) 97{ 98 struct m_ext2fs *fs; 99 daddr_t nb; 100 struct buf *bp, *nbp; 101 struct vnode *vp = ITOV(ip); 102 struct indir indirs[EXT2FS_NIADDR + 2]; 103 daddr_t newb, lbn, pref; 104 int32_t *bap; /* XXX ondisk32 */ 105 int num, i, error; 106 u_int deallocated; 107 daddr_t *blkp, *allocblk, allociblk[EXT2FS_NIADDR + 1]; 108 int32_t *allocib; /* XXX ondisk32 */ 109 int unwindidx = -1; 110 UVMHIST_FUNC("ext2fs_balloc"); UVMHIST_CALLED(ubchist); 111 112 UVMHIST_LOG(ubchist, "bn 0x%x", bn, 0, 0, 0); 113 114 if (bpp != NULL) { 115 *bpp = NULL; 116 } 117 if (bn < 0) 118 return EFBIG; 119 fs = ip->i_e2fs; 120 lbn = bn; 121 122 /* 123 * The first EXT2FS_NDADDR blocks are direct blocks 124 */ 125 if (bn < EXT2FS_NDADDR) { 126 /* XXX ondisk32 */ 127 nb = fs2h32(ip->i_e2fs_blocks[bn]); 128 if (nb != 0) { 129 130 /* 131 * the block is already allocated, just read it. 132 */ 133 134 if (bpp != NULL) { 135 error = bread(vp, bn, fs->e2fs_bsize, 136 B_MODIFY, &bp); 137 if (error) { 138 return error; 139 } 140 *bpp = bp; 141 } 142 return 0; 143 } 144 145 /* 146 * allocate a new direct block. 147 */ 148 149 error = ext2fs_alloc(ip, bn, 150 ext2fs_blkpref(ip, bn, bn, &ip->i_e2fs_blocks[0]), 151 cred, &newb); 152 if (error) 153 return error; 154 ip->i_e2fs_last_lblk = lbn; 155 ip->i_e2fs_last_blk = newb; 156 /* XXX ondisk32 */ 157 ip->i_e2fs_blocks[bn] = h2fs32((int32_t)newb); 158 ip->i_flag |= IN_CHANGE | IN_UPDATE; 159 if (bpp != NULL) { 160 bp = getblk(vp, bn, fs->e2fs_bsize, 0, 0); 161 bp->b_blkno = EXT2_FSBTODB(fs, newb); 162 if (flags & B_CLRBUF) 163 clrbuf(bp); 164 *bpp = bp; 165 } 166 return 0; 167 } 168 /* 169 * Determine the number of levels of indirection. 170 */ 171 pref = 0; 172 if ((error = ufs_getlbns(vp, bn, indirs, &num)) != 0) 173 return error; 174#ifdef DIAGNOSTIC 175 if (num < 1) 176 panic("%s: ufs_getlbns returned indirect block\n", __func__); 177#endif 178 /* 179 * Fetch the first indirect block allocating if necessary. 180 */ 181 --num; 182 /* XXX ondisk32 */ 183 nb = fs2h32(ip->i_e2fs_blocks[EXT2FS_NDADDR + indirs[0].in_off]); 184 allocib = NULL; 185 allocblk = allociblk; 186 if (nb == 0) { 187 pref = ext2fs_blkpref(ip, lbn, 0, (int32_t *)0); 188 error = ext2fs_alloc(ip, lbn, pref, cred, &newb); 189 if (error) 190 return error; 191 nb = newb; 192 *allocblk++ = nb; 193 ip->i_e2fs_last_blk = newb; 194 bp = getblk(vp, indirs[1].in_lbn, fs->e2fs_bsize, 0, 0); 195 bp->b_blkno = EXT2_FSBTODB(fs, newb); 196 clrbuf(bp); 197 /* 198 * Write synchronously so that indirect blocks 199 * never point at garbage. 200 */ 201 if ((error = bwrite(bp)) != 0) 202 goto fail; 203 unwindidx = 0; 204 allocib = &ip->i_e2fs_blocks[EXT2FS_NDADDR + indirs[0].in_off]; 205 /* XXX ondisk32 */ 206 *allocib = h2fs32((int32_t)newb); 207 ip->i_flag |= IN_CHANGE | IN_UPDATE; 208 } 209 /* 210 * Fetch through the indirect blocks, allocating as necessary. 211 */ 212 for (i = 1;;) { 213 error = bread(vp, 214 indirs[i].in_lbn, (int)fs->e2fs_bsize, 0, &bp); 215 if (error) { 216 goto fail; 217 } 218 bap = (int32_t *)bp->b_data; /* XXX ondisk32 */ 219 nb = fs2h32(bap[indirs[i].in_off]); 220 if (i == num) 221 break; 222 i++; 223 if (nb != 0) { 224 brelse(bp, 0); 225 continue; 226 } 227 pref = ext2fs_blkpref(ip, lbn, 0, (int32_t *)0); 228 error = ext2fs_alloc(ip, lbn, pref, cred, &newb); 229 if (error) { 230 brelse(bp, 0); 231 goto fail; 232 } 233 nb = newb; 234 *allocblk++ = nb; 235 ip->i_e2fs_last_blk = newb; 236 nbp = getblk(vp, indirs[i].in_lbn, fs->e2fs_bsize, 0, 0); 237 nbp->b_blkno = EXT2_FSBTODB(fs, nb); 238 clrbuf(nbp); 239 /* 240 * Write synchronously so that indirect blocks 241 * never point at garbage. 242 */ 243 if ((error = bwrite(nbp)) != 0) { 244 brelse(bp, 0); 245 goto fail; 246 } 247 if (unwindidx < 0) 248 unwindidx = i - 1; 249 /* XXX ondisk32 */ 250 bap[indirs[i - 1].in_off] = h2fs32((int32_t)nb); 251 /* 252 * If required, write synchronously, otherwise use 253 * delayed write. 254 */ 255 if (flags & B_SYNC) { 256 bwrite(bp); 257 } else { 258 bdwrite(bp); 259 } 260 } 261 /* 262 * Get the data block, allocating if necessary. 263 */ 264 if (nb == 0) { 265 pref = ext2fs_blkpref(ip, lbn, indirs[num].in_off, &bap[0]); 266 error = ext2fs_alloc(ip, lbn, pref, cred, &newb); 267 if (error) { 268 brelse(bp, 0); 269 goto fail; 270 } 271 nb = newb; 272 *allocblk++ = nb; 273 ip->i_e2fs_last_lblk = lbn; 274 ip->i_e2fs_last_blk = newb; 275 /* XXX ondisk32 */ 276 bap[indirs[num].in_off] = h2fs32((int32_t)nb); 277 /* 278 * If required, write synchronously, otherwise use 279 * delayed write. 280 */ 281 if (flags & B_SYNC) { 282 bwrite(bp); 283 } else { 284 bdwrite(bp); 285 } 286 if (bpp != NULL) { 287 nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0); 288 nbp->b_blkno = EXT2_FSBTODB(fs, nb); 289 if (flags & B_CLRBUF) 290 clrbuf(nbp); 291 *bpp = nbp; 292 } 293 return 0; 294 } 295 brelse(bp, 0); 296 if (bpp != NULL) { 297 if (flags & B_CLRBUF) { 298 error = bread(vp, lbn, (int)fs->e2fs_bsize, 299 B_MODIFY, &nbp); 300 if (error) { 301 goto fail; 302 } 303 } else { 304 nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0); 305 nbp->b_blkno = EXT2_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, B_MODIFY, &bp); 327 if (r) { 328 panic("%s: Could not unwind indirect block, " 329 "error %d", __func__, r); 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 ext2fs_setnblock(ip, ext2fs_nblock(ip) - 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 = uimin(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, ext2_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", 395 error, 0, 0, 0); 396 return error; 397 } 398 } 399 400 off += bsize; 401 len -= bsize; 402 } 403 return 0; 404} 405