growfs.c revision 203770
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 203770 2010-02-11 06:42:08Z mckusick $"); 5169800Stomsoft 5269800Stomsoft/* ********************************************************** INCLUDES ***** */ 5369800Stomsoft#include <sys/param.h> 5469800Stomsoft#include <sys/disklabel.h> 5569800Stomsoft#include <sys/ioctl.h> 5669800Stomsoft#include <sys/stat.h> 57114936Sgrog#include <sys/disk.h> 5869800Stomsoft 5969800Stomsoft#include <stdio.h> 6069800Stomsoft#include <paths.h> 6169800Stomsoft#include <ctype.h> 6269800Stomsoft#include <err.h> 6369800Stomsoft#include <fcntl.h> 64103949Smike#include <limits.h> 6569800Stomsoft#include <stdlib.h> 66127798Sle#include <stdint.h> 6769800Stomsoft#include <string.h> 68127821Sbde#include <time.h> 6969800Stomsoft#include <unistd.h> 7069800Stomsoft#include <ufs/ufs/dinode.h> 7169800Stomsoft#include <ufs/ffs/fs.h> 7269800Stomsoft 7369800Stomsoft#include "debug.h" 7469800Stomsoft 7569800Stomsoft/* *************************************************** GLOBALS & TYPES ***** */ 7669800Stomsoft#ifdef FS_DEBUG 7769800Stomsoftint _dbg_lvl_ = (DL_INFO); /* DL_TRC */ 7869800Stomsoft#endif /* FS_DEBUG */ 7969800Stomsoft 8069800Stomsoftstatic union { 8169800Stomsoft struct fs fs; 8298542Smckusick char pad[SBLOCKSIZE]; 8369800Stomsoft} fsun1, fsun2; 8469800Stomsoft#define sblock fsun1.fs /* the new superblock */ 8569800Stomsoft#define osblock fsun2.fs /* the old superblock */ 8669800Stomsoft 8798542Smckusick/* 8898542Smckusick * Possible superblock locations ordered from most to least likely. 8998542Smckusick */ 9098542Smckusickstatic int sblock_try[] = SBLOCKSEARCH; 9198542Smckusickstatic ufs2_daddr_t sblockloc; 9298542Smckusick 9369800Stomsoftstatic union { 9469800Stomsoft struct cg cg; 9569800Stomsoft char pad[MAXBSIZE]; 9669800Stomsoft} cgun1, cgun2; 9769800Stomsoft#define acg cgun1.cg /* a cylinder cgroup (new) */ 9869800Stomsoft#define aocg cgun2.cg /* an old cylinder group */ 9969800Stomsoft 10098542Smckusickstatic char ablk[MAXBSIZE]; /* a block */ 10169800Stomsoft 10298542Smckusickstatic struct csum *fscs; /* cylinder summary */ 10369800Stomsoft 10498542Smckusickunion dinode { 10598542Smckusick struct ufs1_dinode dp1; 10698542Smckusick struct ufs2_dinode dp2; 10769800Stomsoft}; 10898542Smckusick#define DIP(dp, field) \ 10998542Smckusick ((sblock.fs_magic == FS_UFS1_MAGIC) ? \ 110127798Sle (uint32_t)(dp)->dp1.field : (dp)->dp2.field) 111132832Sle#define DIP_SET(dp, field, val) do { \ 112132832Sle if (sblock.fs_magic == FS_UFS1_MAGIC) \ 113132832Sle (dp)->dp1.field = (val); \ 114132832Sle else \ 115132832Sle (dp)->dp2.field = (val); \ 116132832Sle } while (0) 11798542Smckusickstatic ufs2_daddr_t inoblk; /* inode block address */ 11898542Smckusickstatic char inobuf[MAXBSIZE]; /* inode block */ 119127798Sleino_t maxino; /* last valid inode */ 120114936Sgrogstatic int unlabeled; /* unlabeled partition, e.g. vinum volume etc. */ 12169800Stomsoft 12269800Stomsoft/* 123114067Sschweikh * An array of elements of type struct gfs_bpp describes all blocks to 12469800Stomsoft * be relocated in order to free the space needed for the cylinder group 12569800Stomsoft * summary for all cylinder groups located in the first cylinder group. 12669800Stomsoft */ 12769800Stomsoftstruct gfs_bpp { 12898542Smckusick ufs2_daddr_t old; /* old block number */ 12998542Smckusick ufs2_daddr_t new; /* new block number */ 13069800Stomsoft#define GFS_FL_FIRST 1 13169800Stomsoft#define GFS_FL_LAST 2 13277885Stomsoft unsigned int flags; /* special handling required */ 13369800Stomsoft int found; /* how many references were updated */ 13469800Stomsoft}; 13569800Stomsoft 13669800Stomsoft/* ******************************************************** PROTOTYPES ***** */ 13777885Stomsoftstatic void growfs(int, int, unsigned int); 13898542Smckusickstatic void rdfs(ufs2_daddr_t, size_t, void *, int); 13998542Smckusickstatic void wtfs(ufs2_daddr_t, size_t, void *, int, unsigned int); 14098542Smckusickstatic ufs2_daddr_t alloc(void); 14169800Stomsoftstatic int charsperline(void); 14269926Stomsoftstatic void usage(void); 14369800Stomsoftstatic int isblock(struct fs *, unsigned char *, int); 14469800Stomsoftstatic void clrblock(struct fs *, unsigned char *, int); 14569800Stomsoftstatic void setblock(struct fs *, unsigned char *, int); 14677885Stomsoftstatic void initcg(int, time_t, int, unsigned int); 14777885Stomsoftstatic void updjcg(int, time_t, int, int, unsigned int); 14877885Stomsoftstatic void updcsloc(time_t, int, int, unsigned int); 14969800Stomsoftstatic struct disklabel *get_disklabel(int); 15077885Stomsoftstatic void return_disklabel(int, struct disklabel *, unsigned int); 15198542Smckusickstatic union dinode *ginode(ino_t, int, int); 15298542Smckusickstatic void frag_adjust(ufs2_daddr_t, int); 15398542Smckusickstatic int cond_bl_upd(ufs2_daddr_t *, struct gfs_bpp *, int, int, 15498542Smckusick unsigned int); 15569800Stomsoftstatic void updclst(int); 15677885Stomsoftstatic void updrefs(int, ino_t, struct gfs_bpp *, int, int, unsigned int); 15798542Smckusickstatic void indirchk(ufs_lbn_t, ufs_lbn_t, ufs2_daddr_t, ufs_lbn_t, 15898542Smckusick struct gfs_bpp *, int, int, unsigned int); 159114936Sgrogstatic void get_dev_size(int, int *); 16069800Stomsoft 16169800Stomsoft/* ************************************************************ growfs ***** */ 16269800Stomsoft/* 163114067Sschweikh * Here we actually start growing the file system. We basically read the 164114067Sschweikh * cylinder summary from the first cylinder group as we want to update 165114067Sschweikh * this on the fly during our various operations. First we handle the 16669800Stomsoft * changes in the former last cylinder group. Afterwards we create all new 167114067Sschweikh * cylinder groups. Now we handle the cylinder group containing the 168114067Sschweikh * cylinder summary which might result in a relocation of the whole 169114067Sschweikh * structure. In the end we write back the updated cylinder summary, the 17069800Stomsoft * new superblock, and slightly patched versions of the super block 17169800Stomsoft * copies. 17269800Stomsoft */ 17369800Stomsoftstatic void 17477885Stomsoftgrowfs(int fsi, int fso, unsigned int Nflag) 17569800Stomsoft{ 17669800Stomsoft DBG_FUNC("growfs") 17769800Stomsoft time_t utime; 178203770Smckusick uint cylno; 179203770Smckusick int i, j, width; 18069800Stomsoft char tmpbuf[100]; 18169800Stomsoft#ifdef FSIRAND 18269800Stomsoft static int randinit=0; 18369800Stomsoft 18469800Stomsoft DBG_ENTER; 18569800Stomsoft 18669800Stomsoft if (!randinit) { 18769800Stomsoft randinit = 1; 18869800Stomsoft srandomdev(); 18969800Stomsoft } 19069800Stomsoft#else /* not FSIRAND */ 19169800Stomsoft 19269800Stomsoft DBG_ENTER; 19369800Stomsoft 19469800Stomsoft#endif /* FSIRAND */ 19569800Stomsoft time(&utime); 19669800Stomsoft 19769800Stomsoft /* 19869800Stomsoft * Get the cylinder summary into the memory. 19969800Stomsoft */ 20077885Stomsoft fscs = (struct csum *)calloc((size_t)1, (size_t)sblock.fs_cssize); 20169926Stomsoft if(fscs == NULL) { 20269926Stomsoft errx(1, "calloc failed"); 20369926Stomsoft } 20469800Stomsoft for (i = 0; i < osblock.fs_cssize; i += osblock.fs_bsize) { 20569800Stomsoft rdfs(fsbtodb(&osblock, osblock.fs_csaddr + 20677885Stomsoft numfrags(&osblock, i)), (size_t)MIN(osblock.fs_cssize - i, 20777885Stomsoft osblock.fs_bsize), (void *)(((char *)fscs)+i), fsi); 20869800Stomsoft } 20969800Stomsoft 21069800Stomsoft#ifdef FS_DEBUG 21169800Stomsoft{ 21269800Stomsoft struct csum *dbg_csp; 21369800Stomsoft int dbg_csc; 21469800Stomsoft char dbg_line[80]; 21569800Stomsoft 21669800Stomsoft dbg_csp=fscs; 21769800Stomsoft for(dbg_csc=0; dbg_csc<osblock.fs_ncg; dbg_csc++) { 21877885Stomsoft snprintf(dbg_line, sizeof(dbg_line), 21977885Stomsoft "%d. old csum in old location", dbg_csc); 22069926Stomsoft DBG_DUMP_CSUM(&osblock, 22169926Stomsoft dbg_line, 22269926Stomsoft dbg_csp++); 22369800Stomsoft } 22469800Stomsoft} 22569800Stomsoft#endif /* FS_DEBUG */ 22669800Stomsoft DBG_PRINT0("fscs read\n"); 22769800Stomsoft 22869800Stomsoft /* 22969800Stomsoft * Do all needed changes in the former last cylinder group. 23069800Stomsoft */ 23169800Stomsoft updjcg(osblock.fs_ncg-1, utime, fsi, fso, Nflag); 23269800Stomsoft 23369800Stomsoft /* 234102231Strhodes * Dump out summary information about file system. 23569800Stomsoft */ 23698542Smckusick# define B2MBFACTOR (1 / (1024.0 * 1024.0)) 237127816Smux printf("growfs: %.1fMB (%jd sectors) block size %d, fragment size %d\n", 23869800Stomsoft (float)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR, 239127816Smux (intmax_t)fsbtodb(&sblock, sblock.fs_size), sblock.fs_bsize, 240127816Smux sblock.fs_fsize); 24198542Smckusick printf("\tusing %d cylinder groups of %.2fMB, %d blks, %d inodes.\n", 24298542Smckusick sblock.fs_ncg, (float)sblock.fs_fpg * sblock.fs_fsize * B2MBFACTOR, 24398542Smckusick sblock.fs_fpg / sblock.fs_frag, sblock.fs_ipg); 24498542Smckusick if (sblock.fs_flags & FS_DOSOFTDEP) 24598542Smckusick printf("\twith soft updates\n"); 24698542Smckusick# undef B2MBFACTOR 24769800Stomsoft 24869800Stomsoft /* 24969800Stomsoft * Now build the cylinders group blocks and 25069800Stomsoft * then print out indices of cylinder groups. 25169800Stomsoft */ 25269800Stomsoft printf("super-block backups (for fsck -b #) at:\n"); 25369800Stomsoft i = 0; 25469800Stomsoft width = charsperline(); 25569800Stomsoft 25669800Stomsoft /* 25769800Stomsoft * Iterate for only the new cylinder groups. 25869800Stomsoft */ 25969800Stomsoft for (cylno = osblock.fs_ncg; cylno < sblock.fs_ncg; cylno++) { 26069800Stomsoft initcg(cylno, utime, fso, Nflag); 261174706Sdas j = sprintf(tmpbuf, " %jd%s", 262174706Sdas (intmax_t)fsbtodb(&sblock, cgsblock(&sblock, cylno)), 26369800Stomsoft cylno < (sblock.fs_ncg-1) ? "," : "" ); 26469800Stomsoft if (i + j >= width) { 26569800Stomsoft printf("\n"); 26669800Stomsoft i = 0; 26769800Stomsoft } 26869800Stomsoft i += j; 26969800Stomsoft printf("%s", tmpbuf); 27069800Stomsoft fflush(stdout); 27169800Stomsoft } 27269800Stomsoft printf("\n"); 27369800Stomsoft 27469800Stomsoft /* 27569800Stomsoft * Do all needed changes in the first cylinder group. 27669800Stomsoft * allocate blocks in new location 27769800Stomsoft */ 27869800Stomsoft updcsloc(utime, fsi, fso, Nflag); 27969800Stomsoft 28069800Stomsoft /* 28169800Stomsoft * Now write the cylinder summary back to disk. 28269800Stomsoft */ 28369800Stomsoft for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize) { 28469800Stomsoft wtfs(fsbtodb(&sblock, sblock.fs_csaddr + numfrags(&sblock, i)), 28577885Stomsoft (size_t)MIN(sblock.fs_cssize - i, sblock.fs_bsize), 28677885Stomsoft (void *)(((char *)fscs) + i), fso, Nflag); 28769800Stomsoft } 28869800Stomsoft DBG_PRINT0("fscs written\n"); 28969800Stomsoft 29069800Stomsoft#ifdef FS_DEBUG 29169800Stomsoft{ 29269800Stomsoft struct csum *dbg_csp; 29369800Stomsoft int dbg_csc; 29469800Stomsoft char dbg_line[80]; 29569800Stomsoft 29669800Stomsoft dbg_csp=fscs; 29769800Stomsoft for(dbg_csc=0; dbg_csc<sblock.fs_ncg; dbg_csc++) { 29877885Stomsoft snprintf(dbg_line, sizeof(dbg_line), 29977885Stomsoft "%d. new csum in new location", dbg_csc); 30069926Stomsoft DBG_DUMP_CSUM(&sblock, 30169926Stomsoft dbg_line, 30269926Stomsoft dbg_csp++); 30369800Stomsoft } 30469800Stomsoft} 30569800Stomsoft#endif /* FS_DEBUG */ 30669800Stomsoft 30769800Stomsoft /* 30869800Stomsoft * Now write the new superblock back to disk. 30969800Stomsoft */ 31069800Stomsoft sblock.fs_time = utime; 31198542Smckusick wtfs(sblockloc, (size_t)SBLOCKSIZE, (void *)&sblock, fso, Nflag); 31269800Stomsoft DBG_PRINT0("sblock written\n"); 31369926Stomsoft DBG_DUMP_FS(&sblock, 31469926Stomsoft "new initial sblock"); 31569800Stomsoft 31669800Stomsoft /* 31769800Stomsoft * Clean up the dynamic fields in our superblock copies. 31869800Stomsoft */ 31969800Stomsoft sblock.fs_fmod = 0; 32069800Stomsoft sblock.fs_clean = 1; 32169800Stomsoft sblock.fs_ronly = 0; 32269800Stomsoft sblock.fs_cgrotor = 0; 32369800Stomsoft sblock.fs_state = 0; 32469800Stomsoft memset((void *)&sblock.fs_fsmnt, 0, sizeof(sblock.fs_fsmnt)); 32569800Stomsoft sblock.fs_flags &= FS_DOSOFTDEP; 32669800Stomsoft 32769800Stomsoft /* 32869800Stomsoft * XXX 329114067Sschweikh * The following fields are currently distributed from the superblock 33069800Stomsoft * to the copies: 33169800Stomsoft * fs_minfree 33269800Stomsoft * fs_rotdelay 33369800Stomsoft * fs_maxcontig 33469800Stomsoft * fs_maxbpg 33569800Stomsoft * fs_minfree, 33669800Stomsoft * fs_optim 33769800Stomsoft * fs_flags regarding SOFTPDATES 33869800Stomsoft * 33969800Stomsoft * We probably should rather change the summary for the cylinder group 34069800Stomsoft * statistics here to the value of what would be in there, if the file 341114067Sschweikh * system were created initially with the new size. Therefor we still 34269800Stomsoft * need to find an easy way of calculating that. 34369800Stomsoft * Possibly we can try to read the first superblock copy and apply the 344114067Sschweikh * "diffed" stats between the old and new superblock by still copying 34569800Stomsoft * certain parameters onto that. 34669800Stomsoft */ 34769800Stomsoft 34869800Stomsoft /* 34969800Stomsoft * Write out the duplicate super blocks. 35069800Stomsoft */ 35169800Stomsoft for (cylno = 0; cylno < sblock.fs_ncg; cylno++) { 35269800Stomsoft wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)), 35398542Smckusick (size_t)SBLOCKSIZE, (void *)&sblock, fso, Nflag); 35469800Stomsoft } 35569800Stomsoft DBG_PRINT0("sblock copies written\n"); 35669926Stomsoft DBG_DUMP_FS(&sblock, 35769926Stomsoft "new other sblocks"); 35869800Stomsoft 35969800Stomsoft DBG_LEAVE; 36069800Stomsoft return; 36169800Stomsoft} 36269800Stomsoft 36369800Stomsoft/* ************************************************************ initcg ***** */ 36469800Stomsoft/* 365114067Sschweikh * This creates a new cylinder group structure, for more details please see 366114067Sschweikh * the source of newfs(8), as this function is taken over almost unchanged. 367114067Sschweikh * As this is never called for the first cylinder group, the special 36869800Stomsoft * provisions for that case are removed here. 36969800Stomsoft */ 37069800Stomsoftstatic void 37177885Stomsoftinitcg(int cylno, time_t utime, int fso, unsigned int Nflag) 37269800Stomsoft{ 37369800Stomsoft DBG_FUNC("initcg") 374127816Smux static void *iobuf; 375203770Smckusick long blkno, start; 376127798Sle ufs2_daddr_t i, cbase, dmax; 37798542Smckusick struct ufs1_dinode *dp1; 37892806Sobrien struct csum *cs; 379203770Smckusick uint d, dupper, dlower; 38069800Stomsoft 38198542Smckusick if (iobuf == NULL && (iobuf = malloc(sblock.fs_bsize)) == NULL) { 38298542Smckusick errx(37, "panic: cannot allocate I/O buffer"); 38398542Smckusick } 38469800Stomsoft /* 38569800Stomsoft * Determine block bounds for cylinder group. 38698542Smckusick * Allow space for super block summary information in first 38798542Smckusick * cylinder group. 38869800Stomsoft */ 38969800Stomsoft cbase = cgbase(&sblock, cylno); 39069800Stomsoft dmax = cbase + sblock.fs_fpg; 39198542Smckusick if (dmax > sblock.fs_size) 39269800Stomsoft dmax = sblock.fs_size; 39369800Stomsoft dlower = cgsblock(&sblock, cylno) - cbase; 39469800Stomsoft dupper = cgdmin(&sblock, cylno) - cbase; 39598542Smckusick if (cylno == 0) /* XXX fscs may be relocated */ 39669800Stomsoft dupper += howmany(sblock.fs_cssize, sblock.fs_fsize); 39798542Smckusick cs = &fscs[cylno]; 39898542Smckusick memset(&acg, 0, sblock.fs_cgsize); 399197763Smjacob /* 400197763Smjacob * Note that we do not set cg_initediblk at all. 401197763Smjacob * In this extension of a previous filesystem 402197763Smjacob * we have no inodes initialized for the cylinder 403197763Smjacob * group at all. The first access to that cylinder 404197763Smjacob * group will do the correct initialization. 405197763Smjacob */ 40669800Stomsoft acg.cg_time = utime; 40769800Stomsoft acg.cg_magic = CG_MAGIC; 40869800Stomsoft acg.cg_cgx = cylno; 40969800Stomsoft acg.cg_niblk = sblock.fs_ipg; 41069800Stomsoft acg.cg_ndblk = dmax - cbase; 41198542Smckusick if (sblock.fs_contigsumsize > 0) 41269800Stomsoft acg.cg_nclusterblks = acg.cg_ndblk / sblock.fs_frag; 41398542Smckusick start = &acg.cg_space[0] - (u_char *)(&acg.cg_firstfield); 41498542Smckusick if (sblock.fs_magic == FS_UFS2_MAGIC) { 41598542Smckusick acg.cg_iusedoff = start; 41698542Smckusick } else { 41798542Smckusick acg.cg_old_ncyl = sblock.fs_old_cpg; 41898542Smckusick acg.cg_old_time = acg.cg_time; 41998542Smckusick acg.cg_time = 0; 42098542Smckusick acg.cg_old_niblk = acg.cg_niblk; 42198542Smckusick acg.cg_niblk = 0; 42298542Smckusick acg.cg_old_btotoff = start; 42398542Smckusick acg.cg_old_boff = acg.cg_old_btotoff + 42498542Smckusick sblock.fs_old_cpg * sizeof(int32_t); 42598542Smckusick acg.cg_iusedoff = acg.cg_old_boff + 42698542Smckusick sblock.fs_old_cpg * sizeof(u_int16_t); 42769800Stomsoft } 428103949Smike acg.cg_freeoff = acg.cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT); 429103949Smike acg.cg_nextfreeoff = acg.cg_freeoff + howmany(sblock.fs_fpg, CHAR_BIT); 43098542Smckusick if (sblock.fs_contigsumsize > 0) { 43169800Stomsoft acg.cg_clustersumoff = 43298542Smckusick roundup(acg.cg_nextfreeoff, sizeof(u_int32_t)); 43398542Smckusick acg.cg_clustersumoff -= sizeof(u_int32_t); 43469800Stomsoft acg.cg_clusteroff = acg.cg_clustersumoff + 43569800Stomsoft (sblock.fs_contigsumsize + 1) * sizeof(u_int32_t); 43698542Smckusick acg.cg_nextfreeoff = acg.cg_clusteroff + 437103949Smike howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT); 43869800Stomsoft } 439203770Smckusick if (acg.cg_nextfreeoff > (unsigned)sblock.fs_cgsize) { 44069800Stomsoft /* 44198542Smckusick * This should never happen as we would have had that panic 442102231Strhodes * already on file system creation 44369800Stomsoft */ 44469926Stomsoft errx(37, "panic: cylinder group too big"); 44569800Stomsoft } 44669800Stomsoft acg.cg_cs.cs_nifree += sblock.fs_ipg; 44769800Stomsoft if (cylno == 0) 44898542Smckusick for (i = 0; i < ROOTINO; i++) { 44969800Stomsoft setbit(cg_inosused(&acg), i); 45069800Stomsoft acg.cg_cs.cs_nifree--; 45169800Stomsoft } 452136289Sscottl /* 453136289Sscottl * XXX Newfs writes out two blocks of initialized inodes 454136289Sscottl * unconditionally. Should we check here to make sure that they 455136289Sscottl * were actually written? 456136289Sscottl */ 457136289Sscottl if (sblock.fs_magic == FS_UFS1_MAGIC) { 458136289Sscottl bzero(iobuf, sblock.fs_bsize); 459136289Sscottl for (i = 2 * sblock.fs_frag; i < sblock.fs_ipg / INOPF(&sblock); 460136289Sscottl i += sblock.fs_frag) { 461136289Sscottl dp1 = (struct ufs1_dinode *)iobuf; 46269800Stomsoft#ifdef FSIRAND 463201401Sgavin for (j = 0; j < INOPB(&sblock); j++) { 464201401Sgavin dp1->di_gen = random(); 465201401Sgavin dp1++; 466201401Sgavin } 46769800Stomsoft#endif 468136289Sscottl wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i), 469136289Sscottl sblock.fs_bsize, iobuf, fso, Nflag); 470136289Sscottl } 47169800Stomsoft } 47298542Smckusick if (cylno > 0) { 47398542Smckusick /* 47498542Smckusick * In cylno 0, beginning space is reserved 47598542Smckusick * for boot and super blocks. 47698542Smckusick */ 47798542Smckusick for (d = 0; d < dlower; d += sblock.fs_frag) { 47898542Smckusick blkno = d / sblock.fs_frag; 47998542Smckusick setblock(&sblock, cg_blksfree(&acg), blkno); 48098542Smckusick if (sblock.fs_contigsumsize > 0) 48198542Smckusick setbit(cg_clustersfree(&acg), blkno); 48298542Smckusick acg.cg_cs.cs_nbfree++; 48369800Stomsoft } 48498542Smckusick sblock.fs_dsize += dlower; 48569800Stomsoft } 48669800Stomsoft sblock.fs_dsize += acg.cg_ndblk - dupper; 48769800Stomsoft if ((i = dupper % sblock.fs_frag)) { 48869800Stomsoft acg.cg_frsum[sblock.fs_frag - i]++; 48969800Stomsoft for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) { 49069800Stomsoft setbit(cg_blksfree(&acg), dupper); 49169800Stomsoft acg.cg_cs.cs_nffree++; 49269800Stomsoft } 49369800Stomsoft } 49498542Smckusick for (d = dupper; d + sblock.fs_frag <= acg.cg_ndblk; 49598542Smckusick d += sblock.fs_frag) { 49669800Stomsoft blkno = d / sblock.fs_frag; 49769800Stomsoft setblock(&sblock, cg_blksfree(&acg), blkno); 49898542Smckusick if (sblock.fs_contigsumsize > 0) 49969800Stomsoft setbit(cg_clustersfree(&acg), blkno); 50069800Stomsoft acg.cg_cs.cs_nbfree++; 50169800Stomsoft } 50298542Smckusick if (d < acg.cg_ndblk) { 50398542Smckusick acg.cg_frsum[acg.cg_ndblk - d]++; 50498542Smckusick for (; d < acg.cg_ndblk; d++) { 50569800Stomsoft setbit(cg_blksfree(&acg), d); 50669800Stomsoft acg.cg_cs.cs_nffree++; 50769800Stomsoft } 50869800Stomsoft } 50969800Stomsoft if (sblock.fs_contigsumsize > 0) { 51098542Smckusick int32_t *sump = cg_clustersum(&acg); 51198542Smckusick u_char *mapp = cg_clustersfree(&acg); 51298542Smckusick int map = *mapp++; 51398542Smckusick int bit = 1; 51498542Smckusick int run = 0; 51569800Stomsoft 51669800Stomsoft for (i = 0; i < acg.cg_nclusterblks; i++) { 51798542Smckusick if ((map & bit) != 0) 51869800Stomsoft run++; 51998542Smckusick else if (run != 0) { 52098542Smckusick if (run > sblock.fs_contigsumsize) 52169800Stomsoft run = sblock.fs_contigsumsize; 52269800Stomsoft sump[run]++; 52369800Stomsoft run = 0; 52469800Stomsoft } 525103949Smike if ((i & (CHAR_BIT - 1)) != CHAR_BIT - 1) 52669800Stomsoft bit <<= 1; 52798542Smckusick else { 52869800Stomsoft map = *mapp++; 52969800Stomsoft bit = 1; 53069800Stomsoft } 53169800Stomsoft } 53269800Stomsoft if (run != 0) { 53398542Smckusick if (run > sblock.fs_contigsumsize) 53469800Stomsoft run = sblock.fs_contigsumsize; 53569800Stomsoft sump[run]++; 53669800Stomsoft } 53769800Stomsoft } 53869800Stomsoft sblock.fs_cstotal.cs_ndir += acg.cg_cs.cs_ndir; 53969800Stomsoft sblock.fs_cstotal.cs_nffree += acg.cg_cs.cs_nffree; 54069800Stomsoft sblock.fs_cstotal.cs_nbfree += acg.cg_cs.cs_nbfree; 54169800Stomsoft sblock.fs_cstotal.cs_nifree += acg.cg_cs.cs_nifree; 54269800Stomsoft *cs = acg.cg_cs; 54369800Stomsoft wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)), 54498542Smckusick sblock.fs_bsize, (char *)&acg, fso, Nflag); 54569926Stomsoft DBG_DUMP_CG(&sblock, 54669926Stomsoft "new cg", 54769926Stomsoft &acg); 54869800Stomsoft 54969800Stomsoft DBG_LEAVE; 55069800Stomsoft return; 55169800Stomsoft} 55269800Stomsoft 55369800Stomsoft/* ******************************************************* frag_adjust ***** */ 55469800Stomsoft/* 555114067Sschweikh * Here we add or subtract (sign +1/-1) the available fragments in a given 55669800Stomsoft * block to or from the fragment statistics. By subtracting before and adding 557114067Sschweikh * after an operation on the free frag map we can easy update the fragment 558108470Sschweikh * statistic, which seems to be otherwise a rather complex operation. 55969800Stomsoft */ 56069800Stomsoftstatic void 56198542Smckusickfrag_adjust(ufs2_daddr_t frag, int sign) 56269800Stomsoft{ 56369800Stomsoft DBG_FUNC("frag_adjust") 56469800Stomsoft int fragsize; 56569800Stomsoft int f; 56669800Stomsoft 56769800Stomsoft DBG_ENTER; 56869800Stomsoft 56969800Stomsoft fragsize=0; 57069800Stomsoft /* 57169800Stomsoft * Here frag only needs to point to any fragment in the block we want 57269800Stomsoft * to examine. 57369800Stomsoft */ 574114067Sschweikh for(f=rounddown(frag, sblock.fs_frag); 57569800Stomsoft f<roundup(frag+1, sblock.fs_frag); 57669800Stomsoft f++) { 57769800Stomsoft /* 578114067Sschweikh * Count contiguous free fragments. 57969800Stomsoft */ 58069800Stomsoft if(isset(cg_blksfree(&acg), f)) { 58169800Stomsoft fragsize++; 58269800Stomsoft } else { 58369800Stomsoft if(fragsize && fragsize<sblock.fs_frag) { 58469800Stomsoft /* 58569800Stomsoft * We found something in between. 58669800Stomsoft */ 58769800Stomsoft acg.cg_frsum[fragsize]+=sign; 58869926Stomsoft DBG_PRINT2("frag_adjust [%d]+=%d\n", 58969926Stomsoft fragsize, 59069926Stomsoft sign); 59169800Stomsoft } 59269800Stomsoft fragsize=0; 59369800Stomsoft } 59469800Stomsoft } 59569800Stomsoft if(fragsize && fragsize<sblock.fs_frag) { 59669800Stomsoft /* 59769800Stomsoft * We found something. 59869800Stomsoft */ 59969800Stomsoft acg.cg_frsum[fragsize]+=sign; 60069926Stomsoft DBG_PRINT2("frag_adjust [%d]+=%d\n", 60169926Stomsoft fragsize, 60269926Stomsoft sign); 60369800Stomsoft } 60469926Stomsoft DBG_PRINT2("frag_adjust [[%d]]+=%d\n", 60569926Stomsoft fragsize, 60669926Stomsoft sign); 60769800Stomsoft 60869800Stomsoft DBG_LEAVE; 60969800Stomsoft return; 61069800Stomsoft} 61169800Stomsoft 61269800Stomsoft/* ******************************************************* cond_bl_upd ***** */ 61369800Stomsoft/* 61469800Stomsoft * Here we conditionally update a pointer to a fragment. We check for all 615114067Sschweikh * relocated blocks if any of its fragments is referenced by the current 616114067Sschweikh * field, and update the pointer to the respective fragment in our new 617114067Sschweikh * block. If we find a reference we write back the block immediately, 61869800Stomsoft * as there is no easy way for our general block reading engine to figure 61969800Stomsoft * out if a write back operation is needed. 62069800Stomsoft */ 62198542Smckusickstatic int 62298542Smckusickcond_bl_upd(ufs2_daddr_t *block, struct gfs_bpp *field, int fsi, int fso, 62398542Smckusick unsigned int Nflag) 62469800Stomsoft{ 62569800Stomsoft DBG_FUNC("cond_bl_upd") 62698542Smckusick struct gfs_bpp *f; 62798542Smckusick ufs2_daddr_t src, dst; 62898542Smckusick int fragnum; 62998542Smckusick void *ibuf; 63069800Stomsoft 63169800Stomsoft DBG_ENTER; 63269800Stomsoft 63398542Smckusick for (f = field; f->old != 0; f++) { 63498542Smckusick src = *block; 63598542Smckusick if (fragstoblks(&sblock, src) != f->old) 63698542Smckusick continue; 63798542Smckusick /* 63898542Smckusick * The fragment is part of the block, so update. 63998542Smckusick */ 64098542Smckusick dst = blkstofrags(&sblock, f->new); 64198542Smckusick fragnum = fragnum(&sblock, src); 64298542Smckusick *block = dst + fragnum; 64398542Smckusick f->found++; 644127798Sle DBG_PRINT3("scg (%jd->%jd)[%d] reference updated\n", 645127798Sle (intmax_t)f->old, 646127798Sle (intmax_t)f->new, 64798542Smckusick fragnum); 64869800Stomsoft 64998542Smckusick /* 65098542Smckusick * Copy the block back immediately. 65198542Smckusick * 65298542Smckusick * XXX If src is is from an indirect block we have 65398542Smckusick * to implement copy on write here in case of 65498542Smckusick * active snapshots. 65598542Smckusick */ 65698542Smckusick ibuf = malloc(sblock.fs_bsize); 65798542Smckusick if (!ibuf) 65898542Smckusick errx(1, "malloc failed"); 65998542Smckusick src -= fragnum; 66098542Smckusick rdfs(fsbtodb(&sblock, src), (size_t)sblock.fs_bsize, ibuf, fsi); 66198542Smckusick wtfs(dst, (size_t)sblock.fs_bsize, ibuf, fso, Nflag); 66298542Smckusick free(ibuf); 66398542Smckusick /* 66498542Smckusick * The same block can't be found again in this loop. 66598542Smckusick */ 66698542Smckusick return (1); 66769800Stomsoft } 66869800Stomsoft 66969800Stomsoft DBG_LEAVE; 67098542Smckusick return (0); 67169800Stomsoft} 67269800Stomsoft 67369800Stomsoft/* ************************************************************ updjcg ***** */ 67469800Stomsoft/* 67569800Stomsoft * Here we do all needed work for the former last cylinder group. It has to be 676114067Sschweikh * changed in any case, even if the file system ended exactly on the end of 677114067Sschweikh * this group, as there is some slightly inconsistent handling of the number 678114067Sschweikh * of cylinders in the cylinder group. We start again by reading the cylinder 67969800Stomsoft * group from disk. If the last block was not fully available, we first handle 680114067Sschweikh * the missing fragments, then we handle all new full blocks in that file 681114067Sschweikh * system and finally we handle the new last fragmented block in the file 682114067Sschweikh * system. We again have to handle the fragment statistics rotational layout 68369800Stomsoft * tables and cluster summary during all those operations. 68469800Stomsoft */ 68569800Stomsoftstatic void 68677885Stomsoftupdjcg(int cylno, time_t utime, int fsi, int fso, unsigned int Nflag) 68769800Stomsoft{ 68869800Stomsoft DBG_FUNC("updjcg") 68998542Smckusick ufs2_daddr_t cbase, dmax, dupper; 69069800Stomsoft struct csum *cs; 69169800Stomsoft int i,k; 69269800Stomsoft int j=0; 69369800Stomsoft 69469800Stomsoft DBG_ENTER; 69569800Stomsoft 69669800Stomsoft /* 69769800Stomsoft * Read the former last (joining) cylinder group from disk, and make 69869800Stomsoft * a copy. 69969800Stomsoft */ 70077885Stomsoft rdfs(fsbtodb(&osblock, cgtod(&osblock, cylno)), 70177885Stomsoft (size_t)osblock.fs_cgsize, (void *)&aocg, fsi); 70269800Stomsoft DBG_PRINT0("jcg read\n"); 70369926Stomsoft DBG_DUMP_CG(&sblock, 70469926Stomsoft "old joining cg", 70569926Stomsoft &aocg); 70669800Stomsoft 70769800Stomsoft memcpy((void *)&cgun1, (void *)&cgun2, sizeof(cgun2)); 70869800Stomsoft 70969800Stomsoft /* 710114067Sschweikh * If the cylinder group had already its new final size almost 71169800Stomsoft * nothing is to be done ... except: 71269800Stomsoft * For some reason the value of cg_ncyl in the last cylinder group has 713114067Sschweikh * to be zero instead of fs_cpg. As this is now no longer the last 71469800Stomsoft * cylinder group we have to change that value now to fs_cpg. 715114067Sschweikh */ 71669800Stomsoft 71769800Stomsoft if(cgbase(&osblock, cylno+1) == osblock.fs_size) { 71898542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 71998542Smckusick acg.cg_old_ncyl=sblock.fs_old_cpg; 72069800Stomsoft 72177885Stomsoft wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)), 72277885Stomsoft (size_t)sblock.fs_cgsize, (void *)&acg, fso, Nflag); 72369800Stomsoft DBG_PRINT0("jcg written\n"); 72469926Stomsoft DBG_DUMP_CG(&sblock, 72569926Stomsoft "new joining cg", 72669926Stomsoft &acg); 72769800Stomsoft 72869800Stomsoft DBG_LEAVE; 72969800Stomsoft return; 73069800Stomsoft } 73169800Stomsoft 73269800Stomsoft /* 73369800Stomsoft * Set up some variables needed later. 73469800Stomsoft */ 73569800Stomsoft cbase = cgbase(&sblock, cylno); 73669800Stomsoft dmax = cbase + sblock.fs_fpg; 73769800Stomsoft if (dmax > sblock.fs_size) 73869800Stomsoft dmax = sblock.fs_size; 73969800Stomsoft dupper = cgdmin(&sblock, cylno) - cbase; 74077885Stomsoft if (cylno == 0) { /* XXX fscs may be relocated */ 74169800Stomsoft dupper += howmany(sblock.fs_cssize, sblock.fs_fsize); 74269800Stomsoft } 74369800Stomsoft 74469800Stomsoft /* 74569800Stomsoft * Set pointer to the cylinder summary for our cylinder group. 74669800Stomsoft */ 74769800Stomsoft cs = fscs + cylno; 74869800Stomsoft 74969800Stomsoft /* 75069800Stomsoft * Touch the cylinder group, update all fields in the cylinder group as 75169800Stomsoft * needed, update the free space in the superblock. 75269800Stomsoft */ 75369800Stomsoft acg.cg_time = utime; 754203770Smckusick if ((unsigned)cylno == sblock.fs_ncg - 1) { 75569800Stomsoft /* 75669800Stomsoft * This is still the last cylinder group. 75769800Stomsoft */ 75898542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 75998542Smckusick acg.cg_old_ncyl = 76098542Smckusick sblock.fs_old_ncyl % sblock.fs_old_cpg; 76169800Stomsoft } else { 76298542Smckusick acg.cg_old_ncyl = sblock.fs_old_cpg; 76369800Stomsoft } 76498542Smckusick DBG_PRINT2("jcg dbg: %d %u", 76569926Stomsoft cylno, 76698542Smckusick sblock.fs_ncg); 767127798Sle#ifdef FS_DEBUG 76898542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 76998542Smckusick DBG_PRINT2("%d %u", 77098542Smckusick acg.cg_old_ncyl, 77198542Smckusick sblock.fs_old_cpg); 772127798Sle#endif 77398542Smckusick DBG_PRINT0("\n"); 77469800Stomsoft acg.cg_ndblk = dmax - cbase; 77569800Stomsoft sblock.fs_dsize += acg.cg_ndblk-aocg.cg_ndblk; 77669800Stomsoft if (sblock.fs_contigsumsize > 0) { 77769800Stomsoft acg.cg_nclusterblks = acg.cg_ndblk / sblock.fs_frag; 77869800Stomsoft } 77969800Stomsoft 78069800Stomsoft /* 781114067Sschweikh * Now we have to update the free fragment bitmap for our new free 782114067Sschweikh * space. There again we have to handle the fragmentation and also 783114067Sschweikh * the rotational layout tables and the cluster summary. This is 784114067Sschweikh * also done per fragment for the first new block if the old file 785114067Sschweikh * system end was not on a block boundary, per fragment for the new 786102231Strhodes * last block if the new file system end is not on a block boundary, 78769800Stomsoft * and per block for all space in between. 78869800Stomsoft * 78969800Stomsoft * Handle the first new block here if it was partially available 79069800Stomsoft * before. 79169800Stomsoft */ 79269800Stomsoft if(osblock.fs_size % sblock.fs_frag) { 79369800Stomsoft if(roundup(osblock.fs_size, sblock.fs_frag)<=sblock.fs_size) { 79469800Stomsoft /* 79569800Stomsoft * The new space is enough to fill at least this 79669800Stomsoft * block 79769800Stomsoft */ 79869800Stomsoft j=0; 79969800Stomsoft for(i=roundup(osblock.fs_size-cbase, sblock.fs_frag)-1; 80069800Stomsoft i>=osblock.fs_size-cbase; 80169800Stomsoft i--) { 80269800Stomsoft setbit(cg_blksfree(&acg), i); 80369800Stomsoft acg.cg_cs.cs_nffree++; 80469800Stomsoft j++; 80569800Stomsoft } 80669800Stomsoft 80769800Stomsoft /* 808114067Sschweikh * Check if the fragment just created could join an 80969800Stomsoft * already existing fragment at the former end of the 810102231Strhodes * file system. 81169800Stomsoft */ 81269800Stomsoft if(isblock(&sblock, cg_blksfree(&acg), 81369800Stomsoft ((osblock.fs_size - cgbase(&sblock, cylno))/ 81469800Stomsoft sblock.fs_frag))) { 81569800Stomsoft /* 816114067Sschweikh * The block is now completely available. 81769800Stomsoft */ 81869800Stomsoft DBG_PRINT0("block was\n"); 81969800Stomsoft acg.cg_frsum[osblock.fs_size%sblock.fs_frag]--; 82069800Stomsoft acg.cg_cs.cs_nbfree++; 82169800Stomsoft acg.cg_cs.cs_nffree-=sblock.fs_frag; 82269800Stomsoft k=rounddown(osblock.fs_size-cbase, 82369800Stomsoft sblock.fs_frag); 82469800Stomsoft updclst((osblock.fs_size-cbase)/sblock.fs_frag); 82569800Stomsoft } else { 82669800Stomsoft /* 82769800Stomsoft * Lets rejoin a possible partially growed 82869800Stomsoft * fragment. 82969800Stomsoft */ 83069800Stomsoft k=0; 83169800Stomsoft while(isset(cg_blksfree(&acg), i) && 83269800Stomsoft (i>=rounddown(osblock.fs_size-cbase, 83369800Stomsoft sblock.fs_frag))) { 83469800Stomsoft i--; 83569800Stomsoft k++; 83669800Stomsoft } 83769800Stomsoft if(k) { 83869800Stomsoft acg.cg_frsum[k]--; 83969800Stomsoft } 84069800Stomsoft acg.cg_frsum[k+j]++; 84169800Stomsoft } 84269800Stomsoft } else { 84369800Stomsoft /* 84469800Stomsoft * We only grow by some fragments within this last 84569800Stomsoft * block. 84669800Stomsoft */ 84769800Stomsoft for(i=sblock.fs_size-cbase-1; 84869800Stomsoft i>=osblock.fs_size-cbase; 84969800Stomsoft i--) { 85069800Stomsoft setbit(cg_blksfree(&acg), i); 85169800Stomsoft acg.cg_cs.cs_nffree++; 85269800Stomsoft j++; 85369800Stomsoft } 85469800Stomsoft /* 85569800Stomsoft * Lets rejoin a possible partially growed fragment. 85669800Stomsoft */ 85769800Stomsoft k=0; 85869800Stomsoft while(isset(cg_blksfree(&acg), i) && 85969800Stomsoft (i>=rounddown(osblock.fs_size-cbase, 86069800Stomsoft sblock.fs_frag))) { 86169800Stomsoft i--; 86269800Stomsoft k++; 86369800Stomsoft } 86469800Stomsoft if(k) { 86569800Stomsoft acg.cg_frsum[k]--; 86669800Stomsoft } 86769800Stomsoft acg.cg_frsum[k+j]++; 86869800Stomsoft } 86969800Stomsoft } 87069800Stomsoft 87169800Stomsoft /* 87269800Stomsoft * Handle all new complete blocks here. 87369800Stomsoft */ 87469800Stomsoft for(i=roundup(osblock.fs_size-cbase, sblock.fs_frag); 87569800Stomsoft i+sblock.fs_frag<=dmax-cbase; /* XXX <= or only < ? */ 87669800Stomsoft i+=sblock.fs_frag) { 87769800Stomsoft j = i / sblock.fs_frag; 87869800Stomsoft setblock(&sblock, cg_blksfree(&acg), j); 87969800Stomsoft updclst(j); 88069800Stomsoft acg.cg_cs.cs_nbfree++; 88169800Stomsoft } 88269800Stomsoft 88369800Stomsoft /* 88469800Stomsoft * Handle the last new block if there are stll some new fragments left. 885114067Sschweikh * Here we don't have to bother about the cluster summary or the even 88669800Stomsoft * the rotational layout table. 88769800Stomsoft */ 88869800Stomsoft if (i < (dmax - cbase)) { 88969800Stomsoft acg.cg_frsum[dmax - cbase - i]++; 89069800Stomsoft for (; i < dmax - cbase; i++) { 89169800Stomsoft setbit(cg_blksfree(&acg), i); 89269800Stomsoft acg.cg_cs.cs_nffree++; 89369800Stomsoft } 89469800Stomsoft } 89569800Stomsoft 89669800Stomsoft sblock.fs_cstotal.cs_nffree += 89769800Stomsoft (acg.cg_cs.cs_nffree - aocg.cg_cs.cs_nffree); 89869800Stomsoft sblock.fs_cstotal.cs_nbfree += 89969800Stomsoft (acg.cg_cs.cs_nbfree - aocg.cg_cs.cs_nbfree); 90069800Stomsoft /* 90169800Stomsoft * The following statistics are not changed here: 90269800Stomsoft * sblock.fs_cstotal.cs_ndir 90369800Stomsoft * sblock.fs_cstotal.cs_nifree 90469800Stomsoft * As the statistics for this cylinder group are ready, copy it to 90569800Stomsoft * the summary information array. 90669800Stomsoft */ 90769800Stomsoft *cs = acg.cg_cs; 90869800Stomsoft 90969800Stomsoft /* 91069800Stomsoft * Write the updated "joining" cylinder group back to disk. 91169800Stomsoft */ 91277885Stomsoft wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)), (size_t)sblock.fs_cgsize, 91377885Stomsoft (void *)&acg, fso, Nflag); 91469800Stomsoft DBG_PRINT0("jcg written\n"); 91569926Stomsoft DBG_DUMP_CG(&sblock, 91669926Stomsoft "new joining cg", 91769926Stomsoft &acg); 91869800Stomsoft 91969800Stomsoft DBG_LEAVE; 92069800Stomsoft return; 92169800Stomsoft} 92269800Stomsoft 92369800Stomsoft/* ********************************************************** updcsloc ***** */ 92469800Stomsoft/* 925114067Sschweikh * Here we update the location of the cylinder summary. We have two possible 92669800Stomsoft * ways of growing the cylinder summary. 927114067Sschweikh * (1) We can try to grow the summary in the current location, and relocate 92869800Stomsoft * possibly used blocks within the current cylinder group. 92969800Stomsoft * (2) Alternatively we can relocate the whole cylinder summary to the first 930114067Sschweikh * new completely empty cylinder group. Once the cylinder summary is no 931114067Sschweikh * longer in the beginning of the first cylinder group you should never 932114067Sschweikh * use a version of fsck which is not aware of the possibility to have 93369800Stomsoft * this structure in a non standard place. 934114067Sschweikh * Option (1) is considered to be less intrusive to the structure of the file- 93569800Stomsoft * system. So we try to stick to that whenever possible. If there is not enough 936114067Sschweikh * space in the cylinder group containing the cylinder summary we have to use 937114067Sschweikh * method (2). In case of active snapshots in the file system we probably can 93869800Stomsoft * completely avoid implementing copy on write if we stick to method (2) only. 93969800Stomsoft */ 94069800Stomsoftstatic void 94177885Stomsoftupdcsloc(time_t utime, int fsi, int fso, unsigned int Nflag) 94269800Stomsoft{ 94369800Stomsoft DBG_FUNC("updcsloc") 94469800Stomsoft struct csum *cs; 94569800Stomsoft int ocscg, ncscg; 94669800Stomsoft int blocks; 94798542Smckusick ufs2_daddr_t cbase, dupper, odupper, d, f, g; 948203770Smckusick int ind, inc; 949203770Smckusick uint cylno; 95069800Stomsoft struct gfs_bpp *bp; 95169800Stomsoft int i, l; 95269800Stomsoft int lcs=0; 95369800Stomsoft int block; 95469800Stomsoft 95569800Stomsoft DBG_ENTER; 95669800Stomsoft 95769800Stomsoft if(howmany(sblock.fs_cssize, sblock.fs_fsize) == 95869800Stomsoft howmany(osblock.fs_cssize, osblock.fs_fsize)) { 95969800Stomsoft /* 96069800Stomsoft * No new fragment needed. 96169800Stomsoft */ 96269800Stomsoft DBG_LEAVE; 96369800Stomsoft return; 96469800Stomsoft } 96569800Stomsoft ocscg=dtog(&osblock, osblock.fs_csaddr); 96669800Stomsoft cs=fscs+ocscg; 96769800Stomsoft blocks = 1+howmany(sblock.fs_cssize, sblock.fs_bsize)- 96869800Stomsoft howmany(osblock.fs_cssize, osblock.fs_bsize); 96969800Stomsoft 97069800Stomsoft /* 97169800Stomsoft * Read original cylinder group from disk, and make a copy. 97281311Schm * XXX If Nflag is set in some very rare cases we now miss 97381311Schm * some changes done in updjcg by reading the unmodified 97481311Schm * block from disk. 97569800Stomsoft */ 97677885Stomsoft rdfs(fsbtodb(&osblock, cgtod(&osblock, ocscg)), 97777885Stomsoft (size_t)osblock.fs_cgsize, (void *)&aocg, fsi); 97869800Stomsoft DBG_PRINT0("oscg read\n"); 97969926Stomsoft DBG_DUMP_CG(&sblock, 98069926Stomsoft "old summary cg", 98169926Stomsoft &aocg); 98269800Stomsoft 98369800Stomsoft memcpy((void *)&cgun1, (void *)&cgun2, sizeof(cgun2)); 98469800Stomsoft 98569800Stomsoft /* 98669800Stomsoft * Touch the cylinder group, set up local variables needed later 98769800Stomsoft * and update the superblock. 98869800Stomsoft */ 98969800Stomsoft acg.cg_time = utime; 99069800Stomsoft 99169800Stomsoft /* 99269800Stomsoft * XXX In the case of having active snapshots we may need much more 993114067Sschweikh * blocks for the copy on write. We need each block twice, and 994114067Sschweikh * also up to 8*3 blocks for indirect blocks for all possible 99569800Stomsoft * references. 99669800Stomsoft */ 99769800Stomsoft if(/*((int)sblock.fs_time&0x3)>0||*/ cs->cs_nbfree < blocks) { 99869800Stomsoft /* 999114067Sschweikh * There is not enough space in the old cylinder group to 1000114067Sschweikh * relocate all blocks as needed, so we relocate the whole 1001114067Sschweikh * cylinder group summary to a new group. We try to use the 100269800Stomsoft * first complete new cylinder group just created. Within the 1003114067Sschweikh * cylinder group we align the area immediately after the 1004114067Sschweikh * cylinder group information location in order to be as 100569800Stomsoft * close as possible to the original implementation of ffs. 100669800Stomsoft * 1007114067Sschweikh * First we have to make sure we'll find enough space in the 1008114067Sschweikh * new cylinder group. If not, then we currently give up. 1009114067Sschweikh * We start with freeing everything which was used by the 101069800Stomsoft * fragments of the old cylinder summary in the current group. 1011114067Sschweikh * Now we write back the group meta data, read in the needed 101269800Stomsoft * meta data from the new cylinder group, and start allocating 1013114067Sschweikh * within that group. Here we can assume, the group to be 101469800Stomsoft * completely empty. Which makes the handling of fragments and 101569800Stomsoft * clusters a lot easier. 101669800Stomsoft */ 101769800Stomsoft DBG_TRC; 101869800Stomsoft if(sblock.fs_ncg-osblock.fs_ncg < 2) { 101969926Stomsoft errx(2, "panic: not enough space"); 102069800Stomsoft } 102169800Stomsoft 102269800Stomsoft /* 102369800Stomsoft * Point "d" to the first fragment not used by the cylinder 102469800Stomsoft * summary. 102569800Stomsoft */ 102669800Stomsoft d=osblock.fs_csaddr+(osblock.fs_cssize/osblock.fs_fsize); 102769800Stomsoft 102869800Stomsoft /* 102969800Stomsoft * Set up last cluster size ("lcs") already here. Calculate 1030114067Sschweikh * the size for the trailing cluster just behind where "d" 103169800Stomsoft * points to. 103269800Stomsoft */ 103369800Stomsoft if(sblock.fs_contigsumsize > 0) { 103469800Stomsoft for(block=howmany(d%sblock.fs_fpg, sblock.fs_frag), 103569800Stomsoft lcs=0; lcs<sblock.fs_contigsumsize; 103669800Stomsoft block++, lcs++) { 103769800Stomsoft if(isclr(cg_clustersfree(&acg), block)){ 103869800Stomsoft break; 103969800Stomsoft } 104069800Stomsoft } 104169800Stomsoft } 104269800Stomsoft 104369800Stomsoft /* 104469800Stomsoft * Point "d" to the last frag used by the cylinder summary. 104569800Stomsoft */ 104669800Stomsoft d--; 104769800Stomsoft 1048127798Sle DBG_PRINT1("d=%jd\n", 1049127798Sle (intmax_t)d); 105069800Stomsoft if((d+1)%sblock.fs_frag) { 105169800Stomsoft /* 105269800Stomsoft * The end of the cylinder summary is not a complete 105369800Stomsoft * block. 105469800Stomsoft */ 105569800Stomsoft DBG_TRC; 105669800Stomsoft frag_adjust(d%sblock.fs_fpg, -1); 105769800Stomsoft for(; (d+1)%sblock.fs_frag; d--) { 1058127798Sle DBG_PRINT1("d=%jd\n", 1059127798Sle (intmax_t)d); 106069800Stomsoft setbit(cg_blksfree(&acg), d%sblock.fs_fpg); 106169800Stomsoft acg.cg_cs.cs_nffree++; 106269800Stomsoft sblock.fs_cstotal.cs_nffree++; 106369800Stomsoft } 106469800Stomsoft /* 1065114067Sschweikh * Point "d" to the last fragment of the last 1066114067Sschweikh * (incomplete) block of the cylinder summary. 106769800Stomsoft */ 106869800Stomsoft d++; 106969800Stomsoft frag_adjust(d%sblock.fs_fpg, 1); 107069800Stomsoft 107169800Stomsoft if(isblock(&sblock, cg_blksfree(&acg), 107269800Stomsoft (d%sblock.fs_fpg)/sblock.fs_frag)) { 1073127798Sle DBG_PRINT1("d=%jd\n", (intmax_t)d); 107469800Stomsoft acg.cg_cs.cs_nffree-=sblock.fs_frag; 107569800Stomsoft acg.cg_cs.cs_nbfree++; 107669800Stomsoft sblock.fs_cstotal.cs_nffree-=sblock.fs_frag; 107769800Stomsoft sblock.fs_cstotal.cs_nbfree++; 107869800Stomsoft if(sblock.fs_contigsumsize > 0) { 107969800Stomsoft setbit(cg_clustersfree(&acg), 108069800Stomsoft (d%sblock.fs_fpg)/sblock.fs_frag); 108169800Stomsoft if(lcs < sblock.fs_contigsumsize) { 108269800Stomsoft if(lcs) { 108369800Stomsoft cg_clustersum(&acg) 108469800Stomsoft [lcs]--; 108569800Stomsoft } 108669800Stomsoft lcs++; 108769800Stomsoft cg_clustersum(&acg)[lcs]++; 108869800Stomsoft } 108969800Stomsoft } 109069800Stomsoft } 109169800Stomsoft /* 109269800Stomsoft * Point "d" to the first fragment of the block before 109369800Stomsoft * the last incomplete block. 109469800Stomsoft */ 109569800Stomsoft d--; 109669800Stomsoft } 109769800Stomsoft 1098127798Sle DBG_PRINT1("d=%jd\n", (intmax_t)d); 109969800Stomsoft for(d=rounddown(d, sblock.fs_frag); d >= osblock.fs_csaddr; 110069800Stomsoft d-=sblock.fs_frag) { 110169800Stomsoft DBG_TRC; 1102127798Sle DBG_PRINT1("d=%jd\n", (intmax_t)d); 110369800Stomsoft setblock(&sblock, cg_blksfree(&acg), 110469800Stomsoft (d%sblock.fs_fpg)/sblock.fs_frag); 110569800Stomsoft acg.cg_cs.cs_nbfree++; 110669800Stomsoft sblock.fs_cstotal.cs_nbfree++; 110769800Stomsoft if(sblock.fs_contigsumsize > 0) { 110869800Stomsoft setbit(cg_clustersfree(&acg), 110969800Stomsoft (d%sblock.fs_fpg)/sblock.fs_frag); 111069800Stomsoft /* 111169800Stomsoft * The last cluster size is already set up. 111269800Stomsoft */ 111369800Stomsoft if(lcs < sblock.fs_contigsumsize) { 111469800Stomsoft if(lcs) { 111569800Stomsoft cg_clustersum(&acg)[lcs]--; 111669800Stomsoft } 111769800Stomsoft lcs++; 111869800Stomsoft cg_clustersum(&acg)[lcs]++; 111969800Stomsoft } 112069800Stomsoft } 112169800Stomsoft } 112269800Stomsoft *cs = acg.cg_cs; 112369800Stomsoft 112469800Stomsoft /* 112569800Stomsoft * Now write the former cylinder group containing the cylinder 112669800Stomsoft * summary back to disk. 112769800Stomsoft */ 112877885Stomsoft wtfs(fsbtodb(&sblock, cgtod(&sblock, ocscg)), 112977885Stomsoft (size_t)sblock.fs_cgsize, (void *)&acg, fso, Nflag); 113069800Stomsoft DBG_PRINT0("oscg written\n"); 113169926Stomsoft DBG_DUMP_CG(&sblock, 113269926Stomsoft "old summary cg", 113369926Stomsoft &acg); 113469800Stomsoft 113569800Stomsoft /* 113669800Stomsoft * Find the beginning of the new cylinder group containing the 113769800Stomsoft * cylinder summary. 113869800Stomsoft */ 113969800Stomsoft sblock.fs_csaddr=cgdmin(&sblock, osblock.fs_ncg); 114069800Stomsoft ncscg=dtog(&sblock, sblock.fs_csaddr); 114169800Stomsoft cs=fscs+ncscg; 114269800Stomsoft 114381311Schm 114469800Stomsoft /* 114581311Schm * If Nflag is specified, we would now read random data instead 114681311Schm * of an empty cg structure from disk. So we can't simulate that 114781311Schm * part for now. 114881311Schm */ 114981311Schm if(Nflag) { 115081311Schm DBG_PRINT0("nscg update skipped\n"); 115181311Schm DBG_LEAVE; 115281311Schm return; 115381311Schm } 115481311Schm 115581311Schm /* 115669800Stomsoft * Read the future cylinder group containing the cylinder 115769800Stomsoft * summary from disk, and make a copy. 115869800Stomsoft */ 115969800Stomsoft rdfs(fsbtodb(&sblock, cgtod(&sblock, ncscg)), 116077885Stomsoft (size_t)sblock.fs_cgsize, (void *)&aocg, fsi); 116169800Stomsoft DBG_PRINT0("nscg read\n"); 116269926Stomsoft DBG_DUMP_CG(&sblock, 116369926Stomsoft "new summary cg", 116469926Stomsoft &aocg); 116569800Stomsoft 116669800Stomsoft memcpy((void *)&cgun1, (void *)&cgun2, sizeof(cgun2)); 116769800Stomsoft 116869800Stomsoft /* 116969800Stomsoft * Allocate all complete blocks used by the new cylinder 117069800Stomsoft * summary. 117169800Stomsoft */ 117269800Stomsoft for(d=sblock.fs_csaddr; d+sblock.fs_frag <= 117369800Stomsoft sblock.fs_csaddr+(sblock.fs_cssize/sblock.fs_fsize); 117469800Stomsoft d+=sblock.fs_frag) { 117569800Stomsoft clrblock(&sblock, cg_blksfree(&acg), 117669800Stomsoft (d%sblock.fs_fpg)/sblock.fs_frag); 117769800Stomsoft acg.cg_cs.cs_nbfree--; 117869800Stomsoft sblock.fs_cstotal.cs_nbfree--; 117969800Stomsoft if(sblock.fs_contigsumsize > 0) { 118069800Stomsoft clrbit(cg_clustersfree(&acg), 118169800Stomsoft (d%sblock.fs_fpg)/sblock.fs_frag); 118269800Stomsoft } 118369800Stomsoft } 118469800Stomsoft 118569800Stomsoft /* 118669800Stomsoft * Allocate all fragments used by the cylinder summary in the 118769800Stomsoft * last block. 118869800Stomsoft */ 118969800Stomsoft if(d<sblock.fs_csaddr+(sblock.fs_cssize/sblock.fs_fsize)) { 119069800Stomsoft for(; d-sblock.fs_csaddr< 119169800Stomsoft sblock.fs_cssize/sblock.fs_fsize; 119269800Stomsoft d++) { 119369800Stomsoft clrbit(cg_blksfree(&acg), d%sblock.fs_fpg); 119469800Stomsoft acg.cg_cs.cs_nffree--; 119569800Stomsoft sblock.fs_cstotal.cs_nffree--; 119669800Stomsoft } 119769800Stomsoft acg.cg_cs.cs_nbfree--; 119869800Stomsoft acg.cg_cs.cs_nffree+=sblock.fs_frag; 119969800Stomsoft sblock.fs_cstotal.cs_nbfree--; 120069800Stomsoft sblock.fs_cstotal.cs_nffree+=sblock.fs_frag; 120169800Stomsoft if(sblock.fs_contigsumsize > 0) { 120269800Stomsoft clrbit(cg_clustersfree(&acg), 120369800Stomsoft (d%sblock.fs_fpg)/sblock.fs_frag); 120469800Stomsoft } 120569800Stomsoft 120669800Stomsoft frag_adjust(d%sblock.fs_fpg, +1); 120769800Stomsoft } 120869800Stomsoft /* 1209114067Sschweikh * XXX Handle the cluster statistics here in the case this 121069800Stomsoft * cylinder group is now almost full, and the remaining 121169800Stomsoft * space is less then the maximum cluster size. This is 121269800Stomsoft * probably not needed, as you would hardly find a file 121369800Stomsoft * system which has only MAXCSBUFS+FS_MAXCONTIG of free 121469800Stomsoft * space right behind the cylinder group information in 121569800Stomsoft * any new cylinder group. 121669800Stomsoft */ 121769800Stomsoft 121869800Stomsoft /* 121969800Stomsoft * Update our statistics in the cylinder summary. 122069800Stomsoft */ 122169800Stomsoft *cs = acg.cg_cs; 122269800Stomsoft 122369800Stomsoft /* 122469800Stomsoft * Write the new cylinder group containing the cylinder summary 122569800Stomsoft * back to disk. 122669800Stomsoft */ 122777885Stomsoft wtfs(fsbtodb(&sblock, cgtod(&sblock, ncscg)), 122877885Stomsoft (size_t)sblock.fs_cgsize, (void *)&acg, fso, Nflag); 122969800Stomsoft DBG_PRINT0("nscg written\n"); 123069926Stomsoft DBG_DUMP_CG(&sblock, 123169926Stomsoft "new summary cg", 123269926Stomsoft &acg); 123369800Stomsoft 123469800Stomsoft DBG_LEAVE; 123569800Stomsoft return; 123669800Stomsoft } 123769800Stomsoft /* 123869800Stomsoft * We have got enough of space in the current cylinder group, so we 1239114067Sschweikh * can relocate just a few blocks, and let the summary information 124069800Stomsoft * grow in place where it is right now. 124169800Stomsoft */ 124269800Stomsoft DBG_TRC; 124369800Stomsoft 124469800Stomsoft cbase = cgbase(&osblock, ocscg); /* old and new are equal */ 124569800Stomsoft dupper = sblock.fs_csaddr - cbase + 124669800Stomsoft howmany(sblock.fs_cssize, sblock.fs_fsize); 124769800Stomsoft odupper = osblock.fs_csaddr - cbase + 124869800Stomsoft howmany(osblock.fs_cssize, osblock.fs_fsize); 124969800Stomsoft 125069800Stomsoft sblock.fs_dsize -= dupper-odupper; 125169800Stomsoft 125269800Stomsoft /* 125369800Stomsoft * Allocate the space for the array of blocks to be relocated. 125469800Stomsoft */ 125569800Stomsoft bp=(struct gfs_bpp *)malloc(((dupper-odupper)/sblock.fs_frag+2)* 125669800Stomsoft sizeof(struct gfs_bpp)); 125769926Stomsoft if(bp == NULL) { 125869926Stomsoft errx(1, "malloc failed"); 125969926Stomsoft } 126077779Stomsoft memset((char *)bp, 0, ((dupper-odupper)/sblock.fs_frag+2)* 126177779Stomsoft sizeof(struct gfs_bpp)); 126269800Stomsoft 126369800Stomsoft /* 1264114067Sschweikh * Lock all new frags needed for the cylinder group summary. This is 1265114067Sschweikh * done per fragment in the first and last block of the new required 126669800Stomsoft * area, and per block for all other blocks. 126769800Stomsoft * 1268114067Sschweikh * Handle the first new block here (but only if some fragments where 126969800Stomsoft * already used for the cylinder summary). 127069800Stomsoft */ 127169800Stomsoft ind=0; 127269800Stomsoft frag_adjust(odupper, -1); 127369800Stomsoft for(d=odupper; ((d<dupper)&&(d%sblock.fs_frag)); d++) { 1274127798Sle DBG_PRINT1("scg first frag check loop d=%jd\n", 1275127798Sle (intmax_t)d); 127669800Stomsoft if(isclr(cg_blksfree(&acg), d)) { 127769800Stomsoft if (!ind) { 127869800Stomsoft bp[ind].old=d/sblock.fs_frag; 127969800Stomsoft bp[ind].flags|=GFS_FL_FIRST; 128069800Stomsoft if(roundup(d, sblock.fs_frag) >= dupper) { 128169800Stomsoft bp[ind].flags|=GFS_FL_LAST; 128269800Stomsoft } 128369800Stomsoft ind++; 128469800Stomsoft } 128569800Stomsoft } else { 128669800Stomsoft clrbit(cg_blksfree(&acg), d); 128769800Stomsoft acg.cg_cs.cs_nffree--; 128869800Stomsoft sblock.fs_cstotal.cs_nffree--; 128969800Stomsoft } 129069800Stomsoft /* 129169800Stomsoft * No cluster handling is needed here, as there was at least 1292114067Sschweikh * one fragment in use by the cylinder summary in the old 1293102231Strhodes * file system. 129469800Stomsoft * No block-free counter handling here as this block was not 129569800Stomsoft * a free block. 129669800Stomsoft */ 129769800Stomsoft } 129869800Stomsoft frag_adjust(odupper, 1); 129969800Stomsoft 130069800Stomsoft /* 130169800Stomsoft * Handle all needed complete blocks here. 130269800Stomsoft */ 130369800Stomsoft for(; d+sblock.fs_frag<=dupper; d+=sblock.fs_frag) { 1304127798Sle DBG_PRINT1("scg block check loop d=%jd\n", 1305127798Sle (intmax_t)d); 130669800Stomsoft if(!isblock(&sblock, cg_blksfree(&acg), d/sblock.fs_frag)) { 130769800Stomsoft for(f=d; f<d+sblock.fs_frag; f++) { 130869800Stomsoft if(isset(cg_blksfree(&aocg), f)) { 130969800Stomsoft acg.cg_cs.cs_nffree--; 131069800Stomsoft sblock.fs_cstotal.cs_nffree--; 131169800Stomsoft } 131269800Stomsoft } 131369800Stomsoft clrblock(&sblock, cg_blksfree(&acg), d/sblock.fs_frag); 131469800Stomsoft bp[ind].old=d/sblock.fs_frag; 131569800Stomsoft ind++; 131669800Stomsoft } else { 131769800Stomsoft clrblock(&sblock, cg_blksfree(&acg), d/sblock.fs_frag); 131869800Stomsoft acg.cg_cs.cs_nbfree--; 131969800Stomsoft sblock.fs_cstotal.cs_nbfree--; 132069800Stomsoft if(sblock.fs_contigsumsize > 0) { 132169800Stomsoft clrbit(cg_clustersfree(&acg), d/sblock.fs_frag); 132269800Stomsoft for(lcs=0, l=(d/sblock.fs_frag)+1; 132369800Stomsoft lcs<sblock.fs_contigsumsize; 132469800Stomsoft l++, lcs++ ) { 132569800Stomsoft if(isclr(cg_clustersfree(&acg),l)){ 132669800Stomsoft break; 132769800Stomsoft } 132869800Stomsoft } 132969800Stomsoft if(lcs < sblock.fs_contigsumsize) { 133069800Stomsoft cg_clustersum(&acg)[lcs+1]--; 133169800Stomsoft if(lcs) { 133269800Stomsoft cg_clustersum(&acg)[lcs]++; 133369800Stomsoft } 133469800Stomsoft } 133569800Stomsoft } 133669800Stomsoft } 133769800Stomsoft /* 133869800Stomsoft * No fragment counter handling is needed here, as this finally 133969800Stomsoft * doesn't change after the relocation. 134069800Stomsoft */ 134169800Stomsoft } 134269800Stomsoft 134369800Stomsoft /* 134469800Stomsoft * Handle all fragments needed in the last new affected block. 134569800Stomsoft */ 134669800Stomsoft if(d<dupper) { 134769800Stomsoft frag_adjust(dupper-1, -1); 134869800Stomsoft 134969800Stomsoft if(isblock(&sblock, cg_blksfree(&acg), d/sblock.fs_frag)) { 135069800Stomsoft acg.cg_cs.cs_nbfree--; 135169800Stomsoft sblock.fs_cstotal.cs_nbfree--; 135269800Stomsoft acg.cg_cs.cs_nffree+=sblock.fs_frag; 135369800Stomsoft sblock.fs_cstotal.cs_nffree+=sblock.fs_frag; 135469800Stomsoft if(sblock.fs_contigsumsize > 0) { 135569800Stomsoft clrbit(cg_clustersfree(&acg), d/sblock.fs_frag); 135669800Stomsoft for(lcs=0, l=(d/sblock.fs_frag)+1; 135769800Stomsoft lcs<sblock.fs_contigsumsize; 135869800Stomsoft l++, lcs++ ) { 135969800Stomsoft if(isclr(cg_clustersfree(&acg),l)){ 136069800Stomsoft break; 136169800Stomsoft } 136269800Stomsoft } 136369800Stomsoft if(lcs < sblock.fs_contigsumsize) { 136469800Stomsoft cg_clustersum(&acg)[lcs+1]--; 136569800Stomsoft if(lcs) { 136669800Stomsoft cg_clustersum(&acg)[lcs]++; 136769800Stomsoft } 136869800Stomsoft } 136969800Stomsoft } 137069800Stomsoft } 137169800Stomsoft 137269800Stomsoft for(; d<dupper; d++) { 1373127798Sle DBG_PRINT1("scg second frag check loop d=%jd\n", 1374127798Sle (intmax_t)d); 137569800Stomsoft if(isclr(cg_blksfree(&acg), d)) { 137669800Stomsoft bp[ind].old=d/sblock.fs_frag; 137769800Stomsoft bp[ind].flags|=GFS_FL_LAST; 137869800Stomsoft } else { 137969800Stomsoft clrbit(cg_blksfree(&acg), d); 138069800Stomsoft acg.cg_cs.cs_nffree--; 138169800Stomsoft sblock.fs_cstotal.cs_nffree--; 138269800Stomsoft } 138369800Stomsoft } 138469800Stomsoft if(bp[ind].flags & GFS_FL_LAST) { /* we have to advance here */ 138569800Stomsoft ind++; 138669800Stomsoft } 138769800Stomsoft frag_adjust(dupper-1, 1); 138869800Stomsoft } 138969800Stomsoft 139069800Stomsoft /* 139169800Stomsoft * If we found a block to relocate just do so. 139269800Stomsoft */ 139369800Stomsoft if(ind) { 139469800Stomsoft for(i=0; i<ind; i++) { 139569800Stomsoft if(!bp[i].old) { /* no more blocks listed */ 139669800Stomsoft /* 139769800Stomsoft * XXX A relative blocknumber should not be 1398114067Sschweikh * zero, which is not explicitly 139969800Stomsoft * guaranteed by our code. 140069800Stomsoft */ 140169800Stomsoft break; 140269800Stomsoft } 140369800Stomsoft /* 140469800Stomsoft * Allocate a complete block in the same (current) 140569800Stomsoft * cylinder group. 140669800Stomsoft */ 140769800Stomsoft bp[i].new=alloc()/sblock.fs_frag; 140869800Stomsoft 140969800Stomsoft /* 141069800Stomsoft * There is no frag_adjust() needed for the new block 141169800Stomsoft * as it will have no fragments yet :-). 141269800Stomsoft */ 141369800Stomsoft for(f=bp[i].old*sblock.fs_frag, 141469800Stomsoft g=bp[i].new*sblock.fs_frag; 141569800Stomsoft f<(bp[i].old+1)*sblock.fs_frag; 141669800Stomsoft f++, g++) { 141769800Stomsoft if(isset(cg_blksfree(&aocg), f)) { 141869800Stomsoft setbit(cg_blksfree(&acg), g); 141969800Stomsoft acg.cg_cs.cs_nffree++; 142069800Stomsoft sblock.fs_cstotal.cs_nffree++; 142169800Stomsoft } 142269800Stomsoft } 142369800Stomsoft 142469800Stomsoft /* 1425114067Sschweikh * Special handling is required if this was the first 142669800Stomsoft * block. We have to consider the fragments which were 1427114067Sschweikh * used by the cylinder summary in the original block 1428114067Sschweikh * which re to be free in the copy of our block. We 1429114067Sschweikh * have to be careful if this first block happens to 143069800Stomsoft * be also the last block to be relocated. 143169800Stomsoft */ 143269800Stomsoft if(bp[i].flags & GFS_FL_FIRST) { 143369800Stomsoft for(f=bp[i].old*sblock.fs_frag, 143469800Stomsoft g=bp[i].new*sblock.fs_frag; 143569800Stomsoft f<odupper; 143669800Stomsoft f++, g++) { 143769800Stomsoft setbit(cg_blksfree(&acg), g); 143869800Stomsoft acg.cg_cs.cs_nffree++; 143969800Stomsoft sblock.fs_cstotal.cs_nffree++; 144069800Stomsoft } 144169800Stomsoft if(!(bp[i].flags & GFS_FL_LAST)) { 144269800Stomsoft frag_adjust(bp[i].new*sblock.fs_frag,1); 144369800Stomsoft } 144469800Stomsoft } 144569800Stomsoft 144669800Stomsoft /* 144769800Stomsoft * Special handling is required if this is the last 144869800Stomsoft * block to be relocated. 144969800Stomsoft */ 145069800Stomsoft if(bp[i].flags & GFS_FL_LAST) { 145169800Stomsoft frag_adjust(bp[i].new*sblock.fs_frag, 1); 145269800Stomsoft frag_adjust(bp[i].old*sblock.fs_frag, -1); 145369800Stomsoft for(f=dupper; 145469800Stomsoft f<roundup(dupper, sblock.fs_frag); 145569800Stomsoft f++) { 145669800Stomsoft if(isclr(cg_blksfree(&acg), f)) { 145769800Stomsoft setbit(cg_blksfree(&acg), f); 145869800Stomsoft acg.cg_cs.cs_nffree++; 145969800Stomsoft sblock.fs_cstotal.cs_nffree++; 146069800Stomsoft } 146169800Stomsoft } 146269800Stomsoft frag_adjust(bp[i].old*sblock.fs_frag, 1); 146369800Stomsoft } 146469800Stomsoft 146569800Stomsoft /* 1466114067Sschweikh * !!! Attach the cylindergroup offset here. 146769800Stomsoft */ 146869800Stomsoft bp[i].old+=cbase/sblock.fs_frag; 146969800Stomsoft bp[i].new+=cbase/sblock.fs_frag; 147069800Stomsoft 147169800Stomsoft /* 147269800Stomsoft * Copy the content of the block. 147369800Stomsoft */ 147469800Stomsoft /* 147569800Stomsoft * XXX Here we will have to implement a copy on write 147669800Stomsoft * in the case we have any active snapshots. 147769800Stomsoft */ 147869800Stomsoft rdfs(fsbtodb(&sblock, bp[i].old*sblock.fs_frag), 147977885Stomsoft (size_t)sblock.fs_bsize, (void *)&ablk, fsi); 148069800Stomsoft wtfs(fsbtodb(&sblock, bp[i].new*sblock.fs_frag), 148177885Stomsoft (size_t)sblock.fs_bsize, (void *)&ablk, fso, Nflag); 148269926Stomsoft DBG_DUMP_HEX(&sblock, 148369926Stomsoft "copied full block", 148469926Stomsoft (unsigned char *)&ablk); 148569800Stomsoft 1486127798Sle DBG_PRINT2("scg (%jd->%jd) block relocated\n", 1487127798Sle (intmax_t)bp[i].old, 1488127798Sle (intmax_t)bp[i].new); 148969800Stomsoft } 149069800Stomsoft 149169800Stomsoft /* 149269800Stomsoft * Now we have to update all references to any fragment which 1493114067Sschweikh * belongs to any block relocated. We iterate now over all 1494114067Sschweikh * cylinder groups, within those over all non zero length 149569800Stomsoft * inodes. 149669800Stomsoft */ 149769800Stomsoft for(cylno=0; cylno<osblock.fs_ncg; cylno++) { 149869926Stomsoft DBG_PRINT1("scg doing cg (%d)\n", 149969926Stomsoft cylno); 1500136289Sscottl for(inc=osblock.fs_ipg-1 ; inc>0 ; inc--) { 150169800Stomsoft updrefs(cylno, (ino_t)inc, bp, fsi, fso, Nflag); 150269800Stomsoft } 150369800Stomsoft } 150469800Stomsoft 150569800Stomsoft /* 150669800Stomsoft * All inodes are checked, now make sure the number of 150769800Stomsoft * references found make sense. 150869800Stomsoft */ 150969800Stomsoft for(i=0; i<ind; i++) { 151069800Stomsoft if(!bp[i].found || (bp[i].found>sblock.fs_frag)) { 1511127798Sle warnx("error: %jd refs found for block %jd.", 1512127798Sle (intmax_t)bp[i].found, (intmax_t)bp[i].old); 151369800Stomsoft } 151469800Stomsoft 151569800Stomsoft } 151669800Stomsoft } 151769800Stomsoft /* 151869800Stomsoft * The following statistics are not changed here: 151969800Stomsoft * sblock.fs_cstotal.cs_ndir 152069800Stomsoft * sblock.fs_cstotal.cs_nifree 152169800Stomsoft * The following statistics were already updated on the fly: 152269800Stomsoft * sblock.fs_cstotal.cs_nffree 152369800Stomsoft * sblock.fs_cstotal.cs_nbfree 152469800Stomsoft * As the statistics for this cylinder group are ready, copy it to 152569800Stomsoft * the summary information array. 152669800Stomsoft */ 152769800Stomsoft 152869800Stomsoft *cs = acg.cg_cs; 152969800Stomsoft 153069800Stomsoft /* 153169800Stomsoft * Write summary cylinder group back to disk. 153269800Stomsoft */ 153377885Stomsoft wtfs(fsbtodb(&sblock, cgtod(&sblock, ocscg)), (size_t)sblock.fs_cgsize, 153477885Stomsoft (void *)&acg, fso, Nflag); 153569800Stomsoft DBG_PRINT0("scg written\n"); 153669926Stomsoft DBG_DUMP_CG(&sblock, 153769926Stomsoft "new summary cg", 153869926Stomsoft &acg); 153969800Stomsoft 154069800Stomsoft DBG_LEAVE; 154169800Stomsoft return; 154269800Stomsoft} 154369800Stomsoft 154469800Stomsoft/* ************************************************************** rdfs ***** */ 154569800Stomsoft/* 154669800Stomsoft * Here we read some block(s) from disk. 154769800Stomsoft */ 154869800Stomsoftstatic void 154998542Smckusickrdfs(ufs2_daddr_t bno, size_t size, void *bf, int fsi) 155069800Stomsoft{ 155169800Stomsoft DBG_FUNC("rdfs") 155277885Stomsoft ssize_t n; 155369800Stomsoft 155469800Stomsoft DBG_ENTER; 155569800Stomsoft 1556136289Sscottl if (bno < 0) { 1557140351Scharnier err(32, "rdfs: attempting to read negative block number"); 1558136289Sscottl } 155969800Stomsoft if (lseek(fsi, (off_t)bno * DEV_BSIZE, 0) < 0) { 1560127798Sle err(33, "rdfs: seek error: %jd", (intmax_t)bno); 156169800Stomsoft } 156277885Stomsoft n = read(fsi, bf, size); 156377885Stomsoft if (n != (ssize_t)size) { 1564127798Sle err(34, "rdfs: read error: %jd", (intmax_t)bno); 156569800Stomsoft } 156669800Stomsoft 156769800Stomsoft DBG_LEAVE; 156869800Stomsoft return; 156969800Stomsoft} 157069800Stomsoft 157169800Stomsoft/* ************************************************************** wtfs ***** */ 157269800Stomsoft/* 157369800Stomsoft * Here we write some block(s) to disk. 157469800Stomsoft */ 157569800Stomsoftstatic void 157698542Smckusickwtfs(ufs2_daddr_t bno, size_t size, void *bf, int fso, unsigned int Nflag) 157769800Stomsoft{ 157869800Stomsoft DBG_FUNC("wtfs") 157977885Stomsoft ssize_t n; 158069800Stomsoft 158169800Stomsoft DBG_ENTER; 158269800Stomsoft 158369800Stomsoft if (Nflag) { 158469800Stomsoft DBG_LEAVE; 158569800Stomsoft return; 158669800Stomsoft } 158769800Stomsoft if (lseek(fso, (off_t)bno * DEV_BSIZE, SEEK_SET) < 0) { 158869926Stomsoft err(35, "wtfs: seek error: %ld", (long)bno); 158969800Stomsoft } 159077885Stomsoft n = write(fso, bf, size); 159177885Stomsoft if (n != (ssize_t)size) { 159269926Stomsoft err(36, "wtfs: write error: %ld", (long)bno); 159369800Stomsoft } 159469800Stomsoft 159569800Stomsoft DBG_LEAVE; 159669800Stomsoft return; 159769800Stomsoft} 159869800Stomsoft 159969800Stomsoft/* ************************************************************* alloc ***** */ 160069800Stomsoft/* 160169800Stomsoft * Here we allocate a free block in the current cylinder group. It is assumed, 1602114067Sschweikh * that acg contains the current cylinder group. As we may take a block from 1603102231Strhodes * somewhere in the file system we have to handle cluster summary here. 160469800Stomsoft */ 160598542Smckusickstatic ufs2_daddr_t 160669800Stomsoftalloc(void) 160769800Stomsoft{ 160869800Stomsoft DBG_FUNC("alloc") 160998542Smckusick ufs2_daddr_t d, blkno; 161069800Stomsoft int lcs1, lcs2; 161169800Stomsoft int l; 161269800Stomsoft int csmin, csmax; 161369800Stomsoft int dlower, dupper, dmax; 161469800Stomsoft 161569800Stomsoft DBG_ENTER; 161669800Stomsoft 161769800Stomsoft if (acg.cg_magic != CG_MAGIC) { 161869926Stomsoft warnx("acg: bad magic number"); 161969800Stomsoft DBG_LEAVE; 162069800Stomsoft return (0); 162169800Stomsoft } 162269800Stomsoft if (acg.cg_cs.cs_nbfree == 0) { 162369926Stomsoft warnx("error: cylinder group ran out of space"); 162469800Stomsoft DBG_LEAVE; 162569800Stomsoft return (0); 162669800Stomsoft } 162769800Stomsoft /* 162869800Stomsoft * We start seeking for free blocks only from the space available after 1629114067Sschweikh * the end of the new grown cylinder summary. Otherwise we allocate a 163069800Stomsoft * block here which we have to relocate a couple of seconds later again 163169800Stomsoft * again, and we are not prepared to to this anyway. 163269800Stomsoft */ 163369800Stomsoft blkno=-1; 163469800Stomsoft dlower=cgsblock(&sblock, acg.cg_cgx)-cgbase(&sblock, acg.cg_cgx); 163569800Stomsoft dupper=cgdmin(&sblock, acg.cg_cgx)-cgbase(&sblock, acg.cg_cgx); 163669800Stomsoft dmax=cgbase(&sblock, acg.cg_cgx)+sblock.fs_fpg; 163769800Stomsoft if (dmax > sblock.fs_size) { 163869800Stomsoft dmax = sblock.fs_size; 163969800Stomsoft } 164069800Stomsoft dmax-=cgbase(&sblock, acg.cg_cgx); /* retransform into cg */ 164169800Stomsoft csmin=sblock.fs_csaddr-cgbase(&sblock, acg.cg_cgx); 164269800Stomsoft csmax=csmin+howmany(sblock.fs_cssize, sblock.fs_fsize); 164369926Stomsoft DBG_PRINT3("seek range: dl=%d, du=%d, dm=%d\n", 164469926Stomsoft dlower, 164569926Stomsoft dupper, 164669926Stomsoft dmax); 164769926Stomsoft DBG_PRINT2("range cont: csmin=%d, csmax=%d\n", 164869926Stomsoft csmin, 164969926Stomsoft csmax); 165069800Stomsoft 165169800Stomsoft for(d=0; (d<dlower && blkno==-1); d+=sblock.fs_frag) { 165269800Stomsoft if(d>=csmin && d<=csmax) { 165369800Stomsoft continue; 165469800Stomsoft } 165569800Stomsoft if(isblock(&sblock, cg_blksfree(&acg), fragstoblks(&sblock, 165669800Stomsoft d))) { 165769800Stomsoft blkno = fragstoblks(&sblock, d);/* Yeah found a block */ 165869800Stomsoft break; 165969800Stomsoft } 166069800Stomsoft } 166169800Stomsoft for(d=dupper; (d<dmax && blkno==-1); d+=sblock.fs_frag) { 166269800Stomsoft if(d>=csmin && d<=csmax) { 166369800Stomsoft continue; 166469800Stomsoft } 166569800Stomsoft if(isblock(&sblock, cg_blksfree(&acg), fragstoblks(&sblock, 166669800Stomsoft d))) { 166769800Stomsoft blkno = fragstoblks(&sblock, d);/* Yeah found a block */ 166869800Stomsoft break; 166969800Stomsoft } 167069800Stomsoft } 167169800Stomsoft if(blkno==-1) { 167269926Stomsoft warnx("internal error: couldn't find promised block in cg"); 167369800Stomsoft DBG_LEAVE; 167469800Stomsoft return (0); 167569800Stomsoft } 167669800Stomsoft 167769800Stomsoft /* 167869800Stomsoft * This is needed if the block was found already in the first loop. 167969800Stomsoft */ 168069800Stomsoft d=blkstofrags(&sblock, blkno); 168169800Stomsoft 168269800Stomsoft clrblock(&sblock, cg_blksfree(&acg), blkno); 168369800Stomsoft if (sblock.fs_contigsumsize > 0) { 168469800Stomsoft /* 168569800Stomsoft * Handle the cluster allocation bitmap. 168669800Stomsoft */ 168769800Stomsoft clrbit(cg_clustersfree(&acg), blkno); 168869800Stomsoft /* 1689114067Sschweikh * We possibly have split a cluster here, so we have to do 169069926Stomsoft * recalculate the sizes of the remaining cluster halves now, 169169800Stomsoft * and use them for updating the cluster summary information. 169269800Stomsoft * 169369800Stomsoft * Lets start with the blocks before our allocated block ... 169469800Stomsoft */ 169569800Stomsoft for(lcs1=0, l=blkno-1; lcs1<sblock.fs_contigsumsize; 169669800Stomsoft l--, lcs1++ ) { 169769800Stomsoft if(isclr(cg_clustersfree(&acg),l)){ 169869800Stomsoft break; 169969800Stomsoft } 170069800Stomsoft } 170169800Stomsoft /* 170269800Stomsoft * ... and continue with the blocks right after our allocated 170369800Stomsoft * block. 170469800Stomsoft */ 170569800Stomsoft for(lcs2=0, l=blkno+1; lcs2<sblock.fs_contigsumsize; 170669800Stomsoft l++, lcs2++ ) { 170769800Stomsoft if(isclr(cg_clustersfree(&acg),l)){ 170869800Stomsoft break; 170969800Stomsoft } 171069800Stomsoft } 171169800Stomsoft 171269800Stomsoft /* 171369800Stomsoft * Now update all counters. 171469800Stomsoft */ 171569800Stomsoft cg_clustersum(&acg)[MIN(lcs1+lcs2+1,sblock.fs_contigsumsize)]--; 171669800Stomsoft if(lcs1) { 171769800Stomsoft cg_clustersum(&acg)[lcs1]++; 171869800Stomsoft } 171969800Stomsoft if(lcs2) { 172069800Stomsoft cg_clustersum(&acg)[lcs2]++; 172169800Stomsoft } 172269800Stomsoft } 172369800Stomsoft /* 172469800Stomsoft * Update all statistics based on blocks. 172569800Stomsoft */ 172669800Stomsoft acg.cg_cs.cs_nbfree--; 172769800Stomsoft sblock.fs_cstotal.cs_nbfree--; 172869800Stomsoft 172969800Stomsoft DBG_LEAVE; 173069800Stomsoft return (d); 173169800Stomsoft} 173269800Stomsoft 173369800Stomsoft/* *********************************************************** isblock ***** */ 173469800Stomsoft/* 1735114067Sschweikh * Here we check if all frags of a block are free. For more details again 173669800Stomsoft * please see the source of newfs(8), as this function is taken over almost 173769800Stomsoft * unchanged. 173869800Stomsoft */ 173969800Stomsoftstatic int 174069800Stomsoftisblock(struct fs *fs, unsigned char *cp, int h) 174169800Stomsoft{ 174269800Stomsoft DBG_FUNC("isblock") 174369800Stomsoft unsigned char mask; 174469800Stomsoft 174569800Stomsoft DBG_ENTER; 174669800Stomsoft 174769800Stomsoft switch (fs->fs_frag) { 174869800Stomsoft case 8: 174969800Stomsoft DBG_LEAVE; 175069800Stomsoft return (cp[h] == 0xff); 175169800Stomsoft case 4: 175269800Stomsoft mask = 0x0f << ((h & 0x1) << 2); 175369800Stomsoft DBG_LEAVE; 175469800Stomsoft return ((cp[h >> 1] & mask) == mask); 175569800Stomsoft case 2: 175669800Stomsoft mask = 0x03 << ((h & 0x3) << 1); 175769800Stomsoft DBG_LEAVE; 175869800Stomsoft return ((cp[h >> 2] & mask) == mask); 175969800Stomsoft case 1: 176069800Stomsoft mask = 0x01 << (h & 0x7); 176169800Stomsoft DBG_LEAVE; 176269800Stomsoft return ((cp[h >> 3] & mask) == mask); 176369800Stomsoft default: 176469800Stomsoft fprintf(stderr, "isblock bad fs_frag %d\n", fs->fs_frag); 176569800Stomsoft DBG_LEAVE; 176669800Stomsoft return (0); 176769800Stomsoft } 176869800Stomsoft} 176969800Stomsoft 177069800Stomsoft/* ********************************************************** clrblock ***** */ 177169800Stomsoft/* 177269800Stomsoft * Here we allocate a complete block in the block map. For more details again 1773114067Sschweikh * please see the source of newfs(8), as this function is taken over almost 177469800Stomsoft * unchanged. 177569800Stomsoft */ 177669800Stomsoftstatic void 177769800Stomsoftclrblock(struct fs *fs, unsigned char *cp, int h) 177869800Stomsoft{ 177969800Stomsoft DBG_FUNC("clrblock") 178069800Stomsoft 178169800Stomsoft DBG_ENTER; 178269800Stomsoft 178369800Stomsoft switch ((fs)->fs_frag) { 178469800Stomsoft case 8: 178569800Stomsoft cp[h] = 0; 178669800Stomsoft break; 178769800Stomsoft case 4: 178869800Stomsoft cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); 178969800Stomsoft break; 179069800Stomsoft case 2: 179169800Stomsoft cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); 179269800Stomsoft break; 179369800Stomsoft case 1: 179469800Stomsoft cp[h >> 3] &= ~(0x01 << (h & 0x7)); 179569800Stomsoft break; 179669800Stomsoft default: 179769926Stomsoft warnx("clrblock bad fs_frag %d", fs->fs_frag); 179869800Stomsoft break; 179969800Stomsoft } 180069800Stomsoft 180169800Stomsoft DBG_LEAVE; 180269800Stomsoft return; 180369800Stomsoft} 180469800Stomsoft 180569800Stomsoft/* ********************************************************** setblock ***** */ 180669800Stomsoft/* 180769800Stomsoft * Here we free a complete block in the free block map. For more details again 1808114067Sschweikh * please see the source of newfs(8), as this function is taken over almost 180969800Stomsoft * unchanged. 181069800Stomsoft */ 181169800Stomsoftstatic void 181269800Stomsoftsetblock(struct fs *fs, unsigned char *cp, int h) 181369800Stomsoft{ 181469800Stomsoft DBG_FUNC("setblock") 181569800Stomsoft 181669800Stomsoft DBG_ENTER; 181769800Stomsoft 181869800Stomsoft switch (fs->fs_frag) { 181969800Stomsoft case 8: 182069800Stomsoft cp[h] = 0xff; 182169800Stomsoft break; 182269800Stomsoft case 4: 182369800Stomsoft cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); 182469800Stomsoft break; 182569800Stomsoft case 2: 182669800Stomsoft cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); 182769800Stomsoft break; 182869800Stomsoft case 1: 182969800Stomsoft cp[h >> 3] |= (0x01 << (h & 0x7)); 183069800Stomsoft break; 183169800Stomsoft default: 183269926Stomsoft warnx("setblock bad fs_frag %d", fs->fs_frag); 183369800Stomsoft break; 183469800Stomsoft } 183569800Stomsoft 183669800Stomsoft DBG_LEAVE; 183769800Stomsoft return; 183869800Stomsoft} 183969800Stomsoft 184069800Stomsoft/* ************************************************************ ginode ***** */ 184169800Stomsoft/* 184269800Stomsoft * This function provides access to an individual inode. We find out in which 1843114067Sschweikh * block the requested inode is located, read it from disk if needed, and 1844114067Sschweikh * return the pointer into that block. We maintain a cache of one block to 1845114067Sschweikh * not read the same block again and again if we iterate linearly over all 184669800Stomsoft * inodes. 184769800Stomsoft */ 184898542Smckusickstatic union dinode * 184969800Stomsoftginode(ino_t inumber, int fsi, int cg) 185069800Stomsoft{ 185169800Stomsoft DBG_FUNC("ginode") 185298542Smckusick static ino_t startinum = 0; /* first inode in cached block */ 185369800Stomsoft 185469800Stomsoft DBG_ENTER; 185569800Stomsoft 1856136289Sscottl /* 1857136289Sscottl * The inumber passed in is relative to the cg, so use it here to see 1858136289Sscottl * if the inode has been allocated yet. 1859136289Sscottl */ 1860127469Sle if (isclr(cg_inosused(&aocg), inumber)) { 1861127469Sle DBG_LEAVE; 1862127469Sle return NULL; 1863127469Sle } 1864136289Sscottl /* 1865136289Sscottl * Now make the inumber relative to the entire inode space so it can 1866136289Sscottl * be sanity checked. 1867136289Sscottl */ 1868136289Sscottl inumber += (cg * sblock.fs_ipg); 1869136289Sscottl if (inumber < ROOTINO) { 1870136289Sscottl DBG_LEAVE; 1871136289Sscottl return NULL; 1872136289Sscottl } 1873136289Sscottl if (inumber > maxino) 187498542Smckusick errx(8, "bad inode number %d to ginode", inumber); 187598542Smckusick if (startinum == 0 || 187698542Smckusick inumber < startinum || inumber >= startinum + INOPB(&sblock)) { 187798542Smckusick inoblk = fsbtodb(&sblock, ino_to_fsba(&sblock, inumber)); 187898542Smckusick rdfs(inoblk, (size_t)sblock.fs_bsize, inobuf, fsi); 187969800Stomsoft startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); 188069800Stomsoft } 188169800Stomsoft DBG_LEAVE; 188298542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 1883127818Smux return (union dinode *)((uintptr_t)inobuf + 1884127818Smux (inumber % INOPB(&sblock)) * sizeof(struct ufs1_dinode)); 1885127818Smux return (union dinode *)((uintptr_t)inobuf + 1886127818Smux (inumber % INOPB(&sblock)) * sizeof(struct ufs2_dinode)); 188769800Stomsoft} 188869800Stomsoft 188969800Stomsoft/* ****************************************************** charsperline ***** */ 189069800Stomsoft/* 189169800Stomsoft * Figure out how many lines our current terminal has. For more details again 1892114067Sschweikh * please see the source of newfs(8), as this function is taken over almost 189369800Stomsoft * unchanged. 189469800Stomsoft */ 189569800Stomsoftstatic int 189669800Stomsoftcharsperline(void) 189769800Stomsoft{ 189869800Stomsoft DBG_FUNC("charsperline") 189969800Stomsoft int columns; 190069800Stomsoft char *cp; 190169800Stomsoft struct winsize ws; 190269800Stomsoft 190369800Stomsoft DBG_ENTER; 190469800Stomsoft 190569800Stomsoft columns = 0; 190669800Stomsoft if (ioctl(0, TIOCGWINSZ, &ws) != -1) { 190769800Stomsoft columns = ws.ws_col; 190869800Stomsoft } 190969800Stomsoft if (columns == 0 && (cp = getenv("COLUMNS"))) { 191069800Stomsoft columns = atoi(cp); 191169800Stomsoft } 191269800Stomsoft if (columns == 0) { 191369800Stomsoft columns = 80; /* last resort */ 191469800Stomsoft } 191569800Stomsoft 191669800Stomsoft DBG_LEAVE; 191769800Stomsoft return columns; 191869800Stomsoft} 191969800Stomsoft 1920114936Sgrog/* ****************************************************** get_dev_size ***** */ 1921114936Sgrog/* 1922114936Sgrog * Get the size of the partition if we can't figure it out from the disklabel, 1923114936Sgrog * e.g. from vinum volumes. 1924114936Sgrog */ 1925114936Sgrogstatic void 1926114936Sgrogget_dev_size(int fd, int *size) 1927114936Sgrog{ 1928114936Sgrog int sectorsize; 1929114936Sgrog off_t mediasize; 1930114936Sgrog 1931114936Sgrog if (ioctl(fd, DIOCGSECTORSIZE, §orsize) == -1) 1932114936Sgrog err(1,"DIOCGSECTORSIZE"); 1933114936Sgrog if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) == -1) 1934114936Sgrog err(1,"DIOCGMEDIASIZE"); 1935114936Sgrog 1936114936Sgrog if (sectorsize <= 0) 1937114936Sgrog errx(1, "bogus sectorsize: %d", sectorsize); 1938114936Sgrog 1939114936Sgrog *size = mediasize / sectorsize; 1940114936Sgrog} 1941114936Sgrog 194269800Stomsoft/* ************************************************************** main ***** */ 194369800Stomsoft/* 1944114067Sschweikh * growfs(8) is a utility which allows to increase the size of an existing 1945114067Sschweikh * ufs file system. Currently this can only be done on unmounted file system. 1946114067Sschweikh * It recognizes some command line options to specify the new desired size, 1947114067Sschweikh * and it does some basic checkings. The old file system size is determined 1948114067Sschweikh * and after some more checks like we can really access the new last block 194969800Stomsoft * on the disk etc. we calculate the new parameters for the superblock. After 1950114067Sschweikh * having done this we just call growfs() which will do the work. Before 195169800Stomsoft * we finish the only thing left is to update the disklabel. 195269800Stomsoft * We still have to provide support for snapshots. Therefore we first have to 1953114067Sschweikh * understand what data structures are always replicated in the snapshot on 1954114067Sschweikh * creation, for all other blocks we touch during our procedure, we have to 195569926Stomsoft * keep the old blocks unchanged somewhere available for the snapshots. If we 1956114067Sschweikh * are lucky, then we only have to handle our blocks to be relocated in that 195769800Stomsoft * way. 1958114067Sschweikh * Also we have to consider in what order we actually update the critical 1959102231Strhodes * data structures of the file system to make sure, that in case of a disaster 196069800Stomsoft * fsck(8) is still able to restore any lost data. 1961114067Sschweikh * The foreseen last step then will be to provide for growing even mounted 1962114067Sschweikh * file systems. There we have to extend the mount() system call to provide 1963102231Strhodes * userland access to the file system locking facility. 196469800Stomsoft */ 196569800Stomsoftint 196669800Stomsoftmain(int argc, char **argv) 196769800Stomsoft{ 196869800Stomsoft DBG_FUNC("main") 196969926Stomsoft char *device, *special, *cp; 1970127816Smux int ch; 197177885Stomsoft unsigned int size=0; 197269800Stomsoft size_t len; 197377885Stomsoft unsigned int Nflag=0; 197469800Stomsoft int ExpertFlag=0; 197569800Stomsoft struct stat st; 197669800Stomsoft struct disklabel *lp; 197769800Stomsoft struct partition *pp; 197898542Smckusick int i,fsi,fso; 1979114936Sgrog u_int32_t p_size; 198069800Stomsoft char reply[5]; 198169800Stomsoft#ifdef FSMAXSNAP 198269800Stomsoft int j; 198369800Stomsoft#endif /* FSMAXSNAP */ 198469800Stomsoft 198569800Stomsoft DBG_ENTER; 198669800Stomsoft 198769800Stomsoft while((ch=getopt(argc, argv, "Ns:vy")) != -1) { 198869800Stomsoft switch(ch) { 198969800Stomsoft case 'N': 199069800Stomsoft Nflag=1; 199169800Stomsoft break; 199269800Stomsoft case 's': 199369800Stomsoft size=(size_t)atol(optarg); 199469800Stomsoft if(size<1) { 199569926Stomsoft usage(); 199669800Stomsoft } 199769800Stomsoft break; 199869800Stomsoft case 'v': /* for compatibility to newfs */ 199969800Stomsoft break; 200069800Stomsoft case 'y': 200169800Stomsoft ExpertFlag=1; 200269800Stomsoft break; 200369800Stomsoft case '?': 200469800Stomsoft /* FALLTHROUGH */ 200569800Stomsoft default: 200669926Stomsoft usage(); 200769800Stomsoft } 200869800Stomsoft } 200969800Stomsoft argc -= optind; 201069800Stomsoft argv += optind; 201169800Stomsoft 201269800Stomsoft if(argc != 1) { 201369926Stomsoft usage(); 201469800Stomsoft } 201569800Stomsoft device=*argv; 201669800Stomsoft 201769800Stomsoft /* 201869800Stomsoft * Now try to guess the (raw)device name. 201969800Stomsoft */ 202069800Stomsoft if (0 == strrchr(device, '/')) { 202169800Stomsoft /* 202269800Stomsoft * No path prefix was given, so try in that order: 202369800Stomsoft * /dev/r%s 202469800Stomsoft * /dev/%s 202569800Stomsoft * /dev/vinum/r%s 202669800Stomsoft * /dev/vinum/%s. 2027114067Sschweikh * 2028114067Sschweikh * FreeBSD now doesn't distinguish between raw and block 202969800Stomsoft * devices any longer, but it should still work this way. 203069800Stomsoft */ 203169800Stomsoft len=strlen(device)+strlen(_PATH_DEV)+2+strlen("vinum/"); 203269800Stomsoft special=(char *)malloc(len); 203369926Stomsoft if(special == NULL) { 203469926Stomsoft errx(1, "malloc failed"); 203569926Stomsoft } 203669800Stomsoft snprintf(special, len, "%sr%s", _PATH_DEV, device); 203769800Stomsoft if (stat(special, &st) == -1) { 203869800Stomsoft snprintf(special, len, "%s%s", _PATH_DEV, device); 203969800Stomsoft if (stat(special, &st) == -1) { 204069800Stomsoft snprintf(special, len, "%svinum/r%s", 204169800Stomsoft _PATH_DEV, device); 204269800Stomsoft if (stat(special, &st) == -1) { 204369800Stomsoft /* For now this is the 'last resort' */ 204469800Stomsoft snprintf(special, len, "%svinum/%s", 204569800Stomsoft _PATH_DEV, device); 204669800Stomsoft } 204769800Stomsoft } 204869800Stomsoft } 204969800Stomsoft device = special; 205069800Stomsoft } 205169800Stomsoft 205269800Stomsoft /* 205369800Stomsoft * Try to access our devices for writing ... 205469800Stomsoft */ 205569800Stomsoft if (Nflag) { 205669800Stomsoft fso = -1; 205769800Stomsoft } else { 205869800Stomsoft fso = open(device, O_WRONLY); 205969800Stomsoft if (fso < 0) { 206069926Stomsoft err(1, "%s", device); 206169800Stomsoft } 206269800Stomsoft } 206369800Stomsoft 206469800Stomsoft /* 206569800Stomsoft * ... and reading. 206669800Stomsoft */ 206769800Stomsoft fsi = open(device, O_RDONLY); 206869800Stomsoft if (fsi < 0) { 206969926Stomsoft err(1, "%s", device); 207069800Stomsoft } 207169800Stomsoft 207269800Stomsoft /* 2073114067Sschweikh * Try to read a label and guess the slice if not specified. This 2074114067Sschweikh * code should guess the right thing and avoid to bother the user 2075114067Sschweikh * with the task of specifying the option -v on vinum volumes. 207669800Stomsoft */ 207769800Stomsoft cp=device+strlen(device)-1; 207869800Stomsoft lp = get_disklabel(fsi); 2079127798Sle pp = NULL; 2080114936Sgrog if (lp != NULL) { 2081114936Sgrog if (isdigit(*cp)) { 2082114936Sgrog pp = &lp->d_partitions[2]; 2083114936Sgrog } else if (*cp>='a' && *cp<='h') { 2084114936Sgrog pp = &lp->d_partitions[*cp - 'a']; 2085114936Sgrog } else { 2086114936Sgrog errx(1, "unknown device"); 2087114936Sgrog } 2088114936Sgrog p_size = pp->p_size; 2089114936Sgrog } else { 2090114936Sgrog get_dev_size(fsi, &p_size); 2091114936Sgrog } 209269800Stomsoft 209369800Stomsoft /* 2094114067Sschweikh * Check if that partition is suitable for growing a file system. 209569800Stomsoft */ 2096114936Sgrog if (p_size < 1) { 209769926Stomsoft errx(1, "partition is unavailable"); 209869800Stomsoft } 209969800Stomsoft 210069800Stomsoft /* 210169800Stomsoft * Read the current superblock, and take a backup. 210269800Stomsoft */ 210398542Smckusick for (i = 0; sblock_try[i] != -1; i++) { 210498542Smckusick sblockloc = sblock_try[i] / DEV_BSIZE; 210598542Smckusick rdfs(sblockloc, (size_t)SBLOCKSIZE, (void *)&(osblock), fsi); 210698542Smckusick if ((osblock.fs_magic == FS_UFS1_MAGIC || 210798542Smckusick (osblock.fs_magic == FS_UFS2_MAGIC && 2108107294Smckusick osblock.fs_sblockloc == sblock_try[i])) && 210998542Smckusick osblock.fs_bsize <= MAXBSIZE && 2110127798Sle osblock.fs_bsize >= (int32_t) sizeof(struct fs)) 211198542Smckusick break; 211298542Smckusick } 211398542Smckusick if (sblock_try[i] == -1) { 211469926Stomsoft errx(1, "superblock not recognized"); 211569800Stomsoft } 211669800Stomsoft memcpy((void *)&fsun1, (void *)&fsun2, sizeof(fsun2)); 211798542Smckusick maxino = sblock.fs_ncg * sblock.fs_ipg; 211869800Stomsoft 211969800Stomsoft DBG_OPEN("/tmp/growfs.debug"); /* already here we need a superblock */ 212069926Stomsoft DBG_DUMP_FS(&sblock, 212169926Stomsoft "old sblock"); 212269800Stomsoft 212369800Stomsoft /* 212469800Stomsoft * Determine size to grow to. Default to the full size specified in 212569800Stomsoft * the disk label. 212669800Stomsoft */ 2127114936Sgrog sblock.fs_size = dbtofsb(&osblock, p_size); 212869800Stomsoft if (size != 0) { 2129114936Sgrog if (size > p_size){ 2130140351Scharnier errx(1, "there is not enough space (%d < %d)", 2131114936Sgrog p_size, size); 213269800Stomsoft } 2133114067Sschweikh sblock.fs_size = dbtofsb(&osblock, size); 213469800Stomsoft } 213569800Stomsoft 213669800Stomsoft /* 213769800Stomsoft * Are we really growing ? 213869800Stomsoft */ 213969800Stomsoft if(osblock.fs_size >= sblock.fs_size) { 2140127798Sle errx(1, "we are not growing (%jd->%jd)", 2141127798Sle (intmax_t)osblock.fs_size, (intmax_t)sblock.fs_size); 214269800Stomsoft } 214369800Stomsoft 214469800Stomsoft 214569800Stomsoft#ifdef FSMAXSNAP 214669800Stomsoft /* 214769800Stomsoft * Check if we find an active snapshot. 214869800Stomsoft */ 214969800Stomsoft if(ExpertFlag == 0) { 215069800Stomsoft for(j=0; j<FSMAXSNAP; j++) { 215169800Stomsoft if(sblock.fs_snapinum[j]) { 2152102231Strhodes errx(1, "active snapshot found in file system\n" 215369800Stomsoft " please remove all snapshots before " 2154140351Scharnier "using growfs"); 215569800Stomsoft } 215669800Stomsoft if(!sblock.fs_snapinum[j]) { /* list is dense */ 215769800Stomsoft break; 215869800Stomsoft } 215969800Stomsoft } 216069800Stomsoft } 216169800Stomsoft#endif 216269800Stomsoft 216369800Stomsoft if (ExpertFlag == 0 && Nflag == 0) { 216469800Stomsoft printf("We strongly recommend you to make a backup " 216569800Stomsoft "before growing the Filesystem\n\n" 216669800Stomsoft " Did you backup your data (Yes/No) ? "); 216777885Stomsoft fgets(reply, (int)sizeof(reply), stdin); 216869800Stomsoft if (strcmp(reply, "Yes\n")){ 216969800Stomsoft printf("\n Nothing done \n"); 217069800Stomsoft exit (0); 2171114067Sschweikh } 217269800Stomsoft } 217369800Stomsoft 2174127798Sle printf("new file systemsize is: %jd frags\n", (intmax_t)sblock.fs_size); 217569800Stomsoft 217669800Stomsoft /* 2177102231Strhodes * Try to access our new last block in the file system. Even if we 217869800Stomsoft * later on realize we have to abort our operation, on that block 217969800Stomsoft * there should be no data, so we can't destroy something yet. 218069800Stomsoft */ 2181114936Sgrog wtfs((ufs2_daddr_t)p_size-1, (size_t)DEV_BSIZE, (void *)&sblock, 218298542Smckusick fso, Nflag); 218369800Stomsoft 218469800Stomsoft /* 218569800Stomsoft * Now calculate new superblock values and check for reasonable 2186102231Strhodes * bound for new file system size: 218769800Stomsoft * fs_size: is derived from label or user input 218869800Stomsoft * fs_dsize: should get updated in the routines creating or 218969800Stomsoft * updating the cylinder groups on the fly 219069800Stomsoft * fs_cstotal: should get updated in the routines creating or 219169800Stomsoft * updating the cylinder groups 219269800Stomsoft */ 219369800Stomsoft 219469800Stomsoft /* 2195102231Strhodes * Update the number of cylinders and cylinder groups in the file system. 219669800Stomsoft */ 219798542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) { 219898542Smckusick sblock.fs_old_ncyl = 219998542Smckusick sblock.fs_size * sblock.fs_old_nspf / sblock.fs_old_spc; 220098542Smckusick if (sblock.fs_size * sblock.fs_old_nspf > 220198542Smckusick sblock.fs_old_ncyl * sblock.fs_old_spc) 220298542Smckusick sblock.fs_old_ncyl++; 220369800Stomsoft } 220498542Smckusick sblock.fs_ncg = howmany(sblock.fs_size, sblock.fs_fpg); 220598542Smckusick maxino = sblock.fs_ncg * sblock.fs_ipg; 220669800Stomsoft 220798542Smckusick if (sblock.fs_size % sblock.fs_fpg != 0 && 220898542Smckusick sblock.fs_size % sblock.fs_fpg < cgdmin(&sblock, sblock.fs_ncg)) { 220969800Stomsoft /* 221069800Stomsoft * The space in the new last cylinder group is too small, 221169800Stomsoft * so revert back. 221269800Stomsoft */ 221369800Stomsoft sblock.fs_ncg--; 221498542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 221598542Smckusick sblock.fs_old_ncyl = sblock.fs_ncg * sblock.fs_old_cpg; 2216127798Sle printf("Warning: %jd sector(s) cannot be allocated.\n", 2217127798Sle (intmax_t)fsbtodb(&sblock, sblock.fs_size % sblock.fs_fpg)); 221898542Smckusick sblock.fs_size = sblock.fs_ncg * sblock.fs_fpg; 2219197763Smjacob maxino -= sblock.fs_ipg; 222069800Stomsoft } 222169800Stomsoft 222269800Stomsoft /* 222369800Stomsoft * Update the space for the cylinder group summary information in the 222469800Stomsoft * respective cylinder group data area. 222569800Stomsoft */ 222669800Stomsoft sblock.fs_cssize = 222769800Stomsoft fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum)); 2228114067Sschweikh 222969800Stomsoft if(osblock.fs_size >= sblock.fs_size) { 223069926Stomsoft errx(1, "not enough new space"); 223169800Stomsoft } 223269800Stomsoft 223369800Stomsoft DBG_PRINT0("sblock calculated\n"); 223469800Stomsoft 223569800Stomsoft /* 223669800Stomsoft * Ok, everything prepared, so now let's do the tricks. 223769800Stomsoft */ 223869800Stomsoft growfs(fsi, fso, Nflag); 223969800Stomsoft 224069800Stomsoft /* 224169800Stomsoft * Update the disk label. 224269800Stomsoft */ 2243114936Sgrog if (!unlabeled) { 2244114936Sgrog pp->p_fsize = sblock.fs_fsize; 2245114936Sgrog pp->p_frag = sblock.fs_frag; 2246114936Sgrog pp->p_cpg = sblock.fs_fpg; 224769800Stomsoft 2248114936Sgrog return_disklabel(fso, lp, Nflag); 2249114936Sgrog DBG_PRINT0("label rewritten\n"); 2250114936Sgrog } 225169800Stomsoft 225269800Stomsoft close(fsi); 225369800Stomsoft if(fso>-1) close(fso); 225469800Stomsoft 225569800Stomsoft DBG_CLOSE; 225669800Stomsoft 225769800Stomsoft DBG_LEAVE; 225869800Stomsoft return 0; 225969800Stomsoft} 226069800Stomsoft 226169800Stomsoft/* ************************************************** return_disklabel ***** */ 226269800Stomsoft/* 226369800Stomsoft * Write the updated disklabel back to disk. 226469800Stomsoft */ 226569800Stomsoftstatic void 226677885Stomsoftreturn_disklabel(int fd, struct disklabel *lp, unsigned int Nflag) 226769800Stomsoft{ 226869800Stomsoft DBG_FUNC("return_disklabel") 226969800Stomsoft u_short sum; 227069800Stomsoft u_short *ptr; 227169800Stomsoft 227269800Stomsoft DBG_ENTER; 227369800Stomsoft 227469800Stomsoft if(!lp) { 227569800Stomsoft DBG_LEAVE; 227669800Stomsoft return; 227769800Stomsoft } 227869800Stomsoft if(!Nflag) { 227969800Stomsoft lp->d_checksum=0; 228069800Stomsoft sum = 0; 228169800Stomsoft ptr=(u_short *)lp; 228269800Stomsoft 228369800Stomsoft /* 228469800Stomsoft * recalculate checksum 228569800Stomsoft */ 228669800Stomsoft while(ptr < (u_short *)&lp->d_partitions[lp->d_npartitions]) { 228769800Stomsoft sum ^= *ptr++; 228869800Stomsoft } 228969800Stomsoft lp->d_checksum=sum; 229069800Stomsoft 229169800Stomsoft if (ioctl(fd, DIOCWDINFO, (char *)lp) < 0) { 229269926Stomsoft errx(1, "DIOCWDINFO failed"); 229369800Stomsoft } 229469800Stomsoft } 229569800Stomsoft free(lp); 229669800Stomsoft 229769800Stomsoft DBG_LEAVE; 229869800Stomsoft return ; 229969800Stomsoft} 230069800Stomsoft 230169800Stomsoft/* ***************************************************** get_disklabel ***** */ 230269800Stomsoft/* 230369800Stomsoft * Read the disklabel from disk. 230469800Stomsoft */ 230569800Stomsoftstatic struct disklabel * 230669800Stomsoftget_disklabel(int fd) 230769800Stomsoft{ 230869800Stomsoft DBG_FUNC("get_disklabel") 230969800Stomsoft static struct disklabel *lab; 231069800Stomsoft 231169800Stomsoft DBG_ENTER; 231269800Stomsoft 231369800Stomsoft lab=(struct disklabel *)malloc(sizeof(struct disklabel)); 2314114936Sgrog if (!lab) 231569926Stomsoft errx(1, "malloc failed"); 231669800Stomsoft 2317114936Sgrog if (!ioctl(fd, DIOCGDINFO, (char *)lab)) 2318114936Sgrog return (lab); 2319114936Sgrog 2320114936Sgrog unlabeled++; 2321114936Sgrog 232269800Stomsoft DBG_LEAVE; 2323114936Sgrog return (NULL); 232469800Stomsoft} 232569800Stomsoft 232669800Stomsoft 232769800Stomsoft/* ************************************************************* usage ***** */ 232869800Stomsoft/* 232969800Stomsoft * Dump a line of usage. 233069800Stomsoft */ 233169800Stomsoftstatic void 233269926Stomsoftusage(void) 2333114067Sschweikh{ 233469800Stomsoft DBG_FUNC("usage") 233569800Stomsoft 233669800Stomsoft DBG_ENTER; 233769800Stomsoft 233869926Stomsoft fprintf(stderr, "usage: growfs [-Ny] [-s size] special\n"); 233969926Stomsoft 234069800Stomsoft DBG_LEAVE; 234169926Stomsoft exit(1); 234269800Stomsoft} 234369800Stomsoft 234469800Stomsoft/* *********************************************************** updclst ***** */ 234569800Stomsoft/* 2346114067Sschweikh * This updates most parameters and the bitmap related to cluster. We have to 2347114067Sschweikh * assume that sblock, osblock, acg are set up. 234869800Stomsoft */ 234969800Stomsoftstatic void 235069800Stomsoftupdclst(int block) 2351114067Sschweikh{ 235269800Stomsoft DBG_FUNC("updclst") 235369800Stomsoft static int lcs=0; 235469800Stomsoft 235569800Stomsoft DBG_ENTER; 235669800Stomsoft 235769800Stomsoft if(sblock.fs_contigsumsize < 1) { /* no clustering */ 235869800Stomsoft return; 235969800Stomsoft } 236069800Stomsoft /* 236169800Stomsoft * update cluster allocation map 236269800Stomsoft */ 236369800Stomsoft setbit(cg_clustersfree(&acg), block); 236469800Stomsoft 236569800Stomsoft /* 236669800Stomsoft * update cluster summary table 236769800Stomsoft */ 236869800Stomsoft if(!lcs) { 236969800Stomsoft /* 237069800Stomsoft * calculate size for the trailing cluster 237169800Stomsoft */ 237269800Stomsoft for(block--; lcs<sblock.fs_contigsumsize; block--, lcs++ ) { 237369800Stomsoft if(isclr(cg_clustersfree(&acg), block)){ 237469800Stomsoft break; 237569800Stomsoft } 237669800Stomsoft } 2377114067Sschweikh } 237869800Stomsoft if(lcs < sblock.fs_contigsumsize) { 237969800Stomsoft if(lcs) { 238069800Stomsoft cg_clustersum(&acg)[lcs]--; 238169800Stomsoft } 238269800Stomsoft lcs++; 238369800Stomsoft cg_clustersum(&acg)[lcs]++; 238469800Stomsoft } 238569800Stomsoft 238669800Stomsoft DBG_LEAVE; 238769800Stomsoft return; 238869800Stomsoft} 238969800Stomsoft 239069800Stomsoft/* *********************************************************** updrefs ***** */ 239169800Stomsoft/* 239269800Stomsoft * This updates all references to relocated blocks for the given inode. The 239369800Stomsoft * inode is given as number within the cylinder group, and the number of the 239469800Stomsoft * cylinder group. 239569800Stomsoft */ 239669800Stomsoftstatic void 239777885Stomsoftupdrefs(int cg, ino_t in, struct gfs_bpp *bp, int fsi, int fso, unsigned int 239877885Stomsoft Nflag) 2399114067Sschweikh{ 240069800Stomsoft DBG_FUNC("updrefs") 240198542Smckusick ufs_lbn_t len, lbn, numblks; 240298542Smckusick ufs2_daddr_t iptr, blksperindir; 240398542Smckusick union dinode *ino; 2404121724Strhodes int i, mode, inodeupdated; 240569800Stomsoft 240669800Stomsoft DBG_ENTER; 240769800Stomsoft 240898542Smckusick ino = ginode(in, fsi, cg); 2409127469Sle if (ino == NULL) { 2410127469Sle DBG_LEAVE; 2411127469Sle return; 2412127469Sle } 241398542Smckusick mode = DIP(ino, di_mode) & IFMT; 241498542Smckusick if (mode != IFDIR && mode != IFREG && mode != IFLNK) { 241569800Stomsoft DBG_LEAVE; 241669800Stomsoft return; /* only check DIR, FILE, LINK */ 241769800Stomsoft } 2418136289Sscottl if (mode == IFLNK && 2419136289Sscottl DIP(ino, di_size) < (u_int64_t) sblock.fs_maxsymlinklen) { 242069800Stomsoft DBG_LEAVE; 242169800Stomsoft return; /* skip short symlinks */ 242269800Stomsoft } 242398542Smckusick numblks = howmany(DIP(ino, di_size), sblock.fs_bsize); 242498542Smckusick if (numblks == 0) { 242569800Stomsoft DBG_LEAVE; 242669800Stomsoft return; /* skip empty file */ 242769800Stomsoft } 242898542Smckusick if (DIP(ino, di_blocks) == 0) { 242969800Stomsoft DBG_LEAVE; 243069800Stomsoft return; /* skip empty swiss cheesy file or old fastlink */ 243169800Stomsoft } 243269926Stomsoft DBG_PRINT2("scg checking inode (%d in %d)\n", 243369926Stomsoft in, 243469926Stomsoft cg); 243569800Stomsoft 243669800Stomsoft /* 243798542Smckusick * Check all the blocks. 243869800Stomsoft */ 243998542Smckusick inodeupdated = 0; 244098542Smckusick len = numblks < NDADDR ? numblks : NDADDR; 244198542Smckusick for (i = 0; i < len; i++) { 244298542Smckusick iptr = DIP(ino, di_db[i]); 244398542Smckusick if (iptr == 0) 244498542Smckusick continue; 244598542Smckusick if (cond_bl_upd(&iptr, bp, fsi, fso, Nflag)) { 2446132832Sle DIP_SET(ino, di_db[i], iptr); 244798542Smckusick inodeupdated++; 244869800Stomsoft } 244969800Stomsoft } 245069800Stomsoft DBG_PRINT0("~~scg direct blocks checked\n"); 245169800Stomsoft 245298542Smckusick blksperindir = 1; 245398542Smckusick len = numblks - NDADDR; 245498542Smckusick lbn = NDADDR; 245598542Smckusick for (i = 0; len > 0 && i < NIADDR; i++) { 245698542Smckusick iptr = DIP(ino, di_ib[i]); 245798542Smckusick if (iptr == 0) 245898542Smckusick continue; 245998542Smckusick if (cond_bl_upd(&iptr, bp, fsi, fso, Nflag)) { 2460132832Sle DIP_SET(ino, di_ib[i], iptr); 246198542Smckusick inodeupdated++; 246269800Stomsoft } 246398542Smckusick indirchk(blksperindir, lbn, iptr, numblks, bp, fsi, fso, Nflag); 246498542Smckusick blksperindir *= NINDIR(&sblock); 246598542Smckusick lbn += blksperindir; 246698542Smckusick len -= blksperindir; 246798542Smckusick DBG_PRINT1("scg indirect_%d blocks checked\n", i + 1); 246869800Stomsoft } 246998542Smckusick if (inodeupdated) 247098542Smckusick wtfs(inoblk, sblock.fs_bsize, inobuf, fso, Nflag); 247169800Stomsoft 247298542Smckusick DBG_LEAVE; 247398542Smckusick return; 247498542Smckusick} 247569800Stomsoft 247698542Smckusick/* 247798542Smckusick * Recursively check all the indirect blocks. 247898542Smckusick */ 247998542Smckusickstatic void 248098542Smckusickindirchk(ufs_lbn_t blksperindir, ufs_lbn_t lbn, ufs2_daddr_t blkno, 248198542Smckusick ufs_lbn_t lastlbn, struct gfs_bpp *bp, int fsi, int fso, unsigned int Nflag) 248298542Smckusick{ 248398542Smckusick DBG_FUNC("indirchk") 248498542Smckusick void *ibuf; 248598542Smckusick int i, last; 248698542Smckusick ufs2_daddr_t iptr; 248798542Smckusick 248898542Smckusick DBG_ENTER; 248998542Smckusick 249098542Smckusick /* read in the indirect block. */ 249198542Smckusick ibuf = malloc(sblock.fs_bsize); 249298542Smckusick if (!ibuf) 249398542Smckusick errx(1, "malloc failed"); 249498542Smckusick rdfs(fsbtodb(&sblock, blkno), (size_t)sblock.fs_bsize, ibuf, fsi); 249598542Smckusick last = howmany(lastlbn - lbn, blksperindir) < NINDIR(&sblock) ? 249698542Smckusick howmany(lastlbn - lbn, blksperindir) : NINDIR(&sblock); 249798542Smckusick for (i = 0; i < last; i++) { 249898542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 249998542Smckusick iptr = ((ufs1_daddr_t *)ibuf)[i]; 250098542Smckusick else 250198542Smckusick iptr = ((ufs2_daddr_t *)ibuf)[i]; 250298542Smckusick if (iptr == 0) 250398542Smckusick continue; 250498542Smckusick if (cond_bl_upd(&iptr, bp, fsi, fso, Nflag)) { 250598542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 250698542Smckusick ((ufs1_daddr_t *)ibuf)[i] = iptr; 250798542Smckusick else 250898542Smckusick ((ufs2_daddr_t *)ibuf)[i] = iptr; 250969800Stomsoft } 251098542Smckusick if (blksperindir == 1) 251198542Smckusick continue; 251298542Smckusick indirchk(blksperindir / NINDIR(&sblock), lbn + blksperindir * i, 251398542Smckusick iptr, lastlbn, bp, fsi, fso, Nflag); 251469800Stomsoft } 251598542Smckusick free(ibuf); 251669800Stomsoft 251769800Stomsoft DBG_LEAVE; 251869800Stomsoft return; 251969800Stomsoft} 2520