mkfs.c revision 65908c77dfc02644236ba18bffe67b5ed6f23135
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
/*
* The maximum supported file system size (in sectors) is the
* number of frags that can be represented in an int32_t field
* (INT_MAX) times the maximum number of sectors per frag. Since
* the maximum frag size is MAXBSIZE, the maximum number of sectors
*/
/*
* make file system for cylinder-group style file systems
*
* usage:
*
* mkfs [-F FSType] [-V] [-G [-P]] [-M dirname] [-m] [options]
* [-o specific_options] special size
* [nsect ntrack bsize fsize cpg minfree rps nbpi opt apc rotdelay
* 2 3 4 5 6 7 8 9 10 11 12
* nrpos maxcontig mtb]
* 13 14 15
*
* where specific_options are:
* N - no create
* nsect - The number of sectors per track
* ntrack - The number of tracks per cylinder
* bsize - block size
* fragsize - fragment size
* cgsize - The number of disk cylinders per cylinder group.
* free - minimum free space
* nbpi - number of data bytes per allocated inode
* opt - optimization (space, time)
* apc - number of alternates
* gap - gap size
* nrpos - number of rotational positions
* maxcontig - maximum number of logical blocks that will be
* allocated contiguously before inserting rotational delay
* mtb - if "y", set up file system for eventual growth to over a
* a terabyte
* -P Do not grow the file system, but print on stdout the maximal
* size in sectors to which the file system can be increased. The calculated
* size is limited by the value provided by the operand size.
*
* Note that -P is a project-private interface and together with -G intended
* to be used only by the growfs script. It is therefore purposely not
* documented in the man page.
* The -P option is covered by PSARC case 2003/422.
*/
/*
* The following constants set the defaults used for the number
*
* NSECT NTRAK
* 72MB CDC 18 9
* 30MB CDC 18 5
* 720KB Diskette 9 2
*
* However the defaults will be different for disks larger than CHSLIMIT.
*/
#define DFLNSECT 32
#define DFLNTRAK 16
/*
* The following default sectors and tracks values are used for
* non-efi disks that are larger than the CHS addressing limit. The
* existing default cpg of 16 (DESCPG) holds good for larger disks too.
*/
#define DEF_SECTORS_EFI 128
#define DEF_TRACKS_EFI 48
/*
* The maximum number of cylinders in a group depends upon how much
* information can be stored on a single cylinder. The default is to
* use 16 cylinders per group. This is effectively tradition - it was
* the largest value acceptable under SunOs 4.1
*/
/*
* The following two constants set the default block and fragment sizes.
* Both constants must be a power of 2 and meet the following constraints:
* MINBSIZE <= DESBLKSIZE <= MAXBSIZE
* DEV_BSIZE <= DESFRAGSIZE <= DESBLKSIZE
* DESBLKSIZE / DESFRAGSIZE <= 8
*/
#define DESBLKSIZE 8192
#define DESFRAGSIZE 1024
/*
* MINFREE gives the minimum acceptable percentage of file system
* blocks which may be free. If the freelist drops below this level
* only the superuser may continue to allocate blocks. This may
* be set to 0 if no reserve of free blocks is deemed necessary,
* however throughput drops by fifty percent if the file system
* is run at between 90% and 100% full; thus the default value of
* fs_minfree is 10%. With 10% free space, fragmentation is not a
* problem, so we choose to optimize for time.
*/
#define MINFREE 10
#define DEFAULTOPT FS_OPTTIME
/*
* ROTDELAY gives the minimum number of milliseconds to initiate
* another disk transfer on the same cylinder. It is no longer used
* and will always default to 0.
*/
#define ROTDELAY 0
/*
* MAXBLKPG determines the maximum number of data blocks which are
* placed in a single cylinder group. The default is one indirect
* block worth of data blocks.
*/
/*
* Each file system has a number of inodes statically allocated.
* We allocate one inode slot per NBPI bytes, expecting this
* to be far more than we will ever need.
*/
/*
* Disks are assumed to rotate at 60HZ, unless otherwise specified.
*/
#define DEFHZ 60
/*
* Cylinder group related limits.
*
* For each cylinder we keep track of the availability of blocks at different
* rotational positions, so that we can lay out the data to be picked
* up with minimum rotational latency. NRPOS is the number of rotational
* positions which we distinguish. With NRPOS 8 the resolution of our
* summary information is 2ms for a typical 3600 rpm drive.
*/
#ifdef DEBUG
#else
#define dprintf(x)
#endif
/*
* For the -N option, when calculating the backup superblocks, do not print
* them if we are not really sure. We may have to try an alternate method of
* arriving at the superblocks. So defer printing till a handful of superblocks
* look good.
*/
else \
/*
* range_check "user_supplied" flag values.
*/
#define RC_DEFAULT 0
#define RC_KEYWORD 1
#define RC_POSITIONAL 2
/*
* ufs hole
*/
#define UFS_HOLE -1
#ifndef STANDALONE
#include <stdio.h>
#endif
#include <stdlib.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#include <errno.h>
#include <time.h>
#include <sys/sysmacros.h>
#include <limits.h>
#include <sys/int_const.h>
#include <signal.h>
#include <sys/efi_partition.h>
#include "roll_log.h"
#include <locale.h>
#include <fcntl.h>
extern char *getfullblkname();
extern long lrand48();
extern int optind;
extern char *optarg;
/*
* The size of a cylinder group is calculated by CGSIZE. The maximum size
* is limited by the fact that cylinder groups are at most one block.
* Its size is derived from the size of the maps maintained in the
* cylinder group and the (struct cg) size.
*/
/* base cg */ (sizeof (struct cg) + \
/*
* We limit the size of the inode map to be no more than a
* third of the cylinder group space, since we must leave at
* least an equal amount of space for the block map.
*
* N.B.: MAXIpG must be a multiple of INOPB(fs).
*/
/*
* Same as MAXIpG, but parameterized by the block size (b) and the
* cylinder group divisor (d), which is the reciprocal of the fraction of the
* cylinder group overhead block that is used for the inode map. So for
* example, if d = 5, the macro's computation assumes that 1/5 of the
* cylinder group overhead block can be dedicated to the inode map.
*/
#define UMASK 0755
#define BETWEEN(x, l, h) ((x) >= (l) && (x) <= (h))
/*
* Used to set the inode generation number. Since both inodes and dinodes
* are dealt with, we really need a pointer to an icommon here.
*/
/*
* Flags for number()
*/
#define NOBLOCK 0 /* don't block in aiowait */
#define SAVE 0 /* don't free the buffer */
typedef struct aio_trans {
char *buffer;
int size;
int release;
} aio_trans;
typedef struct aio_results {
int max;
int outstanding;
int maxpend;
} aio_results;
int aio_inited = 0;
/*
* Allow up to MAXBUF aio requests that each have a unique buffer.
* More aio's might be done, but not using memory through the getbuf()
* interface. This can be raised, but you run into the potential of
* using more memory than is physically available on the machine,
* and if you start swapping, you can forget about performance.
* To prevent this, we also limit the total memory used for a given
* type of buffer to MAXBUFMEM.
*
* Tests indicate a cylinder group's worth of inodes takes:
*
* NBPI Size of Inode Buffer
* 2k 1688k
* 8k 424k
*
* initcg() stores all the inodes for a cylinder group in one buffer,
* so allowing 20 buffers could take 32 MB if not limited by MAXBUFMEM.
*/
#define MAXBUF 20
/*
* header information for buffers managed by getbuf() and freebuf()
*/
typedef struct bufhdr {
} bufhdr;
int bufhdrsize;
/*
* The following constant specifies an upper limit for file system size
* that is actually a lot bigger than we expect to support with UFS. (Since
* it's specified in sectors, the file system size would be 2**44 * 512,
* which is 2**53, which is 8192 Terabytes.) However, it's useful
* for checking the basic sanity of a size value that is input on the
* command line.
*/
#define FS_SIZE_UPPER_LIMIT 0x100000000000LL
/*
* Forward declarations
*/
static void fsinit();
static void usage();
static int match(char *s);
static long get_max_track_size(int fd);
static void recover_from_sigint(int signum);
static int confirm_abort(void);
static void flush_writes(void);
static long compute_maxcpg(long, long, long, long, long);
static int in_64bit_mode(void);
static void dump_sblock(void);
/*
* Workaround for mkfs to function properly on disks attached to XMIT 2.X
* controller. If the address is not aligned at 8 byte boundary, mkfs on
* disks attached to XMIT 2.X controller exhibts un-predictable behaviour.
*/
#define XMIT_2_X_ALIGN 8
union {
union cgun {
} cgun;
/*
* Size of screen in cols in which to fit output
*/
#define WIDTH 80
/*
* file descriptors used for rdfs(fsi) and wtfs(fso).
* Initialized to an illegal file descriptor number.
*/
int fsi = -1;
int fso = -1;
/*
* The BIG parameter is machine dependent. It should be a longlong integer
* constant that can be used by the number parser to check the validity
* of numeric parameters.
*/
#define BIG 0x7fffffffffffffffLL
/* Used to indicate to number() that a bogus value should cause us to exit */
#define NO_DEFAULT LONG_MIN
/*
* INVALIDSBLIMIT is the number of bad backup superblocks that will be
* tolerated before we decide to try arriving at a different set of them
* using a different logic. This is applicable for non-EFI disks only.
*/
#define INVALIDSBLIMIT 10
/*
* The *_flag variables are used to indicate that the user specified
* the values, rather than that we made them up ourselves. We can
* complain about the user giving us bogus values.
*/
/* semi-constants */
/* parameters */
int cpg_flag = RC_DEFAULT;
int rotdelay_flag = RC_DEFAULT;
long maxcontig; /* max contiguous blocks to allocate */
int maxcontig_flag = RC_DEFAULT;
int nsect_flag = RC_DEFAULT;
int ntrack_flag = RC_DEFAULT;
int bsize_flag = RC_DEFAULT;
int fragsize_flag = RC_DEFAULT;
int minfree_flag = RC_DEFAULT;
int rps_flag = RC_DEFAULT;
int nbpi_flag = RC_DEFAULT;
int nrpos_flag = RC_DEFAULT;
long apc = 0; /* alternate sectors per cylinder */
int apc_flag = RC_DEFAULT;
ntrack_flag == RC_DEFAULT && \
cpg_flag == RC_DEFAULT)
long debug = 0; /* enable debugging output */
int spc_flag = 0; /* alternate sectors specified or */
/* found */
/* global state */
int Nflag; /* do not write to disk */
int mflag; /* return the command line used to create this FS */
int rflag; /* report the superblock in an easily-parsed form */
int Rflag; /* dump the superblock in binary */
char *fsys;
char *string;
int label_type;
/*
* logging support
*/
int ismdd; /* true if device is a SVM device */
int islog; /* true if ufs or SVM logging is enabled */
static int isufslog; /* true if ufs logging is enabled */
static int waslog; /* true when ufs logging disabled during grow */
/*
* growfs defines, globals, and forward references
*/
#define NOTENOUGHSPACE 33
int grow;
static int Pflag; /* probe to which size the fs can be grown */
int ismounted;
char *directory;
long grow_fs_size;
long grow_fs_ncg;
long grow_fs_cssize;
int grow_fs_clean;
int test;
int testforce;
int inlockexit;
int isbad;
void lockexit(int);
void randomgeneration(void);
void checksummarysize(void);
int checksblock(struct fs, int);
void growinit(char *);
void checkdev(char *, char *);
void checkmount(struct mnttab *, char *);
int csfraginrange(daddr32_t);
void findcsfragino(void);
void fixindirect(daddr32_t, int);
void fixcsfragino(void);
void extendsummaryinfo(void);
int notenoughspace(void);
void unalloccsfragino(void);
void unalloccsfragfree(void);
void findcsfragfree(void);
void copycsfragino(void);
void rdcg(long);
void wtcg(void);
void flcg(void);
void allocfrags(long, daddr32_t *, long *);
void alloccsfragino(void);
void alloccsfragfree(void);
int findfreerange(long *, long *);
void resetallocinfo(void);
void extendcg(long);
void ulockfs(void);
void wlockfs(void);
void clockfs(void);
void wtsb(void);
static diskaddr_t probe_summaryinfo();
int
{
long mapcramped, inodecramped;
char *special;
char *tmpbuf;
int c, saverr;
long tmpmaxcontig = -1;
int remaining_cg;
int do_dot = 0;
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
switch (c) {
case 'F':
usage();
break;
case 'm': /* return command line used to create this FS */
mflag++;
break;
case 'o':
/*
* ufs specific options.
*/
while (*string != '\0') {
if (match("nsect=")) {
} else if (match("ntrack=")) {
} else if (match("bsize=")) {
} else if (match("fragsize=")) {
"fragsize", 0);
} else if (match("cgsize=")) {
} else if (match("free=")) {
} else if (match("maxcontig=")) {
} else if (match("nrpos=")) {
} else if (match("rps=")) {
} else if (match("nbpi=")) {
} else if (match("opt=")) {
} else if (match("mtb=")) {
} else if (match("apc=")) {
} else if (match("gap=")) {
} else if (match("debug=")) {
} else if (match("N")) {
Nflag++;
} else if (match("calcsb")) {
rflag++;
Nflag++;
} else if (match("calcbinsb")) {
rflag++;
Rflag++;
Nflag++;
} else if (*string == '\0') {
break;
} else {
"illegal option: %s\n"), string);
usage();
}
}
break;
case 'V':
{
char *opt_text;
int opt_count;
opt_count++) {
if (opt_text)
opt_text);
}
}
break;
case 'b': /* do nothing for this */
break;
case 'M': /* grow the mounted file system */
/* FALLTHROUGH */
case 'G': /* grow the file system */
grow = 1;
break;
case 'P': /* probe the file system growing size */
Pflag = 1;
break;
case 'T': /* For testing */
testforce = 1;
/* FALLTHROUGH */
case 't':
test = 1;
break;
case '?':
usage();
break;
}
}
#ifdef MKFS_DEBUG
/*
* Turning on MKFS_DEBUG causes mkfs to produce a filesystem
* that can be reproduced by setting the time to 0 and seeding
* the random number generator to a constant.
*/
mkfstime = 0; /* reproducible results */
#else
#endif
gettext("special not specified\n"));
usage();
} else if (mflag == 0) {
gettext("size not specified\n"));
usage();
}
}
if (fsi < 0) {
lockexit(32);
}
if (mflag) {
lockexit(0);
}
/*
* The task of setting all of the configuration parameters for a
* UFS file system is basically a matter of solving n equations
* in m variables. Typically, m is greater than n, so there is
* usually more than one valid solution. Since this is usually
* an under-constrained problem, it's not always obvious what the
* "best" configuration is.
*
* In general, the approach is to
* 1. Determine the values for the file system parameters
* that are externally contrained and therefore not adjustable
* by mkfs (such as the device's size and maxtransfer size).
* 2. Acquire the user's requested setting for all configuration
* values that can be set on the command line.
* 3. Determine the final value of all configuration values, by
* the following approach:
* - set the file system block size (fs_bsize). Although
* this could be regarded as an adjustable parameter, in
* fact, it's pretty much a constant. At this time, it's
* generally set to 8k (with older hardware, it can
* sometimes make sense to set it to 4k, but those
* situations are pretty rare now).
* - re-adjust the maximum file system size based on the
* value of the file system block size. Since the
* frag size can't be any larger than a file system
* block, and the number of frags in the file system
* has to fit into 31 bits, the file system block size
* affects the maximum file system size.
* - now that the real maximum file system is known, set the
* actual size of the file system to be created to
* MIN(requested size, maximum file system size).
* - now validate, and if necessary, adjust the following
* values:
* rotdelay
* nsect
* maxcontig
* apc
* frag_size
* rps
* minfree
* nrpos
* nrack
* nbpi
* - calculate maxcpg (the maximum value of the cylinders-per-
* cylinder-group configuration parameters). There are two
* algorithms for calculating maxcpg: an old one, which is
* used for file systems of less than 1 terabyte, and a
* new one, implemented in the function compute_maxcpg(),
* which is used for file systems of greater than 1 TB.
* The difference between them is that compute_maxcpg()
* really tries to maximize the cpg value. The old
* algorithm fails to take advantage of smaller frags and
* lower inode density when determining the maximum cpg,
* and thus comes up with much lower numbers in some
* configurations. At some point, we might use the
* new algorithm for determining maxcpg for all file
* systems, but at this time, the changes implemented for
* multi-terabyte UFS are NOT being automatically applied
* to UFS file systems of less than a terabyte (in the
* interest of not changing existing UFS policy too much
* until the ramifications of the changes are well-understood
* and have been evaluated for their effects on performance.)
* - check the current values of the configuration parameters
* against the various constraints imposed by UFS. These
* include:
* * There must be at least one inode in each
* cylinder group.
* * The cylinder group overhead block, which
* contains the inode and frag bigmaps, must fit
* within one file system block.
* * The space required for inode maps should
* occupy no more than a third of the cylinder
* group overhead block.
* * The rotational position tables have to fit
* within the available space in the super block.
* Adjust the configuration values that can be adjusted
* so that these constraints are satisfied. The
* configuration values that are adjustable are:
* * frag size
* * cylinders per group
* * inode density (can be increased)
* * number of rotational positions (the rotational
* position tables are eliminated altogether if
* there isn't enough room for them.)
* 4. Set the values for all the dependent configuration
* values (those that aren't settable on the command
* line and which are completely dependent on the
* adjustable parameters). This include cpc (cycles
* per cylinder, spc (sectors-per-cylinder), and many others.
*/
/*
* Figure out the partition size and initialize the label_type.
*/
/*
* Get and check positional arguments, if any.
*/
switch (argc - 1) {
default:
usage();
/*NOTREACHED*/
case 15:
/* FALLTHROUGH */
case 14:
/* FALLTHROUGH */
case 13:
/* FALLTHROUGH */
case 12:
/* FALLTHROUGH */
case 11:
/* FALLTHROUGH */
case 10:
/* FALLTHROUGH */
case 9:
/* FALLTHROUGH */
case 8:
/* FALLTHROUGH */
case 7:
/* FALLTHROUGH */
case 6:
/* FALLTHROUGH */
case 5:
/* FALLTHROUGH */
case 4:
/* FALLTHROUGH */
case 3:
/* FALLTHROUGH */
case 2:
/* FALLTHROUGH */
case 1:
}
/*
* Initialize the parameters in the same way as newfs so that
* newfs and mkfs would result in the same file system layout
* for EFI labelled disks. Do this only in the absence of user
* specified values for these parameters.
*/
if (label_type == LABEL_TYPE_EFI) {
}
(maxcontig == -1)) {
} else {
}
}
}
/*
* Now that we have the semi-sane args, either positional, via -o,
* or by defaulting, handle inter-dependencies and range checks.
*/
/*
* Settle the file system block size first, since it's a fixed
* parameter once set and so many other parameters, including
* max_fssize, depend on it.
*/
gettext("block size must be a power of 2, not %ld\n"),
bsize);
bsize = DESBLKSIZE;
gettext("mkfs: bsize reset to default %ld\n"),
bsize);
}
"Warning: the requested size of this file system\n"
"(%lld sectors) is greater than the size of the\n"
"device reported by the driver (%lld sectors).\n"
"However, a read of the device at the requested size\n"
"does succeed, so the requested size will be used.\n"),
}
/*
* Since the maximum allocatable unit (the frag) must be less than
* or equal to bsize, and the number of frags must be less than or
* equal to INT_MAX, the total size of the file system (in
* bytes) must be less than or equal to bsize * INT_MAX.
*/
if (fssize_db >= SECTORS_PER_TERABYTE) {
mtb = 'y';
if (!in_64bit_mode()) {
"mkfs: Warning: Creating a file system greater than 1 terabyte on a\n"
" system running a 32-bit kernel. This file system will not be\n"
" accessible until the system is rebooted with a 64-bit kernel.\n"));
}
}
/*
* With newer and much larger disks, the newfs(1M) and mkfs_ufs(1M)
* commands had problems in correctly handling the "native" geometries
* for various storage devices.
*
* To handle the new age disks, mkfs_ufs(1M) will use the EFI style
* for non-EFI disks that are larger than the CHS addressing limit
* ( > 8GB approx ) and ignore the disk geometry information for
* these drives. This is what is currently done for multi-terrabyte
* filesystems on EFI disks.
*
* However if the user asked for a specific layout by supplying values
* for even one of the three parameters (nsect, ntrack, cpg), honour
* the user supplied parameters.
*
* Choosing EFI style or native geometry style can make a lot of
* difference, because the size of a cylinder group is dependent on
* this choice. This in turn means that the position of alternate
* superblocks varies depending on the style chosen. It is not
* necessary that all disks of size > CHSLIMIT have EFI style layout.
* There can be disks which are > CHSLIMIT size, but have native
* geometry style layout, thereby warranting the need for alternate
* logic in superblock detection.
*/
/*
* "-1" indicates that we were called from newfs and ntracks
* was not specified in newfs command line. Calculate nsect
* and ntrack in the same manner as newfs.
*
* This is required because, the defaults for nsect and ntrack
* is hardcoded in mkfs, whereas to generate the alternate
* superblock locations for the -N option, there is a need for
* the geometry based values that newfs would have arrived at.
* Newfs would have arrived at these values as below.
*/
if (label_type == LABEL_TYPE_EFI ||
label_type == LABEL_TYPE_OTHER) {
use_efi_dflts = 1;
retry = 1;
lockexit(32);
} else {
#ifdef i386 /* Bug 1170182 */
}
#endif
dprintf(("DeBuG Unable to determine if %s is"
" Removable Media. Proceeding with system"
" determined parameters.\n", fsys));
isremovable = 0;
}
dprintf(("DeBuG Unable to determine if %s is"
" Hotpluggable Media. Proceeding with "
"system determined parameters.\n", fsys));
ishotpluggable = 0;
}
use_efi_dflts = 1;
retry = 1;
}
}
}
dprintf(("DeBuG label_type = %d isremovable = %d ishotpluggable = %d "
/*
* For the newfs -N case, even if the disksize is > CHSLIMIT, do not
* blindly follow EFI style. If the fs_version indicates a geometry
* based layout, try that one first. If it fails we can always try the
* other logic.
*
* If we were called from growfs, we will have a problem if we mix
* and match the filesystem creation and growth styles. For example,
* if we create using EFI style, we have to also grow using EFI
* style. So follow the style indicated by the fs_version.
*
* Read and verify the primary superblock. If it looks sane, use the
* fs_version from the superblock. If the primary superblock does
* not look good, read and verify the first alternate superblock at
* ALTSB. Use the fs_version to decide whether to use the
* EFI style logic or the old geometry based logic to calculate
* the alternate superblock locations.
*/
goto start_fs_creation;
(char *)&altsblock);
if (!ret) {
mtb = 'y';
goto start_fs_creation;
}
UFS_EFISTYLE4NONEFI_VERSION_2) ? 1 : 0;
} else {
/*
* The primary superblock didn't help in determining
* the fs_version. Try the first alternate superblock.
*/
dprintf(("DeBuG checksblock() failed - error : %d"
(char *)&altsblock);
if (!ret) {
mtb = 'y';
goto start_fs_creation;
}
UFS_EFISTYLE4NONEFI_VERSION_2) ? 1 : 0;
}
dprintf(("DeBuG checksblock() returned : %d"
}
}
geom_nsect = nsect;
dprintf(("DeBuG geom_nsect=%d, geom_ntrack=%d, geom_cpg=%d\n",
invalid_sb_cnt = 0;
cg_too_small = 0;
if (use_efi_dflts) {
dprintf(("\nDeBuG Using EFI defaults\n"));
} else {
nsect = geom_nsect;
dprintf(("\nDeBuG Using Geometry\n"));
/*
* 32K based on max block size of 64K, and rotational layout
* limit is not 64K, but it's growing soon.
*/
/*
* ntrack is the number of tracks per cylinder.
* The ntrack value must be between 1 and the total number of
* sectors in the file system.
*/
}
if (mtb == 'y')
"fragment size %ld is too small, minimum with block size %ld is %ld\n"),
gettext("mkfs: fragsize reset to minimum %ld\n"),
}
gettext("fragment size must be a power of 2, not %ld\n"),
fragsize);
gettext("mkfs: fragsize reset to %ld\n"),
fragsize);
}
/* At this point, bsize must be >= fragsize, so no need to check it */
"WARNING: filesystem block size (%ld) is smaller than "
"memory page size (%ld).\nResulting filesystem can not be "
"mounted on this system.\n\n"),
}
/*
* nbpi is variable, but 2MB seems a reasonable upper limit,
* as 4MB tends to cause problems (using otherwise-default
* parameters). The true limit is where we end up with one
* inode per cylinder group. If this file system is being
* configured for multi-terabyte access, nbpi must be at least 1MB.
*/
if (nbpi_flag != RC_DEFAULT)
"nbpi: must be at least 1048576 for multi-terabyte,"
" nbpi reset to default 1048576\n"));
}
if (mtb == 'y')
else
/*
* maxcpg is another variably-limited parameter. Calculate
* the limit based on what we've got for its dependent
* variables. Effectively, it's how much space is left in the
* superblock after all the other bits are accounted for. We
* only fill in sblock fields so we can use MAXIpG.
*
* If the calculation of maxcpg below (for the mtb == 'n'
* case) is changed, update newfs as well.
*
* For old-style, non-MTB format file systems, use the old
* algorithm for calculating the maximum cylinder group size,
* even though it limits the cylinder group more than necessary.
* Since layout can affect performance, we don't want to change
* the default layout for non-MTB file systems at this time.
* However, for MTB file systems, use the new maxcpg calculation,
* which really maxes out the cylinder group size.
*/
if (mtb == 'n') {
(sizeof (long) + nrpos * sizeof (short) +
} else {
}
/*
* Increase the cpg to maxcpg if either newfs was invoked
* with -T option or if mkfs wants to create a mtb file system
* and if the user has not specified the cpg.
*/
/*
* mincpg is variable in complex ways, so we really can't
* do a sane lower-end limit check at this point.
*/
/*
* get the controller info
*/
ismdd = 0;
islog = 0;
islogok = 0;
waslog = 0;
/*
* if it is an MDD (disksuite) device
*/
ismdd++;
/*
* check the logging device
*/
islog++;
islogok++;
}
}
/*
* Do not grow the file system, but print on stdout the maximum
* size in sectors to which the file system can be increased.
* The calculated size is limited by fssize_db.
* Note that we don't lock the filesystem and therefore under rare
* conditions (the filesystem is mounted, the free block count is
* almost zero, and the superuser is still changing it) the calculated
* size can be imprecise.
*/
if (Pflag) {
exit(0);
}
/*
* If we're growing an existing filesystem, then we're about
* to start doing things that can require recovery efforts if
* we get interrupted, so make sure we get a chance to do so.
*/
if (grow) {
lockexit(3);
}
}
if (!Nflag) {
/*
* Check if MNTTAB is trustable
*/
MNTTAB);
exit(32);
}
"%s file system type is not %s, can't mkfs\n"),
exit(32);
}
/*
* If we found the block device name,
* then check the mount table.
* if mounted, and growing write lock the file system
*
*/
"can't open %s\n"), MNTTAB);
exit(32);
}
if (grow) {
continue;
}
"%s is mounted, can't mkfs\n"),
special);
exit(32);
}
}
}
special);
lockexit(32);
}
if (fso < 0) {
gettext("%s: cannot create: %s\n"),
lockexit(32);
}
} else {
/*
* For the -N case, a file descriptor is needed for the llseek()
* in wtfs(). See the comment in wtfs() for more information.
*
* Get a file descriptor that's read-only so that this code
* doesn't accidentally write to the file.
*/
if (fso < 0) {
lockexit(32);
}
}
/*
* Check the media sector size
*/
if (dkminfo.dki_lbsize != 0 &&
gettext("The device sector size %u is not "
exit(1);
}
}
/*
* seed random # generator (for ic_generation)
*/
#ifdef MKFS_DEBUG
#else
#endif
if (grow) {
goto grow00;
}
/*
* Validate the given file system size.
* Verify that its last block can actually be accessed.
*
* Note: it's ok to use sblock as a buffer because it is immediately
* overwritten by the rdfs() of the superblock in the next line.
*
* ToDo: Because the size checking is done in rdfs()/wtfs(), the
* error message for specifying an illegal size is very unfriendly.
* In the future, one could replace the rdfs()/wtfs() calls
* below with in-line calls to read() or write(). This allows better
* error messages to be put in place.
*/
/*
* make the fs unmountable
*/
/*
* Validate specified/determined spc
* and calculate minimum cylinders per group.
*/
/*
*/
if (apc_flag) {
}
/*
* Have to test for this separately from apc_flag, due to
* the growfs case....
*/
spc_flag = 1;
}
if (grow)
goto grow10;
"warning: wasteful data byte allocation / inode (nbpi):\n"));
"%ld smaller than allocatable fragment size of %d\n"),
}
if (grow)
goto grow20;
if (opt == 's')
else
/*
* Planning now for future expansion.
*/
#if defined(_BIG_ENDIAN)
#endif
#if defined(_LITTLE_ENDIAN)
#endif
"fragment size %d is too small, minimum with block size %d is %d\n"),
lockexit(32);
}
sblock.fs_fsbtodb++;
/*
* Compute the super-block, cylinder group, and inode blocks.
* Note that these "blkno" are really fragment addresses.
* fs_cblkno is 24, and fs_iblkno is 32. This is why CGSIZE is so
* important: only 1 FS block is allocated for the cg struct (fragment
* numbers 24 through 31).
*/
/*
* Validate specified/determined spc
* and calculate minimum cylinders per group.
*/
/* void */;
/* if these calculations are changed, check dump_fscmd also */
/*
* Insure that cylinder group with mincpg has enough space
* for block maps
*/
mapcramped = 0;
/*
* Make sure the cg struct fits within the file system block.
* Use larger block sizes until it fits
*/
mapcramped = 1;
if ((i & 1) == 0) {
i >>= 1;
} else {
mincpc <<= 1;
}
continue;
}
/*
* Looped far enough. The fragment is now as large as the
* filesystem block!
*/
"There is no block size that can support this disk\n"));
lockexit(32);
}
/*
* Try a larger fragment. Double the fragment size.
*/
}
/*
* Insure that cylinder group with mincpg has enough space for inodes
*/
inodecramped = 0;
used *= sectorsize;
inodecramped = 1;
break;
gettext("With a block size of %d %s %lu\n"),
mincpc >>= 1;
break;
}
}
if (inodecramped) {
"Minimum bytes per inode is %d\n"),
} else if (!mapcramped) {
"With %ld bytes per inode, minimum cylinders per group is %ld\n"),
}
}
if (mapcramped) {
"With %d sectors per cylinder, minimum cylinders "
"per group is %ld\n"),
}
if (inodecramped || mapcramped) {
/*
* To make this at least somewhat comprehensible in
* the world of i18n, figure out what we're going to
* say and then say it all at one time. The days of
* needing to scrimp on string space are behind us....
*/
"This requires the block size to be changed from %ld to %d\n"
"and the fragment size to be changed from %ld to %d\n"),
"This requires the block size to be changed from %ld to %d\n"),
"This requires the fragment size to be changed from %ld to %d\n"),
} else {
"Unable to make filesystem fit with the given constraints\n"));
}
"Please re-run mkfs with corrected parameters\n"));
lockexit(32);
}
/*
* Calculate the number of cylinders per group
*/
"Warning: cylinder groups must have a multiple "
"of %ld cylinders with the given\n parameters\n"),
mincpc);
}
/*
* Must insure there is enough space for inodes
*/
/* if these calculations are changed, check dump_fscmd also */
/*
* Slim down cylinders per group, until the inodes can fit.
*/
inodecramped = 1;
}
/*
* Must insure there is enough space to hold block map.
* Cut down on cylinders per group, until the cg struct fits in a
* filesystem block.
*/
mapcramped = 1;
}
gettext("newfs: panic (fs_cpg * fs_spc) %% NSPF != 0\n"));
lockexit(32);
}
"With the given parameters, cgsize must be at least %ld; please re-run mkfs\n"),
mincpg);
lockexit(32);
}
/*
* Now have size for file system and nsect and ntrak.
* Determine number of cylinders and blocks in the file system.
*/
if (fssize_frag > INT_MAX) {
"There are too many fragments in the system, increase fragment size\n"),
mincpg);
lockexit(32);
}
warn = 1;
}
"file systems must have at least one cylinder\n"));
lockexit(32);
}
if (grow)
goto grow30;
/*
* Determine feasability/values of rotational layout tables.
*
* The size of the rotational layout tables is limited by the size
* of the file system block, fs_bsize. The amount of space
* available for tables is calculated as (fs_bsize - sizeof (struct
* fs)). The size of these tables is inversely proportional to the
* block size of the file system. The size increases if sectors per
* track are not powers of two, because more cylinders must be
* described by the tables before the rotational pattern repeats
* (fs_cpc).
*/
goto next;
}
/* do static allocation if nrpos == 8 and fs_cpc == 16 */
/* use old static table space */
} else {
/* use 4.3 dynamic table space */
}
"Warning: insufficient space in super block for\n"
"rotational layout tables with nsect %d, ntrack %d, "
"and nrpos %d.\nOmitting tables - file system "
"performance may be impaired.\n"),
/*
* Setting fs_cpc to 0 tells alloccgblk() in ufs_alloc.c to
* ignore the positional layout table and rotational
* position table.
*/
goto next;
}
/*
* calculate the available blocks for each rotational position
*/
else
}
next:
/*
* Note that if an excessively large filesystem is specified
* (e.g., more than 16384 cylinders for an 8K filesystem block), it
* does not get detected until checksummarysize()
*/
"number of cylinders per cylinder group (%d) must be decreased.\n"),
} else {
"number of cylinders per cylinder group (%d) must be increased.\n"),
}
"Note that cgsize may have been adjusted to allow struct cg to fit.\n"));
lockexit(32);
}
"blocks (%ld) in last\n cylinder group. This "
"implies %ld sector(s) cannot be allocated.\n"),
/*
* If there is only one cylinder group and that is not even
* big enough to hold the inodes, exit.
*/
cg_too_small = 1;
warn = 0;
}
"Warning: %d sector(s) in last cylinder unallocated\n"),
}
/*
* fill in remaining fields of the super block
*/
/*
* The csum records are stored in cylinder group 0, starting at
* cgdmin, the first data block.
*/
sblock.fs_csshift++;
if (mtb == 'y') {
} else {
if (use_efi_dflts)
else
}
if (grow) {
goto grow40;
}
sblock.fs_cgrotor = 0;
/*
* If all that's needed is a dump of the superblock we
* would use by default, we've got it now. So, splat it
* out and leave.
*/
if (rflag) {
dump_sblock();
lockexit(0);
}
/*
* Dump out summary information about file system.
*/
"%s:\t%lld sectors in %d cylinders of %d tracks, %d sectors\n"),
"\t%.1fMB in %d cyl groups (%d c/g, %.2fMB/g, %d i/g)\n"),
perror("calloc");
lockexit(32);
}
if (cg_too_small) {
"There is only one cylinder group and\nthat is "
"not even big enough to hold the inodes.\n"));
lockexit(32);
}
/*
* Now build the cylinders group blocks and
* then print out indices of cylinder groups.
*/
"super-block backups (for fsck -F ufs -o b=#) at:\n"));
/*
* If Nflag and if the disk is larger than the CHSLIMIT,
* then sanity test the superblocks before reporting. If there
* are too many superblocks which look insane, we have
* to retry with alternate logic. If both methods have
* failed, then our efforts to arrive at alternate
* superblocks failed, so complain and exit.
*/
skip_this_sb = 0;
if (ret) {
skip_this_sb = 1;
dprintf(("DeBuG checksblock() failed - error :"
" %d for sb : %llu invalid_sb_cnt : %d\n",
} else {
/*
* Though the superblock looks sane, verify if
* the fs_version in the superblock and the
* logic that we are using to arrive at the
* superblocks match.
*/
skip_this_sb = 1;
}
}
if (invalid_sb_cnt >= INVALIDSBLIMIT) {
if (retry > 1) {
"Error determining alternate "
"superblock locations\n"));
lockexit(32);
}
retry++;
goto retry_alternate_logic;
}
if (skip_this_sb)
continue;
}
tprintf("\n");
} else {
}
else
}
tprintf("\n");
/*
* If there are more than 300 cylinder groups still to be
* initialized, print a "." for every 50 cylinder groups.
*/
if (remaining_cg > 300) {
do_dot = 1;
}
/*
* Now initialize all cylinder groups between the first ten
* and the last ten.
*
* If the number of cylinder groups was less than 10, all of the
* cylinder group offsets would have printed in the last loop
* and cylno will already be equal to sblock.fs_ncg and so this
* loop will not be entered. If there are less than 20 cylinder
* groups, cylno is already less than fs_ncg - 10, so this loop
* won't be entered in that case either.
*/
i = 0;
tprintf(".");
i++;
if (i == WIDTH - 1) {
tprintf("\n");
i = 0;
}
}
}
/*
* Now print the cylinder group offsets for the last 10
* cylinder groups, if any are left.
*/
if (do_dot) {
"\nsuper-block backups for last 10 cylinder groups at:\n"));
}
skip_this_sb = 0;
if (ret) {
skip_this_sb = 1;
dprintf(("DeBuG checksblock() failed - error :"
" %d for sb : %llu invalid_sb_cnt : %d\n",
} else {
/*
* Though the superblock looks sane, verify if
* the fs_version in the superblock and the
* logic that we are using to arrive at the
* superblocks match.
*/
skip_this_sb = 1;
}
}
if (invalid_sb_cnt >= INVALIDSBLIMIT) {
if (retry > 1) {
"Error determining alternate "
"superblock locations\n"));
lockexit(32);
}
retry++;
goto retry_alternate_logic;
}
if (skip_this_sb)
continue;
}
/* Don't print ',' for the last superblock */
else
tprintf("\n");
} else {
}
else
}
tprintf("\n");
if (Nflag) {
if (retry)
lockexit(0);
}
if (grow)
goto grow50;
/*
* Now construct the initial file system,
* then write out the super-block.
*/
fsinit();
/*
* write the superblock and csum information
*/
wtsb();
/*
* extend the last cylinder group in the original file system
*/
if (grow) {
wtsb();
}
/*
* Write out the duplicate super blocks to the first 10
* cylinder groups (or fewer, if there are fewer than 10
* cylinder groups).
*/
/*
* Now write out duplicate super blocks to the remaining
* cylinder groups. In the case of multi-terabyte file
* systems, just write out the super block to the last ten
* cylinder groups (or however many are left).
*/
if (mtb == 'y') {
cylno = 10;
else
}
/*
* Flush out all the AIO writes we've done. It's not
* necessary to do this explicitly, but it's the only
* way to report any errors from those writes.
*/
flush_writes();
/*
* set clean flag
*/
if (grow)
else
isbad = 0;
gettext("mkfs: fsync failed on write disk: %s\n"),
/* we're just cleaning up, so keep going */
}
gettext("mkfs: close failed on read disk: %s\n"),
/* we're just cleaning up, so keep going */
}
gettext("mkfs: close failed on write disk: %s\n"),
/* we're just cleaning up, so keep going */
}
#ifndef STANDALONE
lockexit(0);
#endif
return (0);
}
/*
* Figure out how big the partition we're dealing with is.
* The value returned is in disk blocks (sectors);
*/
static diskaddr_t
get_max_size(int fd)
{
if (index >= 0) {
} else {
/* it might be an EFI label */
}
}
if (index < 0) {
switch (index) {
case VT_ERROR:
break;
case VT_EIO:
break;
case VT_EINVAL:
}
lockexit(32);
}
if (label_type == LABEL_TYPE_EFI) {
} else {
/*
* In the vtoc struct, p_size is a 32-bit signed quantity.
* In the dk_gpt struct (efi's version of the vtoc), p_size
* is an unsigned 64-bit quantity. By casting the vtoc's
* psize to an unsigned 32-bit quantity, it will be copied
* to 'slicesize' (an unsigned 64-bit diskaddr_t) without
* sign extension.
*/
}
dprintf(("DeBuG get_max_size index = %d, p_size = %lld, dolimit = %d\n",
/*
* The next line limits a UFS file system to the maximum
* supported size.
*/
return (FS_MAX);
return (slicesize);
}
static long
get_max_track_size(int fd)
{
long track_size = -1;
}
if ((track_size < 0)) {
int error = 0;
int maxphys;
int gotit = 0;
if (gotit) {
} else {
"Warning: Could not get system value for maxphys. The value for\n"
"maxcontig will default to 1MB.\n"));
track_size = MB;
}
}
return (track_size);
}
/*
* Initialize a cylinder group.
*/
static void
{
diskaddr_t cbase, d;
int64_t i;
struct dinode *inode_buffer;
int size;
/*
* Variables used to store intermediate results as a part of
* the internal implementation of the cbtocylno() macros.
*/
int cbcylno; /* current cylinder number */
int cbcylno_sect; /* sector offset within cylinder */
int cbsect_incr; /* amount to increment sector offset */
/*
* Variables used to store intermediate results as a part of
* the internal implementation of the cbtorpos() macros.
*/
short *cgblks; /* pointer to array of free blocks in cg */
int trackrpos; /* tmp variable for rotation position */
int trackoff; /* offset within a track */
int trackoff_incr; /* amount to increment trackoff */
int rpos; /* rotation position of current block */
int rpos_incr; /* amount to increment rpos per block */
/*
* Determine block bounds for cylinder group.
* Allow space for super block summary information in first
* cylinder group.
*/
if (cylno == 0)
/* last one gets whatever's left */
else
}
if (cylno == 0)
for (i = 0; i < UFSROOTINO; i++) {
}
/*
* Initialize all the inodes in the cylinder group using
* random numbers.
*/
}
/*
* Write all inodes in a single write for performance.
*/
(char *)inode_buffer, RELEASE);
if (cylno > 0) {
}
}
}
}
/*
* WARNING: The following code is somewhat confusing, but
* results in a substantial performance improvement in mkfs.
*
* Instead of using cbtocylno() and cbtorpos() macros, we
* keep track of all the intermediate state of those macros
* in some variables. This allows simple addition to be
* done to calculate the results as we step through the
* blocks in an orderly fashion instead of the slower
* multiplication and division the macros are forced to
* used so they can support random input. (Multiplication,
* division, and remainder operations typically take about
* 10x as many processor cycles as other operations.)
*
* The basic idea is to take code:
*
* for (x = starting_x; x < max; x++)
* y = (x * c) / z
*
* and rewrite it to take advantage of the fact that
* the variable x is incrementing in an orderly way:
*
* intermediate = starting_x * c
* yval = intermediate / z
* for (x = starting_x; x < max; x++) {
* y = yval;
* intermediate += c
* if (intermediate > z) {
* yval++;
* intermediate -= z
* }
* }
*
* Performance has improved as much as 4X using this code.
*/
/*
* Initialize the starting points for all the cbtocylno()
* macro variables and figure out the increments needed each
* time through the loop.
*/
/*
* Initialize the starting points for all the cbtorpos()
* macro variables and figure out the increments needed each
* time through the loop.
*
* It's harder to simplify the cbtorpos() macro if there were
* alternate sectors specified (or if they previously existed
* in the growfs case). Since this is rare, we just revert to
* using the macros in this case and skip the variable setup.
*/
if (!spc_flag) {
}
/*
* Loop through all the blocks, marking them free and
* updating totals kept in the superblock and cg summary.
*/
if (!spc_flag)
else
bno++;
/*
* Increment the sector offset within the cylinder
* for the cbtocylno() macro reimplementation. If
* we're beyond the end of the cylinder, update the
* cylinder number, calculate the offset in the
* new cylinder, and update the cgblks pointer
* to the next rotational position.
*/
cbcylno++;
}
/*
* If there aren't alternate sectors, increment the
* rotational position variables for the cbtorpos()
* reimplementation. Note that we potentially
* increment rpos twice. Once by rpos_incr, and one
* more time when we wrap to a new track because
* trackoff >= fs_nsect.
*/
if (!spc_flag) {
rpos++;
}
}
}
}
}
}
/*
* initialize the file system
*/
#define LOSTDIR
#ifdef LOSTDIR
#define PREDEFDIR 3
#else
#define PREDEFDIR 2
#endif
#ifdef LOSTDIR
#endif
};
#ifdef LOSTDIR
struct direct lost_found_dir[] = {
{ 0, DIRBLKSIZ, 0, 0 },
};
#endif
static void
fsinit()
{
int i;
/*
* initialize the node
*/
#ifdef LOSTDIR
/*
* create the lost+found directory
*/
}
#endif
/*
* create the root directory
*/
/* i_size < 2GB because we are initializing the file system */
}
/*
* construct a set of directory entries in "buf".
* return size of directory.
*/
static int
{
char *cp;
int i;
}
return (DIRBLKSIZ);
}
/*
* allocate a block or frag
*/
static daddr32_t
{
int i, frag;
daddr32_t d;
(char *)&acg);
lockexit(32);
}
gettext("first cylinder group ran out of space\n"));
lockexit(32);
}
goto goth;
gettext("internal error: can't find block in cyl 0\n"));
lockexit(32);
goth:
}
}
(char *)&acg);
return (d);
}
/*
* Allocate an inode on the disk
*/
static void
{
diskaddr_t d;
(char *)&acg);
lockexit(32);
}
(char *)&acg);
gettext("fsinit: inode value out of range (%d).\n"),
lockexit(32);
}
}
/*
* getbuf() -- Get a buffer for use in an AIO operation. Buffer
* is zero'd the first time returned, left with whatever
* was in memory after that. This function actually gets
* enough memory the first time it's called to support
* MAXBUF buffers like a slab allocator. When all the
* buffers are in use, it waits for an aio to complete
* and make a buffer available.
*
* Never returns an error. Either succeeds or exits.
*/
static char *
{
int i;
/*
* Initialize all the buffers
*/
/*
* round up the size of our buffer header to a
* 16 byte boundary so the address we return to
* the caller is "suitably aligned".
*/
/*
* Add in our header to the buffer and round it all up to
* a 16 byte boundry so each member of the slab is aligned.
*/
/*
* Limit number of buffers to lesser of MAXBUFMEM's worth
* or MAXBUF, whichever is less.
*/
perror("calloc");
lockexit(32);
}
for (i = 0; i < max_bufs; i++) {
}
}
/*
* Get an available buffer, waiting for I/O if necessary
*/
/*
* Take the buffer off the list
*/
/*
* return the empty buffer space just past the header
*/
return ((char *)pbuf + bufhdrsize);
}
/*
* freebuf() -- Free a buffer gotten previously through getbuf.
* Puts the buffer back on the appropriate list for
* later use. Never calls free().
*
* Assumes that SIGINT is blocked.
*/
static void
{
/*
* get the header for this buffer
*/
/*
* Put it back on the list of available buffers
*/
}
/*
* freetrans() -- Free a transaction gotten previously through getaiop.
* Puts the transaction struct back on the appropriate list for
* later use. Never calls free().
*
* Assumes that SIGINT is blocked.
*/
static void
{
/*
* free the buffer associated with this AIO if needed
*/
/*
* Put transaction on the free list
*/
}
/*
* wait_for_write() -- Wait for an aio write to complete. Return
* the transaction structure for that write.
*
* Blocks SIGINT if necessary.
*/
wait_for_write(int block)
{
/*
* If we know there aren't any outstanding transactions, just return
*/
if (results.outstanding == 0)
return ((aio_trans *) 0);
return ((aio_trans *) 0);
}
/*
* The aiowrite() may have failed because the
* kernel didn't have enough memory to do the job.
* Flush all pending writes and try a normal
* write(). wtfs_breakup() will call exit if it
* fails, so we don't worry about errors here.
*/
flush_writes();
} else {
"short write (%d of %d bytes) on sector %lld\n"),
/*
* Don't unblock SIGINT, to avoid potential
* looping due to queued interrupts and
* error handling.
*/
lockexit(32);
}
}
resultp->aio_return = 0;
return (transp);
}
/*
* flush_writes() -- flush all the outstanding aio writes.
*/
static void
flush_writes(void)
{
while (wait_for_write(BLOCK))
;
}
/*
* get_aiop() -- find and return an aio_trans structure on which a new
* aio can be done. Blocks on aiowait() if needed. Reaps
* all outstanding completed aio's.
*
* Assumes that SIGINT is blocked.
*/
get_aiop()
{
int i;
/*
* initialize aio stuff
*/
if (!aio_inited) {
aio_inited = 1;
results.outstanding = 0;
sizeof (aio_trans));
perror("calloc");
lockexit(32);
}
/*
* Initialize the linked list of aio transaction
* structures. Note that the final "next" pointer
* will be NULL since we got the buffer from calloc().
*/
}
}
return (transp);
}
/*
* read a block from the file system
*/
static void
{
int n, saverr;
/*
* In case we need any data that's pending in an aiowrite(),
* we wait for them all to complete before doing a read.
*/
flush_writes();
/*
* Note: the llseek() can succeed, even if the offset is out of range.
* It's not until the file i/o operation (the read()) that one knows
* for sure if the raw device can handle the offset.
*/
gettext("seek error on sector %lld: %s\n"),
lockexit(32);
}
if (n != size) {
if (n == -1)
gettext("read error on sector %lld: %s\n"),
else
"short read (%d of %d bytes) on sector %lld\n"),
lockexit(32);
}
}
/*
* write a block to the file system
*/
static void
{
int n, saverr;
if (fso == -1)
return;
/*
* Note: the llseek() can succeed, even if the offset is out of range.
* It's not until the file i/o operation (the write()) that one knows
* for sure if the raw device can handle the offset.
*/
gettext("seek error on sector %lld: %s\n"),
lockexit(32);
}
if (Nflag)
return;
if (n != size) {
if (n == -1)
gettext("write error on sector %lld: %s\n"),
else
"short write (%d of %d bytes) on sector %lld\n"),
lockexit(32);
}
}
/*
* write a block to the file system -- buffered with aio
*/
static void
{
int n;
if (fso == -1)
return;
/*
* We need to keep things consistent if we get interrupted,
* so defer any expected interrupts for the time being.
*/
if (Nflag) {
} else {
if (n < 0) {
/*
* The aiowrite() may have failed because the
* kernel didn't have enough memory to do the job.
* Flush all pending writes and try a normal
* write(). wtfs_breakup() will call exit if it
* fails, so we don't worry about errors here.
*/
flush_writes();
} else {
/*
* Keep track of our pending writes.
*/
}
}
}
/*
* write a block to the file system, but break it up into sbsize
* chunks to avoid forcing a large amount of memory to be locked down.
* Only used as a fallback when an aio write has failed.
*/
static void
{
int n, saverr;
int wsize;
else
n = 0;
while (size) {
/*
* Note: the llseek() can succeed, even if the offset is
* out of range. It's not until the file i/o operation
* (the write()) that one knows for sure if the raw device
* can handle the offset.
*/
gettext("seek error on sector %lld: %s\n"),
lockexit(32);
}
if (n == -1) {
gettext("write error on sector %lld: %s\n"),
lockexit(32);
}
if (n != wsize) {
"short write (%d of %d bytes) on sector %lld\n"),
lockexit(32);
}
bno += block_incr;
}
}
/*
* check if a block is available
*/
static int
{
unsigned char mask;
case 8:
return (cp[h] == 0xff);
case 4:
case 2:
case 1:
default:
return (0);
}
}
/*
* take a block out of the map
*/
static void
{
case 8:
cp[h] = 0;
return;
case 4:
return;
case 2:
return;
case 1:
return;
default:
return;
}
}
/*
* put a block into the map
*/
static void
{
case 8:
cp[h] = 0xff;
return;
case 4:
return;
case 2:
return;
case 1:
return;
default:
return;
}
}
static void
usage()
{
gettext("ufs usage: mkfs [-F FSType] [-V] [-m] [-o options] "
"special " /* param 0 */
"size(sectors) \\ \n")); /* param 1 */
"[nsect " /* param 2 */
"ntrack " /* param 3 */
"bsize " /* param 4 */
"fragsize " /* param 5 */
"cpg " /* param 6 */
"free " /* param 7 */
"rps " /* param 8 */
"nbpi " /* param 9 */
"opt " /* param 10 */
"apc " /* param 11 */
"gap " /* param 12 */
"nrpos " /* param 13 */
"maxcontig " /* param 14 */
"mtb]\n"); /* param 15 */
gettext(" -m : dump fs cmd line used to make this partition\n"
" -V :print this command line and return\n"
" -o :ufs options: :nsect=%d,ntrack=%d,bsize=%d,fragsize=%d\n"
" -o :ufs options: :cgsize=%d,free=%d,rps=%d,nbpi=%d,opt=%c\n"
" -o :ufs options: :apc=%d,gap=%d,nrpos=%d,maxcontig=%d\n"
" -o :ufs options: :mtb=%c,calcsb,calcbinsb\n"
"NOTE that all -o suboptions: must be separated only by commas so as to\n"
"be parsed as a single argument\n"),
lockexit(32);
}
/*ARGSUSED*/
static void
{
/*
* ensure a valid file system and if not, exit with error or else
* we will end up computing block numbers etc and dividing by zero
* which will cause floating point errors in this routine.
*/
"[not currently a valid file system - bad superblock]\n"));
lockexit(32);
}
lockexit(32);
}
lockexit(32);
}
/*
* Compute a reasonable nbpi value.
* The algorithm for "used" is copied from code
* in main() verbatim.
* The nbpi equation is taken from main where the
* fs_ipg value is set for the last time. The INOPB(...) - 1
* is used to account for the roundup.
* The problem is that a range of nbpi values map to
* the same file system layout. So it is not possible
* to calculate the exact value specified when the file
* system was created. So instead we determine the top
* end of the range of values.
*/
used *= sectorsize;
/*
* The top end of the range of values for nbpi may not be
* a valid command line value for mkfs. Report the bottom
* end instead.
*/
}
/* number ************************************************************* */
/* */
/* Convert a numeric string arg to binary */
/* */
/* Args: d_value - default value, if have parse error */
/* param - the name of the argument, for error messages */
/* flags - parser state and what's allowed in the arg */
/* Global arg: string - pointer to command arg */
/* */
/* Valid forms: 123 | 123k | 123*123 | 123x123 */
/* */
/* Return: converted number */
/* */
/* ******************************************************************** */
static uint64_t
{
char *cs;
uint64_t n, t;
int minus = 0;
if (*cs == '-') {
minus = 1;
cs += 1;
}
goto bail_out;
}
n = 0;
}
if (minus)
n = -n;
for (;;) {
switch (*cs++) {
case 'k':
if (flags & ALLOW_END_ONLY)
goto bail_out;
if (n > (BIG / 1024))
goto overflow;
n *= 1024;
continue;
case '*':
case 'x':
if (flags & ALLOW_END_ONLY)
goto bail_out;
if (n > (BIG / t))
goto overflow;
n *= t;
/* recursion has read rest of expression */
/* FALLTHROUGH */
case ',':
case '\0':
cs--;
return (n);
case '%':
if (flags & ALLOW_END_ONLY)
goto bail_out;
if (flags & ALLOW_PERCENT) {
flags &= ~ALLOW_PERCENT;
flags |= ALLOW_END_ONLY;
continue;
}
goto bail_out;
case 'm':
if (flags & ALLOW_END_ONLY)
goto bail_out;
continue;
}
goto bail_out;
case 's':
if (flags & ALLOW_END_ONLY)
goto bail_out;
flags |= ALLOW_END_ONLY;
continue;
}
goto bail_out;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
gettext("mkfs: value for %s overflowed\n"),
param);
cs++;
return (BIG);
default:
"mkfs: bad numeric arg for %s: \"%s\"\n"),
cs++;
if (d_value != NO_DEFAULT) {
gettext("mkfs: %s reset to default %lld\n"),
return (d_value);
}
lockexit(2);
}
} /* never gets here */
}
/* match ************************************************************** */
/* */
/* Compare two text strings for equality */
/* */
/* Arg: s - pointer to string to match with a command arg */
/* Global arg: string - pointer to command arg */
/* */
/* Return: 1 if match, 0 if no match */
/* If match, also reset `string' to point to the text */
/* that follows the matching text. */
/* */
/* ******************************************************************** */
static int
match(char *s)
{
char *cs;
while (*cs++ == *s) {
if (*s++ == '\0') {
goto true;
}
}
if (*s != '\0') {
return (0);
}
true:
cs--;
return (1);
}
/*
* GROWFS ROUTINES
*/
/* ARGSUSED */
void
lockexit(int exitstatus)
{
if (Pflag) {
/* the probe mode neither changes nor locks the filesystem */
}
/*
* flush the dirty cylinder group
*/
if (inlockexit == 0) {
inlockexit = 1;
flcg();
}
if (aio_inited) {
flush_writes();
}
/*
* make sure the file system is unlocked before exiting
*/
inlockexit = 2;
ulockfs();
/*
* if logging was enabled, then re-enable it
*/
if (waslog) {
"failed to re-enable logging\n"));
}
}
} else if (grow) {
if (isbad) {
"Filesystem is currently inconsistent. It "
"must be repaired with fsck(1M)\nbefore being "
"used. Use the following command to "
"do this:\n\n\tfsck %s\n\n"), fsys);
if (ismounted) {
"You will be told that the filesystem "
"is already mounted, and asked if you\n"
"wish to continue. Answer `yes' to "
"this question.\n\n"));
}
"One problem should be reported, that the summary "
"information is bad.\nYou will then be asked if it "
"should be salvaged. Answer `yes' to\nthis "
"question.\n\n"));
}
if (ismounted) {
/*
* In theory, there's no way to get here without
* isbad also being set, but be robust in the
* face of future code changes.
*/
"The filesystem is currently mounted "
"read-only and write-locked. "));
if (isbad) {
"After\nrunning fsck, unlock the "
"filesystem and "));
} else {
"Unlock the filesystem\nand "));
}
"re-enable writing with\nthe following "
"command:\n\n\tlockfs -u %s\n\n"), directory);
}
}
}
void
{
int i;
/*
* always perform fsirand(1) function... newfs will notice that
* the inodes have been randomized and will not call fsirand itself
*/
}
/*
* Check the size of the summary information.
* Fields in sblock are not changed in this function.
*
* For an 8K filesystem block, the maximum number of cylinder groups is 16384.
* MAXCSBUFS {32} * 8K {FS block size}
* divided by (sizeof csum) {16}
*
* Note that MAXCSBUFS is not used in the kernel; as of Solaris 2.6 build 32,
* this is the only place where it's referenced.
*/
void
{
/*
* compute the maximum summary info size
*/
if (maxfrags > maxfs_blocks)
/*
* remember for later processing in extendsummaryinfo()
*/
if (test)
if (testfrags == 0)
if (testforce)
gettext("Too many test frags (%lld); "
lockexit(32);
}
/*
* if summary info is too large (too many cg's) tell the user and exit
*/
"Too many cylinder groups with %llu sectors;\n try "
"increasing cgsize, or decreasing fssize to %llu\n"),
lockexit(32);
}
}
/*
* checksblock() has two uses:
* - One is to sanity test the superblock and is used when newfs(1M)
* is invoked with the "-N" option. If any discrepancy was found,
* just return whatever error was found and do not exit.
* - the other use of it is in places where you expect the superblock
* to be sane, and if it isn't, then we exit.
* Which of the above two actions to take is indicated with the second argument.
*/
int
{
int err = 0;
char *errmsg;
err = 1;
err = 2;
err = 3;
err = 4;
err = 5;
err = 6;
"range\n");
}
if (proceed) {
return (err);
}
if (err) {
lockexit(32);
}
return (32);
}
/*
* Roll the embedded log, if any, and set up the global variables
* islog, islogok and isufslog.
*/
static void
{
/*
* Does the superblock indicate that we are supposed to have a log ?
*/
/*
* No log present, nothing to do.
*/
islogok = 0;
islog = 0;
isufslog = 0;
return;
} else {
/*
* There's a log in a yet unknown state, attempt to roll it.
*/
islog = 1;
islogok = 0;
isufslog = 0;
/*
* We failed to roll the log, bail out.
*/
return;
isufslog = 1;
/* log is not okay; check the fs */
return;
/* get the log allocation block */
return;
return;
}
/* log allocation block is not okay; check the fs */
return;
}
/* get the log state block(s) */
/* log state is okay */
islogok = 1;
}
}
void
{
int i;
/*
* Read and verify the superblock
*/
(void) checksblock(sblock, 0);
gettext("old file system format; can't growfs\n"));
lockexit(32);
}
/*
* can't shrink a file system
*/
if (fssize_db < grow_fssize) {
gettext("%lld sectors < current size of %lld sectors\n"),
lockexit(32);
}
/*
* can't grow a system to over a terabyte unless it was set up
* as an MTB UFS file system.
*/
if (fssize_db >= SECTORS_PER_TERABYTE) {
"File system was not set up with the multi-terabyte format.\n"));
"Its size cannot be increased to a terabyte or more.\n"));
} else {
"Cannot convert file system to multi-terabyte format.\n"));
}
lockexit(32);
}
/*
* can't growfs when logging device has errors
*/
gettext("logging device has errors; can't growfs\n"));
lockexit(32);
}
/*
* disable ufs logging for growing
*/
if (isufslog) {
"failed to disable logging\n"));
lockexit(32);
}
islog = 0;
waslog = 1;
}
/*
* if mounted write lock the file system to be grown
*/
if (ismounted)
wlockfs();
/*
* refresh dynamic superblock state - disabling logging will have
* changed the amount of free space available in the file system
*/
/*
* make sure device is big enough
*/
/*
* read current summary information
*/
/*
* save some current size related fields from the superblock
* These are used in extendsummaryinfo()
*/
/*
* save and reset the clean flag
*/
else
isbad = 1;
}
void
{
lockexit(32);
}
"can't check mount point; %s is not a block device\n"),
bdev);
lockexit(32);
}
lockexit(32);
}
lockexit(32);
}
}
void
{
mntp->mnt_mountp);
lockexit(32);
}
mntp->mnt_special);
lockexit(32);
}
"%s is not mounted on %s; mnttab(4) wrong\n"),
lockexit(32);
}
ismounted = 1;
if (directory) {
gettext("%s is mounted on %s, not %s\n"),
lockexit(32);
}
} else {
if (grow)
"%s is mounted on %s; can't growfs\n"),
else
gettext("%s is mounted, can't mkfs\n"),
bdevname);
lockexit(32);
}
}
}
diskaddr_t difrag = 0;
struct dinode *
{
/*
* read the block of inodes containing inode number ino
*/
if (dibuf == 0)
(char *)dibuf);
}
}
/*
* structure that manages the frags we need for extended summary info
* These frags can be:
* free
* data block
* alloc block
*/
struct csfrag {
long cylno; /* cylno of nfrag */
long frags; /* number of frags */
long size; /* size in bytes */
long fixed; /* Boolean - Already fixed? */
};
int
{
}
struct csfrag *
{
if (!csfraginrange(frag))
return (NULL);
return (cfp);
return (NULL);
}
void
{
int i;
if (frag == 0)
return;
(char *)fsb);
if (level)
}
void
{
/*
* establish a range for faster checking in csfraginrange()
*/
/*
* if this frag belongs to an inode and is not the start of a block
* then see if it is part of a frag range for this inode
*/
continue;
continue;
return;
}
/*
* allocate a csfrag entry and insert it in an increasing order into the
* specified list
*/
if (prev)
else
break;
}
break;
}
}
}
void
{
/*
* free up entry whose beginning frag matches
*/
return;
}
}
}
/*
* See whether any of the direct blocks in the array pointed by "db" and of
* length "ne" are within the range of frags needed to extend the cylinder
* summary. If so, remove those frags from the "as-yet-unclassified" list
* (csfrag) and add them to the "owned-by-inode" list (csfragino).
* For each such frag found, decrement the frag count pointed to by fragsp.
* "ino" is the inode that contains (either directly or indirectly) the frags
* being checked.
*/
void
{
int i;
int j;
int found;
/*
* scan for allocation within the new summary info range
*/
found = 0;
}
++frag;
--(*fragsp);
}
}
}
}
void
{
int i;
int j;
/*
* scan all old inodes looking for allocations in the new
* summary info range. Move the affected frag from the
* generic csfrag list onto the `owned-by-inode' list csfragino.
*/
case IFSHAD :
case IFLNK :
case IFDIR :
case IFREG : break;
default : continue;
}
/* Negate the block if its an fallocate'd block */
else
}
}
}
void
{
int i;
if (frag == 0)
return;
(char *)fsb);
if (level)
for (i = 0; i < ne; ++i)
}
void
{
int i;
if (*db == 0)
continue;
continue;
bp);
}
}
void
{
int i;
continue;
for (i = 0; i < NIADDR; ++i)
}
}
/*
* Read the cylinders summary information specified by settings in the
* passed 'fs' structure into a new allocated array of csum structures.
* The caller is responsible for freeing the returned array.
* Return a pointer to an array of csum structures.
*/
static struct csum *
{
int i;
" not enough memory\n"));
exit(32);
}
}
return (csp);
}
/*
* Check the allocation of fragments that are to be made part of a csum block.
* A fragment is allocated if it is either in the csfragfree list or, it is
* in the csfragino list and has new frags associated with it.
* Return the number of allocated fragments.
*/
{
/*
* Since the lists are sorted we can break the search if the asked
* frag is smaller then the one in the list.
*/
return (1);
}
}
return (0);
}
/*
* Figure out how much the filesystem can be grown. The limiting factor is
* the available free space needed to extend the cg summary info block.
* The free space is determined in three steps:
* - Try to extend the cg summary block to the required size.
* - Find free blocks in last cg.
* - Find free space in the last already allocated fragment of the summary info
* block, and use it for additional csum structures.
* Return the maximum size of the new filesystem or 0 if it can't be grown.
* Please note that this function leaves the global list pointers csfrag,
* csfragfree, and csfragino initialized, and the caller is responsible for
* freeing the lists.
*/
{
/* fragments by which the csum block can be extended. */
int64_t growth_csum_frags = 0;
/* fragments by which the filesystem can be extended. */
int64_t growth_fs_frags = 0;
int i;
/*
* read and verify the superblock
*/
(void) checksblock(sblock, 0);
/*
* check how much we can extend the cg summary info block
*/
/*
* read current summary information
*/
/*
* build list of frags needed for cg summary info block extension
*/
/*
* add all of the frags that are required to grow the cyl summary to the
* we don't yet know the state of those frags.
*/
/*
* filter free fragments and allocate them. Note that the free frags
* must be allocated first otherwise they could be grabbed by
* alloccsfragino() for data frags.
*/
/*
* filter fragments owned by inodes and allocate them
*/
if (notenoughspace()) {
/*
* check how many consecutive fragments could be allocated
* in both lists.
*/
else
break;
}
} else {
/*
* We have all we need for the new desired size,
* so clean up and report back.
*/
return (fssize_db);
}
/*
* given the number of fragments by which the csum block can be grown
* compute by how many new fragments the FS can be increased.
* It is the number of csum instances per fragment multiplied by
* `growth_csum_frags' and the number of fragments per cylinder group.
*/
/*
* compute free fragments in the last cylinder group
*/
/*
* compute how many csum instances are unused in the old csum block.
* For each unused csum instance the FS can be grown by one cylinder
* group without extending the csum block.
*/
if (spare_csum > 0)
/*
* recalculate the new filesystem size in sectors, shorten it by
* the requested size `fssize_db' if necessary.
*/
if (growth_fs_frags > 0) {
}
return (0);
}
void
{
int64_t i;
/*
* if no-write (-N), don't bother
*/
if (Nflag)
return;
flcg();
/*
* summary info did not change size -- do nothing unless in test mode
*/
if (!localtest)
return;
/*
* build list of frags needed for additional summary information
*/
/*
* add all of the frags that are required to grow the cyl summary to the
* we don't yet know the state of those frags.
*/
/*
* reduce the number of data blocks in the file system (fs_dsize) by
* the number of frags that need to be added to the cyl summary
*/
/*
* In test mode, we move more data than necessary from
* better stressed without having to create HUGE file systems.
*/
if (localtest)
for (i = newfrag; i < grow_sifrag; ++i) {
break;
frags++;
}
/*
* move frags to free or inode lists, depending on owner
*/
/*
* if not all frags can be located, file system must be inconsistent
*/
if (csfrag) {
lockexit(32);
}
/*
* allocate the free frags. Note that the free frags must be allocated
* first otherwise they could be grabbed by alloccsfragino() for data
* frags.
*/
/*
* allocate extra space for inode frags
*/
/*
* not enough space
*/
if (notenoughspace()) {
localtest = 0;
goto again;
}
}
/*
* copy the data from old frags to new frags
*/
/*
* fix the inodes to point to the new frags
*/
fixcsfragino();
/*
* We may have moved more frags than we needed. Free them.
*/
rdcg((long)0);
wtcg();
flcg();
}
/*
* Check if all fragments in the `csfragino' list were reallocated.
*/
int
{
/*
* If any element in the csfragino array has a "new frag location"
* of 0, the allocfrags() function was unsuccessful in allocating
* space for moving the frag represented by this array element.
*/
return (1);
return (0);
}
void
{
}
}
void
{
}
}
/*
* For each frag in the "as-yet-unclassified" list (csfrag), see if
* it's free (i.e., its bit is set in the free frag bit map). If so,
* move it from the "as-yet-unclassified" list to the csfragfree list.
*/
void
{
/*
* move free frags onto the free-frag list
*/
rdcg((long)0);
}
}
}
void
{
/*
* copy data from old frags to newly allocated frags
*/
buf);
buf);
}
}
long curcylno = -1;
int cylnodirty = 0;
void
{
flcg();
}
}
void
flcg()
{
if (cylnodirty) {
"Assert: cylnodirty set in probe mode\n");
return;
}
cylnodirty = 0;
}
curcylno = -1;
}
void
wtcg()
{
if (!Pflag) {
/* probe mode should never write to disk */
cylnodirty = 1;
}
}
void
{
int i;
int j;
long bits;
long bit;
/*
* Allocate a free-frag range in an old cylinder group
*/
for (i = 0, *fragp = 0; i < grow_fs_ncg; ++i) {
continue;
rdcg((long)i);
for (j = 0; j < frags; ++j)
wtcg();
*cylnop = i;
return;
}
}
}
}
/*
* Allocate space for frags that need to be moved in order to free up space for
* expanding the cylinder summary info.
* For each frag that needs to be moved (each frag or range of frags in
* the csfragino list), allocate a new location and store the frag number
* of that new location in the nfrag field of the csfrag struct.
* If a new frag can't be allocated for any element in the csfragino list,
* set the new frag number for that element to 0 and return immediately.
* The notenoughspace() function will detect this condition.
*/
void
{
/*
* allocate space for inode frag ranges
*/
break;
}
}
void
{
/*
* allocate the free frags needed for extended summary info
*/
rdcg((long)0);
wtcg();
}
void
{
int i;
/*
* free frags
*/
for (i = 0; i < frags; ++i) {
}
wtcg();
}
int
{
long bit;
/*
* find a range of free bits in a cylinder group bit map
*/
break;
return (0);
*bitsp = 1;
break;
break;
}
return (1);
}
void
{
long cno;
long bit;
long bits;
/*
* inmemory superblock, summary info, and cylinder group fields
*/
} else {
}
}
}
void
{
int i;
/*
* extend the cylinder group at the end of the old file system
* if it was partially allocated becase of lack of space
*/
flcg();
else
wtcg();
flcg();
}
int lockfd;
int islocked;
int lockfskey;
char lockfscomment[128];
void
ulockfs()
{
/*
* if the file system was locked, unlock it before exiting
*/
if (islocked == 0)
return;
/*
* first, check if the lock held
*/
lockexit(32);
}
if (LOCKFS_IS_MOD(&lockfs)) {
gettext("FILE SYSTEM CHANGED DURING GROWFS!\n"));
gettext(" See lockfs(1), umount(1), and fsck(1)\n"));
lockexit(32);
}
/*
* unlock the file system
*/
clockfs();
lockexit(32);
}
}
void
wlockfs()
{
/*
* if no-write (-N), don't bother
*/
if (Nflag)
return;
/*
* open the mountpoint, and write lock the file system
*/
lockexit(32);
}
/*
* check if it is already locked
*/
lockexit(32);
}
clockfs();
lockexit(32);
}
}
islocked = 1;
}
void
clockfs()
{
time_t t;
char *ct;
(void) time(&t);
}
/*
* Write the csum records and the superblock
*/
void
wtsb()
{
long i;
/*
* write summary information
*/
((char *)fscs) + i);
/*
* write superblock
*/
}
/*
* Verify that the optimization selection is reasonable, and advance
* the global "string" appropriately.
*/
static char
{
char opt;
switch (limit) {
case 0: /* missing indicator (have comma or nul) */
"mkfs: missing optimization flag reset to `t' (time)\n"));
opt = 't';
break;
case 1: /* single-character indicator */
"mkfs: bad optimization value `%c' reset to `t' (time)\n"),
opt);
opt = 't';
}
break;
default: /* multi-character indicator */
"mkfs: bad optimization value `%*.*s' reset to `t' (time)\n"),
opt = 't';
break;
}
return (opt);
}
/*
* Verify that the mtb selection is reasonable, and advance
* the global "string" appropriately.
*/
static char
{
char mtbc;
switch (limit) {
case 0: /* missing indicator (have comma or nul) */
"mkfs: missing mtb flag reset to `n' (no mtb support)\n"));
mtbc = 'n';
break;
case 1: /* single-character indicator */
"mkfs: bad mtb value `%c' reset to `n' (no mtb support)\n"),
mtbc);
mtbc = 'n';
}
break;
default: /* multi-character indicator */
"mkfs: bad mtb value `%*.*s' reset to `n' (no mtb support)\n"),
opt = 'n';
break;
}
return (mtbc);
}
/*
* Verify that a value is in a range. If it is not, resets it to
* its default value if one is supplied, exits otherwise.
*
* When testing, can compare user_supplied to RC_KEYWORD or RC_POSITIONAL.
*/
static void
long def_val, int user_supplied)
{
dprintf(("DeBuG %s : %ld (%ld %ld %ld)\n",
if (user_supplied != RC_DEFAULT) {
"mkfs: bad value for %s: %ld must be between %ld and %ld\n"),
}
if (def_val != NO_DEFAULT) {
if (user_supplied) {
gettext("mkfs: %s reset to default %ld\n"),
}
return;
}
lockexit(2);
/*NOTREACHED*/
}
}
/*
* Verify that a value is in a range. If it is not, resets it to
* its default value if one is supplied, exits otherwise.
*
* When testing, can compare user_supplied to RC_KEYWORD or RC_POSITIONAL.
*/
static void
{
if (user_supplied != RC_DEFAULT) {
"mkfs: bad value for %s: %lld must be between %lld and %lld\n"),
}
if (def_val != NO_DEFAULT) {
if (user_supplied) {
gettext("mkfs: %s reset to default %lld\n"),
}
return;
}
lockexit(2);
/*NOTREACHED*/
}
}
/*
* Blocks SIGINT from delivery. Returns the previous mask in the
* buffer provided, so that mask may be later restored.
*/
static void
{
if (sigemptyset(&block_mask) < 0) {
lockexit(3);
}
lockexit(3);
}
lockexit(3);
}
}
/*
* Restores the signal mask that was in force before a call
* to block_sigint(). This may actually still have SIGINT blocked,
* if we've been recursively invoked.
*/
static void
{
lockexit(3);
}
}
/*
* Attempt to be somewhat graceful about being interrupted, rather than
* just silently leaving the filesystem in an unusable state.
*
* The kernel has blocked SIGINT upon entry, so we don't have to worry
* about recursion if the user starts pounding on the keyboard.
*/
static void
{
if (fso > -1) {
if ((Nflag != 0) || confirm_abort()) {
lockexit(4);
}
}
}
static int
confirm_abort(void)
{
char line[80];
"in an inconsistent\nstate. If you do choose to stop, "
"you will be given instructions on how to\nrecover "
"the filesystem. Do you wish to cancel the filesystem "
"grow\noperation (y/n)?"));
line[0] = 'y';
printf("\n");
return (1);
else {
return (0);
}
}
static int
{
int n;
char *p, *lastloc;
p = loc;
if (n == EOF)
return (EOF);
*p++ = n;
}
*p = 0;
return (p - loc);
}
/*
* Calculate the maximum value of cylinders-per-group for a file
* system with the characteristics:
*
* bsize - file system block size
* fragsize - frag size
* nbpi - number of bytes of disk space per inode
* nrpos - number of rotational positions
* spc - sectors per cylinder
*
* These five characteristic are not adjustable (by this function).
* The only attribute of the file system which IS adjusted by this
* function in order to maximize cylinders-per-group is the proportion
* of the cylinder group overhead block used for the inode map. The
* inode map cannot occupy more than one-third of the cylinder group
* overhead block, but it's OK for it to occupy less than one-third
* of the overhead block.
*
* The setting of nbpi determines one possible value for the maximum
* size of a cylinder group. It does so because it determines the total
* number of inodes in the file system (file system size is fixed, and
* nbpi is fixed, so the total number of inodes is fixed too). The
* cylinder group has to be small enough so that the number of inodes
* in the cylinder group is less than or equal to the number of bits
* in one-third (or whatever proportion is assumed) of a file system
* block. The details of the calculation are:
*
* The macro MAXIpG_B(bsize, inode_divisor) determines the maximum
* number of inodes that can be in a cylinder group, given the
* proportion of the cylinder group overhead block used for the
* inode bitmaps (an inode_divisor of 3 means that 1/3 of the
* block is used for inode bitmaps; an inode_divisor of 12 means
* that 1/12 of the block is used for inode bitmaps.)
*
* Once the number of inodes per cylinder group is known, the
* maximum value of cylinders-per-group (determined by nbpi)
* is calculated by the formula
*
* maxcpg_given_nbpi = (size of a cylinder group)/(size of a cylinder)
*
* = (inodes-per-cg * nbpi)/(spc * DEV_BSIZE)
*
* (Interestingly, the size of the file system never enters
* into this calculation.)
*
* Another possible value for the maximum cylinder group size is determined
* by frag_size and nrpos. The frags in the cylinder group must be
* representable in the frag bitmaps in the cylinder overhead block and the
* rotational positions for each cylinder must be represented in the
* rotational position tables. The calculation of the maximum cpg
* value, given the frag and nrpos vales, is:
*
* maxcpg_given_fragsize =
* (available space in the overhead block) / (size of per-cylinder data)
*
* The available space in the overhead block =
* bsize - sizeof (struct cg) - space_used_for_inode_bitmaps
*
* The size of the per-cylinder data is:
* sizeof(long) # for the "blocks avail per cylinder" field
* + nrpos * sizeof(short) # for the rotational position table entry
* + frags-per-cylinder/NBBY # number of bytes to represent this
* # cylinder in the frag bitmap
*
* The two calculated maximum values of cylinder-per-group will typically
* turn out to be different, since they are derived from two different
* constraints. Usually, maxcpg_given_nbpi is much bigger than
* maxcpg_given_fragsize. But they can be brought together by
* adjusting the proportion of the overhead block dedicated to
* the inode bitmaps. Decreasing the proportion of the cylinder
* group overhead block used for inode maps will decrease
* maxcpg_given_nbpi and increase maxcpg_given_fragsize.
*
* This function calculates the initial values of maxcpg_given_nbpi
* and maxcpg_given_fragsize assuming that 1/3 of the cg overhead
* block is used for inode bitmaps. Then it decreases the proportion
* of the cg overhead block used for inode bitmaps (by increasing
* the value of inode_divisor) until maxcpg_given_nbpi and
* maxcpg_given_fragsize are the same, or stop changing, or
* maxcpg_given_nbpi is less than maxcpg_given_fragsize.
*
* The loop terminates when any of the following occur:
* * maxcpg_given_fragsize is greater than or equal to
* maxcpg_given_nbpi
* * neither maxcpg_given_fragsize nor maxcpg_given_nbpi
* change in the expected direction
*
* The loop is guaranteed to terminate because it only continues
* while maxcpg_given_fragsize and maxcpg_given_nbpi are approaching
* each other. As soon they cross each other, or neither one changes
* in the direction of the other, or one of them moves in the wrong
* direction, the loop completes.
*/
static long
{
int maxcpg_given_nbpi; /* in cylinders */
int maxcpg_given_fragsize; /* in cylinders */
int spf; /* sectors per frag */
int inode_divisor;
int old_max_given_frag = 0;
int old_max_given_nbpi = INT_MAX;
inode_divisor = 3;
while (1) {
(sizeof (long) + nrpos * sizeof (short) +
return (maxcpg_given_nbpi);
/*
* If neither value moves toward the other, return the
* least of the old values (we use the old instead of the
* new because: if the old is the same as the new, it
* doesn't matter which ones we use. If one of the
* values changed, but in the wrong direction, the
* new values are suspect. Better use the old. This
* shouldn't happen, but it's best to check.
*/
if (!(maxcpg_given_nbpi < old_max_given_nbpi) &&
/*
* This is probably impossible, but if one of the maxcpg
* values moved in the "right" direction and one moved
* in the "wrong" direction (that is, the two values moved
* in the same direction), the previous conditional won't
* recognize that the values aren't converging (since at
* least one value moved in the "right" direction, the
* last conditional says "keep going").
*
* Just to make absolutely certain that the loop terminates,
* check for one of the values moving in the "wrong" direction
* and terminate the loop if it happens.
*/
if (maxcpg_given_nbpi > old_max_given_nbpi ||
}
}
static int
in_64bit_mode(void)
{
/* cmd must be an absolute path, for security */
int retval = 0;
putenv("IFS= \t");
retval = 1;
}
return (retval);
}
/*
* validate_size
*
* Return 1 if the device appears to be at least "size" sectors long.
* Return 0 if it's shorter or we can't read it.
*/
static int
{
int rc;
rc = 0;
else
rc = 1;
return (rc);
}
/*
* Print every field of the calculated superblock, along with
* its value. To make parsing easier on the caller, the value
* is printed first, then the name. Additionally, there's only
* hexadecimal (with the traditional 0x prefix), as that's slightly
* easier for humans to read. Not that they're expected to, but
* debugging happens.
*/
static void
dump_sblock(void)
{
if (Rflag) {
do {
if (written < 0) {
lockexit(1);
}
return;
} else {
#ifdef _LITTLE_ENDIAN
#else
#endif
/*
* No macros are defined for the dimensions of the
* opostbl array.
*/
printf("0x%x sblock.fs_opostbl[%d][%d]\n",
}
}
/*
* Ditto the size of sparecon.
*/
printf("0x%x sblock.fs_sparecon[%d]\n",
}
#ifdef _LITTLE_ENDIAN
#else
#endif
/*
* fs_space isn't of much use in this context, so we'll
* just ignore it for now.
*/
}
}