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> 45e09c00caSUlf Lilleengen #include <sys/stat.h> 46e09c00caSUlf Lilleengen #include <sys/mount.h> 475b63c125SPedro F. Giffuni #include <sys/sysctl.h> 48e09c00caSUlf Lilleengen #include <sys/syslog.h> 49e09c00caSUlf Lilleengen #include <sys/buf.h> 50d23db91eSPedro F. Giffuni #include <sys/endian.h> 51e09c00caSUlf Lilleengen 52b6113fb3SPedro F. Giffuni #include <fs/ext2fs/fs.h> 53e09c00caSUlf Lilleengen #include <fs/ext2fs/inode.h> 54e09c00caSUlf Lilleengen #include <fs/ext2fs/ext2_mount.h> 55e09c00caSUlf Lilleengen #include <fs/ext2fs/ext2fs.h> 56e09c00caSUlf Lilleengen #include <fs/ext2fs/ext2_extern.h> 57e09c00caSUlf Lilleengen 58e09c00caSUlf Lilleengen static daddr_t ext2_alloccg(struct inode *, int, daddr_t, int); 595b63c125SPedro F. Giffuni static daddr_t ext2_clusteralloc(struct inode *, int, daddr_t, int); 60e09c00caSUlf Lilleengen static u_long ext2_dirpref(struct inode *); 61ffbde5eaSFedor Uporov static e4fs_daddr_t ext2_hashalloc(struct inode *, int, long, int, 62e09c00caSUlf Lilleengen daddr_t (*)(struct inode *, int, daddr_t, 63e09c00caSUlf Lilleengen int)); 64e09c00caSUlf Lilleengen static daddr_t ext2_nodealloccg(struct inode *, int, daddr_t, int); 65e09c00caSUlf Lilleengen static daddr_t ext2_mapsearch(struct m_ext2fs *, char *, daddr_t); 66c767faa5SJohn Baldwin 67e09c00caSUlf Lilleengen /* 68e09c00caSUlf Lilleengen * Allocate a block in the filesystem. 69e09c00caSUlf Lilleengen * 70e09c00caSUlf Lilleengen * A preference may be optionally specified. If a preference is given 71e09c00caSUlf Lilleengen * the following hierarchy is used to allocate a block: 72e09c00caSUlf Lilleengen * 1) allocate the requested block. 73e09c00caSUlf Lilleengen * 2) allocate a rotationally optimal block in the same cylinder. 74e09c00caSUlf Lilleengen * 3) allocate a block in the same cylinder group. 75e09c00caSUlf Lilleengen * 4) quadradically rehash into other cylinder groups, until an 76e09c00caSUlf Lilleengen * available block is located. 77e09c00caSUlf Lilleengen * If no block preference is given the following hierarchy is used 78e09c00caSUlf Lilleengen * to allocate a block: 79e09c00caSUlf Lilleengen * 1) allocate a block in the cylinder group that contains the 80e09c00caSUlf Lilleengen * inode for the file. 81e09c00caSUlf Lilleengen * 2) quadradically rehash into other cylinder groups, until an 82e09c00caSUlf Lilleengen * available block is located. 83e09c00caSUlf Lilleengen */ 84e09c00caSUlf Lilleengen int 8570097aacSPedro F. Giffuni ext2_alloc(struct inode *ip, daddr_t lbn, e4fs_daddr_t bpref, int size, 8670097aacSPedro F. Giffuni struct ucred *cred, e4fs_daddr_t *bnp) 87e09c00caSUlf Lilleengen { 88e09c00caSUlf Lilleengen struct m_ext2fs *fs; 89e09c00caSUlf Lilleengen struct ext2mount *ump; 90ffbde5eaSFedor Uporov e4fs_daddr_t bno; 91e09c00caSUlf Lilleengen int cg; 92bf9a211dSPedro F. Giffuni 93e09c00caSUlf Lilleengen *bnp = 0; 94e09c00caSUlf Lilleengen fs = ip->i_e2fs; 95e09c00caSUlf Lilleengen ump = ip->i_ump; 96e09c00caSUlf Lilleengen mtx_assert(EXT2_MTX(ump), MA_OWNED); 9777b193c2SPedro F. Giffuni #ifdef INVARIANTS 98e09c00caSUlf Lilleengen if ((u_int)size > fs->e2fs_bsize || blkoff(fs, size) != 0) { 99e09c00caSUlf Lilleengen vn_printf(ip->i_devvp, "bsize = %lu, size = %d, fs = %s\n", 100e09c00caSUlf Lilleengen (long unsigned int)fs->e2fs_bsize, size, fs->e2fs_fsmnt); 101e09c00caSUlf Lilleengen panic("ext2_alloc: bad size"); 102e09c00caSUlf Lilleengen } 103e09c00caSUlf Lilleengen if (cred == NOCRED) 104e09c00caSUlf Lilleengen panic("ext2_alloc: missing credential"); 10577b193c2SPedro F. Giffuni #endif /* INVARIANTS */ 1063acd9182SFedor Uporov if (size == fs->e2fs_bsize && fs->e2fs_fbcount == 0) 107e09c00caSUlf Lilleengen goto nospace; 108e09c00caSUlf Lilleengen if (cred->cr_uid != 0 && 1093acd9182SFedor Uporov fs->e2fs_fbcount < fs->e2fs_rbcount) 110e09c00caSUlf Lilleengen goto nospace; 1113acd9182SFedor Uporov if (bpref >= fs->e2fs_bcount) 112e09c00caSUlf Lilleengen bpref = 0; 113e09c00caSUlf Lilleengen if (bpref == 0) 114e09c00caSUlf Lilleengen cg = ino_to_cg(fs, ip->i_number); 115e09c00caSUlf Lilleengen else 116e09c00caSUlf Lilleengen cg = dtog(fs, bpref); 117e09c00caSUlf Lilleengen bno = (daddr_t)ext2_hashalloc(ip, cg, bpref, fs->e2fs_bsize, 118e09c00caSUlf Lilleengen ext2_alloccg); 119e09c00caSUlf Lilleengen if (bno > 0) { 120c767faa5SJohn Baldwin /* set next_alloc fields as done in block_getblk */ 121c767faa5SJohn Baldwin ip->i_next_alloc_block = lbn; 122c767faa5SJohn Baldwin ip->i_next_alloc_goal = bno; 123c767faa5SJohn Baldwin 124e09c00caSUlf Lilleengen ip->i_blocks += btodb(fs->e2fs_bsize); 125e09c00caSUlf Lilleengen ip->i_flag |= IN_CHANGE | IN_UPDATE; 126e09c00caSUlf Lilleengen *bnp = bno; 127e09c00caSUlf Lilleengen return (0); 128e09c00caSUlf Lilleengen } 129e09c00caSUlf Lilleengen nospace: 130e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 131e09c00caSUlf Lilleengen ext2_fserr(fs, cred->cr_uid, "filesystem full"); 132e09c00caSUlf Lilleengen uprintf("\n%s: write failed, filesystem is full\n", fs->e2fs_fsmnt); 133e09c00caSUlf Lilleengen return (ENOSPC); 134e09c00caSUlf Lilleengen } 135e09c00caSUlf Lilleengen 136e09c00caSUlf Lilleengen /* 13734f43888SPedro F. Giffuni * Allocate EA's block for inode. 13834f43888SPedro F. Giffuni */ 139ffbde5eaSFedor Uporov e4fs_daddr_t 140b394cd1eSFedor Uporov ext2_alloc_meta(struct inode *ip) 14134f43888SPedro F. Giffuni { 14234f43888SPedro F. Giffuni struct m_ext2fs *fs; 143b394cd1eSFedor Uporov daddr_t blk; 14434f43888SPedro F. Giffuni 14534f43888SPedro F. Giffuni fs = ip->i_e2fs; 14634f43888SPedro F. Giffuni 14734f43888SPedro F. Giffuni EXT2_LOCK(ip->i_ump); 148b394cd1eSFedor Uporov blk = ext2_hashalloc(ip, ino_to_cg(fs, ip->i_number), 0, fs->e2fs_bsize, 149b394cd1eSFedor Uporov ext2_alloccg); 150b394cd1eSFedor Uporov if (0 == blk) 15134f43888SPedro F. Giffuni EXT2_UNLOCK(ip->i_ump); 15234f43888SPedro F. Giffuni 153b394cd1eSFedor Uporov return (blk); 15434f43888SPedro F. Giffuni } 15534f43888SPedro F. Giffuni 15634f43888SPedro F. Giffuni /* 157e09c00caSUlf Lilleengen * Reallocate a sequence of blocks into a contiguous sequence of blocks. 158e09c00caSUlf Lilleengen * 159e09c00caSUlf Lilleengen * The vnode and an array of buffer pointers for a range of sequential 160e09c00caSUlf Lilleengen * logical blocks to be made contiguous is given. The allocator attempts 161e09c00caSUlf Lilleengen * to find a range of sequential blocks starting as close as possible to 162e09c00caSUlf Lilleengen * an fs_rotdelay offset from the end of the allocation for the logical 163e09c00caSUlf Lilleengen * block immediately preceding the current range. If successful, the 164e09c00caSUlf Lilleengen * physical block numbers in the buffer pointers and in the inode are 165e09c00caSUlf Lilleengen * changed to reflect the new allocation. If unsuccessful, the allocation 166e09c00caSUlf Lilleengen * is left unchanged. The success in doing the reallocation is returned. 167e09c00caSUlf Lilleengen * Note that the error return is not reflected back to the user. Rather 168e09c00caSUlf Lilleengen * the previous block allocation will be used. 169e09c00caSUlf Lilleengen */ 170e09c00caSUlf Lilleengen 1716472ac3dSEd Schouten static SYSCTL_NODE(_vfs, OID_AUTO, ext2fs, CTLFLAG_RW, 0, "EXT2FS filesystem"); 172e09c00caSUlf Lilleengen 17399984d22SPedro F. Giffuni static int doasyncfree = 1; 174bf9a211dSPedro F. Giffuni 175c767faa5SJohn Baldwin SYSCTL_INT(_vfs_ext2fs, OID_AUTO, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, 176c767faa5SJohn Baldwin "Use asychronous writes to update block pointers when freeing blocks"); 177c767faa5SJohn Baldwin 178dc262e5bSFedor Uporov static int doreallocblks = 0; 179bf9a211dSPedro F. Giffuni 180c767faa5SJohn Baldwin SYSCTL_INT(_vfs_ext2fs, OID_AUTO, doreallocblks, CTLFLAG_RW, &doreallocblks, 0, ""); 181e09c00caSUlf Lilleengen 182e09c00caSUlf Lilleengen int 183a9d1b299SPedro F. Giffuni ext2_reallocblks(struct vop_reallocblks_args *ap) 184e09c00caSUlf Lilleengen { 185e09c00caSUlf Lilleengen struct m_ext2fs *fs; 186e09c00caSUlf Lilleengen struct inode *ip; 187e09c00caSUlf Lilleengen struct vnode *vp; 188e09c00caSUlf Lilleengen struct buf *sbp, *ebp; 189e45e8680SPedro F. Giffuni uint32_t *bap, *sbap, *ebap; 190e09c00caSUlf Lilleengen struct ext2mount *ump; 191e09c00caSUlf Lilleengen struct cluster_save *buflist; 1921dc349abSEd Maste struct indir start_ap[EXT2_NIADDR + 1], end_ap[EXT2_NIADDR + 1], *idp; 193da057ed2SPedro F. Giffuni e2fs_lbn_t start_lbn, end_lbn; 19470097aacSPedro F. Giffuni int soff; 19570097aacSPedro F. Giffuni e2fs_daddr_t newblk, blkno; 196e09c00caSUlf Lilleengen int i, len, start_lvl, end_lvl, pref, ssize; 197e09c00caSUlf Lilleengen 1985b63c125SPedro F. Giffuni if (doreallocblks == 0) 1995b63c125SPedro F. Giffuni return (ENOSPC); 2005b63c125SPedro F. Giffuni 201e09c00caSUlf Lilleengen vp = ap->a_vp; 202e09c00caSUlf Lilleengen ip = VTOI(vp); 203e09c00caSUlf Lilleengen fs = ip->i_e2fs; 204e09c00caSUlf Lilleengen ump = ip->i_ump; 2055b63c125SPedro F. Giffuni 206b394cd1eSFedor Uporov if (fs->e2fs_contigsumsize <= 0 || ip->i_flag & IN_E4EXTENTS) 207e09c00caSUlf Lilleengen return (ENOSPC); 2085b63c125SPedro F. Giffuni 209e09c00caSUlf Lilleengen buflist = ap->a_buflist; 210e09c00caSUlf Lilleengen len = buflist->bs_nchildren; 211e09c00caSUlf Lilleengen start_lbn = buflist->bs_children[0]->b_lblkno; 212e09c00caSUlf Lilleengen end_lbn = start_lbn + len - 1; 21377b193c2SPedro F. Giffuni #ifdef INVARIANTS 214e09c00caSUlf Lilleengen for (i = 1; i < len; i++) 215e09c00caSUlf Lilleengen if (buflist->bs_children[i]->b_lblkno != start_lbn + i) 216e09c00caSUlf Lilleengen panic("ext2_reallocblks: non-cluster"); 217e09c00caSUlf Lilleengen #endif 218e09c00caSUlf Lilleengen /* 2197306dea4SPedro F. Giffuni * If the cluster crosses the boundary for the first indirect 2207306dea4SPedro F. Giffuni * block, leave space for the indirect block. Indirect blocks 2217306dea4SPedro F. Giffuni * are initially laid out in a position after the last direct 2227306dea4SPedro F. Giffuni * block. Block reallocation would usually destroy locality by 2237306dea4SPedro F. Giffuni * moving the indirect block out of the way to make room for 2247306dea4SPedro F. Giffuni * data blocks if we didn't compensate here. We should also do 2257306dea4SPedro F. Giffuni * this for other indirect block boundaries, but it is only 2267306dea4SPedro F. Giffuni * important for the first one. 2277306dea4SPedro F. Giffuni */ 2281dc349abSEd Maste if (start_lbn < EXT2_NDADDR && end_lbn >= EXT2_NDADDR) 2297306dea4SPedro F. Giffuni return (ENOSPC); 2307306dea4SPedro F. Giffuni /* 231e09c00caSUlf Lilleengen * If the latest allocation is in a new cylinder group, assume that 232e09c00caSUlf Lilleengen * the filesystem has decided to move and do not force it back to 233e09c00caSUlf Lilleengen * the previous cylinder group. 234e09c00caSUlf Lilleengen */ 235e09c00caSUlf Lilleengen if (dtog(fs, dbtofsb(fs, buflist->bs_children[0]->b_blkno)) != 236e09c00caSUlf Lilleengen dtog(fs, dbtofsb(fs, buflist->bs_children[len - 1]->b_blkno))) 237e09c00caSUlf Lilleengen return (ENOSPC); 238e09c00caSUlf Lilleengen if (ext2_getlbns(vp, start_lbn, start_ap, &start_lvl) || 239e09c00caSUlf Lilleengen ext2_getlbns(vp, end_lbn, end_ap, &end_lvl)) 240e09c00caSUlf Lilleengen return (ENOSPC); 241e09c00caSUlf Lilleengen /* 242e09c00caSUlf Lilleengen * Get the starting offset and block map for the first block. 243e09c00caSUlf Lilleengen */ 244e09c00caSUlf Lilleengen if (start_lvl == 0) { 245e09c00caSUlf Lilleengen sbap = &ip->i_db[0]; 246e09c00caSUlf Lilleengen soff = start_lbn; 247e09c00caSUlf Lilleengen } else { 248e09c00caSUlf Lilleengen idp = &start_ap[start_lvl - 1]; 249e09c00caSUlf Lilleengen if (bread(vp, idp->in_lbn, (int)fs->e2fs_bsize, NOCRED, &sbp)) { 250e09c00caSUlf Lilleengen brelse(sbp); 251e09c00caSUlf Lilleengen return (ENOSPC); 252e09c00caSUlf Lilleengen } 253f744956bSPedro F. Giffuni sbap = (u_int *)sbp->b_data; 254e09c00caSUlf Lilleengen soff = idp->in_off; 255e09c00caSUlf Lilleengen } 256e09c00caSUlf Lilleengen /* 257e09c00caSUlf Lilleengen * If the block range spans two block maps, get the second map. 258e09c00caSUlf Lilleengen */ 259e45e8680SPedro F. Giffuni ebap = NULL; 260e09c00caSUlf Lilleengen if (end_lvl == 0 || (idp = &end_ap[end_lvl - 1])->in_off + 1 >= len) { 261e09c00caSUlf Lilleengen ssize = len; 262e09c00caSUlf Lilleengen } else { 26377b193c2SPedro F. Giffuni #ifdef INVARIANTS 264e09c00caSUlf Lilleengen if (start_ap[start_lvl - 1].in_lbn == idp->in_lbn) 265757224cbSPedro F. Giffuni panic("ext2_reallocblks: start == end"); 266e09c00caSUlf Lilleengen #endif 267e09c00caSUlf Lilleengen ssize = len - (idp->in_off + 1); 2685b63c125SPedro F. Giffuni if (bread(vp, idp->in_lbn, (int)fs->e2fs_bsize, NOCRED, &ebp)) 269e09c00caSUlf Lilleengen goto fail; 270f744956bSPedro F. Giffuni ebap = (u_int *)ebp->b_data; 271e09c00caSUlf Lilleengen } 272e09c00caSUlf Lilleengen /* 2735b63c125SPedro F. Giffuni * Find the preferred location for the cluster. 2745b63c125SPedro F. Giffuni */ 2755b63c125SPedro F. Giffuni EXT2_LOCK(ump); 2765b63c125SPedro F. Giffuni pref = ext2_blkpref(ip, start_lbn, soff, sbap, 0); 2775b63c125SPedro F. Giffuni /* 278e09c00caSUlf Lilleengen * Search the block map looking for an allocation of the desired size. 279e09c00caSUlf Lilleengen */ 28070097aacSPedro F. Giffuni if ((newblk = (e2fs_daddr_t)ext2_hashalloc(ip, dtog(fs, pref), pref, 281e09c00caSUlf Lilleengen len, ext2_clusteralloc)) == 0) { 282e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 283e09c00caSUlf Lilleengen goto fail; 284e09c00caSUlf Lilleengen } 285e09c00caSUlf Lilleengen /* 286e09c00caSUlf Lilleengen * We have found a new contiguous block. 287e09c00caSUlf Lilleengen * 288e09c00caSUlf Lilleengen * First we have to replace the old block pointers with the new 289e09c00caSUlf Lilleengen * block pointers in the inode and indirect blocks associated 290e09c00caSUlf Lilleengen * with the file. 291e09c00caSUlf Lilleengen */ 2925b63c125SPedro F. Giffuni #ifdef DEBUG 293dde58752SGleb Kurtsou printf("realloc: ino %ju, lbns %jd-%jd\n\told:", 294dde58752SGleb Kurtsou (uintmax_t)ip->i_number, (intmax_t)start_lbn, (intmax_t)end_lbn); 2955b63c125SPedro F. Giffuni #endif /* DEBUG */ 296e09c00caSUlf Lilleengen blkno = newblk; 297e09c00caSUlf Lilleengen for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->e2fs_fpb) { 2985b63c125SPedro F. Giffuni if (i == ssize) { 299e09c00caSUlf Lilleengen bap = ebap; 300e09c00caSUlf Lilleengen soff = -i; 3015b63c125SPedro F. Giffuni } 30277b193c2SPedro F. Giffuni #ifdef INVARIANTS 303e09c00caSUlf Lilleengen if (buflist->bs_children[i]->b_blkno != fsbtodb(fs, *bap)) 304e09c00caSUlf Lilleengen panic("ext2_reallocblks: alloc mismatch"); 305e09c00caSUlf Lilleengen #endif 3065b63c125SPedro F. Giffuni #ifdef DEBUG 3075b63c125SPedro F. Giffuni printf(" %d,", *bap); 3085b63c125SPedro F. Giffuni #endif /* DEBUG */ 309e09c00caSUlf Lilleengen *bap++ = blkno; 310e09c00caSUlf Lilleengen } 311e09c00caSUlf Lilleengen /* 312e09c00caSUlf Lilleengen * Next we must write out the modified inode and indirect blocks. 313e09c00caSUlf Lilleengen * For strict correctness, the writes should be synchronous since 314e09c00caSUlf Lilleengen * the old block values may have been written to disk. In practise 315e09c00caSUlf Lilleengen * they are almost never written, but if we are concerned about 316e09c00caSUlf Lilleengen * strict correctness, the `doasyncfree' flag should be set to zero. 317e09c00caSUlf Lilleengen * 318e09c00caSUlf Lilleengen * The test on `doasyncfree' should be changed to test a flag 319e09c00caSUlf Lilleengen * that shows whether the associated buffers and inodes have 320e09c00caSUlf Lilleengen * been written. The flag should be set when the cluster is 321e09c00caSUlf Lilleengen * started and cleared whenever the buffer or inode is flushed. 322e09c00caSUlf Lilleengen * We can then check below to see if it is set, and do the 323e09c00caSUlf Lilleengen * synchronous write only when it has been cleared. 324e09c00caSUlf Lilleengen */ 325e09c00caSUlf Lilleengen if (sbap != &ip->i_db[0]) { 326e09c00caSUlf Lilleengen if (doasyncfree) 327e09c00caSUlf Lilleengen bdwrite(sbp); 328e09c00caSUlf Lilleengen else 329e09c00caSUlf Lilleengen bwrite(sbp); 330e09c00caSUlf Lilleengen } else { 331e09c00caSUlf Lilleengen ip->i_flag |= IN_CHANGE | IN_UPDATE; 332e09c00caSUlf Lilleengen if (!doasyncfree) 333e09c00caSUlf Lilleengen ext2_update(vp, 1); 334e09c00caSUlf Lilleengen } 335e09c00caSUlf Lilleengen if (ssize < len) { 336e09c00caSUlf Lilleengen if (doasyncfree) 337e09c00caSUlf Lilleengen bdwrite(ebp); 338e09c00caSUlf Lilleengen else 339e09c00caSUlf Lilleengen bwrite(ebp); 340e09c00caSUlf Lilleengen } 341e09c00caSUlf Lilleengen /* 342e09c00caSUlf Lilleengen * Last, free the old blocks and assign the new blocks to the buffers. 343e09c00caSUlf Lilleengen */ 3445b63c125SPedro F. Giffuni #ifdef DEBUG 3455b63c125SPedro F. Giffuni printf("\n\tnew:"); 3465b63c125SPedro F. Giffuni #endif /* DEBUG */ 347e09c00caSUlf Lilleengen for (blkno = newblk, i = 0; i < len; i++, blkno += fs->e2fs_fpb) { 348e09c00caSUlf Lilleengen ext2_blkfree(ip, dbtofsb(fs, buflist->bs_children[i]->b_blkno), 349e09c00caSUlf Lilleengen fs->e2fs_bsize); 350e09c00caSUlf Lilleengen buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno); 3515b63c125SPedro F. Giffuni #ifdef DEBUG 3525b63c125SPedro F. Giffuni printf(" %d,", blkno); 3535b63c125SPedro F. Giffuni #endif /* DEBUG */ 354e09c00caSUlf Lilleengen } 3555b63c125SPedro F. Giffuni #ifdef DEBUG 3565b63c125SPedro F. Giffuni printf("\n"); 3575b63c125SPedro F. Giffuni #endif /* DEBUG */ 358e09c00caSUlf Lilleengen return (0); 359e09c00caSUlf Lilleengen 360e09c00caSUlf Lilleengen fail: 361e09c00caSUlf Lilleengen if (ssize < len) 362e09c00caSUlf Lilleengen brelse(ebp); 363e09c00caSUlf Lilleengen if (sbap != &ip->i_db[0]) 364e09c00caSUlf Lilleengen brelse(sbp); 365e09c00caSUlf Lilleengen return (ENOSPC); 366e09c00caSUlf Lilleengen } 367e09c00caSUlf Lilleengen 368e09c00caSUlf Lilleengen /* 369e09c00caSUlf Lilleengen * Allocate an inode in the filesystem. 370e09c00caSUlf Lilleengen * 371e09c00caSUlf Lilleengen */ 372e09c00caSUlf Lilleengen int 373a9d1b299SPedro F. Giffuni ext2_valloc(struct vnode *pvp, int mode, struct ucred *cred, struct vnode **vpp) 374e09c00caSUlf Lilleengen { 375035e4e04SPedro F. Giffuni struct timespec ts; 376e09c00caSUlf Lilleengen struct m_ext2fs *fs; 377e09c00caSUlf Lilleengen struct ext2mount *ump; 378*3eed9f20SFedor Uporov struct inode *pip; 379*3eed9f20SFedor Uporov struct inode *ip; 380*3eed9f20SFedor Uporov struct vnode *vp; 381*3eed9f20SFedor Uporov struct thread *td; 382e09c00caSUlf Lilleengen ino_t ino, ipref; 383b394cd1eSFedor Uporov int error, cg; 384e09c00caSUlf Lilleengen 385e09c00caSUlf Lilleengen *vpp = NULL; 386e09c00caSUlf Lilleengen pip = VTOI(pvp); 387e09c00caSUlf Lilleengen fs = pip->i_e2fs; 388e09c00caSUlf Lilleengen ump = pip->i_ump; 389e09c00caSUlf Lilleengen 390e09c00caSUlf Lilleengen EXT2_LOCK(ump); 391e09c00caSUlf Lilleengen if (fs->e2fs->e2fs_ficount == 0) 392e09c00caSUlf Lilleengen goto noinodes; 393e09c00caSUlf Lilleengen /* 394e09c00caSUlf Lilleengen * If it is a directory then obtain a cylinder group based on 395e09c00caSUlf Lilleengen * ext2_dirpref else obtain it using ino_to_cg. The preferred inode is 396e09c00caSUlf Lilleengen * always the next inode. 397e09c00caSUlf Lilleengen */ 398d8ba45e2SEd Maste if ((mode & IFMT) == IFDIR) { 399e09c00caSUlf Lilleengen cg = ext2_dirpref(pip); 400e09c00caSUlf Lilleengen if (fs->e2fs_contigdirs[cg] < 255) 401e09c00caSUlf Lilleengen fs->e2fs_contigdirs[cg]++; 402e09c00caSUlf Lilleengen } else { 403e09c00caSUlf Lilleengen cg = ino_to_cg(fs, pip->i_number); 404e09c00caSUlf Lilleengen if (fs->e2fs_contigdirs[cg] > 0) 405e09c00caSUlf Lilleengen fs->e2fs_contigdirs[cg]--; 406e09c00caSUlf Lilleengen } 407e09c00caSUlf Lilleengen ipref = cg * fs->e2fs->e2fs_ipg + 1; 408e09c00caSUlf Lilleengen ino = (ino_t)ext2_hashalloc(pip, cg, (long)ipref, mode, ext2_nodealloccg); 409e09c00caSUlf Lilleengen if (ino == 0) 410e09c00caSUlf Lilleengen goto noinodes; 411*3eed9f20SFedor Uporov 412*3eed9f20SFedor Uporov td = curthread; 413*3eed9f20SFedor Uporov error = vfs_hash_get(ump->um_mountp, ino, LK_EXCLUSIVE, td, vpp, NULL, NULL); 414*3eed9f20SFedor Uporov if (error || *vpp != NULL) { 415*3eed9f20SFedor Uporov EXT2_UNLOCK(ump); 416e09c00caSUlf Lilleengen return (error); 417e09c00caSUlf Lilleengen } 418e09c00caSUlf Lilleengen 419*3eed9f20SFedor Uporov ip = malloc(sizeof(struct inode), M_EXT2NODE, M_WAITOK | M_ZERO); 420*3eed9f20SFedor Uporov if (ip == NULL) { 421*3eed9f20SFedor Uporov EXT2_UNLOCK(ump); 422*3eed9f20SFedor Uporov return (ENOMEM); 423*3eed9f20SFedor Uporov } 424*3eed9f20SFedor Uporov 425*3eed9f20SFedor Uporov /* Allocate a new vnode/inode. */ 426*3eed9f20SFedor Uporov if ((error = getnewvnode("ext2fs", ump->um_mountp, &ext2_vnodeops, &vp)) != 0) { 427*3eed9f20SFedor Uporov free(ip, M_EXT2NODE); 428*3eed9f20SFedor Uporov EXT2_UNLOCK(ump); 429*3eed9f20SFedor Uporov return (error); 430*3eed9f20SFedor Uporov } 431*3eed9f20SFedor Uporov 432*3eed9f20SFedor Uporov vp->v_data = ip; 433*3eed9f20SFedor Uporov ip->i_vnode = vp; 434*3eed9f20SFedor Uporov ip->i_e2fs = fs = ump->um_e2fs; 435*3eed9f20SFedor Uporov ip->i_ump = ump; 436*3eed9f20SFedor Uporov ip->i_number = ino; 437*3eed9f20SFedor Uporov ip->i_block_group = ino_to_cg(fs, ino); 438*3eed9f20SFedor Uporov ip->i_next_alloc_block = 0; 439*3eed9f20SFedor Uporov ip->i_next_alloc_goal = 0; 440*3eed9f20SFedor Uporov 441*3eed9f20SFedor Uporov lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL); 442*3eed9f20SFedor Uporov error = insmntque(vp, ump->um_mountp); 443*3eed9f20SFedor Uporov if (error) { 444*3eed9f20SFedor Uporov free(ip, M_EXT2NODE); 445*3eed9f20SFedor Uporov EXT2_UNLOCK(ump); 446*3eed9f20SFedor Uporov return (error); 447*3eed9f20SFedor Uporov } 448*3eed9f20SFedor Uporov 449*3eed9f20SFedor Uporov error = vfs_hash_insert(vp, ino, LK_EXCLUSIVE, td, vpp, NULL, NULL); 450*3eed9f20SFedor Uporov if (error || *vpp != NULL) { 451*3eed9f20SFedor Uporov *vpp = NULL; 452*3eed9f20SFedor Uporov free(ip, M_EXT2NODE); 453*3eed9f20SFedor Uporov EXT2_UNLOCK(ump); 454*3eed9f20SFedor Uporov return (error); 455*3eed9f20SFedor Uporov } 456*3eed9f20SFedor Uporov 457*3eed9f20SFedor Uporov if ((error = ext2_vinit(ump->um_mountp, &ext2_fifoops, &vp)) != 0) { 458*3eed9f20SFedor Uporov vput(vp); 459*3eed9f20SFedor Uporov *vpp = NULL; 460*3eed9f20SFedor Uporov free(ip, M_EXT2NODE); 461*3eed9f20SFedor Uporov EXT2_UNLOCK(ump); 462*3eed9f20SFedor Uporov return (error); 463*3eed9f20SFedor Uporov } 464*3eed9f20SFedor 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 /* 473e09c00caSUlf Lilleengen * Set up a new generation number for this inode. 47443ce40e8SPedro F. Giffuni * Avoid zero values. 475e09c00caSUlf Lilleengen */ 47643ce40e8SPedro F. Giffuni do { 477df04a188SKevin Lo ip->i_gen = arc4random(); 47843ce40e8SPedro F. Giffuni } while (ip->i_gen == 0); 479035e4e04SPedro F. Giffuni 480035e4e04SPedro F. Giffuni vfs_timestamp(&ts); 481035e4e04SPedro F. Giffuni ip->i_birthtime = ts.tv_sec; 482035e4e04SPedro F. Giffuni ip->i_birthnsec = ts.tv_nsec; 483035e4e04SPedro F. Giffuni 484*3eed9f20SFedor Uporov *vpp = vp; 485*3eed9f20SFedor Uporov 486e09c00caSUlf Lilleengen return (0); 487*3eed9f20SFedor Uporov 488e09c00caSUlf Lilleengen noinodes: 489e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 490e09c00caSUlf Lilleengen ext2_fserr(fs, cred->cr_uid, "out of inodes"); 491e09c00caSUlf Lilleengen uprintf("\n%s: create/symlink failed, no inodes free\n", fs->e2fs_fsmnt); 492e09c00caSUlf Lilleengen return (ENOSPC); 493e09c00caSUlf Lilleengen } 494e09c00caSUlf Lilleengen 495e09c00caSUlf Lilleengen /* 4963acd9182SFedor Uporov * 64-bit compatible getters and setters for struct ext2_gd from ext2fs.h 4973acd9182SFedor Uporov */ 4986e38bf94SFedor Uporov uint64_t 4993acd9182SFedor Uporov e2fs_gd_get_b_bitmap(struct ext2_gd *gd) 5003acd9182SFedor Uporov { 5013acd9182SFedor Uporov 5023acd9182SFedor Uporov return (((uint64_t)(gd->ext4bgd_b_bitmap_hi) << 32) | 5033acd9182SFedor Uporov gd->ext2bgd_b_bitmap); 5043acd9182SFedor Uporov } 5053acd9182SFedor Uporov 5066e38bf94SFedor Uporov uint64_t 5073acd9182SFedor Uporov e2fs_gd_get_i_bitmap(struct ext2_gd *gd) 5083acd9182SFedor Uporov { 5093acd9182SFedor Uporov 5103acd9182SFedor Uporov return (((uint64_t)(gd->ext4bgd_i_bitmap_hi) << 32) | 5113acd9182SFedor Uporov gd->ext2bgd_i_bitmap); 5123acd9182SFedor Uporov } 5133acd9182SFedor Uporov 5143acd9182SFedor Uporov uint64_t 5153acd9182SFedor Uporov e2fs_gd_get_i_tables(struct ext2_gd *gd) 5163acd9182SFedor Uporov { 5173acd9182SFedor Uporov 5183acd9182SFedor Uporov return (((uint64_t)(gd->ext4bgd_i_tables_hi) << 32) | 5193acd9182SFedor Uporov gd->ext2bgd_i_tables); 5203acd9182SFedor Uporov } 5213acd9182SFedor Uporov 5223acd9182SFedor Uporov static uint32_t 5233acd9182SFedor Uporov e2fs_gd_get_nbfree(struct ext2_gd *gd) 5243acd9182SFedor Uporov { 5253acd9182SFedor Uporov 5263acd9182SFedor Uporov return (((uint32_t)(gd->ext4bgd_nbfree_hi) << 16) | 5273acd9182SFedor Uporov gd->ext2bgd_nbfree); 5283acd9182SFedor Uporov } 5293acd9182SFedor Uporov 5303acd9182SFedor Uporov static void 5313acd9182SFedor Uporov e2fs_gd_set_nbfree(struct ext2_gd *gd, uint32_t val) 5323acd9182SFedor Uporov { 5333acd9182SFedor Uporov 5343acd9182SFedor Uporov gd->ext2bgd_nbfree = val & 0xffff; 5353acd9182SFedor Uporov gd->ext4bgd_nbfree_hi = val >> 16; 5363acd9182SFedor Uporov } 5373acd9182SFedor Uporov 5383acd9182SFedor Uporov static uint32_t 5393acd9182SFedor Uporov e2fs_gd_get_nifree(struct ext2_gd *gd) 5403acd9182SFedor Uporov { 5413acd9182SFedor Uporov 5423acd9182SFedor Uporov return (((uint32_t)(gd->ext4bgd_nifree_hi) << 16) | 5433acd9182SFedor Uporov gd->ext2bgd_nifree); 5443acd9182SFedor Uporov } 5453acd9182SFedor Uporov 5463acd9182SFedor Uporov static void 5473acd9182SFedor Uporov e2fs_gd_set_nifree(struct ext2_gd *gd, uint32_t val) 5483acd9182SFedor Uporov { 5493acd9182SFedor Uporov 5503acd9182SFedor Uporov gd->ext2bgd_nifree = val & 0xffff; 5513acd9182SFedor Uporov gd->ext4bgd_nifree_hi = val >> 16; 5523acd9182SFedor Uporov } 5533acd9182SFedor Uporov 5543acd9182SFedor Uporov uint32_t 5553acd9182SFedor Uporov e2fs_gd_get_ndirs(struct ext2_gd *gd) 5563acd9182SFedor Uporov { 5573acd9182SFedor Uporov 5583acd9182SFedor Uporov return (((uint32_t)(gd->ext4bgd_ndirs_hi) << 16) | 5593acd9182SFedor Uporov gd->ext2bgd_ndirs); 5603acd9182SFedor Uporov } 5613acd9182SFedor Uporov 5623acd9182SFedor Uporov static void 5633acd9182SFedor Uporov e2fs_gd_set_ndirs(struct ext2_gd *gd, uint32_t val) 5643acd9182SFedor Uporov { 5653acd9182SFedor Uporov 5663acd9182SFedor Uporov gd->ext2bgd_ndirs = val & 0xffff; 5673acd9182SFedor Uporov gd->ext4bgd_ndirs_hi = val >> 16; 5683acd9182SFedor Uporov } 5693acd9182SFedor Uporov 5703acd9182SFedor Uporov static uint32_t 5713acd9182SFedor Uporov e2fs_gd_get_i_unused(struct ext2_gd *gd) 5723acd9182SFedor Uporov { 5733acd9182SFedor Uporov return (((uint32_t)(gd->ext4bgd_i_unused_hi) << 16) | 5743acd9182SFedor Uporov gd->ext4bgd_i_unused); 5753acd9182SFedor Uporov } 5763acd9182SFedor Uporov 5773acd9182SFedor Uporov static void 5783acd9182SFedor Uporov e2fs_gd_set_i_unused(struct ext2_gd *gd, uint32_t val) 5793acd9182SFedor Uporov { 5803acd9182SFedor Uporov 5813acd9182SFedor Uporov gd->ext4bgd_i_unused = val & 0xffff; 5823acd9182SFedor Uporov gd->ext4bgd_i_unused_hi = val >> 16; 5833acd9182SFedor Uporov } 5843acd9182SFedor Uporov 5853acd9182SFedor Uporov /* 586e09c00caSUlf Lilleengen * Find a cylinder to place a directory. 587e09c00caSUlf Lilleengen * 588e09c00caSUlf Lilleengen * The policy implemented by this algorithm is to allocate a 589e09c00caSUlf Lilleengen * directory inode in the same cylinder group as its parent 590e09c00caSUlf Lilleengen * directory, but also to reserve space for its files inodes 591e09c00caSUlf Lilleengen * and data. Restrict the number of directories which may be 592e09c00caSUlf Lilleengen * allocated one after another in the same cylinder group 593e09c00caSUlf Lilleengen * without intervening allocation of files. 594e09c00caSUlf Lilleengen * 595e09c00caSUlf Lilleengen * If we allocate a first level directory then force allocation 596e09c00caSUlf Lilleengen * in another cylinder group. 597e09c00caSUlf Lilleengen * 598e09c00caSUlf Lilleengen */ 599e09c00caSUlf Lilleengen static u_long 600e09c00caSUlf Lilleengen ext2_dirpref(struct inode *pip) 601e09c00caSUlf Lilleengen { 602e09c00caSUlf Lilleengen struct m_ext2fs *fs; 603955ba37bSPedro F. Giffuni int cg, prefcg, cgsize; 6043acd9182SFedor Uporov uint64_t avgbfree, minbfree; 6053acd9182SFedor Uporov u_int avgifree, avgndir, curdirsize; 6063acd9182SFedor Uporov u_int minifree, maxndir; 607f744956bSPedro F. Giffuni u_int mincg, minndir; 608955ba37bSPedro F. Giffuni u_int dirsize, maxcontigdirs; 609e09c00caSUlf Lilleengen 610e09c00caSUlf Lilleengen mtx_assert(EXT2_MTX(pip->i_ump), MA_OWNED); 611e09c00caSUlf Lilleengen fs = pip->i_e2fs; 612e09c00caSUlf Lilleengen 613e09c00caSUlf Lilleengen avgifree = fs->e2fs->e2fs_ficount / fs->e2fs_gcount; 6143acd9182SFedor Uporov avgbfree = fs->e2fs_fbcount / fs->e2fs_gcount; 615e09c00caSUlf Lilleengen avgndir = fs->e2fs_total_dir / fs->e2fs_gcount; 616e09c00caSUlf Lilleengen 617e09c00caSUlf Lilleengen /* 618e09c00caSUlf Lilleengen * Force allocation in another cg if creating a first level dir. 619e09c00caSUlf Lilleengen */ 620e09c00caSUlf Lilleengen ASSERT_VOP_LOCKED(ITOV(pip), "ext2fs_dirpref"); 621e09c00caSUlf Lilleengen if (ITOV(pip)->v_vflag & VV_ROOT) { 622e09c00caSUlf Lilleengen prefcg = arc4random() % fs->e2fs_gcount; 623e09c00caSUlf Lilleengen mincg = prefcg; 624e09c00caSUlf Lilleengen minndir = fs->e2fs_ipg; 625e09c00caSUlf Lilleengen for (cg = prefcg; cg < fs->e2fs_gcount; cg++) 6263acd9182SFedor Uporov if (e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]) < minndir && 6273acd9182SFedor Uporov e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) >= avgifree && 6283acd9182SFedor Uporov e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) >= avgbfree) { 629e09c00caSUlf Lilleengen mincg = cg; 6303acd9182SFedor Uporov minndir = e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]); 631e09c00caSUlf Lilleengen } 632e09c00caSUlf Lilleengen for (cg = 0; cg < prefcg; cg++) 6333acd9182SFedor Uporov if (e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]) < minndir && 6343acd9182SFedor Uporov e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) >= avgifree && 6353acd9182SFedor Uporov e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) >= avgbfree) { 636e09c00caSUlf Lilleengen mincg = cg; 6373acd9182SFedor Uporov minndir = e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]); 638e09c00caSUlf Lilleengen } 639e09c00caSUlf Lilleengen return (mincg); 640e09c00caSUlf Lilleengen } 641e09c00caSUlf Lilleengen /* 642e09c00caSUlf Lilleengen * Count various limits which used for 643e09c00caSUlf Lilleengen * optimal allocation of a directory inode. 644e09c00caSUlf Lilleengen */ 645e09c00caSUlf Lilleengen maxndir = min(avgndir + fs->e2fs_ipg / 16, fs->e2fs_ipg); 646e09c00caSUlf Lilleengen minifree = avgifree - avgifree / 4; 647e09c00caSUlf Lilleengen if (minifree < 1) 648e09c00caSUlf Lilleengen minifree = 1; 649e09c00caSUlf Lilleengen minbfree = avgbfree - avgbfree / 4; 650e09c00caSUlf Lilleengen if (minbfree < 1) 651e09c00caSUlf Lilleengen minbfree = 1; 652e09c00caSUlf Lilleengen cgsize = fs->e2fs_fsize * fs->e2fs_fpg; 653e09c00caSUlf Lilleengen dirsize = AVGDIRSIZE; 654e09c00caSUlf Lilleengen curdirsize = avgndir ? (cgsize - avgbfree * fs->e2fs_bsize) / avgndir : 0; 655e09c00caSUlf Lilleengen if (dirsize < curdirsize) 656e09c00caSUlf Lilleengen dirsize = curdirsize; 657e09c00caSUlf Lilleengen maxcontigdirs = min((avgbfree * fs->e2fs_bsize) / dirsize, 255); 658e09c00caSUlf Lilleengen maxcontigdirs = min(maxcontigdirs, fs->e2fs_ipg / AFPDIR); 659e09c00caSUlf Lilleengen if (maxcontigdirs == 0) 660e09c00caSUlf Lilleengen maxcontigdirs = 1; 661e09c00caSUlf Lilleengen 662e09c00caSUlf Lilleengen /* 663e09c00caSUlf Lilleengen * Limit number of dirs in one cg and reserve space for 664e09c00caSUlf Lilleengen * regular files, but only if we have no deficit in 665e09c00caSUlf Lilleengen * inodes or space. 666e09c00caSUlf Lilleengen */ 667e09c00caSUlf Lilleengen prefcg = ino_to_cg(fs, pip->i_number); 668e09c00caSUlf Lilleengen for (cg = prefcg; cg < fs->e2fs_gcount; cg++) 6693acd9182SFedor Uporov if (e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]) < maxndir && 6703acd9182SFedor Uporov e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) >= minifree && 6713acd9182SFedor Uporov e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) >= minbfree) { 672e09c00caSUlf Lilleengen if (fs->e2fs_contigdirs[cg] < maxcontigdirs) 673e09c00caSUlf Lilleengen return (cg); 674e09c00caSUlf Lilleengen } 675ca73017aSPedro F. Giffuni for (cg = 0; cg < prefcg; cg++) 6763acd9182SFedor Uporov if (e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]) < maxndir && 6773acd9182SFedor Uporov e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) >= minifree && 6783acd9182SFedor Uporov e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) >= minbfree) { 679e09c00caSUlf Lilleengen if (fs->e2fs_contigdirs[cg] < maxcontigdirs) 680e09c00caSUlf Lilleengen return (cg); 681e09c00caSUlf Lilleengen } 682e09c00caSUlf Lilleengen /* 683e09c00caSUlf Lilleengen * This is a backstop when we have deficit in space. 684e09c00caSUlf Lilleengen */ 685e09c00caSUlf Lilleengen for (cg = prefcg; cg < fs->e2fs_gcount; cg++) 6863acd9182SFedor Uporov if (e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) >= avgifree) 687e09c00caSUlf Lilleengen return (cg); 688ca73017aSPedro F. Giffuni for (cg = 0; cg < prefcg; cg++) 6893acd9182SFedor Uporov if (e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) >= avgifree) 690e09c00caSUlf Lilleengen break; 691e09c00caSUlf Lilleengen return (cg); 692e09c00caSUlf Lilleengen } 693e09c00caSUlf Lilleengen 694e09c00caSUlf Lilleengen /* 695e09c00caSUlf Lilleengen * Select the desired position for the next block in a file. 696e09c00caSUlf Lilleengen * 697e09c00caSUlf Lilleengen * we try to mimic what Remy does in inode_getblk/block_getblk 698e09c00caSUlf Lilleengen * 699e09c00caSUlf Lilleengen * we note: blocknr == 0 means that we're about to allocate either 700e09c00caSUlf Lilleengen * a direct block or a pointer block at the first level of indirection 701e09c00caSUlf Lilleengen * (In other words, stuff that will go in i_db[] or i_ib[]) 702e09c00caSUlf Lilleengen * 703e09c00caSUlf Lilleengen * blocknr != 0 means that we're allocating a block that is none 704e09c00caSUlf Lilleengen * of the above. Then, blocknr tells us the number of the block 705e09c00caSUlf Lilleengen * that will hold the pointer 706e09c00caSUlf Lilleengen */ 70770097aacSPedro F. Giffuni e4fs_daddr_t 70870097aacSPedro F. Giffuni ext2_blkpref(struct inode *ip, e2fs_lbn_t lbn, int indx, e2fs_daddr_t *bap, 70970097aacSPedro F. Giffuni e2fs_daddr_t blocknr) 710e09c00caSUlf Lilleengen { 711b394cd1eSFedor Uporov struct m_ext2fs *fs; 712e09c00caSUlf Lilleengen int tmp; 713bf9a211dSPedro F. Giffuni 714b394cd1eSFedor Uporov fs = ip->i_e2fs; 715b394cd1eSFedor Uporov 716e09c00caSUlf Lilleengen mtx_assert(EXT2_MTX(ip->i_ump), MA_OWNED); 717e09c00caSUlf Lilleengen 718bf9a211dSPedro F. Giffuni /* 719bf9a211dSPedro F. Giffuni * If the next block is actually what we thought it is, then set the 720bf9a211dSPedro F. Giffuni * goal to what we thought it should be. 721e09c00caSUlf Lilleengen */ 722e09c00caSUlf Lilleengen if (ip->i_next_alloc_block == lbn && ip->i_next_alloc_goal != 0) 723e09c00caSUlf Lilleengen return ip->i_next_alloc_goal; 724e09c00caSUlf Lilleengen 725bf9a211dSPedro F. Giffuni /* 726bf9a211dSPedro F. Giffuni * Now check whether we were provided with an array that basically 727bf9a211dSPedro F. Giffuni * tells us previous blocks to which we want to stay close. 728e09c00caSUlf Lilleengen */ 729e09c00caSUlf Lilleengen if (bap) 730e09c00caSUlf Lilleengen for (tmp = indx - 1; tmp >= 0; tmp--) 731e09c00caSUlf Lilleengen if (bap[tmp]) 732e09c00caSUlf Lilleengen return bap[tmp]; 733e09c00caSUlf Lilleengen 734bf9a211dSPedro F. Giffuni /* 735bf9a211dSPedro F. Giffuni * Else lets fall back to the blocknr or, if there is none, follow 736bf9a211dSPedro F. Giffuni * the rule that a block should be allocated near its inode. 737e09c00caSUlf Lilleengen */ 738b394cd1eSFedor Uporov return (blocknr ? blocknr : 73970097aacSPedro F. Giffuni (e2fs_daddr_t)(ip->i_block_group * 740b394cd1eSFedor Uporov EXT2_BLOCKS_PER_GROUP(fs)) + fs->e2fs->e2fs_first_dblock); 741e09c00caSUlf Lilleengen } 742e09c00caSUlf Lilleengen 743e09c00caSUlf Lilleengen /* 744e09c00caSUlf Lilleengen * Implement the cylinder overflow algorithm. 745e09c00caSUlf Lilleengen * 746e09c00caSUlf Lilleengen * The policy implemented by this algorithm is: 747e09c00caSUlf Lilleengen * 1) allocate the block in its requested cylinder group. 748e09c00caSUlf Lilleengen * 2) quadradically rehash on the cylinder group number. 749e09c00caSUlf Lilleengen * 3) brute force search for a free block. 750e09c00caSUlf Lilleengen */ 751ffbde5eaSFedor Uporov static e4fs_daddr_t 752e09c00caSUlf Lilleengen ext2_hashalloc(struct inode *ip, int cg, long pref, int size, 753e09c00caSUlf Lilleengen daddr_t (*allocator) (struct inode *, int, daddr_t, int)) 754e09c00caSUlf Lilleengen { 755e09c00caSUlf Lilleengen struct m_ext2fs *fs; 756ffbde5eaSFedor Uporov e4fs_daddr_t result; 757e09c00caSUlf Lilleengen int i, icg = cg; 758e09c00caSUlf Lilleengen 759e09c00caSUlf Lilleengen mtx_assert(EXT2_MTX(ip->i_ump), MA_OWNED); 760e09c00caSUlf Lilleengen fs = ip->i_e2fs; 761e09c00caSUlf Lilleengen /* 762e09c00caSUlf Lilleengen * 1: preferred cylinder group 763e09c00caSUlf Lilleengen */ 764e09c00caSUlf Lilleengen result = (*allocator)(ip, cg, pref, size); 765e09c00caSUlf Lilleengen if (result) 766e09c00caSUlf Lilleengen return (result); 767e09c00caSUlf Lilleengen /* 768e09c00caSUlf Lilleengen * 2: quadratic rehash 769e09c00caSUlf Lilleengen */ 770e09c00caSUlf Lilleengen for (i = 1; i < fs->e2fs_gcount; i *= 2) { 771e09c00caSUlf Lilleengen cg += i; 772e09c00caSUlf Lilleengen if (cg >= fs->e2fs_gcount) 773e09c00caSUlf Lilleengen cg -= fs->e2fs_gcount; 774e09c00caSUlf Lilleengen result = (*allocator)(ip, cg, 0, size); 775e09c00caSUlf Lilleengen if (result) 776e09c00caSUlf Lilleengen return (result); 777e09c00caSUlf Lilleengen } 778e09c00caSUlf Lilleengen /* 779e09c00caSUlf Lilleengen * 3: brute force search 780e09c00caSUlf Lilleengen * Note that we start at i == 2, since 0 was checked initially, 781e09c00caSUlf Lilleengen * and 1 is always checked in the quadratic rehash. 782e09c00caSUlf Lilleengen */ 783e09c00caSUlf Lilleengen cg = (icg + 2) % fs->e2fs_gcount; 784e09c00caSUlf Lilleengen for (i = 2; i < fs->e2fs_gcount; i++) { 785e09c00caSUlf Lilleengen result = (*allocator)(ip, cg, 0, size); 786e09c00caSUlf Lilleengen if (result) 787e09c00caSUlf Lilleengen return (result); 788e09c00caSUlf Lilleengen cg++; 789e09c00caSUlf Lilleengen if (cg == fs->e2fs_gcount) 790e09c00caSUlf Lilleengen cg = 0; 791e09c00caSUlf Lilleengen } 792e09c00caSUlf Lilleengen return (0); 793e09c00caSUlf Lilleengen } 794e09c00caSUlf Lilleengen 7956e38bf94SFedor Uporov static uint64_t 796c0f16c65SFedor Uporov ext2_cg_number_gdb_nometa(struct m_ext2fs *fs, int cg) 797d23db91eSPedro F. Giffuni { 798d23db91eSPedro F. Giffuni 799d23db91eSPedro F. Giffuni if (!ext2_cg_has_sb(fs, cg)) 800d23db91eSPedro F. Giffuni return (0); 801c0f16c65SFedor Uporov 802d23db91eSPedro F. Giffuni if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_META_BG)) 803d23db91eSPedro F. Giffuni return (fs->e2fs->e3fs_first_meta_bg); 804c0f16c65SFedor Uporov 805c0f16c65SFedor Uporov return ((fs->e2fs_gcount + EXT2_DESCS_PER_BLOCK(fs) - 1) / 806c0f16c65SFedor Uporov EXT2_DESCS_PER_BLOCK(fs)); 807d23db91eSPedro F. Giffuni } 808d23db91eSPedro F. Giffuni 8096e38bf94SFedor Uporov static uint64_t 810c0f16c65SFedor Uporov ext2_cg_number_gdb_meta(struct m_ext2fs *fs, int cg) 811c0f16c65SFedor Uporov { 812c0f16c65SFedor Uporov unsigned long metagroup; 813c0f16c65SFedor Uporov int first, last; 814c0f16c65SFedor Uporov 815c0f16c65SFedor Uporov metagroup = cg / EXT2_DESCS_PER_BLOCK(fs); 816c0f16c65SFedor Uporov first = metagroup * EXT2_DESCS_PER_BLOCK(fs); 817c0f16c65SFedor Uporov last = first + EXT2_DESCS_PER_BLOCK(fs) - 1; 818c0f16c65SFedor Uporov 819d23db91eSPedro F. Giffuni if (cg == first || cg == first + 1 || cg == last) 820d23db91eSPedro F. Giffuni return (1); 821d23db91eSPedro F. Giffuni 822c0f16c65SFedor Uporov return (0); 823c0f16c65SFedor Uporov } 824c0f16c65SFedor Uporov 8256e38bf94SFedor Uporov uint64_t 826c0f16c65SFedor Uporov ext2_cg_number_gdb(struct m_ext2fs *fs, int cg) 827c0f16c65SFedor Uporov { 828c0f16c65SFedor Uporov unsigned long first_meta_bg, metagroup; 829c0f16c65SFedor Uporov 830c0f16c65SFedor Uporov first_meta_bg = fs->e2fs->e3fs_first_meta_bg; 831c0f16c65SFedor Uporov metagroup = cg / EXT2_DESCS_PER_BLOCK(fs); 832c0f16c65SFedor Uporov 833c0f16c65SFedor Uporov if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_META_BG) || 834c0f16c65SFedor Uporov metagroup < first_meta_bg) 835c0f16c65SFedor Uporov return (ext2_cg_number_gdb_nometa(fs, cg)); 836c0f16c65SFedor Uporov 837c0f16c65SFedor Uporov return ext2_cg_number_gdb_meta(fs, cg); 838d23db91eSPedro F. Giffuni } 839d23db91eSPedro F. Giffuni 840d23db91eSPedro F. Giffuni static int 841c0f16c65SFedor Uporov ext2_number_base_meta_blocks(struct m_ext2fs *fs, int cg) 842d23db91eSPedro F. Giffuni { 843c0f16c65SFedor Uporov int number; 844d23db91eSPedro F. Giffuni 845c0f16c65SFedor Uporov number = ext2_cg_has_sb(fs, cg); 846d23db91eSPedro F. Giffuni 847d23db91eSPedro F. Giffuni if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_META_BG) || 848c0f16c65SFedor Uporov cg < fs->e2fs->e3fs_first_meta_bg * EXT2_DESCS_PER_BLOCK(fs)) { 849c0f16c65SFedor Uporov if (number) { 850c0f16c65SFedor Uporov number += ext2_cg_number_gdb(fs, cg); 851c0f16c65SFedor Uporov number += 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 878c0f16c65SFedor Uporov return ((block - fs->e2fs->e2fs_first_dblock) / fs->e2fs_bsize); 879c0f16c65SFedor Uporov } 880c0f16c65SFedor Uporov 881c0f16c65SFedor Uporov static int 882c0f16c65SFedor Uporov ext2_block_in_group(struct m_ext2fs *fs, e4fs_daddr_t block, int cg) 883c0f16c65SFedor Uporov { 884c0f16c65SFedor Uporov 885c0f16c65SFedor Uporov return ((ext2_get_group_number(fs, block) == cg) ? 1 : 0); 886c0f16c65SFedor Uporov } 887c0f16c65SFedor Uporov 888c0f16c65SFedor Uporov static int 889d23db91eSPedro F. Giffuni ext2_cg_block_bitmap_init(struct m_ext2fs *fs, int cg, struct buf *bp) 890d23db91eSPedro F. Giffuni { 891d23db91eSPedro F. Giffuni int bit, bit_max, inodes_per_block; 8923acd9182SFedor Uporov uint64_t start, tmp; 893d23db91eSPedro F. Giffuni 8943acd9182SFedor Uporov if (!(fs->e2fs_gd[cg].ext4bgd_flags & EXT2_BG_BLOCK_UNINIT)) 895d23db91eSPedro F. Giffuni return (0); 896d23db91eSPedro F. Giffuni 897d23db91eSPedro F. Giffuni memset(bp->b_data, 0, fs->e2fs_bsize); 898d23db91eSPedro F. Giffuni 899c0f16c65SFedor Uporov bit_max = ext2_number_base_meta_blocks(fs, cg); 900d23db91eSPedro F. Giffuni if ((bit_max >> 3) >= fs->e2fs_bsize) 901d23db91eSPedro F. Giffuni return (EINVAL); 902d23db91eSPedro F. Giffuni 903d23db91eSPedro F. Giffuni for (bit = 0; bit < bit_max; bit++) 904d23db91eSPedro F. Giffuni setbit(bp->b_data, bit); 905d23db91eSPedro F. Giffuni 9063acd9182SFedor Uporov start = (uint64_t)cg * fs->e2fs->e2fs_bpg + fs->e2fs->e2fs_first_dblock; 907d23db91eSPedro F. Giffuni 9083acd9182SFedor Uporov /* Set bits for block and inode bitmaps, and inode table. */ 9093acd9182SFedor Uporov tmp = e2fs_gd_get_b_bitmap(&fs->e2fs_gd[cg]); 910d23db91eSPedro F. Giffuni if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_FLEX_BG) || 911c0f16c65SFedor Uporov ext2_block_in_group(fs, tmp, cg)) 912d23db91eSPedro F. Giffuni setbit(bp->b_data, tmp - start); 913d23db91eSPedro F. Giffuni 9143acd9182SFedor Uporov tmp = e2fs_gd_get_i_bitmap(&fs->e2fs_gd[cg]); 915d23db91eSPedro F. Giffuni if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_FLEX_BG) || 916c0f16c65SFedor Uporov ext2_block_in_group(fs, tmp, cg)) 917d23db91eSPedro F. Giffuni setbit(bp->b_data, tmp - start); 918d23db91eSPedro F. Giffuni 9193acd9182SFedor Uporov tmp = e2fs_gd_get_i_tables(&fs->e2fs_gd[cg]); 920d23db91eSPedro F. Giffuni inodes_per_block = fs->e2fs_bsize/EXT2_INODE_SIZE(fs); 9213acd9182SFedor Uporov while( tmp < e2fs_gd_get_i_tables(&fs->e2fs_gd[cg]) + 922d23db91eSPedro F. Giffuni fs->e2fs->e2fs_ipg / inodes_per_block ) { 923d23db91eSPedro F. Giffuni if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_FLEX_BG) || 924c0f16c65SFedor Uporov ext2_block_in_group(fs, tmp, cg)) 925d23db91eSPedro F. Giffuni setbit(bp->b_data, tmp - start); 926d23db91eSPedro F. Giffuni tmp++; 927d23db91eSPedro F. Giffuni } 928d23db91eSPedro F. Giffuni 929d23db91eSPedro F. Giffuni /* 930d23db91eSPedro F. Giffuni * Also if the number of blocks within the group is less than 931d23db91eSPedro F. Giffuni * the blocksize * 8 ( which is the size of bitmap ), set rest 932d23db91eSPedro F. Giffuni * of the block bitmap to 1 933d23db91eSPedro F. Giffuni */ 934d23db91eSPedro F. Giffuni ext2_mark_bitmap_end(fs->e2fs->e2fs_bpg, fs->e2fs_bsize * 8, 935d23db91eSPedro F. Giffuni bp->b_data); 936d23db91eSPedro F. Giffuni 937d23db91eSPedro F. Giffuni /* Clean the flag */ 938d23db91eSPedro F. Giffuni fs->e2fs_gd[cg].ext4bgd_flags &= ~EXT2_BG_BLOCK_UNINIT; 939d23db91eSPedro F. Giffuni 940d23db91eSPedro F. Giffuni return (0); 941d23db91eSPedro F. Giffuni } 942d23db91eSPedro F. Giffuni 94380a4a971SFedor Uporov static int 94480a4a971SFedor Uporov ext2_b_bitmap_validate(struct m_ext2fs *fs, struct buf *bp, int cg) 94580a4a971SFedor Uporov { 94680a4a971SFedor Uporov struct ext2_gd *gd; 94780a4a971SFedor Uporov uint64_t group_first_block; 94880a4a971SFedor Uporov unsigned int offset, max_bit; 94980a4a971SFedor Uporov 95080a4a971SFedor Uporov if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_FLEX_BG)) { 95180a4a971SFedor Uporov /* 95280a4a971SFedor Uporov * It is not possible to check block bitmap in case of this feature, 95380a4a971SFedor Uporov * because the inode and block bitmaps and inode table 95480a4a971SFedor Uporov * blocks may not be in the group at all. 95580a4a971SFedor Uporov * So, skip check in this case. 95680a4a971SFedor Uporov */ 95780a4a971SFedor Uporov return (0); 95880a4a971SFedor Uporov } 95980a4a971SFedor Uporov 96080a4a971SFedor Uporov gd = &fs->e2fs_gd[cg]; 96180a4a971SFedor Uporov max_bit = fs->e2fs_fpg; 96280a4a971SFedor Uporov group_first_block = ((uint64_t)cg) * fs->e2fs->e2fs_fpg + 96380a4a971SFedor Uporov fs->e2fs->e2fs_first_dblock; 96480a4a971SFedor Uporov 96580a4a971SFedor Uporov /* Check block bitmap block number */ 96680a4a971SFedor Uporov offset = e2fs_gd_get_b_bitmap(gd) - group_first_block; 96780a4a971SFedor Uporov if (offset >= max_bit || !isset(bp->b_data, offset)) { 96880a4a971SFedor Uporov printf("ext2fs: bad block bitmap, group %d\n", cg); 96980a4a971SFedor Uporov return (EINVAL); 97080a4a971SFedor Uporov } 97180a4a971SFedor Uporov 97280a4a971SFedor Uporov /* Check inode bitmap block number */ 97380a4a971SFedor Uporov offset = e2fs_gd_get_i_bitmap(gd) - group_first_block; 97480a4a971SFedor Uporov if (offset >= max_bit || !isset(bp->b_data, offset)) { 97580a4a971SFedor Uporov printf("ext2fs: bad inode bitmap, group %d\n", cg); 97680a4a971SFedor Uporov return (EINVAL); 97780a4a971SFedor Uporov } 97880a4a971SFedor Uporov 97980a4a971SFedor Uporov /* Check inode table */ 98080a4a971SFedor Uporov offset = e2fs_gd_get_i_tables(gd) - group_first_block; 98180a4a971SFedor Uporov if (offset >= max_bit || offset + fs->e2fs_itpg >= max_bit) { 98280a4a971SFedor Uporov printf("ext2fs: bad inode table, group %d\n", cg); 98380a4a971SFedor Uporov return (EINVAL); 98480a4a971SFedor Uporov } 98580a4a971SFedor Uporov 98680a4a971SFedor Uporov return (0); 98780a4a971SFedor Uporov } 98880a4a971SFedor Uporov 989e09c00caSUlf Lilleengen /* 990e09c00caSUlf Lilleengen * Determine whether a block can be allocated. 991e09c00caSUlf Lilleengen * 992e09c00caSUlf Lilleengen * Check to see if a block of the appropriate size is available, 993e09c00caSUlf Lilleengen * and if it is, allocate it. 994e09c00caSUlf Lilleengen */ 995e09c00caSUlf Lilleengen static daddr_t 996e09c00caSUlf Lilleengen ext2_alloccg(struct inode *ip, int cg, daddr_t bpref, int size) 997e09c00caSUlf Lilleengen { 998e09c00caSUlf Lilleengen struct m_ext2fs *fs; 999e09c00caSUlf Lilleengen struct buf *bp; 1000e09c00caSUlf Lilleengen struct ext2mount *ump; 1001c767faa5SJohn Baldwin daddr_t bno, runstart, runlen; 1002c767faa5SJohn Baldwin int bit, loc, end, error, start; 1003e09c00caSUlf Lilleengen char *bbp; 1004e09c00caSUlf Lilleengen /* XXX ondisk32 */ 1005e09c00caSUlf Lilleengen fs = ip->i_e2fs; 1006e09c00caSUlf Lilleengen ump = ip->i_ump; 10073acd9182SFedor Uporov if (e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) == 0) 1008e09c00caSUlf Lilleengen return (0); 100980a4a971SFedor Uporov 1010e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 1011e09c00caSUlf Lilleengen error = bread(ip->i_devvp, fsbtodb(fs, 10123acd9182SFedor Uporov e2fs_gd_get_b_bitmap(&fs->e2fs_gd[cg])), 1013e09c00caSUlf Lilleengen (int)fs->e2fs_bsize, NOCRED, &bp); 101480a4a971SFedor Uporov if (error) 101580a4a971SFedor Uporov goto fail; 101680a4a971SFedor Uporov 1017512f29d1SFedor Uporov if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) || 1018512f29d1SFedor Uporov EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { 1019d23db91eSPedro F. Giffuni error = ext2_cg_block_bitmap_init(fs, cg, bp); 102080a4a971SFedor Uporov if (error) 102180a4a971SFedor Uporov goto fail; 102280a4a971SFedor Uporov 1023512f29d1SFedor Uporov ext2_gd_b_bitmap_csum_set(fs, cg, bp); 1024512f29d1SFedor Uporov } 1025512f29d1SFedor Uporov error = ext2_gd_b_bitmap_csum_verify(fs, cg, bp); 102680a4a971SFedor Uporov if (error) 102780a4a971SFedor Uporov goto fail; 102880a4a971SFedor Uporov 102980a4a971SFedor Uporov error = ext2_b_bitmap_validate(fs,bp, cg); 103080a4a971SFedor Uporov if (error) 103180a4a971SFedor Uporov goto fail; 103280a4a971SFedor Uporov 103373dd6d1fSJohn Baldwin /* 103480a4a971SFedor Uporov * Check, that another thread did not not allocate the last block in this 103573dd6d1fSJohn Baldwin * group while we were waiting for the buffer. 103673dd6d1fSJohn Baldwin */ 103780a4a971SFedor Uporov if (e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) == 0) 103880a4a971SFedor Uporov goto fail; 103980a4a971SFedor Uporov 1040e09c00caSUlf Lilleengen bbp = (char *)bp->b_data; 1041e09c00caSUlf Lilleengen 1042e09c00caSUlf Lilleengen if (dtog(fs, bpref) != cg) 1043e09c00caSUlf Lilleengen bpref = 0; 1044e09c00caSUlf Lilleengen if (bpref != 0) { 1045e09c00caSUlf Lilleengen bpref = dtogd(fs, bpref); 1046e09c00caSUlf Lilleengen /* 1047e09c00caSUlf Lilleengen * if the requested block is available, use it 1048e09c00caSUlf Lilleengen */ 1049e09c00caSUlf Lilleengen if (isclr(bbp, bpref)) { 1050e09c00caSUlf Lilleengen bno = bpref; 1051e09c00caSUlf Lilleengen goto gotit; 1052e09c00caSUlf Lilleengen } 1053e09c00caSUlf Lilleengen } 1054e09c00caSUlf Lilleengen /* 1055e09c00caSUlf Lilleengen * no blocks in the requested cylinder, so take next 1056e09c00caSUlf Lilleengen * available one in this cylinder group. 1057e09c00caSUlf Lilleengen * first try to get 8 contigous blocks, then fall back to a single 1058e09c00caSUlf Lilleengen * block. 1059e09c00caSUlf Lilleengen */ 1060e09c00caSUlf Lilleengen if (bpref) 1061e09c00caSUlf Lilleengen start = dtogd(fs, bpref) / NBBY; 1062e09c00caSUlf Lilleengen else 1063e09c00caSUlf Lilleengen start = 0; 1064e09c00caSUlf Lilleengen end = howmany(fs->e2fs->e2fs_fpg, NBBY) - start; 1065c767faa5SJohn Baldwin retry: 1066c767faa5SJohn Baldwin runlen = 0; 1067c767faa5SJohn Baldwin runstart = 0; 1068e09c00caSUlf Lilleengen for (loc = start; loc < end; loc++) { 1069c767faa5SJohn Baldwin if (bbp[loc] == (char)0xff) { 1070c767faa5SJohn Baldwin runlen = 0; 1071c767faa5SJohn Baldwin continue; 1072c767faa5SJohn Baldwin } 1073c767faa5SJohn Baldwin 1074c767faa5SJohn Baldwin /* Start of a run, find the number of high clear bits. */ 1075c767faa5SJohn Baldwin if (runlen == 0) { 1076c767faa5SJohn Baldwin bit = fls(bbp[loc]); 1077c767faa5SJohn Baldwin runlen = NBBY - bit; 1078c767faa5SJohn Baldwin runstart = loc * NBBY + bit; 1079c767faa5SJohn Baldwin } else if (bbp[loc] == 0) { 1080c767faa5SJohn Baldwin /* Continue a run. */ 1081c767faa5SJohn Baldwin runlen += NBBY; 1082c767faa5SJohn Baldwin } else { 1083c767faa5SJohn Baldwin /* 1084c767faa5SJohn Baldwin * Finish the current run. If it isn't long 1085c767faa5SJohn Baldwin * enough, start a new one. 1086c767faa5SJohn Baldwin */ 1087c767faa5SJohn Baldwin bit = ffs(bbp[loc]) - 1; 1088c767faa5SJohn Baldwin runlen += bit; 1089c767faa5SJohn Baldwin if (runlen >= 8) { 1090c767faa5SJohn Baldwin bno = runstart; 1091c767faa5SJohn Baldwin goto gotit; 1092c767faa5SJohn Baldwin } 1093c767faa5SJohn Baldwin 1094c767faa5SJohn Baldwin /* Run was too short, start a new one. */ 1095c767faa5SJohn Baldwin bit = fls(bbp[loc]); 1096c767faa5SJohn Baldwin runlen = NBBY - bit; 1097c767faa5SJohn Baldwin runstart = loc * NBBY + bit; 1098c767faa5SJohn Baldwin } 1099c767faa5SJohn Baldwin 1100c767faa5SJohn Baldwin /* If the current run is long enough, use it. */ 1101c767faa5SJohn Baldwin if (runlen >= 8) { 1102c767faa5SJohn Baldwin bno = runstart; 1103e09c00caSUlf Lilleengen goto gotit; 1104e09c00caSUlf Lilleengen } 1105e09c00caSUlf Lilleengen } 1106c767faa5SJohn Baldwin if (start != 0) { 1107c767faa5SJohn Baldwin end = start; 1108c767faa5SJohn Baldwin start = 0; 1109c767faa5SJohn Baldwin goto retry; 1110e09c00caSUlf Lilleengen } 1111e09c00caSUlf Lilleengen bno = ext2_mapsearch(fs, bbp, bpref); 111280a4a971SFedor Uporov if (bno < 0) 111380a4a971SFedor Uporov goto fail; 111480a4a971SFedor Uporov 1115e09c00caSUlf Lilleengen gotit: 111677b193c2SPedro F. Giffuni #ifdef INVARIANTS 11178e42a406SJohn Baldwin if (isset(bbp, bno)) { 11188e42a406SJohn Baldwin printf("ext2fs_alloccgblk: cg=%d bno=%jd fs=%s\n", 11198e42a406SJohn Baldwin cg, (intmax_t)bno, fs->e2fs_fsmnt); 1120e09c00caSUlf Lilleengen panic("ext2fs_alloccg: dup alloc"); 1121e09c00caSUlf Lilleengen } 1122e09c00caSUlf Lilleengen #endif 11238e42a406SJohn Baldwin setbit(bbp, bno); 1124e09c00caSUlf Lilleengen EXT2_LOCK(ump); 11255b63c125SPedro F. Giffuni ext2_clusteracct(fs, bbp, cg, bno, -1); 11263acd9182SFedor Uporov fs->e2fs_fbcount--; 11273acd9182SFedor Uporov e2fs_gd_set_nbfree(&fs->e2fs_gd[cg], 11283acd9182SFedor Uporov e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) - 1); 1129e09c00caSUlf Lilleengen fs->e2fs_fmod = 1; 1130e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 1131512f29d1SFedor Uporov ext2_gd_b_bitmap_csum_set(fs, cg, bp); 1132e09c00caSUlf Lilleengen bdwrite(bp); 11333acd9182SFedor Uporov return (((uint64_t)cg) * fs->e2fs->e2fs_fpg + fs->e2fs->e2fs_first_dblock + bno); 113480a4a971SFedor Uporov 113580a4a971SFedor Uporov fail: 113680a4a971SFedor Uporov brelse(bp); 113780a4a971SFedor Uporov EXT2_LOCK(ump); 113880a4a971SFedor Uporov return (0); 1139e09c00caSUlf Lilleengen } 1140e09c00caSUlf Lilleengen 1141e09c00caSUlf Lilleengen /* 11425b63c125SPedro F. Giffuni * Determine whether a cluster can be allocated. 11435b63c125SPedro F. Giffuni */ 11445b63c125SPedro F. Giffuni static daddr_t 11455b63c125SPedro F. Giffuni ext2_clusteralloc(struct inode *ip, int cg, daddr_t bpref, int len) 11465b63c125SPedro F. Giffuni { 11475b63c125SPedro F. Giffuni struct m_ext2fs *fs; 11485b63c125SPedro F. Giffuni struct ext2mount *ump; 11495b63c125SPedro F. Giffuni struct buf *bp; 11505b63c125SPedro F. Giffuni char *bbp; 11515b63c125SPedro F. Giffuni int bit, error, got, i, loc, run; 11525b63c125SPedro F. Giffuni int32_t *lp; 11535b63c125SPedro F. Giffuni daddr_t bno; 11545b63c125SPedro F. Giffuni 11555b63c125SPedro F. Giffuni fs = ip->i_e2fs; 11565b63c125SPedro F. Giffuni ump = ip->i_ump; 11575b63c125SPedro F. Giffuni 11585b63c125SPedro F. Giffuni if (fs->e2fs_maxcluster[cg] < len) 11595b63c125SPedro F. Giffuni return (0); 11605b63c125SPedro F. Giffuni 11615b63c125SPedro F. Giffuni EXT2_UNLOCK(ump); 11625b63c125SPedro F. Giffuni error = bread(ip->i_devvp, 11633acd9182SFedor Uporov fsbtodb(fs, e2fs_gd_get_b_bitmap(&fs->e2fs_gd[cg])), 11645b63c125SPedro F. Giffuni (int)fs->e2fs_bsize, NOCRED, &bp); 11655b63c125SPedro F. Giffuni if (error) 11665b63c125SPedro F. Giffuni goto fail_lock; 11675b63c125SPedro F. Giffuni 11685b63c125SPedro F. Giffuni bbp = (char *)bp->b_data; 11695b63c125SPedro F. Giffuni EXT2_LOCK(ump); 11705b63c125SPedro F. Giffuni /* 11715b63c125SPedro F. Giffuni * Check to see if a cluster of the needed size (or bigger) is 11725b63c125SPedro F. Giffuni * available in this cylinder group. 11735b63c125SPedro F. Giffuni */ 11745b63c125SPedro F. Giffuni lp = &fs->e2fs_clustersum[cg].cs_sum[len]; 11755b63c125SPedro F. Giffuni for (i = len; i <= fs->e2fs_contigsumsize; i++) 11765b63c125SPedro F. Giffuni if (*lp++ > 0) 11775b63c125SPedro F. Giffuni break; 11785b63c125SPedro F. Giffuni if (i > fs->e2fs_contigsumsize) { 11795b63c125SPedro F. Giffuni /* 11805b63c125SPedro F. Giffuni * Update the cluster summary information to reflect 11815b63c125SPedro F. Giffuni * the true maximum-sized cluster so that future cluster 11825b63c125SPedro F. Giffuni * allocation requests can avoid reading the bitmap only 11835b63c125SPedro F. Giffuni * to find no cluster. 11845b63c125SPedro F. Giffuni */ 11855b63c125SPedro F. Giffuni lp = &fs->e2fs_clustersum[cg].cs_sum[len - 1]; 11865b63c125SPedro F. Giffuni for (i = len - 1; i > 0; i--) 11875b63c125SPedro F. Giffuni if (*lp-- > 0) 11885b63c125SPedro F. Giffuni break; 11895b63c125SPedro F. Giffuni fs->e2fs_maxcluster[cg] = i; 11905b63c125SPedro F. Giffuni goto fail; 11915b63c125SPedro F. Giffuni } 11925b63c125SPedro F. Giffuni EXT2_UNLOCK(ump); 11935b63c125SPedro F. Giffuni 11945b63c125SPedro F. Giffuni /* Search the bitmap to find a big enough cluster like in FFS. */ 11955b63c125SPedro F. Giffuni if (dtog(fs, bpref) != cg) 11965b63c125SPedro F. Giffuni bpref = 0; 11975b63c125SPedro F. Giffuni if (bpref != 0) 11985b63c125SPedro F. Giffuni bpref = dtogd(fs, bpref); 11995b63c125SPedro F. Giffuni loc = bpref / NBBY; 12005b63c125SPedro F. Giffuni bit = 1 << (bpref % NBBY); 12015b63c125SPedro F. Giffuni for (run = 0, got = bpref; got < fs->e2fs->e2fs_fpg; got++) { 12025b63c125SPedro F. Giffuni if ((bbp[loc] & bit) != 0) 12035b63c125SPedro F. Giffuni run = 0; 12045b63c125SPedro F. Giffuni else { 12055b63c125SPedro F. Giffuni run++; 12065b63c125SPedro F. Giffuni if (run == len) 12075b63c125SPedro F. Giffuni break; 12085b63c125SPedro F. Giffuni } 12095b63c125SPedro F. Giffuni if ((got & (NBBY - 1)) != (NBBY - 1)) 12105b63c125SPedro F. Giffuni bit <<= 1; 12115b63c125SPedro F. Giffuni else { 12125b63c125SPedro F. Giffuni loc++; 12135b63c125SPedro F. Giffuni bit = 1; 12145b63c125SPedro F. Giffuni } 12155b63c125SPedro F. Giffuni } 12165b63c125SPedro F. Giffuni 12175b63c125SPedro F. Giffuni if (got >= fs->e2fs->e2fs_fpg) 12185b63c125SPedro F. Giffuni goto fail_lock; 12195b63c125SPedro F. Giffuni 12205b63c125SPedro F. Giffuni /* Allocate the cluster that we found. */ 12215b63c125SPedro F. Giffuni for (i = 1; i < len; i++) 12225b63c125SPedro F. Giffuni if (!isclr(bbp, got - run + i)) 12235b63c125SPedro F. Giffuni panic("ext2_clusteralloc: map mismatch"); 12245b63c125SPedro F. Giffuni 12255b63c125SPedro F. Giffuni bno = got - run + 1; 12265b63c125SPedro F. Giffuni if (bno >= fs->e2fs->e2fs_fpg) 12275b63c125SPedro F. Giffuni panic("ext2_clusteralloc: allocated out of group"); 12285b63c125SPedro F. Giffuni 12295b63c125SPedro F. Giffuni EXT2_LOCK(ump); 12305b63c125SPedro F. Giffuni for (i = 0; i < len; i += fs->e2fs_fpb) { 12315b63c125SPedro F. Giffuni setbit(bbp, bno + i); 12325b63c125SPedro F. Giffuni ext2_clusteracct(fs, bbp, cg, bno + i, -1); 12333acd9182SFedor Uporov fs->e2fs_fbcount--; 12343acd9182SFedor Uporov e2fs_gd_set_nbfree(&fs->e2fs_gd[cg], 12353acd9182SFedor Uporov e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) - 1); 12365b63c125SPedro F. Giffuni } 12375b63c125SPedro F. Giffuni fs->e2fs_fmod = 1; 12385b63c125SPedro F. Giffuni EXT2_UNLOCK(ump); 12395b63c125SPedro F. Giffuni 12405b63c125SPedro F. Giffuni bdwrite(bp); 12415b63c125SPedro F. Giffuni return (cg * fs->e2fs->e2fs_fpg + fs->e2fs->e2fs_first_dblock + bno); 12425b63c125SPedro F. Giffuni 12435b63c125SPedro F. Giffuni fail_lock: 12445b63c125SPedro F. Giffuni EXT2_LOCK(ump); 12455b63c125SPedro F. Giffuni fail: 12465b63c125SPedro F. Giffuni brelse(bp); 12475b63c125SPedro F. Giffuni return (0); 12485b63c125SPedro F. Giffuni } 12495b63c125SPedro F. Giffuni 1250d23db91eSPedro F. Giffuni static int 1251d23db91eSPedro F. Giffuni ext2_zero_inode_table(struct inode *ip, int cg) 1252d23db91eSPedro F. Giffuni { 1253d23db91eSPedro F. Giffuni struct m_ext2fs *fs; 1254d23db91eSPedro F. Giffuni struct buf *bp; 1255d23db91eSPedro F. Giffuni int i, all_blks, used_blks; 1256d23db91eSPedro F. Giffuni 1257d23db91eSPedro F. Giffuni fs = ip->i_e2fs; 1258d23db91eSPedro F. Giffuni 1259d23db91eSPedro F. Giffuni if (fs->e2fs_gd[cg].ext4bgd_flags & EXT2_BG_INODE_ZEROED) 1260d23db91eSPedro F. Giffuni return (0); 1261d23db91eSPedro F. Giffuni 1262d23db91eSPedro F. Giffuni all_blks = fs->e2fs->e2fs_inode_size * fs->e2fs->e2fs_ipg / 1263d23db91eSPedro F. Giffuni fs->e2fs_bsize; 1264d23db91eSPedro F. Giffuni 1265d23db91eSPedro F. Giffuni used_blks = howmany(fs->e2fs->e2fs_ipg - 12663acd9182SFedor Uporov e2fs_gd_get_i_unused(&fs->e2fs_gd[cg]), 1267d23db91eSPedro F. Giffuni fs->e2fs_bsize / EXT2_INODE_SIZE(fs)); 1268d23db91eSPedro F. Giffuni 1269d23db91eSPedro F. Giffuni for (i = 0; i < all_blks - used_blks; i++) { 1270d23db91eSPedro F. Giffuni bp = getblk(ip->i_devvp, fsbtodb(fs, 12713acd9182SFedor Uporov e2fs_gd_get_i_tables(&fs->e2fs_gd[cg]) + used_blks + i), 1272d23db91eSPedro F. Giffuni fs->e2fs_bsize, 0, 0, 0); 1273d23db91eSPedro F. Giffuni if (!bp) 1274d23db91eSPedro F. Giffuni return (EIO); 1275d23db91eSPedro F. Giffuni 1276d23db91eSPedro F. Giffuni vfs_bio_bzero_buf(bp, 0, fs->e2fs_bsize); 1277d23db91eSPedro F. Giffuni bawrite(bp); 1278d23db91eSPedro F. Giffuni } 1279d23db91eSPedro F. Giffuni 1280d23db91eSPedro F. Giffuni fs->e2fs_gd[cg].ext4bgd_flags |= EXT2_BG_INODE_ZEROED; 1281d23db91eSPedro F. Giffuni 1282d23db91eSPedro F. Giffuni return (0); 1283d23db91eSPedro F. Giffuni } 1284d23db91eSPedro F. Giffuni 12855b63c125SPedro F. Giffuni /* 1286e09c00caSUlf Lilleengen * Determine whether an inode can be allocated. 1287e09c00caSUlf Lilleengen * 1288e09c00caSUlf Lilleengen * Check to see if an inode is available, and if it is, 1289e09c00caSUlf Lilleengen * allocate it using tode in the specified cylinder group. 1290e09c00caSUlf Lilleengen */ 1291e09c00caSUlf Lilleengen static daddr_t 1292e09c00caSUlf Lilleengen ext2_nodealloccg(struct inode *ip, int cg, daddr_t ipref, int mode) 1293e09c00caSUlf Lilleengen { 1294e09c00caSUlf Lilleengen struct m_ext2fs *fs; 1295e09c00caSUlf Lilleengen struct buf *bp; 1296e09c00caSUlf Lilleengen struct ext2mount *ump; 12974c1e1d2bSFedor Uporov int error, start, len, ifree; 12988f8d3027SEd Schouten char *ibp, *loc; 1299bf9a211dSPedro F. Giffuni 1300e09c00caSUlf Lilleengen ipref--; /* to avoid a lot of (ipref -1) */ 1301e09c00caSUlf Lilleengen if (ipref == -1) 1302e09c00caSUlf Lilleengen ipref = 0; 1303e09c00caSUlf Lilleengen fs = ip->i_e2fs; 1304e09c00caSUlf Lilleengen ump = ip->i_ump; 13053acd9182SFedor Uporov if (e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) == 0) 1306e09c00caSUlf Lilleengen return (0); 1307e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 1308e09c00caSUlf Lilleengen error = bread(ip->i_devvp, fsbtodb(fs, 13093acd9182SFedor Uporov e2fs_gd_get_i_bitmap(&fs->e2fs_gd[cg])), 1310e09c00caSUlf Lilleengen (int)fs->e2fs_bsize, NOCRED, &bp); 1311e09c00caSUlf Lilleengen if (error) { 1312e09c00caSUlf Lilleengen brelse(bp); 1313e09c00caSUlf Lilleengen EXT2_LOCK(ump); 1314e09c00caSUlf Lilleengen return (0); 1315e09c00caSUlf Lilleengen } 1316512f29d1SFedor Uporov if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) || 1317512f29d1SFedor Uporov EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { 1318d23db91eSPedro F. Giffuni if (fs->e2fs_gd[cg].ext4bgd_flags & EXT2_BG_INODE_UNINIT) { 1319d23db91eSPedro F. Giffuni memset(bp->b_data, 0, fs->e2fs_bsize); 1320d23db91eSPedro F. Giffuni fs->e2fs_gd[cg].ext4bgd_flags &= ~EXT2_BG_INODE_UNINIT; 1321d23db91eSPedro F. Giffuni } 1322512f29d1SFedor Uporov ext2_gd_i_bitmap_csum_set(fs, cg, bp); 1323d23db91eSPedro F. Giffuni error = ext2_zero_inode_table(ip, cg); 1324d23db91eSPedro F. Giffuni if (error) { 1325d23db91eSPedro F. Giffuni brelse(bp); 1326d23db91eSPedro F. Giffuni EXT2_LOCK(ump); 1327d23db91eSPedro F. Giffuni return (0); 1328d23db91eSPedro F. Giffuni } 1329d23db91eSPedro F. Giffuni } 1330512f29d1SFedor Uporov error = ext2_gd_i_bitmap_csum_verify(fs, cg, bp); 1331512f29d1SFedor Uporov if (error) { 1332512f29d1SFedor Uporov brelse(bp); 1333512f29d1SFedor Uporov EXT2_LOCK(ump); 1334512f29d1SFedor Uporov return (0); 1335512f29d1SFedor Uporov } 13363acd9182SFedor Uporov if (e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) == 0) { 133773dd6d1fSJohn Baldwin /* 133873dd6d1fSJohn Baldwin * Another thread allocated the last i-node in this 133973dd6d1fSJohn Baldwin * group while we were waiting for the buffer. 134073dd6d1fSJohn Baldwin */ 134173dd6d1fSJohn Baldwin brelse(bp); 134273dd6d1fSJohn Baldwin EXT2_LOCK(ump); 134373dd6d1fSJohn Baldwin return (0); 134473dd6d1fSJohn Baldwin } 1345e09c00caSUlf Lilleengen ibp = (char *)bp->b_data; 1346e09c00caSUlf Lilleengen if (ipref) { 1347e09c00caSUlf Lilleengen ipref %= fs->e2fs->e2fs_ipg; 1348e09c00caSUlf Lilleengen if (isclr(ibp, ipref)) 1349e09c00caSUlf Lilleengen goto gotit; 1350e09c00caSUlf Lilleengen } 1351e09c00caSUlf Lilleengen start = ipref / NBBY; 1352e09c00caSUlf Lilleengen len = howmany(fs->e2fs->e2fs_ipg - ipref, NBBY); 13538f8d3027SEd Schouten loc = memcchr(&ibp[start], 0xff, len); 13548f8d3027SEd Schouten if (loc == NULL) { 1355e09c00caSUlf Lilleengen len = start + 1; 1356e09c00caSUlf Lilleengen start = 0; 13578f8d3027SEd Schouten loc = memcchr(&ibp[start], 0xff, len); 13588f8d3027SEd Schouten if (loc == NULL) { 13594ff6603aSFedor Uporov printf("ext2fs: inode bitmap corrupted: " 13604ff6603aSFedor Uporov "cg = %d, ipref = %lld, fs = %s - run fsck\n", 1361e09c00caSUlf Lilleengen cg, (long long)ipref, fs->e2fs_fsmnt); 13624ff6603aSFedor Uporov brelse(bp); 13634ff6603aSFedor Uporov EXT2_LOCK(ump); 13644ff6603aSFedor Uporov return (0); 1365e09c00caSUlf Lilleengen } 1366e09c00caSUlf Lilleengen } 13678f8d3027SEd Schouten ipref = (loc - ibp) * NBBY + ffs(~*loc) - 1; 1368e09c00caSUlf Lilleengen gotit: 1369e09c00caSUlf Lilleengen setbit(ibp, ipref); 1370e09c00caSUlf Lilleengen EXT2_LOCK(ump); 13713acd9182SFedor Uporov e2fs_gd_set_nifree(&fs->e2fs_gd[cg], 13723acd9182SFedor Uporov e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) - 1); 1373512f29d1SFedor Uporov if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) || 13744c1e1d2bSFedor Uporov EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { 13754c1e1d2bSFedor Uporov ifree = fs->e2fs->e2fs_ipg - e2fs_gd_get_i_unused(&fs->e2fs_gd[cg]); 13764c1e1d2bSFedor Uporov if (ipref + 1 > ifree) 13773acd9182SFedor Uporov e2fs_gd_set_i_unused(&fs->e2fs_gd[cg], 13784c1e1d2bSFedor Uporov fs->e2fs->e2fs_ipg - (ipref + 1)); 13794c1e1d2bSFedor Uporov } 1380e09c00caSUlf Lilleengen fs->e2fs->e2fs_ficount--; 1381e09c00caSUlf Lilleengen fs->e2fs_fmod = 1; 1382d8ba45e2SEd Maste if ((mode & IFMT) == IFDIR) { 13833acd9182SFedor Uporov e2fs_gd_set_ndirs(&fs->e2fs_gd[cg], 13843acd9182SFedor Uporov e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]) + 1); 1385e09c00caSUlf Lilleengen fs->e2fs_total_dir++; 1386e09c00caSUlf Lilleengen } 1387e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 1388512f29d1SFedor Uporov ext2_gd_i_bitmap_csum_set(fs, cg, bp); 1389e09c00caSUlf Lilleengen bdwrite(bp); 13903acd9182SFedor Uporov return ((uint64_t)cg * fs->e2fs_ipg + ipref + 1); 1391e09c00caSUlf Lilleengen } 1392e09c00caSUlf Lilleengen 1393e09c00caSUlf Lilleengen /* 1394e09c00caSUlf Lilleengen * Free a block or fragment. 1395e09c00caSUlf Lilleengen * 1396e09c00caSUlf Lilleengen */ 1397e09c00caSUlf Lilleengen void 139870097aacSPedro F. Giffuni ext2_blkfree(struct inode *ip, e4fs_daddr_t bno, long size) 1399e09c00caSUlf Lilleengen { 1400e09c00caSUlf Lilleengen struct m_ext2fs *fs; 1401e09c00caSUlf Lilleengen struct buf *bp; 1402e09c00caSUlf Lilleengen struct ext2mount *ump; 1403e09c00caSUlf Lilleengen int cg, error; 1404e09c00caSUlf Lilleengen char *bbp; 1405e09c00caSUlf Lilleengen 1406e09c00caSUlf Lilleengen fs = ip->i_e2fs; 1407e09c00caSUlf Lilleengen ump = ip->i_ump; 1408e09c00caSUlf Lilleengen cg = dtog(fs, bno); 14093acd9182SFedor Uporov if (bno >= fs->e2fs_bcount) { 1410dde58752SGleb Kurtsou printf("bad block %lld, ino %ju\n", (long long)bno, 1411dde58752SGleb Kurtsou (uintmax_t)ip->i_number); 1412e09c00caSUlf Lilleengen ext2_fserr(fs, ip->i_uid, "bad block"); 1413e09c00caSUlf Lilleengen return; 1414e09c00caSUlf Lilleengen } 1415e09c00caSUlf Lilleengen error = bread(ip->i_devvp, 14163acd9182SFedor Uporov fsbtodb(fs, e2fs_gd_get_b_bitmap(&fs->e2fs_gd[cg])), 1417e09c00caSUlf Lilleengen (int)fs->e2fs_bsize, NOCRED, &bp); 1418e09c00caSUlf Lilleengen if (error) { 1419e09c00caSUlf Lilleengen brelse(bp); 1420e09c00caSUlf Lilleengen return; 1421e09c00caSUlf Lilleengen } 1422e09c00caSUlf Lilleengen bbp = (char *)bp->b_data; 1423e09c00caSUlf Lilleengen bno = dtogd(fs, bno); 1424e09c00caSUlf Lilleengen if (isclr(bbp, bno)) { 1425e09c00caSUlf Lilleengen printf("block = %lld, fs = %s\n", 1426e09c00caSUlf Lilleengen (long long)bno, fs->e2fs_fsmnt); 1427757224cbSPedro F. Giffuni panic("ext2_blkfree: freeing free block"); 1428e09c00caSUlf Lilleengen } 1429e09c00caSUlf Lilleengen clrbit(bbp, bno); 1430e09c00caSUlf Lilleengen EXT2_LOCK(ump); 14315b63c125SPedro F. Giffuni ext2_clusteracct(fs, bbp, cg, bno, 1); 14323acd9182SFedor Uporov fs->e2fs_fbcount++; 14333acd9182SFedor Uporov e2fs_gd_set_nbfree(&fs->e2fs_gd[cg], 14343acd9182SFedor Uporov e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) + 1); 1435e09c00caSUlf Lilleengen fs->e2fs_fmod = 1; 1436e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 1437512f29d1SFedor Uporov ext2_gd_b_bitmap_csum_set(fs, cg, bp); 1438e09c00caSUlf Lilleengen bdwrite(bp); 1439e09c00caSUlf Lilleengen } 1440e09c00caSUlf Lilleengen 1441e09c00caSUlf Lilleengen /* 1442e09c00caSUlf Lilleengen * Free an inode. 1443e09c00caSUlf Lilleengen * 1444e09c00caSUlf Lilleengen */ 1445e09c00caSUlf Lilleengen int 1446a9d1b299SPedro F. Giffuni ext2_vfree(struct vnode *pvp, ino_t ino, int mode) 1447e09c00caSUlf Lilleengen { 1448e09c00caSUlf Lilleengen struct m_ext2fs *fs; 1449e09c00caSUlf Lilleengen struct inode *pip; 1450e09c00caSUlf Lilleengen struct buf *bp; 1451e09c00caSUlf Lilleengen struct ext2mount *ump; 1452e09c00caSUlf Lilleengen int error, cg; 1453e09c00caSUlf Lilleengen char *ibp; 1454e09c00caSUlf Lilleengen 1455e09c00caSUlf Lilleengen pip = VTOI(pvp); 1456e09c00caSUlf Lilleengen fs = pip->i_e2fs; 1457e09c00caSUlf Lilleengen ump = pip->i_ump; 1458e09c00caSUlf Lilleengen if ((u_int)ino > fs->e2fs_ipg * fs->e2fs_gcount) 1459fc8fdae0SMatthew D Fleming panic("ext2_vfree: range: devvp = %p, ino = %ju, fs = %s", 1460fc8fdae0SMatthew D Fleming pip->i_devvp, (uintmax_t)ino, fs->e2fs_fsmnt); 1461e09c00caSUlf Lilleengen 1462e09c00caSUlf Lilleengen cg = ino_to_cg(fs, ino); 1463e09c00caSUlf Lilleengen error = bread(pip->i_devvp, 14643acd9182SFedor Uporov fsbtodb(fs, e2fs_gd_get_i_bitmap(&fs->e2fs_gd[cg])), 1465e09c00caSUlf Lilleengen (int)fs->e2fs_bsize, NOCRED, &bp); 1466e09c00caSUlf Lilleengen if (error) { 1467e09c00caSUlf Lilleengen brelse(bp); 1468e09c00caSUlf Lilleengen return (0); 1469e09c00caSUlf Lilleengen } 1470e09c00caSUlf Lilleengen ibp = (char *)bp->b_data; 1471e09c00caSUlf Lilleengen ino = (ino - 1) % fs->e2fs->e2fs_ipg; 1472e09c00caSUlf Lilleengen if (isclr(ibp, ino)) { 1473e06e5241SFedor Uporov printf("ino = %ju, fs = %s\n", 1474e06e5241SFedor Uporov ino, fs->e2fs_fsmnt); 1475e09c00caSUlf Lilleengen if (fs->e2fs_ronly == 0) 1476757224cbSPedro F. Giffuni panic("ext2_vfree: freeing free inode"); 1477e09c00caSUlf Lilleengen } 1478e09c00caSUlf Lilleengen clrbit(ibp, ino); 1479e09c00caSUlf Lilleengen EXT2_LOCK(ump); 1480e09c00caSUlf Lilleengen fs->e2fs->e2fs_ficount++; 14813acd9182SFedor Uporov e2fs_gd_set_nifree(&fs->e2fs_gd[cg], 14823acd9182SFedor Uporov e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) + 1); 1483d8ba45e2SEd Maste if ((mode & IFMT) == IFDIR) { 14843acd9182SFedor Uporov e2fs_gd_set_ndirs(&fs->e2fs_gd[cg], 14853acd9182SFedor Uporov e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]) - 1); 1486e09c00caSUlf Lilleengen fs->e2fs_total_dir--; 1487e09c00caSUlf Lilleengen } 1488e09c00caSUlf Lilleengen fs->e2fs_fmod = 1; 1489e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 1490512f29d1SFedor Uporov ext2_gd_i_bitmap_csum_set(fs, cg, bp); 1491e09c00caSUlf Lilleengen bdwrite(bp); 1492e09c00caSUlf Lilleengen return (0); 1493e09c00caSUlf Lilleengen } 1494e09c00caSUlf Lilleengen 1495e09c00caSUlf Lilleengen /* 1496e09c00caSUlf Lilleengen * Find a block in the specified cylinder group. 1497e09c00caSUlf Lilleengen * 1498e09c00caSUlf Lilleengen * It is a panic if a request is made to find a block if none are 1499e09c00caSUlf Lilleengen * available. 1500e09c00caSUlf Lilleengen */ 1501e09c00caSUlf Lilleengen static daddr_t 1502e09c00caSUlf Lilleengen ext2_mapsearch(struct m_ext2fs *fs, char *bbp, daddr_t bpref) 1503e09c00caSUlf Lilleengen { 15048f8d3027SEd Schouten char *loc; 15058f8d3027SEd Schouten int start, len; 1506e09c00caSUlf Lilleengen 1507e09c00caSUlf Lilleengen /* 1508e09c00caSUlf Lilleengen * find the fragment by searching through the free block 1509e09c00caSUlf Lilleengen * map for an appropriate bit pattern 1510e09c00caSUlf Lilleengen */ 1511e09c00caSUlf Lilleengen if (bpref) 1512e09c00caSUlf Lilleengen start = dtogd(fs, bpref) / NBBY; 1513e09c00caSUlf Lilleengen else 1514e09c00caSUlf Lilleengen start = 0; 1515e09c00caSUlf Lilleengen len = howmany(fs->e2fs->e2fs_fpg, NBBY) - start; 15168f8d3027SEd Schouten loc = memcchr(&bbp[start], 0xff, len); 15178f8d3027SEd Schouten if (loc == NULL) { 1518e09c00caSUlf Lilleengen len = start + 1; 1519e09c00caSUlf Lilleengen start = 0; 15208f8d3027SEd Schouten loc = memcchr(&bbp[start], 0xff, len); 15218f8d3027SEd Schouten if (loc == NULL) { 1522e09c00caSUlf Lilleengen printf("start = %d, len = %d, fs = %s\n", 1523e09c00caSUlf Lilleengen start, len, fs->e2fs_fsmnt); 1524757224cbSPedro F. Giffuni panic("ext2_mapsearch: map corrupted"); 1525e09c00caSUlf Lilleengen /* NOTREACHED */ 1526e09c00caSUlf Lilleengen } 1527e09c00caSUlf Lilleengen } 15288f8d3027SEd Schouten return ((loc - bbp) * NBBY + ffs(~*loc) - 1); 1529e09c00caSUlf Lilleengen } 1530e09c00caSUlf Lilleengen 1531e09c00caSUlf Lilleengen /* 1532e09c00caSUlf Lilleengen * Fserr prints the name of a filesystem with an error diagnostic. 1533e09c00caSUlf Lilleengen * 1534e09c00caSUlf Lilleengen * The form of the error message is: 1535e09c00caSUlf Lilleengen * fs: error message 1536e09c00caSUlf Lilleengen */ 153772530f91SFedor Uporov void 1538a9d1b299SPedro F. Giffuni ext2_fserr(struct m_ext2fs *fs, uid_t uid, char *cp) 1539e09c00caSUlf Lilleengen { 1540e09c00caSUlf Lilleengen 1541e09c00caSUlf Lilleengen log(LOG_ERR, "uid %u on %s: %s\n", uid, fs->e2fs_fsmnt, cp); 1542e09c00caSUlf Lilleengen } 1543e09c00caSUlf Lilleengen 1544e09c00caSUlf Lilleengen int 1545d23db91eSPedro F. Giffuni ext2_cg_has_sb(struct m_ext2fs *fs, int cg) 1546e09c00caSUlf Lilleengen { 1547e09c00caSUlf Lilleengen int a3, a5, a7; 1548e09c00caSUlf Lilleengen 1549d23db91eSPedro F. Giffuni if (cg == 0) 1550d23db91eSPedro F. Giffuni return (1); 1551d23db91eSPedro F. Giffuni 1552d23db91eSPedro F. Giffuni if (EXT2_HAS_COMPAT_FEATURE(fs, EXT2F_COMPAT_SPARSESUPER2)) { 1553d23db91eSPedro F. Giffuni if (cg == fs->e2fs->e4fs_backup_bgs[0] || 1554d23db91eSPedro F. Giffuni cg == fs->e2fs->e4fs_backup_bgs[1]) 1555d23db91eSPedro F. Giffuni return (1); 1556d23db91eSPedro F. Giffuni return (0); 1557d23db91eSPedro F. Giffuni } 1558d23db91eSPedro F. Giffuni 1559d23db91eSPedro F. Giffuni if ((cg <= 1) || 1560d23db91eSPedro F. Giffuni !EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_SPARSESUPER)) 1561d23db91eSPedro F. Giffuni return (1); 1562d23db91eSPedro F. Giffuni 1563d23db91eSPedro F. Giffuni if (!(cg & 1)) 1564d23db91eSPedro F. Giffuni return (0); 1565d23db91eSPedro F. Giffuni 1566e09c00caSUlf Lilleengen for (a3 = 3, a5 = 5, a7 = 7; 1567d23db91eSPedro F. Giffuni a3 <= cg || a5 <= cg || a7 <= cg; 1568e09c00caSUlf Lilleengen a3 *= 3, a5 *= 5, a7 *= 7) 1569d23db91eSPedro F. Giffuni if (cg == a3 || cg == a5 || cg == a7) 1570d23db91eSPedro F. Giffuni return (1); 1571d23db91eSPedro F. Giffuni return (0); 1572e09c00caSUlf Lilleengen } 1573