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