1 1.59 andvar /* $NetBSD: ext2fs_alloc.c,v 1.59 2025/06/27 19:55:38 andvar Exp $ */ 2 1.1 bouyer 3 1.1 bouyer /* 4 1.1 bouyer * Copyright (c) 1982, 1986, 1989, 1993 5 1.1 bouyer * The Regents of the University of California. All rights reserved. 6 1.1 bouyer * 7 1.1 bouyer * Redistribution and use in source and binary forms, with or without 8 1.1 bouyer * modification, are permitted provided that the following conditions 9 1.1 bouyer * are met: 10 1.1 bouyer * 1. Redistributions of source code must retain the above copyright 11 1.1 bouyer * notice, this list of conditions and the following disclaimer. 12 1.1 bouyer * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 bouyer * notice, this list of conditions and the following disclaimer in the 14 1.1 bouyer * documentation and/or other materials provided with the distribution. 15 1.20 agc * 3. Neither the name of the University nor the names of its contributors 16 1.20 agc * may be used to endorse or promote products derived from this software 17 1.20 agc * without specific prior written permission. 18 1.20 agc * 19 1.20 agc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.20 agc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.20 agc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.20 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.20 agc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.20 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.20 agc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.20 agc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.20 agc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.20 agc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.20 agc * SUCH DAMAGE. 30 1.20 agc * 31 1.20 agc * @(#)ffs_alloc.c 8.11 (Berkeley) 10/27/94 32 1.20 agc * Modified for ext2fs by Manuel Bouyer. 33 1.20 agc */ 34 1.20 agc 35 1.20 agc /* 36 1.20 agc * Copyright (c) 1997 Manuel Bouyer. 37 1.20 agc * 38 1.20 agc * Redistribution and use in source and binary forms, with or without 39 1.20 agc * modification, are permitted provided that the following conditions 40 1.20 agc * are met: 41 1.20 agc * 1. Redistributions of source code must retain the above copyright 42 1.20 agc * notice, this list of conditions and the following disclaimer. 43 1.20 agc * 2. Redistributions in binary form must reproduce the above copyright 44 1.20 agc * notice, this list of conditions and the following disclaimer in the 45 1.20 agc * documentation and/or other materials provided with the distribution. 46 1.1 bouyer * 47 1.22 bouyer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 48 1.22 bouyer * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 49 1.22 bouyer * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 50 1.22 bouyer * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 51 1.22 bouyer * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 52 1.22 bouyer * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 53 1.22 bouyer * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 54 1.22 bouyer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 55 1.22 bouyer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 56 1.22 bouyer * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 57 1.1 bouyer * 58 1.1 bouyer * @(#)ffs_alloc.c 8.11 (Berkeley) 10/27/94 59 1.1 bouyer * Modified for ext2fs by Manuel Bouyer. 60 1.1 bouyer */ 61 1.13 lukem 62 1.13 lukem #include <sys/cdefs.h> 63 1.59 andvar __KERNEL_RCSID(0, "$NetBSD: ext2fs_alloc.c,v 1.59 2025/06/27 19:55:38 andvar Exp $"); 64 1.1 bouyer 65 1.1 bouyer #include <sys/param.h> 66 1.1 bouyer #include <sys/systm.h> 67 1.1 bouyer #include <sys/buf.h> 68 1.1 bouyer #include <sys/proc.h> 69 1.1 bouyer #include <sys/vnode.h> 70 1.1 bouyer #include <sys/mount.h> 71 1.1 bouyer #include <sys/kernel.h> 72 1.1 bouyer #include <sys/syslog.h> 73 1.29 elad #include <sys/kauth.h> 74 1.1 bouyer 75 1.49 jdolecek #include <lib/libkern/crc16.h> 76 1.49 jdolecek 77 1.1 bouyer #include <ufs/ufs/inode.h> 78 1.1 bouyer #include <ufs/ufs/ufs_extern.h> 79 1.27 yamt #include <ufs/ufs/ufsmount.h> 80 1.1 bouyer 81 1.1 bouyer #include <ufs/ext2fs/ext2fs.h> 82 1.1 bouyer #include <ufs/ext2fs/ext2fs_extern.h> 83 1.1 bouyer 84 1.1 bouyer u_long ext2gennumber; 85 1.1 bouyer 86 1.26 xtraeme static daddr_t ext2fs_alloccg(struct inode *, int, daddr_t, int); 87 1.26 xtraeme static u_long ext2fs_dirpref(struct m_ext2fs *); 88 1.26 xtraeme static void ext2fs_fserr(struct m_ext2fs *, u_int, const char *); 89 1.26 xtraeme static u_long ext2fs_hashalloc(struct inode *, int, long, int, 90 1.40 tsutsui daddr_t (*)(struct inode *, int, daddr_t, int)); 91 1.26 xtraeme static daddr_t ext2fs_nodealloccg(struct inode *, int, daddr_t, int); 92 1.26 xtraeme static daddr_t ext2fs_mapsearch(struct m_ext2fs *, char *, daddr_t); 93 1.53 christos static __inline void ext2fs_cg_update(struct m_ext2fs *, int, 94 1.53 christos struct ext2_gd *, int, int, int, daddr_t); 95 1.53 christos static uint16_t ext2fs_cg_get_csum(struct m_ext2fs *, int, struct ext2_gd *); 96 1.53 christos static void ext2fs_init_bb(struct m_ext2fs *, int, struct ext2_gd *, 97 1.53 christos char *); 98 1.1 bouyer 99 1.1 bouyer /* 100 1.1 bouyer * Allocate a block in the file system. 101 1.23 perry * 102 1.1 bouyer * A preference may be optionally specified. If a preference is given 103 1.1 bouyer * the following hierarchy is used to allocate a block: 104 1.1 bouyer * 1) allocate the requested block. 105 1.1 bouyer * 2) allocate a rotationally optimal block in the same cylinder. 106 1.1 bouyer * 3) allocate a block in the same cylinder group. 107 1.59 andvar * 4) quadratically rehash into other cylinder groups, until an 108 1.1 bouyer * available block is located. 109 1.11 wiz * If no block preference is given the following hierarchy is used 110 1.1 bouyer * to allocate a block: 111 1.1 bouyer * 1) allocate a block in the cylinder group that contains the 112 1.1 bouyer * inode for the file. 113 1.59 andvar * 2) quadratically rehash into other cylinder groups, until an 114 1.1 bouyer * available block is located. 115 1.1 bouyer */ 116 1.1 bouyer int 117 1.32 christos ext2fs_alloc(struct inode *ip, daddr_t lbn, daddr_t bpref, 118 1.31 christos kauth_cred_t cred, daddr_t *bnp) 119 1.1 bouyer { 120 1.7 augustss struct m_ext2fs *fs; 121 1.15 fvdl daddr_t bno; 122 1.1 bouyer int cg; 123 1.23 perry 124 1.1 bouyer *bnp = 0; 125 1.1 bouyer fs = ip->i_e2fs; 126 1.1 bouyer #ifdef DIAGNOSTIC 127 1.1 bouyer if (cred == NOCRED) 128 1.14 provos panic("ext2fs_alloc: missing credential"); 129 1.1 bouyer #endif /* DIAGNOSTIC */ 130 1.1 bouyer if (fs->e2fs.e2fs_fbcount == 0) 131 1.1 bouyer goto nospace; 132 1.39 elad if (kauth_authorize_system(cred, KAUTH_SYSTEM_FS_RESERVEDSPACE, 0, NULL, 133 1.39 elad NULL, NULL) != 0 && 134 1.34 elad freespace(fs) <= 0) 135 1.1 bouyer goto nospace; 136 1.1 bouyer if (bpref >= fs->e2fs.e2fs_bcount) 137 1.1 bouyer bpref = 0; 138 1.1 bouyer if (bpref == 0) 139 1.1 bouyer cg = ino_to_cg(fs, ip->i_number); 140 1.1 bouyer else 141 1.1 bouyer cg = dtog(fs, bpref); 142 1.15 fvdl bno = (daddr_t)ext2fs_hashalloc(ip, cg, bpref, fs->e2fs_bsize, 143 1.40 tsutsui ext2fs_alloccg); 144 1.1 bouyer if (bno > 0) { 145 1.43 jakllsch ext2fs_setnblock(ip, ext2fs_nblock(ip) + btodb(fs->e2fs_bsize)); 146 1.1 bouyer ip->i_flag |= IN_CHANGE | IN_UPDATE; 147 1.1 bouyer *bnp = bno; 148 1.48 christos return 0; 149 1.1 bouyer } 150 1.1 bouyer nospace: 151 1.29 elad ext2fs_fserr(fs, kauth_cred_geteuid(cred), "file system full"); 152 1.1 bouyer uprintf("\n%s: write failed, file system is full\n", fs->e2fs_fsmnt); 153 1.48 christos return ENOSPC; 154 1.1 bouyer } 155 1.1 bouyer 156 1.1 bouyer /* 157 1.1 bouyer * Allocate an inode in the file system. 158 1.23 perry * 159 1.1 bouyer * If allocating a directory, use ext2fs_dirpref to select the inode. 160 1.1 bouyer * If allocating in a directory, the following hierarchy is followed: 161 1.1 bouyer * 1) allocate the preferred inode. 162 1.1 bouyer * 2) allocate an inode in the same cylinder group. 163 1.59 andvar * 3) quadratically rehash into other cylinder groups, until an 164 1.1 bouyer * available inode is located. 165 1.11 wiz * If no inode preference is given the following hierarchy is used 166 1.1 bouyer * to allocate an inode: 167 1.1 bouyer * 1) allocate an inode in cylinder group 0. 168 1.59 andvar * 2) quadratically rehash into other cylinder groups, until an 169 1.1 bouyer * available inode is located. 170 1.1 bouyer */ 171 1.1 bouyer int 172 1.52 hannken ext2fs_valloc(struct vnode *pvp, int mode, kauth_cred_t cred, ino_t *inop) 173 1.1 bouyer { 174 1.7 augustss struct inode *pip; 175 1.7 augustss struct m_ext2fs *fs; 176 1.1 bouyer ino_t ino, ipref; 177 1.52 hannken int cg; 178 1.23 perry 179 1.1 bouyer pip = VTOI(pvp); 180 1.1 bouyer fs = pip->i_e2fs; 181 1.1 bouyer if (fs->e2fs.e2fs_ficount == 0) 182 1.1 bouyer goto noinodes; 183 1.1 bouyer 184 1.1 bouyer if ((mode & IFMT) == IFDIR) 185 1.1 bouyer cg = ext2fs_dirpref(fs); 186 1.1 bouyer else 187 1.1 bouyer cg = ino_to_cg(fs, pip->i_number); 188 1.1 bouyer ipref = cg * fs->e2fs.e2fs_ipg + 1; 189 1.1 bouyer ino = (ino_t)ext2fs_hashalloc(pip, cg, (long)ipref, mode, ext2fs_nodealloccg); 190 1.1 bouyer if (ino == 0) 191 1.1 bouyer goto noinodes; 192 1.49 jdolecek 193 1.52 hannken *inop = ino; 194 1.52 hannken return 0; 195 1.1 bouyer 196 1.1 bouyer noinodes: 197 1.29 elad ext2fs_fserr(fs, kauth_cred_geteuid(cred), "out of inodes"); 198 1.1 bouyer uprintf("\n%s: create/symlink failed, no inodes free\n", fs->e2fs_fsmnt); 199 1.48 christos return ENOSPC; 200 1.1 bouyer } 201 1.1 bouyer 202 1.1 bouyer /* 203 1.1 bouyer * Find a cylinder to place a directory. 204 1.1 bouyer * 205 1.1 bouyer * The policy implemented by this algorithm is to select from 206 1.1 bouyer * among those cylinder groups with above the average number of 207 1.1 bouyer * free inodes, the one with the smallest number of directories. 208 1.1 bouyer */ 209 1.1 bouyer static u_long 210 1.26 xtraeme ext2fs_dirpref(struct m_ext2fs *fs) 211 1.1 bouyer { 212 1.1 bouyer int cg, maxspace, mincg, avgifree; 213 1.1 bouyer 214 1.1 bouyer avgifree = fs->e2fs.e2fs_ficount / fs->e2fs_ncg; 215 1.1 bouyer maxspace = 0; 216 1.1 bouyer mincg = -1; 217 1.53 christos for (cg = 0; cg < fs->e2fs_ncg; cg++) { 218 1.53 christos uint32_t nifree = 219 1.53 christos (fs2h16(fs->e2fs_gd[cg].ext2bgd_nifree_hi) << 16) 220 1.53 christos | fs2h16(fs->e2fs_gd[cg].ext2bgd_nifree); 221 1.53 christos if (nifree < avgifree) { 222 1.53 christos continue; 223 1.53 christos } 224 1.53 christos uint32_t nbfree = 225 1.53 christos (fs2h16(fs->e2fs_gd[cg].ext2bgd_nbfree_hi) << 16) 226 1.53 christos | fs2h16(fs->e2fs_gd[cg].ext2bgd_nbfree); 227 1.53 christos if (mincg == -1 || nbfree > maxspace) { 228 1.53 christos mincg = cg; 229 1.53 christos maxspace = nbfree; 230 1.1 bouyer } 231 1.53 christos } 232 1.1 bouyer return mincg; 233 1.1 bouyer } 234 1.1 bouyer 235 1.1 bouyer /* 236 1.1 bouyer * Select the desired position for the next block in a file. The file is 237 1.1 bouyer * logically divided into sections. The first section is composed of the 238 1.1 bouyer * direct blocks. Each additional section contains fs_maxbpg blocks. 239 1.23 perry * 240 1.1 bouyer * If no blocks have been allocated in the first section, the policy is to 241 1.1 bouyer * request a block in the same cylinder group as the inode that describes 242 1.1 bouyer * the file. Otherwise, the policy is to try to allocate the blocks 243 1.57 msaitoh * contiguously. The two fields of the ext2 inode extension (see 244 1.1 bouyer * ufs/ufs/inode.h) help this. 245 1.1 bouyer */ 246 1.15 fvdl daddr_t 247 1.26 xtraeme ext2fs_blkpref(struct inode *ip, daddr_t lbn, int indx, 248 1.26 xtraeme int32_t *bap /* XXX ondisk32 */) 249 1.1 bouyer { 250 1.7 augustss struct m_ext2fs *fs; 251 1.7 augustss int cg, i; 252 1.1 bouyer 253 1.1 bouyer fs = ip->i_e2fs; 254 1.1 bouyer /* 255 1.58 andvar * if we are doing contiguous lbn allocation, try to alloc blocks 256 1.58 andvar * contiguously on disk 257 1.1 bouyer */ 258 1.1 bouyer 259 1.1 bouyer if ( ip->i_e2fs_last_blk && lbn == ip->i_e2fs_last_lblk + 1) { 260 1.1 bouyer return ip->i_e2fs_last_blk + 1; 261 1.1 bouyer } 262 1.1 bouyer 263 1.1 bouyer /* 264 1.1 bouyer * bap, if provided, gives us a list of blocks to which we want to 265 1.1 bouyer * stay close 266 1.1 bouyer */ 267 1.1 bouyer 268 1.1 bouyer if (bap) { 269 1.1 bouyer for (i = indx; i >= 0 ; i--) { 270 1.1 bouyer if (bap[i]) { 271 1.2 bouyer return fs2h32(bap[i]) + 1; 272 1.1 bouyer } 273 1.1 bouyer } 274 1.1 bouyer } 275 1.1 bouyer 276 1.1 bouyer /* fall back to the first block of the cylinder containing the inode */ 277 1.1 bouyer 278 1.1 bouyer cg = ino_to_cg(fs, ip->i_number); 279 1.1 bouyer return fs->e2fs.e2fs_bpg * cg + fs->e2fs.e2fs_first_dblock + 1; 280 1.1 bouyer } 281 1.1 bouyer 282 1.1 bouyer /* 283 1.1 bouyer * Implement the cylinder overflow algorithm. 284 1.1 bouyer * 285 1.1 bouyer * The policy implemented by this algorithm is: 286 1.1 bouyer * 1) allocate the block in its requested cylinder group. 287 1.59 andvar * 2) quadratically rehash on the cylinder group number. 288 1.1 bouyer * 3) brute force search for a free block. 289 1.1 bouyer */ 290 1.1 bouyer static u_long 291 1.26 xtraeme ext2fs_hashalloc(struct inode *ip, int cg, long pref, int size, 292 1.26 xtraeme daddr_t (*allocator)(struct inode *, int, daddr_t, int)) 293 1.1 bouyer { 294 1.7 augustss struct m_ext2fs *fs; 295 1.1 bouyer long result; 296 1.1 bouyer int i, icg = cg; 297 1.1 bouyer 298 1.1 bouyer fs = ip->i_e2fs; 299 1.1 bouyer /* 300 1.1 bouyer * 1: preferred cylinder group 301 1.1 bouyer */ 302 1.1 bouyer result = (*allocator)(ip, cg, pref, size); 303 1.1 bouyer if (result) 304 1.48 christos return result; 305 1.1 bouyer /* 306 1.1 bouyer * 2: quadratic rehash 307 1.1 bouyer */ 308 1.1 bouyer for (i = 1; i < fs->e2fs_ncg; i *= 2) { 309 1.1 bouyer cg += i; 310 1.1 bouyer if (cg >= fs->e2fs_ncg) 311 1.1 bouyer cg -= fs->e2fs_ncg; 312 1.1 bouyer result = (*allocator)(ip, cg, 0, size); 313 1.1 bouyer if (result) 314 1.48 christos return result; 315 1.1 bouyer } 316 1.1 bouyer /* 317 1.1 bouyer * 3: brute force search 318 1.1 bouyer * Note that we start at i == 2, since 0 was checked initially, 319 1.1 bouyer * and 1 is always checked in the quadratic rehash. 320 1.1 bouyer */ 321 1.1 bouyer cg = (icg + 2) % fs->e2fs_ncg; 322 1.1 bouyer for (i = 2; i < fs->e2fs_ncg; i++) { 323 1.1 bouyer result = (*allocator)(ip, cg, 0, size); 324 1.1 bouyer if (result) 325 1.48 christos return result; 326 1.1 bouyer cg++; 327 1.1 bouyer if (cg == fs->e2fs_ncg) 328 1.1 bouyer cg = 0; 329 1.1 bouyer } 330 1.48 christos return 0; 331 1.1 bouyer } 332 1.1 bouyer 333 1.1 bouyer /* 334 1.1 bouyer * Determine whether a block can be allocated. 335 1.1 bouyer * 336 1.1 bouyer * Check to see if a block of the appropriate size is available, 337 1.1 bouyer * and if it is, allocate it. 338 1.1 bouyer */ 339 1.1 bouyer 340 1.15 fvdl static daddr_t 341 1.32 christos ext2fs_alloccg(struct inode *ip, int cg, daddr_t bpref, int size) 342 1.1 bouyer { 343 1.7 augustss struct m_ext2fs *fs; 344 1.7 augustss char *bbp; 345 1.1 bouyer struct buf *bp; 346 1.1 bouyer int error, bno, start, end, loc; 347 1.1 bouyer 348 1.1 bouyer fs = ip->i_e2fs; 349 1.53 christos if (fs->e2fs_gd[cg].ext2bgd_nbfree == 0 && 350 1.53 christos fs->e2fs_gd[cg].ext2bgd_nbfree_hi == 0) 351 1.48 christos return 0; 352 1.53 christos error = bread(ip->i_devvp, EXT2_FSBTODB64(fs, 353 1.53 christos fs2h32(fs->e2fs_gd[cg].ext2bgd_b_bitmap), 354 1.53 christos fs2h32(fs->e2fs_gd[cg].ext2bgd_b_bitmap_hi)), 355 1.46 maxv (int)fs->e2fs_bsize, B_MODIFY, &bp); 356 1.1 bouyer if (error) { 357 1.48 christos return 0; 358 1.1 bouyer } 359 1.1 bouyer bbp = (char *)bp->b_data; 360 1.1 bouyer 361 1.1 bouyer if (dtog(fs, bpref) != cg) 362 1.1 bouyer bpref = 0; 363 1.49 jdolecek 364 1.49 jdolecek /* initialize block bitmap now if uninit */ 365 1.49 jdolecek if (__predict_false(E2FS_HAS_GD_CSUM(fs) && 366 1.49 jdolecek (fs->e2fs_gd[cg].ext2bgd_flags & h2fs16(E2FS_BG_BLOCK_UNINIT)))) { 367 1.49 jdolecek ext2fs_init_bb(fs, cg, &fs->e2fs_gd[cg], bbp); 368 1.49 jdolecek fs->e2fs_gd[cg].ext2bgd_flags &= h2fs16(~E2FS_BG_BLOCK_UNINIT); 369 1.49 jdolecek } 370 1.49 jdolecek 371 1.1 bouyer if (bpref != 0) { 372 1.1 bouyer bpref = dtogd(fs, bpref); 373 1.1 bouyer /* 374 1.1 bouyer * if the requested block is available, use it 375 1.1 bouyer */ 376 1.1 bouyer if (isclr(bbp, bpref)) { 377 1.1 bouyer bno = bpref; 378 1.1 bouyer goto gotit; 379 1.1 bouyer } 380 1.1 bouyer } 381 1.1 bouyer /* 382 1.1 bouyer * no blocks in the requested cylinder, so take next 383 1.1 bouyer * available one in this cylinder group. 384 1.58 andvar * first try to get 8 contiguous blocks, then fall back to a single 385 1.1 bouyer * block. 386 1.1 bouyer */ 387 1.1 bouyer if (bpref) 388 1.1 bouyer start = dtogd(fs, bpref) / NBBY; 389 1.1 bouyer else 390 1.1 bouyer start = 0; 391 1.1 bouyer end = howmany(fs->e2fs.e2fs_fpg, NBBY) - start; 392 1.1 bouyer for (loc = start; loc < end; loc++) { 393 1.1 bouyer if (bbp[loc] == 0) { 394 1.1 bouyer bno = loc * NBBY; 395 1.1 bouyer goto gotit; 396 1.1 bouyer } 397 1.1 bouyer } 398 1.1 bouyer for (loc = 0; loc < start; loc++) { 399 1.1 bouyer if (bbp[loc] == 0) { 400 1.1 bouyer bno = loc * NBBY; 401 1.1 bouyer goto gotit; 402 1.1 bouyer } 403 1.1 bouyer } 404 1.1 bouyer 405 1.1 bouyer bno = ext2fs_mapsearch(fs, bbp, bpref); 406 1.50 jdolecek #if 0 407 1.51 jdolecek /* 408 1.51 jdolecek * XXX jdolecek mapsearch actually never fails, it panics instead. 409 1.51 jdolecek * If re-enabling, make sure to brele() before returning. 410 1.51 jdolecek */ 411 1.1 bouyer if (bno < 0) 412 1.48 christos return 0; 413 1.50 jdolecek #endif 414 1.1 bouyer gotit: 415 1.1 bouyer #ifdef DIAGNOSTIC 416 1.15 fvdl if (isset(bbp, (daddr_t)bno)) { 417 1.53 christos printf("%s: cg=%d bno=%d fs=%s\n", __func__, 418 1.53 christos cg, bno, fs->e2fs_fsmnt); 419 1.2 bouyer panic("ext2fs_alloccg: dup alloc"); 420 1.1 bouyer } 421 1.1 bouyer #endif 422 1.15 fvdl setbit(bbp, (daddr_t)bno); 423 1.1 bouyer fs->e2fs.e2fs_fbcount--; 424 1.49 jdolecek ext2fs_cg_update(fs, cg, &fs->e2fs_gd[cg], -1, 0, 0, 0); 425 1.1 bouyer fs->e2fs_fmod = 1; 426 1.1 bouyer bdwrite(bp); 427 1.48 christos return cg * fs->e2fs.e2fs_fpg + fs->e2fs.e2fs_first_dblock + bno; 428 1.1 bouyer } 429 1.1 bouyer 430 1.1 bouyer /* 431 1.1 bouyer * Determine whether an inode can be allocated. 432 1.1 bouyer * 433 1.1 bouyer * Check to see if an inode is available, and if it is, 434 1.1 bouyer * allocate it using the following policy: 435 1.1 bouyer * 1) allocate the requested inode. 436 1.1 bouyer * 2) allocate the next available inode after the requested 437 1.1 bouyer * inode in the specified cylinder group. 438 1.1 bouyer */ 439 1.15 fvdl static daddr_t 440 1.26 xtraeme ext2fs_nodealloccg(struct inode *ip, int cg, daddr_t ipref, int mode) 441 1.1 bouyer { 442 1.7 augustss struct m_ext2fs *fs; 443 1.7 augustss char *ibp; 444 1.1 bouyer struct buf *bp; 445 1.1 bouyer int error, start, len, loc, map, i; 446 1.1 bouyer 447 1.1 bouyer ipref--; /* to avoid a lot of (ipref -1) */ 448 1.33 chs if (ipref == -1) 449 1.33 chs ipref = 0; 450 1.1 bouyer fs = ip->i_e2fs; 451 1.56 christos if (fs->e2fs_gd[cg].ext2bgd_nifree == 0 && 452 1.53 christos fs->e2fs_gd[cg].ext2bgd_nifree_hi == 0) 453 1.48 christos return 0; 454 1.53 christos error = bread(ip->i_devvp, EXT2_FSBTODB64(fs, 455 1.53 christos fs2h32(fs->e2fs_gd[cg].ext2bgd_i_bitmap), 456 1.53 christos fs2h32(fs->e2fs_gd[cg].ext2bgd_i_bitmap_hi)), 457 1.46 maxv (int)fs->e2fs_bsize, B_MODIFY, &bp); 458 1.1 bouyer if (error) { 459 1.48 christos return 0; 460 1.1 bouyer } 461 1.1 bouyer ibp = (char *)bp->b_data; 462 1.49 jdolecek 463 1.49 jdolecek KASSERT(!E2FS_HAS_GD_CSUM(fs) || (fs->e2fs_gd[cg].ext2bgd_flags & h2fs16(E2FS_BG_INODE_ZEROED)) != 0); 464 1.49 jdolecek 465 1.49 jdolecek /* initialize inode bitmap now if uninit */ 466 1.49 jdolecek if (__predict_false(E2FS_HAS_GD_CSUM(fs) && 467 1.49 jdolecek (fs->e2fs_gd[cg].ext2bgd_flags & h2fs16(E2FS_BG_INODE_UNINIT)))) { 468 1.49 jdolecek KASSERT(fs2h16(fs->e2fs_gd[cg].ext2bgd_nifree) == fs->e2fs.e2fs_ipg); 469 1.49 jdolecek memset(ibp, 0, fs->e2fs_bsize); 470 1.49 jdolecek fs->e2fs_gd[cg].ext2bgd_flags &= h2fs16(~E2FS_BG_INODE_UNINIT); 471 1.49 jdolecek } 472 1.49 jdolecek 473 1.1 bouyer if (ipref) { 474 1.1 bouyer ipref %= fs->e2fs.e2fs_ipg; 475 1.1 bouyer if (isclr(ibp, ipref)) 476 1.1 bouyer goto gotit; 477 1.1 bouyer } 478 1.1 bouyer start = ipref / NBBY; 479 1.1 bouyer len = howmany(fs->e2fs.e2fs_ipg - ipref, NBBY); 480 1.1 bouyer loc = skpc(0xff, len, &ibp[start]); 481 1.1 bouyer if (loc == 0) { 482 1.1 bouyer len = start + 1; 483 1.1 bouyer start = 0; 484 1.1 bouyer loc = skpc(0xff, len, &ibp[0]); 485 1.1 bouyer if (loc == 0) { 486 1.53 christos printf("%s: cg = %d, ipref = %lld, fs = %s\n", __func__, 487 1.53 christos cg, (long long)ipref, fs->e2fs_fsmnt); 488 1.53 christos panic("%s: map corrupted", __func__); 489 1.1 bouyer /* NOTREACHED */ 490 1.1 bouyer } 491 1.1 bouyer } 492 1.1 bouyer i = start + len - loc; 493 1.42 rmind map = ibp[i] ^ 0xff; 494 1.42 rmind if (map == 0) { 495 1.53 christos printf("%s: fs = %s\n", __func__, fs->e2fs_fsmnt); 496 1.53 christos panic("%s: inode not in map", __func__); 497 1.1 bouyer } 498 1.42 rmind ipref = i * NBBY + ffs(map) - 1; 499 1.1 bouyer gotit: 500 1.1 bouyer setbit(ibp, ipref); 501 1.1 bouyer fs->e2fs.e2fs_ficount--; 502 1.49 jdolecek ext2fs_cg_update(fs, cg, &fs->e2fs_gd[cg], 503 1.49 jdolecek 0, -1, ((mode & IFMT) == IFDIR) ? 1 : 0, ipref); 504 1.1 bouyer fs->e2fs_fmod = 1; 505 1.1 bouyer bdwrite(bp); 506 1.48 christos return cg * fs->e2fs.e2fs_ipg + ipref + 1; 507 1.1 bouyer } 508 1.1 bouyer 509 1.1 bouyer /* 510 1.1 bouyer * Free a block. 511 1.1 bouyer * 512 1.1 bouyer * The specified block is placed back in the 513 1.1 bouyer * free map. 514 1.1 bouyer */ 515 1.1 bouyer void 516 1.26 xtraeme ext2fs_blkfree(struct inode *ip, daddr_t bno) 517 1.1 bouyer { 518 1.7 augustss struct m_ext2fs *fs; 519 1.7 augustss char *bbp; 520 1.1 bouyer struct buf *bp; 521 1.1 bouyer int error, cg; 522 1.1 bouyer 523 1.1 bouyer fs = ip->i_e2fs; 524 1.1 bouyer cg = dtog(fs, bno); 525 1.49 jdolecek 526 1.53 christos KASSERT(!E2FS_HAS_GD_CSUM(fs) || 527 1.53 christos (fs->e2fs_gd[cg].ext2bgd_flags & h2fs16(E2FS_BG_BLOCK_UNINIT)) == 0); 528 1.49 jdolecek 529 1.1 bouyer if ((u_int)bno >= fs->e2fs.e2fs_bcount) { 530 1.53 christos printf("%s: bad block %jd, ino %ju\n", 531 1.53 christos __func__, (intmax_t)bno, (uintmax_t)ip->i_number); 532 1.37 mrg ext2fs_fserr(fs, ip->i_uid, "bad block"); 533 1.1 bouyer return; 534 1.1 bouyer } 535 1.53 christos error = bread(ip->i_devvp, EXT2_FSBTODB64(fs, 536 1.53 christos fs2h32(fs->e2fs_gd[cg].ext2bgd_b_bitmap), 537 1.53 christos fs2h32(fs->e2fs_gd[cg].ext2bgd_b_bitmap_hi)), 538 1.53 christos (int)fs->e2fs_bsize, B_MODIFY, &bp); 539 1.1 bouyer if (error) { 540 1.1 bouyer return; 541 1.1 bouyer } 542 1.1 bouyer bbp = (char *)bp->b_data; 543 1.1 bouyer bno = dtogd(fs, bno); 544 1.1 bouyer if (isclr(bbp, bno)) { 545 1.53 christos printf("%s: dev = %#jx, block = %jd, fs = %s\n", __func__, 546 1.53 christos (uintmax_t)ip->i_dev, (intmax_t)bno, 547 1.38 christos fs->e2fs_fsmnt); 548 1.53 christos panic("%s: freeing free block", __func__); 549 1.1 bouyer } 550 1.1 bouyer clrbit(bbp, bno); 551 1.1 bouyer fs->e2fs.e2fs_fbcount++; 552 1.49 jdolecek ext2fs_cg_update(fs, cg, &fs->e2fs_gd[cg], 1, 0, 0, 0); 553 1.1 bouyer fs->e2fs_fmod = 1; 554 1.1 bouyer bdwrite(bp); 555 1.1 bouyer } 556 1.1 bouyer 557 1.1 bouyer /* 558 1.1 bouyer * Free an inode. 559 1.1 bouyer * 560 1.1 bouyer * The specified inode is placed back in the free map. 561 1.1 bouyer */ 562 1.1 bouyer int 563 1.27 yamt ext2fs_vfree(struct vnode *pvp, ino_t ino, int mode) 564 1.1 bouyer { 565 1.7 augustss struct m_ext2fs *fs; 566 1.7 augustss char *ibp; 567 1.7 augustss struct inode *pip; 568 1.1 bouyer struct buf *bp; 569 1.1 bouyer int error, cg; 570 1.1 bouyer 571 1.27 yamt pip = VTOI(pvp); 572 1.1 bouyer fs = pip->i_e2fs; 573 1.49 jdolecek 574 1.33 chs if ((u_int)ino > fs->e2fs.e2fs_icount || (u_int)ino < EXT2_FIRSTINO) 575 1.53 christos panic("%s: range: dev = %#jx, ino = %ju, fs = %s", 576 1.53 christos __func__, (uintmax_t)pip->i_dev, (uintmax_t)ino, 577 1.38 christos fs->e2fs_fsmnt); 578 1.49 jdolecek 579 1.1 bouyer cg = ino_to_cg(fs, ino); 580 1.49 jdolecek 581 1.53 christos KASSERT(!E2FS_HAS_GD_CSUM(fs) || 582 1.53 christos (fs->e2fs_gd[cg].ext2bgd_flags & h2fs16(E2FS_BG_INODE_UNINIT)) == 0); 583 1.49 jdolecek 584 1.53 christos error = bread(pip->i_devvp, EXT2_FSBTODB64(fs, 585 1.53 christos fs2h32(fs->e2fs_gd[cg].ext2bgd_i_bitmap), 586 1.53 christos fs2h32(fs->e2fs_gd[cg].ext2bgd_i_bitmap_hi)), 587 1.53 christos (int)fs->e2fs_bsize, B_MODIFY, &bp); 588 1.1 bouyer if (error) { 589 1.48 christos return 0; 590 1.1 bouyer } 591 1.1 bouyer ibp = (char *)bp->b_data; 592 1.1 bouyer ino = (ino - 1) % fs->e2fs.e2fs_ipg; 593 1.1 bouyer if (isclr(ibp, ino)) { 594 1.53 christos printf("%s: dev = %#jx, ino = %ju, fs = %s\n", __func__, 595 1.53 christos (uintmax_t)pip->i_dev, 596 1.53 christos (uintmax_t)ino, fs->e2fs_fsmnt); 597 1.1 bouyer if (fs->e2fs_ronly == 0) 598 1.53 christos panic("%s: freeing free inode", __func__); 599 1.1 bouyer } 600 1.1 bouyer clrbit(ibp, ino); 601 1.1 bouyer fs->e2fs.e2fs_ficount++; 602 1.49 jdolecek ext2fs_cg_update(fs, cg, &fs->e2fs_gd[cg], 603 1.49 jdolecek 0, 1, ((mode & IFMT) == IFDIR) ? -1 : 0, 0); 604 1.1 bouyer fs->e2fs_fmod = 1; 605 1.1 bouyer bdwrite(bp); 606 1.48 christos return 0; 607 1.1 bouyer } 608 1.1 bouyer 609 1.1 bouyer /* 610 1.1 bouyer * Find a block in the specified cylinder group. 611 1.1 bouyer * 612 1.1 bouyer * It is a panic if a request is made to find a block if none are 613 1.1 bouyer * available. 614 1.1 bouyer */ 615 1.1 bouyer 616 1.15 fvdl static daddr_t 617 1.26 xtraeme ext2fs_mapsearch(struct m_ext2fs *fs, char *bbp, daddr_t bpref) 618 1.1 bouyer { 619 1.1 bouyer int start, len, loc, i, map; 620 1.1 bouyer 621 1.1 bouyer /* 622 1.1 bouyer * find the fragment by searching through the free block 623 1.1 bouyer * map for an appropriate bit pattern 624 1.1 bouyer */ 625 1.1 bouyer if (bpref) 626 1.1 bouyer start = dtogd(fs, bpref) / NBBY; 627 1.1 bouyer else 628 1.1 bouyer start = 0; 629 1.1 bouyer len = howmany(fs->e2fs.e2fs_fpg, NBBY) - start; 630 1.1 bouyer loc = skpc(0xff, len, &bbp[start]); 631 1.1 bouyer if (loc == 0) { 632 1.1 bouyer len = start + 1; 633 1.1 bouyer start = 0; 634 1.1 bouyer loc = skpc(0xff, len, &bbp[start]); 635 1.1 bouyer if (loc == 0) { 636 1.53 christos printf("%s: start = %d, len = %d, fs = %s\n", 637 1.53 christos __func__, start, len, fs->e2fs_fsmnt); 638 1.53 christos panic("%s: map corrupted", __func__); 639 1.1 bouyer /* NOTREACHED */ 640 1.1 bouyer } 641 1.1 bouyer } 642 1.1 bouyer i = start + len - loc; 643 1.42 rmind map = bbp[i] ^ 0xff; 644 1.42 rmind if (map == 0) { 645 1.53 christos printf("%s: fs = %s\n", __func__, fs->e2fs_fsmnt); 646 1.53 christos panic("%s: block not in map", __func__); 647 1.42 rmind } 648 1.42 rmind return i * NBBY + ffs(map) - 1; 649 1.1 bouyer } 650 1.1 bouyer 651 1.1 bouyer /* 652 1.1 bouyer * Fserr prints the name of a file system with an error diagnostic. 653 1.23 perry * 654 1.1 bouyer * The form of the error message is: 655 1.1 bouyer * fs: error message 656 1.1 bouyer */ 657 1.1 bouyer static void 658 1.26 xtraeme ext2fs_fserr(struct m_ext2fs *fs, u_int uid, const char *cp) 659 1.1 bouyer { 660 1.1 bouyer 661 1.1 bouyer log(LOG_ERR, "uid %d on %s: %s\n", uid, fs->e2fs_fsmnt, cp); 662 1.1 bouyer } 663 1.49 jdolecek 664 1.49 jdolecek static __inline void 665 1.49 jdolecek ext2fs_cg_update(struct m_ext2fs *fs, int cg, struct ext2_gd *gd, int nbfree, int nifree, int ndirs, daddr_t ioff) 666 1.49 jdolecek { 667 1.49 jdolecek if (nifree) { 668 1.53 christos uint32_t ext2bgd_nifree = fs2h16(gd->ext2bgd_nifree) | 669 1.53 christos (fs2h16(gd->ext2bgd_nifree_hi) << 16); 670 1.54 riastrad ext2bgd_nifree += nifree; 671 1.53 christos gd->ext2bgd_nifree = h2fs16(ext2bgd_nifree); 672 1.53 christos gd->ext2bgd_nifree_hi = h2fs16(ext2bgd_nifree >> 16); 673 1.49 jdolecek /* 674 1.49 jdolecek * If we allocated inode on bigger offset than what was 675 1.49 jdolecek * ever used before, bump the itable_unused count. This 676 1.49 jdolecek * member only ever grows, and is used only for initialization 677 1.49 jdolecek * !INODE_ZEROED groups with used inodes. Of course, by the 678 1.49 jdolecek * time we get here the itables are already zeroed, but 679 1.49 jdolecek * e2fstools fsck.ext4 still checks this. 680 1.49 jdolecek */ 681 1.53 christos if (E2FS_HAS_GD_CSUM(fs) && nifree < 0 && 682 1.53 christos (ioff + 1) >= (fs->e2fs.e2fs_ipg - 683 1.53 christos fs2h16(gd->ext2bgd_itable_unused_lo))) { 684 1.53 christos gd->ext2bgd_itable_unused_lo = 685 1.53 christos h2fs16(fs->e2fs.e2fs_ipg - (ioff + 1)); 686 1.49 jdolecek } 687 1.49 jdolecek 688 1.53 christos KASSERT(!E2FS_HAS_GD_CSUM(fs) || 689 1.53 christos gd->ext2bgd_itable_unused_lo <= ext2bgd_nifree); 690 1.49 jdolecek } 691 1.49 jdolecek 692 1.49 jdolecek 693 1.53 christos if (nbfree) { 694 1.53 christos uint32_t ext2bgd_nbfree = fs2h16(gd->ext2bgd_nbfree) 695 1.53 christos | (fs2h16(gd->ext2bgd_nbfree_hi) << 16); 696 1.53 christos ext2bgd_nbfree += nbfree; 697 1.53 christos gd->ext2bgd_nbfree = h2fs16(ext2bgd_nbfree); 698 1.53 christos gd->ext2bgd_nbfree_hi = h2fs16(ext2bgd_nbfree >> 16); 699 1.53 christos } 700 1.53 christos 701 1.53 christos if (ndirs) { 702 1.53 christos uint32_t ext2bgd_ndirs = fs2h16(gd->ext2bgd_ndirs) 703 1.53 christos | (fs2h16(gd->ext2bgd_ndirs_hi) << 16); 704 1.53 christos ext2bgd_ndirs += ndirs; 705 1.53 christos gd->ext2bgd_ndirs = h2fs16(ext2bgd_ndirs); 706 1.53 christos gd->ext2bgd_ndirs_hi = h2fs16(ext2bgd_ndirs >> 16); 707 1.53 christos } 708 1.49 jdolecek 709 1.49 jdolecek if (E2FS_HAS_GD_CSUM(fs)) 710 1.49 jdolecek gd->ext2bgd_checksum = ext2fs_cg_get_csum(fs, cg, gd); 711 1.49 jdolecek } 712 1.49 jdolecek 713 1.55 christos static const uint32_t ext2fs_crc32c_table[256] = { 714 1.55 christos 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, 715 1.55 christos 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, 716 1.55 christos 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, 717 1.55 christos 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, 718 1.55 christos 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, 719 1.55 christos 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, 720 1.55 christos 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, 721 1.55 christos 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, 722 1.55 christos 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, 723 1.55 christos 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, 724 1.55 christos 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, 725 1.55 christos 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, 726 1.55 christos 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, 727 1.55 christos 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a, 728 1.55 christos 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, 729 1.55 christos 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, 730 1.55 christos 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, 731 1.55 christos 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, 732 1.55 christos 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, 733 1.55 christos 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, 734 1.55 christos 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, 735 1.55 christos 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, 736 1.55 christos 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, 737 1.55 christos 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7, 738 1.55 christos 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, 739 1.55 christos 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, 740 1.55 christos 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, 741 1.55 christos 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, 742 1.55 christos 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, 743 1.55 christos 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, 744 1.55 christos 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, 745 1.55 christos 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, 746 1.55 christos 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, 747 1.55 christos 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, 748 1.55 christos 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, 749 1.55 christos 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, 750 1.55 christos 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, 751 1.55 christos 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, 752 1.55 christos 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, 753 1.55 christos 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, 754 1.55 christos 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, 755 1.55 christos 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, 756 1.55 christos 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, 757 1.55 christos 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982, 758 1.55 christos 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, 759 1.55 christos 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, 760 1.55 christos 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, 761 1.55 christos 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed, 762 1.55 christos 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, 763 1.55 christos 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, 764 1.55 christos 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, 765 1.55 christos 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, 766 1.55 christos 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, 767 1.55 christos 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540, 768 1.55 christos 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, 769 1.55 christos 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, 770 1.55 christos 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, 771 1.55 christos 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, 772 1.55 christos 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, 773 1.55 christos 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, 774 1.55 christos 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, 775 1.55 christos 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, 776 1.55 christos 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, 777 1.55 christos 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351, 778 1.55 christos }; 779 1.55 christos 780 1.55 christos static uint32_t 781 1.55 christos ext2fs_crc32c(uint32_t last, const void *vbuf, size_t len) 782 1.55 christos { 783 1.55 christos uint32_t crc = last; 784 1.55 christos const uint8_t *buf = vbuf; 785 1.55 christos 786 1.55 christos while (len--) 787 1.55 christos crc = ext2fs_crc32c_table[(crc ^ *buf++) & 0xff] ^ (crc >> 8); 788 1.55 christos 789 1.55 christos return crc; 790 1.55 christos } 791 1.55 christos 792 1.49 jdolecek /* 793 1.49 jdolecek * Compute group description csum. Structure data must be LE (not host). 794 1.49 jdolecek * Returned as LE (disk encoding). 795 1.49 jdolecek */ 796 1.49 jdolecek static uint16_t 797 1.49 jdolecek ext2fs_cg_get_csum(struct m_ext2fs *fs, int cg, struct ext2_gd *gd) 798 1.49 jdolecek { 799 1.49 jdolecek uint16_t crc; 800 1.53 christos size_t cgsize = 1 << fs->e2fs_group_desc_shift; 801 1.49 jdolecek uint32_t cg_bswapped = h2fs32((uint32_t)cg); 802 1.49 jdolecek size_t off; 803 1.49 jdolecek 804 1.55 christos if (EXT2F_HAS_ROCOMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { 805 1.55 christos uint32_t crc32; 806 1.55 christos uint8_t dummy[2] = {0, 0}; 807 1.55 christos 808 1.55 christos off = offsetof(struct ext2_gd, ext2bgd_checksum); 809 1.55 christos 810 1.55 christos crc32 = ext2fs_crc32c(~0, fs->e2fs.e2fs_uuid, 811 1.55 christos sizeof(fs->e2fs.e2fs_uuid)); 812 1.55 christos crc32 = ext2fs_crc32c(crc32, &cg_bswapped, sizeof(cg_bswapped)); 813 1.55 christos crc32 = ext2fs_crc32c(crc32, gd, off); 814 1.55 christos crc32 = ext2fs_crc32c(crc32, dummy, 2); 815 1.55 christos crc32 = ext2fs_crc32c(crc32, gd + off + 2, cgsize - (off + 2)); 816 1.55 christos 817 1.55 christos return h2fs16(crc32 & 0xffff); 818 1.55 christos } 819 1.55 christos 820 1.49 jdolecek if (!EXT2F_HAS_ROCOMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM)) 821 1.49 jdolecek return 0; 822 1.49 jdolecek 823 1.49 jdolecek off = offsetof(struct ext2_gd, ext2bgd_checksum); 824 1.49 jdolecek 825 1.55 christos crc = crc16(~0, (uint8_t *)fs->e2fs.e2fs_uuid, 826 1.55 christos sizeof(fs->e2fs.e2fs_uuid)); 827 1.49 jdolecek crc = crc16(crc, (uint8_t *)&cg_bswapped, sizeof(cg_bswapped)); 828 1.49 jdolecek crc = crc16(crc, (uint8_t *)gd, off); 829 1.53 christos crc = crc16(crc, (uint8_t *)gd + off + 2, cgsize - (off + 2)); 830 1.49 jdolecek 831 1.49 jdolecek return h2fs16(crc); 832 1.49 jdolecek } 833 1.49 jdolecek 834 1.49 jdolecek static void 835 1.49 jdolecek ext2fs_init_bb(struct m_ext2fs *fs, int cg, struct ext2_gd *gd, char *bbp) 836 1.49 jdolecek { 837 1.49 jdolecek int i; 838 1.49 jdolecek 839 1.49 jdolecek memset(bbp, 0, fs->e2fs_bsize); 840 1.49 jdolecek 841 1.49 jdolecek /* 842 1.49 jdolecek * No block was ever allocated on this cg before, so the only used 843 1.49 jdolecek * blocks are metadata blocks on start of the group. We could optimize 844 1.49 jdolecek * this to set by bytes, but since this is done once per the group 845 1.49 jdolecek * in lifetime of filesystem, it really is not worth it. 846 1.49 jdolecek */ 847 1.49 jdolecek for(i=0; i < fs->e2fs.e2fs_bpg - fs2h16(gd->ext2bgd_nbfree); i++) 848 1.49 jdolecek setbit(bbp, i); 849 1.49 jdolecek } 850 1.49 jdolecek 851 1.49 jdolecek /* 852 1.49 jdolecek * Verify csum and initialize itable if not done already 853 1.49 jdolecek */ 854 1.49 jdolecek int 855 1.49 jdolecek ext2fs_cg_verify_and_initialize(struct vnode *devvp, struct m_ext2fs *fs, int ronly) 856 1.49 jdolecek { 857 1.49 jdolecek struct ext2_gd *gd; 858 1.49 jdolecek ino_t ioff; 859 1.49 jdolecek size_t boff; 860 1.49 jdolecek struct buf *bp; 861 1.49 jdolecek int cg, i, error; 862 1.49 jdolecek 863 1.49 jdolecek if (!E2FS_HAS_GD_CSUM(fs)) 864 1.49 jdolecek return 0; 865 1.49 jdolecek 866 1.53 christos for(cg = 0; cg < fs->e2fs_ncg; cg++) { 867 1.49 jdolecek gd = &fs->e2fs_gd[cg]; 868 1.49 jdolecek 869 1.49 jdolecek /* Verify checksum */ 870 1.53 christos uint16_t csum = ext2fs_cg_get_csum(fs, cg, gd); 871 1.53 christos if (gd->ext2bgd_checksum != csum) { 872 1.53 christos printf("%s: group %d invalid csum (%#x != %#x)\n", 873 1.53 christos __func__, cg, gd->ext2bgd_checksum, csum); 874 1.49 jdolecek return EINVAL; 875 1.49 jdolecek } 876 1.49 jdolecek 877 1.49 jdolecek /* if mounting read-write, zero itable if not already done */ 878 1.53 christos if (ronly || 879 1.53 christos (gd->ext2bgd_flags & h2fs16(E2FS_BG_INODE_ZEROED)) != 0) 880 1.49 jdolecek continue; 881 1.49 jdolecek 882 1.49 jdolecek /* 883 1.49 jdolecek * We are skipping already used inodes, zero rest of itable 884 1.49 jdolecek * blocks. First block to zero could be only partial wipe, all 885 1.49 jdolecek * others are wiped completely. This might take a while, 886 1.49 jdolecek * there could be many inode table blocks. We use 887 1.49 jdolecek * delayed writes, so this shouldn't block for very 888 1.49 jdolecek * long. 889 1.49 jdolecek */ 890 1.49 jdolecek ioff = fs->e2fs.e2fs_ipg - fs2h16(gd->ext2bgd_itable_unused_lo); 891 1.49 jdolecek boff = (ioff % fs->e2fs_ipb) * EXT2_DINODE_SIZE(fs); 892 1.49 jdolecek 893 1.49 jdolecek for(i = ioff / fs->e2fs_ipb; i < fs->e2fs_itpg; i++) { 894 1.49 jdolecek if (boff) { 895 1.49 jdolecek /* partial wipe, must read old data */ 896 1.53 christos error = bread(devvp, EXT2_FSBTODB64OFF(fs, 897 1.53 christos fs2h32(gd->ext2bgd_i_tables), 898 1.53 christos fs2h32(gd->ext2bgd_i_tables_hi), i), 899 1.53 christos (int)fs->e2fs_bsize, B_MODIFY, &bp); 900 1.49 jdolecek if (error) { 901 1.53 christos printf("%s: can't read itable block", 902 1.53 christos __func__); 903 1.49 jdolecek return error; 904 1.49 jdolecek } 905 1.53 christos memset((char *)bp->b_data + boff, 0, 906 1.53 christos fs->e2fs_bsize - boff); 907 1.49 jdolecek boff = 0; 908 1.49 jdolecek } else { 909 1.49 jdolecek /* 910 1.49 jdolecek * Complete wipe, don't need to read data. This 911 1.49 jdolecek * assumes nothing else is changing the data. 912 1.49 jdolecek */ 913 1.53 christos bp = getblk(devvp, EXT2_FSBTODB64OFF(fs, 914 1.53 christos fs2h32(gd->ext2bgd_i_tables), 915 1.53 christos fs2h32(gd->ext2bgd_i_tables_hi), i), 916 1.53 christos (int)fs->e2fs_bsize, 0, 0); 917 1.49 jdolecek clrbuf(bp); 918 1.49 jdolecek } 919 1.54 riastrad 920 1.49 jdolecek bdwrite(bp); 921 1.49 jdolecek } 922 1.49 jdolecek 923 1.49 jdolecek gd->ext2bgd_flags |= h2fs16(E2FS_BG_INODE_ZEROED); 924 1.49 jdolecek gd->ext2bgd_checksum = ext2fs_cg_get_csum(fs, cg, gd); 925 1.49 jdolecek fs->e2fs_fmod = 1; 926 1.49 jdolecek } 927 1.49 jdolecek 928 1.49 jdolecek return 0; 929 1.49 jdolecek } 930