ffs_alloc.c revision 203763
1139825Simp/*- 298542Smckusick * Copyright (c) 2002 Networks Associates Technology, Inc. 398542Smckusick * All rights reserved. 498542Smckusick * 598542Smckusick * This software was developed for the FreeBSD Project by Marshall 698542Smckusick * Kirk McKusick and Network Associates Laboratories, the Security 798542Smckusick * Research Division of Network Associates, Inc. under DARPA/SPAWAR 898542Smckusick * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS 998542Smckusick * research program 1098542Smckusick * 11136721Srwatson * Redistribution and use in source and binary forms, with or without 12136721Srwatson * modification, are permitted provided that the following conditions 13136721Srwatson * are met: 14136721Srwatson * 1. Redistributions of source code must retain the above copyright 15136721Srwatson * notice, this list of conditions and the following disclaimer. 16136721Srwatson * 2. Redistributions in binary form must reproduce the above copyright 17136721Srwatson * notice, this list of conditions and the following disclaimer in the 18136721Srwatson * documentation and/or other materials provided with the distribution. 19136721Srwatson * 20136721Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21136721Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22136721Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23136721Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24136721Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25136721Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26136721Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27136721Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28136721Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29136721Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30136721Srwatson * SUCH DAMAGE. 31136721Srwatson * 321541Srgrimes * Copyright (c) 1982, 1986, 1989, 1993 331541Srgrimes * The Regents of the University of California. All rights reserved. 341541Srgrimes * 351541Srgrimes * Redistribution and use in source and binary forms, with or without 361541Srgrimes * modification, are permitted provided that the following conditions 371541Srgrimes * are met: 381541Srgrimes * 1. Redistributions of source code must retain the above copyright 391541Srgrimes * notice, this list of conditions and the following disclaimer. 401541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 411541Srgrimes * notice, this list of conditions and the following disclaimer in the 421541Srgrimes * documentation and/or other materials provided with the distribution. 431541Srgrimes * 4. Neither the name of the University nor the names of its contributors 441541Srgrimes * may be used to endorse or promote products derived from this software 451541Srgrimes * without specific prior written permission. 461541Srgrimes * 471541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 481541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 491541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 501541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 511541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 521541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 531541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 541541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 551541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 561541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 571541Srgrimes * SUCH DAMAGE. 581541Srgrimes * 5922521Sdyson * @(#)ffs_alloc.c 8.18 (Berkeley) 5/26/95 601541Srgrimes */ 611541Srgrimes 62116192Sobrien#include <sys/cdefs.h> 63116192Sobrien__FBSDID("$FreeBSD: head/sys/ufs/ffs/ffs_alloc.c 203763 2010-02-10 20:10:35Z mckusick $"); 64116192Sobrien 6513260Swollman#include "opt_quota.h" 6613260Swollman 671541Srgrimes#include <sys/param.h> 681541Srgrimes#include <sys/systm.h> 6960041Sphk#include <sys/bio.h> 701541Srgrimes#include <sys/buf.h> 7150253Sbde#include <sys/conf.h> 72202113Smckusick#include <sys/fcntl.h> 7374548Smckusick#include <sys/file.h> 74108524Salfred#include <sys/filedesc.h> 75164033Srwatson#include <sys/priv.h> 761541Srgrimes#include <sys/proc.h> 771541Srgrimes#include <sys/vnode.h> 781541Srgrimes#include <sys/mount.h> 7941124Sdg#include <sys/kernel.h> 80202113Smckusick#include <sys/syscallsubr.h> 8112911Sphk#include <sys/sysctl.h> 821541Srgrimes#include <sys/syslog.h> 831541Srgrimes 84202113Smckusick#include <security/audit/audit.h> 85202113Smckusick 86202113Smckusick#include <ufs/ufs/dir.h> 8759241Srwatson#include <ufs/ufs/extattr.h> 881541Srgrimes#include <ufs/ufs/quota.h> 891541Srgrimes#include <ufs/ufs/inode.h> 9041124Sdg#include <ufs/ufs/ufs_extern.h> 9130474Sphk#include <ufs/ufs/ufsmount.h> 921541Srgrimes 931541Srgrimes#include <ufs/ffs/fs.h> 941541Srgrimes#include <ufs/ffs/ffs_extern.h> 951541Srgrimes 96203763Smckusicktypedef ufs2_daddr_t allocfcn_t(struct inode *ip, u_int cg, ufs2_daddr_t bpref, 9792728Salfred int size); 9812590Sbde 99203763Smckusickstatic ufs2_daddr_t ffs_alloccg(struct inode *, u_int, ufs2_daddr_t, int); 10098542Smckusickstatic ufs2_daddr_t 10198542Smckusick ffs_alloccgblk(struct inode *, struct buf *, ufs2_daddr_t); 102173464Sobrien#ifdef INVARIANTS 10398542Smckusickstatic int ffs_checkblk(struct inode *, ufs2_daddr_t, long); 10431352Sbde#endif 105203763Smckusickstatic ufs2_daddr_t ffs_clusteralloc(struct inode *, u_int, ufs2_daddr_t, int); 106140704Sjeffstatic void ffs_clusteracct(struct ufsmount *, struct fs *, struct cg *, 107140704Sjeff ufs1_daddr_t, int); 10892728Salfredstatic ino_t ffs_dirpref(struct inode *); 109203763Smckusickstatic ufs2_daddr_t ffs_fragextend(struct inode *, u_int, ufs2_daddr_t, 110203763Smckusick int, int); 11192728Salfredstatic void ffs_fserr(struct fs *, ino_t, char *); 11298542Smckusickstatic ufs2_daddr_t ffs_hashalloc 113203763Smckusick (struct inode *, u_int, ufs2_daddr_t, int, allocfcn_t *); 114203763Smckusickstatic ufs2_daddr_t ffs_nodealloccg(struct inode *, u_int, ufs2_daddr_t, int); 11598542Smckusickstatic ufs1_daddr_t ffs_mapsearch(struct fs *, struct cg *, ufs2_daddr_t, int); 11698542Smckusickstatic int ffs_reallocblks_ufs1(struct vop_reallocblks_args *); 11798542Smckusickstatic int ffs_reallocblks_ufs2(struct vop_reallocblks_args *); 1181541Srgrimes 1191541Srgrimes/* 12096755Strhodes * Allocate a block in the filesystem. 1218876Srgrimes * 1221541Srgrimes * The size of the requested block is given, which must be some 1231541Srgrimes * multiple of fs_fsize and <= fs_bsize. 1241541Srgrimes * A preference may be optionally specified. If a preference is given 1251541Srgrimes * the following hierarchy is used to allocate a block: 1261541Srgrimes * 1) allocate the requested block. 1271541Srgrimes * 2) allocate a rotationally optimal block in the same cylinder. 1281541Srgrimes * 3) allocate a block in the same cylinder group. 1291541Srgrimes * 4) quadradically rehash into other cylinder groups, until an 1301541Srgrimes * available block is located. 131166051Smpp * If no block preference is given the following hierarchy is used 1321541Srgrimes * to allocate a block: 1331541Srgrimes * 1) allocate a block in the cylinder group that contains the 1341541Srgrimes * inode for the file. 1351541Srgrimes * 2) quadradically rehash into other cylinder groups, until an 1361541Srgrimes * available block is located. 1371541Srgrimes */ 1381549Srgrimesint 139187790Srwatsonffs_alloc(ip, lbn, bpref, size, flags, cred, bnp) 14096506Sphk struct inode *ip; 14198542Smckusick ufs2_daddr_t lbn, bpref; 142187790Srwatson int size, flags; 1431541Srgrimes struct ucred *cred; 14498542Smckusick ufs2_daddr_t *bnp; 1451541Srgrimes{ 14696506Sphk struct fs *fs; 147140704Sjeff struct ufsmount *ump; 14898542Smckusick ufs2_daddr_t bno; 149203763Smckusick u_int cg, reclaimed; 150151906Sps static struct timeval lastfail; 151151906Sps static int curfail; 152166924Sbrian int64_t delta; 1536357Sphk#ifdef QUOTA 1546357Sphk int error; 1556357Sphk#endif 1568876Srgrimes 1571541Srgrimes *bnp = 0; 1581541Srgrimes fs = ip->i_fs; 159140704Sjeff ump = ip->i_ump; 160140704Sjeff mtx_assert(UFS_MTX(ump), MA_OWNED); 161173464Sobrien#ifdef INVARIANTS 1621541Srgrimes if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0) { 16350253Sbde printf("dev = %s, bsize = %ld, size = %d, fs = %s\n", 16450253Sbde devtoname(ip->i_dev), (long)fs->fs_bsize, size, 16550253Sbde fs->fs_fsmnt); 1661541Srgrimes panic("ffs_alloc: bad size"); 1671541Srgrimes } 1681541Srgrimes if (cred == NOCRED) 1697170Sdg panic("ffs_alloc: missing credential"); 170173464Sobrien#endif /* INVARIANTS */ 17189637Smckusick reclaimed = 0; 17289637Smckusickretry: 173140704Sjeff#ifdef QUOTA 174140704Sjeff UFS_UNLOCK(ump); 175140704Sjeff error = chkdq(ip, btodb(size), cred, 0); 176140704Sjeff if (error) 177140704Sjeff return (error); 178140704Sjeff UFS_LOCK(ump); 179140704Sjeff#endif 1801541Srgrimes if (size == fs->fs_bsize && fs->fs_cstotal.cs_nbfree == 0) 1811541Srgrimes goto nospace; 182170587Srwatson if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0) && 18329609Sphk freespace(fs, fs->fs_minfree) - numfrags(fs, size) < 0) 1841541Srgrimes goto nospace; 1851541Srgrimes if (bpref >= fs->fs_size) 1861541Srgrimes bpref = 0; 1871541Srgrimes if (bpref == 0) 1881541Srgrimes cg = ino_to_cg(fs, ip->i_number); 1891541Srgrimes else 1901541Srgrimes cg = dtog(fs, bpref); 19198542Smckusick bno = ffs_hashalloc(ip, cg, bpref, size, ffs_alloccg); 1921541Srgrimes if (bno > 0) { 193166924Sbrian delta = btodb(size); 194166924Sbrian if (ip->i_flag & IN_SPACECOUNTED) { 195166924Sbrian UFS_LOCK(ump); 196166924Sbrian fs->fs_pendingblocks += delta; 197166924Sbrian UFS_UNLOCK(ump); 198166924Sbrian } 199166924Sbrian DIP_SET(ip, i_blocks, DIP(ip, i_blocks) + delta); 200187790Srwatson if (flags & IO_EXT) 201187790Srwatson ip->i_flag |= IN_CHANGE; 202187790Srwatson else 203187790Srwatson ip->i_flag |= IN_CHANGE | IN_UPDATE; 2041541Srgrimes *bnp = bno; 2051541Srgrimes return (0); 2061541Srgrimes } 207166142Smppnospace: 2081541Srgrimes#ifdef QUOTA 209140704Sjeff UFS_UNLOCK(ump); 2101541Srgrimes /* 2111541Srgrimes * Restore user's disk quota because allocation failed. 2121541Srgrimes */ 21398542Smckusick (void) chkdq(ip, -btodb(size), cred, FORCE); 214140704Sjeff UFS_LOCK(ump); 2151541Srgrimes#endif 21689637Smckusick if (fs->fs_pendingblocks > 0 && reclaimed == 0) { 21789637Smckusick reclaimed = 1; 21889637Smckusick softdep_request_cleanup(fs, ITOV(ip)); 21989637Smckusick goto retry; 22089637Smckusick } 221140704Sjeff UFS_UNLOCK(ump); 222151906Sps if (ppsratecheck(&lastfail, &curfail, 1)) { 223151906Sps ffs_fserr(fs, ip->i_number, "filesystem full"); 224151906Sps uprintf("\n%s: write failed, filesystem is full\n", 225151906Sps fs->fs_fsmnt); 226151906Sps } 2271541Srgrimes return (ENOSPC); 2281541Srgrimes} 2291541Srgrimes 2301541Srgrimes/* 2311541Srgrimes * Reallocate a fragment to a bigger size 2321541Srgrimes * 2331541Srgrimes * The number and size of the old block is given, and a preference 2341541Srgrimes * and new size is also specified. The allocator attempts to extend 2351541Srgrimes * the original block. Failing that, the regular block allocator is 2361541Srgrimes * invoked to get an appropriate block. 2371541Srgrimes */ 2381549Srgrimesint 239187790Srwatsonffs_realloccg(ip, lbprev, bprev, bpref, osize, nsize, flags, cred, bpp) 24096506Sphk struct inode *ip; 24198542Smckusick ufs2_daddr_t lbprev; 242100344Smckusick ufs2_daddr_t bprev; 24398542Smckusick ufs2_daddr_t bpref; 244187790Srwatson int osize, nsize, flags; 2451541Srgrimes struct ucred *cred; 2461541Srgrimes struct buf **bpp; 2471541Srgrimes{ 24889637Smckusick struct vnode *vp; 24989637Smckusick struct fs *fs; 2501541Srgrimes struct buf *bp; 251140704Sjeff struct ufsmount *ump; 252203763Smckusick u_int cg, request, reclaimed; 253203763Smckusick int error; 254100344Smckusick ufs2_daddr_t bno; 255151906Sps static struct timeval lastfail; 256151906Sps static int curfail; 257166924Sbrian int64_t delta; 2588876Srgrimes 2591541Srgrimes *bpp = 0; 26089637Smckusick vp = ITOV(ip); 2611541Srgrimes fs = ip->i_fs; 262140704Sjeff bp = NULL; 263140704Sjeff ump = ip->i_ump; 264140704Sjeff mtx_assert(UFS_MTX(ump), MA_OWNED); 265173464Sobrien#ifdef INVARIANTS 26689637Smckusick if (vp->v_mount->mnt_kern_flag & MNTK_SUSPENDED) 26762976Smckusick panic("ffs_realloccg: allocation on suspended filesystem"); 2681541Srgrimes if ((u_int)osize > fs->fs_bsize || fragoff(fs, osize) != 0 || 2691541Srgrimes (u_int)nsize > fs->fs_bsize || fragoff(fs, nsize) != 0) { 2701541Srgrimes printf( 27150253Sbde "dev = %s, bsize = %ld, osize = %d, nsize = %d, fs = %s\n", 27250253Sbde devtoname(ip->i_dev), (long)fs->fs_bsize, osize, 2738456Srgrimes nsize, fs->fs_fsmnt); 2741541Srgrimes panic("ffs_realloccg: bad size"); 2751541Srgrimes } 2761541Srgrimes if (cred == NOCRED) 2777170Sdg panic("ffs_realloccg: missing credential"); 278173464Sobrien#endif /* INVARIANTS */ 27989637Smckusick reclaimed = 0; 28089637Smckusickretry: 281170587Srwatson if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0) && 282140704Sjeff freespace(fs, fs->fs_minfree) - numfrags(fs, nsize - osize) < 0) { 2831541Srgrimes goto nospace; 284140704Sjeff } 285100344Smckusick if (bprev == 0) { 28698687Smux printf("dev = %s, bsize = %ld, bprev = %jd, fs = %s\n", 28798542Smckusick devtoname(ip->i_dev), (long)fs->fs_bsize, (intmax_t)bprev, 28837555Sbde fs->fs_fsmnt); 2891541Srgrimes panic("ffs_realloccg: bad bprev"); 2901541Srgrimes } 291140704Sjeff UFS_UNLOCK(ump); 2921541Srgrimes /* 2931541Srgrimes * Allocate the extra space in the buffer. 2941541Srgrimes */ 29589637Smckusick error = bread(vp, lbprev, osize, NOCRED, &bp); 2963487Sphk if (error) { 2971541Srgrimes brelse(bp); 2981541Srgrimes return (error); 2991541Srgrimes } 3006864Sdg 30198542Smckusick if (bp->b_blkno == bp->b_lblkno) { 30298542Smckusick if (lbprev >= NDADDR) 3036864Sdg panic("ffs_realloccg: lbprev out of range"); 3046864Sdg bp->b_blkno = fsbtodb(fs, bprev); 3056864Sdg } 3068876Srgrimes 3071541Srgrimes#ifdef QUOTA 30898542Smckusick error = chkdq(ip, btodb(nsize - osize), cred, 0); 3093487Sphk if (error) { 3101541Srgrimes brelse(bp); 3111541Srgrimes return (error); 3121541Srgrimes } 3131541Srgrimes#endif 3141541Srgrimes /* 3151541Srgrimes * Check for extension in the existing location. 3161541Srgrimes */ 3171541Srgrimes cg = dtog(fs, bprev); 318140704Sjeff UFS_LOCK(ump); 31998542Smckusick bno = ffs_fragextend(ip, cg, bprev, osize, nsize); 3203487Sphk if (bno) { 3211541Srgrimes if (bp->b_blkno != fsbtodb(fs, bno)) 32223560Smpp panic("ffs_realloccg: bad blockno"); 323166924Sbrian delta = btodb(nsize - osize); 324166924Sbrian if (ip->i_flag & IN_SPACECOUNTED) { 325166924Sbrian UFS_LOCK(ump); 326166924Sbrian fs->fs_pendingblocks += delta; 327166924Sbrian UFS_UNLOCK(ump); 328166924Sbrian } 329166924Sbrian DIP_SET(ip, i_blocks, DIP(ip, i_blocks) + delta); 330187790Srwatson if (flags & IO_EXT) 331187790Srwatson ip->i_flag |= IN_CHANGE; 332187790Srwatson else 333187790Srwatson ip->i_flag |= IN_CHANGE | IN_UPDATE; 3347399Sdg allocbuf(bp, nsize); 3351541Srgrimes bp->b_flags |= B_DONE; 336192260Salc bzero(bp->b_data + osize, nsize - osize); 337192260Salc if ((bp->b_flags & (B_MALLOC | B_VMIO)) == B_VMIO) 338192260Salc vfs_bio_set_valid(bp, osize, nsize - osize); 3391541Srgrimes *bpp = bp; 3401541Srgrimes return (0); 3411541Srgrimes } 3421541Srgrimes /* 3431541Srgrimes * Allocate a new disk location. 3441541Srgrimes */ 3451541Srgrimes if (bpref >= fs->fs_size) 3461541Srgrimes bpref = 0; 3471541Srgrimes switch ((int)fs->fs_optim) { 3481541Srgrimes case FS_OPTSPACE: 3491541Srgrimes /* 3508876Srgrimes * Allocate an exact sized fragment. Although this makes 3518876Srgrimes * best use of space, we will waste time relocating it if 3521541Srgrimes * the file continues to grow. If the fragmentation is 3531541Srgrimes * less than half of the minimum free reserve, we choose 3541541Srgrimes * to begin optimizing for time. 3551541Srgrimes */ 3561541Srgrimes request = nsize; 3576993Sdg if (fs->fs_minfree <= 5 || 3581541Srgrimes fs->fs_cstotal.cs_nffree > 35958087Smckusick (off_t)fs->fs_dsize * fs->fs_minfree / (2 * 100)) 3601541Srgrimes break; 3611541Srgrimes log(LOG_NOTICE, "%s: optimization changed from SPACE to TIME\n", 3621541Srgrimes fs->fs_fsmnt); 3631541Srgrimes fs->fs_optim = FS_OPTTIME; 3641541Srgrimes break; 3651541Srgrimes case FS_OPTTIME: 3661541Srgrimes /* 3671541Srgrimes * At this point we have discovered a file that is trying to 3681541Srgrimes * grow a small fragment to a larger fragment. To save time, 3691541Srgrimes * we allocate a full sized block, then free the unused portion. 3701541Srgrimes * If the file continues to grow, the `ffs_fragextend' call 3711541Srgrimes * above will be able to grow it in place without further 3721541Srgrimes * copying. If aberrant programs cause disk fragmentation to 3731541Srgrimes * grow within 2% of the free reserve, we choose to begin 3741541Srgrimes * optimizing for space. 3751541Srgrimes */ 3761541Srgrimes request = fs->fs_bsize; 3771541Srgrimes if (fs->fs_cstotal.cs_nffree < 37858087Smckusick (off_t)fs->fs_dsize * (fs->fs_minfree - 2) / 100) 3791541Srgrimes break; 3801541Srgrimes log(LOG_NOTICE, "%s: optimization changed from TIME to SPACE\n", 3811541Srgrimes fs->fs_fsmnt); 3821541Srgrimes fs->fs_optim = FS_OPTSPACE; 3831541Srgrimes break; 3841541Srgrimes default: 38550253Sbde printf("dev = %s, optim = %ld, fs = %s\n", 38650253Sbde devtoname(ip->i_dev), (long)fs->fs_optim, fs->fs_fsmnt); 3871541Srgrimes panic("ffs_realloccg: bad optim"); 3881541Srgrimes /* NOTREACHED */ 3891541Srgrimes } 39098542Smckusick bno = ffs_hashalloc(ip, cg, bpref, request, ffs_alloccg); 3911541Srgrimes if (bno > 0) { 3921541Srgrimes bp->b_blkno = fsbtodb(fs, bno); 39389637Smckusick if (!DOINGSOFTDEP(vp)) 394140704Sjeff ffs_blkfree(ump, fs, ip->i_devvp, bprev, (long)osize, 39590098Smckusick ip->i_number); 3961541Srgrimes if (nsize < request) 397140704Sjeff ffs_blkfree(ump, fs, ip->i_devvp, 398140704Sjeff bno + numfrags(fs, nsize), 39990098Smckusick (long)(request - nsize), ip->i_number); 400166924Sbrian delta = btodb(nsize - osize); 401166924Sbrian if (ip->i_flag & IN_SPACECOUNTED) { 402166924Sbrian UFS_LOCK(ump); 403166924Sbrian fs->fs_pendingblocks += delta; 404166924Sbrian UFS_UNLOCK(ump); 405166924Sbrian } 406166924Sbrian DIP_SET(ip, i_blocks, DIP(ip, i_blocks) + delta); 407187790Srwatson if (flags & IO_EXT) 408187790Srwatson ip->i_flag |= IN_CHANGE; 409187790Srwatson else 410187790Srwatson ip->i_flag |= IN_CHANGE | IN_UPDATE; 4117399Sdg allocbuf(bp, nsize); 4121541Srgrimes bp->b_flags |= B_DONE; 413192260Salc bzero(bp->b_data + osize, nsize - osize); 414192260Salc if ((bp->b_flags & (B_MALLOC | B_VMIO)) == B_VMIO) 415192260Salc vfs_bio_set_valid(bp, osize, nsize - osize); 4161541Srgrimes *bpp = bp; 4171541Srgrimes return (0); 4181541Srgrimes } 4191541Srgrimes#ifdef QUOTA 420140704Sjeff UFS_UNLOCK(ump); 4211541Srgrimes /* 4221541Srgrimes * Restore user's disk quota because allocation failed. 4231541Srgrimes */ 42498542Smckusick (void) chkdq(ip, -btodb(nsize - osize), cred, FORCE); 425140704Sjeff UFS_LOCK(ump); 4261541Srgrimes#endif 4271541Srgrimesnospace: 4281541Srgrimes /* 4291541Srgrimes * no space available 4301541Srgrimes */ 43189637Smckusick if (fs->fs_pendingblocks > 0 && reclaimed == 0) { 43289637Smckusick reclaimed = 1; 43389637Smckusick softdep_request_cleanup(fs, vp); 434140704Sjeff UFS_UNLOCK(ump); 435140704Sjeff if (bp) 436140704Sjeff brelse(bp); 437140704Sjeff UFS_LOCK(ump); 43889637Smckusick goto retry; 43989637Smckusick } 440140704Sjeff UFS_UNLOCK(ump); 441140704Sjeff if (bp) 442140704Sjeff brelse(bp); 443151906Sps if (ppsratecheck(&lastfail, &curfail, 1)) { 444151906Sps ffs_fserr(fs, ip->i_number, "filesystem full"); 445151906Sps uprintf("\n%s: write failed, filesystem is full\n", 446151906Sps fs->fs_fsmnt); 447151906Sps } 4481541Srgrimes return (ENOSPC); 4491541Srgrimes} 4501541Srgrimes 4511541Srgrimes/* 4521541Srgrimes * Reallocate a sequence of blocks into a contiguous sequence of blocks. 4531541Srgrimes * 4541541Srgrimes * The vnode and an array of buffer pointers for a range of sequential 4551541Srgrimes * logical blocks to be made contiguous is given. The allocator attempts 45698542Smckusick * to find a range of sequential blocks starting as close as possible 45798542Smckusick * from the end of the allocation for the logical block immediately 45898542Smckusick * preceding the current range. If successful, the physical block numbers 45998542Smckusick * in the buffer pointers and in the inode are changed to reflect the new 46098542Smckusick * allocation. If unsuccessful, the allocation is left unchanged. The 46198542Smckusick * success in doing the reallocation is returned. Note that the error 46298542Smckusick * return is not reflected back to the user. Rather the previous block 46398542Smckusick * allocation will be used. 4641541Srgrimes */ 46574548Smckusick 46674548SmckusickSYSCTL_NODE(_vfs, OID_AUTO, ffs, CTLFLAG_RW, 0, "FFS filesystem"); 46774548Smckusick 46812911Sphkstatic int doasyncfree = 1; 46974548SmckusickSYSCTL_INT(_vfs_ffs, OID_AUTO, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, ""); 47022521Sdyson 47131352Sbdestatic int doreallocblks = 1; 47274548SmckusickSYSCTL_INT(_vfs_ffs, OID_AUTO, doreallocblks, CTLFLAG_RW, &doreallocblks, 0, ""); 47322521Sdyson 47442351Sbde#ifdef DEBUG 47542351Sbdestatic volatile int prtrealloc = 0; 47642351Sbde#endif 47731351Sbde 4781541Srgrimesint 4791541Srgrimesffs_reallocblks(ap) 4801541Srgrimes struct vop_reallocblks_args /* { 4811541Srgrimes struct vnode *a_vp; 4821541Srgrimes struct cluster_save *a_buflist; 4831541Srgrimes } */ *ap; 4841541Srgrimes{ 48598542Smckusick 48698542Smckusick if (doreallocblks == 0) 48798542Smckusick return (ENOSPC); 48898542Smckusick if (VTOI(ap->a_vp)->i_ump->um_fstype == UFS1) 48998542Smckusick return (ffs_reallocblks_ufs1(ap)); 49098542Smckusick return (ffs_reallocblks_ufs2(ap)); 49198542Smckusick} 49298542Smckusick 49398542Smckusickstatic int 49498542Smckusickffs_reallocblks_ufs1(ap) 49598542Smckusick struct vop_reallocblks_args /* { 49698542Smckusick struct vnode *a_vp; 49798542Smckusick struct cluster_save *a_buflist; 49898542Smckusick } */ *ap; 49998542Smckusick{ 5001541Srgrimes struct fs *fs; 5011541Srgrimes struct inode *ip; 5021541Srgrimes struct vnode *vp; 5031541Srgrimes struct buf *sbp, *ebp; 50498542Smckusick ufs1_daddr_t *bap, *sbap, *ebap = 0; 5051541Srgrimes struct cluster_save *buflist; 506140704Sjeff struct ufsmount *ump; 50798542Smckusick ufs_lbn_t start_lbn, end_lbn; 50898542Smckusick ufs1_daddr_t soff, newblk, blkno; 50998542Smckusick ufs2_daddr_t pref; 5101541Srgrimes struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp; 51198542Smckusick int i, len, start_lvl, end_lvl, ssize; 5121541Srgrimes 5131541Srgrimes vp = ap->a_vp; 5141541Srgrimes ip = VTOI(vp); 5151541Srgrimes fs = ip->i_fs; 516140704Sjeff ump = ip->i_ump; 5171541Srgrimes if (fs->fs_contigsumsize <= 0) 5181541Srgrimes return (ENOSPC); 5191541Srgrimes buflist = ap->a_buflist; 5201541Srgrimes len = buflist->bs_nchildren; 5211541Srgrimes start_lbn = buflist->bs_children[0]->b_lblkno; 5221541Srgrimes end_lbn = start_lbn + len - 1; 523173464Sobrien#ifdef INVARIANTS 52422521Sdyson for (i = 0; i < len; i++) 52522521Sdyson if (!ffs_checkblk(ip, 52622521Sdyson dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) 52722521Sdyson panic("ffs_reallocblks: unallocated block 1"); 5281541Srgrimes for (i = 1; i < len; i++) 5291541Srgrimes if (buflist->bs_children[i]->b_lblkno != start_lbn + i) 53022521Sdyson panic("ffs_reallocblks: non-logical cluster"); 53122521Sdyson blkno = buflist->bs_children[0]->b_blkno; 53222521Sdyson ssize = fsbtodb(fs, fs->fs_frag); 53322521Sdyson for (i = 1; i < len - 1; i++) 53422521Sdyson if (buflist->bs_children[i]->b_blkno != blkno + (i * ssize)) 53522521Sdyson panic("ffs_reallocblks: non-physical cluster %d", i); 5361541Srgrimes#endif 5371541Srgrimes /* 5381541Srgrimes * If the latest allocation is in a new cylinder group, assume that 5391541Srgrimes * the filesystem has decided to move and do not force it back to 5401541Srgrimes * the previous cylinder group. 5411541Srgrimes */ 5421541Srgrimes if (dtog(fs, dbtofsb(fs, buflist->bs_children[0]->b_blkno)) != 5431541Srgrimes dtog(fs, dbtofsb(fs, buflist->bs_children[len - 1]->b_blkno))) 5441541Srgrimes return (ENOSPC); 5451541Srgrimes if (ufs_getlbns(vp, start_lbn, start_ap, &start_lvl) || 5461541Srgrimes ufs_getlbns(vp, end_lbn, end_ap, &end_lvl)) 5471541Srgrimes return (ENOSPC); 5481541Srgrimes /* 5491541Srgrimes * Get the starting offset and block map for the first block. 5501541Srgrimes */ 5511541Srgrimes if (start_lvl == 0) { 55298542Smckusick sbap = &ip->i_din1->di_db[0]; 5531541Srgrimes soff = start_lbn; 5541541Srgrimes } else { 5551541Srgrimes idp = &start_ap[start_lvl - 1]; 5561541Srgrimes if (bread(vp, idp->in_lbn, (int)fs->fs_bsize, NOCRED, &sbp)) { 5571541Srgrimes brelse(sbp); 5581541Srgrimes return (ENOSPC); 5591541Srgrimes } 56098542Smckusick sbap = (ufs1_daddr_t *)sbp->b_data; 5611541Srgrimes soff = idp->in_off; 5621541Srgrimes } 5631541Srgrimes /* 5641541Srgrimes * If the block range spans two block maps, get the second map. 5651541Srgrimes */ 5661541Srgrimes if (end_lvl == 0 || (idp = &end_ap[end_lvl - 1])->in_off + 1 >= len) { 5671541Srgrimes ssize = len; 5681541Srgrimes } else { 569173464Sobrien#ifdef INVARIANTS 570174126Skensmith if (start_lvl > 0 && 571174126Skensmith start_ap[start_lvl - 1].in_lbn == idp->in_lbn) 5721541Srgrimes panic("ffs_reallocblk: start == end"); 5731541Srgrimes#endif 5741541Srgrimes ssize = len - (idp->in_off + 1); 5751541Srgrimes if (bread(vp, idp->in_lbn, (int)fs->fs_bsize, NOCRED, &ebp)) 5761541Srgrimes goto fail; 57798542Smckusick ebap = (ufs1_daddr_t *)ebp->b_data; 5781541Srgrimes } 5791541Srgrimes /* 580140704Sjeff * Find the preferred location for the cluster. 581140704Sjeff */ 582140704Sjeff UFS_LOCK(ump); 583140704Sjeff pref = ffs_blkpref_ufs1(ip, start_lbn, soff, sbap); 584140704Sjeff /* 5851541Srgrimes * Search the block map looking for an allocation of the desired size. 5861541Srgrimes */ 58798542Smckusick if ((newblk = ffs_hashalloc(ip, dtog(fs, pref), pref, 588140704Sjeff len, ffs_clusteralloc)) == 0) { 589140704Sjeff UFS_UNLOCK(ump); 5901541Srgrimes goto fail; 591140704Sjeff } 5921541Srgrimes /* 5931541Srgrimes * We have found a new contiguous block. 5941541Srgrimes * 5951541Srgrimes * First we have to replace the old block pointers with the new 5961541Srgrimes * block pointers in the inode and indirect blocks associated 5971541Srgrimes * with the file. 5981541Srgrimes */ 59922521Sdyson#ifdef DEBUG 60022521Sdyson if (prtrealloc) 601103594Sobrien printf("realloc: ino %d, lbns %jd-%jd\n\told:", ip->i_number, 60298542Smckusick (intmax_t)start_lbn, (intmax_t)end_lbn); 60322521Sdyson#endif 6041541Srgrimes blkno = newblk; 6051541Srgrimes for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->fs_frag) { 60634266Sjulian if (i == ssize) { 6071541Srgrimes bap = ebap; 60834266Sjulian soff = -i; 60934266Sjulian } 610173464Sobrien#ifdef INVARIANTS 61122521Sdyson if (!ffs_checkblk(ip, 61222521Sdyson dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) 61322521Sdyson panic("ffs_reallocblks: unallocated block 2"); 61422521Sdyson if (dbtofsb(fs, buflist->bs_children[i]->b_blkno) != *bap) 6151541Srgrimes panic("ffs_reallocblks: alloc mismatch"); 6161541Srgrimes#endif 61722521Sdyson#ifdef DEBUG 61822521Sdyson if (prtrealloc) 61922521Sdyson printf(" %d,", *bap); 62022521Sdyson#endif 62134266Sjulian if (DOINGSOFTDEP(vp)) { 62298542Smckusick if (sbap == &ip->i_din1->di_db[0] && i < ssize) 62334266Sjulian softdep_setup_allocdirect(ip, start_lbn + i, 62434266Sjulian blkno, *bap, fs->fs_bsize, fs->fs_bsize, 62534266Sjulian buflist->bs_children[i]); 62634266Sjulian else 62734266Sjulian softdep_setup_allocindir_page(ip, start_lbn + i, 62834266Sjulian i < ssize ? sbp : ebp, soff + i, blkno, 62934266Sjulian *bap, buflist->bs_children[i]); 63034266Sjulian } 6311541Srgrimes *bap++ = blkno; 6321541Srgrimes } 6331541Srgrimes /* 6341541Srgrimes * Next we must write out the modified inode and indirect blocks. 6351541Srgrimes * For strict correctness, the writes should be synchronous since 6361541Srgrimes * the old block values may have been written to disk. In practise 6378876Srgrimes * they are almost never written, but if we are concerned about 6381541Srgrimes * strict correctness, the `doasyncfree' flag should be set to zero. 6391541Srgrimes * 6401541Srgrimes * The test on `doasyncfree' should be changed to test a flag 6411541Srgrimes * that shows whether the associated buffers and inodes have 6421541Srgrimes * been written. The flag should be set when the cluster is 6431541Srgrimes * started and cleared whenever the buffer or inode is flushed. 6441541Srgrimes * We can then check below to see if it is set, and do the 6451541Srgrimes * synchronous write only when it has been cleared. 6461541Srgrimes */ 64798542Smckusick if (sbap != &ip->i_din1->di_db[0]) { 6481541Srgrimes if (doasyncfree) 6491541Srgrimes bdwrite(sbp); 6501541Srgrimes else 6511541Srgrimes bwrite(sbp); 6521541Srgrimes } else { 6531541Srgrimes ip->i_flag |= IN_CHANGE | IN_UPDATE; 65442374Sbde if (!doasyncfree) 655141526Sphk ffs_update(vp, 1); 6561541Srgrimes } 65746568Speter if (ssize < len) { 6581541Srgrimes if (doasyncfree) 6591541Srgrimes bdwrite(ebp); 6601541Srgrimes else 6611541Srgrimes bwrite(ebp); 66246568Speter } 6631541Srgrimes /* 6641541Srgrimes * Last, free the old blocks and assign the new blocks to the buffers. 6651541Srgrimes */ 66622521Sdyson#ifdef DEBUG 66722521Sdyson if (prtrealloc) 66822521Sdyson printf("\n\tnew:"); 66922521Sdyson#endif 6701541Srgrimes for (blkno = newblk, i = 0; i < len; i++, blkno += fs->fs_frag) { 67134266Sjulian if (!DOINGSOFTDEP(vp)) 672140704Sjeff ffs_blkfree(ump, fs, ip->i_devvp, 67334266Sjulian dbtofsb(fs, buflist->bs_children[i]->b_blkno), 67490098Smckusick fs->fs_bsize, ip->i_number); 6751541Srgrimes buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno); 676173464Sobrien#ifdef INVARIANTS 67722521Sdyson if (!ffs_checkblk(ip, 67822521Sdyson dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) 67922521Sdyson panic("ffs_reallocblks: unallocated block 3"); 68050305Ssheldonh#endif 68150305Ssheldonh#ifdef DEBUG 68222521Sdyson if (prtrealloc) 68322521Sdyson printf(" %d,", blkno); 68422521Sdyson#endif 6851541Srgrimes } 68622521Sdyson#ifdef DEBUG 68722521Sdyson if (prtrealloc) { 68822521Sdyson prtrealloc--; 68922521Sdyson printf("\n"); 69022521Sdyson } 69122521Sdyson#endif 6921541Srgrimes return (0); 6931541Srgrimes 6941541Srgrimesfail: 6951541Srgrimes if (ssize < len) 6961541Srgrimes brelse(ebp); 69798542Smckusick if (sbap != &ip->i_din1->di_db[0]) 6981541Srgrimes brelse(sbp); 6991541Srgrimes return (ENOSPC); 7001541Srgrimes} 7011541Srgrimes 70298542Smckusickstatic int 70398542Smckusickffs_reallocblks_ufs2(ap) 70498542Smckusick struct vop_reallocblks_args /* { 70598542Smckusick struct vnode *a_vp; 70698542Smckusick struct cluster_save *a_buflist; 70798542Smckusick } */ *ap; 70898542Smckusick{ 70998542Smckusick struct fs *fs; 71098542Smckusick struct inode *ip; 71198542Smckusick struct vnode *vp; 71298542Smckusick struct buf *sbp, *ebp; 71398542Smckusick ufs2_daddr_t *bap, *sbap, *ebap = 0; 71498542Smckusick struct cluster_save *buflist; 715140704Sjeff struct ufsmount *ump; 71698542Smckusick ufs_lbn_t start_lbn, end_lbn; 71798542Smckusick ufs2_daddr_t soff, newblk, blkno, pref; 71898542Smckusick struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp; 71998542Smckusick int i, len, start_lvl, end_lvl, ssize; 72098542Smckusick 72198542Smckusick vp = ap->a_vp; 72298542Smckusick ip = VTOI(vp); 72398542Smckusick fs = ip->i_fs; 724140704Sjeff ump = ip->i_ump; 72598542Smckusick if (fs->fs_contigsumsize <= 0) 72698542Smckusick return (ENOSPC); 72798542Smckusick buflist = ap->a_buflist; 72898542Smckusick len = buflist->bs_nchildren; 72998542Smckusick start_lbn = buflist->bs_children[0]->b_lblkno; 73098542Smckusick end_lbn = start_lbn + len - 1; 731173464Sobrien#ifdef INVARIANTS 73298542Smckusick for (i = 0; i < len; i++) 73398542Smckusick if (!ffs_checkblk(ip, 73498542Smckusick dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) 73598542Smckusick panic("ffs_reallocblks: unallocated block 1"); 73698542Smckusick for (i = 1; i < len; i++) 73798542Smckusick if (buflist->bs_children[i]->b_lblkno != start_lbn + i) 73898542Smckusick panic("ffs_reallocblks: non-logical cluster"); 73998542Smckusick blkno = buflist->bs_children[0]->b_blkno; 74098542Smckusick ssize = fsbtodb(fs, fs->fs_frag); 74198542Smckusick for (i = 1; i < len - 1; i++) 74298542Smckusick if (buflist->bs_children[i]->b_blkno != blkno + (i * ssize)) 74398542Smckusick panic("ffs_reallocblks: non-physical cluster %d", i); 74498542Smckusick#endif 74598542Smckusick /* 74698542Smckusick * If the latest allocation is in a new cylinder group, assume that 74798542Smckusick * the filesystem has decided to move and do not force it back to 74898542Smckusick * the previous cylinder group. 74998542Smckusick */ 75098542Smckusick if (dtog(fs, dbtofsb(fs, buflist->bs_children[0]->b_blkno)) != 75198542Smckusick dtog(fs, dbtofsb(fs, buflist->bs_children[len - 1]->b_blkno))) 75298542Smckusick return (ENOSPC); 75398542Smckusick if (ufs_getlbns(vp, start_lbn, start_ap, &start_lvl) || 75498542Smckusick ufs_getlbns(vp, end_lbn, end_ap, &end_lvl)) 75598542Smckusick return (ENOSPC); 75698542Smckusick /* 75798542Smckusick * Get the starting offset and block map for the first block. 75898542Smckusick */ 75998542Smckusick if (start_lvl == 0) { 76098542Smckusick sbap = &ip->i_din2->di_db[0]; 76198542Smckusick soff = start_lbn; 76298542Smckusick } else { 76398542Smckusick idp = &start_ap[start_lvl - 1]; 76498542Smckusick if (bread(vp, idp->in_lbn, (int)fs->fs_bsize, NOCRED, &sbp)) { 76598542Smckusick brelse(sbp); 76698542Smckusick return (ENOSPC); 76798542Smckusick } 76898542Smckusick sbap = (ufs2_daddr_t *)sbp->b_data; 76998542Smckusick soff = idp->in_off; 77098542Smckusick } 77198542Smckusick /* 77298542Smckusick * If the block range spans two block maps, get the second map. 77398542Smckusick */ 77498542Smckusick if (end_lvl == 0 || (idp = &end_ap[end_lvl - 1])->in_off + 1 >= len) { 77598542Smckusick ssize = len; 77698542Smckusick } else { 777173464Sobrien#ifdef INVARIANTS 778174126Skensmith if (start_lvl > 0 && 779174126Skensmith start_ap[start_lvl - 1].in_lbn == idp->in_lbn) 78098542Smckusick panic("ffs_reallocblk: start == end"); 78198542Smckusick#endif 78298542Smckusick ssize = len - (idp->in_off + 1); 78398542Smckusick if (bread(vp, idp->in_lbn, (int)fs->fs_bsize, NOCRED, &ebp)) 78498542Smckusick goto fail; 78598542Smckusick ebap = (ufs2_daddr_t *)ebp->b_data; 78698542Smckusick } 78798542Smckusick /* 788140704Sjeff * Find the preferred location for the cluster. 789140704Sjeff */ 790140704Sjeff UFS_LOCK(ump); 791140704Sjeff pref = ffs_blkpref_ufs2(ip, start_lbn, soff, sbap); 792140704Sjeff /* 79398542Smckusick * Search the block map looking for an allocation of the desired size. 79498542Smckusick */ 79598542Smckusick if ((newblk = ffs_hashalloc(ip, dtog(fs, pref), pref, 796140704Sjeff len, ffs_clusteralloc)) == 0) { 797140704Sjeff UFS_UNLOCK(ump); 79898542Smckusick goto fail; 799140704Sjeff } 80098542Smckusick /* 80198542Smckusick * We have found a new contiguous block. 80298542Smckusick * 80398542Smckusick * First we have to replace the old block pointers with the new 80498542Smckusick * block pointers in the inode and indirect blocks associated 80598542Smckusick * with the file. 80698542Smckusick */ 80798542Smckusick#ifdef DEBUG 80898542Smckusick if (prtrealloc) 809103594Sobrien printf("realloc: ino %d, lbns %jd-%jd\n\told:", ip->i_number, 81098542Smckusick (intmax_t)start_lbn, (intmax_t)end_lbn); 81198542Smckusick#endif 81298542Smckusick blkno = newblk; 81398542Smckusick for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->fs_frag) { 81498542Smckusick if (i == ssize) { 81598542Smckusick bap = ebap; 81698542Smckusick soff = -i; 81798542Smckusick } 818173464Sobrien#ifdef INVARIANTS 81998542Smckusick if (!ffs_checkblk(ip, 82098542Smckusick dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) 82198542Smckusick panic("ffs_reallocblks: unallocated block 2"); 82298542Smckusick if (dbtofsb(fs, buflist->bs_children[i]->b_blkno) != *bap) 82398542Smckusick panic("ffs_reallocblks: alloc mismatch"); 82498542Smckusick#endif 82598542Smckusick#ifdef DEBUG 82698542Smckusick if (prtrealloc) 827103594Sobrien printf(" %jd,", (intmax_t)*bap); 82898542Smckusick#endif 82998542Smckusick if (DOINGSOFTDEP(vp)) { 83098542Smckusick if (sbap == &ip->i_din2->di_db[0] && i < ssize) 83198542Smckusick softdep_setup_allocdirect(ip, start_lbn + i, 83298542Smckusick blkno, *bap, fs->fs_bsize, fs->fs_bsize, 83398542Smckusick buflist->bs_children[i]); 83498542Smckusick else 83598542Smckusick softdep_setup_allocindir_page(ip, start_lbn + i, 83698542Smckusick i < ssize ? sbp : ebp, soff + i, blkno, 83798542Smckusick *bap, buflist->bs_children[i]); 83898542Smckusick } 83998542Smckusick *bap++ = blkno; 84098542Smckusick } 84198542Smckusick /* 84298542Smckusick * Next we must write out the modified inode and indirect blocks. 84398542Smckusick * For strict correctness, the writes should be synchronous since 84498542Smckusick * the old block values may have been written to disk. In practise 84598542Smckusick * they are almost never written, but if we are concerned about 84698542Smckusick * strict correctness, the `doasyncfree' flag should be set to zero. 84798542Smckusick * 84898542Smckusick * The test on `doasyncfree' should be changed to test a flag 84998542Smckusick * that shows whether the associated buffers and inodes have 85098542Smckusick * been written. The flag should be set when the cluster is 85198542Smckusick * started and cleared whenever the buffer or inode is flushed. 85298542Smckusick * We can then check below to see if it is set, and do the 85398542Smckusick * synchronous write only when it has been cleared. 85498542Smckusick */ 85598542Smckusick if (sbap != &ip->i_din2->di_db[0]) { 85698542Smckusick if (doasyncfree) 85798542Smckusick bdwrite(sbp); 85898542Smckusick else 85998542Smckusick bwrite(sbp); 86098542Smckusick } else { 86198542Smckusick ip->i_flag |= IN_CHANGE | IN_UPDATE; 86298542Smckusick if (!doasyncfree) 863141526Sphk ffs_update(vp, 1); 86498542Smckusick } 86598542Smckusick if (ssize < len) { 86698542Smckusick if (doasyncfree) 86798542Smckusick bdwrite(ebp); 86898542Smckusick else 86998542Smckusick bwrite(ebp); 87098542Smckusick } 87198542Smckusick /* 87298542Smckusick * Last, free the old blocks and assign the new blocks to the buffers. 87398542Smckusick */ 87498542Smckusick#ifdef DEBUG 87598542Smckusick if (prtrealloc) 87698542Smckusick printf("\n\tnew:"); 87798542Smckusick#endif 87898542Smckusick for (blkno = newblk, i = 0; i < len; i++, blkno += fs->fs_frag) { 87998542Smckusick if (!DOINGSOFTDEP(vp)) 880140704Sjeff ffs_blkfree(ump, fs, ip->i_devvp, 88198542Smckusick dbtofsb(fs, buflist->bs_children[i]->b_blkno), 88298542Smckusick fs->fs_bsize, ip->i_number); 88398542Smckusick buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno); 884173464Sobrien#ifdef INVARIANTS 88598542Smckusick if (!ffs_checkblk(ip, 88698542Smckusick dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) 88798542Smckusick panic("ffs_reallocblks: unallocated block 3"); 88898542Smckusick#endif 88998542Smckusick#ifdef DEBUG 89098542Smckusick if (prtrealloc) 89199590Sbde printf(" %jd,", (intmax_t)blkno); 89298542Smckusick#endif 89398542Smckusick } 89498542Smckusick#ifdef DEBUG 89598542Smckusick if (prtrealloc) { 89698542Smckusick prtrealloc--; 89798542Smckusick printf("\n"); 89898542Smckusick } 89998542Smckusick#endif 90098542Smckusick return (0); 90198542Smckusick 90298542Smckusickfail: 90398542Smckusick if (ssize < len) 90498542Smckusick brelse(ebp); 90598542Smckusick if (sbap != &ip->i_din2->di_db[0]) 90698542Smckusick brelse(sbp); 90798542Smckusick return (ENOSPC); 90898542Smckusick} 90998542Smckusick 9101541Srgrimes/* 91196755Strhodes * Allocate an inode in the filesystem. 9128876Srgrimes * 9131541Srgrimes * If allocating a directory, use ffs_dirpref to select the inode. 9141541Srgrimes * If allocating in a directory, the following hierarchy is followed: 9151541Srgrimes * 1) allocate the preferred inode. 9161541Srgrimes * 2) allocate an inode in the same cylinder group. 9171541Srgrimes * 3) quadradically rehash into other cylinder groups, until an 9181541Srgrimes * available inode is located. 919166051Smpp * If no inode preference is given the following hierarchy is used 9201541Srgrimes * to allocate an inode: 9211541Srgrimes * 1) allocate an inode in cylinder group 0. 9221541Srgrimes * 2) quadradically rehash into other cylinder groups, until an 9231541Srgrimes * available inode is located. 9241541Srgrimes */ 9251549Srgrimesint 92630474Sphkffs_valloc(pvp, mode, cred, vpp) 92730474Sphk struct vnode *pvp; 92830474Sphk int mode; 92930474Sphk struct ucred *cred; 93030474Sphk struct vnode **vpp; 9311541Srgrimes{ 93296506Sphk struct inode *pip; 93396506Sphk struct fs *fs; 93496506Sphk struct inode *ip; 93598542Smckusick struct timespec ts; 936140704Sjeff struct ufsmount *ump; 9371541Srgrimes ino_t ino, ipref; 938203763Smckusick u_int cg; 939203763Smckusick int error, error1; 940151906Sps static struct timeval lastfail; 941151906Sps static int curfail; 9428876Srgrimes 94330474Sphk *vpp = NULL; 9441541Srgrimes pip = VTOI(pvp); 9451541Srgrimes fs = pip->i_fs; 946140704Sjeff ump = pip->i_ump; 947140704Sjeff 948140704Sjeff UFS_LOCK(ump); 9491541Srgrimes if (fs->fs_cstotal.cs_nifree == 0) 9501541Srgrimes goto noinodes; 9511541Srgrimes 9521541Srgrimes if ((mode & IFMT) == IFDIR) 95375377Smckusick ipref = ffs_dirpref(pip); 9541541Srgrimes else 9551541Srgrimes ipref = pip->i_number; 956108010Smckusick if (ipref >= fs->fs_ncg * fs->fs_ipg) 9571541Srgrimes ipref = 0; 9581541Srgrimes cg = ino_to_cg(fs, ipref); 95975377Smckusick /* 96075377Smckusick * Track number of dirs created one after another 96175377Smckusick * in a same cg without intervening by files. 96275377Smckusick */ 96375377Smckusick if ((mode & IFMT) == IFDIR) { 96475377Smckusick if (fs->fs_contigdirs[cg] < 255) 96575377Smckusick fs->fs_contigdirs[cg]++; 96675377Smckusick } else { 96775377Smckusick if (fs->fs_contigdirs[cg] > 0) 96875377Smckusick fs->fs_contigdirs[cg]--; 96975377Smckusick } 97098542Smckusick ino = (ino_t)ffs_hashalloc(pip, cg, ipref, mode, 97112861Speter (allocfcn_t *)ffs_nodealloccg); 9721541Srgrimes if (ino == 0) 9731541Srgrimes goto noinodes; 974141526Sphk error = ffs_vget(pvp->v_mount, ino, LK_EXCLUSIVE, vpp); 9751541Srgrimes if (error) { 976182366Skib error1 = ffs_vgetf(pvp->v_mount, ino, LK_EXCLUSIVE, vpp, 977182366Skib FFSV_FORCEINSMQ); 978141526Sphk ffs_vfree(pvp, ino, mode); 979182366Skib if (error1 == 0) { 980182366Skib ip = VTOI(*vpp); 981182366Skib if (ip->i_mode) 982182366Skib goto dup_alloc; 983182366Skib ip->i_flag |= IN_MODIFIED; 984182366Skib vput(*vpp); 985182366Skib } 9861541Srgrimes return (error); 9871541Srgrimes } 98830474Sphk ip = VTOI(*vpp); 9891541Srgrimes if (ip->i_mode) { 990182366Skibdup_alloc: 99137555Sbde printf("mode = 0%o, inum = %lu, fs = %s\n", 99237555Sbde ip->i_mode, (u_long)ip->i_number, fs->fs_fsmnt); 9931541Srgrimes panic("ffs_valloc: dup alloc"); 9941541Srgrimes } 99598542Smckusick if (DIP(ip, i_blocks) && (fs->fs_flags & FS_UNCLEAN) == 0) { /* XXX */ 99637555Sbde printf("free inode %s/%lu had %ld blocks\n", 99798542Smckusick fs->fs_fsmnt, (u_long)ino, (long)DIP(ip, i_blocks)); 998132775Skan DIP_SET(ip, i_blocks, 0); 9991541Srgrimes } 10001541Srgrimes ip->i_flags = 0; 1001132775Skan DIP_SET(ip, i_flags, 0); 10021541Srgrimes /* 10031541Srgrimes * Set up a new generation number for this inode. 10041541Srgrimes */ 100531484Sbde if (ip->i_gen == 0 || ++ip->i_gen == 0) 1006110885Smckusick ip->i_gen = arc4random() / 2 + 1; 1007132775Skan DIP_SET(ip, i_gen, ip->i_gen); 100898542Smckusick if (fs->fs_magic == FS_UFS2_MAGIC) { 100998542Smckusick vfs_timestamp(&ts); 1010100201Smckusick ip->i_din2->di_birthtime = ts.tv_sec; 1011100201Smckusick ip->i_din2->di_birthnsec = ts.tv_nsec; 101298542Smckusick } 1013150891Struckman ip->i_flag = 0; 1014151218Stegge vnode_destroy_vobject(*vpp); 1015151176Stegge (*vpp)->v_type = VNON; 1016151176Stegge if (fs->fs_magic == FS_UFS2_MAGIC) 1017151176Stegge (*vpp)->v_op = &ffs_vnodeops2; 1018151176Stegge else 1019151176Stegge (*vpp)->v_op = &ffs_vnodeops1; 10201541Srgrimes return (0); 10211541Srgrimesnoinodes: 1022140704Sjeff UFS_UNLOCK(ump); 1023151906Sps if (ppsratecheck(&lastfail, &curfail, 1)) { 1024151906Sps ffs_fserr(fs, pip->i_number, "out of inodes"); 1025151906Sps uprintf("\n%s: create/symlink failed, no inodes free\n", 1026151906Sps fs->fs_fsmnt); 1027151906Sps } 10281541Srgrimes return (ENOSPC); 10291541Srgrimes} 10301541Srgrimes 10311541Srgrimes/* 103275377Smckusick * Find a cylinder group to place a directory. 10331541Srgrimes * 103475377Smckusick * The policy implemented by this algorithm is to allocate a 103575377Smckusick * directory inode in the same cylinder group as its parent 103675377Smckusick * directory, but also to reserve space for its files inodes 103775377Smckusick * and data. Restrict the number of directories which may be 103875377Smckusick * allocated one after another in the same cylinder group 103975377Smckusick * without intervening allocation of files. 104075377Smckusick * 104175377Smckusick * If we allocate a first level directory then force allocation 104275377Smckusick * in another cylinder group. 10431541Srgrimes */ 10441541Srgrimesstatic ino_t 104575377Smckusickffs_dirpref(pip) 104675377Smckusick struct inode *pip; 104775377Smckusick{ 104896506Sphk struct fs *fs; 1049203763Smckusick u_int cg, prefcg, dirsize, cgsize; 1050203763Smckusick u_int avgifree, avgbfree, avgndir, curdirsize; 1051203763Smckusick u_int minifree, minbfree, maxndir; 1052203763Smckusick u_int mincg, minndir; 1053203763Smckusick u_int maxcontigdirs; 10541541Srgrimes 1055140704Sjeff mtx_assert(UFS_MTX(pip->i_ump), MA_OWNED); 105675377Smckusick fs = pip->i_fs; 105775377Smckusick 10581541Srgrimes avgifree = fs->fs_cstotal.cs_nifree / fs->fs_ncg; 105975377Smckusick avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg; 106075377Smckusick avgndir = fs->fs_cstotal.cs_ndir / fs->fs_ncg; 106175377Smckusick 106275377Smckusick /* 106375377Smckusick * Force allocation in another cg if creating a first level dir. 106475377Smckusick */ 1065101308Sjeff ASSERT_VOP_LOCKED(ITOV(pip), "ffs_dirpref"); 1066101308Sjeff if (ITOV(pip)->v_vflag & VV_ROOT) { 106775377Smckusick prefcg = arc4random() % fs->fs_ncg; 106875377Smckusick mincg = prefcg; 106975377Smckusick minndir = fs->fs_ipg; 107075377Smckusick for (cg = prefcg; cg < fs->fs_ncg; cg++) 107175377Smckusick if (fs->fs_cs(fs, cg).cs_ndir < minndir && 107275377Smckusick fs->fs_cs(fs, cg).cs_nifree >= avgifree && 107375377Smckusick fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { 107475377Smckusick mincg = cg; 107575377Smckusick minndir = fs->fs_cs(fs, cg).cs_ndir; 107675377Smckusick } 107775377Smckusick for (cg = 0; cg < prefcg; cg++) 107875377Smckusick if (fs->fs_cs(fs, cg).cs_ndir < minndir && 107975377Smckusick fs->fs_cs(fs, cg).cs_nifree >= avgifree && 108075377Smckusick fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { 108175377Smckusick mincg = cg; 108275377Smckusick minndir = fs->fs_cs(fs, cg).cs_ndir; 108375377Smckusick } 108475377Smckusick return ((ino_t)(fs->fs_ipg * mincg)); 108575377Smckusick } 108675377Smckusick 108775377Smckusick /* 108875377Smckusick * Count various limits which used for 108975377Smckusick * optimal allocation of a directory inode. 109075377Smckusick */ 109175377Smckusick maxndir = min(avgndir + fs->fs_ipg / 16, fs->fs_ipg); 1092121785Struckman minifree = avgifree - avgifree / 4; 1093121785Struckman if (minifree < 1) 1094121785Struckman minifree = 1; 1095121785Struckman minbfree = avgbfree - avgbfree / 4; 1096121785Struckman if (minbfree < 1) 1097121785Struckman minbfree = 1; 109875377Smckusick cgsize = fs->fs_fsize * fs->fs_fpg; 109975377Smckusick dirsize = fs->fs_avgfilesize * fs->fs_avgfpdir; 110075377Smckusick curdirsize = avgndir ? (cgsize - avgbfree * fs->fs_bsize) / avgndir : 0; 110175377Smckusick if (dirsize < curdirsize) 110275377Smckusick dirsize = curdirsize; 1103172113Sbz if (dirsize <= 0) 1104172113Sbz maxcontigdirs = 0; /* dirsize overflowed */ 1105172113Sbz else 1106172113Sbz maxcontigdirs = min((avgbfree * fs->fs_bsize) / dirsize, 255); 110775377Smckusick if (fs->fs_avgfpdir > 0) 110875377Smckusick maxcontigdirs = min(maxcontigdirs, 110975377Smckusick fs->fs_ipg / fs->fs_avgfpdir); 111075377Smckusick if (maxcontigdirs == 0) 111175377Smckusick maxcontigdirs = 1; 111275377Smckusick 111375377Smckusick /* 111475377Smckusick * Limit number of dirs in one cg and reserve space for 111575377Smckusick * regular files, but only if we have no deficit in 111675377Smckusick * inodes or space. 111775377Smckusick */ 111875377Smckusick prefcg = ino_to_cg(fs, pip->i_number); 111975377Smckusick for (cg = prefcg; cg < fs->fs_ncg; cg++) 112075377Smckusick if (fs->fs_cs(fs, cg).cs_ndir < maxndir && 112175377Smckusick fs->fs_cs(fs, cg).cs_nifree >= minifree && 112275377Smckusick fs->fs_cs(fs, cg).cs_nbfree >= minbfree) { 112375377Smckusick if (fs->fs_contigdirs[cg] < maxcontigdirs) 112475377Smckusick return ((ino_t)(fs->fs_ipg * cg)); 11251541Srgrimes } 112675377Smckusick for (cg = 0; cg < prefcg; cg++) 112775377Smckusick if (fs->fs_cs(fs, cg).cs_ndir < maxndir && 112875377Smckusick fs->fs_cs(fs, cg).cs_nifree >= minifree && 112975377Smckusick fs->fs_cs(fs, cg).cs_nbfree >= minbfree) { 113075377Smckusick if (fs->fs_contigdirs[cg] < maxcontigdirs) 113175377Smckusick return ((ino_t)(fs->fs_ipg * cg)); 113275377Smckusick } 113375377Smckusick /* 113475377Smckusick * This is a backstop when we have deficit in space. 113575377Smckusick */ 113675377Smckusick for (cg = prefcg; cg < fs->fs_ncg; cg++) 113775377Smckusick if (fs->fs_cs(fs, cg).cs_nifree >= avgifree) 113875377Smckusick return ((ino_t)(fs->fs_ipg * cg)); 113975377Smckusick for (cg = 0; cg < prefcg; cg++) 114075377Smckusick if (fs->fs_cs(fs, cg).cs_nifree >= avgifree) 114175377Smckusick break; 114275377Smckusick return ((ino_t)(fs->fs_ipg * cg)); 11431541Srgrimes} 11441541Srgrimes 11451541Srgrimes/* 11461541Srgrimes * Select the desired position for the next block in a file. The file is 11471541Srgrimes * logically divided into sections. The first section is composed of the 11481541Srgrimes * direct blocks. Each additional section contains fs_maxbpg blocks. 11498876Srgrimes * 11501541Srgrimes * If no blocks have been allocated in the first section, the policy is to 11511541Srgrimes * request a block in the same cylinder group as the inode that describes 11521541Srgrimes * the file. If no blocks have been allocated in any other section, the 11531541Srgrimes * policy is to place the section in a cylinder group with a greater than 11541541Srgrimes * average number of free blocks. An appropriate cylinder group is found 11551541Srgrimes * by using a rotor that sweeps the cylinder groups. When a new group of 11561541Srgrimes * blocks is needed, the sweep begins in the cylinder group following the 11571541Srgrimes * cylinder group from which the previous allocation was made. The sweep 11581541Srgrimes * continues until a cylinder group with greater than the average number 11591541Srgrimes * of free blocks is found. If the allocation is for the first block in an 11601541Srgrimes * indirect block, the information on the previous allocation is unavailable; 11611541Srgrimes * here a best guess is made based upon the logical block number being 11621541Srgrimes * allocated. 11638876Srgrimes * 11641541Srgrimes * If a section is already partially allocated, the policy is to 116598542Smckusick * contiguously allocate fs_maxcontig blocks. The end of one of these 116698542Smckusick * contiguous blocks and the beginning of the next is laid out 116798542Smckusick * contiguously if possible. 11681541Srgrimes */ 116998542Smckusickufs2_daddr_t 117098542Smckusickffs_blkpref_ufs1(ip, lbn, indx, bap) 11711541Srgrimes struct inode *ip; 117298542Smckusick ufs_lbn_t lbn; 11731541Srgrimes int indx; 117498542Smckusick ufs1_daddr_t *bap; 11751541Srgrimes{ 117696506Sphk struct fs *fs; 1177203763Smckusick u_int cg; 1178203763Smckusick u_int avgbfree, startcg; 11791541Srgrimes 1180140704Sjeff mtx_assert(UFS_MTX(ip->i_ump), MA_OWNED); 11811541Srgrimes fs = ip->i_fs; 11821541Srgrimes if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) { 118353996Smckusick if (lbn < NDADDR + NINDIR(fs)) { 11841541Srgrimes cg = ino_to_cg(fs, ip->i_number); 1185138634Smckusick return (cgbase(fs, cg) + fs->fs_frag); 11861541Srgrimes } 11871541Srgrimes /* 11881541Srgrimes * Find a cylinder with greater than average number of 11891541Srgrimes * unused data blocks. 11901541Srgrimes */ 11911541Srgrimes if (indx == 0 || bap[indx - 1] == 0) 11921541Srgrimes startcg = 11931541Srgrimes ino_to_cg(fs, ip->i_number) + lbn / fs->fs_maxbpg; 11941541Srgrimes else 11951541Srgrimes startcg = dtog(fs, bap[indx - 1]) + 1; 11961541Srgrimes startcg %= fs->fs_ncg; 11971541Srgrimes avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg; 11981541Srgrimes for (cg = startcg; cg < fs->fs_ncg; cg++) 11991541Srgrimes if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { 12001541Srgrimes fs->fs_cgrotor = cg; 1201138634Smckusick return (cgbase(fs, cg) + fs->fs_frag); 12021541Srgrimes } 12031541Srgrimes for (cg = 0; cg <= startcg; cg++) 12041541Srgrimes if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { 12051541Srgrimes fs->fs_cgrotor = cg; 1206138634Smckusick return (cgbase(fs, cg) + fs->fs_frag); 12071541Srgrimes } 120817108Sbde return (0); 12091541Srgrimes } 12101541Srgrimes /* 121198542Smckusick * We just always try to lay things out contiguously. 12121541Srgrimes */ 121398542Smckusick return (bap[indx - 1] + fs->fs_frag); 121498542Smckusick} 121598542Smckusick 121698542Smckusick/* 121798542Smckusick * Same as above, but for UFS2 121898542Smckusick */ 121998542Smckusickufs2_daddr_t 122098542Smckusickffs_blkpref_ufs2(ip, lbn, indx, bap) 122198542Smckusick struct inode *ip; 122298542Smckusick ufs_lbn_t lbn; 122398542Smckusick int indx; 122498542Smckusick ufs2_daddr_t *bap; 122598542Smckusick{ 122698542Smckusick struct fs *fs; 1227203763Smckusick u_int cg; 1228203763Smckusick u_int avgbfree, startcg; 122998542Smckusick 1230140704Sjeff mtx_assert(UFS_MTX(ip->i_ump), MA_OWNED); 123198542Smckusick fs = ip->i_fs; 123298542Smckusick if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) { 123398542Smckusick if (lbn < NDADDR + NINDIR(fs)) { 123498542Smckusick cg = ino_to_cg(fs, ip->i_number); 1235138634Smckusick return (cgbase(fs, cg) + fs->fs_frag); 123698542Smckusick } 123798542Smckusick /* 123898542Smckusick * Find a cylinder with greater than average number of 123998542Smckusick * unused data blocks. 124098542Smckusick */ 124198542Smckusick if (indx == 0 || bap[indx - 1] == 0) 124298542Smckusick startcg = 124398542Smckusick ino_to_cg(fs, ip->i_number) + lbn / fs->fs_maxbpg; 124498542Smckusick else 124598542Smckusick startcg = dtog(fs, bap[indx - 1]) + 1; 124698542Smckusick startcg %= fs->fs_ncg; 124798542Smckusick avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg; 124898542Smckusick for (cg = startcg; cg < fs->fs_ncg; cg++) 124998542Smckusick if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { 125098542Smckusick fs->fs_cgrotor = cg; 1251138634Smckusick return (cgbase(fs, cg) + fs->fs_frag); 125298542Smckusick } 125398542Smckusick for (cg = 0; cg <= startcg; cg++) 125498542Smckusick if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { 125598542Smckusick fs->fs_cgrotor = cg; 1256138634Smckusick return (cgbase(fs, cg) + fs->fs_frag); 125798542Smckusick } 125898542Smckusick return (0); 125998542Smckusick } 126010632Sdg /* 126198542Smckusick * We just always try to lay things out contiguously. 126210632Sdg */ 126398542Smckusick return (bap[indx - 1] + fs->fs_frag); 12641541Srgrimes} 12651541Srgrimes 12661541Srgrimes/* 12671541Srgrimes * Implement the cylinder overflow algorithm. 12681541Srgrimes * 12691541Srgrimes * The policy implemented by this algorithm is: 12701541Srgrimes * 1) allocate the block in its requested cylinder group. 12711541Srgrimes * 2) quadradically rehash on the cylinder group number. 12721541Srgrimes * 3) brute force search for a free block. 1273140704Sjeff * 1274140704Sjeff * Must be called with the UFS lock held. Will release the lock on success 1275140704Sjeff * and return with it held on failure. 12761541Srgrimes */ 12771541Srgrimes/*VARARGS5*/ 127898542Smckusickstatic ufs2_daddr_t 12791541Srgrimesffs_hashalloc(ip, cg, pref, size, allocator) 12801541Srgrimes struct inode *ip; 1281203763Smckusick u_int cg; 128298542Smckusick ufs2_daddr_t pref; 12831541Srgrimes int size; /* size for data blocks, mode for inodes */ 128412590Sbde allocfcn_t *allocator; 12851541Srgrimes{ 128696506Sphk struct fs *fs; 128798542Smckusick ufs2_daddr_t result; 1288203763Smckusick u_int i, icg = cg; 12891541Srgrimes 1290140704Sjeff mtx_assert(UFS_MTX(ip->i_ump), MA_OWNED); 1291173464Sobrien#ifdef INVARIANTS 129262976Smckusick if (ITOV(ip)->v_mount->mnt_kern_flag & MNTK_SUSPENDED) 129362976Smckusick panic("ffs_hashalloc: allocation on suspended filesystem"); 129462976Smckusick#endif 12951541Srgrimes fs = ip->i_fs; 12961541Srgrimes /* 12971541Srgrimes * 1: preferred cylinder group 12981541Srgrimes */ 12991541Srgrimes result = (*allocator)(ip, cg, pref, size); 13001541Srgrimes if (result) 13011541Srgrimes return (result); 13021541Srgrimes /* 13031541Srgrimes * 2: quadratic rehash 13041541Srgrimes */ 13051541Srgrimes for (i = 1; i < fs->fs_ncg; i *= 2) { 13061541Srgrimes cg += i; 13071541Srgrimes if (cg >= fs->fs_ncg) 13081541Srgrimes cg -= fs->fs_ncg; 13091541Srgrimes result = (*allocator)(ip, cg, 0, size); 13101541Srgrimes if (result) 13111541Srgrimes return (result); 13121541Srgrimes } 13131541Srgrimes /* 13141541Srgrimes * 3: brute force search 13151541Srgrimes * Note that we start at i == 2, since 0 was checked initially, 13161541Srgrimes * and 1 is always checked in the quadratic rehash. 13171541Srgrimes */ 13181541Srgrimes cg = (icg + 2) % fs->fs_ncg; 13191541Srgrimes for (i = 2; i < fs->fs_ncg; i++) { 13201541Srgrimes result = (*allocator)(ip, cg, 0, size); 13211541Srgrimes if (result) 13221541Srgrimes return (result); 13231541Srgrimes cg++; 13241541Srgrimes if (cg == fs->fs_ncg) 13251541Srgrimes cg = 0; 13261541Srgrimes } 132712590Sbde return (0); 13281541Srgrimes} 13291541Srgrimes 13301541Srgrimes/* 13311541Srgrimes * Determine whether a fragment can be extended. 13321541Srgrimes * 13338876Srgrimes * Check to see if the necessary fragments are available, and 13341541Srgrimes * if they are, allocate them. 13351541Srgrimes */ 133698542Smckusickstatic ufs2_daddr_t 13371541Srgrimesffs_fragextend(ip, cg, bprev, osize, nsize) 13381541Srgrimes struct inode *ip; 1339203763Smckusick u_int cg; 134098542Smckusick ufs2_daddr_t bprev; 13411541Srgrimes int osize, nsize; 13421541Srgrimes{ 134396506Sphk struct fs *fs; 134496506Sphk struct cg *cgp; 13451541Srgrimes struct buf *bp; 1346140704Sjeff struct ufsmount *ump; 1347140704Sjeff int nffree; 13481541Srgrimes long bno; 13491541Srgrimes int frags, bbase; 13501541Srgrimes int i, error; 135158087Smckusick u_int8_t *blksfree; 13521541Srgrimes 1353140704Sjeff ump = ip->i_ump; 13541541Srgrimes fs = ip->i_fs; 13551541Srgrimes if (fs->fs_cs(fs, cg).cs_nffree < numfrags(fs, nsize - osize)) 135617108Sbde return (0); 13571541Srgrimes frags = numfrags(fs, nsize); 13581541Srgrimes bbase = fragnum(fs, bprev); 13591541Srgrimes if (bbase > fragnum(fs, (bprev + frags - 1))) { 13601541Srgrimes /* cannot extend across a block boundary */ 136117108Sbde return (0); 13621541Srgrimes } 1363140704Sjeff UFS_UNLOCK(ump); 13641541Srgrimes error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)), 13651541Srgrimes (int)fs->fs_cgsize, NOCRED, &bp); 1366140704Sjeff if (error) 1367140704Sjeff goto fail; 13681541Srgrimes cgp = (struct cg *)bp->b_data; 1369140704Sjeff if (!cg_chkmagic(cgp)) 1370140704Sjeff goto fail; 137155697Smckusick bp->b_xflags |= BX_BKGRDWRITE; 137298542Smckusick cgp->cg_old_time = cgp->cg_time = time_second; 13731541Srgrimes bno = dtogd(fs, bprev); 137458087Smckusick blksfree = cg_blksfree(cgp); 13751541Srgrimes for (i = numfrags(fs, osize); i < frags; i++) 1376140704Sjeff if (isclr(blksfree, bno + i)) 1377140704Sjeff goto fail; 13781541Srgrimes /* 13791541Srgrimes * the current fragment can be extended 13801541Srgrimes * deduct the count on fragment being extended into 13811541Srgrimes * increase the count on the remaining fragment (if any) 13821541Srgrimes * allocate the extended piece 13831541Srgrimes */ 13841541Srgrimes for (i = frags; i < fs->fs_frag - bbase; i++) 138558087Smckusick if (isclr(blksfree, bno + i)) 13861541Srgrimes break; 13871541Srgrimes cgp->cg_frsum[i - numfrags(fs, osize)]--; 13881541Srgrimes if (i != frags) 13891541Srgrimes cgp->cg_frsum[i - frags]++; 1390140704Sjeff for (i = numfrags(fs, osize), nffree = 0; i < frags; i++) { 139158087Smckusick clrbit(blksfree, bno + i); 13921541Srgrimes cgp->cg_cs.cs_nffree--; 1393140704Sjeff nffree++; 13941541Srgrimes } 1395140704Sjeff UFS_LOCK(ump); 1396140704Sjeff fs->fs_cstotal.cs_nffree -= nffree; 1397140704Sjeff fs->fs_cs(fs, cg).cs_nffree -= nffree; 13981541Srgrimes fs->fs_fmod = 1; 1399140704Sjeff ACTIVECLEAR(fs, cg); 1400140704Sjeff UFS_UNLOCK(ump); 140134266Sjulian if (DOINGSOFTDEP(ITOV(ip))) 1402156203Sjeff softdep_setup_blkmapdep(bp, UFSTOVFS(ump), bprev); 14031541Srgrimes bdwrite(bp); 14041541Srgrimes return (bprev); 1405140704Sjeff 1406140704Sjefffail: 1407140704Sjeff brelse(bp); 1408140704Sjeff UFS_LOCK(ump); 1409140704Sjeff return (0); 1410140704Sjeff 14111541Srgrimes} 14121541Srgrimes 14131541Srgrimes/* 14141541Srgrimes * Determine whether a block can be allocated. 14151541Srgrimes * 14161541Srgrimes * Check to see if a block of the appropriate size is available, 14171541Srgrimes * and if it is, allocate it. 14181541Srgrimes */ 141998542Smckusickstatic ufs2_daddr_t 14201541Srgrimesffs_alloccg(ip, cg, bpref, size) 14211541Srgrimes struct inode *ip; 1422203763Smckusick u_int cg; 142398542Smckusick ufs2_daddr_t bpref; 14241541Srgrimes int size; 14251541Srgrimes{ 142696506Sphk struct fs *fs; 142796506Sphk struct cg *cgp; 14281541Srgrimes struct buf *bp; 1429140704Sjeff struct ufsmount *ump; 143098542Smckusick ufs1_daddr_t bno; 143198542Smckusick ufs2_daddr_t blkno; 143298542Smckusick int i, allocsiz, error, frags; 143358087Smckusick u_int8_t *blksfree; 14341541Srgrimes 1435140704Sjeff ump = ip->i_ump; 14361541Srgrimes fs = ip->i_fs; 14371541Srgrimes if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize) 143817108Sbde return (0); 1439140704Sjeff UFS_UNLOCK(ump); 14401541Srgrimes error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)), 14411541Srgrimes (int)fs->fs_cgsize, NOCRED, &bp); 1442140704Sjeff if (error) 1443140704Sjeff goto fail; 14441541Srgrimes cgp = (struct cg *)bp->b_data; 14451541Srgrimes if (!cg_chkmagic(cgp) || 1446140704Sjeff (cgp->cg_cs.cs_nbfree == 0 && size == fs->fs_bsize)) 1447140704Sjeff goto fail; 144855697Smckusick bp->b_xflags |= BX_BKGRDWRITE; 144998542Smckusick cgp->cg_old_time = cgp->cg_time = time_second; 14501541Srgrimes if (size == fs->fs_bsize) { 1451140704Sjeff UFS_LOCK(ump); 145298542Smckusick blkno = ffs_alloccgblk(ip, bp, bpref); 1453140704Sjeff ACTIVECLEAR(fs, cg); 1454140704Sjeff UFS_UNLOCK(ump); 14551541Srgrimes bdwrite(bp); 145698542Smckusick return (blkno); 14571541Srgrimes } 14581541Srgrimes /* 14591541Srgrimes * check to see if any fragments are already available 14601541Srgrimes * allocsiz is the size which will be allocated, hacking 14611541Srgrimes * it down to a smaller size if necessary 14621541Srgrimes */ 146358087Smckusick blksfree = cg_blksfree(cgp); 14641541Srgrimes frags = numfrags(fs, size); 14651541Srgrimes for (allocsiz = frags; allocsiz < fs->fs_frag; allocsiz++) 14661541Srgrimes if (cgp->cg_frsum[allocsiz] != 0) 14671541Srgrimes break; 14681541Srgrimes if (allocsiz == fs->fs_frag) { 14691541Srgrimes /* 14708876Srgrimes * no fragments were available, so a block will be 14711541Srgrimes * allocated, and hacked up 14721541Srgrimes */ 1473140704Sjeff if (cgp->cg_cs.cs_nbfree == 0) 1474140704Sjeff goto fail; 1475140704Sjeff UFS_LOCK(ump); 147698542Smckusick blkno = ffs_alloccgblk(ip, bp, bpref); 147798542Smckusick bno = dtogd(fs, blkno); 14781541Srgrimes for (i = frags; i < fs->fs_frag; i++) 147998542Smckusick setbit(blksfree, bno + i); 14801541Srgrimes i = fs->fs_frag - frags; 14811541Srgrimes cgp->cg_cs.cs_nffree += i; 14821541Srgrimes fs->fs_cstotal.cs_nffree += i; 14831541Srgrimes fs->fs_cs(fs, cg).cs_nffree += i; 14841541Srgrimes fs->fs_fmod = 1; 14851541Srgrimes cgp->cg_frsum[i]++; 1486140704Sjeff ACTIVECLEAR(fs, cg); 1487140704Sjeff UFS_UNLOCK(ump); 14881541Srgrimes bdwrite(bp); 148998542Smckusick return (blkno); 14901541Srgrimes } 14911541Srgrimes bno = ffs_mapsearch(fs, cgp, bpref, allocsiz); 1492140704Sjeff if (bno < 0) 1493140704Sjeff goto fail; 14941541Srgrimes for (i = 0; i < frags; i++) 149558087Smckusick clrbit(blksfree, bno + i); 14961541Srgrimes cgp->cg_cs.cs_nffree -= frags; 1497140704Sjeff cgp->cg_frsum[allocsiz]--; 1498140704Sjeff if (frags != allocsiz) 1499140704Sjeff cgp->cg_frsum[allocsiz - frags]++; 1500140704Sjeff UFS_LOCK(ump); 15011541Srgrimes fs->fs_cstotal.cs_nffree -= frags; 15021541Srgrimes fs->fs_cs(fs, cg).cs_nffree -= frags; 15031541Srgrimes fs->fs_fmod = 1; 1504138634Smckusick blkno = cgbase(fs, cg) + bno; 1505140704Sjeff ACTIVECLEAR(fs, cg); 1506140704Sjeff UFS_UNLOCK(ump); 150734266Sjulian if (DOINGSOFTDEP(ITOV(ip))) 1508156203Sjeff softdep_setup_blkmapdep(bp, UFSTOVFS(ump), blkno); 15091541Srgrimes bdwrite(bp); 151098542Smckusick return (blkno); 1511140704Sjeff 1512140704Sjefffail: 1513140704Sjeff brelse(bp); 1514140704Sjeff UFS_LOCK(ump); 1515140704Sjeff return (0); 15161541Srgrimes} 15171541Srgrimes 15181541Srgrimes/* 15191541Srgrimes * Allocate a block in a cylinder group. 15201541Srgrimes * 15211541Srgrimes * This algorithm implements the following policy: 15221541Srgrimes * 1) allocate the requested block. 15231541Srgrimes * 2) allocate a rotationally optimal block in the same cylinder. 15241541Srgrimes * 3) allocate the next available block on the block rotor for the 15251541Srgrimes * specified cylinder group. 15261541Srgrimes * Note that this routine only allocates fs_bsize blocks; these 15271541Srgrimes * blocks may be fragmented by the routine that allocates them. 15281541Srgrimes */ 152998542Smckusickstatic ufs2_daddr_t 153034266Sjulianffs_alloccgblk(ip, bp, bpref) 153134266Sjulian struct inode *ip; 153234266Sjulian struct buf *bp; 153398542Smckusick ufs2_daddr_t bpref; 15341541Srgrimes{ 153534266Sjulian struct fs *fs; 153634266Sjulian struct cg *cgp; 1537140704Sjeff struct ufsmount *ump; 153898542Smckusick ufs1_daddr_t bno; 153998542Smckusick ufs2_daddr_t blkno; 154058087Smckusick u_int8_t *blksfree; 15411541Srgrimes 154234266Sjulian fs = ip->i_fs; 1543140704Sjeff ump = ip->i_ump; 1544140704Sjeff mtx_assert(UFS_MTX(ump), MA_OWNED); 154534266Sjulian cgp = (struct cg *)bp->b_data; 154658087Smckusick blksfree = cg_blksfree(cgp); 15471541Srgrimes if (bpref == 0 || dtog(fs, bpref) != cgp->cg_cgx) { 15481541Srgrimes bpref = cgp->cg_rotor; 154998542Smckusick } else { 155098542Smckusick bpref = blknum(fs, bpref); 155198542Smckusick bno = dtogd(fs, bpref); 15521541Srgrimes /* 155398542Smckusick * if the requested block is available, use it 15541541Srgrimes */ 155598542Smckusick if (ffs_isblock(fs, blksfree, fragstoblks(fs, bno))) 155698542Smckusick goto gotit; 15571541Srgrimes } 15581541Srgrimes /* 155998542Smckusick * Take the next available block in this cylinder group. 15606769Sse */ 15611541Srgrimes bno = ffs_mapsearch(fs, cgp, bpref, (int)fs->fs_frag); 15621541Srgrimes if (bno < 0) 156317108Sbde return (0); 15641541Srgrimes cgp->cg_rotor = bno; 15651541Srgrimesgotit: 15661541Srgrimes blkno = fragstoblks(fs, bno); 156758087Smckusick ffs_clrblock(fs, blksfree, (long)blkno); 1568140704Sjeff ffs_clusteracct(ump, fs, cgp, blkno, -1); 15691541Srgrimes cgp->cg_cs.cs_nbfree--; 15701541Srgrimes fs->fs_cstotal.cs_nbfree--; 15711541Srgrimes fs->fs_cs(fs, cgp->cg_cgx).cs_nbfree--; 15721541Srgrimes fs->fs_fmod = 1; 1573138634Smckusick blkno = cgbase(fs, cgp->cg_cgx) + bno; 1574140704Sjeff /* XXX Fixme. */ 1575140704Sjeff UFS_UNLOCK(ump); 157634266Sjulian if (DOINGSOFTDEP(ITOV(ip))) 1577156203Sjeff softdep_setup_blkmapdep(bp, UFSTOVFS(ump), blkno); 1578140704Sjeff UFS_LOCK(ump); 157934266Sjulian return (blkno); 15801541Srgrimes} 15811541Srgrimes 15821541Srgrimes/* 15831541Srgrimes * Determine whether a cluster can be allocated. 15841541Srgrimes * 15851541Srgrimes * We do not currently check for optimal rotational layout if there 15861541Srgrimes * are multiple choices in the same cylinder group. Instead we just 15871541Srgrimes * take the first one that we find following bpref. 15881541Srgrimes */ 158998542Smckusickstatic ufs2_daddr_t 15901541Srgrimesffs_clusteralloc(ip, cg, bpref, len) 15911541Srgrimes struct inode *ip; 1592203763Smckusick u_int cg; 159398542Smckusick ufs2_daddr_t bpref; 15941541Srgrimes int len; 15951541Srgrimes{ 159696506Sphk struct fs *fs; 159796506Sphk struct cg *cgp; 15981541Srgrimes struct buf *bp; 1599140704Sjeff struct ufsmount *ump; 160098542Smckusick int i, run, bit, map, got; 160198542Smckusick ufs2_daddr_t bno; 16021541Srgrimes u_char *mapp; 160322521Sdyson int32_t *lp; 160458087Smckusick u_int8_t *blksfree; 16051541Srgrimes 16061541Srgrimes fs = ip->i_fs; 1607140704Sjeff ump = ip->i_ump; 160822521Sdyson if (fs->fs_maxcluster[cg] < len) 160954952Seivind return (0); 1610140704Sjeff UFS_UNLOCK(ump); 16111541Srgrimes if (bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, 16121541Srgrimes NOCRED, &bp)) 1613140704Sjeff goto fail_lock; 16141541Srgrimes cgp = (struct cg *)bp->b_data; 16151541Srgrimes if (!cg_chkmagic(cgp)) 1616140704Sjeff goto fail_lock; 161755697Smckusick bp->b_xflags |= BX_BKGRDWRITE; 16181541Srgrimes /* 16191541Srgrimes * Check to see if a cluster of the needed size (or bigger) is 16201541Srgrimes * available in this cylinder group. 16211541Srgrimes */ 162222521Sdyson lp = &cg_clustersum(cgp)[len]; 16231541Srgrimes for (i = len; i <= fs->fs_contigsumsize; i++) 162422521Sdyson if (*lp++ > 0) 16251541Srgrimes break; 162622521Sdyson if (i > fs->fs_contigsumsize) { 162722521Sdyson /* 162822521Sdyson * This is the first time looking for a cluster in this 162922521Sdyson * cylinder group. Update the cluster summary information 163022521Sdyson * to reflect the true maximum sized cluster so that 163122521Sdyson * future cluster allocation requests can avoid reading 163222521Sdyson * the cylinder group map only to find no clusters. 163322521Sdyson */ 163422521Sdyson lp = &cg_clustersum(cgp)[len - 1]; 163522521Sdyson for (i = len - 1; i > 0; i--) 163622521Sdyson if (*lp-- > 0) 163722521Sdyson break; 1638140704Sjeff UFS_LOCK(ump); 163922521Sdyson fs->fs_maxcluster[cg] = i; 16401541Srgrimes goto fail; 164122521Sdyson } 16421541Srgrimes /* 16431541Srgrimes * Search the cluster map to find a big enough cluster. 16441541Srgrimes * We take the first one that we find, even if it is larger 16451541Srgrimes * than we need as we prefer to get one close to the previous 16461541Srgrimes * block allocation. We do not search before the current 16471541Srgrimes * preference point as we do not want to allocate a block 16481541Srgrimes * that is allocated before the previous one (as we will 16491541Srgrimes * then have to wait for another pass of the elevator 16501541Srgrimes * algorithm before it will be read). We prefer to fail and 16511541Srgrimes * be recalled to try an allocation in the next cylinder group. 16521541Srgrimes */ 16531541Srgrimes if (dtog(fs, bpref) != cg) 16541541Srgrimes bpref = 0; 16551541Srgrimes else 16561541Srgrimes bpref = fragstoblks(fs, dtogd(fs, blknum(fs, bpref))); 16571541Srgrimes mapp = &cg_clustersfree(cgp)[bpref / NBBY]; 16581541Srgrimes map = *mapp++; 16591541Srgrimes bit = 1 << (bpref % NBBY); 166022521Sdyson for (run = 0, got = bpref; got < cgp->cg_nclusterblks; got++) { 16611541Srgrimes if ((map & bit) == 0) { 16621541Srgrimes run = 0; 16631541Srgrimes } else { 16641541Srgrimes run++; 16651541Srgrimes if (run == len) 16661541Srgrimes break; 16671541Srgrimes } 166822521Sdyson if ((got & (NBBY - 1)) != (NBBY - 1)) { 16691541Srgrimes bit <<= 1; 16701541Srgrimes } else { 16711541Srgrimes map = *mapp++; 16721541Srgrimes bit = 1; 16731541Srgrimes } 16741541Srgrimes } 167527890Sphk if (got >= cgp->cg_nclusterblks) 1676140704Sjeff goto fail_lock; 16771541Srgrimes /* 16781541Srgrimes * Allocate the cluster that we have found. 16791541Srgrimes */ 168058087Smckusick blksfree = cg_blksfree(cgp); 168122521Sdyson for (i = 1; i <= len; i++) 168258087Smckusick if (!ffs_isblock(fs, blksfree, got - run + i)) 168322521Sdyson panic("ffs_clusteralloc: map mismatch"); 1684138634Smckusick bno = cgbase(fs, cg) + blkstofrags(fs, got - run + 1); 168522521Sdyson if (dtog(fs, bno) != cg) 168622521Sdyson panic("ffs_clusteralloc: allocated out of group"); 16871541Srgrimes len = blkstofrags(fs, len); 1688140704Sjeff UFS_LOCK(ump); 16891541Srgrimes for (i = 0; i < len; i += fs->fs_frag) 169098542Smckusick if (ffs_alloccgblk(ip, bp, bno + i) != bno + i) 16911541Srgrimes panic("ffs_clusteralloc: lost block"); 1692140704Sjeff ACTIVECLEAR(fs, cg); 1693140704Sjeff UFS_UNLOCK(ump); 16949980Sdg bdwrite(bp); 16951541Srgrimes return (bno); 16961541Srgrimes 1697140704Sjefffail_lock: 1698140704Sjeff UFS_LOCK(ump); 16991541Srgrimesfail: 17001541Srgrimes brelse(bp); 17011541Srgrimes return (0); 17021541Srgrimes} 17031541Srgrimes 17041541Srgrimes/* 17051541Srgrimes * Determine whether an inode can be allocated. 17061541Srgrimes * 17071541Srgrimes * Check to see if an inode is available, and if it is, 17081541Srgrimes * allocate it using the following policy: 17091541Srgrimes * 1) allocate the requested inode. 17101541Srgrimes * 2) allocate the next available inode after the requested 17111541Srgrimes * inode in the specified cylinder group. 17121541Srgrimes */ 171398640Smckusickstatic ufs2_daddr_t 17141541Srgrimesffs_nodealloccg(ip, cg, ipref, mode) 17151541Srgrimes struct inode *ip; 1716203763Smckusick u_int cg; 171798542Smckusick ufs2_daddr_t ipref; 17181541Srgrimes int mode; 17191541Srgrimes{ 172096506Sphk struct fs *fs; 172196506Sphk struct cg *cgp; 172298542Smckusick struct buf *bp, *ibp; 1723140704Sjeff struct ufsmount *ump; 172458087Smckusick u_int8_t *inosused; 172598542Smckusick struct ufs2_dinode *dp2; 17261541Srgrimes int error, start, len, loc, map, i; 17271541Srgrimes 17281541Srgrimes fs = ip->i_fs; 1729140704Sjeff ump = ip->i_ump; 17301541Srgrimes if (fs->fs_cs(fs, cg).cs_nifree == 0) 173117108Sbde return (0); 1732140704Sjeff UFS_UNLOCK(ump); 17331541Srgrimes error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)), 17341541Srgrimes (int)fs->fs_cgsize, NOCRED, &bp); 17351541Srgrimes if (error) { 17361541Srgrimes brelse(bp); 1737140704Sjeff UFS_LOCK(ump); 173817108Sbde return (0); 17391541Srgrimes } 17401541Srgrimes cgp = (struct cg *)bp->b_data; 17411541Srgrimes if (!cg_chkmagic(cgp) || cgp->cg_cs.cs_nifree == 0) { 17421541Srgrimes brelse(bp); 1743140704Sjeff UFS_LOCK(ump); 174417108Sbde return (0); 17451541Srgrimes } 174655697Smckusick bp->b_xflags |= BX_BKGRDWRITE; 174798542Smckusick cgp->cg_old_time = cgp->cg_time = time_second; 174858087Smckusick inosused = cg_inosused(cgp); 17491541Srgrimes if (ipref) { 17501541Srgrimes ipref %= fs->fs_ipg; 175158087Smckusick if (isclr(inosused, ipref)) 17521541Srgrimes goto gotit; 17531541Srgrimes } 17541541Srgrimes start = cgp->cg_irotor / NBBY; 17551541Srgrimes len = howmany(fs->fs_ipg - cgp->cg_irotor, NBBY); 175658087Smckusick loc = skpc(0xff, len, &inosused[start]); 17571541Srgrimes if (loc == 0) { 17581541Srgrimes len = start + 1; 17591541Srgrimes start = 0; 176058087Smckusick loc = skpc(0xff, len, &inosused[0]); 17611541Srgrimes if (loc == 0) { 17626357Sphk printf("cg = %d, irotor = %ld, fs = %s\n", 176337555Sbde cg, (long)cgp->cg_irotor, fs->fs_fsmnt); 17641541Srgrimes panic("ffs_nodealloccg: map corrupted"); 17651541Srgrimes /* NOTREACHED */ 17661541Srgrimes } 17671541Srgrimes } 17681541Srgrimes i = start + len - loc; 176958087Smckusick map = inosused[i]; 17701541Srgrimes ipref = i * NBBY; 17711541Srgrimes for (i = 1; i < (1 << NBBY); i <<= 1, ipref++) { 17721541Srgrimes if ((map & i) == 0) { 17731541Srgrimes cgp->cg_irotor = ipref; 17741541Srgrimes goto gotit; 17751541Srgrimes } 17761541Srgrimes } 17771541Srgrimes printf("fs = %s\n", fs->fs_fsmnt); 17781541Srgrimes panic("ffs_nodealloccg: block not in map"); 17791541Srgrimes /* NOTREACHED */ 17801541Srgrimesgotit: 178198542Smckusick /* 178298542Smckusick * Check to see if we need to initialize more inodes. 178398542Smckusick */ 1784127095Skan ibp = NULL; 178598542Smckusick if (fs->fs_magic == FS_UFS2_MAGIC && 178698542Smckusick ipref + INOPB(fs) > cgp->cg_initediblk && 178798542Smckusick cgp->cg_initediblk < cgp->cg_niblk) { 178898542Smckusick ibp = getblk(ip->i_devvp, fsbtodb(fs, 178998542Smckusick ino_to_fsba(fs, cg * fs->fs_ipg + cgp->cg_initediblk)), 1790111856Sjeff (int)fs->fs_bsize, 0, 0, 0); 179198542Smckusick bzero(ibp->b_data, (int)fs->fs_bsize); 179298542Smckusick dp2 = (struct ufs2_dinode *)(ibp->b_data); 179398542Smckusick for (i = 0; i < INOPB(fs); i++) { 1794110885Smckusick dp2->di_gen = arc4random() / 2 + 1; 179598542Smckusick dp2++; 179698542Smckusick } 179798542Smckusick cgp->cg_initediblk += INOPB(fs); 179898542Smckusick } 1799140704Sjeff UFS_LOCK(ump); 1800140704Sjeff ACTIVECLEAR(fs, cg); 1801140704Sjeff setbit(inosused, ipref); 1802140704Sjeff cgp->cg_cs.cs_nifree--; 1803140704Sjeff fs->fs_cstotal.cs_nifree--; 1804140704Sjeff fs->fs_cs(fs, cg).cs_nifree--; 1805140704Sjeff fs->fs_fmod = 1; 1806140704Sjeff if ((mode & IFMT) == IFDIR) { 1807140704Sjeff cgp->cg_cs.cs_ndir++; 1808140704Sjeff fs->fs_cstotal.cs_ndir++; 1809140704Sjeff fs->fs_cs(fs, cg).cs_ndir++; 1810140704Sjeff } 1811140704Sjeff UFS_UNLOCK(ump); 1812140704Sjeff if (DOINGSOFTDEP(ITOV(ip))) 1813140704Sjeff softdep_setup_inomapdep(bp, ip, cg * fs->fs_ipg + ipref); 18141541Srgrimes bdwrite(bp); 1815127095Skan if (ibp != NULL) 1816127095Skan bawrite(ibp); 1817203763Smckusick return ((ino_t)(cg * fs->fs_ipg + ipref)); 18181541Srgrimes} 18191541Srgrimes 18201541Srgrimes/* 1821100925Sphk * check if a block is free 1822100925Sphk */ 1823100925Sphkstatic int 1824108010Smckusickffs_isfreeblock(struct fs *fs, u_char *cp, ufs1_daddr_t h) 1825100925Sphk{ 1826100925Sphk 1827100925Sphk switch ((int)fs->fs_frag) { 1828100925Sphk case 8: 1829100925Sphk return (cp[h] == 0); 1830100925Sphk case 4: 1831100925Sphk return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0); 1832100925Sphk case 2: 1833100925Sphk return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0); 1834100925Sphk case 1: 1835100925Sphk return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0); 1836100925Sphk default: 1837100925Sphk panic("ffs_isfreeblock"); 1838100925Sphk } 1839100925Sphk return (0); 1840100925Sphk} 1841100925Sphk 1842100925Sphk/* 18431541Srgrimes * Free a block or fragment. 18441541Srgrimes * 18451541Srgrimes * The specified block or fragment is placed back in the 18468876Srgrimes * free map. If a fragment is deallocated, a possible 18471541Srgrimes * block reassembly is checked. 18481541Srgrimes */ 18491549Srgrimesvoid 1850140704Sjeffffs_blkfree(ump, fs, devvp, bno, size, inum) 1851140704Sjeff struct ufsmount *ump; 185290098Smckusick struct fs *fs; 185390098Smckusick struct vnode *devvp; 185498542Smckusick ufs2_daddr_t bno; 18551541Srgrimes long size; 185690098Smckusick ino_t inum; 18571541Srgrimes{ 185890098Smckusick struct cg *cgp; 18591541Srgrimes struct buf *bp; 186098542Smckusick ufs1_daddr_t fragno, cgbno; 186198542Smckusick ufs2_daddr_t cgblkno; 1862203763Smckusick int i, blk, frags, bbase; 1863203763Smckusick u_int cg; 186458087Smckusick u_int8_t *blksfree; 1865130585Sphk struct cdev *dev; 18661541Srgrimes 186790098Smckusick cg = dtog(fs, bno); 1868188240Strasz if (devvp->v_type == VREG) { 186990098Smckusick /* devvp is a snapshot */ 187090098Smckusick dev = VTOI(devvp)->i_devvp->v_rdev; 187198542Smckusick cgblkno = fragstoblks(fs, cgtod(fs, cg)); 187290098Smckusick } else { 187390098Smckusick /* devvp is a normal disk device */ 187490098Smckusick dev = devvp->v_rdev; 187598542Smckusick cgblkno = fsbtodb(fs, cgtod(fs, cg)); 1876101308Sjeff ASSERT_VOP_LOCKED(devvp, "ffs_blkfree"); 1877101308Sjeff if ((devvp->v_vflag & VV_COPYONWRITE) && 187890098Smckusick ffs_snapblkfree(fs, devvp, bno, size, inum)) 187990098Smckusick return; 188090098Smckusick } 1881173464Sobrien#ifdef INVARIANTS 188234266Sjulian if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0 || 188334266Sjulian fragnum(fs, bno) + numfrags(fs, size) > fs->fs_frag) { 1884103594Sobrien printf("dev=%s, bno = %jd, bsize = %ld, size = %ld, fs = %s\n", 188598542Smckusick devtoname(dev), (intmax_t)bno, (long)fs->fs_bsize, 188690098Smckusick size, fs->fs_fsmnt); 188723560Smpp panic("ffs_blkfree: bad size"); 18881541Srgrimes } 188962976Smckusick#endif 18901541Srgrimes if ((u_int)bno >= fs->fs_size) { 189198687Smux printf("bad block %jd, ino %lu\n", (intmax_t)bno, 189298542Smckusick (u_long)inum); 189390098Smckusick ffs_fserr(fs, inum, "bad block"); 18941541Srgrimes return; 18951541Srgrimes } 1896115474Sphk if (bread(devvp, cgblkno, (int)fs->fs_cgsize, NOCRED, &bp)) { 18971541Srgrimes brelse(bp); 18981541Srgrimes return; 18991541Srgrimes } 19001541Srgrimes cgp = (struct cg *)bp->b_data; 19011541Srgrimes if (!cg_chkmagic(cgp)) { 19021541Srgrimes brelse(bp); 19031541Srgrimes return; 19041541Srgrimes } 190555697Smckusick bp->b_xflags |= BX_BKGRDWRITE; 190698542Smckusick cgp->cg_old_time = cgp->cg_time = time_second; 190774545Smckusick cgbno = dtogd(fs, bno); 190858087Smckusick blksfree = cg_blksfree(cgp); 1909140704Sjeff UFS_LOCK(ump); 19101541Srgrimes if (size == fs->fs_bsize) { 191174545Smckusick fragno = fragstoblks(fs, cgbno); 191274545Smckusick if (!ffs_isfreeblock(fs, blksfree, fragno)) { 1913188240Strasz if (devvp->v_type == VREG) { 1914140704Sjeff UFS_UNLOCK(ump); 191590098Smckusick /* devvp is a snapshot */ 191690098Smckusick brelse(bp); 191790098Smckusick return; 191890098Smckusick } 191998687Smux printf("dev = %s, block = %jd, fs = %s\n", 192098542Smckusick devtoname(dev), (intmax_t)bno, fs->fs_fsmnt); 192123560Smpp panic("ffs_blkfree: freeing free block"); 19221541Srgrimes } 192374545Smckusick ffs_setblock(fs, blksfree, fragno); 1924140704Sjeff ffs_clusteracct(ump, fs, cgp, fragno, 1); 19251541Srgrimes cgp->cg_cs.cs_nbfree++; 19261541Srgrimes fs->fs_cstotal.cs_nbfree++; 19271541Srgrimes fs->fs_cs(fs, cg).cs_nbfree++; 19281541Srgrimes } else { 192974545Smckusick bbase = cgbno - fragnum(fs, cgbno); 19301541Srgrimes /* 19311541Srgrimes * decrement the counts associated with the old frags 19321541Srgrimes */ 193358087Smckusick blk = blkmap(fs, blksfree, bbase); 19341541Srgrimes ffs_fragacct(fs, blk, cgp->cg_frsum, -1); 19351541Srgrimes /* 19361541Srgrimes * deallocate the fragment 19371541Srgrimes */ 19381541Srgrimes frags = numfrags(fs, size); 19391541Srgrimes for (i = 0; i < frags; i++) { 194074545Smckusick if (isset(blksfree, cgbno + i)) { 194198687Smux printf("dev = %s, block = %jd, fs = %s\n", 194298542Smckusick devtoname(dev), (intmax_t)(bno + i), 194337555Sbde fs->fs_fsmnt); 194423560Smpp panic("ffs_blkfree: freeing free frag"); 19451541Srgrimes } 194674545Smckusick setbit(blksfree, cgbno + i); 19471541Srgrimes } 19481541Srgrimes cgp->cg_cs.cs_nffree += i; 19491541Srgrimes fs->fs_cstotal.cs_nffree += i; 19501541Srgrimes fs->fs_cs(fs, cg).cs_nffree += i; 19511541Srgrimes /* 19521541Srgrimes * add back in counts associated with the new frags 19531541Srgrimes */ 195458087Smckusick blk = blkmap(fs, blksfree, bbase); 19551541Srgrimes ffs_fragacct(fs, blk, cgp->cg_frsum, 1); 19561541Srgrimes /* 19571541Srgrimes * if a complete block has been reassembled, account for it 19581541Srgrimes */ 195974545Smckusick fragno = fragstoblks(fs, bbase); 196074545Smckusick if (ffs_isblock(fs, blksfree, fragno)) { 19611541Srgrimes cgp->cg_cs.cs_nffree -= fs->fs_frag; 19621541Srgrimes fs->fs_cstotal.cs_nffree -= fs->fs_frag; 19631541Srgrimes fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag; 1964140704Sjeff ffs_clusteracct(ump, fs, cgp, fragno, 1); 19651541Srgrimes cgp->cg_cs.cs_nbfree++; 19661541Srgrimes fs->fs_cstotal.cs_nbfree++; 19671541Srgrimes fs->fs_cs(fs, cg).cs_nbfree++; 19681541Srgrimes } 19691541Srgrimes } 19701541Srgrimes fs->fs_fmod = 1; 1971140704Sjeff ACTIVECLEAR(fs, cg); 1972140704Sjeff UFS_UNLOCK(ump); 19731541Srgrimes bdwrite(bp); 19741541Srgrimes} 19751541Srgrimes 1976173464Sobrien#ifdef INVARIANTS 19771541Srgrimes/* 197822521Sdyson * Verify allocation of a block or fragment. Returns true if block or 197922521Sdyson * fragment is allocated, false if it is free. 198022521Sdyson */ 198131352Sbdestatic int 198222521Sdysonffs_checkblk(ip, bno, size) 198322521Sdyson struct inode *ip; 198498542Smckusick ufs2_daddr_t bno; 198522521Sdyson long size; 198622521Sdyson{ 198722521Sdyson struct fs *fs; 198822521Sdyson struct cg *cgp; 198922521Sdyson struct buf *bp; 199098542Smckusick ufs1_daddr_t cgbno; 199122521Sdyson int i, error, frags, free; 199258087Smckusick u_int8_t *blksfree; 199322521Sdyson 199422521Sdyson fs = ip->i_fs; 199522521Sdyson if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0) { 199637555Sbde printf("bsize = %ld, size = %ld, fs = %s\n", 199737555Sbde (long)fs->fs_bsize, size, fs->fs_fsmnt); 199822544Smpp panic("ffs_checkblk: bad size"); 199922521Sdyson } 200022521Sdyson if ((u_int)bno >= fs->fs_size) 2001103594Sobrien panic("ffs_checkblk: bad block %jd", (intmax_t)bno); 200222521Sdyson error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, dtog(fs, bno))), 200322521Sdyson (int)fs->fs_cgsize, NOCRED, &bp); 200422544Smpp if (error) 200522544Smpp panic("ffs_checkblk: cg bread failed"); 200622521Sdyson cgp = (struct cg *)bp->b_data; 200722544Smpp if (!cg_chkmagic(cgp)) 200822544Smpp panic("ffs_checkblk: cg magic mismatch"); 200955697Smckusick bp->b_xflags |= BX_BKGRDWRITE; 201058087Smckusick blksfree = cg_blksfree(cgp); 201198542Smckusick cgbno = dtogd(fs, bno); 201222521Sdyson if (size == fs->fs_bsize) { 201398542Smckusick free = ffs_isblock(fs, blksfree, fragstoblks(fs, cgbno)); 201422521Sdyson } else { 201522521Sdyson frags = numfrags(fs, size); 201622521Sdyson for (free = 0, i = 0; i < frags; i++) 201798542Smckusick if (isset(blksfree, cgbno + i)) 201822521Sdyson free++; 201922521Sdyson if (free != 0 && free != frags) 202022544Smpp panic("ffs_checkblk: partially free fragment"); 202122521Sdyson } 202222521Sdyson brelse(bp); 202322521Sdyson return (!free); 202422521Sdyson} 2025173464Sobrien#endif /* INVARIANTS */ 202622521Sdyson 202722521Sdyson/* 20281541Srgrimes * Free an inode. 20291541Srgrimes */ 20301541Srgrimesint 203174548Smckusickffs_vfree(pvp, ino, mode) 203230474Sphk struct vnode *pvp; 203330474Sphk ino_t ino; 203430474Sphk int mode; 20351541Srgrimes{ 2036140704Sjeff struct inode *ip; 2037140704Sjeff 203834266Sjulian if (DOINGSOFTDEP(pvp)) { 203934266Sjulian softdep_freefile(pvp, ino, mode); 204034266Sjulian return (0); 204134266Sjulian } 2042140704Sjeff ip = VTOI(pvp); 2043140704Sjeff return (ffs_freefile(ip->i_ump, ip->i_fs, ip->i_devvp, ino, mode)); 204434266Sjulian} 204534266Sjulian 204634266Sjulian/* 204734266Sjulian * Do the actual free operation. 204834266Sjulian * The specified inode is placed back in the free map. 204934266Sjulian */ 205074548Smckusickint 2051140704Sjeffffs_freefile(ump, fs, devvp, ino, mode) 2052140704Sjeff struct ufsmount *ump; 205390098Smckusick struct fs *fs; 205490098Smckusick struct vnode *devvp; 205534266Sjulian ino_t ino; 205634266Sjulian int mode; 205734266Sjulian{ 205890098Smckusick struct cg *cgp; 20591541Srgrimes struct buf *bp; 206098542Smckusick ufs2_daddr_t cgbno; 2061203763Smckusick int error; 2062203763Smckusick u_int cg; 206358087Smckusick u_int8_t *inosused; 2064130585Sphk struct cdev *dev; 20651541Srgrimes 206690098Smckusick cg = ino_to_cg(fs, ino); 2067188240Strasz if (devvp->v_type == VREG) { 206890098Smckusick /* devvp is a snapshot */ 206990098Smckusick dev = VTOI(devvp)->i_devvp->v_rdev; 207090098Smckusick cgbno = fragstoblks(fs, cgtod(fs, cg)); 207190098Smckusick } else { 207290098Smckusick /* devvp is a normal disk device */ 207390098Smckusick dev = devvp->v_rdev; 207490098Smckusick cgbno = fsbtodb(fs, cgtod(fs, cg)); 207590098Smckusick } 2076203763Smckusick if (ino >= fs->fs_ipg * fs->fs_ncg) 2077108010Smckusick panic("ffs_freefile: range: dev = %s, ino = %lu, fs = %s", 2078108010Smckusick devtoname(dev), (u_long)ino, fs->fs_fsmnt); 207990098Smckusick if ((error = bread(devvp, cgbno, (int)fs->fs_cgsize, NOCRED, &bp))) { 20801541Srgrimes brelse(bp); 208134266Sjulian return (error); 20821541Srgrimes } 20831541Srgrimes cgp = (struct cg *)bp->b_data; 20841541Srgrimes if (!cg_chkmagic(cgp)) { 20851541Srgrimes brelse(bp); 20861541Srgrimes return (0); 20871541Srgrimes } 208855697Smckusick bp->b_xflags |= BX_BKGRDWRITE; 208998542Smckusick cgp->cg_old_time = cgp->cg_time = time_second; 209058087Smckusick inosused = cg_inosused(cgp); 20911541Srgrimes ino %= fs->fs_ipg; 209258087Smckusick if (isclr(inosused, ino)) { 2093203763Smckusick printf("dev = %s, ino = %u, fs = %s\n", devtoname(dev), 2094203763Smckusick ino + cg * fs->fs_ipg, fs->fs_fsmnt); 20951541Srgrimes if (fs->fs_ronly == 0) 2096108010Smckusick panic("ffs_freefile: freeing free inode"); 20971541Srgrimes } 209858087Smckusick clrbit(inosused, ino); 20991541Srgrimes if (ino < cgp->cg_irotor) 21001541Srgrimes cgp->cg_irotor = ino; 21011541Srgrimes cgp->cg_cs.cs_nifree++; 2102140704Sjeff UFS_LOCK(ump); 21031541Srgrimes fs->fs_cstotal.cs_nifree++; 21041541Srgrimes fs->fs_cs(fs, cg).cs_nifree++; 210530474Sphk if ((mode & IFMT) == IFDIR) { 21061541Srgrimes cgp->cg_cs.cs_ndir--; 21071541Srgrimes fs->fs_cstotal.cs_ndir--; 21081541Srgrimes fs->fs_cs(fs, cg).cs_ndir--; 21091541Srgrimes } 21101541Srgrimes fs->fs_fmod = 1; 2111140704Sjeff ACTIVECLEAR(fs, cg); 2112140704Sjeff UFS_UNLOCK(ump); 21131541Srgrimes bdwrite(bp); 21141541Srgrimes return (0); 21151541Srgrimes} 21161541Srgrimes 21171541Srgrimes/* 2118111239Smckusick * Check to see if a file is free. 2119111239Smckusick */ 2120111239Smckusickint 2121111239Smckusickffs_checkfreefile(fs, devvp, ino) 2122111239Smckusick struct fs *fs; 2123111239Smckusick struct vnode *devvp; 2124111239Smckusick ino_t ino; 2125111239Smckusick{ 2126111239Smckusick struct cg *cgp; 2127111239Smckusick struct buf *bp; 2128111239Smckusick ufs2_daddr_t cgbno; 2129203763Smckusick int ret; 2130203763Smckusick u_int cg; 2131111239Smckusick u_int8_t *inosused; 2132111239Smckusick 2133111239Smckusick cg = ino_to_cg(fs, ino); 2134188240Strasz if (devvp->v_type == VREG) { 2135111239Smckusick /* devvp is a snapshot */ 2136111239Smckusick cgbno = fragstoblks(fs, cgtod(fs, cg)); 2137111239Smckusick } else { 2138111239Smckusick /* devvp is a normal disk device */ 2139111239Smckusick cgbno = fsbtodb(fs, cgtod(fs, cg)); 2140111239Smckusick } 2141203763Smckusick if (ino >= fs->fs_ipg * fs->fs_ncg) 2142111239Smckusick return (1); 2143115474Sphk if (bread(devvp, cgbno, (int)fs->fs_cgsize, NOCRED, &bp)) { 2144111239Smckusick brelse(bp); 2145111239Smckusick return (1); 2146111239Smckusick } 2147111239Smckusick cgp = (struct cg *)bp->b_data; 2148111239Smckusick if (!cg_chkmagic(cgp)) { 2149111239Smckusick brelse(bp); 2150111239Smckusick return (1); 2151111239Smckusick } 2152111239Smckusick inosused = cg_inosused(cgp); 2153111239Smckusick ino %= fs->fs_ipg; 2154111239Smckusick ret = isclr(inosused, ino); 2155111239Smckusick brelse(bp); 2156111239Smckusick return (ret); 2157111239Smckusick} 2158111239Smckusick 2159111239Smckusick/* 21601541Srgrimes * Find a block of the specified size in the specified cylinder group. 21611541Srgrimes * 21621541Srgrimes * It is a panic if a request is made to find a block if none are 21631541Srgrimes * available. 21641541Srgrimes */ 216598542Smckusickstatic ufs1_daddr_t 21661541Srgrimesffs_mapsearch(fs, cgp, bpref, allocsiz) 216796506Sphk struct fs *fs; 216896506Sphk struct cg *cgp; 216998542Smckusick ufs2_daddr_t bpref; 21701541Srgrimes int allocsiz; 21711541Srgrimes{ 217298542Smckusick ufs1_daddr_t bno; 21731541Srgrimes int start, len, loc, i; 21741541Srgrimes int blk, field, subfield, pos; 217558087Smckusick u_int8_t *blksfree; 21761541Srgrimes 21771541Srgrimes /* 21781541Srgrimes * find the fragment by searching through the free block 21791541Srgrimes * map for an appropriate bit pattern 21801541Srgrimes */ 21811541Srgrimes if (bpref) 21821541Srgrimes start = dtogd(fs, bpref) / NBBY; 21831541Srgrimes else 21841541Srgrimes start = cgp->cg_frotor / NBBY; 218558087Smckusick blksfree = cg_blksfree(cgp); 21861541Srgrimes len = howmany(fs->fs_fpg, NBBY) - start; 218758087Smckusick loc = scanc((u_int)len, (u_char *)&blksfree[start], 2188160462Sstefanf fragtbl[fs->fs_frag], 21891541Srgrimes (u_char)(1 << (allocsiz - 1 + (fs->fs_frag % NBBY)))); 21901541Srgrimes if (loc == 0) { 21911541Srgrimes len = start + 1; 21921541Srgrimes start = 0; 219358087Smckusick loc = scanc((u_int)len, (u_char *)&blksfree[0], 2194160462Sstefanf fragtbl[fs->fs_frag], 21951541Srgrimes (u_char)(1 << (allocsiz - 1 + (fs->fs_frag % NBBY)))); 21961541Srgrimes if (loc == 0) { 21971541Srgrimes printf("start = %d, len = %d, fs = %s\n", 21981541Srgrimes start, len, fs->fs_fsmnt); 21991541Srgrimes panic("ffs_alloccg: map corrupted"); 22001541Srgrimes /* NOTREACHED */ 22011541Srgrimes } 22021541Srgrimes } 22031541Srgrimes bno = (start + len - loc) * NBBY; 22041541Srgrimes cgp->cg_frotor = bno; 22051541Srgrimes /* 22061541Srgrimes * found the byte in the map 22071541Srgrimes * sift through the bits to find the selected frag 22081541Srgrimes */ 22091541Srgrimes for (i = bno + NBBY; bno < i; bno += fs->fs_frag) { 221058087Smckusick blk = blkmap(fs, blksfree, bno); 22111541Srgrimes blk <<= 1; 22121541Srgrimes field = around[allocsiz]; 22131541Srgrimes subfield = inside[allocsiz]; 22141541Srgrimes for (pos = 0; pos <= fs->fs_frag - allocsiz; pos++) { 22151541Srgrimes if ((blk & field) == subfield) 22161541Srgrimes return (bno + pos); 22171541Srgrimes field <<= 1; 22181541Srgrimes subfield <<= 1; 22191541Srgrimes } 22201541Srgrimes } 22213487Sphk printf("bno = %lu, fs = %s\n", (u_long)bno, fs->fs_fsmnt); 22221541Srgrimes panic("ffs_alloccg: block not in map"); 22231541Srgrimes return (-1); 22241541Srgrimes} 22251541Srgrimes 22261541Srgrimes/* 22271541Srgrimes * Update the cluster map because of an allocation or free. 22281541Srgrimes * 22291541Srgrimes * Cnt == 1 means free; cnt == -1 means allocating. 22301541Srgrimes */ 223176269Smckusickvoid 2232140704Sjeffffs_clusteracct(ump, fs, cgp, blkno, cnt) 2233140704Sjeff struct ufsmount *ump; 22341541Srgrimes struct fs *fs; 22351541Srgrimes struct cg *cgp; 223698542Smckusick ufs1_daddr_t blkno; 22371541Srgrimes int cnt; 22381541Srgrimes{ 223922521Sdyson int32_t *sump; 224022521Sdyson int32_t *lp; 22411541Srgrimes u_char *freemapp, *mapp; 22421541Srgrimes int i, start, end, forw, back, map, bit; 22431541Srgrimes 2244140704Sjeff mtx_assert(UFS_MTX(ump), MA_OWNED); 2245140704Sjeff 22461541Srgrimes if (fs->fs_contigsumsize <= 0) 22471541Srgrimes return; 22481541Srgrimes freemapp = cg_clustersfree(cgp); 22491541Srgrimes sump = cg_clustersum(cgp); 22501541Srgrimes /* 22511541Srgrimes * Allocate or clear the actual block. 22521541Srgrimes */ 22531541Srgrimes if (cnt > 0) 22541541Srgrimes setbit(freemapp, blkno); 22551541Srgrimes else 22561541Srgrimes clrbit(freemapp, blkno); 22571541Srgrimes /* 22581541Srgrimes * Find the size of the cluster going forward. 22591541Srgrimes */ 22601541Srgrimes start = blkno + 1; 22611541Srgrimes end = start + fs->fs_contigsumsize; 22621541Srgrimes if (end >= cgp->cg_nclusterblks) 22631541Srgrimes end = cgp->cg_nclusterblks; 22641541Srgrimes mapp = &freemapp[start / NBBY]; 22651541Srgrimes map = *mapp++; 22661541Srgrimes bit = 1 << (start % NBBY); 22671541Srgrimes for (i = start; i < end; i++) { 22681541Srgrimes if ((map & bit) == 0) 22691541Srgrimes break; 22701541Srgrimes if ((i & (NBBY - 1)) != (NBBY - 1)) { 22711541Srgrimes bit <<= 1; 22721541Srgrimes } else { 22731541Srgrimes map = *mapp++; 22741541Srgrimes bit = 1; 22751541Srgrimes } 22761541Srgrimes } 22771541Srgrimes forw = i - start; 22781541Srgrimes /* 22791541Srgrimes * Find the size of the cluster going backward. 22801541Srgrimes */ 22811541Srgrimes start = blkno - 1; 22821541Srgrimes end = start - fs->fs_contigsumsize; 22831541Srgrimes if (end < 0) 22841541Srgrimes end = -1; 22851541Srgrimes mapp = &freemapp[start / NBBY]; 22861541Srgrimes map = *mapp--; 22871541Srgrimes bit = 1 << (start % NBBY); 22881541Srgrimes for (i = start; i > end; i--) { 22891541Srgrimes if ((map & bit) == 0) 22901541Srgrimes break; 22911541Srgrimes if ((i & (NBBY - 1)) != 0) { 22921541Srgrimes bit >>= 1; 22931541Srgrimes } else { 22941541Srgrimes map = *mapp--; 22951541Srgrimes bit = 1 << (NBBY - 1); 22961541Srgrimes } 22971541Srgrimes } 22981541Srgrimes back = start - i; 22991541Srgrimes /* 23001541Srgrimes * Account for old cluster and the possibly new forward and 23011541Srgrimes * back clusters. 23021541Srgrimes */ 23031541Srgrimes i = back + forw + 1; 23041541Srgrimes if (i > fs->fs_contigsumsize) 23051541Srgrimes i = fs->fs_contigsumsize; 23061541Srgrimes sump[i] += cnt; 23071541Srgrimes if (back > 0) 23081541Srgrimes sump[back] -= cnt; 23091541Srgrimes if (forw > 0) 23101541Srgrimes sump[forw] -= cnt; 231122521Sdyson /* 231222521Sdyson * Update cluster summary information. 231322521Sdyson */ 231422521Sdyson lp = &sump[fs->fs_contigsumsize]; 231522521Sdyson for (i = fs->fs_contigsumsize; i > 0; i--) 231622521Sdyson if (*lp-- > 0) 231722521Sdyson break; 231822521Sdyson fs->fs_maxcluster[cgp->cg_cgx] = i; 23191541Srgrimes} 23201541Srgrimes 23211541Srgrimes/* 232296755Strhodes * Fserr prints the name of a filesystem with an error diagnostic. 23238876Srgrimes * 23241541Srgrimes * The form of the error message is: 23251541Srgrimes * fs: error message 23261541Srgrimes */ 23271541Srgrimesstatic void 232890098Smckusickffs_fserr(fs, inum, cp) 23291541Srgrimes struct fs *fs; 233090098Smckusick ino_t inum; 23311541Srgrimes char *cp; 23321541Srgrimes{ 2333112450Sjhb struct thread *td = curthread; /* XXX */ 2334112450Sjhb struct proc *p = td->td_proc; 23351541Srgrimes 233690098Smckusick log(LOG_ERR, "pid %d (%s), uid %d inumber %d on %s: %s\n", 2337112450Sjhb p->p_pid, p->p_comm, td->td_ucred->cr_uid, inum, fs->fs_fsmnt, cp); 23381541Srgrimes} 233974548Smckusick 234074548Smckusick/* 234174548Smckusick * This function provides the capability for the fsck program to 2342202113Smckusick * update an active filesystem. Fourteen operations are provided: 234374548Smckusick * 234474548Smckusick * adjrefcnt(inode, amt) - adjusts the reference count on the 234574548Smckusick * specified inode by the specified amount. Under normal 234674548Smckusick * operation the count should always go down. Decrementing 234774548Smckusick * the count to zero will cause the inode to be freed. 234874548Smckusick * adjblkcnt(inode, amt) - adjust the number of blocks used to 234974548Smckusick * by the specifed amount. 2350142123Sdelphij * adjndir, adjbfree, adjifree, adjffree, adjnumclusters(amt) - 2351142123Sdelphij * adjust the superblock summary. 235274548Smckusick * freedirs(inode, count) - directory inodes [inode..inode + count - 1] 235374548Smckusick * are marked as free. Inodes should never have to be marked 235474548Smckusick * as in use. 235574548Smckusick * freefiles(inode, count) - file inodes [inode..inode + count - 1] 235674548Smckusick * are marked as free. Inodes should never have to be marked 235774548Smckusick * as in use. 235874548Smckusick * freeblks(blockno, size) - blocks [blockno..blockno + size - 1] 235974548Smckusick * are marked as free. Blocks should never have to be marked 236074548Smckusick * as in use. 236174548Smckusick * setflags(flags, set/clear) - the fs_flags field has the specified 236274548Smckusick * flags set (second parameter +1) or cleared (second parameter -1). 2363202113Smckusick * setcwd(dirinode) - set the current directory to dirinode in the 2364202113Smckusick * filesystem associated with the snapshot. 2365202113Smckusick * setdotdot(oldvalue, newvalue) - Verify that the inode number for ".." 2366202113Smckusick * in the current directory is oldvalue then change it to newvalue. 2367202113Smckusick * unlink(nameptr, oldvalue) - Verify that the inode number associated 2368202113Smckusick * with nameptr in the current directory is oldvalue then unlink it. 236974548Smckusick */ 237074548Smckusick 237192728Salfredstatic int sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS); 237274548Smckusick 237374548SmckusickSYSCTL_PROC(_vfs_ffs, FFS_ADJ_REFCNT, adjrefcnt, CTLFLAG_WR|CTLTYPE_STRUCT, 237474548Smckusick 0, 0, sysctl_ffs_fsck, "S,fsck", "Adjust Inode Reference Count"); 237574548Smckusick 2376141631Sphkstatic SYSCTL_NODE(_vfs_ffs, FFS_ADJ_BLKCNT, adjblkcnt, CTLFLAG_WR, 237774548Smckusick sysctl_ffs_fsck, "Adjust Inode Used Blocks Count"); 237874548Smckusick 2379142123Sdelphijstatic SYSCTL_NODE(_vfs_ffs, FFS_ADJ_NDIR, adjndir, CTLFLAG_WR, 2380142123Sdelphij sysctl_ffs_fsck, "Adjust number of directories"); 2381142123Sdelphij 2382142123Sdelphijstatic SYSCTL_NODE(_vfs_ffs, FFS_ADJ_NBFREE, adjnbfree, CTLFLAG_WR, 2383142123Sdelphij sysctl_ffs_fsck, "Adjust number of free blocks"); 2384142123Sdelphij 2385142123Sdelphijstatic SYSCTL_NODE(_vfs_ffs, FFS_ADJ_NIFREE, adjnifree, CTLFLAG_WR, 2386142123Sdelphij sysctl_ffs_fsck, "Adjust number of free inodes"); 2387142123Sdelphij 2388142123Sdelphijstatic SYSCTL_NODE(_vfs_ffs, FFS_ADJ_NFFREE, adjnffree, CTLFLAG_WR, 2389142123Sdelphij sysctl_ffs_fsck, "Adjust number of free frags"); 2390142123Sdelphij 2391142123Sdelphijstatic SYSCTL_NODE(_vfs_ffs, FFS_ADJ_NUMCLUSTERS, adjnumclusters, CTLFLAG_WR, 2392142123Sdelphij sysctl_ffs_fsck, "Adjust number of free clusters"); 2393142123Sdelphij 2394141631Sphkstatic SYSCTL_NODE(_vfs_ffs, FFS_DIR_FREE, freedirs, CTLFLAG_WR, 239574548Smckusick sysctl_ffs_fsck, "Free Range of Directory Inodes"); 239674548Smckusick 2397141631Sphkstatic SYSCTL_NODE(_vfs_ffs, FFS_FILE_FREE, freefiles, CTLFLAG_WR, 239874548Smckusick sysctl_ffs_fsck, "Free Range of File Inodes"); 239974548Smckusick 2400141631Sphkstatic SYSCTL_NODE(_vfs_ffs, FFS_BLK_FREE, freeblks, CTLFLAG_WR, 240174548Smckusick sysctl_ffs_fsck, "Free Range of Blocks"); 240274548Smckusick 2403141631Sphkstatic SYSCTL_NODE(_vfs_ffs, FFS_SET_FLAGS, setflags, CTLFLAG_WR, 240474548Smckusick sysctl_ffs_fsck, "Change Filesystem Flags"); 240574548Smckusick 2406202113Smckusickstatic SYSCTL_NODE(_vfs_ffs, FFS_SET_CWD, setcwd, CTLFLAG_WR, 2407202113Smckusick sysctl_ffs_fsck, "Set Current Working Directory"); 2408202113Smckusick 2409202113Smckusickstatic SYSCTL_NODE(_vfs_ffs, FFS_SET_DOTDOT, setdotdot, CTLFLAG_WR, 2410202113Smckusick sysctl_ffs_fsck, "Change Value of .. Entry"); 2411202113Smckusick 2412202113Smckusickstatic SYSCTL_NODE(_vfs_ffs, FFS_UNLINK, unlink, CTLFLAG_WR, 2413202113Smckusick sysctl_ffs_fsck, "Unlink a Duplicate Name"); 2414202113Smckusick 241574548Smckusick#ifdef DEBUG 241674548Smckusickstatic int fsckcmds = 0; 241774548SmckusickSYSCTL_INT(_debug, OID_AUTO, fsckcmds, CTLFLAG_RW, &fsckcmds, 0, ""); 241874548Smckusick#endif /* DEBUG */ 241974548Smckusick 242074548Smckusickstatic int 242174548Smckusicksysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) 242274548Smckusick{ 2423202113Smckusick struct thread *td = curthread; 242474548Smckusick struct fsck_cmd cmd; 242574548Smckusick struct ufsmount *ump; 2426202113Smckusick struct vnode *vp, *vpold, *dvp, *fdvp; 2427202113Smckusick struct inode *ip, *dp; 242874548Smckusick struct mount *mp; 242974548Smckusick struct fs *fs; 243098542Smckusick ufs2_daddr_t blkno; 243174548Smckusick long blkcnt, blksize; 2432202113Smckusick struct filedesc *fdp; 243374548Smckusick struct file *fp; 2434202113Smckusick int vfslocked, filetype, error; 243574548Smckusick 243674548Smckusick if (req->newlen > sizeof cmd) 243774548Smckusick return (EBADRPC); 243874548Smckusick if ((error = SYSCTL_IN(req, &cmd, sizeof cmd)) != 0) 243974548Smckusick return (error); 244074548Smckusick if (cmd.version != FFS_CMD_VERSION) 244174548Smckusick return (ERPCMISMATCH); 244274548Smckusick if ((error = getvnode(curproc->p_fd, cmd.handle, &fp)) != 0) 244374548Smckusick return (error); 2444202113Smckusick vp = fp->f_data; 2445202113Smckusick if (vp->v_type != VREG && vp->v_type != VDIR) { 2446202113Smckusick fdrop(fp, td); 2447202113Smckusick return (EINVAL); 2448202113Smckusick } 2449202113Smckusick vn_start_write(vp, &mp, V_WAIT); 245075572Smckusick if (mp == 0 || strncmp(mp->mnt_stat.f_fstypename, "ufs", MFSNAMELEN)) { 245175572Smckusick vn_finished_write(mp); 2452202113Smckusick fdrop(fp, td); 245374705Smckusick return (EINVAL); 245475572Smckusick } 245575572Smckusick if (mp->mnt_flag & MNT_RDONLY) { 245675572Smckusick vn_finished_write(mp); 2457202113Smckusick fdrop(fp, td); 245874548Smckusick return (EROFS); 245975572Smckusick } 246074548Smckusick ump = VFSTOUFS(mp); 246174548Smckusick fs = ump->um_fs; 246274548Smckusick filetype = IFREG; 246374548Smckusick 246474548Smckusick switch (oidp->oid_number) { 246574548Smckusick 246674548Smckusick case FFS_SET_FLAGS: 246774548Smckusick#ifdef DEBUG 246874548Smckusick if (fsckcmds) 246974548Smckusick printf("%s: %s flags\n", mp->mnt_stat.f_mntonname, 247074548Smckusick cmd.size > 0 ? "set" : "clear"); 247174548Smckusick#endif /* DEBUG */ 247274548Smckusick if (cmd.size > 0) 247374548Smckusick fs->fs_flags |= (long)cmd.value; 247474548Smckusick else 247574548Smckusick fs->fs_flags &= ~(long)cmd.value; 247674548Smckusick break; 247774548Smckusick 247874548Smckusick case FFS_ADJ_REFCNT: 247974548Smckusick#ifdef DEBUG 248074548Smckusick if (fsckcmds) { 248199590Sbde printf("%s: adjust inode %jd count by %jd\n", 248299590Sbde mp->mnt_stat.f_mntonname, (intmax_t)cmd.value, 248399590Sbde (intmax_t)cmd.size); 248474548Smckusick } 248574548Smckusick#endif /* DEBUG */ 2486141526Sphk if ((error = ffs_vget(mp, (ino_t)cmd.value, LK_EXCLUSIVE, &vp))) 248775572Smckusick break; 248874548Smckusick ip = VTOI(vp); 248974548Smckusick ip->i_nlink += cmd.size; 2490132775Skan DIP_SET(ip, i_nlink, ip->i_nlink); 249174548Smckusick ip->i_effnlink += cmd.size; 249274548Smckusick ip->i_flag |= IN_CHANGE; 249374548Smckusick if (DOINGSOFTDEP(vp)) 249474548Smckusick softdep_change_linkcnt(ip); 249574548Smckusick vput(vp); 249674548Smckusick break; 249774548Smckusick 249874548Smckusick case FFS_ADJ_BLKCNT: 249974548Smckusick#ifdef DEBUG 250074548Smckusick if (fsckcmds) { 250199590Sbde printf("%s: adjust inode %jd block count by %jd\n", 250299590Sbde mp->mnt_stat.f_mntonname, (intmax_t)cmd.value, 250399590Sbde (intmax_t)cmd.size); 250474548Smckusick } 250574548Smckusick#endif /* DEBUG */ 2506141526Sphk if ((error = ffs_vget(mp, (ino_t)cmd.value, LK_EXCLUSIVE, &vp))) 250775572Smckusick break; 250874548Smckusick ip = VTOI(vp); 2509166924Sbrian if (ip->i_flag & IN_SPACECOUNTED) { 2510166924Sbrian UFS_LOCK(ump); 2511166924Sbrian fs->fs_pendingblocks += cmd.size; 2512166924Sbrian UFS_UNLOCK(ump); 2513166924Sbrian } 2514132775Skan DIP_SET(ip, i_blocks, DIP(ip, i_blocks) + cmd.size); 251574548Smckusick ip->i_flag |= IN_CHANGE; 251674548Smckusick vput(vp); 251774548Smckusick break; 251874548Smckusick 251974548Smckusick case FFS_DIR_FREE: 252074548Smckusick filetype = IFDIR; 252174548Smckusick /* fall through */ 252274548Smckusick 252374548Smckusick case FFS_FILE_FREE: 252474548Smckusick#ifdef DEBUG 252574548Smckusick if (fsckcmds) { 252674548Smckusick if (cmd.size == 1) 252774548Smckusick printf("%s: free %s inode %d\n", 252874548Smckusick mp->mnt_stat.f_mntonname, 252974548Smckusick filetype == IFDIR ? "directory" : "file", 253074548Smckusick (ino_t)cmd.value); 253174548Smckusick else 253274548Smckusick printf("%s: free %s inodes %d-%d\n", 253374548Smckusick mp->mnt_stat.f_mntonname, 253474548Smckusick filetype == IFDIR ? "directory" : "file", 253574747Sasmodai (ino_t)cmd.value, 253678256Speter (ino_t)(cmd.value + cmd.size - 1)); 253774548Smckusick } 253874548Smckusick#endif /* DEBUG */ 253974548Smckusick while (cmd.size > 0) { 2540140704Sjeff if ((error = ffs_freefile(ump, fs, ump->um_devvp, 2541140704Sjeff cmd.value, filetype))) 254275572Smckusick break; 254374548Smckusick cmd.size -= 1; 254474548Smckusick cmd.value += 1; 254574548Smckusick } 254674548Smckusick break; 254774548Smckusick 254874548Smckusick case FFS_BLK_FREE: 254974548Smckusick#ifdef DEBUG 255074548Smckusick if (fsckcmds) { 255174548Smckusick if (cmd.size == 1) 2552103594Sobrien printf("%s: free block %jd\n", 255374548Smckusick mp->mnt_stat.f_mntonname, 255498542Smckusick (intmax_t)cmd.value); 255574548Smckusick else 2556103594Sobrien printf("%s: free blocks %jd-%jd\n", 255774548Smckusick mp->mnt_stat.f_mntonname, 255898542Smckusick (intmax_t)cmd.value, 255998542Smckusick (intmax_t)cmd.value + cmd.size - 1); 256074548Smckusick } 256174548Smckusick#endif /* DEBUG */ 256298542Smckusick blkno = cmd.value; 256374548Smckusick blkcnt = cmd.size; 256474548Smckusick blksize = fs->fs_frag - (blkno % fs->fs_frag); 256574548Smckusick while (blkcnt > 0) { 256674548Smckusick if (blksize > blkcnt) 256774548Smckusick blksize = blkcnt; 2568140704Sjeff ffs_blkfree(ump, fs, ump->um_devvp, blkno, 256990098Smckusick blksize * fs->fs_fsize, ROOTINO); 257074548Smckusick blkno += blksize; 257174548Smckusick blkcnt -= blksize; 257274548Smckusick blksize = fs->fs_frag; 257374548Smckusick } 257474548Smckusick break; 257574548Smckusick 2576142123Sdelphij /* 2577142123Sdelphij * Adjust superblock summaries. fsck(8) is expected to 2578142123Sdelphij * submit deltas when necessary. 2579142123Sdelphij */ 2580142123Sdelphij case FFS_ADJ_NDIR: 2581142123Sdelphij#ifdef DEBUG 2582142123Sdelphij if (fsckcmds) { 2583142123Sdelphij printf("%s: adjust number of directories by %jd\n", 2584142123Sdelphij mp->mnt_stat.f_mntonname, (intmax_t)cmd.value); 2585142123Sdelphij } 2586142123Sdelphij#endif /* DEBUG */ 2587142123Sdelphij fs->fs_cstotal.cs_ndir += cmd.value; 2588142123Sdelphij break; 2589202113Smckusick 2590142123Sdelphij case FFS_ADJ_NBFREE: 2591142123Sdelphij#ifdef DEBUG 2592142123Sdelphij if (fsckcmds) { 2593142123Sdelphij printf("%s: adjust number of free blocks by %+jd\n", 2594142123Sdelphij mp->mnt_stat.f_mntonname, (intmax_t)cmd.value); 2595142123Sdelphij } 2596142123Sdelphij#endif /* DEBUG */ 2597142123Sdelphij fs->fs_cstotal.cs_nbfree += cmd.value; 2598142123Sdelphij break; 2599202113Smckusick 2600142123Sdelphij case FFS_ADJ_NIFREE: 2601142123Sdelphij#ifdef DEBUG 2602142123Sdelphij if (fsckcmds) { 2603142123Sdelphij printf("%s: adjust number of free inodes by %+jd\n", 2604142123Sdelphij mp->mnt_stat.f_mntonname, (intmax_t)cmd.value); 2605142123Sdelphij } 2606142123Sdelphij#endif /* DEBUG */ 2607142123Sdelphij fs->fs_cstotal.cs_nifree += cmd.value; 2608142123Sdelphij break; 2609202113Smckusick 2610142123Sdelphij case FFS_ADJ_NFFREE: 2611142123Sdelphij#ifdef DEBUG 2612142123Sdelphij if (fsckcmds) { 2613142123Sdelphij printf("%s: adjust number of free frags by %+jd\n", 2614142123Sdelphij mp->mnt_stat.f_mntonname, (intmax_t)cmd.value); 2615142123Sdelphij } 2616142123Sdelphij#endif /* DEBUG */ 2617142123Sdelphij fs->fs_cstotal.cs_nffree += cmd.value; 2618142123Sdelphij break; 2619202113Smckusick 2620142123Sdelphij case FFS_ADJ_NUMCLUSTERS: 2621142123Sdelphij#ifdef DEBUG 2622142123Sdelphij if (fsckcmds) { 2623142123Sdelphij printf("%s: adjust number of free clusters by %+jd\n", 2624142123Sdelphij mp->mnt_stat.f_mntonname, (intmax_t)cmd.value); 2625142123Sdelphij } 2626142123Sdelphij#endif /* DEBUG */ 2627142123Sdelphij fs->fs_cstotal.cs_numclusters += cmd.value; 2628142123Sdelphij break; 2629142123Sdelphij 2630202113Smckusick case FFS_SET_CWD: 2631202113Smckusick#ifdef DEBUG 2632202113Smckusick if (fsckcmds) { 2633202113Smckusick printf("%s: set current directory to inode %jd\n", 2634202113Smckusick mp->mnt_stat.f_mntonname, (intmax_t)cmd.value); 2635202113Smckusick } 2636202113Smckusick#endif /* DEBUG */ 2637202113Smckusick if ((error = ffs_vget(mp, (ino_t)cmd.value, LK_SHARED, &vp))) 2638202113Smckusick break; 2639202113Smckusick vfslocked = VFS_LOCK_GIANT(vp->v_mount); 2640202113Smckusick AUDIT_ARG_VNODE1(vp); 2641202113Smckusick if ((error = change_dir(vp, td)) != 0) { 2642202113Smckusick vput(vp); 2643202113Smckusick VFS_UNLOCK_GIANT(vfslocked); 2644202113Smckusick break; 2645202113Smckusick } 2646202113Smckusick VOP_UNLOCK(vp, 0); 2647202113Smckusick VFS_UNLOCK_GIANT(vfslocked); 2648202113Smckusick fdp = td->td_proc->p_fd; 2649202113Smckusick FILEDESC_XLOCK(fdp); 2650202113Smckusick vpold = fdp->fd_cdir; 2651202113Smckusick fdp->fd_cdir = vp; 2652202113Smckusick FILEDESC_XUNLOCK(fdp); 2653202113Smckusick vfslocked = VFS_LOCK_GIANT(vpold->v_mount); 2654202113Smckusick vrele(vpold); 2655202113Smckusick VFS_UNLOCK_GIANT(vfslocked); 2656202113Smckusick break; 2657202113Smckusick 2658202113Smckusick case FFS_SET_DOTDOT: 2659202113Smckusick#ifdef DEBUG 2660202113Smckusick if (fsckcmds) { 2661202113Smckusick printf("%s: change .. in cwd from %jd to %jd\n", 2662202113Smckusick mp->mnt_stat.f_mntonname, (intmax_t)cmd.value, 2663202113Smckusick (intmax_t)cmd.size); 2664202113Smckusick } 2665202113Smckusick#endif /* DEBUG */ 2666202113Smckusick /* 2667202113Smckusick * First we have to get and lock the parent directory 2668202113Smckusick * to which ".." points. 2669202113Smckusick */ 2670202113Smckusick error = ffs_vget(mp, (ino_t)cmd.value, LK_EXCLUSIVE, &fdvp); 2671202113Smckusick if (error) 2672202113Smckusick break; 2673202113Smckusick /* 2674202113Smckusick * Now we get and lock the child directory containing "..". 2675202113Smckusick */ 2676202113Smckusick FILEDESC_SLOCK(td->td_proc->p_fd); 2677202113Smckusick dvp = td->td_proc->p_fd->fd_cdir; 2678202113Smckusick FILEDESC_SUNLOCK(td->td_proc->p_fd); 2679202113Smckusick if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) { 2680202113Smckusick vput(fdvp); 2681202113Smckusick break; 2682202113Smckusick } 2683202113Smckusick dp = VTOI(dvp); 2684202113Smckusick dp->i_offset = 12; /* XXX mastertemplate.dot_reclen */ 2685202113Smckusick error = ufs_dirrewrite(dp, VTOI(fdvp), (ino_t)cmd.size, 2686202113Smckusick DT_DIR, 0); 2687202113Smckusick cache_purge(fdvp); 2688202113Smckusick cache_purge(dvp); 2689202113Smckusick vput(dvp); 2690202113Smckusick vput(fdvp); 2691202113Smckusick break; 2692202113Smckusick 2693202113Smckusick case FFS_UNLINK: 2694202113Smckusick#ifdef DEBUG 2695202113Smckusick if (fsckcmds) { 2696202113Smckusick char buf[32]; 2697202113Smckusick 2698202125Smckusick if (copyinstr((char *)(intptr_t)cmd.value, buf,32,NULL)) 2699202113Smckusick strncpy(buf, "Name_too_long", 32); 2700202113Smckusick printf("%s: unlink %s (inode %jd)\n", 2701202113Smckusick mp->mnt_stat.f_mntonname, buf, (intmax_t)cmd.size); 2702202113Smckusick } 2703202113Smckusick#endif /* DEBUG */ 2704202113Smckusick /* 2705202113Smckusick * kern_unlinkat will do its own start/finish writes and 2706202113Smckusick * they do not nest, so drop ours here. Setting mp == NULL 2707202113Smckusick * indicates that vn_finished_write is not needed down below. 2708202113Smckusick */ 2709202113Smckusick vn_finished_write(mp); 2710202113Smckusick mp = NULL; 2711202125Smckusick error = kern_unlinkat(td, AT_FDCWD, (char *)(intptr_t)cmd.value, 2712202113Smckusick UIO_USERSPACE, (ino_t)cmd.size); 2713202113Smckusick break; 2714202113Smckusick 271574548Smckusick default: 271674548Smckusick#ifdef DEBUG 271774548Smckusick if (fsckcmds) { 271874548Smckusick printf("Invalid request %d from fsck\n", 271974548Smckusick oidp->oid_number); 272074548Smckusick } 272174548Smckusick#endif /* DEBUG */ 272275572Smckusick error = EINVAL; 272375572Smckusick break; 272474548Smckusick 272574548Smckusick } 2726202113Smckusick fdrop(fp, td); 272775572Smckusick vn_finished_write(mp); 272875572Smckusick return (error); 272974548Smckusick} 2730