growfs.c revision 234314
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. 5114067Sschweikh * 669800Stomsoft * This code is derived from software contributed to Berkeley by 769800Stomsoft * Christoph Herrmann and Thomas-Henning von Kamptz, Munich and Frankfurt. 8114067Sschweikh * 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. 25114067Sschweikh * 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 49140351Scharnier#include <sys/cdefs.h> 50140351Scharnier__FBSDID("$FreeBSD: head/sbin/growfs/growfs.c 234314 2012-04-15 15:15:16Z trasz $"); 5169800Stomsoft 5269800Stomsoft#include <sys/param.h> 5369800Stomsoft#include <sys/ioctl.h> 5469800Stomsoft#include <sys/stat.h> 55114936Sgrog#include <sys/disk.h> 5669800Stomsoft 5769800Stomsoft#include <stdio.h> 5869800Stomsoft#include <paths.h> 5969800Stomsoft#include <ctype.h> 6069800Stomsoft#include <err.h> 6169800Stomsoft#include <fcntl.h> 62103949Smike#include <limits.h> 6369800Stomsoft#include <stdlib.h> 64127798Sle#include <stdint.h> 6569800Stomsoft#include <string.h> 66127821Sbde#include <time.h> 6769800Stomsoft#include <unistd.h> 6869800Stomsoft#include <ufs/ufs/dinode.h> 6969800Stomsoft#include <ufs/ffs/fs.h> 7069800Stomsoft 7169800Stomsoft#include "debug.h" 7269800Stomsoft 7369800Stomsoft#ifdef FS_DEBUG 7469800Stomsoftint _dbg_lvl_ = (DL_INFO); /* DL_TRC */ 7569800Stomsoft#endif /* FS_DEBUG */ 7669800Stomsoft 7769800Stomsoftstatic union { 7869800Stomsoft struct fs fs; 79234189Strasz char pad[SBLOCKSIZE]; 8069800Stomsoft} fsun1, fsun2; 8169800Stomsoft#define sblock fsun1.fs /* the new superblock */ 8269800Stomsoft#define osblock fsun2.fs /* the old superblock */ 8369800Stomsoft 8498542Smckusick/* 8598542Smckusick * Possible superblock locations ordered from most to least likely. 8698542Smckusick */ 8798542Smckusickstatic int sblock_try[] = SBLOCKSEARCH; 8898542Smckusickstatic ufs2_daddr_t sblockloc; 8998542Smckusick 9069800Stomsoftstatic union { 9169800Stomsoft struct cg cg; 92234189Strasz char pad[MAXBSIZE]; 9369800Stomsoft} cgun1, cgun2; 9469800Stomsoft#define acg cgun1.cg /* a cylinder cgroup (new) */ 9569800Stomsoft#define aocg cgun2.cg /* an old cylinder group */ 9669800Stomsoft 9798542Smckusickstatic struct csum *fscs; /* cylinder summary */ 9869800Stomsoft 9977885Stomsoftstatic void growfs(int, int, unsigned int); 10098542Smckusickstatic void rdfs(ufs2_daddr_t, size_t, void *, int); 10198542Smckusickstatic void wtfs(ufs2_daddr_t, size_t, void *, int, unsigned int); 10269800Stomsoftstatic int charsperline(void); 10369926Stomsoftstatic void usage(void); 10469800Stomsoftstatic int isblock(struct fs *, unsigned char *, int); 10569800Stomsoftstatic void clrblock(struct fs *, unsigned char *, int); 10669800Stomsoftstatic void setblock(struct fs *, unsigned char *, int); 10777885Stomsoftstatic void initcg(int, time_t, int, unsigned int); 10877885Stomsoftstatic void updjcg(int, time_t, int, int, unsigned int); 10977885Stomsoftstatic void updcsloc(time_t, int, int, unsigned int); 11098542Smckusickstatic void frag_adjust(ufs2_daddr_t, int); 11169800Stomsoftstatic void updclst(int); 112114936Sgrogstatic void get_dev_size(int, int *); 11369800Stomsoft 11469800Stomsoft/* 115223652Strasz * Here we actually start growing the file system. We basically read the 116114067Sschweikh * cylinder summary from the first cylinder group as we want to update 117114067Sschweikh * this on the fly during our various operations. First we handle the 11869800Stomsoft * changes in the former last cylinder group. Afterwards we create all new 119114067Sschweikh * cylinder groups. Now we handle the cylinder group containing the 120114067Sschweikh * cylinder summary which might result in a relocation of the whole 121114067Sschweikh * structure. In the end we write back the updated cylinder summary, the 12269800Stomsoft * new superblock, and slightly patched versions of the super block 12369800Stomsoft * copies. 12469800Stomsoft */ 12569800Stomsoftstatic void 12677885Stomsoftgrowfs(int fsi, int fso, unsigned int Nflag) 12769800Stomsoft{ 12869800Stomsoft DBG_FUNC("growfs") 129232548Strasz time_t modtime; 130232548Strasz uint cylno; 131232548Strasz int i, j, width; 132232548Strasz char tmpbuf[100]; 133234314Strasz static int randinit = 0; 13469800Stomsoft 13569800Stomsoft DBG_ENTER; 13669800Stomsoft 13769800Stomsoft if (!randinit) { 13869800Stomsoft randinit = 1; 13969800Stomsoft srandomdev(); 14069800Stomsoft } 141217726Smarcel time(&modtime); 14269800Stomsoft 14369800Stomsoft /* 14469800Stomsoft * Get the cylinder summary into the memory. 14569800Stomsoft */ 14677885Stomsoft fscs = (struct csum *)calloc((size_t)1, (size_t)sblock.fs_cssize); 147232548Strasz if (fscs == NULL) 14869926Stomsoft errx(1, "calloc failed"); 14969800Stomsoft for (i = 0; i < osblock.fs_cssize; i += osblock.fs_bsize) { 15069800Stomsoft rdfs(fsbtodb(&osblock, osblock.fs_csaddr + 15177885Stomsoft numfrags(&osblock, i)), (size_t)MIN(osblock.fs_cssize - i, 152232548Strasz osblock.fs_bsize), (void *)(((char *)fscs) + i), fsi); 15369800Stomsoft } 15469800Stomsoft 15569800Stomsoft#ifdef FS_DEBUG 156232548Strasz { 157232548Strasz struct csum *dbg_csp; 158232548Strasz int dbg_csc; 159232548Strasz char dbg_line[80]; 16069800Stomsoft 161232548Strasz dbg_csp = fscs; 162232548Strasz 163232548Strasz for (dbg_csc = 0; dbg_csc < osblock.fs_ncg; dbg_csc++) { 164232548Strasz snprintf(dbg_line, sizeof(dbg_line), 165232548Strasz "%d. old csum in old location", dbg_csc); 166232548Strasz DBG_DUMP_CSUM(&osblock, dbg_line, dbg_csp++); 167232548Strasz } 16869800Stomsoft } 16969800Stomsoft#endif /* FS_DEBUG */ 17069800Stomsoft DBG_PRINT0("fscs read\n"); 17169800Stomsoft 17269800Stomsoft /* 17369800Stomsoft * Do all needed changes in the former last cylinder group. 17469800Stomsoft */ 175232548Strasz updjcg(osblock.fs_ncg - 1, modtime, fsi, fso, Nflag); 17669800Stomsoft 17769800Stomsoft /* 178223652Strasz * Dump out summary information about file system. 17969800Stomsoft */ 180234314Strasz#define B2MBFACTOR (1 / (1024.0 * 1024.0)) 181127816Smux printf("growfs: %.1fMB (%jd sectors) block size %d, fragment size %d\n", 18269800Stomsoft (float)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR, 183127816Smux (intmax_t)fsbtodb(&sblock, sblock.fs_size), sblock.fs_bsize, 184127816Smux sblock.fs_fsize); 18598542Smckusick printf("\tusing %d cylinder groups of %.2fMB, %d blks, %d inodes.\n", 18698542Smckusick sblock.fs_ncg, (float)sblock.fs_fpg * sblock.fs_fsize * B2MBFACTOR, 18798542Smckusick sblock.fs_fpg / sblock.fs_frag, sblock.fs_ipg); 18898542Smckusick if (sblock.fs_flags & FS_DOSOFTDEP) 18998542Smckusick printf("\twith soft updates\n"); 190234314Strasz#undef B2MBFACTOR 19169800Stomsoft 19269800Stomsoft /* 19369800Stomsoft * Now build the cylinders group blocks and 19469800Stomsoft * then print out indices of cylinder groups. 19569800Stomsoft */ 19669800Stomsoft printf("super-block backups (for fsck -b #) at:\n"); 19769800Stomsoft i = 0; 19869800Stomsoft width = charsperline(); 19969800Stomsoft 20069800Stomsoft /* 20169800Stomsoft * Iterate for only the new cylinder groups. 20269800Stomsoft */ 20369800Stomsoft for (cylno = osblock.fs_ncg; cylno < sblock.fs_ncg; cylno++) { 204217726Smarcel initcg(cylno, modtime, fso, Nflag); 205174706Sdas j = sprintf(tmpbuf, " %jd%s", 206174706Sdas (intmax_t)fsbtodb(&sblock, cgsblock(&sblock, cylno)), 207232548Strasz cylno < (sblock.fs_ncg - 1) ? "," : "" ); 20869800Stomsoft if (i + j >= width) { 20969800Stomsoft printf("\n"); 21069800Stomsoft i = 0; 21169800Stomsoft } 21269800Stomsoft i += j; 21369800Stomsoft printf("%s", tmpbuf); 21469800Stomsoft fflush(stdout); 21569800Stomsoft } 21669800Stomsoft printf("\n"); 21769800Stomsoft 21869800Stomsoft /* 21969800Stomsoft * Do all needed changes in the first cylinder group. 22069800Stomsoft * allocate blocks in new location 22169800Stomsoft */ 222217726Smarcel updcsloc(modtime, fsi, fso, Nflag); 22369800Stomsoft 22469800Stomsoft /* 22569800Stomsoft * Now write the cylinder summary back to disk. 22669800Stomsoft */ 22769800Stomsoft for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize) { 22869800Stomsoft wtfs(fsbtodb(&sblock, sblock.fs_csaddr + numfrags(&sblock, i)), 22977885Stomsoft (size_t)MIN(sblock.fs_cssize - i, sblock.fs_bsize), 23077885Stomsoft (void *)(((char *)fscs) + i), fso, Nflag); 23169800Stomsoft } 23269800Stomsoft DBG_PRINT0("fscs written\n"); 23369800Stomsoft 23469800Stomsoft#ifdef FS_DEBUG 235232548Strasz { 236232548Strasz struct csum *dbg_csp; 237232548Strasz int dbg_csc; 238232548Strasz char dbg_line[80]; 23969800Stomsoft 240232548Strasz dbg_csp = fscs; 241232548Strasz for (dbg_csc = 0; dbg_csc < sblock.fs_ncg; dbg_csc++) { 242232548Strasz snprintf(dbg_line, sizeof(dbg_line), 243232548Strasz "%d. new csum in new location", dbg_csc); 244232548Strasz DBG_DUMP_CSUM(&sblock, dbg_line, dbg_csp++); 245232548Strasz } 24669800Stomsoft } 24769800Stomsoft#endif /* FS_DEBUG */ 24869800Stomsoft 24969800Stomsoft /* 25069800Stomsoft * Now write the new superblock back to disk. 25169800Stomsoft */ 252217726Smarcel sblock.fs_time = modtime; 25398542Smckusick wtfs(sblockloc, (size_t)SBLOCKSIZE, (void *)&sblock, fso, Nflag); 25469800Stomsoft DBG_PRINT0("sblock written\n"); 255232548Strasz DBG_DUMP_FS(&sblock, "new initial sblock"); 25669800Stomsoft 25769800Stomsoft /* 25869800Stomsoft * Clean up the dynamic fields in our superblock copies. 25969800Stomsoft */ 26069800Stomsoft sblock.fs_fmod = 0; 26169800Stomsoft sblock.fs_clean = 1; 26269800Stomsoft sblock.fs_ronly = 0; 26369800Stomsoft sblock.fs_cgrotor = 0; 26469800Stomsoft sblock.fs_state = 0; 26569800Stomsoft memset((void *)&sblock.fs_fsmnt, 0, sizeof(sblock.fs_fsmnt)); 26669800Stomsoft sblock.fs_flags &= FS_DOSOFTDEP; 26769800Stomsoft 26869800Stomsoft /* 26969800Stomsoft * XXX 270114067Sschweikh * The following fields are currently distributed from the superblock 27169800Stomsoft * to the copies: 27269800Stomsoft * fs_minfree 27369800Stomsoft * fs_rotdelay 27469800Stomsoft * fs_maxcontig 27569800Stomsoft * fs_maxbpg 27669800Stomsoft * fs_minfree, 27769800Stomsoft * fs_optim 27869800Stomsoft * fs_flags regarding SOFTPDATES 27969800Stomsoft * 28069800Stomsoft * We probably should rather change the summary for the cylinder group 28169800Stomsoft * statistics here to the value of what would be in there, if the file 282114067Sschweikh * system were created initially with the new size. Therefor we still 28369800Stomsoft * need to find an easy way of calculating that. 28469800Stomsoft * Possibly we can try to read the first superblock copy and apply the 285114067Sschweikh * "diffed" stats between the old and new superblock by still copying 28669800Stomsoft * certain parameters onto that. 28769800Stomsoft */ 28869800Stomsoft 28969800Stomsoft /* 29069800Stomsoft * Write out the duplicate super blocks. 29169800Stomsoft */ 29269800Stomsoft for (cylno = 0; cylno < sblock.fs_ncg; cylno++) { 29369800Stomsoft wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)), 29498542Smckusick (size_t)SBLOCKSIZE, (void *)&sblock, fso, Nflag); 29569800Stomsoft } 29669800Stomsoft DBG_PRINT0("sblock copies written\n"); 297232548Strasz DBG_DUMP_FS(&sblock, "new other sblocks"); 29869800Stomsoft 29969800Stomsoft DBG_LEAVE; 30069800Stomsoft return; 30169800Stomsoft} 30269800Stomsoft 30369800Stomsoft/* 304114067Sschweikh * This creates a new cylinder group structure, for more details please see 305114067Sschweikh * the source of newfs(8), as this function is taken over almost unchanged. 306114067Sschweikh * As this is never called for the first cylinder group, the special 30769800Stomsoft * provisions for that case are removed here. 30869800Stomsoft */ 30969800Stomsoftstatic void 310217726Smarcelinitcg(int cylno, time_t modtime, int fso, unsigned int Nflag) 31169800Stomsoft{ 31269800Stomsoft DBG_FUNC("initcg") 313212839Sbrian static caddr_t iobuf; 314203770Smckusick long blkno, start; 315127798Sle ufs2_daddr_t i, cbase, dmax; 31698542Smckusick struct ufs1_dinode *dp1; 31792806Sobrien struct csum *cs; 318234312Strasz uint j, d, dupper, dlower; 31969800Stomsoft 320212839Sbrian if (iobuf == NULL && (iobuf = malloc(sblock.fs_bsize * 3)) == NULL) 32198542Smckusick errx(37, "panic: cannot allocate I/O buffer"); 322212839Sbrian 32369800Stomsoft /* 32469800Stomsoft * Determine block bounds for cylinder group. 32598542Smckusick * Allow space for super block summary information in first 32698542Smckusick * cylinder group. 32769800Stomsoft */ 32869800Stomsoft cbase = cgbase(&sblock, cylno); 32969800Stomsoft dmax = cbase + sblock.fs_fpg; 33098542Smckusick if (dmax > sblock.fs_size) 33169800Stomsoft dmax = sblock.fs_size; 33269800Stomsoft dlower = cgsblock(&sblock, cylno) - cbase; 33369800Stomsoft dupper = cgdmin(&sblock, cylno) - cbase; 33498542Smckusick if (cylno == 0) /* XXX fscs may be relocated */ 33569800Stomsoft dupper += howmany(sblock.fs_cssize, sblock.fs_fsize); 33698542Smckusick cs = &fscs[cylno]; 33798542Smckusick memset(&acg, 0, sblock.fs_cgsize); 338217726Smarcel acg.cg_time = modtime; 33969800Stomsoft acg.cg_magic = CG_MAGIC; 34069800Stomsoft acg.cg_cgx = cylno; 34169800Stomsoft acg.cg_niblk = sblock.fs_ipg; 342212839Sbrian acg.cg_initediblk = sblock.fs_ipg < 2 * INOPB(&sblock) ? 343212839Sbrian sblock.fs_ipg : 2 * INOPB(&sblock); 34469800Stomsoft acg.cg_ndblk = dmax - cbase; 34598542Smckusick if (sblock.fs_contigsumsize > 0) 34669800Stomsoft acg.cg_nclusterblks = acg.cg_ndblk / sblock.fs_frag; 34798542Smckusick start = &acg.cg_space[0] - (u_char *)(&acg.cg_firstfield); 34898542Smckusick if (sblock.fs_magic == FS_UFS2_MAGIC) { 34998542Smckusick acg.cg_iusedoff = start; 35098542Smckusick } else { 35198542Smckusick acg.cg_old_ncyl = sblock.fs_old_cpg; 35298542Smckusick acg.cg_old_time = acg.cg_time; 35398542Smckusick acg.cg_time = 0; 35498542Smckusick acg.cg_old_niblk = acg.cg_niblk; 35598542Smckusick acg.cg_niblk = 0; 356212839Sbrian acg.cg_initediblk = 0; 35798542Smckusick acg.cg_old_btotoff = start; 35898542Smckusick acg.cg_old_boff = acg.cg_old_btotoff + 35998542Smckusick sblock.fs_old_cpg * sizeof(int32_t); 36098542Smckusick acg.cg_iusedoff = acg.cg_old_boff + 36198542Smckusick sblock.fs_old_cpg * sizeof(u_int16_t); 36269800Stomsoft } 363103949Smike acg.cg_freeoff = acg.cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT); 364103949Smike acg.cg_nextfreeoff = acg.cg_freeoff + howmany(sblock.fs_fpg, CHAR_BIT); 36598542Smckusick if (sblock.fs_contigsumsize > 0) { 36669800Stomsoft acg.cg_clustersumoff = 36798542Smckusick roundup(acg.cg_nextfreeoff, sizeof(u_int32_t)); 36898542Smckusick acg.cg_clustersumoff -= sizeof(u_int32_t); 36969800Stomsoft acg.cg_clusteroff = acg.cg_clustersumoff + 37069800Stomsoft (sblock.fs_contigsumsize + 1) * sizeof(u_int32_t); 37198542Smckusick acg.cg_nextfreeoff = acg.cg_clusteroff + 372103949Smike howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT); 37369800Stomsoft } 374203770Smckusick if (acg.cg_nextfreeoff > (unsigned)sblock.fs_cgsize) { 37569800Stomsoft /* 37698542Smckusick * This should never happen as we would have had that panic 377223652Strasz * already on file system creation 37869800Stomsoft */ 37969926Stomsoft errx(37, "panic: cylinder group too big"); 38069800Stomsoft } 38169800Stomsoft acg.cg_cs.cs_nifree += sblock.fs_ipg; 38269800Stomsoft if (cylno == 0) 38398542Smckusick for (i = 0; i < ROOTINO; i++) { 38469800Stomsoft setbit(cg_inosused(&acg), i); 38569800Stomsoft acg.cg_cs.cs_nifree--; 38669800Stomsoft } 387136289Sscottl /* 388223652Strasz * For the old file system, we have to initialize all the inodes. 389136289Sscottl */ 390136289Sscottl if (sblock.fs_magic == FS_UFS1_MAGIC) { 391136289Sscottl bzero(iobuf, sblock.fs_bsize); 392203835Sgavin for (i = 0; i < sblock.fs_ipg / INOPF(&sblock); 393232548Strasz i += sblock.fs_frag) { 394212886Smarcel dp1 = (struct ufs1_dinode *)(void *)iobuf; 395201401Sgavin for (j = 0; j < INOPB(&sblock); j++) { 396201401Sgavin dp1->di_gen = random(); 397201401Sgavin dp1++; 398201401Sgavin } 399136289Sscottl wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i), 400136289Sscottl sblock.fs_bsize, iobuf, fso, Nflag); 401136289Sscottl } 40269800Stomsoft } 40398542Smckusick if (cylno > 0) { 40498542Smckusick /* 40598542Smckusick * In cylno 0, beginning space is reserved 40698542Smckusick * for boot and super blocks. 40798542Smckusick */ 40898542Smckusick for (d = 0; d < dlower; d += sblock.fs_frag) { 40998542Smckusick blkno = d / sblock.fs_frag; 41098542Smckusick setblock(&sblock, cg_blksfree(&acg), blkno); 41198542Smckusick if (sblock.fs_contigsumsize > 0) 41298542Smckusick setbit(cg_clustersfree(&acg), blkno); 41398542Smckusick acg.cg_cs.cs_nbfree++; 41469800Stomsoft } 41598542Smckusick sblock.fs_dsize += dlower; 41669800Stomsoft } 41769800Stomsoft sblock.fs_dsize += acg.cg_ndblk - dupper; 41869800Stomsoft if ((i = dupper % sblock.fs_frag)) { 41969800Stomsoft acg.cg_frsum[sblock.fs_frag - i]++; 42069800Stomsoft for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) { 42169800Stomsoft setbit(cg_blksfree(&acg), dupper); 42269800Stomsoft acg.cg_cs.cs_nffree++; 42369800Stomsoft } 42469800Stomsoft } 42598542Smckusick for (d = dupper; d + sblock.fs_frag <= acg.cg_ndblk; 426232548Strasz d += sblock.fs_frag) { 42769800Stomsoft blkno = d / sblock.fs_frag; 42869800Stomsoft setblock(&sblock, cg_blksfree(&acg), blkno); 42998542Smckusick if (sblock.fs_contigsumsize > 0) 43069800Stomsoft setbit(cg_clustersfree(&acg), blkno); 43169800Stomsoft acg.cg_cs.cs_nbfree++; 43269800Stomsoft } 43398542Smckusick if (d < acg.cg_ndblk) { 43498542Smckusick acg.cg_frsum[acg.cg_ndblk - d]++; 43598542Smckusick for (; d < acg.cg_ndblk; d++) { 43669800Stomsoft setbit(cg_blksfree(&acg), d); 43769800Stomsoft acg.cg_cs.cs_nffree++; 43869800Stomsoft } 43969800Stomsoft } 44069800Stomsoft if (sblock.fs_contigsumsize > 0) { 44198542Smckusick int32_t *sump = cg_clustersum(&acg); 44298542Smckusick u_char *mapp = cg_clustersfree(&acg); 44398542Smckusick int map = *mapp++; 44498542Smckusick int bit = 1; 44598542Smckusick int run = 0; 44669800Stomsoft 44769800Stomsoft for (i = 0; i < acg.cg_nclusterblks; i++) { 44898542Smckusick if ((map & bit) != 0) 44969800Stomsoft run++; 45098542Smckusick else if (run != 0) { 45198542Smckusick if (run > sblock.fs_contigsumsize) 45269800Stomsoft run = sblock.fs_contigsumsize; 45369800Stomsoft sump[run]++; 45469800Stomsoft run = 0; 45569800Stomsoft } 456103949Smike if ((i & (CHAR_BIT - 1)) != CHAR_BIT - 1) 45769800Stomsoft bit <<= 1; 45898542Smckusick else { 45969800Stomsoft map = *mapp++; 46069800Stomsoft bit = 1; 46169800Stomsoft } 46269800Stomsoft } 46369800Stomsoft if (run != 0) { 46498542Smckusick if (run > sblock.fs_contigsumsize) 46569800Stomsoft run = sblock.fs_contigsumsize; 46669800Stomsoft sump[run]++; 46769800Stomsoft } 46869800Stomsoft } 46969800Stomsoft sblock.fs_cstotal.cs_ndir += acg.cg_cs.cs_ndir; 47069800Stomsoft sblock.fs_cstotal.cs_nffree += acg.cg_cs.cs_nffree; 47169800Stomsoft sblock.fs_cstotal.cs_nbfree += acg.cg_cs.cs_nbfree; 47269800Stomsoft sblock.fs_cstotal.cs_nifree += acg.cg_cs.cs_nifree; 47369800Stomsoft *cs = acg.cg_cs; 474212839Sbrian 475212839Sbrian memcpy(iobuf, &acg, sblock.fs_cgsize); 476212839Sbrian memset(iobuf + sblock.fs_cgsize, '\0', 477212839Sbrian sblock.fs_bsize * 3 - sblock.fs_cgsize); 478212839Sbrian 47969800Stomsoft wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)), 480212839Sbrian sblock.fs_bsize * 3, iobuf, fso, Nflag); 481212839Sbrian DBG_DUMP_CG(&sblock, "new cg", &acg); 48269800Stomsoft 48369800Stomsoft DBG_LEAVE; 48469800Stomsoft return; 48569800Stomsoft} 48669800Stomsoft 48769800Stomsoft/* 488114067Sschweikh * Here we add or subtract (sign +1/-1) the available fragments in a given 48969800Stomsoft * block to or from the fragment statistics. By subtracting before and adding 490114067Sschweikh * after an operation on the free frag map we can easy update the fragment 491108470Sschweikh * statistic, which seems to be otherwise a rather complex operation. 49269800Stomsoft */ 49369800Stomsoftstatic void 49498542Smckusickfrag_adjust(ufs2_daddr_t frag, int sign) 49569800Stomsoft{ 49669800Stomsoft DBG_FUNC("frag_adjust") 49769800Stomsoft int fragsize; 49869800Stomsoft int f; 49969800Stomsoft 50069800Stomsoft DBG_ENTER; 50169800Stomsoft 502234314Strasz fragsize = 0; 50369800Stomsoft /* 50469800Stomsoft * Here frag only needs to point to any fragment in the block we want 50569800Stomsoft * to examine. 50669800Stomsoft */ 507232548Strasz for (f = rounddown(frag, sblock.fs_frag); 508232548Strasz f < roundup(frag + 1, sblock.fs_frag); f++) { 50969800Stomsoft /* 510114067Sschweikh * Count contiguous free fragments. 51169800Stomsoft */ 512232548Strasz if (isset(cg_blksfree(&acg), f)) { 51369800Stomsoft fragsize++; 51469800Stomsoft } else { 515232548Strasz if (fragsize && fragsize < sblock.fs_frag) { 51669800Stomsoft /* 51769800Stomsoft * We found something in between. 51869800Stomsoft */ 519234189Strasz acg.cg_frsum[fragsize] += sign; 52069926Stomsoft DBG_PRINT2("frag_adjust [%d]+=%d\n", 521232548Strasz fragsize, sign); 52269800Stomsoft } 523232548Strasz fragsize = 0; 52469800Stomsoft } 52569800Stomsoft } 526232548Strasz if (fragsize && fragsize < sblock.fs_frag) { 52769800Stomsoft /* 52869800Stomsoft * We found something. 52969800Stomsoft */ 530232548Strasz acg.cg_frsum[fragsize] += sign; 531232548Strasz DBG_PRINT2("frag_adjust [%d]+=%d\n", fragsize, sign); 53269800Stomsoft } 533232548Strasz DBG_PRINT2("frag_adjust [[%d]]+=%d\n", fragsize, sign); 53469800Stomsoft 53569800Stomsoft DBG_LEAVE; 53669800Stomsoft return; 53769800Stomsoft} 53869800Stomsoft 53969800Stomsoft/* 54069800Stomsoft * Here we do all needed work for the former last cylinder group. It has to be 541223652Strasz * changed in any case, even if the file system ended exactly on the end of 542114067Sschweikh * this group, as there is some slightly inconsistent handling of the number 543114067Sschweikh * of cylinders in the cylinder group. We start again by reading the cylinder 54469800Stomsoft * group from disk. If the last block was not fully available, we first handle 545114067Sschweikh * the missing fragments, then we handle all new full blocks in that file 546114067Sschweikh * system and finally we handle the new last fragmented block in the file 547114067Sschweikh * system. We again have to handle the fragment statistics rotational layout 54869800Stomsoft * tables and cluster summary during all those operations. 54969800Stomsoft */ 55069800Stomsoftstatic void 551217726Smarcelupdjcg(int cylno, time_t modtime, int fsi, int fso, unsigned int Nflag) 55269800Stomsoft{ 55369800Stomsoft DBG_FUNC("updjcg") 554232548Strasz ufs2_daddr_t cbase, dmax, dupper; 555232548Strasz struct csum *cs; 556232548Strasz int i, k; 557232548Strasz int j = 0; 55869800Stomsoft 55969800Stomsoft DBG_ENTER; 56069800Stomsoft 56169800Stomsoft /* 56269800Stomsoft * Read the former last (joining) cylinder group from disk, and make 56369800Stomsoft * a copy. 56469800Stomsoft */ 56577885Stomsoft rdfs(fsbtodb(&osblock, cgtod(&osblock, cylno)), 56677885Stomsoft (size_t)osblock.fs_cgsize, (void *)&aocg, fsi); 56769800Stomsoft DBG_PRINT0("jcg read\n"); 568232548Strasz DBG_DUMP_CG(&sblock, "old joining cg", &aocg); 56969800Stomsoft 57069800Stomsoft memcpy((void *)&cgun1, (void *)&cgun2, sizeof(cgun2)); 57169800Stomsoft 57269800Stomsoft /* 573114067Sschweikh * If the cylinder group had already its new final size almost 57469800Stomsoft * nothing is to be done ... except: 57569800Stomsoft * For some reason the value of cg_ncyl in the last cylinder group has 576114067Sschweikh * to be zero instead of fs_cpg. As this is now no longer the last 57769800Stomsoft * cylinder group we have to change that value now to fs_cpg. 578114067Sschweikh */ 57969800Stomsoft 580232548Strasz if (cgbase(&osblock, cylno + 1) == osblock.fs_size) { 58198542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 582234314Strasz acg.cg_old_ncyl = sblock.fs_old_cpg; 58369800Stomsoft 58477885Stomsoft wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)), 58577885Stomsoft (size_t)sblock.fs_cgsize, (void *)&acg, fso, Nflag); 58669800Stomsoft DBG_PRINT0("jcg written\n"); 587232548Strasz DBG_DUMP_CG(&sblock, "new joining cg", &acg); 58869800Stomsoft 58969800Stomsoft DBG_LEAVE; 59069800Stomsoft return; 59169800Stomsoft } 59269800Stomsoft 59369800Stomsoft /* 59469800Stomsoft * Set up some variables needed later. 59569800Stomsoft */ 59669800Stomsoft cbase = cgbase(&sblock, cylno); 59769800Stomsoft dmax = cbase + sblock.fs_fpg; 59869800Stomsoft if (dmax > sblock.fs_size) 59969800Stomsoft dmax = sblock.fs_size; 60069800Stomsoft dupper = cgdmin(&sblock, cylno) - cbase; 601232548Strasz if (cylno == 0) /* XXX fscs may be relocated */ 60269800Stomsoft dupper += howmany(sblock.fs_cssize, sblock.fs_fsize); 60369800Stomsoft 60469800Stomsoft /* 60569800Stomsoft * Set pointer to the cylinder summary for our cylinder group. 60669800Stomsoft */ 60769800Stomsoft cs = fscs + cylno; 60869800Stomsoft 60969800Stomsoft /* 61069800Stomsoft * Touch the cylinder group, update all fields in the cylinder group as 61169800Stomsoft * needed, update the free space in the superblock. 61269800Stomsoft */ 613217726Smarcel acg.cg_time = modtime; 614203770Smckusick if ((unsigned)cylno == sblock.fs_ncg - 1) { 61569800Stomsoft /* 61669800Stomsoft * This is still the last cylinder group. 61769800Stomsoft */ 61898542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 61998542Smckusick acg.cg_old_ncyl = 62098542Smckusick sblock.fs_old_ncyl % sblock.fs_old_cpg; 62169800Stomsoft } else { 62298542Smckusick acg.cg_old_ncyl = sblock.fs_old_cpg; 62369800Stomsoft } 624232548Strasz DBG_PRINT2("jcg dbg: %d %u", cylno, sblock.fs_ncg); 625127798Sle#ifdef FS_DEBUG 62698542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 627232548Strasz DBG_PRINT2("%d %u", acg.cg_old_ncyl, sblock.fs_old_cpg); 628127798Sle#endif 62998542Smckusick DBG_PRINT0("\n"); 63069800Stomsoft acg.cg_ndblk = dmax - cbase; 631232548Strasz sblock.fs_dsize += acg.cg_ndblk - aocg.cg_ndblk; 632232548Strasz if (sblock.fs_contigsumsize > 0) 63369800Stomsoft acg.cg_nclusterblks = acg.cg_ndblk / sblock.fs_frag; 63469800Stomsoft 63569800Stomsoft /* 636114067Sschweikh * Now we have to update the free fragment bitmap for our new free 637114067Sschweikh * space. There again we have to handle the fragmentation and also 638114067Sschweikh * the rotational layout tables and the cluster summary. This is 639114067Sschweikh * also done per fragment for the first new block if the old file 640114067Sschweikh * system end was not on a block boundary, per fragment for the new 641223652Strasz * last block if the new file system end is not on a block boundary, 64269800Stomsoft * and per block for all space in between. 64369800Stomsoft * 64469800Stomsoft * Handle the first new block here if it was partially available 64569800Stomsoft * before. 64669800Stomsoft */ 647232548Strasz if (osblock.fs_size % sblock.fs_frag) { 648232548Strasz if (roundup(osblock.fs_size, sblock.fs_frag) <= 649232548Strasz sblock.fs_size) { 65069800Stomsoft /* 65169800Stomsoft * The new space is enough to fill at least this 65269800Stomsoft * block 65369800Stomsoft */ 654232548Strasz j = 0; 655232548Strasz for (i = roundup(osblock.fs_size - cbase, 656232548Strasz sblock.fs_frag) - 1; i >= osblock.fs_size - cbase; 65769800Stomsoft i--) { 65869800Stomsoft setbit(cg_blksfree(&acg), i); 65969800Stomsoft acg.cg_cs.cs_nffree++; 66069800Stomsoft j++; 66169800Stomsoft } 66269800Stomsoft 66369800Stomsoft /* 664114067Sschweikh * Check if the fragment just created could join an 66569800Stomsoft * already existing fragment at the former end of the 666223652Strasz * file system. 66769800Stomsoft */ 668232548Strasz if (isblock(&sblock, cg_blksfree(&acg), 669232548Strasz ((osblock.fs_size - cgbase(&sblock, cylno)) / 670232548Strasz sblock.fs_frag))) { 67169800Stomsoft /* 672114067Sschweikh * The block is now completely available. 67369800Stomsoft */ 67469800Stomsoft DBG_PRINT0("block was\n"); 675232548Strasz acg.cg_frsum[osblock.fs_size % sblock.fs_frag]--; 67669800Stomsoft acg.cg_cs.cs_nbfree++; 677232548Strasz acg.cg_cs.cs_nffree -= sblock.fs_frag; 678232548Strasz k = rounddown(osblock.fs_size - cbase, 67969800Stomsoft sblock.fs_frag); 680232548Strasz updclst((osblock.fs_size - cbase) / 681232548Strasz sblock.fs_frag); 68269800Stomsoft } else { 68369800Stomsoft /* 68469800Stomsoft * Lets rejoin a possible partially growed 68569800Stomsoft * fragment. 68669800Stomsoft */ 687232548Strasz k = 0; 688232548Strasz while (isset(cg_blksfree(&acg), i) && 689232548Strasz (i >= rounddown(osblock.fs_size - cbase, 69069800Stomsoft sblock.fs_frag))) { 69169800Stomsoft i--; 69269800Stomsoft k++; 69369800Stomsoft } 694232548Strasz if (k) 69569800Stomsoft acg.cg_frsum[k]--; 696232548Strasz acg.cg_frsum[k + j]++; 69769800Stomsoft } 69869800Stomsoft } else { 69969800Stomsoft /* 70069800Stomsoft * We only grow by some fragments within this last 70169800Stomsoft * block. 70269800Stomsoft */ 703232548Strasz for (i = sblock.fs_size - cbase - 1; 704232548Strasz i >= osblock.fs_size - cbase; i--) { 70569800Stomsoft setbit(cg_blksfree(&acg), i); 70669800Stomsoft acg.cg_cs.cs_nffree++; 70769800Stomsoft j++; 70869800Stomsoft } 70969800Stomsoft /* 71069800Stomsoft * Lets rejoin a possible partially growed fragment. 71169800Stomsoft */ 712232548Strasz k = 0; 713232548Strasz while (isset(cg_blksfree(&acg), i) && 714232548Strasz (i >= rounddown(osblock.fs_size - cbase, 71569800Stomsoft sblock.fs_frag))) { 71669800Stomsoft i--; 71769800Stomsoft k++; 71869800Stomsoft } 719232548Strasz if (k) 72069800Stomsoft acg.cg_frsum[k]--; 721232548Strasz acg.cg_frsum[k + j]++; 72269800Stomsoft } 72369800Stomsoft } 72469800Stomsoft 72569800Stomsoft /* 72669800Stomsoft * Handle all new complete blocks here. 72769800Stomsoft */ 728232548Strasz for (i = roundup(osblock.fs_size - cbase, sblock.fs_frag); 729232548Strasz i + sblock.fs_frag <= dmax - cbase; /* XXX <= or only < ? */ 730232548Strasz i += sblock.fs_frag) { 73169800Stomsoft j = i / sblock.fs_frag; 73269800Stomsoft setblock(&sblock, cg_blksfree(&acg), j); 73369800Stomsoft updclst(j); 73469800Stomsoft acg.cg_cs.cs_nbfree++; 73569800Stomsoft } 73669800Stomsoft 73769800Stomsoft /* 73869800Stomsoft * Handle the last new block if there are stll some new fragments left. 739114067Sschweikh * Here we don't have to bother about the cluster summary or the even 74069800Stomsoft * the rotational layout table. 74169800Stomsoft */ 74269800Stomsoft if (i < (dmax - cbase)) { 74369800Stomsoft acg.cg_frsum[dmax - cbase - i]++; 74469800Stomsoft for (; i < dmax - cbase; i++) { 74569800Stomsoft setbit(cg_blksfree(&acg), i); 74669800Stomsoft acg.cg_cs.cs_nffree++; 74769800Stomsoft } 74869800Stomsoft } 74969800Stomsoft 75069800Stomsoft sblock.fs_cstotal.cs_nffree += 75169800Stomsoft (acg.cg_cs.cs_nffree - aocg.cg_cs.cs_nffree); 75269800Stomsoft sblock.fs_cstotal.cs_nbfree += 75369800Stomsoft (acg.cg_cs.cs_nbfree - aocg.cg_cs.cs_nbfree); 75469800Stomsoft /* 75569800Stomsoft * The following statistics are not changed here: 75669800Stomsoft * sblock.fs_cstotal.cs_ndir 75769800Stomsoft * sblock.fs_cstotal.cs_nifree 75869800Stomsoft * As the statistics for this cylinder group are ready, copy it to 75969800Stomsoft * the summary information array. 76069800Stomsoft */ 76169800Stomsoft *cs = acg.cg_cs; 76269800Stomsoft 76369800Stomsoft /* 76469800Stomsoft * Write the updated "joining" cylinder group back to disk. 76569800Stomsoft */ 76677885Stomsoft wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)), (size_t)sblock.fs_cgsize, 76777885Stomsoft (void *)&acg, fso, Nflag); 76869800Stomsoft DBG_PRINT0("jcg written\n"); 769232548Strasz DBG_DUMP_CG(&sblock, "new joining cg", &acg); 77069800Stomsoft 77169800Stomsoft DBG_LEAVE; 77269800Stomsoft return; 77369800Stomsoft} 77469800Stomsoft 77569800Stomsoft/* 776114067Sschweikh * Here we update the location of the cylinder summary. We have two possible 77769800Stomsoft * ways of growing the cylinder summary. 778114067Sschweikh * (1) We can try to grow the summary in the current location, and relocate 77969800Stomsoft * possibly used blocks within the current cylinder group. 78069800Stomsoft * (2) Alternatively we can relocate the whole cylinder summary to the first 781114067Sschweikh * new completely empty cylinder group. Once the cylinder summary is no 782114067Sschweikh * longer in the beginning of the first cylinder group you should never 783114067Sschweikh * use a version of fsck which is not aware of the possibility to have 78469800Stomsoft * this structure in a non standard place. 785234178Strasz * Option (2) is considered to be less intrusive to the structure of the file- 786234178Strasz * system, so that's the one being used. 78769800Stomsoft */ 78869800Stomsoftstatic void 789217726Smarcelupdcsloc(time_t modtime, int fsi, int fso, unsigned int Nflag) 79069800Stomsoft{ 79169800Stomsoft DBG_FUNC("updcsloc") 792232548Strasz struct csum *cs; 793232548Strasz int ocscg, ncscg; 794232548Strasz int blocks; 795234178Strasz ufs2_daddr_t d; 796232548Strasz int lcs = 0; 797232548Strasz int block; 79869800Stomsoft 79969800Stomsoft DBG_ENTER; 80069800Stomsoft 801232548Strasz if (howmany(sblock.fs_cssize, sblock.fs_fsize) == 80269800Stomsoft howmany(osblock.fs_cssize, osblock.fs_fsize)) { 80369800Stomsoft /* 80469800Stomsoft * No new fragment needed. 80569800Stomsoft */ 80669800Stomsoft DBG_LEAVE; 80769800Stomsoft return; 80869800Stomsoft } 809232548Strasz ocscg = dtog(&osblock, osblock.fs_csaddr); 810232548Strasz cs = fscs + ocscg; 811232548Strasz blocks = 1 + howmany(sblock.fs_cssize, sblock.fs_bsize) - 81269800Stomsoft howmany(osblock.fs_cssize, osblock.fs_bsize); 81369800Stomsoft 81469800Stomsoft /* 81569800Stomsoft * Read original cylinder group from disk, and make a copy. 81681311Schm * XXX If Nflag is set in some very rare cases we now miss 81781311Schm * some changes done in updjcg by reading the unmodified 81881311Schm * block from disk. 81969800Stomsoft */ 82077885Stomsoft rdfs(fsbtodb(&osblock, cgtod(&osblock, ocscg)), 82177885Stomsoft (size_t)osblock.fs_cgsize, (void *)&aocg, fsi); 82269800Stomsoft DBG_PRINT0("oscg read\n"); 823232548Strasz DBG_DUMP_CG(&sblock, "old summary cg", &aocg); 82469800Stomsoft 82569800Stomsoft memcpy((void *)&cgun1, (void *)&cgun2, sizeof(cgun2)); 82669800Stomsoft 82769800Stomsoft /* 82869800Stomsoft * Touch the cylinder group, set up local variables needed later 82969800Stomsoft * and update the superblock. 83069800Stomsoft */ 831217726Smarcel acg.cg_time = modtime; 83269800Stomsoft 83369800Stomsoft /* 83469800Stomsoft * XXX In the case of having active snapshots we may need much more 835114067Sschweikh * blocks for the copy on write. We need each block twice, and 836114067Sschweikh * also up to 8*3 blocks for indirect blocks for all possible 83769800Stomsoft * references. 83869800Stomsoft */ 839234178Strasz /* 840234178Strasz * There is not enough space in the old cylinder group to 841234178Strasz * relocate all blocks as needed, so we relocate the whole 842234178Strasz * cylinder group summary to a new group. We try to use the 843234178Strasz * first complete new cylinder group just created. Within the 844234178Strasz * cylinder group we align the area immediately after the 845234178Strasz * cylinder group information location in order to be as 846234178Strasz * close as possible to the original implementation of ffs. 847234178Strasz * 848234178Strasz * First we have to make sure we'll find enough space in the 849234178Strasz * new cylinder group. If not, then we currently give up. 850234178Strasz * We start with freeing everything which was used by the 851234178Strasz * fragments of the old cylinder summary in the current group. 852234178Strasz * Now we write back the group meta data, read in the needed 853234178Strasz * meta data from the new cylinder group, and start allocating 854234178Strasz * within that group. Here we can assume, the group to be 855234178Strasz * completely empty. Which makes the handling of fragments and 856234178Strasz * clusters a lot easier. 857234178Strasz */ 858234178Strasz DBG_TRC; 859234178Strasz if (sblock.fs_ncg - osblock.fs_ncg < 2) 860234178Strasz errx(2, "panic: not enough space"); 86169800Stomsoft 862234178Strasz /* 863234178Strasz * Point "d" to the first fragment not used by the cylinder 864234178Strasz * summary. 865234178Strasz */ 866234178Strasz d = osblock.fs_csaddr + (osblock.fs_cssize / osblock.fs_fsize); 86769800Stomsoft 868234178Strasz /* 869234178Strasz * Set up last cluster size ("lcs") already here. Calculate 870234178Strasz * the size for the trailing cluster just behind where "d" 871234178Strasz * points to. 872234178Strasz */ 873234178Strasz if (sblock.fs_contigsumsize > 0) { 874234178Strasz for (block = howmany(d % sblock.fs_fpg, sblock.fs_frag), 875234189Strasz lcs = 0; lcs < sblock.fs_contigsumsize; block++, lcs++) { 876234178Strasz if (isclr(cg_clustersfree(&acg), block)) 877234178Strasz break; 878234178Strasz } 879234178Strasz } 880234178Strasz 881234178Strasz /* 882234178Strasz * Point "d" to the last frag used by the cylinder summary. 883234178Strasz */ 884234178Strasz d--; 885234178Strasz 886234178Strasz DBG_PRINT1("d=%jd\n", (intmax_t)d); 887234178Strasz if ((d + 1) % sblock.fs_frag) { 88869800Stomsoft /* 889234178Strasz * The end of the cylinder summary is not a complete 890234178Strasz * block. 89169800Stomsoft */ 892234178Strasz DBG_TRC; 893234178Strasz frag_adjust(d % sblock.fs_fpg, -1); 894234178Strasz for (; (d + 1) % sblock.fs_frag; d--) { 895234178Strasz DBG_PRINT1("d=%jd\n", (intmax_t)d); 896234178Strasz setbit(cg_blksfree(&acg), d % sblock.fs_fpg); 897234178Strasz acg.cg_cs.cs_nffree++; 898234178Strasz sblock.fs_cstotal.cs_nffree++; 89969800Stomsoft } 90069800Stomsoft /* 901234178Strasz * Point "d" to the last fragment of the last 902234178Strasz * (incomplete) block of the cylinder summary. 90369800Stomsoft */ 904234178Strasz d++; 905234189Strasz frag_adjust(d % sblock.fs_fpg, 1); 90669800Stomsoft 907234178Strasz if (isblock(&sblock, cg_blksfree(&acg), 908234178Strasz (d % sblock.fs_fpg) / sblock.fs_frag)) { 909127798Sle DBG_PRINT1("d=%jd\n", (intmax_t)d); 910234178Strasz acg.cg_cs.cs_nffree -= sblock.fs_frag; 91169800Stomsoft acg.cg_cs.cs_nbfree++; 912234178Strasz sblock.fs_cstotal.cs_nffree -= sblock.fs_frag; 91369800Stomsoft sblock.fs_cstotal.cs_nbfree++; 914232548Strasz if (sblock.fs_contigsumsize > 0) { 91569800Stomsoft setbit(cg_clustersfree(&acg), 916234189Strasz (d % sblock.fs_fpg) / sblock.fs_frag); 917232548Strasz if (lcs < sblock.fs_contigsumsize) { 918232548Strasz if (lcs) 91969800Stomsoft cg_clustersum(&acg)[lcs]--; 92069800Stomsoft lcs++; 92169800Stomsoft cg_clustersum(&acg)[lcs]++; 92269800Stomsoft } 92369800Stomsoft } 92469800Stomsoft } 92569800Stomsoft /* 926234178Strasz * Point "d" to the first fragment of the block before 927234178Strasz * the last incomplete block. 92869800Stomsoft */ 929234178Strasz d--; 930234178Strasz } 93169800Stomsoft 932234178Strasz DBG_PRINT1("d=%jd\n", (intmax_t)d); 933234178Strasz for (d = rounddown(d, sblock.fs_frag); d >= osblock.fs_csaddr; 934234178Strasz d -= sblock.fs_frag) { 935234178Strasz DBG_TRC; 936234178Strasz DBG_PRINT1("d=%jd\n", (intmax_t)d); 937234178Strasz setblock(&sblock, cg_blksfree(&acg), 938234178Strasz (d % sblock.fs_fpg) / sblock.fs_frag); 939234178Strasz acg.cg_cs.cs_nbfree++; 940234178Strasz sblock.fs_cstotal.cs_nbfree++; 941234178Strasz if (sblock.fs_contigsumsize > 0) { 942234178Strasz setbit(cg_clustersfree(&acg), 943232548Strasz (d % sblock.fs_fpg) / sblock.fs_frag); 944234178Strasz /* 945234178Strasz * The last cluster size is already set up. 946234178Strasz */ 947234178Strasz if (lcs < sblock.fs_contigsumsize) { 948234178Strasz if (lcs) 949234178Strasz cg_clustersum(&acg)[lcs]--; 950234178Strasz lcs++; 951234178Strasz cg_clustersum(&acg)[lcs]++; 95269800Stomsoft } 95369800Stomsoft } 954234178Strasz } 955234178Strasz *cs = acg.cg_cs; 95669800Stomsoft 95769800Stomsoft /* 958234178Strasz * Now write the former cylinder group containing the cylinder 959234178Strasz * summary back to disk. 96069800Stomsoft */ 961234178Strasz wtfs(fsbtodb(&sblock, cgtod(&sblock, ocscg)), 962234178Strasz (size_t)sblock.fs_cgsize, (void *)&acg, fso, Nflag); 963234178Strasz DBG_PRINT0("oscg written\n"); 964234178Strasz DBG_DUMP_CG(&sblock, "old summary cg", &acg); 96569800Stomsoft 96669800Stomsoft /* 967234178Strasz * Find the beginning of the new cylinder group containing the 968234178Strasz * cylinder summary. 96969800Stomsoft */ 970234178Strasz sblock.fs_csaddr = cgdmin(&sblock, osblock.fs_ncg); 971234178Strasz ncscg = dtog(&sblock, sblock.fs_csaddr); 972234178Strasz cs = fscs + ncscg; 97369800Stomsoft 97469800Stomsoft /* 975234178Strasz * If Nflag is specified, we would now read random data instead 976234178Strasz * of an empty cg structure from disk. So we can't simulate that 977234178Strasz * part for now. 97869800Stomsoft */ 979234178Strasz if (Nflag) { 980234178Strasz DBG_PRINT0("nscg update skipped\n"); 981234178Strasz DBG_LEAVE; 982234178Strasz return; 98369800Stomsoft } 98469800Stomsoft 98569800Stomsoft /* 986234178Strasz * Read the future cylinder group containing the cylinder 987234178Strasz * summary from disk, and make a copy. 98869800Stomsoft */ 989234178Strasz rdfs(fsbtodb(&sblock, cgtod(&sblock, ncscg)), 990234178Strasz (size_t)sblock.fs_cgsize, (void *)&aocg, fsi); 991234178Strasz DBG_PRINT0("nscg read\n"); 992234178Strasz DBG_DUMP_CG(&sblock, "new summary cg", &aocg); 99369800Stomsoft 994234178Strasz memcpy((void *)&cgun1, (void *)&cgun2, sizeof(cgun2)); 995234178Strasz 99669800Stomsoft /* 997234178Strasz * Allocate all complete blocks used by the new cylinder 998234178Strasz * summary. 99969800Stomsoft */ 1000234178Strasz for (d = sblock.fs_csaddr; d + sblock.fs_frag <= 1001234178Strasz sblock.fs_csaddr + (sblock.fs_cssize / sblock.fs_fsize); 1002234178Strasz d += sblock.fs_frag) { 1003234178Strasz clrblock(&sblock, cg_blksfree(&acg), 1004234178Strasz (d % sblock.fs_fpg) / sblock.fs_frag); 1005234178Strasz acg.cg_cs.cs_nbfree--; 1006234178Strasz sblock.fs_cstotal.cs_nbfree--; 1007234178Strasz if (sblock.fs_contigsumsize > 0) { 1008234178Strasz clrbit(cg_clustersfree(&acg), 1009234178Strasz (d % sblock.fs_fpg) / sblock.fs_frag); 101069800Stomsoft } 101169800Stomsoft } 101269800Stomsoft 101369800Stomsoft /* 1014234178Strasz * Allocate all fragments used by the cylinder summary in the 1015234178Strasz * last block. 101669800Stomsoft */ 1017234189Strasz if (d < sblock.fs_csaddr + (sblock.fs_cssize / sblock.fs_fsize)) { 1018234178Strasz for (; d - sblock.fs_csaddr < 1019234178Strasz sblock.fs_cssize/sblock.fs_fsize; d++) { 1020234178Strasz clrbit(cg_blksfree(&acg), d % sblock.fs_fpg); 1021234178Strasz acg.cg_cs.cs_nffree--; 1022234178Strasz sblock.fs_cstotal.cs_nffree--; 102369800Stomsoft } 1024234178Strasz acg.cg_cs.cs_nbfree--; 1025234178Strasz acg.cg_cs.cs_nffree += sblock.fs_frag; 1026234178Strasz sblock.fs_cstotal.cs_nbfree--; 1027234178Strasz sblock.fs_cstotal.cs_nffree += sblock.fs_frag; 1028234178Strasz if (sblock.fs_contigsumsize > 0) 1029234178Strasz clrbit(cg_clustersfree(&acg), 1030234178Strasz (d % sblock.fs_fpg) / sblock.fs_frag); 103169800Stomsoft 1032234178Strasz frag_adjust(d % sblock.fs_fpg, 1); 103369800Stomsoft } 103469800Stomsoft /* 1035234178Strasz * XXX Handle the cluster statistics here in the case this 1036234178Strasz * cylinder group is now almost full, and the remaining 1037234178Strasz * space is less then the maximum cluster size. This is 1038234178Strasz * probably not needed, as you would hardly find a file 1039234178Strasz * system which has only MAXCSBUFS+FS_MAXCONTIG of free 1040234178Strasz * space right behind the cylinder group information in 1041234178Strasz * any new cylinder group. 104269800Stomsoft */ 104369800Stomsoft 1044234178Strasz /* 1045234178Strasz * Update our statistics in the cylinder summary. 1046234178Strasz */ 104769800Stomsoft *cs = acg.cg_cs; 104869800Stomsoft 104969800Stomsoft /* 1050234178Strasz * Write the new cylinder group containing the cylinder summary 1051234178Strasz * back to disk. 105269800Stomsoft */ 1053234178Strasz wtfs(fsbtodb(&sblock, cgtod(&sblock, ncscg)), 1054234178Strasz (size_t)sblock.fs_cgsize, (void *)&acg, fso, Nflag); 1055234178Strasz DBG_PRINT0("nscg written\n"); 1056232548Strasz DBG_DUMP_CG(&sblock, "new summary cg", &acg); 105769800Stomsoft 105869800Stomsoft DBG_LEAVE; 105969800Stomsoft return; 106069800Stomsoft} 106169800Stomsoft 106269800Stomsoft/* 106369800Stomsoft * Here we read some block(s) from disk. 106469800Stomsoft */ 106569800Stomsoftstatic void 106698542Smckusickrdfs(ufs2_daddr_t bno, size_t size, void *bf, int fsi) 106769800Stomsoft{ 106869800Stomsoft DBG_FUNC("rdfs") 106977885Stomsoft ssize_t n; 107069800Stomsoft 107169800Stomsoft DBG_ENTER; 107269800Stomsoft 1073232548Strasz if (bno < 0) 1074140351Scharnier err(32, "rdfs: attempting to read negative block number"); 1075232548Strasz if (lseek(fsi, (off_t)bno * DEV_BSIZE, 0) < 0) 1076127798Sle err(33, "rdfs: seek error: %jd", (intmax_t)bno); 107777885Stomsoft n = read(fsi, bf, size); 1078232548Strasz if (n != (ssize_t)size) 1079127798Sle err(34, "rdfs: read error: %jd", (intmax_t)bno); 108069800Stomsoft 108169800Stomsoft DBG_LEAVE; 108269800Stomsoft return; 108369800Stomsoft} 108469800Stomsoft 108569800Stomsoft/* 108669800Stomsoft * Here we write some block(s) to disk. 108769800Stomsoft */ 108869800Stomsoftstatic void 108998542Smckusickwtfs(ufs2_daddr_t bno, size_t size, void *bf, int fso, unsigned int Nflag) 109069800Stomsoft{ 109169800Stomsoft DBG_FUNC("wtfs") 109277885Stomsoft ssize_t n; 109369800Stomsoft 109469800Stomsoft DBG_ENTER; 109569800Stomsoft 109669800Stomsoft if (Nflag) { 109769800Stomsoft DBG_LEAVE; 109869800Stomsoft return; 109969800Stomsoft } 1100232548Strasz if (lseek(fso, (off_t)bno * DEV_BSIZE, SEEK_SET) < 0) 110169926Stomsoft err(35, "wtfs: seek error: %ld", (long)bno); 110277885Stomsoft n = write(fso, bf, size); 1103232548Strasz if (n != (ssize_t)size) 110469926Stomsoft err(36, "wtfs: write error: %ld", (long)bno); 110569800Stomsoft 110669800Stomsoft DBG_LEAVE; 110769800Stomsoft return; 110869800Stomsoft} 110969800Stomsoft 111069800Stomsoft/* 1111114067Sschweikh * Here we check if all frags of a block are free. For more details again 111269800Stomsoft * please see the source of newfs(8), as this function is taken over almost 111369800Stomsoft * unchanged. 111469800Stomsoft */ 111569800Stomsoftstatic int 111669800Stomsoftisblock(struct fs *fs, unsigned char *cp, int h) 111769800Stomsoft{ 111869800Stomsoft DBG_FUNC("isblock") 1119232548Strasz unsigned char mask; 112069800Stomsoft 112169800Stomsoft DBG_ENTER; 112269800Stomsoft 112369800Stomsoft switch (fs->fs_frag) { 112469800Stomsoft case 8: 112569800Stomsoft DBG_LEAVE; 112669800Stomsoft return (cp[h] == 0xff); 112769800Stomsoft case 4: 112869800Stomsoft mask = 0x0f << ((h & 0x1) << 2); 112969800Stomsoft DBG_LEAVE; 113069800Stomsoft return ((cp[h >> 1] & mask) == mask); 113169800Stomsoft case 2: 113269800Stomsoft mask = 0x03 << ((h & 0x3) << 1); 113369800Stomsoft DBG_LEAVE; 113469800Stomsoft return ((cp[h >> 2] & mask) == mask); 113569800Stomsoft case 1: 113669800Stomsoft mask = 0x01 << (h & 0x7); 113769800Stomsoft DBG_LEAVE; 113869800Stomsoft return ((cp[h >> 3] & mask) == mask); 113969800Stomsoft default: 114069800Stomsoft fprintf(stderr, "isblock bad fs_frag %d\n", fs->fs_frag); 114169800Stomsoft DBG_LEAVE; 114269800Stomsoft return (0); 114369800Stomsoft } 114469800Stomsoft} 114569800Stomsoft 114669800Stomsoft/* 114769800Stomsoft * Here we allocate a complete block in the block map. For more details again 1148114067Sschweikh * please see the source of newfs(8), as this function is taken over almost 114969800Stomsoft * unchanged. 115069800Stomsoft */ 115169800Stomsoftstatic void 115269800Stomsoftclrblock(struct fs *fs, unsigned char *cp, int h) 115369800Stomsoft{ 115469800Stomsoft DBG_FUNC("clrblock") 115569800Stomsoft 115669800Stomsoft DBG_ENTER; 115769800Stomsoft 115869800Stomsoft switch ((fs)->fs_frag) { 115969800Stomsoft case 8: 116069800Stomsoft cp[h] = 0; 116169800Stomsoft break; 116269800Stomsoft case 4: 116369800Stomsoft cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); 116469800Stomsoft break; 116569800Stomsoft case 2: 116669800Stomsoft cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); 116769800Stomsoft break; 116869800Stomsoft case 1: 116969800Stomsoft cp[h >> 3] &= ~(0x01 << (h & 0x7)); 117069800Stomsoft break; 117169800Stomsoft default: 117269926Stomsoft warnx("clrblock bad fs_frag %d", fs->fs_frag); 117369800Stomsoft break; 117469800Stomsoft } 117569800Stomsoft 117669800Stomsoft DBG_LEAVE; 117769800Stomsoft return; 117869800Stomsoft} 117969800Stomsoft 118069800Stomsoft/* 118169800Stomsoft * Here we free a complete block in the free block map. For more details again 1182114067Sschweikh * please see the source of newfs(8), as this function is taken over almost 118369800Stomsoft * unchanged. 118469800Stomsoft */ 118569800Stomsoftstatic void 118669800Stomsoftsetblock(struct fs *fs, unsigned char *cp, int h) 118769800Stomsoft{ 118869800Stomsoft DBG_FUNC("setblock") 118969800Stomsoft 119069800Stomsoft DBG_ENTER; 119169800Stomsoft 119269800Stomsoft switch (fs->fs_frag) { 119369800Stomsoft case 8: 119469800Stomsoft cp[h] = 0xff; 119569800Stomsoft break; 119669800Stomsoft case 4: 119769800Stomsoft cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); 119869800Stomsoft break; 119969800Stomsoft case 2: 120069800Stomsoft cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); 120169800Stomsoft break; 120269800Stomsoft case 1: 120369800Stomsoft cp[h >> 3] |= (0x01 << (h & 0x7)); 120469800Stomsoft break; 120569800Stomsoft default: 120669926Stomsoft warnx("setblock bad fs_frag %d", fs->fs_frag); 120769800Stomsoft break; 120869800Stomsoft } 120969800Stomsoft 121069800Stomsoft DBG_LEAVE; 121169800Stomsoft return; 121269800Stomsoft} 121369800Stomsoft 121469800Stomsoft/* 121569800Stomsoft * Figure out how many lines our current terminal has. For more details again 1216114067Sschweikh * please see the source of newfs(8), as this function is taken over almost 121769800Stomsoft * unchanged. 121869800Stomsoft */ 121969800Stomsoftstatic int 122069800Stomsoftcharsperline(void) 122169800Stomsoft{ 122269800Stomsoft DBG_FUNC("charsperline") 1223232548Strasz int columns; 1224232548Strasz char *cp; 1225232548Strasz struct winsize ws; 122669800Stomsoft 122769800Stomsoft DBG_ENTER; 122869800Stomsoft 122969800Stomsoft columns = 0; 1230232548Strasz if (ioctl(0, TIOCGWINSZ, &ws) != -1) 123169800Stomsoft columns = ws.ws_col; 1232232548Strasz if (columns == 0 && (cp = getenv("COLUMNS"))) 123369800Stomsoft columns = atoi(cp); 1234232548Strasz if (columns == 0) 123569800Stomsoft columns = 80; /* last resort */ 123669800Stomsoft 123769800Stomsoft DBG_LEAVE; 123869800Stomsoft return columns; 123969800Stomsoft} 124069800Stomsoft 1241114936Sgrog/* 1242233656Strasz * Get the size of the partition. 1243114936Sgrog */ 1244114936Sgrogstatic void 1245114936Sgrogget_dev_size(int fd, int *size) 1246114936Sgrog{ 1247232548Strasz int sectorsize; 1248232548Strasz off_t mediasize; 1249114936Sgrog 1250232548Strasz if (ioctl(fd, DIOCGSECTORSIZE, §orsize) == -1) 1251232548Strasz err(1,"DIOCGSECTORSIZE"); 1252232548Strasz if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) == -1) 1253232548Strasz err(1,"DIOCGMEDIASIZE"); 1254114936Sgrog 1255232548Strasz if (sectorsize <= 0) 1256232548Strasz errx(1, "bogus sectorsize: %d", sectorsize); 1257114936Sgrog 1258232548Strasz *size = mediasize / sectorsize; 1259114936Sgrog} 1260114936Sgrog 126169800Stomsoft/* 1262232548Strasz * growfs(8) is a utility which allows to increase the size of an existing 1263223652Strasz * ufs file system. Currently this can only be done on unmounted file system. 1264114067Sschweikh * It recognizes some command line options to specify the new desired size, 1265223652Strasz * and it does some basic checkings. The old file system size is determined 1266114067Sschweikh * and after some more checks like we can really access the new last block 126769800Stomsoft * on the disk etc. we calculate the new parameters for the superblock. After 1268233656Strasz * having done this we just call growfs() which will do the work. 126969800Stomsoft * We still have to provide support for snapshots. Therefore we first have to 1270114067Sschweikh * understand what data structures are always replicated in the snapshot on 1271114067Sschweikh * creation, for all other blocks we touch during our procedure, we have to 127269926Stomsoft * keep the old blocks unchanged somewhere available for the snapshots. If we 1273114067Sschweikh * are lucky, then we only have to handle our blocks to be relocated in that 127469800Stomsoft * way. 1275114067Sschweikh * Also we have to consider in what order we actually update the critical 1276223652Strasz * data structures of the file system to make sure, that in case of a disaster 127769800Stomsoft * fsck(8) is still able to restore any lost data. 1278114067Sschweikh * The foreseen last step then will be to provide for growing even mounted 1279223652Strasz * file systems. There we have to extend the mount() system call to provide 1280223652Strasz * userland access to the file system locking facility. 128169800Stomsoft */ 128269800Stomsoftint 128369800Stomsoftmain(int argc, char **argv) 128469800Stomsoft{ 128569800Stomsoft DBG_FUNC("main") 1286233656Strasz char *device, *special; 1287232548Strasz int ch; 1288232548Strasz unsigned int size = 0; 1289232548Strasz size_t len; 1290232548Strasz unsigned int Nflag = 0; 1291232548Strasz int ExpertFlag = 0; 1292232548Strasz struct stat st; 1293232548Strasz int i, fsi, fso; 1294232548Strasz u_int32_t p_size; 1295232548Strasz char reply[5]; 1296232548Strasz int j; 129769800Stomsoft 129869800Stomsoft DBG_ENTER; 129969800Stomsoft 1300232548Strasz while ((ch = getopt(argc, argv, "Ns:vy")) != -1) { 130169800Stomsoft switch(ch) { 130269800Stomsoft case 'N': 1303232548Strasz Nflag = 1; 130469800Stomsoft break; 130569800Stomsoft case 's': 1306232548Strasz size = (size_t)atol(optarg); 1307232548Strasz if (size < 1) 130869926Stomsoft usage(); 130969800Stomsoft break; 131069800Stomsoft case 'v': /* for compatibility to newfs */ 131169800Stomsoft break; 131269800Stomsoft case 'y': 1313232548Strasz ExpertFlag = 1; 131469800Stomsoft break; 131569800Stomsoft case '?': 131669800Stomsoft /* FALLTHROUGH */ 131769800Stomsoft default: 131869926Stomsoft usage(); 131969800Stomsoft } 132069800Stomsoft } 132169800Stomsoft argc -= optind; 132269800Stomsoft argv += optind; 132369800Stomsoft 1324232548Strasz if (argc != 1) 132569926Stomsoft usage(); 132669800Stomsoft 1327232548Strasz device = *argv; 1328232548Strasz 132969800Stomsoft /* 133069800Stomsoft * Now try to guess the (raw)device name. 133169800Stomsoft */ 133269800Stomsoft if (0 == strrchr(device, '/')) { 133369800Stomsoft /* 133469800Stomsoft * No path prefix was given, so try in that order: 133569800Stomsoft * /dev/r%s 133669800Stomsoft * /dev/%s 133769800Stomsoft * /dev/vinum/r%s 133869800Stomsoft * /dev/vinum/%s. 1339114067Sschweikh * 1340114067Sschweikh * FreeBSD now doesn't distinguish between raw and block 134169800Stomsoft * devices any longer, but it should still work this way. 134269800Stomsoft */ 1343232548Strasz len = strlen(device) + strlen(_PATH_DEV) + 2 + strlen("vinum/"); 1344232548Strasz special = (char *)malloc(len); 1345232548Strasz if (special == NULL) 134669926Stomsoft errx(1, "malloc failed"); 134769800Stomsoft snprintf(special, len, "%sr%s", _PATH_DEV, device); 134869800Stomsoft if (stat(special, &st) == -1) { 134969800Stomsoft snprintf(special, len, "%s%s", _PATH_DEV, device); 135069800Stomsoft if (stat(special, &st) == -1) { 135169800Stomsoft snprintf(special, len, "%svinum/r%s", 135269800Stomsoft _PATH_DEV, device); 135369800Stomsoft if (stat(special, &st) == -1) { 135469800Stomsoft /* For now this is the 'last resort' */ 135569800Stomsoft snprintf(special, len, "%svinum/%s", 135669800Stomsoft _PATH_DEV, device); 135769800Stomsoft } 135869800Stomsoft } 135969800Stomsoft } 136069800Stomsoft device = special; 136169800Stomsoft } 136269800Stomsoft 136369800Stomsoft /* 136469800Stomsoft * Try to access our devices for writing ... 136569800Stomsoft */ 136669800Stomsoft if (Nflag) { 136769800Stomsoft fso = -1; 136869800Stomsoft } else { 136969800Stomsoft fso = open(device, O_WRONLY); 1370232548Strasz if (fso < 0) 137169926Stomsoft err(1, "%s", device); 137269800Stomsoft } 137369800Stomsoft 137469800Stomsoft /* 137569800Stomsoft * ... and reading. 137669800Stomsoft */ 137769800Stomsoft fsi = open(device, O_RDONLY); 1378232548Strasz if (fsi < 0) 137969926Stomsoft err(1, "%s", device); 138069800Stomsoft 138169800Stomsoft /* 1382233656Strasz * Try to guess the slice if not specified. This code should guess 1383233656Strasz * the right thing and avoid to bother the user with the task 1384233656Strasz * of specifying the option -v on vinum volumes. 138569800Stomsoft */ 1386233656Strasz get_dev_size(fsi, &p_size); 138769800Stomsoft 138869800Stomsoft /* 1389223652Strasz * Check if that partition is suitable for growing a file system. 139069800Stomsoft */ 1391232548Strasz if (p_size < 1) 139269926Stomsoft errx(1, "partition is unavailable"); 139369800Stomsoft 139469800Stomsoft /* 139569800Stomsoft * Read the current superblock, and take a backup. 139669800Stomsoft */ 139798542Smckusick for (i = 0; sblock_try[i] != -1; i++) { 139898542Smckusick sblockloc = sblock_try[i] / DEV_BSIZE; 139998542Smckusick rdfs(sblockloc, (size_t)SBLOCKSIZE, (void *)&(osblock), fsi); 140098542Smckusick if ((osblock.fs_magic == FS_UFS1_MAGIC || 1401232548Strasz (osblock.fs_magic == FS_UFS2_MAGIC && 1402232548Strasz osblock.fs_sblockloc == sblock_try[i])) && 140398542Smckusick osblock.fs_bsize <= MAXBSIZE && 1404127798Sle osblock.fs_bsize >= (int32_t) sizeof(struct fs)) 140598542Smckusick break; 140698542Smckusick } 1407232548Strasz if (sblock_try[i] == -1) 140869926Stomsoft errx(1, "superblock not recognized"); 140969800Stomsoft memcpy((void *)&fsun1, (void *)&fsun2, sizeof(fsun2)); 141069800Stomsoft 141169800Stomsoft DBG_OPEN("/tmp/growfs.debug"); /* already here we need a superblock */ 1412232548Strasz DBG_DUMP_FS(&sblock, "old sblock"); 141369800Stomsoft 141469800Stomsoft /* 1415233656Strasz * Determine size to grow to. Default to the device size. 141669800Stomsoft */ 1417114936Sgrog sblock.fs_size = dbtofsb(&osblock, p_size); 141869800Stomsoft if (size != 0) { 1419232548Strasz if (size > p_size) 1420140351Scharnier errx(1, "there is not enough space (%d < %d)", 1421114936Sgrog p_size, size); 1422114067Sschweikh sblock.fs_size = dbtofsb(&osblock, size); 142369800Stomsoft } 142469800Stomsoft 142569800Stomsoft /* 142669800Stomsoft * Are we really growing ? 142769800Stomsoft */ 1428232548Strasz if (osblock.fs_size >= sblock.fs_size) { 1429127798Sle errx(1, "we are not growing (%jd->%jd)", 1430127798Sle (intmax_t)osblock.fs_size, (intmax_t)sblock.fs_size); 143169800Stomsoft } 143269800Stomsoft 143369800Stomsoft /* 143469800Stomsoft * Check if we find an active snapshot. 143569800Stomsoft */ 1436232548Strasz if (ExpertFlag == 0) { 1437232548Strasz for (j = 0; j < FSMAXSNAP; j++) { 1438232548Strasz if (sblock.fs_snapinum[j]) { 1439223652Strasz errx(1, "active snapshot found in file system; " 1440223429Strasz "please remove all snapshots before " 1441140351Scharnier "using growfs"); 144269800Stomsoft } 1443232548Strasz if (!sblock.fs_snapinum[j]) /* list is dense */ 144469800Stomsoft break; 144569800Stomsoft } 144669800Stomsoft } 144769800Stomsoft 144869800Stomsoft if (ExpertFlag == 0 && Nflag == 0) { 144969800Stomsoft printf("We strongly recommend you to make a backup " 1450223652Strasz "before growing the file system.\n" 1451223429Strasz "Did you backup your data (Yes/No)? "); 145277885Stomsoft fgets(reply, (int)sizeof(reply), stdin); 145369800Stomsoft if (strcmp(reply, "Yes\n")){ 1454223429Strasz printf("\nNothing done\n"); 145569800Stomsoft exit (0); 1456114067Sschweikh } 145769800Stomsoft } 145869800Stomsoft 1459223652Strasz printf("New file system size is %jd frags\n", (intmax_t)sblock.fs_size); 146069800Stomsoft 146169800Stomsoft /* 1462223652Strasz * Try to access our new last block in the file system. Even if we 146369800Stomsoft * later on realize we have to abort our operation, on that block 146469800Stomsoft * there should be no data, so we can't destroy something yet. 146569800Stomsoft */ 1466232548Strasz wtfs((ufs2_daddr_t)p_size - 1, (size_t)DEV_BSIZE, (void *)&sblock, 146798542Smckusick fso, Nflag); 146869800Stomsoft 146969800Stomsoft /* 147069800Stomsoft * Now calculate new superblock values and check for reasonable 1471223652Strasz * bound for new file system size: 1472233656Strasz * fs_size: is derived from user input 147369800Stomsoft * fs_dsize: should get updated in the routines creating or 147469800Stomsoft * updating the cylinder groups on the fly 147569800Stomsoft * fs_cstotal: should get updated in the routines creating or 147669800Stomsoft * updating the cylinder groups 147769800Stomsoft */ 147869800Stomsoft 147969800Stomsoft /* 1480223652Strasz * Update the number of cylinders and cylinder groups in the file system. 148169800Stomsoft */ 148298542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) { 148398542Smckusick sblock.fs_old_ncyl = 148498542Smckusick sblock.fs_size * sblock.fs_old_nspf / sblock.fs_old_spc; 148598542Smckusick if (sblock.fs_size * sblock.fs_old_nspf > 148698542Smckusick sblock.fs_old_ncyl * sblock.fs_old_spc) 148798542Smckusick sblock.fs_old_ncyl++; 148869800Stomsoft } 148998542Smckusick sblock.fs_ncg = howmany(sblock.fs_size, sblock.fs_fpg); 149069800Stomsoft 149198542Smckusick if (sblock.fs_size % sblock.fs_fpg != 0 && 149298542Smckusick sblock.fs_size % sblock.fs_fpg < cgdmin(&sblock, sblock.fs_ncg)) { 149369800Stomsoft /* 149469800Stomsoft * The space in the new last cylinder group is too small, 149569800Stomsoft * so revert back. 149669800Stomsoft */ 149769800Stomsoft sblock.fs_ncg--; 149898542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 149998542Smckusick sblock.fs_old_ncyl = sblock.fs_ncg * sblock.fs_old_cpg; 1500127798Sle printf("Warning: %jd sector(s) cannot be allocated.\n", 1501127798Sle (intmax_t)fsbtodb(&sblock, sblock.fs_size % sblock.fs_fpg)); 150298542Smckusick sblock.fs_size = sblock.fs_ncg * sblock.fs_fpg; 150369800Stomsoft } 150469800Stomsoft 150569800Stomsoft /* 150669800Stomsoft * Update the space for the cylinder group summary information in the 150769800Stomsoft * respective cylinder group data area. 150869800Stomsoft */ 150969800Stomsoft sblock.fs_cssize = 151069800Stomsoft fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum)); 1511114067Sschweikh 1512232548Strasz if (osblock.fs_size >= sblock.fs_size) 151369926Stomsoft errx(1, "not enough new space"); 151469800Stomsoft 151569800Stomsoft DBG_PRINT0("sblock calculated\n"); 151669800Stomsoft 151769800Stomsoft /* 151869800Stomsoft * Ok, everything prepared, so now let's do the tricks. 151969800Stomsoft */ 152069800Stomsoft growfs(fsi, fso, Nflag); 152169800Stomsoft 152269800Stomsoft close(fsi); 1523232548Strasz if (fso > -1) 1524232548Strasz close(fso); 152569800Stomsoft 152669800Stomsoft DBG_CLOSE; 152769800Stomsoft 152869800Stomsoft DBG_LEAVE; 152969800Stomsoft return 0; 153069800Stomsoft} 153169800Stomsoft 153269800Stomsoft/* 153369800Stomsoft * Dump a line of usage. 153469800Stomsoft */ 153569800Stomsoftstatic void 153669926Stomsoftusage(void) 1537114067Sschweikh{ 153869800Stomsoft DBG_FUNC("usage") 153969800Stomsoft 154069800Stomsoft DBG_ENTER; 154169800Stomsoft 154269926Stomsoft fprintf(stderr, "usage: growfs [-Ny] [-s size] special\n"); 154369926Stomsoft 154469800Stomsoft DBG_LEAVE; 154569926Stomsoft exit(1); 154669800Stomsoft} 154769800Stomsoft 154869800Stomsoft/* 1549114067Sschweikh * This updates most parameters and the bitmap related to cluster. We have to 1550114067Sschweikh * assume that sblock, osblock, acg are set up. 155169800Stomsoft */ 155269800Stomsoftstatic void 155369800Stomsoftupdclst(int block) 1554114067Sschweikh{ 155569800Stomsoft DBG_FUNC("updclst") 1556232548Strasz static int lcs = 0; 155769800Stomsoft 155869800Stomsoft DBG_ENTER; 155969800Stomsoft 1560232548Strasz if (sblock.fs_contigsumsize < 1) /* no clustering */ 156169800Stomsoft return; 156269800Stomsoft /* 156369800Stomsoft * update cluster allocation map 156469800Stomsoft */ 156569800Stomsoft setbit(cg_clustersfree(&acg), block); 156669800Stomsoft 156769800Stomsoft /* 156869800Stomsoft * update cluster summary table 156969800Stomsoft */ 1570232548Strasz if (!lcs) { 157169800Stomsoft /* 157269800Stomsoft * calculate size for the trailing cluster 157369800Stomsoft */ 1574232548Strasz for (block--; lcs < sblock.fs_contigsumsize; block--, lcs++ ) { 1575232548Strasz if (isclr(cg_clustersfree(&acg), block)) 157669800Stomsoft break; 157769800Stomsoft } 1578114067Sschweikh } 1579232548Strasz if (lcs < sblock.fs_contigsumsize) { 1580232548Strasz if (lcs) 158169800Stomsoft cg_clustersum(&acg)[lcs]--; 158269800Stomsoft lcs++; 158369800Stomsoft cg_clustersum(&acg)[lcs]++; 158469800Stomsoft } 158569800Stomsoft 158669800Stomsoft DBG_LEAVE; 158769800Stomsoft return; 158869800Stomsoft} 1589