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 inode *pip; 377e09c00caSUlf Lilleengen struct m_ext2fs *fs; 378e09c00caSUlf Lilleengen struct inode *ip; 379e09c00caSUlf Lilleengen struct ext2mount *ump; 380e09c00caSUlf Lilleengen ino_t ino, ipref; 381b394cd1eSFedor Uporov int error, cg; 382e09c00caSUlf Lilleengen 383e09c00caSUlf Lilleengen *vpp = NULL; 384e09c00caSUlf Lilleengen pip = VTOI(pvp); 385e09c00caSUlf Lilleengen fs = pip->i_e2fs; 386e09c00caSUlf Lilleengen ump = pip->i_ump; 387e09c00caSUlf Lilleengen 388e09c00caSUlf Lilleengen EXT2_LOCK(ump); 389e09c00caSUlf Lilleengen if (fs->e2fs->e2fs_ficount == 0) 390e09c00caSUlf Lilleengen goto noinodes; 391e09c00caSUlf Lilleengen /* 392e09c00caSUlf Lilleengen * If it is a directory then obtain a cylinder group based on 393e09c00caSUlf Lilleengen * ext2_dirpref else obtain it using ino_to_cg. The preferred inode is 394e09c00caSUlf Lilleengen * always the next inode. 395e09c00caSUlf Lilleengen */ 396d8ba45e2SEd Maste if ((mode & IFMT) == IFDIR) { 397e09c00caSUlf Lilleengen cg = ext2_dirpref(pip); 398e09c00caSUlf Lilleengen if (fs->e2fs_contigdirs[cg] < 255) 399e09c00caSUlf Lilleengen fs->e2fs_contigdirs[cg]++; 400e09c00caSUlf Lilleengen } else { 401e09c00caSUlf Lilleengen cg = ino_to_cg(fs, pip->i_number); 402e09c00caSUlf Lilleengen if (fs->e2fs_contigdirs[cg] > 0) 403e09c00caSUlf Lilleengen fs->e2fs_contigdirs[cg]--; 404e09c00caSUlf Lilleengen } 405e09c00caSUlf Lilleengen ipref = cg * fs->e2fs->e2fs_ipg + 1; 406e09c00caSUlf Lilleengen ino = (ino_t)ext2_hashalloc(pip, cg, (long)ipref, mode, ext2_nodealloccg); 407e09c00caSUlf Lilleengen 408e09c00caSUlf Lilleengen if (ino == 0) 409e09c00caSUlf Lilleengen goto noinodes; 410e09c00caSUlf Lilleengen error = VFS_VGET(pvp->v_mount, ino, LK_EXCLUSIVE, vpp); 411e09c00caSUlf Lilleengen if (error) { 412e09c00caSUlf Lilleengen ext2_vfree(pvp, ino, mode); 413e09c00caSUlf Lilleengen return (error); 414e09c00caSUlf Lilleengen } 415e09c00caSUlf Lilleengen ip = VTOI(*vpp); 416e09c00caSUlf Lilleengen 417e09c00caSUlf Lilleengen /* 418035e4e04SPedro F. Giffuni * The question is whether using VGET was such good idea at all: 419035e4e04SPedro F. Giffuni * Linux doesn't read the old inode in when it is allocating a 420035e4e04SPedro F. Giffuni * new one. I will set at least i_size and i_blocks to zero. 421e09c00caSUlf Lilleengen */ 422e08ad8f0SPedro F. Giffuni ip->i_flag = 0; 423e09c00caSUlf Lilleengen ip->i_size = 0; 424e09c00caSUlf Lilleengen ip->i_blocks = 0; 425035e4e04SPedro F. Giffuni ip->i_mode = 0; 426e09c00caSUlf Lilleengen ip->i_flags = 0; 427b394cd1eSFedor Uporov if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_EXTENTS) 428b394cd1eSFedor Uporov && (S_ISREG(mode) || S_ISDIR(mode))) 429b394cd1eSFedor Uporov ext4_ext_tree_init(ip); 430b394cd1eSFedor Uporov else 431b394cd1eSFedor Uporov memset(ip->i_data, 0, sizeof(ip->i_data)); 432b394cd1eSFedor Uporov 433e09c00caSUlf Lilleengen 434e09c00caSUlf Lilleengen /* 435e09c00caSUlf Lilleengen * Set up a new generation number for this inode. 43643ce40e8SPedro F. Giffuni * Avoid zero values. 437e09c00caSUlf Lilleengen */ 43843ce40e8SPedro F. Giffuni do { 439df04a188SKevin Lo ip->i_gen = arc4random(); 44043ce40e8SPedro F. Giffuni } while (ip->i_gen == 0); 441035e4e04SPedro F. Giffuni 442035e4e04SPedro F. Giffuni vfs_timestamp(&ts); 443035e4e04SPedro F. Giffuni ip->i_birthtime = ts.tv_sec; 444035e4e04SPedro F. Giffuni ip->i_birthnsec = ts.tv_nsec; 445035e4e04SPedro F. Giffuni 446e09c00caSUlf Lilleengen /* 447e09c00caSUlf Lilleengen printf("ext2_valloc: allocated inode %d\n", ino); 448e09c00caSUlf Lilleengen */ 449e09c00caSUlf Lilleengen return (0); 450e09c00caSUlf Lilleengen noinodes: 451e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 452e09c00caSUlf Lilleengen ext2_fserr(fs, cred->cr_uid, "out of inodes"); 453e09c00caSUlf Lilleengen uprintf("\n%s: create/symlink failed, no inodes free\n", fs->e2fs_fsmnt); 454e09c00caSUlf Lilleengen return (ENOSPC); 455e09c00caSUlf Lilleengen } 456e09c00caSUlf Lilleengen 457e09c00caSUlf Lilleengen /* 4583acd9182SFedor Uporov * 64-bit compatible getters and setters for struct ext2_gd from ext2fs.h 4593acd9182SFedor Uporov */ 460*6e38bf94SFedor Uporov uint64_t 4613acd9182SFedor Uporov e2fs_gd_get_b_bitmap(struct ext2_gd *gd) 4623acd9182SFedor Uporov { 4633acd9182SFedor Uporov 4643acd9182SFedor Uporov return (((uint64_t)(gd->ext4bgd_b_bitmap_hi) << 32) | 4653acd9182SFedor Uporov gd->ext2bgd_b_bitmap); 4663acd9182SFedor Uporov } 4673acd9182SFedor Uporov 468*6e38bf94SFedor Uporov uint64_t 4693acd9182SFedor Uporov e2fs_gd_get_i_bitmap(struct ext2_gd *gd) 4703acd9182SFedor Uporov { 4713acd9182SFedor Uporov 4723acd9182SFedor Uporov return (((uint64_t)(gd->ext4bgd_i_bitmap_hi) << 32) | 4733acd9182SFedor Uporov gd->ext2bgd_i_bitmap); 4743acd9182SFedor Uporov } 4753acd9182SFedor Uporov 4763acd9182SFedor Uporov uint64_t 4773acd9182SFedor Uporov e2fs_gd_get_i_tables(struct ext2_gd *gd) 4783acd9182SFedor Uporov { 4793acd9182SFedor Uporov 4803acd9182SFedor Uporov return (((uint64_t)(gd->ext4bgd_i_tables_hi) << 32) | 4813acd9182SFedor Uporov gd->ext2bgd_i_tables); 4823acd9182SFedor Uporov } 4833acd9182SFedor Uporov 4843acd9182SFedor Uporov static uint32_t 4853acd9182SFedor Uporov e2fs_gd_get_nbfree(struct ext2_gd *gd) 4863acd9182SFedor Uporov { 4873acd9182SFedor Uporov 4883acd9182SFedor Uporov return (((uint32_t)(gd->ext4bgd_nbfree_hi) << 16) | 4893acd9182SFedor Uporov gd->ext2bgd_nbfree); 4903acd9182SFedor Uporov } 4913acd9182SFedor Uporov 4923acd9182SFedor Uporov static void 4933acd9182SFedor Uporov e2fs_gd_set_nbfree(struct ext2_gd *gd, uint32_t val) 4943acd9182SFedor Uporov { 4953acd9182SFedor Uporov 4963acd9182SFedor Uporov gd->ext2bgd_nbfree = val & 0xffff; 4973acd9182SFedor Uporov gd->ext4bgd_nbfree_hi = val >> 16; 4983acd9182SFedor Uporov } 4993acd9182SFedor Uporov 5003acd9182SFedor Uporov static uint32_t 5013acd9182SFedor Uporov e2fs_gd_get_nifree(struct ext2_gd *gd) 5023acd9182SFedor Uporov { 5033acd9182SFedor Uporov 5043acd9182SFedor Uporov return (((uint32_t)(gd->ext4bgd_nifree_hi) << 16) | 5053acd9182SFedor Uporov gd->ext2bgd_nifree); 5063acd9182SFedor Uporov } 5073acd9182SFedor Uporov 5083acd9182SFedor Uporov static void 5093acd9182SFedor Uporov e2fs_gd_set_nifree(struct ext2_gd *gd, uint32_t val) 5103acd9182SFedor Uporov { 5113acd9182SFedor Uporov 5123acd9182SFedor Uporov gd->ext2bgd_nifree = val & 0xffff; 5133acd9182SFedor Uporov gd->ext4bgd_nifree_hi = val >> 16; 5143acd9182SFedor Uporov } 5153acd9182SFedor Uporov 5163acd9182SFedor Uporov uint32_t 5173acd9182SFedor Uporov e2fs_gd_get_ndirs(struct ext2_gd *gd) 5183acd9182SFedor Uporov { 5193acd9182SFedor Uporov 5203acd9182SFedor Uporov return (((uint32_t)(gd->ext4bgd_ndirs_hi) << 16) | 5213acd9182SFedor Uporov gd->ext2bgd_ndirs); 5223acd9182SFedor Uporov } 5233acd9182SFedor Uporov 5243acd9182SFedor Uporov static void 5253acd9182SFedor Uporov e2fs_gd_set_ndirs(struct ext2_gd *gd, uint32_t val) 5263acd9182SFedor Uporov { 5273acd9182SFedor Uporov 5283acd9182SFedor Uporov gd->ext2bgd_ndirs = val & 0xffff; 5293acd9182SFedor Uporov gd->ext4bgd_ndirs_hi = val >> 16; 5303acd9182SFedor Uporov } 5313acd9182SFedor Uporov 5323acd9182SFedor Uporov static uint32_t 5333acd9182SFedor Uporov e2fs_gd_get_i_unused(struct ext2_gd *gd) 5343acd9182SFedor Uporov { 5353acd9182SFedor Uporov return (((uint32_t)(gd->ext4bgd_i_unused_hi) << 16) | 5363acd9182SFedor Uporov gd->ext4bgd_i_unused); 5373acd9182SFedor Uporov } 5383acd9182SFedor Uporov 5393acd9182SFedor Uporov static void 5403acd9182SFedor Uporov e2fs_gd_set_i_unused(struct ext2_gd *gd, uint32_t val) 5413acd9182SFedor Uporov { 5423acd9182SFedor Uporov 5433acd9182SFedor Uporov gd->ext4bgd_i_unused = val & 0xffff; 5443acd9182SFedor Uporov gd->ext4bgd_i_unused_hi = val >> 16; 5453acd9182SFedor Uporov } 5463acd9182SFedor Uporov 5473acd9182SFedor Uporov /* 548e09c00caSUlf Lilleengen * Find a cylinder to place a directory. 549e09c00caSUlf Lilleengen * 550e09c00caSUlf Lilleengen * The policy implemented by this algorithm is to allocate a 551e09c00caSUlf Lilleengen * directory inode in the same cylinder group as its parent 552e09c00caSUlf Lilleengen * directory, but also to reserve space for its files inodes 553e09c00caSUlf Lilleengen * and data. Restrict the number of directories which may be 554e09c00caSUlf Lilleengen * allocated one after another in the same cylinder group 555e09c00caSUlf Lilleengen * without intervening allocation of files. 556e09c00caSUlf Lilleengen * 557e09c00caSUlf Lilleengen * If we allocate a first level directory then force allocation 558e09c00caSUlf Lilleengen * in another cylinder group. 559e09c00caSUlf Lilleengen * 560e09c00caSUlf Lilleengen */ 561e09c00caSUlf Lilleengen static u_long 562e09c00caSUlf Lilleengen ext2_dirpref(struct inode *pip) 563e09c00caSUlf Lilleengen { 564e09c00caSUlf Lilleengen struct m_ext2fs *fs; 565955ba37bSPedro F. Giffuni int cg, prefcg, cgsize; 5663acd9182SFedor Uporov uint64_t avgbfree, minbfree; 5673acd9182SFedor Uporov u_int avgifree, avgndir, curdirsize; 5683acd9182SFedor Uporov u_int minifree, maxndir; 569f744956bSPedro F. Giffuni u_int mincg, minndir; 570955ba37bSPedro F. Giffuni u_int dirsize, maxcontigdirs; 571e09c00caSUlf Lilleengen 572e09c00caSUlf Lilleengen mtx_assert(EXT2_MTX(pip->i_ump), MA_OWNED); 573e09c00caSUlf Lilleengen fs = pip->i_e2fs; 574e09c00caSUlf Lilleengen 575e09c00caSUlf Lilleengen avgifree = fs->e2fs->e2fs_ficount / fs->e2fs_gcount; 5763acd9182SFedor Uporov avgbfree = fs->e2fs_fbcount / fs->e2fs_gcount; 577e09c00caSUlf Lilleengen avgndir = fs->e2fs_total_dir / fs->e2fs_gcount; 578e09c00caSUlf Lilleengen 579e09c00caSUlf Lilleengen /* 580e09c00caSUlf Lilleengen * Force allocation in another cg if creating a first level dir. 581e09c00caSUlf Lilleengen */ 582e09c00caSUlf Lilleengen ASSERT_VOP_LOCKED(ITOV(pip), "ext2fs_dirpref"); 583e09c00caSUlf Lilleengen if (ITOV(pip)->v_vflag & VV_ROOT) { 584e09c00caSUlf Lilleengen prefcg = arc4random() % fs->e2fs_gcount; 585e09c00caSUlf Lilleengen mincg = prefcg; 586e09c00caSUlf Lilleengen minndir = fs->e2fs_ipg; 587e09c00caSUlf Lilleengen for (cg = prefcg; cg < fs->e2fs_gcount; cg++) 5883acd9182SFedor Uporov if (e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]) < minndir && 5893acd9182SFedor Uporov e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) >= avgifree && 5903acd9182SFedor Uporov e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) >= avgbfree) { 591e09c00caSUlf Lilleengen mincg = cg; 5923acd9182SFedor Uporov minndir = e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]); 593e09c00caSUlf Lilleengen } 594e09c00caSUlf Lilleengen for (cg = 0; cg < prefcg; cg++) 5953acd9182SFedor Uporov if (e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]) < minndir && 5963acd9182SFedor Uporov e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) >= avgifree && 5973acd9182SFedor Uporov e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) >= avgbfree) { 598e09c00caSUlf Lilleengen mincg = cg; 5993acd9182SFedor Uporov minndir = e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]); 600e09c00caSUlf Lilleengen } 601e09c00caSUlf Lilleengen return (mincg); 602e09c00caSUlf Lilleengen } 603e09c00caSUlf Lilleengen /* 604e09c00caSUlf Lilleengen * Count various limits which used for 605e09c00caSUlf Lilleengen * optimal allocation of a directory inode. 606e09c00caSUlf Lilleengen */ 607e09c00caSUlf Lilleengen maxndir = min(avgndir + fs->e2fs_ipg / 16, fs->e2fs_ipg); 608e09c00caSUlf Lilleengen minifree = avgifree - avgifree / 4; 609e09c00caSUlf Lilleengen if (minifree < 1) 610e09c00caSUlf Lilleengen minifree = 1; 611e09c00caSUlf Lilleengen minbfree = avgbfree - avgbfree / 4; 612e09c00caSUlf Lilleengen if (minbfree < 1) 613e09c00caSUlf Lilleengen minbfree = 1; 614e09c00caSUlf Lilleengen cgsize = fs->e2fs_fsize * fs->e2fs_fpg; 615e09c00caSUlf Lilleengen dirsize = AVGDIRSIZE; 616e09c00caSUlf Lilleengen curdirsize = avgndir ? (cgsize - avgbfree * fs->e2fs_bsize) / avgndir : 0; 617e09c00caSUlf Lilleengen if (dirsize < curdirsize) 618e09c00caSUlf Lilleengen dirsize = curdirsize; 619e09c00caSUlf Lilleengen maxcontigdirs = min((avgbfree * fs->e2fs_bsize) / dirsize, 255); 620e09c00caSUlf Lilleengen maxcontigdirs = min(maxcontigdirs, fs->e2fs_ipg / AFPDIR); 621e09c00caSUlf Lilleengen if (maxcontigdirs == 0) 622e09c00caSUlf Lilleengen maxcontigdirs = 1; 623e09c00caSUlf Lilleengen 624e09c00caSUlf Lilleengen /* 625e09c00caSUlf Lilleengen * Limit number of dirs in one cg and reserve space for 626e09c00caSUlf Lilleengen * regular files, but only if we have no deficit in 627e09c00caSUlf Lilleengen * inodes or space. 628e09c00caSUlf Lilleengen */ 629e09c00caSUlf Lilleengen prefcg = ino_to_cg(fs, pip->i_number); 630e09c00caSUlf Lilleengen for (cg = prefcg; cg < fs->e2fs_gcount; cg++) 6313acd9182SFedor Uporov if (e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]) < maxndir && 6323acd9182SFedor Uporov e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) >= minifree && 6333acd9182SFedor Uporov e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) >= minbfree) { 634e09c00caSUlf Lilleengen if (fs->e2fs_contigdirs[cg] < maxcontigdirs) 635e09c00caSUlf Lilleengen return (cg); 636e09c00caSUlf Lilleengen } 637ca73017aSPedro F. Giffuni for (cg = 0; cg < prefcg; cg++) 6383acd9182SFedor Uporov if (e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]) < maxndir && 6393acd9182SFedor Uporov e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) >= minifree && 6403acd9182SFedor Uporov e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) >= minbfree) { 641e09c00caSUlf Lilleengen if (fs->e2fs_contigdirs[cg] < maxcontigdirs) 642e09c00caSUlf Lilleengen return (cg); 643e09c00caSUlf Lilleengen } 644e09c00caSUlf Lilleengen /* 645e09c00caSUlf Lilleengen * This is a backstop when we have deficit in space. 646e09c00caSUlf Lilleengen */ 647e09c00caSUlf Lilleengen for (cg = prefcg; cg < fs->e2fs_gcount; cg++) 6483acd9182SFedor Uporov if (e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) >= avgifree) 649e09c00caSUlf Lilleengen return (cg); 650ca73017aSPedro F. Giffuni for (cg = 0; cg < prefcg; cg++) 6513acd9182SFedor Uporov if (e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) >= avgifree) 652e09c00caSUlf Lilleengen break; 653e09c00caSUlf Lilleengen return (cg); 654e09c00caSUlf Lilleengen } 655e09c00caSUlf Lilleengen 656e09c00caSUlf Lilleengen /* 657e09c00caSUlf Lilleengen * Select the desired position for the next block in a file. 658e09c00caSUlf Lilleengen * 659e09c00caSUlf Lilleengen * we try to mimic what Remy does in inode_getblk/block_getblk 660e09c00caSUlf Lilleengen * 661e09c00caSUlf Lilleengen * we note: blocknr == 0 means that we're about to allocate either 662e09c00caSUlf Lilleengen * a direct block or a pointer block at the first level of indirection 663e09c00caSUlf Lilleengen * (In other words, stuff that will go in i_db[] or i_ib[]) 664e09c00caSUlf Lilleengen * 665e09c00caSUlf Lilleengen * blocknr != 0 means that we're allocating a block that is none 666e09c00caSUlf Lilleengen * of the above. Then, blocknr tells us the number of the block 667e09c00caSUlf Lilleengen * that will hold the pointer 668e09c00caSUlf Lilleengen */ 66970097aacSPedro F. Giffuni e4fs_daddr_t 67070097aacSPedro F. Giffuni ext2_blkpref(struct inode *ip, e2fs_lbn_t lbn, int indx, e2fs_daddr_t *bap, 67170097aacSPedro F. Giffuni e2fs_daddr_t blocknr) 672e09c00caSUlf Lilleengen { 673b394cd1eSFedor Uporov struct m_ext2fs *fs; 674e09c00caSUlf Lilleengen int tmp; 675bf9a211dSPedro F. Giffuni 676b394cd1eSFedor Uporov fs = ip->i_e2fs; 677b394cd1eSFedor Uporov 678e09c00caSUlf Lilleengen mtx_assert(EXT2_MTX(ip->i_ump), MA_OWNED); 679e09c00caSUlf Lilleengen 680bf9a211dSPedro F. Giffuni /* 681bf9a211dSPedro F. Giffuni * If the next block is actually what we thought it is, then set the 682bf9a211dSPedro F. Giffuni * goal to what we thought it should be. 683e09c00caSUlf Lilleengen */ 684e09c00caSUlf Lilleengen if (ip->i_next_alloc_block == lbn && ip->i_next_alloc_goal != 0) 685e09c00caSUlf Lilleengen return ip->i_next_alloc_goal; 686e09c00caSUlf Lilleengen 687bf9a211dSPedro F. Giffuni /* 688bf9a211dSPedro F. Giffuni * Now check whether we were provided with an array that basically 689bf9a211dSPedro F. Giffuni * tells us previous blocks to which we want to stay close. 690e09c00caSUlf Lilleengen */ 691e09c00caSUlf Lilleengen if (bap) 692e09c00caSUlf Lilleengen for (tmp = indx - 1; tmp >= 0; tmp--) 693e09c00caSUlf Lilleengen if (bap[tmp]) 694e09c00caSUlf Lilleengen return bap[tmp]; 695e09c00caSUlf Lilleengen 696bf9a211dSPedro F. Giffuni /* 697bf9a211dSPedro F. Giffuni * Else lets fall back to the blocknr or, if there is none, follow 698bf9a211dSPedro F. Giffuni * the rule that a block should be allocated near its inode. 699e09c00caSUlf Lilleengen */ 700b394cd1eSFedor Uporov return (blocknr ? blocknr : 70170097aacSPedro F. Giffuni (e2fs_daddr_t)(ip->i_block_group * 702b394cd1eSFedor Uporov EXT2_BLOCKS_PER_GROUP(fs)) + fs->e2fs->e2fs_first_dblock); 703e09c00caSUlf Lilleengen } 704e09c00caSUlf Lilleengen 705e09c00caSUlf Lilleengen /* 706e09c00caSUlf Lilleengen * Implement the cylinder overflow algorithm. 707e09c00caSUlf Lilleengen * 708e09c00caSUlf Lilleengen * The policy implemented by this algorithm is: 709e09c00caSUlf Lilleengen * 1) allocate the block in its requested cylinder group. 710e09c00caSUlf Lilleengen * 2) quadradically rehash on the cylinder group number. 711e09c00caSUlf Lilleengen * 3) brute force search for a free block. 712e09c00caSUlf Lilleengen */ 713ffbde5eaSFedor Uporov static e4fs_daddr_t 714e09c00caSUlf Lilleengen ext2_hashalloc(struct inode *ip, int cg, long pref, int size, 715e09c00caSUlf Lilleengen daddr_t (*allocator) (struct inode *, int, daddr_t, int)) 716e09c00caSUlf Lilleengen { 717e09c00caSUlf Lilleengen struct m_ext2fs *fs; 718ffbde5eaSFedor Uporov e4fs_daddr_t result; 719e09c00caSUlf Lilleengen int i, icg = cg; 720e09c00caSUlf Lilleengen 721e09c00caSUlf Lilleengen mtx_assert(EXT2_MTX(ip->i_ump), MA_OWNED); 722e09c00caSUlf Lilleengen fs = ip->i_e2fs; 723e09c00caSUlf Lilleengen /* 724e09c00caSUlf Lilleengen * 1: preferred cylinder group 725e09c00caSUlf Lilleengen */ 726e09c00caSUlf Lilleengen result = (*allocator)(ip, cg, pref, size); 727e09c00caSUlf Lilleengen if (result) 728e09c00caSUlf Lilleengen return (result); 729e09c00caSUlf Lilleengen /* 730e09c00caSUlf Lilleengen * 2: quadratic rehash 731e09c00caSUlf Lilleengen */ 732e09c00caSUlf Lilleengen for (i = 1; i < fs->e2fs_gcount; i *= 2) { 733e09c00caSUlf Lilleengen cg += i; 734e09c00caSUlf Lilleengen if (cg >= fs->e2fs_gcount) 735e09c00caSUlf Lilleengen cg -= fs->e2fs_gcount; 736e09c00caSUlf Lilleengen result = (*allocator)(ip, cg, 0, size); 737e09c00caSUlf Lilleengen if (result) 738e09c00caSUlf Lilleengen return (result); 739e09c00caSUlf Lilleengen } 740e09c00caSUlf Lilleengen /* 741e09c00caSUlf Lilleengen * 3: brute force search 742e09c00caSUlf Lilleengen * Note that we start at i == 2, since 0 was checked initially, 743e09c00caSUlf Lilleengen * and 1 is always checked in the quadratic rehash. 744e09c00caSUlf Lilleengen */ 745e09c00caSUlf Lilleengen cg = (icg + 2) % fs->e2fs_gcount; 746e09c00caSUlf Lilleengen for (i = 2; i < fs->e2fs_gcount; i++) { 747e09c00caSUlf Lilleengen result = (*allocator)(ip, cg, 0, size); 748e09c00caSUlf Lilleengen if (result) 749e09c00caSUlf Lilleengen return (result); 750e09c00caSUlf Lilleengen cg++; 751e09c00caSUlf Lilleengen if (cg == fs->e2fs_gcount) 752e09c00caSUlf Lilleengen cg = 0; 753e09c00caSUlf Lilleengen } 754e09c00caSUlf Lilleengen return (0); 755e09c00caSUlf Lilleengen } 756e09c00caSUlf Lilleengen 757*6e38bf94SFedor Uporov static uint64_t 758c0f16c65SFedor Uporov ext2_cg_number_gdb_nometa(struct m_ext2fs *fs, int cg) 759d23db91eSPedro F. Giffuni { 760d23db91eSPedro F. Giffuni 761d23db91eSPedro F. Giffuni if (!ext2_cg_has_sb(fs, cg)) 762d23db91eSPedro F. Giffuni return (0); 763c0f16c65SFedor Uporov 764d23db91eSPedro F. Giffuni if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_META_BG)) 765d23db91eSPedro F. Giffuni return (fs->e2fs->e3fs_first_meta_bg); 766c0f16c65SFedor Uporov 767c0f16c65SFedor Uporov return ((fs->e2fs_gcount + EXT2_DESCS_PER_BLOCK(fs) - 1) / 768c0f16c65SFedor Uporov EXT2_DESCS_PER_BLOCK(fs)); 769d23db91eSPedro F. Giffuni } 770d23db91eSPedro F. Giffuni 771*6e38bf94SFedor Uporov static uint64_t 772c0f16c65SFedor Uporov ext2_cg_number_gdb_meta(struct m_ext2fs *fs, int cg) 773c0f16c65SFedor Uporov { 774c0f16c65SFedor Uporov unsigned long metagroup; 775c0f16c65SFedor Uporov int first, last; 776c0f16c65SFedor Uporov 777c0f16c65SFedor Uporov metagroup = cg / EXT2_DESCS_PER_BLOCK(fs); 778c0f16c65SFedor Uporov first = metagroup * EXT2_DESCS_PER_BLOCK(fs); 779c0f16c65SFedor Uporov last = first + EXT2_DESCS_PER_BLOCK(fs) - 1; 780c0f16c65SFedor Uporov 781d23db91eSPedro F. Giffuni if (cg == first || cg == first + 1 || cg == last) 782d23db91eSPedro F. Giffuni return (1); 783d23db91eSPedro F. Giffuni 784c0f16c65SFedor Uporov return (0); 785c0f16c65SFedor Uporov } 786c0f16c65SFedor Uporov 787*6e38bf94SFedor Uporov uint64_t 788c0f16c65SFedor Uporov ext2_cg_number_gdb(struct m_ext2fs *fs, int cg) 789c0f16c65SFedor Uporov { 790c0f16c65SFedor Uporov unsigned long first_meta_bg, metagroup; 791c0f16c65SFedor Uporov 792c0f16c65SFedor Uporov first_meta_bg = fs->e2fs->e3fs_first_meta_bg; 793c0f16c65SFedor Uporov metagroup = cg / EXT2_DESCS_PER_BLOCK(fs); 794c0f16c65SFedor Uporov 795c0f16c65SFedor Uporov if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_META_BG) || 796c0f16c65SFedor Uporov metagroup < first_meta_bg) 797c0f16c65SFedor Uporov return (ext2_cg_number_gdb_nometa(fs, cg)); 798c0f16c65SFedor Uporov 799c0f16c65SFedor Uporov return ext2_cg_number_gdb_meta(fs, cg); 800d23db91eSPedro F. Giffuni } 801d23db91eSPedro F. Giffuni 802d23db91eSPedro F. Giffuni static int 803c0f16c65SFedor Uporov ext2_number_base_meta_blocks(struct m_ext2fs *fs, int cg) 804d23db91eSPedro F. Giffuni { 805c0f16c65SFedor Uporov int number; 806d23db91eSPedro F. Giffuni 807c0f16c65SFedor Uporov number = ext2_cg_has_sb(fs, cg); 808d23db91eSPedro F. Giffuni 809d23db91eSPedro F. Giffuni if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_META_BG) || 810c0f16c65SFedor Uporov cg < fs->e2fs->e3fs_first_meta_bg * EXT2_DESCS_PER_BLOCK(fs)) { 811c0f16c65SFedor Uporov if (number) { 812c0f16c65SFedor Uporov number += ext2_cg_number_gdb(fs, cg); 813c0f16c65SFedor Uporov number += fs->e2fs->e2fs_reserved_ngdb; 814d23db91eSPedro F. Giffuni } 815d23db91eSPedro F. Giffuni } else { 816c0f16c65SFedor Uporov number += ext2_cg_number_gdb(fs, cg); 817d23db91eSPedro F. Giffuni } 818d23db91eSPedro F. Giffuni 819c0f16c65SFedor Uporov return (number); 820d23db91eSPedro F. Giffuni } 821d23db91eSPedro F. Giffuni 822d23db91eSPedro F. Giffuni static void 823d23db91eSPedro F. Giffuni ext2_mark_bitmap_end(int start_bit, int end_bit, char *bitmap) 824d23db91eSPedro F. Giffuni { 825d23db91eSPedro F. Giffuni int i; 826d23db91eSPedro F. Giffuni 827d23db91eSPedro F. Giffuni if (start_bit >= end_bit) 828d23db91eSPedro F. Giffuni return; 829d23db91eSPedro F. Giffuni 830d23db91eSPedro F. Giffuni for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++) 831d23db91eSPedro F. Giffuni setbit(bitmap, i); 832d23db91eSPedro F. Giffuni if (i < end_bit) 833d23db91eSPedro F. Giffuni memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3); 834d23db91eSPedro F. Giffuni } 835d23db91eSPedro F. Giffuni 836d23db91eSPedro F. Giffuni static int 837c0f16c65SFedor Uporov ext2_get_group_number(struct m_ext2fs *fs, e4fs_daddr_t block) 838c0f16c65SFedor Uporov { 839c0f16c65SFedor Uporov 840c0f16c65SFedor Uporov return ((block - fs->e2fs->e2fs_first_dblock) / fs->e2fs_bsize); 841c0f16c65SFedor Uporov } 842c0f16c65SFedor Uporov 843c0f16c65SFedor Uporov static int 844c0f16c65SFedor Uporov ext2_block_in_group(struct m_ext2fs *fs, e4fs_daddr_t block, int cg) 845c0f16c65SFedor Uporov { 846c0f16c65SFedor Uporov 847c0f16c65SFedor Uporov return ((ext2_get_group_number(fs, block) == cg) ? 1 : 0); 848c0f16c65SFedor Uporov } 849c0f16c65SFedor Uporov 850c0f16c65SFedor Uporov static int 851d23db91eSPedro F. Giffuni ext2_cg_block_bitmap_init(struct m_ext2fs *fs, int cg, struct buf *bp) 852d23db91eSPedro F. Giffuni { 853d23db91eSPedro F. Giffuni int bit, bit_max, inodes_per_block; 8543acd9182SFedor Uporov uint64_t start, tmp; 855d23db91eSPedro F. Giffuni 8563acd9182SFedor Uporov if (!(fs->e2fs_gd[cg].ext4bgd_flags & EXT2_BG_BLOCK_UNINIT)) 857d23db91eSPedro F. Giffuni return (0); 858d23db91eSPedro F. Giffuni 859d23db91eSPedro F. Giffuni memset(bp->b_data, 0, fs->e2fs_bsize); 860d23db91eSPedro F. Giffuni 861c0f16c65SFedor Uporov bit_max = ext2_number_base_meta_blocks(fs, cg); 862d23db91eSPedro F. Giffuni if ((bit_max >> 3) >= fs->e2fs_bsize) 863d23db91eSPedro F. Giffuni return (EINVAL); 864d23db91eSPedro F. Giffuni 865d23db91eSPedro F. Giffuni for (bit = 0; bit < bit_max; bit++) 866d23db91eSPedro F. Giffuni setbit(bp->b_data, bit); 867d23db91eSPedro F. Giffuni 8683acd9182SFedor Uporov start = (uint64_t)cg * fs->e2fs->e2fs_bpg + fs->e2fs->e2fs_first_dblock; 869d23db91eSPedro F. Giffuni 8703acd9182SFedor Uporov /* Set bits for block and inode bitmaps, and inode table. */ 8713acd9182SFedor Uporov tmp = e2fs_gd_get_b_bitmap(&fs->e2fs_gd[cg]); 872d23db91eSPedro F. Giffuni if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_FLEX_BG) || 873c0f16c65SFedor Uporov ext2_block_in_group(fs, tmp, cg)) 874d23db91eSPedro F. Giffuni setbit(bp->b_data, tmp - start); 875d23db91eSPedro F. Giffuni 8763acd9182SFedor Uporov tmp = e2fs_gd_get_i_bitmap(&fs->e2fs_gd[cg]); 877d23db91eSPedro F. Giffuni if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_FLEX_BG) || 878c0f16c65SFedor Uporov ext2_block_in_group(fs, tmp, cg)) 879d23db91eSPedro F. Giffuni setbit(bp->b_data, tmp - start); 880d23db91eSPedro F. Giffuni 8813acd9182SFedor Uporov tmp = e2fs_gd_get_i_tables(&fs->e2fs_gd[cg]); 882d23db91eSPedro F. Giffuni inodes_per_block = fs->e2fs_bsize/EXT2_INODE_SIZE(fs); 8833acd9182SFedor Uporov while( tmp < e2fs_gd_get_i_tables(&fs->e2fs_gd[cg]) + 884d23db91eSPedro F. Giffuni fs->e2fs->e2fs_ipg / inodes_per_block ) { 885d23db91eSPedro F. Giffuni if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_FLEX_BG) || 886c0f16c65SFedor Uporov ext2_block_in_group(fs, tmp, cg)) 887d23db91eSPedro F. Giffuni setbit(bp->b_data, tmp - start); 888d23db91eSPedro F. Giffuni tmp++; 889d23db91eSPedro F. Giffuni } 890d23db91eSPedro F. Giffuni 891d23db91eSPedro F. Giffuni /* 892d23db91eSPedro F. Giffuni * Also if the number of blocks within the group is less than 893d23db91eSPedro F. Giffuni * the blocksize * 8 ( which is the size of bitmap ), set rest 894d23db91eSPedro F. Giffuni * of the block bitmap to 1 895d23db91eSPedro F. Giffuni */ 896d23db91eSPedro F. Giffuni ext2_mark_bitmap_end(fs->e2fs->e2fs_bpg, fs->e2fs_bsize * 8, 897d23db91eSPedro F. Giffuni bp->b_data); 898d23db91eSPedro F. Giffuni 899d23db91eSPedro F. Giffuni /* Clean the flag */ 900d23db91eSPedro F. Giffuni fs->e2fs_gd[cg].ext4bgd_flags &= ~EXT2_BG_BLOCK_UNINIT; 901d23db91eSPedro F. Giffuni 902d23db91eSPedro F. Giffuni return (0); 903d23db91eSPedro F. Giffuni } 904d23db91eSPedro F. Giffuni 905e09c00caSUlf Lilleengen /* 906e09c00caSUlf Lilleengen * Determine whether a block can be allocated. 907e09c00caSUlf Lilleengen * 908e09c00caSUlf Lilleengen * Check to see if a block of the appropriate size is available, 909e09c00caSUlf Lilleengen * and if it is, allocate it. 910e09c00caSUlf Lilleengen */ 911e09c00caSUlf Lilleengen static daddr_t 912e09c00caSUlf Lilleengen ext2_alloccg(struct inode *ip, int cg, daddr_t bpref, int size) 913e09c00caSUlf Lilleengen { 914e09c00caSUlf Lilleengen struct m_ext2fs *fs; 915e09c00caSUlf Lilleengen struct buf *bp; 916e09c00caSUlf Lilleengen struct ext2mount *ump; 917c767faa5SJohn Baldwin daddr_t bno, runstart, runlen; 918c767faa5SJohn Baldwin int bit, loc, end, error, start; 919e09c00caSUlf Lilleengen char *bbp; 920e09c00caSUlf Lilleengen /* XXX ondisk32 */ 921e09c00caSUlf Lilleengen fs = ip->i_e2fs; 922e09c00caSUlf Lilleengen ump = ip->i_ump; 9233acd9182SFedor Uporov if (e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) == 0) 924e09c00caSUlf Lilleengen return (0); 925e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 926e09c00caSUlf Lilleengen error = bread(ip->i_devvp, fsbtodb(fs, 9273acd9182SFedor Uporov e2fs_gd_get_b_bitmap(&fs->e2fs_gd[cg])), 928e09c00caSUlf Lilleengen (int)fs->e2fs_bsize, NOCRED, &bp); 929e09c00caSUlf Lilleengen if (error) { 930e09c00caSUlf Lilleengen brelse(bp); 931e09c00caSUlf Lilleengen EXT2_LOCK(ump); 932e09c00caSUlf Lilleengen return (0); 933e09c00caSUlf Lilleengen } 934512f29d1SFedor Uporov if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) || 935512f29d1SFedor Uporov EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { 936d23db91eSPedro F. Giffuni error = ext2_cg_block_bitmap_init(fs, cg, bp); 937d23db91eSPedro F. Giffuni if (error) { 938d23db91eSPedro F. Giffuni brelse(bp); 939d23db91eSPedro F. Giffuni EXT2_LOCK(ump); 940d23db91eSPedro F. Giffuni return (0); 941d23db91eSPedro F. Giffuni } 942512f29d1SFedor Uporov ext2_gd_b_bitmap_csum_set(fs, cg, bp); 943512f29d1SFedor Uporov } 944512f29d1SFedor Uporov error = ext2_gd_b_bitmap_csum_verify(fs, cg, bp); 945512f29d1SFedor Uporov if (error) { 946512f29d1SFedor Uporov brelse(bp); 947512f29d1SFedor Uporov EXT2_LOCK(ump); 948512f29d1SFedor Uporov return (0); 949d23db91eSPedro F. Giffuni } 9503acd9182SFedor Uporov if (e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) == 0) { 95173dd6d1fSJohn Baldwin /* 95273dd6d1fSJohn Baldwin * Another thread allocated the last block in this 95373dd6d1fSJohn Baldwin * group while we were waiting for the buffer. 95473dd6d1fSJohn Baldwin */ 95573dd6d1fSJohn Baldwin brelse(bp); 95673dd6d1fSJohn Baldwin EXT2_LOCK(ump); 95773dd6d1fSJohn Baldwin return (0); 95873dd6d1fSJohn Baldwin } 959e09c00caSUlf Lilleengen bbp = (char *)bp->b_data; 960e09c00caSUlf Lilleengen 961e09c00caSUlf Lilleengen if (dtog(fs, bpref) != cg) 962e09c00caSUlf Lilleengen bpref = 0; 963e09c00caSUlf Lilleengen if (bpref != 0) { 964e09c00caSUlf Lilleengen bpref = dtogd(fs, bpref); 965e09c00caSUlf Lilleengen /* 966e09c00caSUlf Lilleengen * if the requested block is available, use it 967e09c00caSUlf Lilleengen */ 968e09c00caSUlf Lilleengen if (isclr(bbp, bpref)) { 969e09c00caSUlf Lilleengen bno = bpref; 970e09c00caSUlf Lilleengen goto gotit; 971e09c00caSUlf Lilleengen } 972e09c00caSUlf Lilleengen } 973e09c00caSUlf Lilleengen /* 974e09c00caSUlf Lilleengen * no blocks in the requested cylinder, so take next 975e09c00caSUlf Lilleengen * available one in this cylinder group. 976e09c00caSUlf Lilleengen * first try to get 8 contigous blocks, then fall back to a single 977e09c00caSUlf Lilleengen * block. 978e09c00caSUlf Lilleengen */ 979e09c00caSUlf Lilleengen if (bpref) 980e09c00caSUlf Lilleengen start = dtogd(fs, bpref) / NBBY; 981e09c00caSUlf Lilleengen else 982e09c00caSUlf Lilleengen start = 0; 983e09c00caSUlf Lilleengen end = howmany(fs->e2fs->e2fs_fpg, NBBY) - start; 984c767faa5SJohn Baldwin retry: 985c767faa5SJohn Baldwin runlen = 0; 986c767faa5SJohn Baldwin runstart = 0; 987e09c00caSUlf Lilleengen for (loc = start; loc < end; loc++) { 988c767faa5SJohn Baldwin if (bbp[loc] == (char)0xff) { 989c767faa5SJohn Baldwin runlen = 0; 990c767faa5SJohn Baldwin continue; 991c767faa5SJohn Baldwin } 992c767faa5SJohn Baldwin 993c767faa5SJohn Baldwin /* Start of a run, find the number of high clear bits. */ 994c767faa5SJohn Baldwin if (runlen == 0) { 995c767faa5SJohn Baldwin bit = fls(bbp[loc]); 996c767faa5SJohn Baldwin runlen = NBBY - bit; 997c767faa5SJohn Baldwin runstart = loc * NBBY + bit; 998c767faa5SJohn Baldwin } else if (bbp[loc] == 0) { 999c767faa5SJohn Baldwin /* Continue a run. */ 1000c767faa5SJohn Baldwin runlen += NBBY; 1001c767faa5SJohn Baldwin } else { 1002c767faa5SJohn Baldwin /* 1003c767faa5SJohn Baldwin * Finish the current run. If it isn't long 1004c767faa5SJohn Baldwin * enough, start a new one. 1005c767faa5SJohn Baldwin */ 1006c767faa5SJohn Baldwin bit = ffs(bbp[loc]) - 1; 1007c767faa5SJohn Baldwin runlen += bit; 1008c767faa5SJohn Baldwin if (runlen >= 8) { 1009c767faa5SJohn Baldwin bno = runstart; 1010c767faa5SJohn Baldwin goto gotit; 1011c767faa5SJohn Baldwin } 1012c767faa5SJohn Baldwin 1013c767faa5SJohn Baldwin /* Run was too short, start a new one. */ 1014c767faa5SJohn Baldwin bit = fls(bbp[loc]); 1015c767faa5SJohn Baldwin runlen = NBBY - bit; 1016c767faa5SJohn Baldwin runstart = loc * NBBY + bit; 1017c767faa5SJohn Baldwin } 1018c767faa5SJohn Baldwin 1019c767faa5SJohn Baldwin /* If the current run is long enough, use it. */ 1020c767faa5SJohn Baldwin if (runlen >= 8) { 1021c767faa5SJohn Baldwin bno = runstart; 1022e09c00caSUlf Lilleengen goto gotit; 1023e09c00caSUlf Lilleengen } 1024e09c00caSUlf Lilleengen } 1025c767faa5SJohn Baldwin if (start != 0) { 1026c767faa5SJohn Baldwin end = start; 1027c767faa5SJohn Baldwin start = 0; 1028c767faa5SJohn Baldwin goto retry; 1029e09c00caSUlf Lilleengen } 1030e09c00caSUlf Lilleengen bno = ext2_mapsearch(fs, bbp, bpref); 1031e09c00caSUlf Lilleengen if (bno < 0) { 1032e09c00caSUlf Lilleengen brelse(bp); 1033e09c00caSUlf Lilleengen EXT2_LOCK(ump); 1034e09c00caSUlf Lilleengen return (0); 1035e09c00caSUlf Lilleengen } 1036e09c00caSUlf Lilleengen gotit: 103777b193c2SPedro F. Giffuni #ifdef INVARIANTS 10388e42a406SJohn Baldwin if (isset(bbp, bno)) { 10398e42a406SJohn Baldwin printf("ext2fs_alloccgblk: cg=%d bno=%jd fs=%s\n", 10408e42a406SJohn Baldwin cg, (intmax_t)bno, fs->e2fs_fsmnt); 1041e09c00caSUlf Lilleengen panic("ext2fs_alloccg: dup alloc"); 1042e09c00caSUlf Lilleengen } 1043e09c00caSUlf Lilleengen #endif 10448e42a406SJohn Baldwin setbit(bbp, bno); 1045e09c00caSUlf Lilleengen EXT2_LOCK(ump); 10465b63c125SPedro F. Giffuni ext2_clusteracct(fs, bbp, cg, bno, -1); 10473acd9182SFedor Uporov fs->e2fs_fbcount--; 10483acd9182SFedor Uporov e2fs_gd_set_nbfree(&fs->e2fs_gd[cg], 10493acd9182SFedor Uporov e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) - 1); 1050e09c00caSUlf Lilleengen fs->e2fs_fmod = 1; 1051e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 1052512f29d1SFedor Uporov ext2_gd_b_bitmap_csum_set(fs, cg, bp); 1053e09c00caSUlf Lilleengen bdwrite(bp); 10543acd9182SFedor Uporov return (((uint64_t)cg) * fs->e2fs->e2fs_fpg + fs->e2fs->e2fs_first_dblock + bno); 1055e09c00caSUlf Lilleengen } 1056e09c00caSUlf Lilleengen 1057e09c00caSUlf Lilleengen /* 10585b63c125SPedro F. Giffuni * Determine whether a cluster can be allocated. 10595b63c125SPedro F. Giffuni */ 10605b63c125SPedro F. Giffuni static daddr_t 10615b63c125SPedro F. Giffuni ext2_clusteralloc(struct inode *ip, int cg, daddr_t bpref, int len) 10625b63c125SPedro F. Giffuni { 10635b63c125SPedro F. Giffuni struct m_ext2fs *fs; 10645b63c125SPedro F. Giffuni struct ext2mount *ump; 10655b63c125SPedro F. Giffuni struct buf *bp; 10665b63c125SPedro F. Giffuni char *bbp; 10675b63c125SPedro F. Giffuni int bit, error, got, i, loc, run; 10685b63c125SPedro F. Giffuni int32_t *lp; 10695b63c125SPedro F. Giffuni daddr_t bno; 10705b63c125SPedro F. Giffuni 10715b63c125SPedro F. Giffuni fs = ip->i_e2fs; 10725b63c125SPedro F. Giffuni ump = ip->i_ump; 10735b63c125SPedro F. Giffuni 10745b63c125SPedro F. Giffuni if (fs->e2fs_maxcluster[cg] < len) 10755b63c125SPedro F. Giffuni return (0); 10765b63c125SPedro F. Giffuni 10775b63c125SPedro F. Giffuni EXT2_UNLOCK(ump); 10785b63c125SPedro F. Giffuni error = bread(ip->i_devvp, 10793acd9182SFedor Uporov fsbtodb(fs, e2fs_gd_get_b_bitmap(&fs->e2fs_gd[cg])), 10805b63c125SPedro F. Giffuni (int)fs->e2fs_bsize, NOCRED, &bp); 10815b63c125SPedro F. Giffuni if (error) 10825b63c125SPedro F. Giffuni goto fail_lock; 10835b63c125SPedro F. Giffuni 10845b63c125SPedro F. Giffuni bbp = (char *)bp->b_data; 10855b63c125SPedro F. Giffuni EXT2_LOCK(ump); 10865b63c125SPedro F. Giffuni /* 10875b63c125SPedro F. Giffuni * Check to see if a cluster of the needed size (or bigger) is 10885b63c125SPedro F. Giffuni * available in this cylinder group. 10895b63c125SPedro F. Giffuni */ 10905b63c125SPedro F. Giffuni lp = &fs->e2fs_clustersum[cg].cs_sum[len]; 10915b63c125SPedro F. Giffuni for (i = len; i <= fs->e2fs_contigsumsize; i++) 10925b63c125SPedro F. Giffuni if (*lp++ > 0) 10935b63c125SPedro F. Giffuni break; 10945b63c125SPedro F. Giffuni if (i > fs->e2fs_contigsumsize) { 10955b63c125SPedro F. Giffuni /* 10965b63c125SPedro F. Giffuni * Update the cluster summary information to reflect 10975b63c125SPedro F. Giffuni * the true maximum-sized cluster so that future cluster 10985b63c125SPedro F. Giffuni * allocation requests can avoid reading the bitmap only 10995b63c125SPedro F. Giffuni * to find no cluster. 11005b63c125SPedro F. Giffuni */ 11015b63c125SPedro F. Giffuni lp = &fs->e2fs_clustersum[cg].cs_sum[len - 1]; 11025b63c125SPedro F. Giffuni for (i = len - 1; i > 0; i--) 11035b63c125SPedro F. Giffuni if (*lp-- > 0) 11045b63c125SPedro F. Giffuni break; 11055b63c125SPedro F. Giffuni fs->e2fs_maxcluster[cg] = i; 11065b63c125SPedro F. Giffuni goto fail; 11075b63c125SPedro F. Giffuni } 11085b63c125SPedro F. Giffuni EXT2_UNLOCK(ump); 11095b63c125SPedro F. Giffuni 11105b63c125SPedro F. Giffuni /* Search the bitmap to find a big enough cluster like in FFS. */ 11115b63c125SPedro F. Giffuni if (dtog(fs, bpref) != cg) 11125b63c125SPedro F. Giffuni bpref = 0; 11135b63c125SPedro F. Giffuni if (bpref != 0) 11145b63c125SPedro F. Giffuni bpref = dtogd(fs, bpref); 11155b63c125SPedro F. Giffuni loc = bpref / NBBY; 11165b63c125SPedro F. Giffuni bit = 1 << (bpref % NBBY); 11175b63c125SPedro F. Giffuni for (run = 0, got = bpref; got < fs->e2fs->e2fs_fpg; got++) { 11185b63c125SPedro F. Giffuni if ((bbp[loc] & bit) != 0) 11195b63c125SPedro F. Giffuni run = 0; 11205b63c125SPedro F. Giffuni else { 11215b63c125SPedro F. Giffuni run++; 11225b63c125SPedro F. Giffuni if (run == len) 11235b63c125SPedro F. Giffuni break; 11245b63c125SPedro F. Giffuni } 11255b63c125SPedro F. Giffuni if ((got & (NBBY - 1)) != (NBBY - 1)) 11265b63c125SPedro F. Giffuni bit <<= 1; 11275b63c125SPedro F. Giffuni else { 11285b63c125SPedro F. Giffuni loc++; 11295b63c125SPedro F. Giffuni bit = 1; 11305b63c125SPedro F. Giffuni } 11315b63c125SPedro F. Giffuni } 11325b63c125SPedro F. Giffuni 11335b63c125SPedro F. Giffuni if (got >= fs->e2fs->e2fs_fpg) 11345b63c125SPedro F. Giffuni goto fail_lock; 11355b63c125SPedro F. Giffuni 11365b63c125SPedro F. Giffuni /* Allocate the cluster that we found. */ 11375b63c125SPedro F. Giffuni for (i = 1; i < len; i++) 11385b63c125SPedro F. Giffuni if (!isclr(bbp, got - run + i)) 11395b63c125SPedro F. Giffuni panic("ext2_clusteralloc: map mismatch"); 11405b63c125SPedro F. Giffuni 11415b63c125SPedro F. Giffuni bno = got - run + 1; 11425b63c125SPedro F. Giffuni if (bno >= fs->e2fs->e2fs_fpg) 11435b63c125SPedro F. Giffuni panic("ext2_clusteralloc: allocated out of group"); 11445b63c125SPedro F. Giffuni 11455b63c125SPedro F. Giffuni EXT2_LOCK(ump); 11465b63c125SPedro F. Giffuni for (i = 0; i < len; i += fs->e2fs_fpb) { 11475b63c125SPedro F. Giffuni setbit(bbp, bno + i); 11485b63c125SPedro F. Giffuni ext2_clusteracct(fs, bbp, cg, bno + i, -1); 11493acd9182SFedor Uporov fs->e2fs_fbcount--; 11503acd9182SFedor Uporov e2fs_gd_set_nbfree(&fs->e2fs_gd[cg], 11513acd9182SFedor Uporov e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) - 1); 11525b63c125SPedro F. Giffuni } 11535b63c125SPedro F. Giffuni fs->e2fs_fmod = 1; 11545b63c125SPedro F. Giffuni EXT2_UNLOCK(ump); 11555b63c125SPedro F. Giffuni 11565b63c125SPedro F. Giffuni bdwrite(bp); 11575b63c125SPedro F. Giffuni return (cg * fs->e2fs->e2fs_fpg + fs->e2fs->e2fs_first_dblock + bno); 11585b63c125SPedro F. Giffuni 11595b63c125SPedro F. Giffuni fail_lock: 11605b63c125SPedro F. Giffuni EXT2_LOCK(ump); 11615b63c125SPedro F. Giffuni fail: 11625b63c125SPedro F. Giffuni brelse(bp); 11635b63c125SPedro F. Giffuni return (0); 11645b63c125SPedro F. Giffuni } 11655b63c125SPedro F. Giffuni 1166d23db91eSPedro F. Giffuni static int 1167d23db91eSPedro F. Giffuni ext2_zero_inode_table(struct inode *ip, int cg) 1168d23db91eSPedro F. Giffuni { 1169d23db91eSPedro F. Giffuni struct m_ext2fs *fs; 1170d23db91eSPedro F. Giffuni struct buf *bp; 1171d23db91eSPedro F. Giffuni int i, all_blks, used_blks; 1172d23db91eSPedro F. Giffuni 1173d23db91eSPedro F. Giffuni fs = ip->i_e2fs; 1174d23db91eSPedro F. Giffuni 1175d23db91eSPedro F. Giffuni if (fs->e2fs_gd[cg].ext4bgd_flags & EXT2_BG_INODE_ZEROED) 1176d23db91eSPedro F. Giffuni return (0); 1177d23db91eSPedro F. Giffuni 1178d23db91eSPedro F. Giffuni all_blks = fs->e2fs->e2fs_inode_size * fs->e2fs->e2fs_ipg / 1179d23db91eSPedro F. Giffuni fs->e2fs_bsize; 1180d23db91eSPedro F. Giffuni 1181d23db91eSPedro F. Giffuni used_blks = howmany(fs->e2fs->e2fs_ipg - 11823acd9182SFedor Uporov e2fs_gd_get_i_unused(&fs->e2fs_gd[cg]), 1183d23db91eSPedro F. Giffuni fs->e2fs_bsize / EXT2_INODE_SIZE(fs)); 1184d23db91eSPedro F. Giffuni 1185d23db91eSPedro F. Giffuni for (i = 0; i < all_blks - used_blks; i++) { 1186d23db91eSPedro F. Giffuni bp = getblk(ip->i_devvp, fsbtodb(fs, 11873acd9182SFedor Uporov e2fs_gd_get_i_tables(&fs->e2fs_gd[cg]) + used_blks + i), 1188d23db91eSPedro F. Giffuni fs->e2fs_bsize, 0, 0, 0); 1189d23db91eSPedro F. Giffuni if (!bp) 1190d23db91eSPedro F. Giffuni return (EIO); 1191d23db91eSPedro F. Giffuni 1192d23db91eSPedro F. Giffuni vfs_bio_bzero_buf(bp, 0, fs->e2fs_bsize); 1193d23db91eSPedro F. Giffuni bawrite(bp); 1194d23db91eSPedro F. Giffuni } 1195d23db91eSPedro F. Giffuni 1196d23db91eSPedro F. Giffuni fs->e2fs_gd[cg].ext4bgd_flags |= EXT2_BG_INODE_ZEROED; 1197d23db91eSPedro F. Giffuni 1198d23db91eSPedro F. Giffuni return (0); 1199d23db91eSPedro F. Giffuni } 1200d23db91eSPedro F. Giffuni 12015b63c125SPedro F. Giffuni /* 1202e09c00caSUlf Lilleengen * Determine whether an inode can be allocated. 1203e09c00caSUlf Lilleengen * 1204e09c00caSUlf Lilleengen * Check to see if an inode is available, and if it is, 1205e09c00caSUlf Lilleengen * allocate it using tode in the specified cylinder group. 1206e09c00caSUlf Lilleengen */ 1207e09c00caSUlf Lilleengen static daddr_t 1208e09c00caSUlf Lilleengen ext2_nodealloccg(struct inode *ip, int cg, daddr_t ipref, int mode) 1209e09c00caSUlf Lilleengen { 1210e09c00caSUlf Lilleengen struct m_ext2fs *fs; 1211e09c00caSUlf Lilleengen struct buf *bp; 1212e09c00caSUlf Lilleengen struct ext2mount *ump; 12134c1e1d2bSFedor Uporov int error, start, len, ifree; 12148f8d3027SEd Schouten char *ibp, *loc; 1215bf9a211dSPedro F. Giffuni 1216e09c00caSUlf Lilleengen ipref--; /* to avoid a lot of (ipref -1) */ 1217e09c00caSUlf Lilleengen if (ipref == -1) 1218e09c00caSUlf Lilleengen ipref = 0; 1219e09c00caSUlf Lilleengen fs = ip->i_e2fs; 1220e09c00caSUlf Lilleengen ump = ip->i_ump; 12213acd9182SFedor Uporov if (e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) == 0) 1222e09c00caSUlf Lilleengen return (0); 1223e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 1224e09c00caSUlf Lilleengen error = bread(ip->i_devvp, fsbtodb(fs, 12253acd9182SFedor Uporov e2fs_gd_get_i_bitmap(&fs->e2fs_gd[cg])), 1226e09c00caSUlf Lilleengen (int)fs->e2fs_bsize, NOCRED, &bp); 1227e09c00caSUlf Lilleengen if (error) { 1228e09c00caSUlf Lilleengen brelse(bp); 1229e09c00caSUlf Lilleengen EXT2_LOCK(ump); 1230e09c00caSUlf Lilleengen return (0); 1231e09c00caSUlf Lilleengen } 1232512f29d1SFedor Uporov if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) || 1233512f29d1SFedor Uporov EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { 1234d23db91eSPedro F. Giffuni if (fs->e2fs_gd[cg].ext4bgd_flags & EXT2_BG_INODE_UNINIT) { 1235d23db91eSPedro F. Giffuni memset(bp->b_data, 0, fs->e2fs_bsize); 1236d23db91eSPedro F. Giffuni fs->e2fs_gd[cg].ext4bgd_flags &= ~EXT2_BG_INODE_UNINIT; 1237d23db91eSPedro F. Giffuni } 1238512f29d1SFedor Uporov ext2_gd_i_bitmap_csum_set(fs, cg, bp); 1239d23db91eSPedro F. Giffuni error = ext2_zero_inode_table(ip, cg); 1240d23db91eSPedro F. Giffuni if (error) { 1241d23db91eSPedro F. Giffuni brelse(bp); 1242d23db91eSPedro F. Giffuni EXT2_LOCK(ump); 1243d23db91eSPedro F. Giffuni return (0); 1244d23db91eSPedro F. Giffuni } 1245d23db91eSPedro F. Giffuni } 1246512f29d1SFedor Uporov error = ext2_gd_i_bitmap_csum_verify(fs, cg, bp); 1247512f29d1SFedor Uporov if (error) { 1248512f29d1SFedor Uporov brelse(bp); 1249512f29d1SFedor Uporov EXT2_LOCK(ump); 1250512f29d1SFedor Uporov return (0); 1251512f29d1SFedor Uporov } 12523acd9182SFedor Uporov if (e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) == 0) { 125373dd6d1fSJohn Baldwin /* 125473dd6d1fSJohn Baldwin * Another thread allocated the last i-node in this 125573dd6d1fSJohn Baldwin * group while we were waiting for the buffer. 125673dd6d1fSJohn Baldwin */ 125773dd6d1fSJohn Baldwin brelse(bp); 125873dd6d1fSJohn Baldwin EXT2_LOCK(ump); 125973dd6d1fSJohn Baldwin return (0); 126073dd6d1fSJohn Baldwin } 1261e09c00caSUlf Lilleengen ibp = (char *)bp->b_data; 1262e09c00caSUlf Lilleengen if (ipref) { 1263e09c00caSUlf Lilleengen ipref %= fs->e2fs->e2fs_ipg; 1264e09c00caSUlf Lilleengen if (isclr(ibp, ipref)) 1265e09c00caSUlf Lilleengen goto gotit; 1266e09c00caSUlf Lilleengen } 1267e09c00caSUlf Lilleengen start = ipref / NBBY; 1268e09c00caSUlf Lilleengen len = howmany(fs->e2fs->e2fs_ipg - ipref, NBBY); 12698f8d3027SEd Schouten loc = memcchr(&ibp[start], 0xff, len); 12708f8d3027SEd Schouten if (loc == NULL) { 1271e09c00caSUlf Lilleengen len = start + 1; 1272e09c00caSUlf Lilleengen start = 0; 12738f8d3027SEd Schouten loc = memcchr(&ibp[start], 0xff, len); 12748f8d3027SEd Schouten if (loc == NULL) { 1275e09c00caSUlf Lilleengen printf("cg = %d, ipref = %lld, fs = %s\n", 1276e09c00caSUlf Lilleengen cg, (long long)ipref, fs->e2fs_fsmnt); 1277e09c00caSUlf Lilleengen panic("ext2fs_nodealloccg: map corrupted"); 1278e09c00caSUlf Lilleengen /* NOTREACHED */ 1279e09c00caSUlf Lilleengen } 1280e09c00caSUlf Lilleengen } 12818f8d3027SEd Schouten ipref = (loc - ibp) * NBBY + ffs(~*loc) - 1; 1282e09c00caSUlf Lilleengen gotit: 1283e09c00caSUlf Lilleengen setbit(ibp, ipref); 1284e09c00caSUlf Lilleengen EXT2_LOCK(ump); 12853acd9182SFedor Uporov e2fs_gd_set_nifree(&fs->e2fs_gd[cg], 12863acd9182SFedor Uporov e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) - 1); 1287512f29d1SFedor Uporov if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) || 12884c1e1d2bSFedor Uporov EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { 12894c1e1d2bSFedor Uporov ifree = fs->e2fs->e2fs_ipg - e2fs_gd_get_i_unused(&fs->e2fs_gd[cg]); 12904c1e1d2bSFedor Uporov if (ipref + 1 > ifree) 12913acd9182SFedor Uporov e2fs_gd_set_i_unused(&fs->e2fs_gd[cg], 12924c1e1d2bSFedor Uporov fs->e2fs->e2fs_ipg - (ipref + 1)); 12934c1e1d2bSFedor Uporov } 1294e09c00caSUlf Lilleengen fs->e2fs->e2fs_ficount--; 1295e09c00caSUlf Lilleengen fs->e2fs_fmod = 1; 1296d8ba45e2SEd Maste if ((mode & IFMT) == IFDIR) { 12973acd9182SFedor Uporov e2fs_gd_set_ndirs(&fs->e2fs_gd[cg], 12983acd9182SFedor Uporov e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]) + 1); 1299e09c00caSUlf Lilleengen fs->e2fs_total_dir++; 1300e09c00caSUlf Lilleengen } 1301e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 1302512f29d1SFedor Uporov ext2_gd_i_bitmap_csum_set(fs, cg, bp); 1303e09c00caSUlf Lilleengen bdwrite(bp); 13043acd9182SFedor Uporov return ((uint64_t)cg * fs->e2fs_ipg + ipref + 1); 1305e09c00caSUlf Lilleengen } 1306e09c00caSUlf Lilleengen 1307e09c00caSUlf Lilleengen /* 1308e09c00caSUlf Lilleengen * Free a block or fragment. 1309e09c00caSUlf Lilleengen * 1310e09c00caSUlf Lilleengen */ 1311e09c00caSUlf Lilleengen void 131270097aacSPedro F. Giffuni ext2_blkfree(struct inode *ip, e4fs_daddr_t bno, long size) 1313e09c00caSUlf Lilleengen { 1314e09c00caSUlf Lilleengen struct m_ext2fs *fs; 1315e09c00caSUlf Lilleengen struct buf *bp; 1316e09c00caSUlf Lilleengen struct ext2mount *ump; 1317e09c00caSUlf Lilleengen int cg, error; 1318e09c00caSUlf Lilleengen char *bbp; 1319e09c00caSUlf Lilleengen 1320e09c00caSUlf Lilleengen fs = ip->i_e2fs; 1321e09c00caSUlf Lilleengen ump = ip->i_ump; 1322e09c00caSUlf Lilleengen cg = dtog(fs, bno); 13233acd9182SFedor Uporov if (bno >= fs->e2fs_bcount) { 1324dde58752SGleb Kurtsou printf("bad block %lld, ino %ju\n", (long long)bno, 1325dde58752SGleb Kurtsou (uintmax_t)ip->i_number); 1326e09c00caSUlf Lilleengen ext2_fserr(fs, ip->i_uid, "bad block"); 1327e09c00caSUlf Lilleengen return; 1328e09c00caSUlf Lilleengen } 1329e09c00caSUlf Lilleengen error = bread(ip->i_devvp, 13303acd9182SFedor Uporov fsbtodb(fs, e2fs_gd_get_b_bitmap(&fs->e2fs_gd[cg])), 1331e09c00caSUlf Lilleengen (int)fs->e2fs_bsize, NOCRED, &bp); 1332e09c00caSUlf Lilleengen if (error) { 1333e09c00caSUlf Lilleengen brelse(bp); 1334e09c00caSUlf Lilleengen return; 1335e09c00caSUlf Lilleengen } 1336e09c00caSUlf Lilleengen bbp = (char *)bp->b_data; 1337e09c00caSUlf Lilleengen bno = dtogd(fs, bno); 1338e09c00caSUlf Lilleengen if (isclr(bbp, bno)) { 1339e09c00caSUlf Lilleengen printf("block = %lld, fs = %s\n", 1340e09c00caSUlf Lilleengen (long long)bno, fs->e2fs_fsmnt); 1341757224cbSPedro F. Giffuni panic("ext2_blkfree: freeing free block"); 1342e09c00caSUlf Lilleengen } 1343e09c00caSUlf Lilleengen clrbit(bbp, bno); 1344e09c00caSUlf Lilleengen EXT2_LOCK(ump); 13455b63c125SPedro F. Giffuni ext2_clusteracct(fs, bbp, cg, bno, 1); 13463acd9182SFedor Uporov fs->e2fs_fbcount++; 13473acd9182SFedor Uporov e2fs_gd_set_nbfree(&fs->e2fs_gd[cg], 13483acd9182SFedor Uporov e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) + 1); 1349e09c00caSUlf Lilleengen fs->e2fs_fmod = 1; 1350e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 1351512f29d1SFedor Uporov ext2_gd_b_bitmap_csum_set(fs, cg, bp); 1352e09c00caSUlf Lilleengen bdwrite(bp); 1353e09c00caSUlf Lilleengen } 1354e09c00caSUlf Lilleengen 1355e09c00caSUlf Lilleengen /* 1356e09c00caSUlf Lilleengen * Free an inode. 1357e09c00caSUlf Lilleengen * 1358e09c00caSUlf Lilleengen */ 1359e09c00caSUlf Lilleengen int 1360a9d1b299SPedro F. Giffuni ext2_vfree(struct vnode *pvp, ino_t ino, int mode) 1361e09c00caSUlf Lilleengen { 1362e09c00caSUlf Lilleengen struct m_ext2fs *fs; 1363e09c00caSUlf Lilleengen struct inode *pip; 1364e09c00caSUlf Lilleengen struct buf *bp; 1365e09c00caSUlf Lilleengen struct ext2mount *ump; 1366e09c00caSUlf Lilleengen int error, cg; 1367e09c00caSUlf Lilleengen char *ibp; 1368e09c00caSUlf Lilleengen 1369e09c00caSUlf Lilleengen pip = VTOI(pvp); 1370e09c00caSUlf Lilleengen fs = pip->i_e2fs; 1371e09c00caSUlf Lilleengen ump = pip->i_ump; 1372e09c00caSUlf Lilleengen if ((u_int)ino > fs->e2fs_ipg * fs->e2fs_gcount) 1373fc8fdae0SMatthew D Fleming panic("ext2_vfree: range: devvp = %p, ino = %ju, fs = %s", 1374fc8fdae0SMatthew D Fleming pip->i_devvp, (uintmax_t)ino, fs->e2fs_fsmnt); 1375e09c00caSUlf Lilleengen 1376e09c00caSUlf Lilleengen cg = ino_to_cg(fs, ino); 1377e09c00caSUlf Lilleengen error = bread(pip->i_devvp, 13783acd9182SFedor Uporov fsbtodb(fs, e2fs_gd_get_i_bitmap(&fs->e2fs_gd[cg])), 1379e09c00caSUlf Lilleengen (int)fs->e2fs_bsize, NOCRED, &bp); 1380e09c00caSUlf Lilleengen if (error) { 1381e09c00caSUlf Lilleengen brelse(bp); 1382e09c00caSUlf Lilleengen return (0); 1383e09c00caSUlf Lilleengen } 1384e09c00caSUlf Lilleengen ibp = (char *)bp->b_data; 1385e09c00caSUlf Lilleengen ino = (ino - 1) % fs->e2fs->e2fs_ipg; 1386e09c00caSUlf Lilleengen if (isclr(ibp, ino)) { 1387e06e5241SFedor Uporov printf("ino = %ju, fs = %s\n", 1388e06e5241SFedor Uporov ino, fs->e2fs_fsmnt); 1389e09c00caSUlf Lilleengen if (fs->e2fs_ronly == 0) 1390757224cbSPedro F. Giffuni panic("ext2_vfree: freeing free inode"); 1391e09c00caSUlf Lilleengen } 1392e09c00caSUlf Lilleengen clrbit(ibp, ino); 1393e09c00caSUlf Lilleengen EXT2_LOCK(ump); 1394e09c00caSUlf Lilleengen fs->e2fs->e2fs_ficount++; 13953acd9182SFedor Uporov e2fs_gd_set_nifree(&fs->e2fs_gd[cg], 13963acd9182SFedor Uporov e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) + 1); 1397d8ba45e2SEd Maste if ((mode & IFMT) == IFDIR) { 13983acd9182SFedor Uporov e2fs_gd_set_ndirs(&fs->e2fs_gd[cg], 13993acd9182SFedor Uporov e2fs_gd_get_ndirs(&fs->e2fs_gd[cg]) - 1); 1400e09c00caSUlf Lilleengen fs->e2fs_total_dir--; 1401e09c00caSUlf Lilleengen } 1402e09c00caSUlf Lilleengen fs->e2fs_fmod = 1; 1403e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 1404512f29d1SFedor Uporov ext2_gd_i_bitmap_csum_set(fs, cg, bp); 1405e09c00caSUlf Lilleengen bdwrite(bp); 1406e09c00caSUlf Lilleengen return (0); 1407e09c00caSUlf Lilleengen } 1408e09c00caSUlf Lilleengen 1409e09c00caSUlf Lilleengen /* 1410e09c00caSUlf Lilleengen * Find a block in the specified cylinder group. 1411e09c00caSUlf Lilleengen * 1412e09c00caSUlf Lilleengen * It is a panic if a request is made to find a block if none are 1413e09c00caSUlf Lilleengen * available. 1414e09c00caSUlf Lilleengen */ 1415e09c00caSUlf Lilleengen static daddr_t 1416e09c00caSUlf Lilleengen ext2_mapsearch(struct m_ext2fs *fs, char *bbp, daddr_t bpref) 1417e09c00caSUlf Lilleengen { 14188f8d3027SEd Schouten char *loc; 14198f8d3027SEd Schouten int start, len; 1420e09c00caSUlf Lilleengen 1421e09c00caSUlf Lilleengen /* 1422e09c00caSUlf Lilleengen * find the fragment by searching through the free block 1423e09c00caSUlf Lilleengen * map for an appropriate bit pattern 1424e09c00caSUlf Lilleengen */ 1425e09c00caSUlf Lilleengen if (bpref) 1426e09c00caSUlf Lilleengen start = dtogd(fs, bpref) / NBBY; 1427e09c00caSUlf Lilleengen else 1428e09c00caSUlf Lilleengen start = 0; 1429e09c00caSUlf Lilleengen len = howmany(fs->e2fs->e2fs_fpg, NBBY) - start; 14308f8d3027SEd Schouten loc = memcchr(&bbp[start], 0xff, len); 14318f8d3027SEd Schouten if (loc == NULL) { 1432e09c00caSUlf Lilleengen len = start + 1; 1433e09c00caSUlf Lilleengen start = 0; 14348f8d3027SEd Schouten loc = memcchr(&bbp[start], 0xff, len); 14358f8d3027SEd Schouten if (loc == NULL) { 1436e09c00caSUlf Lilleengen printf("start = %d, len = %d, fs = %s\n", 1437e09c00caSUlf Lilleengen start, len, fs->e2fs_fsmnt); 1438757224cbSPedro F. Giffuni panic("ext2_mapsearch: map corrupted"); 1439e09c00caSUlf Lilleengen /* NOTREACHED */ 1440e09c00caSUlf Lilleengen } 1441e09c00caSUlf Lilleengen } 14428f8d3027SEd Schouten return ((loc - bbp) * NBBY + ffs(~*loc) - 1); 1443e09c00caSUlf Lilleengen } 1444e09c00caSUlf Lilleengen 1445e09c00caSUlf Lilleengen /* 1446e09c00caSUlf Lilleengen * Fserr prints the name of a filesystem with an error diagnostic. 1447e09c00caSUlf Lilleengen * 1448e09c00caSUlf Lilleengen * The form of the error message is: 1449e09c00caSUlf Lilleengen * fs: error message 1450e09c00caSUlf Lilleengen */ 145172530f91SFedor Uporov void 1452a9d1b299SPedro F. Giffuni ext2_fserr(struct m_ext2fs *fs, uid_t uid, char *cp) 1453e09c00caSUlf Lilleengen { 1454e09c00caSUlf Lilleengen 1455e09c00caSUlf Lilleengen log(LOG_ERR, "uid %u on %s: %s\n", uid, fs->e2fs_fsmnt, cp); 1456e09c00caSUlf Lilleengen } 1457e09c00caSUlf Lilleengen 1458e09c00caSUlf Lilleengen int 1459d23db91eSPedro F. Giffuni ext2_cg_has_sb(struct m_ext2fs *fs, int cg) 1460e09c00caSUlf Lilleengen { 1461e09c00caSUlf Lilleengen int a3, a5, a7; 1462e09c00caSUlf Lilleengen 1463d23db91eSPedro F. Giffuni if (cg == 0) 1464d23db91eSPedro F. Giffuni return (1); 1465d23db91eSPedro F. Giffuni 1466d23db91eSPedro F. Giffuni if (EXT2_HAS_COMPAT_FEATURE(fs, EXT2F_COMPAT_SPARSESUPER2)) { 1467d23db91eSPedro F. Giffuni if (cg == fs->e2fs->e4fs_backup_bgs[0] || 1468d23db91eSPedro F. Giffuni cg == fs->e2fs->e4fs_backup_bgs[1]) 1469d23db91eSPedro F. Giffuni return (1); 1470d23db91eSPedro F. Giffuni return (0); 1471d23db91eSPedro F. Giffuni } 1472d23db91eSPedro F. Giffuni 1473d23db91eSPedro F. Giffuni if ((cg <= 1) || 1474d23db91eSPedro F. Giffuni !EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_SPARSESUPER)) 1475d23db91eSPedro F. Giffuni return (1); 1476d23db91eSPedro F. Giffuni 1477d23db91eSPedro F. Giffuni if (!(cg & 1)) 1478d23db91eSPedro F. Giffuni return (0); 1479d23db91eSPedro F. Giffuni 1480e09c00caSUlf Lilleengen for (a3 = 3, a5 = 5, a7 = 7; 1481d23db91eSPedro F. Giffuni a3 <= cg || a5 <= cg || a7 <= cg; 1482e09c00caSUlf Lilleengen a3 *= 3, a5 *= 5, a7 *= 7) 1483d23db91eSPedro F. Giffuni if (cg == a3 || cg == a5 || cg == a7) 1484d23db91eSPedro F. Giffuni return (1); 1485d23db91eSPedro F. Giffuni return (0); 1486e09c00caSUlf Lilleengen } 1487