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 /*- 8e09c00caSUlf Lilleengen * Copyright (c) 1982, 1986, 1989, 1993 9e09c00caSUlf Lilleengen * The Regents of the University of California. All rights reserved. 10e09c00caSUlf Lilleengen * 11e09c00caSUlf Lilleengen * Redistribution and use in source and binary forms, with or without 12e09c00caSUlf Lilleengen * modification, are permitted provided that the following conditions 13e09c00caSUlf Lilleengen * are met: 14e09c00caSUlf Lilleengen * 1. Redistributions of source code must retain the above copyright 15e09c00caSUlf Lilleengen * notice, this list of conditions and the following disclaimer. 16e09c00caSUlf Lilleengen * 2. Redistributions in binary form must reproduce the above copyright 17e09c00caSUlf Lilleengen * notice, this list of conditions and the following disclaimer in the 18e09c00caSUlf Lilleengen * documentation and/or other materials provided with the distribution. 19e09c00caSUlf Lilleengen * 4. Neither the name of the University nor the names of its contributors 20e09c00caSUlf Lilleengen * may be used to endorse or promote products derived from this software 21e09c00caSUlf Lilleengen * without specific prior written permission. 22e09c00caSUlf Lilleengen * 23e09c00caSUlf Lilleengen * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24e09c00caSUlf Lilleengen * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25e09c00caSUlf Lilleengen * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26e09c00caSUlf Lilleengen * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27e09c00caSUlf Lilleengen * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28e09c00caSUlf Lilleengen * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29e09c00caSUlf Lilleengen * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30e09c00caSUlf Lilleengen * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31e09c00caSUlf Lilleengen * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32e09c00caSUlf Lilleengen * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33e09c00caSUlf Lilleengen * SUCH DAMAGE. 34e09c00caSUlf Lilleengen * 35e09c00caSUlf Lilleengen * @(#)ffs_alloc.c 8.8 (Berkeley) 2/21/94 36e09c00caSUlf Lilleengen * $FreeBSD$ 37e09c00caSUlf Lilleengen */ 38e09c00caSUlf Lilleengen 39e09c00caSUlf Lilleengen #include <sys/param.h> 40e09c00caSUlf Lilleengen #include <sys/systm.h> 41e09c00caSUlf Lilleengen #include <sys/conf.h> 42e09c00caSUlf Lilleengen #include <sys/vnode.h> 43e09c00caSUlf Lilleengen #include <sys/stat.h> 44e09c00caSUlf Lilleengen #include <sys/mount.h> 45e09c00caSUlf Lilleengen #include <sys/syslog.h> 46e09c00caSUlf Lilleengen #include <sys/buf.h> 47e09c00caSUlf Lilleengen 48e09c00caSUlf Lilleengen #include <fs/ext2fs/inode.h> 49e09c00caSUlf Lilleengen #include <fs/ext2fs/ext2_mount.h> 50e09c00caSUlf Lilleengen #include <fs/ext2fs/ext2fs.h> 51e09c00caSUlf Lilleengen #include <fs/ext2fs/fs.h> 52e09c00caSUlf Lilleengen #include <fs/ext2fs/ext2_extern.h> 53e09c00caSUlf Lilleengen 54e09c00caSUlf Lilleengen static daddr_t ext2_alloccg(struct inode *, int, daddr_t, int); 55e09c00caSUlf Lilleengen static u_long ext2_dirpref(struct inode *); 56e09c00caSUlf Lilleengen static void ext2_fserr(struct m_ext2fs *, uid_t, char *); 57e09c00caSUlf Lilleengen static u_long ext2_hashalloc(struct inode *, int, long, int, 58e09c00caSUlf Lilleengen daddr_t (*)(struct inode *, int, daddr_t, 59e09c00caSUlf Lilleengen int)); 60e09c00caSUlf Lilleengen static daddr_t ext2_nodealloccg(struct inode *, int, daddr_t, int); 61e09c00caSUlf Lilleengen static daddr_t ext2_mapsearch(struct m_ext2fs *, char *, daddr_t); 62*c767faa5SJohn Baldwin #ifdef FANCY_REALLOC 63*c767faa5SJohn Baldwin static int ext2_reallocblks(struct vop_reallocblks_args *); 64*c767faa5SJohn Baldwin #endif 65*c767faa5SJohn Baldwin 66e09c00caSUlf Lilleengen /* 67e09c00caSUlf Lilleengen * Allocate a block in the file system. 68e09c00caSUlf Lilleengen * 69e09c00caSUlf Lilleengen * A preference may be optionally specified. If a preference is given 70e09c00caSUlf Lilleengen * the following hierarchy is used to allocate a block: 71e09c00caSUlf Lilleengen * 1) allocate the requested block. 72e09c00caSUlf Lilleengen * 2) allocate a rotationally optimal block in the same cylinder. 73e09c00caSUlf Lilleengen * 3) allocate a block in the same cylinder group. 74e09c00caSUlf Lilleengen * 4) quadradically rehash into other cylinder groups, until an 75e09c00caSUlf Lilleengen * available block is located. 76e09c00caSUlf Lilleengen * If no block preference is given the following hierarchy is used 77e09c00caSUlf Lilleengen * to allocate a block: 78e09c00caSUlf Lilleengen * 1) allocate a block in the cylinder group that contains the 79e09c00caSUlf Lilleengen * inode for the file. 80e09c00caSUlf Lilleengen * 2) quadradically rehash into other cylinder groups, until an 81e09c00caSUlf Lilleengen * available block is located. 82e09c00caSUlf Lilleengen */ 83e09c00caSUlf Lilleengen int 84e09c00caSUlf Lilleengen ext2_alloc(ip, lbn, bpref, size, cred, bnp) 85e09c00caSUlf Lilleengen struct inode *ip; 86e09c00caSUlf Lilleengen int32_t lbn, bpref; 87e09c00caSUlf Lilleengen int size; 88e09c00caSUlf Lilleengen struct ucred *cred; 89e09c00caSUlf Lilleengen int32_t *bnp; 90e09c00caSUlf Lilleengen { 91e09c00caSUlf Lilleengen struct m_ext2fs *fs; 92e09c00caSUlf Lilleengen struct ext2mount *ump; 93e09c00caSUlf Lilleengen int32_t bno; 94e09c00caSUlf Lilleengen int cg; 95e09c00caSUlf Lilleengen *bnp = 0; 96e09c00caSUlf Lilleengen fs = ip->i_e2fs; 97e09c00caSUlf Lilleengen ump = ip->i_ump; 98e09c00caSUlf Lilleengen mtx_assert(EXT2_MTX(ump), MA_OWNED); 99e09c00caSUlf Lilleengen #ifdef DIAGNOSTIC 100e09c00caSUlf Lilleengen if ((u_int)size > fs->e2fs_bsize || blkoff(fs, size) != 0) { 101e09c00caSUlf Lilleengen vn_printf(ip->i_devvp, "bsize = %lu, size = %d, fs = %s\n", 102e09c00caSUlf Lilleengen (long unsigned int)fs->e2fs_bsize, size, fs->e2fs_fsmnt); 103e09c00caSUlf Lilleengen panic("ext2_alloc: bad size"); 104e09c00caSUlf Lilleengen } 105e09c00caSUlf Lilleengen if (cred == NOCRED) 106e09c00caSUlf Lilleengen panic("ext2_alloc: missing credential"); 107e09c00caSUlf Lilleengen #endif /* DIAGNOSTIC */ 108e09c00caSUlf Lilleengen if (size == fs->e2fs_bsize && fs->e2fs->e2fs_fbcount == 0) 109e09c00caSUlf Lilleengen goto nospace; 110e09c00caSUlf Lilleengen if (cred->cr_uid != 0 && 111e09c00caSUlf Lilleengen fs->e2fs->e2fs_fbcount < fs->e2fs->e2fs_rbcount) 112e09c00caSUlf Lilleengen goto nospace; 113e09c00caSUlf Lilleengen if (bpref >= fs->e2fs->e2fs_bcount) 114e09c00caSUlf Lilleengen bpref = 0; 115e09c00caSUlf Lilleengen if (bpref == 0) 116e09c00caSUlf Lilleengen cg = ino_to_cg(fs, ip->i_number); 117e09c00caSUlf Lilleengen else 118e09c00caSUlf Lilleengen cg = dtog(fs, bpref); 119e09c00caSUlf Lilleengen bno = (daddr_t)ext2_hashalloc(ip, cg, bpref, fs->e2fs_bsize, 120e09c00caSUlf Lilleengen ext2_alloccg); 121e09c00caSUlf Lilleengen if (bno > 0) { 122*c767faa5SJohn Baldwin /* set next_alloc fields as done in block_getblk */ 123*c767faa5SJohn Baldwin ip->i_next_alloc_block = lbn; 124*c767faa5SJohn Baldwin ip->i_next_alloc_goal = bno; 125*c767faa5SJohn Baldwin 126e09c00caSUlf Lilleengen ip->i_blocks += btodb(fs->e2fs_bsize); 127e09c00caSUlf Lilleengen ip->i_flag |= IN_CHANGE | IN_UPDATE; 128e09c00caSUlf Lilleengen *bnp = bno; 129e09c00caSUlf Lilleengen return (0); 130e09c00caSUlf Lilleengen } 131e09c00caSUlf Lilleengen nospace: 132e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 133e09c00caSUlf Lilleengen ext2_fserr(fs, cred->cr_uid, "file system full"); 134e09c00caSUlf Lilleengen uprintf("\n%s: write failed, file system is full\n", fs->e2fs_fsmnt); 135e09c00caSUlf Lilleengen return (ENOSPC); 136e09c00caSUlf Lilleengen } 137e09c00caSUlf Lilleengen 138e09c00caSUlf Lilleengen /* 139e09c00caSUlf Lilleengen * Reallocate a sequence of blocks into a contiguous sequence of blocks. 140e09c00caSUlf Lilleengen * 141e09c00caSUlf Lilleengen * The vnode and an array of buffer pointers for a range of sequential 142e09c00caSUlf Lilleengen * logical blocks to be made contiguous is given. The allocator attempts 143e09c00caSUlf Lilleengen * to find a range of sequential blocks starting as close as possible to 144e09c00caSUlf Lilleengen * an fs_rotdelay offset from the end of the allocation for the logical 145e09c00caSUlf Lilleengen * block immediately preceding the current range. If successful, the 146e09c00caSUlf Lilleengen * physical block numbers in the buffer pointers and in the inode are 147e09c00caSUlf Lilleengen * changed to reflect the new allocation. If unsuccessful, the allocation 148e09c00caSUlf Lilleengen * is left unchanged. The success in doing the reallocation is returned. 149e09c00caSUlf Lilleengen * Note that the error return is not reflected back to the user. Rather 150e09c00caSUlf Lilleengen * the previous block allocation will be used. 151e09c00caSUlf Lilleengen */ 152e09c00caSUlf Lilleengen 153e09c00caSUlf Lilleengen #ifdef FANCY_REALLOC 154*c767faa5SJohn Baldwin SYSCTL_NODE(_vfs, OID_AUTO, ext2fs, CTLFLAG_RW, 0, "EXT2FS filesystem"); 155e09c00caSUlf Lilleengen 156*c767faa5SJohn Baldwin static int doasyncfree = 1; 157*c767faa5SJohn Baldwin SYSCTL_INT(_vfs_ext2fs, OID_AUTO, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, 158*c767faa5SJohn Baldwin "Use asychronous writes to update block pointers when freeing blocks"); 159*c767faa5SJohn Baldwin 160*c767faa5SJohn Baldwin static int doreallocblks = 1; 161*c767faa5SJohn Baldwin SYSCTL_INT(_vfs_ext2fs, OID_AUTO, doreallocblks, CTLFLAG_RW, &doreallocblks, 0, ""); 162e09c00caSUlf Lilleengen #endif 163e09c00caSUlf Lilleengen 164e09c00caSUlf Lilleengen int 165e09c00caSUlf Lilleengen ext2_reallocblks(ap) 166e09c00caSUlf Lilleengen struct vop_reallocblks_args /* { 167e09c00caSUlf Lilleengen struct vnode *a_vp; 168e09c00caSUlf Lilleengen struct cluster_save *a_buflist; 169e09c00caSUlf Lilleengen } */ *ap; 170e09c00caSUlf Lilleengen { 171e09c00caSUlf Lilleengen #ifndef FANCY_REALLOC 172e09c00caSUlf Lilleengen /* printf("ext2_reallocblks not implemented\n"); */ 173e09c00caSUlf Lilleengen return ENOSPC; 174e09c00caSUlf Lilleengen #else 175e09c00caSUlf Lilleengen 176e09c00caSUlf Lilleengen struct m_ext2fs *fs; 177e09c00caSUlf Lilleengen struct inode *ip; 178e09c00caSUlf Lilleengen struct vnode *vp; 179e09c00caSUlf Lilleengen struct buf *sbp, *ebp; 180e09c00caSUlf Lilleengen int32_t *bap, *sbap, *ebap = 0; 181e09c00caSUlf Lilleengen struct ext2mount *ump; 182e09c00caSUlf Lilleengen struct cluster_save *buflist; 183e09c00caSUlf Lilleengen struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp; 184e09c00caSUlf Lilleengen int32_t start_lbn, end_lbn, soff, newblk, blkno =0; 185e09c00caSUlf Lilleengen int i, len, start_lvl, end_lvl, pref, ssize; 186e09c00caSUlf Lilleengen 187e09c00caSUlf Lilleengen vp = ap->a_vp; 188e09c00caSUlf Lilleengen ip = VTOI(vp); 189e09c00caSUlf Lilleengen fs = ip->i_e2fs; 190e09c00caSUlf Lilleengen ump = ip->i_ump; 191e09c00caSUlf Lilleengen #ifdef UNKLAR 192e09c00caSUlf Lilleengen if (fs->fs_contigsumsize <= 0) 193e09c00caSUlf Lilleengen return (ENOSPC); 194e09c00caSUlf Lilleengen #endif 195e09c00caSUlf Lilleengen buflist = ap->a_buflist; 196e09c00caSUlf Lilleengen len = buflist->bs_nchildren; 197e09c00caSUlf Lilleengen start_lbn = buflist->bs_children[0]->b_lblkno; 198e09c00caSUlf Lilleengen end_lbn = start_lbn + len - 1; 199e09c00caSUlf Lilleengen #ifdef DIAGNOSTIC 200e09c00caSUlf Lilleengen for (i = 1; i < len; i++) 201e09c00caSUlf Lilleengen if (buflist->bs_children[i]->b_lblkno != start_lbn + i) 202e09c00caSUlf Lilleengen panic("ext2_reallocblks: non-cluster"); 203e09c00caSUlf Lilleengen #endif 204e09c00caSUlf Lilleengen /* 205e09c00caSUlf Lilleengen * If the latest allocation is in a new cylinder group, assume that 206e09c00caSUlf Lilleengen * the filesystem has decided to move and do not force it back to 207e09c00caSUlf Lilleengen * the previous cylinder group. 208e09c00caSUlf Lilleengen */ 209e09c00caSUlf Lilleengen if (dtog(fs, dbtofsb(fs, buflist->bs_children[0]->b_blkno)) != 210e09c00caSUlf Lilleengen dtog(fs, dbtofsb(fs, buflist->bs_children[len - 1]->b_blkno))) 211e09c00caSUlf Lilleengen return (ENOSPC); 212e09c00caSUlf Lilleengen if (ext2_getlbns(vp, start_lbn, start_ap, &start_lvl) || 213e09c00caSUlf Lilleengen ext2_getlbns(vp, end_lbn, end_ap, &end_lvl)) 214e09c00caSUlf Lilleengen return (ENOSPC); 215e09c00caSUlf Lilleengen /* 216e09c00caSUlf Lilleengen * Get the starting offset and block map for the first block. 217e09c00caSUlf Lilleengen */ 218e09c00caSUlf Lilleengen if (start_lvl == 0) { 219e09c00caSUlf Lilleengen sbap = &ip->i_db[0]; 220e09c00caSUlf Lilleengen soff = start_lbn; 221e09c00caSUlf Lilleengen } else { 222e09c00caSUlf Lilleengen idp = &start_ap[start_lvl - 1]; 223e09c00caSUlf Lilleengen if (bread(vp, idp->in_lbn, (int)fs->e2fs_bsize, NOCRED, &sbp)) { 224e09c00caSUlf Lilleengen brelse(sbp); 225e09c00caSUlf Lilleengen return (ENOSPC); 226e09c00caSUlf Lilleengen } 227e09c00caSUlf Lilleengen sbap = (int32_t *)sbp->b_data; 228e09c00caSUlf Lilleengen soff = idp->in_off; 229e09c00caSUlf Lilleengen } 230e09c00caSUlf Lilleengen /* 231e09c00caSUlf Lilleengen * Find the preferred location for the cluster. 232e09c00caSUlf Lilleengen */ 233e09c00caSUlf Lilleengen EXT2_LOCK(ump); 234e09c00caSUlf Lilleengen pref = ext2_blkpref(ip, start_lbn, soff, sbap, blkno); 235e09c00caSUlf Lilleengen /* 236e09c00caSUlf Lilleengen * If the block range spans two block maps, get the second map. 237e09c00caSUlf Lilleengen */ 238e09c00caSUlf Lilleengen if (end_lvl == 0 || (idp = &end_ap[end_lvl - 1])->in_off + 1 >= len) { 239e09c00caSUlf Lilleengen ssize = len; 240e09c00caSUlf Lilleengen } else { 241e09c00caSUlf Lilleengen #ifdef DIAGNOSTIC 242e09c00caSUlf Lilleengen if (start_ap[start_lvl-1].in_lbn == idp->in_lbn) 243e09c00caSUlf Lilleengen panic("ext2_reallocblk: start == end"); 244e09c00caSUlf Lilleengen #endif 245e09c00caSUlf Lilleengen ssize = len - (idp->in_off + 1); 246e09c00caSUlf Lilleengen if (bread(vp, idp->in_lbn, (int)fs->e2fs_bsize, NOCRED, &ebp)){ 247e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 248e09c00caSUlf Lilleengen goto fail; 249e09c00caSUlf Lilleengen } 250e09c00caSUlf Lilleengen ebap = (int32_t *)ebp->b_data; 251e09c00caSUlf Lilleengen } 252e09c00caSUlf Lilleengen /* 253e09c00caSUlf Lilleengen * Search the block map looking for an allocation of the desired size. 254e09c00caSUlf Lilleengen */ 255e09c00caSUlf Lilleengen if ((newblk = (int32_t)ext2_hashalloc(ip, dtog(fs, pref), pref, 256e09c00caSUlf Lilleengen len, ext2_clusteralloc)) == 0){ 257e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 258e09c00caSUlf Lilleengen goto fail; 259e09c00caSUlf Lilleengen } 260e09c00caSUlf Lilleengen /* 261e09c00caSUlf Lilleengen * We have found a new contiguous block. 262e09c00caSUlf Lilleengen * 263e09c00caSUlf Lilleengen * First we have to replace the old block pointers with the new 264e09c00caSUlf Lilleengen * block pointers in the inode and indirect blocks associated 265e09c00caSUlf Lilleengen * with the file. 266e09c00caSUlf Lilleengen */ 267e09c00caSUlf Lilleengen blkno = newblk; 268e09c00caSUlf Lilleengen for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->e2fs_fpb) { 269e09c00caSUlf Lilleengen if (i == ssize) 270e09c00caSUlf Lilleengen bap = ebap; 271e09c00caSUlf Lilleengen soff = -i; 272e09c00caSUlf Lilleengen #ifdef DIAGNOSTIC 273e09c00caSUlf Lilleengen if (buflist->bs_children[i]->b_blkno != fsbtodb(fs, *bap)) 274e09c00caSUlf Lilleengen panic("ext2_reallocblks: alloc mismatch"); 275e09c00caSUlf Lilleengen #endif 276e09c00caSUlf Lilleengen *bap++ = blkno; 277e09c00caSUlf Lilleengen } 278e09c00caSUlf Lilleengen /* 279e09c00caSUlf Lilleengen * Next we must write out the modified inode and indirect blocks. 280e09c00caSUlf Lilleengen * For strict correctness, the writes should be synchronous since 281e09c00caSUlf Lilleengen * the old block values may have been written to disk. In practise 282e09c00caSUlf Lilleengen * they are almost never written, but if we are concerned about 283e09c00caSUlf Lilleengen * strict correctness, the `doasyncfree' flag should be set to zero. 284e09c00caSUlf Lilleengen * 285e09c00caSUlf Lilleengen * The test on `doasyncfree' should be changed to test a flag 286e09c00caSUlf Lilleengen * that shows whether the associated buffers and inodes have 287e09c00caSUlf Lilleengen * been written. The flag should be set when the cluster is 288e09c00caSUlf Lilleengen * started and cleared whenever the buffer or inode is flushed. 289e09c00caSUlf Lilleengen * We can then check below to see if it is set, and do the 290e09c00caSUlf Lilleengen * synchronous write only when it has been cleared. 291e09c00caSUlf Lilleengen */ 292e09c00caSUlf Lilleengen if (sbap != &ip->i_db[0]) { 293e09c00caSUlf Lilleengen if (doasyncfree) 294e09c00caSUlf Lilleengen bdwrite(sbp); 295e09c00caSUlf Lilleengen else 296e09c00caSUlf Lilleengen bwrite(sbp); 297e09c00caSUlf Lilleengen } else { 298e09c00caSUlf Lilleengen ip->i_flag |= IN_CHANGE | IN_UPDATE; 299e09c00caSUlf Lilleengen if (!doasyncfree) 300e09c00caSUlf Lilleengen ext2_update(vp, 1); 301e09c00caSUlf Lilleengen } 302e09c00caSUlf Lilleengen if (ssize < len) { 303e09c00caSUlf Lilleengen if (doasyncfree) 304e09c00caSUlf Lilleengen bdwrite(ebp); 305e09c00caSUlf Lilleengen else 306e09c00caSUlf Lilleengen bwrite(ebp); 307e09c00caSUlf Lilleengen } 308e09c00caSUlf Lilleengen /* 309e09c00caSUlf Lilleengen * Last, free the old blocks and assign the new blocks to the buffers. 310e09c00caSUlf Lilleengen */ 311e09c00caSUlf Lilleengen for (blkno = newblk, i = 0; i < len; i++, blkno += fs->e2fs_fpb) { 312e09c00caSUlf Lilleengen ext2_blkfree(ip, dbtofsb(fs, buflist->bs_children[i]->b_blkno), 313e09c00caSUlf Lilleengen fs->e2fs_bsize); 314e09c00caSUlf Lilleengen buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno); 315e09c00caSUlf Lilleengen } 316e09c00caSUlf Lilleengen return (0); 317e09c00caSUlf Lilleengen 318e09c00caSUlf Lilleengen fail: 319e09c00caSUlf Lilleengen if (ssize < len) 320e09c00caSUlf Lilleengen brelse(ebp); 321e09c00caSUlf Lilleengen if (sbap != &ip->i_db[0]) 322e09c00caSUlf Lilleengen brelse(sbp); 323e09c00caSUlf Lilleengen return (ENOSPC); 324e09c00caSUlf Lilleengen 325e09c00caSUlf Lilleengen #endif /* FANCY_REALLOC */ 326e09c00caSUlf Lilleengen } 327e09c00caSUlf Lilleengen 328e09c00caSUlf Lilleengen /* 329e09c00caSUlf Lilleengen * Allocate an inode in the file system. 330e09c00caSUlf Lilleengen * 331e09c00caSUlf Lilleengen */ 332e09c00caSUlf Lilleengen int 333e09c00caSUlf Lilleengen ext2_valloc(pvp, mode, cred, vpp) 334e09c00caSUlf Lilleengen struct vnode *pvp; 335e09c00caSUlf Lilleengen int mode; 336e09c00caSUlf Lilleengen struct ucred *cred; 337e09c00caSUlf Lilleengen struct vnode **vpp; 338e09c00caSUlf Lilleengen { 339e09c00caSUlf Lilleengen struct inode *pip; 340e09c00caSUlf Lilleengen struct m_ext2fs *fs; 341e09c00caSUlf Lilleengen struct inode *ip; 342e09c00caSUlf Lilleengen struct ext2mount *ump; 343e09c00caSUlf Lilleengen ino_t ino, ipref; 344e09c00caSUlf Lilleengen int i, error, cg; 345e09c00caSUlf Lilleengen 346e09c00caSUlf Lilleengen *vpp = NULL; 347e09c00caSUlf Lilleengen pip = VTOI(pvp); 348e09c00caSUlf Lilleengen fs = pip->i_e2fs; 349e09c00caSUlf Lilleengen ump = pip->i_ump; 350e09c00caSUlf Lilleengen 351e09c00caSUlf Lilleengen EXT2_LOCK(ump); 352e09c00caSUlf Lilleengen if (fs->e2fs->e2fs_ficount == 0) 353e09c00caSUlf Lilleengen goto noinodes; 354e09c00caSUlf Lilleengen /* 355e09c00caSUlf Lilleengen * If it is a directory then obtain a cylinder group based on 356e09c00caSUlf Lilleengen * ext2_dirpref else obtain it using ino_to_cg. The preferred inode is 357e09c00caSUlf Lilleengen * always the next inode. 358e09c00caSUlf Lilleengen */ 359e09c00caSUlf Lilleengen if((mode & IFMT) == IFDIR) { 360e09c00caSUlf Lilleengen cg = ext2_dirpref(pip); 361e09c00caSUlf Lilleengen if (fs->e2fs_contigdirs[cg] < 255) 362e09c00caSUlf Lilleengen fs->e2fs_contigdirs[cg]++; 363e09c00caSUlf Lilleengen } else { 364e09c00caSUlf Lilleengen cg = ino_to_cg(fs, pip->i_number); 365e09c00caSUlf Lilleengen if (fs->e2fs_contigdirs[cg] > 0) 366e09c00caSUlf Lilleengen fs->e2fs_contigdirs[cg]--; 367e09c00caSUlf Lilleengen } 368e09c00caSUlf Lilleengen ipref = cg * fs->e2fs->e2fs_ipg + 1; 369e09c00caSUlf Lilleengen ino = (ino_t)ext2_hashalloc(pip, cg, (long)ipref, mode, ext2_nodealloccg); 370e09c00caSUlf Lilleengen 371e09c00caSUlf Lilleengen if (ino == 0) 372e09c00caSUlf Lilleengen goto noinodes; 373e09c00caSUlf Lilleengen error = VFS_VGET(pvp->v_mount, ino, LK_EXCLUSIVE, vpp); 374e09c00caSUlf Lilleengen if (error) { 375e09c00caSUlf Lilleengen ext2_vfree(pvp, ino, mode); 376e09c00caSUlf Lilleengen return (error); 377e09c00caSUlf Lilleengen } 378e09c00caSUlf Lilleengen ip = VTOI(*vpp); 379e09c00caSUlf Lilleengen 380e09c00caSUlf Lilleengen /* 381e09c00caSUlf Lilleengen the question is whether using VGET was such good idea at all - 382e09c00caSUlf Lilleengen Linux doesn't read the old inode in when it's allocating a 383e09c00caSUlf Lilleengen new one. I will set at least i_size & i_blocks the zero. 384e09c00caSUlf Lilleengen */ 385e09c00caSUlf Lilleengen ip->i_mode = 0; 386e09c00caSUlf Lilleengen ip->i_size = 0; 387e09c00caSUlf Lilleengen ip->i_blocks = 0; 388e09c00caSUlf Lilleengen ip->i_flags = 0; 389e09c00caSUlf Lilleengen /* now we want to make sure that the block pointers are zeroed out */ 390e09c00caSUlf Lilleengen for (i = 0; i < NDADDR; i++) 391e09c00caSUlf Lilleengen ip->i_db[i] = 0; 392e09c00caSUlf Lilleengen for (i = 0; i < NIADDR; i++) 393e09c00caSUlf Lilleengen ip->i_ib[i] = 0; 394e09c00caSUlf Lilleengen 395e09c00caSUlf Lilleengen /* 396e09c00caSUlf Lilleengen * Set up a new generation number for this inode. 397e09c00caSUlf Lilleengen * XXX check if this makes sense in ext2 398e09c00caSUlf Lilleengen */ 399e09c00caSUlf Lilleengen if (ip->i_gen == 0 || ++ip->i_gen == 0) 400e09c00caSUlf Lilleengen ip->i_gen = random() / 2 + 1; 401e09c00caSUlf Lilleengen /* 402e09c00caSUlf Lilleengen printf("ext2_valloc: allocated inode %d\n", ino); 403e09c00caSUlf Lilleengen */ 404e09c00caSUlf Lilleengen return (0); 405e09c00caSUlf Lilleengen noinodes: 406e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 407e09c00caSUlf Lilleengen ext2_fserr(fs, cred->cr_uid, "out of inodes"); 408e09c00caSUlf Lilleengen uprintf("\n%s: create/symlink failed, no inodes free\n", fs->e2fs_fsmnt); 409e09c00caSUlf Lilleengen return (ENOSPC); 410e09c00caSUlf Lilleengen } 411e09c00caSUlf Lilleengen 412e09c00caSUlf Lilleengen /* 413e09c00caSUlf Lilleengen * Find a cylinder to place a directory. 414e09c00caSUlf Lilleengen * 415e09c00caSUlf Lilleengen * The policy implemented by this algorithm is to allocate a 416e09c00caSUlf Lilleengen * directory inode in the same cylinder group as its parent 417e09c00caSUlf Lilleengen * directory, but also to reserve space for its files inodes 418e09c00caSUlf Lilleengen * and data. Restrict the number of directories which may be 419e09c00caSUlf Lilleengen * allocated one after another in the same cylinder group 420e09c00caSUlf Lilleengen * without intervening allocation of files. 421e09c00caSUlf Lilleengen * 422e09c00caSUlf Lilleengen * If we allocate a first level directory then force allocation 423e09c00caSUlf Lilleengen * in another cylinder group. 424e09c00caSUlf Lilleengen * 425e09c00caSUlf Lilleengen */ 426e09c00caSUlf Lilleengen static u_long 427e09c00caSUlf Lilleengen ext2_dirpref(struct inode *pip) 428e09c00caSUlf Lilleengen { 429e09c00caSUlf Lilleengen struct m_ext2fs *fs; 430e09c00caSUlf Lilleengen int cg, prefcg, dirsize, cgsize; 431e09c00caSUlf Lilleengen int avgifree, avgbfree, avgndir, curdirsize; 432e09c00caSUlf Lilleengen int minifree, minbfree, maxndir; 433e09c00caSUlf Lilleengen int mincg, minndir; 434e09c00caSUlf Lilleengen int maxcontigdirs; 435e09c00caSUlf Lilleengen 436e09c00caSUlf Lilleengen mtx_assert(EXT2_MTX(pip->i_ump), MA_OWNED); 437e09c00caSUlf Lilleengen fs = pip->i_e2fs; 438e09c00caSUlf Lilleengen 439e09c00caSUlf Lilleengen avgifree = fs->e2fs->e2fs_ficount / fs->e2fs_gcount; 440e09c00caSUlf Lilleengen avgbfree = fs->e2fs->e2fs_fbcount / fs->e2fs_gcount; 441e09c00caSUlf Lilleengen avgndir = fs->e2fs_total_dir / fs->e2fs_gcount; 442e09c00caSUlf Lilleengen 443e09c00caSUlf Lilleengen /* 444e09c00caSUlf Lilleengen * Force allocation in another cg if creating a first level dir. 445e09c00caSUlf Lilleengen */ 446e09c00caSUlf Lilleengen ASSERT_VOP_LOCKED(ITOV(pip), "ext2fs_dirpref"); 447e09c00caSUlf Lilleengen if (ITOV(pip)->v_vflag & VV_ROOT) { 448e09c00caSUlf Lilleengen prefcg = arc4random() % fs->e2fs_gcount; 449e09c00caSUlf Lilleengen mincg = prefcg; 450e09c00caSUlf Lilleengen minndir = fs->e2fs_ipg; 451e09c00caSUlf Lilleengen for (cg = prefcg; cg < fs->e2fs_gcount; cg++) 452e09c00caSUlf Lilleengen if (fs->e2fs_gd[cg].ext2bgd_ndirs < minndir && 453e09c00caSUlf Lilleengen fs->e2fs_gd[cg].ext2bgd_nifree >= avgifree && 454e09c00caSUlf Lilleengen fs->e2fs_gd[cg].ext2bgd_nbfree >= avgbfree) { 455e09c00caSUlf Lilleengen mincg = cg; 456e09c00caSUlf Lilleengen minndir = fs->e2fs_gd[cg].ext2bgd_ndirs; 457e09c00caSUlf Lilleengen } 458e09c00caSUlf Lilleengen for (cg = 0; cg < prefcg; cg++) 459e09c00caSUlf Lilleengen if (fs->e2fs_gd[cg].ext2bgd_ndirs < minndir && 460e09c00caSUlf Lilleengen fs->e2fs_gd[cg].ext2bgd_nifree >= avgifree && 461e09c00caSUlf Lilleengen fs->e2fs_gd[cg].ext2bgd_nbfree >= avgbfree) { 462e09c00caSUlf Lilleengen mincg = cg; 463e09c00caSUlf Lilleengen minndir = fs->e2fs_gd[cg].ext2bgd_ndirs; 464e09c00caSUlf Lilleengen } 465e09c00caSUlf Lilleengen 466e09c00caSUlf Lilleengen return (mincg); 467e09c00caSUlf Lilleengen } 468e09c00caSUlf Lilleengen 469e09c00caSUlf Lilleengen /* 470e09c00caSUlf Lilleengen * Count various limits which used for 471e09c00caSUlf Lilleengen * optimal allocation of a directory inode. 472e09c00caSUlf Lilleengen */ 473e09c00caSUlf Lilleengen maxndir = min(avgndir + fs->e2fs_ipg / 16, fs->e2fs_ipg); 474e09c00caSUlf Lilleengen minifree = avgifree - avgifree / 4; 475e09c00caSUlf Lilleengen if (minifree < 1) 476e09c00caSUlf Lilleengen minifree = 1; 477e09c00caSUlf Lilleengen minbfree = avgbfree - avgbfree / 4; 478e09c00caSUlf Lilleengen if (minbfree < 1) 479e09c00caSUlf Lilleengen minbfree = 1; 480e09c00caSUlf Lilleengen cgsize = fs->e2fs_fsize * fs->e2fs_fpg; 481e09c00caSUlf Lilleengen dirsize = AVGDIRSIZE; 482e09c00caSUlf Lilleengen curdirsize = avgndir ? (cgsize - avgbfree * fs->e2fs_bsize) / avgndir : 0; 483e09c00caSUlf Lilleengen if (dirsize < curdirsize) 484e09c00caSUlf Lilleengen dirsize = curdirsize; 485e09c00caSUlf Lilleengen if (dirsize <= 0) 486e09c00caSUlf Lilleengen maxcontigdirs = 0; /* dirsize overflowed */ 487e09c00caSUlf Lilleengen else 488e09c00caSUlf Lilleengen maxcontigdirs = min((avgbfree * fs->e2fs_bsize) / dirsize, 255); 489e09c00caSUlf Lilleengen maxcontigdirs = min(maxcontigdirs, fs->e2fs_ipg / AFPDIR); 490e09c00caSUlf Lilleengen if (maxcontigdirs == 0) 491e09c00caSUlf Lilleengen maxcontigdirs = 1; 492e09c00caSUlf Lilleengen 493e09c00caSUlf Lilleengen /* 494e09c00caSUlf Lilleengen * Limit number of dirs in one cg and reserve space for 495e09c00caSUlf Lilleengen * regular files, but only if we have no deficit in 496e09c00caSUlf Lilleengen * inodes or space. 497e09c00caSUlf Lilleengen */ 498e09c00caSUlf Lilleengen prefcg = ino_to_cg(fs, pip->i_number); 499e09c00caSUlf Lilleengen for (cg = prefcg; cg < fs->e2fs_gcount; cg++) 500e09c00caSUlf Lilleengen if (fs->e2fs_gd[cg].ext2bgd_ndirs < maxndir && 501e09c00caSUlf Lilleengen fs->e2fs_gd[cg].ext2bgd_nifree >= minifree && 502e09c00caSUlf Lilleengen fs->e2fs_gd[cg].ext2bgd_nbfree >= minbfree) { 503e09c00caSUlf Lilleengen if (fs->e2fs_contigdirs[cg] < maxcontigdirs) 504e09c00caSUlf Lilleengen return (cg); 505e09c00caSUlf Lilleengen } 506e09c00caSUlf Lilleengen for (cg = 0; cg < prefcg; cg++) 507e09c00caSUlf Lilleengen if (fs->e2fs_gd[cg].ext2bgd_ndirs < maxndir && 508e09c00caSUlf Lilleengen fs->e2fs_gd[cg].ext2bgd_nifree >= minifree && 509e09c00caSUlf Lilleengen fs->e2fs_gd[cg].ext2bgd_nbfree >= minbfree) { 510e09c00caSUlf Lilleengen if (fs->e2fs_contigdirs[cg] < maxcontigdirs) 511e09c00caSUlf Lilleengen return (cg); 512e09c00caSUlf Lilleengen } 513e09c00caSUlf Lilleengen /* 514e09c00caSUlf Lilleengen * This is a backstop when we have deficit in space. 515e09c00caSUlf Lilleengen */ 516e09c00caSUlf Lilleengen for (cg = prefcg; cg < fs->e2fs_gcount; cg++) 517e09c00caSUlf Lilleengen if (fs->e2fs_gd[cg].ext2bgd_nifree >= avgifree) 518e09c00caSUlf Lilleengen return (cg); 519e09c00caSUlf Lilleengen for (cg = 0; cg < prefcg; cg++) 520e09c00caSUlf Lilleengen if (fs->e2fs_gd[cg].ext2bgd_nifree >= avgifree) 521e09c00caSUlf Lilleengen break; 522e09c00caSUlf Lilleengen return (cg); 523e09c00caSUlf Lilleengen } 524e09c00caSUlf Lilleengen 525e09c00caSUlf Lilleengen /* 526e09c00caSUlf Lilleengen * Select the desired position for the next block in a file. 527e09c00caSUlf Lilleengen * 528e09c00caSUlf Lilleengen * we try to mimic what Remy does in inode_getblk/block_getblk 529e09c00caSUlf Lilleengen * 530e09c00caSUlf Lilleengen * we note: blocknr == 0 means that we're about to allocate either 531e09c00caSUlf Lilleengen * a direct block or a pointer block at the first level of indirection 532e09c00caSUlf Lilleengen * (In other words, stuff that will go in i_db[] or i_ib[]) 533e09c00caSUlf Lilleengen * 534e09c00caSUlf Lilleengen * blocknr != 0 means that we're allocating a block that is none 535e09c00caSUlf Lilleengen * of the above. Then, blocknr tells us the number of the block 536e09c00caSUlf Lilleengen * that will hold the pointer 537e09c00caSUlf Lilleengen */ 538e09c00caSUlf Lilleengen int32_t 539e09c00caSUlf Lilleengen ext2_blkpref(ip, lbn, indx, bap, blocknr) 540e09c00caSUlf Lilleengen struct inode *ip; 541e09c00caSUlf Lilleengen int32_t lbn; 542e09c00caSUlf Lilleengen int indx; 543e09c00caSUlf Lilleengen int32_t *bap; 544e09c00caSUlf Lilleengen int32_t blocknr; 545e09c00caSUlf Lilleengen { 546e09c00caSUlf Lilleengen int tmp; 547e09c00caSUlf Lilleengen mtx_assert(EXT2_MTX(ip->i_ump), MA_OWNED); 548e09c00caSUlf Lilleengen 549e09c00caSUlf Lilleengen /* if the next block is actually what we thought it is, 550e09c00caSUlf Lilleengen then set the goal to what we thought it should be 551e09c00caSUlf Lilleengen */ 552e09c00caSUlf Lilleengen if(ip->i_next_alloc_block == lbn && ip->i_next_alloc_goal != 0) 553e09c00caSUlf Lilleengen return ip->i_next_alloc_goal; 554e09c00caSUlf Lilleengen 555e09c00caSUlf Lilleengen /* now check whether we were provided with an array that basically 556e09c00caSUlf Lilleengen tells us previous blocks to which we want to stay closeby 557e09c00caSUlf Lilleengen */ 558e09c00caSUlf Lilleengen if(bap) 559e09c00caSUlf Lilleengen for (tmp = indx - 1; tmp >= 0; tmp--) 560e09c00caSUlf Lilleengen if (bap[tmp]) 561e09c00caSUlf Lilleengen return bap[tmp]; 562e09c00caSUlf Lilleengen 563e09c00caSUlf Lilleengen /* else let's fall back to the blocknr, or, if there is none, 564e09c00caSUlf Lilleengen follow the rule that a block should be allocated near its inode 565e09c00caSUlf Lilleengen */ 566e09c00caSUlf Lilleengen return blocknr ? blocknr : 567e09c00caSUlf Lilleengen (int32_t)(ip->i_block_group * 568e09c00caSUlf Lilleengen EXT2_BLOCKS_PER_GROUP(ip->i_e2fs)) + 569e09c00caSUlf Lilleengen ip->i_e2fs->e2fs->e2fs_first_dblock; 570e09c00caSUlf Lilleengen } 571e09c00caSUlf Lilleengen 572e09c00caSUlf Lilleengen /* 573e09c00caSUlf Lilleengen * Implement the cylinder overflow algorithm. 574e09c00caSUlf Lilleengen * 575e09c00caSUlf Lilleengen * The policy implemented by this algorithm is: 576e09c00caSUlf Lilleengen * 1) allocate the block in its requested cylinder group. 577e09c00caSUlf Lilleengen * 2) quadradically rehash on the cylinder group number. 578e09c00caSUlf Lilleengen * 3) brute force search for a free block. 579e09c00caSUlf Lilleengen */ 580e09c00caSUlf Lilleengen static u_long 581e09c00caSUlf Lilleengen ext2_hashalloc(struct inode *ip, int cg, long pref, int size, 582e09c00caSUlf Lilleengen daddr_t (*allocator)(struct inode *, int, daddr_t, int)) 583e09c00caSUlf Lilleengen { 584e09c00caSUlf Lilleengen struct m_ext2fs *fs; 585e09c00caSUlf Lilleengen ino_t result; 586e09c00caSUlf Lilleengen int i, icg = cg; 587e09c00caSUlf Lilleengen 588e09c00caSUlf Lilleengen mtx_assert(EXT2_MTX(ip->i_ump), MA_OWNED); 589e09c00caSUlf Lilleengen fs = ip->i_e2fs; 590e09c00caSUlf Lilleengen /* 591e09c00caSUlf Lilleengen * 1: preferred cylinder group 592e09c00caSUlf Lilleengen */ 593e09c00caSUlf Lilleengen result = (*allocator)(ip, cg, pref, size); 594e09c00caSUlf Lilleengen if (result) 595e09c00caSUlf Lilleengen return (result); 596e09c00caSUlf Lilleengen /* 597e09c00caSUlf Lilleengen * 2: quadratic rehash 598e09c00caSUlf Lilleengen */ 599e09c00caSUlf Lilleengen for (i = 1; i < fs->e2fs_gcount; i *= 2) { 600e09c00caSUlf Lilleengen cg += i; 601e09c00caSUlf Lilleengen if (cg >= fs->e2fs_gcount) 602e09c00caSUlf Lilleengen cg -= fs->e2fs_gcount; 603e09c00caSUlf Lilleengen result = (*allocator)(ip, cg, 0, size); 604e09c00caSUlf Lilleengen if (result) 605e09c00caSUlf Lilleengen return (result); 606e09c00caSUlf Lilleengen } 607e09c00caSUlf Lilleengen /* 608e09c00caSUlf Lilleengen * 3: brute force search 609e09c00caSUlf Lilleengen * Note that we start at i == 2, since 0 was checked initially, 610e09c00caSUlf Lilleengen * and 1 is always checked in the quadratic rehash. 611e09c00caSUlf Lilleengen */ 612e09c00caSUlf Lilleengen cg = (icg + 2) % fs->e2fs_gcount; 613e09c00caSUlf Lilleengen for (i = 2; i < fs->e2fs_gcount; i++) { 614e09c00caSUlf Lilleengen result = (*allocator)(ip, cg, 0, size); 615e09c00caSUlf Lilleengen if (result) 616e09c00caSUlf Lilleengen return (result); 617e09c00caSUlf Lilleengen cg++; 618e09c00caSUlf Lilleengen if (cg == fs->e2fs_gcount) 619e09c00caSUlf Lilleengen cg = 0; 620e09c00caSUlf Lilleengen } 621e09c00caSUlf Lilleengen return (0); 622e09c00caSUlf Lilleengen } 623e09c00caSUlf Lilleengen 624e09c00caSUlf Lilleengen /* 625e09c00caSUlf Lilleengen * Determine whether a block can be allocated. 626e09c00caSUlf Lilleengen * 627e09c00caSUlf Lilleengen * Check to see if a block of the appropriate size is available, 628e09c00caSUlf Lilleengen * and if it is, allocate it. 629e09c00caSUlf Lilleengen */ 630e09c00caSUlf Lilleengen static daddr_t 631e09c00caSUlf Lilleengen ext2_alloccg(struct inode *ip, int cg, daddr_t bpref, int size) 632e09c00caSUlf Lilleengen { 633e09c00caSUlf Lilleengen struct m_ext2fs *fs; 634e09c00caSUlf Lilleengen struct buf *bp; 635e09c00caSUlf Lilleengen struct ext2mount *ump; 636*c767faa5SJohn Baldwin daddr_t bno, runstart, runlen; 637*c767faa5SJohn Baldwin int bit, loc, end, error, start; 638e09c00caSUlf Lilleengen char *bbp; 639e09c00caSUlf Lilleengen /* XXX ondisk32 */ 640e09c00caSUlf Lilleengen fs = ip->i_e2fs; 641e09c00caSUlf Lilleengen ump = ip->i_ump; 642e09c00caSUlf Lilleengen if (fs->e2fs_gd[cg].ext2bgd_nbfree == 0) 643e09c00caSUlf Lilleengen return (0); 644e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 645e09c00caSUlf Lilleengen error = bread(ip->i_devvp, fsbtodb(fs, 646e09c00caSUlf Lilleengen fs->e2fs_gd[cg].ext2bgd_b_bitmap), 647e09c00caSUlf Lilleengen (int)fs->e2fs_bsize, NOCRED, &bp); 648e09c00caSUlf Lilleengen if (error) { 649e09c00caSUlf Lilleengen brelse(bp); 650e09c00caSUlf Lilleengen EXT2_LOCK(ump); 651e09c00caSUlf Lilleengen return (0); 652e09c00caSUlf Lilleengen } 653e09c00caSUlf Lilleengen bbp = (char *)bp->b_data; 654e09c00caSUlf Lilleengen 655e09c00caSUlf Lilleengen if (dtog(fs, bpref) != cg) 656e09c00caSUlf Lilleengen bpref = 0; 657e09c00caSUlf Lilleengen if (bpref != 0) { 658e09c00caSUlf Lilleengen bpref = dtogd(fs, bpref); 659e09c00caSUlf Lilleengen /* 660e09c00caSUlf Lilleengen * if the requested block is available, use it 661e09c00caSUlf Lilleengen */ 662e09c00caSUlf Lilleengen if (isclr(bbp, bpref)) { 663e09c00caSUlf Lilleengen bno = bpref; 664e09c00caSUlf Lilleengen goto gotit; 665e09c00caSUlf Lilleengen } 666e09c00caSUlf Lilleengen } 667e09c00caSUlf Lilleengen /* 668e09c00caSUlf Lilleengen * no blocks in the requested cylinder, so take next 669e09c00caSUlf Lilleengen * available one in this cylinder group. 670e09c00caSUlf Lilleengen * first try to get 8 contigous blocks, then fall back to a single 671e09c00caSUlf Lilleengen * block. 672e09c00caSUlf Lilleengen */ 673e09c00caSUlf Lilleengen if (bpref) 674e09c00caSUlf Lilleengen start = dtogd(fs, bpref) / NBBY; 675e09c00caSUlf Lilleengen else 676e09c00caSUlf Lilleengen start = 0; 677e09c00caSUlf Lilleengen end = howmany(fs->e2fs->e2fs_fpg, NBBY) - start; 678*c767faa5SJohn Baldwin retry: 679*c767faa5SJohn Baldwin runlen = 0; 680*c767faa5SJohn Baldwin runstart = 0; 681e09c00caSUlf Lilleengen for (loc = start; loc < end; loc++) { 682*c767faa5SJohn Baldwin if (bbp[loc] == (char)0xff) { 683*c767faa5SJohn Baldwin runlen = 0; 684*c767faa5SJohn Baldwin continue; 685*c767faa5SJohn Baldwin } 686*c767faa5SJohn Baldwin 687*c767faa5SJohn Baldwin /* Start of a run, find the number of high clear bits. */ 688*c767faa5SJohn Baldwin if (runlen == 0) { 689*c767faa5SJohn Baldwin bit = fls(bbp[loc]); 690*c767faa5SJohn Baldwin runlen = NBBY - bit; 691*c767faa5SJohn Baldwin runstart = loc * NBBY + bit; 692*c767faa5SJohn Baldwin } else if (bbp[loc] == 0) { 693*c767faa5SJohn Baldwin /* Continue a run. */ 694*c767faa5SJohn Baldwin runlen += NBBY; 695*c767faa5SJohn Baldwin } else { 696*c767faa5SJohn Baldwin /* 697*c767faa5SJohn Baldwin * Finish the current run. If it isn't long 698*c767faa5SJohn Baldwin * enough, start a new one. 699*c767faa5SJohn Baldwin */ 700*c767faa5SJohn Baldwin bit = ffs(bbp[loc]) - 1; 701*c767faa5SJohn Baldwin runlen += bit; 702*c767faa5SJohn Baldwin if (runlen >= 8) { 703*c767faa5SJohn Baldwin bno = runstart; 704*c767faa5SJohn Baldwin goto gotit; 705*c767faa5SJohn Baldwin } 706*c767faa5SJohn Baldwin 707*c767faa5SJohn Baldwin /* Run was too short, start a new one. */ 708*c767faa5SJohn Baldwin bit = fls(bbp[loc]); 709*c767faa5SJohn Baldwin runlen = NBBY - bit; 710*c767faa5SJohn Baldwin runstart = loc * NBBY + bit; 711*c767faa5SJohn Baldwin } 712*c767faa5SJohn Baldwin 713*c767faa5SJohn Baldwin /* If the current run is long enough, use it. */ 714*c767faa5SJohn Baldwin if (runlen >= 8) { 715*c767faa5SJohn Baldwin bno = runstart; 716e09c00caSUlf Lilleengen goto gotit; 717e09c00caSUlf Lilleengen } 718e09c00caSUlf Lilleengen } 719*c767faa5SJohn Baldwin if (start != 0) { 720*c767faa5SJohn Baldwin end = start; 721*c767faa5SJohn Baldwin start = 0; 722*c767faa5SJohn Baldwin goto retry; 723e09c00caSUlf Lilleengen } 724e09c00caSUlf Lilleengen 725e09c00caSUlf Lilleengen bno = ext2_mapsearch(fs, bbp, bpref); 726e09c00caSUlf Lilleengen if (bno < 0){ 727e09c00caSUlf Lilleengen brelse(bp); 728e09c00caSUlf Lilleengen EXT2_LOCK(ump); 729e09c00caSUlf Lilleengen return (0); 730e09c00caSUlf Lilleengen } 731e09c00caSUlf Lilleengen gotit: 732e09c00caSUlf Lilleengen #ifdef DIAGNOSTIC 733e09c00caSUlf Lilleengen if (isset(bbp, (daddr_t)bno)) { 734e09c00caSUlf Lilleengen printf("ext2fs_alloccgblk: cg=%d bno=%d fs=%s\n", 735e09c00caSUlf Lilleengen cg, bno, fs->e2fs_fsmnt); 736e09c00caSUlf Lilleengen panic("ext2fs_alloccg: dup alloc"); 737e09c00caSUlf Lilleengen } 738e09c00caSUlf Lilleengen #endif 739e09c00caSUlf Lilleengen setbit(bbp, (daddr_t)bno); 740e09c00caSUlf Lilleengen EXT2_LOCK(ump); 741e09c00caSUlf Lilleengen fs->e2fs->e2fs_fbcount--; 742e09c00caSUlf Lilleengen fs->e2fs_gd[cg].ext2bgd_nbfree--; 743e09c00caSUlf Lilleengen fs->e2fs_fmod = 1; 744e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 745e09c00caSUlf Lilleengen bdwrite(bp); 746e09c00caSUlf Lilleengen return (cg * fs->e2fs->e2fs_fpg + fs->e2fs->e2fs_first_dblock + bno); 747e09c00caSUlf Lilleengen } 748e09c00caSUlf Lilleengen 749e09c00caSUlf Lilleengen /* 750e09c00caSUlf Lilleengen * Determine whether an inode can be allocated. 751e09c00caSUlf Lilleengen * 752e09c00caSUlf Lilleengen * Check to see if an inode is available, and if it is, 753e09c00caSUlf Lilleengen * allocate it using tode in the specified cylinder group. 754e09c00caSUlf Lilleengen */ 755e09c00caSUlf Lilleengen static daddr_t 756e09c00caSUlf Lilleengen ext2_nodealloccg(struct inode *ip, int cg, daddr_t ipref, int mode) 757e09c00caSUlf Lilleengen { 758e09c00caSUlf Lilleengen struct m_ext2fs *fs; 759e09c00caSUlf Lilleengen struct buf *bp; 760e09c00caSUlf Lilleengen struct ext2mount *ump; 761e09c00caSUlf Lilleengen int error, start, len, loc, map, i; 762e09c00caSUlf Lilleengen char *ibp; 763e09c00caSUlf Lilleengen ipref--; /* to avoid a lot of (ipref -1) */ 764e09c00caSUlf Lilleengen if (ipref == -1) 765e09c00caSUlf Lilleengen ipref = 0; 766e09c00caSUlf Lilleengen fs = ip->i_e2fs; 767e09c00caSUlf Lilleengen ump = ip->i_ump; 768e09c00caSUlf Lilleengen if (fs->e2fs_gd[cg].ext2bgd_nifree == 0) 769e09c00caSUlf Lilleengen return (0); 770e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 771e09c00caSUlf Lilleengen error = bread(ip->i_devvp, fsbtodb(fs, 772e09c00caSUlf Lilleengen fs->e2fs_gd[cg].ext2bgd_i_bitmap), 773e09c00caSUlf Lilleengen (int)fs->e2fs_bsize, NOCRED, &bp); 774e09c00caSUlf Lilleengen if (error) { 775e09c00caSUlf Lilleengen brelse(bp); 776e09c00caSUlf Lilleengen EXT2_LOCK(ump); 777e09c00caSUlf Lilleengen return (0); 778e09c00caSUlf Lilleengen } 779e09c00caSUlf Lilleengen ibp = (char *)bp->b_data; 780e09c00caSUlf Lilleengen if (ipref) { 781e09c00caSUlf Lilleengen ipref %= fs->e2fs->e2fs_ipg; 782e09c00caSUlf Lilleengen if (isclr(ibp, ipref)) 783e09c00caSUlf Lilleengen goto gotit; 784e09c00caSUlf Lilleengen } 785e09c00caSUlf Lilleengen start = ipref / NBBY; 786e09c00caSUlf Lilleengen len = howmany(fs->e2fs->e2fs_ipg - ipref, NBBY); 787e09c00caSUlf Lilleengen loc = skpc(0xff, len, &ibp[start]); 788e09c00caSUlf Lilleengen if (loc == 0) { 789e09c00caSUlf Lilleengen len = start + 1; 790e09c00caSUlf Lilleengen start = 0; 791e09c00caSUlf Lilleengen loc = skpc(0xff, len, &ibp[0]); 792e09c00caSUlf Lilleengen if (loc == 0) { 793e09c00caSUlf Lilleengen printf("cg = %d, ipref = %lld, fs = %s\n", 794e09c00caSUlf Lilleengen cg, (long long)ipref, fs->e2fs_fsmnt); 795e09c00caSUlf Lilleengen panic("ext2fs_nodealloccg: map corrupted"); 796e09c00caSUlf Lilleengen /* NOTREACHED */ 797e09c00caSUlf Lilleengen } 798e09c00caSUlf Lilleengen } 799e09c00caSUlf Lilleengen i = start + len - loc; 800e09c00caSUlf Lilleengen map = ibp[i]; 801e09c00caSUlf Lilleengen ipref = i * NBBY; 802e09c00caSUlf Lilleengen for (i = 1; i < (1 << NBBY); i <<= 1, ipref++) { 803e09c00caSUlf Lilleengen if ((map & i) == 0) { 804e09c00caSUlf Lilleengen goto gotit; 805e09c00caSUlf Lilleengen } 806e09c00caSUlf Lilleengen } 807e09c00caSUlf Lilleengen printf("fs = %s\n", fs->e2fs_fsmnt); 808e09c00caSUlf Lilleengen panic("ext2fs_nodealloccg: block not in map"); 809e09c00caSUlf Lilleengen /* NOTREACHED */ 810e09c00caSUlf Lilleengen gotit: 811e09c00caSUlf Lilleengen setbit(ibp, ipref); 812e09c00caSUlf Lilleengen EXT2_LOCK(ump); 813e09c00caSUlf Lilleengen fs->e2fs_gd[cg].ext2bgd_nifree--; 814e09c00caSUlf Lilleengen fs->e2fs->e2fs_ficount--; 815e09c00caSUlf Lilleengen fs->e2fs_fmod = 1; 816e09c00caSUlf Lilleengen if ((mode & IFMT) == IFDIR) { 817e09c00caSUlf Lilleengen fs->e2fs_gd[cg].ext2bgd_ndirs++; 818e09c00caSUlf Lilleengen fs->e2fs_total_dir++; 819e09c00caSUlf Lilleengen } 820e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 821e09c00caSUlf Lilleengen bdwrite(bp); 822e09c00caSUlf Lilleengen return (cg * fs->e2fs->e2fs_ipg + ipref +1); 823e09c00caSUlf Lilleengen } 824e09c00caSUlf Lilleengen 825e09c00caSUlf Lilleengen /* 826e09c00caSUlf Lilleengen * Free a block or fragment. 827e09c00caSUlf Lilleengen * 828e09c00caSUlf Lilleengen */ 829e09c00caSUlf Lilleengen void 830e09c00caSUlf Lilleengen ext2_blkfree(ip, bno, size) 831e09c00caSUlf Lilleengen struct inode *ip; 832e09c00caSUlf Lilleengen int32_t bno; 833e09c00caSUlf Lilleengen long size; 834e09c00caSUlf Lilleengen { 835e09c00caSUlf Lilleengen struct m_ext2fs *fs; 836e09c00caSUlf Lilleengen struct buf *bp; 837e09c00caSUlf Lilleengen struct ext2mount *ump; 838e09c00caSUlf Lilleengen int cg, error; 839e09c00caSUlf Lilleengen char *bbp; 840e09c00caSUlf Lilleengen 841e09c00caSUlf Lilleengen fs = ip->i_e2fs; 842e09c00caSUlf Lilleengen ump = ip->i_ump; 843e09c00caSUlf Lilleengen cg = dtog(fs, bno); 844e09c00caSUlf Lilleengen if ((u_int)bno >= fs->e2fs->e2fs_bcount) { 845e09c00caSUlf Lilleengen printf("bad block %lld, ino %llu\n", (long long)bno, 846e09c00caSUlf Lilleengen (unsigned long long)ip->i_number); 847e09c00caSUlf Lilleengen ext2_fserr(fs, ip->i_uid, "bad block"); 848e09c00caSUlf Lilleengen return; 849e09c00caSUlf Lilleengen } 850e09c00caSUlf Lilleengen error = bread(ip->i_devvp, 851e09c00caSUlf Lilleengen fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_b_bitmap), 852e09c00caSUlf Lilleengen (int)fs->e2fs_bsize, NOCRED, &bp); 853e09c00caSUlf Lilleengen if (error) { 854e09c00caSUlf Lilleengen brelse(bp); 855e09c00caSUlf Lilleengen return; 856e09c00caSUlf Lilleengen } 857e09c00caSUlf Lilleengen bbp = (char *)bp->b_data; 858e09c00caSUlf Lilleengen bno = dtogd(fs, bno); 859e09c00caSUlf Lilleengen if (isclr(bbp, bno)) { 860e09c00caSUlf Lilleengen printf("block = %lld, fs = %s\n", 861e09c00caSUlf Lilleengen (long long)bno, fs->e2fs_fsmnt); 862e09c00caSUlf Lilleengen panic("blkfree: freeing free block"); 863e09c00caSUlf Lilleengen } 864e09c00caSUlf Lilleengen clrbit(bbp, bno); 865e09c00caSUlf Lilleengen EXT2_LOCK(ump); 866e09c00caSUlf Lilleengen fs->e2fs->e2fs_fbcount++; 867e09c00caSUlf Lilleengen fs->e2fs_gd[cg].ext2bgd_nbfree++; 868e09c00caSUlf Lilleengen fs->e2fs_fmod = 1; 869e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 870e09c00caSUlf Lilleengen bdwrite(bp); 871e09c00caSUlf Lilleengen } 872e09c00caSUlf Lilleengen 873e09c00caSUlf Lilleengen /* 874e09c00caSUlf Lilleengen * Free an inode. 875e09c00caSUlf Lilleengen * 876e09c00caSUlf Lilleengen */ 877e09c00caSUlf Lilleengen int 878e09c00caSUlf Lilleengen ext2_vfree(pvp, ino, mode) 879e09c00caSUlf Lilleengen struct vnode *pvp; 880e09c00caSUlf Lilleengen ino_t ino; 881e09c00caSUlf Lilleengen int mode; 882e09c00caSUlf Lilleengen { 883e09c00caSUlf Lilleengen struct m_ext2fs *fs; 884e09c00caSUlf Lilleengen struct inode *pip; 885e09c00caSUlf Lilleengen struct buf *bp; 886e09c00caSUlf Lilleengen struct ext2mount *ump; 887e09c00caSUlf Lilleengen int error, cg; 888e09c00caSUlf Lilleengen char * ibp; 889e09c00caSUlf Lilleengen /* mode_t save_i_mode; */ 890e09c00caSUlf Lilleengen 891e09c00caSUlf Lilleengen pip = VTOI(pvp); 892e09c00caSUlf Lilleengen fs = pip->i_e2fs; 893e09c00caSUlf Lilleengen ump = pip->i_ump; 894e09c00caSUlf Lilleengen if ((u_int)ino > fs->e2fs_ipg * fs->e2fs_gcount) 895e09c00caSUlf Lilleengen panic("ext2_vfree: range: devvp = %p, ino = %d, fs = %s", 896e09c00caSUlf Lilleengen pip->i_devvp, ino, fs->e2fs_fsmnt); 897e09c00caSUlf Lilleengen 898e09c00caSUlf Lilleengen cg = ino_to_cg(fs, ino); 899e09c00caSUlf Lilleengen error = bread(pip->i_devvp, 900e09c00caSUlf Lilleengen fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_i_bitmap), 901e09c00caSUlf Lilleengen (int)fs->e2fs_bsize, NOCRED, &bp); 902e09c00caSUlf Lilleengen if (error) { 903e09c00caSUlf Lilleengen brelse(bp); 904e09c00caSUlf Lilleengen return (0); 905e09c00caSUlf Lilleengen } 906e09c00caSUlf Lilleengen ibp = (char *)bp->b_data; 907e09c00caSUlf Lilleengen ino = (ino - 1) % fs->e2fs->e2fs_ipg; 908e09c00caSUlf Lilleengen if (isclr(ibp, ino)) { 909e09c00caSUlf Lilleengen printf("ino = %llu, fs = %s\n", 910e09c00caSUlf Lilleengen (unsigned long long)ino, fs->e2fs_fsmnt); 911e09c00caSUlf Lilleengen if (fs->e2fs_ronly == 0) 912e09c00caSUlf Lilleengen panic("ifree: freeing free inode"); 913e09c00caSUlf Lilleengen } 914e09c00caSUlf Lilleengen clrbit(ibp, ino); 915e09c00caSUlf Lilleengen EXT2_LOCK(ump); 916e09c00caSUlf Lilleengen fs->e2fs->e2fs_ficount++; 917e09c00caSUlf Lilleengen fs->e2fs_gd[cg].ext2bgd_nifree++; 918e09c00caSUlf Lilleengen if ((mode & IFMT) == IFDIR) { 919e09c00caSUlf Lilleengen fs->e2fs_gd[cg].ext2bgd_ndirs--; 920e09c00caSUlf Lilleengen fs->e2fs_total_dir--; 921e09c00caSUlf Lilleengen } 922e09c00caSUlf Lilleengen fs->e2fs_fmod = 1; 923e09c00caSUlf Lilleengen EXT2_UNLOCK(ump); 924e09c00caSUlf Lilleengen bdwrite(bp); 925e09c00caSUlf Lilleengen return (0); 926e09c00caSUlf Lilleengen } 927e09c00caSUlf Lilleengen 928e09c00caSUlf Lilleengen /* 929e09c00caSUlf Lilleengen * Find a block in the specified cylinder group. 930e09c00caSUlf Lilleengen * 931e09c00caSUlf Lilleengen * It is a panic if a request is made to find a block if none are 932e09c00caSUlf Lilleengen * available. 933e09c00caSUlf Lilleengen */ 934e09c00caSUlf Lilleengen static daddr_t 935e09c00caSUlf Lilleengen ext2_mapsearch(struct m_ext2fs *fs, char *bbp, daddr_t bpref) 936e09c00caSUlf Lilleengen { 937e09c00caSUlf Lilleengen daddr_t bno; 938e09c00caSUlf Lilleengen int start, len, loc, i, map; 939e09c00caSUlf Lilleengen 940e09c00caSUlf Lilleengen /* 941e09c00caSUlf Lilleengen * find the fragment by searching through the free block 942e09c00caSUlf Lilleengen * map for an appropriate bit pattern 943e09c00caSUlf Lilleengen */ 944e09c00caSUlf Lilleengen if (bpref) 945e09c00caSUlf Lilleengen start = dtogd(fs, bpref) / NBBY; 946e09c00caSUlf Lilleengen else 947e09c00caSUlf Lilleengen start = 0; 948e09c00caSUlf Lilleengen len = howmany(fs->e2fs->e2fs_fpg, NBBY) - start; 949e09c00caSUlf Lilleengen loc = skpc(0xff, len, &bbp[start]); 950e09c00caSUlf Lilleengen if (loc == 0) { 951e09c00caSUlf Lilleengen len = start + 1; 952e09c00caSUlf Lilleengen start = 0; 953e09c00caSUlf Lilleengen loc = skpc(0xff, len, &bbp[start]); 954e09c00caSUlf Lilleengen if (loc == 0) { 955e09c00caSUlf Lilleengen printf("start = %d, len = %d, fs = %s\n", 956e09c00caSUlf Lilleengen start, len, fs->e2fs_fsmnt); 957e09c00caSUlf Lilleengen panic("ext2fs_alloccg: map corrupted"); 958e09c00caSUlf Lilleengen /* NOTREACHED */ 959e09c00caSUlf Lilleengen } 960e09c00caSUlf Lilleengen } 961e09c00caSUlf Lilleengen i = start + len - loc; 962e09c00caSUlf Lilleengen map = bbp[i]; 963e09c00caSUlf Lilleengen bno = i * NBBY; 964e09c00caSUlf Lilleengen for (i = 1; i < (1 << NBBY); i <<= 1, bno++) { 965e09c00caSUlf Lilleengen if ((map & i) == 0) 966e09c00caSUlf Lilleengen return (bno); 967e09c00caSUlf Lilleengen } 968e09c00caSUlf Lilleengen printf("fs = %s\n", fs->e2fs_fsmnt); 969e09c00caSUlf Lilleengen panic("ext2fs_mapsearch: block not in map"); 970e09c00caSUlf Lilleengen /* NOTREACHED */ 971e09c00caSUlf Lilleengen } 972e09c00caSUlf Lilleengen 973e09c00caSUlf Lilleengen /* 974e09c00caSUlf Lilleengen * Fserr prints the name of a file system with an error diagnostic. 975e09c00caSUlf Lilleengen * 976e09c00caSUlf Lilleengen * The form of the error message is: 977e09c00caSUlf Lilleengen * fs: error message 978e09c00caSUlf Lilleengen */ 979e09c00caSUlf Lilleengen static void 980e09c00caSUlf Lilleengen ext2_fserr(fs, uid, cp) 981e09c00caSUlf Lilleengen struct m_ext2fs *fs; 982e09c00caSUlf Lilleengen uid_t uid; 983e09c00caSUlf Lilleengen char *cp; 984e09c00caSUlf Lilleengen { 985e09c00caSUlf Lilleengen 986e09c00caSUlf Lilleengen log(LOG_ERR, "uid %u on %s: %s\n", uid, fs->e2fs_fsmnt, cp); 987e09c00caSUlf Lilleengen } 988e09c00caSUlf Lilleengen 989e09c00caSUlf Lilleengen int 990e09c00caSUlf Lilleengen cg_has_sb(int i) 991e09c00caSUlf Lilleengen { 992e09c00caSUlf Lilleengen int a3, a5, a7; 993e09c00caSUlf Lilleengen 994e09c00caSUlf Lilleengen if (i == 0 || i == 1) 995e09c00caSUlf Lilleengen return 1; 996e09c00caSUlf Lilleengen for (a3 = 3, a5 = 5, a7 = 7; 997e09c00caSUlf Lilleengen a3 <= i || a5 <= i || a7 <= i; 998e09c00caSUlf Lilleengen a3 *= 3, a5 *= 5, a7 *= 7) 999e09c00caSUlf Lilleengen if (i == a3 || i == a5 || i == a7) 1000e09c00caSUlf Lilleengen return 1; 1001e09c00caSUlf Lilleengen return 0; 1002e09c00caSUlf Lilleengen } 1003