growfs.c revision 103949
169800Stomsoft/* 269800Stomsoft * Copyright (c) 2000 Christoph Herrmann, Thomas-Henning von Kamptz 369800Stomsoft * Copyright (c) 1980, 1989, 1993 The Regents of the University of California. 469800Stomsoft * All rights reserved. 569800Stomsoft * 669800Stomsoft * This code is derived from software contributed to Berkeley by 769800Stomsoft * Christoph Herrmann and Thomas-Henning von Kamptz, Munich and Frankfurt. 869800Stomsoft * 969800Stomsoft * Redistribution and use in source and binary forms, with or without 1069800Stomsoft * modification, are permitted provided that the following conditions 1169800Stomsoft * are met: 1269800Stomsoft * 1. Redistributions of source code must retain the above copyright 1369800Stomsoft * notice, this list of conditions and the following disclaimer. 1469800Stomsoft * 2. Redistributions in binary form must reproduce the above copyright 1569800Stomsoft * notice, this list of conditions and the following disclaimer in the 1669800Stomsoft * documentation and/or other materials provided with the distribution. 1769800Stomsoft * 3. All advertising materials mentioning features or use of this software 1869800Stomsoft * must display the following acknowledgment: 1969800Stomsoft * This product includes software developed by the University of 2069800Stomsoft * California, Berkeley and its contributors, as well as Christoph 2169800Stomsoft * Herrmann and Thomas-Henning von Kamptz. 2269800Stomsoft * 4. Neither the name of the University nor the names of its contributors 2369800Stomsoft * may be used to endorse or promote products derived from this software 2469800Stomsoft * without specific prior written permission. 2569800Stomsoft * 2669800Stomsoft * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2769800Stomsoft * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2869800Stomsoft * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2969800Stomsoft * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3069800Stomsoft * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3169800Stomsoft * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3269800Stomsoft * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3369800Stomsoft * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3469800Stomsoft * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3569800Stomsoft * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3669800Stomsoft * SUCH DAMAGE. 3769800Stomsoft * 3869926Stomsoft * $TSHeader: src/sbin/growfs/growfs.c,v 1.5 2000/12/12 19:31:00 tomsoft Exp $ 3969800Stomsoft * 4069800Stomsoft */ 4169800Stomsoft 4269800Stomsoft#ifndef lint 4369800Stomsoftstatic const char copyright[] = 4469800Stomsoft"@(#) Copyright (c) 2000 Christoph Herrmann, Thomas-Henning von Kamptz\n\ 4569800StomsoftCopyright (c) 1980, 1989, 1993 The Regents of the University of California.\n\ 4669800StomsoftAll rights reserved.\n"; 4769800Stomsoft#endif /* not lint */ 4869800Stomsoft 4969800Stomsoft#ifndef lint 5069800Stomsoftstatic const char rcsid[] = 5169926Stomsoft "$FreeBSD: head/sbin/growfs/growfs.c 103949 2002-09-25 04:06:37Z mike $"; 5269800Stomsoft#endif /* not lint */ 5369800Stomsoft 5469800Stomsoft/* ********************************************************** INCLUDES ***** */ 5569800Stomsoft#include <sys/param.h> 5669800Stomsoft#include <sys/disklabel.h> 5769800Stomsoft#include <sys/ioctl.h> 5869800Stomsoft#include <sys/stat.h> 5969800Stomsoft 6069800Stomsoft#include <stdio.h> 6169800Stomsoft#include <paths.h> 6269800Stomsoft#include <ctype.h> 6369800Stomsoft#include <err.h> 6469800Stomsoft#include <fcntl.h> 65103949Smike#include <limits.h> 6669800Stomsoft#include <stdlib.h> 6769800Stomsoft#include <string.h> 6869800Stomsoft#include <unistd.h> 6969800Stomsoft#include <ufs/ufs/dinode.h> 7069800Stomsoft#include <ufs/ffs/fs.h> 7169800Stomsoft 7269800Stomsoft#include "debug.h" 7369800Stomsoft 7469800Stomsoft/* *************************************************** GLOBALS & TYPES ***** */ 7569800Stomsoft#ifdef FS_DEBUG 7669800Stomsoftint _dbg_lvl_ = (DL_INFO); /* DL_TRC */ 7769800Stomsoft#endif /* FS_DEBUG */ 7869800Stomsoft 7969800Stomsoftstatic union { 8069800Stomsoft struct fs fs; 8198542Smckusick char pad[SBLOCKSIZE]; 8269800Stomsoft} fsun1, fsun2; 8369800Stomsoft#define sblock fsun1.fs /* the new superblock */ 8469800Stomsoft#define osblock fsun2.fs /* the old superblock */ 8569800Stomsoft 8698542Smckusick/* 8798542Smckusick * Possible superblock locations ordered from most to least likely. 8898542Smckusick */ 8998542Smckusickstatic int sblock_try[] = SBLOCKSEARCH; 9098542Smckusickstatic ufs2_daddr_t sblockloc; 9198542Smckusick 9269800Stomsoftstatic union { 9369800Stomsoft struct cg cg; 9469800Stomsoft char pad[MAXBSIZE]; 9569800Stomsoft} cgun1, cgun2; 9669800Stomsoft#define acg cgun1.cg /* a cylinder cgroup (new) */ 9769800Stomsoft#define aocg cgun2.cg /* an old cylinder group */ 9869800Stomsoft 9998542Smckusickstatic char ablk[MAXBSIZE]; /* a block */ 10069800Stomsoft 10198542Smckusickstatic struct csum *fscs; /* cylinder summary */ 10269800Stomsoft 10398542Smckusickunion dinode { 10498542Smckusick struct ufs1_dinode dp1; 10598542Smckusick struct ufs2_dinode dp2; 10669800Stomsoft}; 10798542Smckusick#define DIP(dp, field) \ 10898542Smckusick ((sblock.fs_magic == FS_UFS1_MAGIC) ? \ 10998542Smckusick (dp)->dp1.field : (dp)->dp2.field) 11098542Smckusickstatic ufs2_daddr_t inoblk; /* inode block address */ 11198542Smckusickstatic char inobuf[MAXBSIZE]; /* inode block */ 11298542Smckusickstatic int maxino; /* last valid inode */ 11369800Stomsoft 11469800Stomsoft/* 11569800Stomsoft * An array of elements of type struct gfs_bpp describes all blocks to 11669800Stomsoft * be relocated in order to free the space needed for the cylinder group 11769800Stomsoft * summary for all cylinder groups located in the first cylinder group. 11869800Stomsoft */ 11969800Stomsoftstruct gfs_bpp { 12098542Smckusick ufs2_daddr_t old; /* old block number */ 12198542Smckusick ufs2_daddr_t new; /* new block number */ 12269800Stomsoft#define GFS_FL_FIRST 1 12369800Stomsoft#define GFS_FL_LAST 2 12477885Stomsoft unsigned int flags; /* special handling required */ 12569800Stomsoft int found; /* how many references were updated */ 12669800Stomsoft}; 12769800Stomsoft 12869800Stomsoft/* ******************************************************** PROTOTYPES ***** */ 12977885Stomsoftstatic void growfs(int, int, unsigned int); 13098542Smckusickstatic void rdfs(ufs2_daddr_t, size_t, void *, int); 13198542Smckusickstatic void wtfs(ufs2_daddr_t, size_t, void *, int, unsigned int); 13298542Smckusickstatic ufs2_daddr_t alloc(void); 13369800Stomsoftstatic int charsperline(void); 13469926Stomsoftstatic void usage(void); 13569800Stomsoftstatic int isblock(struct fs *, unsigned char *, int); 13669800Stomsoftstatic void clrblock(struct fs *, unsigned char *, int); 13769800Stomsoftstatic void setblock(struct fs *, unsigned char *, int); 13877885Stomsoftstatic void initcg(int, time_t, int, unsigned int); 13977885Stomsoftstatic void updjcg(int, time_t, int, int, unsigned int); 14077885Stomsoftstatic void updcsloc(time_t, int, int, unsigned int); 14169800Stomsoftstatic struct disklabel *get_disklabel(int); 14277885Stomsoftstatic void return_disklabel(int, struct disklabel *, unsigned int); 14398542Smckusickstatic union dinode *ginode(ino_t, int, int); 14498542Smckusickstatic void frag_adjust(ufs2_daddr_t, int); 14598542Smckusickstatic int cond_bl_upd(ufs2_daddr_t *, struct gfs_bpp *, int, int, 14698542Smckusick unsigned int); 14769800Stomsoftstatic void updclst(int); 14877885Stomsoftstatic void updrefs(int, ino_t, struct gfs_bpp *, int, int, unsigned int); 14998542Smckusickstatic void indirchk(ufs_lbn_t, ufs_lbn_t, ufs2_daddr_t, ufs_lbn_t, 15098542Smckusick struct gfs_bpp *, int, int, unsigned int); 15169800Stomsoft 15269800Stomsoft/* ************************************************************ growfs ***** */ 15369800Stomsoft/* 154102231Strhodes * Here we actually start growing the file system. We basically read the 15569926Stomsoft * cylinder summary from the first cylinder group as we want to update 15669800Stomsoft * this on the fly during our various operations. First we handle the 15769800Stomsoft * changes in the former last cylinder group. Afterwards we create all new 15869800Stomsoft * cylinder groups. Now we handle the cylinder group containing the 15969800Stomsoft * cylinder summary which might result in a relocation of the whole 16069800Stomsoft * structure. In the end we write back the updated cylinder summary, the 16169800Stomsoft * new superblock, and slightly patched versions of the super block 16269800Stomsoft * copies. 16369800Stomsoft */ 16469800Stomsoftstatic void 16577885Stomsoftgrowfs(int fsi, int fso, unsigned int Nflag) 16669800Stomsoft{ 16769800Stomsoft DBG_FUNC("growfs") 16877885Stomsoft int i; 16977885Stomsoft int cylno, j; 17069800Stomsoft time_t utime; 17169800Stomsoft int width; 17269800Stomsoft char tmpbuf[100]; 17369800Stomsoft#ifdef FSIRAND 17469800Stomsoft static int randinit=0; 17569800Stomsoft 17669800Stomsoft DBG_ENTER; 17769800Stomsoft 17869800Stomsoft if (!randinit) { 17969800Stomsoft randinit = 1; 18069800Stomsoft srandomdev(); 18169800Stomsoft } 18269800Stomsoft#else /* not FSIRAND */ 18369800Stomsoft 18469800Stomsoft DBG_ENTER; 18569800Stomsoft 18669800Stomsoft#endif /* FSIRAND */ 18769800Stomsoft time(&utime); 18869800Stomsoft 18969800Stomsoft /* 19069800Stomsoft * Get the cylinder summary into the memory. 19169800Stomsoft */ 19277885Stomsoft fscs = (struct csum *)calloc((size_t)1, (size_t)sblock.fs_cssize); 19369926Stomsoft if(fscs == NULL) { 19469926Stomsoft errx(1, "calloc failed"); 19569926Stomsoft } 19669800Stomsoft for (i = 0; i < osblock.fs_cssize; i += osblock.fs_bsize) { 19769800Stomsoft rdfs(fsbtodb(&osblock, osblock.fs_csaddr + 19877885Stomsoft numfrags(&osblock, i)), (size_t)MIN(osblock.fs_cssize - i, 19977885Stomsoft osblock.fs_bsize), (void *)(((char *)fscs)+i), fsi); 20069800Stomsoft } 20169800Stomsoft 20269800Stomsoft#ifdef FS_DEBUG 20369800Stomsoft{ 20469800Stomsoft struct csum *dbg_csp; 20569800Stomsoft int dbg_csc; 20669800Stomsoft char dbg_line[80]; 20769800Stomsoft 20869800Stomsoft dbg_csp=fscs; 20969800Stomsoft for(dbg_csc=0; dbg_csc<osblock.fs_ncg; dbg_csc++) { 21077885Stomsoft snprintf(dbg_line, sizeof(dbg_line), 21177885Stomsoft "%d. old csum in old location", dbg_csc); 21269926Stomsoft DBG_DUMP_CSUM(&osblock, 21369926Stomsoft dbg_line, 21469926Stomsoft dbg_csp++); 21569800Stomsoft } 21669800Stomsoft} 21769800Stomsoft#endif /* FS_DEBUG */ 21869800Stomsoft DBG_PRINT0("fscs read\n"); 21969800Stomsoft 22069800Stomsoft /* 22169800Stomsoft * Do all needed changes in the former last cylinder group. 22269800Stomsoft */ 22369800Stomsoft updjcg(osblock.fs_ncg-1, utime, fsi, fso, Nflag); 22469800Stomsoft 22569800Stomsoft /* 226102231Strhodes * Dump out summary information about file system. 22769800Stomsoft */ 22898542Smckusick# define B2MBFACTOR (1 / (1024.0 * 1024.0)) 22998542Smckusick printf("growfs: %.1fMB (%qd sectors) block size %d, fragment size %d\n", 23069800Stomsoft (float)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR, 23198542Smckusick fsbtodb(&sblock, sblock.fs_size), sblock.fs_bsize, sblock.fs_fsize); 23298542Smckusick printf("\tusing %d cylinder groups of %.2fMB, %d blks, %d inodes.\n", 23398542Smckusick sblock.fs_ncg, (float)sblock.fs_fpg * sblock.fs_fsize * B2MBFACTOR, 23498542Smckusick sblock.fs_fpg / sblock.fs_frag, sblock.fs_ipg); 23598542Smckusick if (sblock.fs_flags & FS_DOSOFTDEP) 23698542Smckusick printf("\twith soft updates\n"); 23798542Smckusick# undef B2MBFACTOR 23869800Stomsoft 23969800Stomsoft /* 24069800Stomsoft * Now build the cylinders group blocks and 24169800Stomsoft * then print out indices of cylinder groups. 24269800Stomsoft */ 24369800Stomsoft printf("super-block backups (for fsck -b #) at:\n"); 24469800Stomsoft i = 0; 24569800Stomsoft width = charsperline(); 24669800Stomsoft 24769800Stomsoft /* 24869800Stomsoft * Iterate for only the new cylinder groups. 24969800Stomsoft */ 25069800Stomsoft for (cylno = osblock.fs_ncg; cylno < sblock.fs_ncg; cylno++) { 25169800Stomsoft initcg(cylno, utime, fso, Nflag); 25277885Stomsoft j = sprintf(tmpbuf, " %d%s", 25377885Stomsoft (int)fsbtodb(&sblock, cgsblock(&sblock, cylno)), 25469800Stomsoft cylno < (sblock.fs_ncg-1) ? "," : "" ); 25569800Stomsoft if (i + j >= width) { 25669800Stomsoft printf("\n"); 25769800Stomsoft i = 0; 25869800Stomsoft } 25969800Stomsoft i += j; 26069800Stomsoft printf("%s", tmpbuf); 26169800Stomsoft fflush(stdout); 26269800Stomsoft } 26369800Stomsoft printf("\n"); 26469800Stomsoft 26569800Stomsoft /* 26669800Stomsoft * Do all needed changes in the first cylinder group. 26769800Stomsoft * allocate blocks in new location 26869800Stomsoft */ 26969800Stomsoft updcsloc(utime, fsi, fso, Nflag); 27069800Stomsoft 27169800Stomsoft /* 27269800Stomsoft * Now write the cylinder summary back to disk. 27369800Stomsoft */ 27469800Stomsoft for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize) { 27569800Stomsoft wtfs(fsbtodb(&sblock, sblock.fs_csaddr + numfrags(&sblock, i)), 27677885Stomsoft (size_t)MIN(sblock.fs_cssize - i, sblock.fs_bsize), 27777885Stomsoft (void *)(((char *)fscs) + i), fso, Nflag); 27869800Stomsoft } 27969800Stomsoft DBG_PRINT0("fscs written\n"); 28069800Stomsoft 28169800Stomsoft#ifdef FS_DEBUG 28269800Stomsoft{ 28369800Stomsoft struct csum *dbg_csp; 28469800Stomsoft int dbg_csc; 28569800Stomsoft char dbg_line[80]; 28669800Stomsoft 28769800Stomsoft dbg_csp=fscs; 28869800Stomsoft for(dbg_csc=0; dbg_csc<sblock.fs_ncg; dbg_csc++) { 28977885Stomsoft snprintf(dbg_line, sizeof(dbg_line), 29077885Stomsoft "%d. new csum in new location", dbg_csc); 29169926Stomsoft DBG_DUMP_CSUM(&sblock, 29269926Stomsoft dbg_line, 29369926Stomsoft dbg_csp++); 29469800Stomsoft } 29569800Stomsoft} 29669800Stomsoft#endif /* FS_DEBUG */ 29769800Stomsoft 29869800Stomsoft /* 29969800Stomsoft * Now write the new superblock back to disk. 30069800Stomsoft */ 30169800Stomsoft sblock.fs_time = utime; 30298542Smckusick wtfs(sblockloc, (size_t)SBLOCKSIZE, (void *)&sblock, fso, Nflag); 30369800Stomsoft DBG_PRINT0("sblock written\n"); 30469926Stomsoft DBG_DUMP_FS(&sblock, 30569926Stomsoft "new initial sblock"); 30669800Stomsoft 30769800Stomsoft /* 30869800Stomsoft * Clean up the dynamic fields in our superblock copies. 30969800Stomsoft */ 31069800Stomsoft sblock.fs_fmod = 0; 31169800Stomsoft sblock.fs_clean = 1; 31269800Stomsoft sblock.fs_ronly = 0; 31369800Stomsoft sblock.fs_cgrotor = 0; 31469800Stomsoft sblock.fs_state = 0; 31569800Stomsoft memset((void *)&sblock.fs_fsmnt, 0, sizeof(sblock.fs_fsmnt)); 31669800Stomsoft sblock.fs_flags &= FS_DOSOFTDEP; 31769800Stomsoft 31869800Stomsoft /* 31969800Stomsoft * XXX 32069800Stomsoft * The following fields are currently distributed from the superblock 32169800Stomsoft * to the copies: 32269800Stomsoft * fs_minfree 32369800Stomsoft * fs_rotdelay 32469800Stomsoft * fs_maxcontig 32569800Stomsoft * fs_maxbpg 32669800Stomsoft * fs_minfree, 32769800Stomsoft * fs_optim 32869800Stomsoft * fs_flags regarding SOFTPDATES 32969800Stomsoft * 33069800Stomsoft * We probably should rather change the summary for the cylinder group 33169800Stomsoft * statistics here to the value of what would be in there, if the file 33269800Stomsoft * system were created initially with the new size. Therefor we still 33369800Stomsoft * need to find an easy way of calculating that. 33469800Stomsoft * Possibly we can try to read the first superblock copy and apply the 33569800Stomsoft * "diffed" stats between the old and new superblock by still copying 33669800Stomsoft * certain parameters onto that. 33769800Stomsoft */ 33869800Stomsoft 33969800Stomsoft /* 34069800Stomsoft * Write out the duplicate super blocks. 34169800Stomsoft */ 34269800Stomsoft for (cylno = 0; cylno < sblock.fs_ncg; cylno++) { 34369800Stomsoft wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)), 34498542Smckusick (size_t)SBLOCKSIZE, (void *)&sblock, fso, Nflag); 34569800Stomsoft } 34669800Stomsoft DBG_PRINT0("sblock copies written\n"); 34769926Stomsoft DBG_DUMP_FS(&sblock, 34869926Stomsoft "new other sblocks"); 34969800Stomsoft 35069800Stomsoft DBG_LEAVE; 35169800Stomsoft return; 35269800Stomsoft} 35369800Stomsoft 35469800Stomsoft/* ************************************************************ initcg ***** */ 35569800Stomsoft/* 35669800Stomsoft * This creates a new cylinder group structure, for more details please see 35769800Stomsoft * the source of newfs(8), as this function is taken over almost unchanged. 35869800Stomsoft * As this is never called for the first cylinder group, the special 35969800Stomsoft * provisions for that case are removed here. 36069800Stomsoft */ 36169800Stomsoftstatic void 36277885Stomsoftinitcg(int cylno, time_t utime, int fso, unsigned int Nflag) 36369800Stomsoft{ 36469800Stomsoft DBG_FUNC("initcg") 36598542Smckusick static caddr_t iobuf; 36698542Smckusick long i, j, d, dlower, dupper, blkno, start; 36798542Smckusick ufs2_daddr_t cbase, dmax; 36898542Smckusick struct ufs1_dinode *dp1; 36998542Smckusick struct ufs2_dinode *dp2; 37092806Sobrien struct csum *cs; 37169800Stomsoft 37298542Smckusick if (iobuf == NULL && (iobuf = malloc(sblock.fs_bsize)) == NULL) { 37398542Smckusick errx(37, "panic: cannot allocate I/O buffer"); 37498542Smckusick } 37569800Stomsoft /* 37669800Stomsoft * Determine block bounds for cylinder group. 37798542Smckusick * Allow space for super block summary information in first 37898542Smckusick * cylinder group. 37969800Stomsoft */ 38069800Stomsoft cbase = cgbase(&sblock, cylno); 38169800Stomsoft dmax = cbase + sblock.fs_fpg; 38298542Smckusick if (dmax > sblock.fs_size) 38369800Stomsoft dmax = sblock.fs_size; 38469800Stomsoft dlower = cgsblock(&sblock, cylno) - cbase; 38569800Stomsoft dupper = cgdmin(&sblock, cylno) - cbase; 38698542Smckusick if (cylno == 0) /* XXX fscs may be relocated */ 38769800Stomsoft dupper += howmany(sblock.fs_cssize, sblock.fs_fsize); 38898542Smckusick cs = &fscs[cylno]; 38998542Smckusick memset(&acg, 0, sblock.fs_cgsize); 39069800Stomsoft acg.cg_time = utime; 39169800Stomsoft acg.cg_magic = CG_MAGIC; 39269800Stomsoft acg.cg_cgx = cylno; 39369800Stomsoft acg.cg_niblk = sblock.fs_ipg; 39498542Smckusick acg.cg_initediblk = sblock.fs_ipg; 39569800Stomsoft acg.cg_ndblk = dmax - cbase; 39698542Smckusick if (sblock.fs_contigsumsize > 0) 39769800Stomsoft acg.cg_nclusterblks = acg.cg_ndblk / sblock.fs_frag; 39898542Smckusick start = &acg.cg_space[0] - (u_char *)(&acg.cg_firstfield); 39998542Smckusick if (sblock.fs_magic == FS_UFS2_MAGIC) { 40098542Smckusick acg.cg_iusedoff = start; 40198542Smckusick } else { 40298542Smckusick acg.cg_old_ncyl = sblock.fs_old_cpg; 40398542Smckusick acg.cg_old_time = acg.cg_time; 40498542Smckusick acg.cg_time = 0; 40598542Smckusick acg.cg_old_niblk = acg.cg_niblk; 40698542Smckusick acg.cg_niblk = 0; 40798542Smckusick acg.cg_initediblk = 0; 40898542Smckusick acg.cg_old_btotoff = start; 40998542Smckusick acg.cg_old_boff = acg.cg_old_btotoff + 41098542Smckusick sblock.fs_old_cpg * sizeof(int32_t); 41198542Smckusick acg.cg_iusedoff = acg.cg_old_boff + 41298542Smckusick sblock.fs_old_cpg * sizeof(u_int16_t); 41369800Stomsoft } 414103949Smike acg.cg_freeoff = acg.cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT); 415103949Smike acg.cg_nextfreeoff = acg.cg_freeoff + howmany(sblock.fs_fpg, CHAR_BIT); 41698542Smckusick if (sblock.fs_contigsumsize > 0) { 41769800Stomsoft acg.cg_clustersumoff = 41898542Smckusick roundup(acg.cg_nextfreeoff, sizeof(u_int32_t)); 41998542Smckusick acg.cg_clustersumoff -= sizeof(u_int32_t); 42069800Stomsoft acg.cg_clusteroff = acg.cg_clustersumoff + 42169800Stomsoft (sblock.fs_contigsumsize + 1) * sizeof(u_int32_t); 42298542Smckusick acg.cg_nextfreeoff = acg.cg_clusteroff + 423103949Smike howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT); 42469800Stomsoft } 42598542Smckusick if (acg.cg_nextfreeoff > sblock.fs_cgsize) { 42669800Stomsoft /* 42798542Smckusick * This should never happen as we would have had that panic 428102231Strhodes * already on file system creation 42969800Stomsoft */ 43069926Stomsoft errx(37, "panic: cylinder group too big"); 43169800Stomsoft } 43269800Stomsoft acg.cg_cs.cs_nifree += sblock.fs_ipg; 43369800Stomsoft if (cylno == 0) 43498542Smckusick for (i = 0; i < ROOTINO; i++) { 43569800Stomsoft setbit(cg_inosused(&acg), i); 43669800Stomsoft acg.cg_cs.cs_nifree--; 43769800Stomsoft } 43898542Smckusick bzero(iobuf, sblock.fs_bsize); 43969800Stomsoft for (i = 0; i < sblock.fs_ipg / INOPF(&sblock); i += sblock.fs_frag) { 44098542Smckusick dp1 = (struct ufs1_dinode *)iobuf; 44198542Smckusick dp2 = (struct ufs2_dinode *)iobuf; 44269800Stomsoft#ifdef FSIRAND 44398542Smckusick for (j = 0; j < INOPB(&sblock); j++) 44498542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) { 44598542Smckusick dp1->di_gen = random(); 44698542Smckusick dp1++; 44798542Smckusick } else { 44898542Smckusick dp2->di_gen = random(); 44998542Smckusick dp2++; 45098542Smckusick } 45169800Stomsoft#endif 45269800Stomsoft wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i), 45398542Smckusick sblock.fs_bsize, iobuf, fso, Nflag); 45469800Stomsoft } 45598542Smckusick if (cylno > 0) { 45698542Smckusick /* 45798542Smckusick * In cylno 0, beginning space is reserved 45898542Smckusick * for boot and super blocks. 45998542Smckusick */ 46098542Smckusick for (d = 0; d < dlower; d += sblock.fs_frag) { 46198542Smckusick blkno = d / sblock.fs_frag; 46298542Smckusick setblock(&sblock, cg_blksfree(&acg), blkno); 46398542Smckusick if (sblock.fs_contigsumsize > 0) 46498542Smckusick setbit(cg_clustersfree(&acg), blkno); 46598542Smckusick acg.cg_cs.cs_nbfree++; 46669800Stomsoft } 46798542Smckusick sblock.fs_dsize += dlower; 46869800Stomsoft } 46969800Stomsoft sblock.fs_dsize += acg.cg_ndblk - dupper; 47069800Stomsoft if ((i = dupper % sblock.fs_frag)) { 47169800Stomsoft acg.cg_frsum[sblock.fs_frag - i]++; 47269800Stomsoft for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) { 47369800Stomsoft setbit(cg_blksfree(&acg), dupper); 47469800Stomsoft acg.cg_cs.cs_nffree++; 47569800Stomsoft } 47669800Stomsoft } 47798542Smckusick for (d = dupper; d + sblock.fs_frag <= acg.cg_ndblk; 47898542Smckusick d += sblock.fs_frag) { 47969800Stomsoft blkno = d / sblock.fs_frag; 48069800Stomsoft setblock(&sblock, cg_blksfree(&acg), blkno); 48198542Smckusick if (sblock.fs_contigsumsize > 0) 48269800Stomsoft setbit(cg_clustersfree(&acg), blkno); 48369800Stomsoft acg.cg_cs.cs_nbfree++; 48469800Stomsoft } 48598542Smckusick if (d < acg.cg_ndblk) { 48698542Smckusick acg.cg_frsum[acg.cg_ndblk - d]++; 48798542Smckusick for (; d < acg.cg_ndblk; d++) { 48869800Stomsoft setbit(cg_blksfree(&acg), d); 48969800Stomsoft acg.cg_cs.cs_nffree++; 49069800Stomsoft } 49169800Stomsoft } 49269800Stomsoft if (sblock.fs_contigsumsize > 0) { 49398542Smckusick int32_t *sump = cg_clustersum(&acg); 49498542Smckusick u_char *mapp = cg_clustersfree(&acg); 49598542Smckusick int map = *mapp++; 49698542Smckusick int bit = 1; 49798542Smckusick int run = 0; 49869800Stomsoft 49969800Stomsoft for (i = 0; i < acg.cg_nclusterblks; i++) { 50098542Smckusick if ((map & bit) != 0) 50169800Stomsoft run++; 50298542Smckusick else if (run != 0) { 50398542Smckusick if (run > sblock.fs_contigsumsize) 50469800Stomsoft run = sblock.fs_contigsumsize; 50569800Stomsoft sump[run]++; 50669800Stomsoft run = 0; 50769800Stomsoft } 508103949Smike if ((i & (CHAR_BIT - 1)) != CHAR_BIT - 1) 50969800Stomsoft bit <<= 1; 51098542Smckusick else { 51169800Stomsoft map = *mapp++; 51269800Stomsoft bit = 1; 51369800Stomsoft } 51469800Stomsoft } 51569800Stomsoft if (run != 0) { 51698542Smckusick if (run > sblock.fs_contigsumsize) 51769800Stomsoft run = sblock.fs_contigsumsize; 51869800Stomsoft sump[run]++; 51969800Stomsoft } 52069800Stomsoft } 52169800Stomsoft sblock.fs_cstotal.cs_ndir += acg.cg_cs.cs_ndir; 52269800Stomsoft sblock.fs_cstotal.cs_nffree += acg.cg_cs.cs_nffree; 52369800Stomsoft sblock.fs_cstotal.cs_nbfree += acg.cg_cs.cs_nbfree; 52469800Stomsoft sblock.fs_cstotal.cs_nifree += acg.cg_cs.cs_nifree; 52569800Stomsoft *cs = acg.cg_cs; 52669800Stomsoft wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)), 52798542Smckusick sblock.fs_bsize, (char *)&acg, fso, Nflag); 52869926Stomsoft DBG_DUMP_CG(&sblock, 52969926Stomsoft "new cg", 53069926Stomsoft &acg); 53169800Stomsoft 53269800Stomsoft DBG_LEAVE; 53369800Stomsoft return; 53469800Stomsoft} 53569800Stomsoft 53669800Stomsoft/* ******************************************************* frag_adjust ***** */ 53769800Stomsoft/* 53869800Stomsoft * Here we add or subtract (sign +1/-1) the available fragments in a given 53969800Stomsoft * block to or from the fragment statistics. By subtracting before and adding 54069800Stomsoft * after an operation on the free frag map we can easy update the fragment 54169800Stomsoft * statistic, which seems to be otherwise an rather complex operation. 54269800Stomsoft */ 54369800Stomsoftstatic void 54498542Smckusickfrag_adjust(ufs2_daddr_t frag, int sign) 54569800Stomsoft{ 54669800Stomsoft DBG_FUNC("frag_adjust") 54769800Stomsoft int fragsize; 54869800Stomsoft int f; 54969800Stomsoft 55069800Stomsoft DBG_ENTER; 55169800Stomsoft 55269800Stomsoft fragsize=0; 55369800Stomsoft /* 55469800Stomsoft * Here frag only needs to point to any fragment in the block we want 55569800Stomsoft * to examine. 55669800Stomsoft */ 55769800Stomsoft for(f=rounddown(frag, sblock.fs_frag); 55869800Stomsoft f<roundup(frag+1, sblock.fs_frag); 55969800Stomsoft f++) { 56069800Stomsoft /* 56169800Stomsoft * Count contiguos free fragments. 56269800Stomsoft */ 56369800Stomsoft if(isset(cg_blksfree(&acg), f)) { 56469800Stomsoft fragsize++; 56569800Stomsoft } else { 56669800Stomsoft if(fragsize && fragsize<sblock.fs_frag) { 56769800Stomsoft /* 56869800Stomsoft * We found something in between. 56969800Stomsoft */ 57069800Stomsoft acg.cg_frsum[fragsize]+=sign; 57169926Stomsoft DBG_PRINT2("frag_adjust [%d]+=%d\n", 57269926Stomsoft fragsize, 57369926Stomsoft sign); 57469800Stomsoft } 57569800Stomsoft fragsize=0; 57669800Stomsoft } 57769800Stomsoft } 57869800Stomsoft if(fragsize && fragsize<sblock.fs_frag) { 57969800Stomsoft /* 58069800Stomsoft * We found something. 58169800Stomsoft */ 58269800Stomsoft acg.cg_frsum[fragsize]+=sign; 58369926Stomsoft DBG_PRINT2("frag_adjust [%d]+=%d\n", 58469926Stomsoft fragsize, 58569926Stomsoft sign); 58669800Stomsoft } 58769926Stomsoft DBG_PRINT2("frag_adjust [[%d]]+=%d\n", 58869926Stomsoft fragsize, 58969926Stomsoft sign); 59069800Stomsoft 59169800Stomsoft DBG_LEAVE; 59269800Stomsoft return; 59369800Stomsoft} 59469800Stomsoft 59569800Stomsoft/* ******************************************************* cond_bl_upd ***** */ 59669800Stomsoft/* 59769800Stomsoft * Here we conditionally update a pointer to a fragment. We check for all 59869800Stomsoft * relocated blocks if any of it's fragments is referenced by the current 59969800Stomsoft * field, and update the pointer to the respective fragment in our new 60069800Stomsoft * block. If we find a reference we write back the block immediately, 60169800Stomsoft * as there is no easy way for our general block reading engine to figure 60269800Stomsoft * out if a write back operation is needed. 60369800Stomsoft */ 60498542Smckusickstatic int 60598542Smckusickcond_bl_upd(ufs2_daddr_t *block, struct gfs_bpp *field, int fsi, int fso, 60698542Smckusick unsigned int Nflag) 60769800Stomsoft{ 60869800Stomsoft DBG_FUNC("cond_bl_upd") 60998542Smckusick struct gfs_bpp *f; 61098542Smckusick ufs2_daddr_t src, dst; 61198542Smckusick int fragnum; 61298542Smckusick void *ibuf; 61369800Stomsoft 61469800Stomsoft DBG_ENTER; 61569800Stomsoft 61698542Smckusick f = field; 61798542Smckusick for (f = field; f->old != 0; f++) { 61898542Smckusick src = *block; 61998542Smckusick if (fragstoblks(&sblock, src) != f->old) 62098542Smckusick continue; 62198542Smckusick /* 62298542Smckusick * The fragment is part of the block, so update. 62398542Smckusick */ 62498542Smckusick dst = blkstofrags(&sblock, f->new); 62598542Smckusick fragnum = fragnum(&sblock, src); 62698542Smckusick *block = dst + fragnum; 62798542Smckusick f->found++; 62898542Smckusick DBG_PRINT3("scg (%d->%d)[%d] reference updated\n", 62998542Smckusick f->old, 63098542Smckusick f->new, 63198542Smckusick fragnum); 63269800Stomsoft 63398542Smckusick /* 63498542Smckusick * Copy the block back immediately. 63598542Smckusick * 63698542Smckusick * XXX If src is is from an indirect block we have 63798542Smckusick * to implement copy on write here in case of 63898542Smckusick * active snapshots. 63998542Smckusick */ 64098542Smckusick ibuf = malloc(sblock.fs_bsize); 64198542Smckusick if (!ibuf) 64298542Smckusick errx(1, "malloc failed"); 64398542Smckusick src -= fragnum; 64498542Smckusick rdfs(fsbtodb(&sblock, src), (size_t)sblock.fs_bsize, ibuf, fsi); 64598542Smckusick wtfs(dst, (size_t)sblock.fs_bsize, ibuf, fso, Nflag); 64698542Smckusick free(ibuf); 64798542Smckusick /* 64898542Smckusick * The same block can't be found again in this loop. 64998542Smckusick */ 65098542Smckusick return (1); 65169800Stomsoft } 65269800Stomsoft 65369800Stomsoft DBG_LEAVE; 65498542Smckusick return (0); 65569800Stomsoft} 65669800Stomsoft 65769800Stomsoft/* ************************************************************ updjcg ***** */ 65869800Stomsoft/* 65969800Stomsoft * Here we do all needed work for the former last cylinder group. It has to be 660102231Strhodes * changed in any case, even if the file system ended exactly on the end of 66169800Stomsoft * this group, as there is some slightly inconsistent handling of the number 66269800Stomsoft * of cylinders in the cylinder group. We start again by reading the cylinder 66369800Stomsoft * group from disk. If the last block was not fully available, we first handle 66469800Stomsoft * the missing fragments, then we handle all new full blocks in that file 66569800Stomsoft * system and finally we handle the new last fragmented block in the file 66669800Stomsoft * system. We again have to handle the fragment statistics rotational layout 66769800Stomsoft * tables and cluster summary during all those operations. 66869800Stomsoft */ 66969800Stomsoftstatic void 67077885Stomsoftupdjcg(int cylno, time_t utime, int fsi, int fso, unsigned int Nflag) 67169800Stomsoft{ 67269800Stomsoft DBG_FUNC("updjcg") 67398542Smckusick ufs2_daddr_t cbase, dmax, dupper; 67469800Stomsoft struct csum *cs; 67569800Stomsoft int i,k; 67669800Stomsoft int j=0; 67769800Stomsoft 67869800Stomsoft DBG_ENTER; 67969800Stomsoft 68069800Stomsoft /* 68169800Stomsoft * Read the former last (joining) cylinder group from disk, and make 68269800Stomsoft * a copy. 68369800Stomsoft */ 68477885Stomsoft rdfs(fsbtodb(&osblock, cgtod(&osblock, cylno)), 68577885Stomsoft (size_t)osblock.fs_cgsize, (void *)&aocg, fsi); 68669800Stomsoft DBG_PRINT0("jcg read\n"); 68769926Stomsoft DBG_DUMP_CG(&sblock, 68869926Stomsoft "old joining cg", 68969926Stomsoft &aocg); 69069800Stomsoft 69169800Stomsoft memcpy((void *)&cgun1, (void *)&cgun2, sizeof(cgun2)); 69269800Stomsoft 69369800Stomsoft /* 69469800Stomsoft * If the cylinder group had already it's new final size almost 69569800Stomsoft * nothing is to be done ... except: 69669800Stomsoft * For some reason the value of cg_ncyl in the last cylinder group has 69769800Stomsoft * to be zero instead of fs_cpg. As this is now no longer the last 69869800Stomsoft * cylinder group we have to change that value now to fs_cpg. 69969800Stomsoft */ 70069800Stomsoft 70169800Stomsoft if(cgbase(&osblock, cylno+1) == osblock.fs_size) { 70298542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 70398542Smckusick acg.cg_old_ncyl=sblock.fs_old_cpg; 70469800Stomsoft 70577885Stomsoft wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)), 70677885Stomsoft (size_t)sblock.fs_cgsize, (void *)&acg, fso, Nflag); 70769800Stomsoft DBG_PRINT0("jcg written\n"); 70869926Stomsoft DBG_DUMP_CG(&sblock, 70969926Stomsoft "new joining cg", 71069926Stomsoft &acg); 71169800Stomsoft 71269800Stomsoft DBG_LEAVE; 71369800Stomsoft return; 71469800Stomsoft } 71569800Stomsoft 71669800Stomsoft /* 71769800Stomsoft * Set up some variables needed later. 71869800Stomsoft */ 71969800Stomsoft cbase = cgbase(&sblock, cylno); 72069800Stomsoft dmax = cbase + sblock.fs_fpg; 72169800Stomsoft if (dmax > sblock.fs_size) 72269800Stomsoft dmax = sblock.fs_size; 72369800Stomsoft dupper = cgdmin(&sblock, cylno) - cbase; 72477885Stomsoft if (cylno == 0) { /* XXX fscs may be relocated */ 72569800Stomsoft dupper += howmany(sblock.fs_cssize, sblock.fs_fsize); 72669800Stomsoft } 72769800Stomsoft 72869800Stomsoft /* 72969800Stomsoft * Set pointer to the cylinder summary for our cylinder group. 73069800Stomsoft */ 73169800Stomsoft cs = fscs + cylno; 73269800Stomsoft 73369800Stomsoft /* 73469800Stomsoft * Touch the cylinder group, update all fields in the cylinder group as 73569800Stomsoft * needed, update the free space in the superblock. 73669800Stomsoft */ 73769800Stomsoft acg.cg_time = utime; 73869800Stomsoft if (cylno == sblock.fs_ncg - 1) { 73969800Stomsoft /* 74069800Stomsoft * This is still the last cylinder group. 74169800Stomsoft */ 74298542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 74398542Smckusick acg.cg_old_ncyl = 74498542Smckusick sblock.fs_old_ncyl % sblock.fs_old_cpg; 74569800Stomsoft } else { 74698542Smckusick acg.cg_old_ncyl = sblock.fs_old_cpg; 74769800Stomsoft } 74898542Smckusick DBG_PRINT2("jcg dbg: %d %u", 74969926Stomsoft cylno, 75098542Smckusick sblock.fs_ncg); 75198542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 75298542Smckusick DBG_PRINT2("%d %u", 75398542Smckusick acg.cg_old_ncyl, 75498542Smckusick sblock.fs_old_cpg); 75598542Smckusick DBG_PRINT0("\n"); 75669800Stomsoft acg.cg_ndblk = dmax - cbase; 75769800Stomsoft sblock.fs_dsize += acg.cg_ndblk-aocg.cg_ndblk; 75869800Stomsoft if (sblock.fs_contigsumsize > 0) { 75969800Stomsoft acg.cg_nclusterblks = acg.cg_ndblk / sblock.fs_frag; 76069800Stomsoft } 76169800Stomsoft 76269800Stomsoft /* 76369800Stomsoft * Now we have to update the free fragment bitmap for our new free 76469800Stomsoft * space. There again we have to handle the fragmentation and also 76569800Stomsoft * the rotational layout tables and the cluster summary. This is 76669800Stomsoft * also done per fragment for the first new block if the old file 76769800Stomsoft * system end was not on a block boundary, per fragment for the new 768102231Strhodes * last block if the new file system end is not on a block boundary, 76969800Stomsoft * and per block for all space in between. 77069800Stomsoft * 77169800Stomsoft * Handle the first new block here if it was partially available 77269800Stomsoft * before. 77369800Stomsoft */ 77469800Stomsoft if(osblock.fs_size % sblock.fs_frag) { 77569800Stomsoft if(roundup(osblock.fs_size, sblock.fs_frag)<=sblock.fs_size) { 77669800Stomsoft /* 77769800Stomsoft * The new space is enough to fill at least this 77869800Stomsoft * block 77969800Stomsoft */ 78069800Stomsoft j=0; 78169800Stomsoft for(i=roundup(osblock.fs_size-cbase, sblock.fs_frag)-1; 78269800Stomsoft i>=osblock.fs_size-cbase; 78369800Stomsoft i--) { 78469800Stomsoft setbit(cg_blksfree(&acg), i); 78569800Stomsoft acg.cg_cs.cs_nffree++; 78669800Stomsoft j++; 78769800Stomsoft } 78869800Stomsoft 78969800Stomsoft /* 79069800Stomsoft * Check if the fragment just created could join an 79169800Stomsoft * already existing fragment at the former end of the 792102231Strhodes * file system. 79369800Stomsoft */ 79469800Stomsoft if(isblock(&sblock, cg_blksfree(&acg), 79569800Stomsoft ((osblock.fs_size - cgbase(&sblock, cylno))/ 79669800Stomsoft sblock.fs_frag))) { 79769800Stomsoft /* 79869800Stomsoft * The block is now completely available 79969800Stomsoft */ 80069800Stomsoft DBG_PRINT0("block was\n"); 80169800Stomsoft acg.cg_frsum[osblock.fs_size%sblock.fs_frag]--; 80269800Stomsoft acg.cg_cs.cs_nbfree++; 80369800Stomsoft acg.cg_cs.cs_nffree-=sblock.fs_frag; 80469800Stomsoft k=rounddown(osblock.fs_size-cbase, 80569800Stomsoft sblock.fs_frag); 80669800Stomsoft updclst((osblock.fs_size-cbase)/sblock.fs_frag); 80769800Stomsoft } else { 80869800Stomsoft /* 80969800Stomsoft * Lets rejoin a possible partially growed 81069800Stomsoft * fragment. 81169800Stomsoft */ 81269800Stomsoft k=0; 81369800Stomsoft while(isset(cg_blksfree(&acg), i) && 81469800Stomsoft (i>=rounddown(osblock.fs_size-cbase, 81569800Stomsoft sblock.fs_frag))) { 81669800Stomsoft i--; 81769800Stomsoft k++; 81869800Stomsoft } 81969800Stomsoft if(k) { 82069800Stomsoft acg.cg_frsum[k]--; 82169800Stomsoft } 82269800Stomsoft acg.cg_frsum[k+j]++; 82369800Stomsoft } 82469800Stomsoft } else { 82569800Stomsoft /* 82669800Stomsoft * We only grow by some fragments within this last 82769800Stomsoft * block. 82869800Stomsoft */ 82969800Stomsoft for(i=sblock.fs_size-cbase-1; 83069800Stomsoft i>=osblock.fs_size-cbase; 83169800Stomsoft i--) { 83269800Stomsoft setbit(cg_blksfree(&acg), i); 83369800Stomsoft acg.cg_cs.cs_nffree++; 83469800Stomsoft j++; 83569800Stomsoft } 83669800Stomsoft /* 83769800Stomsoft * Lets rejoin a possible partially growed fragment. 83869800Stomsoft */ 83969800Stomsoft k=0; 84069800Stomsoft while(isset(cg_blksfree(&acg), i) && 84169800Stomsoft (i>=rounddown(osblock.fs_size-cbase, 84269800Stomsoft sblock.fs_frag))) { 84369800Stomsoft i--; 84469800Stomsoft k++; 84569800Stomsoft } 84669800Stomsoft if(k) { 84769800Stomsoft acg.cg_frsum[k]--; 84869800Stomsoft } 84969800Stomsoft acg.cg_frsum[k+j]++; 85069800Stomsoft } 85169800Stomsoft } 85269800Stomsoft 85369800Stomsoft /* 85469800Stomsoft * Handle all new complete blocks here. 85569800Stomsoft */ 85669800Stomsoft for(i=roundup(osblock.fs_size-cbase, sblock.fs_frag); 85769800Stomsoft i+sblock.fs_frag<=dmax-cbase; /* XXX <= or only < ? */ 85869800Stomsoft i+=sblock.fs_frag) { 85969800Stomsoft j = i / sblock.fs_frag; 86069800Stomsoft setblock(&sblock, cg_blksfree(&acg), j); 86169800Stomsoft updclst(j); 86269800Stomsoft acg.cg_cs.cs_nbfree++; 86369800Stomsoft } 86469800Stomsoft 86569800Stomsoft /* 86669800Stomsoft * Handle the last new block if there are stll some new fragments left. 86769800Stomsoft * Here we don't have to bother about the cluster summary or the even 86869800Stomsoft * the rotational layout table. 86969800Stomsoft */ 87069800Stomsoft if (i < (dmax - cbase)) { 87169800Stomsoft acg.cg_frsum[dmax - cbase - i]++; 87269800Stomsoft for (; i < dmax - cbase; i++) { 87369800Stomsoft setbit(cg_blksfree(&acg), i); 87469800Stomsoft acg.cg_cs.cs_nffree++; 87569800Stomsoft } 87669800Stomsoft } 87769800Stomsoft 87869800Stomsoft sblock.fs_cstotal.cs_nffree += 87969800Stomsoft (acg.cg_cs.cs_nffree - aocg.cg_cs.cs_nffree); 88069800Stomsoft sblock.fs_cstotal.cs_nbfree += 88169800Stomsoft (acg.cg_cs.cs_nbfree - aocg.cg_cs.cs_nbfree); 88269800Stomsoft /* 88369800Stomsoft * The following statistics are not changed here: 88469800Stomsoft * sblock.fs_cstotal.cs_ndir 88569800Stomsoft * sblock.fs_cstotal.cs_nifree 88669800Stomsoft * As the statistics for this cylinder group are ready, copy it to 88769800Stomsoft * the summary information array. 88869800Stomsoft */ 88969800Stomsoft *cs = acg.cg_cs; 89069800Stomsoft 89169800Stomsoft /* 89269800Stomsoft * Write the updated "joining" cylinder group back to disk. 89369800Stomsoft */ 89477885Stomsoft wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)), (size_t)sblock.fs_cgsize, 89577885Stomsoft (void *)&acg, fso, Nflag); 89669800Stomsoft DBG_PRINT0("jcg written\n"); 89769926Stomsoft DBG_DUMP_CG(&sblock, 89869926Stomsoft "new joining cg", 89969926Stomsoft &acg); 90069800Stomsoft 90169800Stomsoft DBG_LEAVE; 90269800Stomsoft return; 90369800Stomsoft} 90469800Stomsoft 90569800Stomsoft/* ********************************************************** updcsloc ***** */ 90669800Stomsoft/* 90769800Stomsoft * Here we update the location of the cylinder summary. We have two possible 90869800Stomsoft * ways of growing the cylinder summary. 90969800Stomsoft * (1) We can try to grow the summary in the current location, and relocate 91069800Stomsoft * possibly used blocks within the current cylinder group. 91169800Stomsoft * (2) Alternatively we can relocate the whole cylinder summary to the first 91269800Stomsoft * new completely empty cylinder group. Once the cylinder summary is no 91369800Stomsoft * longer in the beginning of the first cylinder group you should never 91469800Stomsoft * use a version of fsck which is not aware of the possibility to have 91569800Stomsoft * this structure in a non standard place. 91669800Stomsoft * Option (1) is considered to be less intrusive to the structure of the file- 91769800Stomsoft * system. So we try to stick to that whenever possible. If there is not enough 91869800Stomsoft * space in the cylinder group containing the cylinder summary we have to use 919102231Strhodes * method (2). In case of active snapshots in the file system we probably can 92069800Stomsoft * completely avoid implementing copy on write if we stick to method (2) only. 92169800Stomsoft */ 92269800Stomsoftstatic void 92377885Stomsoftupdcsloc(time_t utime, int fsi, int fso, unsigned int Nflag) 92469800Stomsoft{ 92569800Stomsoft DBG_FUNC("updcsloc") 92669800Stomsoft struct csum *cs; 92769800Stomsoft int ocscg, ncscg; 92869800Stomsoft int blocks; 92998542Smckusick ufs2_daddr_t cbase, dupper, odupper, d, f, g; 93069800Stomsoft int ind; 93169800Stomsoft int cylno, inc; 93269800Stomsoft struct gfs_bpp *bp; 93369800Stomsoft int i, l; 93469800Stomsoft int lcs=0; 93569800Stomsoft int block; 93669800Stomsoft 93769800Stomsoft DBG_ENTER; 93869800Stomsoft 93969800Stomsoft if(howmany(sblock.fs_cssize, sblock.fs_fsize) == 94069800Stomsoft howmany(osblock.fs_cssize, osblock.fs_fsize)) { 94169800Stomsoft /* 94269800Stomsoft * No new fragment needed. 94369800Stomsoft */ 94469800Stomsoft DBG_LEAVE; 94569800Stomsoft return; 94669800Stomsoft } 94769800Stomsoft ocscg=dtog(&osblock, osblock.fs_csaddr); 94869800Stomsoft cs=fscs+ocscg; 94969800Stomsoft blocks = 1+howmany(sblock.fs_cssize, sblock.fs_bsize)- 95069800Stomsoft howmany(osblock.fs_cssize, osblock.fs_bsize); 95169800Stomsoft 95269800Stomsoft /* 95369800Stomsoft * Read original cylinder group from disk, and make a copy. 95481311Schm * XXX If Nflag is set in some very rare cases we now miss 95581311Schm * some changes done in updjcg by reading the unmodified 95681311Schm * block from disk. 95769800Stomsoft */ 95877885Stomsoft rdfs(fsbtodb(&osblock, cgtod(&osblock, ocscg)), 95977885Stomsoft (size_t)osblock.fs_cgsize, (void *)&aocg, fsi); 96069800Stomsoft DBG_PRINT0("oscg read\n"); 96169926Stomsoft DBG_DUMP_CG(&sblock, 96269926Stomsoft "old summary cg", 96369926Stomsoft &aocg); 96469800Stomsoft 96569800Stomsoft memcpy((void *)&cgun1, (void *)&cgun2, sizeof(cgun2)); 96669800Stomsoft 96769800Stomsoft /* 96869800Stomsoft * Touch the cylinder group, set up local variables needed later 96969800Stomsoft * and update the superblock. 97069800Stomsoft */ 97169800Stomsoft acg.cg_time = utime; 97269800Stomsoft 97369800Stomsoft /* 97469800Stomsoft * XXX In the case of having active snapshots we may need much more 97569800Stomsoft * blocks for the copy on write. We need each block twice, and 97669800Stomsoft * also up to 8*3 blocks for indirect blocks for all possible 97769800Stomsoft * references. 97869800Stomsoft */ 97969800Stomsoft if(/*((int)sblock.fs_time&0x3)>0||*/ cs->cs_nbfree < blocks) { 98069800Stomsoft /* 98169800Stomsoft * There is not enough space in the old cylinder group to 98269800Stomsoft * relocate all blocks as needed, so we relocate the whole 98369800Stomsoft * cylinder group summary to a new group. We try to use the 98469800Stomsoft * first complete new cylinder group just created. Within the 98569800Stomsoft * cylinder group we allign the area immediately after the 98669800Stomsoft * cylinder group information location in order to be as 98769800Stomsoft * close as possible to the original implementation of ffs. 98869800Stomsoft * 98969800Stomsoft * First we have to make sure we'll find enough space in the 99069800Stomsoft * new cylinder group. If not, then we currently give up. 99169800Stomsoft * We start with freeing everything which was used by the 99269800Stomsoft * fragments of the old cylinder summary in the current group. 99369800Stomsoft * Now we write back the group meta data, read in the needed 99469800Stomsoft * meta data from the new cylinder group, and start allocating 99569800Stomsoft * within that group. Here we can assume, the group to be 99669800Stomsoft * completely empty. Which makes the handling of fragments and 99769800Stomsoft * clusters a lot easier. 99869800Stomsoft */ 99969800Stomsoft DBG_TRC; 100069800Stomsoft if(sblock.fs_ncg-osblock.fs_ncg < 2) { 100169926Stomsoft errx(2, "panic: not enough space"); 100269800Stomsoft } 100369800Stomsoft 100469800Stomsoft /* 100569800Stomsoft * Point "d" to the first fragment not used by the cylinder 100669800Stomsoft * summary. 100769800Stomsoft */ 100869800Stomsoft d=osblock.fs_csaddr+(osblock.fs_cssize/osblock.fs_fsize); 100969800Stomsoft 101069800Stomsoft /* 101169800Stomsoft * Set up last cluster size ("lcs") already here. Calculate 101269800Stomsoft * the size for the trailing cluster just behind where "d" 101369800Stomsoft * points to. 101469800Stomsoft */ 101569800Stomsoft if(sblock.fs_contigsumsize > 0) { 101669800Stomsoft for(block=howmany(d%sblock.fs_fpg, sblock.fs_frag), 101769800Stomsoft lcs=0; lcs<sblock.fs_contigsumsize; 101869800Stomsoft block++, lcs++) { 101969800Stomsoft if(isclr(cg_clustersfree(&acg), block)){ 102069800Stomsoft break; 102169800Stomsoft } 102269800Stomsoft } 102369800Stomsoft } 102469800Stomsoft 102569800Stomsoft /* 102669800Stomsoft * Point "d" to the last frag used by the cylinder summary. 102769800Stomsoft */ 102869800Stomsoft d--; 102969800Stomsoft 103069926Stomsoft DBG_PRINT1("d=%d\n", 103169926Stomsoft d); 103269800Stomsoft if((d+1)%sblock.fs_frag) { 103369800Stomsoft /* 103469800Stomsoft * The end of the cylinder summary is not a complete 103569800Stomsoft * block. 103669800Stomsoft */ 103769800Stomsoft DBG_TRC; 103869800Stomsoft frag_adjust(d%sblock.fs_fpg, -1); 103969800Stomsoft for(; (d+1)%sblock.fs_frag; d--) { 104069926Stomsoft DBG_PRINT1("d=%d\n", 104169926Stomsoft d); 104269800Stomsoft setbit(cg_blksfree(&acg), d%sblock.fs_fpg); 104369800Stomsoft acg.cg_cs.cs_nffree++; 104469800Stomsoft sblock.fs_cstotal.cs_nffree++; 104569800Stomsoft } 104669800Stomsoft /* 104769800Stomsoft * Point "d" to the last fragment of the last 104869800Stomsoft * (incomplete) block of the clinder summary. 104969800Stomsoft */ 105069800Stomsoft d++; 105169800Stomsoft frag_adjust(d%sblock.fs_fpg, 1); 105269800Stomsoft 105369800Stomsoft if(isblock(&sblock, cg_blksfree(&acg), 105469800Stomsoft (d%sblock.fs_fpg)/sblock.fs_frag)) { 105569926Stomsoft DBG_PRINT1("d=%d\n", 105669926Stomsoft d); 105769800Stomsoft acg.cg_cs.cs_nffree-=sblock.fs_frag; 105869800Stomsoft acg.cg_cs.cs_nbfree++; 105969800Stomsoft sblock.fs_cstotal.cs_nffree-=sblock.fs_frag; 106069800Stomsoft sblock.fs_cstotal.cs_nbfree++; 106169800Stomsoft if(sblock.fs_contigsumsize > 0) { 106269800Stomsoft setbit(cg_clustersfree(&acg), 106369800Stomsoft (d%sblock.fs_fpg)/sblock.fs_frag); 106469800Stomsoft if(lcs < sblock.fs_contigsumsize) { 106569800Stomsoft if(lcs) { 106669800Stomsoft cg_clustersum(&acg) 106769800Stomsoft [lcs]--; 106869800Stomsoft } 106969800Stomsoft lcs++; 107069800Stomsoft cg_clustersum(&acg)[lcs]++; 107169800Stomsoft } 107269800Stomsoft } 107369800Stomsoft } 107469800Stomsoft /* 107569800Stomsoft * Point "d" to the first fragment of the block before 107669800Stomsoft * the last incomplete block. 107769800Stomsoft */ 107869800Stomsoft d--; 107969800Stomsoft } 108069800Stomsoft 108169926Stomsoft DBG_PRINT1("d=%d\n", 108269926Stomsoft d); 108369800Stomsoft for(d=rounddown(d, sblock.fs_frag); d >= osblock.fs_csaddr; 108469800Stomsoft d-=sblock.fs_frag) { 108569800Stomsoft DBG_TRC; 108669926Stomsoft DBG_PRINT1("d=%d\n", 108769926Stomsoft d); 108869800Stomsoft setblock(&sblock, cg_blksfree(&acg), 108969800Stomsoft (d%sblock.fs_fpg)/sblock.fs_frag); 109069800Stomsoft acg.cg_cs.cs_nbfree++; 109169800Stomsoft sblock.fs_cstotal.cs_nbfree++; 109269800Stomsoft if(sblock.fs_contigsumsize > 0) { 109369800Stomsoft setbit(cg_clustersfree(&acg), 109469800Stomsoft (d%sblock.fs_fpg)/sblock.fs_frag); 109569800Stomsoft /* 109669800Stomsoft * The last cluster size is already set up. 109769800Stomsoft */ 109869800Stomsoft if(lcs < sblock.fs_contigsumsize) { 109969800Stomsoft if(lcs) { 110069800Stomsoft cg_clustersum(&acg)[lcs]--; 110169800Stomsoft } 110269800Stomsoft lcs++; 110369800Stomsoft cg_clustersum(&acg)[lcs]++; 110469800Stomsoft } 110569800Stomsoft } 110669800Stomsoft } 110769800Stomsoft *cs = acg.cg_cs; 110869800Stomsoft 110969800Stomsoft /* 111069800Stomsoft * Now write the former cylinder group containing the cylinder 111169800Stomsoft * summary back to disk. 111269800Stomsoft */ 111377885Stomsoft wtfs(fsbtodb(&sblock, cgtod(&sblock, ocscg)), 111477885Stomsoft (size_t)sblock.fs_cgsize, (void *)&acg, fso, Nflag); 111569800Stomsoft DBG_PRINT0("oscg written\n"); 111669926Stomsoft DBG_DUMP_CG(&sblock, 111769926Stomsoft "old summary cg", 111869926Stomsoft &acg); 111969800Stomsoft 112069800Stomsoft /* 112169800Stomsoft * Find the beginning of the new cylinder group containing the 112269800Stomsoft * cylinder summary. 112369800Stomsoft */ 112469800Stomsoft sblock.fs_csaddr=cgdmin(&sblock, osblock.fs_ncg); 112569800Stomsoft ncscg=dtog(&sblock, sblock.fs_csaddr); 112669800Stomsoft cs=fscs+ncscg; 112769800Stomsoft 112881311Schm 112969800Stomsoft /* 113081311Schm * If Nflag is specified, we would now read random data instead 113181311Schm * of an empty cg structure from disk. So we can't simulate that 113281311Schm * part for now. 113381311Schm */ 113481311Schm if(Nflag) { 113581311Schm DBG_PRINT0("nscg update skipped\n"); 113681311Schm DBG_LEAVE; 113781311Schm return; 113881311Schm } 113981311Schm 114081311Schm /* 114169800Stomsoft * Read the future cylinder group containing the cylinder 114269800Stomsoft * summary from disk, and make a copy. 114369800Stomsoft */ 114469800Stomsoft rdfs(fsbtodb(&sblock, cgtod(&sblock, ncscg)), 114577885Stomsoft (size_t)sblock.fs_cgsize, (void *)&aocg, fsi); 114669800Stomsoft DBG_PRINT0("nscg read\n"); 114769926Stomsoft DBG_DUMP_CG(&sblock, 114869926Stomsoft "new summary cg", 114969926Stomsoft &aocg); 115069800Stomsoft 115169800Stomsoft memcpy((void *)&cgun1, (void *)&cgun2, sizeof(cgun2)); 115269800Stomsoft 115369800Stomsoft /* 115469800Stomsoft * Allocate all complete blocks used by the new cylinder 115569800Stomsoft * summary. 115669800Stomsoft */ 115769800Stomsoft for(d=sblock.fs_csaddr; d+sblock.fs_frag <= 115869800Stomsoft sblock.fs_csaddr+(sblock.fs_cssize/sblock.fs_fsize); 115969800Stomsoft d+=sblock.fs_frag) { 116069800Stomsoft clrblock(&sblock, cg_blksfree(&acg), 116169800Stomsoft (d%sblock.fs_fpg)/sblock.fs_frag); 116269800Stomsoft acg.cg_cs.cs_nbfree--; 116369800Stomsoft sblock.fs_cstotal.cs_nbfree--; 116469800Stomsoft if(sblock.fs_contigsumsize > 0) { 116569800Stomsoft clrbit(cg_clustersfree(&acg), 116669800Stomsoft (d%sblock.fs_fpg)/sblock.fs_frag); 116769800Stomsoft } 116869800Stomsoft } 116969800Stomsoft 117069800Stomsoft /* 117169800Stomsoft * Allocate all fragments used by the cylinder summary in the 117269800Stomsoft * last block. 117369800Stomsoft */ 117469800Stomsoft if(d<sblock.fs_csaddr+(sblock.fs_cssize/sblock.fs_fsize)) { 117569800Stomsoft for(; d-sblock.fs_csaddr< 117669800Stomsoft sblock.fs_cssize/sblock.fs_fsize; 117769800Stomsoft d++) { 117869800Stomsoft clrbit(cg_blksfree(&acg), d%sblock.fs_fpg); 117969800Stomsoft acg.cg_cs.cs_nffree--; 118069800Stomsoft sblock.fs_cstotal.cs_nffree--; 118169800Stomsoft } 118269800Stomsoft acg.cg_cs.cs_nbfree--; 118369800Stomsoft acg.cg_cs.cs_nffree+=sblock.fs_frag; 118469800Stomsoft sblock.fs_cstotal.cs_nbfree--; 118569800Stomsoft sblock.fs_cstotal.cs_nffree+=sblock.fs_frag; 118669800Stomsoft if(sblock.fs_contigsumsize > 0) { 118769800Stomsoft clrbit(cg_clustersfree(&acg), 118869800Stomsoft (d%sblock.fs_fpg)/sblock.fs_frag); 118969800Stomsoft } 119069800Stomsoft 119169800Stomsoft frag_adjust(d%sblock.fs_fpg, +1); 119269800Stomsoft } 119369800Stomsoft /* 119469800Stomsoft * XXX Handle the cluster statistics here in the case this 119569800Stomsoft * cylinder group is now almost full, and the remaining 119669800Stomsoft * space is less then the maximum cluster size. This is 119769800Stomsoft * probably not needed, as you would hardly find a file 119869800Stomsoft * system which has only MAXCSBUFS+FS_MAXCONTIG of free 119969800Stomsoft * space right behind the cylinder group information in 120069800Stomsoft * any new cylinder group. 120169800Stomsoft */ 120269800Stomsoft 120369800Stomsoft /* 120469800Stomsoft * Update our statistics in the cylinder summary. 120569800Stomsoft */ 120669800Stomsoft *cs = acg.cg_cs; 120769800Stomsoft 120869800Stomsoft /* 120969800Stomsoft * Write the new cylinder group containing the cylinder summary 121069800Stomsoft * back to disk. 121169800Stomsoft */ 121277885Stomsoft wtfs(fsbtodb(&sblock, cgtod(&sblock, ncscg)), 121377885Stomsoft (size_t)sblock.fs_cgsize, (void *)&acg, fso, Nflag); 121469800Stomsoft DBG_PRINT0("nscg written\n"); 121569926Stomsoft DBG_DUMP_CG(&sblock, 121669926Stomsoft "new summary cg", 121769926Stomsoft &acg); 121869800Stomsoft 121969800Stomsoft DBG_LEAVE; 122069800Stomsoft return; 122169800Stomsoft } 122269800Stomsoft /* 122369800Stomsoft * We have got enough of space in the current cylinder group, so we 122469800Stomsoft * can relocate just a few blocks, and let the summary information 122569800Stomsoft * grow in place where it is right now. 122669800Stomsoft */ 122769800Stomsoft DBG_TRC; 122869800Stomsoft 122969800Stomsoft cbase = cgbase(&osblock, ocscg); /* old and new are equal */ 123069800Stomsoft dupper = sblock.fs_csaddr - cbase + 123169800Stomsoft howmany(sblock.fs_cssize, sblock.fs_fsize); 123269800Stomsoft odupper = osblock.fs_csaddr - cbase + 123369800Stomsoft howmany(osblock.fs_cssize, osblock.fs_fsize); 123469800Stomsoft 123569800Stomsoft sblock.fs_dsize -= dupper-odupper; 123669800Stomsoft 123769800Stomsoft /* 123869800Stomsoft * Allocate the space for the array of blocks to be relocated. 123969800Stomsoft */ 124069800Stomsoft bp=(struct gfs_bpp *)malloc(((dupper-odupper)/sblock.fs_frag+2)* 124169800Stomsoft sizeof(struct gfs_bpp)); 124269926Stomsoft if(bp == NULL) { 124369926Stomsoft errx(1, "malloc failed"); 124469926Stomsoft } 124577779Stomsoft memset((char *)bp, 0, ((dupper-odupper)/sblock.fs_frag+2)* 124677779Stomsoft sizeof(struct gfs_bpp)); 124769800Stomsoft 124869800Stomsoft /* 124969800Stomsoft * Lock all new frags needed for the cylinder group summary. This is 125069800Stomsoft * done per fragment in the first and last block of the new required 125169800Stomsoft * area, and per block for all other blocks. 125269800Stomsoft * 125369800Stomsoft * Handle the first new block here (but only if some fragments where 125469800Stomsoft * already used for the cylinder summary). 125569800Stomsoft */ 125669800Stomsoft ind=0; 125769800Stomsoft frag_adjust(odupper, -1); 125869800Stomsoft for(d=odupper; ((d<dupper)&&(d%sblock.fs_frag)); d++) { 125969926Stomsoft DBG_PRINT1("scg first frag check loop d=%d\n", 126069926Stomsoft d); 126169800Stomsoft if(isclr(cg_blksfree(&acg), d)) { 126269800Stomsoft if (!ind) { 126369800Stomsoft bp[ind].old=d/sblock.fs_frag; 126469800Stomsoft bp[ind].flags|=GFS_FL_FIRST; 126569800Stomsoft if(roundup(d, sblock.fs_frag) >= dupper) { 126669800Stomsoft bp[ind].flags|=GFS_FL_LAST; 126769800Stomsoft } 126869800Stomsoft ind++; 126969800Stomsoft } 127069800Stomsoft } else { 127169800Stomsoft clrbit(cg_blksfree(&acg), d); 127269800Stomsoft acg.cg_cs.cs_nffree--; 127369800Stomsoft sblock.fs_cstotal.cs_nffree--; 127469800Stomsoft } 127569800Stomsoft /* 127669800Stomsoft * No cluster handling is needed here, as there was at least 127769800Stomsoft * one fragment in use by the cylinder summary in the old 1278102231Strhodes * file system. 127969800Stomsoft * No block-free counter handling here as this block was not 128069800Stomsoft * a free block. 128169800Stomsoft */ 128269800Stomsoft } 128369800Stomsoft frag_adjust(odupper, 1); 128469800Stomsoft 128569800Stomsoft /* 128669800Stomsoft * Handle all needed complete blocks here. 128769800Stomsoft */ 128869800Stomsoft for(; d+sblock.fs_frag<=dupper; d+=sblock.fs_frag) { 128969926Stomsoft DBG_PRINT1("scg block check loop d=%d\n", 129069926Stomsoft d); 129169800Stomsoft if(!isblock(&sblock, cg_blksfree(&acg), d/sblock.fs_frag)) { 129269800Stomsoft for(f=d; f<d+sblock.fs_frag; f++) { 129369800Stomsoft if(isset(cg_blksfree(&aocg), f)) { 129469800Stomsoft acg.cg_cs.cs_nffree--; 129569800Stomsoft sblock.fs_cstotal.cs_nffree--; 129669800Stomsoft } 129769800Stomsoft } 129869800Stomsoft clrblock(&sblock, cg_blksfree(&acg), d/sblock.fs_frag); 129969800Stomsoft bp[ind].old=d/sblock.fs_frag; 130069800Stomsoft ind++; 130169800Stomsoft } else { 130269800Stomsoft clrblock(&sblock, cg_blksfree(&acg), d/sblock.fs_frag); 130369800Stomsoft acg.cg_cs.cs_nbfree--; 130469800Stomsoft sblock.fs_cstotal.cs_nbfree--; 130569800Stomsoft if(sblock.fs_contigsumsize > 0) { 130669800Stomsoft clrbit(cg_clustersfree(&acg), d/sblock.fs_frag); 130769800Stomsoft for(lcs=0, l=(d/sblock.fs_frag)+1; 130869800Stomsoft lcs<sblock.fs_contigsumsize; 130969800Stomsoft l++, lcs++ ) { 131069800Stomsoft if(isclr(cg_clustersfree(&acg),l)){ 131169800Stomsoft break; 131269800Stomsoft } 131369800Stomsoft } 131469800Stomsoft if(lcs < sblock.fs_contigsumsize) { 131569800Stomsoft cg_clustersum(&acg)[lcs+1]--; 131669800Stomsoft if(lcs) { 131769800Stomsoft cg_clustersum(&acg)[lcs]++; 131869800Stomsoft } 131969800Stomsoft } 132069800Stomsoft } 132169800Stomsoft } 132269800Stomsoft /* 132369800Stomsoft * No fragment counter handling is needed here, as this finally 132469800Stomsoft * doesn't change after the relocation. 132569800Stomsoft */ 132669800Stomsoft } 132769800Stomsoft 132869800Stomsoft /* 132969800Stomsoft * Handle all fragments needed in the last new affected block. 133069800Stomsoft */ 133169800Stomsoft if(d<dupper) { 133269800Stomsoft frag_adjust(dupper-1, -1); 133369800Stomsoft 133469800Stomsoft if(isblock(&sblock, cg_blksfree(&acg), d/sblock.fs_frag)) { 133569800Stomsoft acg.cg_cs.cs_nbfree--; 133669800Stomsoft sblock.fs_cstotal.cs_nbfree--; 133769800Stomsoft acg.cg_cs.cs_nffree+=sblock.fs_frag; 133869800Stomsoft sblock.fs_cstotal.cs_nffree+=sblock.fs_frag; 133969800Stomsoft if(sblock.fs_contigsumsize > 0) { 134069800Stomsoft clrbit(cg_clustersfree(&acg), d/sblock.fs_frag); 134169800Stomsoft for(lcs=0, l=(d/sblock.fs_frag)+1; 134269800Stomsoft lcs<sblock.fs_contigsumsize; 134369800Stomsoft l++, lcs++ ) { 134469800Stomsoft if(isclr(cg_clustersfree(&acg),l)){ 134569800Stomsoft break; 134669800Stomsoft } 134769800Stomsoft } 134869800Stomsoft if(lcs < sblock.fs_contigsumsize) { 134969800Stomsoft cg_clustersum(&acg)[lcs+1]--; 135069800Stomsoft if(lcs) { 135169800Stomsoft cg_clustersum(&acg)[lcs]++; 135269800Stomsoft } 135369800Stomsoft } 135469800Stomsoft } 135569800Stomsoft } 135669800Stomsoft 135769800Stomsoft for(; d<dupper; d++) { 135869926Stomsoft DBG_PRINT1("scg second frag check loop d=%d\n", 135969926Stomsoft d); 136069800Stomsoft if(isclr(cg_blksfree(&acg), d)) { 136169800Stomsoft bp[ind].old=d/sblock.fs_frag; 136269800Stomsoft bp[ind].flags|=GFS_FL_LAST; 136369800Stomsoft } else { 136469800Stomsoft clrbit(cg_blksfree(&acg), d); 136569800Stomsoft acg.cg_cs.cs_nffree--; 136669800Stomsoft sblock.fs_cstotal.cs_nffree--; 136769800Stomsoft } 136869800Stomsoft } 136969800Stomsoft if(bp[ind].flags & GFS_FL_LAST) { /* we have to advance here */ 137069800Stomsoft ind++; 137169800Stomsoft } 137269800Stomsoft frag_adjust(dupper-1, 1); 137369800Stomsoft } 137469800Stomsoft 137569800Stomsoft /* 137669800Stomsoft * If we found a block to relocate just do so. 137769800Stomsoft */ 137869800Stomsoft if(ind) { 137969800Stomsoft for(i=0; i<ind; i++) { 138069800Stomsoft if(!bp[i].old) { /* no more blocks listed */ 138169800Stomsoft /* 138269800Stomsoft * XXX A relative blocknumber should not be 138369800Stomsoft * zero, which is not explicitly 138469800Stomsoft * guaranteed by our code. 138569800Stomsoft */ 138669800Stomsoft break; 138769800Stomsoft } 138869800Stomsoft /* 138969800Stomsoft * Allocate a complete block in the same (current) 139069800Stomsoft * cylinder group. 139169800Stomsoft */ 139269800Stomsoft bp[i].new=alloc()/sblock.fs_frag; 139369800Stomsoft 139469800Stomsoft /* 139569800Stomsoft * There is no frag_adjust() needed for the new block 139669800Stomsoft * as it will have no fragments yet :-). 139769800Stomsoft */ 139869800Stomsoft for(f=bp[i].old*sblock.fs_frag, 139969800Stomsoft g=bp[i].new*sblock.fs_frag; 140069800Stomsoft f<(bp[i].old+1)*sblock.fs_frag; 140169800Stomsoft f++, g++) { 140269800Stomsoft if(isset(cg_blksfree(&aocg), f)) { 140369800Stomsoft setbit(cg_blksfree(&acg), g); 140469800Stomsoft acg.cg_cs.cs_nffree++; 140569800Stomsoft sblock.fs_cstotal.cs_nffree++; 140669800Stomsoft } 140769800Stomsoft } 140869800Stomsoft 140969800Stomsoft /* 141069800Stomsoft * Special handling is required if this was the first 141169800Stomsoft * block. We have to consider the fragments which were 141269800Stomsoft * used by the cylinder summary in the original block 141369800Stomsoft * which re to be free in the copy of our block. We 141469800Stomsoft * have to be careful if this first block happens to 141569800Stomsoft * be also the last block to be relocated. 141669800Stomsoft */ 141769800Stomsoft if(bp[i].flags & GFS_FL_FIRST) { 141869800Stomsoft for(f=bp[i].old*sblock.fs_frag, 141969800Stomsoft g=bp[i].new*sblock.fs_frag; 142069800Stomsoft f<odupper; 142169800Stomsoft f++, g++) { 142269800Stomsoft setbit(cg_blksfree(&acg), g); 142369800Stomsoft acg.cg_cs.cs_nffree++; 142469800Stomsoft sblock.fs_cstotal.cs_nffree++; 142569800Stomsoft } 142669800Stomsoft if(!(bp[i].flags & GFS_FL_LAST)) { 142769800Stomsoft frag_adjust(bp[i].new*sblock.fs_frag,1); 142869800Stomsoft } 142969800Stomsoft 143069800Stomsoft } 143169800Stomsoft 143269800Stomsoft /* 143369800Stomsoft * Special handling is required if this is the last 143469800Stomsoft * block to be relocated. 143569800Stomsoft */ 143669800Stomsoft if(bp[i].flags & GFS_FL_LAST) { 143769800Stomsoft frag_adjust(bp[i].new*sblock.fs_frag, 1); 143869800Stomsoft frag_adjust(bp[i].old*sblock.fs_frag, -1); 143969800Stomsoft for(f=dupper; 144069800Stomsoft f<roundup(dupper, sblock.fs_frag); 144169800Stomsoft f++) { 144269800Stomsoft if(isclr(cg_blksfree(&acg), f)) { 144369800Stomsoft setbit(cg_blksfree(&acg), f); 144469800Stomsoft acg.cg_cs.cs_nffree++; 144569800Stomsoft sblock.fs_cstotal.cs_nffree++; 144669800Stomsoft } 144769800Stomsoft } 144869800Stomsoft frag_adjust(bp[i].old*sblock.fs_frag, 1); 144969800Stomsoft } 145069800Stomsoft 145169800Stomsoft /* 145269800Stomsoft * !!! Attach the cylindergroup offset here. 145369800Stomsoft */ 145469800Stomsoft bp[i].old+=cbase/sblock.fs_frag; 145569800Stomsoft bp[i].new+=cbase/sblock.fs_frag; 145669800Stomsoft 145769800Stomsoft /* 145869800Stomsoft * Copy the content of the block. 145969800Stomsoft */ 146069800Stomsoft /* 146169800Stomsoft * XXX Here we will have to implement a copy on write 146269800Stomsoft * in the case we have any active snapshots. 146369800Stomsoft */ 146469800Stomsoft rdfs(fsbtodb(&sblock, bp[i].old*sblock.fs_frag), 146577885Stomsoft (size_t)sblock.fs_bsize, (void *)&ablk, fsi); 146669800Stomsoft wtfs(fsbtodb(&sblock, bp[i].new*sblock.fs_frag), 146777885Stomsoft (size_t)sblock.fs_bsize, (void *)&ablk, fso, Nflag); 146869926Stomsoft DBG_DUMP_HEX(&sblock, 146969926Stomsoft "copied full block", 147069926Stomsoft (unsigned char *)&ablk); 147169800Stomsoft 147269926Stomsoft DBG_PRINT2("scg (%d->%d) block relocated\n", 147369926Stomsoft bp[i].old, 147469926Stomsoft bp[i].new); 147569800Stomsoft } 147669800Stomsoft 147769800Stomsoft /* 147869800Stomsoft * Now we have to update all references to any fragment which 147969800Stomsoft * belongs to any block relocated. We iterate now over all 148069800Stomsoft * cylinder groups, within those over all non zero length 148169800Stomsoft * inodes. 148269800Stomsoft */ 148369800Stomsoft for(cylno=0; cylno<osblock.fs_ncg; cylno++) { 148469926Stomsoft DBG_PRINT1("scg doing cg (%d)\n", 148569926Stomsoft cylno); 148669800Stomsoft for(inc=osblock.fs_ipg-1 ; inc>=0 ; inc--) { 148769800Stomsoft updrefs(cylno, (ino_t)inc, bp, fsi, fso, Nflag); 148869800Stomsoft } 148969800Stomsoft } 149069800Stomsoft 149169800Stomsoft /* 149269800Stomsoft * All inodes are checked, now make sure the number of 149369800Stomsoft * references found make sense. 149469800Stomsoft */ 149569800Stomsoft for(i=0; i<ind; i++) { 149669800Stomsoft if(!bp[i].found || (bp[i].found>sblock.fs_frag)) { 149769926Stomsoft warnx("error: %d refs found for block %d.", 149869800Stomsoft bp[i].found, bp[i].old); 149969800Stomsoft } 150069800Stomsoft 150169800Stomsoft } 150269800Stomsoft } 150369800Stomsoft /* 150469800Stomsoft * The following statistics are not changed here: 150569800Stomsoft * sblock.fs_cstotal.cs_ndir 150669800Stomsoft * sblock.fs_cstotal.cs_nifree 150769800Stomsoft * The following statistics were already updated on the fly: 150869800Stomsoft * sblock.fs_cstotal.cs_nffree 150969800Stomsoft * sblock.fs_cstotal.cs_nbfree 151069800Stomsoft * As the statistics for this cylinder group are ready, copy it to 151169800Stomsoft * the summary information array. 151269800Stomsoft */ 151369800Stomsoft 151469800Stomsoft *cs = acg.cg_cs; 151569800Stomsoft 151669800Stomsoft /* 151769800Stomsoft * Write summary cylinder group back to disk. 151869800Stomsoft */ 151977885Stomsoft wtfs(fsbtodb(&sblock, cgtod(&sblock, ocscg)), (size_t)sblock.fs_cgsize, 152077885Stomsoft (void *)&acg, fso, Nflag); 152169800Stomsoft DBG_PRINT0("scg written\n"); 152269926Stomsoft DBG_DUMP_CG(&sblock, 152369926Stomsoft "new summary cg", 152469926Stomsoft &acg); 152569800Stomsoft 152669800Stomsoft DBG_LEAVE; 152769800Stomsoft return; 152869800Stomsoft} 152969800Stomsoft 153069800Stomsoft/* ************************************************************** rdfs ***** */ 153169800Stomsoft/* 153269800Stomsoft * Here we read some block(s) from disk. 153369800Stomsoft */ 153469800Stomsoftstatic void 153598542Smckusickrdfs(ufs2_daddr_t bno, size_t size, void *bf, int fsi) 153669800Stomsoft{ 153769800Stomsoft DBG_FUNC("rdfs") 153877885Stomsoft ssize_t n; 153969800Stomsoft 154069800Stomsoft DBG_ENTER; 154169800Stomsoft 154269800Stomsoft if (lseek(fsi, (off_t)bno * DEV_BSIZE, 0) < 0) { 154369926Stomsoft err(33, "rdfs: seek error: %ld", (long)bno); 154469800Stomsoft } 154577885Stomsoft n = read(fsi, bf, size); 154677885Stomsoft if (n != (ssize_t)size) { 154769926Stomsoft err(34, "rdfs: read error: %ld", (long)bno); 154869800Stomsoft } 154969800Stomsoft 155069800Stomsoft DBG_LEAVE; 155169800Stomsoft return; 155269800Stomsoft} 155369800Stomsoft 155469800Stomsoft/* ************************************************************** wtfs ***** */ 155569800Stomsoft/* 155669800Stomsoft * Here we write some block(s) to disk. 155769800Stomsoft */ 155869800Stomsoftstatic void 155998542Smckusickwtfs(ufs2_daddr_t bno, size_t size, void *bf, int fso, unsigned int Nflag) 156069800Stomsoft{ 156169800Stomsoft DBG_FUNC("wtfs") 156277885Stomsoft ssize_t n; 156369800Stomsoft 156469800Stomsoft DBG_ENTER; 156569800Stomsoft 156669800Stomsoft if (Nflag) { 156769800Stomsoft DBG_LEAVE; 156869800Stomsoft return; 156969800Stomsoft } 157069800Stomsoft if (lseek(fso, (off_t)bno * DEV_BSIZE, SEEK_SET) < 0) { 157169926Stomsoft err(35, "wtfs: seek error: %ld", (long)bno); 157269800Stomsoft } 157377885Stomsoft n = write(fso, bf, size); 157477885Stomsoft if (n != (ssize_t)size) { 157569926Stomsoft err(36, "wtfs: write error: %ld", (long)bno); 157669800Stomsoft } 157769800Stomsoft 157869800Stomsoft DBG_LEAVE; 157969800Stomsoft return; 158069800Stomsoft} 158169800Stomsoft 158269800Stomsoft/* ************************************************************* alloc ***** */ 158369800Stomsoft/* 158469800Stomsoft * Here we allocate a free block in the current cylinder group. It is assumed, 158569800Stomsoft * that acg contains the current cylinder group. As we may take a block from 1586102231Strhodes * somewhere in the file system we have to handle cluster summary here. 158769800Stomsoft */ 158898542Smckusickstatic ufs2_daddr_t 158969800Stomsoftalloc(void) 159069800Stomsoft{ 159169800Stomsoft DBG_FUNC("alloc") 159298542Smckusick ufs2_daddr_t d, blkno; 159369800Stomsoft int lcs1, lcs2; 159469800Stomsoft int l; 159569800Stomsoft int csmin, csmax; 159669800Stomsoft int dlower, dupper, dmax; 159769800Stomsoft 159869800Stomsoft DBG_ENTER; 159969800Stomsoft 160069800Stomsoft if (acg.cg_magic != CG_MAGIC) { 160169926Stomsoft warnx("acg: bad magic number"); 160269800Stomsoft DBG_LEAVE; 160369800Stomsoft return (0); 160469800Stomsoft } 160569800Stomsoft if (acg.cg_cs.cs_nbfree == 0) { 160669926Stomsoft warnx("error: cylinder group ran out of space"); 160769800Stomsoft DBG_LEAVE; 160869800Stomsoft return (0); 160969800Stomsoft } 161069800Stomsoft /* 161169800Stomsoft * We start seeking for free blocks only from the space available after 161269800Stomsoft * the end of the new grown cylinder summary. Otherwise we allocate a 161369800Stomsoft * block here which we have to relocate a couple of seconds later again 161469800Stomsoft * again, and we are not prepared to to this anyway. 161569800Stomsoft */ 161669800Stomsoft blkno=-1; 161769800Stomsoft dlower=cgsblock(&sblock, acg.cg_cgx)-cgbase(&sblock, acg.cg_cgx); 161869800Stomsoft dupper=cgdmin(&sblock, acg.cg_cgx)-cgbase(&sblock, acg.cg_cgx); 161969800Stomsoft dmax=cgbase(&sblock, acg.cg_cgx)+sblock.fs_fpg; 162069800Stomsoft if (dmax > sblock.fs_size) { 162169800Stomsoft dmax = sblock.fs_size; 162269800Stomsoft } 162369800Stomsoft dmax-=cgbase(&sblock, acg.cg_cgx); /* retransform into cg */ 162469800Stomsoft csmin=sblock.fs_csaddr-cgbase(&sblock, acg.cg_cgx); 162569800Stomsoft csmax=csmin+howmany(sblock.fs_cssize, sblock.fs_fsize); 162669926Stomsoft DBG_PRINT3("seek range: dl=%d, du=%d, dm=%d\n", 162769926Stomsoft dlower, 162869926Stomsoft dupper, 162969926Stomsoft dmax); 163069926Stomsoft DBG_PRINT2("range cont: csmin=%d, csmax=%d\n", 163169926Stomsoft csmin, 163269926Stomsoft csmax); 163369800Stomsoft 163469800Stomsoft for(d=0; (d<dlower && blkno==-1); d+=sblock.fs_frag) { 163569800Stomsoft if(d>=csmin && d<=csmax) { 163669800Stomsoft continue; 163769800Stomsoft } 163869800Stomsoft if(isblock(&sblock, cg_blksfree(&acg), fragstoblks(&sblock, 163969800Stomsoft d))) { 164069800Stomsoft blkno = fragstoblks(&sblock, d);/* Yeah found a block */ 164169800Stomsoft break; 164269800Stomsoft } 164369800Stomsoft } 164469800Stomsoft for(d=dupper; (d<dmax && blkno==-1); d+=sblock.fs_frag) { 164569800Stomsoft if(d>=csmin && d<=csmax) { 164669800Stomsoft continue; 164769800Stomsoft } 164869800Stomsoft if(isblock(&sblock, cg_blksfree(&acg), fragstoblks(&sblock, 164969800Stomsoft d))) { 165069800Stomsoft blkno = fragstoblks(&sblock, d);/* Yeah found a block */ 165169800Stomsoft break; 165269800Stomsoft } 165369800Stomsoft } 165469800Stomsoft if(blkno==-1) { 165569926Stomsoft warnx("internal error: couldn't find promised block in cg"); 165669800Stomsoft DBG_LEAVE; 165769800Stomsoft return (0); 165869800Stomsoft } 165969800Stomsoft 166069800Stomsoft /* 166169800Stomsoft * This is needed if the block was found already in the first loop. 166269800Stomsoft */ 166369800Stomsoft d=blkstofrags(&sblock, blkno); 166469800Stomsoft 166569800Stomsoft clrblock(&sblock, cg_blksfree(&acg), blkno); 166669800Stomsoft if (sblock.fs_contigsumsize > 0) { 166769800Stomsoft /* 166869800Stomsoft * Handle the cluster allocation bitmap. 166969800Stomsoft */ 167069800Stomsoft clrbit(cg_clustersfree(&acg), blkno); 167169800Stomsoft /* 167269800Stomsoft * We possibly have split a cluster here, so we have to do 167369926Stomsoft * recalculate the sizes of the remaining cluster halves now, 167469800Stomsoft * and use them for updating the cluster summary information. 167569800Stomsoft * 167669800Stomsoft * Lets start with the blocks before our allocated block ... 167769800Stomsoft */ 167869800Stomsoft for(lcs1=0, l=blkno-1; lcs1<sblock.fs_contigsumsize; 167969800Stomsoft l--, lcs1++ ) { 168069800Stomsoft if(isclr(cg_clustersfree(&acg),l)){ 168169800Stomsoft break; 168269800Stomsoft } 168369800Stomsoft } 168469800Stomsoft /* 168569800Stomsoft * ... and continue with the blocks right after our allocated 168669800Stomsoft * block. 168769800Stomsoft */ 168869800Stomsoft for(lcs2=0, l=blkno+1; lcs2<sblock.fs_contigsumsize; 168969800Stomsoft l++, lcs2++ ) { 169069800Stomsoft if(isclr(cg_clustersfree(&acg),l)){ 169169800Stomsoft break; 169269800Stomsoft } 169369800Stomsoft } 169469800Stomsoft 169569800Stomsoft /* 169669800Stomsoft * Now update all counters. 169769800Stomsoft */ 169869800Stomsoft cg_clustersum(&acg)[MIN(lcs1+lcs2+1,sblock.fs_contigsumsize)]--; 169969800Stomsoft if(lcs1) { 170069800Stomsoft cg_clustersum(&acg)[lcs1]++; 170169800Stomsoft } 170269800Stomsoft if(lcs2) { 170369800Stomsoft cg_clustersum(&acg)[lcs2]++; 170469800Stomsoft } 170569800Stomsoft } 170669800Stomsoft /* 170769800Stomsoft * Update all statistics based on blocks. 170869800Stomsoft */ 170969800Stomsoft acg.cg_cs.cs_nbfree--; 171069800Stomsoft sblock.fs_cstotal.cs_nbfree--; 171169800Stomsoft 171269800Stomsoft DBG_LEAVE; 171369800Stomsoft return (d); 171469800Stomsoft} 171569800Stomsoft 171669800Stomsoft/* *********************************************************** isblock ***** */ 171769800Stomsoft/* 171869800Stomsoft * Here we check if all frags of a block are free. For more details again 171969800Stomsoft * please see the source of newfs(8), as this function is taken over almost 172069800Stomsoft * unchanged. 172169800Stomsoft */ 172269800Stomsoftstatic int 172369800Stomsoftisblock(struct fs *fs, unsigned char *cp, int h) 172469800Stomsoft{ 172569800Stomsoft DBG_FUNC("isblock") 172669800Stomsoft unsigned char mask; 172769800Stomsoft 172869800Stomsoft DBG_ENTER; 172969800Stomsoft 173069800Stomsoft switch (fs->fs_frag) { 173169800Stomsoft case 8: 173269800Stomsoft DBG_LEAVE; 173369800Stomsoft return (cp[h] == 0xff); 173469800Stomsoft case 4: 173569800Stomsoft mask = 0x0f << ((h & 0x1) << 2); 173669800Stomsoft DBG_LEAVE; 173769800Stomsoft return ((cp[h >> 1] & mask) == mask); 173869800Stomsoft case 2: 173969800Stomsoft mask = 0x03 << ((h & 0x3) << 1); 174069800Stomsoft DBG_LEAVE; 174169800Stomsoft return ((cp[h >> 2] & mask) == mask); 174269800Stomsoft case 1: 174369800Stomsoft mask = 0x01 << (h & 0x7); 174469800Stomsoft DBG_LEAVE; 174569800Stomsoft return ((cp[h >> 3] & mask) == mask); 174669800Stomsoft default: 174769800Stomsoft fprintf(stderr, "isblock bad fs_frag %d\n", fs->fs_frag); 174869800Stomsoft DBG_LEAVE; 174969800Stomsoft return (0); 175069800Stomsoft } 175169800Stomsoft} 175269800Stomsoft 175369800Stomsoft/* ********************************************************** clrblock ***** */ 175469800Stomsoft/* 175569800Stomsoft * Here we allocate a complete block in the block map. For more details again 175669800Stomsoft * please see the source of newfs(8), as this function is taken over almost 175769800Stomsoft * unchanged. 175869800Stomsoft */ 175969800Stomsoftstatic void 176069800Stomsoftclrblock(struct fs *fs, unsigned char *cp, int h) 176169800Stomsoft{ 176269800Stomsoft DBG_FUNC("clrblock") 176369800Stomsoft 176469800Stomsoft DBG_ENTER; 176569800Stomsoft 176669800Stomsoft switch ((fs)->fs_frag) { 176769800Stomsoft case 8: 176869800Stomsoft cp[h] = 0; 176969800Stomsoft break; 177069800Stomsoft case 4: 177169800Stomsoft cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); 177269800Stomsoft break; 177369800Stomsoft case 2: 177469800Stomsoft cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); 177569800Stomsoft break; 177669800Stomsoft case 1: 177769800Stomsoft cp[h >> 3] &= ~(0x01 << (h & 0x7)); 177869800Stomsoft break; 177969800Stomsoft default: 178069926Stomsoft warnx("clrblock bad fs_frag %d", fs->fs_frag); 178169800Stomsoft break; 178269800Stomsoft } 178369800Stomsoft 178469800Stomsoft DBG_LEAVE; 178569800Stomsoft return; 178669800Stomsoft} 178769800Stomsoft 178869800Stomsoft/* ********************************************************** setblock ***** */ 178969800Stomsoft/* 179069800Stomsoft * Here we free a complete block in the free block map. For more details again 179169800Stomsoft * please see the source of newfs(8), as this function is taken over almost 179269800Stomsoft * unchanged. 179369800Stomsoft */ 179469800Stomsoftstatic void 179569800Stomsoftsetblock(struct fs *fs, unsigned char *cp, int h) 179669800Stomsoft{ 179769800Stomsoft DBG_FUNC("setblock") 179869800Stomsoft 179969800Stomsoft DBG_ENTER; 180069800Stomsoft 180169800Stomsoft switch (fs->fs_frag) { 180269800Stomsoft case 8: 180369800Stomsoft cp[h] = 0xff; 180469800Stomsoft break; 180569800Stomsoft case 4: 180669800Stomsoft cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); 180769800Stomsoft break; 180869800Stomsoft case 2: 180969800Stomsoft cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); 181069800Stomsoft break; 181169800Stomsoft case 1: 181269800Stomsoft cp[h >> 3] |= (0x01 << (h & 0x7)); 181369800Stomsoft break; 181469800Stomsoft default: 181569926Stomsoft warnx("setblock bad fs_frag %d", fs->fs_frag); 181669800Stomsoft break; 181769800Stomsoft } 181869800Stomsoft 181969800Stomsoft DBG_LEAVE; 182069800Stomsoft return; 182169800Stomsoft} 182269800Stomsoft 182369800Stomsoft/* ************************************************************ ginode ***** */ 182469800Stomsoft/* 182569800Stomsoft * This function provides access to an individual inode. We find out in which 182669800Stomsoft * block the requested inode is located, read it from disk if needed, and 182769800Stomsoft * return the pointer into that block. We maintain a cache of one block to 182869926Stomsoft * not read the same block again and again if we iterate linearly over all 182969800Stomsoft * inodes. 183069800Stomsoft */ 183198542Smckusickstatic union dinode * 183269800Stomsoftginode(ino_t inumber, int fsi, int cg) 183369800Stomsoft{ 183469800Stomsoft DBG_FUNC("ginode") 183598542Smckusick static ino_t startinum = 0; /* first inode in cached block */ 183669800Stomsoft 183769800Stomsoft DBG_ENTER; 183869800Stomsoft 183998542Smckusick inumber += (cg * sblock.fs_ipg); 184098542Smckusick if (inumber < ROOTINO || inumber > maxino) 184198542Smckusick errx(8, "bad inode number %d to ginode", inumber); 184298542Smckusick if (startinum == 0 || 184398542Smckusick inumber < startinum || inumber >= startinum + INOPB(&sblock)) { 184498542Smckusick inoblk = fsbtodb(&sblock, ino_to_fsba(&sblock, inumber)); 184598542Smckusick rdfs(inoblk, (size_t)sblock.fs_bsize, inobuf, fsi); 184669800Stomsoft startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); 184769800Stomsoft } 184869800Stomsoft DBG_LEAVE; 184998542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 185098542Smckusick return ((union dinode *) 185198542Smckusick &((struct ufs1_dinode *)inobuf)[inumber % INOPB(&sblock)]); 185298542Smckusick return ((union dinode *) 185398542Smckusick &((struct ufs2_dinode *)inobuf)[inumber % INOPB(&sblock)]); 185469800Stomsoft} 185569800Stomsoft 185669800Stomsoft/* ****************************************************** charsperline ***** */ 185769800Stomsoft/* 185869800Stomsoft * Figure out how many lines our current terminal has. For more details again 185969800Stomsoft * please see the source of newfs(8), as this function is taken over almost 186069800Stomsoft * unchanged. 186169800Stomsoft */ 186269800Stomsoftstatic int 186369800Stomsoftcharsperline(void) 186469800Stomsoft{ 186569800Stomsoft DBG_FUNC("charsperline") 186669800Stomsoft int columns; 186769800Stomsoft char *cp; 186869800Stomsoft struct winsize ws; 186969800Stomsoft 187069800Stomsoft DBG_ENTER; 187169800Stomsoft 187269800Stomsoft columns = 0; 187369800Stomsoft if (ioctl(0, TIOCGWINSZ, &ws) != -1) { 187469800Stomsoft columns = ws.ws_col; 187569800Stomsoft } 187669800Stomsoft if (columns == 0 && (cp = getenv("COLUMNS"))) { 187769800Stomsoft columns = atoi(cp); 187869800Stomsoft } 187969800Stomsoft if (columns == 0) { 188069800Stomsoft columns = 80; /* last resort */ 188169800Stomsoft } 188269800Stomsoft 188369800Stomsoft DBG_LEAVE; 188469800Stomsoft return columns; 188569800Stomsoft} 188669800Stomsoft 188769800Stomsoft/* ************************************************************** main ***** */ 188869800Stomsoft/* 188969800Stomsoft * growfs(8) is a utility which allows to increase the size of an existing 1890102231Strhodes * ufs file system. Currently this can only be done on unmounted file system. 189169800Stomsoft * It recognizes some command line options to specify the new desired size, 1892102231Strhodes * and it does some basic checkings. The old file system size is determined 189369800Stomsoft * and after some more checks like we can really access the new last block 189469800Stomsoft * on the disk etc. we calculate the new parameters for the superblock. After 189569800Stomsoft * having done this we just call growfs() which will do the work. Before 189669800Stomsoft * we finish the only thing left is to update the disklabel. 189769800Stomsoft * We still have to provide support for snapshots. Therefore we first have to 189869800Stomsoft * understand what data structures are always replicated in the snapshot on 189969800Stomsoft * creation, for all other blocks we touch during our procedure, we have to 190069926Stomsoft * keep the old blocks unchanged somewhere available for the snapshots. If we 190169800Stomsoft * are lucky, then we only have to handle our blocks to be relocated in that 190269800Stomsoft * way. 190369800Stomsoft * Also we have to consider in what order we actually update the critical 1904102231Strhodes * data structures of the file system to make sure, that in case of a disaster 190569800Stomsoft * fsck(8) is still able to restore any lost data. 190669926Stomsoft * The foreseen last step then will be to provide for growing even mounted 190769926Stomsoft * file systems. There we have to extend the mount() system call to provide 1908102231Strhodes * userland access to the file system locking facility. 190969800Stomsoft */ 191069800Stomsoftint 191169800Stomsoftmain(int argc, char **argv) 191269800Stomsoft{ 191369800Stomsoft DBG_FUNC("main") 191469926Stomsoft char *device, *special, *cp; 191569800Stomsoft char ch; 191677885Stomsoft unsigned int size=0; 191769800Stomsoft size_t len; 191877885Stomsoft unsigned int Nflag=0; 191969800Stomsoft int ExpertFlag=0; 192069800Stomsoft struct stat st; 192169800Stomsoft struct disklabel *lp; 192269800Stomsoft struct partition *pp; 192398542Smckusick int i,fsi,fso; 192469800Stomsoft char reply[5]; 192569800Stomsoft#ifdef FSMAXSNAP 192669800Stomsoft int j; 192769800Stomsoft#endif /* FSMAXSNAP */ 192869800Stomsoft 192969800Stomsoft DBG_ENTER; 193069800Stomsoft 193169800Stomsoft while((ch=getopt(argc, argv, "Ns:vy")) != -1) { 193269800Stomsoft switch(ch) { 193369800Stomsoft case 'N': 193469800Stomsoft Nflag=1; 193569800Stomsoft break; 193669800Stomsoft case 's': 193769800Stomsoft size=(size_t)atol(optarg); 193869800Stomsoft if(size<1) { 193969926Stomsoft usage(); 194069800Stomsoft } 194169800Stomsoft break; 194269800Stomsoft case 'v': /* for compatibility to newfs */ 194369800Stomsoft break; 194469800Stomsoft case 'y': 194569800Stomsoft ExpertFlag=1; 194669800Stomsoft break; 194769800Stomsoft case '?': 194869800Stomsoft /* FALLTHROUGH */ 194969800Stomsoft default: 195069926Stomsoft usage(); 195169800Stomsoft } 195269800Stomsoft } 195369800Stomsoft argc -= optind; 195469800Stomsoft argv += optind; 195569800Stomsoft 195669800Stomsoft if(argc != 1) { 195769926Stomsoft usage(); 195869800Stomsoft } 195969800Stomsoft device=*argv; 196069800Stomsoft 196169800Stomsoft /* 196269800Stomsoft * Now try to guess the (raw)device name. 196369800Stomsoft */ 196469800Stomsoft if (0 == strrchr(device, '/')) { 196569800Stomsoft /* 196669800Stomsoft * No path prefix was given, so try in that order: 196769800Stomsoft * /dev/r%s 196869800Stomsoft * /dev/%s 196969800Stomsoft * /dev/vinum/r%s 197069800Stomsoft * /dev/vinum/%s. 197169800Stomsoft * 197269800Stomsoft * FreeBSD now doesn't distinguish between raw and block 197369800Stomsoft * devices any longer, but it should still work this way. 197469800Stomsoft */ 197569800Stomsoft len=strlen(device)+strlen(_PATH_DEV)+2+strlen("vinum/"); 197669800Stomsoft special=(char *)malloc(len); 197769926Stomsoft if(special == NULL) { 197869926Stomsoft errx(1, "malloc failed"); 197969926Stomsoft } 198069800Stomsoft snprintf(special, len, "%sr%s", _PATH_DEV, device); 198169800Stomsoft if (stat(special, &st) == -1) { 198269800Stomsoft snprintf(special, len, "%s%s", _PATH_DEV, device); 198369800Stomsoft if (stat(special, &st) == -1) { 198469800Stomsoft snprintf(special, len, "%svinum/r%s", 198569800Stomsoft _PATH_DEV, device); 198669800Stomsoft if (stat(special, &st) == -1) { 198769800Stomsoft /* For now this is the 'last resort' */ 198869800Stomsoft snprintf(special, len, "%svinum/%s", 198969800Stomsoft _PATH_DEV, device); 199069800Stomsoft } 199169800Stomsoft } 199269800Stomsoft } 199369800Stomsoft device = special; 199469800Stomsoft } 199569800Stomsoft 199669800Stomsoft /* 199769800Stomsoft * Try to access our devices for writing ... 199869800Stomsoft */ 199969800Stomsoft if (Nflag) { 200069800Stomsoft fso = -1; 200169800Stomsoft } else { 200269800Stomsoft fso = open(device, O_WRONLY); 200369800Stomsoft if (fso < 0) { 200469926Stomsoft err(1, "%s", device); 200569800Stomsoft } 200669800Stomsoft } 200769800Stomsoft 200869800Stomsoft /* 200969800Stomsoft * ... and reading. 201069800Stomsoft */ 201169800Stomsoft fsi = open(device, O_RDONLY); 201269800Stomsoft if (fsi < 0) { 201369926Stomsoft err(1, "%s", device); 201469800Stomsoft } 201569800Stomsoft 201669800Stomsoft /* 201769800Stomsoft * Try to read a label and gess the slice if not specified. This 201869800Stomsoft * code should guess the right thing and avaid to bother the user 201969800Stomsoft * user with the task of specifying the option -v on vinum volumes. 202069800Stomsoft */ 202169800Stomsoft cp=device+strlen(device)-1; 202269800Stomsoft lp = get_disklabel(fsi); 202369800Stomsoft if(lp->d_type == DTYPE_VINUM) { 202469800Stomsoft pp = &lp->d_partitions[0]; 202569800Stomsoft } else if (isdigit(*cp)) { 202669800Stomsoft pp = &lp->d_partitions[2]; 202769800Stomsoft } else if (*cp>='a' && *cp<='h') { 202869800Stomsoft pp = &lp->d_partitions[*cp - 'a']; 202969800Stomsoft } else { 203069926Stomsoft errx(1, "unknown device"); 203169800Stomsoft } 203269800Stomsoft 203369800Stomsoft /* 2034102231Strhodes * Check if that partition looks suited for growing a file system. 203569800Stomsoft */ 203669800Stomsoft if (pp->p_size < 1) { 203769926Stomsoft errx(1, "partition is unavailable"); 203869800Stomsoft } 203969800Stomsoft if (pp->p_fstype != FS_BSDFFS) { 204069926Stomsoft errx(1, "partition not 4.2BSD"); 204169800Stomsoft } 204269800Stomsoft 204369800Stomsoft /* 204469800Stomsoft * Read the current superblock, and take a backup. 204569800Stomsoft */ 204698542Smckusick for (i = 0; sblock_try[i] != -1; i++) { 204798542Smckusick sblockloc = sblock_try[i] / DEV_BSIZE; 204898542Smckusick rdfs(sblockloc, (size_t)SBLOCKSIZE, (void *)&(osblock), fsi); 204998542Smckusick if ((osblock.fs_magic == FS_UFS1_MAGIC || 205098542Smckusick (osblock.fs_magic == FS_UFS2_MAGIC && 205198542Smckusick osblock.fs_sblockloc == 205298542Smckusick numfrags(&osblock, sblock_try[i]))) && 205398542Smckusick osblock.fs_bsize <= MAXBSIZE && 205498542Smckusick osblock.fs_bsize >= sizeof(struct fs)) 205598542Smckusick break; 205698542Smckusick } 205798542Smckusick if (sblock_try[i] == -1) { 205869926Stomsoft errx(1, "superblock not recognized"); 205969800Stomsoft } 206069800Stomsoft memcpy((void *)&fsun1, (void *)&fsun2, sizeof(fsun2)); 206198542Smckusick maxino = sblock.fs_ncg * sblock.fs_ipg; 206269800Stomsoft 206369800Stomsoft DBG_OPEN("/tmp/growfs.debug"); /* already here we need a superblock */ 206469926Stomsoft DBG_DUMP_FS(&sblock, 206569926Stomsoft "old sblock"); 206669800Stomsoft 206769800Stomsoft /* 206869800Stomsoft * Determine size to grow to. Default to the full size specified in 206969800Stomsoft * the disk label. 207069800Stomsoft */ 207169800Stomsoft sblock.fs_size = dbtofsb(&osblock, pp->p_size); 207269800Stomsoft if (size != 0) { 207369800Stomsoft if (size > pp->p_size){ 207477885Stomsoft errx(1, "There is not enough space (%d < %d)", 207569800Stomsoft pp->p_size, size); 207669800Stomsoft } 207769800Stomsoft sblock.fs_size = dbtofsb(&osblock, size); 207869800Stomsoft } 207969800Stomsoft 208069800Stomsoft /* 208169800Stomsoft * Are we really growing ? 208269800Stomsoft */ 208369800Stomsoft if(osblock.fs_size >= sblock.fs_size) { 208469926Stomsoft errx(1, "we are not growing (%d->%d)", osblock.fs_size, 208569926Stomsoft sblock.fs_size); 208669800Stomsoft } 208769800Stomsoft 208869800Stomsoft 208969800Stomsoft#ifdef FSMAXSNAP 209069800Stomsoft /* 209169800Stomsoft * Check if we find an active snapshot. 209269800Stomsoft */ 209369800Stomsoft if(ExpertFlag == 0) { 209469800Stomsoft for(j=0; j<FSMAXSNAP; j++) { 209569800Stomsoft if(sblock.fs_snapinum[j]) { 2096102231Strhodes errx(1, "active snapshot found in file system\n" 209769800Stomsoft " please remove all snapshots before " 209869800Stomsoft "using growfs\n"); 209969800Stomsoft } 210069800Stomsoft if(!sblock.fs_snapinum[j]) { /* list is dense */ 210169800Stomsoft break; 210269800Stomsoft } 210369800Stomsoft } 210469800Stomsoft } 210569800Stomsoft#endif 210669800Stomsoft 210769800Stomsoft if (ExpertFlag == 0 && Nflag == 0) { 210869800Stomsoft printf("We strongly recommend you to make a backup " 210969800Stomsoft "before growing the Filesystem\n\n" 211069800Stomsoft " Did you backup your data (Yes/No) ? "); 211177885Stomsoft fgets(reply, (int)sizeof(reply), stdin); 211269800Stomsoft if (strcmp(reply, "Yes\n")){ 211369800Stomsoft printf("\n Nothing done \n"); 211469800Stomsoft exit (0); 211569800Stomsoft } 211669800Stomsoft } 211769800Stomsoft 2118102231Strhodes printf("new file systemsize is: %d frags\n", sblock.fs_size); 211969800Stomsoft 212069800Stomsoft /* 2121102231Strhodes * Try to access our new last block in the file system. Even if we 212269800Stomsoft * later on realize we have to abort our operation, on that block 212369800Stomsoft * there should be no data, so we can't destroy something yet. 212469800Stomsoft */ 212598542Smckusick wtfs((ufs2_daddr_t)pp->p_size-1, (size_t)DEV_BSIZE, (void *)&sblock, 212698542Smckusick fso, Nflag); 212769800Stomsoft 212869800Stomsoft /* 212969800Stomsoft * Now calculate new superblock values and check for reasonable 2130102231Strhodes * bound for new file system size: 213169800Stomsoft * fs_size: is derived from label or user input 213269800Stomsoft * fs_dsize: should get updated in the routines creating or 213369800Stomsoft * updating the cylinder groups on the fly 213469800Stomsoft * fs_cstotal: should get updated in the routines creating or 213569800Stomsoft * updating the cylinder groups 213669800Stomsoft */ 213769800Stomsoft 213869800Stomsoft /* 2139102231Strhodes * Update the number of cylinders and cylinder groups in the file system. 214069800Stomsoft */ 214198542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) { 214298542Smckusick sblock.fs_old_ncyl = 214398542Smckusick sblock.fs_size * sblock.fs_old_nspf / sblock.fs_old_spc; 214498542Smckusick if (sblock.fs_size * sblock.fs_old_nspf > 214598542Smckusick sblock.fs_old_ncyl * sblock.fs_old_spc) 214698542Smckusick sblock.fs_old_ncyl++; 214769800Stomsoft } 214898542Smckusick sblock.fs_ncg = howmany(sblock.fs_size, sblock.fs_fpg); 214998542Smckusick maxino = sblock.fs_ncg * sblock.fs_ipg; 215069800Stomsoft 215198542Smckusick if (sblock.fs_size % sblock.fs_fpg != 0 && 215298542Smckusick sblock.fs_size % sblock.fs_fpg < cgdmin(&sblock, sblock.fs_ncg)) { 215369800Stomsoft /* 215469800Stomsoft * The space in the new last cylinder group is too small, 215569800Stomsoft * so revert back. 215669800Stomsoft */ 215769800Stomsoft sblock.fs_ncg--; 215898542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 215998542Smckusick sblock.fs_old_ncyl = sblock.fs_ncg * sblock.fs_old_cpg; 216098542Smckusick printf("Warning: %d sector(s) cannot be allocated.\n", 216198542Smckusick fsbtodb(&sblock, sblock.fs_size % sblock.fs_fpg)); 216298542Smckusick sblock.fs_size = sblock.fs_ncg * sblock.fs_fpg; 216369800Stomsoft } 216469800Stomsoft 216569800Stomsoft /* 216669800Stomsoft * Update the space for the cylinder group summary information in the 216769800Stomsoft * respective cylinder group data area. 216869800Stomsoft */ 216969800Stomsoft sblock.fs_cssize = 217069800Stomsoft fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum)); 217169800Stomsoft 217269800Stomsoft if(osblock.fs_size >= sblock.fs_size) { 217369926Stomsoft errx(1, "not enough new space"); 217469800Stomsoft } 217569800Stomsoft 217669800Stomsoft DBG_PRINT0("sblock calculated\n"); 217769800Stomsoft 217869800Stomsoft /* 217969800Stomsoft * Ok, everything prepared, so now let's do the tricks. 218069800Stomsoft */ 218169800Stomsoft growfs(fsi, fso, Nflag); 218269800Stomsoft 218369800Stomsoft /* 218469800Stomsoft * Update the disk label. 218569800Stomsoft */ 218669800Stomsoft pp->p_fsize = sblock.fs_fsize; 218769800Stomsoft pp->p_frag = sblock.fs_frag; 218898542Smckusick pp->p_cpg = sblock.fs_fpg; 218969800Stomsoft 219069800Stomsoft return_disklabel(fso, lp, Nflag); 219169800Stomsoft DBG_PRINT0("label rewritten\n"); 219269800Stomsoft 219369800Stomsoft close(fsi); 219469800Stomsoft if(fso>-1) close(fso); 219569800Stomsoft 219669800Stomsoft DBG_CLOSE; 219769800Stomsoft 219869800Stomsoft DBG_LEAVE; 219969800Stomsoft return 0; 220069800Stomsoft} 220169800Stomsoft 220269800Stomsoft/* ************************************************** return_disklabel ***** */ 220369800Stomsoft/* 220469800Stomsoft * Write the updated disklabel back to disk. 220569800Stomsoft */ 220669800Stomsoftstatic void 220777885Stomsoftreturn_disklabel(int fd, struct disklabel *lp, unsigned int Nflag) 220869800Stomsoft{ 220969800Stomsoft DBG_FUNC("return_disklabel") 221069800Stomsoft u_short sum; 221169800Stomsoft u_short *ptr; 221269800Stomsoft 221369800Stomsoft DBG_ENTER; 221469800Stomsoft 221569800Stomsoft if(!lp) { 221669800Stomsoft DBG_LEAVE; 221769800Stomsoft return; 221869800Stomsoft } 221969800Stomsoft if(!Nflag) { 222069800Stomsoft lp->d_checksum=0; 222169800Stomsoft sum = 0; 222269800Stomsoft ptr=(u_short *)lp; 222369800Stomsoft 222469800Stomsoft /* 222569800Stomsoft * recalculate checksum 222669800Stomsoft */ 222769800Stomsoft while(ptr < (u_short *)&lp->d_partitions[lp->d_npartitions]) { 222869800Stomsoft sum ^= *ptr++; 222969800Stomsoft } 223069800Stomsoft lp->d_checksum=sum; 223169800Stomsoft 223269800Stomsoft if (ioctl(fd, DIOCWDINFO, (char *)lp) < 0) { 223369926Stomsoft errx(1, "DIOCWDINFO failed"); 223469800Stomsoft } 223569800Stomsoft } 223669800Stomsoft free(lp); 223769800Stomsoft 223869800Stomsoft DBG_LEAVE; 223969800Stomsoft return ; 224069800Stomsoft} 224169800Stomsoft 224269800Stomsoft/* ***************************************************** get_disklabel ***** */ 224369800Stomsoft/* 224469800Stomsoft * Read the disklabel from disk. 224569800Stomsoft */ 224669800Stomsoftstatic struct disklabel * 224769800Stomsoftget_disklabel(int fd) 224869800Stomsoft{ 224969800Stomsoft DBG_FUNC("get_disklabel") 225069800Stomsoft static struct disklabel *lab; 225169800Stomsoft 225269800Stomsoft DBG_ENTER; 225369800Stomsoft 225469800Stomsoft lab=(struct disklabel *)malloc(sizeof(struct disklabel)); 225569800Stomsoft if (!lab) { 225669926Stomsoft errx(1, "malloc failed"); 225769800Stomsoft } 225869800Stomsoft if (ioctl(fd, DIOCGDINFO, (char *)lab) < 0) { 225969926Stomsoft errx(1, "DIOCGDINFO failed"); 226069800Stomsoft } 226169800Stomsoft 226269800Stomsoft DBG_LEAVE; 226369800Stomsoft return (lab); 226469800Stomsoft} 226569800Stomsoft 226669800Stomsoft 226769800Stomsoft/* ************************************************************* usage ***** */ 226869800Stomsoft/* 226969800Stomsoft * Dump a line of usage. 227069800Stomsoft */ 227169800Stomsoftstatic void 227269926Stomsoftusage(void) 227369800Stomsoft{ 227469800Stomsoft DBG_FUNC("usage") 227569800Stomsoft 227669800Stomsoft DBG_ENTER; 227769800Stomsoft 227869926Stomsoft fprintf(stderr, "usage: growfs [-Ny] [-s size] special\n"); 227969926Stomsoft 228069800Stomsoft DBG_LEAVE; 228169926Stomsoft exit(1); 228269800Stomsoft} 228369800Stomsoft 228469800Stomsoft/* *********************************************************** updclst ***** */ 228569800Stomsoft/* 228669800Stomsoft * This updates most paramters and the bitmap related to cluster. We have to 228769800Stomsoft * assume, that sblock, osblock, acg are set up. 228869800Stomsoft */ 228969800Stomsoftstatic void 229069800Stomsoftupdclst(int block) 229169800Stomsoft{ 229269800Stomsoft DBG_FUNC("updclst") 229369800Stomsoft static int lcs=0; 229469800Stomsoft 229569800Stomsoft DBG_ENTER; 229669800Stomsoft 229769800Stomsoft if(sblock.fs_contigsumsize < 1) { /* no clustering */ 229869800Stomsoft return; 229969800Stomsoft } 230069800Stomsoft /* 230169800Stomsoft * update cluster allocation map 230269800Stomsoft */ 230369800Stomsoft setbit(cg_clustersfree(&acg), block); 230469800Stomsoft 230569800Stomsoft /* 230669800Stomsoft * update cluster summary table 230769800Stomsoft */ 230869800Stomsoft if(!lcs) { 230969800Stomsoft /* 231069800Stomsoft * calculate size for the trailing cluster 231169800Stomsoft */ 231269800Stomsoft for(block--; lcs<sblock.fs_contigsumsize; block--, lcs++ ) { 231369800Stomsoft if(isclr(cg_clustersfree(&acg), block)){ 231469800Stomsoft break; 231569800Stomsoft } 231669800Stomsoft } 231769800Stomsoft } 231869800Stomsoft if(lcs < sblock.fs_contigsumsize) { 231969800Stomsoft if(lcs) { 232069800Stomsoft cg_clustersum(&acg)[lcs]--; 232169800Stomsoft } 232269800Stomsoft lcs++; 232369800Stomsoft cg_clustersum(&acg)[lcs]++; 232469800Stomsoft } 232569800Stomsoft 232669800Stomsoft DBG_LEAVE; 232769800Stomsoft return; 232869800Stomsoft} 232969800Stomsoft 233069800Stomsoft/* *********************************************************** updrefs ***** */ 233169800Stomsoft/* 233269800Stomsoft * This updates all references to relocated blocks for the given inode. The 233369800Stomsoft * inode is given as number within the cylinder group, and the number of the 233469800Stomsoft * cylinder group. 233569800Stomsoft */ 233669800Stomsoftstatic void 233777885Stomsoftupdrefs(int cg, ino_t in, struct gfs_bpp *bp, int fsi, int fso, unsigned int 233877885Stomsoft Nflag) 233969800Stomsoft{ 234069800Stomsoft DBG_FUNC("updrefs") 234198542Smckusick ufs_lbn_t len, lbn, numblks; 234298542Smckusick ufs2_daddr_t iptr, blksperindir; 234398542Smckusick union dinode *ino; 234498542Smckusick int i, mode, remaining_blocks, inodeupdated; 234569800Stomsoft 234669800Stomsoft DBG_ENTER; 234769800Stomsoft 234869800Stomsoft /* 234998542Smckusick * XXX We should skip unused inodes even from being read from disk 235069800Stomsoft * here by using the bitmap. 235169800Stomsoft */ 235298542Smckusick ino = ginode(in, fsi, cg); 235398542Smckusick mode = DIP(ino, di_mode) & IFMT; 235498542Smckusick if (mode != IFDIR && mode != IFREG && mode != IFLNK) { 235569800Stomsoft DBG_LEAVE; 235669800Stomsoft return; /* only check DIR, FILE, LINK */ 235769800Stomsoft } 235898542Smckusick if (mode == IFLNK && DIP(ino, di_size) < sblock.fs_maxsymlinklen) { 235969800Stomsoft DBG_LEAVE; 236069800Stomsoft return; /* skip short symlinks */ 236169800Stomsoft } 236298542Smckusick numblks = howmany(DIP(ino, di_size), sblock.fs_bsize); 236398542Smckusick if (numblks == 0) { 236469800Stomsoft DBG_LEAVE; 236569800Stomsoft return; /* skip empty file */ 236669800Stomsoft } 236798542Smckusick if (DIP(ino, di_blocks) == 0) { 236869800Stomsoft DBG_LEAVE; 236969800Stomsoft return; /* skip empty swiss cheesy file or old fastlink */ 237069800Stomsoft } 237169926Stomsoft DBG_PRINT2("scg checking inode (%d in %d)\n", 237269926Stomsoft in, 237369926Stomsoft cg); 237469800Stomsoft 237569800Stomsoft /* 237698542Smckusick * Check all the blocks. 237769800Stomsoft */ 237898542Smckusick inodeupdated = 0; 237998542Smckusick len = numblks < NDADDR ? numblks : NDADDR; 238098542Smckusick for (i = 0; i < len; i++) { 238198542Smckusick iptr = DIP(ino, di_db[i]); 238298542Smckusick if (iptr == 0) 238398542Smckusick continue; 238498542Smckusick if (cond_bl_upd(&iptr, bp, fsi, fso, Nflag)) { 238598542Smckusick DIP(ino, di_db[i]) = iptr; 238698542Smckusick inodeupdated++; 238769800Stomsoft } 238869800Stomsoft } 238969800Stomsoft DBG_PRINT0("~~scg direct blocks checked\n"); 239069800Stomsoft 239198542Smckusick blksperindir = 1; 239298542Smckusick len = numblks - NDADDR; 239398542Smckusick lbn = NDADDR; 239498542Smckusick for (i = 0; len > 0 && i < NIADDR; i++) { 239598542Smckusick iptr = DIP(ino, di_ib[i]); 239698542Smckusick if (iptr == 0) 239798542Smckusick continue; 239898542Smckusick if (cond_bl_upd(&iptr, bp, fsi, fso, Nflag)) { 239998542Smckusick DIP(ino, di_ib[i]) = iptr; 240098542Smckusick inodeupdated++; 240169800Stomsoft } 240298542Smckusick indirchk(blksperindir, lbn, iptr, numblks, bp, fsi, fso, Nflag); 240398542Smckusick blksperindir *= NINDIR(&sblock); 240498542Smckusick lbn += blksperindir; 240598542Smckusick len -= blksperindir; 240698542Smckusick DBG_PRINT1("scg indirect_%d blocks checked\n", i + 1); 240769800Stomsoft } 240898542Smckusick if (inodeupdated) 240998542Smckusick wtfs(inoblk, sblock.fs_bsize, inobuf, fso, Nflag); 241069800Stomsoft 241198542Smckusick DBG_LEAVE; 241298542Smckusick return; 241398542Smckusick} 241469800Stomsoft 241598542Smckusick/* 241698542Smckusick * Recursively check all the indirect blocks. 241798542Smckusick */ 241898542Smckusickstatic void 241998542Smckusickindirchk(ufs_lbn_t blksperindir, ufs_lbn_t lbn, ufs2_daddr_t blkno, 242098542Smckusick ufs_lbn_t lastlbn, struct gfs_bpp *bp, int fsi, int fso, unsigned int Nflag) 242198542Smckusick{ 242298542Smckusick DBG_FUNC("indirchk") 242398542Smckusick void *ibuf; 242498542Smckusick off_t offset; 242598542Smckusick int i, last; 242698542Smckusick ufs2_daddr_t iptr; 242798542Smckusick 242898542Smckusick DBG_ENTER; 242998542Smckusick 243098542Smckusick /* read in the indirect block. */ 243198542Smckusick ibuf = malloc(sblock.fs_bsize); 243298542Smckusick if (!ibuf) 243398542Smckusick errx(1, "malloc failed"); 243498542Smckusick rdfs(fsbtodb(&sblock, blkno), (size_t)sblock.fs_bsize, ibuf, fsi); 243598542Smckusick last = howmany(lastlbn - lbn, blksperindir) < NINDIR(&sblock) ? 243698542Smckusick howmany(lastlbn - lbn, blksperindir) : NINDIR(&sblock); 243798542Smckusick for (i = 0; i < last; i++) { 243898542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 243998542Smckusick iptr = ((ufs1_daddr_t *)ibuf)[i]; 244098542Smckusick else 244198542Smckusick iptr = ((ufs2_daddr_t *)ibuf)[i]; 244298542Smckusick if (iptr == 0) 244398542Smckusick continue; 244498542Smckusick if (cond_bl_upd(&iptr, bp, fsi, fso, Nflag)) { 244598542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 244698542Smckusick ((ufs1_daddr_t *)ibuf)[i] = iptr; 244798542Smckusick else 244898542Smckusick ((ufs2_daddr_t *)ibuf)[i] = iptr; 244969800Stomsoft } 245098542Smckusick if (blksperindir == 1) 245198542Smckusick continue; 245298542Smckusick indirchk(blksperindir / NINDIR(&sblock), lbn + blksperindir * i, 245398542Smckusick iptr, lastlbn, bp, fsi, fso, Nflag); 245469800Stomsoft } 245598542Smckusick free(ibuf); 245669800Stomsoft 245769800Stomsoft DBG_LEAVE; 245869800Stomsoft return; 245969800Stomsoft} 2460