xref: /illumos-gate/usr/src/cmd/fs.d/ufs/mkfs/mkfs.c (revision 6d24e334)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5d1a180b0Smaheshvs  * Common Development and Distribution License (the "License").
6d1a180b0Smaheshvs  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*6d24e334Svsakar  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
277c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
317c478bd9Sstevel@tonic-gate  * The Regents of the University of California
327c478bd9Sstevel@tonic-gate  * All Rights Reserved
337c478bd9Sstevel@tonic-gate  *
347c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
357c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
367c478bd9Sstevel@tonic-gate  * contributors.
377c478bd9Sstevel@tonic-gate  */
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /*
437c478bd9Sstevel@tonic-gate  * The maximum supported file system size (in sectors) is the
447c478bd9Sstevel@tonic-gate  * number of frags that can be represented in an int32_t field
457c478bd9Sstevel@tonic-gate  * (INT_MAX) times the maximum number of sectors per frag.  Since
467c478bd9Sstevel@tonic-gate  * the maximum frag size is MAXBSIZE, the maximum number of sectors
477c478bd9Sstevel@tonic-gate  * per frag is MAXBSIZE/DEV_BSIZE.
487c478bd9Sstevel@tonic-gate  */
497c478bd9Sstevel@tonic-gate #define	FS_MAX	(((diskaddr_t)INT_MAX) * (MAXBSIZE/DEV_BSIZE))
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate /*
527c478bd9Sstevel@tonic-gate  * make file system for cylinder-group style file systems
537c478bd9Sstevel@tonic-gate  *
547c478bd9Sstevel@tonic-gate  * usage:
557c478bd9Sstevel@tonic-gate  *
567c478bd9Sstevel@tonic-gate  *    mkfs [-F FSType] [-V] [-G [-P]] [-M dirname] [-m] [options]
577c478bd9Sstevel@tonic-gate  *	[-o specific_options]  special size
587c478bd9Sstevel@tonic-gate  *	[nsect ntrack bsize fsize cpg	minfree	rps nbpi opt apc rotdelay
597c478bd9Sstevel@tonic-gate  *	  2     3      4     5     6	7	8   9	 10  11  12
607c478bd9Sstevel@tonic-gate  *	nrpos maxcontig mtb]
617c478bd9Sstevel@tonic-gate  *	13    14	15
627c478bd9Sstevel@tonic-gate  *
637c478bd9Sstevel@tonic-gate  *  where specific_options are:
647c478bd9Sstevel@tonic-gate  *	N - no create
657c478bd9Sstevel@tonic-gate  *	nsect - The number of sectors per track
667c478bd9Sstevel@tonic-gate  *	ntrack - The number of tracks per cylinder
677c478bd9Sstevel@tonic-gate  *	bsize - block size
687c478bd9Sstevel@tonic-gate  *	fragsize - fragment size
697c478bd9Sstevel@tonic-gate  *	cgsize - The number of disk cylinders per cylinder group.
707c478bd9Sstevel@tonic-gate  * 	free - minimum free space
717c478bd9Sstevel@tonic-gate  *	rps - rotational speed (rev/sec).
727c478bd9Sstevel@tonic-gate  *	nbpi - number of data bytes per allocated inode
737c478bd9Sstevel@tonic-gate  *	opt - optimization (space, time)
747c478bd9Sstevel@tonic-gate  *	apc - number of alternates
757c478bd9Sstevel@tonic-gate  *	gap - gap size
767c478bd9Sstevel@tonic-gate  *	nrpos - number of rotational positions
777c478bd9Sstevel@tonic-gate  *	maxcontig - maximum number of logical blocks that will be
787c478bd9Sstevel@tonic-gate  *		allocated contiguously before inserting rotational delay
797c478bd9Sstevel@tonic-gate  *	mtb - if "y", set up file system for eventual growth to over a
807c478bd9Sstevel@tonic-gate  *		a terabyte
817c478bd9Sstevel@tonic-gate  * -P Do not grow the file system, but print on stdout the maximal
827c478bd9Sstevel@tonic-gate  *    size in sectors to which the file system can be increased. The calculated
837c478bd9Sstevel@tonic-gate  *    size is limited by the value provided by the operand size.
847c478bd9Sstevel@tonic-gate  *
857c478bd9Sstevel@tonic-gate  * Note that -P is a project-private interface and together with -G intended
867c478bd9Sstevel@tonic-gate  * to be used only by the growfs script. It is therefore purposely not
877c478bd9Sstevel@tonic-gate  * documented in the man page.
887c478bd9Sstevel@tonic-gate  * The -P option is covered by PSARC case 2003/422.
897c478bd9Sstevel@tonic-gate  */
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate /*
927c478bd9Sstevel@tonic-gate  * The following constants set the defaults used for the number
937c478bd9Sstevel@tonic-gate  * of sectors/track (fs_nsect), and number of tracks/cyl (fs_ntrak).
947c478bd9Sstevel@tonic-gate  *
957c478bd9Sstevel@tonic-gate  *			NSECT		NTRAK
967c478bd9Sstevel@tonic-gate  *	72MB CDC	18		9
977c478bd9Sstevel@tonic-gate  *	30MB CDC	18		5
987c478bd9Sstevel@tonic-gate  *	720KB Diskette	9		2
996451fdbcSvsakar  *
1006451fdbcSvsakar  * However the defaults will be different for disks larger than CHSLIMIT.
1017c478bd9Sstevel@tonic-gate  */
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate #define	DFLNSECT	32
1047c478bd9Sstevel@tonic-gate #define	DFLNTRAK	16
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate /*
1076451fdbcSvsakar  * The following default sectors and tracks values are used for
1086451fdbcSvsakar  * non-efi disks that are larger than the CHS addressing limit. The
1096451fdbcSvsakar  * existing default cpg of 16 (DESCPG) holds good for larger disks too.
1107c478bd9Sstevel@tonic-gate  */
1116451fdbcSvsakar #define	DEF_SECTORS_EFI	128
1126451fdbcSvsakar #define	DEF_TRACKS_EFI	48
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate /*
1157c478bd9Sstevel@tonic-gate  * The maximum number of cylinders in a group depends upon how much
1167c478bd9Sstevel@tonic-gate  * information can be stored on a single cylinder. The default is to
1177c478bd9Sstevel@tonic-gate  * use 16 cylinders per group.  This is effectively tradition - it was
1187c478bd9Sstevel@tonic-gate  * the largest value acceptable under SunOs 4.1
1197c478bd9Sstevel@tonic-gate  */
1207c478bd9Sstevel@tonic-gate #define	DESCPG		16	/* desired fs_cpg */
1217c478bd9Sstevel@tonic-gate 
1226451fdbcSvsakar /*
1236451fdbcSvsakar  * The following two constants set the default block and fragment sizes.
1246451fdbcSvsakar  * Both constants must be a power of 2 and meet the following constraints:
1256451fdbcSvsakar  *	MINBSIZE <= DESBLKSIZE <= MAXBSIZE
1266451fdbcSvsakar  *	DEV_BSIZE <= DESFRAGSIZE <= DESBLKSIZE
1276451fdbcSvsakar  *	DESBLKSIZE / DESFRAGSIZE <= 8
1286451fdbcSvsakar  */
1296451fdbcSvsakar #define	DESBLKSIZE	8192
1306451fdbcSvsakar #define	DESFRAGSIZE	1024
1316451fdbcSvsakar 
1327c478bd9Sstevel@tonic-gate /*
1337c478bd9Sstevel@tonic-gate  * MINFREE gives the minimum acceptable percentage of file system
1347c478bd9Sstevel@tonic-gate  * blocks which may be free. If the freelist drops below this level
1357c478bd9Sstevel@tonic-gate  * only the superuser may continue to allocate blocks. This may
1367c478bd9Sstevel@tonic-gate  * be set to 0 if no reserve of free blocks is deemed necessary,
1377c478bd9Sstevel@tonic-gate  * however throughput drops by fifty percent if the file system
1387c478bd9Sstevel@tonic-gate  * is run at between 90% and 100% full; thus the default value of
1397c478bd9Sstevel@tonic-gate  * fs_minfree is 10%. With 10% free space, fragmentation is not a
1407c478bd9Sstevel@tonic-gate  * problem, so we choose to optimize for time.
1417c478bd9Sstevel@tonic-gate  */
1427c478bd9Sstevel@tonic-gate #define	MINFREE		10
1437c478bd9Sstevel@tonic-gate #define	DEFAULTOPT	FS_OPTTIME
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate /*
1467c478bd9Sstevel@tonic-gate  * ROTDELAY gives the minimum number of milliseconds to initiate
1477c478bd9Sstevel@tonic-gate  * another disk transfer on the same cylinder. It is no longer used
1487c478bd9Sstevel@tonic-gate  * and will always default to 0.
1497c478bd9Sstevel@tonic-gate  */
1507c478bd9Sstevel@tonic-gate #define	ROTDELAY	0
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate /*
1537c478bd9Sstevel@tonic-gate  * MAXBLKPG determines the maximum number of data blocks which are
1547c478bd9Sstevel@tonic-gate  * placed in a single cylinder group. The default is one indirect
1557c478bd9Sstevel@tonic-gate  * block worth of data blocks.
1567c478bd9Sstevel@tonic-gate  */
1577c478bd9Sstevel@tonic-gate #define	MAXBLKPG(bsize)	((bsize) / sizeof (daddr32_t))
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate /*
1607c478bd9Sstevel@tonic-gate  * Each file system has a number of inodes statically allocated.
1617c478bd9Sstevel@tonic-gate  * We allocate one inode slot per NBPI bytes, expecting this
1627c478bd9Sstevel@tonic-gate  * to be far more than we will ever need.
1637c478bd9Sstevel@tonic-gate  */
1647c478bd9Sstevel@tonic-gate #define	NBPI		2048	/* Number Bytes Per Inode */
1657c478bd9Sstevel@tonic-gate #define	MTB_NBPI	(MB)	/* Number Bytes Per Inode for multi-terabyte */
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate /*
1687c478bd9Sstevel@tonic-gate  * Disks are assumed to rotate at 60HZ, unless otherwise specified.
1697c478bd9Sstevel@tonic-gate  */
1707c478bd9Sstevel@tonic-gate #define	DEFHZ		60
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate /*
1737c478bd9Sstevel@tonic-gate  * Cylinder group related limits.
1747c478bd9Sstevel@tonic-gate  *
1757c478bd9Sstevel@tonic-gate  * For each cylinder we keep track of the availability of blocks at different
1767c478bd9Sstevel@tonic-gate  * rotational positions, so that we can lay out the data to be picked
1777c478bd9Sstevel@tonic-gate  * up with minimum rotational latency.  NRPOS is the number of rotational
1787c478bd9Sstevel@tonic-gate  * positions which we distinguish.  With NRPOS 8 the resolution of our
1797c478bd9Sstevel@tonic-gate  * summary information is 2ms for a typical 3600 rpm drive.
1807c478bd9Sstevel@tonic-gate  */
1817c478bd9Sstevel@tonic-gate #define	NRPOS		8	/* number distinct rotational positions */
1827c478bd9Sstevel@tonic-gate 
1836451fdbcSvsakar #ifdef DEBUG
1846451fdbcSvsakar #define	dprintf(x)	printf x
1856451fdbcSvsakar #else
1866451fdbcSvsakar #define	dprintf(x)
1876451fdbcSvsakar #endif
1886451fdbcSvsakar 
1896451fdbcSvsakar /*
1906451fdbcSvsakar  * For the -N option, when calculating the backup superblocks, do not print
1916451fdbcSvsakar  * them if we are not really sure. We may have to try an alternate method of
1926451fdbcSvsakar  * arriving at the superblocks. So defer printing till a handful of superblocks
1936451fdbcSvsakar  * look good.
1946451fdbcSvsakar  */
1956451fdbcSvsakar #define	tprintf(x)	if (Nflag && retry) \
196*6d24e334Svsakar 				(void) strncat(tmpbuf, x, strlen(x)); \
1976451fdbcSvsakar 			else \
1986451fdbcSvsakar 				(void) fprintf(stderr, x);
1996451fdbcSvsakar 
2006451fdbcSvsakar #define	ALTSB		32	/* Location of first backup superblock */
2016451fdbcSvsakar 
2027c478bd9Sstevel@tonic-gate /*
2037c478bd9Sstevel@tonic-gate  * range_check "user_supplied" flag values.
2047c478bd9Sstevel@tonic-gate  */
2057c478bd9Sstevel@tonic-gate #define	RC_DEFAULT	0
2067c478bd9Sstevel@tonic-gate #define	RC_KEYWORD	1
2077c478bd9Sstevel@tonic-gate #define	RC_POSITIONAL	2
2087c478bd9Sstevel@tonic-gate 
209303bf60bSsdebnath /*
210303bf60bSsdebnath  * ufs hole
211303bf60bSsdebnath  */
212303bf60bSsdebnath #define	UFS_HOLE	-1
213303bf60bSsdebnath 
2147c478bd9Sstevel@tonic-gate #ifndef	STANDALONE
2157c478bd9Sstevel@tonic-gate #include	<stdio.h>
2167c478bd9Sstevel@tonic-gate #include	<sys/mnttab.h>
2177c478bd9Sstevel@tonic-gate #endif
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate #include	<stdlib.h>
2207c478bd9Sstevel@tonic-gate #include	<unistd.h>
2217c478bd9Sstevel@tonic-gate #include	<malloc.h>
2227c478bd9Sstevel@tonic-gate #include	<string.h>
2237c478bd9Sstevel@tonic-gate #include	<strings.h>
2247c478bd9Sstevel@tonic-gate #include	<ctype.h>
2257c478bd9Sstevel@tonic-gate #include	<errno.h>
2267c478bd9Sstevel@tonic-gate #include	<sys/param.h>
2277c478bd9Sstevel@tonic-gate #include	<time.h>
2287c478bd9Sstevel@tonic-gate #include	<sys/types.h>
2297c478bd9Sstevel@tonic-gate #include	<sys/sysmacros.h>
2307c478bd9Sstevel@tonic-gate #include	<sys/vnode.h>
2317c478bd9Sstevel@tonic-gate #include	<sys/fs/ufs_fsdir.h>
2327c478bd9Sstevel@tonic-gate #include	<sys/fs/ufs_inode.h>
2337c478bd9Sstevel@tonic-gate #include	<sys/fs/ufs_fs.h>
2347c478bd9Sstevel@tonic-gate #include	<sys/fs/ufs_log.h>
2357c478bd9Sstevel@tonic-gate #include	<sys/mntent.h>
2367c478bd9Sstevel@tonic-gate #include	<sys/filio.h>
2377c478bd9Sstevel@tonic-gate #include	<limits.h>
2387c478bd9Sstevel@tonic-gate #include	<sys/int_const.h>
2397c478bd9Sstevel@tonic-gate #include	<signal.h>
2407c478bd9Sstevel@tonic-gate #include	<sys/efi_partition.h>
2417c478bd9Sstevel@tonic-gate #include	"roll_log.h"
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate #define	bcopy(f, t, n)    (void) memcpy(t, f, n)
2447c478bd9Sstevel@tonic-gate #define	bzero(s, n)	(void) memset(s, 0, n)
2457c478bd9Sstevel@tonic-gate #define	bcmp(s, d, n)	memcmp(s, d, n)
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate #define	index(s, r)	strchr(s, r)
2487c478bd9Sstevel@tonic-gate #define	rindex(s, r)	strrchr(s, r)
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate #include	<sys/stat.h>
2517c478bd9Sstevel@tonic-gate #include	<sys/statvfs.h>
2527c478bd9Sstevel@tonic-gate #include	<locale.h>
2537c478bd9Sstevel@tonic-gate #include	<fcntl.h>
2547c478bd9Sstevel@tonic-gate #include 	<sys/isa_defs.h>	/* for ENDIAN defines */
2557c478bd9Sstevel@tonic-gate #include	<sys/vtoc.h>
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate #include	<sys/dkio.h>
2587c478bd9Sstevel@tonic-gate #include	<sys/asynch.h>
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate extern offset_t	llseek();
2617c478bd9Sstevel@tonic-gate extern char	*getfullblkname();
2627c478bd9Sstevel@tonic-gate extern long	lrand48();
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate extern int	optind;
2657c478bd9Sstevel@tonic-gate extern char	*optarg;
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate /*
2697c478bd9Sstevel@tonic-gate  * The size of a cylinder group is calculated by CGSIZE. The maximum size
2707c478bd9Sstevel@tonic-gate  * is limited by the fact that cylinder groups are at most one block.
2717c478bd9Sstevel@tonic-gate  * Its size is derived from the size of the maps maintained in the
2727c478bd9Sstevel@tonic-gate  * cylinder group and the (struct cg) size.
2737c478bd9Sstevel@tonic-gate  */
2747c478bd9Sstevel@tonic-gate #define	CGSIZE(fs) \
2757c478bd9Sstevel@tonic-gate 	/* base cg		*/ (sizeof (struct cg) + \
2767c478bd9Sstevel@tonic-gate 	/* blktot size	*/ (fs)->fs_cpg * sizeof (long) + \
2777c478bd9Sstevel@tonic-gate 	/* blks size	*/ (fs)->fs_cpg * (fs)->fs_nrpos * sizeof (short) + \
2787c478bd9Sstevel@tonic-gate 	/* inode map	*/ howmany((fs)->fs_ipg, NBBY) + \
2797c478bd9Sstevel@tonic-gate 	/* block map */ howmany((fs)->fs_cpg * (fs)->fs_spc / NSPF(fs), NBBY))
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate /*
2827c478bd9Sstevel@tonic-gate  * We limit the size of the inode map to be no more than a
2837c478bd9Sstevel@tonic-gate  * third of the cylinder group space, since we must leave at
2847c478bd9Sstevel@tonic-gate  * least an equal amount of space for the block map.
2857c478bd9Sstevel@tonic-gate  *
2867c478bd9Sstevel@tonic-gate  * N.B.: MAXIpG must be a multiple of INOPB(fs).
2877c478bd9Sstevel@tonic-gate  */
2887c478bd9Sstevel@tonic-gate #define	MAXIpG(fs)	roundup((fs)->fs_bsize * NBBY / 3, INOPB(fs))
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate /*
2917c478bd9Sstevel@tonic-gate  * Same as MAXIpG, but parameterized by the block size (b) and the
2927c478bd9Sstevel@tonic-gate  * cylinder group divisor (d), which is the reciprocal of the fraction of the
2937c478bd9Sstevel@tonic-gate  * cylinder group overhead block that is used for the inode map.  So for
2947c478bd9Sstevel@tonic-gate  * example, if d = 5, the macro's computation assumes that 1/5 of the
2957c478bd9Sstevel@tonic-gate  * cylinder group overhead block can be dedicated to the inode map.
2967c478bd9Sstevel@tonic-gate  */
2977c478bd9Sstevel@tonic-gate #define	MAXIpG_B(b, d)	roundup((b) * NBBY / (d), (b) / sizeof (struct dinode))
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate #define	UMASK		0755
3007c478bd9Sstevel@tonic-gate #define	MAXINOPB	(MAXBSIZE / sizeof (struct dinode))
3017c478bd9Sstevel@tonic-gate #define	POWEROF2(num)	(((num) & ((num) - 1)) == 0)
3027c478bd9Sstevel@tonic-gate #define	MB		(1024*1024)
3037c478bd9Sstevel@tonic-gate #define	BETWEEN(x, l, h)	((x) >= (l) && (x) <= (h))
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate /*
3067c478bd9Sstevel@tonic-gate  * Used to set the inode generation number. Since both inodes and dinodes
3077c478bd9Sstevel@tonic-gate  * are dealt with, we really need a pointer to an icommon here.
3087c478bd9Sstevel@tonic-gate  */
3097c478bd9Sstevel@tonic-gate #define	IRANDOMIZE(icp)	(icp)->ic_gen = lrand48();
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate /*
3127c478bd9Sstevel@tonic-gate  * Flags for number()
3137c478bd9Sstevel@tonic-gate  */
3147c478bd9Sstevel@tonic-gate #define	ALLOW_PERCENT	0x01	/* allow trailing `%' on number */
3157c478bd9Sstevel@tonic-gate #define	ALLOW_MS1	0x02	/* allow trailing `ms', state 1 */
3167c478bd9Sstevel@tonic-gate #define	ALLOW_MS2	0x04	/* allow trailing `ms', state 2 */
3177c478bd9Sstevel@tonic-gate #define	ALLOW_END_ONLY	0x08	/* must be at end of number & suffixes */
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate #define	MAXAIO	1000	/* maximum number of outstanding I/O's we'll manage */
3207c478bd9Sstevel@tonic-gate #define	BLOCK	1	/* block in aiowait */
3217c478bd9Sstevel@tonic-gate #define	NOBLOCK	0	/* don't block in aiowait */
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate #define	RELEASE 1	/* free an aio buffer after use */
3247c478bd9Sstevel@tonic-gate #define	SAVE	0	/* don't free the buffer */
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate typedef struct aio_trans {
3277c478bd9Sstevel@tonic-gate 	aio_result_t resultbuf;
3287c478bd9Sstevel@tonic-gate 	diskaddr_t bno;
3297c478bd9Sstevel@tonic-gate 	char *buffer;
3307c478bd9Sstevel@tonic-gate 	int size;
3317c478bd9Sstevel@tonic-gate 	int release;
3327c478bd9Sstevel@tonic-gate 	struct aio_trans *next;
3337c478bd9Sstevel@tonic-gate } aio_trans;
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate typedef struct aio_results {
3367c478bd9Sstevel@tonic-gate 	int max;
3377c478bd9Sstevel@tonic-gate 	int outstanding;
3387c478bd9Sstevel@tonic-gate 	int maxpend;
3397c478bd9Sstevel@tonic-gate 	aio_trans *trans;
3407c478bd9Sstevel@tonic-gate } aio_results;
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate int aio_inited = 0;
3437c478bd9Sstevel@tonic-gate aio_results results;
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate /*
3467c478bd9Sstevel@tonic-gate  * Allow up to MAXBUF aio requests that each have a unique buffer.
3477c478bd9Sstevel@tonic-gate  * More aio's might be done, but not using memory through the getbuf()
3487c478bd9Sstevel@tonic-gate  * interface.  This can be raised, but you run into the potential of
3497c478bd9Sstevel@tonic-gate  * using more memory than is physically available on the machine,
3507c478bd9Sstevel@tonic-gate  * and if you start swapping, you can forget about performance.
3517c478bd9Sstevel@tonic-gate  * To prevent this, we also limit the total memory used for a given
3527c478bd9Sstevel@tonic-gate  * type of buffer to MAXBUFMEM.
3537c478bd9Sstevel@tonic-gate  *
3547c478bd9Sstevel@tonic-gate  * Tests indicate a cylinder group's worth of inodes takes:
3557c478bd9Sstevel@tonic-gate  *
3567c478bd9Sstevel@tonic-gate  *	NBPI	Size of Inode Buffer
3577c478bd9Sstevel@tonic-gate  *	 2k	1688k
3587c478bd9Sstevel@tonic-gate  *	 8k	 424k
3597c478bd9Sstevel@tonic-gate  *
3607c478bd9Sstevel@tonic-gate  * initcg() stores all the inodes for a cylinder group in one buffer,
3617c478bd9Sstevel@tonic-gate  * so allowing 20 buffers could take 32 MB if not limited by MAXBUFMEM.
3627c478bd9Sstevel@tonic-gate  */
3637c478bd9Sstevel@tonic-gate #define	MAXBUF		20
3647c478bd9Sstevel@tonic-gate #define	MAXBUFMEM	(8 * 1024 * 1024)
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate /*
3677c478bd9Sstevel@tonic-gate  * header information for buffers managed by getbuf() and freebuf()
3687c478bd9Sstevel@tonic-gate  */
3697c478bd9Sstevel@tonic-gate typedef struct bufhdr {
3707c478bd9Sstevel@tonic-gate 	struct bufhdr *head;
3717c478bd9Sstevel@tonic-gate 	struct bufhdr *next;
3727c478bd9Sstevel@tonic-gate } bufhdr;
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate int bufhdrsize;
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate bufhdr inodebuf = { NULL, NULL };
3777c478bd9Sstevel@tonic-gate bufhdr cgsumbuf = { NULL, NULL };
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate #define	SECTORS_PER_TERABYTE	(1LL << 31)
3807c478bd9Sstevel@tonic-gate /*
3817c478bd9Sstevel@tonic-gate  * The following constant specifies an upper limit for file system size
3827c478bd9Sstevel@tonic-gate  * that is actually a lot bigger than we expect to support with UFS. (Since
3837c478bd9Sstevel@tonic-gate  * it's specified in sectors, the file system size would be 2**44 * 512,
3847c478bd9Sstevel@tonic-gate  * which is 2**53, which is 8192 Terabytes.)  However, it's useful
3857c478bd9Sstevel@tonic-gate  * for checking the basic sanity of a size value that is input on the
3867c478bd9Sstevel@tonic-gate  * command line.
3877c478bd9Sstevel@tonic-gate  */
3887c478bd9Sstevel@tonic-gate #define	FS_SIZE_UPPER_LIMIT	0x100000000000LL
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate /*
3917c478bd9Sstevel@tonic-gate  * Forward declarations
3927c478bd9Sstevel@tonic-gate  */
3937c478bd9Sstevel@tonic-gate static char *getbuf(bufhdr *bufhead, int size);
3947c478bd9Sstevel@tonic-gate static void freebuf(char *buf);
3957c478bd9Sstevel@tonic-gate static void freetrans(aio_trans *transp);
3967c478bd9Sstevel@tonic-gate static aio_trans *get_aiop();
3977c478bd9Sstevel@tonic-gate static aio_trans *wait_for_write(int block);
3987c478bd9Sstevel@tonic-gate static void initcg(int cylno);
3997c478bd9Sstevel@tonic-gate static void fsinit();
4007c478bd9Sstevel@tonic-gate static int makedir(struct direct *protodir, int entries);
4017c478bd9Sstevel@tonic-gate static void iput(struct inode *ip);
4027c478bd9Sstevel@tonic-gate static void rdfs(diskaddr_t bno, int size, char *bf);
4037c478bd9Sstevel@tonic-gate static void wtfs(diskaddr_t bno, int size, char *bf);
4047c478bd9Sstevel@tonic-gate static void awtfs(diskaddr_t bno, int size, char *bf, int release);
4057c478bd9Sstevel@tonic-gate static void wtfs_breakup(diskaddr_t bno, int size, char *bf);
4067c478bd9Sstevel@tonic-gate static int isblock(struct fs *fs, unsigned char *cp, int h);
4077c478bd9Sstevel@tonic-gate static void clrblock(struct fs *fs, unsigned char *cp, int h);
4087c478bd9Sstevel@tonic-gate static void setblock(struct fs *fs, unsigned char *cp, int h);
4097c478bd9Sstevel@tonic-gate static void usage();
4107c478bd9Sstevel@tonic-gate static void dump_fscmd(char *fsys, int fsi);
4117c478bd9Sstevel@tonic-gate static uint64_t number(uint64_t d_value, char *param, int flags);
4127c478bd9Sstevel@tonic-gate static int match(char *s);
4137c478bd9Sstevel@tonic-gate static char checkopt(char *optim);
4147c478bd9Sstevel@tonic-gate static char checkmtb(char *mtbarg);
4157c478bd9Sstevel@tonic-gate static void range_check(long *varp, char *name, long minimum,
4167c478bd9Sstevel@tonic-gate     long maximum, long def_val, int user_supplied);
4177c478bd9Sstevel@tonic-gate static void range_check_64(uint64_t *varp, char *name, uint64_t minimum,
4187c478bd9Sstevel@tonic-gate     uint64_t maximum, uint64_t def_val, int user_supplied);
4197c478bd9Sstevel@tonic-gate static daddr32_t alloc(int size, int mode);
4207c478bd9Sstevel@tonic-gate static diskaddr_t get_max_size(int fd);
4217c478bd9Sstevel@tonic-gate static long get_max_track_size(int fd);
4227c478bd9Sstevel@tonic-gate static void block_sigint(sigset_t *old_mask);
4237c478bd9Sstevel@tonic-gate static void unblock_sigint(sigset_t *old_mask);
4247c478bd9Sstevel@tonic-gate static void recover_from_sigint(int signum);
4257c478bd9Sstevel@tonic-gate static int confirm_abort(void);
4267c478bd9Sstevel@tonic-gate static int getline(FILE *fp, char *loc, int maxlen);
4277c478bd9Sstevel@tonic-gate static void flush_writes(void);
4287c478bd9Sstevel@tonic-gate static long compute_maxcpg(long, long, long, long, long);
4297c478bd9Sstevel@tonic-gate static int in_64bit_mode(void);
4307c478bd9Sstevel@tonic-gate static int validate_size(int fd, diskaddr_t size);
431355d6bb5Sswilcox static void dump_sblock(void);
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate union {
4347c478bd9Sstevel@tonic-gate 	struct fs fs;
4357c478bd9Sstevel@tonic-gate 	char pad[SBSIZE];
4366451fdbcSvsakar } fsun, altfsun;
4377c478bd9Sstevel@tonic-gate #define	sblock	fsun.fs
4386451fdbcSvsakar #define	altsblock	altfsun.fs
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate struct	csum *fscs;
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate union cgun {
4437c478bd9Sstevel@tonic-gate 	struct cg cg;
4447c478bd9Sstevel@tonic-gate 	char pad[MAXBSIZE];
4457c478bd9Sstevel@tonic-gate } cgun;
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate #define	acg	cgun.cg
4487c478bd9Sstevel@tonic-gate /*
4497c478bd9Sstevel@tonic-gate  * Size of screen in cols in which to fit output
4507c478bd9Sstevel@tonic-gate  */
4517c478bd9Sstevel@tonic-gate #define	WIDTH	80
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate struct dinode zino[MAXBSIZE / sizeof (struct dinode)];
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate /*
4567c478bd9Sstevel@tonic-gate  * file descriptors used for rdfs(fsi) and wtfs(fso).
4577c478bd9Sstevel@tonic-gate  * Initialized to an illegal file descriptor number.
4587c478bd9Sstevel@tonic-gate  */
4597c478bd9Sstevel@tonic-gate int	fsi = -1;
4607c478bd9Sstevel@tonic-gate int	fso = -1;
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate /*
4637c478bd9Sstevel@tonic-gate  * The BIG parameter is machine dependent.  It should be a longlong integer
4647c478bd9Sstevel@tonic-gate  * constant that can be used by the number parser to check the validity
4657c478bd9Sstevel@tonic-gate  * of numeric parameters.
4667c478bd9Sstevel@tonic-gate  */
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate #define	BIG		0x7fffffffffffffffLL
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate /* Used to indicate to number() that a bogus value should cause us to exit */
4717c478bd9Sstevel@tonic-gate #define	NO_DEFAULT	LONG_MIN
4727c478bd9Sstevel@tonic-gate 
4736451fdbcSvsakar /*
4746451fdbcSvsakar  * INVALIDSBLIMIT is the number of bad backup superblocks that will be
4756451fdbcSvsakar  * tolerated before we decide to try arriving at a different set of them
4766451fdbcSvsakar  * using a different logic. This is applicable for non-EFI disks only.
4776451fdbcSvsakar  */
4786451fdbcSvsakar #define	INVALIDSBLIMIT	10
4796451fdbcSvsakar 
4807c478bd9Sstevel@tonic-gate /*
4817c478bd9Sstevel@tonic-gate  * The *_flag variables are used to indicate that the user specified
4827c478bd9Sstevel@tonic-gate  * the values, rather than that we made them up ourselves.  We can
4837c478bd9Sstevel@tonic-gate  * complain about the user giving us bogus values.
4847c478bd9Sstevel@tonic-gate  */
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate /* semi-constants */
4877c478bd9Sstevel@tonic-gate long	sectorsize = DEV_BSIZE;		/* bytes/sector from param.h */
4887c478bd9Sstevel@tonic-gate long	bbsize = BBSIZE;		/* boot block size */
4897c478bd9Sstevel@tonic-gate long	sbsize = SBSIZE;		/* superblock size */
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate /* parameters */
4927c478bd9Sstevel@tonic-gate diskaddr_t	fssize_db;		/* file system size in disk blocks */
4937c478bd9Sstevel@tonic-gate diskaddr_t	fssize_frag;		/* file system size in frags */
4947c478bd9Sstevel@tonic-gate long	cpg;				/* cylinders/cylinder group */
4957c478bd9Sstevel@tonic-gate int	cpg_flag = RC_DEFAULT;
4967c478bd9Sstevel@tonic-gate long	rotdelay = -1;			/* rotational delay between blocks */
4977c478bd9Sstevel@tonic-gate int	rotdelay_flag = RC_DEFAULT;
4987c478bd9Sstevel@tonic-gate long	maxcontig;			/* max contiguous blocks to allocate */
4997c478bd9Sstevel@tonic-gate int	maxcontig_flag = RC_DEFAULT;
5007c478bd9Sstevel@tonic-gate long	nsect = DFLNSECT;		/* sectors per track */
5017c478bd9Sstevel@tonic-gate int	nsect_flag = RC_DEFAULT;
5027c478bd9Sstevel@tonic-gate long	ntrack = DFLNTRAK;		/* tracks per cylinder group */
5037c478bd9Sstevel@tonic-gate int	ntrack_flag = RC_DEFAULT;
5047c478bd9Sstevel@tonic-gate long	bsize = DESBLKSIZE;		/* filesystem block size */
5057c478bd9Sstevel@tonic-gate int	bsize_flag = RC_DEFAULT;
5067c478bd9Sstevel@tonic-gate long	fragsize = DESFRAGSIZE; 	/* filesystem fragment size */
5077c478bd9Sstevel@tonic-gate int	fragsize_flag = RC_DEFAULT;
5087c478bd9Sstevel@tonic-gate long	minfree = MINFREE; 		/* fs_minfree */
5097c478bd9Sstevel@tonic-gate int	minfree_flag = RC_DEFAULT;
5107c478bd9Sstevel@tonic-gate long	rps = DEFHZ;			/* revolutions/second of drive */
5117c478bd9Sstevel@tonic-gate int	rps_flag = RC_DEFAULT;
5127c478bd9Sstevel@tonic-gate long	nbpi = NBPI;			/* number of bytes per inode */
5137c478bd9Sstevel@tonic-gate int	nbpi_flag = RC_DEFAULT;
5147c478bd9Sstevel@tonic-gate long	nrpos = NRPOS;			/* number of rotational positions */
5157c478bd9Sstevel@tonic-gate int	nrpos_flag = RC_DEFAULT;
5167c478bd9Sstevel@tonic-gate long	apc = 0;			/* alternate sectors per cylinder */
5177c478bd9Sstevel@tonic-gate int	apc_flag = RC_DEFAULT;
5187c478bd9Sstevel@tonic-gate char	opt = 't';			/* optimization style, `t' or `s' */
5197c478bd9Sstevel@tonic-gate char	mtb = 'n';			/* multi-terabyte format, 'y' or 'n' */
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate long	debug = 0;			/* enable debugging output */
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate int	spc_flag = 0;			/* alternate sectors specified or */
5247c478bd9Sstevel@tonic-gate 					/* found */
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate /* global state */
5277c478bd9Sstevel@tonic-gate int	Nflag;		/* do not write to disk */
5287c478bd9Sstevel@tonic-gate int	mflag;		/* return the command line used to create this FS */
529355d6bb5Sswilcox int	rflag;		/* report the superblock in an easily-parsed form */
530355d6bb5Sswilcox int	Rflag;		/* dump the superblock in binary */
5317c478bd9Sstevel@tonic-gate char	*fsys;
5327c478bd9Sstevel@tonic-gate time_t	mkfstime;
5337c478bd9Sstevel@tonic-gate char	*string;
5346451fdbcSvsakar int	label_type;
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate /*
5377c478bd9Sstevel@tonic-gate  * logging support
5387c478bd9Sstevel@tonic-gate  */
5397c478bd9Sstevel@tonic-gate int	ismdd;			/* true if device is a SVM device */
5407c478bd9Sstevel@tonic-gate int	islog;			/* true if ufs or SVM logging is enabled */
5417c478bd9Sstevel@tonic-gate int	islogok;		/* true if ufs/SVM log state is good */
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate static int	isufslog;	/* true if ufs logging is enabled */
5447c478bd9Sstevel@tonic-gate static int	waslog;		/* true when ufs logging disabled during grow */
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate /*
5477c478bd9Sstevel@tonic-gate  * growfs defines, globals, and forward references
5487c478bd9Sstevel@tonic-gate  */
5497c478bd9Sstevel@tonic-gate #define	NOTENOUGHSPACE 33
5507c478bd9Sstevel@tonic-gate int		grow;
5517c478bd9Sstevel@tonic-gate static int	Pflag;		/* probe to which size the fs can be grown */
5527c478bd9Sstevel@tonic-gate int		ismounted;
5537c478bd9Sstevel@tonic-gate char		*directory;
5547c478bd9Sstevel@tonic-gate diskaddr_t	grow_fssize;
5557c478bd9Sstevel@tonic-gate long		grow_fs_size;
5567c478bd9Sstevel@tonic-gate long		grow_fs_ncg;
5577c478bd9Sstevel@tonic-gate diskaddr_t		grow_fs_csaddr;
5587c478bd9Sstevel@tonic-gate long		grow_fs_cssize;
5597c478bd9Sstevel@tonic-gate int		grow_fs_clean;
5607c478bd9Sstevel@tonic-gate struct csum	*grow_fscs;
5617c478bd9Sstevel@tonic-gate diskaddr_t		grow_sifrag;
5627c478bd9Sstevel@tonic-gate int		test;
5637c478bd9Sstevel@tonic-gate int		testforce;
5647c478bd9Sstevel@tonic-gate diskaddr_t		testfrags;
5657c478bd9Sstevel@tonic-gate int		inlockexit;
5667c478bd9Sstevel@tonic-gate int		isbad;
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate void		lockexit(int);
5697c478bd9Sstevel@tonic-gate void		randomgeneration(void);
5707c478bd9Sstevel@tonic-gate void		checksummarysize(void);
5716451fdbcSvsakar int		checksblock(struct fs, int);
5727c478bd9Sstevel@tonic-gate void		growinit(char *);
5737c478bd9Sstevel@tonic-gate void		checkdev(char *, char  *);
5747c478bd9Sstevel@tonic-gate void		checkmount(struct mnttab *, char *);
5757c478bd9Sstevel@tonic-gate struct dinode	*gdinode(ino_t);
5767c478bd9Sstevel@tonic-gate int		csfraginrange(daddr32_t);
5777c478bd9Sstevel@tonic-gate struct csfrag	*findcsfrag(daddr32_t, struct csfrag **);
5787c478bd9Sstevel@tonic-gate void		checkindirect(ino_t, daddr32_t *, daddr32_t, int);
5797c478bd9Sstevel@tonic-gate void		addcsfrag(ino_t, daddr32_t, struct csfrag **);
5807c478bd9Sstevel@tonic-gate void		delcsfrag(daddr32_t, struct csfrag **);
5817c478bd9Sstevel@tonic-gate void		checkdirect(ino_t, daddr32_t *, daddr32_t *, int);
5827c478bd9Sstevel@tonic-gate void		findcsfragino(void);
5837c478bd9Sstevel@tonic-gate void		fixindirect(daddr32_t, int);
5847c478bd9Sstevel@tonic-gate void		fixdirect(caddr_t, daddr32_t, daddr32_t *, int);
5857c478bd9Sstevel@tonic-gate void		fixcsfragino(void);
5867c478bd9Sstevel@tonic-gate void		extendsummaryinfo(void);
5877c478bd9Sstevel@tonic-gate int		notenoughspace(void);
5887c478bd9Sstevel@tonic-gate void		unalloccsfragino(void);
5897c478bd9Sstevel@tonic-gate void		unalloccsfragfree(void);
5907c478bd9Sstevel@tonic-gate void		findcsfragfree(void);
5917c478bd9Sstevel@tonic-gate void		copycsfragino(void);
5927c478bd9Sstevel@tonic-gate void		rdcg(long);
5937c478bd9Sstevel@tonic-gate void		wtcg(void);
5947c478bd9Sstevel@tonic-gate void		flcg(void);
5957c478bd9Sstevel@tonic-gate void		allocfrags(long, daddr32_t *, long *);
5967c478bd9Sstevel@tonic-gate void		alloccsfragino(void);
5977c478bd9Sstevel@tonic-gate void		alloccsfragfree(void);
5987c478bd9Sstevel@tonic-gate void		freefrags(daddr32_t, long, long);
5997c478bd9Sstevel@tonic-gate int		findfreerange(long *, long *);
6007c478bd9Sstevel@tonic-gate void		resetallocinfo(void);
6017c478bd9Sstevel@tonic-gate void		extendcg(long);
6027c478bd9Sstevel@tonic-gate void		ulockfs(void);
6037c478bd9Sstevel@tonic-gate void		wlockfs(void);
6047c478bd9Sstevel@tonic-gate void		clockfs(void);
6057c478bd9Sstevel@tonic-gate void		wtsb(void);
6067c478bd9Sstevel@tonic-gate static int64_t	checkfragallocated(daddr32_t);
6077c478bd9Sstevel@tonic-gate static struct csum 	*read_summaryinfo(struct fs *);
6087c478bd9Sstevel@tonic-gate static diskaddr_t 	probe_summaryinfo();
6097c478bd9Sstevel@tonic-gate 
610d1a180b0Smaheshvs int
6117c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
6127c478bd9Sstevel@tonic-gate {
6137c478bd9Sstevel@tonic-gate 	long i, mincpc, mincpg, ibpcl;
6147c478bd9Sstevel@tonic-gate 	long cylno, rpos, blk, j, warn = 0;
6157c478bd9Sstevel@tonic-gate 	long mincpgcnt, maxcpg;
6167c478bd9Sstevel@tonic-gate 	uint64_t used, bpcg, inospercg;
6177c478bd9Sstevel@tonic-gate 	long mapcramped, inodecramped;
6187c478bd9Sstevel@tonic-gate 	long postblsize, rotblsize, totalsbsize;
6197c478bd9Sstevel@tonic-gate 	FILE *mnttab;
6207c478bd9Sstevel@tonic-gate 	struct mnttab mntp;
6217c478bd9Sstevel@tonic-gate 	char *special;
6227c478bd9Sstevel@tonic-gate 	struct statvfs64 fs;
6236451fdbcSvsakar 	struct dk_geom dkg;
6247c478bd9Sstevel@tonic-gate 	struct dk_cinfo dkcinfo;
6257c478bd9Sstevel@tonic-gate 	char pbuf[sizeof (uint64_t) * 3 + 1];
6266451fdbcSvsakar 	char *tmpbuf;
6277c478bd9Sstevel@tonic-gate 	int width, plen;
6287c478bd9Sstevel@tonic-gate 	uint64_t num;
6297c478bd9Sstevel@tonic-gate 	int c, saverr;
6307c478bd9Sstevel@tonic-gate 	diskaddr_t max_fssize;
6317c478bd9Sstevel@tonic-gate 	long tmpmaxcontig = -1;
6327c478bd9Sstevel@tonic-gate 	struct sigaction sigact;
6337c478bd9Sstevel@tonic-gate 	uint64_t nbytes64;
6347c478bd9Sstevel@tonic-gate 	int remaining_cg;
6357c478bd9Sstevel@tonic-gate 	int do_dot = 0;
6366451fdbcSvsakar 	int use_efi_dflts = 0, retry = 0;
637*6d24e334Svsakar 	int invalid_sb_cnt, ret, skip_this_sb, cg_too_small;
638*6d24e334Svsakar 	int geom_nsect, geom_ntrack, geom_cpg;
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
6437c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
6447c478bd9Sstevel@tonic-gate #endif
6457c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "F:bmo:VPGM:T:t:")) != EOF) {
6487c478bd9Sstevel@tonic-gate 		switch (c) {
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 		case 'F':
6517c478bd9Sstevel@tonic-gate 			string = optarg;
6527c478bd9Sstevel@tonic-gate 			if (strcmp(string, "ufs") != 0)
6537c478bd9Sstevel@tonic-gate 				usage();
6547c478bd9Sstevel@tonic-gate 			break;
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 		case 'm':	/* return command line used to create this FS */
6577c478bd9Sstevel@tonic-gate 			mflag++;
6587c478bd9Sstevel@tonic-gate 			break;
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 		case 'o':
6617c478bd9Sstevel@tonic-gate 			/*
6627c478bd9Sstevel@tonic-gate 			 * ufs specific options.
6637c478bd9Sstevel@tonic-gate 			 */
6647c478bd9Sstevel@tonic-gate 			string = optarg;
6657c478bd9Sstevel@tonic-gate 			while (*string != '\0') {
6667c478bd9Sstevel@tonic-gate 				if (match("nsect=")) {
6677c478bd9Sstevel@tonic-gate 					nsect = number(DFLNSECT, "nsect", 0);
6687c478bd9Sstevel@tonic-gate 					nsect_flag = RC_KEYWORD;
6697c478bd9Sstevel@tonic-gate 				} else if (match("ntrack=")) {
6707c478bd9Sstevel@tonic-gate 					ntrack = number(DFLNTRAK, "ntrack", 0);
6717c478bd9Sstevel@tonic-gate 					ntrack_flag = RC_KEYWORD;
6727c478bd9Sstevel@tonic-gate 				} else if (match("bsize=")) {
6737c478bd9Sstevel@tonic-gate 					bsize = number(DESBLKSIZE, "bsize", 0);
6747c478bd9Sstevel@tonic-gate 					bsize_flag = RC_KEYWORD;
6757c478bd9Sstevel@tonic-gate 				} else if (match("fragsize=")) {
6767c478bd9Sstevel@tonic-gate 					fragsize = number(DESFRAGSIZE,
6777c478bd9Sstevel@tonic-gate 					    "fragsize", 0);
6787c478bd9Sstevel@tonic-gate 					fragsize_flag = RC_KEYWORD;
6797c478bd9Sstevel@tonic-gate 				} else if (match("cgsize=")) {
6807c478bd9Sstevel@tonic-gate 					cpg = number(DESCPG, "cgsize", 0);
6817c478bd9Sstevel@tonic-gate 					cpg_flag = RC_KEYWORD;
6827c478bd9Sstevel@tonic-gate 				} else if (match("free=")) {
6837c478bd9Sstevel@tonic-gate 					minfree = number(MINFREE, "free",
6847c478bd9Sstevel@tonic-gate 					    ALLOW_PERCENT);
6857c478bd9Sstevel@tonic-gate 					minfree_flag = RC_KEYWORD;
6867c478bd9Sstevel@tonic-gate 				} else if (match("maxcontig=")) {
6877c478bd9Sstevel@tonic-gate 					tmpmaxcontig =
6887c478bd9Sstevel@tonic-gate 					    number(-1, "maxcontig", 0);
6897c478bd9Sstevel@tonic-gate 					maxcontig_flag = RC_KEYWORD;
6907c478bd9Sstevel@tonic-gate 				} else if (match("nrpos=")) {
6917c478bd9Sstevel@tonic-gate 					nrpos = number(NRPOS, "nrpos", 0);
6927c478bd9Sstevel@tonic-gate 					nrpos_flag = RC_KEYWORD;
6937c478bd9Sstevel@tonic-gate 				} else if (match("rps=")) {
6947c478bd9Sstevel@tonic-gate 					rps = number(DEFHZ, "rps", 0);
6957c478bd9Sstevel@tonic-gate 					rps_flag = RC_KEYWORD;
6967c478bd9Sstevel@tonic-gate 				} else if (match("nbpi=")) {
6977c478bd9Sstevel@tonic-gate 					nbpi = number(NBPI, "nbpi", 0);
6987c478bd9Sstevel@tonic-gate 					nbpi_flag = RC_KEYWORD;
6997c478bd9Sstevel@tonic-gate 				} else if (match("opt=")) {
7007c478bd9Sstevel@tonic-gate 					opt = checkopt(string);
7017c478bd9Sstevel@tonic-gate 				} else if (match("mtb=")) {
7027c478bd9Sstevel@tonic-gate 					mtb = checkmtb(string);
7037c478bd9Sstevel@tonic-gate 				} else if (match("apc=")) {
7047c478bd9Sstevel@tonic-gate 					apc = number(0, "apc", 0);
7057c478bd9Sstevel@tonic-gate 					apc_flag = RC_KEYWORD;
7067c478bd9Sstevel@tonic-gate 				} else if (match("gap=")) {
7077c478bd9Sstevel@tonic-gate 					(void) number(0, "gap", ALLOW_MS1);
7087c478bd9Sstevel@tonic-gate 					rotdelay = ROTDELAY;
7097c478bd9Sstevel@tonic-gate 					rotdelay_flag = RC_DEFAULT;
7107c478bd9Sstevel@tonic-gate 				} else if (match("debug=")) {
7117c478bd9Sstevel@tonic-gate 					debug = number(0, "debug", 0);
7127c478bd9Sstevel@tonic-gate 				} else if (match("N")) {
7137c478bd9Sstevel@tonic-gate 					Nflag++;
714355d6bb5Sswilcox 				} else if (match("calcsb")) {
715355d6bb5Sswilcox 					rflag++;
716355d6bb5Sswilcox 					Nflag++;
717355d6bb5Sswilcox 				} else if (match("calcbinsb")) {
718355d6bb5Sswilcox 					rflag++;
719355d6bb5Sswilcox 					Rflag++;
720355d6bb5Sswilcox 					Nflag++;
7217c478bd9Sstevel@tonic-gate 				} else if (*string == '\0') {
7227c478bd9Sstevel@tonic-gate 					break;
7237c478bd9Sstevel@tonic-gate 				} else {
7247c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
7257c478bd9Sstevel@tonic-gate 						"illegal option: %s\n"),
7267c478bd9Sstevel@tonic-gate 						string);
7277c478bd9Sstevel@tonic-gate 					usage();
7287c478bd9Sstevel@tonic-gate 				}
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 				if (*string == ',') string++;
7317c478bd9Sstevel@tonic-gate 				if (*string == ' ') string++;
7327c478bd9Sstevel@tonic-gate 			}
7337c478bd9Sstevel@tonic-gate 			break;
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 		case 'V':
7367c478bd9Sstevel@tonic-gate 			{
7377c478bd9Sstevel@tonic-gate 				char	*opt_text;
7387c478bd9Sstevel@tonic-gate 				int	opt_count;
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 				(void) fprintf(stdout, gettext("mkfs -F ufs "));
7417c478bd9Sstevel@tonic-gate 				for (opt_count = 1; opt_count < argc;
7427c478bd9Sstevel@tonic-gate 								opt_count++) {
7437c478bd9Sstevel@tonic-gate 					opt_text = argv[opt_count];
7447c478bd9Sstevel@tonic-gate 					if (opt_text)
7457c478bd9Sstevel@tonic-gate 					    (void) fprintf(stdout, " %s ",
7467c478bd9Sstevel@tonic-gate 								opt_text);
7477c478bd9Sstevel@tonic-gate 				}
7487c478bd9Sstevel@tonic-gate 				(void) fprintf(stdout, "\n");
7497c478bd9Sstevel@tonic-gate 			}
7507c478bd9Sstevel@tonic-gate 			break;
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 		case 'b':	/* do nothing for this */
7537c478bd9Sstevel@tonic-gate 			break;
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 		case 'M':	/* grow the mounted file system */
7567c478bd9Sstevel@tonic-gate 			directory = optarg;
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
7597c478bd9Sstevel@tonic-gate 		case 'G':	/* grow the file system */
7607c478bd9Sstevel@tonic-gate 			grow = 1;
7617c478bd9Sstevel@tonic-gate 			break;
7627c478bd9Sstevel@tonic-gate 		case 'P':	/* probe the file system growing size 	*/
7637c478bd9Sstevel@tonic-gate 			Pflag = 1;
7647c478bd9Sstevel@tonic-gate 			grow = 1; /* probe mode implies fs growing	*/
7657c478bd9Sstevel@tonic-gate 			break;
7667c478bd9Sstevel@tonic-gate 		case 'T':	/* For testing */
7677c478bd9Sstevel@tonic-gate 			testforce = 1;
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
7707c478bd9Sstevel@tonic-gate 		case 't':
7717c478bd9Sstevel@tonic-gate 			test = 1;
7727c478bd9Sstevel@tonic-gate 			string = optarg;
7737c478bd9Sstevel@tonic-gate 			testfrags = number(NO_DEFAULT, "testfrags", 0);
7747c478bd9Sstevel@tonic-gate 			break;
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 		case '?':
7777c478bd9Sstevel@tonic-gate 			usage();
7787c478bd9Sstevel@tonic-gate 			break;
7797c478bd9Sstevel@tonic-gate 		}
7807c478bd9Sstevel@tonic-gate 	}
7817c478bd9Sstevel@tonic-gate #ifdef MKFS_DEBUG
7827c478bd9Sstevel@tonic-gate 	/*
7837c478bd9Sstevel@tonic-gate 	 * Turning on MKFS_DEBUG causes mkfs to produce a filesystem
7847c478bd9Sstevel@tonic-gate 	 * that can be reproduced by setting the time to 0 and seeding
7857c478bd9Sstevel@tonic-gate 	 * the random number generator to a constant.
7867c478bd9Sstevel@tonic-gate 	 */
7877c478bd9Sstevel@tonic-gate 	mkfstime = 0;	/* reproducible results */
7887c478bd9Sstevel@tonic-gate #else
7897c478bd9Sstevel@tonic-gate 	(void) time(&mkfstime);
7907c478bd9Sstevel@tonic-gate #endif
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 	if (optind >= (argc - 1)) {
7937c478bd9Sstevel@tonic-gate 		if (optind > (argc - 1)) {
7947c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
7957c478bd9Sstevel@tonic-gate 			    gettext("special not specified\n"));
7967c478bd9Sstevel@tonic-gate 			usage();
7977c478bd9Sstevel@tonic-gate 		} else if (mflag == 0) {
7987c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
7997c478bd9Sstevel@tonic-gate 			    gettext("size not specified\n"));
8007c478bd9Sstevel@tonic-gate 			usage();
8017c478bd9Sstevel@tonic-gate 		}
8027c478bd9Sstevel@tonic-gate 	}
8037c478bd9Sstevel@tonic-gate 	argc -= optind;
8047c478bd9Sstevel@tonic-gate 	argv = &argv[optind];
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	fsys = argv[0];
8077c478bd9Sstevel@tonic-gate 	fsi = open64(fsys, O_RDONLY);
8087c478bd9Sstevel@tonic-gate 	if (fsi < 0) {
8097c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: cannot open\n"), fsys);
8107c478bd9Sstevel@tonic-gate 		lockexit(32);
8117c478bd9Sstevel@tonic-gate 	}
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	if (mflag) {
8147c478bd9Sstevel@tonic-gate 		dump_fscmd(fsys, fsi);
8157c478bd9Sstevel@tonic-gate 		lockexit(0);
8167c478bd9Sstevel@tonic-gate 	}
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 	/*
8197c478bd9Sstevel@tonic-gate 	 * The task of setting all of the configuration parameters for a
8207c478bd9Sstevel@tonic-gate 	 * UFS file system is basically a matter of solving n equations
8217c478bd9Sstevel@tonic-gate 	 * in m variables.  Typically, m is greater than n, so there is
8227c478bd9Sstevel@tonic-gate 	 * usually more than one valid solution.  Since this is usually
8237c478bd9Sstevel@tonic-gate 	 * an under-constrained problem, it's not always obvious what the
8247c478bd9Sstevel@tonic-gate 	 * "best" configuration is.
8257c478bd9Sstevel@tonic-gate 	 *
8267c478bd9Sstevel@tonic-gate 	 * In general, the approach is to
8277c478bd9Sstevel@tonic-gate 	 * 1. Determine the values for the file system parameters
8287c478bd9Sstevel@tonic-gate 	 *    that are externally contrained and therefore not adjustable
8297c478bd9Sstevel@tonic-gate 	 *    by mkfs (such as the device's size and maxtransfer size).
8307c478bd9Sstevel@tonic-gate 	 * 2. Acquire the user's requested setting for all configuration
8317c478bd9Sstevel@tonic-gate 	 *    values that can be set on the command line.
8327c478bd9Sstevel@tonic-gate 	 * 3. Determine the final value of all configuration values, by
8337c478bd9Sstevel@tonic-gate 	 *    the following approach:
8347c478bd9Sstevel@tonic-gate 	 *	- set the file system block size (fs_bsize).  Although
8357c478bd9Sstevel@tonic-gate 	 *	  this could be regarded as an adjustable parameter, in
8367c478bd9Sstevel@tonic-gate 	 *	  fact, it's pretty much a constant.  At this time, it's
8377c478bd9Sstevel@tonic-gate 	 *	  generally set to 8k (with older hardware, it can
8387c478bd9Sstevel@tonic-gate 	 *	  sometimes make sense to set it to 4k, but those
8397c478bd9Sstevel@tonic-gate 	 *	  situations are pretty rare now).
8407c478bd9Sstevel@tonic-gate 	 *	- re-adjust the maximum file system size based on the
8417c478bd9Sstevel@tonic-gate 	 *	  value of the file system block size.  Since the
8427c478bd9Sstevel@tonic-gate 	 *	  frag size can't be any larger than a file system
8437c478bd9Sstevel@tonic-gate 	 *	  block, and the number of frags in the file system
8447c478bd9Sstevel@tonic-gate 	 *	  has to fit into 31 bits, the file system block size
8457c478bd9Sstevel@tonic-gate 	 *	  affects the maximum file system size.
8467c478bd9Sstevel@tonic-gate 	 *	- now that the real maximum file system is known, set the
8477c478bd9Sstevel@tonic-gate 	 *	  actual size of the file system to be created to
8487c478bd9Sstevel@tonic-gate 	 *	  MIN(requested size, maximum file system size).
8497c478bd9Sstevel@tonic-gate 	 *	- now validate, and if necessary, adjust the following
8507c478bd9Sstevel@tonic-gate 	 *	  values:
8517c478bd9Sstevel@tonic-gate 	 *		rotdelay
8527c478bd9Sstevel@tonic-gate 	 *		nsect
8537c478bd9Sstevel@tonic-gate 	 *		maxcontig
8547c478bd9Sstevel@tonic-gate 	 *		apc
8557c478bd9Sstevel@tonic-gate 	 *		frag_size
8567c478bd9Sstevel@tonic-gate 	 *		rps
8577c478bd9Sstevel@tonic-gate 	 *		minfree
8587c478bd9Sstevel@tonic-gate 	 *		nrpos
8597c478bd9Sstevel@tonic-gate 	 *		nrack
8607c478bd9Sstevel@tonic-gate 	 *		nbpi
8617c478bd9Sstevel@tonic-gate 	 *	- calculate maxcpg (the maximum value of the cylinders-per-
8627c478bd9Sstevel@tonic-gate 	 *	  cylinder-group configuration parameters).  There are two
8637c478bd9Sstevel@tonic-gate 	 *	  algorithms for calculating maxcpg:  an old one, which is
8647c478bd9Sstevel@tonic-gate 	 *	  used for file systems of less than 1 terabyte, and a
8657c478bd9Sstevel@tonic-gate 	 *	  new one, implemented in the function compute_maxcpg(),
8667c478bd9Sstevel@tonic-gate 	 *	  which is used for file systems of greater than 1 TB.
8677c478bd9Sstevel@tonic-gate 	 *	  The difference between them is that compute_maxcpg()
8687c478bd9Sstevel@tonic-gate 	 *	  really tries to maximize the cpg value.  The old
8697c478bd9Sstevel@tonic-gate 	 *	  algorithm fails to take advantage of smaller frags and
8707c478bd9Sstevel@tonic-gate 	 *	  lower inode density when determining the maximum cpg,
8717c478bd9Sstevel@tonic-gate 	 *	  and thus comes up with much lower numbers in some
8727c478bd9Sstevel@tonic-gate 	 *	  configurations.  At some point, we might use the
8737c478bd9Sstevel@tonic-gate 	 *	  new algorithm for determining maxcpg for all file
8747c478bd9Sstevel@tonic-gate 	 *	  systems, but at this time, the changes implemented for
8757c478bd9Sstevel@tonic-gate 	 *	  multi-terabyte UFS are NOT being automatically applied
8767c478bd9Sstevel@tonic-gate 	 *	  to UFS file systems of less than a terabyte (in the
8777c478bd9Sstevel@tonic-gate 	 *	  interest of not changing existing UFS policy too much
8787c478bd9Sstevel@tonic-gate 	 *	  until the ramifications of the changes are well-understood
8797c478bd9Sstevel@tonic-gate 	 *	  and have been evaluated for their effects on performance.)
8807c478bd9Sstevel@tonic-gate 	 *	- check the current values of the configuration parameters
8817c478bd9Sstevel@tonic-gate 	 *	  against the various constraints imposed by UFS.  These
8827c478bd9Sstevel@tonic-gate 	 *	  include:
8837c478bd9Sstevel@tonic-gate 	 *		* There must be at least one inode in each
8847c478bd9Sstevel@tonic-gate 	 *		  cylinder group.
8857c478bd9Sstevel@tonic-gate 	 *		* The cylinder group overhead block, which
8867c478bd9Sstevel@tonic-gate 	 *		  contains the inode and frag bigmaps, must fit
8877c478bd9Sstevel@tonic-gate 	 *		  within one file system block.
8887c478bd9Sstevel@tonic-gate 	 *		* The space required for inode maps should
8897c478bd9Sstevel@tonic-gate 	 *		  occupy no more than a third of the cylinder
8907c478bd9Sstevel@tonic-gate 	 *		  group overhead block.
8917c478bd9Sstevel@tonic-gate 	 *		* The rotational position tables have to fit
8927c478bd9Sstevel@tonic-gate 	 *		  within the available space in the super block.
8937c478bd9Sstevel@tonic-gate 	 *	  Adjust the configuration values that can be adjusted
8947c478bd9Sstevel@tonic-gate 	 *	  so that these constraints are satisfied.  The
8957c478bd9Sstevel@tonic-gate 	 *	  configuration values that are adjustable are:
8967c478bd9Sstevel@tonic-gate 	 *		* frag size
8977c478bd9Sstevel@tonic-gate 	 *		* cylinders per group
8987c478bd9Sstevel@tonic-gate 	 *		* inode density (can be increased)
8997c478bd9Sstevel@tonic-gate 	 *		* number of rotational positions (the rotational
9007c478bd9Sstevel@tonic-gate 	 *		  position tables are eliminated altogether if
9017c478bd9Sstevel@tonic-gate 	 *		  there isn't enough room for them.)
9027c478bd9Sstevel@tonic-gate 	 * 4. Set the values for all the dependent configuration
9037c478bd9Sstevel@tonic-gate 	 *    values (those that aren't settable on the command
9047c478bd9Sstevel@tonic-gate 	 *    line and which are completely dependent on the
9057c478bd9Sstevel@tonic-gate 	 *    adjustable parameters).  This include cpc (cycles
9067c478bd9Sstevel@tonic-gate 	 *    per cylinder, spc (sectors-per-cylinder), and many others.
9077c478bd9Sstevel@tonic-gate 	 */
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 	max_fssize = get_max_size(fsi);
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 	/*
9127c478bd9Sstevel@tonic-gate 	 * Get and check positional arguments, if any.
9137c478bd9Sstevel@tonic-gate 	 */
9147c478bd9Sstevel@tonic-gate 	switch (argc - 1) {
9157c478bd9Sstevel@tonic-gate 	default:
9167c478bd9Sstevel@tonic-gate 		usage();
9177c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
9187c478bd9Sstevel@tonic-gate 	case 15:
9197c478bd9Sstevel@tonic-gate 		mtb = checkmtb(argv[15]);
9207c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
9217c478bd9Sstevel@tonic-gate 	case 14:
9227c478bd9Sstevel@tonic-gate 		string = argv[14];
9237c478bd9Sstevel@tonic-gate 		tmpmaxcontig = number(-1, "maxcontig", 0);
9247c478bd9Sstevel@tonic-gate 		maxcontig_flag = RC_POSITIONAL;
9257c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
9267c478bd9Sstevel@tonic-gate 	case 13:
9277c478bd9Sstevel@tonic-gate 		string = argv[13];
9287c478bd9Sstevel@tonic-gate 		nrpos = number(NRPOS, "nrpos", 0);
9297c478bd9Sstevel@tonic-gate 		nrpos_flag = RC_POSITIONAL;
9307c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
9317c478bd9Sstevel@tonic-gate 	case 12:
9327c478bd9Sstevel@tonic-gate 		string = argv[12];
9337c478bd9Sstevel@tonic-gate 		rotdelay = ROTDELAY;
9347c478bd9Sstevel@tonic-gate 		rotdelay_flag = RC_DEFAULT;
9357c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
9367c478bd9Sstevel@tonic-gate 	case 11:
9377c478bd9Sstevel@tonic-gate 		string = argv[11];
9387c478bd9Sstevel@tonic-gate 		apc = number(0, "apc", 0);
9397c478bd9Sstevel@tonic-gate 		apc_flag = RC_POSITIONAL;
9407c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
9417c478bd9Sstevel@tonic-gate 	case 10:
9427c478bd9Sstevel@tonic-gate 		opt = checkopt(argv[10]);
9437c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
9447c478bd9Sstevel@tonic-gate 	case 9:
9457c478bd9Sstevel@tonic-gate 		string = argv[9];
9467c478bd9Sstevel@tonic-gate 		nbpi = number(NBPI, "nbpi", 0);
9477c478bd9Sstevel@tonic-gate 		nbpi_flag = RC_POSITIONAL;
9487c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
9497c478bd9Sstevel@tonic-gate 	case 8:
9507c478bd9Sstevel@tonic-gate 		string = argv[8];
9517c478bd9Sstevel@tonic-gate 		rps = number(DEFHZ, "rps", 0);
9527c478bd9Sstevel@tonic-gate 		rps_flag = RC_POSITIONAL;
9537c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
9547c478bd9Sstevel@tonic-gate 	case 7:
9557c478bd9Sstevel@tonic-gate 		string = argv[7];
9567c478bd9Sstevel@tonic-gate 		minfree = number(MINFREE, "free", ALLOW_PERCENT);
9577c478bd9Sstevel@tonic-gate 		minfree_flag = RC_POSITIONAL;
9587c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
9597c478bd9Sstevel@tonic-gate 	case 6:
9607c478bd9Sstevel@tonic-gate 		string = argv[6];
9617c478bd9Sstevel@tonic-gate 		cpg = number(DESCPG, "cgsize", 0);
9627c478bd9Sstevel@tonic-gate 		cpg_flag = RC_POSITIONAL;
9637c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
9647c478bd9Sstevel@tonic-gate 	case 5:
9657c478bd9Sstevel@tonic-gate 		string = argv[5];
9667c478bd9Sstevel@tonic-gate 		fragsize = number(DESFRAGSIZE, "fragsize", 0);
9677c478bd9Sstevel@tonic-gate 		fragsize_flag = RC_POSITIONAL;
9687c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
9697c478bd9Sstevel@tonic-gate 	case 4:
9707c478bd9Sstevel@tonic-gate 		string = argv[4];
9717c478bd9Sstevel@tonic-gate 		bsize = number(DESBLKSIZE, "bsize", 0);
9727c478bd9Sstevel@tonic-gate 		bsize_flag = RC_POSITIONAL;
9737c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
9747c478bd9Sstevel@tonic-gate 	case 3:
9757c478bd9Sstevel@tonic-gate 		string = argv[3];
9767c478bd9Sstevel@tonic-gate 		ntrack = number(DFLNTRAK, "ntrack", 0);
9777c478bd9Sstevel@tonic-gate 		ntrack_flag = RC_POSITIONAL;
9787c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
9797c478bd9Sstevel@tonic-gate 	case 2:
9807c478bd9Sstevel@tonic-gate 		string = argv[2];
9817c478bd9Sstevel@tonic-gate 		nsect = number(DFLNSECT, "nsect", 0);
9827c478bd9Sstevel@tonic-gate 		nsect_flag = RC_POSITIONAL;
9837c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
9847c478bd9Sstevel@tonic-gate 	case 1:
9857c478bd9Sstevel@tonic-gate 		string = argv[1];
9867c478bd9Sstevel@tonic-gate 		fssize_db = number(max_fssize, "size", 0);
9877c478bd9Sstevel@tonic-gate 	}
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate 	if ((maxcontig_flag == RC_DEFAULT) || (tmpmaxcontig == -1) ||
9917c478bd9Sstevel@tonic-gate 		(maxcontig == -1)) {
9927c478bd9Sstevel@tonic-gate 		long maxtrax = get_max_track_size(fsi);
9937c478bd9Sstevel@tonic-gate 		maxcontig = maxtrax / bsize;
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 	} else {
9967c478bd9Sstevel@tonic-gate 		maxcontig = tmpmaxcontig;
9977c478bd9Sstevel@tonic-gate 	}
9986451fdbcSvsakar 	dprintf(("DeBuG maxcontig : %ld\n", maxcontig));
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate 	if (rotdelay == -1) {	/* default by newfs and mkfs */
10017c478bd9Sstevel@tonic-gate 		rotdelay = ROTDELAY;
10027c478bd9Sstevel@tonic-gate 	}
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 	if (cpg_flag == RC_DEFAULT) { /* If not explicity set, use default */
10057c478bd9Sstevel@tonic-gate 		cpg = DESCPG;
10067c478bd9Sstevel@tonic-gate 	}
10076451fdbcSvsakar 	dprintf(("DeBuG cpg : %ld\n", cpg));
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate 	/*
10107c478bd9Sstevel@tonic-gate 	 * Now that we have the semi-sane args, either positional, via -o,
10117c478bd9Sstevel@tonic-gate 	 * or by defaulting, handle inter-dependencies and range checks.
10127c478bd9Sstevel@tonic-gate 	 */
10137c478bd9Sstevel@tonic-gate 
10147c478bd9Sstevel@tonic-gate 	/*
10157c478bd9Sstevel@tonic-gate 	 * Settle the file system block size first, since it's a fixed
10167c478bd9Sstevel@tonic-gate 	 * parameter once set and so many other parameters, including
10177c478bd9Sstevel@tonic-gate 	 * max_fssize, depend on it.
10187c478bd9Sstevel@tonic-gate 	 */
10197c478bd9Sstevel@tonic-gate 	range_check(&bsize, "bsize", MINBSIZE, MAXBSIZE, DESBLKSIZE,
10207c478bd9Sstevel@tonic-gate 	    bsize_flag);
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate 	if (!POWEROF2(bsize)) {
10237c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
10247c478bd9Sstevel@tonic-gate 		    gettext("block size must be a power of 2, not %ld\n"),
10257c478bd9Sstevel@tonic-gate 		    bsize);
10267c478bd9Sstevel@tonic-gate 		bsize = DESBLKSIZE;
10277c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
10287c478bd9Sstevel@tonic-gate 		    gettext("mkfs: bsize reset to default %ld\n"),
10297c478bd9Sstevel@tonic-gate 		    bsize);
10307c478bd9Sstevel@tonic-gate 	}
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate 	if (fssize_db > max_fssize && validate_size(fsi, fssize_db)) {
10337c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
10347c478bd9Sstevel@tonic-gate 		    "Warning: the requested size of this file system\n"
10357c478bd9Sstevel@tonic-gate 		    "(%lld sectors) is greater than the size of the\n"
10367c478bd9Sstevel@tonic-gate 		    "device reported by the driver (%lld sectors).\n"
10377c478bd9Sstevel@tonic-gate 		    "However, a read of the device at the requested size\n"
10387c478bd9Sstevel@tonic-gate 		    "does succeed, so the requested size will be used.\n"),
10397c478bd9Sstevel@tonic-gate 		    fssize_db, max_fssize);
10407c478bd9Sstevel@tonic-gate 		max_fssize = fssize_db;
10417c478bd9Sstevel@tonic-gate 	}
10427c478bd9Sstevel@tonic-gate 	/*
10437c478bd9Sstevel@tonic-gate 	 * Since the maximum allocatable unit (the frag) must be less than
10447c478bd9Sstevel@tonic-gate 	 * or equal to bsize, and the number of frags must be less than or
10457c478bd9Sstevel@tonic-gate 	 * equal to INT_MAX, the total size of the file system (in
10467c478bd9Sstevel@tonic-gate 	 * bytes) must be less than or equal to bsize * INT_MAX.
10477c478bd9Sstevel@tonic-gate 	 */
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 	if (max_fssize > ((diskaddr_t)bsize/DEV_BSIZE) * INT_MAX)
10507c478bd9Sstevel@tonic-gate 		max_fssize = ((diskaddr_t)bsize/DEV_BSIZE) * INT_MAX;
10517c478bd9Sstevel@tonic-gate 	range_check_64(&fssize_db, "size", 1024LL, max_fssize, max_fssize, 1);
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate 	if (fssize_db >= SECTORS_PER_TERABYTE) {
10547c478bd9Sstevel@tonic-gate 		mtb = 'y';
10557c478bd9Sstevel@tonic-gate 		if (!in_64bit_mode()) {
10567c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
10577c478bd9Sstevel@tonic-gate "mkfs:  Warning: Creating a file system greater than 1 terabyte on a\n"
10587c478bd9Sstevel@tonic-gate "       system running a 32-bit kernel.  This file system will not be\n"
10597c478bd9Sstevel@tonic-gate "       accessible until the system is rebooted with a 64-bit kernel.\n"));
10607c478bd9Sstevel@tonic-gate 		}
10617c478bd9Sstevel@tonic-gate 	}
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 	/*
10646451fdbcSvsakar 	 * With newer and much larger disks, the newfs(1M) and mkfs_ufs(1M)
10656451fdbcSvsakar 	 * commands had problems in correctly handling the "native" geometries
10666451fdbcSvsakar 	 * for various storage devices.
10676451fdbcSvsakar 	 *
10686451fdbcSvsakar 	 * To handle the new age disks, mkfs_ufs(1M) will use the EFI style
10696451fdbcSvsakar 	 * for non-EFI disks that are larger than the CHS addressing limit
10706451fdbcSvsakar 	 * ( > 8GB approx ) and ignore the disk geometry information for
10716451fdbcSvsakar 	 * these drives. This is what is currently done for multi-terrabyte
10726451fdbcSvsakar 	 * filesystems on EFI disks.
10736451fdbcSvsakar 	 *
10746451fdbcSvsakar 	 * However if the user asked for a specific layout by supplying values
1075*6d24e334Svsakar 	 * for even one of the three parameters (nsect, ntrack, cpg), honour
1076*6d24e334Svsakar 	 * the user supplied parameters.
1077*6d24e334Svsakar 	 *
1078*6d24e334Svsakar 	 * Choosing EFI style or native geometry style can make a lot of
1079*6d24e334Svsakar 	 * difference, because the size of a cylinder group is dependent on
1080*6d24e334Svsakar 	 * this choice. This in turn means that the position of alternate
1081*6d24e334Svsakar 	 * superblocks varies depending on the style chosen. It is not
1082*6d24e334Svsakar 	 * necessary that all disks of size > CHSLIMIT have EFI style layout.
1083*6d24e334Svsakar 	 * There can be disks which are > CHSLIMIT size, but have native
1084*6d24e334Svsakar 	 * geometry style layout, thereby warranting the need for alternate
1085*6d24e334Svsakar 	 * logic in superblock detection.
10867c478bd9Sstevel@tonic-gate 	 */
10876451fdbcSvsakar 
10886451fdbcSvsakar 	if (mtb != 'y' && label_type == LABEL_TYPE_VTOC &&
1089*6d24e334Svsakar 	    ((ntrack == -1 || (grow && ntrack_flag == RC_DEFAULT)) ||
1090*6d24e334Svsakar 	    (nsect_flag == RC_DEFAULT && ntrack_flag == RC_DEFAULT &&
1091*6d24e334Svsakar 	    cpg_flag == RC_DEFAULT))) {
10926451fdbcSvsakar 		/*
1093*6d24e334Svsakar 		 * "-1" indicates that we were called from newfs and ntracks
1094*6d24e334Svsakar 		 * was not specified in newfs command line. Calculate nsect
10956451fdbcSvsakar 		 * and ntrack in the same manner as newfs.
10966451fdbcSvsakar 		 *
10976451fdbcSvsakar 		 * This is required because, the defaults for nsect and ntrack
10986451fdbcSvsakar 		 * is hardcoded in mkfs, whereas to generate the alternate
10996451fdbcSvsakar 		 * superblock locations for the -N option, there is a need for
11006451fdbcSvsakar 		 * the geometry based values that newfs would have arrived at.
11016451fdbcSvsakar 		 * Newfs would have arrived at these values as below.
11026451fdbcSvsakar 		 */
11036451fdbcSvsakar 
11046451fdbcSvsakar 		if (ioctl(fsi, DKIOCGGEOM, &dkg)) {
11056451fdbcSvsakar 		    dprintf(("%s: Unable to read Disk geometry", fsys));
11066451fdbcSvsakar 		    perror(gettext("Unable to read Disk geometry"));
11076451fdbcSvsakar 		    lockexit(32);
11086451fdbcSvsakar 		} else {
11096451fdbcSvsakar 		    nsect = dkg.dkg_nsect;
11106451fdbcSvsakar 		    ntrack = dkg.dkg_nhead;
11116451fdbcSvsakar #ifdef i386	/* Bug 1170182 */
11126451fdbcSvsakar 		    if (ntrack > 32 && (ntrack % 16) != 0) {
11136451fdbcSvsakar 			ntrack -= (ntrack % 16);
11146451fdbcSvsakar 		    }
11156451fdbcSvsakar #endif
11166451fdbcSvsakar 		    if ((dkg.dkg_ncyl * dkg.dkg_nhead * dkg.dkg_nsect)
11176451fdbcSvsakar 				> CHSLIMIT) {
11186451fdbcSvsakar 			use_efi_dflts = 1;
11196451fdbcSvsakar 			retry = 1;
11206451fdbcSvsakar 		    }
11216451fdbcSvsakar 		}
1122*6d24e334Svsakar 		dprintf(("DeBuG CHSLIMIT = %d geom = %ld\n", CHSLIMIT,
1123*6d24e334Svsakar 			dkg.dkg_ncyl * dkg.dkg_nhead * dkg.dkg_nsect));
11246451fdbcSvsakar 	}
11256451fdbcSvsakar 
11266451fdbcSvsakar 	/*
11276451fdbcSvsakar 	 * For the newfs -N case, even if the disksize is > CHSLIMIT, do not
11286451fdbcSvsakar 	 * blindly follow EFI style. If the fs_version indicates a geometry
11296451fdbcSvsakar 	 * based layout, try that one first. If it fails we can always try the
11306451fdbcSvsakar 	 * other logic.
11316451fdbcSvsakar 	 *
11326451fdbcSvsakar 	 * If we were called from growfs, we will have a problem if we mix
11336451fdbcSvsakar 	 * and match the filesystem creation and growth styles. For example,
1134*6d24e334Svsakar 	 * if we create using EFI style, we have to also grow using EFI
11356451fdbcSvsakar 	 * style. So follow the style indicated by the fs_version.
11366451fdbcSvsakar 	 *
11376451fdbcSvsakar 	 * Read and verify the primary superblock. If it looks sane, use the
11386451fdbcSvsakar 	 * fs_version from the superblock. If the primary superblock does
11396451fdbcSvsakar 	 * not look good, read and verify the first alternate superblock at
11406451fdbcSvsakar 	 * ALTSB. Use the fs_version to decide whether to use the
11416451fdbcSvsakar 	 * EFI style logic or the old geometry based logic to calculate
11426451fdbcSvsakar 	 * the alternate superblock locations.
11436451fdbcSvsakar 	 */
11446451fdbcSvsakar 	if ((Nflag && use_efi_dflts) || (grow)) {
11456451fdbcSvsakar 		if (grow && ntrack_flag != RC_DEFAULT)
1146*6d24e334Svsakar 			goto start_fs_creation;
11476451fdbcSvsakar 		rdfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize,
11486451fdbcSvsakar 			(char *)&altsblock);
11496451fdbcSvsakar 		ret = checksblock(altsblock, 1);
11506451fdbcSvsakar 
11516451fdbcSvsakar 		if (!ret) {
11526451fdbcSvsakar 			if (altsblock.fs_magic == MTB_UFS_MAGIC) {
11536451fdbcSvsakar 				mtb = 'y';
1154*6d24e334Svsakar 				goto start_fs_creation;
11556451fdbcSvsakar 			}
11566451fdbcSvsakar 			use_efi_dflts = (altsblock.fs_version ==
11576451fdbcSvsakar 				UFS_EFISTYLE4NONEFI_VERSION_2) ? 1 : 0;
11586451fdbcSvsakar 		} else {
11596451fdbcSvsakar 			/*
11606451fdbcSvsakar 			 * The primary superblock didn't help in determining
11616451fdbcSvsakar 			 * the fs_version. Try the first alternate superblock.
11626451fdbcSvsakar 			 */
11636451fdbcSvsakar 			dprintf(("DeBuG checksblock() failed - error : %d"
11646451fdbcSvsakar 				" for sb : %d\n", ret, SBOFF/sectorsize));
11656451fdbcSvsakar 			rdfs((diskaddr_t)ALTSB, (int)sbsize,
11666451fdbcSvsakar 				(char *)&altsblock);
11676451fdbcSvsakar 			ret = checksblock(altsblock, 1);
11686451fdbcSvsakar 
11696451fdbcSvsakar 			if (!ret) {
11706451fdbcSvsakar 			    if (altsblock.fs_magic == MTB_UFS_MAGIC) {
11716451fdbcSvsakar 				mtb = 'y';
1172*6d24e334Svsakar 				goto start_fs_creation;
11736451fdbcSvsakar 			    }
11746451fdbcSvsakar 			    use_efi_dflts = (altsblock.fs_version ==
11756451fdbcSvsakar 				UFS_EFISTYLE4NONEFI_VERSION_2) ? 1 : 0;
1176*6d24e334Svsakar 			}
1177*6d24e334Svsakar 			dprintf(("DeBuG checksblock() returned : %d"
11786451fdbcSvsakar 				" for sb : %d\n", ret, ALTSB));
11796451fdbcSvsakar 		}
11806451fdbcSvsakar 	}
11816451fdbcSvsakar 
1182*6d24e334Svsakar 	geom_nsect = nsect;
1183*6d24e334Svsakar 	geom_ntrack = ntrack;
1184*6d24e334Svsakar 	geom_cpg = cpg;
1185*6d24e334Svsakar 	dprintf(("DeBuG geom_nsect=%d, geom_ntrack=%d, geom_cpg=%d\n",
1186*6d24e334Svsakar 		geom_nsect, geom_ntrack, geom_cpg));
1187*6d24e334Svsakar 
1188*6d24e334Svsakar start_fs_creation:
11896451fdbcSvsakar retry_alternate_logic:
11906451fdbcSvsakar 	invalid_sb_cnt = 0;
1191*6d24e334Svsakar 	cg_too_small = 0;
11926451fdbcSvsakar 	if (use_efi_dflts) {
11936451fdbcSvsakar 		nsect = DEF_SECTORS_EFI;
11946451fdbcSvsakar 		ntrack = DEF_TRACKS_EFI;
11956451fdbcSvsakar 		cpg = DESCPG;
11966451fdbcSvsakar 		dprintf(("\nDeBuG Using EFI defaults\n"));
11976451fdbcSvsakar 	} else {
1198*6d24e334Svsakar 		nsect = geom_nsect;
1199*6d24e334Svsakar 		ntrack = geom_ntrack;
1200*6d24e334Svsakar 		cpg = geom_cpg;
1201*6d24e334Svsakar 		dprintf(("\nDeBuG Using Geometry\n"));
12026451fdbcSvsakar 		/*
12036451fdbcSvsakar 		 * 32K based on max block size of 64K, and rotational layout
12046451fdbcSvsakar 		 * test of nsect <= (256 * sectors/block).  Current block size
12056451fdbcSvsakar 		 * limit is not 64K, but it's growing soon.
12066451fdbcSvsakar 		 */
12076451fdbcSvsakar 		range_check(&nsect, "nsect", 1, 32768, DFLNSECT, nsect_flag);
12086451fdbcSvsakar 		/*
12096451fdbcSvsakar 		 * ntrack is the number of tracks per cylinder.
12106451fdbcSvsakar 		 * The ntrack value must be between 1 and the total number of
12116451fdbcSvsakar 		 * sectors in the file system.
12126451fdbcSvsakar 		 */
12136451fdbcSvsakar 		range_check(&ntrack, "ntrack", 1,
12146451fdbcSvsakar 		    fssize_db > INT_MAX ? INT_MAX : (uint32_t)fssize_db,
12156451fdbcSvsakar 		    DFLNTRAK, ntrack_flag);
12166451fdbcSvsakar 	}
12176451fdbcSvsakar 
12187c478bd9Sstevel@tonic-gate 	range_check(&apc, "apc", 0, nsect - 1, 0, apc_flag);
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate 	if (mtb == 'y')
12217c478bd9Sstevel@tonic-gate 		fragsize = bsize;
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate 	range_check(&fragsize, "fragsize", sectorsize, bsize,
12247c478bd9Sstevel@tonic-gate 	    MAX(bsize / MAXFRAG, MIN(DESFRAGSIZE, bsize)), fragsize_flag);
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate 	if ((bsize / MAXFRAG) > fragsize) {
12277c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
12287c478bd9Sstevel@tonic-gate "fragment size %ld is too small, minimum with block size %ld is %ld\n"),
12297c478bd9Sstevel@tonic-gate 		    fragsize, bsize, bsize / MAXFRAG);
12307c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
12317c478bd9Sstevel@tonic-gate 		    gettext("mkfs: fragsize reset to minimum %ld\n"),
12327c478bd9Sstevel@tonic-gate 		    bsize / MAXFRAG);
12337c478bd9Sstevel@tonic-gate 		fragsize = bsize / MAXFRAG;
12347c478bd9Sstevel@tonic-gate 	}
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate 	if (!POWEROF2(fragsize)) {
12377c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
12387c478bd9Sstevel@tonic-gate 		    gettext("fragment size must be a power of 2, not %ld\n"),
12397c478bd9Sstevel@tonic-gate 		    fragsize);
12407c478bd9Sstevel@tonic-gate 		fragsize = MAX(bsize / MAXFRAG, MIN(DESFRAGSIZE, bsize));
12417c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
12427c478bd9Sstevel@tonic-gate 		    gettext("mkfs: fragsize reset to %ld\n"),
12437c478bd9Sstevel@tonic-gate 		    fragsize);
12447c478bd9Sstevel@tonic-gate 	}
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate 	/* At this point, bsize must be >= fragsize, so no need to check it */
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate 	if (bsize < PAGESIZE) {
12497c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
12507c478bd9Sstevel@tonic-gate 		    "WARNING: filesystem block size (%ld) is smaller than "
12517c478bd9Sstevel@tonic-gate 		    "memory page size (%ld).\nResulting filesystem can not be "
12527c478bd9Sstevel@tonic-gate 		    "mounted on this system.\n\n"),
12537c478bd9Sstevel@tonic-gate 		    bsize, (long)PAGESIZE);
12547c478bd9Sstevel@tonic-gate 	}
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 	range_check(&rps, "rps", 1, 1000, DEFHZ, rps_flag);
12577c478bd9Sstevel@tonic-gate 	range_check(&minfree, "free", 0, 99, MINFREE, minfree_flag);
12587c478bd9Sstevel@tonic-gate 	range_check(&nrpos, "nrpos", 1, nsect, MIN(nsect, NRPOS), nrpos_flag);
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate 	/*
12617c478bd9Sstevel@tonic-gate 	 * nbpi is variable, but 2MB seems a reasonable upper limit,
12627c478bd9Sstevel@tonic-gate 	 * as 4MB tends to cause problems (using otherwise-default
12637c478bd9Sstevel@tonic-gate 	 * parameters).  The true limit is where we end up with one
12647c478bd9Sstevel@tonic-gate 	 * inode per cylinder group.  If this file system is being
12657c478bd9Sstevel@tonic-gate 	 * configured for multi-terabyte access, nbpi must be at least 1MB.
12667c478bd9Sstevel@tonic-gate 	 */
12677c478bd9Sstevel@tonic-gate 	if (mtb == 'y' && nbpi < MTB_NBPI) {
12687c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("mkfs: bad value for nbpi: "
12697c478bd9Sstevel@tonic-gate 			"must be at least 1048576 for multi-terabyte, "
12707c478bd9Sstevel@tonic-gate 			"nbpi reset to default 1048576\n"));
12717c478bd9Sstevel@tonic-gate 		nbpi = MTB_NBPI;
12727c478bd9Sstevel@tonic-gate 	}
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 	if (mtb == 'y')
12757c478bd9Sstevel@tonic-gate 		range_check(&nbpi, "nbpi", MTB_NBPI, 2 * MB, MTB_NBPI,
12767c478bd9Sstevel@tonic-gate 			nbpi_flag);
12777c478bd9Sstevel@tonic-gate 	else
12787c478bd9Sstevel@tonic-gate 		range_check(&nbpi, "nbpi", DEV_BSIZE, 2 * MB, NBPI, nbpi_flag);
12797c478bd9Sstevel@tonic-gate 
12807c478bd9Sstevel@tonic-gate 	/*
12817c478bd9Sstevel@tonic-gate 	 * maxcpg is another variably-limited parameter.  Calculate
12827c478bd9Sstevel@tonic-gate 	 * the limit based on what we've got for its dependent
12837c478bd9Sstevel@tonic-gate 	 * variables.  Effectively, it's how much space is left in the
12847c478bd9Sstevel@tonic-gate 	 * superblock after all the other bits are accounted for.  We
12857c478bd9Sstevel@tonic-gate 	 * only fill in sblock fields so we can use MAXIpG.
12867c478bd9Sstevel@tonic-gate 	 *
12877c478bd9Sstevel@tonic-gate 	 * If the calculation of maxcpg below (for the mtb == 'n'
12887c478bd9Sstevel@tonic-gate 	 * case) is changed, update newfs as well.
12897c478bd9Sstevel@tonic-gate 	 *
12907c478bd9Sstevel@tonic-gate 	 * For old-style, non-MTB format file systems, use the old
12917c478bd9Sstevel@tonic-gate 	 * algorithm for calculating the maximum cylinder group size,
12927c478bd9Sstevel@tonic-gate 	 * even though it limits the cylinder group more than necessary.
12937c478bd9Sstevel@tonic-gate 	 * Since layout can affect performance, we don't want to change
12947c478bd9Sstevel@tonic-gate 	 * the default layout for non-MTB file systems at this time.
12957c478bd9Sstevel@tonic-gate 	 * However, for MTB file systems, use the new maxcpg calculation,
12967c478bd9Sstevel@tonic-gate 	 * which really maxes out the cylinder group size.
12977c478bd9Sstevel@tonic-gate 	 */
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate 	sblock.fs_bsize = bsize;
13007c478bd9Sstevel@tonic-gate 	sblock.fs_inopb = sblock.fs_bsize / sizeof (struct dinode);
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate 	if (mtb == 'n') {
13037c478bd9Sstevel@tonic-gate 		maxcpg = (bsize - sizeof (struct cg) -
13047c478bd9Sstevel@tonic-gate 		    howmany(MAXIpG(&sblock), NBBY)) /
13057c478bd9Sstevel@tonic-gate 		    (sizeof (long) + nrpos * sizeof (short) +
13067c478bd9Sstevel@tonic-gate 		    nsect / (MAXFRAG * NBBY));
13077c478bd9Sstevel@tonic-gate 	} else {
13087c478bd9Sstevel@tonic-gate 		maxcpg = compute_maxcpg(bsize, fragsize, nbpi, nrpos,
13097c478bd9Sstevel@tonic-gate 		    nsect * ntrack);
13107c478bd9Sstevel@tonic-gate 	}
13117c478bd9Sstevel@tonic-gate 
13126451fdbcSvsakar 	dprintf(("DeBuG cpg : %ld\n", cpg));
13137c478bd9Sstevel@tonic-gate 	if (cpg == -1)
13147c478bd9Sstevel@tonic-gate 		cpg = maxcpg;
13156451fdbcSvsakar 	dprintf(("DeBuG cpg : %ld\n", cpg));
13166451fdbcSvsakar 
13177c478bd9Sstevel@tonic-gate 	/*
13187c478bd9Sstevel@tonic-gate 	 * mincpg is variable in complex ways, so we really can't
13197c478bd9Sstevel@tonic-gate 	 * do a sane lower-end limit check at this point.
13207c478bd9Sstevel@tonic-gate 	 */
13217c478bd9Sstevel@tonic-gate 	range_check(&cpg, "cgsize", 1, maxcpg, MIN(maxcpg, DESCPG), cpg_flag);
13227c478bd9Sstevel@tonic-gate 
13237c478bd9Sstevel@tonic-gate 	/*
13247c478bd9Sstevel@tonic-gate 	 * get the controller info
13257c478bd9Sstevel@tonic-gate 	 */
13267c478bd9Sstevel@tonic-gate 	ismdd = 0;
13277c478bd9Sstevel@tonic-gate 	islog = 0;
13287c478bd9Sstevel@tonic-gate 	islogok = 0;
13297c478bd9Sstevel@tonic-gate 	waslog = 0;
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 	if (ioctl(fsi, DKIOCINFO, &dkcinfo) == 0)
13327c478bd9Sstevel@tonic-gate 		/*
13337c478bd9Sstevel@tonic-gate 		 * if it is an MDD (disksuite) device
13347c478bd9Sstevel@tonic-gate 		 */
13357c478bd9Sstevel@tonic-gate 		if (dkcinfo.dki_ctype == DKC_MD) {
13367c478bd9Sstevel@tonic-gate 			ismdd++;
13377c478bd9Sstevel@tonic-gate 			/*
13387c478bd9Sstevel@tonic-gate 			 * check the logging device
13397c478bd9Sstevel@tonic-gate 			 */
13407c478bd9Sstevel@tonic-gate 			if (ioctl(fsi, _FIOISLOG, NULL) == 0) {
13417c478bd9Sstevel@tonic-gate 				islog++;
13427c478bd9Sstevel@tonic-gate 				if (ioctl(fsi, _FIOISLOGOK, NULL) == 0)
13437c478bd9Sstevel@tonic-gate 					islogok++;
13447c478bd9Sstevel@tonic-gate 			}
13457c478bd9Sstevel@tonic-gate 		}
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate 	/*
13487c478bd9Sstevel@tonic-gate 	 * Do not grow the file system, but print on stdout the maximum
13497c478bd9Sstevel@tonic-gate 	 * size in sectors to which the file system can be increased.
13507c478bd9Sstevel@tonic-gate 	 * The calculated size is limited by fssize_db.
13517c478bd9Sstevel@tonic-gate 	 * Note that we don't lock the filesystem and therefore under rare
13527c478bd9Sstevel@tonic-gate 	 * conditions (the filesystem is mounted, the free block count is
13537c478bd9Sstevel@tonic-gate 	 * almost zero, and the superuser is still changing it) the calculated
13547c478bd9Sstevel@tonic-gate 	 * size can be imprecise.
13557c478bd9Sstevel@tonic-gate 	 */
13567c478bd9Sstevel@tonic-gate 	if (Pflag) {
13577c478bd9Sstevel@tonic-gate 		(void) printf("%llu\n", probe_summaryinfo());
13587c478bd9Sstevel@tonic-gate 		exit(0);
13597c478bd9Sstevel@tonic-gate 	}
13607c478bd9Sstevel@tonic-gate 
13617c478bd9Sstevel@tonic-gate 	/*
13627c478bd9Sstevel@tonic-gate 	 * If we're growing an existing filesystem, then we're about
13637c478bd9Sstevel@tonic-gate 	 * to start doing things that can require recovery efforts if
13647c478bd9Sstevel@tonic-gate 	 * we get interrupted, so make sure we get a chance to do so.
13657c478bd9Sstevel@tonic-gate 	 */
13667c478bd9Sstevel@tonic-gate 	if (grow) {
13677c478bd9Sstevel@tonic-gate 		sigact.sa_handler = recover_from_sigint;
13687c478bd9Sstevel@tonic-gate 		sigemptyset(&sigact.sa_mask);
13697c478bd9Sstevel@tonic-gate 		sigact.sa_flags = SA_RESTART;
13707c478bd9Sstevel@tonic-gate 
13717c478bd9Sstevel@tonic-gate 		if (sigaction(SIGINT, &sigact, (struct sigaction *)NULL) < 0) {
13727c478bd9Sstevel@tonic-gate 			perror(gettext("Could not register SIGINT handler"));
13737c478bd9Sstevel@tonic-gate 			lockexit(3);
13747c478bd9Sstevel@tonic-gate 		}
13757c478bd9Sstevel@tonic-gate 	}
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate 	if (!Nflag) {
13787c478bd9Sstevel@tonic-gate 		/*
13797c478bd9Sstevel@tonic-gate 		 * Check if MNTTAB is trustable
13807c478bd9Sstevel@tonic-gate 		 */
13817c478bd9Sstevel@tonic-gate 		if (statvfs64(MNTTAB, &fs) < 0) {
13827c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("can't statvfs %s\n"),
13837c478bd9Sstevel@tonic-gate 				MNTTAB);
13847c478bd9Sstevel@tonic-gate 			exit(32);
13857c478bd9Sstevel@tonic-gate 		}
13867c478bd9Sstevel@tonic-gate 
13877c478bd9Sstevel@tonic-gate 		if (strcmp(MNTTYPE_MNTFS, fs.f_basetype) != 0) {
13887c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
13897c478bd9Sstevel@tonic-gate 				"%s file system type is not %s, can't mkfs\n"),
13907c478bd9Sstevel@tonic-gate 				MNTTAB, MNTTYPE_MNTFS);
13917c478bd9Sstevel@tonic-gate 			exit(32);
13927c478bd9Sstevel@tonic-gate 		}
13937c478bd9Sstevel@tonic-gate 
13947c478bd9Sstevel@tonic-gate 		special = getfullblkname(fsys);
13957c478bd9Sstevel@tonic-gate 		checkdev(fsys, special);
13967c478bd9Sstevel@tonic-gate 
13977c478bd9Sstevel@tonic-gate 		/*
13987c478bd9Sstevel@tonic-gate 		 * If we found the block device name,
13997c478bd9Sstevel@tonic-gate 		 * then check the mount table.
14007c478bd9Sstevel@tonic-gate 		 * if mounted, and growing write lock the file system
14017c478bd9Sstevel@tonic-gate 		 *
14027c478bd9Sstevel@tonic-gate 		 */
14037c478bd9Sstevel@tonic-gate 		if ((special != NULL) && (*special != '\0')) {
14047c478bd9Sstevel@tonic-gate 			if ((mnttab = fopen(MNTTAB, "r")) == NULL) {
14057c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
14067c478bd9Sstevel@tonic-gate 					"can't open %s\n"), MNTTAB);
14077c478bd9Sstevel@tonic-gate 				exit(32);
14087c478bd9Sstevel@tonic-gate 			}
14097c478bd9Sstevel@tonic-gate 			while ((getmntent(mnttab, &mntp)) == NULL) {
14107c478bd9Sstevel@tonic-gate 				if (grow) {
14117c478bd9Sstevel@tonic-gate 					checkmount(&mntp, special);
14127c478bd9Sstevel@tonic-gate 					continue;
14137c478bd9Sstevel@tonic-gate 				}
14147c478bd9Sstevel@tonic-gate 				if (strcmp(special, mntp.mnt_special) == 0) {
14157c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
14167c478bd9Sstevel@tonic-gate 					    "%s is mounted, can't mkfs\n"),
14177c478bd9Sstevel@tonic-gate 					    special);
14187c478bd9Sstevel@tonic-gate 					exit(32);
14197c478bd9Sstevel@tonic-gate 				}
14207c478bd9Sstevel@tonic-gate 			}
14217c478bd9Sstevel@tonic-gate 			(void) fclose(mnttab);
14227c478bd9Sstevel@tonic-gate 		}
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate 		if (directory && (ismounted == 0)) {
14257c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s is not mounted\n"),
14267c478bd9Sstevel@tonic-gate 			    special);
14277c478bd9Sstevel@tonic-gate 			lockexit(32);
14287c478bd9Sstevel@tonic-gate 		}
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate 		fso = (grow) ? open64(fsys, O_WRONLY) : creat64(fsys, 0666);
14317c478bd9Sstevel@tonic-gate 		if (fso < 0) {
14327c478bd9Sstevel@tonic-gate 			saverr = errno;
14337c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
14347c478bd9Sstevel@tonic-gate 			    gettext("%s: cannot create: %s\n"),
14357c478bd9Sstevel@tonic-gate 			    fsys, strerror(saverr));
14367c478bd9Sstevel@tonic-gate 			lockexit(32);
14377c478bd9Sstevel@tonic-gate 		}
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate 	} else {
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 		/*
14427c478bd9Sstevel@tonic-gate 		 * For the -N case, a file descriptor is needed for the llseek()
14437c478bd9Sstevel@tonic-gate 		 * in wtfs(). See the comment in wtfs() for more information.
14447c478bd9Sstevel@tonic-gate 		 *
14457c478bd9Sstevel@tonic-gate 		 * Get a file descriptor that's read-only so that this code
14467c478bd9Sstevel@tonic-gate 		 * doesn't accidentally write to the file.
14477c478bd9Sstevel@tonic-gate 		 */
14487c478bd9Sstevel@tonic-gate 		fso = open64(fsys, O_RDONLY);
14497c478bd9Sstevel@tonic-gate 		if (fso < 0) {
14507c478bd9Sstevel@tonic-gate 			saverr = errno;
14517c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s: cannot open: %s\n"),
14527c478bd9Sstevel@tonic-gate 			    fsys, strerror(saverr));
14537c478bd9Sstevel@tonic-gate 			lockexit(32);
14547c478bd9Sstevel@tonic-gate 		}
14557c478bd9Sstevel@tonic-gate 	}
14567c478bd9Sstevel@tonic-gate 
14577c478bd9Sstevel@tonic-gate 	/*
14587c478bd9Sstevel@tonic-gate 	 * seed random # generator (for ic_generation)
14597c478bd9Sstevel@tonic-gate 	 */
14607c478bd9Sstevel@tonic-gate #ifdef MKFS_DEBUG
14617c478bd9Sstevel@tonic-gate 	srand48(12962);	/* reproducible results */
14627c478bd9Sstevel@tonic-gate #else
14637c478bd9Sstevel@tonic-gate 	srand48((long)(time((time_t *)NULL) + getpid()));
14647c478bd9Sstevel@tonic-gate #endif
14657c478bd9Sstevel@tonic-gate 
14667c478bd9Sstevel@tonic-gate 	if (grow) {
14677c478bd9Sstevel@tonic-gate 		growinit(fsys);
14687c478bd9Sstevel@tonic-gate 		goto grow00;
14697c478bd9Sstevel@tonic-gate 	}
14707c478bd9Sstevel@tonic-gate 
14717c478bd9Sstevel@tonic-gate 	/*
14727c478bd9Sstevel@tonic-gate 	 * Validate the given file system size.
14737c478bd9Sstevel@tonic-gate 	 * Verify that its last block can actually be accessed.
14747c478bd9Sstevel@tonic-gate 	 *
14757c478bd9Sstevel@tonic-gate 	 * Note: it's ok to use sblock as a buffer because it is immediately
14767c478bd9Sstevel@tonic-gate 	 * overwritten by the rdfs() of the superblock in the next line.
14777c478bd9Sstevel@tonic-gate 	 *
14787c478bd9Sstevel@tonic-gate 	 * ToDo: Because the size checking is done in rdfs()/wtfs(), the
14797c478bd9Sstevel@tonic-gate 	 * error message for specifying an illegal size is very unfriendly.
14807c478bd9Sstevel@tonic-gate 	 * In the future, one could replace the rdfs()/wtfs() calls
14817c478bd9Sstevel@tonic-gate 	 * below with in-line calls to read() or write(). This allows better
14827c478bd9Sstevel@tonic-gate 	 * error messages to be put in place.
14837c478bd9Sstevel@tonic-gate 	 */
14847c478bd9Sstevel@tonic-gate 	rdfs(fssize_db - 1, (int)sectorsize, (char *)&sblock);
14857c478bd9Sstevel@tonic-gate 
14867c478bd9Sstevel@tonic-gate 	/*
14877c478bd9Sstevel@tonic-gate 	 * make the fs unmountable
14887c478bd9Sstevel@tonic-gate 	 */
14897c478bd9Sstevel@tonic-gate 	rdfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize, (char *)&sblock);
14907c478bd9Sstevel@tonic-gate 	sblock.fs_magic = -1;
14917c478bd9Sstevel@tonic-gate 	sblock.fs_clean = FSBAD;
14927c478bd9Sstevel@tonic-gate 	sblock.fs_state = FSOKAY - sblock.fs_time;
14937c478bd9Sstevel@tonic-gate 	wtfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize, (char *)&sblock);
14947c478bd9Sstevel@tonic-gate 	bzero(&sblock, (size_t)sbsize);
14957c478bd9Sstevel@tonic-gate 
14967c478bd9Sstevel@tonic-gate 	sblock.fs_nsect = nsect;
14977c478bd9Sstevel@tonic-gate 	sblock.fs_ntrak = ntrack;
14987c478bd9Sstevel@tonic-gate 
14997c478bd9Sstevel@tonic-gate 	/*
15007c478bd9Sstevel@tonic-gate 	 * Validate specified/determined spc
15017c478bd9Sstevel@tonic-gate 	 * and calculate minimum cylinders per group.
15027c478bd9Sstevel@tonic-gate 	 */
15037c478bd9Sstevel@tonic-gate 
15047c478bd9Sstevel@tonic-gate 	/*
15057c478bd9Sstevel@tonic-gate 	 * sectors/cyl = tracks/cyl * sectors/track
15067c478bd9Sstevel@tonic-gate 	 */
15077c478bd9Sstevel@tonic-gate 	sblock.fs_spc = sblock.fs_ntrak * sblock.fs_nsect;
15087c478bd9Sstevel@tonic-gate 
15097c478bd9Sstevel@tonic-gate grow00:
15107c478bd9Sstevel@tonic-gate 	if (apc_flag) {
15117c478bd9Sstevel@tonic-gate 		sblock.fs_spc -= apc;
15127c478bd9Sstevel@tonic-gate 	}
15137c478bd9Sstevel@tonic-gate 	/*
15147c478bd9Sstevel@tonic-gate 	 * Have to test for this separately from apc_flag, due to
15157c478bd9Sstevel@tonic-gate 	 * the growfs case....
15167c478bd9Sstevel@tonic-gate 	 */
15177c478bd9Sstevel@tonic-gate 	if (sblock.fs_spc != sblock.fs_ntrak * sblock.fs_nsect) {
15187c478bd9Sstevel@tonic-gate 		spc_flag = 1;
15197c478bd9Sstevel@tonic-gate 	}
15207c478bd9Sstevel@tonic-gate 	if (grow)
15217c478bd9Sstevel@tonic-gate 		goto grow10;
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate 	sblock.fs_nrpos = nrpos;
15247c478bd9Sstevel@tonic-gate 	sblock.fs_bsize = bsize;
15257c478bd9Sstevel@tonic-gate 	sblock.fs_fsize = fragsize;
15267c478bd9Sstevel@tonic-gate 	sblock.fs_minfree = minfree;
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate grow10:
15297c478bd9Sstevel@tonic-gate 	if (nbpi < sblock.fs_fsize) {
15307c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
15317c478bd9Sstevel@tonic-gate 		"warning: wasteful data byte allocation / inode (nbpi):\n"));
15327c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
15337c478bd9Sstevel@tonic-gate 		    "%ld smaller than allocatable fragment size of %d\n"),
15347c478bd9Sstevel@tonic-gate 		    nbpi, sblock.fs_fsize);
15357c478bd9Sstevel@tonic-gate 	}
15367c478bd9Sstevel@tonic-gate 	if (grow)
15377c478bd9Sstevel@tonic-gate 		goto grow20;
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate 	if (opt == 's')
15407c478bd9Sstevel@tonic-gate 		sblock.fs_optim = FS_OPTSPACE;
15417c478bd9Sstevel@tonic-gate 	else
15427c478bd9Sstevel@tonic-gate 		sblock.fs_optim = FS_OPTTIME;
15437c478bd9Sstevel@tonic-gate 
15447c478bd9Sstevel@tonic-gate 	sblock.fs_bmask = ~(sblock.fs_bsize - 1);
15457c478bd9Sstevel@tonic-gate 	sblock.fs_fmask = ~(sblock.fs_fsize - 1);
15467c478bd9Sstevel@tonic-gate 	/*
15477c478bd9Sstevel@tonic-gate 	 * Planning now for future expansion.
15487c478bd9Sstevel@tonic-gate 	 */
15497c478bd9Sstevel@tonic-gate #if defined(_BIG_ENDIAN)
15507c478bd9Sstevel@tonic-gate 		sblock.fs_qbmask.val[0] = 0;
15517c478bd9Sstevel@tonic-gate 		sblock.fs_qbmask.val[1] = ~sblock.fs_bmask;
15527c478bd9Sstevel@tonic-gate 		sblock.fs_qfmask.val[0] = 0;
15537c478bd9Sstevel@tonic-gate 		sblock.fs_qfmask.val[1] = ~sblock.fs_fmask;
15547c478bd9Sstevel@tonic-gate #endif
15557c478bd9Sstevel@tonic-gate #if defined(_LITTLE_ENDIAN)
15567c478bd9Sstevel@tonic-gate 		sblock.fs_qbmask.val[0] = ~sblock.fs_bmask;
15577c478bd9Sstevel@tonic-gate 		sblock.fs_qbmask.val[1] = 0;
15587c478bd9Sstevel@tonic-gate 		sblock.fs_qfmask.val[0] = ~sblock.fs_fmask;
15597c478bd9Sstevel@tonic-gate 		sblock.fs_qfmask.val[1] = 0;
15607c478bd9Sstevel@tonic-gate #endif
15617c478bd9Sstevel@tonic-gate 	for (sblock.fs_bshift = 0, i = sblock.fs_bsize; i > 1; i >>= 1)
15627c478bd9Sstevel@tonic-gate 		sblock.fs_bshift++;
15637c478bd9Sstevel@tonic-gate 	for (sblock.fs_fshift = 0, i = sblock.fs_fsize; i > 1; i >>= 1)
15647c478bd9Sstevel@tonic-gate 		sblock.fs_fshift++;
15657c478bd9Sstevel@tonic-gate 	sblock.fs_frag = numfrags(&sblock, sblock.fs_bsize);
15667c478bd9Sstevel@tonic-gate 	for (sblock.fs_fragshift = 0, i = sblock.fs_frag; i > 1; i >>= 1)
15677c478bd9Sstevel@tonic-gate 		sblock.fs_fragshift++;
15687c478bd9Sstevel@tonic-gate 	if (sblock.fs_frag > MAXFRAG) {
15697c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
15707c478bd9Sstevel@tonic-gate 	"fragment size %d is too small, minimum with block size %d is %d\n"),
15717c478bd9Sstevel@tonic-gate 		    sblock.fs_fsize, sblock.fs_bsize,
15727c478bd9Sstevel@tonic-gate 		    sblock.fs_bsize / MAXFRAG);
15737c478bd9Sstevel@tonic-gate 		lockexit(32);
15747c478bd9Sstevel@tonic-gate 	}
15757c478bd9Sstevel@tonic-gate 	sblock.fs_nindir = sblock.fs_bsize / sizeof (daddr32_t);
15767c478bd9Sstevel@tonic-gate 	sblock.fs_inopb = sblock.fs_bsize / sizeof (struct dinode);
15777c478bd9Sstevel@tonic-gate 	sblock.fs_nspf = sblock.fs_fsize / sectorsize;
15787c478bd9Sstevel@tonic-gate 	for (sblock.fs_fsbtodb = 0, i = NSPF(&sblock); i > 1; i >>= 1)
15797c478bd9Sstevel@tonic-gate 		sblock.fs_fsbtodb++;
15807c478bd9Sstevel@tonic-gate 
15817c478bd9Sstevel@tonic-gate 	/*
15827c478bd9Sstevel@tonic-gate 	 * Compute the super-block, cylinder group, and inode blocks.
15837c478bd9Sstevel@tonic-gate 	 * Note that these "blkno" are really fragment addresses.
15847c478bd9Sstevel@tonic-gate 	 * For example, on an 8K/1K (block/fragment) system, fs_sblkno is 16,
15857c478bd9Sstevel@tonic-gate 	 * fs_cblkno is 24, and fs_iblkno is 32. This is why CGSIZE is so
15867c478bd9Sstevel@tonic-gate 	 * important: only 1 FS block is allocated for the cg struct (fragment
15877c478bd9Sstevel@tonic-gate 	 * numbers 24 through 31).
15887c478bd9Sstevel@tonic-gate 	 */
15897c478bd9Sstevel@tonic-gate 	sblock.fs_sblkno =
15907c478bd9Sstevel@tonic-gate 	    roundup(howmany(bbsize + sbsize, sblock.fs_fsize), sblock.fs_frag);
15917c478bd9Sstevel@tonic-gate 	sblock.fs_cblkno = (daddr32_t)(sblock.fs_sblkno +
15927c478bd9Sstevel@tonic-gate 	    roundup(howmany(sbsize, sblock.fs_fsize), sblock.fs_frag));
15937c478bd9Sstevel@tonic-gate 	sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag;
15947c478bd9Sstevel@tonic-gate 
15957c478bd9Sstevel@tonic-gate 	sblock.fs_cgoffset = roundup(
15967c478bd9Sstevel@tonic-gate 	    howmany(sblock.fs_nsect, NSPF(&sblock)), sblock.fs_frag);
15977c478bd9Sstevel@tonic-gate 	for (sblock.fs_cgmask = -1, i = sblock.fs_ntrak; i > 1; i >>= 1)
15987c478bd9Sstevel@tonic-gate 		sblock.fs_cgmask <<= 1;
15997c478bd9Sstevel@tonic-gate 	if (!POWEROF2(sblock.fs_ntrak))
16007c478bd9Sstevel@tonic-gate 		sblock.fs_cgmask <<= 1;
16017c478bd9Sstevel@tonic-gate 	/*
16027c478bd9Sstevel@tonic-gate 	 * Validate specified/determined spc
16037c478bd9Sstevel@tonic-gate 	 * and calculate minimum cylinders per group.
16047c478bd9Sstevel@tonic-gate 	 */
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate 	for (sblock.fs_cpc = NSPB(&sblock), i = sblock.fs_spc;
16077c478bd9Sstevel@tonic-gate 	    sblock.fs_cpc > 1 && (i & 1) == 0;
16087c478bd9Sstevel@tonic-gate 	    sblock.fs_cpc >>= 1, i >>= 1)
16097c478bd9Sstevel@tonic-gate 		/* void */;
16107c478bd9Sstevel@tonic-gate 	mincpc = sblock.fs_cpc;
16117c478bd9Sstevel@tonic-gate 
16127c478bd9Sstevel@tonic-gate 	/* if these calculations are changed, check dump_fscmd also */
16137c478bd9Sstevel@tonic-gate 	bpcg = (uint64_t)sblock.fs_spc * sectorsize;
16147c478bd9Sstevel@tonic-gate 	inospercg = (uint64_t)roundup(bpcg / sizeof (struct dinode),
16157c478bd9Sstevel@tonic-gate 	    INOPB(&sblock));
16167c478bd9Sstevel@tonic-gate 	if (inospercg > MAXIpG(&sblock))
16177c478bd9Sstevel@tonic-gate 		inospercg = MAXIpG(&sblock);
16187c478bd9Sstevel@tonic-gate 	used = (uint64_t)(sblock.fs_iblkno + inospercg /
16197c478bd9Sstevel@tonic-gate 	    INOPF(&sblock)) * NSPF(&sblock);
16207c478bd9Sstevel@tonic-gate 	mincpgcnt = (long)howmany((uint64_t)sblock.fs_cgoffset *
16217c478bd9Sstevel@tonic-gate 	    (~sblock.fs_cgmask) + used, sblock.fs_spc);
16227c478bd9Sstevel@tonic-gate 	mincpg = roundup(mincpgcnt, mincpc);
16237c478bd9Sstevel@tonic-gate 	/*
16247c478bd9Sstevel@tonic-gate 	 * Insure that cylinder group with mincpg has enough space
16257c478bd9Sstevel@tonic-gate 	 * for block maps
16267c478bd9Sstevel@tonic-gate 	 */
16277c478bd9Sstevel@tonic-gate 	sblock.fs_cpg = mincpg;
16287c478bd9Sstevel@tonic-gate 	sblock.fs_ipg = (int32_t)inospercg;
16297c478bd9Sstevel@tonic-gate 	mapcramped = 0;
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate 	/*
16327c478bd9Sstevel@tonic-gate 	 * Make sure the cg struct fits within the file system block.
16337c478bd9Sstevel@tonic-gate 	 * Use larger block sizes until it fits
16347c478bd9Sstevel@tonic-gate 	 */
16357c478bd9Sstevel@tonic-gate 	while (CGSIZE(&sblock) > sblock.fs_bsize) {
16367c478bd9Sstevel@tonic-gate 		mapcramped = 1;
16377c478bd9Sstevel@tonic-gate 		if (sblock.fs_bsize < MAXBSIZE) {
16387c478bd9Sstevel@tonic-gate 			sblock.fs_bsize <<= 1;
16397c478bd9Sstevel@tonic-gate 			if ((i & 1) == 0) {
16407c478bd9Sstevel@tonic-gate 				i >>= 1;
16417c478bd9Sstevel@tonic-gate 			} else {
16427c478bd9Sstevel@tonic-gate 				sblock.fs_cpc <<= 1;
16437c478bd9Sstevel@tonic-gate 				mincpc <<= 1;
16447c478bd9Sstevel@tonic-gate 				mincpg = roundup(mincpgcnt, mincpc);
16457c478bd9Sstevel@tonic-gate 				sblock.fs_cpg = mincpg;
16467c478bd9Sstevel@tonic-gate 			}
16477c478bd9Sstevel@tonic-gate 			sblock.fs_frag <<= 1;
16487c478bd9Sstevel@tonic-gate 			sblock.fs_fragshift += 1;
16497c478bd9Sstevel@tonic-gate 			if (sblock.fs_frag <= MAXFRAG)
16507c478bd9Sstevel@tonic-gate 				continue;
16517c478bd9Sstevel@tonic-gate 		}
16527c478bd9Sstevel@tonic-gate 
16537c478bd9Sstevel@tonic-gate 		/*
16547c478bd9Sstevel@tonic-gate 		 * Looped far enough. The fragment is now as large as the
16557c478bd9Sstevel@tonic-gate 		 * filesystem block!
16567c478bd9Sstevel@tonic-gate 		 */
16577c478bd9Sstevel@tonic-gate 		if (sblock.fs_fsize == sblock.fs_bsize) {
16587c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
16597c478bd9Sstevel@tonic-gate 		    "There is no block size that can support this disk\n"));
16607c478bd9Sstevel@tonic-gate 			lockexit(32);
16617c478bd9Sstevel@tonic-gate 		}
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate 		/*
16647c478bd9Sstevel@tonic-gate 		 * Try a larger fragment. Double the fragment size.
16657c478bd9Sstevel@tonic-gate 		 */
16667c478bd9Sstevel@tonic-gate 		sblock.fs_frag >>= 1;
16677c478bd9Sstevel@tonic-gate 		sblock.fs_fragshift -= 1;
16687c478bd9Sstevel@tonic-gate 		sblock.fs_fsize <<= 1;
16697c478bd9Sstevel@tonic-gate 		sblock.fs_nspf <<= 1;
16707c478bd9Sstevel@tonic-gate 	}
16717c478bd9Sstevel@tonic-gate 	/*
16727c478bd9Sstevel@tonic-gate 	 * Insure that cylinder group with mincpg has enough space for inodes
16737c478bd9Sstevel@tonic-gate 	 */
16747c478bd9Sstevel@tonic-gate 	inodecramped = 0;
16757c478bd9Sstevel@tonic-gate 	used *= sectorsize;
16767c478bd9Sstevel@tonic-gate 	nbytes64 = (uint64_t)mincpg * bpcg - used;
16777c478bd9Sstevel@tonic-gate 	inospercg = (uint64_t)roundup((nbytes64 / nbpi), INOPB(&sblock));
16787c478bd9Sstevel@tonic-gate 	sblock.fs_ipg = (int32_t)inospercg;
16797c478bd9Sstevel@tonic-gate 	while (inospercg > MAXIpG(&sblock)) {
16807c478bd9Sstevel@tonic-gate 		inodecramped = 1;
16817c478bd9Sstevel@tonic-gate 		if (mincpc == 1 || sblock.fs_frag == 1 ||
16827c478bd9Sstevel@tonic-gate 		    sblock.fs_bsize == MINBSIZE)
16837c478bd9Sstevel@tonic-gate 			break;
16847c478bd9Sstevel@tonic-gate 		nbytes64 = (uint64_t)mincpg * bpcg - used;
16857c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
16867c478bd9Sstevel@tonic-gate 		    gettext("With a block size of %d %s %lu\n"),
16877c478bd9Sstevel@tonic-gate 		    sblock.fs_bsize, gettext("minimum bytes per inode is"),
16887c478bd9Sstevel@tonic-gate 		    (uint32_t)(nbytes64 / MAXIpG(&sblock) + 1));
16897c478bd9Sstevel@tonic-gate 		sblock.fs_bsize >>= 1;
16907c478bd9Sstevel@tonic-gate 		sblock.fs_frag >>= 1;
16917c478bd9Sstevel@tonic-gate 		sblock.fs_fragshift -= 1;
16927c478bd9Sstevel@tonic-gate 		mincpc >>= 1;
16937c478bd9Sstevel@tonic-gate 		sblock.fs_cpg = roundup(mincpgcnt, mincpc);
16947c478bd9Sstevel@tonic-gate 		if (CGSIZE(&sblock) > sblock.fs_bsize) {
16957c478bd9Sstevel@tonic-gate 			sblock.fs_bsize <<= 1;
16967c478bd9Sstevel@tonic-gate 			break;
16977c478bd9Sstevel@tonic-gate 		}
16987c478bd9Sstevel@tonic-gate 		mincpg = sblock.fs_cpg;
16997c478bd9Sstevel@tonic-gate 		nbytes64 = (uint64_t)mincpg * bpcg - used;
17007c478bd9Sstevel@tonic-gate 		inospercg = (uint64_t)roundup((nbytes64 / nbpi),
17017c478bd9Sstevel@tonic-gate 			INOPB(&sblock));
17027c478bd9Sstevel@tonic-gate 		sblock.fs_ipg = (int32_t)inospercg;
17037c478bd9Sstevel@tonic-gate 	}
17047c478bd9Sstevel@tonic-gate 	if (inodecramped) {
17057c478bd9Sstevel@tonic-gate 		if (inospercg > MAXIpG(&sblock)) {
17067c478bd9Sstevel@tonic-gate 			nbytes64 = (uint64_t)mincpg * bpcg - used;
17077c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
17087c478bd9Sstevel@tonic-gate 			    "Minimum bytes per inode is %d\n"),
17097c478bd9Sstevel@tonic-gate 			    (uint32_t)(nbytes64 / MAXIpG(&sblock) + 1));
17107c478bd9Sstevel@tonic-gate 		} else if (!mapcramped) {
17117c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
17127c478bd9Sstevel@tonic-gate 	    "With %ld bytes per inode, minimum cylinders per group is %ld\n"),
17137c478bd9Sstevel@tonic-gate 			    nbpi, mincpg);
17147c478bd9Sstevel@tonic-gate 		}
17157c478bd9Sstevel@tonic-gate 	}
17167c478bd9Sstevel@tonic-gate 	if (mapcramped) {
17177c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
17187c478bd9Sstevel@tonic-gate 		    "With %d sectors per cylinder, minimum cylinders "
17197c478bd9Sstevel@tonic-gate 		    "per group is %ld\n"),
17207c478bd9Sstevel@tonic-gate 		    sblock.fs_spc, mincpg);
17217c478bd9Sstevel@tonic-gate 	}
17227c478bd9Sstevel@tonic-gate 	if (inodecramped || mapcramped) {
17237c478bd9Sstevel@tonic-gate 		/*
17247c478bd9Sstevel@tonic-gate 		 * To make this at least somewhat comprehensible in
17257c478bd9Sstevel@tonic-gate 		 * the world of i18n, figure out what we're going to
17267c478bd9Sstevel@tonic-gate 		 * say and then say it all at one time.  The days of
17277c478bd9Sstevel@tonic-gate 		 * needing to scrimp on string space are behind us....
17287c478bd9Sstevel@tonic-gate 		 */
17297c478bd9Sstevel@tonic-gate 		if ((sblock.fs_bsize != bsize) &&
17307c478bd9Sstevel@tonic-gate 		    (sblock.fs_fsize != fragsize)) {
17317c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
17327c478bd9Sstevel@tonic-gate 	    "This requires the block size to be changed from %ld to %d\n"
17337c478bd9Sstevel@tonic-gate 	    "and the fragment size to be changed from %ld to %d\n"),
17347c478bd9Sstevel@tonic-gate 			    bsize, sblock.fs_bsize,
17357c478bd9Sstevel@tonic-gate 			    fragsize, sblock.fs_fsize);
17367c478bd9Sstevel@tonic-gate 		} else if (sblock.fs_bsize != bsize) {
17377c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
17387c478bd9Sstevel@tonic-gate 	    "This requires the block size to be changed from %ld to %d\n"),
17397c478bd9Sstevel@tonic-gate 			    bsize, sblock.fs_bsize);
17407c478bd9Sstevel@tonic-gate 		} else if (sblock.fs_fsize != fragsize) {
17417c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
17427c478bd9Sstevel@tonic-gate 	    "This requires the fragment size to be changed from %ld to %d\n"),
17437c478bd9Sstevel@tonic-gate 			    fragsize, sblock.fs_fsize);
17447c478bd9Sstevel@tonic-gate 		} else {
17457c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
17467c478bd9Sstevel@tonic-gate 	    "Unable to make filesystem fit with the given constraints\n"));
17477c478bd9Sstevel@tonic-gate 		}
17487c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
17497c478bd9Sstevel@tonic-gate 		    "Please re-run mkfs with corrected parameters\n"));
17507c478bd9Sstevel@tonic-gate 		lockexit(32);
17517c478bd9Sstevel@tonic-gate 	}
17527c478bd9Sstevel@tonic-gate 	/*
17537c478bd9Sstevel@tonic-gate 	 * Calculate the number of cylinders per group
17547c478bd9Sstevel@tonic-gate 	 */
17557c478bd9Sstevel@tonic-gate 	sblock.fs_cpg = cpg;
17567c478bd9Sstevel@tonic-gate 	if (sblock.fs_cpg % mincpc != 0) {
17577c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
17587c478bd9Sstevel@tonic-gate 		    "Warning: cylinder groups must have a multiple "
17597c478bd9Sstevel@tonic-gate 		    "of %ld cylinders with the given\n         parameters\n"),
17607c478bd9Sstevel@tonic-gate 		    mincpc);
17617c478bd9Sstevel@tonic-gate 		sblock.fs_cpg = roundup(sblock.fs_cpg, mincpc);
17627c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Rounded cgsize up to %d\n"),
17637c478bd9Sstevel@tonic-gate 		    sblock.fs_cpg);
17647c478bd9Sstevel@tonic-gate 	}
17657c478bd9Sstevel@tonic-gate 	/*
17667c478bd9Sstevel@tonic-gate 	 * Must insure there is enough space for inodes
17677c478bd9Sstevel@tonic-gate 	 */
17687c478bd9Sstevel@tonic-gate 	/* if these calculations are changed, check dump_fscmd also */
17697c478bd9Sstevel@tonic-gate 	nbytes64 = (uint64_t)sblock.fs_cpg * bpcg - used;
17707c478bd9Sstevel@tonic-gate 	sblock.fs_ipg = roundup((uint32_t)(nbytes64 / nbpi), INOPB(&sblock));
17717c478bd9Sstevel@tonic-gate 
17727c478bd9Sstevel@tonic-gate 	/*
17737c478bd9Sstevel@tonic-gate 	 * Slim down cylinders per group, until the inodes can fit.
17747c478bd9Sstevel@tonic-gate 	 */
17757c478bd9Sstevel@tonic-gate 	while (sblock.fs_ipg > MAXIpG(&sblock)) {
17767c478bd9Sstevel@tonic-gate 		inodecramped = 1;
17777c478bd9Sstevel@tonic-gate 		sblock.fs_cpg -= mincpc;
17787c478bd9Sstevel@tonic-gate 		nbytes64 = (uint64_t)sblock.fs_cpg * bpcg - used;
17797c478bd9Sstevel@tonic-gate 		sblock.fs_ipg = roundup((uint32_t)(nbytes64 / nbpi),
17807c478bd9Sstevel@tonic-gate 			INOPB(&sblock));
17817c478bd9Sstevel@tonic-gate 	}
17827c478bd9Sstevel@tonic-gate 	/*
17837c478bd9Sstevel@tonic-gate 	 * Must insure there is enough space to hold block map.
17847c478bd9Sstevel@tonic-gate 	 * Cut down on cylinders per group, until the cg struct fits in a
17857c478bd9Sstevel@tonic-gate 	 * filesystem block.
17867c478bd9Sstevel@tonic-gate 	 */
17877c478bd9Sstevel@tonic-gate 	while (CGSIZE(&sblock) > sblock.fs_bsize) {
17887c478bd9Sstevel@tonic-gate 		mapcramped = 1;
17897c478bd9Sstevel@tonic-gate 		sblock.fs_cpg -= mincpc;
17907c478bd9Sstevel@tonic-gate 		nbytes64 = (uint64_t)sblock.fs_cpg * bpcg - used;
17917c478bd9Sstevel@tonic-gate 		sblock.fs_ipg = roundup((uint32_t)(nbytes64 / nbpi),
17927c478bd9Sstevel@tonic-gate 			INOPB(&sblock));
17937c478bd9Sstevel@tonic-gate 	}
17947c478bd9Sstevel@tonic-gate 	sblock.fs_fpg = (sblock.fs_cpg * sblock.fs_spc) / NSPF(&sblock);
17957c478bd9Sstevel@tonic-gate 	if ((sblock.fs_cpg * sblock.fs_spc) % NSPB(&sblock) != 0) {
17967c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
17977c478bd9Sstevel@tonic-gate 		gettext("newfs: panic (fs_cpg * fs_spc) %% NSPF != 0\n"));
17987c478bd9Sstevel@tonic-gate 		lockexit(32);
17997c478bd9Sstevel@tonic-gate 	}
18007c478bd9Sstevel@tonic-gate 	if (sblock.fs_cpg < mincpg) {
18017c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
18027c478bd9Sstevel@tonic-gate "With the given parameters, cgsize must be at least %ld; please re-run mkfs\n"),
18037c478bd9Sstevel@tonic-gate 			mincpg);
18047c478bd9Sstevel@tonic-gate 		lockexit(32);
18057c478bd9Sstevel@tonic-gate 	}
18067c478bd9Sstevel@tonic-gate 	sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock));
18077c478bd9Sstevel@tonic-gate grow20:
18087c478bd9Sstevel@tonic-gate 	/*
18097c478bd9Sstevel@tonic-gate 	 * Now have size for file system and nsect and ntrak.
18107c478bd9Sstevel@tonic-gate 	 * Determine number of cylinders and blocks in the file system.
18117c478bd9Sstevel@tonic-gate 	 */
18127c478bd9Sstevel@tonic-gate 	fssize_frag = (int64_t)dbtofsb(&sblock, fssize_db);
18137c478bd9Sstevel@tonic-gate 	if (fssize_frag > INT_MAX) {
18147c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
18157c478bd9Sstevel@tonic-gate "There are too many fragments in the system, increase fragment size\n"),
18167c478bd9Sstevel@tonic-gate 		    mincpg);
18177c478bd9Sstevel@tonic-gate 		lockexit(32);
18187c478bd9Sstevel@tonic-gate 	}
18197c478bd9Sstevel@tonic-gate 	sblock.fs_size = (int32_t)fssize_frag;
18207c478bd9Sstevel@tonic-gate 	sblock.fs_ncyl = (int32_t)(fssize_frag * NSPF(&sblock) / sblock.fs_spc);
18217c478bd9Sstevel@tonic-gate 	if (fssize_frag * NSPF(&sblock) >
18227c478bd9Sstevel@tonic-gate 	    (uint64_t)sblock.fs_ncyl * sblock.fs_spc) {
18237c478bd9Sstevel@tonic-gate 		sblock.fs_ncyl++;
18247c478bd9Sstevel@tonic-gate 		warn = 1;
18257c478bd9Sstevel@tonic-gate 	}
18267c478bd9Sstevel@tonic-gate 	if (sblock.fs_ncyl < 1) {
18277c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
18287c478bd9Sstevel@tonic-gate 			"file systems must have at least one cylinder\n"));
18297c478bd9Sstevel@tonic-gate 		lockexit(32);
18307c478bd9Sstevel@tonic-gate 	}
18317c478bd9Sstevel@tonic-gate 	if (grow)
18327c478bd9Sstevel@tonic-gate 		goto grow30;
18337c478bd9Sstevel@tonic-gate 	/*
18347c478bd9Sstevel@tonic-gate 	 * Determine feasability/values of rotational layout tables.
18357c478bd9Sstevel@tonic-gate 	 *
18367c478bd9Sstevel@tonic-gate 	 * The size of the rotational layout tables is limited by the size
18377c478bd9Sstevel@tonic-gate 	 * of the file system block, fs_bsize.  The amount of space
18387c478bd9Sstevel@tonic-gate 	 * available for tables is calculated as (fs_bsize - sizeof (struct
18397c478bd9Sstevel@tonic-gate 	 * fs)).  The size of these tables is inversely proportional to the
18407c478bd9Sstevel@tonic-gate 	 * block size of the file system. The size increases if sectors per
18417c478bd9Sstevel@tonic-gate 	 * track are not powers of two, because more cylinders must be
18427c478bd9Sstevel@tonic-gate 	 * described by the tables before the rotational pattern repeats
18437c478bd9Sstevel@tonic-gate 	 * (fs_cpc).
18447c478bd9Sstevel@tonic-gate 	 */
18457c478bd9Sstevel@tonic-gate 	sblock.fs_postblformat = FS_DYNAMICPOSTBLFMT;
18467c478bd9Sstevel@tonic-gate 	sblock.fs_sbsize = fragroundup(&sblock, sizeof (struct fs));
18477c478bd9Sstevel@tonic-gate 	sblock.fs_npsect = sblock.fs_nsect;
18487c478bd9Sstevel@tonic-gate 	if (sblock.fs_ntrak == 1) {
18497c478bd9Sstevel@tonic-gate 		sblock.fs_cpc = 0;
18507c478bd9Sstevel@tonic-gate 		goto next;
18517c478bd9Sstevel@tonic-gate 	}
18527c478bd9Sstevel@tonic-gate 	postblsize = sblock.fs_nrpos * sblock.fs_cpc * sizeof (short);
18537c478bd9Sstevel@tonic-gate 	rotblsize = sblock.fs_cpc * sblock.fs_spc / NSPB(&sblock);
18547c478bd9Sstevel@tonic-gate 	totalsbsize = sizeof (struct fs) + rotblsize;
18557c478bd9Sstevel@tonic-gate 
18567c478bd9Sstevel@tonic-gate 	/* do static allocation if nrpos == 8 and fs_cpc == 16  */
18577c478bd9Sstevel@tonic-gate 	if (sblock.fs_nrpos == 8 && sblock.fs_cpc <= 16) {
18587c478bd9Sstevel@tonic-gate 		/* use old static table space */
18597c478bd9Sstevel@tonic-gate 		sblock.fs_postbloff = (char *)(&sblock.fs_opostbl[0][0]) -
18607c478bd9Sstevel@tonic-gate 		    (char *)(&sblock.fs_link);
18617c478bd9Sstevel@tonic-gate 		sblock.fs_rotbloff = &sblock.fs_space[0] -
18627c478bd9Sstevel@tonic-gate 		    (uchar_t *)(&sblock.fs_link);
18637c478bd9Sstevel@tonic-gate 	} else {
18647c478bd9Sstevel@tonic-gate 		/* use 4.3 dynamic table space */
18657c478bd9Sstevel@tonic-gate 		sblock.fs_postbloff = &sblock.fs_space[0] -
18667c478bd9Sstevel@tonic-gate 		    (uchar_t *)(&sblock.fs_link);
18677c478bd9Sstevel@tonic-gate 		sblock.fs_rotbloff = sblock.fs_postbloff + postblsize;
18687c478bd9Sstevel@tonic-gate 		totalsbsize += postblsize;
18697c478bd9Sstevel@tonic-gate 	}
18707c478bd9Sstevel@tonic-gate 	if (totalsbsize > sblock.fs_bsize ||
18717c478bd9Sstevel@tonic-gate 	    sblock.fs_nsect > (1 << NBBY) * NSPB(&sblock)) {
18727c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
18737c478bd9Sstevel@tonic-gate 		    "Warning: insufficient space in super block for\n"
18747c478bd9Sstevel@tonic-gate 		    "rotational layout tables with nsect %d, ntrack %d, "
18757c478bd9Sstevel@tonic-gate 		    "and nrpos %d.\nOmitting tables - file system "
18767c478bd9Sstevel@tonic-gate 		    "performance may be impaired.\n"),
18777c478bd9Sstevel@tonic-gate 		    sblock.fs_nsect, sblock.fs_ntrak, sblock.fs_nrpos);
18787c478bd9Sstevel@tonic-gate 
18797c478bd9Sstevel@tonic-gate 		/*
18807c478bd9Sstevel@tonic-gate 		 * Setting fs_cpc to 0 tells alloccgblk() in ufs_alloc.c to
18817c478bd9Sstevel@tonic-gate 		 * ignore the positional layout table and rotational
18827c478bd9Sstevel@tonic-gate 		 * position table.
18837c478bd9Sstevel@tonic-gate 		 */
18847c478bd9Sstevel@tonic-gate 		sblock.fs_cpc = 0;
18857c478bd9Sstevel@tonic-gate 		goto next;
18867c478bd9Sstevel@tonic-gate 	}
18877c478bd9Sstevel@tonic-gate 	sblock.fs_sbsize = fragroundup(&sblock, totalsbsize);
18887c478bd9Sstevel@tonic-gate 
18897c478bd9Sstevel@tonic-gate 
18907c478bd9Sstevel@tonic-gate 	/*
18917c478bd9Sstevel@tonic-gate 	 * calculate the available blocks for each rotational position
18927c478bd9Sstevel@tonic-gate 	 */
18937c478bd9Sstevel@tonic-gate 	for (cylno = 0; cylno < sblock.fs_cpc; cylno++)
18947c478bd9Sstevel@tonic-gate 		for (rpos = 0; rpos < sblock.fs_nrpos; rpos++)
18957c478bd9Sstevel@tonic-gate 			fs_postbl(&sblock, cylno)[rpos] = -1;
18967c478bd9Sstevel@tonic-gate 	for (i = (rotblsize - 1) * sblock.fs_frag;
18977c478bd9Sstevel@tonic-gate 	    i >= 0; i -= sblock.fs_frag) {
18987c478bd9Sstevel@tonic-gate 		cylno = cbtocylno(&sblock, i);
18997c478bd9Sstevel@tonic-gate 		rpos = cbtorpos(&sblock, i);
19007c478bd9Sstevel@tonic-gate 		blk = fragstoblks(&sblock, i);
19017c478bd9Sstevel@tonic-gate 		if (fs_postbl(&sblock, cylno)[rpos] == -1)
19027c478bd9Sstevel@tonic-gate 			fs_rotbl(&sblock)[blk] = 0;
19037c478bd9Sstevel@tonic-gate 		else
19047c478bd9Sstevel@tonic-gate 			fs_rotbl(&sblock)[blk] =
19057c478bd9Sstevel@tonic-gate 			    fs_postbl(&sblock, cylno)[rpos] - blk;
19067c478bd9Sstevel@tonic-gate 		fs_postbl(&sblock, cylno)[rpos] = blk;
19077c478bd9Sstevel@tonic-gate 	}
19087c478bd9Sstevel@tonic-gate next:
19097c478bd9Sstevel@tonic-gate grow30:
19107c478bd9Sstevel@tonic-gate 	/*
19117c478bd9Sstevel@tonic-gate 	 * Compute/validate number of cylinder groups.
19127c478bd9Sstevel@tonic-gate 	 * Note that if an excessively large filesystem is specified
19137c478bd9Sstevel@tonic-gate 	 * (e.g., more than 16384 cylinders for an 8K filesystem block), it
19147c478bd9Sstevel@tonic-gate 	 * does not get detected until checksummarysize()
19157c478bd9Sstevel@tonic-gate 	 */
19167c478bd9Sstevel@tonic-gate 	sblock.fs_ncg = sblock.fs_ncyl / sblock.fs_cpg;
19177c478bd9Sstevel@tonic-gate 	if (sblock.fs_ncyl % sblock.fs_cpg)
19187c478bd9Sstevel@tonic-gate 		sblock.fs_ncg++;
19197c478bd9Sstevel@tonic-gate 	sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock);
19207c478bd9Sstevel@tonic-gate 	i = MIN(~sblock.fs_cgmask, sblock.fs_ncg - 1);
19217c478bd9Sstevel@tonic-gate 	ibpcl = cgdmin(&sblock, i) - cgbase(&sblock, i);
19227c478bd9Sstevel@tonic-gate 	if (ibpcl >= sblock.fs_fpg) {
19237c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
19247c478bd9Sstevel@tonic-gate 		    "inode blocks/cyl group (%d) >= data blocks (%d)\n"),
19257c478bd9Sstevel@tonic-gate 		    cgdmin(&sblock, i) - cgbase(&sblock, i) / sblock.fs_frag,
19267c478bd9Sstevel@tonic-gate 		    sblock.fs_fpg / sblock.fs_frag);
19277c478bd9Sstevel@tonic-gate 		if ((ibpcl < 0) || (sblock.fs_fpg < 0)) {
19287c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
19297c478bd9Sstevel@tonic-gate 	    "number of cylinders per cylinder group (%d) must be decreased.\n"),
19307c478bd9Sstevel@tonic-gate 			    sblock.fs_cpg);
19317c478bd9Sstevel@tonic-gate 		} else {
19327c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
19337c478bd9Sstevel@tonic-gate 	    "number of cylinders per cylinder group (%d) must be increased.\n"),
19347c478bd9Sstevel@tonic-gate 			    sblock.fs_cpg);
19357c478bd9Sstevel@tonic-gate 		}
19367c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
19377c478bd9Sstevel@tonic-gate "Note that cgsize may have been adjusted to allow struct cg to fit.\n"));
19387c478bd9Sstevel@tonic-gate 		lockexit(32);
19397c478bd9Sstevel@tonic-gate 	}
19407c478bd9Sstevel@tonic-gate 	j = sblock.fs_ncg - 1;
19417c478bd9Sstevel@tonic-gate 	if ((i = fssize_frag - j * sblock.fs_fpg) < sblock.fs_fpg &&
19427c478bd9Sstevel@tonic-gate 	    cgdmin(&sblock, j) - cgbase(&sblock, j) > i) {
19437c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
19447c478bd9Sstevel@tonic-gate 		    "Warning: inode blocks/cyl group (%d) >= data "
19457c478bd9Sstevel@tonic-gate 		    "blocks (%ld) in last\n    cylinder group. This "
19467c478bd9Sstevel@tonic-gate 		    "implies %ld sector(s) cannot be allocated.\n"),
19477c478bd9Sstevel@tonic-gate 		    (cgdmin(&sblock, j) - cgbase(&sblock, j)) / sblock.fs_frag,
19487c478bd9Sstevel@tonic-gate 		    i / sblock.fs_frag, i * NSPF(&sblock));
1949*6d24e334Svsakar 		/*
1950*6d24e334Svsakar 		 * If there is only one cylinder group and that is not even
1951*6d24e334Svsakar 		 * big enough to hold the inodes, exit.
1952*6d24e334Svsakar 		 */
1953*6d24e334Svsakar 		if (sblock.fs_ncg == 1)
1954*6d24e334Svsakar 			cg_too_small = 1;
19557c478bd9Sstevel@tonic-gate 		sblock.fs_ncg--;
19567c478bd9Sstevel@tonic-gate 		sblock.fs_ncyl -= sblock.fs_ncyl % sblock.fs_cpg;
19577c478bd9Sstevel@tonic-gate 		sblock.fs_size = fssize_frag =
19587c478bd9Sstevel@tonic-gate 		    (int64_t)sblock.fs_ncyl * (int64_t)sblock.fs_spc /
19597c478bd9Sstevel@tonic-gate 		    (int64_t)NSPF(&sblock);
19607c478bd9Sstevel@tonic-gate 		warn = 0;
19617c478bd9Sstevel@tonic-gate 	}
19627c478bd9Sstevel@tonic-gate 	if (warn && !spc_flag) {
19637c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
19647c478bd9Sstevel@tonic-gate 		    "Warning: %d sector(s) in last cylinder unallocated\n"),
19657c478bd9Sstevel@tonic-gate 		    sblock.fs_spc - (uint32_t)(fssize_frag * NSPF(&sblock) -
19667c478bd9Sstevel@tonic-gate 		    (uint64_t)(sblock.fs_ncyl - 1) * sblock.fs_spc));
19677c478bd9Sstevel@tonic-gate 	}
19687c478bd9Sstevel@tonic-gate 	/*
19697c478bd9Sstevel@tonic-gate 	 * fill in remaining fields of the super block
19707c478bd9Sstevel@tonic-gate 	 */
19717c478bd9Sstevel@tonic-gate 
19727c478bd9Sstevel@tonic-gate 	/*
19737c478bd9Sstevel@tonic-gate 	 * The csum records are stored in cylinder group 0, starting at
19747c478bd9Sstevel@tonic-gate 	 * cgdmin, the first data block.
19757c478bd9Sstevel@tonic-gate 	 */
19767c478bd9Sstevel@tonic-gate 	sblock.fs_csaddr = cgdmin(&sblock, 0);
19777c478bd9Sstevel@tonic-gate 	sblock.fs_cssize =
19787c478bd9Sstevel@tonic-gate 	    fragroundup(&sblock, sblock.fs_ncg * sizeof (struct csum));
19797c478bd9Sstevel@tonic-gate 	i = sblock.fs_bsize / sizeof (struct csum);
19807c478bd9Sstevel@tonic-gate 	sblock.fs_csmask = ~(i - 1);
19817c478bd9Sstevel@tonic-gate 	for (sblock.fs_csshift = 0; i > 1; i >>= 1)
19827c478bd9Sstevel@tonic-gate 		sblock.fs_csshift++;
19837c478bd9Sstevel@tonic-gate 	fscs = (struct csum *)calloc(1, sblock.fs_cssize);
19847c478bd9Sstevel@tonic-gate 
19857c478bd9Sstevel@tonic-gate 	checksummarysize();
19867c478bd9Sstevel@tonic-gate 	if (mtb == 'y') {
19877c478bd9Sstevel@tonic-gate 		sblock.fs_magic = MTB_UFS_MAGIC;
19887c478bd9Sstevel@tonic-gate 		sblock.fs_version = MTB_UFS_VERSION_1;
19897c478bd9Sstevel@tonic-gate 	} else {
19907c478bd9Sstevel@tonic-gate 		sblock.fs_magic = FS_MAGIC;
19916451fdbcSvsakar 		if (use_efi_dflts)
19926451fdbcSvsakar 			sblock.fs_version = UFS_EFISTYLE4NONEFI_VERSION_2;
19936451fdbcSvsakar 		else
19946451fdbcSvsakar 			sblock.fs_version = UFS_VERSION_MIN;
19957c478bd9Sstevel@tonic-gate 	}
19967c478bd9Sstevel@tonic-gate 
19977c478bd9Sstevel@tonic-gate 	if (grow) {
19987c478bd9Sstevel@tonic-gate 		bcopy((caddr_t)grow_fscs, (caddr_t)fscs, (int)grow_fs_cssize);
19997c478bd9Sstevel@tonic-gate 		extendsummaryinfo();
20007c478bd9Sstevel@tonic-gate 		goto grow40;
20017c478bd9Sstevel@tonic-gate 	}
20027c478bd9Sstevel@tonic-gate 	sblock.fs_rotdelay = rotdelay;
20037c478bd9Sstevel@tonic-gate 	sblock.fs_maxcontig = maxcontig;
20047c478bd9Sstevel@tonic-gate 	sblock.fs_maxbpg = MAXBLKPG(sblock.fs_bsize);
20057c478bd9Sstevel@tonic-gate 
20067c478bd9Sstevel@tonic-gate 	sblock.fs_rps = rps;
20077c478bd9Sstevel@tonic-gate 	sblock.fs_cgrotor = 0;
20087c478bd9Sstevel@tonic-gate 	sblock.fs_cstotal.cs_ndir = 0;
20097c478bd9Sstevel@tonic-gate 	sblock.fs_cstotal.cs_nbfree = 0;
20107c478bd9Sstevel@tonic-gate 	sblock.fs_cstotal.cs_nifree = 0;
20117c478bd9Sstevel@tonic-gate 	sblock.fs_cstotal.cs_nffree = 0;
20127c478bd9Sstevel@tonic-gate 	sblock.fs_fmod = 0;
20137c478bd9Sstevel@tonic-gate 	sblock.fs_ronly = 0;
20147c478bd9Sstevel@tonic-gate 	sblock.fs_time = mkfstime;
20157c478bd9Sstevel@tonic-gate 	sblock.fs_state = FSOKAY - sblock.fs_time;
20167c478bd9Sstevel@tonic-gate 	sblock.fs_clean = FSCLEAN;
20177c478bd9Sstevel@tonic-gate grow40:
20187c478bd9Sstevel@tonic-gate 
2019355d6bb5Sswilcox 	/*
2020355d6bb5Sswilcox 	 * If all that's needed is a dump of the superblock we
2021355d6bb5Sswilcox 	 * would use by default, we've got it now.  So, splat it
2022355d6bb5Sswilcox 	 * out and leave.
2023355d6bb5Sswilcox 	 */
2024355d6bb5Sswilcox 	if (rflag) {
2025355d6bb5Sswilcox 		dump_sblock();
2026355d6bb5Sswilcox 		lockexit(0);
2027355d6bb5Sswilcox 	}
20287c478bd9Sstevel@tonic-gate 	/*
20297c478bd9Sstevel@tonic-gate 	 * Dump out summary information about file system.
20307c478bd9Sstevel@tonic-gate 	 */
20317c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
20327c478bd9Sstevel@tonic-gate 	    "%s:\t%lld sectors in %d cylinders of %d tracks, %d sectors\n"),
20337c478bd9Sstevel@tonic-gate 	    fsys, (uint64_t)sblock.fs_size * NSPF(&sblock), sblock.fs_ncyl,
20347c478bd9Sstevel@tonic-gate 	    sblock.fs_ntrak, sblock.fs_nsect);
20357c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
20367c478bd9Sstevel@tonic-gate 	    "\t%.1fMB in %d cyl groups (%d c/g, %.2fMB/g, %d i/g)\n"),
20377c478bd9Sstevel@tonic-gate 	    (float)sblock.fs_size * sblock.fs_fsize / MB, sblock.fs_ncg,
20387c478bd9Sstevel@tonic-gate 	    sblock.fs_cpg, (float)sblock.fs_fpg * sblock.fs_fsize / MB,
20397c478bd9Sstevel@tonic-gate 	    sblock.fs_ipg);
20406451fdbcSvsakar 
20416451fdbcSvsakar 	tmpbuf = calloc(sblock.fs_ncg / 50 + 500, 1);
20426451fdbcSvsakar 	if (tmpbuf == NULL) {
20436451fdbcSvsakar 		perror("calloc");
20446451fdbcSvsakar 		lockexit(32);
20456451fdbcSvsakar 	}
2046*6d24e334Svsakar 	if (cg_too_small) {
2047*6d24e334Svsakar 		(void) fprintf(stderr, gettext("File system creation failed. "
2048*6d24e334Svsakar 			"There is only one cylinder group and\nthat is "
2049*6d24e334Svsakar 			"not even big enough to hold the inodes.\n"));
2050*6d24e334Svsakar 		lockexit(32);
2051*6d24e334Svsakar 	}
20527c478bd9Sstevel@tonic-gate 	/*
20537c478bd9Sstevel@tonic-gate 	 * Now build the cylinders group blocks and
20547c478bd9Sstevel@tonic-gate 	 * then print out indices of cylinder groups.
20557c478bd9Sstevel@tonic-gate 	 */
20566451fdbcSvsakar 	tprintf(gettext(
20577c478bd9Sstevel@tonic-gate 	    "super-block backups (for fsck -F ufs -o b=#) at:\n"));
20587c478bd9Sstevel@tonic-gate 	for (width = cylno = 0; cylno < sblock.fs_ncg && cylno < 10; cylno++) {
20597c478bd9Sstevel@tonic-gate 		if ((grow == 0) || (cylno >= grow_fs_ncg))
20607c478bd9Sstevel@tonic-gate 			initcg(cylno);
20617c478bd9Sstevel@tonic-gate 		num = fsbtodb(&sblock, (uint64_t)cgsblock(&sblock, cylno));
20626451fdbcSvsakar 		/*
20636451fdbcSvsakar 		 * If Nflag and if the disk is larger than the CHSLIMIT,
20646451fdbcSvsakar 		 * then sanity test the superblocks before reporting. If there
2065*6d24e334Svsakar 		 * are too many superblocks which look insane, we have
2066*6d24e334Svsakar 		 * to retry with alternate logic. If both methods have
2067*6d24e334Svsakar 		 * failed, then our efforts to arrive at alternate
20686451fdbcSvsakar 		 * superblocks failed, so complain and exit.
20696451fdbcSvsakar 		 */
20706451fdbcSvsakar 		if (Nflag && retry) {
20716451fdbcSvsakar 		    skip_this_sb = 0;
20726451fdbcSvsakar 		    rdfs((diskaddr_t)num, sbsize, (char *)&altsblock);
20736451fdbcSvsakar 		    ret = checksblock(altsblock, 1);
20746451fdbcSvsakar 		    if (ret) {
20756451fdbcSvsakar 			skip_this_sb = 1;
20766451fdbcSvsakar 			invalid_sb_cnt++;
20776451fdbcSvsakar 			dprintf(("DeBuG checksblock() failed - error : %d"
20786451fdbcSvsakar 			    " for sb : %llu invalid_sb_cnt : %d\n",
20796451fdbcSvsakar 			    ret, num, invalid_sb_cnt));
20806451fdbcSvsakar 		    } else {
20816451fdbcSvsakar 			/*
20826451fdbcSvsakar 			 * Though the superblock looks sane, verify if the
20836451fdbcSvsakar 			 * fs_version in the superblock and the logic that
20846451fdbcSvsakar 			 * we are using to arrive at the superblocks match.
20856451fdbcSvsakar 			 */
20866451fdbcSvsakar 			if (use_efi_dflts && altsblock.fs_version
20876451fdbcSvsakar 			    != UFS_EFISTYLE4NONEFI_VERSION_2) {
20886451fdbcSvsakar 				skip_this_sb = 1;
20896451fdbcSvsakar 				invalid_sb_cnt++;
20906451fdbcSvsakar 			}
20916451fdbcSvsakar 		    }
20926451fdbcSvsakar 		    if (invalid_sb_cnt >= INVALIDSBLIMIT) {
20936451fdbcSvsakar 			if (retry > 1) {
20946451fdbcSvsakar 			    (void) fprintf(stderr, gettext(
20956451fdbcSvsakar 				"Error determining alternate "
20966451fdbcSvsakar 				"superblock locations\n"));
20976451fdbcSvsakar 			    free(tmpbuf);
20986451fdbcSvsakar 			    lockexit(32);
20996451fdbcSvsakar 			}
21006451fdbcSvsakar 			retry++;
21016451fdbcSvsakar 			use_efi_dflts = !use_efi_dflts;
21026451fdbcSvsakar 			free(tmpbuf);
21036451fdbcSvsakar 			goto retry_alternate_logic;
21046451fdbcSvsakar 		    }
21056451fdbcSvsakar 		    if (skip_this_sb)
21066451fdbcSvsakar 			continue;
21076451fdbcSvsakar 		}
21087c478bd9Sstevel@tonic-gate 		(void) sprintf(pbuf, " %llu,", num);
21097c478bd9Sstevel@tonic-gate 		plen = strlen(pbuf);
21107c478bd9Sstevel@tonic-gate 		if ((width + plen) > (WIDTH - 1)) {
21117c478bd9Sstevel@tonic-gate 			width = plen;
21126451fdbcSvsakar 			tprintf("\n");
21137c478bd9Sstevel@tonic-gate 		} else {
21147c478bd9Sstevel@tonic-gate 			width += plen;
21157c478bd9Sstevel@tonic-gate 		}
21166451fdbcSvsakar 		if (Nflag && retry)
2117*6d24e334Svsakar 			(void) strncat(tmpbuf, pbuf, strlen(pbuf));
21186451fdbcSvsakar 		else
21196451fdbcSvsakar 			(void) fprintf(stderr, "%s", pbuf);
21207c478bd9Sstevel@tonic-gate 	}
21216451fdbcSvsakar 	tprintf("\n");
21227c478bd9Sstevel@tonic-gate 
21237c478bd9Sstevel@tonic-gate 	remaining_cg = sblock.fs_ncg - cylno;
21247c478bd9Sstevel@tonic-gate 
21257c478bd9Sstevel@tonic-gate 	/*
21267c478bd9Sstevel@tonic-gate 	 * If there are more than 300 cylinder groups still to be
21277c478bd9Sstevel@tonic-gate 	 * initialized, print a "." for every 50 cylinder groups.
21287c478bd9Sstevel@tonic-gate 	 */
21297c478bd9Sstevel@tonic-gate 	if (remaining_cg > 300) {
21306451fdbcSvsakar 		tprintf(gettext("Initializing cylinder groups:\n"));
21317c478bd9Sstevel@tonic-gate 		do_dot = 1;
21327c478bd9Sstevel@tonic-gate 	}
21337c478bd9Sstevel@tonic-gate 
21347c478bd9Sstevel@tonic-gate 	/*
21357c478bd9Sstevel@tonic-gate 	 * Now initialize all cylinder groups between the first ten
21367c478bd9Sstevel@tonic-gate 	 * and the last ten.
21377c478bd9Sstevel@tonic-gate 	 *
21387c478bd9Sstevel@tonic-gate 	 * If the number of cylinder groups was less than 10, all of the
21397c478bd9Sstevel@tonic-gate 	 * cylinder group offsets would have printed in the last loop
21407c478bd9Sstevel@tonic-gate 	 * and cylno will already be equal to sblock.fs_ncg and so this
21417c478bd9Sstevel@tonic-gate 	 * loop will not be entered.  If there are less than 20 cylinder
21427c478bd9Sstevel@tonic-gate 	 * groups, cylno is already less than fs_ncg - 10, so this loop
21437c478bd9Sstevel@tonic-gate 	 * won't be entered in that case either.
21447c478bd9Sstevel@tonic-gate 	 */
21457c478bd9Sstevel@tonic-gate 
21467c478bd9Sstevel@tonic-gate 	i = 0;
21477c478bd9Sstevel@tonic-gate 	for (; cylno < sblock.fs_ncg - 10; cylno++) {
21487c478bd9Sstevel@tonic-gate 		if ((grow == 0) || (cylno >= grow_fs_ncg))
21497c478bd9Sstevel@tonic-gate 			initcg(cylno);
21507c478bd9Sstevel@tonic-gate 		if (do_dot && cylno % 50 == 0) {
21516451fdbcSvsakar 			tprintf(".");
21527c478bd9Sstevel@tonic-gate 			i++;
21537c478bd9Sstevel@tonic-gate 			if (i == WIDTH - 1) {
21546451fdbcSvsakar 				tprintf("\n");
21557c478bd9Sstevel@tonic-gate 				i = 0;
21567c478bd9Sstevel@tonic-gate 			}
21577c478bd9Sstevel@tonic-gate 		}
21587c478bd9Sstevel@tonic-gate 	}
21597c478bd9Sstevel@tonic-gate 
21607c478bd9Sstevel@tonic-gate 	/*
21617c478bd9Sstevel@tonic-gate 	 * Now print the cylinder group offsets for the last 10
21627c478bd9Sstevel@tonic-gate 	 * cylinder groups, if any are left.
21637c478bd9Sstevel@tonic-gate 	 */
21647c478bd9Sstevel@tonic-gate 
21657c478bd9Sstevel@tonic-gate 	if (do_dot) {
21666451fdbcSvsakar 		tprintf(gettext(
21677c478bd9Sstevel@tonic-gate 	    "\nsuper-block backups for last 10 cylinder groups at:\n"));
21687c478bd9Sstevel@tonic-gate 	}
21697c478bd9Sstevel@tonic-gate 	for (width = 0; cylno < sblock.fs_ncg; cylno++) {
21707c478bd9Sstevel@tonic-gate 		if ((grow == 0) || (cylno >= grow_fs_ncg))
21717c478bd9Sstevel@tonic-gate 			initcg(cylno);
21727c478bd9Sstevel@tonic-gate 		num = fsbtodb(&sblock, (uint64_t)cgsblock(&sblock, cylno));
21736451fdbcSvsakar 		if (Nflag && retry) {
21746451fdbcSvsakar 		    skip_this_sb = 0;
21756451fdbcSvsakar 		    rdfs((diskaddr_t)num, sbsize, (char *)&altsblock);
21766451fdbcSvsakar 		    ret = checksblock(altsblock, 1);
21776451fdbcSvsakar 		    if (ret) {
21786451fdbcSvsakar 			skip_this_sb = 1;
21796451fdbcSvsakar 			invalid_sb_cnt++;
21806451fdbcSvsakar 			dprintf(("DeBuG checksblock() failed - error : %d"
21816451fdbcSvsakar 			    " for sb : %llu invalid_sb_cnt : %d\n",
21826451fdbcSvsakar 			    ret, num, invalid_sb_cnt));
21836451fdbcSvsakar 		    } else {
21846451fdbcSvsakar 			/*
21856451fdbcSvsakar 			 * Though the superblock looks sane, verify if the
21866451fdbcSvsakar 			 * fs_version in the superblock and the logic that
21876451fdbcSvsakar 			 * we are using to arrive at the superblocks match.
21886451fdbcSvsakar 			 */
21896451fdbcSvsakar 			if (use_efi_dflts && altsblock.fs_version
21906451fdbcSvsakar 			    != UFS_EFISTYLE4NONEFI_VERSION_2) {
21916451fdbcSvsakar 				skip_this_sb = 1;
21926451fdbcSvsakar 				invalid_sb_cnt++;
21936451fdbcSvsakar 			}
21946451fdbcSvsakar 		    }
21956451fdbcSvsakar 		    if (invalid_sb_cnt >= INVALIDSBLIMIT) {
21966451fdbcSvsakar 			if (retry > 1) {
21976451fdbcSvsakar 			    (void) fprintf(stderr, gettext(
21986451fdbcSvsakar 				"Error determining alternate "
21996451fdbcSvsakar 				"superblock locations\n"));
22006451fdbcSvsakar 			    free(tmpbuf);
22016451fdbcSvsakar 			    lockexit(32);
22026451fdbcSvsakar 			}
22036451fdbcSvsakar 			retry++;
22046451fdbcSvsakar 			use_efi_dflts = !use_efi_dflts;
22056451fdbcSvsakar 			free(tmpbuf);
22066451fdbcSvsakar 			goto retry_alternate_logic;
22076451fdbcSvsakar 		    }
22086451fdbcSvsakar 		    if (skip_this_sb)
22096451fdbcSvsakar 			continue;
22106451fdbcSvsakar 		}
22116451fdbcSvsakar 		/* Don't print ',' for the last superblock */
22126451fdbcSvsakar 		if (cylno == sblock.fs_ncg-1)
22136451fdbcSvsakar 			(void) sprintf(pbuf, " %llu", num);
22146451fdbcSvsakar 		else
22156451fdbcSvsakar 			(void) sprintf(pbuf, " %llu,", num);
22167c478bd9Sstevel@tonic-gate 		plen = strlen(pbuf);
22177c478bd9Sstevel@tonic-gate 		if ((width + plen) > (WIDTH - 1)) {
22187c478bd9Sstevel@tonic-gate 			width = plen;
22196451fdbcSvsakar 			tprintf("\n");
22207c478bd9Sstevel@tonic-gate 		} else {
22217c478bd9Sstevel@tonic-gate 			width += plen;
22227c478bd9Sstevel@tonic-gate 		}
22236451fdbcSvsakar 		if (Nflag && retry)
2224*6d24e334Svsakar 			(void) strncat(tmpbuf, pbuf, strlen(pbuf));
22256451fdbcSvsakar 		else
22266451fdbcSvsakar 			(void) fprintf(stderr, "%s", pbuf);
22277c478bd9Sstevel@tonic-gate 	}
22286451fdbcSvsakar 	tprintf("\n");
22296451fdbcSvsakar 	if (Nflag) {
22306451fdbcSvsakar 		if (retry)
2231*6d24e334Svsakar 			(void) fprintf(stderr, "%s", tmpbuf);
22326451fdbcSvsakar 		free(tmpbuf);
22337c478bd9Sstevel@tonic-gate 		lockexit(0);
22346451fdbcSvsakar 	}
22356451fdbcSvsakar 
22366451fdbcSvsakar 	free(tmpbuf);
22377c478bd9Sstevel@tonic-gate 	if (grow)
22387c478bd9Sstevel@tonic-gate 		goto grow50;
22397c478bd9Sstevel@tonic-gate 
22407c478bd9Sstevel@tonic-gate 	/*
22417c478bd9Sstevel@tonic-gate 	 * Now construct the initial file system,
22427c478bd9Sstevel@tonic-gate 	 * then write out the super-block.
22437c478bd9Sstevel@tonic-gate 	 */
22447c478bd9Sstevel@tonic-gate 	fsinit();
22457c478bd9Sstevel@tonic-gate grow50:
22467c478bd9Sstevel@tonic-gate 	/*
22477c478bd9Sstevel@tonic-gate 	 * write the superblock and csum information
22487c478bd9Sstevel@tonic-gate 	 */
22497c478bd9Sstevel@tonic-gate 	wtsb();
22507c478bd9Sstevel@tonic-gate 
22517c478bd9Sstevel@tonic-gate 	/*
22527c478bd9Sstevel@tonic-gate 	 * extend the last cylinder group in the original file system
22537c478bd9Sstevel@tonic-gate 	 */
22547c478bd9Sstevel@tonic-gate 	if (grow) {
22557c478bd9Sstevel@tonic-gate 		extendcg(grow_fs_ncg-1);
22567c478bd9Sstevel@tonic-gate 		wtsb();
22577c478bd9Sstevel@tonic-gate 	}
22587c478bd9Sstevel@tonic-gate 
22597c478bd9Sstevel@tonic-gate 	/*
22607c478bd9Sstevel@tonic-gate 	 * Write out the duplicate super blocks to the first 10
22617c478bd9Sstevel@tonic-gate 	 * cylinder groups (or fewer, if there are fewer than 10
22627c478bd9Sstevel@tonic-gate 	 * cylinder groups).
22637c478bd9Sstevel@tonic-gate 	 */
22647c478bd9Sstevel@tonic-gate 	for (cylno = 0; cylno < sblock.fs_ncg && cylno < 10; cylno++)
22657c478bd9Sstevel@tonic-gate 		awtfs(fsbtodb(&sblock, (uint64_t)cgsblock(&sblock, cylno)),
22667c478bd9Sstevel@tonic-gate 		    (int)sbsize, (char *)&sblock, SAVE);
22677c478bd9Sstevel@tonic-gate 
22687c478bd9Sstevel@tonic-gate 	/*
22697c478bd9Sstevel@tonic-gate 	 * Now write out duplicate super blocks to the remaining
22707c478bd9Sstevel@tonic-gate 	 * cylinder groups.  In the case of multi-terabyte file
22717c478bd9Sstevel@tonic-gate 	 * systems, just write out the super block to the last ten
22727c478bd9Sstevel@tonic-gate 	 * cylinder groups (or however many are left).
22737c478bd9Sstevel@tonic-gate 	 */
22747c478bd9Sstevel@tonic-gate 	if (mtb == 'y') {
22757c478bd9Sstevel@tonic-gate 		if (sblock.fs_ncg <= 10)
22767c478bd9Sstevel@tonic-gate 			cylno = sblock.fs_ncg;
22777c478bd9Sstevel@tonic-gate 		else if (sblock.fs_ncg <= 20)
22787c478bd9Sstevel@tonic-gate 			cylno = 10;
22797c478bd9Sstevel@tonic-gate 		else
22807c478bd9Sstevel@tonic-gate 			cylno = sblock.fs_ncg - 10;
22817c478bd9Sstevel@tonic-gate 	}
22827c478bd9Sstevel@tonic-gate 
22837c478bd9Sstevel@tonic-gate 	for (; cylno < sblock.fs_ncg; cylno++)
22847c478bd9Sstevel@tonic-gate 		awtfs(fsbtodb(&sblock, (uint64_t)cgsblock(&sblock, cylno)),
22857c478bd9Sstevel@tonic-gate 		    (int)sbsize, (char *)&sblock, SAVE);
22867c478bd9Sstevel@tonic-gate 
22877c478bd9Sstevel@tonic-gate 	/*
22887c478bd9Sstevel@tonic-gate 	 * Flush out all the AIO writes we've done.  It's not
22897c478bd9Sstevel@tonic-gate 	 * necessary to do this explicitly, but it's the only
22907c478bd9Sstevel@tonic-gate 	 * way to report any errors from those writes.
22917c478bd9Sstevel@tonic-gate 	 */
22927c478bd9Sstevel@tonic-gate 	flush_writes();
22937c478bd9Sstevel@tonic-gate 
22947c478bd9Sstevel@tonic-gate 	/*
22957c478bd9Sstevel@tonic-gate 	 * set clean flag
22967c478bd9Sstevel@tonic-gate 	 */
22977c478bd9Sstevel@tonic-gate 	if (grow)
22987c478bd9Sstevel@tonic-gate 		sblock.fs_clean = grow_fs_clean;
22997c478bd9Sstevel@tonic-gate 	else
23007c478bd9Sstevel@tonic-gate 		sblock.fs_clean = FSCLEAN;
23017c478bd9Sstevel@tonic-gate 	sblock.fs_time = mkfstime;
23027c478bd9Sstevel@tonic-gate 	sblock.fs_state = FSOKAY - sblock.fs_time;
23037c478bd9Sstevel@tonic-gate 	wtfs((diskaddr_t)(SBOFF / sectorsize), sbsize, (char *)&sblock);
23047c478bd9Sstevel@tonic-gate 	isbad = 0;
23057c478bd9Sstevel@tonic-gate 
23067c478bd9Sstevel@tonic-gate 	if (fsync(fso) == -1) {
23077c478bd9Sstevel@tonic-gate 		saverr = errno;
23087c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
23097c478bd9Sstevel@tonic-gate 		    gettext("mkfs: fsync failed on write disk: %s\n"),
23107c478bd9Sstevel@tonic-gate 		    strerror(saverr));
23117c478bd9Sstevel@tonic-gate 		/* we're just cleaning up, so keep going */
23127c478bd9Sstevel@tonic-gate 	}
23137c478bd9Sstevel@tonic-gate 	if (close(fsi) == -1) {
23147c478bd9Sstevel@tonic-gate 		saverr = errno;
23157c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
23167c478bd9Sstevel@tonic-gate 		    gettext("mkfs: close failed on read disk: %s\n"),
23177c478bd9Sstevel@tonic-gate 		    strerror(saverr));
23187c478bd9Sstevel@tonic-gate 		/* we're just cleaning up, so keep going */
23197c478bd9Sstevel@tonic-gate 	}
23207c478bd9Sstevel@tonic-gate 	if (close(fso) == -1) {
23217c478bd9Sstevel@tonic-gate 		saverr = errno;
23227c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
23237c478bd9Sstevel@tonic-gate 		    gettext("mkfs: close failed on write disk: %s\n"),
23247c478bd9Sstevel@tonic-gate 		    strerror(saverr));
23257c478bd9Sstevel@tonic-gate 		/* we're just cleaning up, so keep going */
23267c478bd9Sstevel@tonic-gate 	}
23277c478bd9Sstevel@tonic-gate 	fsi = fso = -1;
2328029b4de8Sswilcox 
23297c478bd9Sstevel@tonic-gate #ifndef STANDALONE
23307c478bd9Sstevel@tonic-gate 	lockexit(0);
23317c478bd9Sstevel@tonic-gate #endif
2332029b4de8Sswilcox 
2333029b4de8Sswilcox 	return (0);
23347c478bd9Sstevel@tonic-gate }
23357c478bd9Sstevel@tonic-gate 
23367c478bd9Sstevel@tonic-gate /*
23377c478bd9Sstevel@tonic-gate  * Figure out how big the partition we're dealing with is.
23387c478bd9Sstevel@tonic-gate  * The value returned is in disk blocks (sectors);
23397c478bd9Sstevel@tonic-gate  */
23407c478bd9Sstevel@tonic-gate static diskaddr_t
23417c478bd9Sstevel@tonic-gate get_max_size(int fd)
23427c478bd9Sstevel@tonic-gate {
23437c478bd9Sstevel@tonic-gate 	struct vtoc vtoc;
23447c478bd9Sstevel@tonic-gate 	dk_gpt_t *efi_vtoc;
23457c478bd9Sstevel@tonic-gate 	diskaddr_t	slicesize;
23467c478bd9Sstevel@tonic-gate 
23477c478bd9Sstevel@tonic-gate 	int index = read_vtoc(fd, &vtoc);
23487c478bd9Sstevel@tonic-gate 
23496451fdbcSvsakar 	if (index >= 0) {
23506451fdbcSvsakar 		label_type = LABEL_TYPE_VTOC;
23516451fdbcSvsakar 	} else {
23527c478bd9Sstevel@tonic-gate 		if (index == VT_ENOTSUP || index == VT_ERROR) {
23537c478bd9Sstevel@tonic-gate 			/* it might be an EFI label */
23547c478bd9Sstevel@tonic-gate 			index = efi_alloc_and_read(fd, &efi_vtoc);
23556451fdbcSvsakar 			label_type = LABEL_TYPE_EFI;
23567c478bd9Sstevel@tonic-gate 		}
23577c478bd9Sstevel@tonic-gate 	}
23587c478bd9Sstevel@tonic-gate 
23597c478bd9Sstevel@tonic-gate 	if (index < 0) {
23607c478bd9Sstevel@tonic-gate 		switch (index) {
23617c478bd9Sstevel@tonic-gate 		case VT_ERROR:
23627c478bd9Sstevel@tonic-gate 			break;
23637c478bd9Sstevel@tonic-gate 		case VT_EIO:
23647c478bd9Sstevel@tonic-gate 			errno = EIO;
23657c478bd9Sstevel@tonic-gate 			break;
23667c478bd9Sstevel@tonic-gate 		case VT_EINVAL:
23677c478bd9Sstevel@tonic-gate 			errno = EINVAL;
23687c478bd9Sstevel@tonic-gate 		}
23697c478bd9Sstevel@tonic-gate 		perror(gettext("Can not determine partition size"));
23707c478bd9Sstevel@tonic-gate 		lockexit(32);
23717c478bd9Sstevel@tonic-gate 	}
23727c478bd9Sstevel@tonic-gate 
23736451fdbcSvsakar 	if (label_type == LABEL_TYPE_EFI) {
23747c478bd9Sstevel@tonic-gate 		slicesize = efi_vtoc->efi_parts[index].p_size;
23757c478bd9Sstevel@tonic-gate 		efi_free(efi_vtoc);
23767c478bd9Sstevel@tonic-gate 	} else {
23777c478bd9Sstevel@tonic-gate 		/*
23787c478bd9Sstevel@tonic-gate 		 * In the vtoc struct, p_size is a 32-bit signed quantity.
23797c478bd9Sstevel@tonic-gate 		 * In the dk_gpt struct (efi's version of the vtoc), p_size
23807c478bd9Sstevel@tonic-gate 		 * is an unsigned 64-bit quantity.  By casting the vtoc's
23817c478bd9Sstevel@tonic-gate 		 * psize to an unsigned 32-bit quantity, it will be copied
23827c478bd9Sstevel@tonic-gate 		 * to 'slicesize' (an unsigned 64-bit diskaddr_t) without
23837c478bd9Sstevel@tonic-gate 		 * sign extension.
23847c478bd9Sstevel@tonic-gate 		 */
23857c478bd9Sstevel@tonic-gate 
23867c478bd9Sstevel@tonic-gate 		slicesize = (uint32_t)vtoc.v_part[index].p_size;
23877c478bd9Sstevel@tonic-gate 	}
23887c478bd9Sstevel@tonic-gate 
23896451fdbcSvsakar 	dprintf(("DeBuG get_max_size index = %d, p_size = %lld, dolimit = %d\n",
23906451fdbcSvsakar 	    index, slicesize, (slicesize > FS_MAX)));
23917c478bd9Sstevel@tonic-gate 
23927c478bd9Sstevel@tonic-gate 	/*
23937c478bd9Sstevel@tonic-gate 	 * The next line limits a UFS file system to the maximum
23947c478bd9Sstevel@tonic-gate 	 * supported size.
23957c478bd9Sstevel@tonic-gate 	 */
23967c478bd9Sstevel@tonic-gate 
23977c478bd9Sstevel@tonic-gate 	if (slicesize > FS_MAX)
23987c478bd9Sstevel@tonic-gate 		return (FS_MAX);
23997c478bd9Sstevel@tonic-gate 	return (slicesize);
24007c478bd9Sstevel@tonic-gate }
24017c478bd9Sstevel@tonic-gate 
24027c478bd9Sstevel@tonic-gate static long
24037c478bd9Sstevel@tonic-gate get_max_track_size(int fd)
24047c478bd9Sstevel@tonic-gate {
24057c478bd9Sstevel@tonic-gate 	struct dk_cinfo ci;
24067c478bd9Sstevel@tonic-gate 	long track_size = -1;
24077c478bd9Sstevel@tonic-gate 
24087c478bd9Sstevel@tonic-gate 	if (ioctl(fd, DKIOCINFO, &ci) == 0) {
24097c478bd9Sstevel@tonic-gate 		track_size = ci.dki_maxtransfer * DEV_BSIZE;
24107c478bd9Sstevel@tonic-gate 	}
24117c478bd9Sstevel@tonic-gate 
24127c478bd9Sstevel@tonic-gate 	if ((track_size < 0)) {
24137c478bd9Sstevel@tonic-gate 		int	error = 0;
24147c478bd9Sstevel@tonic-gate 		int	maxphys;
24157c478bd9Sstevel@tonic-gate 		int	gotit = 0;
24167c478bd9Sstevel@tonic-gate 
24177c478bd9Sstevel@tonic-gate 		gotit = fsgetmaxphys(&maxphys, &error);
24187c478bd9Sstevel@tonic-gate 		if (gotit) {
24197c478bd9Sstevel@tonic-gate 			track_size = MIN(MB, maxphys);
24207c478bd9Sstevel@tonic-gate 		} else {
24217c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
24227c478bd9Sstevel@tonic-gate "Warning: Could not get system value for maxphys. The value for\n"
24237c478bd9Sstevel@tonic-gate "maxcontig will default to 1MB.\n"));
24247c478bd9Sstevel@tonic-gate 			track_size = MB;
24257c478bd9Sstevel@tonic-gate 		}
24267c478bd9Sstevel@tonic-gate 	}
24277c478bd9Sstevel@tonic-gate 	return (track_size);
24287c478bd9Sstevel@tonic-gate }
24297c478bd9Sstevel@tonic-gate 
24307c478bd9Sstevel@tonic-gate /*
24317c478bd9Sstevel@tonic-gate  * Initialize a cylinder group.
24327c478bd9Sstevel@tonic-gate  */
24337c478bd9Sstevel@tonic-gate static void
24347c478bd9Sstevel@tonic-gate initcg(int cylno)
24357c478bd9Sstevel@tonic-gate {
24367c478bd9Sstevel@tonic-gate 	diskaddr_t cbase, d;
24377c478bd9Sstevel@tonic-gate 	diskaddr_t dlower;	/* last data block before cg metadata */
24387c478bd9Sstevel@tonic-gate 	diskaddr_t dupper;	/* first data block after cg metadata */
24397c478bd9Sstevel@tonic-gate 	diskaddr_t dmax;
24407c478bd9Sstevel@tonic-gate 	int64_t i;
24417c478bd9Sstevel@tonic-gate 	struct csum *cs;
24427c478bd9Sstevel@tonic-gate 	struct dinode *inode_buffer;
24437c478bd9Sstevel@tonic-gate 	int size;
24447c478bd9Sstevel@tonic-gate 
24457c478bd9Sstevel@tonic-gate 	/*
24467c478bd9Sstevel@tonic-gate 	 * Variables used to store intermediate results as a part of
24477c478bd9Sstevel@tonic-gate 	 * the internal implementation of the cbtocylno() macros.
24487c478bd9Sstevel@tonic-gate 	 */
24497c478bd9Sstevel@tonic-gate 	diskaddr_t bno;		/* UFS block number (not sector number) */
24507c478bd9Sstevel@tonic-gate 	int	cbcylno;	/* current cylinder number */
24517c478bd9Sstevel@tonic-gate 	int	cbcylno_sect;	/* sector offset within cylinder */
24527c478bd9Sstevel@tonic-gate 	int	cbsect_incr;	/* amount to increment sector offset */
24537c478bd9Sstevel@tonic-gate 
24547c478bd9Sstevel@tonic-gate 	/*
24557c478bd9Sstevel@tonic-gate 	 * Variables used to store intermediate results as a part of
24567c478bd9Sstevel@tonic-gate 	 * the internal implementation of the cbtorpos() macros.
24577c478bd9Sstevel@tonic-gate 	 */
24587c478bd9Sstevel@tonic-gate 	short	*cgblks;	/* pointer to array of free blocks in cg */
24597c478bd9Sstevel@tonic-gate 	int	trackrpos;	/* tmp variable for rotation position */
24607c478bd9Sstevel@tonic-gate 	int	trackoff;	/* offset within a track */
24617c478bd9Sstevel@tonic-gate 	int	trackoff_incr;	/* amount to increment trackoff */
24627c478bd9Sstevel@tonic-gate 	int	rpos;		/* rotation position of current block */
24637c478bd9Sstevel@tonic-gate 	int	rpos_incr;	/* amount to increment rpos per block */
24647c478bd9Sstevel@tonic-gate 
24657c478bd9Sstevel@tonic-gate 	union cgun *icgun;	/* local pointer to a cg summary block */
24667c478bd9Sstevel@tonic-gate #define	icg	(icgun->cg)
24677c478bd9Sstevel@tonic-gate 
24687c478bd9Sstevel@tonic-gate 	icgun = (union cgun *)getbuf(&cgsumbuf, sizeof (union cgun));
24697c478bd9Sstevel@tonic-gate 
24707c478bd9Sstevel@tonic-gate 	/*
24717c478bd9Sstevel@tonic-gate 	 * Determine block bounds for cylinder group.
24727c478bd9Sstevel@tonic-gate 	 * Allow space for super block summary information in first
24737c478bd9Sstevel@tonic-gate 	 * cylinder group.
24747c478bd9Sstevel@tonic-gate 	 */
24757c478bd9Sstevel@tonic-gate 	cbase = cgbase(&sblock, cylno);
24767c478bd9Sstevel@tonic-gate 	dmax = cbase + sblock.fs_fpg;
24777c478bd9Sstevel@tonic-gate 	if (dmax > sblock.fs_size)	/* last cg may be smaller than normal */
24787c478bd9Sstevel@tonic-gate 		dmax = sblock.fs_size;
24797c478bd9Sstevel@tonic-gate 	dlower = cgsblock(&sblock, cylno) - cbase;
24807c478bd9Sstevel@tonic-gate 	dupper = cgdmin(&sblock, cylno) - cbase;
24817c478bd9Sstevel@tonic-gate 	if (cylno == 0)
24827c478bd9Sstevel@tonic-gate 		dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
24837c478bd9Sstevel@tonic-gate 	cs = fscs + cylno;
24847c478bd9Sstevel@tonic-gate 	icg.cg_time = mkfstime;
24857c478bd9Sstevel@tonic-gate 	icg.cg_magic = CG_MAGIC;
24867c478bd9Sstevel@tonic-gate 	icg.cg_cgx = cylno;
2487355d6bb5Sswilcox 	/* last one gets whatever's left */
24887c478bd9Sstevel@tonic-gate 	if (cylno == sblock.fs_ncg - 1)
2489355d6bb5Sswilcox 		icg.cg_ncyl = sblock.fs_ncyl - (sblock.fs_cpg * cylno);
24907c478bd9Sstevel@tonic-gate 	else
24917c478bd9Sstevel@tonic-gate 		icg.cg_ncyl = sblock.fs_cpg;
24927c478bd9Sstevel@tonic-gate 	icg.cg_niblk = sblock.fs_ipg;
24937c478bd9Sstevel@tonic-gate 	icg.cg_ndblk = dmax - cbase;
24947c478bd9Sstevel@tonic-gate 	icg.cg_cs.cs_ndir = 0;
24957c478bd9Sstevel@tonic-gate 	icg.cg_cs.cs_nffree = 0;
24967c478bd9Sstevel@tonic-gate 	icg.cg_cs.cs_nbfree = 0;
24977c478bd9Sstevel@tonic-gate 	icg.cg_cs.cs_nifree = 0;
24987c478bd9Sstevel@tonic-gate 	icg.cg_rotor = 0;
24997c478bd9Sstevel@tonic-gate 	icg.cg_frotor = 0;
25007c478bd9Sstevel@tonic-gate 	icg.cg_irotor = 0;
25017c478bd9Sstevel@tonic-gate 	icg.cg_btotoff = &icg.cg_space[0] - (uchar_t *)(&icg.cg_link);
25027c478bd9Sstevel@tonic-gate 	icg.cg_boff = icg.cg_btotoff + sblock.fs_cpg * sizeof (long);
25037c478bd9Sstevel@tonic-gate 	icg.cg_iusedoff = icg.cg_boff +
25047c478bd9Sstevel@tonic-gate 		sblock.fs_cpg * sblock.fs_nrpos * sizeof (short);
25057c478bd9Sstevel@tonic-gate 	icg.cg_freeoff = icg.cg_iusedoff + howmany(sblock.fs_ipg, NBBY);
25067c478bd9Sstevel@tonic-gate 	icg.cg_nextfreeoff = icg.cg_freeoff +
25077c478bd9Sstevel@tonic-gate 		howmany(sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock), NBBY);
25087c478bd9Sstevel@tonic-gate 	for (i = 0; i < sblock.fs_frag; i++) {
25097c478bd9Sstevel@tonic-gate 		icg.cg_frsum[i] = 0;
25107c478bd9Sstevel@tonic-gate 	}
25117c478bd9Sstevel@tonic-gate 	bzero((caddr_t)cg_inosused(&icg), icg.cg_freeoff - icg.cg_iusedoff);
25127c478bd9Sstevel@tonic-gate 	icg.cg_cs.cs_nifree += sblock.fs_ipg;
25137c478bd9Sstevel@tonic-gate 	if (cylno == 0)
25147c478bd9Sstevel@tonic-gate 		for (i = 0; i < UFSROOTINO; i++) {
25157c478bd9Sstevel@tonic-gate 			setbit(cg_inosused(&icg), i);
25167c478bd9Sstevel@tonic-gate 			icg.cg_cs.cs_nifree--;
25177c478bd9Sstevel@tonic-gate 		}
25187c478bd9Sstevel@tonic-gate 
25197c478bd9Sstevel@tonic-gate 	/*
25207c478bd9Sstevel@tonic-gate 	 * Initialize all the inodes in the cylinder group using
25217c478bd9Sstevel@tonic-gate 	 * random numbers.
25227c478bd9Sstevel@tonic-gate 	 */
25237c478bd9Sstevel@tonic-gate 	size = sblock.fs_ipg * sizeof (struct dinode);
25247c478bd9Sstevel@tonic-gate 	inode_buffer = (struct dinode *)getbuf(&inodebuf, size);
25257c478bd9Sstevel@tonic-gate 
25267c478bd9Sstevel@tonic-gate 	for (i = 0; i < sblock.fs_ipg; i++) {
25277c478bd9Sstevel@tonic-gate 		IRANDOMIZE(&(inode_buffer[i].di_ic));
25287c478bd9Sstevel@tonic-gate 	}
25297c478bd9Sstevel@tonic-gate 
25307c478bd9Sstevel@tonic-gate 	/*
25317c478bd9Sstevel@tonic-gate 	 * Write all inodes in a single write for performance.
25327c478bd9Sstevel@tonic-gate 	 */
25337c478bd9Sstevel@tonic-gate 	awtfs(fsbtodb(&sblock, (uint64_t)cgimin(&sblock, cylno)), (int)size,
25347c478bd9Sstevel@tonic-gate 	    (char *)inode_buffer, RELEASE);
25357c478bd9Sstevel@tonic-gate 
25367c478bd9Sstevel@tonic-gate 	bzero((caddr_t)cg_blktot(&icg), icg.cg_boff - icg.cg_btotoff);
25377c478bd9Sstevel@tonic-gate 	bzero((caddr_t)cg_blks(&sblock, &icg, 0),
25387c478bd9Sstevel@tonic-gate 	    icg.cg_iusedoff - icg.cg_boff);
25397c478bd9Sstevel@tonic-gate 	bzero((caddr_t)cg_blksfree(&icg), icg.cg_nextfreeoff - icg.cg_freeoff);
25407c478bd9Sstevel@tonic-gate 
25417c478bd9Sstevel@tonic-gate 	if (cylno > 0) {
25427c478bd9Sstevel@tonic-gate 		for (d = 0; d < dlower; d += sblock.fs_frag) {
25437c478bd9Sstevel@tonic-gate 			setblock(&sblock, cg_blksfree(&icg), d/sblock.fs_frag);
25447c478bd9Sstevel@tonic-gate 			icg.cg_cs.cs_nbfree++;
25457c478bd9Sstevel@tonic-gate 			cg_blktot(&icg)[cbtocylno(&sblock, d)]++;
25467c478bd9Sstevel@tonic-gate 			cg_blks(&sblock, &icg, cbtocylno(&sblock, d))
25477c478bd9Sstevel@tonic-gate 			    [cbtorpos(&sblock, d)]++;
25487c478bd9Sstevel@tonic-gate 		}
25497c478bd9Sstevel@tonic-gate 		sblock.fs_dsize += dlower;
25507c478bd9Sstevel@tonic-gate 	}
25517c478bd9Sstevel@tonic-gate 	sblock.fs_dsize += icg.cg_ndblk - dupper;
25527c478bd9Sstevel@tonic-gate 	if ((i = dupper % sblock.fs_frag) != 0) {
25537c478bd9Sstevel@tonic-gate 		icg.cg_frsum[sblock.fs_frag - i]++;
25547c478bd9Sstevel@tonic-gate 		for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) {
25557c478bd9Sstevel@tonic-gate 			setbit(cg_blksfree(&icg), dupper);
25567c478bd9Sstevel@tonic-gate 			icg.cg_cs.cs_nffree++;
25577c478bd9Sstevel@tonic-gate 		}
25587c478bd9Sstevel@tonic-gate 	}
25597c478bd9Sstevel@tonic-gate 
25607c478bd9Sstevel@tonic-gate 	/*
25617c478bd9Sstevel@tonic-gate 	 * WARNING: The following code is somewhat confusing, but
25627c478bd9Sstevel@tonic-gate 	 * results in a substantial performance improvement in mkfs.
25637c478bd9Sstevel@tonic-gate 	 *
25647c478bd9Sstevel@tonic-gate 	 * Instead of using cbtocylno() and cbtorpos() macros, we
25657c478bd9Sstevel@tonic-gate 	 * keep track of all the intermediate state of those macros
25667c478bd9Sstevel@tonic-gate 	 * in some variables.  This allows simple addition to be
25677c478bd9Sstevel@tonic-gate 	 * done to calculate the results as we step through the
25687c478bd9Sstevel@tonic-gate 	 * blocks in an orderly fashion instead of the slower
25697c478bd9Sstevel@tonic-gate 	 * multiplication and division the macros are forced to
25707c478bd9Sstevel@tonic-gate 	 * used so they can support random input.  (Multiplication,
25717c478bd9Sstevel@tonic-gate 	 * division, and remainder operations typically take about
25727c478bd9Sstevel@tonic-gate 	 * 10x as many processor cycles as other operations.)
25737c478bd9Sstevel@tonic-gate 	 *
25747c478bd9Sstevel@tonic-gate 	 * The basic idea is to take code:
25757c478bd9Sstevel@tonic-gate 	 *
25767c478bd9Sstevel@tonic-gate 	 *	for (x = starting_x; x < max; x++)
25777c478bd9Sstevel@tonic-gate 	 *		y = (x * c) / z
25787c478bd9Sstevel@tonic-gate 	 *
25797c478bd9Sstevel@tonic-gate 	 * and rewrite it to take advantage of the fact that
25807c478bd9Sstevel@tonic-gate 	 * the variable x is incrementing in an orderly way:
25817c478bd9Sstevel@tonic-gate 	 *
25827c478bd9Sstevel@tonic-gate 	 *	intermediate = starting_x * c
25837c478bd9Sstevel@tonic-gate 	 *	yval = intermediate / z
25847c478bd9Sstevel@tonic-gate 	 *	for (x = starting_x; x < max; x++) {
25857c478bd9Sstevel@tonic-gate 	 *		y = yval;
25867c478bd9Sstevel@tonic-gate 	 *		intermediate += c
25877c478bd9Sstevel@tonic-gate 	 *		if (intermediate > z) {
25887c478bd9Sstevel@tonic-gate 	 *			yval++;
25897c478bd9Sstevel@tonic-gate 	 *			intermediate -= z
25907c478bd9Sstevel@tonic-gate 	 *		}
25917c478bd9Sstevel@tonic-gate 	 *	}
25927c478bd9Sstevel@tonic-gate 	 *
25937c478bd9Sstevel@tonic-gate 	 * Performance has improved as much as 4X using this code.
25947c478bd9Sstevel@tonic-gate 	 */
25957c478bd9Sstevel@tonic-gate 
25967c478bd9Sstevel@tonic-gate 	/*
25977c478bd9Sstevel@tonic-gate 	 * Initialize the starting points for all the cbtocylno()
25987c478bd9Sstevel@tonic-gate 	 * macro variables and figure out the increments needed each
25997c478bd9Sstevel@tonic-gate 	 * time through the loop.
26007c478bd9Sstevel@tonic-gate 	 */
26017c478bd9Sstevel@tonic-gate 	cbcylno_sect = dupper * NSPF(&sblock);
26027c478bd9Sstevel@tonic-gate 	cbsect_incr = sblock.fs_frag * NSPF(&sblock);
26037c478bd9Sstevel@tonic-gate 	cbcylno = cbcylno_sect / sblock.fs_spc;
26047c478bd9Sstevel@tonic-gate 	cbcylno_sect %= sblock.fs_spc;
26057c478bd9Sstevel@tonic-gate 	cgblks = cg_blks(&sblock, &icg, cbcylno);
26067c478bd9Sstevel@tonic-gate 	bno = dupper / sblock.fs_frag;
26077c478bd9Sstevel@tonic-gate 
26087c478bd9Sstevel@tonic-gate 	/*
26097c478bd9Sstevel@tonic-gate 	 * Initialize the starting points for all the cbtorpos()
26107c478bd9Sstevel@tonic-gate 	 * macro variables and figure out the increments needed each
26117c478bd9Sstevel@tonic-gate 	 * time through the loop.
26127c478bd9Sstevel@tonic-gate 	 *
26137c478bd9Sstevel@tonic-gate 	 * It's harder to simplify the cbtorpos() macro if there were
26147c478bd9Sstevel@tonic-gate 	 * alternate sectors specified (or if they previously existed
26157c478bd9Sstevel@tonic-gate 	 * in the growfs case).  Since this is rare, we just revert to
26167c478bd9Sstevel@tonic-gate 	 * using the macros in this case and skip the variable setup.
26177c478bd9Sstevel@tonic-gate 	 */
26187c478bd9Sstevel@tonic-gate 	if (!spc_flag) {
26197c478bd9Sstevel@tonic-gate 		trackrpos = (cbcylno_sect % sblock.fs_nsect) * sblock.fs_nrpos;
26207c478bd9Sstevel@tonic-gate 		rpos = trackrpos / sblock.fs_nsect;
26217c478bd9Sstevel@tonic-gate 		trackoff = trackrpos % sblock.fs_nsect;
26227c478bd9Sstevel@tonic-gate 		trackoff_incr = cbsect_incr * sblock.fs_nrpos;
26237c478bd9Sstevel@tonic-gate 		rpos_incr = (trackoff_incr / sblock.fs_nsect) % sblock.fs_nrpos;
26247c478bd9Sstevel@tonic-gate 		trackoff_incr = trackoff_incr % sblock.fs_nsect;
26257c478bd9Sstevel@tonic-gate 	}
26267c478bd9Sstevel@tonic-gate 
26277c478bd9Sstevel@tonic-gate 	/*
26287c478bd9Sstevel@tonic-gate 	 * Loop through all the blocks, marking them free and
26297c478bd9Sstevel@tonic-gate 	 * updating totals kept in the superblock and cg summary.
26307c478bd9Sstevel@tonic-gate 	 */
26317c478bd9Sstevel@tonic-gate 	for (d = dupper; d + sblock.fs_frag <= dmax - cbase; ) {
26327c478bd9Sstevel@tonic-gate 		setblock(&sblock, cg_blksfree(&icg),  bno);
26337c478bd9Sstevel@tonic-gate 		icg.cg_cs.cs_nbfree++;
26347c478bd9Sstevel@tonic-gate 
26357c478bd9Sstevel@tonic-gate 		cg_blktot(&icg)[cbcylno]++;
26367c478bd9Sstevel@tonic-gate 
26377c478bd9Sstevel@tonic-gate 		if (!spc_flag)
26387c478bd9Sstevel@tonic-gate 			cgblks[rpos]++;
26397c478bd9Sstevel@tonic-gate 		else
26407c478bd9Sstevel@tonic-gate 			cg_blks(&sblock, &icg, cbtocylno(&sblock, d))
26417c478bd9Sstevel@tonic-gate 			    [cbtorpos(&sblock, d)]++;
26427c478bd9Sstevel@tonic-gate 
26437c478bd9Sstevel@tonic-gate 		d += sblock.fs_frag;
26447c478bd9Sstevel@tonic-gate 		bno++;
26457c478bd9Sstevel@tonic-gate 
26467c478bd9Sstevel@tonic-gate 		/*
26477c478bd9Sstevel@tonic-gate 		 * Increment the sector offset within the cylinder
26487c478bd9Sstevel@tonic-gate 		 * for the cbtocylno() macro reimplementation.  If
26497c478bd9Sstevel@tonic-gate 		 * we're beyond the end of the cylinder, update the
26507c478bd9Sstevel@tonic-gate 		 * cylinder number, calculate the offset in the
26517c478bd9Sstevel@tonic-gate 		 * new cylinder, and update the cgblks pointer
26527c478bd9Sstevel@tonic-gate 		 * to the next rotational position.
26537c478bd9Sstevel@tonic-gate 		 */
26547c478bd9Sstevel@tonic-gate 		cbcylno_sect += cbsect_incr;
26557c478bd9Sstevel@tonic-gate 		if (cbcylno_sect >= sblock.fs_spc) {
26567c478bd9Sstevel@tonic-gate 			cbcylno++;
26577c478bd9Sstevel@tonic-gate 			cbcylno_sect -= sblock.fs_spc;
26587c478bd9Sstevel@tonic-gate 			cgblks += sblock.fs_nrpos;
26597c478bd9Sstevel@tonic-gate 		}
26607c478bd9Sstevel@tonic-gate 
26617c478bd9Sstevel@tonic-gate 		/*
26627c478bd9Sstevel@tonic-gate 		 * If there aren't alternate sectors, increment the
26637c478bd9Sstevel@tonic-gate 		 * rotational position variables for the cbtorpos()
26647c478bd9Sstevel@tonic-gate 		 * reimplementation.  Note that we potentially
26657c478bd9Sstevel@tonic-gate 		 * increment rpos twice.  Once by rpos_incr, and one
26667c478bd9Sstevel@tonic-gate 		 * more time when we wrap to a new track because
26677c478bd9Sstevel@tonic-gate 		 * trackoff >= fs_nsect.
26687c478bd9Sstevel@tonic-gate 		 */
26697c478bd9Sstevel@tonic-gate 		if (!spc_flag) {
26707c478bd9Sstevel@tonic-gate 			trackoff += trackoff_incr;
26717c478bd9Sstevel@tonic-gate 			rpos += rpos_incr;
26727c478bd9Sstevel@tonic-gate 			if (trackoff >= sblock.fs_nsect) {
26737c478bd9Sstevel@tonic-gate 				trackoff -= sblock.fs_nsect;
26747c478bd9Sstevel@tonic-gate 				rpos++;
26757c478bd9Sstevel@tonic-gate 			}
26767c478bd9Sstevel@tonic-gate 			if (rpos >= sblock.fs_nrpos)
26777c478bd9Sstevel@tonic-gate 				rpos -= sblock.fs_nrpos;
26787c478bd9Sstevel@tonic-gate 		}
26797c478bd9Sstevel@tonic-gate 	}
26807c478bd9Sstevel@tonic-gate 
26817c478bd9Sstevel@tonic-gate 	if (d < dmax - cbase) {
26827c478bd9Sstevel@tonic-gate 		icg.cg_frsum[dmax - cbase - d]++;
26837c478bd9Sstevel@tonic-gate 		for (; d < dmax - cbase; d++) {
26847c478bd9Sstevel@tonic-gate 			setbit(cg_blksfree(&icg), d);
26857c478bd9Sstevel@tonic-gate 			icg.cg_cs.cs_nffree++;
26867c478bd9Sstevel@tonic-gate 		}
26877c478bd9Sstevel@tonic-gate 	}
26887c478bd9Sstevel@tonic-gate 	sblock.fs_cstotal.cs_ndir += icg.cg_cs.cs_ndir;
26897c478bd9Sstevel@tonic-gate 	sblock.fs_cstotal.cs_nffree += icg.cg_cs.cs_nffree;
26907c478bd9Sstevel@tonic-gate 	sblock.fs_cstotal.cs_nbfree += icg.cg_cs.cs_nbfree;
26917c478bd9Sstevel@tonic-gate 	sblock.fs_cstotal.cs_nifree += icg.cg_cs.cs_nifree;
26927c478bd9Sstevel@tonic-gate 	*cs = icg.cg_cs;
26937c478bd9Sstevel@tonic-gate 	awtfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, cylno)),
26947c478bd9Sstevel@tonic-gate 		sblock.fs_bsize, (char *)&icg, RELEASE);
26957c478bd9Sstevel@tonic-gate }
26967c478bd9Sstevel@tonic-gate 
26977c478bd9Sstevel@tonic-gate /*
26987c478bd9Sstevel@tonic-gate  * initialize the file system
26997c478bd9Sstevel@tonic-gate  */
27007c478bd9Sstevel@tonic-gate struct inode node;
27017c478bd9Sstevel@tonic-gate 
27027c478bd9Sstevel@tonic-gate #define	LOSTDIR
27037c478bd9Sstevel@tonic-gate #ifdef LOSTDIR
27047c478bd9Sstevel@tonic-gate #define	PREDEFDIR 3
27057c478bd9Sstevel@tonic-gate #else
27067c478bd9Sstevel@tonic-gate #define	PREDEFDIR 2
27077c478bd9Sstevel@tonic-gate #endif
27087c478bd9Sstevel@tonic-gate 
27097c478bd9Sstevel@tonic-gate struct direct root_dir[] = {
27107c478bd9Sstevel@tonic-gate 	{ UFSROOTINO, sizeof (struct direct), 1, "." },
27117c478bd9Sstevel@tonic-gate 	{ UFSROOTINO, sizeof (struct direct), 2, ".." },
27127c478bd9Sstevel@tonic-gate #ifdef LOSTDIR
27137c478bd9Sstevel@tonic-gate 	{ LOSTFOUNDINO, sizeof (struct direct), 10, "lost+found" },
27147c478bd9Sstevel@tonic-gate #endif
27157c478bd9Sstevel@tonic-gate };
27167c478bd9Sstevel@tonic-gate #ifdef LOSTDIR
27177c478bd9Sstevel@tonic-gate struct direct lost_found_dir[] = {
27187c478bd9Sstevel@tonic-gate 	{ LOSTFOUNDINO, sizeof (struct direct), 1, "." },
27197c478bd9Sstevel@tonic-gate 	{ UFSROOTINO, sizeof (struct direct), 2, ".." },
27207c478bd9Sstevel@tonic-gate 	{ 0, DIRBLKSIZ, 0, 0 },
27217c478bd9Sstevel@tonic-gate };
27227c478bd9Sstevel@tonic-gate #endif
27237c478bd9Sstevel@tonic-gate char buf[MAXBSIZE];
27247c478bd9Sstevel@tonic-gate 
27257c478bd9Sstevel@tonic-gate static void
27267c478bd9Sstevel@tonic-gate fsinit()
27277c478bd9Sstevel@tonic-gate {
27287c478bd9Sstevel@tonic-gate 	int i;
27297c478bd9Sstevel@tonic-gate 
27307c478bd9Sstevel@tonic-gate 
27317c478bd9Sstevel@tonic-gate 	/*
27327c478bd9Sstevel@tonic-gate 	 * initialize the node
27337c478bd9Sstevel@tonic-gate 	 */
27347c478bd9Sstevel@tonic-gate 	node.i_atime = mkfstime;
27357c478bd9Sstevel@tonic-gate 	node.i_mtime = mkfstime;
27367c478bd9Sstevel@tonic-gate 	node.i_ctime = mkfstime;
27377c478bd9Sstevel@tonic-gate #ifdef LOSTDIR
27387c478bd9Sstevel@tonic-gate 	/*
27397c478bd9Sstevel@tonic-gate 	 * create the lost+found directory
27407c478bd9Sstevel@tonic-gate 	 */
27417c478bd9Sstevel@tonic-gate 	(void) makedir(lost_found_dir, 2);
27427c478bd9Sstevel@tonic-gate 	for (i = DIRBLKSIZ; i < sblock.fs_bsize; i += DIRBLKSIZ) {
27437c478bd9Sstevel@tonic-gate 		bcopy(&lost_found_dir[2], &buf[i], DIRSIZ(&lost_found_dir[2]));
27447c478bd9Sstevel@tonic-gate 	}
27457c478bd9Sstevel@tonic-gate 	node.i_number = LOSTFOUNDINO;
27467c478bd9Sstevel@tonic-gate 	node.i_smode = node.i_mode = IFDIR | 0700;
27477c478bd9Sstevel@tonic-gate 	node.i_nlink = 2;
27487c478bd9Sstevel@tonic-gate 	node.i_size = sblock.fs_bsize;
27497c478bd9Sstevel@tonic-gate 	node.i_db[0] = alloc((int)node.i_size, node.i_mode);
27507c478bd9Sstevel@tonic-gate 	node.i_blocks = btodb(fragroundup(&sblock, (int)node.i_size));
27517c478bd9Sstevel@tonic-gate 	IRANDOMIZE(&node.i_ic);
27527c478bd9Sstevel@tonic-gate 	wtfs(fsbtodb(&sblock, (uint64_t)node.i_db[0]), (int)node.i_size, buf);
27537c478bd9Sstevel@tonic-gate 	iput(&node);
27547c478bd9Sstevel@tonic-gate #endif
27557c478bd9Sstevel@tonic-gate 	/*
27567c478bd9Sstevel@tonic-gate 	 * create the root directory
27577c478bd9Sstevel@tonic-gate 	 */
27587c478bd9Sstevel@tonic-gate 	node.i_number = UFSROOTINO;
27597c478bd9Sstevel@tonic-gate 	node.i_mode = node.i_smode = IFDIR | UMASK;
27607c478bd9Sstevel@tonic-gate 	node.i_nlink = PREDEFDIR;
27617c478bd9Sstevel@tonic-gate 	node.i_size = makedir(root_dir, PREDEFDIR);
27627c478bd9Sstevel@tonic-gate 	node.i_db[0] = alloc(sblock.fs_fsize, node.i_mode);
27637c478bd9Sstevel@tonic-gate 	/* i_size < 2GB because we are initializing the file system */
27647c478bd9Sstevel@tonic-gate 	node.i_blocks = btodb(fragroundup(&sblock, (int)node.i_size));
27657c478bd9Sstevel@tonic-gate 	IRANDOMIZE(&node.i_ic);
27667c478bd9Sstevel@tonic-gate 	wtfs(fsbtodb(&sblock, (uint64_t)node.i_db[0]), sblock.fs_fsize, buf);
27677c478bd9Sstevel@tonic-gate 	iput(&node);
27687c478bd9Sstevel@tonic-gate }
27697c478bd9Sstevel@tonic-gate 
27707c478bd9Sstevel@tonic-gate /*
27717c478bd9Sstevel@tonic-gate  * construct a set of directory entries in "buf".
27727c478bd9Sstevel@tonic-gate  * return size of directory.
27737c478bd9Sstevel@tonic-gate  */
27747c478bd9Sstevel@tonic-gate static int
27757c478bd9Sstevel@tonic-gate makedir(struct direct *protodir, int entries)
27767c478bd9Sstevel@tonic-gate {
27777c478bd9Sstevel@tonic-gate 	char *cp;
27787c478bd9Sstevel@tonic-gate 	int i;
27797c478bd9Sstevel@tonic-gate 	ushort_t spcleft;
27807c478bd9Sstevel@tonic-gate 
27817c478bd9Sstevel@tonic-gate 	spcleft = DIRBLKSIZ;
27827c478bd9Sstevel@tonic-gate 	for (cp = buf, i = 0; i < entries - 1; i++) {
27837c478bd9Sstevel@tonic-gate 		protodir[i].d_reclen = DIRSIZ(&protodir[i]);
27847c478bd9Sstevel@tonic-gate 		bcopy(&protodir[i], cp, protodir[i].d_reclen);
27857c478bd9Sstevel@tonic-gate 		cp += protodir[i].d_reclen;
27867c478bd9Sstevel@tonic-gate 		spcleft -= protodir[i].d_reclen;
27877c478bd9Sstevel@tonic-gate 	}
27887c478bd9Sstevel@tonic-gate 	protodir[i].d_reclen = spcleft;
27897c478bd9Sstevel@tonic-gate 	bcopy(&protodir[i], cp, DIRSIZ(&protodir[i]));
27907c478bd9Sstevel@tonic-gate 	return (DIRBLKSIZ);
27917c478bd9Sstevel@tonic-gate }
27927c478bd9Sstevel@tonic-gate 
27937c478bd9Sstevel@tonic-gate /*
27947c478bd9Sstevel@tonic-gate  * allocate a block or frag
27957c478bd9Sstevel@tonic-gate  */
27967c478bd9Sstevel@tonic-gate static daddr32_t
27977c478bd9Sstevel@tonic-gate alloc(int size, int mode)
27987c478bd9Sstevel@tonic-gate {
27997c478bd9Sstevel@tonic-gate 	int i, frag;
28007c478bd9Sstevel@tonic-gate 	daddr32_t d;
28017c478bd9Sstevel@tonic-gate 
28027c478bd9Sstevel@tonic-gate 	rdfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, 0)), sblock.fs_cgsize,
28037c478bd9Sstevel@tonic-gate 	    (char *)&acg);
28047c478bd9Sstevel@tonic-gate 	if (acg.cg_magic != CG_MAGIC) {
28057c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("cg 0: bad magic number\n"));
28067c478bd9Sstevel@tonic-gate 		lockexit(32);
28077c478bd9Sstevel@tonic-gate 	}
28087c478bd9Sstevel@tonic-gate 	if (acg.cg_cs.cs_nbfree == 0) {
28097c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
28107c478bd9Sstevel@tonic-gate 			gettext("first cylinder group ran out of space\n"));
28117c478bd9Sstevel@tonic-gate 		lockexit(32);
28127c478bd9Sstevel@tonic-gate 	}
28137c478bd9Sstevel@tonic-gate 	for (d = 0; d < acg.cg_ndblk; d += sblock.fs_frag)
28147c478bd9Sstevel@tonic-gate 		if (isblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag))
28157c478bd9Sstevel@tonic-gate 			goto goth;
28167c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
28177c478bd9Sstevel@tonic-gate 	    gettext("internal error: can't find block in cyl 0\n"));
28187c478bd9Sstevel@tonic-gate 	lockexit(32);
28197c478bd9Sstevel@tonic-gate goth:
28207c478bd9Sstevel@tonic-gate 	clrblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag);
28217c478bd9Sstevel@tonic-gate 	acg.cg_cs.cs_nbfree--;
28227c478bd9Sstevel@tonic-gate 	sblock.fs_cstotal.cs_nbfree--;
28237c478bd9Sstevel@tonic-gate 	fscs[0].cs_nbfree--;
28247c478bd9Sstevel@tonic-gate 	if (mode & IFDIR) {
28257c478bd9Sstevel@tonic-gate 		acg.cg_cs.cs_ndir++;
28267c478bd9Sstevel@tonic-gate 		sblock.fs_cstotal.cs_ndir++;
28277c478bd9Sstevel@tonic-gate 		fscs[0].cs_ndir++;
28287c478bd9Sstevel@tonic-gate 	}
28297c478bd9Sstevel@tonic-gate 	cg_blktot(&acg)[cbtocylno(&sblock, d)]--;
28307c478bd9Sstevel@tonic-gate 	cg_blks(&sblock, &acg, cbtocylno(&sblock, d))[cbtorpos(&sblock, d)]--;
28317c478bd9Sstevel@tonic-gate 	if (size != sblock.fs_bsize) {
28327c478bd9Sstevel@tonic-gate 		frag = howmany(size, sblock.fs_fsize);
28337c478bd9Sstevel@tonic-gate 		fscs[0].cs_nffree += sblock.fs_frag - frag;
28347c478bd9Sstevel@tonic-gate 		sblock.fs_cstotal.cs_nffree += sblock.fs_frag - frag;
28357c478bd9Sstevel@tonic-gate 		acg.cg_cs.cs_nffree += sblock.fs_frag - frag;
28367c478bd9Sstevel@tonic-gate 		acg.cg_frsum[sblock.fs_frag - frag]++;
28377c478bd9Sstevel@tonic-gate 		for (i = frag; i < sblock.fs_frag; i++)
28387c478bd9Sstevel@tonic-gate 			setbit(cg_blksfree(&acg), d + i);
28397c478bd9Sstevel@tonic-gate 	}
28407c478bd9Sstevel@tonic-gate 	wtfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, 0)), sblock.fs_cgsize,
28417c478bd9Sstevel@tonic-gate 	    (char *)&acg);
28427c478bd9Sstevel@tonic-gate 	return (d);
28437c478bd9Sstevel@tonic-gate }
28447c478bd9Sstevel@tonic-gate 
28457c478bd9Sstevel@tonic-gate /*
28467c478bd9Sstevel@tonic-gate  * Allocate an inode on the disk
28477c478bd9Sstevel@tonic-gate  */
28487c478bd9Sstevel@tonic-gate static void
28497c478bd9Sstevel@tonic-gate iput(struct inode *ip)
28507c478bd9Sstevel@tonic-gate {
28517c478bd9Sstevel@tonic-gate 	struct dinode buf[MAXINOPB];
28527c478bd9Sstevel@tonic-gate 	diskaddr_t d;
28537c478bd9Sstevel@tonic-gate 
28547c478bd9Sstevel@tonic-gate 	rdfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, 0)), sblock.fs_cgsize,
28557c478bd9Sstevel@tonic-gate 	    (char *)&acg);
28567c478bd9Sstevel@tonic-gate 	if (acg.cg_magic != CG_MAGIC) {
28577c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("cg 0: bad magic number\n"));
28587c478bd9Sstevel@tonic-gate 		lockexit(32);
28597c478bd9Sstevel@tonic-gate 	}
28607c478bd9Sstevel@tonic-gate 	acg.cg_cs.cs_nifree--;
28617c478bd9Sstevel@tonic-gate 	setbit(cg_inosused(&acg), ip->i_number);
28627c478bd9Sstevel@tonic-gate 	wtfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, 0)), sblock.fs_cgsize,
28637c478bd9Sstevel@tonic-gate 	    (char *)&acg);
28647c478bd9Sstevel@tonic-gate 	sblock.fs_cstotal.cs_nifree--;
28657c478bd9Sstevel@tonic-gate 	fscs[0].cs_nifree--;
28667c478bd9Sstevel@tonic-gate 	if ((int)ip->i_number >= sblock.fs_ipg * sblock.fs_ncg) {
28677c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
28687c478bd9Sstevel@tonic-gate 			gettext("fsinit: inode value out of range (%d).\n"),
28697c478bd9Sstevel@tonic-gate 			ip->i_number);
28707c478bd9Sstevel@tonic-gate 		lockexit(32);
28717c478bd9Sstevel@tonic-gate 	}
28727c478bd9Sstevel@tonic-gate 	d = fsbtodb(&sblock, (uint64_t)itod(&sblock, (int)ip->i_number));
28737c478bd9Sstevel@tonic-gate 	rdfs(d, sblock.fs_bsize, (char *)buf);
28747c478bd9Sstevel@tonic-gate 	buf[itoo(&sblock, (int)ip->i_number)].di_ic = ip->i_ic;
28757c478bd9Sstevel@tonic-gate 	wtfs(d, sblock.fs_bsize, (char *)buf);
28767c478bd9Sstevel@tonic-gate }
28777c478bd9Sstevel@tonic-gate 
28787c478bd9Sstevel@tonic-gate /*
28797c478bd9Sstevel@tonic-gate  * getbuf()	-- Get a buffer for use in an AIO operation.  Buffer
28807c478bd9Sstevel@tonic-gate  *		is zero'd the first time returned, left with whatever
28817c478bd9Sstevel@tonic-gate  *		was in memory after that.  This function actually gets
28827c478bd9Sstevel@tonic-gate  *		enough memory the first time it's called to support
28837c478bd9Sstevel@tonic-gate  *		MAXBUF buffers like a slab allocator.  When all the
28847c478bd9Sstevel@tonic-gate  *		buffers are in use, it waits for an aio to complete
28857c478bd9Sstevel@tonic-gate  *		and make a buffer available.
28867c478bd9Sstevel@tonic-gate  *
28877c478bd9Sstevel@tonic-gate  *		Never returns an error.  Either succeeds or exits.
28887c478bd9Sstevel@tonic-gate  */
28897c478bd9Sstevel@tonic-gate static char *
28907c478bd9Sstevel@tonic-gate getbuf(bufhdr *bufhead, int size)
28917c478bd9Sstevel@tonic-gate {
28927c478bd9Sstevel@tonic-gate 	bufhdr *pbuf;
28937c478bd9Sstevel@tonic-gate 	bufhdr *prev;
28947c478bd9Sstevel@tonic-gate 	int i;
28957c478bd9Sstevel@tonic-gate 	int buf_size, max_bufs;
28967c478bd9Sstevel@tonic-gate 
28977c478bd9Sstevel@tonic-gate 	/*
28987c478bd9Sstevel@tonic-gate 	 * Initialize all the buffers
28997c478bd9Sstevel@tonic-gate 	 */
29007c478bd9Sstevel@tonic-gate 	if (bufhead->head == NULL) {
29017c478bd9Sstevel@tonic-gate 		/*
29027c478bd9Sstevel@tonic-gate 		 * round up the size of our buffer header to a
29037c478bd9Sstevel@tonic-gate 		 * 16 byte boundary so the address we return to
29047c478bd9Sstevel@tonic-gate 		 * the caller is "suitably aligned".
29057c478bd9Sstevel@tonic-gate 		 */
29067c478bd9Sstevel@tonic-gate 		bufhdrsize = (sizeof (bufhdr) + 15) & ~15;
29077c478bd9Sstevel@tonic-gate 
29087c478bd9Sstevel@tonic-gate 		/*
29097c478bd9Sstevel@tonic-gate 		 * Add in our header to the buffer and round it all up to
29107c478bd9Sstevel@tonic-gate 		 * a 16 byte boundry so each member of the slab is aligned.
29117c478bd9Sstevel@tonic-gate 		 */
29127c478bd9Sstevel@tonic-gate 		buf_size = (size + bufhdrsize + 15) & ~15;
29137c478bd9Sstevel@tonic-gate 
29147c478bd9Sstevel@tonic-gate 		/*
29157c478bd9Sstevel@tonic-gate 		 * Limit number of buffers to lesser of MAXBUFMEM's worth
29167c478bd9Sstevel@tonic-gate 		 * or MAXBUF, whichever is less.
29177c478bd9Sstevel@tonic-gate 		 */
29187c478bd9Sstevel@tonic-gate 		max_bufs = MAXBUFMEM / buf_size;
29197c478bd9Sstevel@tonic-gate 		if (max_bufs > MAXBUF)
29207c478bd9Sstevel@tonic-gate 			max_bufs = MAXBUF;
29217c478bd9Sstevel@tonic-gate 
29227c478bd9Sstevel@tonic-gate 		pbuf = (bufhdr *)calloc(max_bufs, buf_size);
29237c478bd9Sstevel@tonic-gate 		if (pbuf == NULL) {
29247c478bd9Sstevel@tonic-gate 			perror("calloc");
29257c478bd9Sstevel@tonic-gate 			lockexit(32);
29267c478bd9Sstevel@tonic-gate 		}
29277c478bd9Sstevel@tonic-gate 
29287c478bd9Sstevel@tonic-gate 		bufhead->head = bufhead;
29297c478bd9Sstevel@tonic-gate 		prev = bufhead;
29307c478bd9Sstevel@tonic-gate 		for (i = 0; i < max_bufs; i++) {
29317c478bd9Sstevel@tonic-gate 			pbuf->head = bufhead;
29327c478bd9Sstevel@tonic-gate 			prev->next = pbuf;
29337c478bd9Sstevel@tonic-gate 			prev = pbuf;
29347c478bd9Sstevel@tonic-gate 			pbuf = (bufhdr *)((char *)pbuf + buf_size);
29357c478bd9Sstevel@tonic-gate 		}
29367c478bd9Sstevel@tonic-gate 	}
29377c478bd9Sstevel@tonic-gate 
29387c478bd9Sstevel@tonic-gate 	/*
29397c478bd9Sstevel@tonic-gate 	 * Get an available buffer, waiting for I/O if necessary
29407c478bd9Sstevel@tonic-gate 	 */
29417c478bd9Sstevel@tonic-gate 	wait_for_write(NOBLOCK);
29427c478bd9Sstevel@tonic-gate 	while (bufhead->next == NULL)
29437c478bd9Sstevel@tonic-gate 		wait_for_write(BLOCK);
29447c478bd9Sstevel@tonic-gate 
29457c478bd9Sstevel@tonic-gate 	/*
29467c478bd9Sstevel@tonic-gate 	 * Take the buffer off the list
29477c478bd9Sstevel@tonic-gate 	 */
29487c478bd9Sstevel@tonic-gate 	pbuf = bufhead->next;
29497c478bd9Sstevel@tonic-gate 	bufhead->next = pbuf->next;
29507c478bd9Sstevel@tonic-gate 	pbuf->next = NULL;
29517c478bd9Sstevel@tonic-gate 
29527c478bd9Sstevel@tonic-gate 	/*
29537c478bd9Sstevel@tonic-gate 	 * return the empty buffer space just past the header
29547c478bd9Sstevel@tonic-gate 	 */
29557c478bd9Sstevel@tonic-gate 	return ((char *)pbuf + bufhdrsize);
29567c478bd9Sstevel@tonic-gate }
29577c478bd9Sstevel@tonic-gate 
29587c478bd9Sstevel@tonic-gate /*
29597c478bd9Sstevel@tonic-gate  * freebuf()	-- Free a buffer gotten previously through getbuf.
29607c478bd9Sstevel@tonic-gate  *		Puts the buffer back on the appropriate list for
29617c478bd9Sstevel@tonic-gate  *		later use.  Never calls free().
29627c478bd9Sstevel@tonic-gate  *
29637c478bd9Sstevel@tonic-gate  * Assumes that SIGINT is blocked.
29647c478bd9Sstevel@tonic-gate  */
29657c478bd9Sstevel@tonic-gate static void
29667c478bd9Sstevel@tonic-gate freebuf(char *buf)
29677c478bd9Sstevel@tonic-gate {
29687c478bd9Sstevel@tonic-gate 	bufhdr *pbuf;
29697c478bd9Sstevel@tonic-gate 	bufhdr *bufhead;
29707c478bd9Sstevel@tonic-gate 
29717c478bd9Sstevel@tonic-gate 	/*
29727c478bd9Sstevel@tonic-gate 	 * get the header for this buffer
29737c478bd9Sstevel@tonic-gate 	 */
29747c478bd9Sstevel@tonic-gate 	pbuf = (bufhdr *)(buf - bufhdrsize);
29757c478bd9Sstevel@tonic-gate 
29767c478bd9Sstevel@tonic-gate 	/*
29777c478bd9Sstevel@tonic-gate 	 * Put it back on the list of available buffers
29787c478bd9Sstevel@tonic-gate 	 */
29797c478bd9Sstevel@tonic-gate 	bufhead = pbuf->head;
29807c478bd9Sstevel@tonic-gate 	pbuf->next = bufhead->next;
29817c478bd9Sstevel@tonic-gate 	bufhead->next = pbuf;
29827c478bd9Sstevel@tonic-gate }
29837c478bd9Sstevel@tonic-gate 
29847c478bd9Sstevel@tonic-gate /*
29857c478bd9Sstevel@tonic-gate  * freetrans()	-- Free a transaction gotten previously through getaiop.
29867c478bd9Sstevel@tonic-gate  *		Puts the transaction struct back on the appropriate list for
29877c478bd9Sstevel@tonic-gate  *		later use.  Never calls free().
29887c478bd9Sstevel@tonic-gate  *
29897c478bd9Sstevel@tonic-gate  * Assumes that SIGINT is blocked.
29907c478bd9Sstevel@tonic-gate  */
29917c478bd9Sstevel@tonic-gate static void
29927c478bd9Sstevel@tonic-gate freetrans(aio_trans *transp)
29937c478bd9Sstevel@tonic-gate {
29947c478bd9Sstevel@tonic-gate 	/*
29957c478bd9Sstevel@tonic-gate 	 * free the buffer associated with this AIO if needed
29967c478bd9Sstevel@tonic-gate 	 */
29977c478bd9Sstevel@tonic-gate 	if (transp->release == RELEASE)
29987c478bd9Sstevel@tonic-gate 		freebuf(transp->buffer);
29997c478bd9Sstevel@tonic-gate 
30007c478bd9Sstevel@tonic-gate 	/*
30017c478bd9Sstevel@tonic-gate 	 * Put transaction on the free list
30027c478bd9Sstevel@tonic-gate 	 */
30037c478bd9Sstevel@tonic-gate 	transp->next = results.trans;
30047c478bd9Sstevel@tonic-gate 	results.trans = transp;
30057c478bd9Sstevel@tonic-gate }
30067c478bd9Sstevel@tonic-gate 
30077c478bd9Sstevel@tonic-gate /*
30087c478bd9Sstevel@tonic-gate  * wait_for_write()	-- Wait for an aio write to complete.  Return
30097c478bd9Sstevel@tonic-gate  *			the transaction structure for that write.
30107c478bd9Sstevel@tonic-gate  *
30117c478bd9Sstevel@tonic-gate  * Blocks SIGINT if necessary.
30127c478bd9Sstevel@tonic-gate  */
30137c478bd9Sstevel@tonic-gate aio_trans *
30147c478bd9Sstevel@tonic-gate wait_for_write(int block)
30157c478bd9Sstevel@tonic-gate {
30167c478bd9Sstevel@tonic-gate 	aio_trans	*transp;
30177c478bd9Sstevel@tonic-gate 	aio_result_t	*resultp;
30187c478bd9Sstevel@tonic-gate 	static struct timeval  zero_wait = { 0, 0 };
30197c478bd9Sstevel@tonic-gate 	sigset_t	old_mask;
30207c478bd9Sstevel@tonic-gate 
30217c478bd9Sstevel@tonic-gate 	/*
30227c478bd9Sstevel@tonic-gate 	 * If we know there aren't any outstanding transactions, just return
30237c478bd9Sstevel@tonic-gate 	 */
30247c478bd9Sstevel@tonic-gate 	if (results.outstanding == 0)
30257c478bd9Sstevel@tonic-gate 		return ((aio_trans *) 0);
30267c478bd9Sstevel@tonic-gate 
30277c478bd9Sstevel@tonic-gate 	block_sigint(&old_mask);
30287c478bd9Sstevel@tonic-gate 
30297c478bd9Sstevel@tonic-gate 	resultp = aiowait(block ? NULL : &zero_wait);
30307c478bd9Sstevel@tonic-gate 	if (resultp == NULL ||
30317c478bd9Sstevel@tonic-gate 	    (resultp == (aio_result_t *)-1 && errno == EINVAL)) {
30327c478bd9Sstevel@tonic-gate 		unblock_sigint(&old_mask);
30337c478bd9Sstevel@tonic-gate 		return ((aio_trans *) 0);
30347c478bd9Sstevel@tonic-gate 	}
30357c478bd9Sstevel@tonic-gate 
30367c478bd9Sstevel@tonic-gate 	results.outstanding--;
30377c478bd9Sstevel@tonic-gate 	transp = (aio_trans *)resultp;
30387c478bd9Sstevel@tonic-gate 
30397c478bd9Sstevel@tonic-gate 	if (resultp->aio_return != transp->size) {
30407c478bd9Sstevel@tonic-gate 		if (resultp->aio_return == -1) {
30417c478bd9Sstevel@tonic-gate 			/*
30427c478bd9Sstevel@tonic-gate 			 * The aiowrite() may have failed because the
30437c478bd9Sstevel@tonic-gate 			 * kernel didn't have enough memory to do the job.
30447c478bd9Sstevel@tonic-gate 			 * Flush all pending writes and try a normal
30457c478bd9Sstevel@tonic-gate 			 * write().  wtfs_breakup() will call exit if it
30467c478bd9Sstevel@tonic-gate 			 * fails, so we don't worry about errors here.
30477c478bd9Sstevel@tonic-gate 			 */
30487c478bd9Sstevel@tonic-gate 			flush_writes();
30497c478bd9Sstevel@tonic-gate 			wtfs_breakup(transp->bno, transp->size, transp->buffer);
30507c478bd9Sstevel@tonic-gate 		} else {
30517c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
30527c478bd9Sstevel@tonic-gate 			    "short write (%d of %d bytes) on sector %lld\n"),
30537c478bd9Sstevel@tonic-gate 			    resultp->aio_return, transp->size,
30547c478bd9Sstevel@tonic-gate 			    transp->bno);
30557c478bd9Sstevel@tonic-gate 			/*
30567c478bd9Sstevel@tonic-gate 			 * Don't unblock SIGINT, to avoid potential
30577c478bd9Sstevel@tonic-gate 			 * looping due to queued interrupts and
30587c478bd9Sstevel@tonic-gate 			 * error handling.
30597c478bd9Sstevel@tonic-gate 			 */
30607c478bd9Sstevel@tonic-gate 			lockexit(32);
30617c478bd9Sstevel@tonic-gate 		}
30627c478bd9Sstevel@tonic-gate 	}
30637c478bd9Sstevel@tonic-gate 
30647c478bd9Sstevel@tonic-gate 	resultp->aio_return = 0;
30657c478bd9Sstevel@tonic-gate 	freetrans(transp);
30667c478bd9Sstevel@tonic-gate 	unblock_sigint(&old_mask);
30677c478bd9Sstevel@tonic-gate 	return (transp);
30687c478bd9Sstevel@tonic-gate }
30697c478bd9Sstevel@tonic-gate 
30707c478bd9Sstevel@tonic-gate /*
30717c478bd9Sstevel@tonic-gate  * flush_writes()	-- flush all the outstanding aio writes.
30727c478bd9Sstevel@tonic-gate  */
30737c478bd9Sstevel@tonic-gate static void
30747c478bd9Sstevel@tonic-gate flush_writes(void)
30757c478bd9Sstevel@tonic-gate {
30767c478bd9Sstevel@tonic-gate 	while (wait_for_write(BLOCK))
30777c478bd9Sstevel@tonic-gate 		;
30787c478bd9Sstevel@tonic-gate }
30797c478bd9Sstevel@tonic-gate 
30807c478bd9Sstevel@tonic-gate /*
30817c478bd9Sstevel@tonic-gate  * get_aiop()	-- find and return an aio_trans structure on which a new
30827c478bd9Sstevel@tonic-gate  *		aio can be done.  Blocks on aiowait() if needed.  Reaps
30837c478bd9Sstevel@tonic-gate  *		all outstanding completed aio's.
30847c478bd9Sstevel@tonic-gate  *
30857c478bd9Sstevel@tonic-gate  * Assumes that SIGINT is blocked.
30867c478bd9Sstevel@tonic-gate  */
30877c478bd9Sstevel@tonic-gate aio_trans *
30887c478bd9Sstevel@tonic-gate get_aiop()
30897c478bd9Sstevel@tonic-gate {
30907c478bd9Sstevel@tonic-gate 	int i;
30917c478bd9Sstevel@tonic-gate 	aio_trans *transp;
30927c478bd9Sstevel@tonic-gate 	aio_trans *prev;
30937c478bd9Sstevel@tonic-gate 
30947c478bd9Sstevel@tonic-gate 	/*
30957c478bd9Sstevel@tonic-gate 	 * initialize aio stuff
30967c478bd9Sstevel@tonic-gate 	 */
30977c478bd9Sstevel@tonic-gate 	if (!aio_inited) {
30987c478bd9Sstevel@tonic-gate 		aio_inited = 1;
30997c478bd9Sstevel@tonic-gate 
31007c478bd9Sstevel@tonic-gate 		results.maxpend = 0;
31017c478bd9Sstevel@tonic-gate 		results.outstanding = 0;
31027c478bd9Sstevel@tonic-gate 		results.max = MAXAIO;
31037c478bd9Sstevel@tonic-gate 
31047c478bd9Sstevel@tonic-gate 		results.trans = (aio_trans *)calloc(results.max,
31057c478bd9Sstevel@tonic-gate 						sizeof (aio_trans));
31067c478bd9Sstevel@tonic-gate 		if (results.trans == NULL) {
31077c478bd9Sstevel@tonic-gate 			perror("calloc");
31087c478bd9Sstevel@tonic-gate 			lockexit(32);
31097c478bd9Sstevel@tonic-gate 		}
31107c478bd9Sstevel@tonic-gate 
31117c478bd9Sstevel@tonic-gate 		/*
31127c478bd9Sstevel@tonic-gate 		 * Initialize the linked list of aio transaction
31137c478bd9Sstevel@tonic-gate 		 * structures.  Note that the final "next" pointer
31147c478bd9Sstevel@tonic-gate 		 * will be NULL since we got the buffer from calloc().
31157c478bd9Sstevel@tonic-gate 		 */
31167c478bd9Sstevel@tonic-gate 		prev = results.trans;
31177c478bd9Sstevel@tonic-gate 		for (i = 1; i < results.max; i++) {
31187c478bd9Sstevel@tonic-gate 			prev->next = &(results.trans[i]);
31197c478bd9Sstevel@tonic-gate 			prev = prev->next;
31207c478bd9Sstevel@tonic-gate 		}
31217c478bd9Sstevel@tonic-gate 	}
31227c478bd9Sstevel@tonic-gate 
31237c478bd9Sstevel@tonic-gate 	wait_for_write(NOBLOCK);
31247c478bd9Sstevel@tonic-gate 	while (results.trans == NULL)
31257c478bd9Sstevel@tonic-gate 		wait_for_write(BLOCK);
31267c478bd9Sstevel@tonic-gate 	transp = results.trans;
31277c478bd9Sstevel@tonic-gate 	results.trans = results.trans->next;
31287c478bd9Sstevel@tonic-gate 
31297c478bd9Sstevel@tonic-gate 	transp->next = 0;
31307c478bd9Sstevel@tonic-gate 	transp->resultbuf.aio_return = AIO_INPROGRESS;
31317c478bd9Sstevel@tonic-gate 	return (transp);
31327c478bd9Sstevel@tonic-gate }
31337c478bd9Sstevel@tonic-gate 
31347c478bd9Sstevel@tonic-gate /*
31357c478bd9Sstevel@tonic-gate  * read a block from the file system
31367c478bd9Sstevel@tonic-gate  */
31377c478bd9Sstevel@tonic-gate static void
31387c478bd9Sstevel@tonic-gate rdfs(diskaddr_t bno, int size, char *bf)
31397c478bd9Sstevel@tonic-gate {
31407c478bd9Sstevel@tonic-gate 	int n, saverr;
31417c478bd9Sstevel@tonic-gate 
31427c478bd9Sstevel@tonic-gate 	/*
31437c478bd9Sstevel@tonic-gate 	 * In case we need any data that's pending in an aiowrite(),
31447c478bd9Sstevel@tonic-gate 	 * we wait for them all to complete before doing a read.
31457c478bd9Sstevel@tonic-gate 	 */
31467c478bd9Sstevel@tonic-gate 	flush_writes();
31477c478bd9Sstevel@tonic-gate 
31487c478bd9Sstevel@tonic-gate 	/*
31497c478bd9Sstevel@tonic-gate 	 * Note: the llseek() can succeed, even if the offset is out of range.
31507c478bd9Sstevel@tonic-gate 	 * It's not until the file i/o operation (the read()) that one knows
31517c478bd9Sstevel@tonic-gate 	 * for sure if the raw device can handle the offset.
31527c478bd9Sstevel@tonic-gate 	 */
31537c478bd9Sstevel@tonic-gate 	if (llseek(fsi, (offset_t)bno * sectorsize, 0) < 0) {
31547c478bd9Sstevel@tonic-gate 		saverr = errno;
31557c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
31567c478bd9Sstevel@tonic-gate 		    gettext("seek error on sector %lld: %s\n"),
31577c478bd9Sstevel@tonic-gate 		    bno, strerror(saverr));
31587c478bd9Sstevel@tonic-gate 		lockexit(32);
31597c478bd9Sstevel@tonic-gate 	}
31607c478bd9Sstevel@tonic-gate 	n = read(fsi, bf, size);
31617c478bd9Sstevel@tonic-gate 	if (n != size) {
31627c478bd9Sstevel@tonic-gate 		saverr = errno;
31637c478bd9Sstevel@tonic-gate 		if (n == -1)
31647c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
31657c478bd9Sstevel@tonic-gate 			    gettext("read error on sector %lld: %s\n"),
31667c478bd9Sstevel@tonic-gate 			    bno, strerror(saverr));
31677c478bd9Sstevel@tonic-gate 		else
31687c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
31697c478bd9Sstevel@tonic-gate 			    "short read (%d of %d bytes) on sector %lld\n"),
31707c478bd9Sstevel@tonic-gate 			    n, size, bno);
31717c478bd9Sstevel@tonic-gate 		lockexit(32);
31727c478bd9Sstevel@tonic-gate 	}
31737c478bd9Sstevel@tonic-gate }
31747c478bd9Sstevel@tonic-gate 
31757c478bd9Sstevel@tonic-gate /*
31767c478bd9Sstevel@tonic-gate  * write a block to the file system
31777c478bd9Sstevel@tonic-gate  */
31787c478bd9Sstevel@tonic-gate static void
31797c478bd9Sstevel@tonic-gate wtfs(diskaddr_t bno, int size, char *bf)
31807c478bd9Sstevel@tonic-gate {
31817c478bd9Sstevel@tonic-gate 	int n, saverr;
31827c478bd9Sstevel@tonic-gate 
31837c478bd9Sstevel@tonic-gate 	if (fso == -1)
31847c478bd9Sstevel@tonic-gate 		return;
31857c478bd9Sstevel@tonic-gate 
31867c478bd9Sstevel@tonic-gate 	/*
31877c478bd9Sstevel@tonic-gate 	 * Note: the llseek() can succeed, even if the offset is out of range.
31887c478bd9Sstevel@tonic-gate 	 * It's not until the file i/o operation (the write()) that one knows
31897c478bd9Sstevel@tonic-gate 	 * for sure if the raw device can handle the offset.
31907c478bd9Sstevel@tonic-gate 	 */
31917c478bd9Sstevel@tonic-gate 	if (llseek(fso, (offset_t)bno * sectorsize, 0) < 0) {
31927c478bd9Sstevel@tonic-gate 		saverr = errno;
31937c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
31947c478bd9Sstevel@tonic-gate 		    gettext("seek error on sector %lld: %s\n"),
31957c478bd9Sstevel@tonic-gate 		    bno, strerror(saverr));
31967c478bd9Sstevel@tonic-gate 		lockexit(32);
31977c478bd9Sstevel@tonic-gate 	}
31987c478bd9Sstevel@tonic-gate 	if (Nflag)
31997c478bd9Sstevel@tonic-gate 		return;
32007c478bd9Sstevel@tonic-gate 	n = write(fso, bf, size);
32017c478bd9Sstevel@tonic-gate 	if (n != size) {
32027c478bd9Sstevel@tonic-gate 		saverr = errno;
32037c478bd9Sstevel@tonic-gate 		if (n == -1)
32047c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
32057c478bd9Sstevel@tonic-gate 			    gettext("write error on sector %lld: %s\n"),
32067c478bd9Sstevel@tonic-gate 			    bno, strerror(saverr));
32077c478bd9Sstevel@tonic-gate 		else
32087c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
32097c478bd9Sstevel@tonic-gate 			    "short write (%d of %d bytes) on sector %lld\n"),
32107c478bd9Sstevel@tonic-gate 			    n, size, bno);
32117c478bd9Sstevel@tonic-gate 		lockexit(32);
32127c478bd9Sstevel@tonic-gate 	}
32137c478bd9Sstevel@tonic-gate }
32147c478bd9Sstevel@tonic-gate 
32157c478bd9Sstevel@tonic-gate /*
32167c478bd9Sstevel@tonic-gate  * write a block to the file system -- buffered with aio
32177c478bd9Sstevel@tonic-gate  */
32187c478bd9Sstevel@tonic-gate static void
32197c478bd9Sstevel@tonic-gate awtfs(diskaddr_t bno, int size, char *bf, int release)
32207c478bd9Sstevel@tonic-gate {
32217c478bd9Sstevel@tonic-gate 	int n;
32227c478bd9Sstevel@tonic-gate 	aio_trans 	*transp;
32237c478bd9Sstevel@tonic-gate 	sigset_t 	old_mask;
32247c478bd9Sstevel@tonic-gate 
32257c478bd9Sstevel@tonic-gate 	if (fso == -1)
32267c478bd9Sstevel@tonic-gate 		return;
32277c478bd9Sstevel@tonic-gate 
32287c478bd9Sstevel@tonic-gate 	/*
32297c478bd9Sstevel@tonic-gate 	 * We need to keep things consistent if we get interrupted,
32307c478bd9Sstevel@tonic-gate 	 * so defer any expected interrupts for the time being.
32317c478bd9Sstevel@tonic-gate 	 */
32327c478bd9Sstevel@tonic-gate 	block_sigint(&old_mask);
32337c478bd9Sstevel@tonic-gate 
32347c478bd9Sstevel@tonic-gate 	if (Nflag) {
32357c478bd9Sstevel@tonic-gate 		if (release == RELEASE)
32367c478bd9Sstevel@tonic-gate 			freebuf(bf);
32377c478bd9Sstevel@tonic-gate 	} else {
32387c478bd9Sstevel@tonic-gate 		transp = get_aiop();
32397c478bd9Sstevel@tonic-gate 		transp->bno = bno;
32407c478bd9Sstevel@tonic-gate 		transp->buffer = bf;
32417c478bd9Sstevel@tonic-gate 		transp->size = size;
32427c478bd9Sstevel@tonic-gate 		transp->release = release;
32437c478bd9Sstevel@tonic-gate 
32447c478bd9Sstevel@tonic-gate 		n = aiowrite(fso, bf, size, (off_t)bno * sectorsize,
32457c478bd9Sstevel@tonic-gate 				SEEK_SET, &transp->resultbuf);
32467c478bd9Sstevel@tonic-gate 
32477c478bd9Sstevel@tonic-gate 		if (n < 0) {
32487c478bd9Sstevel@tonic-gate 			/*
32497c478bd9Sstevel@tonic-gate 			 * The aiowrite() may have failed because the
32507c478bd9Sstevel@tonic-gate 			 * kernel didn't have enough memory to do the job.
32517c478bd9Sstevel@tonic-gate 			 * Flush all pending writes and try a normal
32527c478bd9Sstevel@tonic-gate 			 * write().  wtfs_breakup() will call exit if it
32537c478bd9Sstevel@tonic-gate 			 * fails, so we don't worry about errors here.
32547c478bd9Sstevel@tonic-gate 			 */
32557c478bd9Sstevel@tonic-gate 			flush_writes();
32567c478bd9Sstevel@tonic-gate 			wtfs_breakup(transp->bno, transp->size, transp->buffer);
32577c478bd9Sstevel@tonic-gate 			freetrans(transp);
32587c478bd9Sstevel@tonic-gate 		} else {
32597c478bd9Sstevel@tonic-gate 			/*
32607c478bd9Sstevel@tonic-gate 			 * Keep track of our pending writes.
32617c478bd9Sstevel@tonic-gate 			 */
32627c478bd9Sstevel@tonic-gate 			results.outstanding++;
32637c478bd9Sstevel@tonic-gate 			if (results.outstanding > results.maxpend)
32647c478bd9Sstevel@tonic-gate 			    results.maxpend = results.outstanding;
32657c478bd9Sstevel@tonic-gate 		}
32667c478bd9Sstevel@tonic-gate 	}
32677c478bd9Sstevel@tonic-gate 
32687c478bd9Sstevel@tonic-gate 	unblock_sigint(&old_mask);
32697c478bd9Sstevel@tonic-gate }
32707c478bd9Sstevel@tonic-gate 
32717c478bd9Sstevel@tonic-gate 
32727c478bd9Sstevel@tonic-gate /*
32737c478bd9Sstevel@tonic-gate  * write a block to the file system, but break it up into sbsize
32747c478bd9Sstevel@tonic-gate  * chunks to avoid forcing a large amount of memory to be locked down.
32757c478bd9Sstevel@tonic-gate  * Only used as a fallback when an aio write has failed.
32767c478bd9Sstevel@tonic-gate  */
32777c478bd9Sstevel@tonic-gate static void
32787c478bd9Sstevel@tonic-gate wtfs_breakup(diskaddr_t bno, int size, char *bf)
32797c478bd9Sstevel@tonic-gate {
32807c478bd9Sstevel@tonic-gate 	int n, saverr;
32817c478bd9Sstevel@tonic-gate 	int wsize;
32827c478bd9Sstevel@tonic-gate 	int block_incr = sbsize / sectorsize;
32837c478bd9Sstevel@tonic-gate 
32847c478bd9Sstevel@tonic-gate 	if (size < sbsize)
32857c478bd9Sstevel@tonic-gate 		wsize = size;
32867c478bd9Sstevel@tonic-gate 	else
32877c478bd9Sstevel@tonic-gate 		wsize = sbsize;
32887c478bd9Sstevel@tonic-gate 
32897c478bd9Sstevel@tonic-gate 	n = 0;
32907c478bd9Sstevel@tonic-gate 	while (size) {
32917c478bd9Sstevel@tonic-gate 		/*
32927c478bd9Sstevel@tonic-gate 		 * Note: the llseek() can succeed, even if the offset is
32937c478bd9Sstevel@tonic-gate 		 * out of range.  It's not until the file i/o operation
32947c478bd9Sstevel@tonic-gate 		 * (the write()) that one knows for sure if the raw device
32957c478bd9Sstevel@tonic-gate 		 * can handle the offset.
32967c478bd9Sstevel@tonic-gate 		 */
32977c478bd9Sstevel@tonic-gate 		if (llseek(fso, (offset_t)bno * sectorsize, 0) < 0) {
32987c478bd9Sstevel@tonic-gate 			saverr = errno;
32997c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
33007c478bd9Sstevel@tonic-gate 			    gettext("seek error on sector %lld: %s\n"),
33017c478bd9Sstevel@tonic-gate 			    bno, strerror(saverr));
33027c478bd9Sstevel@tonic-gate 			lockexit(32);
33037c478bd9Sstevel@tonic-gate 		}
33047c478bd9Sstevel@tonic-gate 
33057c478bd9Sstevel@tonic-gate 		n = write(fso, bf, wsize);
33067c478bd9Sstevel@tonic-gate 		if (n == -1) {
33077c478bd9Sstevel@tonic-gate 			saverr = errno;
33087c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
33097c478bd9Sstevel@tonic-gate 			    gettext("write error on sector %lld: %s\n"),
33107c478bd9Sstevel@tonic-gate 			    bno, strerror(saverr));
33117c478bd9Sstevel@tonic-gate 			lockexit(32);
33127c478bd9Sstevel@tonic-gate 		}
33137c478bd9Sstevel@tonic-gate 		if (n != wsize) {
33147c478bd9Sstevel@tonic-gate 			saverr = errno;
33157c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
33167c478bd9Sstevel@tonic-gate 			    "short write (%d of %d bytes) on sector %lld\n"),
33177c478bd9Sstevel@tonic-gate 			    n, size, bno);
33187c478bd9Sstevel@tonic-gate 			lockexit(32);
33197c478bd9Sstevel@tonic-gate 		}
33207c478bd9Sstevel@tonic-gate 
33217c478bd9Sstevel@tonic-gate 		bno += block_incr;
33227c478bd9Sstevel@tonic-gate 		bf += wsize;
33237c478bd9Sstevel@tonic-gate 		size -= wsize;
33247c478bd9Sstevel@tonic-gate 		if (size < wsize)
33257c478bd9Sstevel@tonic-gate 			wsize = size;
33267c478bd9Sstevel@tonic-gate 	}
33277c478bd9Sstevel@tonic-gate }
33287c478bd9Sstevel@tonic-gate 
33297c478bd9Sstevel@tonic-gate 
33307c478bd9Sstevel@tonic-gate /*
33317c478bd9Sstevel@tonic-gate  * check if a block is available
33327c478bd9Sstevel@tonic-gate  */
33337c478bd9Sstevel@tonic-gate static int
33347c478bd9Sstevel@tonic-gate isblock(struct fs *fs, unsigned char *cp, int h)
33357c478bd9Sstevel@tonic-gate {
33367c478bd9Sstevel@tonic-gate 	unsigned char mask;
33377c478bd9Sstevel@tonic-gate 
33387c478bd9Sstevel@tonic-gate 	switch (fs->fs_frag) {
33397c478bd9Sstevel@tonic-gate 	case 8:
33407c478bd9Sstevel@tonic-gate 		return (cp[h] == 0xff);
33417c478bd9Sstevel@tonic-gate 	case 4:
33427c478bd9Sstevel@tonic-gate 		mask = 0x0f << ((h & 0x1) << 2);
33437c478bd9Sstevel@tonic-gate 		return ((cp[h >> 1] & mask) == mask);
33447c478bd9Sstevel@tonic-gate 	case 2:
33457c478bd9Sstevel@tonic-gate 		mask = 0x03 << ((h & 0x3) << 1);
33467c478bd9Sstevel@tonic-gate 		return ((cp[h >> 2] & mask) == mask);
33477c478bd9Sstevel@tonic-gate 	case 1:
33487c478bd9Sstevel@tonic-gate 		mask = 0x01 << (h & 0x7);
33497c478bd9Sstevel@tonic-gate 		return ((cp[h >> 3] & mask) == mask);
33507c478bd9Sstevel@tonic-gate 	default:
33517c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "isblock bad fs_frag %d\n", fs->fs_frag);
33527c478bd9Sstevel@tonic-gate 		return (0);
33537c478bd9Sstevel@tonic-gate 	}
33547c478bd9Sstevel@tonic-gate }
33557c478bd9Sstevel@tonic-gate 
33567c478bd9Sstevel@tonic-gate /*
33577c478bd9Sstevel@tonic-gate  * take a block out of the map
33587c478bd9Sstevel@tonic-gate  */
33597c478bd9Sstevel@tonic-gate static void
33607c478bd9Sstevel@tonic-gate clrblock(struct fs *fs, unsigned char *cp, int h)
33617c478bd9Sstevel@tonic-gate {
33627c478bd9Sstevel@tonic-gate 	switch ((fs)->fs_frag) {
33637c478bd9Sstevel@tonic-gate 	case 8:
33647c478bd9Sstevel@tonic-gate 		cp[h] = 0;
33657c478bd9Sstevel@tonic-gate 		return;
33667c478bd9Sstevel@tonic-gate 	case 4:
33677c478bd9Sstevel@tonic-gate 		cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
33687c478bd9Sstevel@tonic-gate 		return;
33697c478bd9Sstevel@tonic-gate 	case 2:
33707c478bd9Sstevel@tonic-gate 		cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
33717c478bd9Sstevel@tonic-gate 		return;
33727c478bd9Sstevel@tonic-gate 	case 1:
33737c478bd9Sstevel@tonic-gate 		cp[h >> 3] &= ~(0x01 << (h & 0x7));
33747c478bd9Sstevel@tonic-gate 		return;
33757c478bd9Sstevel@tonic-gate 	default:
33767c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
33777c478bd9Sstevel@tonic-gate 		    gettext("clrblock: bad fs_frag value %d\n"), fs->fs_frag);
33787c478bd9Sstevel@tonic-gate 		return;
33797c478bd9Sstevel@tonic-gate 	}
33807c478bd9Sstevel@tonic-gate }
33817c478bd9Sstevel@tonic-gate 
33827c478bd9Sstevel@tonic-gate /*
33837c478bd9Sstevel@tonic-gate  * put a block into the map
33847c478bd9Sstevel@tonic-gate  */
33857c478bd9Sstevel@tonic-gate static void
33867c478bd9Sstevel@tonic-gate setblock(struct fs *fs, unsigned char *cp, int h)
33877c478bd9Sstevel@tonic-gate {
33887c478bd9Sstevel@tonic-gate 	switch (fs->fs_frag) {
33897c478bd9Sstevel@tonic-gate 	case 8:
33907c478bd9Sstevel@tonic-gate 		cp[h] = 0xff;
33917c478bd9Sstevel@tonic-gate 		return;
33927c478bd9Sstevel@tonic-gate 	case 4:
33937c478bd9Sstevel@tonic-gate 		cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
33947c478bd9Sstevel@tonic-gate 		return;
33957c478bd9Sstevel@tonic-gate 	case 2:
33967c478bd9Sstevel@tonic-gate 		cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
33977c478bd9Sstevel@tonic-gate 		return;
33987c478bd9Sstevel@tonic-gate 	case 1:
33997c478bd9Sstevel@tonic-gate 		cp[h >> 3] |= (0x01 << (h & 0x7));
34007c478bd9Sstevel@tonic-gate 		return;
34017c478bd9Sstevel@tonic-gate 	default:
34027c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
34037c478bd9Sstevel@tonic-gate 		    gettext("setblock: bad fs_frag value %d\n"), fs->fs_frag);
34047c478bd9Sstevel@tonic-gate 		return;
34057c478bd9Sstevel@tonic-gate 	}
34067c478bd9Sstevel@tonic-gate }
34077c478bd9Sstevel@tonic-gate 
34087c478bd9Sstevel@tonic-gate static void
34097c478bd9Sstevel@tonic-gate usage()
34107c478bd9Sstevel@tonic-gate {
34117c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
34127c478bd9Sstevel@tonic-gate 	    gettext("ufs usage: mkfs [-F FSType] [-V] [-m] [-o options] "
34137c478bd9Sstevel@tonic-gate 		"special "			/* param 0 */
34147c478bd9Sstevel@tonic-gate 		"size(sectors) \\ \n"));	/* param 1 */
34157c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
34167c478bd9Sstevel@tonic-gate 		"[nsect "			/* param 2 */
34177c478bd9Sstevel@tonic-gate 		"ntrack "			/* param 3 */
34187c478bd9Sstevel@tonic-gate 		"bsize "			/* param 4 */
34197c478bd9Sstevel@tonic-gate 		"fragsize "			/* param 5 */
34207c478bd9Sstevel@tonic-gate 		"cpg "				/* param 6 */
34217c478bd9Sstevel@tonic-gate 		"free "				/* param 7 */
34227c478bd9Sstevel@tonic-gate 		"rps "				/* param 8 */
34237c478bd9Sstevel@tonic-gate 		"nbpi "				/* param 9 */
34247c478bd9Sstevel@tonic-gate 		"opt "				/* param 10 */
34257c478bd9Sstevel@tonic-gate 		"apc "				/* param 11 */
34267c478bd9Sstevel@tonic-gate 		"gap "				/* param 12 */
34277c478bd9Sstevel@tonic-gate 		"nrpos "			/* param 13 */
34287c478bd9Sstevel@tonic-gate 		"maxcontig "			/* param 14 */
34297c478bd9Sstevel@tonic-gate 		"mtb]\n");			/* param 15 */
34307c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
34317c478bd9Sstevel@tonic-gate 		gettext(" -m : dump fs cmd line used to make this partition\n"
34327c478bd9Sstevel@tonic-gate 		" -V :print this command line and return\n"
34337c478bd9Sstevel@tonic-gate 		" -o :ufs options: :nsect=%d,ntrack=%d,bsize=%d,fragsize=%d\n"
34347c478bd9Sstevel@tonic-gate 		" -o :ufs options: :cgsize=%d,free=%d,rps=%d,nbpi=%d,opt=%c\n"
34357c478bd9Sstevel@tonic-gate 		" -o :ufs options: :apc=%d,gap=%d,nrpos=%d,maxcontig=%d\n"
3436355d6bb5Sswilcox 		" -o :ufs options: :mtb=%c,calcsb,calcbinsb\n"
34377c478bd9Sstevel@tonic-gate "NOTE that all -o suboptions: must be separated only by commas so as to\n"
34387c478bd9Sstevel@tonic-gate "be parsed as a single argument\n"),
34397c478bd9Sstevel@tonic-gate 		nsect, ntrack, bsize, fragsize, cpg, sblock.fs_minfree, rps,
34407c478bd9Sstevel@tonic-gate 		nbpi, opt, apc, (rotdelay == -1) ? 0 : rotdelay,
34417c478bd9Sstevel@tonic-gate 		sblock.fs_nrpos, maxcontig, mtb);
34427c478bd9Sstevel@tonic-gate 	lockexit(32);
34437c478bd9Sstevel@tonic-gate }
34447c478bd9Sstevel@tonic-gate 
34457c478bd9Sstevel@tonic-gate /*ARGSUSED*/
34467c478bd9Sstevel@tonic-gate static void
34477c478bd9Sstevel@tonic-gate dump_fscmd(char *fsys, int fsi)
34487c478bd9Sstevel@tonic-gate {
34497c478bd9Sstevel@tonic-gate 	int64_t used, bpcg, inospercg;
34507c478bd9Sstevel@tonic-gate 	int64_t nbpi;
34517c478bd9Sstevel@tonic-gate 	uint64_t nbytes64;
34527c478bd9Sstevel@tonic-gate 
34537c478bd9Sstevel@tonic-gate 	bzero((char *)&sblock, sizeof (sblock));
34547c478bd9Sstevel@tonic-gate 	rdfs((diskaddr_t)SBLOCK, SBSIZE, (char *)&sblock);
34557c478bd9Sstevel@tonic-gate 
34567c478bd9Sstevel@tonic-gate 	/*
34577c478bd9Sstevel@tonic-gate 	 * ensure a valid file system and if not, exit with error or else
34587c478bd9Sstevel@tonic-gate 	 * we will end up computing block numbers etc and dividing by zero
34597c478bd9Sstevel@tonic-gate 	 * which will cause floating point errors in this routine.
34607c478bd9Sstevel@tonic-gate 	 */
34617c478bd9Sstevel@tonic-gate 
34627c478bd9Sstevel@tonic-gate 	if ((sblock.fs_magic != FS_MAGIC) &&
34637c478bd9Sstevel@tonic-gate 	    (sblock.fs_magic != MTB_UFS_MAGIC)) {
34647c478bd9Sstevel@tonic-gate 	    (void) fprintf(stderr, gettext(
34657c478bd9Sstevel@tonic-gate 		"[not currently a valid file system - bad superblock]\n"));
34667c478bd9Sstevel@tonic-gate 		lockexit(32);
34677c478bd9Sstevel@tonic-gate 	}
34687c478bd9Sstevel@tonic-gate 
34696451fdbcSvsakar 	if (sblock.fs_magic == FS_MAGIC &&
34706451fdbcSvsakar 	    (sblock.fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 &&
34716451fdbcSvsakar 	    sblock.fs_version != UFS_VERSION_MIN)) {
34726451fdbcSvsakar 	    (void) fprintf(stderr, gettext(
34736451fdbcSvsakar 		"Unknown version of UFS format: %d\n"), sblock.fs_version);
34746451fdbcSvsakar 		lockexit(32);
34756451fdbcSvsakar 	}
34766451fdbcSvsakar 
34777c478bd9Sstevel@tonic-gate 	if (sblock.fs_magic == MTB_UFS_MAGIC &&
34787c478bd9Sstevel@tonic-gate 	    (sblock.fs_version > MTB_UFS_VERSION_1 ||
34797c478bd9Sstevel@tonic-gate 	    sblock.fs_version < MTB_UFS_VERSION_MIN)) {
34807c478bd9Sstevel@tonic-gate 	    (void) fprintf(stderr, gettext(
34817c478bd9Sstevel@tonic-gate 		"Unknown version of UFS format: %d\n"), sblock.fs_version);
34827c478bd9Sstevel@tonic-gate 		lockexit(32);
34837c478bd9Sstevel@tonic-gate 	}
34847c478bd9Sstevel@tonic-gate 
34857c478bd9Sstevel@tonic-gate 	/*
34867c478bd9Sstevel@tonic-gate 	 * Compute a reasonable nbpi value.
34877c478bd9Sstevel@tonic-gate 	 * The algorithm for "used" is copied from code
34887c478bd9Sstevel@tonic-gate 	 * in main() verbatim.
34897c478bd9Sstevel@tonic-gate 	 * The nbpi equation is taken from main where the
34907c478bd9Sstevel@tonic-gate 	 * fs_ipg value is set for the last time.  The INOPB(...) - 1
34917c478bd9Sstevel@tonic-gate 	 * is used to account for the roundup.
34927c478bd9Sstevel@tonic-gate 	 * The problem is that a range of nbpi values map to
34937c478bd9Sstevel@tonic-gate 	 * the same file system layout.  So it is not possible
34947c478bd9Sstevel@tonic-gate 	 * to calculate the exact value specified when the file
34957c478bd9Sstevel@tonic-gate 	 * system was created.  So instead we determine the top
34967c478bd9Sstevel@tonic-gate 	 * end of the range of values.
34977c478bd9Sstevel@tonic-gate 	 */
34987c478bd9Sstevel@tonic-gate 	bpcg = sblock.fs_spc * sectorsize;
34997c478bd9Sstevel@tonic-gate 	inospercg = (int64_t)roundup(bpcg / sizeof (struct dinode),
35007c478bd9Sstevel@tonic-gate 	    INOPB(&sblock));
35017c478bd9Sstevel@tonic-gate 	if (inospercg > MAXIpG(&sblock))
35027c478bd9Sstevel@tonic-gate 		inospercg = MAXIpG(&sblock);
35037c478bd9Sstevel@tonic-gate 	used = (int64_t)
35047c478bd9Sstevel@tonic-gate 	    (sblock.fs_iblkno + inospercg / INOPF(&sblock)) * NSPF(&sblock);
35057c478bd9Sstevel@tonic-gate 	used *= sectorsize;
35067c478bd9Sstevel@tonic-gate 	nbytes64 = (uint64_t)sblock.fs_cpg * bpcg - used;
35077c478bd9Sstevel@tonic-gate 
35087c478bd9Sstevel@tonic-gate 	/*
35097c478bd9Sstevel@tonic-gate 	 * The top end of the range of values for nbpi may not be
35107c478bd9Sstevel@tonic-gate 	 * a valid command line value for mkfs. Report the bottom
35117c478bd9Sstevel@tonic-gate 	 * end instead.
35127c478bd9Sstevel@tonic-gate 	 */
35137c478bd9Sstevel@tonic-gate 	nbpi = (int64_t)(nbytes64 / (sblock.fs_ipg));
35147c478bd9Sstevel@tonic-gate 
35157c478bd9Sstevel@tonic-gate 	(void) fprintf(stdout, gettext("mkfs -F ufs -o "), fsys);
35167c478bd9Sstevel@tonic-gate 	(void) fprintf(stdout, "nsect=%d,ntrack=%d,",
35177c478bd9Sstevel@tonic-gate 	    sblock.fs_nsect, sblock.fs_ntrak);
35187c478bd9Sstevel@tonic-gate 	(void) fprintf(stdout, "bsize=%d,fragsize=%d,cgsize=%d,free=%d,",
35197c478bd9Sstevel@tonic-gate 	    sblock.fs_bsize, sblock.fs_fsize, sblock.fs_cpg, sblock.fs_minfree);
35207c478bd9Sstevel@tonic-gate 	(void) fprintf(stdout, "rps=%d,nbpi=%lld,opt=%c,apc=%d,gap=%d,",
35217c478bd9Sstevel@tonic-gate 	    sblock.fs_rps, nbpi, (sblock.fs_optim == FS_OPTSPACE) ? 's' : 't',
35227c478bd9Sstevel@tonic-gate 	    (sblock.fs_ntrak * sblock.fs_nsect) - sblock.fs_spc,
35237c478bd9Sstevel@tonic-gate 	    sblock.fs_rotdelay);
35247c478bd9Sstevel@tonic-gate 	(void) fprintf(stdout, "nrpos=%d,maxcontig=%d,mtb=%c ",
35257c478bd9Sstevel@tonic-gate 	    sblock.fs_nrpos, sblock.fs_maxcontig,
35267c478bd9Sstevel@tonic-gate 	    ((sblock.fs_magic == MTB_UFS_MAGIC) ? 'y' : 'n'));
35277c478bd9Sstevel@tonic-gate 	(void) fprintf(stdout, "%s %lld\n", fsys,
35287c478bd9Sstevel@tonic-gate 	    fsbtodb(&sblock, sblock.fs_size));
35297c478bd9Sstevel@tonic-gate 
35307c478bd9Sstevel@tonic-gate 	bzero((char *)&sblock, sizeof (sblock));
35317c478bd9Sstevel@tonic-gate }
35327c478bd9Sstevel@tonic-gate 
35337c478bd9Sstevel@tonic-gate /* number ************************************************************* */
35347c478bd9Sstevel@tonic-gate /*									*/
35357c478bd9Sstevel@tonic-gate /* Convert a numeric string arg to binary				*/
35367c478bd9Sstevel@tonic-gate /*									*/
35377c478bd9Sstevel@tonic-gate /* Args:	d_value - default value, if have parse error		*/
35387c478bd9Sstevel@tonic-gate /*		param - the name of the argument, for error messages	*/
35397c478bd9Sstevel@tonic-gate /*		flags - parser state and what's allowed in the arg	*/
35407c478bd9Sstevel@tonic-gate /* Global arg:  string - pointer to command arg				*/
35417c478bd9Sstevel@tonic-gate /*									*/
35427c478bd9Sstevel@tonic-gate /* Valid forms: 123 | 123k | 123*123 | 123x123				*/
35437c478bd9Sstevel@tonic-gate /*									*/
35447c478bd9Sstevel@tonic-gate /* Return:	converted number					*/
35457c478bd9Sstevel@tonic-gate /*									*/
35467c478bd9Sstevel@tonic-gate /* ******************************************************************** */
35477c478bd9Sstevel@tonic-gate 
35487c478bd9Sstevel@tonic-gate static uint64_t
35497c478bd9Sstevel@tonic-gate number(uint64_t d_value, char *param, int flags)
35507c478bd9Sstevel@tonic-gate {
35517c478bd9Sstevel@tonic-gate 	char *cs;
35527c478bd9Sstevel@tonic-gate 	uint64_t n, t;
35537c478bd9Sstevel@tonic-gate 	uint64_t cut = BIG / 10;    /* limit to avoid overflow */
35547c478bd9Sstevel@tonic-gate 	int minus = 0;
35557c478bd9Sstevel@tonic-gate 
35567c478bd9Sstevel@tonic-gate 	cs = string;
35577c478bd9Sstevel@tonic-gate 	if (*cs == '-') {
35587c478bd9Sstevel@tonic-gate 		minus = 1;
35597c478bd9Sstevel@tonic-gate 		cs += 1;
35607c478bd9Sstevel@tonic-gate 	}
35617c478bd9Sstevel@tonic-gate 	if ((*cs < '0') || (*cs > '9')) {
35627c478bd9Sstevel@tonic-gate 		goto bail_out;
35637c478bd9Sstevel@tonic-gate 	}
35647c478bd9Sstevel@tonic-gate 	n = 0;
35657c478bd9Sstevel@tonic-gate 	while ((*cs >= '0') && (*cs <= '9') && (n <= cut)) {
35667c478bd9Sstevel@tonic-gate 		n = n*10 + *cs++ - '0';
35677c478bd9Sstevel@tonic-gate 	}
35687c478bd9Sstevel@tonic-gate 	if (minus)
35697c478bd9Sstevel@tonic-gate 	    n = -n;
35707c478bd9Sstevel@tonic-gate 	for (;;) {
35717c478bd9Sstevel@tonic-gate 		switch (*cs++) {
35727c478bd9Sstevel@tonic-gate 		case 'k':
35737c478bd9Sstevel@tonic-gate 			if (flags & ALLOW_END_ONLY)
35747c478bd9Sstevel@tonic-gate 				goto bail_out;
35757c478bd9Sstevel@tonic-gate 			if (n > (BIG / 1024))
35767c478bd9Sstevel@tonic-gate 				goto overflow;
35777c478bd9Sstevel@tonic-gate 			n *= 1024;
35787c478bd9Sstevel@tonic-gate 			continue;
35797c478bd9Sstevel@tonic-gate 
35807c478bd9Sstevel@tonic-gate 		case '*':
35817c478bd9Sstevel@tonic-gate 		case 'x':
35827c478bd9Sstevel@tonic-gate 			if (flags & ALLOW_END_ONLY)
35837c478bd9Sstevel@tonic-gate 				goto bail_out;
35847c478bd9Sstevel@tonic-gate 			string = cs;
35857c478bd9Sstevel@tonic-gate 			t = number(d_value, param, flags);
35867c478bd9Sstevel@tonic-gate 			if (n > (BIG / t))
35877c478bd9Sstevel@tonic-gate 				goto overflow;
35887c478bd9Sstevel@tonic-gate 			n *= t;
35897c478bd9Sstevel@tonic-gate 			cs = string + 1; /* adjust for -- below */
35907c478bd9Sstevel@tonic-gate 
35917c478bd9Sstevel@tonic-gate 			/* recursion has read rest of expression */
35927c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
35937c478bd9Sstevel@tonic-gate 
35947c478bd9Sstevel@tonic-gate 		case ',':
35957c478bd9Sstevel@tonic-gate 		case '\0':
35967c478bd9Sstevel@tonic-gate 			cs--;
35977c478bd9Sstevel@tonic-gate 			string = cs;
35987c478bd9Sstevel@tonic-gate 			return (n);
35997c478bd9Sstevel@tonic-gate 
36007c478bd9Sstevel@tonic-gate 		case '%':
36017c478bd9Sstevel@tonic-gate 			if (flags & ALLOW_END_ONLY)
36027c478bd9Sstevel@tonic-gate 				goto bail_out;
36037c478bd9Sstevel@tonic-gate 			if (flags & ALLOW_PERCENT) {
36047c478bd9Sstevel@tonic-gate 				flags &= ~ALLOW_PERCENT;
36057c478bd9Sstevel@tonic-gate 				flags |= ALLOW_END_ONLY;
36067c478bd9Sstevel@tonic-gate 				continue;
36077c478bd9Sstevel@tonic-gate 			}
36087c478bd9Sstevel@tonic-gate 			goto bail_out;
36097c478bd9Sstevel@tonic-gate 
36107c478bd9Sstevel@tonic-gate 		case 'm':
36117c478bd9Sstevel@tonic-gate 			if (flags & ALLOW_END_ONLY)
36127c478bd9Sstevel@tonic-gate 				goto bail_out;
36137c478bd9Sstevel@tonic-gate 			if (flags & ALLOW_MS1) {
36147c478bd9Sstevel@tonic-gate 				flags &= ~ALLOW_MS1;
36157c478bd9Sstevel@tonic-gate 				flags |= ALLOW_MS2;
36167c478bd9Sstevel@tonic-gate 				continue;
36177c478bd9Sstevel@tonic-gate 			}
36187c478bd9Sstevel@tonic-gate 			goto bail_out;
36197c478bd9Sstevel@tonic-gate 
36207c478bd9Sstevel@tonic-gate 		case 's':
36217c478bd9Sstevel@tonic-gate 			if (flags & ALLOW_END_ONLY)
36227c478bd9Sstevel@tonic-gate 				goto bail_out;
36237c478bd9Sstevel@tonic-gate 			if (flags & ALLOW_MS2) {
36247c478bd9Sstevel@tonic-gate 				flags &= ~ALLOW_MS2;
36257c478bd9Sstevel@tonic-gate 				flags |= ALLOW_END_ONLY;
36267c478bd9Sstevel@tonic-gate 				continue;
36277c478bd9Sstevel@tonic-gate 			}
36287c478bd9Sstevel@tonic-gate 			goto bail_out;
36297c478bd9Sstevel@tonic-gate 
36307c478bd9Sstevel@tonic-gate 		case '0': case '1': case '2': case '3': case '4':
36317c478bd9Sstevel@tonic-gate 		case '5': case '6': case '7': case '8': case '9':
36327c478bd9Sstevel@tonic-gate overflow:
36337c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
36347c478bd9Sstevel@tonic-gate 			    gettext("mkfs: value for %s overflowed\n"),
36357c478bd9Sstevel@tonic-gate 			    param);
36367c478bd9Sstevel@tonic-gate 			while ((*cs != '\0') && (*cs != ','))
36377c478bd9Sstevel@tonic-gate 				cs++;
36387c478bd9Sstevel@tonic-gate 			string = cs;
36397c478bd9Sstevel@tonic-gate 			return (BIG);
36407c478bd9Sstevel@tonic-gate 
36417c478bd9Sstevel@tonic-gate 		default:
36427c478bd9Sstevel@tonic-gate bail_out:
36437c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
36447c478bd9Sstevel@tonic-gate 			    "mkfs: bad numeric arg for %s: \"%s\"\n"),
36457c478bd9Sstevel@tonic-gate 			    param, string);
36467c478bd9Sstevel@tonic-gate 			while ((*cs != '\0') && (*cs != ','))
36477c478bd9Sstevel@tonic-gate 				cs++;
36487c478bd9Sstevel@tonic-gate 			string = cs;
36497c478bd9Sstevel@tonic-gate 			if (d_value != NO_DEFAULT) {
36507c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
36517c478bd9Sstevel@tonic-gate 				    gettext("mkfs: %s reset to default %lld\n"),
36527c478bd9Sstevel@tonic-gate 				    param, d_value);
36537c478bd9Sstevel@tonic-gate 				return (d_value);
36547c478bd9Sstevel@tonic-gate 			}
36557c478bd9Sstevel@tonic-gate 			lockexit(2);
36567c478bd9Sstevel@tonic-gate 
36577c478bd9Sstevel@tonic-gate 		}
36587c478bd9Sstevel@tonic-gate 	} /* never gets here */
36597c478bd9Sstevel@tonic-gate }
36607c478bd9Sstevel@tonic-gate 
36617c478bd9Sstevel@tonic-gate /* match ************************************************************** */
36627c478bd9Sstevel@tonic-gate /*									*/
36637c478bd9Sstevel@tonic-gate /* Compare two text strings for equality				*/
36647c478bd9Sstevel@tonic-gate /*									*/
36657c478bd9Sstevel@tonic-gate /* Arg:	 s - pointer to string to match with a command arg		*/
36667c478bd9Sstevel@tonic-gate /* Global arg:  string - pointer to command arg				*/
36677c478bd9Sstevel@tonic-gate /*									*/
36687c478bd9Sstevel@tonic-gate /* Return:	1 if match, 0 if no match				*/
36697c478bd9Sstevel@tonic-gate /*		If match, also reset `string' to point to the text	*/
36707c478bd9Sstevel@tonic-gate /*		that follows the matching text.				*/
36717c478bd9Sstevel@tonic-gate /*									*/
36727c478bd9Sstevel@tonic-gate /* ******************************************************************** */
36737c478bd9Sstevel@tonic-gate 
36747c478bd9Sstevel@tonic-gate static int
36757c478bd9Sstevel@tonic-gate match(char *s)
36767c478bd9Sstevel@tonic-gate {
36777c478bd9Sstevel@tonic-gate 	char *cs;
36787c478bd9Sstevel@tonic-gate 
36797c478bd9Sstevel@tonic-gate 	cs = string;
36807c478bd9Sstevel@tonic-gate 	while (*cs++ == *s) {
36817c478bd9Sstevel@tonic-gate 		if (*s++ == '\0') {
36827c478bd9Sstevel@tonic-gate 			goto true;
36837c478bd9Sstevel@tonic-gate 		}
36847c478bd9Sstevel@tonic-gate 	}
36857c478bd9Sstevel@tonic-gate 	if (*s != '\0') {
36867c478bd9Sstevel@tonic-gate 		return (0);
36877c478bd9Sstevel@tonic-gate 	}
36887c478bd9Sstevel@tonic-gate 
36897c478bd9Sstevel@tonic-gate true:
36907c478bd9Sstevel@tonic-gate 	cs--;
36917c478bd9Sstevel@tonic-gate 	string = cs;
36927c478bd9Sstevel@tonic-gate 	return (1);
36937c478bd9Sstevel@tonic-gate }
36947c478bd9Sstevel@tonic-gate 
36957c478bd9Sstevel@tonic-gate /*
36967c478bd9Sstevel@tonic-gate  * GROWFS ROUTINES
36977c478bd9Sstevel@tonic-gate  */
36987c478bd9Sstevel@tonic-gate 
36997c478bd9Sstevel@tonic-gate /* ARGSUSED */
37007c478bd9Sstevel@tonic-gate void
37017c478bd9Sstevel@tonic-gate lockexit(int exitstatus)
37027c478bd9Sstevel@tonic-gate {
37037c478bd9Sstevel@tonic-gate 	if (Pflag) {
37047c478bd9Sstevel@tonic-gate 		/* the probe mode neither changes nor locks the filesystem */
37057c478bd9Sstevel@tonic-gate 		exit(exitstatus);
37067c478bd9Sstevel@tonic-gate 	}
37077c478bd9Sstevel@tonic-gate 
37087c478bd9Sstevel@tonic-gate 	/*
37097c478bd9Sstevel@tonic-gate 	 * flush the dirty cylinder group
37107c478bd9Sstevel@tonic-gate 	 */
37117c478bd9Sstevel@tonic-gate 	if (inlockexit == 0) {
37127c478bd9Sstevel@tonic-gate 		inlockexit = 1;
37137c478bd9Sstevel@tonic-gate 		flcg();
37147c478bd9Sstevel@tonic-gate 	}
37157c478bd9Sstevel@tonic-gate 
37167c478bd9Sstevel@tonic-gate 	if (aio_inited) {
37177c478bd9Sstevel@tonic-gate 		flush_writes();
37187c478bd9Sstevel@tonic-gate 	}
37197c478bd9Sstevel@tonic-gate 
37207c478bd9Sstevel@tonic-gate 	/*
37217c478bd9Sstevel@tonic-gate 	 * make sure the file system is unlocked before exiting
37227c478bd9Sstevel@tonic-gate 	 */
37237c478bd9Sstevel@tonic-gate 	if ((inlockexit == 1) && (!isbad)) {
37247c478bd9Sstevel@tonic-gate 		inlockexit = 2;
37257c478bd9Sstevel@tonic-gate 		ulockfs();
37267c478bd9Sstevel@tonic-gate 		/*
37277c478bd9Sstevel@tonic-gate 		 * if logging was enabled, then re-enable it
37287c478bd9Sstevel@tonic-gate 		 */
37297c478bd9Sstevel@tonic-gate 		if (waslog) {
37307c478bd9Sstevel@tonic-gate 			if (rl_log_control(fsys, _FIOLOGENABLE) != RL_SUCCESS) {
37317c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
37327c478bd9Sstevel@tonic-gate 					"failed to re-enable logging\n"));
37337c478bd9Sstevel@tonic-gate 			}
37347c478bd9Sstevel@tonic-gate 		}
37357c478bd9Sstevel@tonic-gate 	} else if (grow) {
37367c478bd9Sstevel@tonic-gate 		if (isbad) {
37377c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
37387c478bd9Sstevel@tonic-gate 				"Filesystem is currently inconsistent.  It "
37397c478bd9Sstevel@tonic-gate 				"must be repaired with fsck(1M)\nbefore being "
37407c478bd9Sstevel@tonic-gate 				"used.  Use the following command to "
37417c478bd9Sstevel@tonic-gate 				"do this:\n\n\tfsck %s\n\n"),
37427c478bd9Sstevel@tonic-gate 					fsys);
37437c478bd9Sstevel@tonic-gate 
37447c478bd9Sstevel@tonic-gate 			if (ismounted) {
37457c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
37467c478bd9Sstevel@tonic-gate 					"You will be told that the filesystem "
37477c478bd9Sstevel@tonic-gate 					"is already mounted, and asked if you\n"
37487c478bd9Sstevel@tonic-gate 					"wish to continue.  Answer `yes' to "
37497c478bd9Sstevel@tonic-gate 					"this question.\n\n"));
37507c478bd9Sstevel@tonic-gate 			}
37517c478bd9Sstevel@tonic-gate 
37527c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
37537c478bd9Sstevel@tonic-gate 					"One problem should be reported, that "
37547c478bd9Sstevel@tonic-gate 					"the summary information is bad.\n"
37557c478bd9Sstevel@tonic-gate 					"You will then be asked if it "
37567c478bd9Sstevel@tonic-gate 					"should be salvaged.  Answer `yes' "
37577c478bd9Sstevel@tonic-gate 					"to\nthis question.\n\n"));
37587c478bd9Sstevel@tonic-gate 		}
37597c478bd9Sstevel@tonic-gate 
37607c478bd9Sstevel@tonic-gate 		if (ismounted) {
37617c478bd9Sstevel@tonic-gate 			/*
37627c478bd9Sstevel@tonic-gate 			 * In theory, there's no way to get here without
37637c478bd9Sstevel@tonic-gate 			 * isbad also being set, but be robust in the
37647c478bd9Sstevel@tonic-gate 			 * face of future code changes.
37657c478bd9Sstevel@tonic-gate 			 */
37667c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
37677c478bd9Sstevel@tonic-gate 				"The filesystem is currently mounted "
37687c478bd9Sstevel@tonic-gate 				"read-only and write-locked.  "));
37697c478bd9Sstevel@tonic-gate 			if (isbad) {
37707c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
37717c478bd9Sstevel@tonic-gate 					"After\nrunning fsck, unlock the "
37727c478bd9Sstevel@tonic-gate 					"filesystem and "));
37737c478bd9Sstevel@tonic-gate 			} else {
37747c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
37757c478bd9Sstevel@tonic-gate 					"Unlock the filesystem\nand "));
37767c478bd9Sstevel@tonic-gate 			}
37777c478bd9Sstevel@tonic-gate 
37787c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
37797c478bd9Sstevel@tonic-gate 				"re-enable writing with\nthe following "
37807c478bd9Sstevel@tonic-gate 				"command:\n\n\tlockfs -u %s\n\n"),
37817c478bd9Sstevel@tonic-gate 					directory);
37827c478bd9Sstevel@tonic-gate 		}
37837c478bd9Sstevel@tonic-gate 	}
37847c478bd9Sstevel@tonic-gate 
37857c478bd9Sstevel@tonic-gate 	exit(exitstatus);
37867c478bd9Sstevel@tonic-gate }
37877c478bd9Sstevel@tonic-gate 
37887c478bd9Sstevel@tonic-gate void
37897c478bd9Sstevel@tonic-gate randomgeneration()
37907c478bd9Sstevel@tonic-gate {
37917c478bd9Sstevel@tonic-gate 	int		 i;
37927c478bd9Sstevel@tonic-gate 	struct dinode	*dp;
37937c478bd9Sstevel@tonic-gate 
37947c478bd9Sstevel@tonic-gate 	/*
37957c478bd9Sstevel@tonic-gate 	 * always perform fsirand(1) function... newfs will notice that
37967c478bd9Sstevel@tonic-gate 	 * the inodes have been randomized and will not call fsirand itself
37977c478bd9Sstevel@tonic-gate 	 */
37987c478bd9Sstevel@tonic-gate 	for (i = 0, dp = zino; i < sblock.fs_inopb; ++i, ++dp)
37997c478bd9Sstevel@tonic-gate 		IRANDOMIZE(&dp->di_ic);
38007c478bd9Sstevel@tonic-gate }
38017c478bd9Sstevel@tonic-gate 
38027c478bd9Sstevel@tonic-gate /*
38037c478bd9Sstevel@tonic-gate  * Check the size of the summary information.
38047c478bd9Sstevel@tonic-gate  * Fields in sblock are not changed in this function.
38057c478bd9Sstevel@tonic-gate  *
38067c478bd9Sstevel@tonic-gate  * For an 8K filesystem block, the maximum number of cylinder groups is 16384.
38077c478bd9Sstevel@tonic-gate  *     MAXCSBUFS {32}  *   8K  {FS block size}
38087c478bd9Sstevel@tonic-gate  *                         divided by (sizeof csum) {16}
38097c478bd9Sstevel@tonic-gate  *
38107c478bd9Sstevel@tonic-gate  * Note that MAXCSBUFS is not used in the kernel; as of Solaris 2.6 build 32,
38117c478bd9Sstevel@tonic-gate  * this is the only place where it's referenced.
38127c478bd9Sstevel@tonic-gate  */
38137c478bd9Sstevel@tonic-gate void
38147c478bd9Sstevel@tonic-gate checksummarysize()
38157c478bd9Sstevel@tonic-gate {
38167c478bd9Sstevel@tonic-gate 	diskaddr_t	dmax;
38177c478bd9Sstevel@tonic-gate 	diskaddr_t	dmin;
38187c478bd9Sstevel@tonic-gate 	int64_t	cg0frags;
38197c478bd9Sstevel@tonic-gate 	int64_t	cg0blocks;
38207c478bd9Sstevel@tonic-gate 	int64_t	maxncg;
38217c478bd9Sstevel@tonic-gate 	int64_t	maxfrags;
38227c478bd9Sstevel@tonic-gate 	uint64_t	fs_size;
38237c478bd9Sstevel@tonic-gate 	uint64_t maxfs_blocks; /* filesystem blocks for max filesystem size */
38247c478bd9Sstevel@tonic-gate 
38257c478bd9Sstevel@tonic-gate 	/*
38267c478bd9Sstevel@tonic-gate 	 * compute the maximum summary info size
38277c478bd9Sstevel@tonic-gate 	 */
38287c478bd9Sstevel@tonic-gate 	dmin = cgdmin(&sblock, 0);
38297c478bd9Sstevel@tonic-gate 	dmax = cgbase(&sblock, 0) + sblock.fs_fpg;
38307c478bd9Sstevel@tonic-gate 	fs_size = (grow) ? grow_fs_size : sblock.fs_size;
38317c478bd9Sstevel@tonic-gate 	if (dmax > fs_size)
38327c478bd9Sstevel@tonic-gate 		dmax = fs_size;
38337c478bd9Sstevel@tonic-gate 	cg0frags  = dmax - dmin;
38347c478bd9Sstevel@tonic-gate 	cg0blocks = cg0frags / sblock.fs_frag;
38357c478bd9Sstevel@tonic-gate 	cg0frags = cg0blocks * sblock.fs_frag;
38367c478bd9Sstevel@tonic-gate 	maxncg   = (longlong_t)cg0blocks *
38377c478bd9Sstevel@tonic-gate 	    (longlong_t)(sblock.fs_bsize / sizeof (struct csum));
38387c478bd9Sstevel@tonic-gate 
38397c478bd9Sstevel@tonic-gate 	maxfs_blocks = FS_MAX;
38407c478bd9Sstevel@tonic-gate 
38417c478bd9Sstevel@tonic-gate 	if (maxncg > ((longlong_t)maxfs_blocks / (longlong_t)sblock.fs_fpg) + 1)
38427c478bd9Sstevel@tonic-gate 		maxncg = ((longlong_t)maxfs_blocks /
38437c478bd9Sstevel@tonic-gate 		    (longlong_t)sblock.fs_fpg) + 1;
38447c478bd9Sstevel@tonic-gate 
38457c478bd9Sstevel@tonic-gate 	maxfrags = maxncg * (longlong_t)sblock.fs_fpg;
38467c478bd9Sstevel@tonic-gate 
38477c478bd9Sstevel@tonic-gate 	if (maxfrags > maxfs_blocks)
38487c478bd9Sstevel@tonic-gate 		maxfrags = maxfs_blocks;
38497c478bd9Sstevel@tonic-gate 
38507c478bd9Sstevel@tonic-gate 
38517c478bd9Sstevel@tonic-gate 	/*
38527c478bd9Sstevel@tonic-gate 	 * remember for later processing in extendsummaryinfo()
38537c478bd9Sstevel@tonic-gate 	 */
38547c478bd9Sstevel@tonic-gate 	if (test)
38557c478bd9Sstevel@tonic-gate 		grow_sifrag = dmin + (cg0blocks * sblock.fs_frag);
38567c478bd9Sstevel@tonic-gate 	if (testfrags == 0)
38577c478bd9Sstevel@tonic-gate 		testfrags = cg0frags;
38587c478bd9Sstevel@tonic-gate 	if (testforce)
38597c478bd9Sstevel@tonic-gate 		if (testfrags > cg0frags) {
38607c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
38617c478bd9Sstevel@tonic-gate 				gettext("Too many test frags (%lld); "
38627c478bd9Sstevel@tonic-gate 				"try %lld\n"), testfrags, cg0frags);
38637c478bd9Sstevel@tonic-gate 			lockexit(32);
38647c478bd9Sstevel@tonic-gate 		}
38657c478bd9Sstevel@tonic-gate 
38667c478bd9Sstevel@tonic-gate 	/*
38677c478bd9Sstevel@tonic-gate 	 * if summary info is too large (too many cg's) tell the user and exit
38687c478bd9Sstevel@tonic-gate 	 */
38697c478bd9Sstevel@tonic-gate 	if ((longlong_t)sblock.fs_size > maxfrags) {
38707c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
38717c478bd9Sstevel@tonic-gate 		    "Too many cylinder groups with %llu sectors;\n    try "
38727c478bd9Sstevel@tonic-gate 		    "increasing cgsize, or decreasing fssize to %llu\n"),
38737c478bd9Sstevel@tonic-gate 		    fsbtodb(&sblock, (uint64_t)sblock.fs_size),
38747c478bd9Sstevel@tonic-gate 		    fsbtodb(&sblock, (uint64_t)maxfrags));
38757c478bd9Sstevel@tonic-gate 		lockexit(32);
38767c478bd9Sstevel@tonic-gate 	}
38777c478bd9Sstevel@tonic-gate }
38787c478bd9Sstevel@tonic-gate 
38796451fdbcSvsakar /*
38806451fdbcSvsakar  * checksblock() has two uses:
38816451fdbcSvsakar  *	- One is to sanity test the superblock and is used when newfs(1M)
38826451fdbcSvsakar  *	  is invoked with the "-N" option. If any discrepancy was found,
38836451fdbcSvsakar  *	  just return whatever error was found and do not exit.
38846451fdbcSvsakar  *	- the other use of it is in places where you expect the superblock
38856451fdbcSvsakar  *	  to be sane, and if it isn't, then we exit.
38866451fdbcSvsakar  * Which of the above two actions to take is indicated with the second argument.
38876451fdbcSvsakar  */
38887c478bd9Sstevel@tonic-gate 
38896451fdbcSvsakar int
38906451fdbcSvsakar checksblock(struct fs sb, int proceed)
38916451fdbcSvsakar {
38926451fdbcSvsakar 	int err = 0;
38936451fdbcSvsakar 	char *errmsg;
38946451fdbcSvsakar 
38956451fdbcSvsakar 	if ((sb.fs_magic != FS_MAGIC) && (sb.fs_magic != MTB_UFS_MAGIC)) {
38966451fdbcSvsakar 	    err = 1;
38976451fdbcSvsakar 	    errmsg = gettext("Bad superblock; magic number wrong\n");
38986451fdbcSvsakar 	} else if ((sb.fs_magic == FS_MAGIC &&
38996451fdbcSvsakar 		(sb.fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 &&
39006451fdbcSvsakar 		sb.fs_version != UFS_VERSION_MIN)) ||
39016451fdbcSvsakar 		(sb.fs_magic == MTB_UFS_MAGIC &&
39026451fdbcSvsakar 		(sb.fs_version > MTB_UFS_VERSION_1 ||
39036451fdbcSvsakar 		sb.fs_version < MTB_UFS_VERSION_MIN))) {
39046451fdbcSvsakar 	    err = 2;
39056451fdbcSvsakar 	    errmsg = gettext("Unrecognized version of UFS\n");
39066451fdbcSvsakar 	} else if (sb.fs_ncg < 1) {
39076451fdbcSvsakar 	    err = 3;
39086451fdbcSvsakar 	    errmsg = gettext("Bad superblock; ncg out of range\n");
39096451fdbcSvsakar 	} else if (sb.fs_cpg < 1) {
39106451fdbcSvsakar 	    err = 4;
39116451fdbcSvsakar 	    errmsg = gettext("Bad superblock; cpg out of range\n");
39126451fdbcSvsakar 	} else if (sb.fs_ncg * sb.fs_cpg < sb.fs_ncyl ||
39136451fdbcSvsakar 		(sb.fs_ncg - 1) * sb.fs_cpg >= sb.fs_ncyl) {
39146451fdbcSvsakar 	    err = 5;
39156451fdbcSvsakar 	    errmsg = gettext("Bad superblock; ncyl out of range\n");
39166451fdbcSvsakar 	} else if (sb.fs_sbsize <= 0 || sb.fs_sbsize > sb.fs_bsize) {
39176451fdbcSvsakar 	    err = 6;
39186451fdbcSvsakar 	    errmsg = gettext("Bad superblock; superblock size out of range\n");
39196451fdbcSvsakar 	}
39206451fdbcSvsakar 
39216451fdbcSvsakar 	if (proceed) {
39226451fdbcSvsakar 		if (err) dprintf(("%s", errmsg));
39236451fdbcSvsakar 		return (err);
39246451fdbcSvsakar 	}
39256451fdbcSvsakar 
39266451fdbcSvsakar 	if (err) {
39276451fdbcSvsakar 		fprintf(stderr, "%s", errmsg);
39287c478bd9Sstevel@tonic-gate 		lockexit(32);
39297c478bd9Sstevel@tonic-gate 	}
3930d1a180b0Smaheshvs 	return (32);
39317c478bd9Sstevel@tonic-gate }
39327c478bd9Sstevel@tonic-gate 
39337c478bd9Sstevel@tonic-gate /*
39347c478bd9Sstevel@tonic-gate  * Roll the embedded log, if any, and set up the global variables
39357c478bd9Sstevel@tonic-gate  * islog, islogok and isufslog.
39367c478bd9Sstevel@tonic-gate  */
39377c478bd9Sstevel@tonic-gate static void
39387c478bd9Sstevel@tonic-gate logsetup(char *devstr)
39397c478bd9Sstevel@tonic-gate {
39407c478bd9Sstevel@tonic-gate 	void		*buf, *ud_buf;
39417c478bd9Sstevel@tonic-gate 	extent_block_t	*ebp;
39427c478bd9Sstevel@tonic-gate 	ml_unit_t	*ul;
39437c478bd9Sstevel@tonic-gate 	ml_odunit_t	*ud;
39447c478bd9Sstevel@tonic-gate 
39457c478bd9Sstevel@tonic-gate 	/*
39467c478bd9Sstevel@tonic-gate 	 * Does the superblock indicate that we are supposed to have a log ?
39477c478bd9Sstevel@tonic-gate 	 */
39487c478bd9Sstevel@tonic-gate 	if (sblock.fs_logbno == 0) {
39497c478bd9Sstevel@tonic-gate 		/*
39507c478bd9Sstevel@tonic-gate 		 * No log present, nothing to do.
39517c478bd9Sstevel@tonic-gate 		 */
39527c478bd9Sstevel@tonic-gate 		islogok = 0;
39537c478bd9Sstevel@tonic-gate 		islog = 0;
39547c478bd9Sstevel@tonic-gate 		isufslog = 0;
39557c478bd9Sstevel@tonic-gate 		return;
39567c478bd9Sstevel@tonic-gate 	} else {
39577c478bd9Sstevel@tonic-gate 		/*
39587c478bd9Sstevel@tonic-gate 		 * There's a log in a yet unknown state, attempt to roll it.
39597c478bd9Sstevel@tonic-gate 		 */
39607c478bd9Sstevel@tonic-gate 		islog = 1;
39617c478bd9Sstevel@tonic-gate 		islogok = 0;
39627c478bd9Sstevel@tonic-gate 		isufslog = 0;
39637c478bd9Sstevel@tonic-gate 
39647c478bd9Sstevel@tonic-gate 		/*
39657c478bd9Sstevel@tonic-gate 		 * We failed to roll the log, bail out.
39667c478bd9Sstevel@tonic-gate 		 */
39677c478bd9Sstevel@tonic-gate 		if (rl_roll_log(devstr) != RL_SUCCESS)
39687c478bd9Sstevel@tonic-gate 			return;
39697c478bd9Sstevel@tonic-gate 
39707c478bd9Sstevel@tonic-gate 		isufslog = 1;
39717c478bd9Sstevel@tonic-gate 
39727c478bd9Sstevel@tonic-gate 		/* log is not okay; check the fs */
39737c478bd9Sstevel@tonic-gate 		if ((FSOKAY != (sblock.fs_state + sblock.fs_time)) ||
39747c478bd9Sstevel@tonic-gate 		    (sblock.fs_clean != FSLOG))
39757c478bd9Sstevel@tonic-gate 			return;
39767c478bd9Sstevel@tonic-gate 
39777c478bd9Sstevel@tonic-gate 		/* get the log allocation block */
39787c478bd9Sstevel@tonic-gate 		buf = (void *)malloc(DEV_BSIZE);
39797c478bd9Sstevel@tonic-gate 		if (buf == (void *) NULL)
39807c478bd9Sstevel@tonic-gate 			return;
39817c478bd9Sstevel@tonic-gate 
39827c478bd9Sstevel@tonic-gate 		ud_buf = (void *)malloc(DEV_BSIZE);
39837c478bd9Sstevel@tonic-gate 		if (ud_buf == (void *) NULL) {
39847c478bd9Sstevel@tonic-gate 			free(buf);
39857c478bd9Sstevel@tonic-gate 			return;
39867c478bd9Sstevel@tonic-gate 		}
39877c478bd9Sstevel@tonic-gate 
39887c478bd9Sstevel@tonic-gate 		rdfs((diskaddr_t)logbtodb(&sblock, sblock.fs_logbno),
39897c478bd9Sstevel@tonic-gate 		    DEV_BSIZE, buf);
39907c478bd9Sstevel@tonic-gate 		ebp = (extent_block_t *)buf;
39917c478bd9Sstevel@tonic-gate 
39927c478bd9Sstevel@tonic-gate 		/* log allocation block is not okay; check the fs */
39937c478bd9Sstevel@tonic-gate 		if (ebp->type != LUFS_EXTENTS) {
39947c478bd9Sstevel@tonic-gate 			free(buf);
39957c478bd9Sstevel@tonic-gate 			free(ud_buf);
39967c478bd9Sstevel@tonic-gate 			return;
39977c478bd9Sstevel@tonic-gate 		}
39987c478bd9Sstevel@tonic-gate 
39997c478bd9Sstevel@tonic-gate 		/* get the log state block(s) */
40007c478bd9Sstevel@tonic-gate 		rdfs((diskaddr_t)logbtodb(&sblock, ebp->extents[0].pbno),
40017c478bd9Sstevel@tonic-gate 		    DEV_BSIZE, ud_buf);
40027c478bd9Sstevel@tonic-gate 		ud = (ml_odunit_t *)ud_buf;
40037c478bd9Sstevel@tonic-gate 		ul = (ml_unit_t *)malloc(sizeof (*ul));
40047c478bd9Sstevel@tonic-gate 		ul->un_ondisk = *ud;
40057c478bd9Sstevel@tonic-gate 
40067c478bd9Sstevel@tonic-gate 		/* log state is okay */
40077c478bd9Sstevel@tonic-gate 		if ((ul->un_chksum == ul->un_head_ident + ul->un_tail_ident) &&
40087c478bd9Sstevel@tonic-gate 		    (ul->un_version == LUFS_VERSION_LATEST) &&
40097c478bd9Sstevel@tonic-gate 		    (ul->un_badlog == 0))
40107c478bd9Sstevel@tonic-gate 			islogok = 1;
40117c478bd9Sstevel@tonic-gate 		free(ud_buf);
40127c478bd9Sstevel@tonic-gate 		free(buf);
40137c478bd9Sstevel@tonic-gate 		free(ul);
40147c478bd9Sstevel@tonic-gate 	}
40157c478bd9Sstevel@tonic-gate }
40167c478bd9Sstevel@tonic-gate 
40177c478bd9Sstevel@tonic-gate void
40187c478bd9Sstevel@tonic-gate growinit(char *devstr)
40197c478bd9Sstevel@tonic-gate {
40207c478bd9Sstevel@tonic-gate 	int	i;
40217c478bd9Sstevel@tonic-gate 	char	buf[DEV_BSIZE];
40227c478bd9Sstevel@tonic-gate 
40237c478bd9Sstevel@tonic-gate 	/*
40247c478bd9Sstevel@tonic-gate 	 * Read and verify the superblock
40257c478bd9Sstevel@tonic-gate 	 */
40267c478bd9Sstevel@tonic-gate 	rdfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize, (char *)&sblock);
40276451fdbcSvsakar 	(void) checksblock(sblock, 0);
40287c478bd9Sstevel@tonic-gate 	if (sblock.fs_postblformat != FS_DYNAMICPOSTBLFMT) {
40297c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
40307c478bd9Sstevel@tonic-gate 			gettext("old file system format; can't growfs\n"));
40317c478bd9Sstevel@tonic-gate 		lockexit(32);
40327c478bd9Sstevel@tonic-gate 	}
40337c478bd9Sstevel@tonic-gate 
40347c478bd9Sstevel@tonic-gate 	/*
40357c478bd9Sstevel@tonic-gate 	 * can't shrink a file system
40367c478bd9Sstevel@tonic-gate 	 */
40377c478bd9Sstevel@tonic-gate 	grow_fssize = fsbtodb(&sblock, (uint64_t)sblock.fs_size);
40387c478bd9Sstevel@tonic-gate 	if (fssize_db < grow_fssize) {
40397c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
40407c478bd9Sstevel@tonic-gate 		    gettext("%lld sectors < current size of %lld sectors\n"),
40417c478bd9Sstevel@tonic-gate 		    fssize_db, grow_fssize);
40427c478bd9Sstevel@tonic-gate 		lockexit(32);
40437c478bd9Sstevel@tonic-gate 	}
40447c478bd9Sstevel@tonic-gate 
40457c478bd9Sstevel@tonic-gate 	/*
40467c478bd9Sstevel@tonic-gate 	 * can't grow a system to over a terabyte unless it was set up
40477c478bd9Sstevel@tonic-gate 	 * as an MTB UFS file system.
40487c478bd9Sstevel@tonic-gate 	 */
40497c478bd9Sstevel@tonic-gate 	if (mtb == 'y' && sblock.fs_magic != MTB_UFS_MAGIC) {
40507c478bd9Sstevel@tonic-gate 		if (fssize_db >= SECTORS_PER_TERABYTE) {
40517c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
40527c478bd9Sstevel@tonic-gate "File system was not set up with the multi-terabyte format.\n"));
40537c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
40547c478bd9Sstevel@tonic-gate "Its size cannot be increased to a terabyte or more.\n"));
40557c478bd9Sstevel@tonic-gate 		} else {
40567c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
40577c478bd9Sstevel@tonic-gate "Cannot convert file system to multi-terabyte format.\n"));
40587c478bd9Sstevel@tonic-gate 		}
40597c478bd9Sstevel@tonic-gate 		lockexit(32);
40607c478bd9Sstevel@tonic-gate 	}
40617c478bd9Sstevel@tonic-gate 
40627c478bd9Sstevel@tonic-gate 	logsetup(devstr);
40637c478bd9Sstevel@tonic-gate 
40647c478bd9Sstevel@tonic-gate 	/*
40657c478bd9Sstevel@tonic-gate 	 * can't growfs when logging device has errors
40667c478bd9Sstevel@tonic-gate 	 */
40677c478bd9Sstevel@tonic-gate 	if ((islog && !islogok) ||
40687c478bd9Sstevel@tonic-gate 	    ((FSOKAY == (sblock.fs_state + sblock.fs_time)) &&
40697c478bd9Sstevel@tonic-gate 	    (sblock.fs_clean == FSLOG && !islog))) {
40707c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
40717c478bd9Sstevel@tonic-gate 			gettext("logging device has errors; can't growfs\n"));
40727c478bd9Sstevel@tonic-gate 		lockexit(32);
40737c478bd9Sstevel@tonic-gate 	}
40747c478bd9Sstevel@tonic-gate 
40757c478bd9Sstevel@tonic-gate 	/*
40767c478bd9Sstevel@tonic-gate 	 * disable ufs logging for growing
40777c478bd9Sstevel@tonic-gate 	 */
40787c478bd9Sstevel@tonic-gate 	if (isufslog) {
40797c478bd9Sstevel@tonic-gate 		if (rl_log_control(devstr, _FIOLOGDISABLE) != RL_SUCCESS) {
40807c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
40817c478bd9Sstevel@tonic-gate 				"failed to disable logging\n"));
40827c478bd9Sstevel@tonic-gate 			lockexit(32);
40837c478bd9Sstevel@tonic-gate 		}
40847c478bd9Sstevel@tonic-gate 		islog = 0;
40857c478bd9Sstevel@tonic-gate 		waslog = 1;
40867c478bd9Sstevel@tonic-gate 	}
40877c478bd9Sstevel@tonic-gate 
40887c478bd9Sstevel@tonic-gate 	/*
40897c478bd9Sstevel@tonic-gate 	 * if mounted write lock the file system to be grown
40907c478bd9Sstevel@tonic-gate 	 */
40917c478bd9Sstevel@tonic-gate 	if (ismounted)
40927c478bd9Sstevel@tonic-gate 		wlockfs();
40937c478bd9Sstevel@tonic-gate 
40947c478bd9Sstevel@tonic-gate 	/*
40957c478bd9Sstevel@tonic-gate 	 * refresh dynamic superblock state - disabling logging will have
40967c478bd9Sstevel@tonic-gate 	 * changed the amount of free space available in the file system
40977c478bd9Sstevel@tonic-gate 	 */
40987c478bd9Sstevel@tonic-gate 	rdfs((diskaddr_t)(SBOFF / sectorsize), sbsize, (char *)&sblock);
40997c478bd9Sstevel@tonic-gate 
41007c478bd9Sstevel@tonic-gate 	/*
41017c478bd9Sstevel@tonic-gate 	 * make sure device is big enough
41027c478bd9Sstevel@tonic-gate 	 */
41037c478bd9Sstevel@tonic-gate 	rdfs((diskaddr_t)fssize_db - 1, DEV_BSIZE, buf);
41047c478bd9Sstevel@tonic-gate 	wtfs((diskaddr_t)fssize_db - 1, DEV_BSIZE, buf);
41057c478bd9Sstevel@tonic-gate 
41067c478bd9Sstevel@tonic-gate 	/*
41077c478bd9Sstevel@tonic-gate 	 * read current summary information
41087c478bd9Sstevel@tonic-gate 	 */
41097c478bd9Sstevel@tonic-gate 	grow_fscs = read_summaryinfo(&sblock);
41107c478bd9Sstevel@tonic-gate 
41117c478bd9Sstevel@tonic-gate 	/*
41127c478bd9Sstevel@tonic-gate 	 * save some current size related fields from the superblock
41137c478bd9Sstevel@tonic-gate 	 * These are used in extendsummaryinfo()
41147c478bd9Sstevel@tonic-gate 	 */
41157c478bd9Sstevel@tonic-gate 	grow_fs_size	= sblock.fs_size;
41167c478bd9Sstevel@tonic-gate 	grow_fs_ncg	= sblock.fs_ncg;
41177c478bd9Sstevel@tonic-gate 	grow_fs_csaddr	= (diskaddr_t)sblock.fs_csaddr;
41187c478bd9Sstevel@tonic-gate 	grow_fs_cssize	= sblock.fs_cssize;
41197c478bd9Sstevel@tonic-gate 
41207c478bd9Sstevel@tonic-gate 	/*
41217c478bd9Sstevel@tonic-gate 	 * save and reset the clean flag
41227c478bd9Sstevel@tonic-gate 	 */
41237c478bd9Sstevel@tonic-gate 	if (FSOKAY == (sblock.fs_state + sblock.fs_time))
41247c478bd9Sstevel@tonic-gate 		grow_fs_clean = sblock.fs_clean;
41257c478bd9Sstevel@tonic-gate 	else
41267c478bd9Sstevel@tonic-gate 		grow_fs_clean = FSBAD;
41277c478bd9Sstevel@tonic-gate 	sblock.fs_clean = FSBAD;
41287c478bd9Sstevel@tonic-gate 	sblock.fs_state = FSOKAY - sblock.fs_time;
41297c478bd9Sstevel@tonic-gate 	isbad = 1;
41307c478bd9Sstevel@tonic-gate 	wtfs((diskaddr_t)(SBOFF / sectorsize), sbsize, (char *)&sblock);
41317c478bd9Sstevel@tonic-gate }
41327c478bd9Sstevel@tonic-gate 
41337c478bd9Sstevel@tonic-gate void
41347c478bd9Sstevel@tonic-gate checkdev(char *rdev, char *bdev)
41357c478bd9Sstevel@tonic-gate {
41367c478bd9Sstevel@tonic-gate 	struct stat64	statarea;
41377c478bd9Sstevel@tonic-gate 
41387c478bd9Sstevel@tonic-gate 	if (stat64(bdev, &statarea) < 0) {
41397c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("can't check mount point; "));
41407c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("can't stat %s\n"), bdev);
41417c478bd9Sstevel@tonic-gate 		lockexit(32);
41427c478bd9Sstevel@tonic-gate 	}
41437c478bd9Sstevel@tonic-gate 	if ((statarea.st_mode & S_IFMT) != S_IFBLK) {
41447c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
41457c478bd9Sstevel@tonic-gate 		    "can't check mount point; %s is not a block device\n"),
41467c478bd9Sstevel@tonic-gate 		    bdev);
41477c478bd9Sstevel@tonic-gate 		lockexit(32);
41487c478bd9Sstevel@tonic-gate 	}
41497c478bd9Sstevel@tonic-gate 	if (stat64(rdev, &statarea) < 0) {
41507c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("can't stat %s\n"), rdev);
41517c478bd9Sstevel@tonic-gate 		lockexit(32);
41527c478bd9Sstevel@tonic-gate 	}
41537c478bd9Sstevel@tonic-gate 	if ((statarea.st_mode & S_IFMT) != S_IFCHR) {
41547c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
41557c478bd9Sstevel@tonic-gate 			gettext("%s is not a character device\n"), rdev);
41567c478bd9Sstevel@tonic-gate 		lockexit(32);
41577c478bd9Sstevel@tonic-gate 	}
41587c478bd9Sstevel@tonic-gate }
41597c478bd9Sstevel@tonic-gate 
41607c478bd9Sstevel@tonic-gate void
41617c478bd9Sstevel@tonic-gate checkmount(struct mnttab *mntp, char *bdevname)
41627c478bd9Sstevel@tonic-gate {
41637c478bd9Sstevel@tonic-gate 	struct stat64	statdir;
41647c478bd9Sstevel@tonic-gate 	struct stat64	statdev;
41657c478bd9Sstevel@tonic-gate 
41667c478bd9Sstevel@tonic-gate 	if (strcmp(bdevname, mntp->mnt_special) == 0) {
41677c478bd9Sstevel@tonic-gate 		if (stat64(mntp->mnt_mountp, &statdir) == -1) {
41687c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("can't stat %s\n"),
41697c478bd9Sstevel@tonic-gate 				mntp->mnt_mountp);
41707c478bd9Sstevel@tonic-gate 			lockexit(32);
41717c478bd9Sstevel@tonic-gate 		}
41727c478bd9Sstevel@tonic-gate 		if (stat64(mntp->mnt_special, &statdev) == -1) {
41737c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("can't stat %s\n"),
41747c478bd9Sstevel@tonic-gate 				mntp->mnt_special);
41757c478bd9Sstevel@tonic-gate 			lockexit(32);
41767c478bd9Sstevel@tonic-gate 		}
41777c478bd9Sstevel@tonic-gate 		if (statdir.st_dev != statdev.st_rdev) {
41787c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
41797c478bd9Sstevel@tonic-gate 				"%s is not mounted on %s; mnttab(4) wrong\n"),
41807c478bd9Sstevel@tonic-gate 				mntp->mnt_special, mntp->mnt_mountp);
41817c478bd9Sstevel@tonic-gate 			lockexit(32);
41827c478bd9Sstevel@tonic-gate 		}
41837c478bd9Sstevel@tonic-gate 		ismounted = 1;
41847c478bd9Sstevel@tonic-gate 		if (directory) {
41857c478bd9Sstevel@tonic-gate 			if (strcmp(mntp->mnt_mountp, directory) != 0) {
41867c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
41877c478bd9Sstevel@tonic-gate 				gettext("%s is mounted on %s, not %s\n"),
4188355d6bb5Sswilcox 				    bdevname, mntp->mnt_mountp, directory);
41897c478bd9Sstevel@tonic-gate 				lockexit(32);
41907c478bd9Sstevel@tonic-gate 			}
41917c478bd9Sstevel@tonic-gate 		} else {
41927c478bd9Sstevel@tonic-gate 			if (grow)
41937c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
4194355d6bb5Sswilcox 				    "%s is mounted on %s; can't growfs\n"),
4195355d6bb5Sswilcox 				    bdevname, mntp->mnt_mountp);
41967c478bd9Sstevel@tonic-gate 			else
41977c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
4198355d6bb5Sswilcox 				    gettext("%s is mounted, can't mkfs\n"),
4199355d6bb5Sswilcox 				    bdevname);
42007c478bd9Sstevel@tonic-gate 			lockexit(32);
42017c478bd9Sstevel@tonic-gate 		}
42027c478bd9Sstevel@tonic-gate 	}
42037c478bd9Sstevel@tonic-gate }
42047c478bd9Sstevel@tonic-gate 
42057c478bd9Sstevel@tonic-gate struct dinode	*dibuf	= 0;
42067c478bd9Sstevel@tonic-gate diskaddr_t	difrag	= 0;
42077c478bd9Sstevel@tonic-gate 
42087c478bd9Sstevel@tonic-gate struct dinode *
42097c478bd9Sstevel@tonic-gate gdinode(ino_t ino)
42107c478bd9Sstevel@tonic-gate {
42117c478bd9Sstevel@tonic-gate 	/*
42127c478bd9Sstevel@tonic-gate 	 * read the block of inodes containing inode number ino
42137c478bd9Sstevel@tonic-gate 	 */
42147c478bd9Sstevel@tonic-gate 	if (dibuf == 0)
42157c478bd9Sstevel@tonic-gate 		dibuf = (struct dinode *)malloc((unsigned)sblock.fs_bsize);
42167c478bd9Sstevel@tonic-gate 	if (itod(&sblock, ino) != difrag) {
42177c478bd9Sstevel@tonic-gate 		difrag = itod(&sblock, ino);
42187c478bd9Sstevel@tonic-gate 		rdfs(fsbtodb(&sblock, (uint64_t)difrag), (int)sblock.fs_bsize,
42197c478bd9Sstevel@tonic-gate 			(char *)dibuf);
42207c478bd9Sstevel@tonic-gate 	}
42217c478bd9Sstevel@tonic-gate 	return (dibuf + (ino % INOPB(&sblock)));
42227c478bd9Sstevel@tonic-gate }
42237c478bd9Sstevel@tonic-gate 
42247c478bd9Sstevel@tonic-gate /*
42257c478bd9Sstevel@tonic-gate  * structure that manages the frags we need for extended summary info
42267c478bd9Sstevel@tonic-gate  *	These frags can be:
42277c478bd9Sstevel@tonic-gate  *		free
42287c478bd9Sstevel@tonic-gate  *		data  block
42297c478bd9Sstevel@tonic-gate  *		alloc block
42307c478bd9Sstevel@tonic-gate  */
42317c478bd9Sstevel@tonic-gate struct csfrag {
42327c478bd9Sstevel@tonic-gate 	struct csfrag	*next;		/* next entry */
42337c478bd9Sstevel@tonic-gate 	daddr32_t	 ofrag;		/* old frag */
42347c478bd9Sstevel@tonic-gate 	daddr32_t	 nfrag;		/* new frag */
42357c478bd9Sstevel@tonic-gate 	long		 cylno;		/* cylno of nfrag */
42367c478bd9Sstevel@tonic-gate 	long		 frags;		/* number of frags */
42377c478bd9Sstevel@tonic-gate 	long		 size;		/* size in bytes */
42387c478bd9Sstevel@tonic-gate 	ino_t		 ino;		/* inode number */
42397c478bd9Sstevel@tonic-gate 	long		 fixed;		/* Boolean - Already fixed? */
42407c478bd9Sstevel@tonic-gate };
42417c478bd9Sstevel@tonic-gate struct csfrag	*csfrag;		/* state unknown */
42427c478bd9Sstevel@tonic-gate struct csfrag	*csfragino;		/* frags belonging to an inode */
42437c478bd9Sstevel@tonic-gate struct csfrag	*csfragfree;		/* frags that are free */
42447c478bd9Sstevel@tonic-gate 
42457c478bd9Sstevel@tonic-gate daddr32_t maxcsfrag	= 0;		/* maximum in range */
42467c478bd9Sstevel@tonic-gate daddr32_t mincsfrag	= 0x7fffffff;	/* minimum in range */
42477c478bd9Sstevel@tonic-gate 
42487c478bd9Sstevel@tonic-gate int
42497c478bd9Sstevel@tonic-gate csfraginrange(daddr32_t frag)
42507c478bd9Sstevel@tonic-gate {
42517c478bd9Sstevel@tonic-gate 	return ((frag >= mincsfrag) && (frag <= maxcsfrag));
42527c478bd9Sstevel@tonic-gate }
42537c478bd9Sstevel@tonic-gate 
42547c478bd9Sstevel@tonic-gate struct csfrag *
42557c478bd9Sstevel@tonic-gate findcsfrag(daddr32_t frag, struct csfrag **cfap)
42567c478bd9Sstevel@tonic-gate {
42577c478bd9Sstevel@tonic-gate 	struct csfrag	*cfp;
42587c478bd9Sstevel@tonic-gate 
42597c478bd9Sstevel@tonic-gate 	if (!csfraginrange(frag))
42607c478bd9Sstevel@tonic-gate 		return (NULL);
42617c478bd9Sstevel@tonic-gate 
42627c478bd9Sstevel@tonic-gate 	for (cfp = *cfap; cfp; cfp = cfp->next)
42637c478bd9Sstevel@tonic-gate 		if (cfp->ofrag == frag)
42647c478bd9Sstevel@tonic-gate 			return (cfp);
42657c478bd9Sstevel@tonic-gate 	return (NULL);
42667c478bd9Sstevel@tonic-gate }
42677c478bd9Sstevel@tonic-gate 
42687c478bd9Sstevel@tonic-gate void
42697c478bd9Sstevel@tonic-gate checkindirect(ino_t ino, daddr32_t *fragsp, daddr32_t frag, int level)
42707c478bd9Sstevel@tonic-gate {
42717c478bd9Sstevel@tonic-gate 	int			i;
42727c478bd9Sstevel@tonic-gate 	int			ne	= sblock.fs_bsize / sizeof (daddr32_t);
42737c478bd9Sstevel@tonic-gate 	daddr32_t			fsb[MAXBSIZE / sizeof (daddr32_t)];
42747c478bd9Sstevel@tonic-gate 
42757c478bd9Sstevel@tonic-gate 	if (frag == 0)
42767c478bd9Sstevel@tonic-gate 		return;
42777c478bd9Sstevel@tonic-gate 
42787c478bd9Sstevel@tonic-gate 	rdfs(fsbtodb(&sblock, frag), (int)sblock.fs_bsize,
42797c478bd9Sstevel@tonic-gate 	    (char *)fsb);
42807c478bd9Sstevel@tonic-gate 
42817c478bd9Sstevel@tonic-gate 	checkdirect(ino, fragsp, fsb, sblock.fs_bsize / sizeof (daddr32_t));
42827c478bd9Sstevel@tonic-gate 
42837c478bd9Sstevel@tonic-gate 	if (level)
42847c478bd9Sstevel@tonic-gate 		for (i = 0; i < ne && *fragsp; ++i)
42857c478bd9Sstevel@tonic-gate 			checkindirect(ino, fragsp, fsb[i], level-1);
42867c478bd9Sstevel@tonic-gate }
42877c478bd9Sstevel@tonic-gate 
42887c478bd9Sstevel@tonic-gate void
42897c478bd9Sstevel@tonic-gate addcsfrag(ino_t ino, daddr32_t frag, struct csfrag **cfap)
42907c478bd9Sstevel@tonic-gate {
42917c478bd9Sstevel@tonic-gate 	struct csfrag	*cfp, *curr, *prev;
42927c478bd9Sstevel@tonic-gate 
42937c478bd9Sstevel@tonic-gate 	/*
42947c478bd9Sstevel@tonic-gate 	 * establish a range for faster checking in csfraginrange()
42957c478bd9Sstevel@tonic-gate 	 */
42967c478bd9Sstevel@tonic-gate 	if (frag > maxcsfrag)
42977c478bd9Sstevel@tonic-gate 		maxcsfrag = frag;
42987c478bd9Sstevel@tonic-gate 	if (frag < mincsfrag)
42997c478bd9Sstevel@tonic-gate 		mincsfrag = frag;
43007c478bd9Sstevel@tonic-gate 
43017c478bd9Sstevel@tonic-gate 	/*
43027c478bd9Sstevel@tonic-gate 	 * if this frag belongs to an inode and is not the start of a block
43037c478bd9Sstevel@tonic-gate 	 *	then see if it is part of a frag range for this inode
43047c478bd9Sstevel@tonic-gate 	 */
43057c478bd9Sstevel@tonic-gate 	if (ino && (frag % sblock.fs_frag))
43067c478bd9Sstevel@tonic-gate 		for (cfp = *cfap; cfp; cfp = cfp->next) {
43077c478bd9Sstevel@tonic-gate 			if (ino != cfp->ino)
43087c478bd9Sstevel@tonic-gate 				continue;
43097c478bd9Sstevel@tonic-gate 			if (frag != cfp->ofrag + cfp->frags)
43107c478bd9Sstevel@tonic-gate 				continue;
43117c478bd9Sstevel@tonic-gate 			cfp->frags++;
43127c478bd9Sstevel@tonic-gate 			cfp->size += sblock.fs_fsize;
43137c478bd9Sstevel@tonic-gate 			return;
43147c478bd9Sstevel@tonic-gate 		}
43157c478bd9Sstevel@tonic-gate 	/*
43167c478bd9Sstevel@tonic-gate 	 * allocate a csfrag entry and insert it in an increasing order into the
43177c478bd9Sstevel@tonic-gate 	 * specified list
43187c478bd9Sstevel@tonic-gate 	 */
43197c478bd9Sstevel@tonic-gate 	cfp = (struct csfrag *)calloc(1, sizeof (struct csfrag));
43207c478bd9Sstevel@tonic-gate 	cfp->ino	= ino;
43217c478bd9Sstevel@tonic-gate 	cfp->ofrag	= frag;
43227c478bd9Sstevel@tonic-gate 	cfp->frags	= 1;
43237c478bd9Sstevel@tonic-gate 	cfp->size	= sblock.fs_fsize;
43247c478bd9Sstevel@tonic-gate 	for (prev = NULL, curr = *cfap; curr != NULL;
43257c478bd9Sstevel@tonic-gate 		prev = curr, curr = curr->next) {
43267c478bd9Sstevel@tonic-gate 		if (frag < curr->ofrag) {
43277c478bd9Sstevel@tonic-gate 			cfp->next = curr;
43287c478bd9Sstevel@tonic-gate 			if (prev)
43297c478bd9Sstevel@tonic-gate 				prev->next = cfp;	/* middle element */
43307c478bd9Sstevel@tonic-gate 			else
43317c478bd9Sstevel@tonic-gate 				*cfap = cfp;		/* first element */
43327c478bd9Sstevel@tonic-gate 			break;
43337c478bd9Sstevel@tonic-gate 		}
43347c478bd9Sstevel@tonic-gate 		if (curr->next == NULL) {
43357c478bd9Sstevel@tonic-gate 			curr->next = cfp;		/* last element	*/
43367c478bd9Sstevel@tonic-gate 			break;
43377c478bd9Sstevel@tonic-gate 		}
43387c478bd9Sstevel@tonic-gate 	}
43397c478bd9Sstevel@tonic-gate 	if (*cfap == NULL)	/* will happen only once */
43407c478bd9Sstevel@tonic-gate 		*cfap = cfp;
43417c478bd9Sstevel@tonic-gate }
43427c478bd9Sstevel@tonic-gate 
43437c478bd9Sstevel@tonic-gate void
43447c478bd9Sstevel@tonic-gate delcsfrag(daddr32_t frag, struct csfrag **cfap)
43457c478bd9Sstevel@tonic-gate {
43467c478bd9Sstevel@tonic-gate 	struct csfrag	*cfp;
43477c478bd9Sstevel@tonic-gate 	struct csfrag	**cfpp;
43487c478bd9Sstevel@tonic-gate 
43497c478bd9Sstevel@tonic-gate 	/*
43507c478bd9Sstevel@tonic-gate 	 * free up entry whose beginning frag matches
43517c478bd9Sstevel@tonic-gate 	 */
43527c478bd9Sstevel@tonic-gate 	for (cfpp = cfap; *cfpp; cfpp = &(*cfpp)->next) {
43537c478bd9Sstevel@tonic-gate 		if (frag == (*cfpp)->ofrag) {
43547c478bd9Sstevel@tonic-gate 			cfp = *cfpp;
43557c478bd9Sstevel@tonic-gate 			*cfpp = (*cfpp)->next;
43567c478bd9Sstevel@tonic-gate 			free((char *)cfp);
43577c478bd9Sstevel@tonic-gate 			return;
43587c478bd9Sstevel@tonic-gate 		}
43597c478bd9Sstevel@tonic-gate 	}
43607c478bd9Sstevel@tonic-gate }
43617c478bd9Sstevel@tonic-gate 
43627c478bd9Sstevel@tonic-gate /*
43637c478bd9Sstevel@tonic-gate  * See whether any of the direct blocks in the array pointed by "db" and of
43647c478bd9Sstevel@tonic-gate  * length "ne" are within the range of frags needed to extend the cylinder
43657c478bd9Sstevel@tonic-gate  * summary. If so, remove those frags from the "as-yet-unclassified" list
43667c478bd9Sstevel@tonic-gate  * (csfrag) and add them to the "owned-by-inode" list (csfragino).
43677c478bd9Sstevel@tonic-gate  * For each such frag found, decrement the frag count pointed to by fragsp.
43687c478bd9Sstevel@tonic-gate  * "ino" is the inode that contains (either directly or indirectly) the frags
43697c478bd9Sstevel@tonic-gate  * being checked.
43707c478bd9Sstevel@tonic-gate  */
43717c478bd9Sstevel@tonic-gate void
43727c478bd9Sstevel@tonic-gate checkdirect(ino_t ino, daddr32_t *fragsp, daddr32_t *db, int ne)
43737c478bd9Sstevel@tonic-gate {
43747c478bd9Sstevel@tonic-gate 	int	 i;
43757c478bd9Sstevel@tonic-gate 	int	 j;
43767c478bd9Sstevel@tonic-gate 	int	 found;
43777c478bd9Sstevel@tonic-gate 	diskaddr_t	 frag;
43787c478bd9Sstevel@tonic-gate 
43797c478bd9Sstevel@tonic-gate 	/*
43807c478bd9Sstevel@tonic-gate 	 * scan for allocation within the new summary info range
43817c478bd9Sstevel@tonic-gate 	 */
43827c478bd9Sstevel@tonic-gate 	for (i = 0; i < ne && *fragsp; ++i) {
43837c478bd9Sstevel@tonic-gate 		if ((frag = *db++) != 0) {
43847c478bd9Sstevel@tonic-gate 			found = 0;
43857c478bd9Sstevel@tonic-gate 			for (j = 0; j < sblock.fs_frag && *fragsp; ++j) {
43867c478bd9Sstevel@tonic-gate 				if (found || (found = csfraginrange(frag))) {
43877c478bd9Sstevel@tonic-gate 					addcsfrag(ino, frag, &csfragino);
43887c478bd9Sstevel@tonic-gate 					delcsfrag(frag, &csfrag);
43897c478bd9Sstevel@tonic-gate 				}
43907c478bd9Sstevel@tonic-gate 				++frag;
43917c478bd9Sstevel@tonic-gate 				--(*fragsp);
43927c478bd9Sstevel@tonic-gate 			}
43937c478bd9Sstevel@tonic-gate 		}
43947c478bd9Sstevel@tonic-gate 	}
43957c478bd9Sstevel@tonic-gate }
43967c478bd9Sstevel@tonic-gate 
43977c478bd9Sstevel@tonic-gate void
43987c478bd9Sstevel@tonic-gate findcsfragino()
43997c478bd9Sstevel@tonic-gate {
44007c478bd9Sstevel@tonic-gate 	int		 i;
44017c478bd9Sstevel@tonic-gate 	int		 j;
44027c478bd9Sstevel@tonic-gate 	daddr32_t		 frags;
44037c478bd9Sstevel@tonic-gate 	struct dinode	*dp;
44047c478bd9Sstevel@tonic-gate 
44057c478bd9Sstevel@tonic-gate 	/*
44067c478bd9Sstevel@tonic-gate 	 * scan all old inodes looking for allocations in the new
44077c478bd9Sstevel@tonic-gate 	 * summary info range.  Move the affected frag from the
44087c478bd9Sstevel@tonic-gate 	 * generic csfrag list onto the `owned-by-inode' list csfragino.
44097c478bd9Sstevel@tonic-gate 	 */
44107c478bd9Sstevel@tonic-gate 	for (i = UFSROOTINO; i < grow_fs_ncg*sblock.fs_ipg && csfrag; ++i) {
44117c478bd9Sstevel@tonic-gate 		dp = gdinode((ino_t)i);
44127c478bd9Sstevel@tonic-gate 		switch (dp->di_mode & IFMT) {
44137c478bd9Sstevel@tonic-gate 			case IFSHAD	:
44147c478bd9Sstevel@tonic-gate 			case IFLNK 	:
44157c478bd9Sstevel@tonic-gate 			case IFDIR 	:
44167c478bd9Sstevel@tonic-gate 			case IFREG 	: break;
44177c478bd9Sstevel@tonic-gate 			default		: continue;
44187c478bd9Sstevel@tonic-gate 		}
44197c478bd9Sstevel@tonic-gate 
44207c478bd9Sstevel@tonic-gate 		frags   = dbtofsb(&sblock, dp->di_blocks);
44217c478bd9Sstevel@tonic-gate 
44227c478bd9Sstevel@tonic-gate 		checkdirect((ino_t)i, &frags, &dp->di_db[0], NDADDR+NIADDR);
4423303bf60bSsdebnath 		for (j = 0; j < NIADDR && frags; ++j) {
4424303bf60bSsdebnath 			/* Negate the block if its an fallocate'd block */
4425303bf60bSsdebnath 			if (dp->di_ib[j] < 0 && dp->di_ib[j] != UFS_HOLE)
4426303bf60bSsdebnath 				checkindirect((ino_t)i, &frags,
4427303bf60bSsdebnath 				    -(dp->di_ib[j]), j);
4428303bf60bSsdebnath 			else
4429303bf60bSsdebnath 				checkindirect((ino_t)i, &frags,
4430303bf60bSsdebnath 				    dp->di_ib[j], j);
4431303bf60bSsdebnath 		}
44327c478bd9Sstevel@tonic-gate 	}
44337c478bd9Sstevel@tonic-gate }
44347c478bd9Sstevel@tonic-gate 
44357c478bd9Sstevel@tonic-gate void
44367c478bd9Sstevel@tonic-gate fixindirect(daddr32_t frag, int level)
44377c478bd9Sstevel@tonic-gate {
44387c478bd9Sstevel@tonic-gate 	int			 i;
44397c478bd9Sstevel@tonic-gate 	int			 ne	= sblock.fs_bsize / sizeof (daddr32_t);
44407c478bd9Sstevel@tonic-gate 	daddr32_t			fsb[MAXBSIZE / sizeof (daddr32_t)];
44417c478bd9Sstevel@tonic-gate 
44427c478bd9Sstevel@tonic-gate 	if (frag == 0)
44437c478bd9Sstevel@tonic-gate 		return;
44447c478bd9Sstevel@tonic-gate 
44457c478bd9Sstevel@tonic-gate 	rdfs(fsbtodb(&sblock, (uint64_t)frag), (int)sblock.fs_bsize,
44467c478bd9Sstevel@tonic-gate 	    (char *)fsb);
44477c478bd9Sstevel@tonic-gate 
44487c478bd9Sstevel@tonic-gate 	fixdirect((caddr_t)fsb, frag, fsb, ne);
44497c478bd9Sstevel@tonic-gate 
44507c478bd9Sstevel@tonic-gate 	if (level)
44517c478bd9Sstevel@tonic-gate 		for (i = 0; i < ne; ++i)
44527c478bd9Sstevel@tonic-gate 			fixindirect(fsb[i], level-1);
44537c478bd9Sstevel@tonic-gate }
44547c478bd9Sstevel@tonic-gate 
44557c478bd9Sstevel@tonic-gate void
44567c478bd9Sstevel@tonic-gate fixdirect(caddr_t bp, daddr32_t frag, daddr32_t *db, int ne)
44577c478bd9Sstevel@tonic-gate {
44587c478bd9Sstevel@tonic-gate 	int	 i;
44597c478bd9Sstevel@tonic-gate 	struct csfrag	*cfp;
44607c478bd9Sstevel@tonic-gate 
44617c478bd9Sstevel@tonic-gate 	for (i = 0; i < ne; ++i, ++db) {
44627c478bd9Sstevel@tonic-gate 		if (*db == 0)
44637c478bd9Sstevel@tonic-gate 			continue;
44647c478bd9Sstevel@tonic-gate 		if ((cfp = findcsfrag(*db, &csfragino)) == NULL)
44657c478bd9Sstevel@tonic-gate 			continue;
44667c478bd9Sstevel@tonic-gate 		*db = cfp->nfrag;
44677c478bd9Sstevel@tonic-gate 		cfp->fixed = 1;
44687c478bd9Sstevel@tonic-gate 		wtfs(fsbtodb(&sblock, (uint64_t)frag), (int)sblock.fs_bsize,
44697c478bd9Sstevel@tonic-gate 		    bp);
44707c478bd9Sstevel@tonic-gate 	}
44717c478bd9Sstevel@tonic-gate }
44727c478bd9Sstevel@tonic-gate 
44737c478bd9Sstevel@tonic-gate void
44747c478bd9Sstevel@tonic-gate fixcsfragino()
44757c478bd9Sstevel@tonic-gate {
44767c478bd9Sstevel@tonic-gate 	int		 i;
44777c478bd9Sstevel@tonic-gate 	struct dinode	*dp;
44787c478bd9Sstevel@tonic-gate 	struct csfrag	*cfp;
44797c478bd9Sstevel@tonic-gate 
44807c478bd9Sstevel@tonic-gate 	for (cfp = csfragino; cfp; cfp = cfp->next) {
44817c478bd9Sstevel@tonic-gate 		if (cfp->fixed)
44827c478bd9Sstevel@tonic-gate 			continue;
44837c478bd9Sstevel@tonic-gate 		dp = gdinode((ino_t)cfp->ino);
44847c478bd9Sstevel@tonic-gate 		fixdirect((caddr_t)dibuf, difrag, dp->di_db, NDADDR+NIADDR);
44857c478bd9Sstevel@tonic-gate 		for (i = 0; i < NIADDR; ++i)
44867c478bd9Sstevel@tonic-gate 			fixindirect(dp->di_ib[i], i);
44877c478bd9Sstevel@tonic-gate 	}
44887c478bd9Sstevel@tonic-gate }
44897c478bd9Sstevel@tonic-gate 
44907c478bd9Sstevel@tonic-gate /*
44917c478bd9Sstevel@tonic-gate  * Read the cylinders summary information specified by settings in the
44927c478bd9Sstevel@tonic-gate  * passed 'fs' structure into a new allocated array of csum structures.
44937c478bd9Sstevel@tonic-gate  * The caller is responsible for freeing the returned array.
44947c478bd9Sstevel@tonic-gate  * Return a pointer to an array of csum structures.
44957c478bd9Sstevel@tonic-gate  */
44967c478bd9Sstevel@tonic-gate static struct csum *
44977c478bd9Sstevel@tonic-gate read_summaryinfo(struct	fs *fsp)
44987c478bd9Sstevel@tonic-gate {
44997c478bd9Sstevel@tonic-gate 	struct csum 	*csp;
45007c478bd9Sstevel@tonic-gate 	int		i;
45017c478bd9Sstevel@tonic-gate 
45027c478bd9Sstevel@tonic-gate 	if ((csp = malloc((size_t)fsp->fs_cssize)) == NULL) {
45037c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("cannot create csum list,"
45047c478bd9Sstevel@tonic-gate 			" not enough memory\n"));
45057c478bd9Sstevel@tonic-gate 		exit(32);
45067c478bd9Sstevel@tonic-gate 	}
45077c478bd9Sstevel@tonic-gate 
45087c478bd9Sstevel@tonic-gate 	for (i = 0; i < fsp->fs_cssize; i += fsp->fs_bsize) {
45097c478bd9Sstevel@tonic-gate 		rdfs(fsbtodb(fsp,
45107c478bd9Sstevel@tonic-gate 			(uint64_t)(fsp->fs_csaddr + numfrags(fsp, i))),
45117c478bd9Sstevel@tonic-gate 			(int)(fsp->fs_cssize - i < fsp->fs_bsize ?
45127c478bd9Sstevel@tonic-gate 			fsp->fs_cssize - i : fsp->fs_bsize),
45137c478bd9Sstevel@tonic-gate 			((caddr_t)csp) + i);
45147c478bd9Sstevel@tonic-gate 	}
45157c478bd9Sstevel@tonic-gate 
45167c478bd9Sstevel@tonic-gate 	return (csp);
45177c478bd9Sstevel@tonic-gate }
45187c478bd9Sstevel@tonic-gate 
45197c478bd9Sstevel@tonic-gate /*
45207c478bd9Sstevel@tonic-gate  * Check the allocation of fragments that are to be made part of a csum block.
45217c478bd9Sstevel@tonic-gate  * A fragment is allocated if it is either in the csfragfree list or, it is
45227c478bd9Sstevel@tonic-gate  * in the csfragino list and has new frags associated with it.
45237c478bd9Sstevel@tonic-gate  * Return the number of allocated fragments.
45247c478bd9Sstevel@tonic-gate  */
45257c478bd9Sstevel@tonic-gate int64_t
45267c478bd9Sstevel@tonic-gate checkfragallocated(daddr32_t frag)
45277c478bd9Sstevel@tonic-gate {
45287c478bd9Sstevel@tonic-gate 	struct 	csfrag	*cfp;
45297c478bd9Sstevel@tonic-gate 	/*
45307c478bd9Sstevel@tonic-gate 	 * Since the lists are sorted we can break the search if the asked
45317c478bd9Sstevel@tonic-gate 	 * frag is smaller then the one in the list.
45327c478bd9Sstevel@tonic-gate 	 */
45337c478bd9Sstevel@tonic-gate 	for (cfp = csfragfree; cfp != NULL && frag >= cfp->ofrag;
45347c478bd9Sstevel@tonic-gate 		cfp = cfp->next) {
45357c478bd9Sstevel@tonic-gate 		if (frag == cfp->ofrag)
45367c478bd9Sstevel@tonic-gate 			return (1);
45377c478bd9Sstevel@tonic-gate 	}
45387c478bd9Sstevel@tonic-gate 	for (cfp = csfragino; cfp != NULL && frag >= cfp->ofrag;
45397c478bd9Sstevel@tonic-gate 		cfp = cfp->next) {
45407c478bd9Sstevel@tonic-gate 		if (frag == cfp->ofrag && cfp->nfrag != 0)
45417c478bd9Sstevel@tonic-gate 			return (cfp->frags);
45427c478bd9Sstevel@tonic-gate 	}
45437c478bd9Sstevel@tonic-gate 
45447c478bd9Sstevel@tonic-gate 	return (0);
45457c478bd9Sstevel@tonic-gate }
45467c478bd9Sstevel@tonic-gate 
45477c478bd9Sstevel@tonic-gate /*
45487c478bd9Sstevel@tonic-gate  * Figure out how much the filesystem can be grown. The limiting factor is
45497c478bd9Sstevel@tonic-gate  * the available free space needed to extend the cg summary info block.
45507c478bd9Sstevel@tonic-gate  * The free space is determined in three steps:
45517c478bd9Sstevel@tonic-gate  * - Try to extend the cg summary block to the required size.
45527c478bd9Sstevel@tonic-gate  * - Find free blocks in last cg.
45537c478bd9Sstevel@tonic-gate  * - Find free space in the last already allocated fragment of the summary info
45547c478bd9Sstevel@tonic-gate  *   block, and use it for additional csum structures.
45557c478bd9Sstevel@tonic-gate  * Return the maximum size of the new filesystem or 0 if it can't be grown.
45567c478bd9Sstevel@tonic-gate  * Please note that this function leaves the global list pointers csfrag,
45577c478bd9Sstevel@tonic-gate  * csfragfree, and csfragino initialized, and the caller is responsible for
45587c478bd9Sstevel@tonic-gate  * freeing the lists.
45597c478bd9Sstevel@tonic-gate  */
45607c478bd9Sstevel@tonic-gate diskaddr_t
45617c478bd9Sstevel@tonic-gate probe_summaryinfo()
45627c478bd9Sstevel@tonic-gate {
45637c478bd9Sstevel@tonic-gate 	/* fragments by which the csum block can be extended. */
45647c478bd9Sstevel@tonic-gate 	int64_t 	growth_csum_frags = 0;
45657c478bd9Sstevel@tonic-gate 	/* fragments by which the filesystem can be extended. */
45667c478bd9Sstevel@tonic-gate 	int64_t		growth_fs_frags = 0;
45677c478bd9Sstevel@tonic-gate 	int64_t		new_fs_cssize;	/* size of csum blk in the new FS */
45687c478bd9Sstevel@tonic-gate 	int64_t		new_fs_ncg;	/* number of cg in the new FS */
45697c478bd9Sstevel@tonic-gate 	int64_t 	spare_csum;
45707c478bd9Sstevel@tonic-gate 	daddr32_t	oldfrag_daddr;
45717c478bd9Sstevel@tonic-gate 	daddr32_t	newfrag_daddr;
45727c478bd9Sstevel@tonic-gate 	daddr32_t	daddr;
45737c478bd9Sstevel@tonic-gate 	int		i;
45747c478bd9Sstevel@tonic-gate 
45757c478bd9Sstevel@tonic-gate 	/*
45767c478bd9Sstevel@tonic-gate 	 * read and verify the superblock
45777c478bd9Sstevel@tonic-gate 	 */
45787c478bd9Sstevel@tonic-gate 	rdfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize, (char *)&sblock);
45796451fdbcSvsakar 	(void) checksblock(sblock, 0);
45807c478bd9Sstevel@tonic-gate 
45817c478bd9Sstevel@tonic-gate 	/*
45827c478bd9Sstevel@tonic-gate 	 * check how much we can extend the cg summary info block
45837c478bd9Sstevel@tonic-gate 	 */
45847c478bd9Sstevel@tonic-gate 
45857c478bd9Sstevel@tonic-gate 	/*
45867c478bd9Sstevel@tonic-gate 	 * read current summary information
45877c478bd9Sstevel@tonic-gate 	 */
45887c478bd9Sstevel@tonic-gate 	fscs = read_summaryinfo(&sblock);
45897c478bd9Sstevel@tonic-gate 
45907c478bd9Sstevel@tonic-gate 	/*
45917c478bd9Sstevel@tonic-gate 	 * build list of frags needed for cg summary info block extension
45927c478bd9Sstevel@tonic-gate 	 */
45937c478bd9Sstevel@tonic-gate 	oldfrag_daddr = howmany(sblock.fs_cssize, sblock.fs_fsize) +
45947c478bd9Sstevel@tonic-gate 		sblock.fs_csaddr;
45957c478bd9Sstevel@tonic-gate 	new_fs_ncg = howmany(dbtofsb(&sblock, fssize_db), sblock.fs_fpg);
45967c478bd9Sstevel@tonic-gate 	new_fs_cssize = fragroundup(&sblock, new_fs_ncg * sizeof (struct csum));
45977c478bd9Sstevel@tonic-gate 	newfrag_daddr = howmany(new_fs_cssize, sblock.fs_fsize) +
45987c478bd9Sstevel@tonic-gate 		sblock.fs_csaddr;
45997c478bd9Sstevel@tonic-gate 	/*
46007c478bd9Sstevel@tonic-gate 	 * add all of the frags that are required to grow the cyl summary to the
46017c478bd9Sstevel@tonic-gate 	 * csfrag list, which is the generic/unknown list, since at this point
46027c478bd9Sstevel@tonic-gate 	 * we don't yet know the state of those frags.
46037c478bd9Sstevel@tonic-gate 	 */
46047c478bd9Sstevel@tonic-gate 	for (daddr = oldfrag_daddr; daddr < newfrag_daddr; daddr++)
46057c478bd9Sstevel@tonic-gate 		addcsfrag((ino_t)0, daddr, &csfrag);
46067c478bd9Sstevel@tonic-gate 
46077c478bd9Sstevel@tonic-gate 	/*
46087c478bd9Sstevel@tonic-gate 	 * filter free fragments and allocate them. Note that the free frags
46097c478bd9Sstevel@tonic-gate 	 * must be allocated first otherwise they could be grabbed by
46107c478bd9Sstevel@tonic-gate 	 * alloccsfragino() for data frags.
46117c478bd9Sstevel@tonic-gate 	 */
46127c478bd9Sstevel@tonic-gate 	findcsfragfree();
46137c478bd9Sstevel@tonic-gate 	alloccsfragfree();
46147c478bd9Sstevel@tonic-gate 
46157c478bd9Sstevel@tonic-gate 	/*
46167c478bd9Sstevel@tonic-gate 	 * filter fragments owned by inodes and allocate them
46177c478bd9Sstevel@tonic-gate 	 */
46187c478bd9Sstevel@tonic-gate 	grow_fs_ncg = sblock.fs_ncg; /* findcsfragino() needs this glob. var. */
46197c478bd9Sstevel@tonic-gate 	findcsfragino();
46207c478bd9Sstevel@tonic-gate 	alloccsfragino();
46217c478bd9Sstevel@tonic-gate 
46227c478bd9Sstevel@tonic-gate 	if (notenoughspace()) {
46237c478bd9Sstevel@tonic-gate 		/*
46247c478bd9Sstevel@tonic-gate 		 * check how many consecutive fragments could be allocated
46257c478bd9Sstevel@tonic-gate 		 * in both lists.
46267c478bd9Sstevel@tonic-gate 		 */
46277c478bd9Sstevel@tonic-gate 		int64_t tmp_frags;
46287c478bd9Sstevel@tonic-gate 		for (daddr = oldfrag_daddr; daddr < newfrag_daddr;
46297c478bd9Sstevel@tonic-gate 			daddr += tmp_frags) {
46307c478bd9Sstevel@tonic-gate 			if ((tmp_frags = checkfragallocated(daddr)) > 0)
46317c478bd9Sstevel@tonic-gate 				growth_csum_frags += tmp_frags;
46327c478bd9Sstevel@tonic-gate 			else
46337c478bd9Sstevel@tonic-gate 				break;
46347c478bd9Sstevel@tonic-gate 		}
46357c478bd9Sstevel@tonic-gate 	} else {
46367c478bd9Sstevel@tonic-gate 		/*
46377c478bd9Sstevel@tonic-gate 		 * We have all we need for the new desired size,
46387c478bd9Sstevel@tonic-gate 		 * so clean up and report back.
46397c478bd9Sstevel@tonic-gate 		 */
46407c478bd9Sstevel@tonic-gate 		return (fssize_db);
46417c478bd9Sstevel@tonic-gate 	}
46427c478bd9Sstevel@tonic-gate 
46437c478bd9Sstevel@tonic-gate 	/*
46447c478bd9Sstevel@tonic-gate 	 * given the number of fragments by which the csum block can be grown
46457c478bd9Sstevel@tonic-gate 	 * compute by how many new fragments the FS can be increased.
46467c478bd9Sstevel@tonic-gate 	 * It is the number of csum instances per fragment multiplied by
46477c478bd9Sstevel@tonic-gate 	 * `growth_csum_frags' and the number of fragments per cylinder group.
46487c478bd9Sstevel@tonic-gate 	 */
46497c478bd9Sstevel@tonic-gate 	growth_fs_frags = howmany(sblock.fs_fsize, sizeof (struct csum)) *
46507c478bd9Sstevel@tonic-gate 		growth_csum_frags * sblock.fs_fpg;
46517c478bd9Sstevel@tonic-gate 
46527c478bd9Sstevel@tonic-gate 	/*
46537c478bd9Sstevel@tonic-gate 	 * compute free fragments in the last cylinder group
46547c478bd9Sstevel@tonic-gate 	 */
46557c478bd9Sstevel@tonic-gate 	rdcg(sblock.fs_ncg - 1);
46567c478bd9Sstevel@tonic-gate 	growth_fs_frags += sblock.fs_fpg - acg.cg_ndblk;
46577c478bd9Sstevel@tonic-gate 
46587c478bd9Sstevel@tonic-gate 	/*
46597c478bd9Sstevel@tonic-gate 	 * compute how many csum instances are unused in the old csum block.
46607c478bd9Sstevel@tonic-gate 	 * For each unused csum instance the FS can be grown by one cylinder
46617c478bd9Sstevel@tonic-gate 	 * group without extending the csum block.
46627c478bd9Sstevel@tonic-gate 	 */
46637c478bd9Sstevel@tonic-gate 	spare_csum = howmany(sblock.fs_cssize, sizeof (struct csum)) -
46647c478bd9Sstevel@tonic-gate 		sblock.fs_ncg;
46657c478bd9Sstevel@tonic-gate 	if (spare_csum > 0)
46667c478bd9Sstevel@tonic-gate 		growth_fs_frags += spare_csum * sblock.fs_fpg;
46677c478bd9Sstevel@tonic-gate 
46687c478bd9Sstevel@tonic-gate 	/*
46697c478bd9Sstevel@tonic-gate 	 * recalculate the new filesystem size in sectors, shorten it by
46707c478bd9Sstevel@tonic-gate 	 * the requested size `fssize_db' if necessary.
46717c478bd9Sstevel@tonic-gate 	 */
46727c478bd9Sstevel@tonic-gate 	if (growth_fs_frags > 0) {
46737c478bd9Sstevel@tonic-gate 		diskaddr_t sect;
46747c478bd9Sstevel@tonic-gate 		sect = (sblock.fs_size + growth_fs_frags) * sblock.fs_nspf;
46757c478bd9Sstevel@tonic-gate 		return ((sect > fssize_db) ? fssize_db : sect);
46767c478bd9Sstevel@tonic-gate 	}
46777c478bd9Sstevel@tonic-gate 
46787c478bd9Sstevel@tonic-gate 	return (0);
46797c478bd9Sstevel@tonic-gate }
46807c478bd9Sstevel@tonic-gate 
46817c478bd9Sstevel@tonic-gate void
46827c478bd9Sstevel@tonic-gate extendsummaryinfo()
46837c478bd9Sstevel@tonic-gate {
46847c478bd9Sstevel@tonic-gate 	int64_t		i;
46857c478bd9Sstevel@tonic-gate 	int		localtest	= test;
46867c478bd9Sstevel@tonic-gate 	int64_t		frags;
46877c478bd9Sstevel@tonic-gate 	daddr32_t		oldfrag;
46887c478bd9Sstevel@tonic-gate 	daddr32_t		newfrag;
46897c478bd9Sstevel@tonic-gate 
46907c478bd9Sstevel@tonic-gate 	/*
46917c478bd9Sstevel@tonic-gate 	 * if no-write (-N), don't bother
46927c478bd9Sstevel@tonic-gate 	 */
46937c478bd9Sstevel@tonic-gate 	if (Nflag)
46947c478bd9Sstevel@tonic-gate 		return;
46957c478bd9Sstevel@tonic-gate 
46967c478bd9Sstevel@tonic-gate again:
46977c478bd9Sstevel@tonic-gate 	flcg();
46987c478bd9Sstevel@tonic-gate 	/*
46997c478bd9Sstevel@tonic-gate 	 * summary info did not change size -- do nothing unless in test mode
47007c478bd9Sstevel@tonic-gate 	 */
47017c478bd9Sstevel@tonic-gate 	if (grow_fs_cssize == sblock.fs_cssize)
47027c478bd9Sstevel@tonic-gate 		if (!localtest)
47037c478bd9Sstevel@tonic-gate 			return;
47047c478bd9Sstevel@tonic-gate 
47057c478bd9Sstevel@tonic-gate 	/*
47067c478bd9Sstevel@tonic-gate 	 * build list of frags needed for additional summary information
47077c478bd9Sstevel@tonic-gate 	 */
47087c478bd9Sstevel@tonic-gate 	oldfrag = howmany(grow_fs_cssize, sblock.fs_fsize) + grow_fs_csaddr;
47097c478bd9Sstevel@tonic-gate 	newfrag = howmany(sblock.fs_cssize, sblock.fs_fsize) + grow_fs_csaddr;
47107c478bd9Sstevel@tonic-gate 	/*
47117c478bd9Sstevel@tonic-gate 	 * add all of the frags that are required to grow the cyl summary to the
47127c478bd9Sstevel@tonic-gate 	 * csfrag list, which is the generic/unknown list, since at this point
47137c478bd9Sstevel@tonic-gate 	 * we don't yet know the state of those frags.
47147c478bd9Sstevel@tonic-gate 	 */
47157c478bd9Sstevel@tonic-gate 	for (i = oldfrag, frags = 0; i < newfrag; ++i, ++frags)
47167c478bd9Sstevel@tonic-gate 		addcsfrag((ino_t)0, (diskaddr_t)i, &csfrag);
47177c478bd9Sstevel@tonic-gate 	/*
47187c478bd9Sstevel@tonic-gate 	 * reduce the number of data blocks in the file system (fs_dsize) by
47197c478bd9Sstevel@tonic-gate 	 * the number of frags that need to be added to the cyl summary
47207c478bd9Sstevel@tonic-gate 	 */
47217c478bd9Sstevel@tonic-gate 	sblock.fs_dsize -= (newfrag - oldfrag);
47227c478bd9Sstevel@tonic-gate 
47237c478bd9Sstevel@tonic-gate 	/*
47247c478bd9Sstevel@tonic-gate 	 * In test mode, we move more data than necessary from
47257c478bd9Sstevel@tonic-gate 	 * cylinder group 0.  The lookup/allocate/move code can be
47267c478bd9Sstevel@tonic-gate 	 * better stressed without having to create HUGE file systems.
47277c478bd9Sstevel@tonic-gate 	 */
47287c478bd9Sstevel@tonic-gate 	if (localtest)
47297c478bd9Sstevel@tonic-gate 		for (i = newfrag; i < grow_sifrag; ++i) {
47307c478bd9Sstevel@tonic-gate 			if (frags >= testfrags)
47317c478bd9Sstevel@tonic-gate 				break;
47327c478bd9Sstevel@tonic-gate 			frags++;
47337c478bd9Sstevel@tonic-gate 			addcsfrag((ino_t)0, (diskaddr_t)i, &csfrag);
47347c478bd9Sstevel@tonic-gate 		}
47357c478bd9Sstevel@tonic-gate 
47367c478bd9Sstevel@tonic-gate 	/*
47377c478bd9Sstevel@tonic-gate 	 * move frags to free or inode lists, depending on owner
47387c478bd9Sstevel@tonic-gate 	 */
47397c478bd9Sstevel@tonic-gate 	findcsfragfree();
47407c478bd9Sstevel@tonic-gate 	findcsfragino();
47417c478bd9Sstevel@tonic-gate 
47427c478bd9Sstevel@tonic-gate 	/*
47437c478bd9Sstevel@tonic-gate 	 * if not all frags can be located, file system must be inconsistent
47447c478bd9Sstevel@tonic-gate 	 */
47457c478bd9Sstevel@tonic-gate 	if (csfrag) {
47467c478bd9Sstevel@tonic-gate 		isbad = 1;	/* should already be set, but make sure */
47477c478bd9Sstevel@tonic-gate 		lockexit(32);
47487c478bd9Sstevel@tonic-gate 	}
47497c478bd9Sstevel@tonic-gate 
47507c478bd9Sstevel@tonic-gate 	/*
47517c478bd9Sstevel@tonic-gate 	 * allocate the free frags. Note that the free frags must be allocated
47527c478bd9Sstevel@tonic-gate 	 * first otherwise they could be grabbed by alloccsfragino() for data
47537c478bd9Sstevel@tonic-gate 	 * frags.
47547c478bd9Sstevel@tonic-gate 	 */
47557c478bd9Sstevel@tonic-gate 	alloccsfragfree();
47567c478bd9Sstevel@tonic-gate 	/*
47577c478bd9Sstevel@tonic-gate 	 * allocate extra space for inode frags
47587c478bd9Sstevel@tonic-gate 	 */
47597c478bd9Sstevel@tonic-gate 	alloccsfragino();
47607c478bd9Sstevel@tonic-gate 
47617c478bd9Sstevel@tonic-gate 	/*
47627c478bd9Sstevel@tonic-gate 	 * not enough space
47637c478bd9Sstevel@tonic-gate 	 */
47647c478bd9Sstevel@tonic-gate 	if (notenoughspace()) {
47657c478bd9Sstevel@tonic-gate 		unalloccsfragfree();
47667c478bd9Sstevel@tonic-gate 		unalloccsfragino();
47677c478bd9Sstevel@tonic-gate 		if (localtest && !testforce) {
47687c478bd9Sstevel@tonic-gate 			localtest = 0;
47697c478bd9Sstevel@tonic-gate 			goto again;
47707c478bd9Sstevel@tonic-gate 		}
47717c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Not enough free space\n"));
47727c478bd9Sstevel@tonic-gate 		lockexit(NOTENOUGHSPACE);
47737c478bd9Sstevel@tonic-gate 	}
47747c478bd9Sstevel@tonic-gate 
47757c478bd9Sstevel@tonic-gate 	/*
47767c478bd9Sstevel@tonic-gate 	 * copy the data from old frags to new frags
47777c478bd9Sstevel@tonic-gate 	 */
47787c478bd9Sstevel@tonic-gate 	copycsfragino();
47797c478bd9Sstevel@tonic-gate 
47807c478bd9Sstevel@tonic-gate 	/*
47817c478bd9Sstevel@tonic-gate 	 * fix the inodes to point to the new frags
47827c478bd9Sstevel@tonic-gate 	 */
47837c478bd9Sstevel@tonic-gate 	fixcsfragino();
47847c478bd9Sstevel@tonic-gate 
47857c478bd9Sstevel@tonic-gate 	/*
47867c478bd9Sstevel@tonic-gate 	 * We may have moved more frags than we needed.  Free them.
47877c478bd9Sstevel@tonic-gate 	 */
47887c478bd9Sstevel@tonic-gate 	rdcg((long)0);
47897c478bd9Sstevel@tonic-gate 	for (i = newfrag; i <= maxcsfrag; ++i)
47907c478bd9Sstevel@tonic-gate 		setbit(cg_blksfree(&acg), i-cgbase(&sblock, 0));
47917c478bd9Sstevel@tonic-gate 	wtcg();
47927c478bd9Sstevel@tonic-gate 
47937c478bd9Sstevel@tonic-gate 	flcg();
47947c478bd9Sstevel@tonic-gate }
47957c478bd9Sstevel@tonic-gate 
47967c478bd9Sstevel@tonic-gate /*
47977c478bd9Sstevel@tonic-gate  * Check if all fragments in the `csfragino' list were reallocated.
47987c478bd9Sstevel@tonic-gate  */
47997c478bd9Sstevel@tonic-gate int
48007c478bd9Sstevel@tonic-gate notenoughspace()
48017c478bd9Sstevel@tonic-gate {
48027c478bd9Sstevel@tonic-gate 	struct csfrag	*cfp;
48037c478bd9Sstevel@tonic-gate 
48047c478bd9Sstevel@tonic-gate 	/*
48057c478bd9Sstevel@tonic-gate 	 * If any element in the csfragino array has a "new frag location"
48067c478bd9Sstevel@tonic-gate 	 * of 0, the allocfrags() function was unsuccessful in allocating
48077c478bd9Sstevel@tonic-gate 	 * space for moving the frag represented by this array element.
48087c478bd9Sstevel@tonic-gate 	 */
48097c478bd9Sstevel@tonic-gate 	for (cfp = csfragino; cfp; cfp = cfp->next)
48107c478bd9Sstevel@tonic-gate 		if (cfp->nfrag == 0)
48117c478bd9Sstevel@tonic-gate 			return (1);
48127c478bd9Sstevel@tonic-gate 	return (0);
48137c478bd9Sstevel@tonic-gate }
48147c478bd9Sstevel@tonic-gate 
48157c478bd9Sstevel@tonic-gate void
48167c478bd9Sstevel@tonic-gate unalloccsfragino()
48177c478bd9Sstevel@tonic-gate {
48187c478bd9Sstevel@tonic-gate 	struct csfrag	*cfp;
48197c478bd9Sstevel@tonic-gate 
48207c478bd9Sstevel@tonic-gate 	while ((cfp = csfragino) != NULL) {
48217c478bd9Sstevel@tonic-gate 		if (cfp->nfrag)
48227c478bd9Sstevel@tonic-gate 			freefrags(cfp->nfrag, cfp->frags, cfp->cylno);
48237c478bd9Sstevel@tonic-gate 		delcsfrag(cfp->ofrag, &csfragino);
48247c478bd9Sstevel@tonic-gate 	}
48257c478bd9Sstevel@tonic-gate }
48267c478bd9Sstevel@tonic-gate 
48277c478bd9Sstevel@tonic-gate void
48287c478bd9Sstevel@tonic-gate unalloccsfragfree()
48297c478bd9Sstevel@tonic-gate {
48307c478bd9Sstevel@tonic-gate 	struct csfrag	*cfp;
48317c478bd9Sstevel@tonic-gate 
48327c478bd9Sstevel@tonic-gate 	while ((cfp = csfragfree) != NULL) {
48337c478bd9Sstevel@tonic-gate 		freefrags(cfp->ofrag, cfp->frags, cfp->cylno);
48347c478bd9Sstevel@tonic-gate 		delcsfrag(cfp->ofrag, &csfragfree);
48357c478bd9Sstevel@tonic-gate 	}
48367c478bd9Sstevel@tonic-gate }
48377c478bd9Sstevel@tonic-gate 
48387c478bd9Sstevel@tonic-gate /*
48397c478bd9Sstevel@tonic-gate  * For each frag in the "as-yet-unclassified" list (csfrag), see if
48407c478bd9Sstevel@tonic-gate  * it's free (i.e., its bit is set in the free frag bit map).  If so,
48417c478bd9Sstevel@tonic-gate  * move it from the "as-yet-unclassified" list to the csfragfree list.
48427c478bd9Sstevel@tonic-gate  */
48437c478bd9Sstevel@tonic-gate void
48447c478bd9Sstevel@tonic-gate findcsfragfree()
48457c478bd9Sstevel@tonic-gate {
48467c478bd9Sstevel@tonic-gate 	struct csfrag	*cfp;
48477c478bd9Sstevel@tonic-gate 	struct csfrag	*cfpnext;
48487c478bd9Sstevel@tonic-gate 
48497c478bd9Sstevel@tonic-gate 	/*
48507c478bd9Sstevel@tonic-gate 	 * move free frags onto the free-frag list
48517c478bd9Sstevel@tonic-gate 	 */
48527c478bd9Sstevel@tonic-gate 	rdcg((long)0);
48537c478bd9Sstevel@tonic-gate 	for (cfp = csfrag; cfp; cfp = cfpnext) {
48547c478bd9Sstevel@tonic-gate 		cfpnext = cfp->next;
48557c478bd9Sstevel@tonic-gate 		if (isset(cg_blksfree(&acg), cfp->ofrag - cgbase(&sblock, 0))) {
48567c478bd9Sstevel@tonic-gate 			addcsfrag(cfp->ino, cfp->ofrag, &csfragfree);
48577c478bd9Sstevel@tonic-gate 			delcsfrag(cfp->ofrag, &csfrag);
48587c478bd9Sstevel@tonic-gate 		}
48597c478bd9Sstevel@tonic-gate 	}
48607c478bd9Sstevel@tonic-gate }
48617c478bd9Sstevel@tonic-gate 
48627c478bd9Sstevel@tonic-gate void
48637c478bd9Sstevel@tonic-gate copycsfragino()
48647c478bd9Sstevel@tonic-gate {
48657c478bd9Sstevel@tonic-gate 	struct csfrag	*cfp;
48667c478bd9Sstevel@tonic-gate 	char		buf[MAXBSIZE];
48677c478bd9Sstevel@tonic-gate 
48687c478bd9Sstevel@tonic-gate 	/*
48697c478bd9Sstevel@tonic-gate 	 * copy data from old frags to newly allocated frags
48707c478bd9Sstevel@tonic-gate 	 */
48717c478bd9Sstevel@tonic-gate 	for (cfp = csfragino; cfp; cfp = cfp->next) {
48727c478bd9Sstevel@tonic-gate 		rdfs(fsbtodb(&sblock, (uint64_t)cfp->ofrag), (int)cfp->size,
48737c478bd9Sstevel@tonic-gate 		    buf);
48747c478bd9Sstevel@tonic-gate 		wtfs(fsbtodb(&sblock, (uint64_t)cfp->nfrag), (int)cfp->size,
48757c478bd9Sstevel@tonic-gate 		    buf);
48767c478bd9Sstevel@tonic-gate 	}
48777c478bd9Sstevel@tonic-gate }
48787c478bd9Sstevel@tonic-gate 
48797c478bd9Sstevel@tonic-gate long	curcylno	= -1;
48807c478bd9Sstevel@tonic-gate int	cylnodirty	= 0;
48817c478bd9Sstevel@tonic-gate 
48827c478bd9Sstevel@tonic-gate void
48837c478bd9Sstevel@tonic-gate rdcg(long cylno)
48847c478bd9Sstevel@tonic-gate {
48857c478bd9Sstevel@tonic-gate 	if (cylno != curcylno) {
48867c478bd9Sstevel@tonic-gate 		flcg();
48877c478bd9Sstevel@tonic-gate 		curcylno = cylno;
48887c478bd9Sstevel@tonic-gate 		rdfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, curcylno)),
48897c478bd9Sstevel@tonic-gate 			(int)sblock.fs_cgsize, (char *)&acg);
48907c478bd9Sstevel@tonic-gate 	}
48917c478bd9Sstevel@tonic-gate }
48927c478bd9Sstevel@tonic-gate 
48937c478bd9Sstevel@tonic-gate void
48947c478bd9Sstevel@tonic-gate flcg()
48957c478bd9Sstevel@tonic-gate {
48967c478bd9Sstevel@tonic-gate 	if (cylnodirty) {
48977c478bd9Sstevel@tonic-gate 		if (debug && Pflag) {
48987c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
48997c478bd9Sstevel@tonic-gate 				"Assert: cylnodirty set in probe mode\n");
49007c478bd9Sstevel@tonic-gate 			return;
49017c478bd9Sstevel@tonic-gate 		}
49027c478bd9Sstevel@tonic-gate 		resetallocinfo();
49037c478bd9Sstevel@tonic-gate 		wtfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, curcylno)),
49047c478bd9Sstevel@tonic-gate 			(int)sblock.fs_cgsize, (char *)&acg);
49057c478bd9Sstevel@tonic-gate 		cylnodirty = 0;
49067c478bd9Sstevel@tonic-gate 	}
49077c478bd9Sstevel@tonic-gate 	curcylno = -1;
49087c478bd9Sstevel@tonic-gate }
49097c478bd9Sstevel@tonic-gate 
49107c478bd9Sstevel@tonic-gate void
49117c478bd9Sstevel@tonic-gate wtcg()
49127c478bd9Sstevel@tonic-gate {
49137c478bd9Sstevel@tonic-gate 	if (!Pflag) {
49147c478bd9Sstevel@tonic-gate 		/* probe mode should never write to disk */
49157c478bd9Sstevel@tonic-gate 		cylnodirty = 1;
49167c478bd9Sstevel@tonic-gate 	}
49177c478bd9Sstevel@tonic-gate }
49187c478bd9Sstevel@tonic-gate 
49197c478bd9Sstevel@tonic-gate void
49207c478bd9Sstevel@tonic-gate allocfrags(long frags, daddr32_t *fragp, long *cylnop)
49217c478bd9Sstevel@tonic-gate {
49227c478bd9Sstevel@tonic-gate 	int	 i;
49237c478bd9Sstevel@tonic-gate 	int	 j;
49247c478bd9Sstevel@tonic-gate 	long	 bits;
49257c478bd9Sstevel@tonic-gate 	long	 bit;
49267c478bd9Sstevel@tonic-gate 
49277c478bd9Sstevel@tonic-gate 	/*
49287c478bd9Sstevel@tonic-gate 	 * Allocate a free-frag range in an old cylinder group
49297c478bd9Sstevel@tonic-gate 	 */
49307c478bd9Sstevel@tonic-gate 	for (i = 0, *fragp = 0; i < grow_fs_ncg; ++i) {
49317c478bd9Sstevel@tonic-gate 		if (((fscs+i)->cs_nffree < frags) && ((fscs+i)->cs_nbfree == 0))
49327c478bd9Sstevel@tonic-gate 			continue;
49337c478bd9Sstevel@tonic-gate 		rdcg((long)i);
49347c478bd9Sstevel@tonic-gate 		bit = bits = 0;
49357c478bd9Sstevel@tonic-gate 		while (findfreerange(&bit, &bits)) {
49367c478bd9Sstevel@tonic-gate 			if (frags <= bits)  {
49377c478bd9Sstevel@tonic-gate 				for (j = 0; j < frags; ++j)
49387c478bd9Sstevel@tonic-gate 					clrbit(cg_blksfree(&acg), bit+j);
49397c478bd9Sstevel@tonic-gate 				wtcg();
49407c478bd9Sstevel@tonic-gate 				*cylnop = i;
49417c478bd9Sstevel@tonic-gate 				*fragp  = bit + cgbase(&sblock, i);
49427c478bd9Sstevel@tonic-gate 				return;
49437c478bd9Sstevel@tonic-gate 			}
49447c478bd9Sstevel@tonic-gate 			bit += bits;
49457c478bd9Sstevel@tonic-gate 		}
49467c478bd9Sstevel@tonic-gate 	}
49477c478bd9Sstevel@tonic-gate }
49487c478bd9Sstevel@tonic-gate 
49497c478bd9Sstevel@tonic-gate /*
49507c478bd9Sstevel@tonic-gate  * Allocate space for frags that need to be moved in order to free up space for
49517c478bd9Sstevel@tonic-gate  * expanding the cylinder summary info.
49527c478bd9Sstevel@tonic-gate  * For each frag that needs to be moved (each frag or range of frags in
49537c478bd9Sstevel@tonic-gate  * the csfragino list), allocate a new location and store the frag number
49547c478bd9Sstevel@tonic-gate  * of that new location in the nfrag field of the csfrag struct.
49557c478bd9Sstevel@tonic-gate  * If a new frag can't be allocated for any element in the csfragino list,
49567c478bd9Sstevel@tonic-gate  * set the new frag number for that element to 0 and return immediately.
49577c478bd9Sstevel@tonic-gate  * The notenoughspace() function will detect this condition.
49587c478bd9Sstevel@tonic-gate  */
49597c478bd9Sstevel@tonic-gate void
49607c478bd9Sstevel@tonic-gate alloccsfragino()
49617c478bd9Sstevel@tonic-gate {
49627c478bd9Sstevel@tonic-gate 	struct csfrag	*cfp;
49637c478bd9Sstevel@tonic-gate 
49647c478bd9Sstevel@tonic-gate 	/*
49657c478bd9Sstevel@tonic-gate 	 * allocate space for inode frag ranges
49667c478bd9Sstevel@tonic-gate 	 */
49677c478bd9Sstevel@tonic-gate 	for (cfp = csfragino; cfp; cfp = cfp->next) {
49687c478bd9Sstevel@tonic-gate 		allocfrags(cfp->frags, &cfp->nfrag, &cfp->cylno);
49697c478bd9Sstevel@tonic-gate 		if (cfp->nfrag == 0)
49707c478bd9Sstevel@tonic-gate 			break;
49717c478bd9Sstevel@tonic-gate 	}
49727c478bd9Sstevel@tonic-gate }
49737c478bd9Sstevel@tonic-gate 
49747c478bd9Sstevel@tonic-gate void
49757c478bd9Sstevel@tonic-gate alloccsfragfree()
49767c478bd9Sstevel@tonic-gate {
49777c478bd9Sstevel@tonic-gate 	struct csfrag	*cfp;
49787c478bd9Sstevel@tonic-gate 
49797c478bd9Sstevel@tonic-gate 	/*
49807c478bd9Sstevel@tonic-gate 	 * allocate the free frags needed for extended summary info
49817c478bd9Sstevel@tonic-gate 	 */
49827c478bd9Sstevel@tonic-gate 	rdcg((long)0);
49837c478bd9Sstevel@tonic-gate 
49847c478bd9Sstevel@tonic-gate 	for (cfp = csfragfree; cfp; cfp = cfp->next)
49857c478bd9Sstevel@tonic-gate 		clrbit(cg_blksfree(&acg), cfp->ofrag - cgbase(&sblock, 0));
49867c478bd9Sstevel@tonic-gate 
49877c478bd9Sstevel@tonic-gate 	wtcg();
49887c478bd9Sstevel@tonic-gate }
49897c478bd9Sstevel@tonic-gate 
49907c478bd9Sstevel@tonic-gate void
49917c478bd9Sstevel@tonic-gate freefrags(daddr32_t frag, long frags, long cylno)
49927c478bd9Sstevel@tonic-gate {
49937c478bd9Sstevel@tonic-gate 	int	i;
49947c478bd9Sstevel@tonic-gate 
49957c478bd9Sstevel@tonic-gate 	/*
49967c478bd9Sstevel@tonic-gate 	 * free frags
49977c478bd9Sstevel@tonic-gate 	 */
49987c478bd9Sstevel@tonic-gate 	rdcg(cylno);
49997c478bd9Sstevel@tonic-gate 	for (i = 0; i < frags; ++i) {
50007c478bd9Sstevel@tonic-gate 		setbit(cg_blksfree(&acg), (frag+i) - cgbase(&sblock, cylno));
50017c478bd9Sstevel@tonic-gate 	}
50027c478bd9Sstevel@tonic-gate 	wtcg();
50037c478bd9Sstevel@tonic-gate }
50047c478bd9Sstevel@tonic-gate 
50057c478bd9Sstevel@tonic-gate int
50067c478bd9Sstevel@tonic-gate findfreerange(long *bitp, long *bitsp)
50077c478bd9Sstevel@tonic-gate {
50087c478bd9Sstevel@tonic-gate 	long	 bit;
50097c478bd9Sstevel@tonic-gate 
50107c478bd9Sstevel@tonic-gate 	/*
50117c478bd9Sstevel@tonic-gate 	 * find a range of free bits in a cylinder group bit map
50127c478bd9Sstevel@tonic-gate 	 */
50137c478bd9Sstevel@tonic-gate 	for (bit = *bitp, *bitsp = 0; bit < acg.cg_ndblk; ++bit)
50147c478bd9Sstevel@tonic-gate 		if (isset(cg_blksfree(&acg), bit))
50157c478bd9Sstevel@tonic-gate 			break;
50167c478bd9Sstevel@tonic-gate 
50177c478bd9Sstevel@tonic-gate 	if (bit >= acg.cg_ndblk)
50187c478bd9Sstevel@tonic-gate 		return (0);
50197c478bd9Sstevel@tonic-gate 
50207c478bd9Sstevel@tonic-gate 	*bitp  = bit;
50217c478bd9Sstevel@tonic-gate 	*bitsp = 1;
50227c478bd9Sstevel@tonic-gate 	for (++bit; bit < acg.cg_ndblk; ++bit, ++(*bitsp)) {
50237c478bd9Sstevel@tonic-gate 		if ((bit % sblock.fs_frag) == 0)
50247c478bd9Sstevel@tonic-gate 			break;
50257c478bd9Sstevel@tonic-gate 		if (isclr(cg_blksfree(&acg), bit))
50267c478bd9Sstevel@tonic-gate 			break;
50277c478bd9Sstevel@tonic-gate 	}
50287c478bd9Sstevel@tonic-gate 	return (1);
50297c478bd9Sstevel@tonic-gate }
50307c478bd9Sstevel@tonic-gate 
50317c478bd9Sstevel@tonic-gate void
50327c478bd9Sstevel@tonic-gate resetallocinfo()
50337c478bd9Sstevel@tonic-gate {
50347c478bd9Sstevel@tonic-gate 	long	cno;
50357c478bd9Sstevel@tonic-gate 	long	bit;
50367c478bd9Sstevel@tonic-gate 	long	bits;
50377c478bd9Sstevel@tonic-gate 
50387c478bd9Sstevel@tonic-gate 	/*
50397c478bd9Sstevel@tonic-gate 	 * Compute the free blocks/frags info and update the appropriate
50407c478bd9Sstevel@tonic-gate 	 * inmemory superblock, summary info, and cylinder group fields
50417c478bd9Sstevel@tonic-gate 	 */
50427c478bd9Sstevel@tonic-gate 	sblock.fs_cstotal.cs_nffree -= acg.cg_cs.cs_nffree;
50437c478bd9Sstevel@tonic-gate 	sblock.fs_cstotal.cs_nbfree -= acg.cg_cs.cs_nbfree;
50447c478bd9Sstevel@tonic-gate 
50457c478bd9Sstevel@tonic-gate 	acg.cg_cs.cs_nffree = 0;
50467c478bd9Sstevel@tonic-gate 	acg.cg_cs.cs_nbfree = 0;
50477c478bd9Sstevel@tonic-gate 
50487c478bd9Sstevel@tonic-gate 	bzero((caddr_t)acg.cg_frsum, sizeof (acg.cg_frsum));
50497c478bd9Sstevel@tonic-gate 	bzero((caddr_t)cg_blktot(&acg), (int)(acg.cg_iusedoff-acg.cg_btotoff));
50507c478bd9Sstevel@tonic-gate 
50517c478bd9Sstevel@tonic-gate 	bit = bits = 0;
50527c478bd9Sstevel@tonic-gate 	while (findfreerange(&bit, &bits)) {
50537c478bd9Sstevel@tonic-gate 		if (bits == sblock.fs_frag) {
50547c478bd9Sstevel@tonic-gate 			acg.cg_cs.cs_nbfree++;
50557c478bd9Sstevel@tonic-gate 			cno = cbtocylno(&sblock, bit);
50567c478bd9Sstevel@tonic-gate 			cg_blktot(&acg)[cno]++;
50577c478bd9Sstevel@tonic-gate 			cg_blks(&sblock, &acg, cno)[cbtorpos(&sblock, bit)]++;
50587c478bd9Sstevel@tonic-gate 		} else {
50597c478bd9Sstevel@tonic-gate 			acg.cg_cs.cs_nffree += bits;
50607c478bd9Sstevel@tonic-gate 			acg.cg_frsum[bits]++;
50617c478bd9Sstevel@tonic-gate 		}
50627c478bd9Sstevel@tonic-gate 		bit += bits;
50637c478bd9Sstevel@tonic-gate 	}
50647c478bd9Sstevel@tonic-gate 
50657c478bd9Sstevel@tonic-gate 	*(fscs + acg.cg_cgx) = acg.cg_cs;
50667c478bd9Sstevel@tonic-gate 
50677c478bd9Sstevel@tonic-gate 	sblock.fs_cstotal.cs_nffree += acg.cg_cs.cs_nffree;
50687c478bd9Sstevel@tonic-gate 	sblock.fs_cstotal.cs_nbfree += acg.cg_cs.cs_nbfree;
50697c478bd9Sstevel@tonic-gate }
50707c478bd9Sstevel@tonic-gate 
50717c478bd9Sstevel@tonic-gate void
50727c478bd9Sstevel@tonic-gate extendcg(long cylno)
50737c478bd9Sstevel@tonic-gate {
50747c478bd9Sstevel@tonic-gate 	int	i;
50757c478bd9Sstevel@tonic-gate 	diskaddr_t	dupper;
50767c478bd9Sstevel@tonic-gate 	diskaddr_t	cbase;
50777c478bd9Sstevel@tonic-gate 	diskaddr_t	dmax;
50787c478bd9Sstevel@tonic-gate 
50797c478bd9Sstevel@tonic-gate 	/*
50807c478bd9Sstevel@tonic-gate 	 * extend the cylinder group at the end of the old file system
50817c478bd9Sstevel@tonic-gate 	 * if it was partially allocated becase of lack of space
50827c478bd9Sstevel@tonic-gate 	 */
50837c478bd9Sstevel@tonic-gate 	flcg();
50847c478bd9Sstevel@tonic-gate 	rdcg(cylno);
50857c478bd9Sstevel@tonic-gate 
50867c478bd9Sstevel@tonic-gate 	dupper = acg.cg_ndblk;
50877c478bd9Sstevel@tonic-gate 	if (cylno == sblock.fs_ncg - 1)
5088355d6bb5Sswilcox 		acg.cg_ncyl = sblock.fs_ncyl - (sblock.fs_cpg * cylno);
50897c478bd9Sstevel@tonic-gate 	else
50907c478bd9Sstevel@tonic-gate 		acg.cg_ncyl = sblock.fs_cpg;
50917c478bd9Sstevel@tonic-gate 	cbase = cgbase(&sblock, cylno);
50927c478bd9Sstevel@tonic-gate 	dmax = cbase + sblock.fs_fpg;
50937c478bd9Sstevel@tonic-gate 	if (dmax > sblock.fs_size)
50947c478bd9Sstevel@tonic-gate 		dmax = sblock.fs_size;
50957c478bd9Sstevel@tonic-gate 	acg.cg_ndblk = dmax - cbase;
50967c478bd9Sstevel@tonic-gate 
50977c478bd9Sstevel@tonic-gate 	for (i = dupper; i < acg.cg_ndblk; ++i)
50987c478bd9Sstevel@tonic-gate 		setbit(cg_blksfree(&acg), i);
50997c478bd9Sstevel@tonic-gate 
51007c478bd9Sstevel@tonic-gate 	sblock.fs_dsize += (acg.cg_ndblk - dupper);
51017c478bd9Sstevel@tonic-gate 
51027c478bd9Sstevel@tonic-gate 	wtcg();
51037c478bd9Sstevel@tonic-gate 	flcg();
51047c478bd9Sstevel@tonic-gate }
51057c478bd9Sstevel@tonic-gate 
51067c478bd9Sstevel@tonic-gate struct lockfs	lockfs;
51077c478bd9Sstevel@tonic-gate int		lockfd;
51087c478bd9Sstevel@tonic-gate int		islocked;
51097c478bd9Sstevel@tonic-gate int		lockfskey;
51107c478bd9Sstevel@tonic-gate char		lockfscomment[128];
51117c478bd9Sstevel@tonic-gate 
51127c478bd9Sstevel@tonic-gate void
51137c478bd9Sstevel@tonic-gate ulockfs()
51147c478bd9Sstevel@tonic-gate {
51157c478bd9Sstevel@tonic-gate 	/*
51167c478bd9Sstevel@tonic-gate 	 * if the file system was locked, unlock it before exiting
51177c478bd9Sstevel@tonic-gate 	 */
51187c478bd9Sstevel@tonic-gate 	if (islocked == 0)
51197c478bd9Sstevel@tonic-gate 		return;
51207c478bd9Sstevel@tonic-gate 
51217c478bd9Sstevel@tonic-gate 	/*
51227c478bd9Sstevel@tonic-gate 	 * first, check if the lock held
51237c478bd9Sstevel@tonic-gate 	 */
51247c478bd9Sstevel@tonic-gate 	lockfs.lf_flags = LOCKFS_MOD;
51257c478bd9Sstevel@tonic-gate 	if (ioctl(lockfd, _FIOLFSS, &lockfs) == -1) {
51267c478bd9Sstevel@tonic-gate 		perror(directory);
51277c478bd9Sstevel@tonic-gate 		lockexit(32);
51287c478bd9Sstevel@tonic-gate 	}
51297c478bd9Sstevel@tonic-gate 
51307c478bd9Sstevel@tonic-gate 	if (LOCKFS_IS_MOD(&lockfs)) {
51317c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
51327c478bd9Sstevel@tonic-gate 			gettext("FILE SYSTEM CHANGED DURING GROWFS!\n"));
51337c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
51347c478bd9Sstevel@tonic-gate 			gettext("   See lockfs(1), umount(1), and fsck(1)\n"));
51357c478bd9Sstevel@tonic-gate 		lockexit(32);
51367c478bd9Sstevel@tonic-gate 	}
51377c478bd9Sstevel@tonic-gate 	/*
51387c478bd9Sstevel@tonic-gate 	 * unlock the file system
51397c478bd9Sstevel@tonic-gate 	 */
51407c478bd9Sstevel@tonic-gate 	lockfs.lf_lock  = LOCKFS_ULOCK;
51417c478bd9Sstevel@tonic-gate 	lockfs.lf_flags = 0;
51427c478bd9Sstevel@tonic-gate 	lockfs.lf_key   = lockfskey;
51437c478bd9Sstevel@tonic-gate 	clockfs();
51447c478bd9Sstevel@tonic-gate 	if (ioctl(lockfd, _FIOLFS, &lockfs) == -1) {
51457c478bd9Sstevel@tonic-gate 		perror(directory);
51467c478bd9Sstevel@tonic-gate 		lockexit(32);
51477c478bd9Sstevel@tonic-gate 	}
51487c478bd9Sstevel@tonic-gate }
51497c478bd9Sstevel@tonic-gate 
51507c478bd9Sstevel@tonic-gate void
51517c478bd9Sstevel@tonic-gate wlockfs()
51527c478bd9Sstevel@tonic-gate {
51537c478bd9Sstevel@tonic-gate 
51547c478bd9Sstevel@tonic-gate 	/*
51557c478bd9Sstevel@tonic-gate 	 * if no-write (-N), don't bother
51567c478bd9Sstevel@tonic-gate 	 */
51577c478bd9Sstevel@tonic-gate 	if (Nflag)
51587c478bd9Sstevel@tonic-gate 		return;
51597c478bd9Sstevel@tonic-gate 	/*
51607c478bd9Sstevel@tonic-gate 	 * open the mountpoint, and write lock the file system
51617c478bd9Sstevel@tonic-gate 	 */
51627c478bd9Sstevel@tonic-gate 	if ((lockfd = open64(directory, O_RDONLY)) == -1) {
51637c478bd9Sstevel@tonic-gate 		perror(directory);
51647c478bd9Sstevel@tonic-gate 		lockexit(32);
51657c478bd9Sstevel@tonic-gate 	}
51667c478bd9Sstevel@tonic-gate 
51677c478bd9Sstevel@tonic-gate 	/*
51687c478bd9Sstevel@tonic-gate 	 * check if it is already locked
51697c478bd9Sstevel@tonic-gate 	 */
51707c478bd9Sstevel@tonic-gate 	if (ioctl(lockfd, _FIOLFSS, &lockfs) == -1) {
51717c478bd9Sstevel@tonic-gate 		perror(directory);
51727c478bd9Sstevel@tonic-gate 		lockexit(32);
51737c478bd9Sstevel@tonic-gate 	}
51747c478bd9Sstevel@tonic-gate 
51757c478bd9Sstevel@tonic-gate 	if (lockfs.lf_lock != LOCKFS_WLOCK) {
51767c478bd9Sstevel@tonic-gate 		lockfs.lf_lock  = LOCKFS_WLOCK;
51777c478bd9Sstevel@tonic-gate 		lockfs.lf_flags = 0;
51787c478bd9Sstevel@tonic-gate 		lockfs.lf_key   = 0;
51797c478bd9Sstevel@tonic-gate 		clockfs();
51807c478bd9Sstevel@tonic-gate 		if (ioctl(lockfd, _FIOLFS, &lockfs) == -1) {
51817c478bd9Sstevel@tonic-gate 			perror(directory);
51827c478bd9Sstevel@tonic-gate 			lockexit(32);
51837c478bd9Sstevel@tonic-gate 		}
51847c478bd9Sstevel@tonic-gate 	}
51857c478bd9Sstevel@tonic-gate 	islocked = 1;
51867c478bd9Sstevel@tonic-gate 	lockfskey = lockfs.lf_key;
51877c478bd9Sstevel@tonic-gate }
51887c478bd9Sstevel@tonic-gate 
51897c478bd9Sstevel@tonic-gate void
51907c478bd9Sstevel@tonic-gate clockfs()
51917c478bd9Sstevel@tonic-gate {
51927c478bd9Sstevel@tonic-gate 	time_t	t;
51937c478bd9Sstevel@tonic-gate 	char	*ct;
51947c478bd9Sstevel@tonic-gate 
51957c478bd9Sstevel@tonic-gate 	(void) time(&t);
51967c478bd9Sstevel@tonic-gate 	ct = ctime(&t);
51977c478bd9Sstevel@tonic-gate 	ct[strlen(ct)-1] = '\0';
51987c478bd9Sstevel@tonic-gate 
51997c478bd9Sstevel@tonic-gate 	(void) sprintf(lockfscomment, "%s -- mkfs pid %d", ct, getpid());
52007c478bd9Sstevel@tonic-gate 	lockfs.lf_comlen  = strlen(lockfscomment)+1;
52017c478bd9Sstevel@tonic-gate 	lockfs.lf_comment = lockfscomment;
52027c478bd9Sstevel@tonic-gate }
52037c478bd9Sstevel@tonic-gate 
52047c478bd9Sstevel@tonic-gate /*
52057c478bd9Sstevel@tonic-gate  * Write the csum records and the superblock
52067c478bd9Sstevel@tonic-gate  */
52077c478bd9Sstevel@tonic-gate void
52087c478bd9Sstevel@tonic-gate wtsb()
52097c478bd9Sstevel@tonic-gate {
52107c478bd9Sstevel@tonic-gate 	long	i;
52117c478bd9Sstevel@tonic-gate 
52127c478bd9Sstevel@tonic-gate 	/*
52137c478bd9Sstevel@tonic-gate 	 * write summary information
52147c478bd9Sstevel@tonic-gate 	 */
52157c478bd9Sstevel@tonic-gate 	for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize)
52167c478bd9Sstevel@tonic-gate 		wtfs(fsbtodb(&sblock, (uint64_t)(sblock.fs_csaddr +
52177c478bd9Sstevel@tonic-gate 			numfrags(&sblock, i))),
52187c478bd9Sstevel@tonic-gate 			(int)(sblock.fs_cssize - i < sblock.fs_bsize ?
52197c478bd9Sstevel@tonic-gate 			sblock.fs_cssize - i : sblock.fs_bsize),
52207c478bd9Sstevel@tonic-gate 			((char *)fscs) + i);
52217c478bd9Sstevel@tonic-gate 
52227c478bd9Sstevel@tonic-gate 	/*
52237c478bd9Sstevel@tonic-gate 	 * write superblock
52247c478bd9Sstevel@tonic-gate 	 */
52257c478bd9Sstevel@tonic-gate 	sblock.fs_time = mkfstime;
52267c478bd9Sstevel@tonic-gate 	wtfs((diskaddr_t)(SBOFF / sectorsize), sbsize, (char *)&sblock);
52277c478bd9Sstevel@tonic-gate }
52287c478bd9Sstevel@tonic-gate 
52297c478bd9Sstevel@tonic-gate /*
52307c478bd9Sstevel@tonic-gate  * Verify that the optimization selection is reasonable, and advance
52317c478bd9Sstevel@tonic-gate  * the global "string" appropriately.
52327c478bd9Sstevel@tonic-gate  */
52337c478bd9Sstevel@tonic-gate static char
52347c478bd9Sstevel@tonic-gate checkopt(char *optim)
52357c478bd9Sstevel@tonic-gate {
52367c478bd9Sstevel@tonic-gate 	char	opt;
52377c478bd9Sstevel@tonic-gate 	int	limit = strcspn(optim, ",");
52387c478bd9Sstevel@tonic-gate 
52397c478bd9Sstevel@tonic-gate 	switch (limit) {
52407c478bd9Sstevel@tonic-gate 	case 0:	/* missing indicator (have comma or nul) */
52417c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
52427c478bd9Sstevel@tonic-gate 		    "mkfs: missing optimization flag reset to `t' (time)\n"));
52437c478bd9Sstevel@tonic-gate 		opt = 't';
52447c478bd9Sstevel@tonic-gate 		break;
52457c478bd9Sstevel@tonic-gate 
52467c478bd9Sstevel@tonic-gate 	case 1: /* single-character indicator */
52477c478bd9Sstevel@tonic-gate 		opt = *optim;
52487c478bd9Sstevel@tonic-gate 		if ((opt != 's') && (opt != 't')) {
52497c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
52507c478bd9Sstevel@tonic-gate 		    "mkfs: bad optimization value `%c' reset to `t' (time)\n"),
52517c478bd9Sstevel@tonic-gate 			    opt);
52527c478bd9Sstevel@tonic-gate 			opt = 't';
52537c478bd9Sstevel@tonic-gate 		}
52547c478bd9Sstevel@tonic-gate 		break;
52557c478bd9Sstevel@tonic-gate 
52567c478bd9Sstevel@tonic-gate 	default: /* multi-character indicator */
52577c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
52587c478bd9Sstevel@tonic-gate 	    "mkfs: bad optimization value `%*.*s' reset to `t' (time)\n"),
52597c478bd9Sstevel@tonic-gate 		    limit, limit, optim);
52607c478bd9Sstevel@tonic-gate 		opt = 't';
52617c478bd9Sstevel@tonic-gate 		break;
52627c478bd9Sstevel@tonic-gate 	}
52637c478bd9Sstevel@tonic-gate 
52647c478bd9Sstevel@tonic-gate 	string += limit;
52657c478bd9Sstevel@tonic-gate 
52667c478bd9Sstevel@tonic-gate 	return (opt);
52677c478bd9Sstevel@tonic-gate }
52687c478bd9Sstevel@tonic-gate 
52697c478bd9Sstevel@tonic-gate /*
52707c478bd9Sstevel@tonic-gate  * Verify that the mtb selection is reasonable, and advance
52717c478bd9Sstevel@tonic-gate  * the global "string" appropriately.
52727c478bd9Sstevel@tonic-gate  */
52737c478bd9Sstevel@tonic-gate static char
52747c478bd9Sstevel@tonic-gate checkmtb(char *mtbarg)
52757c478bd9Sstevel@tonic-gate {
52767c478bd9Sstevel@tonic-gate 	char	mtbc;
52777c478bd9Sstevel@tonic-gate 	int	limit = strcspn(mtbarg, ",");
52787c478bd9Sstevel@tonic-gate 
52797c478bd9Sstevel@tonic-gate 	switch (limit) {
52807c478bd9Sstevel@tonic-gate 	case 0:	/* missing indicator (have comma or nul) */
52817c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
52827c478bd9Sstevel@tonic-gate 		    "mkfs: missing mtb flag reset to `n' (no mtb support)\n"));
52837c478bd9Sstevel@tonic-gate 		mtbc = 'n';
52847c478bd9Sstevel@tonic-gate 		break;
52857c478bd9Sstevel@tonic-gate 
52867c478bd9Sstevel@tonic-gate 	case 1: /* single-character indicator */
52877c478bd9Sstevel@tonic-gate 		mtbc = tolower(*mtbarg);
52887c478bd9Sstevel@tonic-gate 		if ((mtbc != 'y') && (mtbc != 'n')) {
52897c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
52907c478bd9Sstevel@tonic-gate 		    "mkfs: bad mtb value `%c' reset to `n' (no mtb support)\n"),
52917c478bd9Sstevel@tonic-gate 			    mtbc);
52927c478bd9Sstevel@tonic-gate 			mtbc = 'n';
52937c478bd9Sstevel@tonic-gate 		}
52947c478bd9Sstevel@tonic-gate 		break;
52957c478bd9Sstevel@tonic-gate 
52967c478bd9Sstevel@tonic-gate 	default: /* multi-character indicator */
52977c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
52987c478bd9Sstevel@tonic-gate 	    "mkfs: bad mtb value `%*.*s' reset to `n' (no mtb support)\n"),
52997c478bd9Sstevel@tonic-gate 		    limit, limit, mtbarg);
53007c478bd9Sstevel@tonic-gate 		opt = 'n';
53017c478bd9Sstevel@tonic-gate 		break;
53027c478bd9Sstevel@tonic-gate 	}
53037c478bd9Sstevel@tonic-gate 
53047c478bd9Sstevel@tonic-gate 	string += limit;
53057c478bd9Sstevel@tonic-gate 
53067c478bd9Sstevel@tonic-gate 	return (mtbc);
53077c478bd9Sstevel@tonic-gate }
53087c478bd9Sstevel@tonic-gate 
53097c478bd9Sstevel@tonic-gate /*
53107c478bd9Sstevel@tonic-gate  * Verify that a value is in a range.  If it is not, resets it to
53117c478bd9Sstevel@tonic-gate  * its default value if one is supplied, exits otherwise.
53127c478bd9Sstevel@tonic-gate  *
53137c478bd9Sstevel@tonic-gate  * When testing, can compare user_supplied to RC_KEYWORD or RC_POSITIONAL.
53147c478bd9Sstevel@tonic-gate  */
53157c478bd9Sstevel@tonic-gate static void
53167c478bd9Sstevel@tonic-gate range_check(long *varp, char *name, long minimum, long maximum,
53177c478bd9Sstevel@tonic-gate     long def_val, int user_supplied)
53187c478bd9Sstevel@tonic-gate {
53196451fdbcSvsakar 	dprintf(("DeBuG %s : %ld (%ld %ld %ld)\n",
53206451fdbcSvsakar 		name, *varp, minimum, maximum, def_val));
53216451fdbcSvsakar 
53227c478bd9Sstevel@tonic-gate 	if ((*varp < minimum) || (*varp > maximum)) {
53237c478bd9Sstevel@tonic-gate 		if (user_supplied != RC_DEFAULT) {
53247c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
53257c478bd9Sstevel@tonic-gate 	    "mkfs: bad value for %s: %ld must be between %ld and %ld\n"),
53267c478bd9Sstevel@tonic-gate 			    name, *varp, minimum, maximum);
53277c478bd9Sstevel@tonic-gate 		}
53287c478bd9Sstevel@tonic-gate 		if (def_val != NO_DEFAULT) {
53297c478bd9Sstevel@tonic-gate 			if (user_supplied) {
53307c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
53317c478bd9Sstevel@tonic-gate 				    gettext("mkfs: %s reset to default %ld\n"),
53327c478bd9Sstevel@tonic-gate 				    name, def_val);
53337c478bd9Sstevel@tonic-gate 			}
53347c478bd9Sstevel@tonic-gate 			*varp = def_val;
53356451fdbcSvsakar 			dprintf(("DeBuG %s : %ld\n", name, *varp));
53367c478bd9Sstevel@tonic-gate 			return;
53377c478bd9Sstevel@tonic-gate 		}
53387c478bd9Sstevel@tonic-gate 		lockexit(2);
53397c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
53407c478bd9Sstevel@tonic-gate 	}
53417c478bd9Sstevel@tonic-gate }
53427c478bd9Sstevel@tonic-gate 
53437c478bd9Sstevel@tonic-gate /*
53447c478bd9Sstevel@tonic-gate  * Verify that a value is in a range.  If it is not, resets it to
53457c478bd9Sstevel@tonic-gate  * its default value if one is supplied, exits otherwise.
53467c478bd9Sstevel@tonic-gate  *
53477c478bd9Sstevel@tonic-gate  * When testing, can compare user_supplied to RC_KEYWORD or RC_POSITIONAL.
53487c478bd9Sstevel@tonic-gate  */
53497c478bd9Sstevel@tonic-gate static void
53507c478bd9Sstevel@tonic-gate range_check_64(uint64_t *varp, char *name, uint64_t minimum, uint64_t maximum,
53517c478bd9Sstevel@tonic-gate     uint64_t def_val, int user_supplied)
53527c478bd9Sstevel@tonic-gate {
53537c478bd9Sstevel@tonic-gate 	if ((*varp < minimum) || (*varp > maximum)) {
53547c478bd9Sstevel@tonic-gate 		if (user_supplied != RC_DEFAULT) {
53557c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
53567c478bd9Sstevel@tonic-gate 	    "mkfs: bad value for %s: %lld must be between %lld and %lld\n"),
53577c478bd9Sstevel@tonic-gate 			    name, *varp, minimum, maximum);
53587c478bd9Sstevel@tonic-gate 		}
53597c478bd9Sstevel@tonic-gate 		if (def_val != NO_DEFAULT) {
53607c478bd9Sstevel@tonic-gate 			if (user_supplied) {
53617c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
53627c478bd9Sstevel@tonic-gate 				    gettext("mkfs: %s reset to default %lld\n"),
53637c478bd9Sstevel@tonic-gate 				    name, def_val);
53647c478bd9Sstevel@tonic-gate 			}
53657c478bd9Sstevel@tonic-gate 			*varp = def_val;
53667c478bd9Sstevel@tonic-gate 			return;
53677c478bd9Sstevel@tonic-gate 		}
53687c478bd9Sstevel@tonic-gate 		lockexit(2);
53697c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
53707c478bd9Sstevel@tonic-gate 	}
53717c478bd9Sstevel@tonic-gate }
53727c478bd9Sstevel@tonic-gate 
53737c478bd9Sstevel@tonic-gate /*
53747c478bd9Sstevel@tonic-gate  * Blocks SIGINT from delivery.  Returns the previous mask in the
53757c478bd9Sstevel@tonic-gate  * buffer provided, so that mask may be later restored.
53767c478bd9Sstevel@tonic-gate  */
53777c478bd9Sstevel@tonic-gate static void
53787c478bd9Sstevel@tonic-gate block_sigint(sigset_t *old_mask)
53797c478bd9Sstevel@tonic-gate {
53807c478bd9Sstevel@tonic-gate 	sigset_t block_mask;
53817c478bd9Sstevel@tonic-gate 
53827c478bd9Sstevel@tonic-gate 	if (sigemptyset(&block_mask) < 0) {
53837c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext("Could not clear signal mask\n"));
53847c478bd9Sstevel@tonic-gate 		lockexit(3);
53857c478bd9Sstevel@tonic-gate 	}
53867c478bd9Sstevel@tonic-gate 	if (sigaddset(&block_mask, SIGINT) < 0) {
53877c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext("Could not set signal mask\n"));
53887c478bd9Sstevel@tonic-gate 		lockexit(3);
53897c478bd9Sstevel@tonic-gate 	}
53907c478bd9Sstevel@tonic-gate 	if (sigprocmask(SIG_BLOCK, &block_mask, old_mask) < 0) {
53917c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext("Could not block SIGINT\n"));
53927c478bd9Sstevel@tonic-gate 		lockexit(3);
53937c478bd9Sstevel@tonic-gate 	}
53947c478bd9Sstevel@tonic-gate }
53957c478bd9Sstevel@tonic-gate 
53967c478bd9Sstevel@tonic-gate /*
53977c478bd9Sstevel@tonic-gate  * Restores the signal mask that was in force before a call
53987c478bd9Sstevel@tonic-gate  * to block_sigint().  This may actually still have SIGINT blocked,
53997c478bd9Sstevel@tonic-gate  * if we've been recursively invoked.
54007c478bd9Sstevel@tonic-gate  */
54017c478bd9Sstevel@tonic-gate static void
54027c478bd9Sstevel@tonic-gate unblock_sigint(sigset_t *old_mask)
54037c478bd9Sstevel@tonic-gate {
54047c478bd9Sstevel@tonic-gate 	if (sigprocmask(SIG_UNBLOCK, old_mask, (sigset_t *)NULL) < 0) {
54057c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext("Could not restore signal mask\n"));
54067c478bd9Sstevel@tonic-gate 		lockexit(3);
54077c478bd9Sstevel@tonic-gate 	}
54087c478bd9Sstevel@tonic-gate }
54097c478bd9Sstevel@tonic-gate 
54107c478bd9Sstevel@tonic-gate /*
54117c478bd9Sstevel@tonic-gate  * Attempt to be somewhat graceful about being interrupted, rather than
54127c478bd9Sstevel@tonic-gate  * just silently leaving the filesystem in an unusable state.
54137c478bd9Sstevel@tonic-gate  *
54147c478bd9Sstevel@tonic-gate  * The kernel has blocked SIGINT upon entry, so we don't have to worry
54157c478bd9Sstevel@tonic-gate  * about recursion if the user starts pounding on the keyboard.
54167c478bd9Sstevel@tonic-gate  */
54177c478bd9Sstevel@tonic-gate static void
54187c478bd9Sstevel@tonic-gate recover_from_sigint(int signum)
54197c478bd9Sstevel@tonic-gate {
54207c478bd9Sstevel@tonic-gate 	if (fso > -1) {
54217c478bd9Sstevel@tonic-gate 		if ((Nflag != 0) || confirm_abort()) {
54227c478bd9Sstevel@tonic-gate 			lockexit(4);
54237c478bd9Sstevel@tonic-gate 		}
54247c478bd9Sstevel@tonic-gate 	}
54257c478bd9Sstevel@tonic-gate }
54267c478bd9Sstevel@tonic-gate 
54277c478bd9Sstevel@tonic-gate static int
54287c478bd9Sstevel@tonic-gate confirm_abort(void)
54297c478bd9Sstevel@tonic-gate {
54307c478bd9Sstevel@tonic-gate 	char line[80];
54317c478bd9Sstevel@tonic-gate 
54327c478bd9Sstevel@tonic-gate 	printf(gettext("\n\nAborting at this point will leave the filesystem "
54337c478bd9Sstevel@tonic-gate 		"in an inconsistent\nstate.  If you do choose to stop, "
54347c478bd9Sstevel@tonic-gate 		"you will be given instructions on how to\nrecover "
54357c478bd9Sstevel@tonic-gate 		"the filesystem.  Do you wish to cancel the filesystem "
54367c478bd9Sstevel@tonic-gate 		"grow\noperation (y/n)?"));
54377c478bd9Sstevel@tonic-gate 	if (getline(stdin, line, sizeof (line)) == EOF)
54387c478bd9Sstevel@tonic-gate 		line[0] = 'y';
54397c478bd9Sstevel@tonic-gate 
54407c478bd9Sstevel@tonic-gate 	printf("\n");
54417c478bd9Sstevel@tonic-gate 	if (line[0] == 'y' || line[0] == 'Y')
54427c478bd9Sstevel@tonic-gate 		return (1);
54437c478bd9Sstevel@tonic-gate 	else {
54447c478bd9Sstevel@tonic-gate 		return (0);
54457c478bd9Sstevel@tonic-gate 	}
54467c478bd9Sstevel@tonic-gate }
54477c478bd9Sstevel@tonic-gate 
54487c478bd9Sstevel@tonic-gate static int
54497c478bd9Sstevel@tonic-gate getline(FILE *fp, char *loc, int maxlen)
54507c478bd9Sstevel@tonic-gate {
54517c478bd9Sstevel@tonic-gate 	int n;
54527c478bd9Sstevel@tonic-gate 	char *p, *lastloc;
54537c478bd9Sstevel@tonic-gate 
54547c478bd9Sstevel@tonic-gate 	p = loc;
54557c478bd9Sstevel@tonic-gate 	lastloc = &p[maxlen-1];
54567c478bd9Sstevel@tonic-gate 	while ((n = getc(fp)) != '\n') {
54577c478bd9Sstevel@tonic-gate 		if (n == EOF)
54587c478bd9Sstevel@tonic-gate 			return (EOF);
54597c478bd9Sstevel@tonic-gate 		if (!isspace(n) && p < lastloc)
54607c478bd9Sstevel@tonic-gate 			*p++ = n;
54617c478bd9Sstevel@tonic-gate 	}
54627c478bd9Sstevel@tonic-gate 	*p = 0;
54637c478bd9Sstevel@tonic-gate 	return (p - loc);
54647c478bd9Sstevel@tonic-gate }
54657c478bd9Sstevel@tonic-gate 
54667c478bd9Sstevel@tonic-gate /*
54677c478bd9Sstevel@tonic-gate  * Calculate the maximum value of cylinders-per-group for a file
54687c478bd9Sstevel@tonic-gate  * system with the characteristics:
54697c478bd9Sstevel@tonic-gate  *
54707c478bd9Sstevel@tonic-gate  *	bsize - file system block size
54717c478bd9Sstevel@tonic-gate  *	fragsize - frag size
54727c478bd9Sstevel@tonic-gate  *	nbpi - number of bytes of disk space per inode
54737c478bd9Sstevel@tonic-gate  *	nrpos - number of rotational positions
54747c478bd9Sstevel@tonic-gate  *	spc - sectors per cylinder
54757c478bd9Sstevel@tonic-gate  *
54767c478bd9Sstevel@tonic-gate  * These five characteristic are not adjustable (by this function).
54777c478bd9Sstevel@tonic-gate  * The only attribute of the file system which IS adjusted by this
54787c478bd9Sstevel@tonic-gate  * function in order to maximize cylinders-per-group is the proportion
54797c478bd9Sstevel@tonic-gate  * of the cylinder group overhead block used for the inode map.  The
54807c478bd9Sstevel@tonic-gate  * inode map cannot occupy more than one-third of the cylinder group
54817c478bd9Sstevel@tonic-gate  * overhead block, but it's OK for it to occupy less than one-third
54827c478bd9Sstevel@tonic-gate  * of the overhead block.
54837c478bd9Sstevel@tonic-gate  *
54847c478bd9Sstevel@tonic-gate  * The setting of nbpi determines one possible value for the maximum
54857c478bd9Sstevel@tonic-gate  * size of a cylinder group.  It does so because it determines the total
54867c478bd9Sstevel@tonic-gate  * number of inodes in the file system (file system size is fixed, and
54877c478bd9Sstevel@tonic-gate  * nbpi is fixed, so the total number of inodes is fixed too).  The
54887c478bd9Sstevel@tonic-gate  * cylinder group has to be small enough so that the number of inodes
54897c478bd9Sstevel@tonic-gate  * in the cylinder group is less than or equal to the number of bits
54907c478bd9Sstevel@tonic-gate  * in one-third (or whatever proportion is assumed) of a file system
54917c478bd9Sstevel@tonic-gate  * block.  The details of the calculation are:
54927c478bd9Sstevel@tonic-gate  *
54937c478bd9Sstevel@tonic-gate  *     The macro MAXIpG_B(bsize, inode_divisor) determines the maximum
54947c478bd9Sstevel@tonic-gate  *     number of inodes that can be in a cylinder group, given the
54957c478bd9Sstevel@tonic-gate  *     proportion of the cylinder group overhead block used for the
54967c478bd9Sstevel@tonic-gate  *     inode bitmaps (an inode_divisor of 3 means that 1/3 of the
54977c478bd9Sstevel@tonic-gate  *     block is used for inode bitmaps; an inode_divisor of 12 means
54987c478bd9Sstevel@tonic-gate  *     that 1/12 of the block is used for inode bitmaps.)
54997c478bd9Sstevel@tonic-gate  *
55007c478bd9Sstevel@tonic-gate  *     Once the number of inodes per cylinder group is known, the
55017c478bd9Sstevel@tonic-gate  *     maximum value of cylinders-per-group (determined by nbpi)
55027c478bd9Sstevel@tonic-gate  *     is calculated by the formula
55037c478bd9Sstevel@tonic-gate  *
55047c478bd9Sstevel@tonic-gate  *     maxcpg_given_nbpi = (size of a cylinder group)/(size of a cylinder)
55057c478bd9Sstevel@tonic-gate  *
55067c478bd9Sstevel@tonic-gate  *			 = (inodes-per-cg * nbpi)/(spc * DEV_BSIZE)
55077c478bd9Sstevel@tonic-gate  *
55087c478bd9Sstevel@tonic-gate  *     (Interestingly, the size of the file system never enters
55097c478bd9Sstevel@tonic-gate  *     into this calculation.)
55107c478bd9Sstevel@tonic-gate  *
55117c478bd9Sstevel@tonic-gate  * Another possible value for the maximum cylinder group size is determined
55127c478bd9Sstevel@tonic-gate  * by frag_size and nrpos.  The frags in the cylinder group must be
55137c478bd9Sstevel@tonic-gate  * representable in the frag bitmaps in the cylinder overhead block and the
55147c478bd9Sstevel@tonic-gate  * rotational positions for each cylinder must be represented in the
55157c478bd9Sstevel@tonic-gate  * rotational position tables.  The calculation of the maximum cpg
55167c478bd9Sstevel@tonic-gate  * value, given the frag and nrpos vales, is:
55177c478bd9Sstevel@tonic-gate  *
55187c478bd9Sstevel@tonic-gate  *     maxcpg_given_fragsize =
55197c478bd9Sstevel@tonic-gate  *	  (available space in the overhead block) / (size of per-cylinder data)
55207c478bd9Sstevel@tonic-gate  *
55217c478bd9Sstevel@tonic-gate  *     The available space in the overhead block =
55227c478bd9Sstevel@tonic-gate  *	  bsize - sizeof (struct cg) - space_used_for_inode_bitmaps
55237c478bd9Sstevel@tonic-gate  *
55247c478bd9Sstevel@tonic-gate  *     The size of the per-cylinder data is:
55257c478bd9Sstevel@tonic-gate  *	    sizeof(long)            # for the "blocks avail per cylinder" field
55267c478bd9Sstevel@tonic-gate  *	    + nrpos * sizeof(short)   # for the rotational position table entry
55277c478bd9Sstevel@tonic-gate  *	    + frags-per-cylinder/NBBY # number of bytes to represent this
55287c478bd9Sstevel@tonic-gate  *				      # cylinder in the frag bitmap
55297c478bd9Sstevel@tonic-gate  *
55307c478bd9Sstevel@tonic-gate  * The two calculated maximum values of cylinder-per-group will typically
55317c478bd9Sstevel@tonic-gate  * turn out to be different, since they are derived from two different
55327c478bd9Sstevel@tonic-gate  * constraints.  Usually, maxcpg_given_nbpi is much bigger than
55337c478bd9Sstevel@tonic-gate  * maxcpg_given_fragsize.  But they can be brought together by
55347c478bd9Sstevel@tonic-gate  * adjusting the proportion of the overhead block dedicated to
55357c478bd9Sstevel@tonic-gate  * the inode bitmaps.  Decreasing the proportion of the cylinder
55367c478bd9Sstevel@tonic-gate  * group overhead block used for inode maps will decrease
55377c478bd9Sstevel@tonic-gate  * maxcpg_given_nbpi and increase maxcpg_given_fragsize.
55387c478bd9Sstevel@tonic-gate  *
55397c478bd9Sstevel@tonic-gate  * This function calculates the initial values of maxcpg_given_nbpi
55407c478bd9Sstevel@tonic-gate  * and maxcpg_given_fragsize assuming that 1/3 of the cg overhead
55417c478bd9Sstevel@tonic-gate  * block is used for inode bitmaps.  Then it decreases the proportion
55427c478bd9Sstevel@tonic-gate  * of the cg overhead block used for inode bitmaps (by increasing
55437c478bd9Sstevel@tonic-gate  * the value of inode_divisor) until maxcpg_given_nbpi and
55447c478bd9Sstevel@tonic-gate  * maxcpg_given_fragsize are the same, or stop changing, or
55457c478bd9Sstevel@tonic-gate  * maxcpg_given_nbpi is less than maxcpg_given_fragsize.
55467c478bd9Sstevel@tonic-gate  *
55477c478bd9Sstevel@tonic-gate  * The loop terminates when any of the following occur:
55487c478bd9Sstevel@tonic-gate  *	* maxcpg_given_fragsize is greater than or equal to
55497c478bd9Sstevel@tonic-gate  *	  maxcpg_given_nbpi
55507c478bd9Sstevel@tonic-gate  *	* neither maxcpg_given_fragsize nor maxcpg_given_nbpi
55517c478bd9Sstevel@tonic-gate  *	  change in the expected direction
55527c478bd9Sstevel@tonic-gate  *
55537c478bd9Sstevel@tonic-gate  * The loop is guaranteed to terminate because it only continues
55547c478bd9Sstevel@tonic-gate  * while maxcpg_given_fragsize and maxcpg_given_nbpi are approaching
55557c478bd9Sstevel@tonic-gate  * each other.  As soon they cross each other, or neither one changes
55567c478bd9Sstevel@tonic-gate  * in the direction of the other, or one of them moves in the wrong
55577c478bd9Sstevel@tonic-gate  * direction, the loop completes.
55587c478bd9Sstevel@tonic-gate  */
55597c478bd9Sstevel@tonic-gate 
55607c478bd9Sstevel@tonic-gate static long
55617c478bd9Sstevel@tonic-gate compute_maxcpg(long bsize, long fragsize, long nbpi, long nrpos, long spc)
55627c478bd9Sstevel@tonic-gate {
55637c478bd9Sstevel@tonic-gate 	int	maxcpg_given_nbpi;	/* in cylinders */
55647c478bd9Sstevel@tonic-gate 	int	maxcpg_given_fragsize;	/* in cylinders */
55657c478bd9Sstevel@tonic-gate 	int	spf;			/* sectors per frag */
55667c478bd9Sstevel@tonic-gate 	int	inode_divisor;
55677c478bd9Sstevel@tonic-gate 	int	old_max_given_frag = 0;
55687c478bd9Sstevel@tonic-gate 	int	old_max_given_nbpi = INT_MAX;
55697c478bd9Sstevel@tonic-gate 
55707c478bd9Sstevel@tonic-gate 	spf = fragsize / DEV_BSIZE;
55717c478bd9Sstevel@tonic-gate 	inode_divisor = 3;
55727c478bd9Sstevel@tonic-gate 
55737c478bd9Sstevel@tonic-gate 	while (1) {
55747c478bd9Sstevel@tonic-gate 		maxcpg_given_nbpi =
55757c478bd9Sstevel@tonic-gate 		    (((int64_t)(MAXIpG_B(bsize, inode_divisor))) * nbpi) /
55767c478bd9Sstevel@tonic-gate 		    (DEV_BSIZE * ((int64_t)spc));
55777c478bd9Sstevel@tonic-gate 		maxcpg_given_fragsize =
55787c478bd9Sstevel@tonic-gate 		    (bsize - (sizeof (struct cg)) - (bsize / inode_divisor)) /
55797c478bd9Sstevel@tonic-gate 		    (sizeof (long) + nrpos * sizeof (short) +
55807c478bd9Sstevel@tonic-gate 						(spc / spf) / NBBY);
55817c478bd9Sstevel@tonic-gate 
55827c478bd9Sstevel@tonic-gate 		if (maxcpg_given_fragsize >= maxcpg_given_nbpi)
55837c478bd9Sstevel@tonic-gate 			return (maxcpg_given_nbpi);
55847c478bd9Sstevel@tonic-gate 
55857c478bd9Sstevel@tonic-gate 		/*
55867c478bd9Sstevel@tonic-gate 		 * If neither value moves toward the other, return the
55877c478bd9Sstevel@tonic-gate 		 * least of the old values (we use the old instead of the
55887c478bd9Sstevel@tonic-gate 		 * new because: if the old is the same as the new, it
55897c478bd9Sstevel@tonic-gate 		 * doesn't matter which ones we use.  If one of the
55907c478bd9Sstevel@tonic-gate 		 * values changed, but in the wrong direction, the
55917c478bd9Sstevel@tonic-gate 		 * new values are suspect.  Better use the old.  This
55927c478bd9Sstevel@tonic-gate 		 * shouldn't happen, but it's best to check.
55937c478bd9Sstevel@tonic-gate 		 */
55947c478bd9Sstevel@tonic-gate 
55957c478bd9Sstevel@tonic-gate 		if (!(maxcpg_given_nbpi < old_max_given_nbpi) &&
55967c478bd9Sstevel@tonic-gate 		    !(maxcpg_given_fragsize > old_max_given_frag))
55977c478bd9Sstevel@tonic-gate 			return (MIN(old_max_given_nbpi, old_max_given_frag));
55987c478bd9Sstevel@tonic-gate 
55997c478bd9Sstevel@tonic-gate 		/*
56007c478bd9Sstevel@tonic-gate 		 * This is probably impossible, but if one of the maxcpg
56017c478bd9Sstevel@tonic-gate 		 * values moved in the "right" direction and one moved
56027c478bd9Sstevel@tonic-gate 		 * in the "wrong" direction (that is, the two values moved
56037c478bd9Sstevel@tonic-gate 		 * in the same direction), the previous conditional won't
56047c478bd9Sstevel@tonic-gate 		 * recognize that the values aren't converging (since at
56057c478bd9Sstevel@tonic-gate 		 * least one value moved in the "right" direction, the
56067c478bd9Sstevel@tonic-gate 		 * last conditional says "keep going").
56077c478bd9Sstevel@tonic-gate 		 *
56087c478bd9Sstevel@tonic-gate 		 * Just to make absolutely certain that the loop terminates,
56097c478bd9Sstevel@tonic-gate 		 * check for one of the values moving in the "wrong" direction
56107c478bd9Sstevel@tonic-gate 		 * and terminate the loop if it happens.
56117c478bd9Sstevel@tonic-gate 		 */
56127c478bd9Sstevel@tonic-gate 
56137c478bd9Sstevel@tonic-gate 		if (maxcpg_given_nbpi > old_max_given_nbpi ||
56147c478bd9Sstevel@tonic-gate 		    maxcpg_given_fragsize < old_max_given_frag)
56157c478bd9Sstevel@tonic-gate 			return (MIN(old_max_given_nbpi, old_max_given_frag));
56167c478bd9Sstevel@tonic-gate 
56177c478bd9Sstevel@tonic-gate 		old_max_given_nbpi = maxcpg_given_nbpi;
56187c478bd9Sstevel@tonic-gate 		old_max_given_frag = maxcpg_given_fragsize;
56197c478bd9Sstevel@tonic-gate 
56207c478bd9Sstevel@tonic-gate 		inode_divisor++;
56217c478bd9Sstevel@tonic-gate 	}
56227c478bd9Sstevel@tonic-gate }
56237c478bd9Sstevel@tonic-gate 
56247c478bd9Sstevel@tonic-gate static int
56257c478bd9Sstevel@tonic-gate in_64bit_mode(void)
56267c478bd9Sstevel@tonic-gate {
56277c478bd9Sstevel@tonic-gate 	/*  cmd must be an absolute path, for security */
56287c478bd9Sstevel@tonic-gate 	char *cmd = "/usr/bin/isainfo -b";
56297c478bd9Sstevel@tonic-gate 	char buf[BUFSIZ];
56307c478bd9Sstevel@tonic-gate 	FILE *ptr;
56317c478bd9Sstevel@tonic-gate 	int retval = 0;
56327c478bd9Sstevel@tonic-gate 
56337c478bd9Sstevel@tonic-gate 	putenv("IFS= \t");
56347c478bd9Sstevel@tonic-gate 	if ((ptr = popen(cmd, "r")) != NULL) {
56357c478bd9Sstevel@tonic-gate 		if (fgets(buf, BUFSIZ, ptr) != NULL &&
56367c478bd9Sstevel@tonic-gate 		    strncmp(buf, "64", 2) == 0)
56377c478bd9Sstevel@tonic-gate 			retval = 1;
56387c478bd9Sstevel@tonic-gate 		(void) pclose(ptr);
56397c478bd9Sstevel@tonic-gate 	}
56407c478bd9Sstevel@tonic-gate 	return (retval);
56417c478bd9Sstevel@tonic-gate }
56427c478bd9Sstevel@tonic-gate 
56437c478bd9Sstevel@tonic-gate /*
56447c478bd9Sstevel@tonic-gate  * validate_size
56457c478bd9Sstevel@tonic-gate  *
56467c478bd9Sstevel@tonic-gate  * Return 1 if the device appears to be at least "size" sectors long.
56477c478bd9Sstevel@tonic-gate  * Return 0 if it's shorter or we can't read it.
56487c478bd9Sstevel@tonic-gate  */
56497c478bd9Sstevel@tonic-gate 
56507c478bd9Sstevel@tonic-gate static int
56517c478bd9Sstevel@tonic-gate validate_size(int fd, diskaddr_t size)
56527c478bd9Sstevel@tonic-gate {
56537c478bd9Sstevel@tonic-gate 	char 		buf[DEV_BSIZE];
56547c478bd9Sstevel@tonic-gate 	int rc;
56557c478bd9Sstevel@tonic-gate 
56567c478bd9Sstevel@tonic-gate 	if ((llseek(fd, (offset_t)((size - 1) * DEV_BSIZE), SEEK_SET) == -1) ||
56577c478bd9Sstevel@tonic-gate 	    (read(fd, buf, DEV_BSIZE)) != DEV_BSIZE)
56587c478bd9Sstevel@tonic-gate 		rc = 0;
56597c478bd9Sstevel@tonic-gate 	else
56607c478bd9Sstevel@tonic-gate 		rc = 1;
56617c478bd9Sstevel@tonic-gate 	return (rc);
56627c478bd9Sstevel@tonic-gate }
5663355d6bb5Sswilcox 
5664355d6bb5Sswilcox /*
5665355d6bb5Sswilcox  * Print every field of the calculated superblock, along with
5666355d6bb5Sswilcox  * its value.  To make parsing easier on the caller, the value
5667355d6bb5Sswilcox  * is printed first, then the name.  Additionally, there's only
5668355d6bb5Sswilcox  * one name/value pair per line.  All values are reported in
5669355d6bb5Sswilcox  * hexadecimal (with the traditional 0x prefix), as that's slightly
5670355d6bb5Sswilcox  * easier for humans to read.  Not that they're expected to, but
5671355d6bb5Sswilcox  * debugging happens.
5672355d6bb5Sswilcox  */
5673355d6bb5Sswilcox static void
5674355d6bb5Sswilcox dump_sblock(void)
5675355d6bb5Sswilcox {
5676355d6bb5Sswilcox 	int row, column, pending, written;
5677355d6bb5Sswilcox 	caddr_t source;
5678355d6bb5Sswilcox 
5679355d6bb5Sswilcox 	if (Rflag) {
5680355d6bb5Sswilcox 		pending = sizeof (sblock);
5681355d6bb5Sswilcox 		source = (caddr_t)&sblock;
5682355d6bb5Sswilcox 		do {
5683355d6bb5Sswilcox 			written = write(fileno(stdout), source, pending);
5684355d6bb5Sswilcox 			pending -= written;
5685355d6bb5Sswilcox 			source += written;
5686355d6bb5Sswilcox 		} while ((pending > 0) && (written > 0));
5687355d6bb5Sswilcox 
5688355d6bb5Sswilcox 		if (written < 0) {
5689355d6bb5Sswilcox 			perror(gettext("Binary dump of superblock failed"));
5690355d6bb5Sswilcox 			lockexit(1);
5691355d6bb5Sswilcox 		}
5692355d6bb5Sswilcox 		return;
5693355d6bb5Sswilcox 	} else {
5694355d6bb5Sswilcox 		printf("0x%x sblock.fs_link\n", sblock.fs_link);
5695355d6bb5Sswilcox 		printf("0x%x sblock.fs_rolled\n", sblock.fs_rolled);
5696355d6bb5Sswilcox 		printf("0x%x sblock.fs_sblkno\n", sblock.fs_sblkno);
5697355d6bb5Sswilcox 		printf("0x%x sblock.fs_cblkno\n", sblock.fs_cblkno);
5698355d6bb5Sswilcox 		printf("0x%x sblock.fs_iblkno\n", sblock.fs_iblkno);
5699355d6bb5Sswilcox 		printf("0x%x sblock.fs_dblkno\n", sblock.fs_dblkno);
5700355d6bb5Sswilcox 		printf("0x%x sblock.fs_cgoffset\n", sblock.fs_cgoffset);
5701355d6bb5Sswilcox 		printf("0x%x sblock.fs_cgmask\n", sblock.fs_cgmask);
5702355d6bb5Sswilcox 		printf("0x%x sblock.fs_time\n", sblock.fs_time);
5703355d6bb5Sswilcox 		printf("0x%x sblock.fs_size\n", sblock.fs_size);
5704355d6bb5Sswilcox 		printf("0x%x sblock.fs_dsize\n", sblock.fs_dsize);
5705355d6bb5Sswilcox 		printf("0x%x sblock.fs_ncg\n", sblock.fs_ncg);
5706355d6bb5Sswilcox 		printf("0x%x sblock.fs_bsize\n", sblock.fs_bsize);
5707355d6bb5Sswilcox 		printf("0x%x sblock.fs_fsize\n", sblock.fs_fsize);
5708355d6bb5Sswilcox 		printf("0x%x sblock.fs_frag\n", sblock.fs_frag);
5709355d6bb5Sswilcox 		printf("0x%x sblock.fs_minfree\n", sblock.fs_minfree);
5710355d6bb5Sswilcox 		printf("0x%x sblock.fs_rotdelay\n", sblock.fs_rotdelay);
5711355d6bb5Sswilcox 		printf("0x%x sblock.fs_rps\n", sblock.fs_rps);
5712355d6bb5Sswilcox 		printf("0x%x sblock.fs_bmask\n", sblock.fs_bmask);
5713355d6bb5Sswilcox 		printf("0x%x sblock.fs_fmask\n", sblock.fs_fmask);
5714355d6bb5Sswilcox 		printf("0x%x sblock.fs_bshift\n", sblock.fs_bshift);
5715355d6bb5Sswilcox 		printf("0x%x sblock.fs_fshift\n", sblock.fs_fshift);
5716355d6bb5Sswilcox 		printf("0x%x sblock.fs_maxcontig\n", sblock.fs_maxcontig);
5717355d6bb5Sswilcox 		printf("0x%x sblock.fs_maxbpg\n", sblock.fs_maxbpg);
5718355d6bb5Sswilcox 		printf("0x%x sblock.fs_fragshift\n", sblock.fs_fragshift);
5719355d6bb5Sswilcox 		printf("0x%x sblock.fs_fsbtodb\n", sblock.fs_fsbtodb);
5720355d6bb5Sswilcox 		printf("0x%x sblock.fs_sbsize\n", sblock.fs_sbsize);
5721355d6bb5Sswilcox 		printf("0x%x sblock.fs_csmask\n", sblock.fs_csmask);
5722355d6bb5Sswilcox 		printf("0x%x sblock.fs_csshift\n", sblock.fs_csshift);
5723355d6bb5Sswilcox 		printf("0x%x sblock.fs_nindir\n", sblock.fs_nindir);
5724355d6bb5Sswilcox 		printf("0x%x sblock.fs_inopb\n", sblock.fs_inopb);
5725355d6bb5Sswilcox 		printf("0x%x sblock.fs_nspf\n", sblock.fs_nspf);
5726355d6bb5Sswilcox 		printf("0x%x sblock.fs_optim\n", sblock.fs_optim);
5727355d6bb5Sswilcox #ifdef _LITTLE_ENDIAN
5728355d6bb5Sswilcox 		printf("0x%x sblock.fs_state\n", sblock.fs_state);
5729355d6bb5Sswilcox #else
5730355d6bb5Sswilcox 		printf("0x%x sblock.fs_npsect\n", sblock.fs_npsect);
5731355d6bb5Sswilcox #endif
5732355d6bb5Sswilcox 		printf("0x%x sblock.fs_si\n", sblock.fs_si);
5733355d6bb5Sswilcox 		printf("0x%x sblock.fs_trackskew\n", sblock.fs_trackskew);
5734355d6bb5Sswilcox 		printf("0x%x sblock.fs_id[0]\n", sblock.fs_id[0]);
5735355d6bb5Sswilcox 		printf("0x%x sblock.fs_id[1]\n", sblock.fs_id[1]);
5736355d6bb5Sswilcox 		printf("0x%x sblock.fs_csaddr\n", sblock.fs_csaddr);
5737355d6bb5Sswilcox 		printf("0x%x sblock.fs_cssize\n", sblock.fs_cssize);
5738355d6bb5Sswilcox 		printf("0x%x sblock.fs_cgsize\n", sblock.fs_cgsize);
5739355d6bb5Sswilcox 		printf("0x%x sblock.fs_ntrak\n", sblock.fs_ntrak);
5740355d6bb5Sswilcox 		printf("0x%x sblock.fs_nsect\n", sblock.fs_nsect);
5741355d6bb5Sswilcox 		printf("0x%x sblock.fs_spc\n", sblock.fs_spc);
5742355d6bb5Sswilcox 		printf("0x%x sblock.fs_ncyl\n", sblock.fs_ncyl);
5743355d6bb5Sswilcox 		printf("0x%x sblock.fs_cpg\n", sblock.fs_cpg);
5744355d6bb5Sswilcox 		printf("0x%x sblock.fs_ipg\n", sblock.fs_ipg);
5745355d6bb5Sswilcox 		printf("0x%x sblock.fs_fpg\n", sblock.fs_fpg);
5746355d6bb5Sswilcox 		printf("0x%x sblock.fs_cstotal\n", sblock.fs_cstotal);
5747355d6bb5Sswilcox 		printf("0x%x sblock.fs_fmod\n", sblock.fs_fmod);
5748355d6bb5Sswilcox 		printf("0x%x sblock.fs_clean\n", sblock.fs_clean);
5749355d6bb5Sswilcox 		printf("0x%x sblock.fs_ronly\n", sblock.fs_ronly);
5750355d6bb5Sswilcox 		printf("0x%x sblock.fs_flags\n", sblock.fs_flags);
5751355d6bb5Sswilcox 		printf("0x%x sblock.fs_fsmnt\n", sblock.fs_fsmnt);
5752355d6bb5Sswilcox 		printf("0x%x sblock.fs_cgrotor\n", sblock.fs_cgrotor);
5753355d6bb5Sswilcox 		printf("0x%x sblock.fs_u.fs_csp\n", sblock.fs_u.fs_csp);
5754355d6bb5Sswilcox 		printf("0x%x sblock.fs_cpc\n", sblock.fs_cpc);
5755355d6bb5Sswilcox 
5756355d6bb5Sswilcox 		/*
5757355d6bb5Sswilcox 		 * No macros are defined for the dimensions of the
5758355d6bb5Sswilcox 		 * opostbl array.
5759355d6bb5Sswilcox 		 */
5760355d6bb5Sswilcox 		for (row = 0; row < 16; row++) {
5761355d6bb5Sswilcox 			for (column = 0; column < 8; column++) {
5762355d6bb5Sswilcox 				printf("0x%x sblock.fs_opostbl[%d][%d]\n",
5763355d6bb5Sswilcox 				    sblock.fs_opostbl[row][column],
5764355d6bb5Sswilcox 				    row, column);
5765355d6bb5Sswilcox 			}
5766355d6bb5Sswilcox 		}
5767355d6bb5Sswilcox 
5768355d6bb5Sswilcox 		/*
5769355d6bb5Sswilcox 		 * Ditto the size of sparecon.
5770355d6bb5Sswilcox 		 */
5771355d6bb5Sswilcox 		for (row = 0; row < 51; row++) {
5772355d6bb5Sswilcox 			printf("0x%x sblock.fs_sparecon[%d]\n",
5773355d6bb5Sswilcox 			    sblock.fs_sparecon[row], row);
5774355d6bb5Sswilcox 		}
5775355d6bb5Sswilcox 
5776355d6bb5Sswilcox 		printf("0x%x sblock.fs_version\n", sblock.fs_version);
5777355d6bb5Sswilcox 		printf("0x%x sblock.fs_logbno\n", sblock.fs_logbno);
5778355d6bb5Sswilcox 		printf("0x%x sblock.fs_reclaim\n", sblock.fs_reclaim);
5779355d6bb5Sswilcox 		printf("0x%x sblock.fs_sparecon2\n", sblock.fs_sparecon2);
5780355d6bb5Sswilcox #ifdef _LITTLE_ENDIAN
5781355d6bb5Sswilcox 		printf("0x%x sblock.fs_npsect\n", sblock.fs_npsect);
5782355d6bb5Sswilcox #else
5783355d6bb5Sswilcox 		printf("0x%x sblock.fs_state\n", sblock.fs_state);
5784355d6bb5Sswilcox #endif
5785355d6bb5Sswilcox 		printf("0x%llx sblock.fs_qbmask\n", sblock.fs_qbmask);
5786355d6bb5Sswilcox 		printf("0x%llx sblock.fs_qfmask\n", sblock.fs_qfmask);
5787355d6bb5Sswilcox 		printf("0x%x sblock.fs_postblformat\n", sblock.fs_postblformat);
5788355d6bb5Sswilcox 		printf("0x%x sblock.fs_nrpos\n", sblock.fs_nrpos);
5789355d6bb5Sswilcox 		printf("0x%x sblock.fs_postbloff\n", sblock.fs_postbloff);
5790355d6bb5Sswilcox 		printf("0x%x sblock.fs_rotbloff\n", sblock.fs_rotbloff);
5791355d6bb5Sswilcox 		printf("0x%x sblock.fs_magic\n", sblock.fs_magic);
5792355d6bb5Sswilcox 
5793355d6bb5Sswilcox 		/*
5794355d6bb5Sswilcox 		 * fs_space isn't of much use in this context, so we'll
5795355d6bb5Sswilcox 		 * just ignore it for now.
5796355d6bb5Sswilcox 		 */
5797355d6bb5Sswilcox 	}
5798355d6bb5Sswilcox }
5799