1e09c00caSUlf Lilleengen /*- 2e09c00caSUlf Lilleengen * modified for Lites 1.1 3e09c00caSUlf Lilleengen * 4e09c00caSUlf Lilleengen * Aug 1995, Godmar Back (gback@cs.utah.edu) 5e09c00caSUlf Lilleengen * University of Utah, Department of Computer Science 6e09c00caSUlf Lilleengen */ 7e09c00caSUlf Lilleengen /*- 851369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 951369649SPedro F. Giffuni * 10e09c00caSUlf Lilleengen * Copyright (c) 1982, 1986, 1989, 1993 11e09c00caSUlf Lilleengen * The Regents of the University of California. All rights reserved. 12e09c00caSUlf Lilleengen * 13e09c00caSUlf Lilleengen * Redistribution and use in source and binary forms, with or without 14e09c00caSUlf Lilleengen * modification, are permitted provided that the following conditions 15e09c00caSUlf Lilleengen * are met: 16e09c00caSUlf Lilleengen * 1. Redistributions of source code must retain the above copyright 17e09c00caSUlf Lilleengen * notice, this list of conditions and the following disclaimer. 18e09c00caSUlf Lilleengen * 2. Redistributions in binary form must reproduce the above copyright 19e09c00caSUlf Lilleengen * notice, this list of conditions and the following disclaimer in the 20e09c00caSUlf Lilleengen * documentation and/or other materials provided with the distribution. 21fca15474SPedro F. Giffuni * 3. Neither the name of the University nor the names of its contributors 22e09c00caSUlf Lilleengen * may be used to endorse or promote products derived from this software 23e09c00caSUlf Lilleengen * without specific prior written permission. 24e09c00caSUlf Lilleengen * 25e09c00caSUlf Lilleengen * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26e09c00caSUlf Lilleengen * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27e09c00caSUlf Lilleengen * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28e09c00caSUlf Lilleengen * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29e09c00caSUlf Lilleengen * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30e09c00caSUlf Lilleengen * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31e09c00caSUlf Lilleengen * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32e09c00caSUlf Lilleengen * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33e09c00caSUlf Lilleengen * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34e09c00caSUlf Lilleengen * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35e09c00caSUlf Lilleengen * SUCH DAMAGE. 36e09c00caSUlf Lilleengen * 37e09c00caSUlf Lilleengen * @(#)ffs_alloc.c 8.8 (Berkeley) 2/21/94 38e09c00caSUlf Lilleengen * $FreeBSD$ 39e09c00caSUlf Lilleengen */ 40e09c00caSUlf Lilleengen 41e09c00caSUlf Lilleengen #include <sys/param.h> 42e09c00caSUlf Lilleengen #include <sys/systm.h> 43e09c00caSUlf Lilleengen #include <sys/conf.h> 44e09c00caSUlf Lilleengen #include <sys/vnode.h> 45ebc94b66SFedor Uporov #include <sys/sdt.h> 46e09c00caSUlf Lilleengen #include <sys/stat.h> 47e09c00caSUlf Lilleengen #include <sys/mount.h> 485b63c125SPedro F. Giffuni #include <sys/sysctl.h> 49e09c00caSUlf Lilleengen #include <sys/syslog.h> 50e09c00caSUlf Lilleengen #include <sys/buf.h> 51d23db91eSPedro F. Giffuni #include <sys/endian.h> 52e09c00caSUlf Lilleengen 53b6113fb3SPedro F. Giffuni #include <fs/ext2fs/fs.h> 54e09c00caSUlf Lilleengen #include <fs/ext2fs/inode.h> 55e09c00caSUlf Lilleengen #include <fs/ext2fs/ext2_mount.h> 56e09c00caSUlf Lilleengen #include <fs/ext2fs/ext2fs.h> 57e09c00caSUlf Lilleengen #include <fs/ext2fs/ext2_extern.h> 58e09c00caSUlf Lilleengen 59ebc94b66SFedor Uporov SDT_PROVIDER_DEFINE(ext2fs); 60ebc94b66SFedor Uporov /* 61ebc94b66SFedor Uporov * ext2fs trace probe: 62ebc94b66SFedor Uporov * arg0: verbosity. Higher numbers give more verbose messages 63ebc94b66SFedor Uporov * arg1: Textual message 64ebc94b66SFedor Uporov */ 65ebc94b66SFedor Uporov SDT_PROBE_DEFINE2(ext2fs, , alloc, trace, "int", "char*"); 66ebc94b66SFedor Uporov SDT_PROBE_DEFINE3(ext2fs, , alloc, ext2_reallocblks_realloc, 67ebc94b66SFedor Uporov "ino_t", "e2fs_lbn_t", "e2fs_lbn_t"); 68ebc94b66SFedor Uporov SDT_PROBE_DEFINE1(ext2fs, , alloc, ext2_reallocblks_bap, "uint32_t"); 69ebc94b66SFedor Uporov SDT_PROBE_DEFINE1(ext2fs, , alloc, ext2_reallocblks_blkno, "e2fs_daddr_t"); 70ebc94b66SFedor Uporov SDT_PROBE_DEFINE2(ext2fs, , alloc, ext2_b_bitmap_validate_error, "char*", "int"); 71ebc94b66SFedor Uporov SDT_PROBE_DEFINE3(ext2fs, , alloc, ext2_nodealloccg_bmap_corrupted, 72ebc94b66SFedor Uporov "int", "daddr_t", "char*"); 73ebc94b66SFedor Uporov SDT_PROBE_DEFINE2(ext2fs, , alloc, ext2_blkfree_bad_block, "ino_t", "e4fs_daddr_t"); 74ebc94b66SFedor Uporov SDT_PROBE_DEFINE2(ext2fs, , alloc, ext2_vfree_doublefree, "char*", "ino_t"); 75ebc94b66SFedor Uporov 76e09c00caSUlf Lilleengen static daddr_t ext2_alloccg(struct inode *, int, daddr_t, int); 775b63c125SPedro F. Giffuni static daddr_t ext2_clusteralloc(struct inode *, int, daddr_t, int); 78e09c00caSUlf Lilleengen static u_long ext2_dirpref(struct inode *); 79ffbde5eaSFedor Uporov static e4fs_daddr_t ext2_hashalloc(struct inode *, int, long, int, 80e09c00caSUlf Lilleengen daddr_t (*)(struct inode *, int, daddr_t, 81e09c00caSUlf Lilleengen int)); 82e09c00caSUlf Lilleengen static daddr_t ext2_nodealloccg(struct inode *, int, daddr_t, int); 83e09c00caSUlf Lilleengen static daddr_t ext2_mapsearch(struct m_ext2fs *, char *, daddr_t); 84c767faa5SJohn Baldwin 85e09c00caSUlf Lilleengen /* 86e09c00caSUlf Lilleengen * Allocate a block in the filesystem. 87e09c00caSUlf Lilleengen * 88e09c00caSUlf Lilleengen * A preference may be optionally specified. If a preference is given 89e09c00caSUlf Lilleengen * the following hierarchy is used to allocate a block: 90e09c00caSUlf Lilleengen * 1) allocate the requested block. 91e09c00caSUlf Lilleengen * 2) allocate a rotationally optimal block in the same cylinder. 92e09c00caSUlf Lilleengen * 3) allocate a block in the same cylinder group. 93e09c00caSUlf Lilleengen * 4) quadradically rehash into other cylinder groups, until an 94e09c00caSUlf Lilleengen * available block is located. 95e09c00caSUlf Lilleengen * If no block preference is given the following hierarchy is used 96e09c00caSUlf Lilleengen * to allocate a block: 97e09c00caSUlf Lilleengen * 1) allocate a block in the cylinder group that contains the 98e09c00caSUlf Lilleengen * inode for the file. 99e09c00caSUlf Lilleengen * 2) quadradically rehash into other cylinder groups, until an 100e09c00caSUlf Lilleengen * available block is located. 101e09c00caSUlf Lilleengen */ 102e09c00caSUlf Lilleengen int 10370097aacSPedro F. Giffuni ext2_alloc(struct inode *ip, daddr_t lbn, e4fs_daddr_t bpref, int size, 10470097aacSPedro F. Giffuni struct ucred *cred, e4fs_daddr_t *bnp) 105e09c00caSUlf Lilleengen { 106e09c00caSUlf Lilleengen struct m_ext2fs *fs; 107e09c00caSUlf Lilleengen struct ext2mount *ump; 108ffbde5eaSFedor Uporov e4fs_daddr_t bno; 109e09c00caSUlf Lilleengen int cg; 110bf9a211dSPedro F. Giffuni 111e09c00caSUlf Lilleengen *bnp = 0; 112e09c00caSUlf Lilleengen fs = ip->i_e2fs; 113e09c00caSUlf Lilleengen ump = ip->i_ump; 114e09c00caSUlf Lilleengen mtx_assert(EXT2_MTX(ump), MA_OWNED); 11577b193c2SPedro F. Giffuni #ifdef INVARIANTS 116e09c00caSUlf Lilleengen if ((u_int)size > fs->e2fs_bsize || blkoff(fs, size) != 0) { 117e09c00caSUlf Lilleengen vn_printf(ip->i_devvp, "bsize = %lu, size = %d, fs = %s\n", 118e09c00caSUlf Lilleengen (long unsigned int)fs->e2fs_bsize, size, fs->e2fs_fsmnt); 119e09c00caSUlf Lilleengen panic("ext2_alloc: bad size"); 120e09c00caSUlf Lilleengen } 121e09c00caSUlf Lilleengen if (cred == NOCRED) 122e09c00caSUlf Lilleengen panic("ext2_alloc: missing credential"); 12377b193c2SPedro F. Giffuni #endif /* INVARIANTS */ 1243acd9182SFedor Uporov if (size == fs->e2fs_bsize && fs->e2fs_fbcount == 0) 125e09c00caSUlf Lilleengen goto nospace; 126e09c00caSUlf Lilleengen if (cred->cr_uid != 0 && 1273acd9182SFedor Uporov fs->e2fs_fbcount < fs->e2fs_rbcount) 128e09c00caSUlf Lilleengen goto nospace; 1293acd9182SFedor Uporov if (bpref >= fs->e2fs_bcount) 130e09c00caSUlf Lilleengen bpref = 0; 131e09c00caSUlf Lilleengen if (bpref == 0) 132e09c00caSUlf Lilleengen cg = ino_to_cg(fs, ip->i_number); 133e09c00caSUlf Lilleengen else 134e09c00caSUlf Lilleengen cg = dtog(fs, bpref); 135e09c00caSUlf Lilleengen bno = (daddr_t)ext2_hashalloc(ip, cg, bpref, fs->e2fs_bsize, 136e09c00caSUlf Lilleengen ext2_alloccg); 137e09c00caSUlf Lilleengen if (bno > 0) { 138c767faa5SJohn Baldwin /* set next_alloc fields as done in block_getblk */ 139c767faa5SJohn Baldwin ip->i_next_alloc_block = lbn; 140c767faa5SJohn Baldwin ip->i_next_alloc_goal = bno; 141c767faa5SJohn Baldwin 142e09c00caSUlf Lilleengen ip->i_blocks += btodb(fs->e2fs_bsize); 143e09c00caSUlf Lilleengen ip->i_flag |= IN_CHANGE | IN_UPDATE; 144e09c00caSUlf Lilleengen *bnp = bno; 145e09c00caSUlf Lilleengen return (0); 146e09c00caSUlf Lilleengen } 147e09c00caSUlf Lilleengen nospace: 148e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 149ebc94b66SFedor Uporov SDT_PROBE2(ext2fs, , alloc, trace, 1, "cannot allocate data block"); 150e09c00caSUlf Lilleengen return (ENOSPC); 151e09c00caSUlf Lilleengen } 152e09c00caSUlf Lilleengen 153e09c00caSUlf Lilleengen /* 15434f43888SPedro F. Giffuni * Allocate EA's block for inode. 15534f43888SPedro F. Giffuni */ 156ffbde5eaSFedor Uporov e4fs_daddr_t 157b394cd1eSFedor Uporov ext2_alloc_meta(struct inode *ip) 15834f43888SPedro F. Giffuni { 15934f43888SPedro F. Giffuni struct m_ext2fs *fs; 160b394cd1eSFedor Uporov daddr_t blk; 16134f43888SPedro F. Giffuni 16234f43888SPedro F. Giffuni fs = ip->i_e2fs; 16334f43888SPedro F. Giffuni 16434f43888SPedro F. Giffuni EXT2_LOCK(ip->i_ump); 165b394cd1eSFedor Uporov blk = ext2_hashalloc(ip, ino_to_cg(fs, ip->i_number), 0, fs->e2fs_bsize, 166b394cd1eSFedor Uporov ext2_alloccg); 167ebc94b66SFedor Uporov if (0 == blk) { 16834f43888SPedro F. Giffuni EXT2_UNLOCK(ip->i_ump); 169ebc94b66SFedor Uporov SDT_PROBE2(ext2fs, , alloc, trace, 1, "cannot allocate meta block"); 170ebc94b66SFedor Uporov } 17134f43888SPedro F. Giffuni 172b394cd1eSFedor Uporov return (blk); 17334f43888SPedro F. Giffuni } 17434f43888SPedro F. Giffuni 17534f43888SPedro F. Giffuni /* 176e09c00caSUlf Lilleengen * Reallocate a sequence of blocks into a contiguous sequence of blocks. 177e09c00caSUlf Lilleengen * 178e09c00caSUlf Lilleengen * The vnode and an array of buffer pointers for a range of sequential 179e09c00caSUlf Lilleengen * logical blocks to be made contiguous is given. The allocator attempts 180e09c00caSUlf Lilleengen * to find a range of sequential blocks starting as close as possible to 181e09c00caSUlf Lilleengen * an fs_rotdelay offset from the end of the allocation for the logical 182e09c00caSUlf Lilleengen * block immediately preceding the current range. If successful, the 183e09c00caSUlf Lilleengen * physical block numbers in the buffer pointers and in the inode are 184e09c00caSUlf Lilleengen * changed to reflect the new allocation. If unsuccessful, the allocation 185e09c00caSUlf Lilleengen * is left unchanged. The success in doing the reallocation is returned. 186e09c00caSUlf Lilleengen * Note that the error return is not reflected back to the user. Rather 187e09c00caSUlf Lilleengen * the previous block allocation will be used. 188e09c00caSUlf Lilleengen */ 189e09c00caSUlf Lilleengen 1907029da5cSPawel Biernacki static SYSCTL_NODE(_vfs, OID_AUTO, ext2fs, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 1917029da5cSPawel Biernacki "EXT2FS filesystem"); 192e09c00caSUlf Lilleengen 19399984d22SPedro F. Giffuni static int doasyncfree = 1; 194bf9a211dSPedro F. Giffuni 195c767faa5SJohn Baldwin SYSCTL_INT(_vfs_ext2fs, OID_AUTO, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, 196*c2f0581eSPedro F. Giffuni "Use asynchronous writes to update block pointers when freeing blocks"); 197c767faa5SJohn Baldwin 198dc262e5bSFedor Uporov static int doreallocblks = 0; 199bf9a211dSPedro F. Giffuni 200c767faa5SJohn Baldwin SYSCTL_INT(_vfs_ext2fs, OID_AUTO, doreallocblks, CTLFLAG_RW, &doreallocblks, 0, ""); 201e09c00caSUlf Lilleengen 202e09c00caSUlf Lilleengen int 203a9d1b299SPedro F. Giffuni ext2_reallocblks(struct vop_reallocblks_args *ap) 204e09c00caSUlf Lilleengen { 205e09c00caSUlf Lilleengen struct m_ext2fs *fs; 206e09c00caSUlf Lilleengen struct inode *ip; 207e09c00caSUlf Lilleengen struct vnode *vp; 208e09c00caSUlf Lilleengen struct buf *sbp, *ebp; 209e45e8680SPedro F. Giffuni uint32_t *bap, *sbap, *ebap; 210e09c00caSUlf Lilleengen struct ext2mount *ump; 211e09c00caSUlf Lilleengen struct cluster_save *buflist; 2121dc349abSEd Maste struct indir start_ap[EXT2_NIADDR + 1], end_ap[EXT2_NIADDR + 1], *idp; 213da057ed2SPedro F. Giffuni e2fs_lbn_t start_lbn, end_lbn; 21470097aacSPedro F. Giffuni int soff; 21570097aacSPedro F. Giffuni e2fs_daddr_t newblk, blkno; 216e09c00caSUlf Lilleengen int i, len, start_lvl, end_lvl, pref, ssize; 217e09c00caSUlf Lilleengen 2185b63c125SPedro F. Giffuni if (doreallocblks == 0) 2195b63c125SPedro F. Giffuni return (ENOSPC); 2205b63c125SPedro F. Giffuni 221e09c00caSUlf Lilleengen vp = ap->a_vp; 222e09c00caSUlf Lilleengen ip = VTOI(vp); 223e09c00caSUlf Lilleengen fs = ip->i_e2fs; 224e09c00caSUlf Lilleengen ump = ip->i_ump; 2255b63c125SPedro F. Giffuni 226b394cd1eSFedor Uporov if (fs->e2fs_contigsumsize <= 0 || ip->i_flag & IN_E4EXTENTS) 227e09c00caSUlf Lilleengen return (ENOSPC); 2285b63c125SPedro F. Giffuni 229e09c00caSUlf Lilleengen buflist = ap->a_buflist; 230e09c00caSUlf Lilleengen len = buflist->bs_nchildren; 231e09c00caSUlf Lilleengen start_lbn = buflist->bs_children[0]->b_lblkno; 232e09c00caSUlf Lilleengen end_lbn = start_lbn + len - 1; 23377b193c2SPedro F. Giffuni #ifdef INVARIANTS 234e09c00caSUlf Lilleengen for (i = 1; i < len; i++) 235e09c00caSUlf Lilleengen if (buflist->bs_children[i]->b_lblkno != start_lbn + i) 236e09c00caSUlf Lilleengen panic("ext2_reallocblks: non-cluster"); 237e09c00caSUlf Lilleengen #endif 238e09c00caSUlf Lilleengen /* 2397306dea4SPedro F. Giffuni * If the cluster crosses the boundary for the first indirect 2407306dea4SPedro F. Giffuni * block, leave space for the indirect block. Indirect blocks 2417306dea4SPedro F. Giffuni * are initially laid out in a position after the last direct 2427306dea4SPedro F. Giffuni * block. Block reallocation would usually destroy locality by 2437306dea4SPedro F. Giffuni * moving the indirect block out of the way to make room for 2447306dea4SPedro F. Giffuni * data blocks if we didn't compensate here. We should also do 2457306dea4SPedro F. Giffuni * this for other indirect block boundaries, but it is only 2467306dea4SPedro F. Giffuni * important for the first one. 2477306dea4SPedro F. Giffuni */ 2481dc349abSEd Maste if (start_lbn < EXT2_NDADDR && end_lbn >= EXT2_NDADDR) 2497306dea4SPedro F. Giffuni return (ENOSPC); 2507306dea4SPedro F. Giffuni /* 251e09c00caSUlf Lilleengen * If the latest allocation is in a new cylinder group, assume that 252e09c00caSUlf Lilleengen * the filesystem has decided to move and do not force it back to 253e09c00caSUlf Lilleengen * the previous cylinder group. 254e09c00caSUlf Lilleengen */ 255e09c00caSUlf Lilleengen if (dtog(fs, dbtofsb(fs, buflist->bs_children[0]->b_blkno)) != 256e09c00caSUlf Lilleengen dtog(fs, dbtofsb(fs, buflist->bs_children[len - 1]->b_blkno))) 257e09c00caSUlf Lilleengen return (ENOSPC); 258e09c00caSUlf Lilleengen if (ext2_getlbns(vp, start_lbn, start_ap, &start_lvl) || 259e09c00caSUlf Lilleengen ext2_getlbns(vp, end_lbn, end_ap, &end_lvl)) 260e09c00caSUlf Lilleengen return (ENOSPC); 261e09c00caSUlf Lilleengen /* 262e09c00caSUlf Lilleengen * Get the starting offset and block map for the first block. 263e09c00caSUlf Lilleengen */ 264e09c00caSUlf Lilleengen if (start_lvl == 0) { 265e09c00caSUlf Lilleengen sbap = &ip->i_db[0]; 266e09c00caSUlf Lilleengen soff = start_lbn; 267e09c00caSUlf Lilleengen } else { 268e09c00caSUlf Lilleengen idp = &start_ap[start_lvl - 1]; 269e09c00caSUlf Lilleengen if (bread(vp, idp->in_lbn, (int)fs->e2fs_bsize, NOCRED, &sbp)) { 270e09c00caSUlf Lilleengen brelse(sbp); 271e09c00caSUlf Lilleengen return (ENOSPC); 272e09c00caSUlf Lilleengen } 273f744956bSPedro F. Giffuni sbap = (u_int *)sbp->b_data; 274e09c00caSUlf Lilleengen soff = idp->in_off; 275e09c00caSUlf Lilleengen } 276e09c00caSUlf Lilleengen /* 277e09c00caSUlf Lilleengen * If the block range spans two block maps, get the second map. 278e09c00caSUlf Lilleengen */ 279e45e8680SPedro F. Giffuni ebap = NULL; 280e09c00caSUlf Lilleengen if (end_lvl == 0 || (idp = &end_ap[end_lvl - 1])->in_off + 1 >= len) { 281e09c00caSUlf Lilleengen ssize = len; 282e09c00caSUlf Lilleengen } else { 28377b193c2SPedro F. Giffuni #ifdef INVARIANTS 284e09c00caSUlf Lilleengen if (start_ap[start_lvl - 1].in_lbn == idp->in_lbn) 285757224cbSPedro F. Giffuni panic("ext2_reallocblks: start == end"); 286e09c00caSUlf Lilleengen #endif 287e09c00caSUlf Lilleengen ssize = len - (idp->in_off + 1); 2885b63c125SPedro F. Giffuni if (bread(vp, idp->in_lbn, (int)fs->e2fs_bsize, NOCRED, &ebp)) 289e09c00caSUlf Lilleengen goto fail; 290f744956bSPedro F. Giffuni ebap = (u_int *)ebp->b_data; 291e09c00caSUlf Lilleengen } 292e09c00caSUlf Lilleengen /* 2935b63c125SPedro F. Giffuni * Find the preferred location for the cluster. 2945b63c125SPedro F. Giffuni */ 2955b63c125SPedro F. Giffuni EXT2_LOCK(ump); 2965b63c125SPedro F. Giffuni pref = ext2_blkpref(ip, start_lbn, soff, sbap, 0); 2975b63c125SPedro F. Giffuni /* 298e09c00caSUlf Lilleengen * Search the block map looking for an allocation of the desired size. 299e09c00caSUlf Lilleengen */ 30070097aacSPedro F. Giffuni if ((newblk = (e2fs_daddr_t)ext2_hashalloc(ip, dtog(fs, pref), pref, 301e09c00caSUlf Lilleengen len, ext2_clusteralloc)) == 0) { 302e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 303e09c00caSUlf Lilleengen goto fail; 304e09c00caSUlf Lilleengen } 305e09c00caSUlf Lilleengen /* 306e09c00caSUlf Lilleengen * We have found a new contiguous block. 307e09c00caSUlf Lilleengen * 308e09c00caSUlf Lilleengen * First we have to replace the old block pointers with the new 309e09c00caSUlf Lilleengen * block pointers in the inode and indirect blocks associated 310e09c00caSUlf Lilleengen * with the file. 311e09c00caSUlf Lilleengen */ 312ebc94b66SFedor Uporov SDT_PROBE3(ext2fs, , alloc, ext2_reallocblks_realloc, 313ebc94b66SFedor Uporov ip->i_number, start_lbn, end_lbn); 314e09c00caSUlf Lilleengen blkno = newblk; 315e09c00caSUlf Lilleengen for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->e2fs_fpb) { 3165b63c125SPedro F. Giffuni if (i == ssize) { 317e09c00caSUlf Lilleengen bap = ebap; 318e09c00caSUlf Lilleengen soff = -i; 3195b63c125SPedro F. Giffuni } 32077b193c2SPedro F. Giffuni #ifdef INVARIANTS 321e09c00caSUlf Lilleengen if (buflist->bs_children[i]->b_blkno != fsbtodb(fs, *bap)) 322e09c00caSUlf Lilleengen panic("ext2_reallocblks: alloc mismatch"); 323e09c00caSUlf Lilleengen #endif 324ebc94b66SFedor Uporov SDT_PROBE1(ext2fs, , alloc, ext2_reallocblks_bap, *bap); 325e09c00caSUlf Lilleengen *bap++ = blkno; 326e09c00caSUlf Lilleengen } 327e09c00caSUlf Lilleengen /* 328e09c00caSUlf Lilleengen * Next we must write out the modified inode and indirect blocks. 329e09c00caSUlf Lilleengen * For strict correctness, the writes should be synchronous since 330e09c00caSUlf Lilleengen * the old block values may have been written to disk. In practise 331e09c00caSUlf Lilleengen * they are almost never written, but if we are concerned about 332e09c00caSUlf Lilleengen * strict correctness, the `doasyncfree' flag should be set to zero. 333e09c00caSUlf Lilleengen * 334e09c00caSUlf Lilleengen * The test on `doasyncfree' should be changed to test a flag 335e09c00caSUlf Lilleengen * that shows whether the associated buffers and inodes have 336e09c00caSUlf Lilleengen * been written. The flag should be set when the cluster is 337e09c00caSUlf Lilleengen * started and cleared whenever the buffer or inode is flushed. 338e09c00caSUlf Lilleengen * We can then check below to see if it is set, and do the 339e09c00caSUlf Lilleengen * synchronous write only when it has been cleared. 340e09c00caSUlf Lilleengen */ 341e09c00caSUlf Lilleengen if (sbap != &ip->i_db[0]) { 342e09c00caSUlf Lilleengen if (doasyncfree) 343e09c00caSUlf Lilleengen bdwrite(sbp); 344e09c00caSUlf Lilleengen else 345e09c00caSUlf Lilleengen bwrite(sbp); 346e09c00caSUlf Lilleengen } else { 347e09c00caSUlf Lilleengen ip->i_flag |= IN_CHANGE | IN_UPDATE; 348e09c00caSUlf Lilleengen if (!doasyncfree) 349e09c00caSUlf Lilleengen ext2_update(vp, 1); 350e09c00caSUlf Lilleengen } 351e09c00caSUlf Lilleengen if (ssize < len) { 352e09c00caSUlf Lilleengen if (doasyncfree) 353e09c00caSUlf Lilleengen bdwrite(ebp); 354e09c00caSUlf Lilleengen else 355e09c00caSUlf Lilleengen bwrite(ebp); 356e09c00caSUlf Lilleengen } 357e09c00caSUlf Lilleengen /* 358e09c00caSUlf Lilleengen * Last, free the old blocks and assign the new blocks to the buffers. 359e09c00caSUlf Lilleengen */ 360e09c00caSUlf Lilleengen for (blkno = newblk, i = 0; i < len; i++, blkno += fs->e2fs_fpb) { 361e09c00caSUlf Lilleengen ext2_blkfree(ip, dbtofsb(fs, buflist->bs_children[i]->b_blkno), 362e09c00caSUlf Lilleengen fs->e2fs_bsize); 363e09c00caSUlf Lilleengen buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno); 364ebc94b66SFedor Uporov SDT_PROBE1(ext2fs, , alloc, ext2_reallocblks_blkno, blkno); 365e09c00caSUlf Lilleengen } 366ebc94b66SFedor Uporov 367e09c00caSUlf Lilleengen return (0); 368e09c00caSUlf Lilleengen 369e09c00caSUlf Lilleengen fail: 370e09c00caSUlf Lilleengen if (ssize < len) 371e09c00caSUlf Lilleengen brelse(ebp); 372e09c00caSUlf Lilleengen if (sbap != &ip->i_db[0]) 373e09c00caSUlf Lilleengen brelse(sbp); 374e09c00caSUlf Lilleengen return (ENOSPC); 375e09c00caSUlf Lilleengen } 376e09c00caSUlf Lilleengen 377e09c00caSUlf Lilleengen /* 378e09c00caSUlf Lilleengen * Allocate an inode in the filesystem. 379e09c00caSUlf Lilleengen * 380e09c00caSUlf Lilleengen */ 381e09c00caSUlf Lilleengen int 382a9d1b299SPedro F. Giffuni ext2_valloc(struct vnode *pvp, int mode, struct ucred *cred, struct vnode **vpp) 383e09c00caSUlf Lilleengen { 384035e4e04SPedro F. Giffuni struct timespec ts; 385e09c00caSUlf Lilleengen struct m_ext2fs *fs; 386e09c00caSUlf Lilleengen struct ext2mount *ump; 3873eed9f20SFedor Uporov struct inode *pip; 3883eed9f20SFedor Uporov struct inode *ip; 3893eed9f20SFedor Uporov struct vnode *vp; 3903eed9f20SFedor Uporov struct thread *td; 391e09c00caSUlf Lilleengen ino_t ino, ipref; 392b394cd1eSFedor Uporov int error, cg; 393e09c00caSUlf Lilleengen 394e09c00caSUlf Lilleengen *vpp = NULL; 395e09c00caSUlf Lilleengen pip = VTOI(pvp); 396e09c00caSUlf Lilleengen fs = pip->i_e2fs; 397e09c00caSUlf Lilleengen ump = pip->i_ump; 398e09c00caSUlf Lilleengen 399e09c00caSUlf Lilleengen EXT2_LOCK(ump); 400cd3acfe7SFedor Uporov if (fs->e2fs_ficount == 0) 401e09c00caSUlf Lilleengen goto noinodes; 402e09c00caSUlf Lilleengen /* 403e09c00caSUlf Lilleengen * If it is a directory then obtain a cylinder group based on 404e09c00caSUlf Lilleengen * ext2_dirpref else obtain it using ino_to_cg. The preferred inode is 405e09c00caSUlf Lilleengen * always the next inode. 406e09c00caSUlf Lilleengen */ 407d8ba45e2SEd Maste if ((mode & IFMT) == IFDIR) { 408e09c00caSUlf Lilleengen cg = ext2_dirpref(pip); 409e09c00caSUlf Lilleengen if (fs->e2fs_contigdirs[cg] < 255) 410e09c00caSUlf Lilleengen fs->e2fs_contigdirs[cg]++; 411e09c00caSUlf Lilleengen } else { 412e09c00caSUlf Lilleengen cg = ino_to_cg(fs, pip->i_number); 413e09c00caSUlf Lilleengen if (fs->e2fs_contigdirs[cg] > 0) 414e09c00caSUlf Lilleengen fs->e2fs_contigdirs[cg]--; 415e09c00caSUlf Lilleengen } 416cd3acfe7SFedor Uporov ipref = cg * fs->e2fs_ipg + 1; 417e09c00caSUlf Lilleengen ino = (ino_t)ext2_hashalloc(pip, cg, (long)ipref, mode, ext2_nodealloccg); 418e09c00caSUlf Lilleengen if (ino == 0) 419e09c00caSUlf Lilleengen goto noinodes; 4203eed9f20SFedor Uporov 4213eed9f20SFedor Uporov td = curthread; 4223eed9f20SFedor Uporov error = vfs_hash_get(ump->um_mountp, ino, LK_EXCLUSIVE, td, vpp, NULL, NULL); 4233eed9f20SFedor Uporov if (error || *vpp != NULL) { 424e09c00caSUlf Lilleengen return (error); 425e09c00caSUlf Lilleengen } 426e09c00caSUlf Lilleengen 4273eed9f20SFedor Uporov ip = malloc(sizeof(struct inode), M_EXT2NODE, M_WAITOK | M_ZERO); 4283eed9f20SFedor Uporov 4293eed9f20SFedor Uporov /* Allocate a new vnode/inode. */ 4303eed9f20SFedor Uporov if ((error = getnewvnode("ext2fs", ump->um_mountp, &ext2_vnodeops, &vp)) != 0) { 4313eed9f20SFedor Uporov free(ip, M_EXT2NODE); 4323eed9f20SFedor Uporov return (error); 4333eed9f20SFedor Uporov } 4343eed9f20SFedor Uporov 4350204d1c7SFedor Uporov lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL); 4363eed9f20SFedor Uporov vp->v_data = ip; 4373eed9f20SFedor Uporov ip->i_vnode = vp; 4383eed9f20SFedor Uporov ip->i_e2fs = fs = ump->um_e2fs; 4393eed9f20SFedor Uporov ip->i_ump = ump; 4403eed9f20SFedor Uporov ip->i_number = ino; 4413eed9f20SFedor Uporov ip->i_block_group = ino_to_cg(fs, ino); 4423eed9f20SFedor Uporov ip->i_next_alloc_block = 0; 4433eed9f20SFedor Uporov ip->i_next_alloc_goal = 0; 4443eed9f20SFedor Uporov 4453eed9f20SFedor Uporov error = insmntque(vp, ump->um_mountp); 4463eed9f20SFedor Uporov if (error) { 4473eed9f20SFedor Uporov free(ip, M_EXT2NODE); 4483eed9f20SFedor Uporov return (error); 4493eed9f20SFedor Uporov } 4503eed9f20SFedor Uporov 4513eed9f20SFedor Uporov error = vfs_hash_insert(vp, ino, LK_EXCLUSIVE, td, vpp, NULL, NULL); 4523eed9f20SFedor Uporov if (error || *vpp != NULL) { 4533eed9f20SFedor Uporov *vpp = NULL; 4543eed9f20SFedor Uporov free(ip, M_EXT2NODE); 4553eed9f20SFedor Uporov return (error); 4563eed9f20SFedor Uporov } 4573eed9f20SFedor Uporov 4583eed9f20SFedor Uporov if ((error = ext2_vinit(ump->um_mountp, &ext2_fifoops, &vp)) != 0) { 4593eed9f20SFedor Uporov vput(vp); 4603eed9f20SFedor Uporov *vpp = NULL; 4613eed9f20SFedor Uporov free(ip, M_EXT2NODE); 4623eed9f20SFedor Uporov return (error); 4633eed9f20SFedor Uporov } 4643eed9f20SFedor Uporov 465b394cd1eSFedor Uporov if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_EXTENTS) 466b394cd1eSFedor Uporov && (S_ISREG(mode) || S_ISDIR(mode))) 467b394cd1eSFedor Uporov ext4_ext_tree_init(ip); 468b394cd1eSFedor Uporov else 469b394cd1eSFedor Uporov memset(ip->i_data, 0, sizeof(ip->i_data)); 470b394cd1eSFedor Uporov 471e09c00caSUlf Lilleengen /* 472e09c00caSUlf Lilleengen * Set up a new generation number for this inode. 47343ce40e8SPedro F. Giffuni * Avoid zero values. 474e09c00caSUlf Lilleengen */ 47543ce40e8SPedro F. Giffuni do { 476df04a188SKevin Lo ip->i_gen = arc4random(); 47743ce40e8SPedro F. Giffuni } while (ip->i_gen == 0); 478035e4e04SPedro F. Giffuni 479035e4e04SPedro F. Giffuni vfs_timestamp(&ts); 480035e4e04SPedro F. Giffuni ip->i_birthtime = ts.tv_sec; 481035e4e04SPedro F. Giffuni ip->i_birthnsec = ts.tv_nsec; 482035e4e04SPedro F. Giffuni 4833eed9f20SFedor Uporov *vpp = vp; 4843eed9f20SFedor Uporov 485e09c00caSUlf Lilleengen return (0); 4863eed9f20SFedor Uporov 487e09c00caSUlf Lilleengen noinodes: 488e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 489ebc94b66SFedor Uporov SDT_PROBE2(ext2fs, , alloc, trace, 1, "out of inodes"); 490e09c00caSUlf Lilleengen return (ENOSPC); 491e09c00caSUlf Lilleengen } 492e09c00caSUlf Lilleengen 493e09c00caSUlf Lilleengen /* 4943acd9182SFedor Uporov * 64-bit compatible getters and setters for struct ext2_gd from ext2fs.h 4953acd9182SFedor Uporov */ 4966e38bf94SFedor Uporov uint64_t 4973acd9182SFedor Uporov e2fs_gd_get_b_bitmap(struct ext2_gd *gd) 4983acd9182SFedor Uporov { 4993acd9182SFedor Uporov 500cd3acfe7SFedor Uporov return (((uint64_t)(le32toh(gd->ext4bgd_b_bitmap_hi)) << 32) | 501cd3acfe7SFedor Uporov le32toh(gd->ext2bgd_b_bitmap)); 5023acd9182SFedor Uporov } 5033acd9182SFedor Uporov 5046e38bf94SFedor Uporov uint64_t 5053acd9182SFedor Uporov e2fs_gd_get_i_bitmap(struct ext2_gd *gd) 5063acd9182SFedor Uporov { 5073acd9182SFedor Uporov 508cd3acfe7SFedor Uporov return (((uint64_t)(le32toh(gd->ext4bgd_i_bitmap_hi)) << 32) | 509cd3acfe7SFedor Uporov le32toh(gd->ext2bgd_i_bitmap)); 5103acd9182SFedor Uporov } 5113acd9182SFedor Uporov 5123acd9182SFedor Uporov uint64_t 5133acd9182SFedor Uporov e2fs_gd_get_i_tables(struct ext2_gd *gd) 5143acd9182SFedor Uporov { 5153acd9182SFedor Uporov 516cd3acfe7SFedor Uporov return (((uint64_t)(le32toh(gd->ext4bgd_i_tables_hi)) << 32) | 517cd3acfe7SFedor Uporov le32toh(gd->ext2bgd_i_tables)); 5183acd9182SFedor Uporov } 5193acd9182SFedor Uporov 5203acd9182SFedor Uporov static uint32_t 5213acd9182SFedor Uporov e2fs_gd_get_nbfree(struct ext2_gd *gd) 5223acd9182SFedor Uporov { 5233acd9182SFedor Uporov 524cd3acfe7SFedor Uporov return (((uint32_t)(le16toh(gd->ext4bgd_nbfree_hi)) << 16) | 525cd3acfe7SFedor Uporov le16toh(gd->ext2bgd_nbfree)); 5263acd9182SFedor Uporov } 5273acd9182SFedor Uporov 5283acd9182SFedor Uporov static void 5293acd9182SFedor Uporov e2fs_gd_set_nbfree(struct ext2_gd *gd, uint32_t val) 5303acd9182SFedor Uporov { 5313acd9182SFedor Uporov 532cd3acfe7SFedor Uporov gd->ext2bgd_nbfree = htole16(val & 0xffff); 533cd3acfe7SFedor Uporov gd->ext4bgd_nbfree_hi = htole16(val >> 16); 5343acd9182SFedor Uporov } 5353acd9182SFedor Uporov 5363acd9182SFedor Uporov static uint32_t 5373acd9182SFedor Uporov e2fs_gd_get_nifree(struct ext2_gd *gd) 5383acd9182SFedor Uporov { 5393acd9182SFedor Uporov 540cd3acfe7SFedor Uporov return (((uint32_t)(le16toh(gd->ext4bgd_nifree_hi)) << 16) | 541cd3acfe7SFedor Uporov le16toh(gd->ext2bgd_nifree)); 5423acd9182SFedor Uporov } 5433acd9182SFedor Uporov 5443acd9182SFedor Uporov static void 5453acd9182SFedor Uporov e2fs_gd_set_nifree(struct ext2_gd *gd, uint32_t val) 5463acd9182SFedor Uporov { 5473acd9182SFedor Uporov 548cd3acfe7SFedor Uporov gd->ext2bgd_nifree = htole16(val & 0xffff); 549cd3acfe7SFedor Uporov gd->ext4bgd_nifree_hi = htole16(val >> 16); 5503acd9182SFedor Uporov } 5513acd9182SFedor Uporov 5523acd9182SFedor Uporov uint32_t 5533acd9182SFedor Uporov e2fs_gd_get_ndirs(struct ext2_gd *gd) 5543acd9182SFedor Uporov { 5553acd9182SFedor Uporov 556cd3acfe7SFedor Uporov return (((uint32_t)(le16toh(gd->ext4bgd_ndirs_hi)) << 16) | 557cd3acfe7SFedor Uporov le16toh(gd->ext2bgd_ndirs)); 5583acd9182SFedor Uporov } 5593acd9182SFedor Uporov 5603acd9182SFedor Uporov static void 5613acd9182SFedor Uporov e2fs_gd_set_ndirs(struct ext2_gd *gd, uint32_t val) 5623acd9182SFedor Uporov { 5633acd9182SFedor Uporov 564cd3acfe7SFedor Uporov gd->ext2bgd_ndirs = htole16(val & 0xffff); 565cd3acfe7SFedor Uporov gd->ext4bgd_ndirs_hi = htole16(val >> 16); 5663acd9182SFedor Uporov } 5673acd9182SFedor Uporov 5683acd9182SFedor Uporov static uint32_t 5693acd9182SFedor Uporov e2fs_gd_get_i_unused(struct ext2_gd *gd) 5703acd9182SFedor Uporov { 571cd3acfe7SFedor Uporov return ((uint32_t)(le16toh(gd->ext4bgd_i_unused_hi) << 16) | 572cd3acfe7SFedor Uporov le16toh(gd->ext4bgd_i_unused)); 5733acd9182SFedor Uporov } 5743acd9182SFedor Uporov 5753acd9182SFedor Uporov static void 5763acd9182SFedor Uporov e2fs_gd_set_i_unused(struct ext2_gd *gd, uint32_t val) 5773acd9182SFedor Uporov { 5783acd9182SFedor Uporov 579cd3acfe7SFedor Uporov gd->ext4bgd_i_unused = htole16(val & 0xffff); 580cd3acfe7SFedor Uporov gd->ext4bgd_i_unused_hi = htole16(val >> 16); 5813acd9182SFedor Uporov } 5823acd9182SFedor Uporov 5833acd9182SFedor Uporov /* 584e09c00caSUlf Lilleengen * Find a cylinder to place a directory. 585e09c00caSUlf Lilleengen * 586e09c00caSUlf Lilleengen * The policy implemented by this algorithm is to allocate a 587e09c00caSUlf Lilleengen * directory inode in the same cylinder group as its parent 588e09c00caSUlf Lilleengen * directory, but also to reserve space for its files inodes 589e09c00caSUlf Lilleengen * and data. Restrict the number of directories which may be 590e09c00caSUlf Lilleengen * allocated one after another in the same cylinder group 591e09c00caSUlf Lilleengen * without intervening allocation of files. 592e09c00caSUlf Lilleengen * 593e09c00caSUlf Lilleengen * If we allocate a first level directory then force allocation 594e09c00caSUlf Lilleengen * in another cylinder group. 595e09c00caSUlf Lilleengen * 596e09c00caSUlf Lilleengen */ 597e09c00caSUlf Lilleengen static u_long 598e09c00caSUlf Lilleengen ext2_dirpref(struct inode *pip) 599e09c00caSUlf Lilleengen { 600e09c00caSUlf Lilleengen struct m_ext2fs *fs; 601955ba37bSPedro F. Giffuni int cg, prefcg, cgsize; 6023acd9182SFedor Uporov uint64_t avgbfree, minbfree; 6033acd9182SFedor Uporov u_int avgifree, avgndir, curdirsize; 6043acd9182SFedor Uporov u_int minifree, maxndir; 605f744956bSPedro F. Giffuni u_int mincg, minndir; 606955ba37bSPedro F. Giffuni u_int dirsize, maxcontigdirs; 607e09c00caSUlf Lilleengen 608e09c00caSUlf Lilleengen mtx_assert(EXT2_MTX(pip->i_ump), MA_OWNED); 609e09c00caSUlf Lilleengen fs = pip->i_e2fs; 610e09c00caSUlf Lilleengen 611cd3acfe7SFedor Uporov avgifree = fs->e2fs_ficount / fs->e2fs_gcount; 6123acd9182SFedor Uporov avgbfree = fs->e2fs_fbcount / fs->e2fs_gcount; 613e09c00caSUlf Lilleengen avgndir = fs->e2fs_total_dir / fs->e2fs_gcount; 614e09c00caSUlf Lilleengen 615e09c00caSUlf Lilleengen /* 616e09c00caSUlf Lilleengen * Force allocation in another cg if creating a first level dir. 617e09c00caSUlf Lilleengen */ 618e09c00caSUlf Lilleengen ASSERT_VOP_LOCKED(ITOV(pip), "ext2fs_dirpref"); 619e09c00caSUlf Lilleengen if (ITOV(pip)->v_vflag & VV_ROOT) { 620e09c00caSUlf Lilleengen prefcg = arc4random() % fs->e2fs_gcount; 621e09c00caSUlf Lilleengen mincg = prefcg; 622e09c00caSUlf Lilleengen minndir = fs->e2fs_ipg; 623e09c00caSUlf Lilleengen for (cg = prefcg; cg < fs->e2fs_gcount; cg++) 6243acd9182SFedor Uporov if (e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]) < minndir && 6253acd9182SFedor Uporov e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) >= avgifree && 6263acd9182SFedor Uporov e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) >= avgbfree) { 627e09c00caSUlf Lilleengen mincg = cg; 6283acd9182SFedor Uporov minndir = e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]); 629e09c00caSUlf Lilleengen } 630e09c00caSUlf Lilleengen for (cg = 0; cg < prefcg; cg++) 6313acd9182SFedor Uporov if (e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]) < minndir && 6323acd9182SFedor Uporov e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) >= avgifree && 6333acd9182SFedor Uporov e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) >= avgbfree) { 634e09c00caSUlf Lilleengen mincg = cg; 6353acd9182SFedor Uporov minndir = e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]); 636e09c00caSUlf Lilleengen } 637e09c00caSUlf Lilleengen return (mincg); 638e09c00caSUlf Lilleengen } 639e09c00caSUlf Lilleengen /* 640e09c00caSUlf Lilleengen * Count various limits which used for 641e09c00caSUlf Lilleengen * optimal allocation of a directory inode. 642e09c00caSUlf Lilleengen */ 643e09c00caSUlf Lilleengen maxndir = min(avgndir + fs->e2fs_ipg / 16, fs->e2fs_ipg); 644e09c00caSUlf Lilleengen minifree = avgifree - avgifree / 4; 645e09c00caSUlf Lilleengen if (minifree < 1) 646e09c00caSUlf Lilleengen minifree = 1; 647e09c00caSUlf Lilleengen minbfree = avgbfree - avgbfree / 4; 648e09c00caSUlf Lilleengen if (minbfree < 1) 649e09c00caSUlf Lilleengen minbfree = 1; 650e09c00caSUlf Lilleengen cgsize = fs->e2fs_fsize * fs->e2fs_fpg; 651e09c00caSUlf Lilleengen dirsize = AVGDIRSIZE; 652cd3acfe7SFedor Uporov curdirsize = avgndir ? 653cd3acfe7SFedor Uporov (cgsize - avgbfree * fs->e2fs_bsize) / avgndir : 0; 654e09c00caSUlf Lilleengen if (dirsize < curdirsize) 655e09c00caSUlf Lilleengen dirsize = curdirsize; 656e09c00caSUlf Lilleengen maxcontigdirs = min((avgbfree * fs->e2fs_bsize) / dirsize, 255); 657e09c00caSUlf Lilleengen maxcontigdirs = min(maxcontigdirs, fs->e2fs_ipg / AFPDIR); 658e09c00caSUlf Lilleengen if (maxcontigdirs == 0) 659e09c00caSUlf Lilleengen maxcontigdirs = 1; 660e09c00caSUlf Lilleengen 661e09c00caSUlf Lilleengen /* 662e09c00caSUlf Lilleengen * Limit number of dirs in one cg and reserve space for 663e09c00caSUlf Lilleengen * regular files, but only if we have no deficit in 664e09c00caSUlf Lilleengen * inodes or space. 665e09c00caSUlf Lilleengen */ 666e09c00caSUlf Lilleengen prefcg = ino_to_cg(fs, pip->i_number); 667e09c00caSUlf Lilleengen for (cg = prefcg; cg < fs->e2fs_gcount; cg++) 6683acd9182SFedor Uporov if (e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]) < maxndir && 6693acd9182SFedor Uporov e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) >= minifree && 6703acd9182SFedor Uporov e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) >= minbfree) { 671e09c00caSUlf Lilleengen if (fs->e2fs_contigdirs[cg] < maxcontigdirs) 672e09c00caSUlf Lilleengen return (cg); 673e09c00caSUlf Lilleengen } 674ca73017aSPedro F. Giffuni for (cg = 0; cg < prefcg; cg++) 6753acd9182SFedor Uporov if (e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]) < maxndir && 6763acd9182SFedor Uporov e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) >= minifree && 6773acd9182SFedor Uporov e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) >= minbfree) { 678e09c00caSUlf Lilleengen if (fs->e2fs_contigdirs[cg] < maxcontigdirs) 679e09c00caSUlf Lilleengen return (cg); 680e09c00caSUlf Lilleengen } 681e09c00caSUlf Lilleengen /* 682e09c00caSUlf Lilleengen * This is a backstop when we have deficit in space. 683e09c00caSUlf Lilleengen */ 684e09c00caSUlf Lilleengen for (cg = prefcg; cg < fs->e2fs_gcount; cg++) 6853acd9182SFedor Uporov if (e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) >= avgifree) 686e09c00caSUlf Lilleengen return (cg); 687ca73017aSPedro F. Giffuni for (cg = 0; cg < prefcg; cg++) 6883acd9182SFedor Uporov if (e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) >= avgifree) 689e09c00caSUlf Lilleengen break; 690e09c00caSUlf Lilleengen return (cg); 691e09c00caSUlf Lilleengen } 692e09c00caSUlf Lilleengen 693e09c00caSUlf Lilleengen /* 694e09c00caSUlf Lilleengen * Select the desired position for the next block in a file. 695e09c00caSUlf Lilleengen * 696e09c00caSUlf Lilleengen * we try to mimic what Remy does in inode_getblk/block_getblk 697e09c00caSUlf Lilleengen * 698e09c00caSUlf Lilleengen * we note: blocknr == 0 means that we're about to allocate either 699e09c00caSUlf Lilleengen * a direct block or a pointer block at the first level of indirection 700e09c00caSUlf Lilleengen * (In other words, stuff that will go in i_db[] or i_ib[]) 701e09c00caSUlf Lilleengen * 702e09c00caSUlf Lilleengen * blocknr != 0 means that we're allocating a block that is none 703e09c00caSUlf Lilleengen * of the above. Then, blocknr tells us the number of the block 704e09c00caSUlf Lilleengen * that will hold the pointer 705e09c00caSUlf Lilleengen */ 70670097aacSPedro F. Giffuni e4fs_daddr_t 70770097aacSPedro F. Giffuni ext2_blkpref(struct inode *ip, e2fs_lbn_t lbn, int indx, e2fs_daddr_t *bap, 70870097aacSPedro F. Giffuni e2fs_daddr_t blocknr) 709e09c00caSUlf Lilleengen { 710b394cd1eSFedor Uporov struct m_ext2fs *fs; 711e09c00caSUlf Lilleengen int tmp; 712bf9a211dSPedro F. Giffuni 713b394cd1eSFedor Uporov fs = ip->i_e2fs; 714b394cd1eSFedor Uporov 715e09c00caSUlf Lilleengen mtx_assert(EXT2_MTX(ip->i_ump), MA_OWNED); 716e09c00caSUlf Lilleengen 717bf9a211dSPedro F. Giffuni /* 718bf9a211dSPedro F. Giffuni * If the next block is actually what we thought it is, then set the 719bf9a211dSPedro F. Giffuni * goal to what we thought it should be. 720e09c00caSUlf Lilleengen */ 721e09c00caSUlf Lilleengen if (ip->i_next_alloc_block == lbn && ip->i_next_alloc_goal != 0) 722e09c00caSUlf Lilleengen return ip->i_next_alloc_goal; 723e09c00caSUlf Lilleengen 724bf9a211dSPedro F. Giffuni /* 725bf9a211dSPedro F. Giffuni * Now check whether we were provided with an array that basically 726bf9a211dSPedro F. Giffuni * tells us previous blocks to which we want to stay close. 727e09c00caSUlf Lilleengen */ 728e09c00caSUlf Lilleengen if (bap) 729e09c00caSUlf Lilleengen for (tmp = indx - 1; tmp >= 0; tmp--) 730e09c00caSUlf Lilleengen if (bap[tmp]) 731cd3acfe7SFedor Uporov return (le32toh(bap[tmp])); 732e09c00caSUlf Lilleengen 733bf9a211dSPedro F. Giffuni /* 734bf9a211dSPedro F. Giffuni * Else lets fall back to the blocknr or, if there is none, follow 735bf9a211dSPedro F. Giffuni * the rule that a block should be allocated near its inode. 736e09c00caSUlf Lilleengen */ 737b394cd1eSFedor Uporov return (blocknr ? blocknr : 73870097aacSPedro F. Giffuni (e2fs_daddr_t)(ip->i_block_group * 739cd3acfe7SFedor Uporov EXT2_BLOCKS_PER_GROUP(fs)) + le32toh(fs->e2fs->e2fs_first_dblock)); 740e09c00caSUlf Lilleengen } 741e09c00caSUlf Lilleengen 742e09c00caSUlf Lilleengen /* 743e09c00caSUlf Lilleengen * Implement the cylinder overflow algorithm. 744e09c00caSUlf Lilleengen * 745e09c00caSUlf Lilleengen * The policy implemented by this algorithm is: 746e09c00caSUlf Lilleengen * 1) allocate the block in its requested cylinder group. 747e09c00caSUlf Lilleengen * 2) quadradically rehash on the cylinder group number. 748e09c00caSUlf Lilleengen * 3) brute force search for a free block. 749e09c00caSUlf Lilleengen */ 750ffbde5eaSFedor Uporov static e4fs_daddr_t 751e09c00caSUlf Lilleengen ext2_hashalloc(struct inode *ip, int cg, long pref, int size, 752e09c00caSUlf Lilleengen daddr_t (*allocator) (struct inode *, int, daddr_t, int)) 753e09c00caSUlf Lilleengen { 754e09c00caSUlf Lilleengen struct m_ext2fs *fs; 755ffbde5eaSFedor Uporov e4fs_daddr_t result; 756e09c00caSUlf Lilleengen int i, icg = cg; 757e09c00caSUlf Lilleengen 758e09c00caSUlf Lilleengen mtx_assert(EXT2_MTX(ip->i_ump), MA_OWNED); 759e09c00caSUlf Lilleengen fs = ip->i_e2fs; 760e09c00caSUlf Lilleengen /* 761e09c00caSUlf Lilleengen * 1: preferred cylinder group 762e09c00caSUlf Lilleengen */ 763e09c00caSUlf Lilleengen result = (*allocator)(ip, cg, pref, size); 764e09c00caSUlf Lilleengen if (result) 765e09c00caSUlf Lilleengen return (result); 766e09c00caSUlf Lilleengen /* 767e09c00caSUlf Lilleengen * 2: quadratic rehash 768e09c00caSUlf Lilleengen */ 769e09c00caSUlf Lilleengen for (i = 1; i < fs->e2fs_gcount; i *= 2) { 770e09c00caSUlf Lilleengen cg += i; 771e09c00caSUlf Lilleengen if (cg >= fs->e2fs_gcount) 772e09c00caSUlf Lilleengen cg -= fs->e2fs_gcount; 773e09c00caSUlf Lilleengen result = (*allocator)(ip, cg, 0, size); 774e09c00caSUlf Lilleengen if (result) 775e09c00caSUlf Lilleengen return (result); 776e09c00caSUlf Lilleengen } 777e09c00caSUlf Lilleengen /* 778e09c00caSUlf Lilleengen * 3: brute force search 779e09c00caSUlf Lilleengen * Note that we start at i == 2, since 0 was checked initially, 780e09c00caSUlf Lilleengen * and 1 is always checked in the quadratic rehash. 781e09c00caSUlf Lilleengen */ 782e09c00caSUlf Lilleengen cg = (icg + 2) % fs->e2fs_gcount; 783e09c00caSUlf Lilleengen for (i = 2; i < fs->e2fs_gcount; i++) { 784e09c00caSUlf Lilleengen result = (*allocator)(ip, cg, 0, size); 785e09c00caSUlf Lilleengen if (result) 786e09c00caSUlf Lilleengen return (result); 787e09c00caSUlf Lilleengen cg++; 788e09c00caSUlf Lilleengen if (cg == fs->e2fs_gcount) 789e09c00caSUlf Lilleengen cg = 0; 790e09c00caSUlf Lilleengen } 791e09c00caSUlf Lilleengen return (0); 792e09c00caSUlf Lilleengen } 793e09c00caSUlf Lilleengen 7946e38bf94SFedor Uporov static uint64_t 795c0f16c65SFedor Uporov ext2_cg_number_gdb_nometa(struct m_ext2fs *fs, int cg) 796d23db91eSPedro F. Giffuni { 797d23db91eSPedro F. Giffuni 798d23db91eSPedro F. Giffuni if (!ext2_cg_has_sb(fs, cg)) 799d23db91eSPedro F. Giffuni return (0); 800c0f16c65SFedor Uporov 801d23db91eSPedro F. Giffuni if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_META_BG)) 802cd3acfe7SFedor Uporov return (le32toh(fs->e2fs->e3fs_first_meta_bg)); 803c0f16c65SFedor Uporov 804c0f16c65SFedor Uporov return ((fs->e2fs_gcount + EXT2_DESCS_PER_BLOCK(fs) - 1) / 805c0f16c65SFedor Uporov EXT2_DESCS_PER_BLOCK(fs)); 806d23db91eSPedro F. Giffuni } 807d23db91eSPedro F. Giffuni 8086e38bf94SFedor Uporov static uint64_t 809c0f16c65SFedor Uporov ext2_cg_number_gdb_meta(struct m_ext2fs *fs, int cg) 810c0f16c65SFedor Uporov { 811c0f16c65SFedor Uporov unsigned long metagroup; 812c0f16c65SFedor Uporov int first, last; 813c0f16c65SFedor Uporov 814c0f16c65SFedor Uporov metagroup = cg / EXT2_DESCS_PER_BLOCK(fs); 815c0f16c65SFedor Uporov first = metagroup * EXT2_DESCS_PER_BLOCK(fs); 816c0f16c65SFedor Uporov last = first + EXT2_DESCS_PER_BLOCK(fs) - 1; 817c0f16c65SFedor Uporov 818d23db91eSPedro F. Giffuni if (cg == first || cg == first + 1 || cg == last) 819d23db91eSPedro F. Giffuni return (1); 820d23db91eSPedro F. Giffuni 821c0f16c65SFedor Uporov return (0); 822c0f16c65SFedor Uporov } 823c0f16c65SFedor Uporov 8246e38bf94SFedor Uporov uint64_t 825c0f16c65SFedor Uporov ext2_cg_number_gdb(struct m_ext2fs *fs, int cg) 826c0f16c65SFedor Uporov { 827c0f16c65SFedor Uporov unsigned long first_meta_bg, metagroup; 828c0f16c65SFedor Uporov 829cd3acfe7SFedor Uporov first_meta_bg = le32toh(fs->e2fs->e3fs_first_meta_bg); 830c0f16c65SFedor Uporov metagroup = cg / EXT2_DESCS_PER_BLOCK(fs); 831c0f16c65SFedor Uporov 832c0f16c65SFedor Uporov if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_META_BG) || 833c0f16c65SFedor Uporov metagroup < first_meta_bg) 834c0f16c65SFedor Uporov return (ext2_cg_number_gdb_nometa(fs, cg)); 835c0f16c65SFedor Uporov 836c0f16c65SFedor Uporov return ext2_cg_number_gdb_meta(fs, cg); 837d23db91eSPedro F. Giffuni } 838d23db91eSPedro F. Giffuni 839d23db91eSPedro F. Giffuni static int 840c0f16c65SFedor Uporov ext2_number_base_meta_blocks(struct m_ext2fs *fs, int cg) 841d23db91eSPedro F. Giffuni { 842c0f16c65SFedor Uporov int number; 843d23db91eSPedro F. Giffuni 844c0f16c65SFedor Uporov number = ext2_cg_has_sb(fs, cg); 845d23db91eSPedro F. Giffuni 846d23db91eSPedro F. Giffuni if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_META_BG) || 847cd3acfe7SFedor Uporov cg < le32toh(fs->e2fs->e3fs_first_meta_bg) * 848cd3acfe7SFedor Uporov EXT2_DESCS_PER_BLOCK(fs)) { 849c0f16c65SFedor Uporov if (number) { 850c0f16c65SFedor Uporov number += ext2_cg_number_gdb(fs, cg); 851cd3acfe7SFedor Uporov number += le16toh(fs->e2fs->e2fs_reserved_ngdb); 852d23db91eSPedro F. Giffuni } 853d23db91eSPedro F. Giffuni } else { 854c0f16c65SFedor Uporov number += ext2_cg_number_gdb(fs, cg); 855d23db91eSPedro F. Giffuni } 856d23db91eSPedro F. Giffuni 857c0f16c65SFedor Uporov return (number); 858d23db91eSPedro F. Giffuni } 859d23db91eSPedro F. Giffuni 860d23db91eSPedro F. Giffuni static void 861d23db91eSPedro F. Giffuni ext2_mark_bitmap_end(int start_bit, int end_bit, char *bitmap) 862d23db91eSPedro F. Giffuni { 863d23db91eSPedro F. Giffuni int i; 864d23db91eSPedro F. Giffuni 865d23db91eSPedro F. Giffuni if (start_bit >= end_bit) 866d23db91eSPedro F. Giffuni return; 867d23db91eSPedro F. Giffuni 868d23db91eSPedro F. Giffuni for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++) 869d23db91eSPedro F. Giffuni setbit(bitmap, i); 870d23db91eSPedro F. Giffuni if (i < end_bit) 871d23db91eSPedro F. Giffuni memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3); 872d23db91eSPedro F. Giffuni } 873d23db91eSPedro F. Giffuni 874d23db91eSPedro F. Giffuni static int 875c0f16c65SFedor Uporov ext2_get_group_number(struct m_ext2fs *fs, e4fs_daddr_t block) 876c0f16c65SFedor Uporov { 877c0f16c65SFedor Uporov 878cd3acfe7SFedor Uporov return ((block - le32toh(fs->e2fs->e2fs_first_dblock)) / 879cd3acfe7SFedor Uporov fs->e2fs_bsize); 880c0f16c65SFedor Uporov } 881c0f16c65SFedor Uporov 882c0f16c65SFedor Uporov static int 883c0f16c65SFedor Uporov ext2_block_in_group(struct m_ext2fs *fs, e4fs_daddr_t block, int cg) 884c0f16c65SFedor Uporov { 885c0f16c65SFedor Uporov 886c0f16c65SFedor Uporov return ((ext2_get_group_number(fs, block) == cg) ? 1 : 0); 887c0f16c65SFedor Uporov } 888c0f16c65SFedor Uporov 889c0f16c65SFedor Uporov static int 890d23db91eSPedro F. Giffuni ext2_cg_block_bitmap_init(struct m_ext2fs *fs, int cg, struct buf *bp) 891d23db91eSPedro F. Giffuni { 892d23db91eSPedro F. Giffuni int bit, bit_max, inodes_per_block; 8933acd9182SFedor Uporov uint64_t start, tmp; 894d23db91eSPedro F. Giffuni 895cd3acfe7SFedor Uporov if (!(le16toh(fs->e2fs_gd[cg].ext4bgd_flags) & EXT2_BG_BLOCK_UNINIT)) 896d23db91eSPedro F. Giffuni return (0); 897d23db91eSPedro F. Giffuni 898d23db91eSPedro F. Giffuni memset(bp->b_data, 0, fs->e2fs_bsize); 899d23db91eSPedro F. Giffuni 900c0f16c65SFedor Uporov bit_max = ext2_number_base_meta_blocks(fs, cg); 901d23db91eSPedro F. Giffuni if ((bit_max >> 3) >= fs->e2fs_bsize) 902d23db91eSPedro F. Giffuni return (EINVAL); 903d23db91eSPedro F. Giffuni 904d23db91eSPedro F. Giffuni for (bit = 0; bit < bit_max; bit++) 905d23db91eSPedro F. Giffuni setbit(bp->b_data, bit); 906d23db91eSPedro F. Giffuni 907cd3acfe7SFedor Uporov start = (uint64_t)cg * fs->e2fs_bpg + 908cd3acfe7SFedor Uporov le32toh(fs->e2fs->e2fs_first_dblock); 909d23db91eSPedro F. Giffuni 9103acd9182SFedor Uporov /* Set bits for block and inode bitmaps, and inode table. */ 9113acd9182SFedor Uporov tmp = e2fs_gd_get_b_bitmap(&fs->e2fs_gd[cg]); 912d23db91eSPedro F. Giffuni if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_FLEX_BG) || 913c0f16c65SFedor Uporov ext2_block_in_group(fs, tmp, cg)) 914d23db91eSPedro F. Giffuni setbit(bp->b_data, tmp - start); 915d23db91eSPedro F. Giffuni 9163acd9182SFedor Uporov tmp = e2fs_gd_get_i_bitmap(&fs->e2fs_gd[cg]); 917d23db91eSPedro F. Giffuni if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_FLEX_BG) || 918c0f16c65SFedor Uporov ext2_block_in_group(fs, tmp, cg)) 919d23db91eSPedro F. Giffuni setbit(bp->b_data, tmp - start); 920d23db91eSPedro F. Giffuni 9213acd9182SFedor Uporov tmp = e2fs_gd_get_i_tables(&fs->e2fs_gd[cg]); 922d23db91eSPedro F. Giffuni inodes_per_block = fs->e2fs_bsize/EXT2_INODE_SIZE(fs); 9233acd9182SFedor Uporov while( tmp < e2fs_gd_get_i_tables(&fs->e2fs_gd[cg]) + 924cd3acfe7SFedor Uporov fs->e2fs_ipg / inodes_per_block ) { 925d23db91eSPedro F. Giffuni if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_FLEX_BG) || 926c0f16c65SFedor Uporov ext2_block_in_group(fs, tmp, cg)) 927d23db91eSPedro F. Giffuni setbit(bp->b_data, tmp - start); 928d23db91eSPedro F. Giffuni tmp++; 929d23db91eSPedro F. Giffuni } 930d23db91eSPedro F. Giffuni 931d23db91eSPedro F. Giffuni /* 932d23db91eSPedro F. Giffuni * Also if the number of blocks within the group is less than 933d23db91eSPedro F. Giffuni * the blocksize * 8 ( which is the size of bitmap ), set rest 934d23db91eSPedro F. Giffuni * of the block bitmap to 1 935d23db91eSPedro F. Giffuni */ 936cd3acfe7SFedor Uporov ext2_mark_bitmap_end(fs->e2fs_bpg, fs->e2fs_bsize * 8, 937d23db91eSPedro F. Giffuni bp->b_data); 938d23db91eSPedro F. Giffuni 939d23db91eSPedro F. Giffuni /* Clean the flag */ 940cd3acfe7SFedor Uporov fs->e2fs_gd[cg].ext4bgd_flags = htole16(le16toh( 941cd3acfe7SFedor Uporov fs->e2fs_gd[cg].ext4bgd_flags) & ~EXT2_BG_BLOCK_UNINIT); 942d23db91eSPedro F. Giffuni 943d23db91eSPedro F. Giffuni return (0); 944d23db91eSPedro F. Giffuni } 945d23db91eSPedro F. Giffuni 94680a4a971SFedor Uporov static int 94780a4a971SFedor Uporov ext2_b_bitmap_validate(struct m_ext2fs *fs, struct buf *bp, int cg) 94880a4a971SFedor Uporov { 94980a4a971SFedor Uporov struct ext2_gd *gd; 95080a4a971SFedor Uporov uint64_t group_first_block; 95180a4a971SFedor Uporov unsigned int offset, max_bit; 95280a4a971SFedor Uporov 95380a4a971SFedor Uporov if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_FLEX_BG)) { 95480a4a971SFedor Uporov /* 955cd3acfe7SFedor Uporov * It is not possible to check block bitmap in case of this 956cd3acfe7SFedor Uporov * feature, because the inode and block bitmaps and inode table 95780a4a971SFedor Uporov * blocks may not be in the group at all. 95880a4a971SFedor Uporov * So, skip check in this case. 95980a4a971SFedor Uporov */ 96080a4a971SFedor Uporov return (0); 96180a4a971SFedor Uporov } 96280a4a971SFedor Uporov 96380a4a971SFedor Uporov gd = &fs->e2fs_gd[cg]; 96480a4a971SFedor Uporov max_bit = fs->e2fs_fpg; 965cd3acfe7SFedor Uporov group_first_block = ((uint64_t)cg) * fs->e2fs_fpg + 966cd3acfe7SFedor Uporov le32toh(fs->e2fs->e2fs_first_dblock); 96780a4a971SFedor Uporov 96880a4a971SFedor Uporov /* Check block bitmap block number */ 96980a4a971SFedor Uporov offset = e2fs_gd_get_b_bitmap(gd) - group_first_block; 97080a4a971SFedor Uporov if (offset >= max_bit || !isset(bp->b_data, offset)) { 971ebc94b66SFedor Uporov SDT_PROBE2(ext2fs, , alloc, ext2_b_bitmap_validate_error, 972ebc94b66SFedor Uporov "bad block bitmap, group", cg); 97380a4a971SFedor Uporov return (EINVAL); 97480a4a971SFedor Uporov } 97580a4a971SFedor Uporov 97680a4a971SFedor Uporov /* Check inode bitmap block number */ 97780a4a971SFedor Uporov offset = e2fs_gd_get_i_bitmap(gd) - group_first_block; 97880a4a971SFedor Uporov if (offset >= max_bit || !isset(bp->b_data, offset)) { 979ebc94b66SFedor Uporov SDT_PROBE2(ext2fs, , alloc, ext2_b_bitmap_validate_error, 980ebc94b66SFedor Uporov "bad inode bitmap", cg); 98180a4a971SFedor Uporov return (EINVAL); 98280a4a971SFedor Uporov } 98380a4a971SFedor Uporov 98480a4a971SFedor Uporov /* Check inode table */ 98580a4a971SFedor Uporov offset = e2fs_gd_get_i_tables(gd) - group_first_block; 98680a4a971SFedor Uporov if (offset >= max_bit || offset + fs->e2fs_itpg >= max_bit) { 987ebc94b66SFedor Uporov SDT_PROBE2(ext2fs, , alloc, ext2_b_bitmap_validate_error, 988ebc94b66SFedor Uporov "bad inode table, group", cg); 98980a4a971SFedor Uporov return (EINVAL); 99080a4a971SFedor Uporov } 99180a4a971SFedor Uporov 99280a4a971SFedor Uporov return (0); 99380a4a971SFedor Uporov } 99480a4a971SFedor Uporov 995e09c00caSUlf Lilleengen /* 996e09c00caSUlf Lilleengen * Determine whether a block can be allocated. 997e09c00caSUlf Lilleengen * 998e09c00caSUlf Lilleengen * Check to see if a block of the appropriate size is available, 999e09c00caSUlf Lilleengen * and if it is, allocate it. 1000e09c00caSUlf Lilleengen */ 1001e09c00caSUlf Lilleengen static daddr_t 1002e09c00caSUlf Lilleengen ext2_alloccg(struct inode *ip, int cg, daddr_t bpref, int size) 1003e09c00caSUlf Lilleengen { 1004e09c00caSUlf Lilleengen struct m_ext2fs *fs; 1005e09c00caSUlf Lilleengen struct buf *bp; 1006e09c00caSUlf Lilleengen struct ext2mount *ump; 1007c767faa5SJohn Baldwin daddr_t bno, runstart, runlen; 1008c767faa5SJohn Baldwin int bit, loc, end, error, start; 1009e09c00caSUlf Lilleengen char *bbp; 1010e09c00caSUlf Lilleengen /* XXX ondisk32 */ 1011e09c00caSUlf Lilleengen fs = ip->i_e2fs; 1012e09c00caSUlf Lilleengen ump = ip->i_ump; 10133acd9182SFedor Uporov if (e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) == 0) 1014e09c00caSUlf Lilleengen return (0); 101580a4a971SFedor Uporov 1016e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 1017e09c00caSUlf Lilleengen error = bread(ip->i_devvp, fsbtodb(fs, 10183acd9182SFedor Uporov e2fs_gd_get_b_bitmap(&fs->e2fs_gd[cg])), 1019e09c00caSUlf Lilleengen (int)fs->e2fs_bsize, NOCRED, &bp); 102080a4a971SFedor Uporov if (error) 102180a4a971SFedor Uporov goto fail; 102280a4a971SFedor Uporov 1023512f29d1SFedor Uporov if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) || 1024512f29d1SFedor Uporov EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { 1025d23db91eSPedro F. Giffuni error = ext2_cg_block_bitmap_init(fs, cg, bp); 102680a4a971SFedor Uporov if (error) 102780a4a971SFedor Uporov goto fail; 102880a4a971SFedor Uporov 1029512f29d1SFedor Uporov ext2_gd_b_bitmap_csum_set(fs, cg, bp); 1030512f29d1SFedor Uporov } 1031512f29d1SFedor Uporov error = ext2_gd_b_bitmap_csum_verify(fs, cg, bp); 103280a4a971SFedor Uporov if (error) 103380a4a971SFedor Uporov goto fail; 103480a4a971SFedor Uporov 103580a4a971SFedor Uporov error = ext2_b_bitmap_validate(fs,bp, cg); 103680a4a971SFedor Uporov if (error) 103780a4a971SFedor Uporov goto fail; 103880a4a971SFedor Uporov 103973dd6d1fSJohn Baldwin /* 1040cd3acfe7SFedor Uporov * Check, that another thread did not not allocate the last block in 1041cd3acfe7SFedor Uporov * this group while we were waiting for the buffer. 104273dd6d1fSJohn Baldwin */ 104380a4a971SFedor Uporov if (e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) == 0) 104480a4a971SFedor Uporov goto fail; 104580a4a971SFedor Uporov 1046e09c00caSUlf Lilleengen bbp = (char *)bp->b_data; 1047e09c00caSUlf Lilleengen 1048e09c00caSUlf Lilleengen if (dtog(fs, bpref) != cg) 1049e09c00caSUlf Lilleengen bpref = 0; 1050e09c00caSUlf Lilleengen if (bpref != 0) { 1051e09c00caSUlf Lilleengen bpref = dtogd(fs, bpref); 1052e09c00caSUlf Lilleengen /* 1053e09c00caSUlf Lilleengen * if the requested block is available, use it 1054e09c00caSUlf Lilleengen */ 1055e09c00caSUlf Lilleengen if (isclr(bbp, bpref)) { 1056e09c00caSUlf Lilleengen bno = bpref; 1057e09c00caSUlf Lilleengen goto gotit; 1058e09c00caSUlf Lilleengen } 1059e09c00caSUlf Lilleengen } 1060e09c00caSUlf Lilleengen /* 1061e09c00caSUlf Lilleengen * no blocks in the requested cylinder, so take next 1062e09c00caSUlf Lilleengen * available one in this cylinder group. 1063e09c00caSUlf Lilleengen * first try to get 8 contigous blocks, then fall back to a single 1064e09c00caSUlf Lilleengen * block. 1065e09c00caSUlf Lilleengen */ 1066e09c00caSUlf Lilleengen if (bpref) 1067e09c00caSUlf Lilleengen start = dtogd(fs, bpref) / NBBY; 1068e09c00caSUlf Lilleengen else 1069e09c00caSUlf Lilleengen start = 0; 1070cd3acfe7SFedor Uporov end = howmany(fs->e2fs_fpg, NBBY) - start; 1071c767faa5SJohn Baldwin retry: 1072c767faa5SJohn Baldwin runlen = 0; 1073c767faa5SJohn Baldwin runstart = 0; 1074e09c00caSUlf Lilleengen for (loc = start; loc < end; loc++) { 1075c767faa5SJohn Baldwin if (bbp[loc] == (char)0xff) { 1076c767faa5SJohn Baldwin runlen = 0; 1077c767faa5SJohn Baldwin continue; 1078c767faa5SJohn Baldwin } 1079c767faa5SJohn Baldwin 1080c767faa5SJohn Baldwin /* Start of a run, find the number of high clear bits. */ 1081c767faa5SJohn Baldwin if (runlen == 0) { 1082c767faa5SJohn Baldwin bit = fls(bbp[loc]); 1083c767faa5SJohn Baldwin runlen = NBBY - bit; 1084c767faa5SJohn Baldwin runstart = loc * NBBY + bit; 1085c767faa5SJohn Baldwin } else if (bbp[loc] == 0) { 1086c767faa5SJohn Baldwin /* Continue a run. */ 1087c767faa5SJohn Baldwin runlen += NBBY; 1088c767faa5SJohn Baldwin } else { 1089c767faa5SJohn Baldwin /* 1090c767faa5SJohn Baldwin * Finish the current run. If it isn't long 1091c767faa5SJohn Baldwin * enough, start a new one. 1092c767faa5SJohn Baldwin */ 1093c767faa5SJohn Baldwin bit = ffs(bbp[loc]) - 1; 1094c767faa5SJohn Baldwin runlen += bit; 1095c767faa5SJohn Baldwin if (runlen >= 8) { 1096c767faa5SJohn Baldwin bno = runstart; 1097c767faa5SJohn Baldwin goto gotit; 1098c767faa5SJohn Baldwin } 1099c767faa5SJohn Baldwin 1100c767faa5SJohn Baldwin /* Run was too short, start a new one. */ 1101c767faa5SJohn Baldwin bit = fls(bbp[loc]); 1102c767faa5SJohn Baldwin runlen = NBBY - bit; 1103c767faa5SJohn Baldwin runstart = loc * NBBY + bit; 1104c767faa5SJohn Baldwin } 1105c767faa5SJohn Baldwin 1106c767faa5SJohn Baldwin /* If the current run is long enough, use it. */ 1107c767faa5SJohn Baldwin if (runlen >= 8) { 1108c767faa5SJohn Baldwin bno = runstart; 1109e09c00caSUlf Lilleengen goto gotit; 1110e09c00caSUlf Lilleengen } 1111e09c00caSUlf Lilleengen } 1112c767faa5SJohn Baldwin if (start != 0) { 1113c767faa5SJohn Baldwin end = start; 1114c767faa5SJohn Baldwin start = 0; 1115c767faa5SJohn Baldwin goto retry; 1116e09c00caSUlf Lilleengen } 1117e09c00caSUlf Lilleengen bno = ext2_mapsearch(fs, bbp, bpref); 111880a4a971SFedor Uporov if (bno < 0) 111980a4a971SFedor Uporov goto fail; 112080a4a971SFedor Uporov 1121e09c00caSUlf Lilleengen gotit: 112277b193c2SPedro F. Giffuni #ifdef INVARIANTS 11238e42a406SJohn Baldwin if (isset(bbp, bno)) { 11248e42a406SJohn Baldwin printf("ext2fs_alloccgblk: cg=%d bno=%jd fs=%s\n", 11258e42a406SJohn Baldwin cg, (intmax_t)bno, fs->e2fs_fsmnt); 1126e09c00caSUlf Lilleengen panic("ext2fs_alloccg: dup alloc"); 1127e09c00caSUlf Lilleengen } 1128e09c00caSUlf Lilleengen #endif 11298e42a406SJohn Baldwin setbit(bbp, bno); 1130e09c00caSUlf Lilleengen EXT2_LOCK(ump); 11315b63c125SPedro F. Giffuni ext2_clusteracct(fs, bbp, cg, bno, -1); 11323acd9182SFedor Uporov fs->e2fs_fbcount--; 11333acd9182SFedor Uporov e2fs_gd_set_nbfree(&fs->e2fs_gd[cg], 11343acd9182SFedor Uporov e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) - 1); 1135e09c00caSUlf Lilleengen fs->e2fs_fmod = 1; 1136e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 1137512f29d1SFedor Uporov ext2_gd_b_bitmap_csum_set(fs, cg, bp); 1138e09c00caSUlf Lilleengen bdwrite(bp); 1139cd3acfe7SFedor Uporov return (((uint64_t)cg) * fs->e2fs_fpg + 1140cd3acfe7SFedor Uporov le32toh(fs->e2fs->e2fs_first_dblock) + bno); 114180a4a971SFedor Uporov 114280a4a971SFedor Uporov fail: 114380a4a971SFedor Uporov brelse(bp); 114480a4a971SFedor Uporov EXT2_LOCK(ump); 114580a4a971SFedor Uporov return (0); 1146e09c00caSUlf Lilleengen } 1147e09c00caSUlf Lilleengen 1148e09c00caSUlf Lilleengen /* 11495b63c125SPedro F. Giffuni * Determine whether a cluster can be allocated. 11505b63c125SPedro F. Giffuni */ 11515b63c125SPedro F. Giffuni static daddr_t 11525b63c125SPedro F. Giffuni ext2_clusteralloc(struct inode *ip, int cg, daddr_t bpref, int len) 11535b63c125SPedro F. Giffuni { 11545b63c125SPedro F. Giffuni struct m_ext2fs *fs; 11555b63c125SPedro F. Giffuni struct ext2mount *ump; 11565b63c125SPedro F. Giffuni struct buf *bp; 11575b63c125SPedro F. Giffuni char *bbp; 11585b63c125SPedro F. Giffuni int bit, error, got, i, loc, run; 11595b63c125SPedro F. Giffuni int32_t *lp; 11605b63c125SPedro F. Giffuni daddr_t bno; 11615b63c125SPedro F. Giffuni 11625b63c125SPedro F. Giffuni fs = ip->i_e2fs; 11635b63c125SPedro F. Giffuni ump = ip->i_ump; 11645b63c125SPedro F. Giffuni 11655b63c125SPedro F. Giffuni if (fs->e2fs_maxcluster[cg] < len) 11665b63c125SPedro F. Giffuni return (0); 11675b63c125SPedro F. Giffuni 11685b63c125SPedro F. Giffuni EXT2_UNLOCK(ump); 11695b63c125SPedro F. Giffuni error = bread(ip->i_devvp, 11703acd9182SFedor Uporov fsbtodb(fs, e2fs_gd_get_b_bitmap(&fs->e2fs_gd[cg])), 11715b63c125SPedro F. Giffuni (int)fs->e2fs_bsize, NOCRED, &bp); 11725b63c125SPedro F. Giffuni if (error) 11735b63c125SPedro F. Giffuni goto fail_lock; 11745b63c125SPedro F. Giffuni 11755b63c125SPedro F. Giffuni bbp = (char *)bp->b_data; 11765b63c125SPedro F. Giffuni EXT2_LOCK(ump); 11775b63c125SPedro F. Giffuni /* 11785b63c125SPedro F. Giffuni * Check to see if a cluster of the needed size (or bigger) is 11795b63c125SPedro F. Giffuni * available in this cylinder group. 11805b63c125SPedro F. Giffuni */ 11815b63c125SPedro F. Giffuni lp = &fs->e2fs_clustersum[cg].cs_sum[len]; 11825b63c125SPedro F. Giffuni for (i = len; i <= fs->e2fs_contigsumsize; i++) 11835b63c125SPedro F. Giffuni if (*lp++ > 0) 11845b63c125SPedro F. Giffuni break; 11855b63c125SPedro F. Giffuni if (i > fs->e2fs_contigsumsize) { 11865b63c125SPedro F. Giffuni /* 11875b63c125SPedro F. Giffuni * Update the cluster summary information to reflect 11885b63c125SPedro F. Giffuni * the true maximum-sized cluster so that future cluster 11895b63c125SPedro F. Giffuni * allocation requests can avoid reading the bitmap only 11905b63c125SPedro F. Giffuni * to find no cluster. 11915b63c125SPedro F. Giffuni */ 11925b63c125SPedro F. Giffuni lp = &fs->e2fs_clustersum[cg].cs_sum[len - 1]; 11935b63c125SPedro F. Giffuni for (i = len - 1; i > 0; i--) 11945b63c125SPedro F. Giffuni if (*lp-- > 0) 11955b63c125SPedro F. Giffuni break; 11965b63c125SPedro F. Giffuni fs->e2fs_maxcluster[cg] = i; 11975b63c125SPedro F. Giffuni goto fail; 11985b63c125SPedro F. Giffuni } 11995b63c125SPedro F. Giffuni EXT2_UNLOCK(ump); 12005b63c125SPedro F. Giffuni 12015b63c125SPedro F. Giffuni /* Search the bitmap to find a big enough cluster like in FFS. */ 12025b63c125SPedro F. Giffuni if (dtog(fs, bpref) != cg) 12035b63c125SPedro F. Giffuni bpref = 0; 12045b63c125SPedro F. Giffuni if (bpref != 0) 12055b63c125SPedro F. Giffuni bpref = dtogd(fs, bpref); 12065b63c125SPedro F. Giffuni loc = bpref / NBBY; 12075b63c125SPedro F. Giffuni bit = 1 << (bpref % NBBY); 1208cd3acfe7SFedor Uporov for (run = 0, got = bpref; got < fs->e2fs_fpg; got++) { 12095b63c125SPedro F. Giffuni if ((bbp[loc] & bit) != 0) 12105b63c125SPedro F. Giffuni run = 0; 12115b63c125SPedro F. Giffuni else { 12125b63c125SPedro F. Giffuni run++; 12135b63c125SPedro F. Giffuni if (run == len) 12145b63c125SPedro F. Giffuni break; 12155b63c125SPedro F. Giffuni } 12165b63c125SPedro F. Giffuni if ((got & (NBBY - 1)) != (NBBY - 1)) 12175b63c125SPedro F. Giffuni bit <<= 1; 12185b63c125SPedro F. Giffuni else { 12195b63c125SPedro F. Giffuni loc++; 12205b63c125SPedro F. Giffuni bit = 1; 12215b63c125SPedro F. Giffuni } 12225b63c125SPedro F. Giffuni } 12235b63c125SPedro F. Giffuni 1224cd3acfe7SFedor Uporov if (got >= fs->e2fs_fpg) 12255b63c125SPedro F. Giffuni goto fail_lock; 12265b63c125SPedro F. Giffuni 12275b63c125SPedro F. Giffuni /* Allocate the cluster that we found. */ 12285b63c125SPedro F. Giffuni for (i = 1; i < len; i++) 12295b63c125SPedro F. Giffuni if (!isclr(bbp, got - run + i)) 12305b63c125SPedro F. Giffuni panic("ext2_clusteralloc: map mismatch"); 12315b63c125SPedro F. Giffuni 12325b63c125SPedro F. Giffuni bno = got - run + 1; 1233cd3acfe7SFedor Uporov if (bno >= fs->e2fs_fpg) 12345b63c125SPedro F. Giffuni panic("ext2_clusteralloc: allocated out of group"); 12355b63c125SPedro F. Giffuni 12365b63c125SPedro F. Giffuni EXT2_LOCK(ump); 12375b63c125SPedro F. Giffuni for (i = 0; i < len; i += fs->e2fs_fpb) { 12385b63c125SPedro F. Giffuni setbit(bbp, bno + i); 12395b63c125SPedro F. Giffuni ext2_clusteracct(fs, bbp, cg, bno + i, -1); 12403acd9182SFedor Uporov fs->e2fs_fbcount--; 12413acd9182SFedor Uporov e2fs_gd_set_nbfree(&fs->e2fs_gd[cg], 12423acd9182SFedor Uporov e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) - 1); 12435b63c125SPedro F. Giffuni } 12445b63c125SPedro F. Giffuni fs->e2fs_fmod = 1; 12455b63c125SPedro F. Giffuni EXT2_UNLOCK(ump); 12465b63c125SPedro F. Giffuni 12475b63c125SPedro F. Giffuni bdwrite(bp); 1248cd3acfe7SFedor Uporov return (cg * fs->e2fs_fpg + le32toh(fs->e2fs->e2fs_first_dblock) 1249cd3acfe7SFedor Uporov + bno); 12505b63c125SPedro F. Giffuni 12515b63c125SPedro F. Giffuni fail_lock: 12525b63c125SPedro F. Giffuni EXT2_LOCK(ump); 12535b63c125SPedro F. Giffuni fail: 12545b63c125SPedro F. Giffuni brelse(bp); 12555b63c125SPedro F. Giffuni return (0); 12565b63c125SPedro F. Giffuni } 12575b63c125SPedro F. Giffuni 1258d23db91eSPedro F. Giffuni static int 1259d23db91eSPedro F. Giffuni ext2_zero_inode_table(struct inode *ip, int cg) 1260d23db91eSPedro F. Giffuni { 1261d23db91eSPedro F. Giffuni struct m_ext2fs *fs; 1262d23db91eSPedro F. Giffuni struct buf *bp; 1263d23db91eSPedro F. Giffuni int i, all_blks, used_blks; 1264d23db91eSPedro F. Giffuni 1265d23db91eSPedro F. Giffuni fs = ip->i_e2fs; 1266d23db91eSPedro F. Giffuni 1267cd3acfe7SFedor Uporov if (le16toh(fs->e2fs_gd[cg].ext4bgd_flags) & EXT2_BG_INODE_ZEROED) 1268d23db91eSPedro F. Giffuni return (0); 1269d23db91eSPedro F. Giffuni 1270cd3acfe7SFedor Uporov all_blks = le16toh(fs->e2fs->e2fs_inode_size) * fs->e2fs_ipg / 1271d23db91eSPedro F. Giffuni fs->e2fs_bsize; 1272d23db91eSPedro F. Giffuni 1273cd3acfe7SFedor Uporov used_blks = howmany(fs->e2fs_ipg - 12743acd9182SFedor Uporov e2fs_gd_get_i_unused(&fs->e2fs_gd[cg]), 1275d23db91eSPedro F. Giffuni fs->e2fs_bsize / EXT2_INODE_SIZE(fs)); 1276d23db91eSPedro F. Giffuni 1277d23db91eSPedro F. Giffuni for (i = 0; i < all_blks - used_blks; i++) { 1278d23db91eSPedro F. Giffuni bp = getblk(ip->i_devvp, fsbtodb(fs, 12793acd9182SFedor Uporov e2fs_gd_get_i_tables(&fs->e2fs_gd[cg]) + used_blks + i), 1280d23db91eSPedro F. Giffuni fs->e2fs_bsize, 0, 0, 0); 1281d23db91eSPedro F. Giffuni if (!bp) 1282d23db91eSPedro F. Giffuni return (EIO); 1283d23db91eSPedro F. Giffuni 1284d23db91eSPedro F. Giffuni vfs_bio_bzero_buf(bp, 0, fs->e2fs_bsize); 1285d23db91eSPedro F. Giffuni bawrite(bp); 1286d23db91eSPedro F. Giffuni } 1287d23db91eSPedro F. Giffuni 1288cd3acfe7SFedor Uporov fs->e2fs_gd[cg].ext4bgd_flags = htole16(le16toh( 1289cd3acfe7SFedor Uporov fs->e2fs_gd[cg].ext4bgd_flags) | EXT2_BG_INODE_ZEROED); 1290d23db91eSPedro F. Giffuni 1291d23db91eSPedro F. Giffuni return (0); 1292d23db91eSPedro F. Giffuni } 1293d23db91eSPedro F. Giffuni 1294ec81c9ccSFedor Uporov static void 1295ec81c9ccSFedor Uporov ext2_fix_bitmap_tail(unsigned char *bitmap, int first, int last) 1296ec81c9ccSFedor Uporov { 1297ec81c9ccSFedor Uporov int i; 1298ec81c9ccSFedor Uporov 1299ec81c9ccSFedor Uporov for (i = first; i <= last; i++) 1300ec81c9ccSFedor Uporov bitmap[i] = 0xff; 1301ec81c9ccSFedor Uporov } 1302ec81c9ccSFedor Uporov 13035b63c125SPedro F. Giffuni /* 1304e09c00caSUlf Lilleengen * Determine whether an inode can be allocated. 1305e09c00caSUlf Lilleengen * 1306e09c00caSUlf Lilleengen * Check to see if an inode is available, and if it is, 1307e09c00caSUlf Lilleengen * allocate it using tode in the specified cylinder group. 1308e09c00caSUlf Lilleengen */ 1309e09c00caSUlf Lilleengen static daddr_t 1310e09c00caSUlf Lilleengen ext2_nodealloccg(struct inode *ip, int cg, daddr_t ipref, int mode) 1311e09c00caSUlf Lilleengen { 1312e09c00caSUlf Lilleengen struct m_ext2fs *fs; 1313e09c00caSUlf Lilleengen struct buf *bp; 1314e09c00caSUlf Lilleengen struct ext2mount *ump; 1315ec81c9ccSFedor Uporov int error, start, len, ifree, ibytes; 13168f8d3027SEd Schouten char *ibp, *loc; 1317bf9a211dSPedro F. Giffuni 1318e09c00caSUlf Lilleengen ipref--; /* to avoid a lot of (ipref -1) */ 1319e09c00caSUlf Lilleengen if (ipref == -1) 1320e09c00caSUlf Lilleengen ipref = 0; 1321e09c00caSUlf Lilleengen fs = ip->i_e2fs; 1322e09c00caSUlf Lilleengen ump = ip->i_ump; 13233acd9182SFedor Uporov if (e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) == 0) 1324e09c00caSUlf Lilleengen return (0); 1325e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 1326e09c00caSUlf Lilleengen error = bread(ip->i_devvp, fsbtodb(fs, 13273acd9182SFedor Uporov e2fs_gd_get_i_bitmap(&fs->e2fs_gd[cg])), 1328e09c00caSUlf Lilleengen (int)fs->e2fs_bsize, NOCRED, &bp); 1329e09c00caSUlf Lilleengen if (error) { 1330e09c00caSUlf Lilleengen EXT2_LOCK(ump); 1331e09c00caSUlf Lilleengen return (0); 1332e09c00caSUlf Lilleengen } 1333512f29d1SFedor Uporov if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) || 1334512f29d1SFedor Uporov EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { 1335cd3acfe7SFedor Uporov if (le16toh(fs->e2fs_gd[cg].ext4bgd_flags) & 1336cd3acfe7SFedor Uporov EXT2_BG_INODE_UNINIT) { 1337ec81c9ccSFedor Uporov ibytes = fs->e2fs_ipg / 8; 1338ec81c9ccSFedor Uporov memset(bp->b_data, 0, ibytes - 1); 1339ec81c9ccSFedor Uporov ext2_fix_bitmap_tail(bp->b_data, ibytes, 1340ec81c9ccSFedor Uporov fs->e2fs_bsize - 1); 1341cd3acfe7SFedor Uporov fs->e2fs_gd[cg].ext4bgd_flags = htole16(le16toh( 1342cd3acfe7SFedor Uporov fs->e2fs_gd[cg].ext4bgd_flags) & 1343cd3acfe7SFedor Uporov ~EXT2_BG_INODE_UNINIT); 1344d23db91eSPedro F. Giffuni } 1345512f29d1SFedor Uporov ext2_gd_i_bitmap_csum_set(fs, cg, bp); 1346d23db91eSPedro F. Giffuni error = ext2_zero_inode_table(ip, cg); 1347d23db91eSPedro F. Giffuni if (error) { 1348d23db91eSPedro F. Giffuni brelse(bp); 1349d23db91eSPedro F. Giffuni EXT2_LOCK(ump); 1350d23db91eSPedro F. Giffuni return (0); 1351d23db91eSPedro F. Giffuni } 1352d23db91eSPedro F. Giffuni } 1353512f29d1SFedor Uporov error = ext2_gd_i_bitmap_csum_verify(fs, cg, bp); 1354512f29d1SFedor Uporov if (error) { 1355512f29d1SFedor Uporov brelse(bp); 1356512f29d1SFedor Uporov EXT2_LOCK(ump); 1357512f29d1SFedor Uporov return (0); 1358512f29d1SFedor Uporov } 13593acd9182SFedor Uporov if (e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) == 0) { 136073dd6d1fSJohn Baldwin /* 136173dd6d1fSJohn Baldwin * Another thread allocated the last i-node in this 136273dd6d1fSJohn Baldwin * group while we were waiting for the buffer. 136373dd6d1fSJohn Baldwin */ 136473dd6d1fSJohn Baldwin brelse(bp); 136573dd6d1fSJohn Baldwin EXT2_LOCK(ump); 136673dd6d1fSJohn Baldwin return (0); 136773dd6d1fSJohn Baldwin } 1368e09c00caSUlf Lilleengen ibp = (char *)bp->b_data; 1369e09c00caSUlf Lilleengen if (ipref) { 1370cd3acfe7SFedor Uporov ipref %= fs->e2fs_ipg; 1371e09c00caSUlf Lilleengen if (isclr(ibp, ipref)) 1372e09c00caSUlf Lilleengen goto gotit; 1373e09c00caSUlf Lilleengen } 1374e09c00caSUlf Lilleengen start = ipref / NBBY; 1375cd3acfe7SFedor Uporov len = howmany(fs->e2fs_ipg - ipref, NBBY); 13768f8d3027SEd Schouten loc = memcchr(&ibp[start], 0xff, len); 13778f8d3027SEd Schouten if (loc == NULL) { 1378e09c00caSUlf Lilleengen len = start + 1; 1379e09c00caSUlf Lilleengen start = 0; 13808f8d3027SEd Schouten loc = memcchr(&ibp[start], 0xff, len); 13818f8d3027SEd Schouten if (loc == NULL) { 1382cd3acfe7SFedor Uporov SDT_PROBE3(ext2fs, , alloc, 1383cd3acfe7SFedor Uporov ext2_nodealloccg_bmap_corrupted, cg, ipref, 1384cd3acfe7SFedor Uporov fs->e2fs_fsmnt); 13854ff6603aSFedor Uporov brelse(bp); 13864ff6603aSFedor Uporov EXT2_LOCK(ump); 13874ff6603aSFedor Uporov return (0); 1388e09c00caSUlf Lilleengen } 1389e09c00caSUlf Lilleengen } 13908f8d3027SEd Schouten ipref = (loc - ibp) * NBBY + ffs(~*loc) - 1; 1391e09c00caSUlf Lilleengen gotit: 1392e09c00caSUlf Lilleengen setbit(ibp, ipref); 1393e09c00caSUlf Lilleengen EXT2_LOCK(ump); 13943acd9182SFedor Uporov e2fs_gd_set_nifree(&fs->e2fs_gd[cg], 13953acd9182SFedor Uporov e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) - 1); 1396512f29d1SFedor Uporov if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) || 13974c1e1d2bSFedor Uporov EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { 1398cd3acfe7SFedor Uporov ifree = fs->e2fs_ipg - e2fs_gd_get_i_unused(&fs->e2fs_gd[cg]); 13994c1e1d2bSFedor Uporov if (ipref + 1 > ifree) 14003acd9182SFedor Uporov e2fs_gd_set_i_unused(&fs->e2fs_gd[cg], 1401cd3acfe7SFedor Uporov fs->e2fs_ipg - (ipref + 1)); 14024c1e1d2bSFedor Uporov } 1403cd3acfe7SFedor Uporov fs->e2fs_ficount--; 1404e09c00caSUlf Lilleengen fs->e2fs_fmod = 1; 1405d8ba45e2SEd Maste if ((mode & IFMT) == IFDIR) { 14063acd9182SFedor Uporov e2fs_gd_set_ndirs(&fs->e2fs_gd[cg], 14073acd9182SFedor Uporov e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]) + 1); 1408e09c00caSUlf Lilleengen fs->e2fs_total_dir++; 1409e09c00caSUlf Lilleengen } 1410e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 1411512f29d1SFedor Uporov ext2_gd_i_bitmap_csum_set(fs, cg, bp); 1412e09c00caSUlf Lilleengen bdwrite(bp); 14133acd9182SFedor Uporov return ((uint64_t)cg * fs->e2fs_ipg + ipref + 1); 1414e09c00caSUlf Lilleengen } 1415e09c00caSUlf Lilleengen 1416e09c00caSUlf Lilleengen /* 1417e09c00caSUlf Lilleengen * Free a block or fragment. 1418e09c00caSUlf Lilleengen * 1419e09c00caSUlf Lilleengen */ 1420e09c00caSUlf Lilleengen void 142170097aacSPedro F. Giffuni ext2_blkfree(struct inode *ip, e4fs_daddr_t bno, long size) 1422e09c00caSUlf Lilleengen { 1423e09c00caSUlf Lilleengen struct m_ext2fs *fs; 1424e09c00caSUlf Lilleengen struct buf *bp; 1425e09c00caSUlf Lilleengen struct ext2mount *ump; 1426e09c00caSUlf Lilleengen int cg, error; 1427e09c00caSUlf Lilleengen char *bbp; 1428e09c00caSUlf Lilleengen 1429e09c00caSUlf Lilleengen fs = ip->i_e2fs; 1430e09c00caSUlf Lilleengen ump = ip->i_ump; 1431e09c00caSUlf Lilleengen cg = dtog(fs, bno); 14323acd9182SFedor Uporov if (bno >= fs->e2fs_bcount) { 1433cd3acfe7SFedor Uporov SDT_PROBE2(ext2fs, , alloc, ext2_blkfree_bad_block, 1434cd3acfe7SFedor Uporov ip->i_number, bno); 1435e09c00caSUlf Lilleengen return; 1436e09c00caSUlf Lilleengen } 1437e09c00caSUlf Lilleengen error = bread(ip->i_devvp, 14383acd9182SFedor Uporov fsbtodb(fs, e2fs_gd_get_b_bitmap(&fs->e2fs_gd[cg])), 1439e09c00caSUlf Lilleengen (int)fs->e2fs_bsize, NOCRED, &bp); 1440e09c00caSUlf Lilleengen if (error) { 1441e09c00caSUlf Lilleengen return; 1442e09c00caSUlf Lilleengen } 1443e09c00caSUlf Lilleengen bbp = (char *)bp->b_data; 1444e09c00caSUlf Lilleengen bno = dtogd(fs, bno); 1445e09c00caSUlf Lilleengen if (isclr(bbp, bno)) { 1446ebc94b66SFedor Uporov panic("ext2_blkfree: freeing free block %lld, fs=%s", 1447e09c00caSUlf Lilleengen (long long)bno, fs->e2fs_fsmnt); 1448e09c00caSUlf Lilleengen } 1449e09c00caSUlf Lilleengen clrbit(bbp, bno); 1450e09c00caSUlf Lilleengen EXT2_LOCK(ump); 14515b63c125SPedro F. Giffuni ext2_clusteracct(fs, bbp, cg, bno, 1); 14523acd9182SFedor Uporov fs->e2fs_fbcount++; 14533acd9182SFedor Uporov e2fs_gd_set_nbfree(&fs->e2fs_gd[cg], 14543acd9182SFedor Uporov e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) + 1); 1455e09c00caSUlf Lilleengen fs->e2fs_fmod = 1; 1456e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 1457512f29d1SFedor Uporov ext2_gd_b_bitmap_csum_set(fs, cg, bp); 1458e09c00caSUlf Lilleengen bdwrite(bp); 1459e09c00caSUlf Lilleengen } 1460e09c00caSUlf Lilleengen 1461e09c00caSUlf Lilleengen /* 1462e09c00caSUlf Lilleengen * Free an inode. 1463e09c00caSUlf Lilleengen * 1464e09c00caSUlf Lilleengen */ 1465e09c00caSUlf Lilleengen int 1466a9d1b299SPedro F. Giffuni ext2_vfree(struct vnode *pvp, ino_t ino, int mode) 1467e09c00caSUlf Lilleengen { 1468e09c00caSUlf Lilleengen struct m_ext2fs *fs; 1469e09c00caSUlf Lilleengen struct inode *pip; 1470e09c00caSUlf Lilleengen struct buf *bp; 1471e09c00caSUlf Lilleengen struct ext2mount *ump; 1472e09c00caSUlf Lilleengen int error, cg; 1473e09c00caSUlf Lilleengen char *ibp; 1474e09c00caSUlf Lilleengen 1475e09c00caSUlf Lilleengen pip = VTOI(pvp); 1476e09c00caSUlf Lilleengen fs = pip->i_e2fs; 1477e09c00caSUlf Lilleengen ump = pip->i_ump; 1478e09c00caSUlf Lilleengen if ((u_int)ino > fs->e2fs_ipg * fs->e2fs_gcount) 1479fc8fdae0SMatthew D Fleming panic("ext2_vfree: range: devvp = %p, ino = %ju, fs = %s", 1480fc8fdae0SMatthew D Fleming pip->i_devvp, (uintmax_t)ino, fs->e2fs_fsmnt); 1481e09c00caSUlf Lilleengen 1482e09c00caSUlf Lilleengen cg = ino_to_cg(fs, ino); 1483e09c00caSUlf Lilleengen error = bread(pip->i_devvp, 14843acd9182SFedor Uporov fsbtodb(fs, e2fs_gd_get_i_bitmap(&fs->e2fs_gd[cg])), 1485e09c00caSUlf Lilleengen (int)fs->e2fs_bsize, NOCRED, &bp); 1486e09c00caSUlf Lilleengen if (error) { 1487e09c00caSUlf Lilleengen return (0); 1488e09c00caSUlf Lilleengen } 1489e09c00caSUlf Lilleengen ibp = (char *)bp->b_data; 1490cd3acfe7SFedor Uporov ino = (ino - 1) % fs->e2fs_ipg; 1491e09c00caSUlf Lilleengen if (isclr(ibp, ino)) { 1492ebc94b66SFedor Uporov SDT_PROBE2(ext2fs, , alloc, ext2_vfree_doublefree, 1493ebc94b66SFedor Uporov fs->e2fs_fsmnt, ino); 1494e09c00caSUlf Lilleengen if (fs->e2fs_ronly == 0) 1495757224cbSPedro F. Giffuni panic("ext2_vfree: freeing free inode"); 1496e09c00caSUlf Lilleengen } 1497e09c00caSUlf Lilleengen clrbit(ibp, ino); 1498e09c00caSUlf Lilleengen EXT2_LOCK(ump); 1499cd3acfe7SFedor Uporov fs->e2fs_ficount++; 15003acd9182SFedor Uporov e2fs_gd_set_nifree(&fs->e2fs_gd[cg], 15013acd9182SFedor Uporov e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) + 1); 1502d8ba45e2SEd Maste if ((mode & IFMT) == IFDIR) { 15033acd9182SFedor Uporov e2fs_gd_set_ndirs(&fs->e2fs_gd[cg], 15043acd9182SFedor Uporov e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]) - 1); 1505e09c00caSUlf Lilleengen fs->e2fs_total_dir--; 1506e09c00caSUlf Lilleengen } 1507e09c00caSUlf Lilleengen fs->e2fs_fmod = 1; 1508e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 1509512f29d1SFedor Uporov ext2_gd_i_bitmap_csum_set(fs, cg, bp); 1510e09c00caSUlf Lilleengen bdwrite(bp); 1511e09c00caSUlf Lilleengen return (0); 1512e09c00caSUlf Lilleengen } 1513e09c00caSUlf Lilleengen 1514e09c00caSUlf Lilleengen /* 1515e09c00caSUlf Lilleengen * Find a block in the specified cylinder group. 1516e09c00caSUlf Lilleengen * 1517e09c00caSUlf Lilleengen * It is a panic if a request is made to find a block if none are 1518e09c00caSUlf Lilleengen * available. 1519e09c00caSUlf Lilleengen */ 1520e09c00caSUlf Lilleengen static daddr_t 1521e09c00caSUlf Lilleengen ext2_mapsearch(struct m_ext2fs *fs, char *bbp, daddr_t bpref) 1522e09c00caSUlf Lilleengen { 15238f8d3027SEd Schouten char *loc; 15248f8d3027SEd Schouten int start, len; 1525e09c00caSUlf Lilleengen 1526e09c00caSUlf Lilleengen /* 1527e09c00caSUlf Lilleengen * find the fragment by searching through the free block 1528e09c00caSUlf Lilleengen * map for an appropriate bit pattern 1529e09c00caSUlf Lilleengen */ 1530e09c00caSUlf Lilleengen if (bpref) 1531e09c00caSUlf Lilleengen start = dtogd(fs, bpref) / NBBY; 1532e09c00caSUlf Lilleengen else 1533e09c00caSUlf Lilleengen start = 0; 1534cd3acfe7SFedor Uporov len = howmany(fs->e2fs_fpg, NBBY) - start; 15358f8d3027SEd Schouten loc = memcchr(&bbp[start], 0xff, len); 15368f8d3027SEd Schouten if (loc == NULL) { 1537e09c00caSUlf Lilleengen len = start + 1; 1538e09c00caSUlf Lilleengen start = 0; 15398f8d3027SEd Schouten loc = memcchr(&bbp[start], 0xff, len); 15408f8d3027SEd Schouten if (loc == NULL) { 1541cd3acfe7SFedor Uporov panic("ext2_mapsearch: map corrupted: start=%d, len=%d," 1542cd3acfe7SFedor Uporov "fs=%s", start, len, fs->e2fs_fsmnt); 1543e09c00caSUlf Lilleengen /* NOTREACHED */ 1544e09c00caSUlf Lilleengen } 1545e09c00caSUlf Lilleengen } 15468f8d3027SEd Schouten return ((loc - bbp) * NBBY + ffs(~*loc) - 1); 1547e09c00caSUlf Lilleengen } 1548e09c00caSUlf Lilleengen 1549e09c00caSUlf Lilleengen int 1550d23db91eSPedro F. Giffuni ext2_cg_has_sb(struct m_ext2fs *fs, int cg) 1551e09c00caSUlf Lilleengen { 1552e09c00caSUlf Lilleengen int a3, a5, a7; 1553e09c00caSUlf Lilleengen 1554d23db91eSPedro F. Giffuni if (cg == 0) 1555d23db91eSPedro F. Giffuni return (1); 1556d23db91eSPedro F. Giffuni 1557d23db91eSPedro F. Giffuni if (EXT2_HAS_COMPAT_FEATURE(fs, EXT2F_COMPAT_SPARSESUPER2)) { 1558cd3acfe7SFedor Uporov if (cg == le32toh(fs->e2fs->e4fs_backup_bgs[0]) || 1559cd3acfe7SFedor Uporov cg == le32toh(fs->e2fs->e4fs_backup_bgs[1])) 1560d23db91eSPedro F. Giffuni return (1); 1561d23db91eSPedro F. Giffuni return (0); 1562d23db91eSPedro F. Giffuni } 1563d23db91eSPedro F. Giffuni 1564d23db91eSPedro F. Giffuni if ((cg <= 1) || 1565d23db91eSPedro F. Giffuni !EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_SPARSESUPER)) 1566d23db91eSPedro F. Giffuni return (1); 1567d23db91eSPedro F. Giffuni 1568d23db91eSPedro F. Giffuni if (!(cg & 1)) 1569d23db91eSPedro F. Giffuni return (0); 1570d23db91eSPedro F. Giffuni 1571e09c00caSUlf Lilleengen for (a3 = 3, a5 = 5, a7 = 7; 1572d23db91eSPedro F. Giffuni a3 <= cg || a5 <= cg || a7 <= cg; 1573e09c00caSUlf Lilleengen a3 *= 3, a5 *= 5, a7 *= 7) 1574d23db91eSPedro F. Giffuni if (cg == a3 || cg == a5 || cg == a7) 1575d23db91eSPedro F. Giffuni return (1); 1576d23db91eSPedro F. Giffuni return (0); 1577e09c00caSUlf Lilleengen } 1578