xref: /freebsd/sbin/growfs/growfs.c (revision 26c3d72eca935191baa4c09563c18b075a4f07a6)
1df57947fSPedro F. Giffuni /*-
2df57947fSPedro F. Giffuni  * SPDX-License-Identifier: BSD-4-Clause
3df57947fSPedro F. Giffuni  *
43d500078SThomas-Henning von Kamptz  * Copyright (c) 1980, 1989, 1993 The Regents of the University of California.
5e35497f1SEdward Tomasz Napierala  * Copyright (c) 2000 Christoph Herrmann, Thomas-Henning von Kamptz
6e35497f1SEdward Tomasz Napierala  * Copyright (c) 2012 The FreeBSD Foundation
73d500078SThomas-Henning von Kamptz  * All rights reserved.
83d500078SThomas-Henning von Kamptz  *
93d500078SThomas-Henning von Kamptz  * This code is derived from software contributed to Berkeley by
103d500078SThomas-Henning von Kamptz  * Christoph Herrmann and Thomas-Henning von Kamptz, Munich and Frankfurt.
113d500078SThomas-Henning von Kamptz  *
12e35497f1SEdward Tomasz Napierala  * Portions of this software were developed by Edward Tomasz Napierala
13e35497f1SEdward Tomasz Napierala  * under sponsorship from the FreeBSD Foundation.
14e35497f1SEdward Tomasz Napierala  *
153d500078SThomas-Henning von Kamptz  * Redistribution and use in source and binary forms, with or without
163d500078SThomas-Henning von Kamptz  * modification, are permitted provided that the following conditions
173d500078SThomas-Henning von Kamptz  * are met:
183d500078SThomas-Henning von Kamptz  * 1. Redistributions of source code must retain the above copyright
193d500078SThomas-Henning von Kamptz  *    notice, this list of conditions and the following disclaimer.
203d500078SThomas-Henning von Kamptz  * 2. Redistributions in binary form must reproduce the above copyright
213d500078SThomas-Henning von Kamptz  *    notice, this list of conditions and the following disclaimer in the
223d500078SThomas-Henning von Kamptz  *    documentation and/or other materials provided with the distribution.
233d500078SThomas-Henning von Kamptz  * 3. All advertising materials mentioning features or use of this software
243d500078SThomas-Henning von Kamptz  *    must display the following acknowledgment:
253d500078SThomas-Henning von Kamptz  *      This product includes software developed by the University of
263d500078SThomas-Henning von Kamptz  *      California, Berkeley and its contributors, as well as Christoph
273d500078SThomas-Henning von Kamptz  *      Herrmann and Thomas-Henning von Kamptz.
283d500078SThomas-Henning von Kamptz  * 4. Neither the name of the University nor the names of its contributors
293d500078SThomas-Henning von Kamptz  *    may be used to endorse or promote products derived from this software
303d500078SThomas-Henning von Kamptz  *    without specific prior written permission.
313d500078SThomas-Henning von Kamptz  *
323d500078SThomas-Henning von Kamptz  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
333d500078SThomas-Henning von Kamptz  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
343d500078SThomas-Henning von Kamptz  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
353d500078SThomas-Henning von Kamptz  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
363d500078SThomas-Henning von Kamptz  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
373d500078SThomas-Henning von Kamptz  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
383d500078SThomas-Henning von Kamptz  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
393d500078SThomas-Henning von Kamptz  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
403d500078SThomas-Henning von Kamptz  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
413d500078SThomas-Henning von Kamptz  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
423d500078SThomas-Henning von Kamptz  * SUCH DAMAGE.
433d500078SThomas-Henning von Kamptz  *
444020c5bcSThomas-Henning von Kamptz  * $TSHeader: src/sbin/growfs/growfs.c,v 1.5 2000/12/12 19:31:00 tomsoft Exp $
453d500078SThomas-Henning von Kamptz  *
463d500078SThomas-Henning von Kamptz  */
473d500078SThomas-Henning von Kamptz 
483d500078SThomas-Henning von Kamptz #include <sys/param.h>
493d500078SThomas-Henning von Kamptz #include <sys/ioctl.h>
503d500078SThomas-Henning von Kamptz #include <sys/stat.h>
514b9748d4SGreg Lehey #include <sys/disk.h>
52e35497f1SEdward Tomasz Napierala #include <sys/ucred.h>
53e35497f1SEdward Tomasz Napierala #include <sys/mount.h>
543d500078SThomas-Henning von Kamptz 
553d500078SThomas-Henning von Kamptz #include <stdio.h>
563d500078SThomas-Henning von Kamptz #include <paths.h>
573d500078SThomas-Henning von Kamptz #include <ctype.h>
583d500078SThomas-Henning von Kamptz #include <err.h>
59dffce215SKirk McKusick #include <errno.h>
603d500078SThomas-Henning von Kamptz #include <fcntl.h>
61e35497f1SEdward Tomasz Napierala #include <fstab.h>
62e35497f1SEdward Tomasz Napierala #include <inttypes.h>
6389fdc4e1SMike Barcroft #include <limits.h>
64e35497f1SEdward Tomasz Napierala #include <mntopts.h>
652ec1a006SEdward Tomasz Napierala #include <paths.h>
663d500078SThomas-Henning von Kamptz #include <stdlib.h>
6775d1ec91SLukas Ertl #include <stdint.h>
683d500078SThomas-Henning von Kamptz #include <string.h>
6935cf80deSBruce Evans #include <time.h>
703d500078SThomas-Henning von Kamptz #include <unistd.h>
713d500078SThomas-Henning von Kamptz #include <ufs/ufs/dinode.h>
723d500078SThomas-Henning von Kamptz #include <ufs/ffs/fs.h>
73e35497f1SEdward Tomasz Napierala #include <libutil.h>
743abf5d76SKirk McKusick #include <libufs.h>
753d500078SThomas-Henning von Kamptz 
763d500078SThomas-Henning von Kamptz #include "debug.h"
773d500078SThomas-Henning von Kamptz 
783d500078SThomas-Henning von Kamptz #ifdef FS_DEBUG
793d500078SThomas-Henning von Kamptz int	_dbg_lvl_ = (DL_INFO);	/* DL_TRC */
803d500078SThomas-Henning von Kamptz #endif /* FS_DEBUG */
813d500078SThomas-Henning von Kamptz 
823d500078SThomas-Henning von Kamptz static union {
833d500078SThomas-Henning von Kamptz 	struct fs	fs;
841c85e6a3SKirk McKusick 	char		pad[SBLOCKSIZE];
853d500078SThomas-Henning von Kamptz } fsun1, fsun2;
863d500078SThomas-Henning von Kamptz #define	sblock	fsun1.fs	/* the new superblock */
873d500078SThomas-Henning von Kamptz #define	osblock	fsun2.fs	/* the old superblock */
883d500078SThomas-Henning von Kamptz 
893d500078SThomas-Henning von Kamptz static union {
903d500078SThomas-Henning von Kamptz 	struct cg	cg;
913d500078SThomas-Henning von Kamptz 	char		pad[MAXBSIZE];
923d500078SThomas-Henning von Kamptz } cgun1, cgun2;
933d500078SThomas-Henning von Kamptz #define	acg	cgun1.cg	/* a cylinder cgroup (new) */
943d500078SThomas-Henning von Kamptz #define	aocg	cgun2.cg	/* an old cylinder group */
953d500078SThomas-Henning von Kamptz 
963d500078SThomas-Henning von Kamptz static struct csum	*fscs;	/* cylinder summary */
973d500078SThomas-Henning von Kamptz 
98adcaff07SThomas-Henning von Kamptz static void	growfs(int, int, unsigned int);
991c85e6a3SKirk McKusick static void	rdfs(ufs2_daddr_t, size_t, void *, int);
1001c85e6a3SKirk McKusick static void	wtfs(ufs2_daddr_t, size_t, void *, int, unsigned int);
1013d500078SThomas-Henning von Kamptz static int	charsperline(void);
1024020c5bcSThomas-Henning von Kamptz static void	usage(void);
1033d500078SThomas-Henning von Kamptz static int	isblock(struct fs *, unsigned char *, int);
1043d500078SThomas-Henning von Kamptz static void	clrblock(struct fs *, unsigned char *, int);
1053d500078SThomas-Henning von Kamptz static void	setblock(struct fs *, unsigned char *, int);
106adcaff07SThomas-Henning von Kamptz static void	initcg(int, time_t, int, unsigned int);
107adcaff07SThomas-Henning von Kamptz static void	updjcg(int, time_t, int, int, unsigned int);
108adcaff07SThomas-Henning von Kamptz static void	updcsloc(time_t, int, int, unsigned int);
1091c85e6a3SKirk McKusick static void	frag_adjust(ufs2_daddr_t, int);
1103d500078SThomas-Henning von Kamptz static void	updclst(int);
1113abf5d76SKirk McKusick static void	cgckhash(struct cg *);
1123d500078SThomas-Henning von Kamptz 
1133d500078SThomas-Henning von Kamptz /*
1143d500078SThomas-Henning von Kamptz  * Here we actually start growing the file system. We basically read the
1154020c5bcSThomas-Henning von Kamptz  * cylinder summary from the first cylinder group as we want to update
1163d500078SThomas-Henning von Kamptz  * this on the fly during our various operations. First we handle the
1173d500078SThomas-Henning von Kamptz  * changes in the former last cylinder group. Afterwards we create all new
1183d500078SThomas-Henning von Kamptz  * cylinder groups.  Now we handle the cylinder group containing the
1193d500078SThomas-Henning von Kamptz  * cylinder summary which might result in a relocation of the whole
1203d500078SThomas-Henning von Kamptz  * structure.  In the end we write back the updated cylinder summary, the
1213d500078SThomas-Henning von Kamptz  * new superblock, and slightly patched versions of the super block
1223d500078SThomas-Henning von Kamptz  * copies.
1233d500078SThomas-Henning von Kamptz  */
1243d500078SThomas-Henning von Kamptz static void
growfs(int fsi,int fso,unsigned int Nflag)125adcaff07SThomas-Henning von Kamptz growfs(int fsi, int fso, unsigned int Nflag)
1263d500078SThomas-Henning von Kamptz {
1273d500078SThomas-Henning von Kamptz 	DBG_FUNC("growfs")
128ea6de5eeSMarcel Moolenaar 	time_t modtime;
12914a176a0SKirk McKusick 	uint cylno;
13014a176a0SKirk McKusick 	int i, j, width;
1313d500078SThomas-Henning von Kamptz 	char tmpbuf[100];
1323d500078SThomas-Henning von Kamptz 
1333d500078SThomas-Henning von Kamptz 	DBG_ENTER;
1343d500078SThomas-Henning von Kamptz 
135ea6de5eeSMarcel Moolenaar 	time(&modtime);
1363d500078SThomas-Henning von Kamptz 
1373d500078SThomas-Henning von Kamptz 	/*
1383d500078SThomas-Henning von Kamptz 	 * Get the cylinder summary into the memory.
1393d500078SThomas-Henning von Kamptz 	 */
140adcaff07SThomas-Henning von Kamptz 	fscs = (struct csum *)calloc((size_t)1, (size_t)sblock.fs_cssize);
141a1da0740SEdward Tomasz Napierala 	if (fscs == NULL)
14270a0fb43SMina Galić 		errx(3, "calloc failed");
143dffce215SKirk McKusick 	memcpy(fscs, osblock.fs_csp, osblock.fs_cssize);
144dffce215SKirk McKusick 	free(osblock.fs_csp);
145dffce215SKirk McKusick 	osblock.fs_csp = NULL;
146dffce215SKirk McKusick 	sblock.fs_csp = fscs;
1473d500078SThomas-Henning von Kamptz 
1483d500078SThomas-Henning von Kamptz #ifdef FS_DEBUG
1493d500078SThomas-Henning von Kamptz 	{
1503d500078SThomas-Henning von Kamptz 		struct csum *dbg_csp;
151a44ba043SEdward Tomasz Napierala 		u_int32_t dbg_csc;
1523d500078SThomas-Henning von Kamptz 		char dbg_line[80];
1533d500078SThomas-Henning von Kamptz 
1543d500078SThomas-Henning von Kamptz 		dbg_csp = fscs;
155a1da0740SEdward Tomasz Napierala 
1563d500078SThomas-Henning von Kamptz 		for (dbg_csc = 0; dbg_csc < osblock.fs_ncg; dbg_csc++) {
157adcaff07SThomas-Henning von Kamptz 			snprintf(dbg_line, sizeof(dbg_line),
158adcaff07SThomas-Henning von Kamptz 			    "%d. old csum in old location", dbg_csc);
159a1da0740SEdward Tomasz Napierala 			DBG_DUMP_CSUM(&osblock, dbg_line, dbg_csp++);
1603d500078SThomas-Henning von Kamptz 		}
1613d500078SThomas-Henning von Kamptz 	}
1623d500078SThomas-Henning von Kamptz #endif /* FS_DEBUG */
1633d500078SThomas-Henning von Kamptz 	DBG_PRINT0("fscs read\n");
1643d500078SThomas-Henning von Kamptz 
1653d500078SThomas-Henning von Kamptz 	/*
1663d500078SThomas-Henning von Kamptz 	 * Do all needed changes in the former last cylinder group.
1673d500078SThomas-Henning von Kamptz 	 */
168ea6de5eeSMarcel Moolenaar 	updjcg(osblock.fs_ncg - 1, modtime, fsi, fso, Nflag);
1693d500078SThomas-Henning von Kamptz 
1703d500078SThomas-Henning von Kamptz 	/*
1713d500078SThomas-Henning von Kamptz 	 * Dump out summary information about file system.
1723d500078SThomas-Henning von Kamptz 	 */
173e35497f1SEdward Tomasz Napierala #ifdef FS_DEBUG
1743d500078SThomas-Henning von Kamptz #define B2MBFACTOR (1 / (1024.0 * 1024.0))
175760ea1faSMaxime Henrion 	printf("growfs: %.1fMB (%jd sectors) block size %d, fragment size %d\n",
1763d500078SThomas-Henning von Kamptz 	    (float)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR,
177760ea1faSMaxime Henrion 	    (intmax_t)fsbtodb(&sblock, sblock.fs_size), sblock.fs_bsize,
178760ea1faSMaxime Henrion 	    sblock.fs_fsize);
1791c85e6a3SKirk McKusick 	printf("\tusing %d cylinder groups of %.2fMB, %d blks, %d inodes.\n",
1801c85e6a3SKirk McKusick 	    sblock.fs_ncg, (float)sblock.fs_fpg * sblock.fs_fsize * B2MBFACTOR,
1811c85e6a3SKirk McKusick 	    sblock.fs_fpg / sblock.fs_frag, sblock.fs_ipg);
1821c85e6a3SKirk McKusick 	if (sblock.fs_flags & FS_DOSOFTDEP)
1831c85e6a3SKirk McKusick 		printf("\twith soft updates\n");
1843d500078SThomas-Henning von Kamptz #undef B2MBFACTOR
185e35497f1SEdward Tomasz Napierala #endif /* FS_DEBUG */
1863d500078SThomas-Henning von Kamptz 
1873d500078SThomas-Henning von Kamptz 	/*
1883d500078SThomas-Henning von Kamptz 	 * Now build the cylinders group blocks and
1893d500078SThomas-Henning von Kamptz 	 * then print out indices of cylinder groups.
1903d500078SThomas-Henning von Kamptz 	 */
191295a5bd7SChristian Brueffer 	printf("super-block backups (for fsck_ffs -b #) at:\n");
1923d500078SThomas-Henning von Kamptz 	i = 0;
1933d500078SThomas-Henning von Kamptz 	width = charsperline();
1943d500078SThomas-Henning von Kamptz 
1953d500078SThomas-Henning von Kamptz 	/*
1963d500078SThomas-Henning von Kamptz 	 * Iterate for only the new cylinder groups.
1973d500078SThomas-Henning von Kamptz 	 */
1983d500078SThomas-Henning von Kamptz 	for (cylno = osblock.fs_ncg; cylno < sblock.fs_ncg; cylno++) {
199ea6de5eeSMarcel Moolenaar 		initcg(cylno, modtime, fso, Nflag);
200baa15be0SDavid Schultz 		j = sprintf(tmpbuf, " %jd%s",
201baa15be0SDavid Schultz 		    (intmax_t)fsbtodb(&sblock, cgsblock(&sblock, cylno)),
2023d500078SThomas-Henning von Kamptz 		    cylno < (sblock.fs_ncg - 1) ? "," : "" );
2033d500078SThomas-Henning von Kamptz 		if (i + j >= width) {
2043d500078SThomas-Henning von Kamptz 			printf("\n");
2053d500078SThomas-Henning von Kamptz 			i = 0;
2063d500078SThomas-Henning von Kamptz 		}
2073d500078SThomas-Henning von Kamptz 		i += j;
2083d500078SThomas-Henning von Kamptz 		printf("%s", tmpbuf);
2093d500078SThomas-Henning von Kamptz 		fflush(stdout);
2103d500078SThomas-Henning von Kamptz 	}
2113d500078SThomas-Henning von Kamptz 	printf("\n");
2123d500078SThomas-Henning von Kamptz 
2133d500078SThomas-Henning von Kamptz 	/*
2143d500078SThomas-Henning von Kamptz 	 * Do all needed changes in the first cylinder group.
2153d500078SThomas-Henning von Kamptz 	 * allocate blocks in new location
2163d500078SThomas-Henning von Kamptz 	 */
217ea6de5eeSMarcel Moolenaar 	updcsloc(modtime, fsi, fso, Nflag);
2183d500078SThomas-Henning von Kamptz 
2193d500078SThomas-Henning von Kamptz 	/*
220dffce215SKirk McKusick 	 * Clean up the dynamic fields in our superblock.
221dffce215SKirk McKusick 	 *
222dffce215SKirk McKusick 	 * XXX
223dffce215SKirk McKusick 	 * The following fields are currently distributed from the superblock
224dffce215SKirk McKusick 	 * to the copies:
225dffce215SKirk McKusick 	 *     fs_minfree
226dffce215SKirk McKusick 	 *     fs_rotdelay
227dffce215SKirk McKusick 	 *     fs_maxcontig
228dffce215SKirk McKusick 	 *     fs_maxbpg
229dffce215SKirk McKusick 	 *     fs_minfree,
230dffce215SKirk McKusick 	 *     fs_optim
231dffce215SKirk McKusick 	 *     fs_flags
232dffce215SKirk McKusick 	 *
233dffce215SKirk McKusick 	 * We probably should rather change the summary for the cylinder group
234dffce215SKirk McKusick 	 * statistics here to the value of what would be in there, if the file
235*26c3d72eSHUANG,YU-JIA 	 * system were created initially with the new size. Therefore we still
236dffce215SKirk McKusick 	 * need to find an easy way of calculating that.
237dffce215SKirk McKusick 	 * Possibly we can try to read the first superblock copy and apply the
238dffce215SKirk McKusick 	 * "diffed" stats between the old and new superblock by still copying
239dffce215SKirk McKusick 	 * certain parameters onto that.
2403d500078SThomas-Henning von Kamptz 	 */
241dffce215SKirk McKusick 	sblock.fs_time = modtime;
242dffce215SKirk McKusick 	sblock.fs_fmod = 0;
243dffce215SKirk McKusick 	sblock.fs_clean = 1;
244dffce215SKirk McKusick 	sblock.fs_ronly = 0;
245dffce215SKirk McKusick 	sblock.fs_cgrotor = 0;
246dffce215SKirk McKusick 	sblock.fs_state = 0;
247dffce215SKirk McKusick 	memset((void *)&sblock.fs_fsmnt, 0, sizeof(sblock.fs_fsmnt));
248dffce215SKirk McKusick 
249dffce215SKirk McKusick 	/*
250dffce215SKirk McKusick 	 * Now write the new superblock, its summary information,
251dffce215SKirk McKusick 	 * and all the alternates back to disk.
252dffce215SKirk McKusick 	 */
253dffce215SKirk McKusick 	if (!Nflag && sbput(fso, &sblock, sblock.fs_ncg) != 0)
25470a0fb43SMina Galić 		errc(3, EIO, "could not write updated superblock");
2553d500078SThomas-Henning von Kamptz 	DBG_PRINT0("fscs written\n");
2563d500078SThomas-Henning von Kamptz 
2573d500078SThomas-Henning von Kamptz #ifdef FS_DEBUG
2583d500078SThomas-Henning von Kamptz 	{
2593d500078SThomas-Henning von Kamptz 		struct csum	*dbg_csp;
260a44ba043SEdward Tomasz Napierala 		u_int32_t	dbg_csc;
2613d500078SThomas-Henning von Kamptz 		char	dbg_line[80];
2623d500078SThomas-Henning von Kamptz 
2633d500078SThomas-Henning von Kamptz 		dbg_csp = fscs;
2643d500078SThomas-Henning von Kamptz 		for (dbg_csc = 0; dbg_csc < sblock.fs_ncg; dbg_csc++) {
265adcaff07SThomas-Henning von Kamptz 			snprintf(dbg_line, sizeof(dbg_line),
266adcaff07SThomas-Henning von Kamptz 			    "%d. new csum in new location", dbg_csc);
267a1da0740SEdward Tomasz Napierala 			DBG_DUMP_CSUM(&sblock, dbg_line, dbg_csp++);
2683d500078SThomas-Henning von Kamptz 		}
2693d500078SThomas-Henning von Kamptz 	}
2703d500078SThomas-Henning von Kamptz #endif /* FS_DEBUG */
2713d500078SThomas-Henning von Kamptz 
2723d500078SThomas-Henning von Kamptz 	DBG_PRINT0("sblock written\n");
273a1da0740SEdward Tomasz Napierala 	DBG_DUMP_FS(&sblock, "new initial sblock");
2743d500078SThomas-Henning von Kamptz 
2753d500078SThomas-Henning von Kamptz 	DBG_PRINT0("sblock copies written\n");
276a1da0740SEdward Tomasz Napierala 	DBG_DUMP_FS(&sblock, "new other sblocks");
2773d500078SThomas-Henning von Kamptz 
2783d500078SThomas-Henning von Kamptz 	DBG_LEAVE;
2793d500078SThomas-Henning von Kamptz 	return;
2803d500078SThomas-Henning von Kamptz }
2813d500078SThomas-Henning von Kamptz 
2823d500078SThomas-Henning von Kamptz /*
2833d500078SThomas-Henning von Kamptz  * This creates a new cylinder group structure, for more details please see
2843d500078SThomas-Henning von Kamptz  * the source of newfs(8), as this function is taken over almost unchanged.
2853d500078SThomas-Henning von Kamptz  * As this is never called for the first cylinder group, the special
2863d500078SThomas-Henning von Kamptz  * provisions for that case are removed here.
2873d500078SThomas-Henning von Kamptz  */
2883d500078SThomas-Henning von Kamptz static void
initcg(int cylno,time_t modtime,int fso,unsigned int Nflag)289ea6de5eeSMarcel Moolenaar initcg(int cylno, time_t modtime, int fso, unsigned int Nflag)
2903d500078SThomas-Henning von Kamptz {
2913d500078SThomas-Henning von Kamptz 	DBG_FUNC("initcg")
2921ad5f80fSBrian Somers 	static caddr_t iobuf;
2939fc5d538SKirk McKusick 	static long iobufsize;
29414a176a0SKirk McKusick 	long blkno, start;
295e25a029eSMatthew D Fleming 	ino_t ino;
29675d1ec91SLukas Ertl 	ufs2_daddr_t i, cbase, dmax;
2971c85e6a3SKirk McKusick 	struct ufs1_dinode *dp1;
2989fc5d538SKirk McKusick 	struct ufs2_dinode *dp2;
2993d438ad6SDavid E. O'Brien 	struct csum *cs;
300b408e19cSEdward Tomasz Napierala 	uint j, d, dupper, dlower;
3013d500078SThomas-Henning von Kamptz 
3029fc5d538SKirk McKusick 	if (iobuf == NULL) {
3039fc5d538SKirk McKusick 		iobufsize = 2 * sblock.fs_bsize;
3049fc5d538SKirk McKusick 		if ((iobuf = malloc(iobufsize)) == NULL)
3051c85e6a3SKirk McKusick 			errx(37, "panic: cannot allocate I/O buffer");
3069fc5d538SKirk McKusick 		memset(iobuf, '\0', iobufsize);
3079fc5d538SKirk McKusick 	}
3083d500078SThomas-Henning von Kamptz 	/*
3093d500078SThomas-Henning von Kamptz 	 * Determine block bounds for cylinder group.
3101c85e6a3SKirk McKusick 	 * Allow space for super block summary information in first
3111c85e6a3SKirk McKusick 	 * cylinder group.
3123d500078SThomas-Henning von Kamptz 	 */
3133d500078SThomas-Henning von Kamptz 	cbase = cgbase(&sblock, cylno);
3143d500078SThomas-Henning von Kamptz 	dmax = cbase + sblock.fs_fpg;
3151c85e6a3SKirk McKusick 	if (dmax > sblock.fs_size)
3163d500078SThomas-Henning von Kamptz 		dmax = sblock.fs_size;
3173d500078SThomas-Henning von Kamptz 	dlower = cgsblock(&sblock, cylno) - cbase;
3183d500078SThomas-Henning von Kamptz 	dupper = cgdmin(&sblock, cylno) - cbase;
3191c85e6a3SKirk McKusick 	if (cylno == 0)	/* XXX fscs may be relocated */
3203d500078SThomas-Henning von Kamptz 		dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
3211c85e6a3SKirk McKusick 	cs = &fscs[cylno];
3221c85e6a3SKirk McKusick 	memset(&acg, 0, sblock.fs_cgsize);
323ea6de5eeSMarcel Moolenaar 	acg.cg_time = modtime;
3243d500078SThomas-Henning von Kamptz 	acg.cg_magic = CG_MAGIC;
3253d500078SThomas-Henning von Kamptz 	acg.cg_cgx = cylno;
3263d500078SThomas-Henning von Kamptz 	acg.cg_niblk = sblock.fs_ipg;
327e921a133SMarcelo Araujo 	acg.cg_initediblk = MIN(sblock.fs_ipg, 2 * INOPB(&sblock));
3283d500078SThomas-Henning von Kamptz 	acg.cg_ndblk = dmax - cbase;
3291c85e6a3SKirk McKusick 	if (sblock.fs_contigsumsize > 0)
3303d500078SThomas-Henning von Kamptz 		acg.cg_nclusterblks = acg.cg_ndblk / sblock.fs_frag;
3310a6e34e9SKirk McKusick 	start = sizeof(acg);
3321c85e6a3SKirk McKusick 	if (sblock.fs_magic == FS_UFS2_MAGIC) {
3331c85e6a3SKirk McKusick 		acg.cg_iusedoff = start;
3343d500078SThomas-Henning von Kamptz 	} else {
3351c85e6a3SKirk McKusick 		acg.cg_old_ncyl = sblock.fs_old_cpg;
3361c85e6a3SKirk McKusick 		acg.cg_old_time = acg.cg_time;
3371c85e6a3SKirk McKusick 		acg.cg_time = 0;
3381c85e6a3SKirk McKusick 		acg.cg_old_niblk = acg.cg_niblk;
3391c85e6a3SKirk McKusick 		acg.cg_niblk = 0;
3401ad5f80fSBrian Somers 		acg.cg_initediblk = 0;
3411c85e6a3SKirk McKusick 		acg.cg_old_btotoff = start;
3421c85e6a3SKirk McKusick 		acg.cg_old_boff = acg.cg_old_btotoff +
3431c85e6a3SKirk McKusick 		    sblock.fs_old_cpg * sizeof(int32_t);
3441c85e6a3SKirk McKusick 		acg.cg_iusedoff = acg.cg_old_boff +
3451c85e6a3SKirk McKusick 		    sblock.fs_old_cpg * sizeof(u_int16_t);
3461c85e6a3SKirk McKusick 	}
34789fdc4e1SMike Barcroft 	acg.cg_freeoff = acg.cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT);
34889fdc4e1SMike Barcroft 	acg.cg_nextfreeoff = acg.cg_freeoff + howmany(sblock.fs_fpg, CHAR_BIT);
3491c85e6a3SKirk McKusick 	if (sblock.fs_contigsumsize > 0) {
3503d500078SThomas-Henning von Kamptz 		acg.cg_clustersumoff =
3511c85e6a3SKirk McKusick 		    roundup(acg.cg_nextfreeoff, sizeof(u_int32_t));
3521c85e6a3SKirk McKusick 		acg.cg_clustersumoff -= sizeof(u_int32_t);
3533d500078SThomas-Henning von Kamptz 		acg.cg_clusteroff = acg.cg_clustersumoff +
3543d500078SThomas-Henning von Kamptz 		    (sblock.fs_contigsumsize + 1) * sizeof(u_int32_t);
3551c85e6a3SKirk McKusick 		acg.cg_nextfreeoff = acg.cg_clusteroff +
35689fdc4e1SMike Barcroft 		    howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT);
3573d500078SThomas-Henning von Kamptz 	}
35814a176a0SKirk McKusick 	if (acg.cg_nextfreeoff > (unsigned)sblock.fs_cgsize) {
3593d500078SThomas-Henning von Kamptz 		/*
3601c85e6a3SKirk McKusick 		 * This should never happen as we would have had that panic
3613d500078SThomas-Henning von Kamptz 		 * already on file system creation
3623d500078SThomas-Henning von Kamptz 		 */
3634020c5bcSThomas-Henning von Kamptz 		errx(37, "panic: cylinder group too big");
3643d500078SThomas-Henning von Kamptz 	}
3653d500078SThomas-Henning von Kamptz 	acg.cg_cs.cs_nifree += sblock.fs_ipg;
3663d500078SThomas-Henning von Kamptz 	if (cylno == 0)
3671dc349abSEd Maste 		for (ino = 0; ino < UFS_ROOTINO; ino++) {
368e25a029eSMatthew D Fleming 			setbit(cg_inosused(&acg), ino);
3693d500078SThomas-Henning von Kamptz 			acg.cg_cs.cs_nifree--;
3703d500078SThomas-Henning von Kamptz 		}
371e7c46054SScott Long 	/*
3729fc5d538SKirk McKusick 	 * Initialize the initial inode blocks.
3739fc5d538SKirk McKusick 	 */
3749fc5d538SKirk McKusick 	dp1 = (struct ufs1_dinode *)(void *)iobuf;
3759fc5d538SKirk McKusick 	dp2 = (struct ufs2_dinode *)(void *)iobuf;
3769fc5d538SKirk McKusick 	for (i = 0; i < acg.cg_initediblk; i++) {
3779fc5d538SKirk McKusick 		if (sblock.fs_magic == FS_UFS1_MAGIC) {
3789fc5d538SKirk McKusick 			dp1->di_gen = arc4random();
3799fc5d538SKirk McKusick 			dp1++;
3809fc5d538SKirk McKusick 		} else {
3819fc5d538SKirk McKusick 			dp2->di_gen = arc4random();
3829fc5d538SKirk McKusick 			dp2++;
3839fc5d538SKirk McKusick 		}
3849fc5d538SKirk McKusick 	}
3859fc5d538SKirk McKusick 	wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno)), iobufsize, iobuf,
3869fc5d538SKirk McKusick 	    fso, Nflag);
3879fc5d538SKirk McKusick 	/*
38808f353ebSGavin Atkinson 	 * For the old file system, we have to initialize all the inodes.
389e7c46054SScott Long 	 */
3909fc5d538SKirk McKusick 	if (sblock.fs_magic == FS_UFS1_MAGIC &&
3919fc5d538SKirk McKusick 	    sblock.fs_ipg > 2 * INOPB(&sblock)) {
3929fc5d538SKirk McKusick 		for (i = 2 * sblock.fs_frag;
3939fc5d538SKirk McKusick 		     i < sblock.fs_ipg / INOPF(&sblock);
394e7c46054SScott Long 		     i += sblock.fs_frag) {
39511dc4806SEd Schouten 			dp1 = (struct ufs1_dinode *)(void *)iobuf;
396eb747250SGavin Atkinson 			for (j = 0; j < INOPB(&sblock); j++) {
39744246b4cSXin LI 				dp1->di_gen = arc4random();
3981c85e6a3SKirk McKusick 				dp1++;
3993d500078SThomas-Henning von Kamptz 			}
4003d500078SThomas-Henning von Kamptz 			wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i),
4011c85e6a3SKirk McKusick 			    sblock.fs_bsize, iobuf, fso, Nflag);
4023d500078SThomas-Henning von Kamptz 		}
403e7c46054SScott Long 	}
4041c85e6a3SKirk McKusick 	if (cylno > 0) {
4051c85e6a3SKirk McKusick 		/*
4061c85e6a3SKirk McKusick 		 * In cylno 0, beginning space is reserved
4071c85e6a3SKirk McKusick 		 * for boot and super blocks.
4081c85e6a3SKirk McKusick 		 */
4093d500078SThomas-Henning von Kamptz 		for (d = 0; d < dlower; d += sblock.fs_frag) {
4103d500078SThomas-Henning von Kamptz 			blkno = d / sblock.fs_frag;
4113d500078SThomas-Henning von Kamptz 			setblock(&sblock, cg_blksfree(&acg), blkno);
4121c85e6a3SKirk McKusick 			if (sblock.fs_contigsumsize > 0)
4133d500078SThomas-Henning von Kamptz 				setbit(cg_clustersfree(&acg), blkno);
4143d500078SThomas-Henning von Kamptz 			acg.cg_cs.cs_nbfree++;
4153d500078SThomas-Henning von Kamptz 		}
4163d500078SThomas-Henning von Kamptz 		sblock.fs_dsize += dlower;
4171c85e6a3SKirk McKusick 	}
4183d500078SThomas-Henning von Kamptz 	sblock.fs_dsize += acg.cg_ndblk - dupper;
4192049cc32SKirk McKusick 	sblock.fs_old_dsize = sblock.fs_dsize;
4203d500078SThomas-Henning von Kamptz 	if ((i = dupper % sblock.fs_frag)) {
4213d500078SThomas-Henning von Kamptz 		acg.cg_frsum[sblock.fs_frag - i]++;
4223d500078SThomas-Henning von Kamptz 		for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) {
4233d500078SThomas-Henning von Kamptz 			setbit(cg_blksfree(&acg), dupper);
4243d500078SThomas-Henning von Kamptz 			acg.cg_cs.cs_nffree++;
4253d500078SThomas-Henning von Kamptz 		}
4263d500078SThomas-Henning von Kamptz 	}
4271c85e6a3SKirk McKusick 	for (d = dupper; d + sblock.fs_frag <= acg.cg_ndblk;
4281c85e6a3SKirk McKusick 	    d += sblock.fs_frag) {
4293d500078SThomas-Henning von Kamptz 		blkno = d / sblock.fs_frag;
4303d500078SThomas-Henning von Kamptz 		setblock(&sblock, cg_blksfree(&acg), blkno);
4311c85e6a3SKirk McKusick 		if (sblock.fs_contigsumsize > 0)
4323d500078SThomas-Henning von Kamptz 			setbit(cg_clustersfree(&acg), blkno);
4333d500078SThomas-Henning von Kamptz 		acg.cg_cs.cs_nbfree++;
4343d500078SThomas-Henning von Kamptz 	}
4351c85e6a3SKirk McKusick 	if (d < acg.cg_ndblk) {
4361c85e6a3SKirk McKusick 		acg.cg_frsum[acg.cg_ndblk - d]++;
4371c85e6a3SKirk McKusick 		for (; d < acg.cg_ndblk; d++) {
4383d500078SThomas-Henning von Kamptz 			setbit(cg_blksfree(&acg), d);
4393d500078SThomas-Henning von Kamptz 			acg.cg_cs.cs_nffree++;
4403d500078SThomas-Henning von Kamptz 		}
4413d500078SThomas-Henning von Kamptz 	}
4423d500078SThomas-Henning von Kamptz 	if (sblock.fs_contigsumsize > 0) {
4433d500078SThomas-Henning von Kamptz 		int32_t *sump = cg_clustersum(&acg);
4443d500078SThomas-Henning von Kamptz 		u_char *mapp = cg_clustersfree(&acg);
4453d500078SThomas-Henning von Kamptz 		int map = *mapp++;
4463d500078SThomas-Henning von Kamptz 		int bit = 1;
4473d500078SThomas-Henning von Kamptz 		int run = 0;
4483d500078SThomas-Henning von Kamptz 
4493d500078SThomas-Henning von Kamptz 		for (i = 0; i < acg.cg_nclusterblks; i++) {
4501c85e6a3SKirk McKusick 			if ((map & bit) != 0)
4513d500078SThomas-Henning von Kamptz 				run++;
4521c85e6a3SKirk McKusick 			else if (run != 0) {
4531c85e6a3SKirk McKusick 				if (run > sblock.fs_contigsumsize)
4543d500078SThomas-Henning von Kamptz 					run = sblock.fs_contigsumsize;
4553d500078SThomas-Henning von Kamptz 				sump[run]++;
4563d500078SThomas-Henning von Kamptz 				run = 0;
4573d500078SThomas-Henning von Kamptz 			}
45889fdc4e1SMike Barcroft 			if ((i & (CHAR_BIT - 1)) != CHAR_BIT - 1)
4593d500078SThomas-Henning von Kamptz 				bit <<= 1;
4601c85e6a3SKirk McKusick 			else {
4613d500078SThomas-Henning von Kamptz 				map = *mapp++;
4623d500078SThomas-Henning von Kamptz 				bit = 1;
4633d500078SThomas-Henning von Kamptz 			}
4643d500078SThomas-Henning von Kamptz 		}
4653d500078SThomas-Henning von Kamptz 		if (run != 0) {
4661c85e6a3SKirk McKusick 			if (run > sblock.fs_contigsumsize)
4673d500078SThomas-Henning von Kamptz 				run = sblock.fs_contigsumsize;
4683d500078SThomas-Henning von Kamptz 			sump[run]++;
4693d500078SThomas-Henning von Kamptz 		}
4703d500078SThomas-Henning von Kamptz 	}
4713d500078SThomas-Henning von Kamptz 	sblock.fs_cstotal.cs_ndir += acg.cg_cs.cs_ndir;
4723d500078SThomas-Henning von Kamptz 	sblock.fs_cstotal.cs_nffree += acg.cg_cs.cs_nffree;
4733d500078SThomas-Henning von Kamptz 	sblock.fs_cstotal.cs_nbfree += acg.cg_cs.cs_nbfree;
4743d500078SThomas-Henning von Kamptz 	sblock.fs_cstotal.cs_nifree += acg.cg_cs.cs_nifree;
4753d500078SThomas-Henning von Kamptz 	*cs = acg.cg_cs;
4761ad5f80fSBrian Somers 
4773abf5d76SKirk McKusick 	cgckhash(&acg);
4789fc5d538SKirk McKusick 	wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)), sblock.fs_cgsize, &acg,
4799fc5d538SKirk McKusick 	    fso, Nflag);
4801ad5f80fSBrian Somers 	DBG_DUMP_CG(&sblock, "new cg", &acg);
4813d500078SThomas-Henning von Kamptz 
4823d500078SThomas-Henning von Kamptz 	DBG_LEAVE;
4833d500078SThomas-Henning von Kamptz 	return;
4843d500078SThomas-Henning von Kamptz }
4853d500078SThomas-Henning von Kamptz 
4863d500078SThomas-Henning von Kamptz /*
4873d500078SThomas-Henning von Kamptz  * Here we add or subtract (sign +1/-1) the available fragments in a given
4883d500078SThomas-Henning von Kamptz  * block to or from the fragment statistics. By subtracting before and adding
4893d500078SThomas-Henning von Kamptz  * after an operation on the free frag map we can easy update the fragment
490d64ada50SJens Schweikhardt  * statistic, which seems to be otherwise a rather complex operation.
4913d500078SThomas-Henning von Kamptz  */
4923d500078SThomas-Henning von Kamptz static void
frag_adjust(ufs2_daddr_t frag,int sign)4931c85e6a3SKirk McKusick frag_adjust(ufs2_daddr_t frag, int sign)
4943d500078SThomas-Henning von Kamptz {
4953d500078SThomas-Henning von Kamptz 	DBG_FUNC("frag_adjust")
4963d500078SThomas-Henning von Kamptz 	int fragsize;
4973d500078SThomas-Henning von Kamptz 	int f;
4983d500078SThomas-Henning von Kamptz 
4993d500078SThomas-Henning von Kamptz 	DBG_ENTER;
5003d500078SThomas-Henning von Kamptz 
5013d500078SThomas-Henning von Kamptz 	fragsize = 0;
5023d500078SThomas-Henning von Kamptz 	/*
5033d500078SThomas-Henning von Kamptz 	 * Here frag only needs to point to any fragment in the block we want
5043d500078SThomas-Henning von Kamptz 	 * to examine.
5053d500078SThomas-Henning von Kamptz 	 */
5063d500078SThomas-Henning von Kamptz 	for (f = rounddown(frag, sblock.fs_frag);
507a1da0740SEdward Tomasz Napierala 	    f < roundup(frag + 1, sblock.fs_frag); f++) {
5083d500078SThomas-Henning von Kamptz 		/*
5096ded0533SJens Schweikhardt 		 * Count contiguous free fragments.
5103d500078SThomas-Henning von Kamptz 		 */
5113d500078SThomas-Henning von Kamptz 		if (isset(cg_blksfree(&acg), f)) {
5123d500078SThomas-Henning von Kamptz 			fragsize++;
5133d500078SThomas-Henning von Kamptz 		} else {
5143d500078SThomas-Henning von Kamptz 			if (fragsize && fragsize < sblock.fs_frag) {
5153d500078SThomas-Henning von Kamptz 				/*
5163d500078SThomas-Henning von Kamptz 				 * We found something in between.
5173d500078SThomas-Henning von Kamptz 				 */
5183d500078SThomas-Henning von Kamptz 				acg.cg_frsum[fragsize] += sign;
5194020c5bcSThomas-Henning von Kamptz 				DBG_PRINT2("frag_adjust [%d]+=%d\n",
520a1da0740SEdward Tomasz Napierala 				    fragsize, sign);
5213d500078SThomas-Henning von Kamptz 			}
5223d500078SThomas-Henning von Kamptz 			fragsize = 0;
5233d500078SThomas-Henning von Kamptz 		}
5243d500078SThomas-Henning von Kamptz 	}
5253d500078SThomas-Henning von Kamptz 	if (fragsize && fragsize < sblock.fs_frag) {
5263d500078SThomas-Henning von Kamptz 		/*
5273d500078SThomas-Henning von Kamptz 		 * We found something.
5283d500078SThomas-Henning von Kamptz 		 */
5293d500078SThomas-Henning von Kamptz 		acg.cg_frsum[fragsize] += sign;
530a1da0740SEdward Tomasz Napierala 		DBG_PRINT2("frag_adjust [%d]+=%d\n", fragsize, sign);
5313d500078SThomas-Henning von Kamptz 	}
532a1da0740SEdward Tomasz Napierala 	DBG_PRINT2("frag_adjust [[%d]]+=%d\n", fragsize, sign);
5333d500078SThomas-Henning von Kamptz 
5343d500078SThomas-Henning von Kamptz 	DBG_LEAVE;
5353d500078SThomas-Henning von Kamptz 	return;
5363d500078SThomas-Henning von Kamptz }
5373d500078SThomas-Henning von Kamptz 
5383d500078SThomas-Henning von Kamptz /*
5393d500078SThomas-Henning von Kamptz  * Here we do all needed work for the former last cylinder group. It has to be
5403d500078SThomas-Henning von Kamptz  * changed in any case, even if the file system ended exactly on the end of
5413d500078SThomas-Henning von Kamptz  * this group, as there is some slightly inconsistent handling of the number
5423d500078SThomas-Henning von Kamptz  * of cylinders in the cylinder group. We start again by reading the cylinder
5433d500078SThomas-Henning von Kamptz  * group from disk. If the last block was not fully available, we first handle
5443d500078SThomas-Henning von Kamptz  * the missing fragments, then we handle all new full blocks in that file
5453d500078SThomas-Henning von Kamptz  * system and finally we handle the new last fragmented block in the file
5463d500078SThomas-Henning von Kamptz  * system.  We again have to handle the fragment statistics rotational layout
5473d500078SThomas-Henning von Kamptz  * tables and cluster summary during all those operations.
5483d500078SThomas-Henning von Kamptz  */
5493d500078SThomas-Henning von Kamptz static void
updjcg(int cylno,time_t modtime,int fsi,int fso,unsigned int Nflag)550ea6de5eeSMarcel Moolenaar updjcg(int cylno, time_t modtime, int fsi, int fso, unsigned int Nflag)
5513d500078SThomas-Henning von Kamptz {
5523d500078SThomas-Henning von Kamptz 	DBG_FUNC("updjcg")
55378dfcf25SKirk McKusick 	ufs2_daddr_t cbase, dmax;
5543d500078SThomas-Henning von Kamptz 	struct csum *cs;
5553d500078SThomas-Henning von Kamptz 	int i, k;
5563d500078SThomas-Henning von Kamptz 	int j = 0;
5573d500078SThomas-Henning von Kamptz 
5583d500078SThomas-Henning von Kamptz 	DBG_ENTER;
5593d500078SThomas-Henning von Kamptz 
5603d500078SThomas-Henning von Kamptz 	/*
5613d500078SThomas-Henning von Kamptz 	 * Read the former last (joining) cylinder group from disk, and make
5623d500078SThomas-Henning von Kamptz 	 * a copy.
5633d500078SThomas-Henning von Kamptz 	 */
564adcaff07SThomas-Henning von Kamptz 	rdfs(fsbtodb(&osblock, cgtod(&osblock, cylno)),
565adcaff07SThomas-Henning von Kamptz 	    (size_t)osblock.fs_cgsize, (void *)&aocg, fsi);
5663d500078SThomas-Henning von Kamptz 	DBG_PRINT0("jcg read\n");
567a1da0740SEdward Tomasz Napierala 	DBG_DUMP_CG(&sblock, "old joining cg", &aocg);
5683d500078SThomas-Henning von Kamptz 
5693d500078SThomas-Henning von Kamptz 	memcpy((void *)&cgun1, (void *)&cgun2, sizeof(cgun2));
5703d500078SThomas-Henning von Kamptz 
5713d500078SThomas-Henning von Kamptz 	/*
5726ded0533SJens Schweikhardt 	 * If the cylinder group had already its new final size almost
5733d500078SThomas-Henning von Kamptz 	 * nothing is to be done ... except:
5743d500078SThomas-Henning von Kamptz 	 * For some reason the value of cg_ncyl in the last cylinder group has
5753d500078SThomas-Henning von Kamptz 	 * to be zero instead of fs_cpg. As this is now no longer the last
5763d500078SThomas-Henning von Kamptz 	 * cylinder group we have to change that value now to fs_cpg.
5773d500078SThomas-Henning von Kamptz 	 */
5783d500078SThomas-Henning von Kamptz 
5793d500078SThomas-Henning von Kamptz 	if (cgbase(&osblock, cylno + 1) == osblock.fs_size) {
5801c85e6a3SKirk McKusick 		if (sblock.fs_magic == FS_UFS1_MAGIC)
5811c85e6a3SKirk McKusick 			acg.cg_old_ncyl = sblock.fs_old_cpg;
5823d500078SThomas-Henning von Kamptz 
58354fab0fbSKirk McKusick 		cgckhash(&acg);
584adcaff07SThomas-Henning von Kamptz 		wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)),
585adcaff07SThomas-Henning von Kamptz 		    (size_t)sblock.fs_cgsize, (void *)&acg, fso, Nflag);
5863d500078SThomas-Henning von Kamptz 		DBG_PRINT0("jcg written\n");
587a1da0740SEdward Tomasz Napierala 		DBG_DUMP_CG(&sblock, "new joining cg", &acg);
5883d500078SThomas-Henning von Kamptz 
5893d500078SThomas-Henning von Kamptz 		DBG_LEAVE;
5903d500078SThomas-Henning von Kamptz 		return;
5913d500078SThomas-Henning von Kamptz 	}
5923d500078SThomas-Henning von Kamptz 
5933d500078SThomas-Henning von Kamptz 	/*
5943d500078SThomas-Henning von Kamptz 	 * Set up some variables needed later.
5953d500078SThomas-Henning von Kamptz 	 */
5963d500078SThomas-Henning von Kamptz 	cbase = cgbase(&sblock, cylno);
5973d500078SThomas-Henning von Kamptz 	dmax = cbase + sblock.fs_fpg;
5983d500078SThomas-Henning von Kamptz 	if (dmax > sblock.fs_size)
5993d500078SThomas-Henning von Kamptz 		dmax = sblock.fs_size;
6003d500078SThomas-Henning von Kamptz 
6013d500078SThomas-Henning von Kamptz 	/*
6023d500078SThomas-Henning von Kamptz 	 * Set pointer to the cylinder summary for our cylinder group.
6033d500078SThomas-Henning von Kamptz 	 */
6043d500078SThomas-Henning von Kamptz 	cs = fscs + cylno;
6053d500078SThomas-Henning von Kamptz 
6063d500078SThomas-Henning von Kamptz 	/*
6073d500078SThomas-Henning von Kamptz 	 * Touch the cylinder group, update all fields in the cylinder group as
6083d500078SThomas-Henning von Kamptz 	 * needed, update the free space in the superblock.
6093d500078SThomas-Henning von Kamptz 	 */
610ea6de5eeSMarcel Moolenaar 	acg.cg_time = modtime;
61114a176a0SKirk McKusick 	if ((unsigned)cylno == sblock.fs_ncg - 1) {
6123d500078SThomas-Henning von Kamptz 		/*
6133d500078SThomas-Henning von Kamptz 		 * This is still the last cylinder group.
6143d500078SThomas-Henning von Kamptz 		 */
6151c85e6a3SKirk McKusick 		if (sblock.fs_magic == FS_UFS1_MAGIC)
6161c85e6a3SKirk McKusick 			acg.cg_old_ncyl =
6171c85e6a3SKirk McKusick 			    sblock.fs_old_ncyl % sblock.fs_old_cpg;
6183d500078SThomas-Henning von Kamptz 	} else {
6191c85e6a3SKirk McKusick 		acg.cg_old_ncyl = sblock.fs_old_cpg;
6203d500078SThomas-Henning von Kamptz 	}
621a1da0740SEdward Tomasz Napierala 	DBG_PRINT2("jcg dbg: %d %u", cylno, sblock.fs_ncg);
62275d1ec91SLukas Ertl #ifdef FS_DEBUG
6231c85e6a3SKirk McKusick 	if (sblock.fs_magic == FS_UFS1_MAGIC)
624a1da0740SEdward Tomasz Napierala 		DBG_PRINT2("%d %u", acg.cg_old_ncyl, sblock.fs_old_cpg);
62575d1ec91SLukas Ertl #endif
6261c85e6a3SKirk McKusick 	DBG_PRINT0("\n");
6273d500078SThomas-Henning von Kamptz 	acg.cg_ndblk = dmax - cbase;
6283d500078SThomas-Henning von Kamptz 	sblock.fs_dsize += acg.cg_ndblk - aocg.cg_ndblk;
6292049cc32SKirk McKusick 	sblock.fs_old_dsize = sblock.fs_dsize;
630a1da0740SEdward Tomasz Napierala 	if (sblock.fs_contigsumsize > 0)
6313d500078SThomas-Henning von Kamptz 		acg.cg_nclusterblks = acg.cg_ndblk / sblock.fs_frag;
6323d500078SThomas-Henning von Kamptz 
6333d500078SThomas-Henning von Kamptz 	/*
6343d500078SThomas-Henning von Kamptz 	 * Now we have to update the free fragment bitmap for our new free
6353d500078SThomas-Henning von Kamptz 	 * space.  There again we have to handle the fragmentation and also
6363d500078SThomas-Henning von Kamptz 	 * the rotational layout tables and the cluster summary.  This is
6373d500078SThomas-Henning von Kamptz 	 * also done per fragment for the first new block if the old file
6383d500078SThomas-Henning von Kamptz 	 * system end was not on a block boundary, per fragment for the new
6393d500078SThomas-Henning von Kamptz 	 * last block if the new file system end is not on a block boundary,
6403d500078SThomas-Henning von Kamptz 	 * and per block for all space in between.
6413d500078SThomas-Henning von Kamptz 	 *
6423d500078SThomas-Henning von Kamptz 	 * Handle the first new block here if it was partially available
6433d500078SThomas-Henning von Kamptz 	 * before.
6443d500078SThomas-Henning von Kamptz 	 */
6453d500078SThomas-Henning von Kamptz 	if (osblock.fs_size % sblock.fs_frag) {
646a1da0740SEdward Tomasz Napierala 		if (roundup(osblock.fs_size, sblock.fs_frag) <=
647a1da0740SEdward Tomasz Napierala 		    sblock.fs_size) {
6483d500078SThomas-Henning von Kamptz 			/*
6493d500078SThomas-Henning von Kamptz 			 * The new space is enough to fill at least this
6503d500078SThomas-Henning von Kamptz 			 * block
6513d500078SThomas-Henning von Kamptz 			 */
6523d500078SThomas-Henning von Kamptz 			j = 0;
653a1da0740SEdward Tomasz Napierala 			for (i = roundup(osblock.fs_size - cbase,
654a1da0740SEdward Tomasz Napierala 			    sblock.fs_frag) - 1; i >= osblock.fs_size - cbase;
6553d500078SThomas-Henning von Kamptz 			    i--) {
6563d500078SThomas-Henning von Kamptz 				setbit(cg_blksfree(&acg), i);
6573d500078SThomas-Henning von Kamptz 				acg.cg_cs.cs_nffree++;
6583d500078SThomas-Henning von Kamptz 				j++;
6593d500078SThomas-Henning von Kamptz 			}
6603d500078SThomas-Henning von Kamptz 
6613d500078SThomas-Henning von Kamptz 			/*
6623d500078SThomas-Henning von Kamptz 			 * Check if the fragment just created could join an
6633d500078SThomas-Henning von Kamptz 			 * already existing fragment at the former end of the
6643d500078SThomas-Henning von Kamptz 			 * file system.
6653d500078SThomas-Henning von Kamptz 			 */
6663d500078SThomas-Henning von Kamptz 			if (isblock(&sblock, cg_blksfree(&acg),
6673d500078SThomas-Henning von Kamptz 			    ((osblock.fs_size - cgbase(&sblock, cylno)) /
6683d500078SThomas-Henning von Kamptz 			     sblock.fs_frag))) {
6693d500078SThomas-Henning von Kamptz 				/*
6706ded0533SJens Schweikhardt 				 * The block is now completely available.
6713d500078SThomas-Henning von Kamptz 				 */
6723d500078SThomas-Henning von Kamptz 				DBG_PRINT0("block was\n");
6733d500078SThomas-Henning von Kamptz 				acg.cg_frsum[osblock.fs_size % sblock.fs_frag]--;
6743d500078SThomas-Henning von Kamptz 				acg.cg_cs.cs_nbfree++;
6753d500078SThomas-Henning von Kamptz 				acg.cg_cs.cs_nffree -= sblock.fs_frag;
6763d500078SThomas-Henning von Kamptz 				k = rounddown(osblock.fs_size - cbase,
6773d500078SThomas-Henning von Kamptz 				    sblock.fs_frag);
678a1da0740SEdward Tomasz Napierala 				updclst((osblock.fs_size - cbase) /
679a1da0740SEdward Tomasz Napierala 				    sblock.fs_frag);
6803d500078SThomas-Henning von Kamptz 			} else {
6813d500078SThomas-Henning von Kamptz 				/*
682*26c3d72eSHUANG,YU-JIA 				 * Lets rejoin a possible partially grown
6833d500078SThomas-Henning von Kamptz 				 * fragment.
6843d500078SThomas-Henning von Kamptz 				 */
6853d500078SThomas-Henning von Kamptz 				k = 0;
6863d500078SThomas-Henning von Kamptz 				while (isset(cg_blksfree(&acg), i) &&
6873d500078SThomas-Henning von Kamptz 				    (i >= rounddown(osblock.fs_size - cbase,
6883d500078SThomas-Henning von Kamptz 				    sblock.fs_frag))) {
6893d500078SThomas-Henning von Kamptz 					i--;
6903d500078SThomas-Henning von Kamptz 					k++;
6913d500078SThomas-Henning von Kamptz 				}
692a1da0740SEdward Tomasz Napierala 				if (k)
6933d500078SThomas-Henning von Kamptz 					acg.cg_frsum[k]--;
6943d500078SThomas-Henning von Kamptz 				acg.cg_frsum[k + j]++;
6953d500078SThomas-Henning von Kamptz 			}
6963d500078SThomas-Henning von Kamptz 		} else {
6973d500078SThomas-Henning von Kamptz 			/*
6983d500078SThomas-Henning von Kamptz 			 * We only grow by some fragments within this last
6993d500078SThomas-Henning von Kamptz 			 * block.
7003d500078SThomas-Henning von Kamptz 			 */
7013d500078SThomas-Henning von Kamptz 			for (i = sblock.fs_size - cbase - 1;
702a1da0740SEdward Tomasz Napierala 			    i >= osblock.fs_size - cbase; i--) {
7033d500078SThomas-Henning von Kamptz 				setbit(cg_blksfree(&acg), i);
7043d500078SThomas-Henning von Kamptz 				acg.cg_cs.cs_nffree++;
7053d500078SThomas-Henning von Kamptz 				j++;
7063d500078SThomas-Henning von Kamptz 			}
7073d500078SThomas-Henning von Kamptz 			/*
708*26c3d72eSHUANG,YU-JIA 			 * Lets rejoin a possible partially grown fragment.
7093d500078SThomas-Henning von Kamptz 			 */
7103d500078SThomas-Henning von Kamptz 			k = 0;
7113d500078SThomas-Henning von Kamptz 			while (isset(cg_blksfree(&acg), i) &&
7123d500078SThomas-Henning von Kamptz 			    (i >= rounddown(osblock.fs_size - cbase,
7133d500078SThomas-Henning von Kamptz 			    sblock.fs_frag))) {
7143d500078SThomas-Henning von Kamptz 				i--;
7153d500078SThomas-Henning von Kamptz 				k++;
7163d500078SThomas-Henning von Kamptz 			}
717a1da0740SEdward Tomasz Napierala 			if (k)
7183d500078SThomas-Henning von Kamptz 				acg.cg_frsum[k]--;
7193d500078SThomas-Henning von Kamptz 			acg.cg_frsum[k + j]++;
7203d500078SThomas-Henning von Kamptz 		}
7213d500078SThomas-Henning von Kamptz 	}
7223d500078SThomas-Henning von Kamptz 
7233d500078SThomas-Henning von Kamptz 	/*
7243d500078SThomas-Henning von Kamptz 	 * Handle all new complete blocks here.
7253d500078SThomas-Henning von Kamptz 	 */
7263d500078SThomas-Henning von Kamptz 	for (i = roundup(osblock.fs_size - cbase, sblock.fs_frag);
7273d500078SThomas-Henning von Kamptz 	    i + sblock.fs_frag <= dmax - cbase;	/* XXX <= or only < ? */
7283d500078SThomas-Henning von Kamptz 	    i += sblock.fs_frag) {
7293d500078SThomas-Henning von Kamptz 		j = i / sblock.fs_frag;
7303d500078SThomas-Henning von Kamptz 		setblock(&sblock, cg_blksfree(&acg), j);
7313d500078SThomas-Henning von Kamptz 		updclst(j);
7323d500078SThomas-Henning von Kamptz 		acg.cg_cs.cs_nbfree++;
7333d500078SThomas-Henning von Kamptz 	}
7343d500078SThomas-Henning von Kamptz 
7353d500078SThomas-Henning von Kamptz 	/*
736*26c3d72eSHUANG,YU-JIA 	 * Handle the last new block if there are still some new fragments left.
7373d500078SThomas-Henning von Kamptz 	 * Here we don't have to bother about the cluster summary or the even
7383d500078SThomas-Henning von Kamptz 	 * the rotational layout table.
7393d500078SThomas-Henning von Kamptz 	 */
7403d500078SThomas-Henning von Kamptz 	if (i < (dmax - cbase)) {
7413d500078SThomas-Henning von Kamptz 		acg.cg_frsum[dmax - cbase - i]++;
7423d500078SThomas-Henning von Kamptz 		for (; i < dmax - cbase; i++) {
7433d500078SThomas-Henning von Kamptz 			setbit(cg_blksfree(&acg), i);
7443d500078SThomas-Henning von Kamptz 			acg.cg_cs.cs_nffree++;
7453d500078SThomas-Henning von Kamptz 		}
7463d500078SThomas-Henning von Kamptz 	}
7473d500078SThomas-Henning von Kamptz 
7483d500078SThomas-Henning von Kamptz 	sblock.fs_cstotal.cs_nffree +=
7493d500078SThomas-Henning von Kamptz 	    (acg.cg_cs.cs_nffree - aocg.cg_cs.cs_nffree);
7503d500078SThomas-Henning von Kamptz 	sblock.fs_cstotal.cs_nbfree +=
7513d500078SThomas-Henning von Kamptz 	    (acg.cg_cs.cs_nbfree - aocg.cg_cs.cs_nbfree);
7523d500078SThomas-Henning von Kamptz 	/*
7533d500078SThomas-Henning von Kamptz 	 * The following statistics are not changed here:
7543d500078SThomas-Henning von Kamptz 	 *     sblock.fs_cstotal.cs_ndir
7553d500078SThomas-Henning von Kamptz 	 *     sblock.fs_cstotal.cs_nifree
7563d500078SThomas-Henning von Kamptz 	 * As the statistics for this cylinder group are ready, copy it to
7573d500078SThomas-Henning von Kamptz 	 * the summary information array.
7583d500078SThomas-Henning von Kamptz 	 */
7593d500078SThomas-Henning von Kamptz 	*cs = acg.cg_cs;
7603d500078SThomas-Henning von Kamptz 
7613d500078SThomas-Henning von Kamptz 	/*
7623d500078SThomas-Henning von Kamptz 	 * Write the updated "joining" cylinder group back to disk.
7633d500078SThomas-Henning von Kamptz 	 */
7643abf5d76SKirk McKusick 	cgckhash(&acg);
765adcaff07SThomas-Henning von Kamptz 	wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)), (size_t)sblock.fs_cgsize,
766adcaff07SThomas-Henning von Kamptz 	    (void *)&acg, fso, Nflag);
7673d500078SThomas-Henning von Kamptz 	DBG_PRINT0("jcg written\n");
768a1da0740SEdward Tomasz Napierala 	DBG_DUMP_CG(&sblock, "new joining cg", &acg);
7693d500078SThomas-Henning von Kamptz 
7703d500078SThomas-Henning von Kamptz 	DBG_LEAVE;
7713d500078SThomas-Henning von Kamptz 	return;
7723d500078SThomas-Henning von Kamptz }
7733d500078SThomas-Henning von Kamptz 
7743d500078SThomas-Henning von Kamptz /*
7753d500078SThomas-Henning von Kamptz  * Here we update the location of the cylinder summary. We have two possible
776e35497f1SEdward Tomasz Napierala  * ways of growing the cylinder summary:
7773d500078SThomas-Henning von Kamptz  * (1)	We can try to grow the summary in the current location, and relocate
7783d500078SThomas-Henning von Kamptz  *	possibly used blocks within the current cylinder group.
7793d500078SThomas-Henning von Kamptz  * (2)	Alternatively we can relocate the whole cylinder summary to the first
7803d500078SThomas-Henning von Kamptz  *	new completely empty cylinder group. Once the cylinder summary is no
7813d500078SThomas-Henning von Kamptz  *	longer in the beginning of the first cylinder group you should never
7823d500078SThomas-Henning von Kamptz  *	use a version of fsck which is not aware of the possibility to have
7833d500078SThomas-Henning von Kamptz  *	this structure in a non standard place.
7849f2d8a38SEdward Tomasz Napierala  * Option (2) is considered to be less intrusive to the structure of the file-
7859f2d8a38SEdward Tomasz Napierala  * system, so that's the one being used.
7863d500078SThomas-Henning von Kamptz  */
7873d500078SThomas-Henning von Kamptz static void
updcsloc(time_t modtime,int fsi,int fso,unsigned int Nflag)788ea6de5eeSMarcel Moolenaar updcsloc(time_t modtime, int fsi, int fso, unsigned int Nflag)
7893d500078SThomas-Henning von Kamptz {
7903d500078SThomas-Henning von Kamptz 	DBG_FUNC("updcsloc")
7913d500078SThomas-Henning von Kamptz 	struct csum *cs;
7923d500078SThomas-Henning von Kamptz 	int ocscg, ncscg;
7939f2d8a38SEdward Tomasz Napierala 	ufs2_daddr_t d;
7943d500078SThomas-Henning von Kamptz 	int lcs = 0;
7953d500078SThomas-Henning von Kamptz 	int block;
7963d500078SThomas-Henning von Kamptz 
7973d500078SThomas-Henning von Kamptz 	DBG_ENTER;
7983d500078SThomas-Henning von Kamptz 
7993d500078SThomas-Henning von Kamptz 	if (howmany(sblock.fs_cssize, sblock.fs_fsize) ==
8003d500078SThomas-Henning von Kamptz 	    howmany(osblock.fs_cssize, osblock.fs_fsize)) {
8013d500078SThomas-Henning von Kamptz 		/*
8023d500078SThomas-Henning von Kamptz 		 * No new fragment needed.
8033d500078SThomas-Henning von Kamptz 		 */
8043d500078SThomas-Henning von Kamptz 		DBG_LEAVE;
8053d500078SThomas-Henning von Kamptz 		return;
8063d500078SThomas-Henning von Kamptz 	}
8072049cc32SKirk McKusick 	/* Adjust fs_dsize by added summary blocks */
8082049cc32SKirk McKusick 	sblock.fs_dsize -= howmany(sblock.fs_cssize, sblock.fs_fsize) -
8092049cc32SKirk McKusick 	    howmany(osblock.fs_cssize, osblock.fs_fsize);
8102049cc32SKirk McKusick 	sblock.fs_old_dsize = sblock.fs_dsize;
8113d500078SThomas-Henning von Kamptz 	ocscg = dtog(&osblock, osblock.fs_csaddr);
8123d500078SThomas-Henning von Kamptz 	cs = fscs + ocscg;
8133d500078SThomas-Henning von Kamptz 
8143d500078SThomas-Henning von Kamptz 	/*
8153d500078SThomas-Henning von Kamptz 	 * Read original cylinder group from disk, and make a copy.
8165455cc1aSChristoph Herrmann 	 * XXX	If Nflag is set in some very rare cases we now miss
8175455cc1aSChristoph Herrmann 	 *	some changes done in updjcg by reading the unmodified
8185455cc1aSChristoph Herrmann 	 *	block from disk.
8193d500078SThomas-Henning von Kamptz 	 */
820adcaff07SThomas-Henning von Kamptz 	rdfs(fsbtodb(&osblock, cgtod(&osblock, ocscg)),
821adcaff07SThomas-Henning von Kamptz 	    (size_t)osblock.fs_cgsize, (void *)&aocg, fsi);
8223d500078SThomas-Henning von Kamptz 	DBG_PRINT0("oscg read\n");
823a1da0740SEdward Tomasz Napierala 	DBG_DUMP_CG(&sblock, "old summary cg", &aocg);
8243d500078SThomas-Henning von Kamptz 
8253d500078SThomas-Henning von Kamptz 	memcpy((void *)&cgun1, (void *)&cgun2, sizeof(cgun2));
8263d500078SThomas-Henning von Kamptz 
8273d500078SThomas-Henning von Kamptz 	/*
8283d500078SThomas-Henning von Kamptz 	 * Touch the cylinder group, set up local variables needed later
8293d500078SThomas-Henning von Kamptz 	 * and update the superblock.
8303d500078SThomas-Henning von Kamptz 	 */
831ea6de5eeSMarcel Moolenaar 	acg.cg_time = modtime;
8323d500078SThomas-Henning von Kamptz 
8333d500078SThomas-Henning von Kamptz 	/*
8343d500078SThomas-Henning von Kamptz 	 * XXX	In the case of having active snapshots we may need much more
8353d500078SThomas-Henning von Kamptz 	 *	blocks for the copy on write. We need each block twice, and
8363d500078SThomas-Henning von Kamptz 	 *	also up to 8*3 blocks for indirect blocks for all possible
8373d500078SThomas-Henning von Kamptz 	 *	references.
8383d500078SThomas-Henning von Kamptz 	 */
8393d500078SThomas-Henning von Kamptz 	/*
8403d500078SThomas-Henning von Kamptz 	 * There is not enough space in the old cylinder group to
8413d500078SThomas-Henning von Kamptz 	 * relocate all blocks as needed, so we relocate the whole
8423d500078SThomas-Henning von Kamptz 	 * cylinder group summary to a new group. We try to use the
8433d500078SThomas-Henning von Kamptz 	 * first complete new cylinder group just created. Within the
8446ded0533SJens Schweikhardt 	 * cylinder group we align the area immediately after the
8453d500078SThomas-Henning von Kamptz 	 * cylinder group information location in order to be as
8463d500078SThomas-Henning von Kamptz 	 * close as possible to the original implementation of ffs.
8473d500078SThomas-Henning von Kamptz 	 *
8483d500078SThomas-Henning von Kamptz 	 * First we have to make sure we'll find enough space in the
8493d500078SThomas-Henning von Kamptz 	 * new cylinder group. If not, then we currently give up.
8503d500078SThomas-Henning von Kamptz 	 * We start with freeing everything which was used by the
8513d500078SThomas-Henning von Kamptz 	 * fragments of the old cylinder summary in the current group.
8523d500078SThomas-Henning von Kamptz 	 * Now we write back the group meta data, read in the needed
8533d500078SThomas-Henning von Kamptz 	 * meta data from the new cylinder group, and start allocating
8543d500078SThomas-Henning von Kamptz 	 * within that group. Here we can assume, the group to be
8553d500078SThomas-Henning von Kamptz 	 * completely empty. Which makes the handling of fragments and
8563d500078SThomas-Henning von Kamptz 	 * clusters a lot easier.
8573d500078SThomas-Henning von Kamptz 	 */
8583d500078SThomas-Henning von Kamptz 	DBG_TRC;
859a1da0740SEdward Tomasz Napierala 	if (sblock.fs_ncg - osblock.fs_ncg < 2)
8604020c5bcSThomas-Henning von Kamptz 		errx(2, "panic: not enough space");
8613d500078SThomas-Henning von Kamptz 
8623d500078SThomas-Henning von Kamptz 	/*
8633d500078SThomas-Henning von Kamptz 	 * Point "d" to the first fragment not used by the cylinder
8643d500078SThomas-Henning von Kamptz 	 * summary.
8653d500078SThomas-Henning von Kamptz 	 */
8663d500078SThomas-Henning von Kamptz 	d = osblock.fs_csaddr + (osblock.fs_cssize / osblock.fs_fsize);
8673d500078SThomas-Henning von Kamptz 
8683d500078SThomas-Henning von Kamptz 	/*
8693d500078SThomas-Henning von Kamptz 	 * Set up last cluster size ("lcs") already here. Calculate
8703d500078SThomas-Henning von Kamptz 	 * the size for the trailing cluster just behind where "d"
8713d500078SThomas-Henning von Kamptz 	 * points to.
8723d500078SThomas-Henning von Kamptz 	 */
8733d500078SThomas-Henning von Kamptz 	if (sblock.fs_contigsumsize > 0) {
8743d500078SThomas-Henning von Kamptz 		for (block = howmany(d % sblock.fs_fpg, sblock.fs_frag),
8756ad07d53SEdward Tomasz Napierala 		    lcs = 0; lcs < sblock.fs_contigsumsize; block++, lcs++) {
876a1da0740SEdward Tomasz Napierala 			if (isclr(cg_clustersfree(&acg), block))
8773d500078SThomas-Henning von Kamptz 				break;
8783d500078SThomas-Henning von Kamptz 		}
8793d500078SThomas-Henning von Kamptz 	}
8803d500078SThomas-Henning von Kamptz 
8813d500078SThomas-Henning von Kamptz 	/*
8823d500078SThomas-Henning von Kamptz 	 * Point "d" to the last frag used by the cylinder summary.
8833d500078SThomas-Henning von Kamptz 	 */
8843d500078SThomas-Henning von Kamptz 	d--;
8853d500078SThomas-Henning von Kamptz 
886a1da0740SEdward Tomasz Napierala 	DBG_PRINT1("d=%jd\n", (intmax_t)d);
8873d500078SThomas-Henning von Kamptz 	if ((d + 1) % sblock.fs_frag) {
8883d500078SThomas-Henning von Kamptz 		/*
8893d500078SThomas-Henning von Kamptz 		 * The end of the cylinder summary is not a complete
8903d500078SThomas-Henning von Kamptz 		 * block.
8913d500078SThomas-Henning von Kamptz 		 */
8923d500078SThomas-Henning von Kamptz 		DBG_TRC;
8933d500078SThomas-Henning von Kamptz 		frag_adjust(d % sblock.fs_fpg, -1);
8943d500078SThomas-Henning von Kamptz 		for (; (d + 1) % sblock.fs_frag; d--) {
895a1da0740SEdward Tomasz Napierala 			DBG_PRINT1("d=%jd\n", (intmax_t)d);
8963d500078SThomas-Henning von Kamptz 			setbit(cg_blksfree(&acg), d % sblock.fs_fpg);
8973d500078SThomas-Henning von Kamptz 			acg.cg_cs.cs_nffree++;
8983d500078SThomas-Henning von Kamptz 			sblock.fs_cstotal.cs_nffree++;
8993d500078SThomas-Henning von Kamptz 		}
9003d500078SThomas-Henning von Kamptz 		/*
9013d500078SThomas-Henning von Kamptz 		 * Point "d" to the last fragment of the last
9026ded0533SJens Schweikhardt 		 * (incomplete) block of the cylinder summary.
9033d500078SThomas-Henning von Kamptz 		 */
9043d500078SThomas-Henning von Kamptz 		d++;
9053d500078SThomas-Henning von Kamptz 		frag_adjust(d % sblock.fs_fpg, 1);
9063d500078SThomas-Henning von Kamptz 
9073d500078SThomas-Henning von Kamptz 		if (isblock(&sblock, cg_blksfree(&acg),
9083d500078SThomas-Henning von Kamptz 		    (d % sblock.fs_fpg) / sblock.fs_frag)) {
90975d1ec91SLukas Ertl 			DBG_PRINT1("d=%jd\n", (intmax_t)d);
9103d500078SThomas-Henning von Kamptz 			acg.cg_cs.cs_nffree -= sblock.fs_frag;
9113d500078SThomas-Henning von Kamptz 			acg.cg_cs.cs_nbfree++;
9123d500078SThomas-Henning von Kamptz 			sblock.fs_cstotal.cs_nffree -= sblock.fs_frag;
9133d500078SThomas-Henning von Kamptz 			sblock.fs_cstotal.cs_nbfree++;
9143d500078SThomas-Henning von Kamptz 			if (sblock.fs_contigsumsize > 0) {
9153d500078SThomas-Henning von Kamptz 				setbit(cg_clustersfree(&acg),
9166ad07d53SEdward Tomasz Napierala 				    (d % sblock.fs_fpg) / sblock.fs_frag);
9173d500078SThomas-Henning von Kamptz 				if (lcs < sblock.fs_contigsumsize) {
918a1da0740SEdward Tomasz Napierala 					if (lcs)
919a1da0740SEdward Tomasz Napierala 						cg_clustersum(&acg)[lcs]--;
9203d500078SThomas-Henning von Kamptz 					lcs++;
9213d500078SThomas-Henning von Kamptz 					cg_clustersum(&acg)[lcs]++;
9223d500078SThomas-Henning von Kamptz 				}
9233d500078SThomas-Henning von Kamptz 			}
9243d500078SThomas-Henning von Kamptz 		}
9253d500078SThomas-Henning von Kamptz 		/*
9263d500078SThomas-Henning von Kamptz 		 * Point "d" to the first fragment of the block before
9273d500078SThomas-Henning von Kamptz 		 * the last incomplete block.
9283d500078SThomas-Henning von Kamptz 		 */
9293d500078SThomas-Henning von Kamptz 		d--;
9303d500078SThomas-Henning von Kamptz 	}
9313d500078SThomas-Henning von Kamptz 
93275d1ec91SLukas Ertl 	DBG_PRINT1("d=%jd\n", (intmax_t)d);
9333d500078SThomas-Henning von Kamptz 	for (d = rounddown(d, sblock.fs_frag); d >= osblock.fs_csaddr;
9343d500078SThomas-Henning von Kamptz 	    d -= sblock.fs_frag) {
9353d500078SThomas-Henning von Kamptz 		DBG_TRC;
93675d1ec91SLukas Ertl 		DBG_PRINT1("d=%jd\n", (intmax_t)d);
9373d500078SThomas-Henning von Kamptz 		setblock(&sblock, cg_blksfree(&acg),
9383d500078SThomas-Henning von Kamptz 		    (d % sblock.fs_fpg) / sblock.fs_frag);
9393d500078SThomas-Henning von Kamptz 		acg.cg_cs.cs_nbfree++;
9403d500078SThomas-Henning von Kamptz 		sblock.fs_cstotal.cs_nbfree++;
9413d500078SThomas-Henning von Kamptz 		if (sblock.fs_contigsumsize > 0) {
9423d500078SThomas-Henning von Kamptz 			setbit(cg_clustersfree(&acg),
9433d500078SThomas-Henning von Kamptz 			    (d % sblock.fs_fpg) / sblock.fs_frag);
9443d500078SThomas-Henning von Kamptz 			/*
9453d500078SThomas-Henning von Kamptz 			 * The last cluster size is already set up.
9463d500078SThomas-Henning von Kamptz 			 */
9473d500078SThomas-Henning von Kamptz 			if (lcs < sblock.fs_contigsumsize) {
948a1da0740SEdward Tomasz Napierala 				if (lcs)
9493d500078SThomas-Henning von Kamptz 					cg_clustersum(&acg)[lcs]--;
9503d500078SThomas-Henning von Kamptz 				lcs++;
9513d500078SThomas-Henning von Kamptz 				cg_clustersum(&acg)[lcs]++;
9523d500078SThomas-Henning von Kamptz 			}
9533d500078SThomas-Henning von Kamptz 		}
9543d500078SThomas-Henning von Kamptz 	}
9553d500078SThomas-Henning von Kamptz 	*cs = acg.cg_cs;
9563d500078SThomas-Henning von Kamptz 
9573d500078SThomas-Henning von Kamptz 	/*
9583d500078SThomas-Henning von Kamptz 	 * Now write the former cylinder group containing the cylinder
9593d500078SThomas-Henning von Kamptz 	 * summary back to disk.
9603d500078SThomas-Henning von Kamptz 	 */
96154fab0fbSKirk McKusick 	cgckhash(&acg);
962adcaff07SThomas-Henning von Kamptz 	wtfs(fsbtodb(&sblock, cgtod(&sblock, ocscg)),
963adcaff07SThomas-Henning von Kamptz 	    (size_t)sblock.fs_cgsize, (void *)&acg, fso, Nflag);
9643d500078SThomas-Henning von Kamptz 	DBG_PRINT0("oscg written\n");
965a1da0740SEdward Tomasz Napierala 	DBG_DUMP_CG(&sblock, "old summary cg", &acg);
9663d500078SThomas-Henning von Kamptz 
9673d500078SThomas-Henning von Kamptz 	/*
9683d500078SThomas-Henning von Kamptz 	 * Find the beginning of the new cylinder group containing the
9693d500078SThomas-Henning von Kamptz 	 * cylinder summary.
9703d500078SThomas-Henning von Kamptz 	 */
9713d500078SThomas-Henning von Kamptz 	sblock.fs_csaddr = cgdmin(&sblock, osblock.fs_ncg);
9723d500078SThomas-Henning von Kamptz 	ncscg = dtog(&sblock, sblock.fs_csaddr);
9733d500078SThomas-Henning von Kamptz 	cs = fscs + ncscg;
9743d500078SThomas-Henning von Kamptz 
9755455cc1aSChristoph Herrmann 	/*
9765455cc1aSChristoph Herrmann 	 * If Nflag is specified, we would now read random data instead
9775455cc1aSChristoph Herrmann 	 * of an empty cg structure from disk. So we can't simulate that
9785455cc1aSChristoph Herrmann 	 * part for now.
9795455cc1aSChristoph Herrmann 	 */
9805455cc1aSChristoph Herrmann 	if (Nflag) {
9815455cc1aSChristoph Herrmann 		DBG_PRINT0("nscg update skipped\n");
9825455cc1aSChristoph Herrmann 		DBG_LEAVE;
9835455cc1aSChristoph Herrmann 		return;
9845455cc1aSChristoph Herrmann 	}
9855455cc1aSChristoph Herrmann 
9863d500078SThomas-Henning von Kamptz 	/*
9873d500078SThomas-Henning von Kamptz 	 * Read the future cylinder group containing the cylinder
9883d500078SThomas-Henning von Kamptz 	 * summary from disk, and make a copy.
9893d500078SThomas-Henning von Kamptz 	 */
9903d500078SThomas-Henning von Kamptz 	rdfs(fsbtodb(&sblock, cgtod(&sblock, ncscg)),
991adcaff07SThomas-Henning von Kamptz 	    (size_t)sblock.fs_cgsize, (void *)&aocg, fsi);
9923d500078SThomas-Henning von Kamptz 	DBG_PRINT0("nscg read\n");
993a1da0740SEdward Tomasz Napierala 	DBG_DUMP_CG(&sblock, "new summary cg", &aocg);
9943d500078SThomas-Henning von Kamptz 
9953d500078SThomas-Henning von Kamptz 	memcpy((void *)&cgun1, (void *)&cgun2, sizeof(cgun2));
9963d500078SThomas-Henning von Kamptz 
9973d500078SThomas-Henning von Kamptz 	/*
9983d500078SThomas-Henning von Kamptz 	 * Allocate all complete blocks used by the new cylinder
9993d500078SThomas-Henning von Kamptz 	 * summary.
10003d500078SThomas-Henning von Kamptz 	 */
10013d500078SThomas-Henning von Kamptz 	for (d = sblock.fs_csaddr; d + sblock.fs_frag <=
10023d500078SThomas-Henning von Kamptz 	    sblock.fs_csaddr + (sblock.fs_cssize / sblock.fs_fsize);
10033d500078SThomas-Henning von Kamptz 	    d += sblock.fs_frag) {
10043d500078SThomas-Henning von Kamptz 		clrblock(&sblock, cg_blksfree(&acg),
10053d500078SThomas-Henning von Kamptz 		    (d % sblock.fs_fpg) / sblock.fs_frag);
10063d500078SThomas-Henning von Kamptz 		acg.cg_cs.cs_nbfree--;
10073d500078SThomas-Henning von Kamptz 		sblock.fs_cstotal.cs_nbfree--;
10083d500078SThomas-Henning von Kamptz 		if (sblock.fs_contigsumsize > 0) {
10093d500078SThomas-Henning von Kamptz 			clrbit(cg_clustersfree(&acg),
10103d500078SThomas-Henning von Kamptz 			    (d % sblock.fs_fpg) / sblock.fs_frag);
10113d500078SThomas-Henning von Kamptz 		}
10123d500078SThomas-Henning von Kamptz 	}
10133d500078SThomas-Henning von Kamptz 
10143d500078SThomas-Henning von Kamptz 	/*
10153d500078SThomas-Henning von Kamptz 	 * Allocate all fragments used by the cylinder summary in the
10163d500078SThomas-Henning von Kamptz 	 * last block.
10173d500078SThomas-Henning von Kamptz 	 */
10186ad07d53SEdward Tomasz Napierala 	if (d < sblock.fs_csaddr + (sblock.fs_cssize / sblock.fs_fsize)) {
10193d500078SThomas-Henning von Kamptz 		for (; d - sblock.fs_csaddr <
1020a1da0740SEdward Tomasz Napierala 		    sblock.fs_cssize/sblock.fs_fsize; d++) {
10213d500078SThomas-Henning von Kamptz 			clrbit(cg_blksfree(&acg), d % sblock.fs_fpg);
10223d500078SThomas-Henning von Kamptz 			acg.cg_cs.cs_nffree--;
10233d500078SThomas-Henning von Kamptz 			sblock.fs_cstotal.cs_nffree--;
10243d500078SThomas-Henning von Kamptz 		}
10253d500078SThomas-Henning von Kamptz 		acg.cg_cs.cs_nbfree--;
10263d500078SThomas-Henning von Kamptz 		acg.cg_cs.cs_nffree += sblock.fs_frag;
10273d500078SThomas-Henning von Kamptz 		sblock.fs_cstotal.cs_nbfree--;
10283d500078SThomas-Henning von Kamptz 		sblock.fs_cstotal.cs_nffree += sblock.fs_frag;
1029a1da0740SEdward Tomasz Napierala 		if (sblock.fs_contigsumsize > 0)
10303d500078SThomas-Henning von Kamptz 			clrbit(cg_clustersfree(&acg),
10313d500078SThomas-Henning von Kamptz 			    (d % sblock.fs_fpg) / sblock.fs_frag);
10323d500078SThomas-Henning von Kamptz 
1033a1da0740SEdward Tomasz Napierala 		frag_adjust(d % sblock.fs_fpg, 1);
10343d500078SThomas-Henning von Kamptz 	}
10353d500078SThomas-Henning von Kamptz 	/*
10363d500078SThomas-Henning von Kamptz 	 * XXX	Handle the cluster statistics here in the case this
10373d500078SThomas-Henning von Kamptz 	 *	cylinder group is now almost full, and the remaining
10383d500078SThomas-Henning von Kamptz 	 *	space is less then the maximum cluster size. This is
10393d500078SThomas-Henning von Kamptz 	 *	probably not needed, as you would hardly find a file
10403d500078SThomas-Henning von Kamptz 	 *	system which has only MAXCSBUFS+FS_MAXCONTIG of free
10413d500078SThomas-Henning von Kamptz 	 *	space right behind the cylinder group information in
10423d500078SThomas-Henning von Kamptz 	 *	any new cylinder group.
10433d500078SThomas-Henning von Kamptz 	 */
10443d500078SThomas-Henning von Kamptz 
10453d500078SThomas-Henning von Kamptz 	/*
10463d500078SThomas-Henning von Kamptz 	 * Update our statistics in the cylinder summary.
10473d500078SThomas-Henning von Kamptz 	 */
10483d500078SThomas-Henning von Kamptz 	*cs = acg.cg_cs;
10493d500078SThomas-Henning von Kamptz 
10503d500078SThomas-Henning von Kamptz 	/*
10513d500078SThomas-Henning von Kamptz 	 * Write the new cylinder group containing the cylinder summary
10523d500078SThomas-Henning von Kamptz 	 * back to disk.
10533d500078SThomas-Henning von Kamptz 	 */
105454fab0fbSKirk McKusick 	cgckhash(&acg);
1055adcaff07SThomas-Henning von Kamptz 	wtfs(fsbtodb(&sblock, cgtod(&sblock, ncscg)),
1056adcaff07SThomas-Henning von Kamptz 	    (size_t)sblock.fs_cgsize, (void *)&acg, fso, Nflag);
10573d500078SThomas-Henning von Kamptz 	DBG_PRINT0("nscg written\n");
1058a1da0740SEdward Tomasz Napierala 	DBG_DUMP_CG(&sblock, "new summary cg", &acg);
10593d500078SThomas-Henning von Kamptz 
10603d500078SThomas-Henning von Kamptz 	DBG_LEAVE;
10613d500078SThomas-Henning von Kamptz 	return;
10623d500078SThomas-Henning von Kamptz }
10633d500078SThomas-Henning von Kamptz 
10643d500078SThomas-Henning von Kamptz /*
10653d500078SThomas-Henning von Kamptz  * Here we read some block(s) from disk.
10663d500078SThomas-Henning von Kamptz  */
10673d500078SThomas-Henning von Kamptz static void
rdfs(ufs2_daddr_t bno,size_t size,void * bf,int fsi)10681c85e6a3SKirk McKusick rdfs(ufs2_daddr_t bno, size_t size, void *bf, int fsi)
10693d500078SThomas-Henning von Kamptz {
10703d500078SThomas-Henning von Kamptz 	DBG_FUNC("rdfs")
1071adcaff07SThomas-Henning von Kamptz 	ssize_t	n;
10723d500078SThomas-Henning von Kamptz 
10733d500078SThomas-Henning von Kamptz 	DBG_ENTER;
10743d500078SThomas-Henning von Kamptz 
1075a1da0740SEdward Tomasz Napierala 	if (bno < 0)
1076e3ec673eSPhilippe Charnier 		err(32, "rdfs: attempting to read negative block number");
1077a1da0740SEdward Tomasz Napierala 	if (lseek(fsi, (off_t)bno * DEV_BSIZE, 0) < 0)
107875d1ec91SLukas Ertl 		err(33, "rdfs: seek error: %jd", (intmax_t)bno);
1079adcaff07SThomas-Henning von Kamptz 	n = read(fsi, bf, size);
1080a1da0740SEdward Tomasz Napierala 	if (n != (ssize_t)size)
108175d1ec91SLukas Ertl 		err(34, "rdfs: read error: %jd", (intmax_t)bno);
10823d500078SThomas-Henning von Kamptz 
10833d500078SThomas-Henning von Kamptz 	DBG_LEAVE;
10843d500078SThomas-Henning von Kamptz 	return;
10853d500078SThomas-Henning von Kamptz }
10863d500078SThomas-Henning von Kamptz 
10873d500078SThomas-Henning von Kamptz /*
10883d500078SThomas-Henning von Kamptz  * Here we write some block(s) to disk.
10893d500078SThomas-Henning von Kamptz  */
10903d500078SThomas-Henning von Kamptz static void
wtfs(ufs2_daddr_t bno,size_t size,void * bf,int fso,unsigned int Nflag)10911c85e6a3SKirk McKusick wtfs(ufs2_daddr_t bno, size_t size, void *bf, int fso, unsigned int Nflag)
10923d500078SThomas-Henning von Kamptz {
10933d500078SThomas-Henning von Kamptz 	DBG_FUNC("wtfs")
1094adcaff07SThomas-Henning von Kamptz 	ssize_t	n;
10953d500078SThomas-Henning von Kamptz 
10963d500078SThomas-Henning von Kamptz 	DBG_ENTER;
10973d500078SThomas-Henning von Kamptz 
10983d500078SThomas-Henning von Kamptz 	if (Nflag) {
10993d500078SThomas-Henning von Kamptz 		DBG_LEAVE;
11003d500078SThomas-Henning von Kamptz 		return;
11013d500078SThomas-Henning von Kamptz 	}
1102a1da0740SEdward Tomasz Napierala 	if (lseek(fso, (off_t)bno * DEV_BSIZE, SEEK_SET) < 0)
11034020c5bcSThomas-Henning von Kamptz 		err(35, "wtfs: seek error: %ld", (long)bno);
1104adcaff07SThomas-Henning von Kamptz 	n = write(fso, bf, size);
1105a1da0740SEdward Tomasz Napierala 	if (n != (ssize_t)size)
11064020c5bcSThomas-Henning von Kamptz 		err(36, "wtfs: write error: %ld", (long)bno);
11073d500078SThomas-Henning von Kamptz 
11083d500078SThomas-Henning von Kamptz 	DBG_LEAVE;
11093d500078SThomas-Henning von Kamptz 	return;
11103d500078SThomas-Henning von Kamptz }
11113d500078SThomas-Henning von Kamptz 
11123d500078SThomas-Henning von Kamptz /*
11133d500078SThomas-Henning von Kamptz  * Here we check if all frags of a block are free. For more details again
11143d500078SThomas-Henning von Kamptz  * please see the source of newfs(8), as this function is taken over almost
11153d500078SThomas-Henning von Kamptz  * unchanged.
11163d500078SThomas-Henning von Kamptz  */
11173d500078SThomas-Henning von Kamptz static int
isblock(struct fs * fs,unsigned char * cp,int h)11183d500078SThomas-Henning von Kamptz isblock(struct fs *fs, unsigned char *cp, int h)
11193d500078SThomas-Henning von Kamptz {
11203d500078SThomas-Henning von Kamptz 	DBG_FUNC("isblock")
11213d500078SThomas-Henning von Kamptz 	unsigned char mask;
11223d500078SThomas-Henning von Kamptz 
11233d500078SThomas-Henning von Kamptz 	DBG_ENTER;
11243d500078SThomas-Henning von Kamptz 
11253d500078SThomas-Henning von Kamptz 	switch (fs->fs_frag) {
11263d500078SThomas-Henning von Kamptz 	case 8:
11273d500078SThomas-Henning von Kamptz 		DBG_LEAVE;
11283d500078SThomas-Henning von Kamptz 		return (cp[h] == 0xff);
11293d500078SThomas-Henning von Kamptz 	case 4:
11303d500078SThomas-Henning von Kamptz 		mask = 0x0f << ((h & 0x1) << 2);
11313d500078SThomas-Henning von Kamptz 		DBG_LEAVE;
11323d500078SThomas-Henning von Kamptz 		return ((cp[h >> 1] & mask) == mask);
11333d500078SThomas-Henning von Kamptz 	case 2:
11343d500078SThomas-Henning von Kamptz 		mask = 0x03 << ((h & 0x3) << 1);
11353d500078SThomas-Henning von Kamptz 		DBG_LEAVE;
11363d500078SThomas-Henning von Kamptz 		return ((cp[h >> 2] & mask) == mask);
11373d500078SThomas-Henning von Kamptz 	case 1:
11383d500078SThomas-Henning von Kamptz 		mask = 0x01 << (h & 0x7);
11393d500078SThomas-Henning von Kamptz 		DBG_LEAVE;
11403d500078SThomas-Henning von Kamptz 		return ((cp[h >> 3] & mask) == mask);
11413d500078SThomas-Henning von Kamptz 	default:
11423d500078SThomas-Henning von Kamptz 		fprintf(stderr, "isblock bad fs_frag %d\n", fs->fs_frag);
11433d500078SThomas-Henning von Kamptz 		DBG_LEAVE;
11443d500078SThomas-Henning von Kamptz 		return (0);
11453d500078SThomas-Henning von Kamptz 	}
11463d500078SThomas-Henning von Kamptz }
11473d500078SThomas-Henning von Kamptz 
11483d500078SThomas-Henning von Kamptz /*
11493d500078SThomas-Henning von Kamptz  * Here we allocate a complete block in the block map. For more details again
11503d500078SThomas-Henning von Kamptz  * please see the source of newfs(8), as this function is taken over almost
11513d500078SThomas-Henning von Kamptz  * unchanged.
11523d500078SThomas-Henning von Kamptz  */
11533d500078SThomas-Henning von Kamptz static void
clrblock(struct fs * fs,unsigned char * cp,int h)11543d500078SThomas-Henning von Kamptz clrblock(struct fs *fs, unsigned char *cp, int h)
11553d500078SThomas-Henning von Kamptz {
11563d500078SThomas-Henning von Kamptz 	DBG_FUNC("clrblock")
11573d500078SThomas-Henning von Kamptz 
11583d500078SThomas-Henning von Kamptz 	DBG_ENTER;
11593d500078SThomas-Henning von Kamptz 
11603d500078SThomas-Henning von Kamptz 	switch ((fs)->fs_frag) {
11613d500078SThomas-Henning von Kamptz 	case 8:
11623d500078SThomas-Henning von Kamptz 		cp[h] = 0;
11633d500078SThomas-Henning von Kamptz 		break;
11643d500078SThomas-Henning von Kamptz 	case 4:
11653d500078SThomas-Henning von Kamptz 		cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
11663d500078SThomas-Henning von Kamptz 		break;
11673d500078SThomas-Henning von Kamptz 	case 2:
11683d500078SThomas-Henning von Kamptz 		cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
11693d500078SThomas-Henning von Kamptz 		break;
11703d500078SThomas-Henning von Kamptz 	case 1:
11713d500078SThomas-Henning von Kamptz 		cp[h >> 3] &= ~(0x01 << (h & 0x7));
11723d500078SThomas-Henning von Kamptz 		break;
11733d500078SThomas-Henning von Kamptz 	default:
11744020c5bcSThomas-Henning von Kamptz 		warnx("clrblock bad fs_frag %d", fs->fs_frag);
11753d500078SThomas-Henning von Kamptz 		break;
11763d500078SThomas-Henning von Kamptz 	}
11773d500078SThomas-Henning von Kamptz 
11783d500078SThomas-Henning von Kamptz 	DBG_LEAVE;
11793d500078SThomas-Henning von Kamptz 	return;
11803d500078SThomas-Henning von Kamptz }
11813d500078SThomas-Henning von Kamptz 
11823d500078SThomas-Henning von Kamptz /*
11833d500078SThomas-Henning von Kamptz  * Here we free a complete block in the free block map. For more details again
11843d500078SThomas-Henning von Kamptz  * please see the source of newfs(8), as this function is taken over almost
11853d500078SThomas-Henning von Kamptz  * unchanged.
11863d500078SThomas-Henning von Kamptz  */
11873d500078SThomas-Henning von Kamptz static void
setblock(struct fs * fs,unsigned char * cp,int h)11883d500078SThomas-Henning von Kamptz setblock(struct fs *fs, unsigned char *cp, int h)
11893d500078SThomas-Henning von Kamptz {
11903d500078SThomas-Henning von Kamptz 	DBG_FUNC("setblock")
11913d500078SThomas-Henning von Kamptz 
11923d500078SThomas-Henning von Kamptz 	DBG_ENTER;
11933d500078SThomas-Henning von Kamptz 
11943d500078SThomas-Henning von Kamptz 	switch (fs->fs_frag) {
11953d500078SThomas-Henning von Kamptz 	case 8:
11963d500078SThomas-Henning von Kamptz 		cp[h] = 0xff;
11973d500078SThomas-Henning von Kamptz 		break;
11983d500078SThomas-Henning von Kamptz 	case 4:
11993d500078SThomas-Henning von Kamptz 		cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
12003d500078SThomas-Henning von Kamptz 		break;
12013d500078SThomas-Henning von Kamptz 	case 2:
12023d500078SThomas-Henning von Kamptz 		cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
12033d500078SThomas-Henning von Kamptz 		break;
12043d500078SThomas-Henning von Kamptz 	case 1:
12053d500078SThomas-Henning von Kamptz 		cp[h >> 3] |= (0x01 << (h & 0x7));
12063d500078SThomas-Henning von Kamptz 		break;
12073d500078SThomas-Henning von Kamptz 	default:
12084020c5bcSThomas-Henning von Kamptz 		warnx("setblock bad fs_frag %d", fs->fs_frag);
12093d500078SThomas-Henning von Kamptz 		break;
12103d500078SThomas-Henning von Kamptz 	}
12113d500078SThomas-Henning von Kamptz 
12123d500078SThomas-Henning von Kamptz 	DBG_LEAVE;
12133d500078SThomas-Henning von Kamptz 	return;
12143d500078SThomas-Henning von Kamptz }
12153d500078SThomas-Henning von Kamptz 
12163d500078SThomas-Henning von Kamptz /*
12173d500078SThomas-Henning von Kamptz  * Figure out how many lines our current terminal has. For more details again
12183d500078SThomas-Henning von Kamptz  * please see the source of newfs(8), as this function is taken over almost
12193d500078SThomas-Henning von Kamptz  * unchanged.
12203d500078SThomas-Henning von Kamptz  */
12213d500078SThomas-Henning von Kamptz static int
charsperline(void)12223d500078SThomas-Henning von Kamptz charsperline(void)
12233d500078SThomas-Henning von Kamptz {
12243d500078SThomas-Henning von Kamptz 	DBG_FUNC("charsperline")
12253d500078SThomas-Henning von Kamptz 	int columns;
12263d500078SThomas-Henning von Kamptz 	char *cp;
12273d500078SThomas-Henning von Kamptz 	struct winsize ws;
12283d500078SThomas-Henning von Kamptz 
12293d500078SThomas-Henning von Kamptz 	DBG_ENTER;
12303d500078SThomas-Henning von Kamptz 
12313d500078SThomas-Henning von Kamptz 	columns = 0;
1232a1da0740SEdward Tomasz Napierala 	if (ioctl(0, TIOCGWINSZ, &ws) != -1)
12333d500078SThomas-Henning von Kamptz 		columns = ws.ws_col;
1234a1da0740SEdward Tomasz Napierala 	if (columns == 0 && (cp = getenv("COLUMNS")))
12353d500078SThomas-Henning von Kamptz 		columns = atoi(cp);
1236a1da0740SEdward Tomasz Napierala 	if (columns == 0)
12373d500078SThomas-Henning von Kamptz 		columns = 80;	/* last resort */
12383d500078SThomas-Henning von Kamptz 
12393d500078SThomas-Henning von Kamptz 	DBG_LEAVE;
124091ac1479SEdward Tomasz Napierala 	return (columns);
12413d500078SThomas-Henning von Kamptz }
12423d500078SThomas-Henning von Kamptz 
1243e35497f1SEdward Tomasz Napierala static int
is_dev(const char * name)1244e35497f1SEdward Tomasz Napierala is_dev(const char *name)
12454b9748d4SGreg Lehey {
1246e35497f1SEdward Tomasz Napierala 	struct stat devstat;
12474b9748d4SGreg Lehey 
1248e35497f1SEdward Tomasz Napierala 	if (stat(name, &devstat) != 0)
1249e35497f1SEdward Tomasz Napierala 		return (0);
1250e35497f1SEdward Tomasz Napierala 	if (!S_ISCHR(devstat.st_mode))
1251e35497f1SEdward Tomasz Napierala 		return (0);
1252e35497f1SEdward Tomasz Napierala 	return (1);
1253e35497f1SEdward Tomasz Napierala }
12544b9748d4SGreg Lehey 
1255e35497f1SEdward Tomasz Napierala static const char *
getdev(const char * name,struct statfs * statfsp)1256906c312bSKirk McKusick getdev(const char *name, struct statfs *statfsp)
1257e35497f1SEdward Tomasz Napierala {
1258e35497f1SEdward Tomasz Napierala 	static char device[MAXPATHLEN];
1259906c312bSKirk McKusick 	const char *cp;
1260e35497f1SEdward Tomasz Napierala 
1261e35497f1SEdward Tomasz Napierala 	if (is_dev(name))
1262e35497f1SEdward Tomasz Napierala 		return (name);
1263e35497f1SEdward Tomasz Napierala 
1264e35497f1SEdward Tomasz Napierala 	cp = strrchr(name, '/');
1265edf6b683SMarcelo Araujo 	if (cp == NULL) {
1266e35497f1SEdward Tomasz Napierala 		snprintf(device, sizeof(device), "%s%s", _PATH_DEV, name);
1267e35497f1SEdward Tomasz Napierala 		if (is_dev(device))
1268e35497f1SEdward Tomasz Napierala 			return (device);
1269e35497f1SEdward Tomasz Napierala 	}
1270e35497f1SEdward Tomasz Napierala 
1271906c312bSKirk McKusick 	if (statfsp != NULL)
1272906c312bSKirk McKusick 		return (statfsp->f_mntfromname);
1273e35497f1SEdward Tomasz Napierala 
1274e35497f1SEdward Tomasz Napierala 	return (NULL);
12754b9748d4SGreg Lehey }
12764b9748d4SGreg Lehey 
12773d500078SThomas-Henning von Kamptz /*
12783d500078SThomas-Henning von Kamptz  * growfs(8) is a utility which allows to increase the size of an existing
12793d500078SThomas-Henning von Kamptz  * ufs file system. Currently this can only be done on unmounted file system.
12803d500078SThomas-Henning von Kamptz  * It recognizes some command line options to specify the new desired size,
12813d500078SThomas-Henning von Kamptz  * and it does some basic checkings. The old file system size is determined
12823d500078SThomas-Henning von Kamptz  * and after some more checks like we can really access the new last block
12833d500078SThomas-Henning von Kamptz  * on the disk etc. we calculate the new parameters for the superblock. After
128450c603c4SEdward Tomasz Napierala  * having done this we just call growfs() which will do the work.
12853d500078SThomas-Henning von Kamptz  * We still have to provide support for snapshots. Therefore we first have to
12863d500078SThomas-Henning von Kamptz  * understand what data structures are always replicated in the snapshot on
12873d500078SThomas-Henning von Kamptz  * creation, for all other blocks we touch during our procedure, we have to
12884020c5bcSThomas-Henning von Kamptz  * keep the old blocks unchanged somewhere available for the snapshots. If we
12893d500078SThomas-Henning von Kamptz  * are lucky, then we only have to handle our blocks to be relocated in that
12903d500078SThomas-Henning von Kamptz  * way.
12913d500078SThomas-Henning von Kamptz  * Also we have to consider in what order we actually update the critical
12924020c5bcSThomas-Henning von Kamptz  * data structures of the file system to make sure, that in case of a disaster
12933d500078SThomas-Henning von Kamptz  * fsck(8) is still able to restore any lost data.
12944020c5bcSThomas-Henning von Kamptz  * The foreseen last step then will be to provide for growing even mounted
12953d500078SThomas-Henning von Kamptz  * file systems. There we have to extend the mount() system call to provide
12963d500078SThomas-Henning von Kamptz  * userland access to the file system locking facility.
12973d500078SThomas-Henning von Kamptz  */
12983d500078SThomas-Henning von Kamptz int
main(int argc,char ** argv)12993d500078SThomas-Henning von Kamptz main(int argc, char **argv)
13003d500078SThomas-Henning von Kamptz {
13013d500078SThomas-Henning von Kamptz 	DBG_FUNC("main")
1302dffce215SKirk McKusick 	struct fs *fs;
1303e35497f1SEdward Tomasz Napierala 	const char *device;
1304906c312bSKirk McKusick 	struct statfs *statfsp;
1305e35497f1SEdward Tomasz Napierala 	uint64_t size = 0;
1306e35497f1SEdward Tomasz Napierala 	off_t mediasize;
1307dffce215SKirk McKusick 	int error, j, fsi, fso, ch, ret, Nflag = 0, yflag = 0;
1308e35497f1SEdward Tomasz Napierala 	char *p, reply[5], oldsizebuf[6], newsizebuf[6];
1309e35497f1SEdward Tomasz Napierala 	void *testbuf;
13103d500078SThomas-Henning von Kamptz 
13113d500078SThomas-Henning von Kamptz 	DBG_ENTER;
13123d500078SThomas-Henning von Kamptz 
13133d500078SThomas-Henning von Kamptz 	while ((ch = getopt(argc, argv, "Ns:vy")) != -1) {
13143d500078SThomas-Henning von Kamptz 		switch(ch) {
13153d500078SThomas-Henning von Kamptz 		case 'N':
13163d500078SThomas-Henning von Kamptz 			Nflag = 1;
13173d500078SThomas-Henning von Kamptz 			break;
13183d500078SThomas-Henning von Kamptz 		case 's':
1319e35497f1SEdward Tomasz Napierala 			size = (off_t)strtoumax(optarg, &p, 0);
1320e35497f1SEdward Tomasz Napierala 			if (p == NULL || *p == '\0')
1321e35497f1SEdward Tomasz Napierala 				size *= DEV_BSIZE;
1322e35497f1SEdward Tomasz Napierala 			else if (*p == 'b' || *p == 'B')
1323e35497f1SEdward Tomasz Napierala 				; /* do nothing */
1324e35497f1SEdward Tomasz Napierala 			else if (*p == 'k' || *p == 'K')
1325e35497f1SEdward Tomasz Napierala 				size <<= 10;
1326e35497f1SEdward Tomasz Napierala 			else if (*p == 'm' || *p == 'M')
1327e35497f1SEdward Tomasz Napierala 				size <<= 20;
1328e35497f1SEdward Tomasz Napierala 			else if (*p == 'g' || *p == 'G')
1329e35497f1SEdward Tomasz Napierala 				size <<= 30;
1330e35497f1SEdward Tomasz Napierala 			else if (*p == 't' || *p == 'T') {
1331e35497f1SEdward Tomasz Napierala 				size <<= 30;
1332e35497f1SEdward Tomasz Napierala 				size <<= 10;
1333e35497f1SEdward Tomasz Napierala 			} else
133470a0fb43SMina Galić 				errx(2, "unknown suffix on -s argument");
13353d500078SThomas-Henning von Kamptz 			break;
13363d500078SThomas-Henning von Kamptz 		case 'v': /* for compatibility to newfs */
13373d500078SThomas-Henning von Kamptz 			break;
13383d500078SThomas-Henning von Kamptz 		case 'y':
1339e35497f1SEdward Tomasz Napierala 			yflag = 1;
13403d500078SThomas-Henning von Kamptz 			break;
13413d500078SThomas-Henning von Kamptz 		case '?':
13423d500078SThomas-Henning von Kamptz 			/* FALLTHROUGH */
13433d500078SThomas-Henning von Kamptz 		default:
13444020c5bcSThomas-Henning von Kamptz 			usage();
13453d500078SThomas-Henning von Kamptz 		}
13463d500078SThomas-Henning von Kamptz 	}
13473d500078SThomas-Henning von Kamptz 	argc -= optind;
13483d500078SThomas-Henning von Kamptz 	argv += optind;
13493d500078SThomas-Henning von Kamptz 
1350a1da0740SEdward Tomasz Napierala 	if (argc != 1)
13514020c5bcSThomas-Henning von Kamptz 		usage();
1352a1da0740SEdward Tomasz Napierala 
1353e35497f1SEdward Tomasz Napierala 	/*
1354e35497f1SEdward Tomasz Napierala 	 * Now try to guess the device name.
1355e35497f1SEdward Tomasz Napierala 	 */
1356906c312bSKirk McKusick 	statfsp = getmntpoint(*argv);
1357906c312bSKirk McKusick 	device = getdev(*argv, statfsp);
1358e35497f1SEdward Tomasz Napierala 	if (device == NULL)
135970a0fb43SMina Galić 		errx(2, "cannot find special device for %s", *argv);
13603d500078SThomas-Henning von Kamptz 
13613d500078SThomas-Henning von Kamptz 	fsi = open(device, O_RDONLY);
1362a1da0740SEdward Tomasz Napierala 	if (fsi < 0)
136370a0fb43SMina Galić 		err(3, "%s", device);
13643d500078SThomas-Henning von Kamptz 
13653d500078SThomas-Henning von Kamptz 	/*
1366e35497f1SEdward Tomasz Napierala 	 * Try to guess the slice size if not specified.
13673d500078SThomas-Henning von Kamptz 	 */
1368e35497f1SEdward Tomasz Napierala 	if (ioctl(fsi, DIOCGMEDIASIZE, &mediasize) == -1)
136970a0fb43SMina Galić 		err(3,"DIOCGMEDIASIZE");
13703d500078SThomas-Henning von Kamptz 
13713d500078SThomas-Henning von Kamptz 	/*
13726ded0533SJens Schweikhardt 	 * Check if that partition is suitable for growing a file system.
13733d500078SThomas-Henning von Kamptz 	 */
1374e35497f1SEdward Tomasz Napierala 	if (mediasize < 1)
137570a0fb43SMina Galić 		errx(2, "partition is unavailable");
13763d500078SThomas-Henning von Kamptz 
13773d500078SThomas-Henning von Kamptz 	/*
13783d500078SThomas-Henning von Kamptz 	 * Read the current superblock, and take a backup.
13793d500078SThomas-Henning von Kamptz 	 */
1380b21582eeSKirk McKusick 	if ((ret = sbget(fsi, &fs, UFS_STDSB, 0)) != 0) {
1381dffce215SKirk McKusick 		switch (ret) {
1382dffce215SKirk McKusick 		case ENOENT:
138370a0fb43SMina Galić 			errx(2, "superblock not recognized");
1384dffce215SKirk McKusick 		default:
138570a0fb43SMina Galić 			errc(3, ret, "unable to read superblock");
1386dffce215SKirk McKusick 		}
1387dffce215SKirk McKusick 	}
13886eb925f8SKirk McKusick 	/*
13890dcde5ccSEd Maste 	 * Check for filesystem that was unclean at mount time.
13906eb925f8SKirk McKusick 	 */
13910dcde5ccSEd Maste 	if ((fs->fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) != 0)
139270a0fb43SMina Galić 		errx(2, "%s is not clean - run fsck.\n", *argv);
1393dffce215SKirk McKusick 	memcpy(&osblock, fs, fs->fs_sbsize);
1394dffce215SKirk McKusick 	free(fs);
1395dffce215SKirk McKusick 	memcpy((void *)&fsun1, (void *)&fsun2, osblock.fs_sbsize);
13963d500078SThomas-Henning von Kamptz 
13973d500078SThomas-Henning von Kamptz 	DBG_OPEN("/tmp/growfs.debug"); /* already here we need a superblock */
1398a1da0740SEdward Tomasz Napierala 	DBG_DUMP_FS(&sblock, "old sblock");
13993d500078SThomas-Henning von Kamptz 
14003d500078SThomas-Henning von Kamptz 	/*
140150c603c4SEdward Tomasz Napierala 	 * Determine size to grow to. Default to the device size.
14023d500078SThomas-Henning von Kamptz 	 */
1403e35497f1SEdward Tomasz Napierala 	if (size == 0)
1404e35497f1SEdward Tomasz Napierala 		size = mediasize;
1405e35497f1SEdward Tomasz Napierala 	else {
1406e35497f1SEdward Tomasz Napierala 		if (size > (uint64_t)mediasize) {
1407e35497f1SEdward Tomasz Napierala 			humanize_number(oldsizebuf, sizeof(oldsizebuf), size,
1408e35497f1SEdward Tomasz Napierala 			    "B", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
1409e35497f1SEdward Tomasz Napierala 			humanize_number(newsizebuf, sizeof(newsizebuf),
1410e35497f1SEdward Tomasz Napierala 			    mediasize,
1411e35497f1SEdward Tomasz Napierala 			    "B", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
1412e35497f1SEdward Tomasz Napierala 
141370a0fb43SMina Galić 			errx(2, "requested size %s is larger "
1414e35497f1SEdward Tomasz Napierala 			    "than the available %s", oldsizebuf, newsizebuf);
14153d500078SThomas-Henning von Kamptz 		}
1416e35497f1SEdward Tomasz Napierala 	}
1417e35497f1SEdward Tomasz Napierala 
1418cd379aafSEdward Tomasz Napierala 	/*
1419cd379aafSEdward Tomasz Napierala 	 * Make sure the new size is a multiple of fs_fsize; /dev/ufssuspend
1420cd379aafSEdward Tomasz Napierala 	 * only supports fragment-aligned IO requests.
1421cd379aafSEdward Tomasz Napierala 	 */
1422cd379aafSEdward Tomasz Napierala 	size -= size % osblock.fs_fsize;
1423cd379aafSEdward Tomasz Napierala 
1424e35497f1SEdward Tomasz Napierala 	if (size <= (uint64_t)(osblock.fs_size * osblock.fs_fsize)) {
1425e35497f1SEdward Tomasz Napierala 		humanize_number(oldsizebuf, sizeof(oldsizebuf),
1426e35497f1SEdward Tomasz Napierala 		    osblock.fs_size * osblock.fs_fsize,
1427e35497f1SEdward Tomasz Napierala 		    "B", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
1428e35497f1SEdward Tomasz Napierala 		humanize_number(newsizebuf, sizeof(newsizebuf), size,
1429e35497f1SEdward Tomasz Napierala 		    "B", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
1430e35497f1SEdward Tomasz Napierala 
14313f9acedbSEd Maste 		if (size == (uint64_t)(osblock.fs_size * osblock.fs_fsize))
14323f9acedbSEd Maste 			errx(0, "requested size %s is equal to the current "
14333f9acedbSEd Maste 			    "filesystem size %s", newsizebuf, oldsizebuf);
143470a0fb43SMina Galić 		errx(2, "requested size %s is smaller than the current "
1435e35497f1SEdward Tomasz Napierala 		   "filesystem size %s", newsizebuf, oldsizebuf);
1436e35497f1SEdward Tomasz Napierala 	}
1437e35497f1SEdward Tomasz Napierala 
14382049cc32SKirk McKusick 	sblock.fs_old_size = sblock.fs_size =
14392049cc32SKirk McKusick 	    dbtofsb(&osblock, size / DEV_BSIZE);
1440549f62faSEdward Tomasz Napierala 	sblock.fs_providersize = dbtofsb(&osblock, mediasize / DEV_BSIZE);
14413d500078SThomas-Henning von Kamptz 
14423d500078SThomas-Henning von Kamptz 	/*
14433d500078SThomas-Henning von Kamptz 	 * Are we really growing?
14443d500078SThomas-Henning von Kamptz 	 */
14453d500078SThomas-Henning von Kamptz 	if (osblock.fs_size >= sblock.fs_size) {
144670a0fb43SMina Galić 		errx(3, "we are not growing (%jd->%jd)",
144775d1ec91SLukas Ertl 		    (intmax_t)osblock.fs_size, (intmax_t)sblock.fs_size);
14483d500078SThomas-Henning von Kamptz 	}
14493d500078SThomas-Henning von Kamptz 
14503d500078SThomas-Henning von Kamptz 	/*
14513d500078SThomas-Henning von Kamptz 	 * Check if we find an active snapshot.
14523d500078SThomas-Henning von Kamptz 	 */
1453e35497f1SEdward Tomasz Napierala 	if (yflag == 0) {
14543d500078SThomas-Henning von Kamptz 		for (j = 0; j < FSMAXSNAP; j++) {
14553d500078SThomas-Henning von Kamptz 			if (sblock.fs_snapinum[j]) {
145670a0fb43SMina Galić 				errx(2, "active snapshot found in file system; "
14573d500078SThomas-Henning von Kamptz 				    "please remove all snapshots before "
1458e3ec673eSPhilippe Charnier 				    "using growfs");
14593d500078SThomas-Henning von Kamptz 			}
1460a1da0740SEdward Tomasz Napierala 			if (!sblock.fs_snapinum[j]) /* list is dense */
14613d500078SThomas-Henning von Kamptz 				break;
14623d500078SThomas-Henning von Kamptz 		}
14633d500078SThomas-Henning von Kamptz 	}
14643d500078SThomas-Henning von Kamptz 
1465e35497f1SEdward Tomasz Napierala 	if (yflag == 0 && Nflag == 0) {
1466e35497f1SEdward Tomasz Napierala 		if (statfsp != NULL && (statfsp->f_flags & MNT_RDONLY) == 0)
14672ec1a006SEdward Tomasz Napierala 			printf("Device is mounted read-write; resizing will "
14682ec1a006SEdward Tomasz Napierala 			    "result in temporary write suspension for %s.\n",
14692ec1a006SEdward Tomasz Napierala 			    statfsp->f_mntonname);
1470e35497f1SEdward Tomasz Napierala 		printf("It's strongly recommended to make a backup "
1471b2168df8SEdward Tomasz Napierala 		    "before growing the file system.\n"
1472e35497f1SEdward Tomasz Napierala 		    "OK to grow filesystem on %s", device);
1473e35497f1SEdward Tomasz Napierala 		if (statfsp != NULL)
1474e35497f1SEdward Tomasz Napierala 			printf(", mounted on %s,", statfsp->f_mntonname);
1475e35497f1SEdward Tomasz Napierala 		humanize_number(oldsizebuf, sizeof(oldsizebuf),
1476e35497f1SEdward Tomasz Napierala 		    osblock.fs_size * osblock.fs_fsize,
1477e35497f1SEdward Tomasz Napierala 		    "B", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
1478e35497f1SEdward Tomasz Napierala 		humanize_number(newsizebuf, sizeof(newsizebuf),
1479e35497f1SEdward Tomasz Napierala 		    sblock.fs_size * sblock.fs_fsize,
1480e35497f1SEdward Tomasz Napierala 		    "B", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
1481b8a1930fSEdward Tomasz Napierala 		printf(" from %s to %s? [yes/no] ", oldsizebuf, newsizebuf);
1482e35497f1SEdward Tomasz Napierala 		fflush(stdout);
1483adcaff07SThomas-Henning von Kamptz 		fgets(reply, (int)sizeof(reply), stdin);
1484b8a1930fSEdward Tomasz Napierala 		if (strcasecmp(reply, "yes\n")){
1485b8a1930fSEdward Tomasz Napierala 			printf("Response other than \"yes\"; aborting\n");
14863d500078SThomas-Henning von Kamptz 			exit(0);
14873d500078SThomas-Henning von Kamptz 		}
14883d500078SThomas-Henning von Kamptz 	}
14893d500078SThomas-Henning von Kamptz 
1490e35497f1SEdward Tomasz Napierala 	/*
1491e35497f1SEdward Tomasz Napierala 	 * Try to access our device for writing.  If it's not mounted,
1492e35497f1SEdward Tomasz Napierala 	 * or mounted read-only, simply open it; otherwise, use UFS
1493e35497f1SEdward Tomasz Napierala 	 * suspension mechanism.
1494e35497f1SEdward Tomasz Napierala 	 */
1495e35497f1SEdward Tomasz Napierala 	if (Nflag) {
1496e35497f1SEdward Tomasz Napierala 		fso = -1;
1497e35497f1SEdward Tomasz Napierala 	} else {
14982ec1a006SEdward Tomasz Napierala 		if (statfsp != NULL && (statfsp->f_flags & MNT_RDONLY) == 0) {
14992ec1a006SEdward Tomasz Napierala 			fso = open(_PATH_UFSSUSPEND, O_RDWR);
15002ec1a006SEdward Tomasz Napierala 			if (fso == -1)
150170a0fb43SMina Galić 				err(3, "unable to open %s", _PATH_UFSSUSPEND);
15022ec1a006SEdward Tomasz Napierala 			error = ioctl(fso, UFSSUSPEND, &statfsp->f_fsid);
15032ec1a006SEdward Tomasz Napierala 			if (error != 0)
150470a0fb43SMina Galić 				err(3, "UFSSUSPEND");
15052ec1a006SEdward Tomasz Napierala 		} else {
1506e35497f1SEdward Tomasz Napierala 			fso = open(device, O_WRONLY);
1507e35497f1SEdward Tomasz Napierala 			if (fso < 0)
150870a0fb43SMina Galić 				err(3, "%s", device);
1509e35497f1SEdward Tomasz Napierala 		}
15102ec1a006SEdward Tomasz Napierala 	}
15113d500078SThomas-Henning von Kamptz 
15123d500078SThomas-Henning von Kamptz 	/*
1513e35497f1SEdward Tomasz Napierala 	 * Try to access our new last block in the file system.
15143d500078SThomas-Henning von Kamptz 	 */
1515e35497f1SEdward Tomasz Napierala 	testbuf = malloc(sblock.fs_fsize);
1516e35497f1SEdward Tomasz Napierala 	if (testbuf == NULL)
151770a0fb43SMina Galić 		err(3, "malloc");
1518deb35287SEdward Tomasz Napierala 	rdfs((ufs2_daddr_t)((size - sblock.fs_fsize) / DEV_BSIZE),
1519e35497f1SEdward Tomasz Napierala 	    sblock.fs_fsize, testbuf, fsi);
1520deb35287SEdward Tomasz Napierala 	wtfs((ufs2_daddr_t)((size - sblock.fs_fsize) / DEV_BSIZE),
1521e35497f1SEdward Tomasz Napierala 	    sblock.fs_fsize, testbuf, fso, Nflag);
1522e35497f1SEdward Tomasz Napierala 	free(testbuf);
15233d500078SThomas-Henning von Kamptz 
15243d500078SThomas-Henning von Kamptz 	/*
15253d500078SThomas-Henning von Kamptz 	 * Now calculate new superblock values and check for reasonable
15263d500078SThomas-Henning von Kamptz 	 * bound for new file system size:
152750c603c4SEdward Tomasz Napierala 	 *     fs_size:    is derived from user input
15283d500078SThomas-Henning von Kamptz 	 *     fs_dsize:   should get updated in the routines creating or
15293d500078SThomas-Henning von Kamptz 	 *                 updating the cylinder groups on the fly
15303d500078SThomas-Henning von Kamptz 	 *     fs_cstotal: should get updated in the routines creating or
15313d500078SThomas-Henning von Kamptz 	 *                 updating the cylinder groups
15323d500078SThomas-Henning von Kamptz 	 */
15333d500078SThomas-Henning von Kamptz 
15343d500078SThomas-Henning von Kamptz 	/*
15351c85e6a3SKirk McKusick 	 * Update the number of cylinders and cylinder groups in the file system.
15363d500078SThomas-Henning von Kamptz 	 */
15371c85e6a3SKirk McKusick 	if (sblock.fs_magic == FS_UFS1_MAGIC) {
15381c85e6a3SKirk McKusick 		sblock.fs_old_ncyl =
15391c85e6a3SKirk McKusick 		    sblock.fs_size * sblock.fs_old_nspf / sblock.fs_old_spc;
15401c85e6a3SKirk McKusick 		if (sblock.fs_size * sblock.fs_old_nspf >
15411c85e6a3SKirk McKusick 		    sblock.fs_old_ncyl * sblock.fs_old_spc)
15421c85e6a3SKirk McKusick 			sblock.fs_old_ncyl++;
15433d500078SThomas-Henning von Kamptz 	}
15441c85e6a3SKirk McKusick 	sblock.fs_ncg = howmany(sblock.fs_size, sblock.fs_fpg);
15453d500078SThomas-Henning von Kamptz 
15463d500078SThomas-Henning von Kamptz 	/*
1547be1bfa99SEdward Tomasz Napierala 	 * Allocate last cylinder group only if there is enough room
1548be1bfa99SEdward Tomasz Napierala 	 * for at least one data block.
15493d500078SThomas-Henning von Kamptz 	 */
1550be1bfa99SEdward Tomasz Napierala 	if (sblock.fs_size % sblock.fs_fpg != 0 &&
1551be1bfa99SEdward Tomasz Napierala 	    sblock.fs_size <= cgdmin(&sblock, sblock.fs_ncg - 1)) {
1552be1bfa99SEdward Tomasz Napierala 		humanize_number(oldsizebuf, sizeof(oldsizebuf),
1553be1bfa99SEdward Tomasz Napierala 		    (sblock.fs_size % sblock.fs_fpg) * sblock.fs_fsize,
1554be1bfa99SEdward Tomasz Napierala 		    "B", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
1555be1bfa99SEdward Tomasz Napierala 		warnx("no room to allocate last cylinder group; "
1556be1bfa99SEdward Tomasz Napierala 		    "leaving %s unused", oldsizebuf);
15573d500078SThomas-Henning von Kamptz 		sblock.fs_ncg--;
15581c85e6a3SKirk McKusick 		if (sblock.fs_magic == FS_UFS1_MAGIC)
15591c85e6a3SKirk McKusick 			sblock.fs_old_ncyl = sblock.fs_ncg * sblock.fs_old_cpg;
15602049cc32SKirk McKusick 		sblock.fs_old_size = sblock.fs_size =
15612049cc32SKirk McKusick 		    sblock.fs_ncg * sblock.fs_fpg;
15623d500078SThomas-Henning von Kamptz 	}
15633d500078SThomas-Henning von Kamptz 
15643d500078SThomas-Henning von Kamptz 	/*
15653d500078SThomas-Henning von Kamptz 	 * Update the space for the cylinder group summary information in the
15663d500078SThomas-Henning von Kamptz 	 * respective cylinder group data area.
15673d500078SThomas-Henning von Kamptz 	 */
15683d500078SThomas-Henning von Kamptz 	sblock.fs_cssize =
15693d500078SThomas-Henning von Kamptz 	    fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum));
15703d500078SThomas-Henning von Kamptz 
1571a1da0740SEdward Tomasz Napierala 	if (osblock.fs_size >= sblock.fs_size)
157270a0fb43SMina Galić 		errx(3, "not enough new space");
15733d500078SThomas-Henning von Kamptz 
15743d500078SThomas-Henning von Kamptz 	DBG_PRINT0("sblock calculated\n");
15753d500078SThomas-Henning von Kamptz 
15763d500078SThomas-Henning von Kamptz 	/*
15773d500078SThomas-Henning von Kamptz 	 * Ok, everything prepared, so now let's do the tricks.
15783d500078SThomas-Henning von Kamptz 	 */
15793d500078SThomas-Henning von Kamptz 	growfs(fsi, fso, Nflag);
15803d500078SThomas-Henning von Kamptz 
15813d500078SThomas-Henning von Kamptz 	close(fsi);
1582e35497f1SEdward Tomasz Napierala 	if (fso > -1) {
15832ec1a006SEdward Tomasz Napierala 		if (statfsp != NULL && (statfsp->f_flags & MNT_RDONLY) == 0) {
15842ec1a006SEdward Tomasz Napierala 			error = ioctl(fso, UFSRESUME);
15852ec1a006SEdward Tomasz Napierala 			if (error != 0)
158670a0fb43SMina Galić 				err(3, "UFSRESUME");
15872ec1a006SEdward Tomasz Napierala 		}
1588e35497f1SEdward Tomasz Napierala 		error = close(fso);
1589e35497f1SEdward Tomasz Napierala 		if (error != 0)
159070a0fb43SMina Galić 			err(3, "close");
1591906c312bSKirk McKusick 		if (statfsp != NULL && (statfsp->f_flags & MNT_RDONLY) != 0 &&
1592906c312bSKirk McKusick 		    chkdoreload(statfsp, warn) != 0)
1593906c312bSKirk McKusick 			exit(9);
15942ec1a006SEdward Tomasz Napierala 	}
15953d500078SThomas-Henning von Kamptz 
15963d500078SThomas-Henning von Kamptz 	DBG_CLOSE;
15973d500078SThomas-Henning von Kamptz 
15983d500078SThomas-Henning von Kamptz 	DBG_LEAVE;
159991ac1479SEdward Tomasz Napierala 	return (0);
16003d500078SThomas-Henning von Kamptz }
16013d500078SThomas-Henning von Kamptz 
16023d500078SThomas-Henning von Kamptz /*
16033d500078SThomas-Henning von Kamptz  * Dump a line of usage.
16043d500078SThomas-Henning von Kamptz  */
16053d500078SThomas-Henning von Kamptz static void
usage(void)16064020c5bcSThomas-Henning von Kamptz usage(void)
16073d500078SThomas-Henning von Kamptz {
16083d500078SThomas-Henning von Kamptz 	DBG_FUNC("usage")
16093d500078SThomas-Henning von Kamptz 
16103d500078SThomas-Henning von Kamptz 	DBG_ENTER;
16113d500078SThomas-Henning von Kamptz 
1612e35497f1SEdward Tomasz Napierala 	fprintf(stderr, "usage: growfs [-Ny] [-s size] special | filesystem\n");
16134020c5bcSThomas-Henning von Kamptz 
16143d500078SThomas-Henning von Kamptz 	DBG_LEAVE;
16154020c5bcSThomas-Henning von Kamptz 	exit(1);
16163d500078SThomas-Henning von Kamptz }
16173d500078SThomas-Henning von Kamptz 
16183d500078SThomas-Henning von Kamptz /*
16196ded0533SJens Schweikhardt  * This updates most parameters and the bitmap related to cluster. We have to
16206ded0533SJens Schweikhardt  * assume that sblock, osblock, acg are set up.
16213d500078SThomas-Henning von Kamptz  */
16223d500078SThomas-Henning von Kamptz static void
updclst(int block)16233d500078SThomas-Henning von Kamptz updclst(int block)
16243d500078SThomas-Henning von Kamptz {
16253d500078SThomas-Henning von Kamptz 	DBG_FUNC("updclst")
16263d500078SThomas-Henning von Kamptz 	static int lcs = 0;
16273d500078SThomas-Henning von Kamptz 
16283d500078SThomas-Henning von Kamptz 	DBG_ENTER;
16293d500078SThomas-Henning von Kamptz 
1630a1da0740SEdward Tomasz Napierala 	if (sblock.fs_contigsumsize < 1) /* no clustering */
16313d500078SThomas-Henning von Kamptz 		return;
16323d500078SThomas-Henning von Kamptz 	/*
16333d500078SThomas-Henning von Kamptz 	 * update cluster allocation map
16343d500078SThomas-Henning von Kamptz 	 */
16353d500078SThomas-Henning von Kamptz 	setbit(cg_clustersfree(&acg), block);
16363d500078SThomas-Henning von Kamptz 
16373d500078SThomas-Henning von Kamptz 	/*
16383d500078SThomas-Henning von Kamptz 	 * update cluster summary table
16393d500078SThomas-Henning von Kamptz 	 */
16403d500078SThomas-Henning von Kamptz 	if (!lcs) {
16413d500078SThomas-Henning von Kamptz 		/*
16423d500078SThomas-Henning von Kamptz 		 * calculate size for the trailing cluster
16433d500078SThomas-Henning von Kamptz 		 */
16443d500078SThomas-Henning von Kamptz 		for (block--; lcs < sblock.fs_contigsumsize; block--, lcs++ ) {
1645a1da0740SEdward Tomasz Napierala 			if (isclr(cg_clustersfree(&acg), block))
16463d500078SThomas-Henning von Kamptz 				break;
16473d500078SThomas-Henning von Kamptz 		}
16483d500078SThomas-Henning von Kamptz 	}
16493d500078SThomas-Henning von Kamptz 	if (lcs < sblock.fs_contigsumsize) {
1650a1da0740SEdward Tomasz Napierala 		if (lcs)
16513d500078SThomas-Henning von Kamptz 			cg_clustersum(&acg)[lcs]--;
16523d500078SThomas-Henning von Kamptz 		lcs++;
16533d500078SThomas-Henning von Kamptz 		cg_clustersum(&acg)[lcs]++;
16543d500078SThomas-Henning von Kamptz 	}
16553d500078SThomas-Henning von Kamptz 
16563d500078SThomas-Henning von Kamptz 	DBG_LEAVE;
16573d500078SThomas-Henning von Kamptz 	return;
16583d500078SThomas-Henning von Kamptz }
1659e35497f1SEdward Tomasz Napierala 
16603abf5d76SKirk McKusick /*
16613abf5d76SKirk McKusick  * Calculate the check-hash of the cylinder group.
16623abf5d76SKirk McKusick  */
16633abf5d76SKirk McKusick static void
cgckhash(struct cg * cgp)16644887fa36SEd Maste cgckhash(struct cg *cgp)
16653abf5d76SKirk McKusick {
16663abf5d76SKirk McKusick 
16673abf5d76SKirk McKusick 	if ((sblock.fs_metackhash & CK_CYLGRP) == 0)
16683abf5d76SKirk McKusick 		return;
16693abf5d76SKirk McKusick 	cgp->cg_ckhash = 0;
16703abf5d76SKirk McKusick 	cgp->cg_ckhash = calculate_crc32c(~0L, (void *)cgp, sblock.fs_cgsize);
16713abf5d76SKirk McKusick }
1672