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 */ 21*23a1cceaSRoger A. Faulkner 227c478bd9Sstevel@tonic-gate /* 23*23a1cceaSRoger A. Faulkner * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. 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 /* 407c478bd9Sstevel@tonic-gate * The maximum supported file system size (in sectors) is the 417c478bd9Sstevel@tonic-gate * number of frags that can be represented in an int32_t field 427c478bd9Sstevel@tonic-gate * (INT_MAX) times the maximum number of sectors per frag. Since 437c478bd9Sstevel@tonic-gate * the maximum frag size is MAXBSIZE, the maximum number of sectors 447c478bd9Sstevel@tonic-gate * per frag is MAXBSIZE/DEV_BSIZE. 457c478bd9Sstevel@tonic-gate */ 467c478bd9Sstevel@tonic-gate #define FS_MAX (((diskaddr_t)INT_MAX) * (MAXBSIZE/DEV_BSIZE)) 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate /* 497c478bd9Sstevel@tonic-gate * make file system for cylinder-group style file systems 507c478bd9Sstevel@tonic-gate * 517c478bd9Sstevel@tonic-gate * usage: 527c478bd9Sstevel@tonic-gate * 537c478bd9Sstevel@tonic-gate * mkfs [-F FSType] [-V] [-G [-P]] [-M dirname] [-m] [options] 547c478bd9Sstevel@tonic-gate * [-o specific_options] special size 557c478bd9Sstevel@tonic-gate * [nsect ntrack bsize fsize cpg minfree rps nbpi opt apc rotdelay 567c478bd9Sstevel@tonic-gate * 2 3 4 5 6 7 8 9 10 11 12 577c478bd9Sstevel@tonic-gate * nrpos maxcontig mtb] 587c478bd9Sstevel@tonic-gate * 13 14 15 597c478bd9Sstevel@tonic-gate * 607c478bd9Sstevel@tonic-gate * where specific_options are: 617c478bd9Sstevel@tonic-gate * N - no create 627c478bd9Sstevel@tonic-gate * nsect - The number of sectors per track 637c478bd9Sstevel@tonic-gate * ntrack - The number of tracks per cylinder 647c478bd9Sstevel@tonic-gate * bsize - block size 657c478bd9Sstevel@tonic-gate * fragsize - fragment size 667c478bd9Sstevel@tonic-gate * cgsize - The number of disk cylinders per cylinder group. 677c478bd9Sstevel@tonic-gate * free - minimum free space 687c478bd9Sstevel@tonic-gate * rps - rotational speed (rev/sec). 697c478bd9Sstevel@tonic-gate * nbpi - number of data bytes per allocated inode 707c478bd9Sstevel@tonic-gate * opt - optimization (space, time) 717c478bd9Sstevel@tonic-gate * apc - number of alternates 727c478bd9Sstevel@tonic-gate * gap - gap size 737c478bd9Sstevel@tonic-gate * nrpos - number of rotational positions 747c478bd9Sstevel@tonic-gate * maxcontig - maximum number of logical blocks that will be 757c478bd9Sstevel@tonic-gate * allocated contiguously before inserting rotational delay 767c478bd9Sstevel@tonic-gate * mtb - if "y", set up file system for eventual growth to over a 777c478bd9Sstevel@tonic-gate * a terabyte 787c478bd9Sstevel@tonic-gate * -P Do not grow the file system, but print on stdout the maximal 797c478bd9Sstevel@tonic-gate * size in sectors to which the file system can be increased. The calculated 807c478bd9Sstevel@tonic-gate * size is limited by the value provided by the operand size. 817c478bd9Sstevel@tonic-gate * 827c478bd9Sstevel@tonic-gate * Note that -P is a project-private interface and together with -G intended 837c478bd9Sstevel@tonic-gate * to be used only by the growfs script. It is therefore purposely not 847c478bd9Sstevel@tonic-gate * documented in the man page. 857c478bd9Sstevel@tonic-gate * The -P option is covered by PSARC case 2003/422. 867c478bd9Sstevel@tonic-gate */ 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate /* 897c478bd9Sstevel@tonic-gate * The following constants set the defaults used for the number 907c478bd9Sstevel@tonic-gate * of sectors/track (fs_nsect), and number of tracks/cyl (fs_ntrak). 917c478bd9Sstevel@tonic-gate * 927c478bd9Sstevel@tonic-gate * NSECT NTRAK 937c478bd9Sstevel@tonic-gate * 72MB CDC 18 9 947c478bd9Sstevel@tonic-gate * 30MB CDC 18 5 957c478bd9Sstevel@tonic-gate * 720KB Diskette 9 2 966451fdbcSvsakar * 976451fdbcSvsakar * However the defaults will be different for disks larger than CHSLIMIT. 987c478bd9Sstevel@tonic-gate */ 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate #define DFLNSECT 32 1017c478bd9Sstevel@tonic-gate #define DFLNTRAK 16 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate /* 1046451fdbcSvsakar * The following default sectors and tracks values are used for 1056451fdbcSvsakar * non-efi disks that are larger than the CHS addressing limit. The 1066451fdbcSvsakar * existing default cpg of 16 (DESCPG) holds good for larger disks too. 1077c478bd9Sstevel@tonic-gate */ 1086451fdbcSvsakar #define DEF_SECTORS_EFI 128 1096451fdbcSvsakar #define DEF_TRACKS_EFI 48 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate /* 1127c478bd9Sstevel@tonic-gate * The maximum number of cylinders in a group depends upon how much 1137c478bd9Sstevel@tonic-gate * information can be stored on a single cylinder. The default is to 1147c478bd9Sstevel@tonic-gate * use 16 cylinders per group. This is effectively tradition - it was 1157c478bd9Sstevel@tonic-gate * the largest value acceptable under SunOs 4.1 1167c478bd9Sstevel@tonic-gate */ 1177c478bd9Sstevel@tonic-gate #define DESCPG 16 /* desired fs_cpg */ 1187c478bd9Sstevel@tonic-gate 1196451fdbcSvsakar /* 1206451fdbcSvsakar * The following two constants set the default block and fragment sizes. 1216451fdbcSvsakar * Both constants must be a power of 2 and meet the following constraints: 1226451fdbcSvsakar * MINBSIZE <= DESBLKSIZE <= MAXBSIZE 1236451fdbcSvsakar * DEV_BSIZE <= DESFRAGSIZE <= DESBLKSIZE 1246451fdbcSvsakar * DESBLKSIZE / DESFRAGSIZE <= 8 1256451fdbcSvsakar */ 1266451fdbcSvsakar #define DESBLKSIZE 8192 1276451fdbcSvsakar #define DESFRAGSIZE 1024 1286451fdbcSvsakar 1297c478bd9Sstevel@tonic-gate /* 1307c478bd9Sstevel@tonic-gate * MINFREE gives the minimum acceptable percentage of file system 1317c478bd9Sstevel@tonic-gate * blocks which may be free. If the freelist drops below this level 1327c478bd9Sstevel@tonic-gate * only the superuser may continue to allocate blocks. This may 1337c478bd9Sstevel@tonic-gate * be set to 0 if no reserve of free blocks is deemed necessary, 1347c478bd9Sstevel@tonic-gate * however throughput drops by fifty percent if the file system 1357c478bd9Sstevel@tonic-gate * is run at between 90% and 100% full; thus the default value of 1367c478bd9Sstevel@tonic-gate * fs_minfree is 10%. With 10% free space, fragmentation is not a 1377c478bd9Sstevel@tonic-gate * problem, so we choose to optimize for time. 1387c478bd9Sstevel@tonic-gate */ 1397c478bd9Sstevel@tonic-gate #define MINFREE 10 1407c478bd9Sstevel@tonic-gate #define DEFAULTOPT FS_OPTTIME 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate /* 1437c478bd9Sstevel@tonic-gate * ROTDELAY gives the minimum number of milliseconds to initiate 1447c478bd9Sstevel@tonic-gate * another disk transfer on the same cylinder. It is no longer used 1457c478bd9Sstevel@tonic-gate * and will always default to 0. 1467c478bd9Sstevel@tonic-gate */ 1477c478bd9Sstevel@tonic-gate #define ROTDELAY 0 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate /* 1507c478bd9Sstevel@tonic-gate * MAXBLKPG determines the maximum number of data blocks which are 1517c478bd9Sstevel@tonic-gate * placed in a single cylinder group. The default is one indirect 1527c478bd9Sstevel@tonic-gate * block worth of data blocks. 1537c478bd9Sstevel@tonic-gate */ 1547c478bd9Sstevel@tonic-gate #define MAXBLKPG(bsize) ((bsize) / sizeof (daddr32_t)) 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate /* 1577c478bd9Sstevel@tonic-gate * Each file system has a number of inodes statically allocated. 1587c478bd9Sstevel@tonic-gate * We allocate one inode slot per NBPI bytes, expecting this 1597c478bd9Sstevel@tonic-gate * to be far more than we will ever need. 1607c478bd9Sstevel@tonic-gate */ 1617c478bd9Sstevel@tonic-gate #define NBPI 2048 /* Number Bytes Per Inode */ 1627c478bd9Sstevel@tonic-gate #define MTB_NBPI (MB) /* Number Bytes Per Inode for multi-terabyte */ 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate /* 1657c478bd9Sstevel@tonic-gate * Disks are assumed to rotate at 60HZ, unless otherwise specified. 1667c478bd9Sstevel@tonic-gate */ 1677c478bd9Sstevel@tonic-gate #define DEFHZ 60 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate /* 1707c478bd9Sstevel@tonic-gate * Cylinder group related limits. 1717c478bd9Sstevel@tonic-gate * 1727c478bd9Sstevel@tonic-gate * For each cylinder we keep track of the availability of blocks at different 1737c478bd9Sstevel@tonic-gate * rotational positions, so that we can lay out the data to be picked 1747c478bd9Sstevel@tonic-gate * up with minimum rotational latency. NRPOS is the number of rotational 1757c478bd9Sstevel@tonic-gate * positions which we distinguish. With NRPOS 8 the resolution of our 1767c478bd9Sstevel@tonic-gate * summary information is 2ms for a typical 3600 rpm drive. 1777c478bd9Sstevel@tonic-gate */ 1787c478bd9Sstevel@tonic-gate #define NRPOS 8 /* number distinct rotational positions */ 1797c478bd9Sstevel@tonic-gate 1806451fdbcSvsakar #ifdef DEBUG 1816451fdbcSvsakar #define dprintf(x) printf x 1826451fdbcSvsakar #else 1836451fdbcSvsakar #define dprintf(x) 1846451fdbcSvsakar #endif 1856451fdbcSvsakar 1866451fdbcSvsakar /* 1876451fdbcSvsakar * For the -N option, when calculating the backup superblocks, do not print 1886451fdbcSvsakar * them if we are not really sure. We may have to try an alternate method of 1896451fdbcSvsakar * arriving at the superblocks. So defer printing till a handful of superblocks 1906451fdbcSvsakar * look good. 1916451fdbcSvsakar */ 1926451fdbcSvsakar #define tprintf(x) if (Nflag && retry) \ 1936d24e334Svsakar (void) strncat(tmpbuf, x, strlen(x)); \ 1946451fdbcSvsakar else \ 1956451fdbcSvsakar (void) fprintf(stderr, x); 1966451fdbcSvsakar 1976451fdbcSvsakar #define ALTSB 32 /* Location of first backup superblock */ 1986451fdbcSvsakar 1997c478bd9Sstevel@tonic-gate /* 2007c478bd9Sstevel@tonic-gate * range_check "user_supplied" flag values. 2017c478bd9Sstevel@tonic-gate */ 2027c478bd9Sstevel@tonic-gate #define RC_DEFAULT 0 2037c478bd9Sstevel@tonic-gate #define RC_KEYWORD 1 2047c478bd9Sstevel@tonic-gate #define RC_POSITIONAL 2 2057c478bd9Sstevel@tonic-gate 206303bf60bSsdebnath /* 207303bf60bSsdebnath * ufs hole 208303bf60bSsdebnath */ 209303bf60bSsdebnath #define UFS_HOLE -1 210303bf60bSsdebnath 2117c478bd9Sstevel@tonic-gate #ifndef STANDALONE 2127c478bd9Sstevel@tonic-gate #include <stdio.h> 2137c478bd9Sstevel@tonic-gate #include <sys/mnttab.h> 2147c478bd9Sstevel@tonic-gate #endif 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate #include <stdlib.h> 2177c478bd9Sstevel@tonic-gate #include <unistd.h> 2187c478bd9Sstevel@tonic-gate #include <malloc.h> 2197c478bd9Sstevel@tonic-gate #include <string.h> 2207c478bd9Sstevel@tonic-gate #include <strings.h> 2217c478bd9Sstevel@tonic-gate #include <ctype.h> 2227c478bd9Sstevel@tonic-gate #include <errno.h> 2237c478bd9Sstevel@tonic-gate #include <sys/param.h> 2247c478bd9Sstevel@tonic-gate #include <time.h> 2257c478bd9Sstevel@tonic-gate #include <sys/types.h> 2267c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 2277c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 2287c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fsdir.h> 2297c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_inode.h> 2307c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h> 2317c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_log.h> 2327c478bd9Sstevel@tonic-gate #include <sys/mntent.h> 2337c478bd9Sstevel@tonic-gate #include <sys/filio.h> 2347c478bd9Sstevel@tonic-gate #include <limits.h> 2357c478bd9Sstevel@tonic-gate #include <sys/int_const.h> 2367c478bd9Sstevel@tonic-gate #include <signal.h> 2377c478bd9Sstevel@tonic-gate #include <sys/efi_partition.h> 2387c478bd9Sstevel@tonic-gate #include "roll_log.h" 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate #define bcopy(f, t, n) (void) memcpy(t, f, n) 2417c478bd9Sstevel@tonic-gate #define bzero(s, n) (void) memset(s, 0, n) 2427c478bd9Sstevel@tonic-gate #define bcmp(s, d, n) memcmp(s, d, n) 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate #define index(s, r) strchr(s, r) 2457c478bd9Sstevel@tonic-gate #define rindex(s, r) strrchr(s, r) 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate #include <sys/stat.h> 2487c478bd9Sstevel@tonic-gate #include <sys/statvfs.h> 2497c478bd9Sstevel@tonic-gate #include <locale.h> 2507c478bd9Sstevel@tonic-gate #include <fcntl.h> 2517c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h> /* for ENDIAN defines */ 2527c478bd9Sstevel@tonic-gate #include <sys/vtoc.h> 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate #include <sys/dkio.h> 2557c478bd9Sstevel@tonic-gate #include <sys/asynch.h> 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate extern offset_t llseek(); 2587c478bd9Sstevel@tonic-gate extern char *getfullblkname(); 2597c478bd9Sstevel@tonic-gate extern long lrand48(); 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate extern int optind; 2627c478bd9Sstevel@tonic-gate extern char *optarg; 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate /* 2667c478bd9Sstevel@tonic-gate * The size of a cylinder group is calculated by CGSIZE. The maximum size 2677c478bd9Sstevel@tonic-gate * is limited by the fact that cylinder groups are at most one block. 2687c478bd9Sstevel@tonic-gate * Its size is derived from the size of the maps maintained in the 2697c478bd9Sstevel@tonic-gate * cylinder group and the (struct cg) size. 2707c478bd9Sstevel@tonic-gate */ 2717c478bd9Sstevel@tonic-gate #define CGSIZE(fs) \ 2727c478bd9Sstevel@tonic-gate /* base cg */ (sizeof (struct cg) + \ 2737c478bd9Sstevel@tonic-gate /* blktot size */ (fs)->fs_cpg * sizeof (long) + \ 2747c478bd9Sstevel@tonic-gate /* blks size */ (fs)->fs_cpg * (fs)->fs_nrpos * sizeof (short) + \ 2757c478bd9Sstevel@tonic-gate /* inode map */ howmany((fs)->fs_ipg, NBBY) + \ 2767c478bd9Sstevel@tonic-gate /* block map */ howmany((fs)->fs_cpg * (fs)->fs_spc / NSPF(fs), NBBY)) 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate /* 2797c478bd9Sstevel@tonic-gate * We limit the size of the inode map to be no more than a 2807c478bd9Sstevel@tonic-gate * third of the cylinder group space, since we must leave at 2817c478bd9Sstevel@tonic-gate * least an equal amount of space for the block map. 2827c478bd9Sstevel@tonic-gate * 2837c478bd9Sstevel@tonic-gate * N.B.: MAXIpG must be a multiple of INOPB(fs). 2847c478bd9Sstevel@tonic-gate */ 2857c478bd9Sstevel@tonic-gate #define MAXIpG(fs) roundup((fs)->fs_bsize * NBBY / 3, INOPB(fs)) 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate /* 2887c478bd9Sstevel@tonic-gate * Same as MAXIpG, but parameterized by the block size (b) and the 2897c478bd9Sstevel@tonic-gate * cylinder group divisor (d), which is the reciprocal of the fraction of the 2907c478bd9Sstevel@tonic-gate * cylinder group overhead block that is used for the inode map. So for 2917c478bd9Sstevel@tonic-gate * example, if d = 5, the macro's computation assumes that 1/5 of the 2927c478bd9Sstevel@tonic-gate * cylinder group overhead block can be dedicated to the inode map. 2937c478bd9Sstevel@tonic-gate */ 2947c478bd9Sstevel@tonic-gate #define MAXIpG_B(b, d) roundup((b) * NBBY / (d), (b) / sizeof (struct dinode)) 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate #define UMASK 0755 2977c478bd9Sstevel@tonic-gate #define MAXINOPB (MAXBSIZE / sizeof (struct dinode)) 2987c478bd9Sstevel@tonic-gate #define POWEROF2(num) (((num) & ((num) - 1)) == 0) 2997c478bd9Sstevel@tonic-gate #define MB (1024*1024) 3007c478bd9Sstevel@tonic-gate #define BETWEEN(x, l, h) ((x) >= (l) && (x) <= (h)) 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate /* 3037c478bd9Sstevel@tonic-gate * Used to set the inode generation number. Since both inodes and dinodes 3047c478bd9Sstevel@tonic-gate * are dealt with, we really need a pointer to an icommon here. 3057c478bd9Sstevel@tonic-gate */ 3067c478bd9Sstevel@tonic-gate #define IRANDOMIZE(icp) (icp)->ic_gen = lrand48(); 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate /* 3097c478bd9Sstevel@tonic-gate * Flags for number() 3107c478bd9Sstevel@tonic-gate */ 3117c478bd9Sstevel@tonic-gate #define ALLOW_PERCENT 0x01 /* allow trailing `%' on number */ 3127c478bd9Sstevel@tonic-gate #define ALLOW_MS1 0x02 /* allow trailing `ms', state 1 */ 3137c478bd9Sstevel@tonic-gate #define ALLOW_MS2 0x04 /* allow trailing `ms', state 2 */ 3147c478bd9Sstevel@tonic-gate #define ALLOW_END_ONLY 0x08 /* must be at end of number & suffixes */ 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate #define MAXAIO 1000 /* maximum number of outstanding I/O's we'll manage */ 3177c478bd9Sstevel@tonic-gate #define BLOCK 1 /* block in aiowait */ 3187c478bd9Sstevel@tonic-gate #define NOBLOCK 0 /* don't block in aiowait */ 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate #define RELEASE 1 /* free an aio buffer after use */ 3217c478bd9Sstevel@tonic-gate #define SAVE 0 /* don't free the buffer */ 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate typedef struct aio_trans { 3247c478bd9Sstevel@tonic-gate aio_result_t resultbuf; 3257c478bd9Sstevel@tonic-gate diskaddr_t bno; 3267c478bd9Sstevel@tonic-gate char *buffer; 3277c478bd9Sstevel@tonic-gate int size; 3287c478bd9Sstevel@tonic-gate int release; 3297c478bd9Sstevel@tonic-gate struct aio_trans *next; 3307c478bd9Sstevel@tonic-gate } aio_trans; 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate typedef struct aio_results { 3337c478bd9Sstevel@tonic-gate int max; 3347c478bd9Sstevel@tonic-gate int outstanding; 3357c478bd9Sstevel@tonic-gate int maxpend; 3367c478bd9Sstevel@tonic-gate aio_trans *trans; 3377c478bd9Sstevel@tonic-gate } aio_results; 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate int aio_inited = 0; 3407c478bd9Sstevel@tonic-gate aio_results results; 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate /* 3437c478bd9Sstevel@tonic-gate * Allow up to MAXBUF aio requests that each have a unique buffer. 3447c478bd9Sstevel@tonic-gate * More aio's might be done, but not using memory through the getbuf() 3457c478bd9Sstevel@tonic-gate * interface. This can be raised, but you run into the potential of 3467c478bd9Sstevel@tonic-gate * using more memory than is physically available on the machine, 3477c478bd9Sstevel@tonic-gate * and if you start swapping, you can forget about performance. 3487c478bd9Sstevel@tonic-gate * To prevent this, we also limit the total memory used for a given 3497c478bd9Sstevel@tonic-gate * type of buffer to MAXBUFMEM. 3507c478bd9Sstevel@tonic-gate * 3517c478bd9Sstevel@tonic-gate * Tests indicate a cylinder group's worth of inodes takes: 3527c478bd9Sstevel@tonic-gate * 3537c478bd9Sstevel@tonic-gate * NBPI Size of Inode Buffer 3547c478bd9Sstevel@tonic-gate * 2k 1688k 3557c478bd9Sstevel@tonic-gate * 8k 424k 3567c478bd9Sstevel@tonic-gate * 3577c478bd9Sstevel@tonic-gate * initcg() stores all the inodes for a cylinder group in one buffer, 3587c478bd9Sstevel@tonic-gate * so allowing 20 buffers could take 32 MB if not limited by MAXBUFMEM. 3597c478bd9Sstevel@tonic-gate */ 3607c478bd9Sstevel@tonic-gate #define MAXBUF 20 3617c478bd9Sstevel@tonic-gate #define MAXBUFMEM (8 * 1024 * 1024) 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate /* 3647c478bd9Sstevel@tonic-gate * header information for buffers managed by getbuf() and freebuf() 3657c478bd9Sstevel@tonic-gate */ 3667c478bd9Sstevel@tonic-gate typedef struct bufhdr { 3677c478bd9Sstevel@tonic-gate struct bufhdr *head; 3687c478bd9Sstevel@tonic-gate struct bufhdr *next; 3697c478bd9Sstevel@tonic-gate } bufhdr; 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate int bufhdrsize; 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate bufhdr inodebuf = { NULL, NULL }; 3747c478bd9Sstevel@tonic-gate bufhdr cgsumbuf = { NULL, NULL }; 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate #define SECTORS_PER_TERABYTE (1LL << 31) 3777c478bd9Sstevel@tonic-gate /* 3787c478bd9Sstevel@tonic-gate * The following constant specifies an upper limit for file system size 3797c478bd9Sstevel@tonic-gate * that is actually a lot bigger than we expect to support with UFS. (Since 3807c478bd9Sstevel@tonic-gate * it's specified in sectors, the file system size would be 2**44 * 512, 3817c478bd9Sstevel@tonic-gate * which is 2**53, which is 8192 Terabytes.) However, it's useful 3827c478bd9Sstevel@tonic-gate * for checking the basic sanity of a size value that is input on the 3837c478bd9Sstevel@tonic-gate * command line. 3847c478bd9Sstevel@tonic-gate */ 3857c478bd9Sstevel@tonic-gate #define FS_SIZE_UPPER_LIMIT 0x100000000000LL 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate /* 3887c478bd9Sstevel@tonic-gate * Forward declarations 3897c478bd9Sstevel@tonic-gate */ 3907c478bd9Sstevel@tonic-gate static char *getbuf(bufhdr *bufhead, int size); 3917c478bd9Sstevel@tonic-gate static void freebuf(char *buf); 3927c478bd9Sstevel@tonic-gate static void freetrans(aio_trans *transp); 3937c478bd9Sstevel@tonic-gate static aio_trans *get_aiop(); 3947c478bd9Sstevel@tonic-gate static aio_trans *wait_for_write(int block); 3957c478bd9Sstevel@tonic-gate static void initcg(int cylno); 3967c478bd9Sstevel@tonic-gate static void fsinit(); 3977c478bd9Sstevel@tonic-gate static int makedir(struct direct *protodir, int entries); 3987c478bd9Sstevel@tonic-gate static void iput(struct inode *ip); 3997c478bd9Sstevel@tonic-gate static void rdfs(diskaddr_t bno, int size, char *bf); 4007c478bd9Sstevel@tonic-gate static void wtfs(diskaddr_t bno, int size, char *bf); 4017c478bd9Sstevel@tonic-gate static void awtfs(diskaddr_t bno, int size, char *bf, int release); 4027c478bd9Sstevel@tonic-gate static void wtfs_breakup(diskaddr_t bno, int size, char *bf); 4037c478bd9Sstevel@tonic-gate static int isblock(struct fs *fs, unsigned char *cp, int h); 4047c478bd9Sstevel@tonic-gate static void clrblock(struct fs *fs, unsigned char *cp, int h); 4057c478bd9Sstevel@tonic-gate static void setblock(struct fs *fs, unsigned char *cp, int h); 4067c478bd9Sstevel@tonic-gate static void usage(); 4077c478bd9Sstevel@tonic-gate static void dump_fscmd(char *fsys, int fsi); 4087c478bd9Sstevel@tonic-gate static uint64_t number(uint64_t d_value, char *param, int flags); 4097c478bd9Sstevel@tonic-gate static int match(char *s); 4107c478bd9Sstevel@tonic-gate static char checkopt(char *optim); 4117c478bd9Sstevel@tonic-gate static char checkmtb(char *mtbarg); 4127c478bd9Sstevel@tonic-gate static void range_check(long *varp, char *name, long minimum, 4137c478bd9Sstevel@tonic-gate long maximum, long def_val, int user_supplied); 4147c478bd9Sstevel@tonic-gate static void range_check_64(uint64_t *varp, char *name, uint64_t minimum, 4157c478bd9Sstevel@tonic-gate uint64_t maximum, uint64_t def_val, int user_supplied); 4167c478bd9Sstevel@tonic-gate static daddr32_t alloc(int size, int mode); 4177c478bd9Sstevel@tonic-gate static diskaddr_t get_max_size(int fd); 4187c478bd9Sstevel@tonic-gate static long get_max_track_size(int fd); 4197c478bd9Sstevel@tonic-gate static void block_sigint(sigset_t *old_mask); 4207c478bd9Sstevel@tonic-gate static void unblock_sigint(sigset_t *old_mask); 4217c478bd9Sstevel@tonic-gate static void recover_from_sigint(int signum); 4227c478bd9Sstevel@tonic-gate static int confirm_abort(void); 423*23a1cceaSRoger A. Faulkner static int getaline(FILE *fp, char *loc, int maxlen); 4247c478bd9Sstevel@tonic-gate static void flush_writes(void); 4257c478bd9Sstevel@tonic-gate static long compute_maxcpg(long, long, long, long, long); 4267c478bd9Sstevel@tonic-gate static int in_64bit_mode(void); 4277c478bd9Sstevel@tonic-gate static int validate_size(int fd, diskaddr_t size); 428355d6bb5Sswilcox static void dump_sblock(void); 4297c478bd9Sstevel@tonic-gate 430140e9cb2Sprabahar /* 431140e9cb2Sprabahar * Workaround for mkfs to function properly on disks attached to XMIT 2.X 432140e9cb2Sprabahar * controller. If the address is not aligned at 8 byte boundary, mkfs on 433140e9cb2Sprabahar * disks attached to XMIT 2.X controller exhibts un-predictable behaviour. 434140e9cb2Sprabahar */ 435140e9cb2Sprabahar #define XMIT_2_X_ALIGN 8 436140e9cb2Sprabahar #pragma align XMIT_2_X_ALIGN(fsun, altfsun, cgun) 437140e9cb2Sprabahar 4387c478bd9Sstevel@tonic-gate union { 4397c478bd9Sstevel@tonic-gate struct fs fs; 4407c478bd9Sstevel@tonic-gate char pad[SBSIZE]; 4416451fdbcSvsakar } fsun, altfsun; 4427c478bd9Sstevel@tonic-gate #define sblock fsun.fs 4436451fdbcSvsakar #define altsblock altfsun.fs 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate struct csum *fscs; 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate union cgun { 4487c478bd9Sstevel@tonic-gate struct cg cg; 4497c478bd9Sstevel@tonic-gate char pad[MAXBSIZE]; 4507c478bd9Sstevel@tonic-gate } cgun; 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate #define acg cgun.cg 4537c478bd9Sstevel@tonic-gate /* 4547c478bd9Sstevel@tonic-gate * Size of screen in cols in which to fit output 4557c478bd9Sstevel@tonic-gate */ 4567c478bd9Sstevel@tonic-gate #define WIDTH 80 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate struct dinode zino[MAXBSIZE / sizeof (struct dinode)]; 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate /* 4617c478bd9Sstevel@tonic-gate * file descriptors used for rdfs(fsi) and wtfs(fso). 4627c478bd9Sstevel@tonic-gate * Initialized to an illegal file descriptor number. 4637c478bd9Sstevel@tonic-gate */ 4647c478bd9Sstevel@tonic-gate int fsi = -1; 4657c478bd9Sstevel@tonic-gate int fso = -1; 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate /* 4687c478bd9Sstevel@tonic-gate * The BIG parameter is machine dependent. It should be a longlong integer 4697c478bd9Sstevel@tonic-gate * constant that can be used by the number parser to check the validity 4707c478bd9Sstevel@tonic-gate * of numeric parameters. 4717c478bd9Sstevel@tonic-gate */ 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate #define BIG 0x7fffffffffffffffLL 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate /* Used to indicate to number() that a bogus value should cause us to exit */ 4767c478bd9Sstevel@tonic-gate #define NO_DEFAULT LONG_MIN 4777c478bd9Sstevel@tonic-gate 4786451fdbcSvsakar /* 4796451fdbcSvsakar * INVALIDSBLIMIT is the number of bad backup superblocks that will be 4806451fdbcSvsakar * tolerated before we decide to try arriving at a different set of them 4816451fdbcSvsakar * using a different logic. This is applicable for non-EFI disks only. 4826451fdbcSvsakar */ 4836451fdbcSvsakar #define INVALIDSBLIMIT 10 4846451fdbcSvsakar 4857c478bd9Sstevel@tonic-gate /* 4867c478bd9Sstevel@tonic-gate * The *_flag variables are used to indicate that the user specified 4877c478bd9Sstevel@tonic-gate * the values, rather than that we made them up ourselves. We can 4887c478bd9Sstevel@tonic-gate * complain about the user giving us bogus values. 4897c478bd9Sstevel@tonic-gate */ 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate /* semi-constants */ 4927c478bd9Sstevel@tonic-gate long sectorsize = DEV_BSIZE; /* bytes/sector from param.h */ 4937c478bd9Sstevel@tonic-gate long bbsize = BBSIZE; /* boot block size */ 4947c478bd9Sstevel@tonic-gate long sbsize = SBSIZE; /* superblock size */ 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate /* parameters */ 4977c478bd9Sstevel@tonic-gate diskaddr_t fssize_db; /* file system size in disk blocks */ 4987c478bd9Sstevel@tonic-gate diskaddr_t fssize_frag; /* file system size in frags */ 4997c478bd9Sstevel@tonic-gate long cpg; /* cylinders/cylinder group */ 5007c478bd9Sstevel@tonic-gate int cpg_flag = RC_DEFAULT; 5017c478bd9Sstevel@tonic-gate long rotdelay = -1; /* rotational delay between blocks */ 5027c478bd9Sstevel@tonic-gate int rotdelay_flag = RC_DEFAULT; 5037c478bd9Sstevel@tonic-gate long maxcontig; /* max contiguous blocks to allocate */ 5047c478bd9Sstevel@tonic-gate int maxcontig_flag = RC_DEFAULT; 5057c478bd9Sstevel@tonic-gate long nsect = DFLNSECT; /* sectors per track */ 5067c478bd9Sstevel@tonic-gate int nsect_flag = RC_DEFAULT; 5077c478bd9Sstevel@tonic-gate long ntrack = DFLNTRAK; /* tracks per cylinder group */ 5087c478bd9Sstevel@tonic-gate int ntrack_flag = RC_DEFAULT; 5097c478bd9Sstevel@tonic-gate long bsize = DESBLKSIZE; /* filesystem block size */ 5107c478bd9Sstevel@tonic-gate int bsize_flag = RC_DEFAULT; 5117c478bd9Sstevel@tonic-gate long fragsize = DESFRAGSIZE; /* filesystem fragment size */ 5127c478bd9Sstevel@tonic-gate int fragsize_flag = RC_DEFAULT; 5137c478bd9Sstevel@tonic-gate long minfree = MINFREE; /* fs_minfree */ 5147c478bd9Sstevel@tonic-gate int minfree_flag = RC_DEFAULT; 5157c478bd9Sstevel@tonic-gate long rps = DEFHZ; /* revolutions/second of drive */ 5167c478bd9Sstevel@tonic-gate int rps_flag = RC_DEFAULT; 5177c478bd9Sstevel@tonic-gate long nbpi = NBPI; /* number of bytes per inode */ 5187c478bd9Sstevel@tonic-gate int nbpi_flag = RC_DEFAULT; 5197c478bd9Sstevel@tonic-gate long nrpos = NRPOS; /* number of rotational positions */ 5207c478bd9Sstevel@tonic-gate int nrpos_flag = RC_DEFAULT; 5217c478bd9Sstevel@tonic-gate long apc = 0; /* alternate sectors per cylinder */ 5227c478bd9Sstevel@tonic-gate int apc_flag = RC_DEFAULT; 5237c478bd9Sstevel@tonic-gate char opt = 't'; /* optimization style, `t' or `s' */ 5247c478bd9Sstevel@tonic-gate char mtb = 'n'; /* multi-terabyte format, 'y' or 'n' */ 525d50c8f90Svsakar #define DEFAULT_SECT_TRAK_CPG (nsect_flag == RC_DEFAULT && \ 526d50c8f90Svsakar ntrack_flag == RC_DEFAULT && \ 527d50c8f90Svsakar cpg_flag == RC_DEFAULT) 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate long debug = 0; /* enable debugging output */ 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate int spc_flag = 0; /* alternate sectors specified or */ 5327c478bd9Sstevel@tonic-gate /* found */ 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate /* global state */ 5357c478bd9Sstevel@tonic-gate int Nflag; /* do not write to disk */ 5367c478bd9Sstevel@tonic-gate int mflag; /* return the command line used to create this FS */ 537355d6bb5Sswilcox int rflag; /* report the superblock in an easily-parsed form */ 538355d6bb5Sswilcox int Rflag; /* dump the superblock in binary */ 5397c478bd9Sstevel@tonic-gate char *fsys; 5407c478bd9Sstevel@tonic-gate time_t mkfstime; 5417c478bd9Sstevel@tonic-gate char *string; 5426451fdbcSvsakar int label_type; 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate /* 5457c478bd9Sstevel@tonic-gate * logging support 5467c478bd9Sstevel@tonic-gate */ 5477c478bd9Sstevel@tonic-gate int ismdd; /* true if device is a SVM device */ 5487c478bd9Sstevel@tonic-gate int islog; /* true if ufs or SVM logging is enabled */ 5497c478bd9Sstevel@tonic-gate int islogok; /* true if ufs/SVM log state is good */ 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate static int isufslog; /* true if ufs logging is enabled */ 5527c478bd9Sstevel@tonic-gate static int waslog; /* true when ufs logging disabled during grow */ 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate /* 5557c478bd9Sstevel@tonic-gate * growfs defines, globals, and forward references 5567c478bd9Sstevel@tonic-gate */ 5577c478bd9Sstevel@tonic-gate #define NOTENOUGHSPACE 33 5587c478bd9Sstevel@tonic-gate int grow; 559d50c8f90Svsakar #define GROW_WITH_DEFAULT_TRAK (grow && ntrack_flag == RC_DEFAULT) 560d50c8f90Svsakar 5617c478bd9Sstevel@tonic-gate static int Pflag; /* probe to which size the fs can be grown */ 5627c478bd9Sstevel@tonic-gate int ismounted; 5637c478bd9Sstevel@tonic-gate char *directory; 5647c478bd9Sstevel@tonic-gate diskaddr_t grow_fssize; 5657c478bd9Sstevel@tonic-gate long grow_fs_size; 5667c478bd9Sstevel@tonic-gate long grow_fs_ncg; 5677c478bd9Sstevel@tonic-gate diskaddr_t grow_fs_csaddr; 5687c478bd9Sstevel@tonic-gate long grow_fs_cssize; 5697c478bd9Sstevel@tonic-gate int grow_fs_clean; 5707c478bd9Sstevel@tonic-gate struct csum *grow_fscs; 5717c478bd9Sstevel@tonic-gate diskaddr_t grow_sifrag; 5727c478bd9Sstevel@tonic-gate int test; 5737c478bd9Sstevel@tonic-gate int testforce; 5747c478bd9Sstevel@tonic-gate diskaddr_t testfrags; 5757c478bd9Sstevel@tonic-gate int inlockexit; 5767c478bd9Sstevel@tonic-gate int isbad; 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate void lockexit(int); 5797c478bd9Sstevel@tonic-gate void randomgeneration(void); 5807c478bd9Sstevel@tonic-gate void checksummarysize(void); 5816451fdbcSvsakar int checksblock(struct fs, int); 5827c478bd9Sstevel@tonic-gate void growinit(char *); 5837c478bd9Sstevel@tonic-gate void checkdev(char *, char *); 5847c478bd9Sstevel@tonic-gate void checkmount(struct mnttab *, char *); 5857c478bd9Sstevel@tonic-gate struct dinode *gdinode(ino_t); 5867c478bd9Sstevel@tonic-gate int csfraginrange(daddr32_t); 5877c478bd9Sstevel@tonic-gate struct csfrag *findcsfrag(daddr32_t, struct csfrag **); 5887c478bd9Sstevel@tonic-gate void checkindirect(ino_t, daddr32_t *, daddr32_t, int); 5897c478bd9Sstevel@tonic-gate void addcsfrag(ino_t, daddr32_t, struct csfrag **); 5907c478bd9Sstevel@tonic-gate void delcsfrag(daddr32_t, struct csfrag **); 5917c478bd9Sstevel@tonic-gate void checkdirect(ino_t, daddr32_t *, daddr32_t *, int); 5927c478bd9Sstevel@tonic-gate void findcsfragino(void); 5937c478bd9Sstevel@tonic-gate void fixindirect(daddr32_t, int); 5947c478bd9Sstevel@tonic-gate void fixdirect(caddr_t, daddr32_t, daddr32_t *, int); 5957c478bd9Sstevel@tonic-gate void fixcsfragino(void); 5967c478bd9Sstevel@tonic-gate void extendsummaryinfo(void); 5977c478bd9Sstevel@tonic-gate int notenoughspace(void); 5987c478bd9Sstevel@tonic-gate void unalloccsfragino(void); 5997c478bd9Sstevel@tonic-gate void unalloccsfragfree(void); 6007c478bd9Sstevel@tonic-gate void findcsfragfree(void); 6017c478bd9Sstevel@tonic-gate void copycsfragino(void); 6027c478bd9Sstevel@tonic-gate void rdcg(long); 6037c478bd9Sstevel@tonic-gate void wtcg(void); 6047c478bd9Sstevel@tonic-gate void flcg(void); 6057c478bd9Sstevel@tonic-gate void allocfrags(long, daddr32_t *, long *); 6067c478bd9Sstevel@tonic-gate void alloccsfragino(void); 6077c478bd9Sstevel@tonic-gate void alloccsfragfree(void); 6087c478bd9Sstevel@tonic-gate void freefrags(daddr32_t, long, long); 6097c478bd9Sstevel@tonic-gate int findfreerange(long *, long *); 6107c478bd9Sstevel@tonic-gate void resetallocinfo(void); 6117c478bd9Sstevel@tonic-gate void extendcg(long); 6127c478bd9Sstevel@tonic-gate void ulockfs(void); 6137c478bd9Sstevel@tonic-gate void wlockfs(void); 6147c478bd9Sstevel@tonic-gate void clockfs(void); 6157c478bd9Sstevel@tonic-gate void wtsb(void); 6167c478bd9Sstevel@tonic-gate static int64_t checkfragallocated(daddr32_t); 6177c478bd9Sstevel@tonic-gate static struct csum *read_summaryinfo(struct fs *); 6187c478bd9Sstevel@tonic-gate static diskaddr_t probe_summaryinfo(); 6197c478bd9Sstevel@tonic-gate 620d1a180b0Smaheshvs int 6217c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 6227c478bd9Sstevel@tonic-gate { 6237c478bd9Sstevel@tonic-gate long i, mincpc, mincpg, ibpcl; 6247c478bd9Sstevel@tonic-gate long cylno, rpos, blk, j, warn = 0; 6257c478bd9Sstevel@tonic-gate long mincpgcnt, maxcpg; 6267c478bd9Sstevel@tonic-gate uint64_t used, bpcg, inospercg; 6277c478bd9Sstevel@tonic-gate long mapcramped, inodecramped; 6287c478bd9Sstevel@tonic-gate long postblsize, rotblsize, totalsbsize; 6297c478bd9Sstevel@tonic-gate FILE *mnttab; 6307c478bd9Sstevel@tonic-gate struct mnttab mntp; 6317c478bd9Sstevel@tonic-gate char *special; 6327c478bd9Sstevel@tonic-gate struct statvfs64 fs; 6336451fdbcSvsakar struct dk_geom dkg; 6347c478bd9Sstevel@tonic-gate struct dk_cinfo dkcinfo; 63565908c77Syu, larry liu - Sun Microsystems - Beijing China struct dk_minfo dkminfo; 6367c478bd9Sstevel@tonic-gate char pbuf[sizeof (uint64_t) * 3 + 1]; 6376451fdbcSvsakar char *tmpbuf; 6387c478bd9Sstevel@tonic-gate int width, plen; 6397c478bd9Sstevel@tonic-gate uint64_t num; 6407c478bd9Sstevel@tonic-gate int c, saverr; 6417c478bd9Sstevel@tonic-gate diskaddr_t max_fssize; 6427c478bd9Sstevel@tonic-gate long tmpmaxcontig = -1; 6437c478bd9Sstevel@tonic-gate struct sigaction sigact; 6447c478bd9Sstevel@tonic-gate uint64_t nbytes64; 6457c478bd9Sstevel@tonic-gate int remaining_cg; 6467c478bd9Sstevel@tonic-gate int do_dot = 0; 6478b7c2cdfSws int use_efi_dflts = 0, retry = 0, isremovable = 0, ishotpluggable = 0; 6486d24e334Svsakar int invalid_sb_cnt, ret, skip_this_sb, cg_too_small; 6496d24e334Svsakar int geom_nsect, geom_ntrack, geom_cpg; 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 6547c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 6557c478bd9Sstevel@tonic-gate #endif 6567c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "F:bmo:VPGM:T:t:")) != EOF) { 6597c478bd9Sstevel@tonic-gate switch (c) { 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate case 'F': 6627c478bd9Sstevel@tonic-gate string = optarg; 6637c478bd9Sstevel@tonic-gate if (strcmp(string, "ufs") != 0) 6647c478bd9Sstevel@tonic-gate usage(); 6657c478bd9Sstevel@tonic-gate break; 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate case 'm': /* return command line used to create this FS */ 6687c478bd9Sstevel@tonic-gate mflag++; 6697c478bd9Sstevel@tonic-gate break; 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate case 'o': 6727c478bd9Sstevel@tonic-gate /* 6737c478bd9Sstevel@tonic-gate * ufs specific options. 6747c478bd9Sstevel@tonic-gate */ 6757c478bd9Sstevel@tonic-gate string = optarg; 6767c478bd9Sstevel@tonic-gate while (*string != '\0') { 6777c478bd9Sstevel@tonic-gate if (match("nsect=")) { 6787c478bd9Sstevel@tonic-gate nsect = number(DFLNSECT, "nsect", 0); 6797c478bd9Sstevel@tonic-gate nsect_flag = RC_KEYWORD; 6807c478bd9Sstevel@tonic-gate } else if (match("ntrack=")) { 6817c478bd9Sstevel@tonic-gate ntrack = number(DFLNTRAK, "ntrack", 0); 6827c478bd9Sstevel@tonic-gate ntrack_flag = RC_KEYWORD; 6837c478bd9Sstevel@tonic-gate } else if (match("bsize=")) { 6847c478bd9Sstevel@tonic-gate bsize = number(DESBLKSIZE, "bsize", 0); 6857c478bd9Sstevel@tonic-gate bsize_flag = RC_KEYWORD; 6867c478bd9Sstevel@tonic-gate } else if (match("fragsize=")) { 6877c478bd9Sstevel@tonic-gate fragsize = number(DESFRAGSIZE, 6887c478bd9Sstevel@tonic-gate "fragsize", 0); 6897c478bd9Sstevel@tonic-gate fragsize_flag = RC_KEYWORD; 6907c478bd9Sstevel@tonic-gate } else if (match("cgsize=")) { 6917c478bd9Sstevel@tonic-gate cpg = number(DESCPG, "cgsize", 0); 6927c478bd9Sstevel@tonic-gate cpg_flag = RC_KEYWORD; 6937c478bd9Sstevel@tonic-gate } else if (match("free=")) { 6947c478bd9Sstevel@tonic-gate minfree = number(MINFREE, "free", 6957c478bd9Sstevel@tonic-gate ALLOW_PERCENT); 6967c478bd9Sstevel@tonic-gate minfree_flag = RC_KEYWORD; 6977c478bd9Sstevel@tonic-gate } else if (match("maxcontig=")) { 6987c478bd9Sstevel@tonic-gate tmpmaxcontig = 6997c478bd9Sstevel@tonic-gate number(-1, "maxcontig", 0); 7007c478bd9Sstevel@tonic-gate maxcontig_flag = RC_KEYWORD; 7017c478bd9Sstevel@tonic-gate } else if (match("nrpos=")) { 7027c478bd9Sstevel@tonic-gate nrpos = number(NRPOS, "nrpos", 0); 7037c478bd9Sstevel@tonic-gate nrpos_flag = RC_KEYWORD; 7047c478bd9Sstevel@tonic-gate } else if (match("rps=")) { 7057c478bd9Sstevel@tonic-gate rps = number(DEFHZ, "rps", 0); 7067c478bd9Sstevel@tonic-gate rps_flag = RC_KEYWORD; 7077c478bd9Sstevel@tonic-gate } else if (match("nbpi=")) { 7087c478bd9Sstevel@tonic-gate nbpi = number(NBPI, "nbpi", 0); 7097c478bd9Sstevel@tonic-gate nbpi_flag = RC_KEYWORD; 7107c478bd9Sstevel@tonic-gate } else if (match("opt=")) { 7117c478bd9Sstevel@tonic-gate opt = checkopt(string); 7127c478bd9Sstevel@tonic-gate } else if (match("mtb=")) { 7137c478bd9Sstevel@tonic-gate mtb = checkmtb(string); 7147c478bd9Sstevel@tonic-gate } else if (match("apc=")) { 7157c478bd9Sstevel@tonic-gate apc = number(0, "apc", 0); 7167c478bd9Sstevel@tonic-gate apc_flag = RC_KEYWORD; 7177c478bd9Sstevel@tonic-gate } else if (match("gap=")) { 7187c478bd9Sstevel@tonic-gate (void) number(0, "gap", ALLOW_MS1); 7197c478bd9Sstevel@tonic-gate rotdelay = ROTDELAY; 7207c478bd9Sstevel@tonic-gate rotdelay_flag = RC_DEFAULT; 7217c478bd9Sstevel@tonic-gate } else if (match("debug=")) { 7227c478bd9Sstevel@tonic-gate debug = number(0, "debug", 0); 7237c478bd9Sstevel@tonic-gate } else if (match("N")) { 7247c478bd9Sstevel@tonic-gate Nflag++; 725355d6bb5Sswilcox } else if (match("calcsb")) { 726355d6bb5Sswilcox rflag++; 727355d6bb5Sswilcox Nflag++; 728355d6bb5Sswilcox } else if (match("calcbinsb")) { 729355d6bb5Sswilcox rflag++; 730355d6bb5Sswilcox Rflag++; 731355d6bb5Sswilcox Nflag++; 7327c478bd9Sstevel@tonic-gate } else if (*string == '\0') { 7337c478bd9Sstevel@tonic-gate break; 7347c478bd9Sstevel@tonic-gate } else { 7357c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 736d50c8f90Svsakar "illegal option: %s\n"), string); 7377c478bd9Sstevel@tonic-gate usage(); 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate if (*string == ',') string++; 7417c478bd9Sstevel@tonic-gate if (*string == ' ') string++; 7427c478bd9Sstevel@tonic-gate } 7437c478bd9Sstevel@tonic-gate break; 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate case 'V': 7467c478bd9Sstevel@tonic-gate { 7477c478bd9Sstevel@tonic-gate char *opt_text; 7487c478bd9Sstevel@tonic-gate int opt_count; 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate (void) fprintf(stdout, gettext("mkfs -F ufs ")); 7517c478bd9Sstevel@tonic-gate for (opt_count = 1; opt_count < argc; 752d50c8f90Svsakar opt_count++) { 7537c478bd9Sstevel@tonic-gate opt_text = argv[opt_count]; 7547c478bd9Sstevel@tonic-gate if (opt_text) 755d50c8f90Svsakar (void) fprintf(stdout, " %s ", 756d50c8f90Svsakar opt_text); 7577c478bd9Sstevel@tonic-gate } 7587c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "\n"); 7597c478bd9Sstevel@tonic-gate } 7607c478bd9Sstevel@tonic-gate break; 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate case 'b': /* do nothing for this */ 7637c478bd9Sstevel@tonic-gate break; 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate case 'M': /* grow the mounted file system */ 7667c478bd9Sstevel@tonic-gate directory = optarg; 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 7697c478bd9Sstevel@tonic-gate case 'G': /* grow the file system */ 7707c478bd9Sstevel@tonic-gate grow = 1; 7717c478bd9Sstevel@tonic-gate break; 7727c478bd9Sstevel@tonic-gate case 'P': /* probe the file system growing size */ 7737c478bd9Sstevel@tonic-gate Pflag = 1; 7747c478bd9Sstevel@tonic-gate grow = 1; /* probe mode implies fs growing */ 7757c478bd9Sstevel@tonic-gate break; 7767c478bd9Sstevel@tonic-gate case 'T': /* For testing */ 7777c478bd9Sstevel@tonic-gate testforce = 1; 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 7807c478bd9Sstevel@tonic-gate case 't': 7817c478bd9Sstevel@tonic-gate test = 1; 7827c478bd9Sstevel@tonic-gate string = optarg; 7837c478bd9Sstevel@tonic-gate testfrags = number(NO_DEFAULT, "testfrags", 0); 7847c478bd9Sstevel@tonic-gate break; 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate case '?': 7877c478bd9Sstevel@tonic-gate usage(); 7887c478bd9Sstevel@tonic-gate break; 7897c478bd9Sstevel@tonic-gate } 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate #ifdef MKFS_DEBUG 7927c478bd9Sstevel@tonic-gate /* 7937c478bd9Sstevel@tonic-gate * Turning on MKFS_DEBUG causes mkfs to produce a filesystem 7947c478bd9Sstevel@tonic-gate * that can be reproduced by setting the time to 0 and seeding 7957c478bd9Sstevel@tonic-gate * the random number generator to a constant. 7967c478bd9Sstevel@tonic-gate */ 7977c478bd9Sstevel@tonic-gate mkfstime = 0; /* reproducible results */ 7987c478bd9Sstevel@tonic-gate #else 7997c478bd9Sstevel@tonic-gate (void) time(&mkfstime); 8007c478bd9Sstevel@tonic-gate #endif 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate if (optind >= (argc - 1)) { 8037c478bd9Sstevel@tonic-gate if (optind > (argc - 1)) { 8047c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 8057c478bd9Sstevel@tonic-gate gettext("special not specified\n")); 8067c478bd9Sstevel@tonic-gate usage(); 8077c478bd9Sstevel@tonic-gate } else if (mflag == 0) { 8087c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 8097c478bd9Sstevel@tonic-gate gettext("size not specified\n")); 8107c478bd9Sstevel@tonic-gate usage(); 8117c478bd9Sstevel@tonic-gate } 8127c478bd9Sstevel@tonic-gate } 8137c478bd9Sstevel@tonic-gate argc -= optind; 8147c478bd9Sstevel@tonic-gate argv = &argv[optind]; 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate fsys = argv[0]; 8177c478bd9Sstevel@tonic-gate fsi = open64(fsys, O_RDONLY); 8187c478bd9Sstevel@tonic-gate if (fsi < 0) { 8197c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: cannot open\n"), fsys); 8207c478bd9Sstevel@tonic-gate lockexit(32); 8217c478bd9Sstevel@tonic-gate } 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate if (mflag) { 8247c478bd9Sstevel@tonic-gate dump_fscmd(fsys, fsi); 8257c478bd9Sstevel@tonic-gate lockexit(0); 8267c478bd9Sstevel@tonic-gate } 8277c478bd9Sstevel@tonic-gate 8287c478bd9Sstevel@tonic-gate /* 8297c478bd9Sstevel@tonic-gate * The task of setting all of the configuration parameters for a 8307c478bd9Sstevel@tonic-gate * UFS file system is basically a matter of solving n equations 8317c478bd9Sstevel@tonic-gate * in m variables. Typically, m is greater than n, so there is 8327c478bd9Sstevel@tonic-gate * usually more than one valid solution. Since this is usually 8337c478bd9Sstevel@tonic-gate * an under-constrained problem, it's not always obvious what the 8347c478bd9Sstevel@tonic-gate * "best" configuration is. 8357c478bd9Sstevel@tonic-gate * 8367c478bd9Sstevel@tonic-gate * In general, the approach is to 8377c478bd9Sstevel@tonic-gate * 1. Determine the values for the file system parameters 8387c478bd9Sstevel@tonic-gate * that are externally contrained and therefore not adjustable 8397c478bd9Sstevel@tonic-gate * by mkfs (such as the device's size and maxtransfer size). 8407c478bd9Sstevel@tonic-gate * 2. Acquire the user's requested setting for all configuration 8417c478bd9Sstevel@tonic-gate * values that can be set on the command line. 8427c478bd9Sstevel@tonic-gate * 3. Determine the final value of all configuration values, by 8437c478bd9Sstevel@tonic-gate * the following approach: 8447c478bd9Sstevel@tonic-gate * - set the file system block size (fs_bsize). Although 8457c478bd9Sstevel@tonic-gate * this could be regarded as an adjustable parameter, in 8467c478bd9Sstevel@tonic-gate * fact, it's pretty much a constant. At this time, it's 8477c478bd9Sstevel@tonic-gate * generally set to 8k (with older hardware, it can 8487c478bd9Sstevel@tonic-gate * sometimes make sense to set it to 4k, but those 8497c478bd9Sstevel@tonic-gate * situations are pretty rare now). 8507c478bd9Sstevel@tonic-gate * - re-adjust the maximum file system size based on the 8517c478bd9Sstevel@tonic-gate * value of the file system block size. Since the 8527c478bd9Sstevel@tonic-gate * frag size can't be any larger than a file system 8537c478bd9Sstevel@tonic-gate * block, and the number of frags in the file system 8547c478bd9Sstevel@tonic-gate * has to fit into 31 bits, the file system block size 8557c478bd9Sstevel@tonic-gate * affects the maximum file system size. 8567c478bd9Sstevel@tonic-gate * - now that the real maximum file system is known, set the 8577c478bd9Sstevel@tonic-gate * actual size of the file system to be created to 8587c478bd9Sstevel@tonic-gate * MIN(requested size, maximum file system size). 8597c478bd9Sstevel@tonic-gate * - now validate, and if necessary, adjust the following 8607c478bd9Sstevel@tonic-gate * values: 8617c478bd9Sstevel@tonic-gate * rotdelay 8627c478bd9Sstevel@tonic-gate * nsect 8637c478bd9Sstevel@tonic-gate * maxcontig 8647c478bd9Sstevel@tonic-gate * apc 8657c478bd9Sstevel@tonic-gate * frag_size 8667c478bd9Sstevel@tonic-gate * rps 8677c478bd9Sstevel@tonic-gate * minfree 8687c478bd9Sstevel@tonic-gate * nrpos 8697c478bd9Sstevel@tonic-gate * nrack 8707c478bd9Sstevel@tonic-gate * nbpi 8717c478bd9Sstevel@tonic-gate * - calculate maxcpg (the maximum value of the cylinders-per- 8727c478bd9Sstevel@tonic-gate * cylinder-group configuration parameters). There are two 8737c478bd9Sstevel@tonic-gate * algorithms for calculating maxcpg: an old one, which is 8747c478bd9Sstevel@tonic-gate * used for file systems of less than 1 terabyte, and a 8757c478bd9Sstevel@tonic-gate * new one, implemented in the function compute_maxcpg(), 8767c478bd9Sstevel@tonic-gate * which is used for file systems of greater than 1 TB. 8777c478bd9Sstevel@tonic-gate * The difference between them is that compute_maxcpg() 8787c478bd9Sstevel@tonic-gate * really tries to maximize the cpg value. The old 8797c478bd9Sstevel@tonic-gate * algorithm fails to take advantage of smaller frags and 8807c478bd9Sstevel@tonic-gate * lower inode density when determining the maximum cpg, 8817c478bd9Sstevel@tonic-gate * and thus comes up with much lower numbers in some 8827c478bd9Sstevel@tonic-gate * configurations. At some point, we might use the 8837c478bd9Sstevel@tonic-gate * new algorithm for determining maxcpg for all file 8847c478bd9Sstevel@tonic-gate * systems, but at this time, the changes implemented for 8857c478bd9Sstevel@tonic-gate * multi-terabyte UFS are NOT being automatically applied 8867c478bd9Sstevel@tonic-gate * to UFS file systems of less than a terabyte (in the 8877c478bd9Sstevel@tonic-gate * interest of not changing existing UFS policy too much 8887c478bd9Sstevel@tonic-gate * until the ramifications of the changes are well-understood 8897c478bd9Sstevel@tonic-gate * and have been evaluated for their effects on performance.) 8907c478bd9Sstevel@tonic-gate * - check the current values of the configuration parameters 8917c478bd9Sstevel@tonic-gate * against the various constraints imposed by UFS. These 8927c478bd9Sstevel@tonic-gate * include: 8937c478bd9Sstevel@tonic-gate * * There must be at least one inode in each 8947c478bd9Sstevel@tonic-gate * cylinder group. 8957c478bd9Sstevel@tonic-gate * * The cylinder group overhead block, which 8967c478bd9Sstevel@tonic-gate * contains the inode and frag bigmaps, must fit 8977c478bd9Sstevel@tonic-gate * within one file system block. 8987c478bd9Sstevel@tonic-gate * * The space required for inode maps should 8997c478bd9Sstevel@tonic-gate * occupy no more than a third of the cylinder 9007c478bd9Sstevel@tonic-gate * group overhead block. 9017c478bd9Sstevel@tonic-gate * * The rotational position tables have to fit 9027c478bd9Sstevel@tonic-gate * within the available space in the super block. 9037c478bd9Sstevel@tonic-gate * Adjust the configuration values that can be adjusted 9047c478bd9Sstevel@tonic-gate * so that these constraints are satisfied. The 9057c478bd9Sstevel@tonic-gate * configuration values that are adjustable are: 9067c478bd9Sstevel@tonic-gate * * frag size 9077c478bd9Sstevel@tonic-gate * * cylinders per group 9087c478bd9Sstevel@tonic-gate * * inode density (can be increased) 9097c478bd9Sstevel@tonic-gate * * number of rotational positions (the rotational 9107c478bd9Sstevel@tonic-gate * position tables are eliminated altogether if 9117c478bd9Sstevel@tonic-gate * there isn't enough room for them.) 9127c478bd9Sstevel@tonic-gate * 4. Set the values for all the dependent configuration 9137c478bd9Sstevel@tonic-gate * values (those that aren't settable on the command 9147c478bd9Sstevel@tonic-gate * line and which are completely dependent on the 9157c478bd9Sstevel@tonic-gate * adjustable parameters). This include cpc (cycles 9167c478bd9Sstevel@tonic-gate * per cylinder, spc (sectors-per-cylinder), and many others. 9177c478bd9Sstevel@tonic-gate */ 9187c478bd9Sstevel@tonic-gate 919d50c8f90Svsakar /* 920d50c8f90Svsakar * Figure out the partition size and initialize the label_type. 921d50c8f90Svsakar */ 9227c478bd9Sstevel@tonic-gate max_fssize = get_max_size(fsi); 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate /* 9257c478bd9Sstevel@tonic-gate * Get and check positional arguments, if any. 9267c478bd9Sstevel@tonic-gate */ 9277c478bd9Sstevel@tonic-gate switch (argc - 1) { 9287c478bd9Sstevel@tonic-gate default: 9297c478bd9Sstevel@tonic-gate usage(); 9307c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 9317c478bd9Sstevel@tonic-gate case 15: 9327c478bd9Sstevel@tonic-gate mtb = checkmtb(argv[15]); 9337c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 9347c478bd9Sstevel@tonic-gate case 14: 9357c478bd9Sstevel@tonic-gate string = argv[14]; 9367c478bd9Sstevel@tonic-gate tmpmaxcontig = number(-1, "maxcontig", 0); 9377c478bd9Sstevel@tonic-gate maxcontig_flag = RC_POSITIONAL; 9387c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 9397c478bd9Sstevel@tonic-gate case 13: 9407c478bd9Sstevel@tonic-gate string = argv[13]; 9417c478bd9Sstevel@tonic-gate nrpos = number(NRPOS, "nrpos", 0); 9427c478bd9Sstevel@tonic-gate nrpos_flag = RC_POSITIONAL; 9437c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 9447c478bd9Sstevel@tonic-gate case 12: 9457c478bd9Sstevel@tonic-gate string = argv[12]; 9467c478bd9Sstevel@tonic-gate rotdelay = ROTDELAY; 9477c478bd9Sstevel@tonic-gate rotdelay_flag = RC_DEFAULT; 9487c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 9497c478bd9Sstevel@tonic-gate case 11: 9507c478bd9Sstevel@tonic-gate string = argv[11]; 9517c478bd9Sstevel@tonic-gate apc = number(0, "apc", 0); 9527c478bd9Sstevel@tonic-gate apc_flag = RC_POSITIONAL; 9537c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 9547c478bd9Sstevel@tonic-gate case 10: 9557c478bd9Sstevel@tonic-gate opt = checkopt(argv[10]); 9567c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 9577c478bd9Sstevel@tonic-gate case 9: 9587c478bd9Sstevel@tonic-gate string = argv[9]; 9597c478bd9Sstevel@tonic-gate nbpi = number(NBPI, "nbpi", 0); 9607c478bd9Sstevel@tonic-gate nbpi_flag = RC_POSITIONAL; 9617c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 9627c478bd9Sstevel@tonic-gate case 8: 9637c478bd9Sstevel@tonic-gate string = argv[8]; 9647c478bd9Sstevel@tonic-gate rps = number(DEFHZ, "rps", 0); 9657c478bd9Sstevel@tonic-gate rps_flag = RC_POSITIONAL; 9667c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 9677c478bd9Sstevel@tonic-gate case 7: 9687c478bd9Sstevel@tonic-gate string = argv[7]; 9697c478bd9Sstevel@tonic-gate minfree = number(MINFREE, "free", ALLOW_PERCENT); 9707c478bd9Sstevel@tonic-gate minfree_flag = RC_POSITIONAL; 9717c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 9727c478bd9Sstevel@tonic-gate case 6: 9737c478bd9Sstevel@tonic-gate string = argv[6]; 9747c478bd9Sstevel@tonic-gate cpg = number(DESCPG, "cgsize", 0); 9757c478bd9Sstevel@tonic-gate cpg_flag = RC_POSITIONAL; 9767c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 9777c478bd9Sstevel@tonic-gate case 5: 9787c478bd9Sstevel@tonic-gate string = argv[5]; 9797c478bd9Sstevel@tonic-gate fragsize = number(DESFRAGSIZE, "fragsize", 0); 9807c478bd9Sstevel@tonic-gate fragsize_flag = RC_POSITIONAL; 9817c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 9827c478bd9Sstevel@tonic-gate case 4: 9837c478bd9Sstevel@tonic-gate string = argv[4]; 9847c478bd9Sstevel@tonic-gate bsize = number(DESBLKSIZE, "bsize", 0); 9857c478bd9Sstevel@tonic-gate bsize_flag = RC_POSITIONAL; 9867c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 9877c478bd9Sstevel@tonic-gate case 3: 9887c478bd9Sstevel@tonic-gate string = argv[3]; 9897c478bd9Sstevel@tonic-gate ntrack = number(DFLNTRAK, "ntrack", 0); 9907c478bd9Sstevel@tonic-gate ntrack_flag = RC_POSITIONAL; 9917c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 9927c478bd9Sstevel@tonic-gate case 2: 9937c478bd9Sstevel@tonic-gate string = argv[2]; 9947c478bd9Sstevel@tonic-gate nsect = number(DFLNSECT, "nsect", 0); 9957c478bd9Sstevel@tonic-gate nsect_flag = RC_POSITIONAL; 9967c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 9977c478bd9Sstevel@tonic-gate case 1: 9987c478bd9Sstevel@tonic-gate string = argv[1]; 9997c478bd9Sstevel@tonic-gate fssize_db = number(max_fssize, "size", 0); 10007c478bd9Sstevel@tonic-gate } 10017c478bd9Sstevel@tonic-gate 1002d50c8f90Svsakar /* 1003d50c8f90Svsakar * Initialize the parameters in the same way as newfs so that 1004d50c8f90Svsakar * newfs and mkfs would result in the same file system layout 1005d50c8f90Svsakar * for EFI labelled disks. Do this only in the absence of user 1006d50c8f90Svsakar * specified values for these parameters. 1007d50c8f90Svsakar */ 1008d50c8f90Svsakar if (label_type == LABEL_TYPE_EFI) { 1009d50c8f90Svsakar if (apc_flag == RC_DEFAULT) apc = 0; 1010d50c8f90Svsakar if (nrpos_flag == RC_DEFAULT) nrpos = 1; 1011d50c8f90Svsakar if (ntrack_flag == RC_DEFAULT) ntrack = DEF_TRACKS_EFI; 1012d50c8f90Svsakar if (rps_flag == RC_DEFAULT) rps = DEFHZ; 1013d50c8f90Svsakar if (nsect_flag == RC_DEFAULT) nsect = DEF_SECTORS_EFI; 1014d50c8f90Svsakar } 10157c478bd9Sstevel@tonic-gate 10167c478bd9Sstevel@tonic-gate if ((maxcontig_flag == RC_DEFAULT) || (tmpmaxcontig == -1) || 1017d50c8f90Svsakar (maxcontig == -1)) { 10187c478bd9Sstevel@tonic-gate long maxtrax = get_max_track_size(fsi); 10197c478bd9Sstevel@tonic-gate maxcontig = maxtrax / bsize; 10207c478bd9Sstevel@tonic-gate 10217c478bd9Sstevel@tonic-gate } else { 10227c478bd9Sstevel@tonic-gate maxcontig = tmpmaxcontig; 10237c478bd9Sstevel@tonic-gate } 10246451fdbcSvsakar dprintf(("DeBuG maxcontig : %ld\n", maxcontig)); 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate if (rotdelay == -1) { /* default by newfs and mkfs */ 10277c478bd9Sstevel@tonic-gate rotdelay = ROTDELAY; 10287c478bd9Sstevel@tonic-gate } 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate if (cpg_flag == RC_DEFAULT) { /* If not explicity set, use default */ 10317c478bd9Sstevel@tonic-gate cpg = DESCPG; 10327c478bd9Sstevel@tonic-gate } 10336451fdbcSvsakar dprintf(("DeBuG cpg : %ld\n", cpg)); 10347c478bd9Sstevel@tonic-gate 10357c478bd9Sstevel@tonic-gate /* 10367c478bd9Sstevel@tonic-gate * Now that we have the semi-sane args, either positional, via -o, 10377c478bd9Sstevel@tonic-gate * or by defaulting, handle inter-dependencies and range checks. 10387c478bd9Sstevel@tonic-gate */ 10397c478bd9Sstevel@tonic-gate 10407c478bd9Sstevel@tonic-gate /* 10417c478bd9Sstevel@tonic-gate * Settle the file system block size first, since it's a fixed 10427c478bd9Sstevel@tonic-gate * parameter once set and so many other parameters, including 10437c478bd9Sstevel@tonic-gate * max_fssize, depend on it. 10447c478bd9Sstevel@tonic-gate */ 10457c478bd9Sstevel@tonic-gate range_check(&bsize, "bsize", MINBSIZE, MAXBSIZE, DESBLKSIZE, 10467c478bd9Sstevel@tonic-gate bsize_flag); 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate if (!POWEROF2(bsize)) { 10497c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 10507c478bd9Sstevel@tonic-gate gettext("block size must be a power of 2, not %ld\n"), 10517c478bd9Sstevel@tonic-gate bsize); 10527c478bd9Sstevel@tonic-gate bsize = DESBLKSIZE; 10537c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 10547c478bd9Sstevel@tonic-gate gettext("mkfs: bsize reset to default %ld\n"), 10557c478bd9Sstevel@tonic-gate bsize); 10567c478bd9Sstevel@tonic-gate } 10577c478bd9Sstevel@tonic-gate 10587c478bd9Sstevel@tonic-gate if (fssize_db > max_fssize && validate_size(fsi, fssize_db)) { 10597c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 10607c478bd9Sstevel@tonic-gate "Warning: the requested size of this file system\n" 10617c478bd9Sstevel@tonic-gate "(%lld sectors) is greater than the size of the\n" 10627c478bd9Sstevel@tonic-gate "device reported by the driver (%lld sectors).\n" 10637c478bd9Sstevel@tonic-gate "However, a read of the device at the requested size\n" 10647c478bd9Sstevel@tonic-gate "does succeed, so the requested size will be used.\n"), 10657c478bd9Sstevel@tonic-gate fssize_db, max_fssize); 10667c478bd9Sstevel@tonic-gate max_fssize = fssize_db; 10677c478bd9Sstevel@tonic-gate } 10687c478bd9Sstevel@tonic-gate /* 10697c478bd9Sstevel@tonic-gate * Since the maximum allocatable unit (the frag) must be less than 10707c478bd9Sstevel@tonic-gate * or equal to bsize, and the number of frags must be less than or 10717c478bd9Sstevel@tonic-gate * equal to INT_MAX, the total size of the file system (in 10727c478bd9Sstevel@tonic-gate * bytes) must be less than or equal to bsize * INT_MAX. 10737c478bd9Sstevel@tonic-gate */ 10747c478bd9Sstevel@tonic-gate 10757c478bd9Sstevel@tonic-gate if (max_fssize > ((diskaddr_t)bsize/DEV_BSIZE) * INT_MAX) 10767c478bd9Sstevel@tonic-gate max_fssize = ((diskaddr_t)bsize/DEV_BSIZE) * INT_MAX; 1077d50c8f90Svsakar 10787c478bd9Sstevel@tonic-gate range_check_64(&fssize_db, "size", 1024LL, max_fssize, max_fssize, 1); 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate if (fssize_db >= SECTORS_PER_TERABYTE) { 10817c478bd9Sstevel@tonic-gate mtb = 'y'; 10827c478bd9Sstevel@tonic-gate if (!in_64bit_mode()) { 10837c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 10847c478bd9Sstevel@tonic-gate "mkfs: Warning: Creating a file system greater than 1 terabyte on a\n" 10857c478bd9Sstevel@tonic-gate " system running a 32-bit kernel. This file system will not be\n" 10867c478bd9Sstevel@tonic-gate " accessible until the system is rebooted with a 64-bit kernel.\n")); 10877c478bd9Sstevel@tonic-gate } 10887c478bd9Sstevel@tonic-gate } 1089d50c8f90Svsakar dprintf(("DeBuG mtb : %c\n", mtb)); 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate /* 10926451fdbcSvsakar * With newer and much larger disks, the newfs(1M) and mkfs_ufs(1M) 10936451fdbcSvsakar * commands had problems in correctly handling the "native" geometries 10946451fdbcSvsakar * for various storage devices. 10956451fdbcSvsakar * 10966451fdbcSvsakar * To handle the new age disks, mkfs_ufs(1M) will use the EFI style 10976451fdbcSvsakar * for non-EFI disks that are larger than the CHS addressing limit 10986451fdbcSvsakar * ( > 8GB approx ) and ignore the disk geometry information for 10996451fdbcSvsakar * these drives. This is what is currently done for multi-terrabyte 11006451fdbcSvsakar * filesystems on EFI disks. 11016451fdbcSvsakar * 11026451fdbcSvsakar * However if the user asked for a specific layout by supplying values 11036d24e334Svsakar * for even one of the three parameters (nsect, ntrack, cpg), honour 11046d24e334Svsakar * the user supplied parameters. 11056d24e334Svsakar * 11066d24e334Svsakar * Choosing EFI style or native geometry style can make a lot of 11076d24e334Svsakar * difference, because the size of a cylinder group is dependent on 11086d24e334Svsakar * this choice. This in turn means that the position of alternate 11096d24e334Svsakar * superblocks varies depending on the style chosen. It is not 11106d24e334Svsakar * necessary that all disks of size > CHSLIMIT have EFI style layout. 11116d24e334Svsakar * There can be disks which are > CHSLIMIT size, but have native 11126d24e334Svsakar * geometry style layout, thereby warranting the need for alternate 11136d24e334Svsakar * logic in superblock detection. 11147c478bd9Sstevel@tonic-gate */ 1115d50c8f90Svsakar if (mtb != 'y' && (ntrack == -1 || GROW_WITH_DEFAULT_TRAK || 1116d50c8f90Svsakar DEFAULT_SECT_TRAK_CPG)) { 11176451fdbcSvsakar /* 11186d24e334Svsakar * "-1" indicates that we were called from newfs and ntracks 11196d24e334Svsakar * was not specified in newfs command line. Calculate nsect 11206451fdbcSvsakar * and ntrack in the same manner as newfs. 11216451fdbcSvsakar * 11226451fdbcSvsakar * This is required because, the defaults for nsect and ntrack 11236451fdbcSvsakar * is hardcoded in mkfs, whereas to generate the alternate 11246451fdbcSvsakar * superblock locations for the -N option, there is a need for 11256451fdbcSvsakar * the geometry based values that newfs would have arrived at. 11266451fdbcSvsakar * Newfs would have arrived at these values as below. 11276451fdbcSvsakar */ 1128d50c8f90Svsakar if (label_type == LABEL_TYPE_EFI || 1129d50c8f90Svsakar label_type == LABEL_TYPE_OTHER) { 1130d50c8f90Svsakar use_efi_dflts = 1; 1131d50c8f90Svsakar retry = 1; 1132d50c8f90Svsakar } else if (ioctl(fsi, DKIOCGGEOM, &dkg)) { 1133d50c8f90Svsakar dprintf(("%s: Unable to read Disk geometry", fsys)); 1134d50c8f90Svsakar perror(gettext("Unable to read Disk geometry")); 1135d50c8f90Svsakar lockexit(32); 11366451fdbcSvsakar } else { 1137d50c8f90Svsakar nsect = dkg.dkg_nsect; 1138d50c8f90Svsakar ntrack = dkg.dkg_nhead; 11396451fdbcSvsakar #ifdef i386 /* Bug 1170182 */ 1140d50c8f90Svsakar if (ntrack > 32 && (ntrack % 16) != 0) { 1141d50c8f90Svsakar ntrack -= (ntrack % 16); 1142d50c8f90Svsakar } 11436451fdbcSvsakar #endif 1144d50c8f90Svsakar if (ioctl(fsi, DKIOCREMOVABLE, &isremovable)) { 11454d594c33Svsakar dprintf(("DeBuG Unable to determine if %s is" 11464d594c33Svsakar " Removable Media. Proceeding with system" 11474d594c33Svsakar " determined parameters.\n", fsys)); 1148d50c8f90Svsakar isremovable = 0; 1149d50c8f90Svsakar } 11508b7c2cdfSws if (ioctl(fsi, DKIOCHOTPLUGGABLE, &ishotpluggable)) { 11518b7c2cdfSws dprintf(("DeBuG Unable to determine if %s is" 11528b7c2cdfSws " Hotpluggable Media. Proceeding with " 11538b7c2cdfSws "system determined parameters.\n", fsys)); 11548b7c2cdfSws ishotpluggable = 0; 11558b7c2cdfSws } 1156342440ecSPrasad Singamsetty if ((((diskaddr_t)dkg.dkg_ncyl * dkg.dkg_nhead * 1157342440ecSPrasad Singamsetty dkg.dkg_nsect) > CHSLIMIT) || isremovable || 1158342440ecSPrasad Singamsetty ishotpluggable) { 1159d50c8f90Svsakar use_efi_dflts = 1; 1160d50c8f90Svsakar retry = 1; 1161d50c8f90Svsakar } 11626451fdbcSvsakar } 11636451fdbcSvsakar } 1164342440ecSPrasad Singamsetty dprintf(("DeBuG CHSLIMIT = %d geom = %llu\n", CHSLIMIT, 1165342440ecSPrasad Singamsetty (diskaddr_t)dkg.dkg_ncyl * dkg.dkg_nhead * dkg.dkg_nsect)); 11668b7c2cdfSws dprintf(("DeBuG label_type = %d isremovable = %d ishotpluggable = %d " 11678b7c2cdfSws "use_efi_dflts = %d\n", label_type, isremovable, ishotpluggable, 11688b7c2cdfSws use_efi_dflts)); 11696451fdbcSvsakar 11706451fdbcSvsakar /* 11716451fdbcSvsakar * For the newfs -N case, even if the disksize is > CHSLIMIT, do not 11726451fdbcSvsakar * blindly follow EFI style. If the fs_version indicates a geometry 11736451fdbcSvsakar * based layout, try that one first. If it fails we can always try the 11746451fdbcSvsakar * other logic. 11756451fdbcSvsakar * 11766451fdbcSvsakar * If we were called from growfs, we will have a problem if we mix 11776451fdbcSvsakar * and match the filesystem creation and growth styles. For example, 11786d24e334Svsakar * if we create using EFI style, we have to also grow using EFI 11796451fdbcSvsakar * style. So follow the style indicated by the fs_version. 11806451fdbcSvsakar * 11816451fdbcSvsakar * Read and verify the primary superblock. If it looks sane, use the 11826451fdbcSvsakar * fs_version from the superblock. If the primary superblock does 11836451fdbcSvsakar * not look good, read and verify the first alternate superblock at 11846451fdbcSvsakar * ALTSB. Use the fs_version to decide whether to use the 11856451fdbcSvsakar * EFI style logic or the old geometry based logic to calculate 11866451fdbcSvsakar * the alternate superblock locations. 11876451fdbcSvsakar */ 11886451fdbcSvsakar if ((Nflag && use_efi_dflts) || (grow)) { 11896451fdbcSvsakar if (grow && ntrack_flag != RC_DEFAULT) 11906d24e334Svsakar goto start_fs_creation; 11916451fdbcSvsakar rdfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize, 1192d50c8f90Svsakar (char *)&altsblock); 11936451fdbcSvsakar ret = checksblock(altsblock, 1); 11946451fdbcSvsakar 11956451fdbcSvsakar if (!ret) { 11966451fdbcSvsakar if (altsblock.fs_magic == MTB_UFS_MAGIC) { 11976451fdbcSvsakar mtb = 'y'; 11986d24e334Svsakar goto start_fs_creation; 11996451fdbcSvsakar } 12006451fdbcSvsakar use_efi_dflts = (altsblock.fs_version == 1201d50c8f90Svsakar UFS_EFISTYLE4NONEFI_VERSION_2) ? 1 : 0; 12026451fdbcSvsakar } else { 12036451fdbcSvsakar /* 12046451fdbcSvsakar * The primary superblock didn't help in determining 12056451fdbcSvsakar * the fs_version. Try the first alternate superblock. 12066451fdbcSvsakar */ 12076451fdbcSvsakar dprintf(("DeBuG checksblock() failed - error : %d" 1208d50c8f90Svsakar " for sb : %d\n", ret, SBOFF/sectorsize)); 12096451fdbcSvsakar rdfs((diskaddr_t)ALTSB, (int)sbsize, 1210d50c8f90Svsakar (char *)&altsblock); 12116451fdbcSvsakar ret = checksblock(altsblock, 1); 12126451fdbcSvsakar 12136451fdbcSvsakar if (!ret) { 1214d50c8f90Svsakar if (altsblock.fs_magic == MTB_UFS_MAGIC) { 1215d50c8f90Svsakar mtb = 'y'; 1216d50c8f90Svsakar goto start_fs_creation; 1217d50c8f90Svsakar } 1218d50c8f90Svsakar use_efi_dflts = (altsblock.fs_version == 1219d50c8f90Svsakar UFS_EFISTYLE4NONEFI_VERSION_2) ? 1 : 0; 12206d24e334Svsakar } 12216d24e334Svsakar dprintf(("DeBuG checksblock() returned : %d" 1222d50c8f90Svsakar " for sb : %d\n", ret, ALTSB)); 12236451fdbcSvsakar } 12246451fdbcSvsakar } 12256451fdbcSvsakar 12266d24e334Svsakar geom_nsect = nsect; 12276d24e334Svsakar geom_ntrack = ntrack; 12286d24e334Svsakar geom_cpg = cpg; 12296d24e334Svsakar dprintf(("DeBuG geom_nsect=%d, geom_ntrack=%d, geom_cpg=%d\n", 1230d50c8f90Svsakar geom_nsect, geom_ntrack, geom_cpg)); 12316d24e334Svsakar 12326d24e334Svsakar start_fs_creation: 12336451fdbcSvsakar retry_alternate_logic: 12346451fdbcSvsakar invalid_sb_cnt = 0; 12356d24e334Svsakar cg_too_small = 0; 12366451fdbcSvsakar if (use_efi_dflts) { 12376451fdbcSvsakar nsect = DEF_SECTORS_EFI; 12386451fdbcSvsakar ntrack = DEF_TRACKS_EFI; 12396451fdbcSvsakar cpg = DESCPG; 12406451fdbcSvsakar dprintf(("\nDeBuG Using EFI defaults\n")); 12416451fdbcSvsakar } else { 12426d24e334Svsakar nsect = geom_nsect; 12436d24e334Svsakar ntrack = geom_ntrack; 12446d24e334Svsakar cpg = geom_cpg; 12456d24e334Svsakar dprintf(("\nDeBuG Using Geometry\n")); 12466451fdbcSvsakar /* 12476451fdbcSvsakar * 32K based on max block size of 64K, and rotational layout 12486451fdbcSvsakar * test of nsect <= (256 * sectors/block). Current block size 12496451fdbcSvsakar * limit is not 64K, but it's growing soon. 12506451fdbcSvsakar */ 12516451fdbcSvsakar range_check(&nsect, "nsect", 1, 32768, DFLNSECT, nsect_flag); 12526451fdbcSvsakar /* 12536451fdbcSvsakar * ntrack is the number of tracks per cylinder. 12546451fdbcSvsakar * The ntrack value must be between 1 and the total number of 12556451fdbcSvsakar * sectors in the file system. 12566451fdbcSvsakar */ 12576451fdbcSvsakar range_check(&ntrack, "ntrack", 1, 12586451fdbcSvsakar fssize_db > INT_MAX ? INT_MAX : (uint32_t)fssize_db, 12596451fdbcSvsakar DFLNTRAK, ntrack_flag); 12606451fdbcSvsakar } 12616451fdbcSvsakar 12627c478bd9Sstevel@tonic-gate range_check(&apc, "apc", 0, nsect - 1, 0, apc_flag); 12637c478bd9Sstevel@tonic-gate 12647c478bd9Sstevel@tonic-gate if (mtb == 'y') 12657c478bd9Sstevel@tonic-gate fragsize = bsize; 12667c478bd9Sstevel@tonic-gate 12677c478bd9Sstevel@tonic-gate range_check(&fragsize, "fragsize", sectorsize, bsize, 12687c478bd9Sstevel@tonic-gate MAX(bsize / MAXFRAG, MIN(DESFRAGSIZE, bsize)), fragsize_flag); 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate if ((bsize / MAXFRAG) > fragsize) { 12717c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 12727c478bd9Sstevel@tonic-gate "fragment size %ld is too small, minimum with block size %ld is %ld\n"), 12737c478bd9Sstevel@tonic-gate fragsize, bsize, bsize / MAXFRAG); 12747c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 12757c478bd9Sstevel@tonic-gate gettext("mkfs: fragsize reset to minimum %ld\n"), 12767c478bd9Sstevel@tonic-gate bsize / MAXFRAG); 12777c478bd9Sstevel@tonic-gate fragsize = bsize / MAXFRAG; 12787c478bd9Sstevel@tonic-gate } 12797c478bd9Sstevel@tonic-gate 12807c478bd9Sstevel@tonic-gate if (!POWEROF2(fragsize)) { 12817c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 12827c478bd9Sstevel@tonic-gate gettext("fragment size must be a power of 2, not %ld\n"), 12837c478bd9Sstevel@tonic-gate fragsize); 12847c478bd9Sstevel@tonic-gate fragsize = MAX(bsize / MAXFRAG, MIN(DESFRAGSIZE, bsize)); 12857c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 12867c478bd9Sstevel@tonic-gate gettext("mkfs: fragsize reset to %ld\n"), 12877c478bd9Sstevel@tonic-gate fragsize); 12887c478bd9Sstevel@tonic-gate } 12897c478bd9Sstevel@tonic-gate 12907c478bd9Sstevel@tonic-gate /* At this point, bsize must be >= fragsize, so no need to check it */ 12917c478bd9Sstevel@tonic-gate 12927c478bd9Sstevel@tonic-gate if (bsize < PAGESIZE) { 12937c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 12947c478bd9Sstevel@tonic-gate "WARNING: filesystem block size (%ld) is smaller than " 12957c478bd9Sstevel@tonic-gate "memory page size (%ld).\nResulting filesystem can not be " 12967c478bd9Sstevel@tonic-gate "mounted on this system.\n\n"), 12977c478bd9Sstevel@tonic-gate bsize, (long)PAGESIZE); 12987c478bd9Sstevel@tonic-gate } 12997c478bd9Sstevel@tonic-gate 13007c478bd9Sstevel@tonic-gate range_check(&rps, "rps", 1, 1000, DEFHZ, rps_flag); 13017c478bd9Sstevel@tonic-gate range_check(&minfree, "free", 0, 99, MINFREE, minfree_flag); 13027c478bd9Sstevel@tonic-gate range_check(&nrpos, "nrpos", 1, nsect, MIN(nsect, NRPOS), nrpos_flag); 13037c478bd9Sstevel@tonic-gate 13047c478bd9Sstevel@tonic-gate /* 13057c478bd9Sstevel@tonic-gate * nbpi is variable, but 2MB seems a reasonable upper limit, 13067c478bd9Sstevel@tonic-gate * as 4MB tends to cause problems (using otherwise-default 13077c478bd9Sstevel@tonic-gate * parameters). The true limit is where we end up with one 13087c478bd9Sstevel@tonic-gate * inode per cylinder group. If this file system is being 13097c478bd9Sstevel@tonic-gate * configured for multi-terabyte access, nbpi must be at least 1MB. 13107c478bd9Sstevel@tonic-gate */ 13117c478bd9Sstevel@tonic-gate if (mtb == 'y' && nbpi < MTB_NBPI) { 1312d50c8f90Svsakar if (nbpi_flag != RC_DEFAULT) 1313d50c8f90Svsakar (void) fprintf(stderr, gettext("mkfs: bad value for " 1314d50c8f90Svsakar "nbpi: must be at least 1048576 for multi-terabyte," 1315d50c8f90Svsakar " nbpi reset to default 1048576\n")); 13167c478bd9Sstevel@tonic-gate nbpi = MTB_NBPI; 13177c478bd9Sstevel@tonic-gate } 13187c478bd9Sstevel@tonic-gate 13197c478bd9Sstevel@tonic-gate if (mtb == 'y') 13207c478bd9Sstevel@tonic-gate range_check(&nbpi, "nbpi", MTB_NBPI, 2 * MB, MTB_NBPI, 1321d50c8f90Svsakar nbpi_flag); 13227c478bd9Sstevel@tonic-gate else 13237c478bd9Sstevel@tonic-gate range_check(&nbpi, "nbpi", DEV_BSIZE, 2 * MB, NBPI, nbpi_flag); 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate /* 13267c478bd9Sstevel@tonic-gate * maxcpg is another variably-limited parameter. Calculate 13277c478bd9Sstevel@tonic-gate * the limit based on what we've got for its dependent 13287c478bd9Sstevel@tonic-gate * variables. Effectively, it's how much space is left in the 13297c478bd9Sstevel@tonic-gate * superblock after all the other bits are accounted for. We 13307c478bd9Sstevel@tonic-gate * only fill in sblock fields so we can use MAXIpG. 13317c478bd9Sstevel@tonic-gate * 13327c478bd9Sstevel@tonic-gate * If the calculation of maxcpg below (for the mtb == 'n' 13337c478bd9Sstevel@tonic-gate * case) is changed, update newfs as well. 13347c478bd9Sstevel@tonic-gate * 13357c478bd9Sstevel@tonic-gate * For old-style, non-MTB format file systems, use the old 13367c478bd9Sstevel@tonic-gate * algorithm for calculating the maximum cylinder group size, 13377c478bd9Sstevel@tonic-gate * even though it limits the cylinder group more than necessary. 13387c478bd9Sstevel@tonic-gate * Since layout can affect performance, we don't want to change 13397c478bd9Sstevel@tonic-gate * the default layout for non-MTB file systems at this time. 13407c478bd9Sstevel@tonic-gate * However, for MTB file systems, use the new maxcpg calculation, 13417c478bd9Sstevel@tonic-gate * which really maxes out the cylinder group size. 13427c478bd9Sstevel@tonic-gate */ 13437c478bd9Sstevel@tonic-gate 13447c478bd9Sstevel@tonic-gate sblock.fs_bsize = bsize; 13457c478bd9Sstevel@tonic-gate sblock.fs_inopb = sblock.fs_bsize / sizeof (struct dinode); 13467c478bd9Sstevel@tonic-gate 13477c478bd9Sstevel@tonic-gate if (mtb == 'n') { 13487c478bd9Sstevel@tonic-gate maxcpg = (bsize - sizeof (struct cg) - 13497c478bd9Sstevel@tonic-gate howmany(MAXIpG(&sblock), NBBY)) / 13507c478bd9Sstevel@tonic-gate (sizeof (long) + nrpos * sizeof (short) + 13517c478bd9Sstevel@tonic-gate nsect / (MAXFRAG * NBBY)); 13527c478bd9Sstevel@tonic-gate } else { 13537c478bd9Sstevel@tonic-gate maxcpg = compute_maxcpg(bsize, fragsize, nbpi, nrpos, 13547c478bd9Sstevel@tonic-gate nsect * ntrack); 13557c478bd9Sstevel@tonic-gate } 13567c478bd9Sstevel@tonic-gate 13576451fdbcSvsakar dprintf(("DeBuG cpg : %ld\n", cpg)); 1358d50c8f90Svsakar /* 1359d50c8f90Svsakar * Increase the cpg to maxcpg if either newfs was invoked 1360d50c8f90Svsakar * with -T option or if mkfs wants to create a mtb file system 1361d50c8f90Svsakar * and if the user has not specified the cpg. 1362d50c8f90Svsakar */ 1363d50c8f90Svsakar if (cpg == -1 || (mtb == 'y' && cpg_flag == RC_DEFAULT)) 13647c478bd9Sstevel@tonic-gate cpg = maxcpg; 13656451fdbcSvsakar dprintf(("DeBuG cpg : %ld\n", cpg)); 13666451fdbcSvsakar 13677c478bd9Sstevel@tonic-gate /* 13687c478bd9Sstevel@tonic-gate * mincpg is variable in complex ways, so we really can't 13697c478bd9Sstevel@tonic-gate * do a sane lower-end limit check at this point. 13707c478bd9Sstevel@tonic-gate */ 13717c478bd9Sstevel@tonic-gate range_check(&cpg, "cgsize", 1, maxcpg, MIN(maxcpg, DESCPG), cpg_flag); 13727c478bd9Sstevel@tonic-gate 13737c478bd9Sstevel@tonic-gate /* 13747c478bd9Sstevel@tonic-gate * get the controller info 13757c478bd9Sstevel@tonic-gate */ 13767c478bd9Sstevel@tonic-gate ismdd = 0; 13777c478bd9Sstevel@tonic-gate islog = 0; 13787c478bd9Sstevel@tonic-gate islogok = 0; 13797c478bd9Sstevel@tonic-gate waslog = 0; 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate if (ioctl(fsi, DKIOCINFO, &dkcinfo) == 0) 13827c478bd9Sstevel@tonic-gate /* 13837c478bd9Sstevel@tonic-gate * if it is an MDD (disksuite) device 13847c478bd9Sstevel@tonic-gate */ 13857c478bd9Sstevel@tonic-gate if (dkcinfo.dki_ctype == DKC_MD) { 13867c478bd9Sstevel@tonic-gate ismdd++; 13877c478bd9Sstevel@tonic-gate /* 13887c478bd9Sstevel@tonic-gate * check the logging device 13897c478bd9Sstevel@tonic-gate */ 13907c478bd9Sstevel@tonic-gate if (ioctl(fsi, _FIOISLOG, NULL) == 0) { 13917c478bd9Sstevel@tonic-gate islog++; 13927c478bd9Sstevel@tonic-gate if (ioctl(fsi, _FIOISLOGOK, NULL) == 0) 13937c478bd9Sstevel@tonic-gate islogok++; 13947c478bd9Sstevel@tonic-gate } 13957c478bd9Sstevel@tonic-gate } 13967c478bd9Sstevel@tonic-gate 13977c478bd9Sstevel@tonic-gate /* 13987c478bd9Sstevel@tonic-gate * Do not grow the file system, but print on stdout the maximum 13997c478bd9Sstevel@tonic-gate * size in sectors to which the file system can be increased. 14007c478bd9Sstevel@tonic-gate * The calculated size is limited by fssize_db. 14017c478bd9Sstevel@tonic-gate * Note that we don't lock the filesystem and therefore under rare 14027c478bd9Sstevel@tonic-gate * conditions (the filesystem is mounted, the free block count is 14037c478bd9Sstevel@tonic-gate * almost zero, and the superuser is still changing it) the calculated 14047c478bd9Sstevel@tonic-gate * size can be imprecise. 14057c478bd9Sstevel@tonic-gate */ 14067c478bd9Sstevel@tonic-gate if (Pflag) { 14077c478bd9Sstevel@tonic-gate (void) printf("%llu\n", probe_summaryinfo()); 14087c478bd9Sstevel@tonic-gate exit(0); 14097c478bd9Sstevel@tonic-gate } 14107c478bd9Sstevel@tonic-gate 14117c478bd9Sstevel@tonic-gate /* 14127c478bd9Sstevel@tonic-gate * If we're growing an existing filesystem, then we're about 14137c478bd9Sstevel@tonic-gate * to start doing things that can require recovery efforts if 14147c478bd9Sstevel@tonic-gate * we get interrupted, so make sure we get a chance to do so. 14157c478bd9Sstevel@tonic-gate */ 14167c478bd9Sstevel@tonic-gate if (grow) { 14177c478bd9Sstevel@tonic-gate sigact.sa_handler = recover_from_sigint; 14187c478bd9Sstevel@tonic-gate sigemptyset(&sigact.sa_mask); 14197c478bd9Sstevel@tonic-gate sigact.sa_flags = SA_RESTART; 14207c478bd9Sstevel@tonic-gate 14217c478bd9Sstevel@tonic-gate if (sigaction(SIGINT, &sigact, (struct sigaction *)NULL) < 0) { 14227c478bd9Sstevel@tonic-gate perror(gettext("Could not register SIGINT handler")); 14237c478bd9Sstevel@tonic-gate lockexit(3); 14247c478bd9Sstevel@tonic-gate } 14257c478bd9Sstevel@tonic-gate } 14267c478bd9Sstevel@tonic-gate 14277c478bd9Sstevel@tonic-gate if (!Nflag) { 14287c478bd9Sstevel@tonic-gate /* 14297c478bd9Sstevel@tonic-gate * Check if MNTTAB is trustable 14307c478bd9Sstevel@tonic-gate */ 14317c478bd9Sstevel@tonic-gate if (statvfs64(MNTTAB, &fs) < 0) { 14327c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("can't statvfs %s\n"), 1433d50c8f90Svsakar MNTTAB); 14347c478bd9Sstevel@tonic-gate exit(32); 14357c478bd9Sstevel@tonic-gate } 14367c478bd9Sstevel@tonic-gate 14377c478bd9Sstevel@tonic-gate if (strcmp(MNTTYPE_MNTFS, fs.f_basetype) != 0) { 14387c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1439d50c8f90Svsakar "%s file system type is not %s, can't mkfs\n"), 1440d50c8f90Svsakar MNTTAB, MNTTYPE_MNTFS); 14417c478bd9Sstevel@tonic-gate exit(32); 14427c478bd9Sstevel@tonic-gate } 14437c478bd9Sstevel@tonic-gate 14447c478bd9Sstevel@tonic-gate special = getfullblkname(fsys); 14457c478bd9Sstevel@tonic-gate checkdev(fsys, special); 14467c478bd9Sstevel@tonic-gate 14477c478bd9Sstevel@tonic-gate /* 14487c478bd9Sstevel@tonic-gate * If we found the block device name, 14497c478bd9Sstevel@tonic-gate * then check the mount table. 14507c478bd9Sstevel@tonic-gate * if mounted, and growing write lock the file system 14517c478bd9Sstevel@tonic-gate * 14527c478bd9Sstevel@tonic-gate */ 14537c478bd9Sstevel@tonic-gate if ((special != NULL) && (*special != '\0')) { 14547c478bd9Sstevel@tonic-gate if ((mnttab = fopen(MNTTAB, "r")) == NULL) { 14557c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1456d50c8f90Svsakar "can't open %s\n"), MNTTAB); 14577c478bd9Sstevel@tonic-gate exit(32); 14587c478bd9Sstevel@tonic-gate } 14597c478bd9Sstevel@tonic-gate while ((getmntent(mnttab, &mntp)) == NULL) { 14607c478bd9Sstevel@tonic-gate if (grow) { 14617c478bd9Sstevel@tonic-gate checkmount(&mntp, special); 14627c478bd9Sstevel@tonic-gate continue; 14637c478bd9Sstevel@tonic-gate } 14647c478bd9Sstevel@tonic-gate if (strcmp(special, mntp.mnt_special) == 0) { 14657c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 14667c478bd9Sstevel@tonic-gate "%s is mounted, can't mkfs\n"), 14677c478bd9Sstevel@tonic-gate special); 14687c478bd9Sstevel@tonic-gate exit(32); 14697c478bd9Sstevel@tonic-gate } 14707c478bd9Sstevel@tonic-gate } 14717c478bd9Sstevel@tonic-gate (void) fclose(mnttab); 14727c478bd9Sstevel@tonic-gate } 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate if (directory && (ismounted == 0)) { 14757c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s is not mounted\n"), 14767c478bd9Sstevel@tonic-gate special); 14777c478bd9Sstevel@tonic-gate lockexit(32); 14787c478bd9Sstevel@tonic-gate } 14797c478bd9Sstevel@tonic-gate 14807c478bd9Sstevel@tonic-gate fso = (grow) ? open64(fsys, O_WRONLY) : creat64(fsys, 0666); 14817c478bd9Sstevel@tonic-gate if (fso < 0) { 14827c478bd9Sstevel@tonic-gate saverr = errno; 14837c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 14847c478bd9Sstevel@tonic-gate gettext("%s: cannot create: %s\n"), 14857c478bd9Sstevel@tonic-gate fsys, strerror(saverr)); 14867c478bd9Sstevel@tonic-gate lockexit(32); 14877c478bd9Sstevel@tonic-gate } 14887c478bd9Sstevel@tonic-gate 14897c478bd9Sstevel@tonic-gate } else { 14907c478bd9Sstevel@tonic-gate 14917c478bd9Sstevel@tonic-gate /* 14927c478bd9Sstevel@tonic-gate * For the -N case, a file descriptor is needed for the llseek() 14937c478bd9Sstevel@tonic-gate * in wtfs(). See the comment in wtfs() for more information. 14947c478bd9Sstevel@tonic-gate * 14957c478bd9Sstevel@tonic-gate * Get a file descriptor that's read-only so that this code 14967c478bd9Sstevel@tonic-gate * doesn't accidentally write to the file. 14977c478bd9Sstevel@tonic-gate */ 14987c478bd9Sstevel@tonic-gate fso = open64(fsys, O_RDONLY); 14997c478bd9Sstevel@tonic-gate if (fso < 0) { 15007c478bd9Sstevel@tonic-gate saverr = errno; 15017c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: cannot open: %s\n"), 15027c478bd9Sstevel@tonic-gate fsys, strerror(saverr)); 15037c478bd9Sstevel@tonic-gate lockexit(32); 15047c478bd9Sstevel@tonic-gate } 15057c478bd9Sstevel@tonic-gate } 15067c478bd9Sstevel@tonic-gate 150765908c77Syu, larry liu - Sun Microsystems - Beijing China /* 150865908c77Syu, larry liu - Sun Microsystems - Beijing China * Check the media sector size 150965908c77Syu, larry liu - Sun Microsystems - Beijing China */ 151065908c77Syu, larry liu - Sun Microsystems - Beijing China if (ioctl(fso, DKIOCGMEDIAINFO, &dkminfo) != -1) { 151165908c77Syu, larry liu - Sun Microsystems - Beijing China if (dkminfo.dki_lbsize != 0 && 151265908c77Syu, larry liu - Sun Microsystems - Beijing China POWEROF2(dkminfo.dki_lbsize / DEV_BSIZE) && 151365908c77Syu, larry liu - Sun Microsystems - Beijing China dkminfo.dki_lbsize != DEV_BSIZE) { 151465908c77Syu, larry liu - Sun Microsystems - Beijing China fprintf(stderr, 151565908c77Syu, larry liu - Sun Microsystems - Beijing China gettext("The device sector size %u is not " 151665908c77Syu, larry liu - Sun Microsystems - Beijing China "supported by ufs!\n"), dkminfo.dki_lbsize); 151765908c77Syu, larry liu - Sun Microsystems - Beijing China (void) close(fso); 151865908c77Syu, larry liu - Sun Microsystems - Beijing China exit(1); 151965908c77Syu, larry liu - Sun Microsystems - Beijing China } 152065908c77Syu, larry liu - Sun Microsystems - Beijing China } 152165908c77Syu, larry liu - Sun Microsystems - Beijing China 15227c478bd9Sstevel@tonic-gate /* 15237c478bd9Sstevel@tonic-gate * seed random # generator (for ic_generation) 15247c478bd9Sstevel@tonic-gate */ 15257c478bd9Sstevel@tonic-gate #ifdef MKFS_DEBUG 15267c478bd9Sstevel@tonic-gate srand48(12962); /* reproducible results */ 15277c478bd9Sstevel@tonic-gate #else 15287c478bd9Sstevel@tonic-gate srand48((long)(time((time_t *)NULL) + getpid())); 15297c478bd9Sstevel@tonic-gate #endif 15307c478bd9Sstevel@tonic-gate 15317c478bd9Sstevel@tonic-gate if (grow) { 15327c478bd9Sstevel@tonic-gate growinit(fsys); 15337c478bd9Sstevel@tonic-gate goto grow00; 15347c478bd9Sstevel@tonic-gate } 15357c478bd9Sstevel@tonic-gate 15367c478bd9Sstevel@tonic-gate /* 15377c478bd9Sstevel@tonic-gate * Validate the given file system size. 15387c478bd9Sstevel@tonic-gate * Verify that its last block can actually be accessed. 15397c478bd9Sstevel@tonic-gate * 15407c478bd9Sstevel@tonic-gate * Note: it's ok to use sblock as a buffer because it is immediately 15417c478bd9Sstevel@tonic-gate * overwritten by the rdfs() of the superblock in the next line. 15427c478bd9Sstevel@tonic-gate * 15437c478bd9Sstevel@tonic-gate * ToDo: Because the size checking is done in rdfs()/wtfs(), the 15447c478bd9Sstevel@tonic-gate * error message for specifying an illegal size is very unfriendly. 15457c478bd9Sstevel@tonic-gate * In the future, one could replace the rdfs()/wtfs() calls 15467c478bd9Sstevel@tonic-gate * below with in-line calls to read() or write(). This allows better 15477c478bd9Sstevel@tonic-gate * error messages to be put in place. 15487c478bd9Sstevel@tonic-gate */ 15497c478bd9Sstevel@tonic-gate rdfs(fssize_db - 1, (int)sectorsize, (char *)&sblock); 15507c478bd9Sstevel@tonic-gate 15517c478bd9Sstevel@tonic-gate /* 15527c478bd9Sstevel@tonic-gate * make the fs unmountable 15537c478bd9Sstevel@tonic-gate */ 15547c478bd9Sstevel@tonic-gate rdfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize, (char *)&sblock); 15557c478bd9Sstevel@tonic-gate sblock.fs_magic = -1; 15567c478bd9Sstevel@tonic-gate sblock.fs_clean = FSBAD; 15577c478bd9Sstevel@tonic-gate sblock.fs_state = FSOKAY - sblock.fs_time; 15587c478bd9Sstevel@tonic-gate wtfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize, (char *)&sblock); 15597c478bd9Sstevel@tonic-gate bzero(&sblock, (size_t)sbsize); 15607c478bd9Sstevel@tonic-gate 15617c478bd9Sstevel@tonic-gate sblock.fs_nsect = nsect; 15627c478bd9Sstevel@tonic-gate sblock.fs_ntrak = ntrack; 15637c478bd9Sstevel@tonic-gate 15647c478bd9Sstevel@tonic-gate /* 15657c478bd9Sstevel@tonic-gate * Validate specified/determined spc 15667c478bd9Sstevel@tonic-gate * and calculate minimum cylinders per group. 15677c478bd9Sstevel@tonic-gate */ 15687c478bd9Sstevel@tonic-gate 15697c478bd9Sstevel@tonic-gate /* 15707c478bd9Sstevel@tonic-gate * sectors/cyl = tracks/cyl * sectors/track 15717c478bd9Sstevel@tonic-gate */ 15727c478bd9Sstevel@tonic-gate sblock.fs_spc = sblock.fs_ntrak * sblock.fs_nsect; 15737c478bd9Sstevel@tonic-gate 15747c478bd9Sstevel@tonic-gate grow00: 15757c478bd9Sstevel@tonic-gate if (apc_flag) { 15767c478bd9Sstevel@tonic-gate sblock.fs_spc -= apc; 15777c478bd9Sstevel@tonic-gate } 15787c478bd9Sstevel@tonic-gate /* 15797c478bd9Sstevel@tonic-gate * Have to test for this separately from apc_flag, due to 15807c478bd9Sstevel@tonic-gate * the growfs case.... 15817c478bd9Sstevel@tonic-gate */ 15827c478bd9Sstevel@tonic-gate if (sblock.fs_spc != sblock.fs_ntrak * sblock.fs_nsect) { 15837c478bd9Sstevel@tonic-gate spc_flag = 1; 15847c478bd9Sstevel@tonic-gate } 15857c478bd9Sstevel@tonic-gate if (grow) 15867c478bd9Sstevel@tonic-gate goto grow10; 15877c478bd9Sstevel@tonic-gate 15887c478bd9Sstevel@tonic-gate sblock.fs_nrpos = nrpos; 15897c478bd9Sstevel@tonic-gate sblock.fs_bsize = bsize; 15907c478bd9Sstevel@tonic-gate sblock.fs_fsize = fragsize; 15917c478bd9Sstevel@tonic-gate sblock.fs_minfree = minfree; 15927c478bd9Sstevel@tonic-gate 15937c478bd9Sstevel@tonic-gate grow10: 15947c478bd9Sstevel@tonic-gate if (nbpi < sblock.fs_fsize) { 15957c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 15967c478bd9Sstevel@tonic-gate "warning: wasteful data byte allocation / inode (nbpi):\n")); 15977c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 15987c478bd9Sstevel@tonic-gate "%ld smaller than allocatable fragment size of %d\n"), 15997c478bd9Sstevel@tonic-gate nbpi, sblock.fs_fsize); 16007c478bd9Sstevel@tonic-gate } 16017c478bd9Sstevel@tonic-gate if (grow) 16027c478bd9Sstevel@tonic-gate goto grow20; 16037c478bd9Sstevel@tonic-gate 16047c478bd9Sstevel@tonic-gate if (opt == 's') 16057c478bd9Sstevel@tonic-gate sblock.fs_optim = FS_OPTSPACE; 16067c478bd9Sstevel@tonic-gate else 16077c478bd9Sstevel@tonic-gate sblock.fs_optim = FS_OPTTIME; 16087c478bd9Sstevel@tonic-gate 16097c478bd9Sstevel@tonic-gate sblock.fs_bmask = ~(sblock.fs_bsize - 1); 16107c478bd9Sstevel@tonic-gate sblock.fs_fmask = ~(sblock.fs_fsize - 1); 16117c478bd9Sstevel@tonic-gate /* 16127c478bd9Sstevel@tonic-gate * Planning now for future expansion. 16137c478bd9Sstevel@tonic-gate */ 16147c478bd9Sstevel@tonic-gate #if defined(_BIG_ENDIAN) 16157c478bd9Sstevel@tonic-gate sblock.fs_qbmask.val[0] = 0; 16167c478bd9Sstevel@tonic-gate sblock.fs_qbmask.val[1] = ~sblock.fs_bmask; 16177c478bd9Sstevel@tonic-gate sblock.fs_qfmask.val[0] = 0; 16187c478bd9Sstevel@tonic-gate sblock.fs_qfmask.val[1] = ~sblock.fs_fmask; 16197c478bd9Sstevel@tonic-gate #endif 16207c478bd9Sstevel@tonic-gate #if defined(_LITTLE_ENDIAN) 16217c478bd9Sstevel@tonic-gate sblock.fs_qbmask.val[0] = ~sblock.fs_bmask; 16227c478bd9Sstevel@tonic-gate sblock.fs_qbmask.val[1] = 0; 16237c478bd9Sstevel@tonic-gate sblock.fs_qfmask.val[0] = ~sblock.fs_fmask; 16247c478bd9Sstevel@tonic-gate sblock.fs_qfmask.val[1] = 0; 16257c478bd9Sstevel@tonic-gate #endif 16267c478bd9Sstevel@tonic-gate for (sblock.fs_bshift = 0, i = sblock.fs_bsize; i > 1; i >>= 1) 16277c478bd9Sstevel@tonic-gate sblock.fs_bshift++; 16287c478bd9Sstevel@tonic-gate for (sblock.fs_fshift = 0, i = sblock.fs_fsize; i > 1; i >>= 1) 16297c478bd9Sstevel@tonic-gate sblock.fs_fshift++; 16307c478bd9Sstevel@tonic-gate sblock.fs_frag = numfrags(&sblock, sblock.fs_bsize); 16317c478bd9Sstevel@tonic-gate for (sblock.fs_fragshift = 0, i = sblock.fs_frag; i > 1; i >>= 1) 16327c478bd9Sstevel@tonic-gate sblock.fs_fragshift++; 16337c478bd9Sstevel@tonic-gate if (sblock.fs_frag > MAXFRAG) { 16347c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 16357c478bd9Sstevel@tonic-gate "fragment size %d is too small, minimum with block size %d is %d\n"), 16367c478bd9Sstevel@tonic-gate sblock.fs_fsize, sblock.fs_bsize, 16377c478bd9Sstevel@tonic-gate sblock.fs_bsize / MAXFRAG); 16387c478bd9Sstevel@tonic-gate lockexit(32); 16397c478bd9Sstevel@tonic-gate } 16407c478bd9Sstevel@tonic-gate sblock.fs_nindir = sblock.fs_bsize / sizeof (daddr32_t); 16417c478bd9Sstevel@tonic-gate sblock.fs_inopb = sblock.fs_bsize / sizeof (struct dinode); 16427c478bd9Sstevel@tonic-gate sblock.fs_nspf = sblock.fs_fsize / sectorsize; 16437c478bd9Sstevel@tonic-gate for (sblock.fs_fsbtodb = 0, i = NSPF(&sblock); i > 1; i >>= 1) 16447c478bd9Sstevel@tonic-gate sblock.fs_fsbtodb++; 16457c478bd9Sstevel@tonic-gate 16467c478bd9Sstevel@tonic-gate /* 16477c478bd9Sstevel@tonic-gate * Compute the super-block, cylinder group, and inode blocks. 16487c478bd9Sstevel@tonic-gate * Note that these "blkno" are really fragment addresses. 16497c478bd9Sstevel@tonic-gate * For example, on an 8K/1K (block/fragment) system, fs_sblkno is 16, 16507c478bd9Sstevel@tonic-gate * fs_cblkno is 24, and fs_iblkno is 32. This is why CGSIZE is so 16517c478bd9Sstevel@tonic-gate * important: only 1 FS block is allocated for the cg struct (fragment 16527c478bd9Sstevel@tonic-gate * numbers 24 through 31). 16537c478bd9Sstevel@tonic-gate */ 16547c478bd9Sstevel@tonic-gate sblock.fs_sblkno = 16557c478bd9Sstevel@tonic-gate roundup(howmany(bbsize + sbsize, sblock.fs_fsize), sblock.fs_frag); 16567c478bd9Sstevel@tonic-gate sblock.fs_cblkno = (daddr32_t)(sblock.fs_sblkno + 16577c478bd9Sstevel@tonic-gate roundup(howmany(sbsize, sblock.fs_fsize), sblock.fs_frag)); 16587c478bd9Sstevel@tonic-gate sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag; 16597c478bd9Sstevel@tonic-gate 16607c478bd9Sstevel@tonic-gate sblock.fs_cgoffset = roundup( 16617c478bd9Sstevel@tonic-gate howmany(sblock.fs_nsect, NSPF(&sblock)), sblock.fs_frag); 16627c478bd9Sstevel@tonic-gate for (sblock.fs_cgmask = -1, i = sblock.fs_ntrak; i > 1; i >>= 1) 16637c478bd9Sstevel@tonic-gate sblock.fs_cgmask <<= 1; 16647c478bd9Sstevel@tonic-gate if (!POWEROF2(sblock.fs_ntrak)) 16657c478bd9Sstevel@tonic-gate sblock.fs_cgmask <<= 1; 16667c478bd9Sstevel@tonic-gate /* 16677c478bd9Sstevel@tonic-gate * Validate specified/determined spc 16687c478bd9Sstevel@tonic-gate * and calculate minimum cylinders per group. 16697c478bd9Sstevel@tonic-gate */ 16707c478bd9Sstevel@tonic-gate 16717c478bd9Sstevel@tonic-gate for (sblock.fs_cpc = NSPB(&sblock), i = sblock.fs_spc; 16727c478bd9Sstevel@tonic-gate sblock.fs_cpc > 1 && (i & 1) == 0; 16737c478bd9Sstevel@tonic-gate sblock.fs_cpc >>= 1, i >>= 1) 16747c478bd9Sstevel@tonic-gate /* void */; 16757c478bd9Sstevel@tonic-gate mincpc = sblock.fs_cpc; 16767c478bd9Sstevel@tonic-gate 16777c478bd9Sstevel@tonic-gate /* if these calculations are changed, check dump_fscmd also */ 16787c478bd9Sstevel@tonic-gate bpcg = (uint64_t)sblock.fs_spc * sectorsize; 16797c478bd9Sstevel@tonic-gate inospercg = (uint64_t)roundup(bpcg / sizeof (struct dinode), 16807c478bd9Sstevel@tonic-gate INOPB(&sblock)); 16817c478bd9Sstevel@tonic-gate if (inospercg > MAXIpG(&sblock)) 16827c478bd9Sstevel@tonic-gate inospercg = MAXIpG(&sblock); 16837c478bd9Sstevel@tonic-gate used = (uint64_t)(sblock.fs_iblkno + inospercg / 16847c478bd9Sstevel@tonic-gate INOPF(&sblock)) * NSPF(&sblock); 16857c478bd9Sstevel@tonic-gate mincpgcnt = (long)howmany((uint64_t)sblock.fs_cgoffset * 16867c478bd9Sstevel@tonic-gate (~sblock.fs_cgmask) + used, sblock.fs_spc); 16877c478bd9Sstevel@tonic-gate mincpg = roundup(mincpgcnt, mincpc); 16887c478bd9Sstevel@tonic-gate /* 16897c478bd9Sstevel@tonic-gate * Insure that cylinder group with mincpg has enough space 16907c478bd9Sstevel@tonic-gate * for block maps 16917c478bd9Sstevel@tonic-gate */ 16927c478bd9Sstevel@tonic-gate sblock.fs_cpg = mincpg; 16937c478bd9Sstevel@tonic-gate sblock.fs_ipg = (int32_t)inospercg; 16947c478bd9Sstevel@tonic-gate mapcramped = 0; 16957c478bd9Sstevel@tonic-gate 16967c478bd9Sstevel@tonic-gate /* 16977c478bd9Sstevel@tonic-gate * Make sure the cg struct fits within the file system block. 16987c478bd9Sstevel@tonic-gate * Use larger block sizes until it fits 16997c478bd9Sstevel@tonic-gate */ 17007c478bd9Sstevel@tonic-gate while (CGSIZE(&sblock) > sblock.fs_bsize) { 17017c478bd9Sstevel@tonic-gate mapcramped = 1; 17027c478bd9Sstevel@tonic-gate if (sblock.fs_bsize < MAXBSIZE) { 17037c478bd9Sstevel@tonic-gate sblock.fs_bsize <<= 1; 17047c478bd9Sstevel@tonic-gate if ((i & 1) == 0) { 17057c478bd9Sstevel@tonic-gate i >>= 1; 17067c478bd9Sstevel@tonic-gate } else { 17077c478bd9Sstevel@tonic-gate sblock.fs_cpc <<= 1; 17087c478bd9Sstevel@tonic-gate mincpc <<= 1; 17097c478bd9Sstevel@tonic-gate mincpg = roundup(mincpgcnt, mincpc); 17107c478bd9Sstevel@tonic-gate sblock.fs_cpg = mincpg; 17117c478bd9Sstevel@tonic-gate } 17127c478bd9Sstevel@tonic-gate sblock.fs_frag <<= 1; 17137c478bd9Sstevel@tonic-gate sblock.fs_fragshift += 1; 17147c478bd9Sstevel@tonic-gate if (sblock.fs_frag <= MAXFRAG) 17157c478bd9Sstevel@tonic-gate continue; 17167c478bd9Sstevel@tonic-gate } 17177c478bd9Sstevel@tonic-gate 17187c478bd9Sstevel@tonic-gate /* 17197c478bd9Sstevel@tonic-gate * Looped far enough. The fragment is now as large as the 17207c478bd9Sstevel@tonic-gate * filesystem block! 17217c478bd9Sstevel@tonic-gate */ 17227c478bd9Sstevel@tonic-gate if (sblock.fs_fsize == sblock.fs_bsize) { 17237c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 17247c478bd9Sstevel@tonic-gate "There is no block size that can support this disk\n")); 17257c478bd9Sstevel@tonic-gate lockexit(32); 17267c478bd9Sstevel@tonic-gate } 17277c478bd9Sstevel@tonic-gate 17287c478bd9Sstevel@tonic-gate /* 17297c478bd9Sstevel@tonic-gate * Try a larger fragment. Double the fragment size. 17307c478bd9Sstevel@tonic-gate */ 17317c478bd9Sstevel@tonic-gate sblock.fs_frag >>= 1; 17327c478bd9Sstevel@tonic-gate sblock.fs_fragshift -= 1; 17337c478bd9Sstevel@tonic-gate sblock.fs_fsize <<= 1; 17347c478bd9Sstevel@tonic-gate sblock.fs_nspf <<= 1; 17357c478bd9Sstevel@tonic-gate } 17367c478bd9Sstevel@tonic-gate /* 17377c478bd9Sstevel@tonic-gate * Insure that cylinder group with mincpg has enough space for inodes 17387c478bd9Sstevel@tonic-gate */ 17397c478bd9Sstevel@tonic-gate inodecramped = 0; 17407c478bd9Sstevel@tonic-gate used *= sectorsize; 17417c478bd9Sstevel@tonic-gate nbytes64 = (uint64_t)mincpg * bpcg - used; 17427c478bd9Sstevel@tonic-gate inospercg = (uint64_t)roundup((nbytes64 / nbpi), INOPB(&sblock)); 17437c478bd9Sstevel@tonic-gate sblock.fs_ipg = (int32_t)inospercg; 17447c478bd9Sstevel@tonic-gate while (inospercg > MAXIpG(&sblock)) { 17457c478bd9Sstevel@tonic-gate inodecramped = 1; 17467c478bd9Sstevel@tonic-gate if (mincpc == 1 || sblock.fs_frag == 1 || 17477c478bd9Sstevel@tonic-gate sblock.fs_bsize == MINBSIZE) 17487c478bd9Sstevel@tonic-gate break; 17497c478bd9Sstevel@tonic-gate nbytes64 = (uint64_t)mincpg * bpcg - used; 17507c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 17517c478bd9Sstevel@tonic-gate gettext("With a block size of %d %s %lu\n"), 17527c478bd9Sstevel@tonic-gate sblock.fs_bsize, gettext("minimum bytes per inode is"), 17537c478bd9Sstevel@tonic-gate (uint32_t)(nbytes64 / MAXIpG(&sblock) + 1)); 17547c478bd9Sstevel@tonic-gate sblock.fs_bsize >>= 1; 17557c478bd9Sstevel@tonic-gate sblock.fs_frag >>= 1; 17567c478bd9Sstevel@tonic-gate sblock.fs_fragshift -= 1; 17577c478bd9Sstevel@tonic-gate mincpc >>= 1; 17587c478bd9Sstevel@tonic-gate sblock.fs_cpg = roundup(mincpgcnt, mincpc); 17597c478bd9Sstevel@tonic-gate if (CGSIZE(&sblock) > sblock.fs_bsize) { 17607c478bd9Sstevel@tonic-gate sblock.fs_bsize <<= 1; 17617c478bd9Sstevel@tonic-gate break; 17627c478bd9Sstevel@tonic-gate } 17637c478bd9Sstevel@tonic-gate mincpg = sblock.fs_cpg; 17647c478bd9Sstevel@tonic-gate nbytes64 = (uint64_t)mincpg * bpcg - used; 17657c478bd9Sstevel@tonic-gate inospercg = (uint64_t)roundup((nbytes64 / nbpi), 1766d50c8f90Svsakar INOPB(&sblock)); 17677c478bd9Sstevel@tonic-gate sblock.fs_ipg = (int32_t)inospercg; 17687c478bd9Sstevel@tonic-gate } 17697c478bd9Sstevel@tonic-gate if (inodecramped) { 17707c478bd9Sstevel@tonic-gate if (inospercg > MAXIpG(&sblock)) { 17717c478bd9Sstevel@tonic-gate nbytes64 = (uint64_t)mincpg * bpcg - used; 17727c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 17737c478bd9Sstevel@tonic-gate "Minimum bytes per inode is %d\n"), 17747c478bd9Sstevel@tonic-gate (uint32_t)(nbytes64 / MAXIpG(&sblock) + 1)); 17757c478bd9Sstevel@tonic-gate } else if (!mapcramped) { 17767c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 17777c478bd9Sstevel@tonic-gate "With %ld bytes per inode, minimum cylinders per group is %ld\n"), 17787c478bd9Sstevel@tonic-gate nbpi, mincpg); 17797c478bd9Sstevel@tonic-gate } 17807c478bd9Sstevel@tonic-gate } 17817c478bd9Sstevel@tonic-gate if (mapcramped) { 17827c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 17837c478bd9Sstevel@tonic-gate "With %d sectors per cylinder, minimum cylinders " 17847c478bd9Sstevel@tonic-gate "per group is %ld\n"), 17857c478bd9Sstevel@tonic-gate sblock.fs_spc, mincpg); 17867c478bd9Sstevel@tonic-gate } 17877c478bd9Sstevel@tonic-gate if (inodecramped || mapcramped) { 17887c478bd9Sstevel@tonic-gate /* 17897c478bd9Sstevel@tonic-gate * To make this at least somewhat comprehensible in 17907c478bd9Sstevel@tonic-gate * the world of i18n, figure out what we're going to 17917c478bd9Sstevel@tonic-gate * say and then say it all at one time. The days of 17927c478bd9Sstevel@tonic-gate * needing to scrimp on string space are behind us.... 17937c478bd9Sstevel@tonic-gate */ 17947c478bd9Sstevel@tonic-gate if ((sblock.fs_bsize != bsize) && 17957c478bd9Sstevel@tonic-gate (sblock.fs_fsize != fragsize)) { 17967c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 17977c478bd9Sstevel@tonic-gate "This requires the block size to be changed from %ld to %d\n" 17987c478bd9Sstevel@tonic-gate "and the fragment size to be changed from %ld to %d\n"), 17997c478bd9Sstevel@tonic-gate bsize, sblock.fs_bsize, 18007c478bd9Sstevel@tonic-gate fragsize, sblock.fs_fsize); 18017c478bd9Sstevel@tonic-gate } else if (sblock.fs_bsize != bsize) { 18027c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 18037c478bd9Sstevel@tonic-gate "This requires the block size to be changed from %ld to %d\n"), 18047c478bd9Sstevel@tonic-gate bsize, sblock.fs_bsize); 18057c478bd9Sstevel@tonic-gate } else if (sblock.fs_fsize != fragsize) { 18067c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 18077c478bd9Sstevel@tonic-gate "This requires the fragment size to be changed from %ld to %d\n"), 18087c478bd9Sstevel@tonic-gate fragsize, sblock.fs_fsize); 18097c478bd9Sstevel@tonic-gate } else { 18107c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 18117c478bd9Sstevel@tonic-gate "Unable to make filesystem fit with the given constraints\n")); 18127c478bd9Sstevel@tonic-gate } 18137c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 18147c478bd9Sstevel@tonic-gate "Please re-run mkfs with corrected parameters\n")); 18157c478bd9Sstevel@tonic-gate lockexit(32); 18167c478bd9Sstevel@tonic-gate } 18177c478bd9Sstevel@tonic-gate /* 18187c478bd9Sstevel@tonic-gate * Calculate the number of cylinders per group 18197c478bd9Sstevel@tonic-gate */ 18207c478bd9Sstevel@tonic-gate sblock.fs_cpg = cpg; 18217c478bd9Sstevel@tonic-gate if (sblock.fs_cpg % mincpc != 0) { 18227c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 18237c478bd9Sstevel@tonic-gate "Warning: cylinder groups must have a multiple " 18247c478bd9Sstevel@tonic-gate "of %ld cylinders with the given\n parameters\n"), 18257c478bd9Sstevel@tonic-gate mincpc); 18267c478bd9Sstevel@tonic-gate sblock.fs_cpg = roundup(sblock.fs_cpg, mincpc); 18277c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Rounded cgsize up to %d\n"), 18287c478bd9Sstevel@tonic-gate sblock.fs_cpg); 18297c478bd9Sstevel@tonic-gate } 18307c478bd9Sstevel@tonic-gate /* 18317c478bd9Sstevel@tonic-gate * Must insure there is enough space for inodes 18327c478bd9Sstevel@tonic-gate */ 18337c478bd9Sstevel@tonic-gate /* if these calculations are changed, check dump_fscmd also */ 18347c478bd9Sstevel@tonic-gate nbytes64 = (uint64_t)sblock.fs_cpg * bpcg - used; 18357c478bd9Sstevel@tonic-gate sblock.fs_ipg = roundup((uint32_t)(nbytes64 / nbpi), INOPB(&sblock)); 18367c478bd9Sstevel@tonic-gate 18377c478bd9Sstevel@tonic-gate /* 18387c478bd9Sstevel@tonic-gate * Slim down cylinders per group, until the inodes can fit. 18397c478bd9Sstevel@tonic-gate */ 18407c478bd9Sstevel@tonic-gate while (sblock.fs_ipg > MAXIpG(&sblock)) { 18417c478bd9Sstevel@tonic-gate inodecramped = 1; 18427c478bd9Sstevel@tonic-gate sblock.fs_cpg -= mincpc; 18437c478bd9Sstevel@tonic-gate nbytes64 = (uint64_t)sblock.fs_cpg * bpcg - used; 18447c478bd9Sstevel@tonic-gate sblock.fs_ipg = roundup((uint32_t)(nbytes64 / nbpi), 1845d50c8f90Svsakar INOPB(&sblock)); 18467c478bd9Sstevel@tonic-gate } 18477c478bd9Sstevel@tonic-gate /* 18487c478bd9Sstevel@tonic-gate * Must insure there is enough space to hold block map. 18497c478bd9Sstevel@tonic-gate * Cut down on cylinders per group, until the cg struct fits in a 18507c478bd9Sstevel@tonic-gate * filesystem block. 18517c478bd9Sstevel@tonic-gate */ 18527c478bd9Sstevel@tonic-gate while (CGSIZE(&sblock) > sblock.fs_bsize) { 18537c478bd9Sstevel@tonic-gate mapcramped = 1; 18547c478bd9Sstevel@tonic-gate sblock.fs_cpg -= mincpc; 18557c478bd9Sstevel@tonic-gate nbytes64 = (uint64_t)sblock.fs_cpg * bpcg - used; 18567c478bd9Sstevel@tonic-gate sblock.fs_ipg = roundup((uint32_t)(nbytes64 / nbpi), 1857d50c8f90Svsakar INOPB(&sblock)); 18587c478bd9Sstevel@tonic-gate } 18597c478bd9Sstevel@tonic-gate sblock.fs_fpg = (sblock.fs_cpg * sblock.fs_spc) / NSPF(&sblock); 18607c478bd9Sstevel@tonic-gate if ((sblock.fs_cpg * sblock.fs_spc) % NSPB(&sblock) != 0) { 18617c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 18627c478bd9Sstevel@tonic-gate gettext("newfs: panic (fs_cpg * fs_spc) %% NSPF != 0\n")); 18637c478bd9Sstevel@tonic-gate lockexit(32); 18647c478bd9Sstevel@tonic-gate } 18657c478bd9Sstevel@tonic-gate if (sblock.fs_cpg < mincpg) { 18667c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 18677c478bd9Sstevel@tonic-gate "With the given parameters, cgsize must be at least %ld; please re-run mkfs\n"), 1868d50c8f90Svsakar mincpg); 18697c478bd9Sstevel@tonic-gate lockexit(32); 18707c478bd9Sstevel@tonic-gate } 18717c478bd9Sstevel@tonic-gate sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock)); 18727c478bd9Sstevel@tonic-gate grow20: 18737c478bd9Sstevel@tonic-gate /* 18747c478bd9Sstevel@tonic-gate * Now have size for file system and nsect and ntrak. 18757c478bd9Sstevel@tonic-gate * Determine number of cylinders and blocks in the file system. 18767c478bd9Sstevel@tonic-gate */ 18777c478bd9Sstevel@tonic-gate fssize_frag = (int64_t)dbtofsb(&sblock, fssize_db); 18787c478bd9Sstevel@tonic-gate if (fssize_frag > INT_MAX) { 18797c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 18807c478bd9Sstevel@tonic-gate "There are too many fragments in the system, increase fragment size\n"), 18817c478bd9Sstevel@tonic-gate mincpg); 18827c478bd9Sstevel@tonic-gate lockexit(32); 18837c478bd9Sstevel@tonic-gate } 18847c478bd9Sstevel@tonic-gate sblock.fs_size = (int32_t)fssize_frag; 18857c478bd9Sstevel@tonic-gate sblock.fs_ncyl = (int32_t)(fssize_frag * NSPF(&sblock) / sblock.fs_spc); 18867c478bd9Sstevel@tonic-gate if (fssize_frag * NSPF(&sblock) > 18877c478bd9Sstevel@tonic-gate (uint64_t)sblock.fs_ncyl * sblock.fs_spc) { 18887c478bd9Sstevel@tonic-gate sblock.fs_ncyl++; 18897c478bd9Sstevel@tonic-gate warn = 1; 18907c478bd9Sstevel@tonic-gate } 18917c478bd9Sstevel@tonic-gate if (sblock.fs_ncyl < 1) { 18927c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1893d50c8f90Svsakar "file systems must have at least one cylinder\n")); 18947c478bd9Sstevel@tonic-gate lockexit(32); 18957c478bd9Sstevel@tonic-gate } 18967c478bd9Sstevel@tonic-gate if (grow) 18977c478bd9Sstevel@tonic-gate goto grow30; 18987c478bd9Sstevel@tonic-gate /* 18997c478bd9Sstevel@tonic-gate * Determine feasability/values of rotational layout tables. 19007c478bd9Sstevel@tonic-gate * 19017c478bd9Sstevel@tonic-gate * The size of the rotational layout tables is limited by the size 19027c478bd9Sstevel@tonic-gate * of the file system block, fs_bsize. The amount of space 19037c478bd9Sstevel@tonic-gate * available for tables is calculated as (fs_bsize - sizeof (struct 19047c478bd9Sstevel@tonic-gate * fs)). The size of these tables is inversely proportional to the 19057c478bd9Sstevel@tonic-gate * block size of the file system. The size increases if sectors per 19067c478bd9Sstevel@tonic-gate * track are not powers of two, because more cylinders must be 19077c478bd9Sstevel@tonic-gate * described by the tables before the rotational pattern repeats 19087c478bd9Sstevel@tonic-gate * (fs_cpc). 19097c478bd9Sstevel@tonic-gate */ 19107c478bd9Sstevel@tonic-gate sblock.fs_postblformat = FS_DYNAMICPOSTBLFMT; 19117c478bd9Sstevel@tonic-gate sblock.fs_sbsize = fragroundup(&sblock, sizeof (struct fs)); 19127c478bd9Sstevel@tonic-gate sblock.fs_npsect = sblock.fs_nsect; 19137c478bd9Sstevel@tonic-gate if (sblock.fs_ntrak == 1) { 19147c478bd9Sstevel@tonic-gate sblock.fs_cpc = 0; 19157c478bd9Sstevel@tonic-gate goto next; 19167c478bd9Sstevel@tonic-gate } 19177c478bd9Sstevel@tonic-gate postblsize = sblock.fs_nrpos * sblock.fs_cpc * sizeof (short); 19187c478bd9Sstevel@tonic-gate rotblsize = sblock.fs_cpc * sblock.fs_spc / NSPB(&sblock); 19197c478bd9Sstevel@tonic-gate totalsbsize = sizeof (struct fs) + rotblsize; 19207c478bd9Sstevel@tonic-gate 19217c478bd9Sstevel@tonic-gate /* do static allocation if nrpos == 8 and fs_cpc == 16 */ 19227c478bd9Sstevel@tonic-gate if (sblock.fs_nrpos == 8 && sblock.fs_cpc <= 16) { 19237c478bd9Sstevel@tonic-gate /* use old static table space */ 19247c478bd9Sstevel@tonic-gate sblock.fs_postbloff = (char *)(&sblock.fs_opostbl[0][0]) - 19257c478bd9Sstevel@tonic-gate (char *)(&sblock.fs_link); 19267c478bd9Sstevel@tonic-gate sblock.fs_rotbloff = &sblock.fs_space[0] - 19277c478bd9Sstevel@tonic-gate (uchar_t *)(&sblock.fs_link); 19287c478bd9Sstevel@tonic-gate } else { 19297c478bd9Sstevel@tonic-gate /* use 4.3 dynamic table space */ 19307c478bd9Sstevel@tonic-gate sblock.fs_postbloff = &sblock.fs_space[0] - 19317c478bd9Sstevel@tonic-gate (uchar_t *)(&sblock.fs_link); 19327c478bd9Sstevel@tonic-gate sblock.fs_rotbloff = sblock.fs_postbloff + postblsize; 19337c478bd9Sstevel@tonic-gate totalsbsize += postblsize; 19347c478bd9Sstevel@tonic-gate } 19357c478bd9Sstevel@tonic-gate if (totalsbsize > sblock.fs_bsize || 19367c478bd9Sstevel@tonic-gate sblock.fs_nsect > (1 << NBBY) * NSPB(&sblock)) { 19377c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 19387c478bd9Sstevel@tonic-gate "Warning: insufficient space in super block for\n" 19397c478bd9Sstevel@tonic-gate "rotational layout tables with nsect %d, ntrack %d, " 19407c478bd9Sstevel@tonic-gate "and nrpos %d.\nOmitting tables - file system " 19417c478bd9Sstevel@tonic-gate "performance may be impaired.\n"), 19427c478bd9Sstevel@tonic-gate sblock.fs_nsect, sblock.fs_ntrak, sblock.fs_nrpos); 19437c478bd9Sstevel@tonic-gate 19447c478bd9Sstevel@tonic-gate /* 19457c478bd9Sstevel@tonic-gate * Setting fs_cpc to 0 tells alloccgblk() in ufs_alloc.c to 19467c478bd9Sstevel@tonic-gate * ignore the positional layout table and rotational 19477c478bd9Sstevel@tonic-gate * position table. 19487c478bd9Sstevel@tonic-gate */ 19497c478bd9Sstevel@tonic-gate sblock.fs_cpc = 0; 19507c478bd9Sstevel@tonic-gate goto next; 19517c478bd9Sstevel@tonic-gate } 19527c478bd9Sstevel@tonic-gate sblock.fs_sbsize = fragroundup(&sblock, totalsbsize); 19537c478bd9Sstevel@tonic-gate 19547c478bd9Sstevel@tonic-gate 19557c478bd9Sstevel@tonic-gate /* 19567c478bd9Sstevel@tonic-gate * calculate the available blocks for each rotational position 19577c478bd9Sstevel@tonic-gate */ 19587c478bd9Sstevel@tonic-gate for (cylno = 0; cylno < sblock.fs_cpc; cylno++) 19597c478bd9Sstevel@tonic-gate for (rpos = 0; rpos < sblock.fs_nrpos; rpos++) 19607c478bd9Sstevel@tonic-gate fs_postbl(&sblock, cylno)[rpos] = -1; 19617c478bd9Sstevel@tonic-gate for (i = (rotblsize - 1) * sblock.fs_frag; 19627c478bd9Sstevel@tonic-gate i >= 0; i -= sblock.fs_frag) { 19637c478bd9Sstevel@tonic-gate cylno = cbtocylno(&sblock, i); 19647c478bd9Sstevel@tonic-gate rpos = cbtorpos(&sblock, i); 19657c478bd9Sstevel@tonic-gate blk = fragstoblks(&sblock, i); 19667c478bd9Sstevel@tonic-gate if (fs_postbl(&sblock, cylno)[rpos] == -1) 19677c478bd9Sstevel@tonic-gate fs_rotbl(&sblock)[blk] = 0; 19687c478bd9Sstevel@tonic-gate else 19697c478bd9Sstevel@tonic-gate fs_rotbl(&sblock)[blk] = 19707c478bd9Sstevel@tonic-gate fs_postbl(&sblock, cylno)[rpos] - blk; 19717c478bd9Sstevel@tonic-gate fs_postbl(&sblock, cylno)[rpos] = blk; 19727c478bd9Sstevel@tonic-gate } 19737c478bd9Sstevel@tonic-gate next: 19747c478bd9Sstevel@tonic-gate grow30: 19757c478bd9Sstevel@tonic-gate /* 19767c478bd9Sstevel@tonic-gate * Compute/validate number of cylinder groups. 19777c478bd9Sstevel@tonic-gate * Note that if an excessively large filesystem is specified 19787c478bd9Sstevel@tonic-gate * (e.g., more than 16384 cylinders for an 8K filesystem block), it 19797c478bd9Sstevel@tonic-gate * does not get detected until checksummarysize() 19807c478bd9Sstevel@tonic-gate */ 19817c478bd9Sstevel@tonic-gate sblock.fs_ncg = sblock.fs_ncyl / sblock.fs_cpg; 19827c478bd9Sstevel@tonic-gate if (sblock.fs_ncyl % sblock.fs_cpg) 19837c478bd9Sstevel@tonic-gate sblock.fs_ncg++; 19847c478bd9Sstevel@tonic-gate sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock); 19857c478bd9Sstevel@tonic-gate i = MIN(~sblock.fs_cgmask, sblock.fs_ncg - 1); 19867c478bd9Sstevel@tonic-gate ibpcl = cgdmin(&sblock, i) - cgbase(&sblock, i); 19877c478bd9Sstevel@tonic-gate if (ibpcl >= sblock.fs_fpg) { 19887c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 19897c478bd9Sstevel@tonic-gate "inode blocks/cyl group (%d) >= data blocks (%d)\n"), 19907c478bd9Sstevel@tonic-gate cgdmin(&sblock, i) - cgbase(&sblock, i) / sblock.fs_frag, 19917c478bd9Sstevel@tonic-gate sblock.fs_fpg / sblock.fs_frag); 19927c478bd9Sstevel@tonic-gate if ((ibpcl < 0) || (sblock.fs_fpg < 0)) { 19937c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 19947c478bd9Sstevel@tonic-gate "number of cylinders per cylinder group (%d) must be decreased.\n"), 19957c478bd9Sstevel@tonic-gate sblock.fs_cpg); 19967c478bd9Sstevel@tonic-gate } else { 19977c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 19987c478bd9Sstevel@tonic-gate "number of cylinders per cylinder group (%d) must be increased.\n"), 19997c478bd9Sstevel@tonic-gate sblock.fs_cpg); 20007c478bd9Sstevel@tonic-gate } 20017c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 20027c478bd9Sstevel@tonic-gate "Note that cgsize may have been adjusted to allow struct cg to fit.\n")); 20037c478bd9Sstevel@tonic-gate lockexit(32); 20047c478bd9Sstevel@tonic-gate } 20057c478bd9Sstevel@tonic-gate j = sblock.fs_ncg - 1; 20067c478bd9Sstevel@tonic-gate if ((i = fssize_frag - j * sblock.fs_fpg) < sblock.fs_fpg && 20077c478bd9Sstevel@tonic-gate cgdmin(&sblock, j) - cgbase(&sblock, j) > i) { 20087c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 20097c478bd9Sstevel@tonic-gate "Warning: inode blocks/cyl group (%d) >= data " 20107c478bd9Sstevel@tonic-gate "blocks (%ld) in last\n cylinder group. This " 20117c478bd9Sstevel@tonic-gate "implies %ld sector(s) cannot be allocated.\n"), 20127c478bd9Sstevel@tonic-gate (cgdmin(&sblock, j) - cgbase(&sblock, j)) / sblock.fs_frag, 20137c478bd9Sstevel@tonic-gate i / sblock.fs_frag, i * NSPF(&sblock)); 20146d24e334Svsakar /* 20156d24e334Svsakar * If there is only one cylinder group and that is not even 20166d24e334Svsakar * big enough to hold the inodes, exit. 20176d24e334Svsakar */ 20186d24e334Svsakar if (sblock.fs_ncg == 1) 20196d24e334Svsakar cg_too_small = 1; 20207c478bd9Sstevel@tonic-gate sblock.fs_ncg--; 202138b58fe3SHarold N Shaw- Sun Microsystem sblock.fs_ncyl = sblock.fs_ncg * sblock.fs_cpg; 20227c478bd9Sstevel@tonic-gate sblock.fs_size = fssize_frag = 20237c478bd9Sstevel@tonic-gate (int64_t)sblock.fs_ncyl * (int64_t)sblock.fs_spc / 20247c478bd9Sstevel@tonic-gate (int64_t)NSPF(&sblock); 20257c478bd9Sstevel@tonic-gate warn = 0; 20267c478bd9Sstevel@tonic-gate } 20277c478bd9Sstevel@tonic-gate if (warn && !spc_flag) { 20287c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 20297c478bd9Sstevel@tonic-gate "Warning: %d sector(s) in last cylinder unallocated\n"), 20307c478bd9Sstevel@tonic-gate sblock.fs_spc - (uint32_t)(fssize_frag * NSPF(&sblock) - 20317c478bd9Sstevel@tonic-gate (uint64_t)(sblock.fs_ncyl - 1) * sblock.fs_spc)); 20327c478bd9Sstevel@tonic-gate } 20337c478bd9Sstevel@tonic-gate /* 20347c478bd9Sstevel@tonic-gate * fill in remaining fields of the super block 20357c478bd9Sstevel@tonic-gate */ 20367c478bd9Sstevel@tonic-gate 20377c478bd9Sstevel@tonic-gate /* 20387c478bd9Sstevel@tonic-gate * The csum records are stored in cylinder group 0, starting at 20397c478bd9Sstevel@tonic-gate * cgdmin, the first data block. 20407c478bd9Sstevel@tonic-gate */ 20417c478bd9Sstevel@tonic-gate sblock.fs_csaddr = cgdmin(&sblock, 0); 20427c478bd9Sstevel@tonic-gate sblock.fs_cssize = 20437c478bd9Sstevel@tonic-gate fragroundup(&sblock, sblock.fs_ncg * sizeof (struct csum)); 20447c478bd9Sstevel@tonic-gate i = sblock.fs_bsize / sizeof (struct csum); 20457c478bd9Sstevel@tonic-gate sblock.fs_csmask = ~(i - 1); 20467c478bd9Sstevel@tonic-gate for (sblock.fs_csshift = 0; i > 1; i >>= 1) 20477c478bd9Sstevel@tonic-gate sblock.fs_csshift++; 20487c478bd9Sstevel@tonic-gate fscs = (struct csum *)calloc(1, sblock.fs_cssize); 20497c478bd9Sstevel@tonic-gate 20507c478bd9Sstevel@tonic-gate checksummarysize(); 20517c478bd9Sstevel@tonic-gate if (mtb == 'y') { 20527c478bd9Sstevel@tonic-gate sblock.fs_magic = MTB_UFS_MAGIC; 20537c478bd9Sstevel@tonic-gate sblock.fs_version = MTB_UFS_VERSION_1; 20547c478bd9Sstevel@tonic-gate } else { 20557c478bd9Sstevel@tonic-gate sblock.fs_magic = FS_MAGIC; 20566451fdbcSvsakar if (use_efi_dflts) 20576451fdbcSvsakar sblock.fs_version = UFS_EFISTYLE4NONEFI_VERSION_2; 20586451fdbcSvsakar else 20596451fdbcSvsakar sblock.fs_version = UFS_VERSION_MIN; 20607c478bd9Sstevel@tonic-gate } 20617c478bd9Sstevel@tonic-gate 20627c478bd9Sstevel@tonic-gate if (grow) { 20637c478bd9Sstevel@tonic-gate bcopy((caddr_t)grow_fscs, (caddr_t)fscs, (int)grow_fs_cssize); 20647c478bd9Sstevel@tonic-gate extendsummaryinfo(); 20657c478bd9Sstevel@tonic-gate goto grow40; 20667c478bd9Sstevel@tonic-gate } 20677c478bd9Sstevel@tonic-gate sblock.fs_rotdelay = rotdelay; 20687c478bd9Sstevel@tonic-gate sblock.fs_maxcontig = maxcontig; 20697c478bd9Sstevel@tonic-gate sblock.fs_maxbpg = MAXBLKPG(sblock.fs_bsize); 20707c478bd9Sstevel@tonic-gate 20717c478bd9Sstevel@tonic-gate sblock.fs_rps = rps; 20727c478bd9Sstevel@tonic-gate sblock.fs_cgrotor = 0; 20737c478bd9Sstevel@tonic-gate sblock.fs_cstotal.cs_ndir = 0; 20747c478bd9Sstevel@tonic-gate sblock.fs_cstotal.cs_nbfree = 0; 20757c478bd9Sstevel@tonic-gate sblock.fs_cstotal.cs_nifree = 0; 20767c478bd9Sstevel@tonic-gate sblock.fs_cstotal.cs_nffree = 0; 20777c478bd9Sstevel@tonic-gate sblock.fs_fmod = 0; 20787c478bd9Sstevel@tonic-gate sblock.fs_ronly = 0; 20797c478bd9Sstevel@tonic-gate sblock.fs_time = mkfstime; 20807c478bd9Sstevel@tonic-gate sblock.fs_state = FSOKAY - sblock.fs_time; 20817c478bd9Sstevel@tonic-gate sblock.fs_clean = FSCLEAN; 20827c478bd9Sstevel@tonic-gate grow40: 20837c478bd9Sstevel@tonic-gate 2084355d6bb5Sswilcox /* 2085355d6bb5Sswilcox * If all that's needed is a dump of the superblock we 2086355d6bb5Sswilcox * would use by default, we've got it now. So, splat it 2087355d6bb5Sswilcox * out and leave. 2088355d6bb5Sswilcox */ 2089355d6bb5Sswilcox if (rflag) { 2090355d6bb5Sswilcox dump_sblock(); 2091355d6bb5Sswilcox lockexit(0); 2092355d6bb5Sswilcox } 20937c478bd9Sstevel@tonic-gate /* 20947c478bd9Sstevel@tonic-gate * Dump out summary information about file system. 20957c478bd9Sstevel@tonic-gate */ 20967c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 20977c478bd9Sstevel@tonic-gate "%s:\t%lld sectors in %d cylinders of %d tracks, %d sectors\n"), 20987c478bd9Sstevel@tonic-gate fsys, (uint64_t)sblock.fs_size * NSPF(&sblock), sblock.fs_ncyl, 20997c478bd9Sstevel@tonic-gate sblock.fs_ntrak, sblock.fs_nsect); 21007c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 21017c478bd9Sstevel@tonic-gate "\t%.1fMB in %d cyl groups (%d c/g, %.2fMB/g, %d i/g)\n"), 21027c478bd9Sstevel@tonic-gate (float)sblock.fs_size * sblock.fs_fsize / MB, sblock.fs_ncg, 21037c478bd9Sstevel@tonic-gate sblock.fs_cpg, (float)sblock.fs_fpg * sblock.fs_fsize / MB, 21047c478bd9Sstevel@tonic-gate sblock.fs_ipg); 21056451fdbcSvsakar 21066451fdbcSvsakar tmpbuf = calloc(sblock.fs_ncg / 50 + 500, 1); 21076451fdbcSvsakar if (tmpbuf == NULL) { 21086451fdbcSvsakar perror("calloc"); 21096451fdbcSvsakar lockexit(32); 21106451fdbcSvsakar } 21116d24e334Svsakar if (cg_too_small) { 21126d24e334Svsakar (void) fprintf(stderr, gettext("File system creation failed. " 2113d50c8f90Svsakar "There is only one cylinder group and\nthat is " 2114d50c8f90Svsakar "not even big enough to hold the inodes.\n")); 21156d24e334Svsakar lockexit(32); 21166d24e334Svsakar } 21177c478bd9Sstevel@tonic-gate /* 21187c478bd9Sstevel@tonic-gate * Now build the cylinders group blocks and 21197c478bd9Sstevel@tonic-gate * then print out indices of cylinder groups. 21207c478bd9Sstevel@tonic-gate */ 21216451fdbcSvsakar tprintf(gettext( 21227c478bd9Sstevel@tonic-gate "super-block backups (for fsck -F ufs -o b=#) at:\n")); 21237c478bd9Sstevel@tonic-gate for (width = cylno = 0; cylno < sblock.fs_ncg && cylno < 10; cylno++) { 21247c478bd9Sstevel@tonic-gate if ((grow == 0) || (cylno >= grow_fs_ncg)) 21257c478bd9Sstevel@tonic-gate initcg(cylno); 21267c478bd9Sstevel@tonic-gate num = fsbtodb(&sblock, (uint64_t)cgsblock(&sblock, cylno)); 21276451fdbcSvsakar /* 21286451fdbcSvsakar * If Nflag and if the disk is larger than the CHSLIMIT, 21296451fdbcSvsakar * then sanity test the superblocks before reporting. If there 21306d24e334Svsakar * are too many superblocks which look insane, we have 21316d24e334Svsakar * to retry with alternate logic. If both methods have 21326d24e334Svsakar * failed, then our efforts to arrive at alternate 21336451fdbcSvsakar * superblocks failed, so complain and exit. 21346451fdbcSvsakar */ 21356451fdbcSvsakar if (Nflag && retry) { 2136d50c8f90Svsakar skip_this_sb = 0; 2137d50c8f90Svsakar rdfs((diskaddr_t)num, sbsize, (char *)&altsblock); 2138d50c8f90Svsakar ret = checksblock(altsblock, 1); 2139d50c8f90Svsakar if (ret) { 21406451fdbcSvsakar skip_this_sb = 1; 21416451fdbcSvsakar invalid_sb_cnt++; 2142d50c8f90Svsakar dprintf(("DeBuG checksblock() failed - error :" 2143d50c8f90Svsakar " %d for sb : %llu invalid_sb_cnt : %d\n", 2144d50c8f90Svsakar ret, num, invalid_sb_cnt)); 2145d50c8f90Svsakar } else { 2146d50c8f90Svsakar /* 2147d50c8f90Svsakar * Though the superblock looks sane, verify if 2148d50c8f90Svsakar * the fs_version in the superblock and the 2149d50c8f90Svsakar * logic that we are using to arrive at the 2150d50c8f90Svsakar * superblocks match. 2151d50c8f90Svsakar */ 2152d50c8f90Svsakar if (use_efi_dflts && altsblock.fs_version 2153d50c8f90Svsakar != UFS_EFISTYLE4NONEFI_VERSION_2) { 2154d50c8f90Svsakar skip_this_sb = 1; 2155d50c8f90Svsakar invalid_sb_cnt++; 2156d50c8f90Svsakar } 21576451fdbcSvsakar } 2158d50c8f90Svsakar if (invalid_sb_cnt >= INVALIDSBLIMIT) { 2159d50c8f90Svsakar if (retry > 1) { 2160d50c8f90Svsakar (void) fprintf(stderr, gettext( 2161d50c8f90Svsakar "Error determining alternate " 2162d50c8f90Svsakar "superblock locations\n")); 2163d50c8f90Svsakar free(tmpbuf); 2164d50c8f90Svsakar lockexit(32); 2165d50c8f90Svsakar } 2166d50c8f90Svsakar retry++; 2167d50c8f90Svsakar use_efi_dflts = !use_efi_dflts; 2168d50c8f90Svsakar free(tmpbuf); 2169d50c8f90Svsakar goto retry_alternate_logic; 21706451fdbcSvsakar } 2171d50c8f90Svsakar if (skip_this_sb) 2172d50c8f90Svsakar continue; 21736451fdbcSvsakar } 21747c478bd9Sstevel@tonic-gate (void) sprintf(pbuf, " %llu,", num); 21757c478bd9Sstevel@tonic-gate plen = strlen(pbuf); 21767c478bd9Sstevel@tonic-gate if ((width + plen) > (WIDTH - 1)) { 21777c478bd9Sstevel@tonic-gate width = plen; 21786451fdbcSvsakar tprintf("\n"); 21797c478bd9Sstevel@tonic-gate } else { 21807c478bd9Sstevel@tonic-gate width += plen; 21817c478bd9Sstevel@tonic-gate } 21826451fdbcSvsakar if (Nflag && retry) 21836d24e334Svsakar (void) strncat(tmpbuf, pbuf, strlen(pbuf)); 21846451fdbcSvsakar else 21856451fdbcSvsakar (void) fprintf(stderr, "%s", pbuf); 21867c478bd9Sstevel@tonic-gate } 21876451fdbcSvsakar tprintf("\n"); 21887c478bd9Sstevel@tonic-gate 21897c478bd9Sstevel@tonic-gate remaining_cg = sblock.fs_ncg - cylno; 21907c478bd9Sstevel@tonic-gate 21917c478bd9Sstevel@tonic-gate /* 21927c478bd9Sstevel@tonic-gate * If there are more than 300 cylinder groups still to be 21937c478bd9Sstevel@tonic-gate * initialized, print a "." for every 50 cylinder groups. 21947c478bd9Sstevel@tonic-gate */ 21957c478bd9Sstevel@tonic-gate if (remaining_cg > 300) { 21966451fdbcSvsakar tprintf(gettext("Initializing cylinder groups:\n")); 21977c478bd9Sstevel@tonic-gate do_dot = 1; 21987c478bd9Sstevel@tonic-gate } 21997c478bd9Sstevel@tonic-gate 22007c478bd9Sstevel@tonic-gate /* 22017c478bd9Sstevel@tonic-gate * Now initialize all cylinder groups between the first ten 22027c478bd9Sstevel@tonic-gate * and the last ten. 22037c478bd9Sstevel@tonic-gate * 22047c478bd9Sstevel@tonic-gate * If the number of cylinder groups was less than 10, all of the 22057c478bd9Sstevel@tonic-gate * cylinder group offsets would have printed in the last loop 22067c478bd9Sstevel@tonic-gate * and cylno will already be equal to sblock.fs_ncg and so this 22077c478bd9Sstevel@tonic-gate * loop will not be entered. If there are less than 20 cylinder 22087c478bd9Sstevel@tonic-gate * groups, cylno is already less than fs_ncg - 10, so this loop 22097c478bd9Sstevel@tonic-gate * won't be entered in that case either. 22107c478bd9Sstevel@tonic-gate */ 22117c478bd9Sstevel@tonic-gate 22127c478bd9Sstevel@tonic-gate i = 0; 22137c478bd9Sstevel@tonic-gate for (; cylno < sblock.fs_ncg - 10; cylno++) { 22147c478bd9Sstevel@tonic-gate if ((grow == 0) || (cylno >= grow_fs_ncg)) 22157c478bd9Sstevel@tonic-gate initcg(cylno); 22167c478bd9Sstevel@tonic-gate if (do_dot && cylno % 50 == 0) { 22176451fdbcSvsakar tprintf("."); 22187c478bd9Sstevel@tonic-gate i++; 22197c478bd9Sstevel@tonic-gate if (i == WIDTH - 1) { 22206451fdbcSvsakar tprintf("\n"); 22217c478bd9Sstevel@tonic-gate i = 0; 22227c478bd9Sstevel@tonic-gate } 22237c478bd9Sstevel@tonic-gate } 22247c478bd9Sstevel@tonic-gate } 22257c478bd9Sstevel@tonic-gate 22267c478bd9Sstevel@tonic-gate /* 22277c478bd9Sstevel@tonic-gate * Now print the cylinder group offsets for the last 10 22287c478bd9Sstevel@tonic-gate * cylinder groups, if any are left. 22297c478bd9Sstevel@tonic-gate */ 22307c478bd9Sstevel@tonic-gate 22317c478bd9Sstevel@tonic-gate if (do_dot) { 22326451fdbcSvsakar tprintf(gettext( 22337c478bd9Sstevel@tonic-gate "\nsuper-block backups for last 10 cylinder groups at:\n")); 22347c478bd9Sstevel@tonic-gate } 22357c478bd9Sstevel@tonic-gate for (width = 0; cylno < sblock.fs_ncg; cylno++) { 22367c478bd9Sstevel@tonic-gate if ((grow == 0) || (cylno >= grow_fs_ncg)) 22377c478bd9Sstevel@tonic-gate initcg(cylno); 22387c478bd9Sstevel@tonic-gate num = fsbtodb(&sblock, (uint64_t)cgsblock(&sblock, cylno)); 22396451fdbcSvsakar if (Nflag && retry) { 2240d50c8f90Svsakar skip_this_sb = 0; 2241d50c8f90Svsakar rdfs((diskaddr_t)num, sbsize, (char *)&altsblock); 2242d50c8f90Svsakar ret = checksblock(altsblock, 1); 2243d50c8f90Svsakar if (ret) { 22446451fdbcSvsakar skip_this_sb = 1; 22456451fdbcSvsakar invalid_sb_cnt++; 2246d50c8f90Svsakar dprintf(("DeBuG checksblock() failed - error :" 2247d50c8f90Svsakar " %d for sb : %llu invalid_sb_cnt : %d\n", 2248d50c8f90Svsakar ret, num, invalid_sb_cnt)); 2249d50c8f90Svsakar } else { 2250d50c8f90Svsakar /* 2251d50c8f90Svsakar * Though the superblock looks sane, verify if 2252d50c8f90Svsakar * the fs_version in the superblock and the 2253d50c8f90Svsakar * logic that we are using to arrive at the 2254d50c8f90Svsakar * superblocks match. 2255d50c8f90Svsakar */ 2256d50c8f90Svsakar if (use_efi_dflts && altsblock.fs_version 2257d50c8f90Svsakar != UFS_EFISTYLE4NONEFI_VERSION_2) { 2258d50c8f90Svsakar skip_this_sb = 1; 2259d50c8f90Svsakar invalid_sb_cnt++; 2260d50c8f90Svsakar } 22616451fdbcSvsakar } 2262d50c8f90Svsakar if (invalid_sb_cnt >= INVALIDSBLIMIT) { 2263d50c8f90Svsakar if (retry > 1) { 2264d50c8f90Svsakar (void) fprintf(stderr, gettext( 2265d50c8f90Svsakar "Error determining alternate " 2266d50c8f90Svsakar "superblock locations\n")); 2267d50c8f90Svsakar free(tmpbuf); 2268d50c8f90Svsakar lockexit(32); 2269d50c8f90Svsakar } 2270d50c8f90Svsakar retry++; 2271d50c8f90Svsakar use_efi_dflts = !use_efi_dflts; 2272d50c8f90Svsakar free(tmpbuf); 2273d50c8f90Svsakar goto retry_alternate_logic; 22746451fdbcSvsakar } 2275d50c8f90Svsakar if (skip_this_sb) 2276d50c8f90Svsakar continue; 22776451fdbcSvsakar } 22786451fdbcSvsakar /* Don't print ',' for the last superblock */ 22796451fdbcSvsakar if (cylno == sblock.fs_ncg-1) 22806451fdbcSvsakar (void) sprintf(pbuf, " %llu", num); 22816451fdbcSvsakar else 22826451fdbcSvsakar (void) sprintf(pbuf, " %llu,", num); 22837c478bd9Sstevel@tonic-gate plen = strlen(pbuf); 22847c478bd9Sstevel@tonic-gate if ((width + plen) > (WIDTH - 1)) { 22857c478bd9Sstevel@tonic-gate width = plen; 22866451fdbcSvsakar tprintf("\n"); 22877c478bd9Sstevel@tonic-gate } else { 22887c478bd9Sstevel@tonic-gate width += plen; 22897c478bd9Sstevel@tonic-gate } 22906451fdbcSvsakar if (Nflag && retry) 22916d24e334Svsakar (void) strncat(tmpbuf, pbuf, strlen(pbuf)); 22926451fdbcSvsakar else 22936451fdbcSvsakar (void) fprintf(stderr, "%s", pbuf); 22947c478bd9Sstevel@tonic-gate } 22956451fdbcSvsakar tprintf("\n"); 22966451fdbcSvsakar if (Nflag) { 22976451fdbcSvsakar if (retry) 22986d24e334Svsakar (void) fprintf(stderr, "%s", tmpbuf); 22996451fdbcSvsakar free(tmpbuf); 23007c478bd9Sstevel@tonic-gate lockexit(0); 23016451fdbcSvsakar } 23026451fdbcSvsakar 23036451fdbcSvsakar free(tmpbuf); 23047c478bd9Sstevel@tonic-gate if (grow) 23057c478bd9Sstevel@tonic-gate goto grow50; 23067c478bd9Sstevel@tonic-gate 23077c478bd9Sstevel@tonic-gate /* 23087c478bd9Sstevel@tonic-gate * Now construct the initial file system, 23097c478bd9Sstevel@tonic-gate * then write out the super-block. 23107c478bd9Sstevel@tonic-gate */ 23117c478bd9Sstevel@tonic-gate fsinit(); 23127c478bd9Sstevel@tonic-gate grow50: 23137c478bd9Sstevel@tonic-gate /* 23147c478bd9Sstevel@tonic-gate * write the superblock and csum information 23157c478bd9Sstevel@tonic-gate */ 23167c478bd9Sstevel@tonic-gate wtsb(); 23177c478bd9Sstevel@tonic-gate 23187c478bd9Sstevel@tonic-gate /* 23197c478bd9Sstevel@tonic-gate * extend the last cylinder group in the original file system 23207c478bd9Sstevel@tonic-gate */ 23217c478bd9Sstevel@tonic-gate if (grow) { 23227c478bd9Sstevel@tonic-gate extendcg(grow_fs_ncg-1); 23237c478bd9Sstevel@tonic-gate wtsb(); 23247c478bd9Sstevel@tonic-gate } 23257c478bd9Sstevel@tonic-gate 23267c478bd9Sstevel@tonic-gate /* 23277c478bd9Sstevel@tonic-gate * Write out the duplicate super blocks to the first 10 23287c478bd9Sstevel@tonic-gate * cylinder groups (or fewer, if there are fewer than 10 23297c478bd9Sstevel@tonic-gate * cylinder groups). 23307c478bd9Sstevel@tonic-gate */ 23317c478bd9Sstevel@tonic-gate for (cylno = 0; cylno < sblock.fs_ncg && cylno < 10; cylno++) 23327c478bd9Sstevel@tonic-gate awtfs(fsbtodb(&sblock, (uint64_t)cgsblock(&sblock, cylno)), 23337c478bd9Sstevel@tonic-gate (int)sbsize, (char *)&sblock, SAVE); 23347c478bd9Sstevel@tonic-gate 23357c478bd9Sstevel@tonic-gate /* 23367c478bd9Sstevel@tonic-gate * Now write out duplicate super blocks to the remaining 23377c478bd9Sstevel@tonic-gate * cylinder groups. In the case of multi-terabyte file 23387c478bd9Sstevel@tonic-gate * systems, just write out the super block to the last ten 23397c478bd9Sstevel@tonic-gate * cylinder groups (or however many are left). 23407c478bd9Sstevel@tonic-gate */ 23417c478bd9Sstevel@tonic-gate if (mtb == 'y') { 23427c478bd9Sstevel@tonic-gate if (sblock.fs_ncg <= 10) 23437c478bd9Sstevel@tonic-gate cylno = sblock.fs_ncg; 23447c478bd9Sstevel@tonic-gate else if (sblock.fs_ncg <= 20) 23457c478bd9Sstevel@tonic-gate cylno = 10; 23467c478bd9Sstevel@tonic-gate else 23477c478bd9Sstevel@tonic-gate cylno = sblock.fs_ncg - 10; 23487c478bd9Sstevel@tonic-gate } 23497c478bd9Sstevel@tonic-gate 23507c478bd9Sstevel@tonic-gate for (; cylno < sblock.fs_ncg; cylno++) 23517c478bd9Sstevel@tonic-gate awtfs(fsbtodb(&sblock, (uint64_t)cgsblock(&sblock, cylno)), 23527c478bd9Sstevel@tonic-gate (int)sbsize, (char *)&sblock, SAVE); 23537c478bd9Sstevel@tonic-gate 23547c478bd9Sstevel@tonic-gate /* 23557c478bd9Sstevel@tonic-gate * Flush out all the AIO writes we've done. It's not 23567c478bd9Sstevel@tonic-gate * necessary to do this explicitly, but it's the only 23577c478bd9Sstevel@tonic-gate * way to report any errors from those writes. 23587c478bd9Sstevel@tonic-gate */ 23597c478bd9Sstevel@tonic-gate flush_writes(); 23607c478bd9Sstevel@tonic-gate 23617c478bd9Sstevel@tonic-gate /* 23627c478bd9Sstevel@tonic-gate * set clean flag 23637c478bd9Sstevel@tonic-gate */ 23647c478bd9Sstevel@tonic-gate if (grow) 23657c478bd9Sstevel@tonic-gate sblock.fs_clean = grow_fs_clean; 23667c478bd9Sstevel@tonic-gate else 23677c478bd9Sstevel@tonic-gate sblock.fs_clean = FSCLEAN; 23687c478bd9Sstevel@tonic-gate sblock.fs_time = mkfstime; 23697c478bd9Sstevel@tonic-gate sblock.fs_state = FSOKAY - sblock.fs_time; 23707c478bd9Sstevel@tonic-gate wtfs((diskaddr_t)(SBOFF / sectorsize), sbsize, (char *)&sblock); 23717c478bd9Sstevel@tonic-gate isbad = 0; 23727c478bd9Sstevel@tonic-gate 23737c478bd9Sstevel@tonic-gate if (fsync(fso) == -1) { 23747c478bd9Sstevel@tonic-gate saverr = errno; 23757c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 23767c478bd9Sstevel@tonic-gate gettext("mkfs: fsync failed on write disk: %s\n"), 23777c478bd9Sstevel@tonic-gate strerror(saverr)); 23787c478bd9Sstevel@tonic-gate /* we're just cleaning up, so keep going */ 23797c478bd9Sstevel@tonic-gate } 23807c478bd9Sstevel@tonic-gate if (close(fsi) == -1) { 23817c478bd9Sstevel@tonic-gate saverr = errno; 23827c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 23837c478bd9Sstevel@tonic-gate gettext("mkfs: close failed on read disk: %s\n"), 23847c478bd9Sstevel@tonic-gate strerror(saverr)); 23857c478bd9Sstevel@tonic-gate /* we're just cleaning up, so keep going */ 23867c478bd9Sstevel@tonic-gate } 23877c478bd9Sstevel@tonic-gate if (close(fso) == -1) { 23887c478bd9Sstevel@tonic-gate saverr = errno; 23897c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 23907c478bd9Sstevel@tonic-gate gettext("mkfs: close failed on write disk: %s\n"), 23917c478bd9Sstevel@tonic-gate strerror(saverr)); 23927c478bd9Sstevel@tonic-gate /* we're just cleaning up, so keep going */ 23937c478bd9Sstevel@tonic-gate } 23947c478bd9Sstevel@tonic-gate fsi = fso = -1; 2395029b4de8Sswilcox 23967c478bd9Sstevel@tonic-gate #ifndef STANDALONE 23977c478bd9Sstevel@tonic-gate lockexit(0); 23987c478bd9Sstevel@tonic-gate #endif 2399029b4de8Sswilcox 2400029b4de8Sswilcox return (0); 24017c478bd9Sstevel@tonic-gate } 24027c478bd9Sstevel@tonic-gate 24037c478bd9Sstevel@tonic-gate /* 24047c478bd9Sstevel@tonic-gate * Figure out how big the partition we're dealing with is. 24057c478bd9Sstevel@tonic-gate * The value returned is in disk blocks (sectors); 24067c478bd9Sstevel@tonic-gate */ 24077c478bd9Sstevel@tonic-gate static diskaddr_t 24087c478bd9Sstevel@tonic-gate get_max_size(int fd) 24097c478bd9Sstevel@tonic-gate { 2410342440ecSPrasad Singamsetty struct extvtoc vtoc; 24117c478bd9Sstevel@tonic-gate dk_gpt_t *efi_vtoc; 24127c478bd9Sstevel@tonic-gate diskaddr_t slicesize; 24137c478bd9Sstevel@tonic-gate 2414342440ecSPrasad Singamsetty int index = read_extvtoc(fd, &vtoc); 24157c478bd9Sstevel@tonic-gate 24166451fdbcSvsakar if (index >= 0) { 24176451fdbcSvsakar label_type = LABEL_TYPE_VTOC; 24186451fdbcSvsakar } else { 24197c478bd9Sstevel@tonic-gate if (index == VT_ENOTSUP || index == VT_ERROR) { 24207c478bd9Sstevel@tonic-gate /* it might be an EFI label */ 24217c478bd9Sstevel@tonic-gate index = efi_alloc_and_read(fd, &efi_vtoc); 24226451fdbcSvsakar label_type = LABEL_TYPE_EFI; 24237c478bd9Sstevel@tonic-gate } 24247c478bd9Sstevel@tonic-gate } 24257c478bd9Sstevel@tonic-gate 24267c478bd9Sstevel@tonic-gate if (index < 0) { 24277c478bd9Sstevel@tonic-gate switch (index) { 24287c478bd9Sstevel@tonic-gate case VT_ERROR: 24297c478bd9Sstevel@tonic-gate break; 24307c478bd9Sstevel@tonic-gate case VT_EIO: 24317c478bd9Sstevel@tonic-gate errno = EIO; 24327c478bd9Sstevel@tonic-gate break; 24337c478bd9Sstevel@tonic-gate case VT_EINVAL: 24347c478bd9Sstevel@tonic-gate errno = EINVAL; 24357c478bd9Sstevel@tonic-gate } 24367c478bd9Sstevel@tonic-gate perror(gettext("Can not determine partition size")); 24377c478bd9Sstevel@tonic-gate lockexit(32); 24387c478bd9Sstevel@tonic-gate } 24397c478bd9Sstevel@tonic-gate 24406451fdbcSvsakar if (label_type == LABEL_TYPE_EFI) { 24417c478bd9Sstevel@tonic-gate slicesize = efi_vtoc->efi_parts[index].p_size; 24427c478bd9Sstevel@tonic-gate efi_free(efi_vtoc); 24437c478bd9Sstevel@tonic-gate } else { 24447c478bd9Sstevel@tonic-gate /* 24457c478bd9Sstevel@tonic-gate * In the vtoc struct, p_size is a 32-bit signed quantity. 24467c478bd9Sstevel@tonic-gate * In the dk_gpt struct (efi's version of the vtoc), p_size 24477c478bd9Sstevel@tonic-gate * is an unsigned 64-bit quantity. By casting the vtoc's 24487c478bd9Sstevel@tonic-gate * psize to an unsigned 32-bit quantity, it will be copied 24497c478bd9Sstevel@tonic-gate * to 'slicesize' (an unsigned 64-bit diskaddr_t) without 24507c478bd9Sstevel@tonic-gate * sign extension. 24517c478bd9Sstevel@tonic-gate */ 24527c478bd9Sstevel@tonic-gate 24537c478bd9Sstevel@tonic-gate slicesize = (uint32_t)vtoc.v_part[index].p_size; 24547c478bd9Sstevel@tonic-gate } 24557c478bd9Sstevel@tonic-gate 24566451fdbcSvsakar dprintf(("DeBuG get_max_size index = %d, p_size = %lld, dolimit = %d\n", 24576451fdbcSvsakar index, slicesize, (slicesize > FS_MAX))); 24587c478bd9Sstevel@tonic-gate 24597c478bd9Sstevel@tonic-gate /* 24607c478bd9Sstevel@tonic-gate * The next line limits a UFS file system to the maximum 24617c478bd9Sstevel@tonic-gate * supported size. 24627c478bd9Sstevel@tonic-gate */ 24637c478bd9Sstevel@tonic-gate 24647c478bd9Sstevel@tonic-gate if (slicesize > FS_MAX) 24657c478bd9Sstevel@tonic-gate return (FS_MAX); 24667c478bd9Sstevel@tonic-gate return (slicesize); 24677c478bd9Sstevel@tonic-gate } 24687c478bd9Sstevel@tonic-gate 24697c478bd9Sstevel@tonic-gate static long 24707c478bd9Sstevel@tonic-gate get_max_track_size(int fd) 24717c478bd9Sstevel@tonic-gate { 24727c478bd9Sstevel@tonic-gate struct dk_cinfo ci; 24737c478bd9Sstevel@tonic-gate long track_size = -1; 24747c478bd9Sstevel@tonic-gate 24757c478bd9Sstevel@tonic-gate if (ioctl(fd, DKIOCINFO, &ci) == 0) { 24767c478bd9Sstevel@tonic-gate track_size = ci.dki_maxtransfer * DEV_BSIZE; 24777c478bd9Sstevel@tonic-gate } 24787c478bd9Sstevel@tonic-gate 24797c478bd9Sstevel@tonic-gate if ((track_size < 0)) { 24807c478bd9Sstevel@tonic-gate int error = 0; 24817c478bd9Sstevel@tonic-gate int maxphys; 24827c478bd9Sstevel@tonic-gate int gotit = 0; 24837c478bd9Sstevel@tonic-gate 24847c478bd9Sstevel@tonic-gate gotit = fsgetmaxphys(&maxphys, &error); 24857c478bd9Sstevel@tonic-gate if (gotit) { 24867c478bd9Sstevel@tonic-gate track_size = MIN(MB, maxphys); 24877c478bd9Sstevel@tonic-gate } else { 24887c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 24897c478bd9Sstevel@tonic-gate "Warning: Could not get system value for maxphys. The value for\n" 24907c478bd9Sstevel@tonic-gate "maxcontig will default to 1MB.\n")); 24917c478bd9Sstevel@tonic-gate track_size = MB; 24927c478bd9Sstevel@tonic-gate } 24937c478bd9Sstevel@tonic-gate } 24947c478bd9Sstevel@tonic-gate return (track_size); 24957c478bd9Sstevel@tonic-gate } 24967c478bd9Sstevel@tonic-gate 24977c478bd9Sstevel@tonic-gate /* 24987c478bd9Sstevel@tonic-gate * Initialize a cylinder group. 24997c478bd9Sstevel@tonic-gate */ 25007c478bd9Sstevel@tonic-gate static void 25017c478bd9Sstevel@tonic-gate initcg(int cylno) 25027c478bd9Sstevel@tonic-gate { 25037c478bd9Sstevel@tonic-gate diskaddr_t cbase, d; 25047c478bd9Sstevel@tonic-gate diskaddr_t dlower; /* last data block before cg metadata */ 25057c478bd9Sstevel@tonic-gate diskaddr_t dupper; /* first data block after cg metadata */ 25067c478bd9Sstevel@tonic-gate diskaddr_t dmax; 25077c478bd9Sstevel@tonic-gate int64_t i; 25087c478bd9Sstevel@tonic-gate struct csum *cs; 25097c478bd9Sstevel@tonic-gate struct dinode *inode_buffer; 25107c478bd9Sstevel@tonic-gate int size; 25117c478bd9Sstevel@tonic-gate 25127c478bd9Sstevel@tonic-gate /* 25137c478bd9Sstevel@tonic-gate * Variables used to store intermediate results as a part of 25147c478bd9Sstevel@tonic-gate * the internal implementation of the cbtocylno() macros. 25157c478bd9Sstevel@tonic-gate */ 25167c478bd9Sstevel@tonic-gate diskaddr_t bno; /* UFS block number (not sector number) */ 25177c478bd9Sstevel@tonic-gate int cbcylno; /* current cylinder number */ 25187c478bd9Sstevel@tonic-gate int cbcylno_sect; /* sector offset within cylinder */ 25197c478bd9Sstevel@tonic-gate int cbsect_incr; /* amount to increment sector offset */ 25207c478bd9Sstevel@tonic-gate 25217c478bd9Sstevel@tonic-gate /* 25227c478bd9Sstevel@tonic-gate * Variables used to store intermediate results as a part of 25237c478bd9Sstevel@tonic-gate * the internal implementation of the cbtorpos() macros. 25247c478bd9Sstevel@tonic-gate */ 25257c478bd9Sstevel@tonic-gate short *cgblks; /* pointer to array of free blocks in cg */ 25267c478bd9Sstevel@tonic-gate int trackrpos; /* tmp variable for rotation position */ 25277c478bd9Sstevel@tonic-gate int trackoff; /* offset within a track */ 25287c478bd9Sstevel@tonic-gate int trackoff_incr; /* amount to increment trackoff */ 25297c478bd9Sstevel@tonic-gate int rpos; /* rotation position of current block */ 25307c478bd9Sstevel@tonic-gate int rpos_incr; /* amount to increment rpos per block */ 25317c478bd9Sstevel@tonic-gate 25327c478bd9Sstevel@tonic-gate union cgun *icgun; /* local pointer to a cg summary block */ 25337c478bd9Sstevel@tonic-gate #define icg (icgun->cg) 25347c478bd9Sstevel@tonic-gate 25357c478bd9Sstevel@tonic-gate icgun = (union cgun *)getbuf(&cgsumbuf, sizeof (union cgun)); 25367c478bd9Sstevel@tonic-gate 25377c478bd9Sstevel@tonic-gate /* 25387c478bd9Sstevel@tonic-gate * Determine block bounds for cylinder group. 25397c478bd9Sstevel@tonic-gate * Allow space for super block summary information in first 25407c478bd9Sstevel@tonic-gate * cylinder group. 25417c478bd9Sstevel@tonic-gate */ 25427c478bd9Sstevel@tonic-gate cbase = cgbase(&sblock, cylno); 25437c478bd9Sstevel@tonic-gate dmax = cbase + sblock.fs_fpg; 25447c478bd9Sstevel@tonic-gate if (dmax > sblock.fs_size) /* last cg may be smaller than normal */ 25457c478bd9Sstevel@tonic-gate dmax = sblock.fs_size; 25467c478bd9Sstevel@tonic-gate dlower = cgsblock(&sblock, cylno) - cbase; 25477c478bd9Sstevel@tonic-gate dupper = cgdmin(&sblock, cylno) - cbase; 25487c478bd9Sstevel@tonic-gate if (cylno == 0) 25497c478bd9Sstevel@tonic-gate dupper += howmany(sblock.fs_cssize, sblock.fs_fsize); 25507c478bd9Sstevel@tonic-gate cs = fscs + cylno; 25517c478bd9Sstevel@tonic-gate icg.cg_time = mkfstime; 25527c478bd9Sstevel@tonic-gate icg.cg_magic = CG_MAGIC; 25537c478bd9Sstevel@tonic-gate icg.cg_cgx = cylno; 2554355d6bb5Sswilcox /* last one gets whatever's left */ 25557c478bd9Sstevel@tonic-gate if (cylno == sblock.fs_ncg - 1) 2556355d6bb5Sswilcox icg.cg_ncyl = sblock.fs_ncyl - (sblock.fs_cpg * cylno); 25577c478bd9Sstevel@tonic-gate else 25587c478bd9Sstevel@tonic-gate icg.cg_ncyl = sblock.fs_cpg; 25597c478bd9Sstevel@tonic-gate icg.cg_niblk = sblock.fs_ipg; 25607c478bd9Sstevel@tonic-gate icg.cg_ndblk = dmax - cbase; 25617c478bd9Sstevel@tonic-gate icg.cg_cs.cs_ndir = 0; 25627c478bd9Sstevel@tonic-gate icg.cg_cs.cs_nffree = 0; 25637c478bd9Sstevel@tonic-gate icg.cg_cs.cs_nbfree = 0; 25647c478bd9Sstevel@tonic-gate icg.cg_cs.cs_nifree = 0; 25657c478bd9Sstevel@tonic-gate icg.cg_rotor = 0; 25667c478bd9Sstevel@tonic-gate icg.cg_frotor = 0; 25677c478bd9Sstevel@tonic-gate icg.cg_irotor = 0; 25687c478bd9Sstevel@tonic-gate icg.cg_btotoff = &icg.cg_space[0] - (uchar_t *)(&icg.cg_link); 25697c478bd9Sstevel@tonic-gate icg.cg_boff = icg.cg_btotoff + sblock.fs_cpg * sizeof (long); 25707c478bd9Sstevel@tonic-gate icg.cg_iusedoff = icg.cg_boff + 2571d50c8f90Svsakar sblock.fs_cpg * sblock.fs_nrpos * sizeof (short); 25727c478bd9Sstevel@tonic-gate icg.cg_freeoff = icg.cg_iusedoff + howmany(sblock.fs_ipg, NBBY); 25737c478bd9Sstevel@tonic-gate icg.cg_nextfreeoff = icg.cg_freeoff + 2574d50c8f90Svsakar howmany(sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock), NBBY); 25757c478bd9Sstevel@tonic-gate for (i = 0; i < sblock.fs_frag; i++) { 25767c478bd9Sstevel@tonic-gate icg.cg_frsum[i] = 0; 25777c478bd9Sstevel@tonic-gate } 25787c478bd9Sstevel@tonic-gate bzero((caddr_t)cg_inosused(&icg), icg.cg_freeoff - icg.cg_iusedoff); 25797c478bd9Sstevel@tonic-gate icg.cg_cs.cs_nifree += sblock.fs_ipg; 25807c478bd9Sstevel@tonic-gate if (cylno == 0) 25817c478bd9Sstevel@tonic-gate for (i = 0; i < UFSROOTINO; i++) { 25827c478bd9Sstevel@tonic-gate setbit(cg_inosused(&icg), i); 25837c478bd9Sstevel@tonic-gate icg.cg_cs.cs_nifree--; 25847c478bd9Sstevel@tonic-gate } 25857c478bd9Sstevel@tonic-gate 25867c478bd9Sstevel@tonic-gate /* 25877c478bd9Sstevel@tonic-gate * Initialize all the inodes in the cylinder group using 25887c478bd9Sstevel@tonic-gate * random numbers. 25897c478bd9Sstevel@tonic-gate */ 25907c478bd9Sstevel@tonic-gate size = sblock.fs_ipg * sizeof (struct dinode); 25917c478bd9Sstevel@tonic-gate inode_buffer = (struct dinode *)getbuf(&inodebuf, size); 25927c478bd9Sstevel@tonic-gate 25937c478bd9Sstevel@tonic-gate for (i = 0; i < sblock.fs_ipg; i++) { 25947c478bd9Sstevel@tonic-gate IRANDOMIZE(&(inode_buffer[i].di_ic)); 25957c478bd9Sstevel@tonic-gate } 25967c478bd9Sstevel@tonic-gate 25977c478bd9Sstevel@tonic-gate /* 25987c478bd9Sstevel@tonic-gate * Write all inodes in a single write for performance. 25997c478bd9Sstevel@tonic-gate */ 26007c478bd9Sstevel@tonic-gate awtfs(fsbtodb(&sblock, (uint64_t)cgimin(&sblock, cylno)), (int)size, 26017c478bd9Sstevel@tonic-gate (char *)inode_buffer, RELEASE); 26027c478bd9Sstevel@tonic-gate 26037c478bd9Sstevel@tonic-gate bzero((caddr_t)cg_blktot(&icg), icg.cg_boff - icg.cg_btotoff); 26047c478bd9Sstevel@tonic-gate bzero((caddr_t)cg_blks(&sblock, &icg, 0), 26057c478bd9Sstevel@tonic-gate icg.cg_iusedoff - icg.cg_boff); 26067c478bd9Sstevel@tonic-gate bzero((caddr_t)cg_blksfree(&icg), icg.cg_nextfreeoff - icg.cg_freeoff); 26077c478bd9Sstevel@tonic-gate 26087c478bd9Sstevel@tonic-gate if (cylno > 0) { 26097c478bd9Sstevel@tonic-gate for (d = 0; d < dlower; d += sblock.fs_frag) { 26107c478bd9Sstevel@tonic-gate setblock(&sblock, cg_blksfree(&icg), d/sblock.fs_frag); 26117c478bd9Sstevel@tonic-gate icg.cg_cs.cs_nbfree++; 26127c478bd9Sstevel@tonic-gate cg_blktot(&icg)[cbtocylno(&sblock, d)]++; 26137c478bd9Sstevel@tonic-gate cg_blks(&sblock, &icg, cbtocylno(&sblock, d)) 26147c478bd9Sstevel@tonic-gate [cbtorpos(&sblock, d)]++; 26157c478bd9Sstevel@tonic-gate } 26167c478bd9Sstevel@tonic-gate sblock.fs_dsize += dlower; 26177c478bd9Sstevel@tonic-gate } 26187c478bd9Sstevel@tonic-gate sblock.fs_dsize += icg.cg_ndblk - dupper; 26197c478bd9Sstevel@tonic-gate if ((i = dupper % sblock.fs_frag) != 0) { 26207c478bd9Sstevel@tonic-gate icg.cg_frsum[sblock.fs_frag - i]++; 26217c478bd9Sstevel@tonic-gate for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) { 26227c478bd9Sstevel@tonic-gate setbit(cg_blksfree(&icg), dupper); 26237c478bd9Sstevel@tonic-gate icg.cg_cs.cs_nffree++; 26247c478bd9Sstevel@tonic-gate } 26257c478bd9Sstevel@tonic-gate } 26267c478bd9Sstevel@tonic-gate 26277c478bd9Sstevel@tonic-gate /* 26287c478bd9Sstevel@tonic-gate * WARNING: The following code is somewhat confusing, but 26297c478bd9Sstevel@tonic-gate * results in a substantial performance improvement in mkfs. 26307c478bd9Sstevel@tonic-gate * 26317c478bd9Sstevel@tonic-gate * Instead of using cbtocylno() and cbtorpos() macros, we 26327c478bd9Sstevel@tonic-gate * keep track of all the intermediate state of those macros 26337c478bd9Sstevel@tonic-gate * in some variables. This allows simple addition to be 26347c478bd9Sstevel@tonic-gate * done to calculate the results as we step through the 26357c478bd9Sstevel@tonic-gate * blocks in an orderly fashion instead of the slower 26367c478bd9Sstevel@tonic-gate * multiplication and division the macros are forced to 26377c478bd9Sstevel@tonic-gate * used so they can support random input. (Multiplication, 26387c478bd9Sstevel@tonic-gate * division, and remainder operations typically take about 26397c478bd9Sstevel@tonic-gate * 10x as many processor cycles as other operations.) 26407c478bd9Sstevel@tonic-gate * 26417c478bd9Sstevel@tonic-gate * The basic idea is to take code: 26427c478bd9Sstevel@tonic-gate * 26437c478bd9Sstevel@tonic-gate * for (x = starting_x; x < max; x++) 26447c478bd9Sstevel@tonic-gate * y = (x * c) / z 26457c478bd9Sstevel@tonic-gate * 26467c478bd9Sstevel@tonic-gate * and rewrite it to take advantage of the fact that 26477c478bd9Sstevel@tonic-gate * the variable x is incrementing in an orderly way: 26487c478bd9Sstevel@tonic-gate * 26497c478bd9Sstevel@tonic-gate * intermediate = starting_x * c 26507c478bd9Sstevel@tonic-gate * yval = intermediate / z 26517c478bd9Sstevel@tonic-gate * for (x = starting_x; x < max; x++) { 26527c478bd9Sstevel@tonic-gate * y = yval; 26537c478bd9Sstevel@tonic-gate * intermediate += c 26547c478bd9Sstevel@tonic-gate * if (intermediate > z) { 26557c478bd9Sstevel@tonic-gate * yval++; 26567c478bd9Sstevel@tonic-gate * intermediate -= z 26577c478bd9Sstevel@tonic-gate * } 26587c478bd9Sstevel@tonic-gate * } 26597c478bd9Sstevel@tonic-gate * 26607c478bd9Sstevel@tonic-gate * Performance has improved as much as 4X using this code. 26617c478bd9Sstevel@tonic-gate */ 26627c478bd9Sstevel@tonic-gate 26637c478bd9Sstevel@tonic-gate /* 26647c478bd9Sstevel@tonic-gate * Initialize the starting points for all the cbtocylno() 26657c478bd9Sstevel@tonic-gate * macro variables and figure out the increments needed each 26667c478bd9Sstevel@tonic-gate * time through the loop. 26677c478bd9Sstevel@tonic-gate */ 26687c478bd9Sstevel@tonic-gate cbcylno_sect = dupper * NSPF(&sblock); 26697c478bd9Sstevel@tonic-gate cbsect_incr = sblock.fs_frag * NSPF(&sblock); 26707c478bd9Sstevel@tonic-gate cbcylno = cbcylno_sect / sblock.fs_spc; 26717c478bd9Sstevel@tonic-gate cbcylno_sect %= sblock.fs_spc; 26727c478bd9Sstevel@tonic-gate cgblks = cg_blks(&sblock, &icg, cbcylno); 26737c478bd9Sstevel@tonic-gate bno = dupper / sblock.fs_frag; 26747c478bd9Sstevel@tonic-gate 26757c478bd9Sstevel@tonic-gate /* 26767c478bd9Sstevel@tonic-gate * Initialize the starting points for all the cbtorpos() 26777c478bd9Sstevel@tonic-gate * macro variables and figure out the increments needed each 26787c478bd9Sstevel@tonic-gate * time through the loop. 26797c478bd9Sstevel@tonic-gate * 26807c478bd9Sstevel@tonic-gate * It's harder to simplify the cbtorpos() macro if there were 26817c478bd9Sstevel@tonic-gate * alternate sectors specified (or if they previously existed 26827c478bd9Sstevel@tonic-gate * in the growfs case). Since this is rare, we just revert to 26837c478bd9Sstevel@tonic-gate * using the macros in this case and skip the variable setup. 26847c478bd9Sstevel@tonic-gate */ 26857c478bd9Sstevel@tonic-gate if (!spc_flag) { 26867c478bd9Sstevel@tonic-gate trackrpos = (cbcylno_sect % sblock.fs_nsect) * sblock.fs_nrpos; 26877c478bd9Sstevel@tonic-gate rpos = trackrpos / sblock.fs_nsect; 26887c478bd9Sstevel@tonic-gate trackoff = trackrpos % sblock.fs_nsect; 26897c478bd9Sstevel@tonic-gate trackoff_incr = cbsect_incr * sblock.fs_nrpos; 26907c478bd9Sstevel@tonic-gate rpos_incr = (trackoff_incr / sblock.fs_nsect) % sblock.fs_nrpos; 26917c478bd9Sstevel@tonic-gate trackoff_incr = trackoff_incr % sblock.fs_nsect; 26927c478bd9Sstevel@tonic-gate } 26937c478bd9Sstevel@tonic-gate 26947c478bd9Sstevel@tonic-gate /* 26957c478bd9Sstevel@tonic-gate * Loop through all the blocks, marking them free and 26967c478bd9Sstevel@tonic-gate * updating totals kept in the superblock and cg summary. 26977c478bd9Sstevel@tonic-gate */ 26987c478bd9Sstevel@tonic-gate for (d = dupper; d + sblock.fs_frag <= dmax - cbase; ) { 26997c478bd9Sstevel@tonic-gate setblock(&sblock, cg_blksfree(&icg), bno); 27007c478bd9Sstevel@tonic-gate icg.cg_cs.cs_nbfree++; 27017c478bd9Sstevel@tonic-gate 27027c478bd9Sstevel@tonic-gate cg_blktot(&icg)[cbcylno]++; 27037c478bd9Sstevel@tonic-gate 27047c478bd9Sstevel@tonic-gate if (!spc_flag) 27057c478bd9Sstevel@tonic-gate cgblks[rpos]++; 27067c478bd9Sstevel@tonic-gate else 27077c478bd9Sstevel@tonic-gate cg_blks(&sblock, &icg, cbtocylno(&sblock, d)) 27087c478bd9Sstevel@tonic-gate [cbtorpos(&sblock, d)]++; 27097c478bd9Sstevel@tonic-gate 27107c478bd9Sstevel@tonic-gate d += sblock.fs_frag; 27117c478bd9Sstevel@tonic-gate bno++; 27127c478bd9Sstevel@tonic-gate 27137c478bd9Sstevel@tonic-gate /* 27147c478bd9Sstevel@tonic-gate * Increment the sector offset within the cylinder 27157c478bd9Sstevel@tonic-gate * for the cbtocylno() macro reimplementation. If 27167c478bd9Sstevel@tonic-gate * we're beyond the end of the cylinder, update the 27177c478bd9Sstevel@tonic-gate * cylinder number, calculate the offset in the 27187c478bd9Sstevel@tonic-gate * new cylinder, and update the cgblks pointer 27197c478bd9Sstevel@tonic-gate * to the next rotational position. 27207c478bd9Sstevel@tonic-gate */ 27217c478bd9Sstevel@tonic-gate cbcylno_sect += cbsect_incr; 27227c478bd9Sstevel@tonic-gate if (cbcylno_sect >= sblock.fs_spc) { 27237c478bd9Sstevel@tonic-gate cbcylno++; 27247c478bd9Sstevel@tonic-gate cbcylno_sect -= sblock.fs_spc; 27257c478bd9Sstevel@tonic-gate cgblks += sblock.fs_nrpos; 27267c478bd9Sstevel@tonic-gate } 27277c478bd9Sstevel@tonic-gate 27287c478bd9Sstevel@tonic-gate /* 27297c478bd9Sstevel@tonic-gate * If there aren't alternate sectors, increment the 27307c478bd9Sstevel@tonic-gate * rotational position variables for the cbtorpos() 27317c478bd9Sstevel@tonic-gate * reimplementation. Note that we potentially 27327c478bd9Sstevel@tonic-gate * increment rpos twice. Once by rpos_incr, and one 27337c478bd9Sstevel@tonic-gate * more time when we wrap to a new track because 27347c478bd9Sstevel@tonic-gate * trackoff >= fs_nsect. 27357c478bd9Sstevel@tonic-gate */ 27367c478bd9Sstevel@tonic-gate if (!spc_flag) { 27377c478bd9Sstevel@tonic-gate trackoff += trackoff_incr; 27387c478bd9Sstevel@tonic-gate rpos += rpos_incr; 27397c478bd9Sstevel@tonic-gate if (trackoff >= sblock.fs_nsect) { 27407c478bd9Sstevel@tonic-gate trackoff -= sblock.fs_nsect; 27417c478bd9Sstevel@tonic-gate rpos++; 27427c478bd9Sstevel@tonic-gate } 27437c478bd9Sstevel@tonic-gate if (rpos >= sblock.fs_nrpos) 27447c478bd9Sstevel@tonic-gate rpos -= sblock.fs_nrpos; 27457c478bd9Sstevel@tonic-gate } 27467c478bd9Sstevel@tonic-gate } 27477c478bd9Sstevel@tonic-gate 27487c478bd9Sstevel@tonic-gate if (d < dmax - cbase) { 27497c478bd9Sstevel@tonic-gate icg.cg_frsum[dmax - cbase - d]++; 27507c478bd9Sstevel@tonic-gate for (; d < dmax - cbase; d++) { 27517c478bd9Sstevel@tonic-gate setbit(cg_blksfree(&icg), d); 27527c478bd9Sstevel@tonic-gate icg.cg_cs.cs_nffree++; 27537c478bd9Sstevel@tonic-gate } 27547c478bd9Sstevel@tonic-gate } 27557c478bd9Sstevel@tonic-gate sblock.fs_cstotal.cs_ndir += icg.cg_cs.cs_ndir; 27567c478bd9Sstevel@tonic-gate sblock.fs_cstotal.cs_nffree += icg.cg_cs.cs_nffree; 27577c478bd9Sstevel@tonic-gate sblock.fs_cstotal.cs_nbfree += icg.cg_cs.cs_nbfree; 27587c478bd9Sstevel@tonic-gate sblock.fs_cstotal.cs_nifree += icg.cg_cs.cs_nifree; 27597c478bd9Sstevel@tonic-gate *cs = icg.cg_cs; 27607c478bd9Sstevel@tonic-gate awtfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, cylno)), 2761d50c8f90Svsakar sblock.fs_bsize, (char *)&icg, RELEASE); 27627c478bd9Sstevel@tonic-gate } 27637c478bd9Sstevel@tonic-gate 27647c478bd9Sstevel@tonic-gate /* 27657c478bd9Sstevel@tonic-gate * initialize the file system 27667c478bd9Sstevel@tonic-gate */ 27677c478bd9Sstevel@tonic-gate struct inode node; 27687c478bd9Sstevel@tonic-gate 27697c478bd9Sstevel@tonic-gate #define LOSTDIR 27707c478bd9Sstevel@tonic-gate #ifdef LOSTDIR 27717c478bd9Sstevel@tonic-gate #define PREDEFDIR 3 27727c478bd9Sstevel@tonic-gate #else 27737c478bd9Sstevel@tonic-gate #define PREDEFDIR 2 27747c478bd9Sstevel@tonic-gate #endif 27757c478bd9Sstevel@tonic-gate 27767c478bd9Sstevel@tonic-gate struct direct root_dir[] = { 27777c478bd9Sstevel@tonic-gate { UFSROOTINO, sizeof (struct direct), 1, "." }, 27787c478bd9Sstevel@tonic-gate { UFSROOTINO, sizeof (struct direct), 2, ".." }, 27797c478bd9Sstevel@tonic-gate #ifdef LOSTDIR 27807c478bd9Sstevel@tonic-gate { LOSTFOUNDINO, sizeof (struct direct), 10, "lost+found" }, 27817c478bd9Sstevel@tonic-gate #endif 27827c478bd9Sstevel@tonic-gate }; 27837c478bd9Sstevel@tonic-gate #ifdef LOSTDIR 27847c478bd9Sstevel@tonic-gate struct direct lost_found_dir[] = { 27857c478bd9Sstevel@tonic-gate { LOSTFOUNDINO, sizeof (struct direct), 1, "." }, 27867c478bd9Sstevel@tonic-gate { UFSROOTINO, sizeof (struct direct), 2, ".." }, 27877c478bd9Sstevel@tonic-gate { 0, DIRBLKSIZ, 0, 0 }, 27887c478bd9Sstevel@tonic-gate }; 27897c478bd9Sstevel@tonic-gate #endif 27907c478bd9Sstevel@tonic-gate char buf[MAXBSIZE]; 27917c478bd9Sstevel@tonic-gate 27927c478bd9Sstevel@tonic-gate static void 27937c478bd9Sstevel@tonic-gate fsinit() 27947c478bd9Sstevel@tonic-gate { 27957c478bd9Sstevel@tonic-gate int i; 27967c478bd9Sstevel@tonic-gate 27977c478bd9Sstevel@tonic-gate 27987c478bd9Sstevel@tonic-gate /* 27997c478bd9Sstevel@tonic-gate * initialize the node 28007c478bd9Sstevel@tonic-gate */ 28017c478bd9Sstevel@tonic-gate node.i_atime = mkfstime; 28027c478bd9Sstevel@tonic-gate node.i_mtime = mkfstime; 28037c478bd9Sstevel@tonic-gate node.i_ctime = mkfstime; 28047c478bd9Sstevel@tonic-gate #ifdef LOSTDIR 28057c478bd9Sstevel@tonic-gate /* 28067c478bd9Sstevel@tonic-gate * create the lost+found directory 28077c478bd9Sstevel@tonic-gate */ 28087c478bd9Sstevel@tonic-gate (void) makedir(lost_found_dir, 2); 28097c478bd9Sstevel@tonic-gate for (i = DIRBLKSIZ; i < sblock.fs_bsize; i += DIRBLKSIZ) { 28107c478bd9Sstevel@tonic-gate bcopy(&lost_found_dir[2], &buf[i], DIRSIZ(&lost_found_dir[2])); 28117c478bd9Sstevel@tonic-gate } 28127c478bd9Sstevel@tonic-gate node.i_number = LOSTFOUNDINO; 28137c478bd9Sstevel@tonic-gate node.i_smode = node.i_mode = IFDIR | 0700; 28147c478bd9Sstevel@tonic-gate node.i_nlink = 2; 28157c478bd9Sstevel@tonic-gate node.i_size = sblock.fs_bsize; 28167c478bd9Sstevel@tonic-gate node.i_db[0] = alloc((int)node.i_size, node.i_mode); 28177c478bd9Sstevel@tonic-gate node.i_blocks = btodb(fragroundup(&sblock, (int)node.i_size)); 28187c478bd9Sstevel@tonic-gate IRANDOMIZE(&node.i_ic); 28197c478bd9Sstevel@tonic-gate wtfs(fsbtodb(&sblock, (uint64_t)node.i_db[0]), (int)node.i_size, buf); 28207c478bd9Sstevel@tonic-gate iput(&node); 28217c478bd9Sstevel@tonic-gate #endif 28227c478bd9Sstevel@tonic-gate /* 28237c478bd9Sstevel@tonic-gate * create the root directory 28247c478bd9Sstevel@tonic-gate */ 28257c478bd9Sstevel@tonic-gate node.i_number = UFSROOTINO; 28267c478bd9Sstevel@tonic-gate node.i_mode = node.i_smode = IFDIR | UMASK; 28277c478bd9Sstevel@tonic-gate node.i_nlink = PREDEFDIR; 28287c478bd9Sstevel@tonic-gate node.i_size = makedir(root_dir, PREDEFDIR); 28297c478bd9Sstevel@tonic-gate node.i_db[0] = alloc(sblock.fs_fsize, node.i_mode); 28307c478bd9Sstevel@tonic-gate /* i_size < 2GB because we are initializing the file system */ 28317c478bd9Sstevel@tonic-gate node.i_blocks = btodb(fragroundup(&sblock, (int)node.i_size)); 28327c478bd9Sstevel@tonic-gate IRANDOMIZE(&node.i_ic); 28337c478bd9Sstevel@tonic-gate wtfs(fsbtodb(&sblock, (uint64_t)node.i_db[0]), sblock.fs_fsize, buf); 28347c478bd9Sstevel@tonic-gate iput(&node); 28357c478bd9Sstevel@tonic-gate } 28367c478bd9Sstevel@tonic-gate 28377c478bd9Sstevel@tonic-gate /* 28387c478bd9Sstevel@tonic-gate * construct a set of directory entries in "buf". 28397c478bd9Sstevel@tonic-gate * return size of directory. 28407c478bd9Sstevel@tonic-gate */ 28417c478bd9Sstevel@tonic-gate static int 28427c478bd9Sstevel@tonic-gate makedir(struct direct *protodir, int entries) 28437c478bd9Sstevel@tonic-gate { 28447c478bd9Sstevel@tonic-gate char *cp; 28457c478bd9Sstevel@tonic-gate int i; 28467c478bd9Sstevel@tonic-gate ushort_t spcleft; 28477c478bd9Sstevel@tonic-gate 28487c478bd9Sstevel@tonic-gate spcleft = DIRBLKSIZ; 28497c478bd9Sstevel@tonic-gate for (cp = buf, i = 0; i < entries - 1; i++) { 28507c478bd9Sstevel@tonic-gate protodir[i].d_reclen = DIRSIZ(&protodir[i]); 28517c478bd9Sstevel@tonic-gate bcopy(&protodir[i], cp, protodir[i].d_reclen); 28527c478bd9Sstevel@tonic-gate cp += protodir[i].d_reclen; 28537c478bd9Sstevel@tonic-gate spcleft -= protodir[i].d_reclen; 28547c478bd9Sstevel@tonic-gate } 28557c478bd9Sstevel@tonic-gate protodir[i].d_reclen = spcleft; 28567c478bd9Sstevel@tonic-gate bcopy(&protodir[i], cp, DIRSIZ(&protodir[i])); 28577c478bd9Sstevel@tonic-gate return (DIRBLKSIZ); 28587c478bd9Sstevel@tonic-gate } 28597c478bd9Sstevel@tonic-gate 28607c478bd9Sstevel@tonic-gate /* 28617c478bd9Sstevel@tonic-gate * allocate a block or frag 28627c478bd9Sstevel@tonic-gate */ 28637c478bd9Sstevel@tonic-gate static daddr32_t 28647c478bd9Sstevel@tonic-gate alloc(int size, int mode) 28657c478bd9Sstevel@tonic-gate { 28667c478bd9Sstevel@tonic-gate int i, frag; 28677c478bd9Sstevel@tonic-gate daddr32_t d; 28687c478bd9Sstevel@tonic-gate 28697c478bd9Sstevel@tonic-gate rdfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, 0)), sblock.fs_cgsize, 28707c478bd9Sstevel@tonic-gate (char *)&acg); 28717c478bd9Sstevel@tonic-gate if (acg.cg_magic != CG_MAGIC) { 28727c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("cg 0: bad magic number\n")); 28737c478bd9Sstevel@tonic-gate lockexit(32); 28747c478bd9Sstevel@tonic-gate } 28757c478bd9Sstevel@tonic-gate if (acg.cg_cs.cs_nbfree == 0) { 28767c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2877d50c8f90Svsakar gettext("first cylinder group ran out of space\n")); 28787c478bd9Sstevel@tonic-gate lockexit(32); 28797c478bd9Sstevel@tonic-gate } 28807c478bd9Sstevel@tonic-gate for (d = 0; d < acg.cg_ndblk; d += sblock.fs_frag) 28817c478bd9Sstevel@tonic-gate if (isblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag)) 28827c478bd9Sstevel@tonic-gate goto goth; 28837c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 28847c478bd9Sstevel@tonic-gate gettext("internal error: can't find block in cyl 0\n")); 28857c478bd9Sstevel@tonic-gate lockexit(32); 28867c478bd9Sstevel@tonic-gate goth: 28877c478bd9Sstevel@tonic-gate clrblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag); 28887c478bd9Sstevel@tonic-gate acg.cg_cs.cs_nbfree--; 28897c478bd9Sstevel@tonic-gate sblock.fs_cstotal.cs_nbfree--; 28907c478bd9Sstevel@tonic-gate fscs[0].cs_nbfree--; 28917c478bd9Sstevel@tonic-gate if (mode & IFDIR) { 28927c478bd9Sstevel@tonic-gate acg.cg_cs.cs_ndir++; 28937c478bd9Sstevel@tonic-gate sblock.fs_cstotal.cs_ndir++; 28947c478bd9Sstevel@tonic-gate fscs[0].cs_ndir++; 28957c478bd9Sstevel@tonic-gate } 28967c478bd9Sstevel@tonic-gate cg_blktot(&acg)[cbtocylno(&sblock, d)]--; 28977c478bd9Sstevel@tonic-gate cg_blks(&sblock, &acg, cbtocylno(&sblock, d))[cbtorpos(&sblock, d)]--; 28987c478bd9Sstevel@tonic-gate if (size != sblock.fs_bsize) { 28997c478bd9Sstevel@tonic-gate frag = howmany(size, sblock.fs_fsize); 29007c478bd9Sstevel@tonic-gate fscs[0].cs_nffree += sblock.fs_frag - frag; 29017c478bd9Sstevel@tonic-gate sblock.fs_cstotal.cs_nffree += sblock.fs_frag - frag; 29027c478bd9Sstevel@tonic-gate acg.cg_cs.cs_nffree += sblock.fs_frag - frag; 29037c478bd9Sstevel@tonic-gate acg.cg_frsum[sblock.fs_frag - frag]++; 29047c478bd9Sstevel@tonic-gate for (i = frag; i < sblock.fs_frag; i++) 29057c478bd9Sstevel@tonic-gate setbit(cg_blksfree(&acg), d + i); 29067c478bd9Sstevel@tonic-gate } 29077c478bd9Sstevel@tonic-gate wtfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, 0)), sblock.fs_cgsize, 29087c478bd9Sstevel@tonic-gate (char *)&acg); 29097c478bd9Sstevel@tonic-gate return (d); 29107c478bd9Sstevel@tonic-gate } 29117c478bd9Sstevel@tonic-gate 29127c478bd9Sstevel@tonic-gate /* 29137c478bd9Sstevel@tonic-gate * Allocate an inode on the disk 29147c478bd9Sstevel@tonic-gate */ 29157c478bd9Sstevel@tonic-gate static void 29167c478bd9Sstevel@tonic-gate iput(struct inode *ip) 29177c478bd9Sstevel@tonic-gate { 29187c478bd9Sstevel@tonic-gate struct dinode buf[MAXINOPB]; 29197c478bd9Sstevel@tonic-gate diskaddr_t d; 29207c478bd9Sstevel@tonic-gate 29217c478bd9Sstevel@tonic-gate rdfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, 0)), sblock.fs_cgsize, 29227c478bd9Sstevel@tonic-gate (char *)&acg); 29237c478bd9Sstevel@tonic-gate if (acg.cg_magic != CG_MAGIC) { 29247c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("cg 0: bad magic number\n")); 29257c478bd9Sstevel@tonic-gate lockexit(32); 29267c478bd9Sstevel@tonic-gate } 29277c478bd9Sstevel@tonic-gate acg.cg_cs.cs_nifree--; 29287c478bd9Sstevel@tonic-gate setbit(cg_inosused(&acg), ip->i_number); 29297c478bd9Sstevel@tonic-gate wtfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, 0)), sblock.fs_cgsize, 29307c478bd9Sstevel@tonic-gate (char *)&acg); 29317c478bd9Sstevel@tonic-gate sblock.fs_cstotal.cs_nifree--; 29327c478bd9Sstevel@tonic-gate fscs[0].cs_nifree--; 29337c478bd9Sstevel@tonic-gate if ((int)ip->i_number >= sblock.fs_ipg * sblock.fs_ncg) { 29347c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2935d50c8f90Svsakar gettext("fsinit: inode value out of range (%d).\n"), 2936d50c8f90Svsakar ip->i_number); 29377c478bd9Sstevel@tonic-gate lockexit(32); 29387c478bd9Sstevel@tonic-gate } 29397c478bd9Sstevel@tonic-gate d = fsbtodb(&sblock, (uint64_t)itod(&sblock, (int)ip->i_number)); 29407c478bd9Sstevel@tonic-gate rdfs(d, sblock.fs_bsize, (char *)buf); 29417c478bd9Sstevel@tonic-gate buf[itoo(&sblock, (int)ip->i_number)].di_ic = ip->i_ic; 29427c478bd9Sstevel@tonic-gate wtfs(d, sblock.fs_bsize, (char *)buf); 29437c478bd9Sstevel@tonic-gate } 29447c478bd9Sstevel@tonic-gate 29457c478bd9Sstevel@tonic-gate /* 29467c478bd9Sstevel@tonic-gate * getbuf() -- Get a buffer for use in an AIO operation. Buffer 29477c478bd9Sstevel@tonic-gate * is zero'd the first time returned, left with whatever 29487c478bd9Sstevel@tonic-gate * was in memory after that. This function actually gets 29497c478bd9Sstevel@tonic-gate * enough memory the first time it's called to support 29507c478bd9Sstevel@tonic-gate * MAXBUF buffers like a slab allocator. When all the 29517c478bd9Sstevel@tonic-gate * buffers are in use, it waits for an aio to complete 29527c478bd9Sstevel@tonic-gate * and make a buffer available. 29537c478bd9Sstevel@tonic-gate * 29547c478bd9Sstevel@tonic-gate * Never returns an error. Either succeeds or exits. 29557c478bd9Sstevel@tonic-gate */ 29567c478bd9Sstevel@tonic-gate static char * 29577c478bd9Sstevel@tonic-gate getbuf(bufhdr *bufhead, int size) 29587c478bd9Sstevel@tonic-gate { 29597c478bd9Sstevel@tonic-gate bufhdr *pbuf; 29607c478bd9Sstevel@tonic-gate bufhdr *prev; 29617c478bd9Sstevel@tonic-gate int i; 29627c478bd9Sstevel@tonic-gate int buf_size, max_bufs; 29637c478bd9Sstevel@tonic-gate 29647c478bd9Sstevel@tonic-gate /* 29657c478bd9Sstevel@tonic-gate * Initialize all the buffers 29667c478bd9Sstevel@tonic-gate */ 29677c478bd9Sstevel@tonic-gate if (bufhead->head == NULL) { 29687c478bd9Sstevel@tonic-gate /* 29697c478bd9Sstevel@tonic-gate * round up the size of our buffer header to a 29707c478bd9Sstevel@tonic-gate * 16 byte boundary so the address we return to 29717c478bd9Sstevel@tonic-gate * the caller is "suitably aligned". 29727c478bd9Sstevel@tonic-gate */ 29737c478bd9Sstevel@tonic-gate bufhdrsize = (sizeof (bufhdr) + 15) & ~15; 29747c478bd9Sstevel@tonic-gate 29757c478bd9Sstevel@tonic-gate /* 29767c478bd9Sstevel@tonic-gate * Add in our header to the buffer and round it all up to 29777c478bd9Sstevel@tonic-gate * a 16 byte boundry so each member of the slab is aligned. 29787c478bd9Sstevel@tonic-gate */ 29797c478bd9Sstevel@tonic-gate buf_size = (size + bufhdrsize + 15) & ~15; 29807c478bd9Sstevel@tonic-gate 29817c478bd9Sstevel@tonic-gate /* 29827c478bd9Sstevel@tonic-gate * Limit number of buffers to lesser of MAXBUFMEM's worth 29837c478bd9Sstevel@tonic-gate * or MAXBUF, whichever is less. 29847c478bd9Sstevel@tonic-gate */ 29857c478bd9Sstevel@tonic-gate max_bufs = MAXBUFMEM / buf_size; 29867c478bd9Sstevel@tonic-gate if (max_bufs > MAXBUF) 29877c478bd9Sstevel@tonic-gate max_bufs = MAXBUF; 29887c478bd9Sstevel@tonic-gate 29897c478bd9Sstevel@tonic-gate pbuf = (bufhdr *)calloc(max_bufs, buf_size); 29907c478bd9Sstevel@tonic-gate if (pbuf == NULL) { 29917c478bd9Sstevel@tonic-gate perror("calloc"); 29927c478bd9Sstevel@tonic-gate lockexit(32); 29937c478bd9Sstevel@tonic-gate } 29947c478bd9Sstevel@tonic-gate 29957c478bd9Sstevel@tonic-gate bufhead->head = bufhead; 29967c478bd9Sstevel@tonic-gate prev = bufhead; 29977c478bd9Sstevel@tonic-gate for (i = 0; i < max_bufs; i++) { 29987c478bd9Sstevel@tonic-gate pbuf->head = bufhead; 29997c478bd9Sstevel@tonic-gate prev->next = pbuf; 30007c478bd9Sstevel@tonic-gate prev = pbuf; 30017c478bd9Sstevel@tonic-gate pbuf = (bufhdr *)((char *)pbuf + buf_size); 30027c478bd9Sstevel@tonic-gate } 30037c478bd9Sstevel@tonic-gate } 30047c478bd9Sstevel@tonic-gate 30057c478bd9Sstevel@tonic-gate /* 30067c478bd9Sstevel@tonic-gate * Get an available buffer, waiting for I/O if necessary 30077c478bd9Sstevel@tonic-gate */ 30087c478bd9Sstevel@tonic-gate wait_for_write(NOBLOCK); 30097c478bd9Sstevel@tonic-gate while (bufhead->next == NULL) 30107c478bd9Sstevel@tonic-gate wait_for_write(BLOCK); 30117c478bd9Sstevel@tonic-gate 30127c478bd9Sstevel@tonic-gate /* 30137c478bd9Sstevel@tonic-gate * Take the buffer off the list 30147c478bd9Sstevel@tonic-gate */ 30157c478bd9Sstevel@tonic-gate pbuf = bufhead->next; 30167c478bd9Sstevel@tonic-gate bufhead->next = pbuf->next; 30177c478bd9Sstevel@tonic-gate pbuf->next = NULL; 30187c478bd9Sstevel@tonic-gate 30197c478bd9Sstevel@tonic-gate /* 30207c478bd9Sstevel@tonic-gate * return the empty buffer space just past the header 30217c478bd9Sstevel@tonic-gate */ 30227c478bd9Sstevel@tonic-gate return ((char *)pbuf + bufhdrsize); 30237c478bd9Sstevel@tonic-gate } 30247c478bd9Sstevel@tonic-gate 30257c478bd9Sstevel@tonic-gate /* 30267c478bd9Sstevel@tonic-gate * freebuf() -- Free a buffer gotten previously through getbuf. 30277c478bd9Sstevel@tonic-gate * Puts the buffer back on the appropriate list for 30287c478bd9Sstevel@tonic-gate * later use. Never calls free(). 30297c478bd9Sstevel@tonic-gate * 30307c478bd9Sstevel@tonic-gate * Assumes that SIGINT is blocked. 30317c478bd9Sstevel@tonic-gate */ 30327c478bd9Sstevel@tonic-gate static void 30337c478bd9Sstevel@tonic-gate freebuf(char *buf) 30347c478bd9Sstevel@tonic-gate { 30357c478bd9Sstevel@tonic-gate bufhdr *pbuf; 30367c478bd9Sstevel@tonic-gate bufhdr *bufhead; 30377c478bd9Sstevel@tonic-gate 30387c478bd9Sstevel@tonic-gate /* 30397c478bd9Sstevel@tonic-gate * get the header for this buffer 30407c478bd9Sstevel@tonic-gate */ 30417c478bd9Sstevel@tonic-gate pbuf = (bufhdr *)(buf - bufhdrsize); 30427c478bd9Sstevel@tonic-gate 30437c478bd9Sstevel@tonic-gate /* 30447c478bd9Sstevel@tonic-gate * Put it back on the list of available buffers 30457c478bd9Sstevel@tonic-gate */ 30467c478bd9Sstevel@tonic-gate bufhead = pbuf->head; 30477c478bd9Sstevel@tonic-gate pbuf->next = bufhead->next; 30487c478bd9Sstevel@tonic-gate bufhead->next = pbuf; 30497c478bd9Sstevel@tonic-gate } 30507c478bd9Sstevel@tonic-gate 30517c478bd9Sstevel@tonic-gate /* 30527c478bd9Sstevel@tonic-gate * freetrans() -- Free a transaction gotten previously through getaiop. 30537c478bd9Sstevel@tonic-gate * Puts the transaction struct back on the appropriate list for 30547c478bd9Sstevel@tonic-gate * later use. Never calls free(). 30557c478bd9Sstevel@tonic-gate * 30567c478bd9Sstevel@tonic-gate * Assumes that SIGINT is blocked. 30577c478bd9Sstevel@tonic-gate */ 30587c478bd9Sstevel@tonic-gate static void 30597c478bd9Sstevel@tonic-gate freetrans(aio_trans *transp) 30607c478bd9Sstevel@tonic-gate { 30617c478bd9Sstevel@tonic-gate /* 30627c478bd9Sstevel@tonic-gate * free the buffer associated with this AIO if needed 30637c478bd9Sstevel@tonic-gate */ 30647c478bd9Sstevel@tonic-gate if (transp->release == RELEASE) 30657c478bd9Sstevel@tonic-gate freebuf(transp->buffer); 30667c478bd9Sstevel@tonic-gate 30677c478bd9Sstevel@tonic-gate /* 30687c478bd9Sstevel@tonic-gate * Put transaction on the free list 30697c478bd9Sstevel@tonic-gate */ 30707c478bd9Sstevel@tonic-gate transp->next = results.trans; 30717c478bd9Sstevel@tonic-gate results.trans = transp; 30727c478bd9Sstevel@tonic-gate } 30737c478bd9Sstevel@tonic-gate 30747c478bd9Sstevel@tonic-gate /* 30757c478bd9Sstevel@tonic-gate * wait_for_write() -- Wait for an aio write to complete. Return 30767c478bd9Sstevel@tonic-gate * the transaction structure for that write. 30777c478bd9Sstevel@tonic-gate * 30787c478bd9Sstevel@tonic-gate * Blocks SIGINT if necessary. 30797c478bd9Sstevel@tonic-gate */ 30807c478bd9Sstevel@tonic-gate aio_trans * 30817c478bd9Sstevel@tonic-gate wait_for_write(int block) 30827c478bd9Sstevel@tonic-gate { 30837c478bd9Sstevel@tonic-gate aio_trans *transp; 30847c478bd9Sstevel@tonic-gate aio_result_t *resultp; 30857c478bd9Sstevel@tonic-gate static struct timeval zero_wait = { 0, 0 }; 30867c478bd9Sstevel@tonic-gate sigset_t old_mask; 30877c478bd9Sstevel@tonic-gate 30887c478bd9Sstevel@tonic-gate /* 30897c478bd9Sstevel@tonic-gate * If we know there aren't any outstanding transactions, just return 30907c478bd9Sstevel@tonic-gate */ 30917c478bd9Sstevel@tonic-gate if (results.outstanding == 0) 30927c478bd9Sstevel@tonic-gate return ((aio_trans *) 0); 30937c478bd9Sstevel@tonic-gate 30947c478bd9Sstevel@tonic-gate block_sigint(&old_mask); 30957c478bd9Sstevel@tonic-gate 30967c478bd9Sstevel@tonic-gate resultp = aiowait(block ? NULL : &zero_wait); 30977c478bd9Sstevel@tonic-gate if (resultp == NULL || 30987c478bd9Sstevel@tonic-gate (resultp == (aio_result_t *)-1 && errno == EINVAL)) { 30997c478bd9Sstevel@tonic-gate unblock_sigint(&old_mask); 31007c478bd9Sstevel@tonic-gate return ((aio_trans *) 0); 31017c478bd9Sstevel@tonic-gate } 31027c478bd9Sstevel@tonic-gate 31037c478bd9Sstevel@tonic-gate results.outstanding--; 31047c478bd9Sstevel@tonic-gate transp = (aio_trans *)resultp; 31057c478bd9Sstevel@tonic-gate 31067c478bd9Sstevel@tonic-gate if (resultp->aio_return != transp->size) { 31077c478bd9Sstevel@tonic-gate if (resultp->aio_return == -1) { 31087c478bd9Sstevel@tonic-gate /* 31097c478bd9Sstevel@tonic-gate * The aiowrite() may have failed because the 31107c478bd9Sstevel@tonic-gate * kernel didn't have enough memory to do the job. 31117c478bd9Sstevel@tonic-gate * Flush all pending writes and try a normal 31127c478bd9Sstevel@tonic-gate * write(). wtfs_breakup() will call exit if it 31137c478bd9Sstevel@tonic-gate * fails, so we don't worry about errors here. 31147c478bd9Sstevel@tonic-gate */ 31157c478bd9Sstevel@tonic-gate flush_writes(); 31167c478bd9Sstevel@tonic-gate wtfs_breakup(transp->bno, transp->size, transp->buffer); 31177c478bd9Sstevel@tonic-gate } else { 31187c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 31197c478bd9Sstevel@tonic-gate "short write (%d of %d bytes) on sector %lld\n"), 31207c478bd9Sstevel@tonic-gate resultp->aio_return, transp->size, 31217c478bd9Sstevel@tonic-gate transp->bno); 31227c478bd9Sstevel@tonic-gate /* 31237c478bd9Sstevel@tonic-gate * Don't unblock SIGINT, to avoid potential 31247c478bd9Sstevel@tonic-gate * looping due to queued interrupts and 31257c478bd9Sstevel@tonic-gate * error handling. 31267c478bd9Sstevel@tonic-gate */ 31277c478bd9Sstevel@tonic-gate lockexit(32); 31287c478bd9Sstevel@tonic-gate } 31297c478bd9Sstevel@tonic-gate } 31307c478bd9Sstevel@tonic-gate 31317c478bd9Sstevel@tonic-gate resultp->aio_return = 0; 31327c478bd9Sstevel@tonic-gate freetrans(transp); 31337c478bd9Sstevel@tonic-gate unblock_sigint(&old_mask); 31347c478bd9Sstevel@tonic-gate return (transp); 31357c478bd9Sstevel@tonic-gate } 31367c478bd9Sstevel@tonic-gate 31377c478bd9Sstevel@tonic-gate /* 31387c478bd9Sstevel@tonic-gate * flush_writes() -- flush all the outstanding aio writes. 31397c478bd9Sstevel@tonic-gate */ 31407c478bd9Sstevel@tonic-gate static void 31417c478bd9Sstevel@tonic-gate flush_writes(void) 31427c478bd9Sstevel@tonic-gate { 31437c478bd9Sstevel@tonic-gate while (wait_for_write(BLOCK)) 31447c478bd9Sstevel@tonic-gate ; 31457c478bd9Sstevel@tonic-gate } 31467c478bd9Sstevel@tonic-gate 31477c478bd9Sstevel@tonic-gate /* 31487c478bd9Sstevel@tonic-gate * get_aiop() -- find and return an aio_trans structure on which a new 31497c478bd9Sstevel@tonic-gate * aio can be done. Blocks on aiowait() if needed. Reaps 31507c478bd9Sstevel@tonic-gate * all outstanding completed aio's. 31517c478bd9Sstevel@tonic-gate * 31527c478bd9Sstevel@tonic-gate * Assumes that SIGINT is blocked. 31537c478bd9Sstevel@tonic-gate */ 31547c478bd9Sstevel@tonic-gate aio_trans * 31557c478bd9Sstevel@tonic-gate get_aiop() 31567c478bd9Sstevel@tonic-gate { 31577c478bd9Sstevel@tonic-gate int i; 31587c478bd9Sstevel@tonic-gate aio_trans *transp; 31597c478bd9Sstevel@tonic-gate aio_trans *prev; 31607c478bd9Sstevel@tonic-gate 31617c478bd9Sstevel@tonic-gate /* 31627c478bd9Sstevel@tonic-gate * initialize aio stuff 31637c478bd9Sstevel@tonic-gate */ 31647c478bd9Sstevel@tonic-gate if (!aio_inited) { 31657c478bd9Sstevel@tonic-gate aio_inited = 1; 31667c478bd9Sstevel@tonic-gate 31677c478bd9Sstevel@tonic-gate results.maxpend = 0; 31687c478bd9Sstevel@tonic-gate results.outstanding = 0; 31697c478bd9Sstevel@tonic-gate results.max = MAXAIO; 31707c478bd9Sstevel@tonic-gate 31717c478bd9Sstevel@tonic-gate results.trans = (aio_trans *)calloc(results.max, 3172d50c8f90Svsakar sizeof (aio_trans)); 31737c478bd9Sstevel@tonic-gate if (results.trans == NULL) { 31747c478bd9Sstevel@tonic-gate perror("calloc"); 31757c478bd9Sstevel@tonic-gate lockexit(32); 31767c478bd9Sstevel@tonic-gate } 31777c478bd9Sstevel@tonic-gate 31787c478bd9Sstevel@tonic-gate /* 31797c478bd9Sstevel@tonic-gate * Initialize the linked list of aio transaction 31807c478bd9Sstevel@tonic-gate * structures. Note that the final "next" pointer 31817c478bd9Sstevel@tonic-gate * will be NULL since we got the buffer from calloc(). 31827c478bd9Sstevel@tonic-gate */ 31837c478bd9Sstevel@tonic-gate prev = results.trans; 31847c478bd9Sstevel@tonic-gate for (i = 1; i < results.max; i++) { 31857c478bd9Sstevel@tonic-gate prev->next = &(results.trans[i]); 31867c478bd9Sstevel@tonic-gate prev = prev->next; 31877c478bd9Sstevel@tonic-gate } 31887c478bd9Sstevel@tonic-gate } 31897c478bd9Sstevel@tonic-gate 31907c478bd9Sstevel@tonic-gate wait_for_write(NOBLOCK); 31917c478bd9Sstevel@tonic-gate while (results.trans == NULL) 31927c478bd9Sstevel@tonic-gate wait_for_write(BLOCK); 31937c478bd9Sstevel@tonic-gate transp = results.trans; 31947c478bd9Sstevel@tonic-gate results.trans = results.trans->next; 31957c478bd9Sstevel@tonic-gate 31967c478bd9Sstevel@tonic-gate transp->next = 0; 31977c478bd9Sstevel@tonic-gate transp->resultbuf.aio_return = AIO_INPROGRESS; 31987c478bd9Sstevel@tonic-gate return (transp); 31997c478bd9Sstevel@tonic-gate } 32007c478bd9Sstevel@tonic-gate 32017c478bd9Sstevel@tonic-gate /* 32027c478bd9Sstevel@tonic-gate * read a block from the file system 32037c478bd9Sstevel@tonic-gate */ 32047c478bd9Sstevel@tonic-gate static void 32057c478bd9Sstevel@tonic-gate rdfs(diskaddr_t bno, int size, char *bf) 32067c478bd9Sstevel@tonic-gate { 32077c478bd9Sstevel@tonic-gate int n, saverr; 32087c478bd9Sstevel@tonic-gate 32097c478bd9Sstevel@tonic-gate /* 32107c478bd9Sstevel@tonic-gate * In case we need any data that's pending in an aiowrite(), 32117c478bd9Sstevel@tonic-gate * we wait for them all to complete before doing a read. 32127c478bd9Sstevel@tonic-gate */ 32137c478bd9Sstevel@tonic-gate flush_writes(); 32147c478bd9Sstevel@tonic-gate 32157c478bd9Sstevel@tonic-gate /* 32167c478bd9Sstevel@tonic-gate * Note: the llseek() can succeed, even if the offset is out of range. 32177c478bd9Sstevel@tonic-gate * It's not until the file i/o operation (the read()) that one knows 32187c478bd9Sstevel@tonic-gate * for sure if the raw device can handle the offset. 32197c478bd9Sstevel@tonic-gate */ 32207c478bd9Sstevel@tonic-gate if (llseek(fsi, (offset_t)bno * sectorsize, 0) < 0) { 32217c478bd9Sstevel@tonic-gate saverr = errno; 32227c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 32237c478bd9Sstevel@tonic-gate gettext("seek error on sector %lld: %s\n"), 32247c478bd9Sstevel@tonic-gate bno, strerror(saverr)); 32257c478bd9Sstevel@tonic-gate lockexit(32); 32267c478bd9Sstevel@tonic-gate } 32277c478bd9Sstevel@tonic-gate n = read(fsi, bf, size); 32287c478bd9Sstevel@tonic-gate if (n != size) { 32297c478bd9Sstevel@tonic-gate saverr = errno; 32307c478bd9Sstevel@tonic-gate if (n == -1) 32317c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 32327c478bd9Sstevel@tonic-gate gettext("read error on sector %lld: %s\n"), 32337c478bd9Sstevel@tonic-gate bno, strerror(saverr)); 32347c478bd9Sstevel@tonic-gate else 32357c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 32367c478bd9Sstevel@tonic-gate "short read (%d of %d bytes) on sector %lld\n"), 32377c478bd9Sstevel@tonic-gate n, size, bno); 32387c478bd9Sstevel@tonic-gate lockexit(32); 32397c478bd9Sstevel@tonic-gate } 32407c478bd9Sstevel@tonic-gate } 32417c478bd9Sstevel@tonic-gate 32427c478bd9Sstevel@tonic-gate /* 32437c478bd9Sstevel@tonic-gate * write a block to the file system 32447c478bd9Sstevel@tonic-gate */ 32457c478bd9Sstevel@tonic-gate static void 32467c478bd9Sstevel@tonic-gate wtfs(diskaddr_t bno, int size, char *bf) 32477c478bd9Sstevel@tonic-gate { 32487c478bd9Sstevel@tonic-gate int n, saverr; 32497c478bd9Sstevel@tonic-gate 32507c478bd9Sstevel@tonic-gate if (fso == -1) 32517c478bd9Sstevel@tonic-gate return; 32527c478bd9Sstevel@tonic-gate 32537c478bd9Sstevel@tonic-gate /* 32547c478bd9Sstevel@tonic-gate * Note: the llseek() can succeed, even if the offset is out of range. 32557c478bd9Sstevel@tonic-gate * It's not until the file i/o operation (the write()) that one knows 32567c478bd9Sstevel@tonic-gate * for sure if the raw device can handle the offset. 32577c478bd9Sstevel@tonic-gate */ 32587c478bd9Sstevel@tonic-gate if (llseek(fso, (offset_t)bno * sectorsize, 0) < 0) { 32597c478bd9Sstevel@tonic-gate saverr = errno; 32607c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 32617c478bd9Sstevel@tonic-gate gettext("seek error on sector %lld: %s\n"), 32627c478bd9Sstevel@tonic-gate bno, strerror(saverr)); 32637c478bd9Sstevel@tonic-gate lockexit(32); 32647c478bd9Sstevel@tonic-gate } 32657c478bd9Sstevel@tonic-gate if (Nflag) 32667c478bd9Sstevel@tonic-gate return; 32677c478bd9Sstevel@tonic-gate n = write(fso, bf, size); 32687c478bd9Sstevel@tonic-gate if (n != size) { 32697c478bd9Sstevel@tonic-gate saverr = errno; 32707c478bd9Sstevel@tonic-gate if (n == -1) 32717c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 32727c478bd9Sstevel@tonic-gate gettext("write error on sector %lld: %s\n"), 32737c478bd9Sstevel@tonic-gate bno, strerror(saverr)); 32747c478bd9Sstevel@tonic-gate else 32757c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 32767c478bd9Sstevel@tonic-gate "short write (%d of %d bytes) on sector %lld\n"), 32777c478bd9Sstevel@tonic-gate n, size, bno); 32787c478bd9Sstevel@tonic-gate lockexit(32); 32797c478bd9Sstevel@tonic-gate } 32807c478bd9Sstevel@tonic-gate } 32817c478bd9Sstevel@tonic-gate 32827c478bd9Sstevel@tonic-gate /* 32837c478bd9Sstevel@tonic-gate * write a block to the file system -- buffered with aio 32847c478bd9Sstevel@tonic-gate */ 32857c478bd9Sstevel@tonic-gate static void 32867c478bd9Sstevel@tonic-gate awtfs(diskaddr_t bno, int size, char *bf, int release) 32877c478bd9Sstevel@tonic-gate { 32887c478bd9Sstevel@tonic-gate int n; 32897c478bd9Sstevel@tonic-gate aio_trans *transp; 32907c478bd9Sstevel@tonic-gate sigset_t old_mask; 32917c478bd9Sstevel@tonic-gate 32927c478bd9Sstevel@tonic-gate if (fso == -1) 32937c478bd9Sstevel@tonic-gate return; 32947c478bd9Sstevel@tonic-gate 32957c478bd9Sstevel@tonic-gate /* 32967c478bd9Sstevel@tonic-gate * We need to keep things consistent if we get interrupted, 32977c478bd9Sstevel@tonic-gate * so defer any expected interrupts for the time being. 32987c478bd9Sstevel@tonic-gate */ 32997c478bd9Sstevel@tonic-gate block_sigint(&old_mask); 33007c478bd9Sstevel@tonic-gate 33017c478bd9Sstevel@tonic-gate if (Nflag) { 33027c478bd9Sstevel@tonic-gate if (release == RELEASE) 33037c478bd9Sstevel@tonic-gate freebuf(bf); 33047c478bd9Sstevel@tonic-gate } else { 33057c478bd9Sstevel@tonic-gate transp = get_aiop(); 33067c478bd9Sstevel@tonic-gate transp->bno = bno; 33077c478bd9Sstevel@tonic-gate transp->buffer = bf; 33087c478bd9Sstevel@tonic-gate transp->size = size; 33097c478bd9Sstevel@tonic-gate transp->release = release; 33107c478bd9Sstevel@tonic-gate 33117c478bd9Sstevel@tonic-gate n = aiowrite(fso, bf, size, (off_t)bno * sectorsize, 3312d50c8f90Svsakar SEEK_SET, &transp->resultbuf); 33137c478bd9Sstevel@tonic-gate 33147c478bd9Sstevel@tonic-gate if (n < 0) { 33157c478bd9Sstevel@tonic-gate /* 33167c478bd9Sstevel@tonic-gate * The aiowrite() may have failed because the 33177c478bd9Sstevel@tonic-gate * kernel didn't have enough memory to do the job. 33187c478bd9Sstevel@tonic-gate * Flush all pending writes and try a normal 33197c478bd9Sstevel@tonic-gate * write(). wtfs_breakup() will call exit if it 33207c478bd9Sstevel@tonic-gate * fails, so we don't worry about errors here. 33217c478bd9Sstevel@tonic-gate */ 33227c478bd9Sstevel@tonic-gate flush_writes(); 33237c478bd9Sstevel@tonic-gate wtfs_breakup(transp->bno, transp->size, transp->buffer); 33247c478bd9Sstevel@tonic-gate freetrans(transp); 33257c478bd9Sstevel@tonic-gate } else { 33267c478bd9Sstevel@tonic-gate /* 33277c478bd9Sstevel@tonic-gate * Keep track of our pending writes. 33287c478bd9Sstevel@tonic-gate */ 33297c478bd9Sstevel@tonic-gate results.outstanding++; 33307c478bd9Sstevel@tonic-gate if (results.outstanding > results.maxpend) 3331d50c8f90Svsakar results.maxpend = results.outstanding; 33327c478bd9Sstevel@tonic-gate } 33337c478bd9Sstevel@tonic-gate } 33347c478bd9Sstevel@tonic-gate 33357c478bd9Sstevel@tonic-gate unblock_sigint(&old_mask); 33367c478bd9Sstevel@tonic-gate } 33377c478bd9Sstevel@tonic-gate 33387c478bd9Sstevel@tonic-gate 33397c478bd9Sstevel@tonic-gate /* 33407c478bd9Sstevel@tonic-gate * write a block to the file system, but break it up into sbsize 33417c478bd9Sstevel@tonic-gate * chunks to avoid forcing a large amount of memory to be locked down. 33427c478bd9Sstevel@tonic-gate * Only used as a fallback when an aio write has failed. 33437c478bd9Sstevel@tonic-gate */ 33447c478bd9Sstevel@tonic-gate static void 33457c478bd9Sstevel@tonic-gate wtfs_breakup(diskaddr_t bno, int size, char *bf) 33467c478bd9Sstevel@tonic-gate { 33477c478bd9Sstevel@tonic-gate int n, saverr; 33487c478bd9Sstevel@tonic-gate int wsize; 33497c478bd9Sstevel@tonic-gate int block_incr = sbsize / sectorsize; 33507c478bd9Sstevel@tonic-gate 33517c478bd9Sstevel@tonic-gate if (size < sbsize) 33527c478bd9Sstevel@tonic-gate wsize = size; 33537c478bd9Sstevel@tonic-gate else 33547c478bd9Sstevel@tonic-gate wsize = sbsize; 33557c478bd9Sstevel@tonic-gate 33567c478bd9Sstevel@tonic-gate n = 0; 33577c478bd9Sstevel@tonic-gate while (size) { 33587c478bd9Sstevel@tonic-gate /* 33597c478bd9Sstevel@tonic-gate * Note: the llseek() can succeed, even if the offset is 33607c478bd9Sstevel@tonic-gate * out of range. It's not until the file i/o operation 33617c478bd9Sstevel@tonic-gate * (the write()) that one knows for sure if the raw device 33627c478bd9Sstevel@tonic-gate * can handle the offset. 33637c478bd9Sstevel@tonic-gate */ 33647c478bd9Sstevel@tonic-gate if (llseek(fso, (offset_t)bno * sectorsize, 0) < 0) { 33657c478bd9Sstevel@tonic-gate saverr = errno; 33667c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 33677c478bd9Sstevel@tonic-gate gettext("seek error on sector %lld: %s\n"), 33687c478bd9Sstevel@tonic-gate bno, strerror(saverr)); 33697c478bd9Sstevel@tonic-gate lockexit(32); 33707c478bd9Sstevel@tonic-gate } 33717c478bd9Sstevel@tonic-gate 33727c478bd9Sstevel@tonic-gate n = write(fso, bf, wsize); 33737c478bd9Sstevel@tonic-gate if (n == -1) { 33747c478bd9Sstevel@tonic-gate saverr = errno; 33757c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 33767c478bd9Sstevel@tonic-gate gettext("write error on sector %lld: %s\n"), 33777c478bd9Sstevel@tonic-gate bno, strerror(saverr)); 33787c478bd9Sstevel@tonic-gate lockexit(32); 33797c478bd9Sstevel@tonic-gate } 33807c478bd9Sstevel@tonic-gate if (n != wsize) { 33817c478bd9Sstevel@tonic-gate saverr = errno; 33827c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 33837c478bd9Sstevel@tonic-gate "short write (%d of %d bytes) on sector %lld\n"), 33847c478bd9Sstevel@tonic-gate n, size, bno); 33857c478bd9Sstevel@tonic-gate lockexit(32); 33867c478bd9Sstevel@tonic-gate } 33877c478bd9Sstevel@tonic-gate 33887c478bd9Sstevel@tonic-gate bno += block_incr; 33897c478bd9Sstevel@tonic-gate bf += wsize; 33907c478bd9Sstevel@tonic-gate size -= wsize; 33917c478bd9Sstevel@tonic-gate if (size < wsize) 33927c478bd9Sstevel@tonic-gate wsize = size; 33937c478bd9Sstevel@tonic-gate } 33947c478bd9Sstevel@tonic-gate } 33957c478bd9Sstevel@tonic-gate 33967c478bd9Sstevel@tonic-gate 33977c478bd9Sstevel@tonic-gate /* 33987c478bd9Sstevel@tonic-gate * check if a block is available 33997c478bd9Sstevel@tonic-gate */ 34007c478bd9Sstevel@tonic-gate static int 34017c478bd9Sstevel@tonic-gate isblock(struct fs *fs, unsigned char *cp, int h) 34027c478bd9Sstevel@tonic-gate { 34037c478bd9Sstevel@tonic-gate unsigned char mask; 34047c478bd9Sstevel@tonic-gate 34057c478bd9Sstevel@tonic-gate switch (fs->fs_frag) { 34067c478bd9Sstevel@tonic-gate case 8: 34077c478bd9Sstevel@tonic-gate return (cp[h] == 0xff); 34087c478bd9Sstevel@tonic-gate case 4: 34097c478bd9Sstevel@tonic-gate mask = 0x0f << ((h & 0x1) << 2); 34107c478bd9Sstevel@tonic-gate return ((cp[h >> 1] & mask) == mask); 34117c478bd9Sstevel@tonic-gate case 2: 34127c478bd9Sstevel@tonic-gate mask = 0x03 << ((h & 0x3) << 1); 34137c478bd9Sstevel@tonic-gate return ((cp[h >> 2] & mask) == mask); 34147c478bd9Sstevel@tonic-gate case 1: 34157c478bd9Sstevel@tonic-gate mask = 0x01 << (h & 0x7); 34167c478bd9Sstevel@tonic-gate return ((cp[h >> 3] & mask) == mask); 34177c478bd9Sstevel@tonic-gate default: 34187c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "isblock bad fs_frag %d\n", fs->fs_frag); 34197c478bd9Sstevel@tonic-gate return (0); 34207c478bd9Sstevel@tonic-gate } 34217c478bd9Sstevel@tonic-gate } 34227c478bd9Sstevel@tonic-gate 34237c478bd9Sstevel@tonic-gate /* 34247c478bd9Sstevel@tonic-gate * take a block out of the map 34257c478bd9Sstevel@tonic-gate */ 34267c478bd9Sstevel@tonic-gate static void 34277c478bd9Sstevel@tonic-gate clrblock(struct fs *fs, unsigned char *cp, int h) 34287c478bd9Sstevel@tonic-gate { 34297c478bd9Sstevel@tonic-gate switch ((fs)->fs_frag) { 34307c478bd9Sstevel@tonic-gate case 8: 34317c478bd9Sstevel@tonic-gate cp[h] = 0; 34327c478bd9Sstevel@tonic-gate return; 34337c478bd9Sstevel@tonic-gate case 4: 34347c478bd9Sstevel@tonic-gate cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); 34357c478bd9Sstevel@tonic-gate return; 34367c478bd9Sstevel@tonic-gate case 2: 34377c478bd9Sstevel@tonic-gate cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); 34387c478bd9Sstevel@tonic-gate return; 34397c478bd9Sstevel@tonic-gate case 1: 34407c478bd9Sstevel@tonic-gate cp[h >> 3] &= ~(0x01 << (h & 0x7)); 34417c478bd9Sstevel@tonic-gate return; 34427c478bd9Sstevel@tonic-gate default: 34437c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 34447c478bd9Sstevel@tonic-gate gettext("clrblock: bad fs_frag value %d\n"), fs->fs_frag); 34457c478bd9Sstevel@tonic-gate return; 34467c478bd9Sstevel@tonic-gate } 34477c478bd9Sstevel@tonic-gate } 34487c478bd9Sstevel@tonic-gate 34497c478bd9Sstevel@tonic-gate /* 34507c478bd9Sstevel@tonic-gate * put a block into the map 34517c478bd9Sstevel@tonic-gate */ 34527c478bd9Sstevel@tonic-gate static void 34537c478bd9Sstevel@tonic-gate setblock(struct fs *fs, unsigned char *cp, int h) 34547c478bd9Sstevel@tonic-gate { 34557c478bd9Sstevel@tonic-gate switch (fs->fs_frag) { 34567c478bd9Sstevel@tonic-gate case 8: 34577c478bd9Sstevel@tonic-gate cp[h] = 0xff; 34587c478bd9Sstevel@tonic-gate return; 34597c478bd9Sstevel@tonic-gate case 4: 34607c478bd9Sstevel@tonic-gate cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); 34617c478bd9Sstevel@tonic-gate return; 34627c478bd9Sstevel@tonic-gate case 2: 34637c478bd9Sstevel@tonic-gate cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); 34647c478bd9Sstevel@tonic-gate return; 34657c478bd9Sstevel@tonic-gate case 1: 34667c478bd9Sstevel@tonic-gate cp[h >> 3] |= (0x01 << (h & 0x7)); 34677c478bd9Sstevel@tonic-gate return; 34687c478bd9Sstevel@tonic-gate default: 34697c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 34707c478bd9Sstevel@tonic-gate gettext("setblock: bad fs_frag value %d\n"), fs->fs_frag); 34717c478bd9Sstevel@tonic-gate return; 34727c478bd9Sstevel@tonic-gate } 34737c478bd9Sstevel@tonic-gate } 34747c478bd9Sstevel@tonic-gate 34757c478bd9Sstevel@tonic-gate static void 34767c478bd9Sstevel@tonic-gate usage() 34777c478bd9Sstevel@tonic-gate { 34787c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 34797c478bd9Sstevel@tonic-gate gettext("ufs usage: mkfs [-F FSType] [-V] [-m] [-o options] " 3480d50c8f90Svsakar "special " /* param 0 */ 3481d50c8f90Svsakar "size(sectors) \\ \n")); /* param 1 */ 34827c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3483d50c8f90Svsakar "[nsect " /* param 2 */ 3484d50c8f90Svsakar "ntrack " /* param 3 */ 3485d50c8f90Svsakar "bsize " /* param 4 */ 3486d50c8f90Svsakar "fragsize " /* param 5 */ 3487d50c8f90Svsakar "cpg " /* param 6 */ 3488d50c8f90Svsakar "free " /* param 7 */ 3489d50c8f90Svsakar "rps " /* param 8 */ 3490d50c8f90Svsakar "nbpi " /* param 9 */ 3491d50c8f90Svsakar "opt " /* param 10 */ 3492d50c8f90Svsakar "apc " /* param 11 */ 3493d50c8f90Svsakar "gap " /* param 12 */ 3494d50c8f90Svsakar "nrpos " /* param 13 */ 3495d50c8f90Svsakar "maxcontig " /* param 14 */ 3496d50c8f90Svsakar "mtb]\n"); /* param 15 */ 34977c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3498d50c8f90Svsakar gettext(" -m : dump fs cmd line used to make this partition\n" 3499d50c8f90Svsakar " -V :print this command line and return\n" 3500d50c8f90Svsakar " -o :ufs options: :nsect=%d,ntrack=%d,bsize=%d,fragsize=%d\n" 3501d50c8f90Svsakar " -o :ufs options: :cgsize=%d,free=%d,rps=%d,nbpi=%d,opt=%c\n" 3502d50c8f90Svsakar " -o :ufs options: :apc=%d,gap=%d,nrpos=%d,maxcontig=%d\n" 3503d50c8f90Svsakar " -o :ufs options: :mtb=%c,calcsb,calcbinsb\n" 35047c478bd9Sstevel@tonic-gate "NOTE that all -o suboptions: must be separated only by commas so as to\n" 35057c478bd9Sstevel@tonic-gate "be parsed as a single argument\n"), 3506d50c8f90Svsakar nsect, ntrack, bsize, fragsize, cpg, sblock.fs_minfree, rps, 3507d50c8f90Svsakar nbpi, opt, apc, (rotdelay == -1) ? 0 : rotdelay, 3508d50c8f90Svsakar sblock.fs_nrpos, maxcontig, mtb); 35097c478bd9Sstevel@tonic-gate lockexit(32); 35107c478bd9Sstevel@tonic-gate } 35117c478bd9Sstevel@tonic-gate 35127c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 35137c478bd9Sstevel@tonic-gate static void 35147c478bd9Sstevel@tonic-gate dump_fscmd(char *fsys, int fsi) 35157c478bd9Sstevel@tonic-gate { 35167c478bd9Sstevel@tonic-gate int64_t used, bpcg, inospercg; 35177c478bd9Sstevel@tonic-gate int64_t nbpi; 35187c478bd9Sstevel@tonic-gate uint64_t nbytes64; 35197c478bd9Sstevel@tonic-gate 35207c478bd9Sstevel@tonic-gate bzero((char *)&sblock, sizeof (sblock)); 35217c478bd9Sstevel@tonic-gate rdfs((diskaddr_t)SBLOCK, SBSIZE, (char *)&sblock); 35227c478bd9Sstevel@tonic-gate 35237c478bd9Sstevel@tonic-gate /* 35247c478bd9Sstevel@tonic-gate * ensure a valid file system and if not, exit with error or else 35257c478bd9Sstevel@tonic-gate * we will end up computing block numbers etc and dividing by zero 35267c478bd9Sstevel@tonic-gate * which will cause floating point errors in this routine. 35277c478bd9Sstevel@tonic-gate */ 35287c478bd9Sstevel@tonic-gate 35297c478bd9Sstevel@tonic-gate if ((sblock.fs_magic != FS_MAGIC) && 35307c478bd9Sstevel@tonic-gate (sblock.fs_magic != MTB_UFS_MAGIC)) { 3531d50c8f90Svsakar (void) fprintf(stderr, gettext( 3532d50c8f90Svsakar "[not currently a valid file system - bad superblock]\n")); 35337c478bd9Sstevel@tonic-gate lockexit(32); 35347c478bd9Sstevel@tonic-gate } 35357c478bd9Sstevel@tonic-gate 35366451fdbcSvsakar if (sblock.fs_magic == FS_MAGIC && 35376451fdbcSvsakar (sblock.fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 && 35386451fdbcSvsakar sblock.fs_version != UFS_VERSION_MIN)) { 3539d50c8f90Svsakar (void) fprintf(stderr, gettext( 3540d50c8f90Svsakar "Unknown version of UFS format: %d\n"), sblock.fs_version); 35416451fdbcSvsakar lockexit(32); 35426451fdbcSvsakar } 35436451fdbcSvsakar 35447c478bd9Sstevel@tonic-gate if (sblock.fs_magic == MTB_UFS_MAGIC && 35457c478bd9Sstevel@tonic-gate (sblock.fs_version > MTB_UFS_VERSION_1 || 35467c478bd9Sstevel@tonic-gate sblock.fs_version < MTB_UFS_VERSION_MIN)) { 3547d50c8f90Svsakar (void) fprintf(stderr, gettext( 3548d50c8f90Svsakar "Unknown version of UFS format: %d\n"), sblock.fs_version); 35497c478bd9Sstevel@tonic-gate lockexit(32); 35507c478bd9Sstevel@tonic-gate } 35517c478bd9Sstevel@tonic-gate 35527c478bd9Sstevel@tonic-gate /* 35537c478bd9Sstevel@tonic-gate * Compute a reasonable nbpi value. 35547c478bd9Sstevel@tonic-gate * The algorithm for "used" is copied from code 35557c478bd9Sstevel@tonic-gate * in main() verbatim. 35567c478bd9Sstevel@tonic-gate * The nbpi equation is taken from main where the 35577c478bd9Sstevel@tonic-gate * fs_ipg value is set for the last time. The INOPB(...) - 1 35587c478bd9Sstevel@tonic-gate * is used to account for the roundup. 35597c478bd9Sstevel@tonic-gate * The problem is that a range of nbpi values map to 35607c478bd9Sstevel@tonic-gate * the same file system layout. So it is not possible 35617c478bd9Sstevel@tonic-gate * to calculate the exact value specified when the file 35627c478bd9Sstevel@tonic-gate * system was created. So instead we determine the top 35637c478bd9Sstevel@tonic-gate * end of the range of values. 35647c478bd9Sstevel@tonic-gate */ 35657c478bd9Sstevel@tonic-gate bpcg = sblock.fs_spc * sectorsize; 35667c478bd9Sstevel@tonic-gate inospercg = (int64_t)roundup(bpcg / sizeof (struct dinode), 35677c478bd9Sstevel@tonic-gate INOPB(&sblock)); 35687c478bd9Sstevel@tonic-gate if (inospercg > MAXIpG(&sblock)) 35697c478bd9Sstevel@tonic-gate inospercg = MAXIpG(&sblock); 35707c478bd9Sstevel@tonic-gate used = (int64_t) 35717c478bd9Sstevel@tonic-gate (sblock.fs_iblkno + inospercg / INOPF(&sblock)) * NSPF(&sblock); 35727c478bd9Sstevel@tonic-gate used *= sectorsize; 35737c478bd9Sstevel@tonic-gate nbytes64 = (uint64_t)sblock.fs_cpg * bpcg - used; 35747c478bd9Sstevel@tonic-gate 35757c478bd9Sstevel@tonic-gate /* 35767c478bd9Sstevel@tonic-gate * The top end of the range of values for nbpi may not be 35777c478bd9Sstevel@tonic-gate * a valid command line value for mkfs. Report the bottom 35787c478bd9Sstevel@tonic-gate * end instead. 35797c478bd9Sstevel@tonic-gate */ 35807c478bd9Sstevel@tonic-gate nbpi = (int64_t)(nbytes64 / (sblock.fs_ipg)); 35817c478bd9Sstevel@tonic-gate 35827c478bd9Sstevel@tonic-gate (void) fprintf(stdout, gettext("mkfs -F ufs -o "), fsys); 35837c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "nsect=%d,ntrack=%d,", 35847c478bd9Sstevel@tonic-gate sblock.fs_nsect, sblock.fs_ntrak); 35857c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "bsize=%d,fragsize=%d,cgsize=%d,free=%d,", 35867c478bd9Sstevel@tonic-gate sblock.fs_bsize, sblock.fs_fsize, sblock.fs_cpg, sblock.fs_minfree); 35877c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "rps=%d,nbpi=%lld,opt=%c,apc=%d,gap=%d,", 35887c478bd9Sstevel@tonic-gate sblock.fs_rps, nbpi, (sblock.fs_optim == FS_OPTSPACE) ? 's' : 't', 35897c478bd9Sstevel@tonic-gate (sblock.fs_ntrak * sblock.fs_nsect) - sblock.fs_spc, 35907c478bd9Sstevel@tonic-gate sblock.fs_rotdelay); 35917c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "nrpos=%d,maxcontig=%d,mtb=%c ", 35927c478bd9Sstevel@tonic-gate sblock.fs_nrpos, sblock.fs_maxcontig, 35937c478bd9Sstevel@tonic-gate ((sblock.fs_magic == MTB_UFS_MAGIC) ? 'y' : 'n')); 35947c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "%s %lld\n", fsys, 35957c478bd9Sstevel@tonic-gate fsbtodb(&sblock, sblock.fs_size)); 35967c478bd9Sstevel@tonic-gate 35977c478bd9Sstevel@tonic-gate bzero((char *)&sblock, sizeof (sblock)); 35987c478bd9Sstevel@tonic-gate } 35997c478bd9Sstevel@tonic-gate 36007c478bd9Sstevel@tonic-gate /* number ************************************************************* */ 36017c478bd9Sstevel@tonic-gate /* */ 36027c478bd9Sstevel@tonic-gate /* Convert a numeric string arg to binary */ 36037c478bd9Sstevel@tonic-gate /* */ 36047c478bd9Sstevel@tonic-gate /* Args: d_value - default value, if have parse error */ 36057c478bd9Sstevel@tonic-gate /* param - the name of the argument, for error messages */ 36067c478bd9Sstevel@tonic-gate /* flags - parser state and what's allowed in the arg */ 36077c478bd9Sstevel@tonic-gate /* Global arg: string - pointer to command arg */ 36087c478bd9Sstevel@tonic-gate /* */ 36097c478bd9Sstevel@tonic-gate /* Valid forms: 123 | 123k | 123*123 | 123x123 */ 36107c478bd9Sstevel@tonic-gate /* */ 36117c478bd9Sstevel@tonic-gate /* Return: converted number */ 36127c478bd9Sstevel@tonic-gate /* */ 36137c478bd9Sstevel@tonic-gate /* ******************************************************************** */ 36147c478bd9Sstevel@tonic-gate 36157c478bd9Sstevel@tonic-gate static uint64_t 36167c478bd9Sstevel@tonic-gate number(uint64_t d_value, char *param, int flags) 36177c478bd9Sstevel@tonic-gate { 36187c478bd9Sstevel@tonic-gate char *cs; 36197c478bd9Sstevel@tonic-gate uint64_t n, t; 36207c478bd9Sstevel@tonic-gate uint64_t cut = BIG / 10; /* limit to avoid overflow */ 36217c478bd9Sstevel@tonic-gate int minus = 0; 36227c478bd9Sstevel@tonic-gate 36237c478bd9Sstevel@tonic-gate cs = string; 36247c478bd9Sstevel@tonic-gate if (*cs == '-') { 36257c478bd9Sstevel@tonic-gate minus = 1; 36267c478bd9Sstevel@tonic-gate cs += 1; 36277c478bd9Sstevel@tonic-gate } 36287c478bd9Sstevel@tonic-gate if ((*cs < '0') || (*cs > '9')) { 36297c478bd9Sstevel@tonic-gate goto bail_out; 36307c478bd9Sstevel@tonic-gate } 36317c478bd9Sstevel@tonic-gate n = 0; 36327c478bd9Sstevel@tonic-gate while ((*cs >= '0') && (*cs <= '9') && (n <= cut)) { 36337c478bd9Sstevel@tonic-gate n = n*10 + *cs++ - '0'; 36347c478bd9Sstevel@tonic-gate } 36357c478bd9Sstevel@tonic-gate if (minus) 3636d50c8f90Svsakar n = -n; 36377c478bd9Sstevel@tonic-gate for (;;) { 36387c478bd9Sstevel@tonic-gate switch (*cs++) { 36397c478bd9Sstevel@tonic-gate case 'k': 36407c478bd9Sstevel@tonic-gate if (flags & ALLOW_END_ONLY) 36417c478bd9Sstevel@tonic-gate goto bail_out; 36427c478bd9Sstevel@tonic-gate if (n > (BIG / 1024)) 36437c478bd9Sstevel@tonic-gate goto overflow; 36447c478bd9Sstevel@tonic-gate n *= 1024; 36457c478bd9Sstevel@tonic-gate continue; 36467c478bd9Sstevel@tonic-gate 36477c478bd9Sstevel@tonic-gate case '*': 36487c478bd9Sstevel@tonic-gate case 'x': 36497c478bd9Sstevel@tonic-gate if (flags & ALLOW_END_ONLY) 36507c478bd9Sstevel@tonic-gate goto bail_out; 36517c478bd9Sstevel@tonic-gate string = cs; 36527c478bd9Sstevel@tonic-gate t = number(d_value, param, flags); 36537c478bd9Sstevel@tonic-gate if (n > (BIG / t)) 36547c478bd9Sstevel@tonic-gate goto overflow; 36557c478bd9Sstevel@tonic-gate n *= t; 36567c478bd9Sstevel@tonic-gate cs = string + 1; /* adjust for -- below */ 36577c478bd9Sstevel@tonic-gate 36587c478bd9Sstevel@tonic-gate /* recursion has read rest of expression */ 36597c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 36607c478bd9Sstevel@tonic-gate 36617c478bd9Sstevel@tonic-gate case ',': 36627c478bd9Sstevel@tonic-gate case '\0': 36637c478bd9Sstevel@tonic-gate cs--; 36647c478bd9Sstevel@tonic-gate string = cs; 36657c478bd9Sstevel@tonic-gate return (n); 36667c478bd9Sstevel@tonic-gate 36677c478bd9Sstevel@tonic-gate case '%': 36687c478bd9Sstevel@tonic-gate if (flags & ALLOW_END_ONLY) 36697c478bd9Sstevel@tonic-gate goto bail_out; 36707c478bd9Sstevel@tonic-gate if (flags & ALLOW_PERCENT) { 36717c478bd9Sstevel@tonic-gate flags &= ~ALLOW_PERCENT; 36727c478bd9Sstevel@tonic-gate flags |= ALLOW_END_ONLY; 36737c478bd9Sstevel@tonic-gate continue; 36747c478bd9Sstevel@tonic-gate } 36757c478bd9Sstevel@tonic-gate goto bail_out; 36767c478bd9Sstevel@tonic-gate 36777c478bd9Sstevel@tonic-gate case 'm': 36787c478bd9Sstevel@tonic-gate if (flags & ALLOW_END_ONLY) 36797c478bd9Sstevel@tonic-gate goto bail_out; 36807c478bd9Sstevel@tonic-gate if (flags & ALLOW_MS1) { 36817c478bd9Sstevel@tonic-gate flags &= ~ALLOW_MS1; 36827c478bd9Sstevel@tonic-gate flags |= ALLOW_MS2; 36837c478bd9Sstevel@tonic-gate continue; 36847c478bd9Sstevel@tonic-gate } 36857c478bd9Sstevel@tonic-gate goto bail_out; 36867c478bd9Sstevel@tonic-gate 36877c478bd9Sstevel@tonic-gate case 's': 36887c478bd9Sstevel@tonic-gate if (flags & ALLOW_END_ONLY) 36897c478bd9Sstevel@tonic-gate goto bail_out; 36907c478bd9Sstevel@tonic-gate if (flags & ALLOW_MS2) { 36917c478bd9Sstevel@tonic-gate flags &= ~ALLOW_MS2; 36927c478bd9Sstevel@tonic-gate flags |= ALLOW_END_ONLY; 36937c478bd9Sstevel@tonic-gate continue; 36947c478bd9Sstevel@tonic-gate } 36957c478bd9Sstevel@tonic-gate goto bail_out; 36967c478bd9Sstevel@tonic-gate 36977c478bd9Sstevel@tonic-gate case '0': case '1': case '2': case '3': case '4': 36987c478bd9Sstevel@tonic-gate case '5': case '6': case '7': case '8': case '9': 36997c478bd9Sstevel@tonic-gate overflow: 37007c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 37017c478bd9Sstevel@tonic-gate gettext("mkfs: value for %s overflowed\n"), 37027c478bd9Sstevel@tonic-gate param); 37037c478bd9Sstevel@tonic-gate while ((*cs != '\0') && (*cs != ',')) 37047c478bd9Sstevel@tonic-gate cs++; 37057c478bd9Sstevel@tonic-gate string = cs; 37067c478bd9Sstevel@tonic-gate return (BIG); 37077c478bd9Sstevel@tonic-gate 37087c478bd9Sstevel@tonic-gate default: 37097c478bd9Sstevel@tonic-gate bail_out: 37107c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 37117c478bd9Sstevel@tonic-gate "mkfs: bad numeric arg for %s: \"%s\"\n"), 37127c478bd9Sstevel@tonic-gate param, string); 37137c478bd9Sstevel@tonic-gate while ((*cs != '\0') && (*cs != ',')) 37147c478bd9Sstevel@tonic-gate cs++; 37157c478bd9Sstevel@tonic-gate string = cs; 37167c478bd9Sstevel@tonic-gate if (d_value != NO_DEFAULT) { 37177c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 37187c478bd9Sstevel@tonic-gate gettext("mkfs: %s reset to default %lld\n"), 37197c478bd9Sstevel@tonic-gate param, d_value); 37207c478bd9Sstevel@tonic-gate return (d_value); 37217c478bd9Sstevel@tonic-gate } 37227c478bd9Sstevel@tonic-gate lockexit(2); 37237c478bd9Sstevel@tonic-gate 37247c478bd9Sstevel@tonic-gate } 37257c478bd9Sstevel@tonic-gate } /* never gets here */ 37267c478bd9Sstevel@tonic-gate } 37277c478bd9Sstevel@tonic-gate 37287c478bd9Sstevel@tonic-gate /* match ************************************************************** */ 37297c478bd9Sstevel@tonic-gate /* */ 37307c478bd9Sstevel@tonic-gate /* Compare two text strings for equality */ 37317c478bd9Sstevel@tonic-gate /* */ 37327c478bd9Sstevel@tonic-gate /* Arg: s - pointer to string to match with a command arg */ 37337c478bd9Sstevel@tonic-gate /* Global arg: string - pointer to command arg */ 37347c478bd9Sstevel@tonic-gate /* */ 37357c478bd9Sstevel@tonic-gate /* Return: 1 if match, 0 if no match */ 37367c478bd9Sstevel@tonic-gate /* If match, also reset `string' to point to the text */ 37377c478bd9Sstevel@tonic-gate /* that follows the matching text. */ 37387c478bd9Sstevel@tonic-gate /* */ 37397c478bd9Sstevel@tonic-gate /* ******************************************************************** */ 37407c478bd9Sstevel@tonic-gate 37417c478bd9Sstevel@tonic-gate static int 37427c478bd9Sstevel@tonic-gate match(char *s) 37437c478bd9Sstevel@tonic-gate { 37447c478bd9Sstevel@tonic-gate char *cs; 37457c478bd9Sstevel@tonic-gate 37467c478bd9Sstevel@tonic-gate cs = string; 37477c478bd9Sstevel@tonic-gate while (*cs++ == *s) { 37487c478bd9Sstevel@tonic-gate if (*s++ == '\0') { 37497c478bd9Sstevel@tonic-gate goto true; 37507c478bd9Sstevel@tonic-gate } 37517c478bd9Sstevel@tonic-gate } 37527c478bd9Sstevel@tonic-gate if (*s != '\0') { 37537c478bd9Sstevel@tonic-gate return (0); 37547c478bd9Sstevel@tonic-gate } 37557c478bd9Sstevel@tonic-gate 37567c478bd9Sstevel@tonic-gate true: 37577c478bd9Sstevel@tonic-gate cs--; 37587c478bd9Sstevel@tonic-gate string = cs; 37597c478bd9Sstevel@tonic-gate return (1); 37607c478bd9Sstevel@tonic-gate } 37617c478bd9Sstevel@tonic-gate 37627c478bd9Sstevel@tonic-gate /* 37637c478bd9Sstevel@tonic-gate * GROWFS ROUTINES 37647c478bd9Sstevel@tonic-gate */ 37657c478bd9Sstevel@tonic-gate 37667c478bd9Sstevel@tonic-gate /* ARGSUSED */ 37677c478bd9Sstevel@tonic-gate void 37687c478bd9Sstevel@tonic-gate lockexit(int exitstatus) 37697c478bd9Sstevel@tonic-gate { 37707c478bd9Sstevel@tonic-gate if (Pflag) { 37717c478bd9Sstevel@tonic-gate /* the probe mode neither changes nor locks the filesystem */ 37727c478bd9Sstevel@tonic-gate exit(exitstatus); 37737c478bd9Sstevel@tonic-gate } 37747c478bd9Sstevel@tonic-gate 37757c478bd9Sstevel@tonic-gate /* 37767c478bd9Sstevel@tonic-gate * flush the dirty cylinder group 37777c478bd9Sstevel@tonic-gate */ 37787c478bd9Sstevel@tonic-gate if (inlockexit == 0) { 37797c478bd9Sstevel@tonic-gate inlockexit = 1; 37807c478bd9Sstevel@tonic-gate flcg(); 37817c478bd9Sstevel@tonic-gate } 37827c478bd9Sstevel@tonic-gate 37837c478bd9Sstevel@tonic-gate if (aio_inited) { 37847c478bd9Sstevel@tonic-gate flush_writes(); 37857c478bd9Sstevel@tonic-gate } 37867c478bd9Sstevel@tonic-gate 37877c478bd9Sstevel@tonic-gate /* 37887c478bd9Sstevel@tonic-gate * make sure the file system is unlocked before exiting 37897c478bd9Sstevel@tonic-gate */ 37907c478bd9Sstevel@tonic-gate if ((inlockexit == 1) && (!isbad)) { 37917c478bd9Sstevel@tonic-gate inlockexit = 2; 37927c478bd9Sstevel@tonic-gate ulockfs(); 37937c478bd9Sstevel@tonic-gate /* 37947c478bd9Sstevel@tonic-gate * if logging was enabled, then re-enable it 37957c478bd9Sstevel@tonic-gate */ 37967c478bd9Sstevel@tonic-gate if (waslog) { 37977c478bd9Sstevel@tonic-gate if (rl_log_control(fsys, _FIOLOGENABLE) != RL_SUCCESS) { 37987c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3799d50c8f90Svsakar "failed to re-enable logging\n")); 38007c478bd9Sstevel@tonic-gate } 38017c478bd9Sstevel@tonic-gate } 38027c478bd9Sstevel@tonic-gate } else if (grow) { 38037c478bd9Sstevel@tonic-gate if (isbad) { 38047c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3805d50c8f90Svsakar "Filesystem is currently inconsistent. It " 3806d50c8f90Svsakar "must be repaired with fsck(1M)\nbefore being " 3807d50c8f90Svsakar "used. Use the following command to " 3808d50c8f90Svsakar "do this:\n\n\tfsck %s\n\n"), fsys); 38097c478bd9Sstevel@tonic-gate 38107c478bd9Sstevel@tonic-gate if (ismounted) { 38117c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3812d50c8f90Svsakar "You will be told that the filesystem " 3813d50c8f90Svsakar "is already mounted, and asked if you\n" 3814d50c8f90Svsakar "wish to continue. Answer `yes' to " 3815d50c8f90Svsakar "this question.\n\n")); 38167c478bd9Sstevel@tonic-gate } 38177c478bd9Sstevel@tonic-gate 38187c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3819d50c8f90Svsakar "One problem should be reported, that the summary " 3820d50c8f90Svsakar "information is bad.\nYou will then be asked if it " 3821d50c8f90Svsakar "should be salvaged. Answer `yes' to\nthis " 3822d50c8f90Svsakar "question.\n\n")); 38237c478bd9Sstevel@tonic-gate } 38247c478bd9Sstevel@tonic-gate 38257c478bd9Sstevel@tonic-gate if (ismounted) { 38267c478bd9Sstevel@tonic-gate /* 38277c478bd9Sstevel@tonic-gate * In theory, there's no way to get here without 38287c478bd9Sstevel@tonic-gate * isbad also being set, but be robust in the 38297c478bd9Sstevel@tonic-gate * face of future code changes. 38307c478bd9Sstevel@tonic-gate */ 38317c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3832d50c8f90Svsakar "The filesystem is currently mounted " 3833d50c8f90Svsakar "read-only and write-locked. ")); 38347c478bd9Sstevel@tonic-gate if (isbad) { 38357c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3836d50c8f90Svsakar "After\nrunning fsck, unlock the " 3837d50c8f90Svsakar "filesystem and ")); 38387c478bd9Sstevel@tonic-gate } else { 38397c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3840d50c8f90Svsakar "Unlock the filesystem\nand ")); 38417c478bd9Sstevel@tonic-gate } 38427c478bd9Sstevel@tonic-gate 38437c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3844d50c8f90Svsakar "re-enable writing with\nthe following " 3845d50c8f90Svsakar "command:\n\n\tlockfs -u %s\n\n"), directory); 38467c478bd9Sstevel@tonic-gate } 38477c478bd9Sstevel@tonic-gate } 38487c478bd9Sstevel@tonic-gate 38497c478bd9Sstevel@tonic-gate exit(exitstatus); 38507c478bd9Sstevel@tonic-gate } 38517c478bd9Sstevel@tonic-gate 38527c478bd9Sstevel@tonic-gate void 38537c478bd9Sstevel@tonic-gate randomgeneration() 38547c478bd9Sstevel@tonic-gate { 38557c478bd9Sstevel@tonic-gate int i; 38567c478bd9Sstevel@tonic-gate struct dinode *dp; 38577c478bd9Sstevel@tonic-gate 38587c478bd9Sstevel@tonic-gate /* 38597c478bd9Sstevel@tonic-gate * always perform fsirand(1) function... newfs will notice that 38607c478bd9Sstevel@tonic-gate * the inodes have been randomized and will not call fsirand itself 38617c478bd9Sstevel@tonic-gate */ 38627c478bd9Sstevel@tonic-gate for (i = 0, dp = zino; i < sblock.fs_inopb; ++i, ++dp) 38637c478bd9Sstevel@tonic-gate IRANDOMIZE(&dp->di_ic); 38647c478bd9Sstevel@tonic-gate } 38657c478bd9Sstevel@tonic-gate 38667c478bd9Sstevel@tonic-gate /* 38677c478bd9Sstevel@tonic-gate * Check the size of the summary information. 38687c478bd9Sstevel@tonic-gate * Fields in sblock are not changed in this function. 38697c478bd9Sstevel@tonic-gate * 38707c478bd9Sstevel@tonic-gate * For an 8K filesystem block, the maximum number of cylinder groups is 16384. 38717c478bd9Sstevel@tonic-gate * MAXCSBUFS {32} * 8K {FS block size} 38727c478bd9Sstevel@tonic-gate * divided by (sizeof csum) {16} 38737c478bd9Sstevel@tonic-gate * 38747c478bd9Sstevel@tonic-gate * Note that MAXCSBUFS is not used in the kernel; as of Solaris 2.6 build 32, 38757c478bd9Sstevel@tonic-gate * this is the only place where it's referenced. 38767c478bd9Sstevel@tonic-gate */ 38777c478bd9Sstevel@tonic-gate void 38787c478bd9Sstevel@tonic-gate checksummarysize() 38797c478bd9Sstevel@tonic-gate { 38807c478bd9Sstevel@tonic-gate diskaddr_t dmax; 38817c478bd9Sstevel@tonic-gate diskaddr_t dmin; 38827c478bd9Sstevel@tonic-gate int64_t cg0frags; 38837c478bd9Sstevel@tonic-gate int64_t cg0blocks; 38847c478bd9Sstevel@tonic-gate int64_t maxncg; 38857c478bd9Sstevel@tonic-gate int64_t maxfrags; 38867c478bd9Sstevel@tonic-gate uint64_t fs_size; 38877c478bd9Sstevel@tonic-gate uint64_t maxfs_blocks; /* filesystem blocks for max filesystem size */ 38887c478bd9Sstevel@tonic-gate 38897c478bd9Sstevel@tonic-gate /* 38907c478bd9Sstevel@tonic-gate * compute the maximum summary info size 38917c478bd9Sstevel@tonic-gate */ 38927c478bd9Sstevel@tonic-gate dmin = cgdmin(&sblock, 0); 38937c478bd9Sstevel@tonic-gate dmax = cgbase(&sblock, 0) + sblock.fs_fpg; 38947c478bd9Sstevel@tonic-gate fs_size = (grow) ? grow_fs_size : sblock.fs_size; 38957c478bd9Sstevel@tonic-gate if (dmax > fs_size) 38967c478bd9Sstevel@tonic-gate dmax = fs_size; 38977c478bd9Sstevel@tonic-gate cg0frags = dmax - dmin; 38987c478bd9Sstevel@tonic-gate cg0blocks = cg0frags / sblock.fs_frag; 38997c478bd9Sstevel@tonic-gate cg0frags = cg0blocks * sblock.fs_frag; 39007c478bd9Sstevel@tonic-gate maxncg = (longlong_t)cg0blocks * 39017c478bd9Sstevel@tonic-gate (longlong_t)(sblock.fs_bsize / sizeof (struct csum)); 39027c478bd9Sstevel@tonic-gate 39037c478bd9Sstevel@tonic-gate maxfs_blocks = FS_MAX; 39047c478bd9Sstevel@tonic-gate 39057c478bd9Sstevel@tonic-gate if (maxncg > ((longlong_t)maxfs_blocks / (longlong_t)sblock.fs_fpg) + 1) 39067c478bd9Sstevel@tonic-gate maxncg = ((longlong_t)maxfs_blocks / 39077c478bd9Sstevel@tonic-gate (longlong_t)sblock.fs_fpg) + 1; 39087c478bd9Sstevel@tonic-gate 39097c478bd9Sstevel@tonic-gate maxfrags = maxncg * (longlong_t)sblock.fs_fpg; 39107c478bd9Sstevel@tonic-gate 39117c478bd9Sstevel@tonic-gate if (maxfrags > maxfs_blocks) 39127c478bd9Sstevel@tonic-gate maxfrags = maxfs_blocks; 39137c478bd9Sstevel@tonic-gate 39147c478bd9Sstevel@tonic-gate 39157c478bd9Sstevel@tonic-gate /* 39167c478bd9Sstevel@tonic-gate * remember for later processing in extendsummaryinfo() 39177c478bd9Sstevel@tonic-gate */ 39187c478bd9Sstevel@tonic-gate if (test) 39197c478bd9Sstevel@tonic-gate grow_sifrag = dmin + (cg0blocks * sblock.fs_frag); 39207c478bd9Sstevel@tonic-gate if (testfrags == 0) 39217c478bd9Sstevel@tonic-gate testfrags = cg0frags; 39227c478bd9Sstevel@tonic-gate if (testforce) 39237c478bd9Sstevel@tonic-gate if (testfrags > cg0frags) { 39247c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3925d50c8f90Svsakar gettext("Too many test frags (%lld); " 3926d50c8f90Svsakar "try %lld\n"), testfrags, cg0frags); 39277c478bd9Sstevel@tonic-gate lockexit(32); 39287c478bd9Sstevel@tonic-gate } 39297c478bd9Sstevel@tonic-gate 39307c478bd9Sstevel@tonic-gate /* 39317c478bd9Sstevel@tonic-gate * if summary info is too large (too many cg's) tell the user and exit 39327c478bd9Sstevel@tonic-gate */ 39337c478bd9Sstevel@tonic-gate if ((longlong_t)sblock.fs_size > maxfrags) { 39347c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 39357c478bd9Sstevel@tonic-gate "Too many cylinder groups with %llu sectors;\n try " 39367c478bd9Sstevel@tonic-gate "increasing cgsize, or decreasing fssize to %llu\n"), 39377c478bd9Sstevel@tonic-gate fsbtodb(&sblock, (uint64_t)sblock.fs_size), 39387c478bd9Sstevel@tonic-gate fsbtodb(&sblock, (uint64_t)maxfrags)); 39397c478bd9Sstevel@tonic-gate lockexit(32); 39407c478bd9Sstevel@tonic-gate } 39417c478bd9Sstevel@tonic-gate } 39427c478bd9Sstevel@tonic-gate 39436451fdbcSvsakar /* 39446451fdbcSvsakar * checksblock() has two uses: 39456451fdbcSvsakar * - One is to sanity test the superblock and is used when newfs(1M) 39466451fdbcSvsakar * is invoked with the "-N" option. If any discrepancy was found, 39476451fdbcSvsakar * just return whatever error was found and do not exit. 39486451fdbcSvsakar * - the other use of it is in places where you expect the superblock 39496451fdbcSvsakar * to be sane, and if it isn't, then we exit. 39506451fdbcSvsakar * Which of the above two actions to take is indicated with the second argument. 39516451fdbcSvsakar */ 39527c478bd9Sstevel@tonic-gate 39536451fdbcSvsakar int 39546451fdbcSvsakar checksblock(struct fs sb, int proceed) 39556451fdbcSvsakar { 39566451fdbcSvsakar int err = 0; 39576451fdbcSvsakar char *errmsg; 39586451fdbcSvsakar 39596451fdbcSvsakar if ((sb.fs_magic != FS_MAGIC) && (sb.fs_magic != MTB_UFS_MAGIC)) { 3960d50c8f90Svsakar err = 1; 3961d50c8f90Svsakar errmsg = gettext("Bad superblock; magic number wrong\n"); 39626451fdbcSvsakar } else if ((sb.fs_magic == FS_MAGIC && 3963d50c8f90Svsakar (sb.fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 && 3964d50c8f90Svsakar sb.fs_version != UFS_VERSION_MIN)) || 3965d50c8f90Svsakar (sb.fs_magic == MTB_UFS_MAGIC && 3966d50c8f90Svsakar (sb.fs_version > MTB_UFS_VERSION_1 || 3967d50c8f90Svsakar sb.fs_version < MTB_UFS_VERSION_MIN))) { 3968d50c8f90Svsakar err = 2; 3969d50c8f90Svsakar errmsg = gettext("Unrecognized version of UFS\n"); 39706451fdbcSvsakar } else if (sb.fs_ncg < 1) { 3971d50c8f90Svsakar err = 3; 3972d50c8f90Svsakar errmsg = gettext("Bad superblock; ncg out of range\n"); 39736451fdbcSvsakar } else if (sb.fs_cpg < 1) { 3974d50c8f90Svsakar err = 4; 3975d50c8f90Svsakar errmsg = gettext("Bad superblock; cpg out of range\n"); 39766451fdbcSvsakar } else if (sb.fs_ncg * sb.fs_cpg < sb.fs_ncyl || 3977d50c8f90Svsakar (sb.fs_ncg - 1) * sb.fs_cpg >= sb.fs_ncyl) { 3978d50c8f90Svsakar err = 5; 3979d50c8f90Svsakar errmsg = gettext("Bad superblock; ncyl out of range\n"); 39806451fdbcSvsakar } else if (sb.fs_sbsize <= 0 || sb.fs_sbsize > sb.fs_bsize) { 3981d50c8f90Svsakar err = 6; 3982d50c8f90Svsakar errmsg = gettext("Bad superblock; superblock size out of " 3983d50c8f90Svsakar "range\n"); 39846451fdbcSvsakar } 39856451fdbcSvsakar 39866451fdbcSvsakar if (proceed) { 39876451fdbcSvsakar if (err) dprintf(("%s", errmsg)); 39886451fdbcSvsakar return (err); 39896451fdbcSvsakar } 39906451fdbcSvsakar 39916451fdbcSvsakar if (err) { 39926451fdbcSvsakar fprintf(stderr, "%s", errmsg); 39937c478bd9Sstevel@tonic-gate lockexit(32); 39947c478bd9Sstevel@tonic-gate } 3995d1a180b0Smaheshvs return (32); 39967c478bd9Sstevel@tonic-gate } 39977c478bd9Sstevel@tonic-gate 39987c478bd9Sstevel@tonic-gate /* 39997c478bd9Sstevel@tonic-gate * Roll the embedded log, if any, and set up the global variables 40007c478bd9Sstevel@tonic-gate * islog, islogok and isufslog. 40017c478bd9Sstevel@tonic-gate */ 40027c478bd9Sstevel@tonic-gate static void 40037c478bd9Sstevel@tonic-gate logsetup(char *devstr) 40047c478bd9Sstevel@tonic-gate { 40057c478bd9Sstevel@tonic-gate void *buf, *ud_buf; 40067c478bd9Sstevel@tonic-gate extent_block_t *ebp; 40077c478bd9Sstevel@tonic-gate ml_unit_t *ul; 40087c478bd9Sstevel@tonic-gate ml_odunit_t *ud; 40097c478bd9Sstevel@tonic-gate 40107c478bd9Sstevel@tonic-gate /* 40117c478bd9Sstevel@tonic-gate * Does the superblock indicate that we are supposed to have a log ? 40127c478bd9Sstevel@tonic-gate */ 40137c478bd9Sstevel@tonic-gate if (sblock.fs_logbno == 0) { 40147c478bd9Sstevel@tonic-gate /* 40157c478bd9Sstevel@tonic-gate * No log present, nothing to do. 40167c478bd9Sstevel@tonic-gate */ 40177c478bd9Sstevel@tonic-gate islogok = 0; 40187c478bd9Sstevel@tonic-gate islog = 0; 40197c478bd9Sstevel@tonic-gate isufslog = 0; 40207c478bd9Sstevel@tonic-gate return; 40217c478bd9Sstevel@tonic-gate } else { 40227c478bd9Sstevel@tonic-gate /* 40237c478bd9Sstevel@tonic-gate * There's a log in a yet unknown state, attempt to roll it. 40247c478bd9Sstevel@tonic-gate */ 40257c478bd9Sstevel@tonic-gate islog = 1; 40267c478bd9Sstevel@tonic-gate islogok = 0; 40277c478bd9Sstevel@tonic-gate isufslog = 0; 40287c478bd9Sstevel@tonic-gate 40297c478bd9Sstevel@tonic-gate /* 40307c478bd9Sstevel@tonic-gate * We failed to roll the log, bail out. 40317c478bd9Sstevel@tonic-gate */ 40327c478bd9Sstevel@tonic-gate if (rl_roll_log(devstr) != RL_SUCCESS) 40337c478bd9Sstevel@tonic-gate return; 40347c478bd9Sstevel@tonic-gate 40357c478bd9Sstevel@tonic-gate isufslog = 1; 40367c478bd9Sstevel@tonic-gate 40377c478bd9Sstevel@tonic-gate /* log is not okay; check the fs */ 40387c478bd9Sstevel@tonic-gate if ((FSOKAY != (sblock.fs_state + sblock.fs_time)) || 40397c478bd9Sstevel@tonic-gate (sblock.fs_clean != FSLOG)) 40407c478bd9Sstevel@tonic-gate return; 40417c478bd9Sstevel@tonic-gate 40427c478bd9Sstevel@tonic-gate /* get the log allocation block */ 40437c478bd9Sstevel@tonic-gate buf = (void *)malloc(DEV_BSIZE); 40447c478bd9Sstevel@tonic-gate if (buf == (void *) NULL) 40457c478bd9Sstevel@tonic-gate return; 40467c478bd9Sstevel@tonic-gate 40477c478bd9Sstevel@tonic-gate ud_buf = (void *)malloc(DEV_BSIZE); 40487c478bd9Sstevel@tonic-gate if (ud_buf == (void *) NULL) { 40497c478bd9Sstevel@tonic-gate free(buf); 40507c478bd9Sstevel@tonic-gate return; 40517c478bd9Sstevel@tonic-gate } 40527c478bd9Sstevel@tonic-gate 40537c478bd9Sstevel@tonic-gate rdfs((diskaddr_t)logbtodb(&sblock, sblock.fs_logbno), 40547c478bd9Sstevel@tonic-gate DEV_BSIZE, buf); 40557c478bd9Sstevel@tonic-gate ebp = (extent_block_t *)buf; 40567c478bd9Sstevel@tonic-gate 40577c478bd9Sstevel@tonic-gate /* log allocation block is not okay; check the fs */ 40587c478bd9Sstevel@tonic-gate if (ebp->type != LUFS_EXTENTS) { 40597c478bd9Sstevel@tonic-gate free(buf); 40607c478bd9Sstevel@tonic-gate free(ud_buf); 40617c478bd9Sstevel@tonic-gate return; 40627c478bd9Sstevel@tonic-gate } 40637c478bd9Sstevel@tonic-gate 40647c478bd9Sstevel@tonic-gate /* get the log state block(s) */ 40657c478bd9Sstevel@tonic-gate rdfs((diskaddr_t)logbtodb(&sblock, ebp->extents[0].pbno), 40667c478bd9Sstevel@tonic-gate DEV_BSIZE, ud_buf); 40677c478bd9Sstevel@tonic-gate ud = (ml_odunit_t *)ud_buf; 40687c478bd9Sstevel@tonic-gate ul = (ml_unit_t *)malloc(sizeof (*ul)); 40697c478bd9Sstevel@tonic-gate ul->un_ondisk = *ud; 40707c478bd9Sstevel@tonic-gate 40717c478bd9Sstevel@tonic-gate /* log state is okay */ 40727c478bd9Sstevel@tonic-gate if ((ul->un_chksum == ul->un_head_ident + ul->un_tail_ident) && 40737c478bd9Sstevel@tonic-gate (ul->un_version == LUFS_VERSION_LATEST) && 40747c478bd9Sstevel@tonic-gate (ul->un_badlog == 0)) 40757c478bd9Sstevel@tonic-gate islogok = 1; 40767c478bd9Sstevel@tonic-gate free(ud_buf); 40777c478bd9Sstevel@tonic-gate free(buf); 40787c478bd9Sstevel@tonic-gate free(ul); 40797c478bd9Sstevel@tonic-gate } 40807c478bd9Sstevel@tonic-gate } 40817c478bd9Sstevel@tonic-gate 40827c478bd9Sstevel@tonic-gate void 40837c478bd9Sstevel@tonic-gate growinit(char *devstr) 40847c478bd9Sstevel@tonic-gate { 40857c478bd9Sstevel@tonic-gate int i; 40867c478bd9Sstevel@tonic-gate char buf[DEV_BSIZE]; 40877c478bd9Sstevel@tonic-gate 40887c478bd9Sstevel@tonic-gate /* 40897c478bd9Sstevel@tonic-gate * Read and verify the superblock 40907c478bd9Sstevel@tonic-gate */ 40917c478bd9Sstevel@tonic-gate rdfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize, (char *)&sblock); 40926451fdbcSvsakar (void) checksblock(sblock, 0); 40937c478bd9Sstevel@tonic-gate if (sblock.fs_postblformat != FS_DYNAMICPOSTBLFMT) { 40947c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 4095d50c8f90Svsakar gettext("old file system format; can't growfs\n")); 40967c478bd9Sstevel@tonic-gate lockexit(32); 40977c478bd9Sstevel@tonic-gate } 40987c478bd9Sstevel@tonic-gate 40997c478bd9Sstevel@tonic-gate /* 41007c478bd9Sstevel@tonic-gate * can't shrink a file system 41017c478bd9Sstevel@tonic-gate */ 41027c478bd9Sstevel@tonic-gate grow_fssize = fsbtodb(&sblock, (uint64_t)sblock.fs_size); 41037c478bd9Sstevel@tonic-gate if (fssize_db < grow_fssize) { 41047c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 41057c478bd9Sstevel@tonic-gate gettext("%lld sectors < current size of %lld sectors\n"), 41067c478bd9Sstevel@tonic-gate fssize_db, grow_fssize); 41077c478bd9Sstevel@tonic-gate lockexit(32); 41087c478bd9Sstevel@tonic-gate } 41097c478bd9Sstevel@tonic-gate 41107c478bd9Sstevel@tonic-gate /* 41117c478bd9Sstevel@tonic-gate * can't grow a system to over a terabyte unless it was set up 41127c478bd9Sstevel@tonic-gate * as an MTB UFS file system. 41137c478bd9Sstevel@tonic-gate */ 41147c478bd9Sstevel@tonic-gate if (mtb == 'y' && sblock.fs_magic != MTB_UFS_MAGIC) { 41157c478bd9Sstevel@tonic-gate if (fssize_db >= SECTORS_PER_TERABYTE) { 41167c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 41177c478bd9Sstevel@tonic-gate "File system was not set up with the multi-terabyte format.\n")); 41187c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 41197c478bd9Sstevel@tonic-gate "Its size cannot be increased to a terabyte or more.\n")); 41207c478bd9Sstevel@tonic-gate } else { 41217c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 41227c478bd9Sstevel@tonic-gate "Cannot convert file system to multi-terabyte format.\n")); 41237c478bd9Sstevel@tonic-gate } 41247c478bd9Sstevel@tonic-gate lockexit(32); 41257c478bd9Sstevel@tonic-gate } 41267c478bd9Sstevel@tonic-gate 41277c478bd9Sstevel@tonic-gate logsetup(devstr); 41287c478bd9Sstevel@tonic-gate 41297c478bd9Sstevel@tonic-gate /* 41307c478bd9Sstevel@tonic-gate * can't growfs when logging device has errors 41317c478bd9Sstevel@tonic-gate */ 41327c478bd9Sstevel@tonic-gate if ((islog && !islogok) || 41337c478bd9Sstevel@tonic-gate ((FSOKAY == (sblock.fs_state + sblock.fs_time)) && 41347c478bd9Sstevel@tonic-gate (sblock.fs_clean == FSLOG && !islog))) { 41357c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 4136d50c8f90Svsakar gettext("logging device has errors; can't growfs\n")); 41377c478bd9Sstevel@tonic-gate lockexit(32); 41387c478bd9Sstevel@tonic-gate } 41397c478bd9Sstevel@tonic-gate 41407c478bd9Sstevel@tonic-gate /* 41417c478bd9Sstevel@tonic-gate * disable ufs logging for growing 41427c478bd9Sstevel@tonic-gate */ 41437c478bd9Sstevel@tonic-gate if (isufslog) { 41447c478bd9Sstevel@tonic-gate if (rl_log_control(devstr, _FIOLOGDISABLE) != RL_SUCCESS) { 41457c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4146d50c8f90Svsakar "failed to disable logging\n")); 41477c478bd9Sstevel@tonic-gate lockexit(32); 41487c478bd9Sstevel@tonic-gate } 41497c478bd9Sstevel@tonic-gate islog = 0; 41507c478bd9Sstevel@tonic-gate waslog = 1; 41517c478bd9Sstevel@tonic-gate } 41527c478bd9Sstevel@tonic-gate 41537c478bd9Sstevel@tonic-gate /* 41547c478bd9Sstevel@tonic-gate * if mounted write lock the file system to be grown 41557c478bd9Sstevel@tonic-gate */ 41567c478bd9Sstevel@tonic-gate if (ismounted) 41577c478bd9Sstevel@tonic-gate wlockfs(); 41587c478bd9Sstevel@tonic-gate 41597c478bd9Sstevel@tonic-gate /* 41607c478bd9Sstevel@tonic-gate * refresh dynamic superblock state - disabling logging will have 41617c478bd9Sstevel@tonic-gate * changed the amount of free space available in the file system 41627c478bd9Sstevel@tonic-gate */ 41637c478bd9Sstevel@tonic-gate rdfs((diskaddr_t)(SBOFF / sectorsize), sbsize, (char *)&sblock); 41647c478bd9Sstevel@tonic-gate 41657c478bd9Sstevel@tonic-gate /* 41667c478bd9Sstevel@tonic-gate * make sure device is big enough 41677c478bd9Sstevel@tonic-gate */ 41687c478bd9Sstevel@tonic-gate rdfs((diskaddr_t)fssize_db - 1, DEV_BSIZE, buf); 41697c478bd9Sstevel@tonic-gate wtfs((diskaddr_t)fssize_db - 1, DEV_BSIZE, buf); 41707c478bd9Sstevel@tonic-gate 41717c478bd9Sstevel@tonic-gate /* 41727c478bd9Sstevel@tonic-gate * read current summary information 41737c478bd9Sstevel@tonic-gate */ 41747c478bd9Sstevel@tonic-gate grow_fscs = read_summaryinfo(&sblock); 41757c478bd9Sstevel@tonic-gate 41767c478bd9Sstevel@tonic-gate /* 41777c478bd9Sstevel@tonic-gate * save some current size related fields from the superblock 41787c478bd9Sstevel@tonic-gate * These are used in extendsummaryinfo() 41797c478bd9Sstevel@tonic-gate */ 41807c478bd9Sstevel@tonic-gate grow_fs_size = sblock.fs_size; 41817c478bd9Sstevel@tonic-gate grow_fs_ncg = sblock.fs_ncg; 41827c478bd9Sstevel@tonic-gate grow_fs_csaddr = (diskaddr_t)sblock.fs_csaddr; 41837c478bd9Sstevel@tonic-gate grow_fs_cssize = sblock.fs_cssize; 41847c478bd9Sstevel@tonic-gate 41857c478bd9Sstevel@tonic-gate /* 41867c478bd9Sstevel@tonic-gate * save and reset the clean flag 41877c478bd9Sstevel@tonic-gate */ 41887c478bd9Sstevel@tonic-gate if (FSOKAY == (sblock.fs_state + sblock.fs_time)) 41897c478bd9Sstevel@tonic-gate grow_fs_clean = sblock.fs_clean; 41907c478bd9Sstevel@tonic-gate else 41917c478bd9Sstevel@tonic-gate grow_fs_clean = FSBAD; 41927c478bd9Sstevel@tonic-gate sblock.fs_clean = FSBAD; 41937c478bd9Sstevel@tonic-gate sblock.fs_state = FSOKAY - sblock.fs_time; 41947c478bd9Sstevel@tonic-gate isbad = 1; 41957c478bd9Sstevel@tonic-gate wtfs((diskaddr_t)(SBOFF / sectorsize), sbsize, (char *)&sblock); 41967c478bd9Sstevel@tonic-gate } 41977c478bd9Sstevel@tonic-gate 41987c478bd9Sstevel@tonic-gate void 41997c478bd9Sstevel@tonic-gate checkdev(char *rdev, char *bdev) 42007c478bd9Sstevel@tonic-gate { 42017c478bd9Sstevel@tonic-gate struct stat64 statarea; 42027c478bd9Sstevel@tonic-gate 42037c478bd9Sstevel@tonic-gate if (stat64(bdev, &statarea) < 0) { 42047c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("can't check mount point; ")); 42057c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("can't stat %s\n"), bdev); 42067c478bd9Sstevel@tonic-gate lockexit(32); 42077c478bd9Sstevel@tonic-gate } 42087c478bd9Sstevel@tonic-gate if ((statarea.st_mode & S_IFMT) != S_IFBLK) { 42097c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 42107c478bd9Sstevel@tonic-gate "can't check mount point; %s is not a block device\n"), 42117c478bd9Sstevel@tonic-gate bdev); 42127c478bd9Sstevel@tonic-gate lockexit(32); 42137c478bd9Sstevel@tonic-gate } 42147c478bd9Sstevel@tonic-gate if (stat64(rdev, &statarea) < 0) { 42157c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("can't stat %s\n"), rdev); 42167c478bd9Sstevel@tonic-gate lockexit(32); 42177c478bd9Sstevel@tonic-gate } 42187c478bd9Sstevel@tonic-gate if ((statarea.st_mode & S_IFMT) != S_IFCHR) { 42197c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 4220d50c8f90Svsakar gettext("%s is not a character device\n"), rdev); 42217c478bd9Sstevel@tonic-gate lockexit(32); 42227c478bd9Sstevel@tonic-gate } 42237c478bd9Sstevel@tonic-gate } 42247c478bd9Sstevel@tonic-gate 42257c478bd9Sstevel@tonic-gate void 42267c478bd9Sstevel@tonic-gate checkmount(struct mnttab *mntp, char *bdevname) 42277c478bd9Sstevel@tonic-gate { 42287c478bd9Sstevel@tonic-gate struct stat64 statdir; 42297c478bd9Sstevel@tonic-gate struct stat64 statdev; 42307c478bd9Sstevel@tonic-gate 42317c478bd9Sstevel@tonic-gate if (strcmp(bdevname, mntp->mnt_special) == 0) { 42327c478bd9Sstevel@tonic-gate if (stat64(mntp->mnt_mountp, &statdir) == -1) { 42337c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("can't stat %s\n"), 4234d50c8f90Svsakar mntp->mnt_mountp); 42357c478bd9Sstevel@tonic-gate lockexit(32); 42367c478bd9Sstevel@tonic-gate } 42377c478bd9Sstevel@tonic-gate if (stat64(mntp->mnt_special, &statdev) == -1) { 42387c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("can't stat %s\n"), 4239d50c8f90Svsakar mntp->mnt_special); 42407c478bd9Sstevel@tonic-gate lockexit(32); 42417c478bd9Sstevel@tonic-gate } 42427c478bd9Sstevel@tonic-gate if (statdir.st_dev != statdev.st_rdev) { 42437c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4244d50c8f90Svsakar "%s is not mounted on %s; mnttab(4) wrong\n"), 4245d50c8f90Svsakar mntp->mnt_special, mntp->mnt_mountp); 42467c478bd9Sstevel@tonic-gate lockexit(32); 42477c478bd9Sstevel@tonic-gate } 42487c478bd9Sstevel@tonic-gate ismounted = 1; 42497c478bd9Sstevel@tonic-gate if (directory) { 42507c478bd9Sstevel@tonic-gate if (strcmp(mntp->mnt_mountp, directory) != 0) { 42517c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 4252d50c8f90Svsakar gettext("%s is mounted on %s, not %s\n"), 4253355d6bb5Sswilcox bdevname, mntp->mnt_mountp, directory); 42547c478bd9Sstevel@tonic-gate lockexit(32); 42557c478bd9Sstevel@tonic-gate } 42567c478bd9Sstevel@tonic-gate } else { 42577c478bd9Sstevel@tonic-gate if (grow) 42587c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4259355d6bb5Sswilcox "%s is mounted on %s; can't growfs\n"), 4260355d6bb5Sswilcox bdevname, mntp->mnt_mountp); 42617c478bd9Sstevel@tonic-gate else 42627c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 4263355d6bb5Sswilcox gettext("%s is mounted, can't mkfs\n"), 4264355d6bb5Sswilcox bdevname); 42657c478bd9Sstevel@tonic-gate lockexit(32); 42667c478bd9Sstevel@tonic-gate } 42677c478bd9Sstevel@tonic-gate } 42687c478bd9Sstevel@tonic-gate } 42697c478bd9Sstevel@tonic-gate 42707c478bd9Sstevel@tonic-gate struct dinode *dibuf = 0; 42717c478bd9Sstevel@tonic-gate diskaddr_t difrag = 0; 42727c478bd9Sstevel@tonic-gate 42737c478bd9Sstevel@tonic-gate struct dinode * 42747c478bd9Sstevel@tonic-gate gdinode(ino_t ino) 42757c478bd9Sstevel@tonic-gate { 42767c478bd9Sstevel@tonic-gate /* 42777c478bd9Sstevel@tonic-gate * read the block of inodes containing inode number ino 42787c478bd9Sstevel@tonic-gate */ 42797c478bd9Sstevel@tonic-gate if (dibuf == 0) 42807c478bd9Sstevel@tonic-gate dibuf = (struct dinode *)malloc((unsigned)sblock.fs_bsize); 42817c478bd9Sstevel@tonic-gate if (itod(&sblock, ino) != difrag) { 42827c478bd9Sstevel@tonic-gate difrag = itod(&sblock, ino); 42837c478bd9Sstevel@tonic-gate rdfs(fsbtodb(&sblock, (uint64_t)difrag), (int)sblock.fs_bsize, 4284d50c8f90Svsakar (char *)dibuf); 42857c478bd9Sstevel@tonic-gate } 42867c478bd9Sstevel@tonic-gate return (dibuf + (ino % INOPB(&sblock))); 42877c478bd9Sstevel@tonic-gate } 42887c478bd9Sstevel@tonic-gate 42897c478bd9Sstevel@tonic-gate /* 42907c478bd9Sstevel@tonic-gate * structure that manages the frags we need for extended summary info 42917c478bd9Sstevel@tonic-gate * These frags can be: 42927c478bd9Sstevel@tonic-gate * free 42937c478bd9Sstevel@tonic-gate * data block 42947c478bd9Sstevel@tonic-gate * alloc block 42957c478bd9Sstevel@tonic-gate */ 42967c478bd9Sstevel@tonic-gate struct csfrag { 42977c478bd9Sstevel@tonic-gate struct csfrag *next; /* next entry */ 42987c478bd9Sstevel@tonic-gate daddr32_t ofrag; /* old frag */ 42997c478bd9Sstevel@tonic-gate daddr32_t nfrag; /* new frag */ 43007c478bd9Sstevel@tonic-gate long cylno; /* cylno of nfrag */ 43017c478bd9Sstevel@tonic-gate long frags; /* number of frags */ 43027c478bd9Sstevel@tonic-gate long size; /* size in bytes */ 43037c478bd9Sstevel@tonic-gate ino_t ino; /* inode number */ 43047c478bd9Sstevel@tonic-gate long fixed; /* Boolean - Already fixed? */ 43057c478bd9Sstevel@tonic-gate }; 43067c478bd9Sstevel@tonic-gate struct csfrag *csfrag; /* state unknown */ 43077c478bd9Sstevel@tonic-gate struct csfrag *csfragino; /* frags belonging to an inode */ 43087c478bd9Sstevel@tonic-gate struct csfrag *csfragfree; /* frags that are free */ 43097c478bd9Sstevel@tonic-gate 43107c478bd9Sstevel@tonic-gate daddr32_t maxcsfrag = 0; /* maximum in range */ 43117c478bd9Sstevel@tonic-gate daddr32_t mincsfrag = 0x7fffffff; /* minimum in range */ 43127c478bd9Sstevel@tonic-gate 43137c478bd9Sstevel@tonic-gate int 43147c478bd9Sstevel@tonic-gate csfraginrange(daddr32_t frag) 43157c478bd9Sstevel@tonic-gate { 43167c478bd9Sstevel@tonic-gate return ((frag >= mincsfrag) && (frag <= maxcsfrag)); 43177c478bd9Sstevel@tonic-gate } 43187c478bd9Sstevel@tonic-gate 43197c478bd9Sstevel@tonic-gate struct csfrag * 43207c478bd9Sstevel@tonic-gate findcsfrag(daddr32_t frag, struct csfrag **cfap) 43217c478bd9Sstevel@tonic-gate { 43227c478bd9Sstevel@tonic-gate struct csfrag *cfp; 43237c478bd9Sstevel@tonic-gate 43247c478bd9Sstevel@tonic-gate if (!csfraginrange(frag)) 43257c478bd9Sstevel@tonic-gate return (NULL); 43267c478bd9Sstevel@tonic-gate 43277c478bd9Sstevel@tonic-gate for (cfp = *cfap; cfp; cfp = cfp->next) 43287c478bd9Sstevel@tonic-gate if (cfp->ofrag == frag) 43297c478bd9Sstevel@tonic-gate return (cfp); 43307c478bd9Sstevel@tonic-gate return (NULL); 43317c478bd9Sstevel@tonic-gate } 43327c478bd9Sstevel@tonic-gate 43337c478bd9Sstevel@tonic-gate void 43347c478bd9Sstevel@tonic-gate checkindirect(ino_t ino, daddr32_t *fragsp, daddr32_t frag, int level) 43357c478bd9Sstevel@tonic-gate { 43367c478bd9Sstevel@tonic-gate int i; 43377c478bd9Sstevel@tonic-gate int ne = sblock.fs_bsize / sizeof (daddr32_t); 43387c478bd9Sstevel@tonic-gate daddr32_t fsb[MAXBSIZE / sizeof (daddr32_t)]; 43397c478bd9Sstevel@tonic-gate 43407c478bd9Sstevel@tonic-gate if (frag == 0) 43417c478bd9Sstevel@tonic-gate return; 43427c478bd9Sstevel@tonic-gate 43437c478bd9Sstevel@tonic-gate rdfs(fsbtodb(&sblock, frag), (int)sblock.fs_bsize, 43447c478bd9Sstevel@tonic-gate (char *)fsb); 43457c478bd9Sstevel@tonic-gate 43467c478bd9Sstevel@tonic-gate checkdirect(ino, fragsp, fsb, sblock.fs_bsize / sizeof (daddr32_t)); 43477c478bd9Sstevel@tonic-gate 43487c478bd9Sstevel@tonic-gate if (level) 43497c478bd9Sstevel@tonic-gate for (i = 0; i < ne && *fragsp; ++i) 43507c478bd9Sstevel@tonic-gate checkindirect(ino, fragsp, fsb[i], level-1); 43517c478bd9Sstevel@tonic-gate } 43527c478bd9Sstevel@tonic-gate 43537c478bd9Sstevel@tonic-gate void 43547c478bd9Sstevel@tonic-gate addcsfrag(ino_t ino, daddr32_t frag, struct csfrag **cfap) 43557c478bd9Sstevel@tonic-gate { 43567c478bd9Sstevel@tonic-gate struct csfrag *cfp, *curr, *prev; 43577c478bd9Sstevel@tonic-gate 43587c478bd9Sstevel@tonic-gate /* 43597c478bd9Sstevel@tonic-gate * establish a range for faster checking in csfraginrange() 43607c478bd9Sstevel@tonic-gate */ 43617c478bd9Sstevel@tonic-gate if (frag > maxcsfrag) 43627c478bd9Sstevel@tonic-gate maxcsfrag = frag; 43637c478bd9Sstevel@tonic-gate if (frag < mincsfrag) 43647c478bd9Sstevel@tonic-gate mincsfrag = frag; 43657c478bd9Sstevel@tonic-gate 43667c478bd9Sstevel@tonic-gate /* 43677c478bd9Sstevel@tonic-gate * if this frag belongs to an inode and is not the start of a block 43687c478bd9Sstevel@tonic-gate * then see if it is part of a frag range for this inode 43697c478bd9Sstevel@tonic-gate */ 43707c478bd9Sstevel@tonic-gate if (ino && (frag % sblock.fs_frag)) 43717c478bd9Sstevel@tonic-gate for (cfp = *cfap; cfp; cfp = cfp->next) { 43727c478bd9Sstevel@tonic-gate if (ino != cfp->ino) 43737c478bd9Sstevel@tonic-gate continue; 43747c478bd9Sstevel@tonic-gate if (frag != cfp->ofrag + cfp->frags) 43757c478bd9Sstevel@tonic-gate continue; 43767c478bd9Sstevel@tonic-gate cfp->frags++; 43777c478bd9Sstevel@tonic-gate cfp->size += sblock.fs_fsize; 43787c478bd9Sstevel@tonic-gate return; 43797c478bd9Sstevel@tonic-gate } 43807c478bd9Sstevel@tonic-gate /* 43817c478bd9Sstevel@tonic-gate * allocate a csfrag entry and insert it in an increasing order into the 43827c478bd9Sstevel@tonic-gate * specified list 43837c478bd9Sstevel@tonic-gate */ 43847c478bd9Sstevel@tonic-gate cfp = (struct csfrag *)calloc(1, sizeof (struct csfrag)); 43857c478bd9Sstevel@tonic-gate cfp->ino = ino; 43867c478bd9Sstevel@tonic-gate cfp->ofrag = frag; 43877c478bd9Sstevel@tonic-gate cfp->frags = 1; 43887c478bd9Sstevel@tonic-gate cfp->size = sblock.fs_fsize; 43897c478bd9Sstevel@tonic-gate for (prev = NULL, curr = *cfap; curr != NULL; 4390d50c8f90Svsakar prev = curr, curr = curr->next) { 43917c478bd9Sstevel@tonic-gate if (frag < curr->ofrag) { 43927c478bd9Sstevel@tonic-gate cfp->next = curr; 43937c478bd9Sstevel@tonic-gate if (prev) 43947c478bd9Sstevel@tonic-gate prev->next = cfp; /* middle element */ 43957c478bd9Sstevel@tonic-gate else 43967c478bd9Sstevel@tonic-gate *cfap = cfp; /* first element */ 43977c478bd9Sstevel@tonic-gate break; 43987c478bd9Sstevel@tonic-gate } 43997c478bd9Sstevel@tonic-gate if (curr->next == NULL) { 44007c478bd9Sstevel@tonic-gate curr->next = cfp; /* last element */ 44017c478bd9Sstevel@tonic-gate break; 44027c478bd9Sstevel@tonic-gate } 44037c478bd9Sstevel@tonic-gate } 44047c478bd9Sstevel@tonic-gate if (*cfap == NULL) /* will happen only once */ 44057c478bd9Sstevel@tonic-gate *cfap = cfp; 44067c478bd9Sstevel@tonic-gate } 44077c478bd9Sstevel@tonic-gate 44087c478bd9Sstevel@tonic-gate void 44097c478bd9Sstevel@tonic-gate delcsfrag(daddr32_t frag, struct csfrag **cfap) 44107c478bd9Sstevel@tonic-gate { 44117c478bd9Sstevel@tonic-gate struct csfrag *cfp; 44127c478bd9Sstevel@tonic-gate struct csfrag **cfpp; 44137c478bd9Sstevel@tonic-gate 44147c478bd9Sstevel@tonic-gate /* 44157c478bd9Sstevel@tonic-gate * free up entry whose beginning frag matches 44167c478bd9Sstevel@tonic-gate */ 44177c478bd9Sstevel@tonic-gate for (cfpp = cfap; *cfpp; cfpp = &(*cfpp)->next) { 44187c478bd9Sstevel@tonic-gate if (frag == (*cfpp)->ofrag) { 44197c478bd9Sstevel@tonic-gate cfp = *cfpp; 44207c478bd9Sstevel@tonic-gate *cfpp = (*cfpp)->next; 44217c478bd9Sstevel@tonic-gate free((char *)cfp); 44227c478bd9Sstevel@tonic-gate return; 44237c478bd9Sstevel@tonic-gate } 44247c478bd9Sstevel@tonic-gate } 44257c478bd9Sstevel@tonic-gate } 44267c478bd9Sstevel@tonic-gate 44277c478bd9Sstevel@tonic-gate /* 44287c478bd9Sstevel@tonic-gate * See whether any of the direct blocks in the array pointed by "db" and of 44297c478bd9Sstevel@tonic-gate * length "ne" are within the range of frags needed to extend the cylinder 44307c478bd9Sstevel@tonic-gate * summary. If so, remove those frags from the "as-yet-unclassified" list 44317c478bd9Sstevel@tonic-gate * (csfrag) and add them to the "owned-by-inode" list (csfragino). 44327c478bd9Sstevel@tonic-gate * For each such frag found, decrement the frag count pointed to by fragsp. 44337c478bd9Sstevel@tonic-gate * "ino" is the inode that contains (either directly or indirectly) the frags 44347c478bd9Sstevel@tonic-gate * being checked. 44357c478bd9Sstevel@tonic-gate */ 44367c478bd9Sstevel@tonic-gate void 44377c478bd9Sstevel@tonic-gate checkdirect(ino_t ino, daddr32_t *fragsp, daddr32_t *db, int ne) 44387c478bd9Sstevel@tonic-gate { 44397c478bd9Sstevel@tonic-gate int i; 44407c478bd9Sstevel@tonic-gate int j; 44417c478bd9Sstevel@tonic-gate int found; 44427c478bd9Sstevel@tonic-gate diskaddr_t frag; 44437c478bd9Sstevel@tonic-gate 44447c478bd9Sstevel@tonic-gate /* 44457c478bd9Sstevel@tonic-gate * scan for allocation within the new summary info range 44467c478bd9Sstevel@tonic-gate */ 44477c478bd9Sstevel@tonic-gate for (i = 0; i < ne && *fragsp; ++i) { 44487c478bd9Sstevel@tonic-gate if ((frag = *db++) != 0) { 44497c478bd9Sstevel@tonic-gate found = 0; 44507c478bd9Sstevel@tonic-gate for (j = 0; j < sblock.fs_frag && *fragsp; ++j) { 44517c478bd9Sstevel@tonic-gate if (found || (found = csfraginrange(frag))) { 44527c478bd9Sstevel@tonic-gate addcsfrag(ino, frag, &csfragino); 44537c478bd9Sstevel@tonic-gate delcsfrag(frag, &csfrag); 44547c478bd9Sstevel@tonic-gate } 44557c478bd9Sstevel@tonic-gate ++frag; 44567c478bd9Sstevel@tonic-gate --(*fragsp); 44577c478bd9Sstevel@tonic-gate } 44587c478bd9Sstevel@tonic-gate } 44597c478bd9Sstevel@tonic-gate } 44607c478bd9Sstevel@tonic-gate } 44617c478bd9Sstevel@tonic-gate 44627c478bd9Sstevel@tonic-gate void 44637c478bd9Sstevel@tonic-gate findcsfragino() 44647c478bd9Sstevel@tonic-gate { 44657c478bd9Sstevel@tonic-gate int i; 44667c478bd9Sstevel@tonic-gate int j; 44677c478bd9Sstevel@tonic-gate daddr32_t frags; 44687c478bd9Sstevel@tonic-gate struct dinode *dp; 44697c478bd9Sstevel@tonic-gate 44707c478bd9Sstevel@tonic-gate /* 44717c478bd9Sstevel@tonic-gate * scan all old inodes looking for allocations in the new 44727c478bd9Sstevel@tonic-gate * summary info range. Move the affected frag from the 44737c478bd9Sstevel@tonic-gate * generic csfrag list onto the `owned-by-inode' list csfragino. 44747c478bd9Sstevel@tonic-gate */ 44757c478bd9Sstevel@tonic-gate for (i = UFSROOTINO; i < grow_fs_ncg*sblock.fs_ipg && csfrag; ++i) { 44767c478bd9Sstevel@tonic-gate dp = gdinode((ino_t)i); 44777c478bd9Sstevel@tonic-gate switch (dp->di_mode & IFMT) { 44787c478bd9Sstevel@tonic-gate case IFSHAD : 44797c478bd9Sstevel@tonic-gate case IFLNK : 44807c478bd9Sstevel@tonic-gate case IFDIR : 44817c478bd9Sstevel@tonic-gate case IFREG : break; 44827c478bd9Sstevel@tonic-gate default : continue; 44837c478bd9Sstevel@tonic-gate } 44847c478bd9Sstevel@tonic-gate 44857c478bd9Sstevel@tonic-gate frags = dbtofsb(&sblock, dp->di_blocks); 44867c478bd9Sstevel@tonic-gate 44877c478bd9Sstevel@tonic-gate checkdirect((ino_t)i, &frags, &dp->di_db[0], NDADDR+NIADDR); 4488303bf60bSsdebnath for (j = 0; j < NIADDR && frags; ++j) { 4489303bf60bSsdebnath /* Negate the block if its an fallocate'd block */ 4490303bf60bSsdebnath if (dp->di_ib[j] < 0 && dp->di_ib[j] != UFS_HOLE) 4491303bf60bSsdebnath checkindirect((ino_t)i, &frags, 4492303bf60bSsdebnath -(dp->di_ib[j]), j); 4493303bf60bSsdebnath else 4494303bf60bSsdebnath checkindirect((ino_t)i, &frags, 4495303bf60bSsdebnath dp->di_ib[j], j); 4496303bf60bSsdebnath } 44977c478bd9Sstevel@tonic-gate } 44987c478bd9Sstevel@tonic-gate } 44997c478bd9Sstevel@tonic-gate 45007c478bd9Sstevel@tonic-gate void 45017c478bd9Sstevel@tonic-gate fixindirect(daddr32_t frag, int level) 45027c478bd9Sstevel@tonic-gate { 45037c478bd9Sstevel@tonic-gate int i; 45047c478bd9Sstevel@tonic-gate int ne = sblock.fs_bsize / sizeof (daddr32_t); 45057c478bd9Sstevel@tonic-gate daddr32_t fsb[MAXBSIZE / sizeof (daddr32_t)]; 45067c478bd9Sstevel@tonic-gate 45077c478bd9Sstevel@tonic-gate if (frag == 0) 45087c478bd9Sstevel@tonic-gate return; 45097c478bd9Sstevel@tonic-gate 45107c478bd9Sstevel@tonic-gate rdfs(fsbtodb(&sblock, (uint64_t)frag), (int)sblock.fs_bsize, 45117c478bd9Sstevel@tonic-gate (char *)fsb); 45127c478bd9Sstevel@tonic-gate 45137c478bd9Sstevel@tonic-gate fixdirect((caddr_t)fsb, frag, fsb, ne); 45147c478bd9Sstevel@tonic-gate 45157c478bd9Sstevel@tonic-gate if (level) 45167c478bd9Sstevel@tonic-gate for (i = 0; i < ne; ++i) 45177c478bd9Sstevel@tonic-gate fixindirect(fsb[i], level-1); 45187c478bd9Sstevel@tonic-gate } 45197c478bd9Sstevel@tonic-gate 45207c478bd9Sstevel@tonic-gate void 45217c478bd9Sstevel@tonic-gate fixdirect(caddr_t bp, daddr32_t frag, daddr32_t *db, int ne) 45227c478bd9Sstevel@tonic-gate { 45237c478bd9Sstevel@tonic-gate int i; 45247c478bd9Sstevel@tonic-gate struct csfrag *cfp; 45257c478bd9Sstevel@tonic-gate 45267c478bd9Sstevel@tonic-gate for (i = 0; i < ne; ++i, ++db) { 45277c478bd9Sstevel@tonic-gate if (*db == 0) 45287c478bd9Sstevel@tonic-gate continue; 45297c478bd9Sstevel@tonic-gate if ((cfp = findcsfrag(*db, &csfragino)) == NULL) 45307c478bd9Sstevel@tonic-gate continue; 45317c478bd9Sstevel@tonic-gate *db = cfp->nfrag; 45327c478bd9Sstevel@tonic-gate cfp->fixed = 1; 45337c478bd9Sstevel@tonic-gate wtfs(fsbtodb(&sblock, (uint64_t)frag), (int)sblock.fs_bsize, 45347c478bd9Sstevel@tonic-gate bp); 45357c478bd9Sstevel@tonic-gate } 45367c478bd9Sstevel@tonic-gate } 45377c478bd9Sstevel@tonic-gate 45387c478bd9Sstevel@tonic-gate void 45397c478bd9Sstevel@tonic-gate fixcsfragino() 45407c478bd9Sstevel@tonic-gate { 45417c478bd9Sstevel@tonic-gate int i; 45427c478bd9Sstevel@tonic-gate struct dinode *dp; 45437c478bd9Sstevel@tonic-gate struct csfrag *cfp; 45447c478bd9Sstevel@tonic-gate 45457c478bd9Sstevel@tonic-gate for (cfp = csfragino; cfp; cfp = cfp->next) { 45467c478bd9Sstevel@tonic-gate if (cfp->fixed) 45477c478bd9Sstevel@tonic-gate continue; 45487c478bd9Sstevel@tonic-gate dp = gdinode((ino_t)cfp->ino); 45497c478bd9Sstevel@tonic-gate fixdirect((caddr_t)dibuf, difrag, dp->di_db, NDADDR+NIADDR); 45507c478bd9Sstevel@tonic-gate for (i = 0; i < NIADDR; ++i) 45517c478bd9Sstevel@tonic-gate fixindirect(dp->di_ib[i], i); 45527c478bd9Sstevel@tonic-gate } 45537c478bd9Sstevel@tonic-gate } 45547c478bd9Sstevel@tonic-gate 45557c478bd9Sstevel@tonic-gate /* 45567c478bd9Sstevel@tonic-gate * Read the cylinders summary information specified by settings in the 45577c478bd9Sstevel@tonic-gate * passed 'fs' structure into a new allocated array of csum structures. 45587c478bd9Sstevel@tonic-gate * The caller is responsible for freeing the returned array. 45597c478bd9Sstevel@tonic-gate * Return a pointer to an array of csum structures. 45607c478bd9Sstevel@tonic-gate */ 45617c478bd9Sstevel@tonic-gate static struct csum * 45627c478bd9Sstevel@tonic-gate read_summaryinfo(struct fs *fsp) 45637c478bd9Sstevel@tonic-gate { 45647c478bd9Sstevel@tonic-gate struct csum *csp; 45657c478bd9Sstevel@tonic-gate int i; 45667c478bd9Sstevel@tonic-gate 45677c478bd9Sstevel@tonic-gate if ((csp = malloc((size_t)fsp->fs_cssize)) == NULL) { 45687c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("cannot create csum list," 4569d50c8f90Svsakar " not enough memory\n")); 45707c478bd9Sstevel@tonic-gate exit(32); 45717c478bd9Sstevel@tonic-gate } 45727c478bd9Sstevel@tonic-gate 45737c478bd9Sstevel@tonic-gate for (i = 0; i < fsp->fs_cssize; i += fsp->fs_bsize) { 45747c478bd9Sstevel@tonic-gate rdfs(fsbtodb(fsp, 4575d50c8f90Svsakar (uint64_t)(fsp->fs_csaddr + numfrags(fsp, i))), 4576d50c8f90Svsakar (int)(fsp->fs_cssize - i < fsp->fs_bsize ? 4577d50c8f90Svsakar fsp->fs_cssize - i : fsp->fs_bsize), ((caddr_t)csp) + i); 45787c478bd9Sstevel@tonic-gate } 45797c478bd9Sstevel@tonic-gate 45807c478bd9Sstevel@tonic-gate return (csp); 45817c478bd9Sstevel@tonic-gate } 45827c478bd9Sstevel@tonic-gate 45837c478bd9Sstevel@tonic-gate /* 45847c478bd9Sstevel@tonic-gate * Check the allocation of fragments that are to be made part of a csum block. 45857c478bd9Sstevel@tonic-gate * A fragment is allocated if it is either in the csfragfree list or, it is 45867c478bd9Sstevel@tonic-gate * in the csfragino list and has new frags associated with it. 45877c478bd9Sstevel@tonic-gate * Return the number of allocated fragments. 45887c478bd9Sstevel@tonic-gate */ 45897c478bd9Sstevel@tonic-gate int64_t 45907c478bd9Sstevel@tonic-gate checkfragallocated(daddr32_t frag) 45917c478bd9Sstevel@tonic-gate { 45927c478bd9Sstevel@tonic-gate struct csfrag *cfp; 45937c478bd9Sstevel@tonic-gate /* 45947c478bd9Sstevel@tonic-gate * Since the lists are sorted we can break the search if the asked 45957c478bd9Sstevel@tonic-gate * frag is smaller then the one in the list. 45967c478bd9Sstevel@tonic-gate */ 45977c478bd9Sstevel@tonic-gate for (cfp = csfragfree; cfp != NULL && frag >= cfp->ofrag; 4598d50c8f90Svsakar cfp = cfp->next) { 45997c478bd9Sstevel@tonic-gate if (frag == cfp->ofrag) 46007c478bd9Sstevel@tonic-gate return (1); 46017c478bd9Sstevel@tonic-gate } 46027c478bd9Sstevel@tonic-gate for (cfp = csfragino; cfp != NULL && frag >= cfp->ofrag; 4603d50c8f90Svsakar cfp = cfp->next) { 46047c478bd9Sstevel@tonic-gate if (frag == cfp->ofrag && cfp->nfrag != 0) 46057c478bd9Sstevel@tonic-gate return (cfp->frags); 46067c478bd9Sstevel@tonic-gate } 46077c478bd9Sstevel@tonic-gate 46087c478bd9Sstevel@tonic-gate return (0); 46097c478bd9Sstevel@tonic-gate } 46107c478bd9Sstevel@tonic-gate 46117c478bd9Sstevel@tonic-gate /* 46127c478bd9Sstevel@tonic-gate * Figure out how much the filesystem can be grown. The limiting factor is 46137c478bd9Sstevel@tonic-gate * the available free space needed to extend the cg summary info block. 46147c478bd9Sstevel@tonic-gate * The free space is determined in three steps: 46157c478bd9Sstevel@tonic-gate * - Try to extend the cg summary block to the required size. 46167c478bd9Sstevel@tonic-gate * - Find free blocks in last cg. 46177c478bd9Sstevel@tonic-gate * - Find free space in the last already allocated fragment of the summary info 46187c478bd9Sstevel@tonic-gate * block, and use it for additional csum structures. 46197c478bd9Sstevel@tonic-gate * Return the maximum size of the new filesystem or 0 if it can't be grown. 46207c478bd9Sstevel@tonic-gate * Please note that this function leaves the global list pointers csfrag, 46217c478bd9Sstevel@tonic-gate * csfragfree, and csfragino initialized, and the caller is responsible for 46227c478bd9Sstevel@tonic-gate * freeing the lists. 46237c478bd9Sstevel@tonic-gate */ 46247c478bd9Sstevel@tonic-gate diskaddr_t 46257c478bd9Sstevel@tonic-gate probe_summaryinfo() 46267c478bd9Sstevel@tonic-gate { 46277c478bd9Sstevel@tonic-gate /* fragments by which the csum block can be extended. */ 46287c478bd9Sstevel@tonic-gate int64_t growth_csum_frags = 0; 46297c478bd9Sstevel@tonic-gate /* fragments by which the filesystem can be extended. */ 46307c478bd9Sstevel@tonic-gate int64_t growth_fs_frags = 0; 46317c478bd9Sstevel@tonic-gate int64_t new_fs_cssize; /* size of csum blk in the new FS */ 46327c478bd9Sstevel@tonic-gate int64_t new_fs_ncg; /* number of cg in the new FS */ 46337c478bd9Sstevel@tonic-gate int64_t spare_csum; 46347c478bd9Sstevel@tonic-gate daddr32_t oldfrag_daddr; 46357c478bd9Sstevel@tonic-gate daddr32_t newfrag_daddr; 46367c478bd9Sstevel@tonic-gate daddr32_t daddr; 46377c478bd9Sstevel@tonic-gate int i; 46387c478bd9Sstevel@tonic-gate 46397c478bd9Sstevel@tonic-gate /* 46407c478bd9Sstevel@tonic-gate * read and verify the superblock 46417c478bd9Sstevel@tonic-gate */ 46427c478bd9Sstevel@tonic-gate rdfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize, (char *)&sblock); 46436451fdbcSvsakar (void) checksblock(sblock, 0); 46447c478bd9Sstevel@tonic-gate 46457c478bd9Sstevel@tonic-gate /* 46467c478bd9Sstevel@tonic-gate * check how much we can extend the cg summary info block 46477c478bd9Sstevel@tonic-gate */ 46487c478bd9Sstevel@tonic-gate 46497c478bd9Sstevel@tonic-gate /* 46507c478bd9Sstevel@tonic-gate * read current summary information 46517c478bd9Sstevel@tonic-gate */ 46527c478bd9Sstevel@tonic-gate fscs = read_summaryinfo(&sblock); 46537c478bd9Sstevel@tonic-gate 46547c478bd9Sstevel@tonic-gate /* 46557c478bd9Sstevel@tonic-gate * build list of frags needed for cg summary info block extension 46567c478bd9Sstevel@tonic-gate */ 46577c478bd9Sstevel@tonic-gate oldfrag_daddr = howmany(sblock.fs_cssize, sblock.fs_fsize) + 4658d50c8f90Svsakar sblock.fs_csaddr; 46597c478bd9Sstevel@tonic-gate new_fs_ncg = howmany(dbtofsb(&sblock, fssize_db), sblock.fs_fpg); 46607c478bd9Sstevel@tonic-gate new_fs_cssize = fragroundup(&sblock, new_fs_ncg * sizeof (struct csum)); 46617c478bd9Sstevel@tonic-gate newfrag_daddr = howmany(new_fs_cssize, sblock.fs_fsize) + 4662d50c8f90Svsakar sblock.fs_csaddr; 46637c478bd9Sstevel@tonic-gate /* 46647c478bd9Sstevel@tonic-gate * add all of the frags that are required to grow the cyl summary to the 46657c478bd9Sstevel@tonic-gate * csfrag list, which is the generic/unknown list, since at this point 46667c478bd9Sstevel@tonic-gate * we don't yet know the state of those frags. 46677c478bd9Sstevel@tonic-gate */ 46687c478bd9Sstevel@tonic-gate for (daddr = oldfrag_daddr; daddr < newfrag_daddr; daddr++) 46697c478bd9Sstevel@tonic-gate addcsfrag((ino_t)0, daddr, &csfrag); 46707c478bd9Sstevel@tonic-gate 46717c478bd9Sstevel@tonic-gate /* 46727c478bd9Sstevel@tonic-gate * filter free fragments and allocate them. Note that the free frags 46737c478bd9Sstevel@tonic-gate * must be allocated first otherwise they could be grabbed by 46747c478bd9Sstevel@tonic-gate * alloccsfragino() for data frags. 46757c478bd9Sstevel@tonic-gate */ 46767c478bd9Sstevel@tonic-gate findcsfragfree(); 46777c478bd9Sstevel@tonic-gate alloccsfragfree(); 46787c478bd9Sstevel@tonic-gate 46797c478bd9Sstevel@tonic-gate /* 46807c478bd9Sstevel@tonic-gate * filter fragments owned by inodes and allocate them 46817c478bd9Sstevel@tonic-gate */ 46827c478bd9Sstevel@tonic-gate grow_fs_ncg = sblock.fs_ncg; /* findcsfragino() needs this glob. var. */ 46837c478bd9Sstevel@tonic-gate findcsfragino(); 46847c478bd9Sstevel@tonic-gate alloccsfragino(); 46857c478bd9Sstevel@tonic-gate 46867c478bd9Sstevel@tonic-gate if (notenoughspace()) { 46877c478bd9Sstevel@tonic-gate /* 46887c478bd9Sstevel@tonic-gate * check how many consecutive fragments could be allocated 46897c478bd9Sstevel@tonic-gate * in both lists. 46907c478bd9Sstevel@tonic-gate */ 46917c478bd9Sstevel@tonic-gate int64_t tmp_frags; 46927c478bd9Sstevel@tonic-gate for (daddr = oldfrag_daddr; daddr < newfrag_daddr; 4693d50c8f90Svsakar daddr += tmp_frags) { 46947c478bd9Sstevel@tonic-gate if ((tmp_frags = checkfragallocated(daddr)) > 0) 46957c478bd9Sstevel@tonic-gate growth_csum_frags += tmp_frags; 46967c478bd9Sstevel@tonic-gate else 46977c478bd9Sstevel@tonic-gate break; 46987c478bd9Sstevel@tonic-gate } 46997c478bd9Sstevel@tonic-gate } else { 47007c478bd9Sstevel@tonic-gate /* 47017c478bd9Sstevel@tonic-gate * We have all we need for the new desired size, 47027c478bd9Sstevel@tonic-gate * so clean up and report back. 47037c478bd9Sstevel@tonic-gate */ 47047c478bd9Sstevel@tonic-gate return (fssize_db); 47057c478bd9Sstevel@tonic-gate } 47067c478bd9Sstevel@tonic-gate 47077c478bd9Sstevel@tonic-gate /* 47087c478bd9Sstevel@tonic-gate * given the number of fragments by which the csum block can be grown 47097c478bd9Sstevel@tonic-gate * compute by how many new fragments the FS can be increased. 47107c478bd9Sstevel@tonic-gate * It is the number of csum instances per fragment multiplied by 47117c478bd9Sstevel@tonic-gate * `growth_csum_frags' and the number of fragments per cylinder group. 47127c478bd9Sstevel@tonic-gate */ 47137c478bd9Sstevel@tonic-gate growth_fs_frags = howmany(sblock.fs_fsize, sizeof (struct csum)) * 4714d50c8f90Svsakar growth_csum_frags * sblock.fs_fpg; 47157c478bd9Sstevel@tonic-gate 47167c478bd9Sstevel@tonic-gate /* 47177c478bd9Sstevel@tonic-gate * compute free fragments in the last cylinder group 47187c478bd9Sstevel@tonic-gate */ 47197c478bd9Sstevel@tonic-gate rdcg(sblock.fs_ncg - 1); 47207c478bd9Sstevel@tonic-gate growth_fs_frags += sblock.fs_fpg - acg.cg_ndblk; 47217c478bd9Sstevel@tonic-gate 47227c478bd9Sstevel@tonic-gate /* 47237c478bd9Sstevel@tonic-gate * compute how many csum instances are unused in the old csum block. 47247c478bd9Sstevel@tonic-gate * For each unused csum instance the FS can be grown by one cylinder 47257c478bd9Sstevel@tonic-gate * group without extending the csum block. 47267c478bd9Sstevel@tonic-gate */ 47277c478bd9Sstevel@tonic-gate spare_csum = howmany(sblock.fs_cssize, sizeof (struct csum)) - 4728d50c8f90Svsakar sblock.fs_ncg; 47297c478bd9Sstevel@tonic-gate if (spare_csum > 0) 47307c478bd9Sstevel@tonic-gate growth_fs_frags += spare_csum * sblock.fs_fpg; 47317c478bd9Sstevel@tonic-gate 47327c478bd9Sstevel@tonic-gate /* 47337c478bd9Sstevel@tonic-gate * recalculate the new filesystem size in sectors, shorten it by 47347c478bd9Sstevel@tonic-gate * the requested size `fssize_db' if necessary. 47357c478bd9Sstevel@tonic-gate */ 47367c478bd9Sstevel@tonic-gate if (growth_fs_frags > 0) { 47377c478bd9Sstevel@tonic-gate diskaddr_t sect; 47387c478bd9Sstevel@tonic-gate sect = (sblock.fs_size + growth_fs_frags) * sblock.fs_nspf; 47397c478bd9Sstevel@tonic-gate return ((sect > fssize_db) ? fssize_db : sect); 47407c478bd9Sstevel@tonic-gate } 47417c478bd9Sstevel@tonic-gate 47427c478bd9Sstevel@tonic-gate return (0); 47437c478bd9Sstevel@tonic-gate } 47447c478bd9Sstevel@tonic-gate 47457c478bd9Sstevel@tonic-gate void 47467c478bd9Sstevel@tonic-gate extendsummaryinfo() 47477c478bd9Sstevel@tonic-gate { 47487c478bd9Sstevel@tonic-gate int64_t i; 47497c478bd9Sstevel@tonic-gate int localtest = test; 47507c478bd9Sstevel@tonic-gate int64_t frags; 47517c478bd9Sstevel@tonic-gate daddr32_t oldfrag; 47527c478bd9Sstevel@tonic-gate daddr32_t newfrag; 47537c478bd9Sstevel@tonic-gate 47547c478bd9Sstevel@tonic-gate /* 47557c478bd9Sstevel@tonic-gate * if no-write (-N), don't bother 47567c478bd9Sstevel@tonic-gate */ 47577c478bd9Sstevel@tonic-gate if (Nflag) 47587c478bd9Sstevel@tonic-gate return; 47597c478bd9Sstevel@tonic-gate 47607c478bd9Sstevel@tonic-gate again: 47617c478bd9Sstevel@tonic-gate flcg(); 47627c478bd9Sstevel@tonic-gate /* 47637c478bd9Sstevel@tonic-gate * summary info did not change size -- do nothing unless in test mode 47647c478bd9Sstevel@tonic-gate */ 47657c478bd9Sstevel@tonic-gate if (grow_fs_cssize == sblock.fs_cssize) 47667c478bd9Sstevel@tonic-gate if (!localtest) 47677c478bd9Sstevel@tonic-gate return; 47687c478bd9Sstevel@tonic-gate 47697c478bd9Sstevel@tonic-gate /* 47707c478bd9Sstevel@tonic-gate * build list of frags needed for additional summary information 47717c478bd9Sstevel@tonic-gate */ 47727c478bd9Sstevel@tonic-gate oldfrag = howmany(grow_fs_cssize, sblock.fs_fsize) + grow_fs_csaddr; 47737c478bd9Sstevel@tonic-gate newfrag = howmany(sblock.fs_cssize, sblock.fs_fsize) + grow_fs_csaddr; 47747c478bd9Sstevel@tonic-gate /* 47757c478bd9Sstevel@tonic-gate * add all of the frags that are required to grow the cyl summary to the 47767c478bd9Sstevel@tonic-gate * csfrag list, which is the generic/unknown list, since at this point 47777c478bd9Sstevel@tonic-gate * we don't yet know the state of those frags. 47787c478bd9Sstevel@tonic-gate */ 47797c478bd9Sstevel@tonic-gate for (i = oldfrag, frags = 0; i < newfrag; ++i, ++frags) 47807c478bd9Sstevel@tonic-gate addcsfrag((ino_t)0, (diskaddr_t)i, &csfrag); 47817c478bd9Sstevel@tonic-gate /* 47827c478bd9Sstevel@tonic-gate * reduce the number of data blocks in the file system (fs_dsize) by 47837c478bd9Sstevel@tonic-gate * the number of frags that need to be added to the cyl summary 47847c478bd9Sstevel@tonic-gate */ 47857c478bd9Sstevel@tonic-gate sblock.fs_dsize -= (newfrag - oldfrag); 47867c478bd9Sstevel@tonic-gate 47877c478bd9Sstevel@tonic-gate /* 47887c478bd9Sstevel@tonic-gate * In test mode, we move more data than necessary from 47897c478bd9Sstevel@tonic-gate * cylinder group 0. The lookup/allocate/move code can be 47907c478bd9Sstevel@tonic-gate * better stressed without having to create HUGE file systems. 47917c478bd9Sstevel@tonic-gate */ 47927c478bd9Sstevel@tonic-gate if (localtest) 47937c478bd9Sstevel@tonic-gate for (i = newfrag; i < grow_sifrag; ++i) { 47947c478bd9Sstevel@tonic-gate if (frags >= testfrags) 47957c478bd9Sstevel@tonic-gate break; 47967c478bd9Sstevel@tonic-gate frags++; 47977c478bd9Sstevel@tonic-gate addcsfrag((ino_t)0, (diskaddr_t)i, &csfrag); 47987c478bd9Sstevel@tonic-gate } 47997c478bd9Sstevel@tonic-gate 48007c478bd9Sstevel@tonic-gate /* 48017c478bd9Sstevel@tonic-gate * move frags to free or inode lists, depending on owner 48027c478bd9Sstevel@tonic-gate */ 48037c478bd9Sstevel@tonic-gate findcsfragfree(); 48047c478bd9Sstevel@tonic-gate findcsfragino(); 48057c478bd9Sstevel@tonic-gate 48067c478bd9Sstevel@tonic-gate /* 48077c478bd9Sstevel@tonic-gate * if not all frags can be located, file system must be inconsistent 48087c478bd9Sstevel@tonic-gate */ 48097c478bd9Sstevel@tonic-gate if (csfrag) { 48107c478bd9Sstevel@tonic-gate isbad = 1; /* should already be set, but make sure */ 48117c478bd9Sstevel@tonic-gate lockexit(32); 48127c478bd9Sstevel@tonic-gate } 48137c478bd9Sstevel@tonic-gate 48147c478bd9Sstevel@tonic-gate /* 48157c478bd9Sstevel@tonic-gate * allocate the free frags. Note that the free frags must be allocated 48167c478bd9Sstevel@tonic-gate * first otherwise they could be grabbed by alloccsfragino() for data 48177c478bd9Sstevel@tonic-gate * frags. 48187c478bd9Sstevel@tonic-gate */ 48197c478bd9Sstevel@tonic-gate alloccsfragfree(); 48207c478bd9Sstevel@tonic-gate /* 48217c478bd9Sstevel@tonic-gate * allocate extra space for inode frags 48227c478bd9Sstevel@tonic-gate */ 48237c478bd9Sstevel@tonic-gate alloccsfragino(); 48247c478bd9Sstevel@tonic-gate 48257c478bd9Sstevel@tonic-gate /* 48267c478bd9Sstevel@tonic-gate * not enough space 48277c478bd9Sstevel@tonic-gate */ 48287c478bd9Sstevel@tonic-gate if (notenoughspace()) { 48297c478bd9Sstevel@tonic-gate unalloccsfragfree(); 48307c478bd9Sstevel@tonic-gate unalloccsfragino(); 48317c478bd9Sstevel@tonic-gate if (localtest && !testforce) { 48327c478bd9Sstevel@tonic-gate localtest = 0; 48337c478bd9Sstevel@tonic-gate goto again; 48347c478bd9Sstevel@tonic-gate } 48357c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Not enough free space\n")); 48367c478bd9Sstevel@tonic-gate lockexit(NOTENOUGHSPACE); 48377c478bd9Sstevel@tonic-gate } 48387c478bd9Sstevel@tonic-gate 48397c478bd9Sstevel@tonic-gate /* 48407c478bd9Sstevel@tonic-gate * copy the data from old frags to new frags 48417c478bd9Sstevel@tonic-gate */ 48427c478bd9Sstevel@tonic-gate copycsfragino(); 48437c478bd9Sstevel@tonic-gate 48447c478bd9Sstevel@tonic-gate /* 48457c478bd9Sstevel@tonic-gate * fix the inodes to point to the new frags 48467c478bd9Sstevel@tonic-gate */ 48477c478bd9Sstevel@tonic-gate fixcsfragino(); 48487c478bd9Sstevel@tonic-gate 48497c478bd9Sstevel@tonic-gate /* 48507c478bd9Sstevel@tonic-gate * We may have moved more frags than we needed. Free them. 48517c478bd9Sstevel@tonic-gate */ 48527c478bd9Sstevel@tonic-gate rdcg((long)0); 48537c478bd9Sstevel@tonic-gate for (i = newfrag; i <= maxcsfrag; ++i) 48547c478bd9Sstevel@tonic-gate setbit(cg_blksfree(&acg), i-cgbase(&sblock, 0)); 48557c478bd9Sstevel@tonic-gate wtcg(); 48567c478bd9Sstevel@tonic-gate 48577c478bd9Sstevel@tonic-gate flcg(); 48587c478bd9Sstevel@tonic-gate } 48597c478bd9Sstevel@tonic-gate 48607c478bd9Sstevel@tonic-gate /* 48617c478bd9Sstevel@tonic-gate * Check if all fragments in the `csfragino' list were reallocated. 48627c478bd9Sstevel@tonic-gate */ 48637c478bd9Sstevel@tonic-gate int 48647c478bd9Sstevel@tonic-gate notenoughspace() 48657c478bd9Sstevel@tonic-gate { 48667c478bd9Sstevel@tonic-gate struct csfrag *cfp; 48677c478bd9Sstevel@tonic-gate 48687c478bd9Sstevel@tonic-gate /* 48697c478bd9Sstevel@tonic-gate * If any element in the csfragino array has a "new frag location" 48707c478bd9Sstevel@tonic-gate * of 0, the allocfrags() function was unsuccessful in allocating 48717c478bd9Sstevel@tonic-gate * space for moving the frag represented by this array element. 48727c478bd9Sstevel@tonic-gate */ 48737c478bd9Sstevel@tonic-gate for (cfp = csfragino; cfp; cfp = cfp->next) 48747c478bd9Sstevel@tonic-gate if (cfp->nfrag == 0) 48757c478bd9Sstevel@tonic-gate return (1); 48767c478bd9Sstevel@tonic-gate return (0); 48777c478bd9Sstevel@tonic-gate } 48787c478bd9Sstevel@tonic-gate 48797c478bd9Sstevel@tonic-gate void 48807c478bd9Sstevel@tonic-gate unalloccsfragino() 48817c478bd9Sstevel@tonic-gate { 48827c478bd9Sstevel@tonic-gate struct csfrag *cfp; 48837c478bd9Sstevel@tonic-gate 48847c478bd9Sstevel@tonic-gate while ((cfp = csfragino) != NULL) { 48857c478bd9Sstevel@tonic-gate if (cfp->nfrag) 48867c478bd9Sstevel@tonic-gate freefrags(cfp->nfrag, cfp->frags, cfp->cylno); 48877c478bd9Sstevel@tonic-gate delcsfrag(cfp->ofrag, &csfragino); 48887c478bd9Sstevel@tonic-gate } 48897c478bd9Sstevel@tonic-gate } 48907c478bd9Sstevel@tonic-gate 48917c478bd9Sstevel@tonic-gate void 48927c478bd9Sstevel@tonic-gate unalloccsfragfree() 48937c478bd9Sstevel@tonic-gate { 48947c478bd9Sstevel@tonic-gate struct csfrag *cfp; 48957c478bd9Sstevel@tonic-gate 48967c478bd9Sstevel@tonic-gate while ((cfp = csfragfree) != NULL) { 48977c478bd9Sstevel@tonic-gate freefrags(cfp->ofrag, cfp->frags, cfp->cylno); 48987c478bd9Sstevel@tonic-gate delcsfrag(cfp->ofrag, &csfragfree); 48997c478bd9Sstevel@tonic-gate } 49007c478bd9Sstevel@tonic-gate } 49017c478bd9Sstevel@tonic-gate 49027c478bd9Sstevel@tonic-gate /* 49037c478bd9Sstevel@tonic-gate * For each frag in the "as-yet-unclassified" list (csfrag), see if 49047c478bd9Sstevel@tonic-gate * it's free (i.e., its bit is set in the free frag bit map). If so, 49057c478bd9Sstevel@tonic-gate * move it from the "as-yet-unclassified" list to the csfragfree list. 49067c478bd9Sstevel@tonic-gate */ 49077c478bd9Sstevel@tonic-gate void 49087c478bd9Sstevel@tonic-gate findcsfragfree() 49097c478bd9Sstevel@tonic-gate { 49107c478bd9Sstevel@tonic-gate struct csfrag *cfp; 49117c478bd9Sstevel@tonic-gate struct csfrag *cfpnext; 49127c478bd9Sstevel@tonic-gate 49137c478bd9Sstevel@tonic-gate /* 49147c478bd9Sstevel@tonic-gate * move free frags onto the free-frag list 49157c478bd9Sstevel@tonic-gate */ 49167c478bd9Sstevel@tonic-gate rdcg((long)0); 49177c478bd9Sstevel@tonic-gate for (cfp = csfrag; cfp; cfp = cfpnext) { 49187c478bd9Sstevel@tonic-gate cfpnext = cfp->next; 49197c478bd9Sstevel@tonic-gate if (isset(cg_blksfree(&acg), cfp->ofrag - cgbase(&sblock, 0))) { 49207c478bd9Sstevel@tonic-gate addcsfrag(cfp->ino, cfp->ofrag, &csfragfree); 49217c478bd9Sstevel@tonic-gate delcsfrag(cfp->ofrag, &csfrag); 49227c478bd9Sstevel@tonic-gate } 49237c478bd9Sstevel@tonic-gate } 49247c478bd9Sstevel@tonic-gate } 49257c478bd9Sstevel@tonic-gate 49267c478bd9Sstevel@tonic-gate void 49277c478bd9Sstevel@tonic-gate copycsfragino() 49287c478bd9Sstevel@tonic-gate { 49297c478bd9Sstevel@tonic-gate struct csfrag *cfp; 49307c478bd9Sstevel@tonic-gate char buf[MAXBSIZE]; 49317c478bd9Sstevel@tonic-gate 49327c478bd9Sstevel@tonic-gate /* 49337c478bd9Sstevel@tonic-gate * copy data from old frags to newly allocated frags 49347c478bd9Sstevel@tonic-gate */ 49357c478bd9Sstevel@tonic-gate for (cfp = csfragino; cfp; cfp = cfp->next) { 49367c478bd9Sstevel@tonic-gate rdfs(fsbtodb(&sblock, (uint64_t)cfp->ofrag), (int)cfp->size, 49377c478bd9Sstevel@tonic-gate buf); 49387c478bd9Sstevel@tonic-gate wtfs(fsbtodb(&sblock, (uint64_t)cfp->nfrag), (int)cfp->size, 49397c478bd9Sstevel@tonic-gate buf); 49407c478bd9Sstevel@tonic-gate } 49417c478bd9Sstevel@tonic-gate } 49427c478bd9Sstevel@tonic-gate 49437c478bd9Sstevel@tonic-gate long curcylno = -1; 49447c478bd9Sstevel@tonic-gate int cylnodirty = 0; 49457c478bd9Sstevel@tonic-gate 49467c478bd9Sstevel@tonic-gate void 49477c478bd9Sstevel@tonic-gate rdcg(long cylno) 49487c478bd9Sstevel@tonic-gate { 49497c478bd9Sstevel@tonic-gate if (cylno != curcylno) { 49507c478bd9Sstevel@tonic-gate flcg(); 49517c478bd9Sstevel@tonic-gate curcylno = cylno; 49527c478bd9Sstevel@tonic-gate rdfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, curcylno)), 4953d50c8f90Svsakar (int)sblock.fs_cgsize, (char *)&acg); 49547c478bd9Sstevel@tonic-gate } 49557c478bd9Sstevel@tonic-gate } 49567c478bd9Sstevel@tonic-gate 49577c478bd9Sstevel@tonic-gate void 49587c478bd9Sstevel@tonic-gate flcg() 49597c478bd9Sstevel@tonic-gate { 49607c478bd9Sstevel@tonic-gate if (cylnodirty) { 49617c478bd9Sstevel@tonic-gate if (debug && Pflag) { 49627c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 4963d50c8f90Svsakar "Assert: cylnodirty set in probe mode\n"); 49647c478bd9Sstevel@tonic-gate return; 49657c478bd9Sstevel@tonic-gate } 49667c478bd9Sstevel@tonic-gate resetallocinfo(); 49677c478bd9Sstevel@tonic-gate wtfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, curcylno)), 4968d50c8f90Svsakar (int)sblock.fs_cgsize, (char *)&acg); 49697c478bd9Sstevel@tonic-gate cylnodirty = 0; 49707c478bd9Sstevel@tonic-gate } 49717c478bd9Sstevel@tonic-gate curcylno = -1; 49727c478bd9Sstevel@tonic-gate } 49737c478bd9Sstevel@tonic-gate 49747c478bd9Sstevel@tonic-gate void 49757c478bd9Sstevel@tonic-gate wtcg() 49767c478bd9Sstevel@tonic-gate { 49777c478bd9Sstevel@tonic-gate if (!Pflag) { 49787c478bd9Sstevel@tonic-gate /* probe mode should never write to disk */ 49797c478bd9Sstevel@tonic-gate cylnodirty = 1; 49807c478bd9Sstevel@tonic-gate } 49817c478bd9Sstevel@tonic-gate } 49827c478bd9Sstevel@tonic-gate 49837c478bd9Sstevel@tonic-gate void 49847c478bd9Sstevel@tonic-gate allocfrags(long frags, daddr32_t *fragp, long *cylnop) 49857c478bd9Sstevel@tonic-gate { 49867c478bd9Sstevel@tonic-gate int i; 49877c478bd9Sstevel@tonic-gate int j; 49887c478bd9Sstevel@tonic-gate long bits; 49897c478bd9Sstevel@tonic-gate long bit; 49907c478bd9Sstevel@tonic-gate 49917c478bd9Sstevel@tonic-gate /* 49927c478bd9Sstevel@tonic-gate * Allocate a free-frag range in an old cylinder group 49937c478bd9Sstevel@tonic-gate */ 49947c478bd9Sstevel@tonic-gate for (i = 0, *fragp = 0; i < grow_fs_ncg; ++i) { 49957c478bd9Sstevel@tonic-gate if (((fscs+i)->cs_nffree < frags) && ((fscs+i)->cs_nbfree == 0)) 49967c478bd9Sstevel@tonic-gate continue; 49977c478bd9Sstevel@tonic-gate rdcg((long)i); 49987c478bd9Sstevel@tonic-gate bit = bits = 0; 49997c478bd9Sstevel@tonic-gate while (findfreerange(&bit, &bits)) { 50007c478bd9Sstevel@tonic-gate if (frags <= bits) { 50017c478bd9Sstevel@tonic-gate for (j = 0; j < frags; ++j) 50027c478bd9Sstevel@tonic-gate clrbit(cg_blksfree(&acg), bit+j); 50037c478bd9Sstevel@tonic-gate wtcg(); 50047c478bd9Sstevel@tonic-gate *cylnop = i; 50057c478bd9Sstevel@tonic-gate *fragp = bit + cgbase(&sblock, i); 50067c478bd9Sstevel@tonic-gate return; 50077c478bd9Sstevel@tonic-gate } 50087c478bd9Sstevel@tonic-gate bit += bits; 50097c478bd9Sstevel@tonic-gate } 50107c478bd9Sstevel@tonic-gate } 50117c478bd9Sstevel@tonic-gate } 50127c478bd9Sstevel@tonic-gate 50137c478bd9Sstevel@tonic-gate /* 50147c478bd9Sstevel@tonic-gate * Allocate space for frags that need to be moved in order to free up space for 50157c478bd9Sstevel@tonic-gate * expanding the cylinder summary info. 50167c478bd9Sstevel@tonic-gate * For each frag that needs to be moved (each frag or range of frags in 50177c478bd9Sstevel@tonic-gate * the csfragino list), allocate a new location and store the frag number 50187c478bd9Sstevel@tonic-gate * of that new location in the nfrag field of the csfrag struct. 50197c478bd9Sstevel@tonic-gate * If a new frag can't be allocated for any element in the csfragino list, 50207c478bd9Sstevel@tonic-gate * set the new frag number for that element to 0 and return immediately. 50217c478bd9Sstevel@tonic-gate * The notenoughspace() function will detect this condition. 50227c478bd9Sstevel@tonic-gate */ 50237c478bd9Sstevel@tonic-gate void 50247c478bd9Sstevel@tonic-gate alloccsfragino() 50257c478bd9Sstevel@tonic-gate { 50267c478bd9Sstevel@tonic-gate struct csfrag *cfp; 50277c478bd9Sstevel@tonic-gate 50287c478bd9Sstevel@tonic-gate /* 50297c478bd9Sstevel@tonic-gate * allocate space for inode frag ranges 50307c478bd9Sstevel@tonic-gate */ 50317c478bd9Sstevel@tonic-gate for (cfp = csfragino; cfp; cfp = cfp->next) { 50327c478bd9Sstevel@tonic-gate allocfrags(cfp->frags, &cfp->nfrag, &cfp->cylno); 50337c478bd9Sstevel@tonic-gate if (cfp->nfrag == 0) 50347c478bd9Sstevel@tonic-gate break; 50357c478bd9Sstevel@tonic-gate } 50367c478bd9Sstevel@tonic-gate } 50377c478bd9Sstevel@tonic-gate 50387c478bd9Sstevel@tonic-gate void 50397c478bd9Sstevel@tonic-gate alloccsfragfree() 50407c478bd9Sstevel@tonic-gate { 50417c478bd9Sstevel@tonic-gate struct csfrag *cfp; 50427c478bd9Sstevel@tonic-gate 50437c478bd9Sstevel@tonic-gate /* 50447c478bd9Sstevel@tonic-gate * allocate the free frags needed for extended summary info 50457c478bd9Sstevel@tonic-gate */ 50467c478bd9Sstevel@tonic-gate rdcg((long)0); 50477c478bd9Sstevel@tonic-gate 50487c478bd9Sstevel@tonic-gate for (cfp = csfragfree; cfp; cfp = cfp->next) 50497c478bd9Sstevel@tonic-gate clrbit(cg_blksfree(&acg), cfp->ofrag - cgbase(&sblock, 0)); 50507c478bd9Sstevel@tonic-gate 50517c478bd9Sstevel@tonic-gate wtcg(); 50527c478bd9Sstevel@tonic-gate } 50537c478bd9Sstevel@tonic-gate 50547c478bd9Sstevel@tonic-gate void 50557c478bd9Sstevel@tonic-gate freefrags(daddr32_t frag, long frags, long cylno) 50567c478bd9Sstevel@tonic-gate { 50577c478bd9Sstevel@tonic-gate int i; 50587c478bd9Sstevel@tonic-gate 50597c478bd9Sstevel@tonic-gate /* 50607c478bd9Sstevel@tonic-gate * free frags 50617c478bd9Sstevel@tonic-gate */ 50627c478bd9Sstevel@tonic-gate rdcg(cylno); 50637c478bd9Sstevel@tonic-gate for (i = 0; i < frags; ++i) { 50647c478bd9Sstevel@tonic-gate setbit(cg_blksfree(&acg), (frag+i) - cgbase(&sblock, cylno)); 50657c478bd9Sstevel@tonic-gate } 50667c478bd9Sstevel@tonic-gate wtcg(); 50677c478bd9Sstevel@tonic-gate } 50687c478bd9Sstevel@tonic-gate 50697c478bd9Sstevel@tonic-gate int 50707c478bd9Sstevel@tonic-gate findfreerange(long *bitp, long *bitsp) 50717c478bd9Sstevel@tonic-gate { 50727c478bd9Sstevel@tonic-gate long bit; 50737c478bd9Sstevel@tonic-gate 50747c478bd9Sstevel@tonic-gate /* 50757c478bd9Sstevel@tonic-gate * find a range of free bits in a cylinder group bit map 50767c478bd9Sstevel@tonic-gate */ 50777c478bd9Sstevel@tonic-gate for (bit = *bitp, *bitsp = 0; bit < acg.cg_ndblk; ++bit) 50787c478bd9Sstevel@tonic-gate if (isset(cg_blksfree(&acg), bit)) 50797c478bd9Sstevel@tonic-gate break; 50807c478bd9Sstevel@tonic-gate 50817c478bd9Sstevel@tonic-gate if (bit >= acg.cg_ndblk) 50827c478bd9Sstevel@tonic-gate return (0); 50837c478bd9Sstevel@tonic-gate 50847c478bd9Sstevel@tonic-gate *bitp = bit; 50857c478bd9Sstevel@tonic-gate *bitsp = 1; 50867c478bd9Sstevel@tonic-gate for (++bit; bit < acg.cg_ndblk; ++bit, ++(*bitsp)) { 50877c478bd9Sstevel@tonic-gate if ((bit % sblock.fs_frag) == 0) 50887c478bd9Sstevel@tonic-gate break; 50897c478bd9Sstevel@tonic-gate if (isclr(cg_blksfree(&acg), bit)) 50907c478bd9Sstevel@tonic-gate break; 50917c478bd9Sstevel@tonic-gate } 50927c478bd9Sstevel@tonic-gate return (1); 50937c478bd9Sstevel@tonic-gate } 50947c478bd9Sstevel@tonic-gate 50957c478bd9Sstevel@tonic-gate void 50967c478bd9Sstevel@tonic-gate resetallocinfo() 50977c478bd9Sstevel@tonic-gate { 50987c478bd9Sstevel@tonic-gate long cno; 50997c478bd9Sstevel@tonic-gate long bit; 51007c478bd9Sstevel@tonic-gate long bits; 51017c478bd9Sstevel@tonic-gate 51027c478bd9Sstevel@tonic-gate /* 51037c478bd9Sstevel@tonic-gate * Compute the free blocks/frags info and update the appropriate 51047c478bd9Sstevel@tonic-gate * inmemory superblock, summary info, and cylinder group fields 51057c478bd9Sstevel@tonic-gate */ 51067c478bd9Sstevel@tonic-gate sblock.fs_cstotal.cs_nffree -= acg.cg_cs.cs_nffree; 51077c478bd9Sstevel@tonic-gate sblock.fs_cstotal.cs_nbfree -= acg.cg_cs.cs_nbfree; 51087c478bd9Sstevel@tonic-gate 51097c478bd9Sstevel@tonic-gate acg.cg_cs.cs_nffree = 0; 51107c478bd9Sstevel@tonic-gate acg.cg_cs.cs_nbfree = 0; 51117c478bd9Sstevel@tonic-gate 51127c478bd9Sstevel@tonic-gate bzero((caddr_t)acg.cg_frsum, sizeof (acg.cg_frsum)); 51137c478bd9Sstevel@tonic-gate bzero((caddr_t)cg_blktot(&acg), (int)(acg.cg_iusedoff-acg.cg_btotoff)); 51147c478bd9Sstevel@tonic-gate 51157c478bd9Sstevel@tonic-gate bit = bits = 0; 51167c478bd9Sstevel@tonic-gate while (findfreerange(&bit, &bits)) { 51177c478bd9Sstevel@tonic-gate if (bits == sblock.fs_frag) { 51187c478bd9Sstevel@tonic-gate acg.cg_cs.cs_nbfree++; 51197c478bd9Sstevel@tonic-gate cno = cbtocylno(&sblock, bit); 51207c478bd9Sstevel@tonic-gate cg_blktot(&acg)[cno]++; 51217c478bd9Sstevel@tonic-gate cg_blks(&sblock, &acg, cno)[cbtorpos(&sblock, bit)]++; 51227c478bd9Sstevel@tonic-gate } else { 51237c478bd9Sstevel@tonic-gate acg.cg_cs.cs_nffree += bits; 51247c478bd9Sstevel@tonic-gate acg.cg_frsum[bits]++; 51257c478bd9Sstevel@tonic-gate } 51267c478bd9Sstevel@tonic-gate bit += bits; 51277c478bd9Sstevel@tonic-gate } 51287c478bd9Sstevel@tonic-gate 51297c478bd9Sstevel@tonic-gate *(fscs + acg.cg_cgx) = acg.cg_cs; 51307c478bd9Sstevel@tonic-gate 51317c478bd9Sstevel@tonic-gate sblock.fs_cstotal.cs_nffree += acg.cg_cs.cs_nffree; 51327c478bd9Sstevel@tonic-gate sblock.fs_cstotal.cs_nbfree += acg.cg_cs.cs_nbfree; 51337c478bd9Sstevel@tonic-gate } 51347c478bd9Sstevel@tonic-gate 51357c478bd9Sstevel@tonic-gate void 51367c478bd9Sstevel@tonic-gate extendcg(long cylno) 51377c478bd9Sstevel@tonic-gate { 51387c478bd9Sstevel@tonic-gate int i; 51397c478bd9Sstevel@tonic-gate diskaddr_t dupper; 51407c478bd9Sstevel@tonic-gate diskaddr_t cbase; 51417c478bd9Sstevel@tonic-gate diskaddr_t dmax; 51427c478bd9Sstevel@tonic-gate 51437c478bd9Sstevel@tonic-gate /* 51447c478bd9Sstevel@tonic-gate * extend the cylinder group at the end of the old file system 51457c478bd9Sstevel@tonic-gate * if it was partially allocated becase of lack of space 51467c478bd9Sstevel@tonic-gate */ 51477c478bd9Sstevel@tonic-gate flcg(); 51487c478bd9Sstevel@tonic-gate rdcg(cylno); 51497c478bd9Sstevel@tonic-gate 51507c478bd9Sstevel@tonic-gate dupper = acg.cg_ndblk; 51517c478bd9Sstevel@tonic-gate if (cylno == sblock.fs_ncg - 1) 5152355d6bb5Sswilcox acg.cg_ncyl = sblock.fs_ncyl - (sblock.fs_cpg * cylno); 51537c478bd9Sstevel@tonic-gate else 51547c478bd9Sstevel@tonic-gate acg.cg_ncyl = sblock.fs_cpg; 51557c478bd9Sstevel@tonic-gate cbase = cgbase(&sblock, cylno); 51567c478bd9Sstevel@tonic-gate dmax = cbase + sblock.fs_fpg; 51577c478bd9Sstevel@tonic-gate if (dmax > sblock.fs_size) 51587c478bd9Sstevel@tonic-gate dmax = sblock.fs_size; 51597c478bd9Sstevel@tonic-gate acg.cg_ndblk = dmax - cbase; 51607c478bd9Sstevel@tonic-gate 51617c478bd9Sstevel@tonic-gate for (i = dupper; i < acg.cg_ndblk; ++i) 51627c478bd9Sstevel@tonic-gate setbit(cg_blksfree(&acg), i); 51637c478bd9Sstevel@tonic-gate 51647c478bd9Sstevel@tonic-gate sblock.fs_dsize += (acg.cg_ndblk - dupper); 51657c478bd9Sstevel@tonic-gate 51667c478bd9Sstevel@tonic-gate wtcg(); 51677c478bd9Sstevel@tonic-gate flcg(); 51687c478bd9Sstevel@tonic-gate } 51697c478bd9Sstevel@tonic-gate 51707c478bd9Sstevel@tonic-gate struct lockfs lockfs; 51717c478bd9Sstevel@tonic-gate int lockfd; 51727c478bd9Sstevel@tonic-gate int islocked; 51737c478bd9Sstevel@tonic-gate int lockfskey; 51747c478bd9Sstevel@tonic-gate char lockfscomment[128]; 51757c478bd9Sstevel@tonic-gate 51767c478bd9Sstevel@tonic-gate void 51777c478bd9Sstevel@tonic-gate ulockfs() 51787c478bd9Sstevel@tonic-gate { 51797c478bd9Sstevel@tonic-gate /* 51807c478bd9Sstevel@tonic-gate * if the file system was locked, unlock it before exiting 51817c478bd9Sstevel@tonic-gate */ 51827c478bd9Sstevel@tonic-gate if (islocked == 0) 51837c478bd9Sstevel@tonic-gate return; 51847c478bd9Sstevel@tonic-gate 51857c478bd9Sstevel@tonic-gate /* 51867c478bd9Sstevel@tonic-gate * first, check if the lock held 51877c478bd9Sstevel@tonic-gate */ 51887c478bd9Sstevel@tonic-gate lockfs.lf_flags = LOCKFS_MOD; 51897c478bd9Sstevel@tonic-gate if (ioctl(lockfd, _FIOLFSS, &lockfs) == -1) { 51907c478bd9Sstevel@tonic-gate perror(directory); 51917c478bd9Sstevel@tonic-gate lockexit(32); 51927c478bd9Sstevel@tonic-gate } 51937c478bd9Sstevel@tonic-gate 51947c478bd9Sstevel@tonic-gate if (LOCKFS_IS_MOD(&lockfs)) { 51957c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 5196d50c8f90Svsakar gettext("FILE SYSTEM CHANGED DURING GROWFS!\n")); 51977c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 5198d50c8f90Svsakar gettext(" See lockfs(1), umount(1), and fsck(1)\n")); 51997c478bd9Sstevel@tonic-gate lockexit(32); 52007c478bd9Sstevel@tonic-gate } 52017c478bd9Sstevel@tonic-gate /* 52027c478bd9Sstevel@tonic-gate * unlock the file system 52037c478bd9Sstevel@tonic-gate */ 52047c478bd9Sstevel@tonic-gate lockfs.lf_lock = LOCKFS_ULOCK; 52057c478bd9Sstevel@tonic-gate lockfs.lf_flags = 0; 52067c478bd9Sstevel@tonic-gate lockfs.lf_key = lockfskey; 52077c478bd9Sstevel@tonic-gate clockfs(); 52087c478bd9Sstevel@tonic-gate if (ioctl(lockfd, _FIOLFS, &lockfs) == -1) { 52097c478bd9Sstevel@tonic-gate perror(directory); 52107c478bd9Sstevel@tonic-gate lockexit(32); 52117c478bd9Sstevel@tonic-gate } 52127c478bd9Sstevel@tonic-gate } 52137c478bd9Sstevel@tonic-gate 52147c478bd9Sstevel@tonic-gate void 52157c478bd9Sstevel@tonic-gate wlockfs() 52167c478bd9Sstevel@tonic-gate { 52177c478bd9Sstevel@tonic-gate 52187c478bd9Sstevel@tonic-gate /* 52197c478bd9Sstevel@tonic-gate * if no-write (-N), don't bother 52207c478bd9Sstevel@tonic-gate */ 52217c478bd9Sstevel@tonic-gate if (Nflag) 52227c478bd9Sstevel@tonic-gate return; 52237c478bd9Sstevel@tonic-gate /* 52247c478bd9Sstevel@tonic-gate * open the mountpoint, and write lock the file system 52257c478bd9Sstevel@tonic-gate */ 52267c478bd9Sstevel@tonic-gate if ((lockfd = open64(directory, O_RDONLY)) == -1) { 52277c478bd9Sstevel@tonic-gate perror(directory); 52287c478bd9Sstevel@tonic-gate lockexit(32); 52297c478bd9Sstevel@tonic-gate } 52307c478bd9Sstevel@tonic-gate 52317c478bd9Sstevel@tonic-gate /* 52327c478bd9Sstevel@tonic-gate * check if it is already locked 52337c478bd9Sstevel@tonic-gate */ 52347c478bd9Sstevel@tonic-gate if (ioctl(lockfd, _FIOLFSS, &lockfs) == -1) { 52357c478bd9Sstevel@tonic-gate perror(directory); 52367c478bd9Sstevel@tonic-gate lockexit(32); 52377c478bd9Sstevel@tonic-gate } 52387c478bd9Sstevel@tonic-gate 52397c478bd9Sstevel@tonic-gate if (lockfs.lf_lock != LOCKFS_WLOCK) { 52407c478bd9Sstevel@tonic-gate lockfs.lf_lock = LOCKFS_WLOCK; 52417c478bd9Sstevel@tonic-gate lockfs.lf_flags = 0; 52427c478bd9Sstevel@tonic-gate lockfs.lf_key = 0; 52437c478bd9Sstevel@tonic-gate clockfs(); 52447c478bd9Sstevel@tonic-gate if (ioctl(lockfd, _FIOLFS, &lockfs) == -1) { 52457c478bd9Sstevel@tonic-gate perror(directory); 52467c478bd9Sstevel@tonic-gate lockexit(32); 52477c478bd9Sstevel@tonic-gate } 52487c478bd9Sstevel@tonic-gate } 52497c478bd9Sstevel@tonic-gate islocked = 1; 52507c478bd9Sstevel@tonic-gate lockfskey = lockfs.lf_key; 52517c478bd9Sstevel@tonic-gate } 52527c478bd9Sstevel@tonic-gate 52537c478bd9Sstevel@tonic-gate void 52547c478bd9Sstevel@tonic-gate clockfs() 52557c478bd9Sstevel@tonic-gate { 52567c478bd9Sstevel@tonic-gate time_t t; 52577c478bd9Sstevel@tonic-gate char *ct; 52587c478bd9Sstevel@tonic-gate 52597c478bd9Sstevel@tonic-gate (void) time(&t); 52607c478bd9Sstevel@tonic-gate ct = ctime(&t); 52617c478bd9Sstevel@tonic-gate ct[strlen(ct)-1] = '\0'; 52627c478bd9Sstevel@tonic-gate 52637c478bd9Sstevel@tonic-gate (void) sprintf(lockfscomment, "%s -- mkfs pid %d", ct, getpid()); 52647c478bd9Sstevel@tonic-gate lockfs.lf_comlen = strlen(lockfscomment)+1; 52657c478bd9Sstevel@tonic-gate lockfs.lf_comment = lockfscomment; 52667c478bd9Sstevel@tonic-gate } 52677c478bd9Sstevel@tonic-gate 52687c478bd9Sstevel@tonic-gate /* 52697c478bd9Sstevel@tonic-gate * Write the csum records and the superblock 52707c478bd9Sstevel@tonic-gate */ 52717c478bd9Sstevel@tonic-gate void 52727c478bd9Sstevel@tonic-gate wtsb() 52737c478bd9Sstevel@tonic-gate { 52747c478bd9Sstevel@tonic-gate long i; 52757c478bd9Sstevel@tonic-gate 52767c478bd9Sstevel@tonic-gate /* 52777c478bd9Sstevel@tonic-gate * write summary information 52787c478bd9Sstevel@tonic-gate */ 52797c478bd9Sstevel@tonic-gate for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize) 52807c478bd9Sstevel@tonic-gate wtfs(fsbtodb(&sblock, (uint64_t)(sblock.fs_csaddr + 5281d50c8f90Svsakar numfrags(&sblock, i))), 5282d50c8f90Svsakar (int)(sblock.fs_cssize - i < sblock.fs_bsize ? 5283d50c8f90Svsakar sblock.fs_cssize - i : sblock.fs_bsize), 5284d50c8f90Svsakar ((char *)fscs) + i); 52857c478bd9Sstevel@tonic-gate 52867c478bd9Sstevel@tonic-gate /* 52877c478bd9Sstevel@tonic-gate * write superblock 52887c478bd9Sstevel@tonic-gate */ 52897c478bd9Sstevel@tonic-gate sblock.fs_time = mkfstime; 52907c478bd9Sstevel@tonic-gate wtfs((diskaddr_t)(SBOFF / sectorsize), sbsize, (char *)&sblock); 52917c478bd9Sstevel@tonic-gate } 52927c478bd9Sstevel@tonic-gate 52937c478bd9Sstevel@tonic-gate /* 52947c478bd9Sstevel@tonic-gate * Verify that the optimization selection is reasonable, and advance 52957c478bd9Sstevel@tonic-gate * the global "string" appropriately. 52967c478bd9Sstevel@tonic-gate */ 52977c478bd9Sstevel@tonic-gate static char 52987c478bd9Sstevel@tonic-gate checkopt(char *optim) 52997c478bd9Sstevel@tonic-gate { 53007c478bd9Sstevel@tonic-gate char opt; 53017c478bd9Sstevel@tonic-gate int limit = strcspn(optim, ","); 53027c478bd9Sstevel@tonic-gate 53037c478bd9Sstevel@tonic-gate switch (limit) { 53047c478bd9Sstevel@tonic-gate case 0: /* missing indicator (have comma or nul) */ 53057c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 53067c478bd9Sstevel@tonic-gate "mkfs: missing optimization flag reset to `t' (time)\n")); 53077c478bd9Sstevel@tonic-gate opt = 't'; 53087c478bd9Sstevel@tonic-gate break; 53097c478bd9Sstevel@tonic-gate 53107c478bd9Sstevel@tonic-gate case 1: /* single-character indicator */ 53117c478bd9Sstevel@tonic-gate opt = *optim; 53127c478bd9Sstevel@tonic-gate if ((opt != 's') && (opt != 't')) { 53137c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 53147c478bd9Sstevel@tonic-gate "mkfs: bad optimization value `%c' reset to `t' (time)\n"), 53157c478bd9Sstevel@tonic-gate opt); 53167c478bd9Sstevel@tonic-gate opt = 't'; 53177c478bd9Sstevel@tonic-gate } 53187c478bd9Sstevel@tonic-gate break; 53197c478bd9Sstevel@tonic-gate 53207c478bd9Sstevel@tonic-gate default: /* multi-character indicator */ 53217c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 53227c478bd9Sstevel@tonic-gate "mkfs: bad optimization value `%*.*s' reset to `t' (time)\n"), 53237c478bd9Sstevel@tonic-gate limit, limit, optim); 53247c478bd9Sstevel@tonic-gate opt = 't'; 53257c478bd9Sstevel@tonic-gate break; 53267c478bd9Sstevel@tonic-gate } 53277c478bd9Sstevel@tonic-gate 53287c478bd9Sstevel@tonic-gate string += limit; 53297c478bd9Sstevel@tonic-gate 53307c478bd9Sstevel@tonic-gate return (opt); 53317c478bd9Sstevel@tonic-gate } 53327c478bd9Sstevel@tonic-gate 53337c478bd9Sstevel@tonic-gate /* 53347c478bd9Sstevel@tonic-gate * Verify that the mtb selection is reasonable, and advance 53357c478bd9Sstevel@tonic-gate * the global "string" appropriately. 53367c478bd9Sstevel@tonic-gate */ 53377c478bd9Sstevel@tonic-gate static char 53387c478bd9Sstevel@tonic-gate checkmtb(char *mtbarg) 53397c478bd9Sstevel@tonic-gate { 53407c478bd9Sstevel@tonic-gate char mtbc; 53417c478bd9Sstevel@tonic-gate int limit = strcspn(mtbarg, ","); 53427c478bd9Sstevel@tonic-gate 53437c478bd9Sstevel@tonic-gate switch (limit) { 53447c478bd9Sstevel@tonic-gate case 0: /* missing indicator (have comma or nul) */ 53457c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 53467c478bd9Sstevel@tonic-gate "mkfs: missing mtb flag reset to `n' (no mtb support)\n")); 53477c478bd9Sstevel@tonic-gate mtbc = 'n'; 53487c478bd9Sstevel@tonic-gate break; 53497c478bd9Sstevel@tonic-gate 53507c478bd9Sstevel@tonic-gate case 1: /* single-character indicator */ 53517c478bd9Sstevel@tonic-gate mtbc = tolower(*mtbarg); 53527c478bd9Sstevel@tonic-gate if ((mtbc != 'y') && (mtbc != 'n')) { 53537c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 53547c478bd9Sstevel@tonic-gate "mkfs: bad mtb value `%c' reset to `n' (no mtb support)\n"), 53557c478bd9Sstevel@tonic-gate mtbc); 53567c478bd9Sstevel@tonic-gate mtbc = 'n'; 53577c478bd9Sstevel@tonic-gate } 53587c478bd9Sstevel@tonic-gate break; 53597c478bd9Sstevel@tonic-gate 53607c478bd9Sstevel@tonic-gate default: /* multi-character indicator */ 53617c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 53627c478bd9Sstevel@tonic-gate "mkfs: bad mtb value `%*.*s' reset to `n' (no mtb support)\n"), 53637c478bd9Sstevel@tonic-gate limit, limit, mtbarg); 53647c478bd9Sstevel@tonic-gate opt = 'n'; 53657c478bd9Sstevel@tonic-gate break; 53667c478bd9Sstevel@tonic-gate } 53677c478bd9Sstevel@tonic-gate 53687c478bd9Sstevel@tonic-gate string += limit; 53697c478bd9Sstevel@tonic-gate 53707c478bd9Sstevel@tonic-gate return (mtbc); 53717c478bd9Sstevel@tonic-gate } 53727c478bd9Sstevel@tonic-gate 53737c478bd9Sstevel@tonic-gate /* 53747c478bd9Sstevel@tonic-gate * Verify that a value is in a range. If it is not, resets it to 53757c478bd9Sstevel@tonic-gate * its default value if one is supplied, exits otherwise. 53767c478bd9Sstevel@tonic-gate * 53777c478bd9Sstevel@tonic-gate * When testing, can compare user_supplied to RC_KEYWORD or RC_POSITIONAL. 53787c478bd9Sstevel@tonic-gate */ 53797c478bd9Sstevel@tonic-gate static void 53807c478bd9Sstevel@tonic-gate range_check(long *varp, char *name, long minimum, long maximum, 53817c478bd9Sstevel@tonic-gate long def_val, int user_supplied) 53827c478bd9Sstevel@tonic-gate { 53836451fdbcSvsakar dprintf(("DeBuG %s : %ld (%ld %ld %ld)\n", 5384d50c8f90Svsakar name, *varp, minimum, maximum, def_val)); 53856451fdbcSvsakar 53867c478bd9Sstevel@tonic-gate if ((*varp < minimum) || (*varp > maximum)) { 53877c478bd9Sstevel@tonic-gate if (user_supplied != RC_DEFAULT) { 53887c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 53897c478bd9Sstevel@tonic-gate "mkfs: bad value for %s: %ld must be between %ld and %ld\n"), 53907c478bd9Sstevel@tonic-gate name, *varp, minimum, maximum); 53917c478bd9Sstevel@tonic-gate } 53927c478bd9Sstevel@tonic-gate if (def_val != NO_DEFAULT) { 53937c478bd9Sstevel@tonic-gate if (user_supplied) { 53947c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 53957c478bd9Sstevel@tonic-gate gettext("mkfs: %s reset to default %ld\n"), 53967c478bd9Sstevel@tonic-gate name, def_val); 53977c478bd9Sstevel@tonic-gate } 53987c478bd9Sstevel@tonic-gate *varp = def_val; 53996451fdbcSvsakar dprintf(("DeBuG %s : %ld\n", name, *varp)); 54007c478bd9Sstevel@tonic-gate return; 54017c478bd9Sstevel@tonic-gate } 54027c478bd9Sstevel@tonic-gate lockexit(2); 54037c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 54047c478bd9Sstevel@tonic-gate } 54057c478bd9Sstevel@tonic-gate } 54067c478bd9Sstevel@tonic-gate 54077c478bd9Sstevel@tonic-gate /* 54087c478bd9Sstevel@tonic-gate * Verify that a value is in a range. If it is not, resets it to 54097c478bd9Sstevel@tonic-gate * its default value if one is supplied, exits otherwise. 54107c478bd9Sstevel@tonic-gate * 54117c478bd9Sstevel@tonic-gate * When testing, can compare user_supplied to RC_KEYWORD or RC_POSITIONAL. 54127c478bd9Sstevel@tonic-gate */ 54137c478bd9Sstevel@tonic-gate static void 54147c478bd9Sstevel@tonic-gate range_check_64(uint64_t *varp, char *name, uint64_t minimum, uint64_t maximum, 54157c478bd9Sstevel@tonic-gate uint64_t def_val, int user_supplied) 54167c478bd9Sstevel@tonic-gate { 54177c478bd9Sstevel@tonic-gate if ((*varp < minimum) || (*varp > maximum)) { 54187c478bd9Sstevel@tonic-gate if (user_supplied != RC_DEFAULT) { 54197c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 54207c478bd9Sstevel@tonic-gate "mkfs: bad value for %s: %lld must be between %lld and %lld\n"), 54217c478bd9Sstevel@tonic-gate name, *varp, minimum, maximum); 54227c478bd9Sstevel@tonic-gate } 54237c478bd9Sstevel@tonic-gate if (def_val != NO_DEFAULT) { 54247c478bd9Sstevel@tonic-gate if (user_supplied) { 54257c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 54267c478bd9Sstevel@tonic-gate gettext("mkfs: %s reset to default %lld\n"), 54277c478bd9Sstevel@tonic-gate name, def_val); 54287c478bd9Sstevel@tonic-gate } 54297c478bd9Sstevel@tonic-gate *varp = def_val; 54307c478bd9Sstevel@tonic-gate return; 54317c478bd9Sstevel@tonic-gate } 54327c478bd9Sstevel@tonic-gate lockexit(2); 54337c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 54347c478bd9Sstevel@tonic-gate } 54357c478bd9Sstevel@tonic-gate } 54367c478bd9Sstevel@tonic-gate 54377c478bd9Sstevel@tonic-gate /* 54387c478bd9Sstevel@tonic-gate * Blocks SIGINT from delivery. Returns the previous mask in the 54397c478bd9Sstevel@tonic-gate * buffer provided, so that mask may be later restored. 54407c478bd9Sstevel@tonic-gate */ 54417c478bd9Sstevel@tonic-gate static void 54427c478bd9Sstevel@tonic-gate block_sigint(sigset_t *old_mask) 54437c478bd9Sstevel@tonic-gate { 54447c478bd9Sstevel@tonic-gate sigset_t block_mask; 54457c478bd9Sstevel@tonic-gate 54467c478bd9Sstevel@tonic-gate if (sigemptyset(&block_mask) < 0) { 54477c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Could not clear signal mask\n")); 54487c478bd9Sstevel@tonic-gate lockexit(3); 54497c478bd9Sstevel@tonic-gate } 54507c478bd9Sstevel@tonic-gate if (sigaddset(&block_mask, SIGINT) < 0) { 54517c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Could not set signal mask\n")); 54527c478bd9Sstevel@tonic-gate lockexit(3); 54537c478bd9Sstevel@tonic-gate } 54547c478bd9Sstevel@tonic-gate if (sigprocmask(SIG_BLOCK, &block_mask, old_mask) < 0) { 54557c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Could not block SIGINT\n")); 54567c478bd9Sstevel@tonic-gate lockexit(3); 54577c478bd9Sstevel@tonic-gate } 54587c478bd9Sstevel@tonic-gate } 54597c478bd9Sstevel@tonic-gate 54607c478bd9Sstevel@tonic-gate /* 54617c478bd9Sstevel@tonic-gate * Restores the signal mask that was in force before a call 54627c478bd9Sstevel@tonic-gate * to block_sigint(). This may actually still have SIGINT blocked, 54637c478bd9Sstevel@tonic-gate * if we've been recursively invoked. 54647c478bd9Sstevel@tonic-gate */ 54657c478bd9Sstevel@tonic-gate static void 54667c478bd9Sstevel@tonic-gate unblock_sigint(sigset_t *old_mask) 54677c478bd9Sstevel@tonic-gate { 54687c478bd9Sstevel@tonic-gate if (sigprocmask(SIG_UNBLOCK, old_mask, (sigset_t *)NULL) < 0) { 54697c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Could not restore signal mask\n")); 54707c478bd9Sstevel@tonic-gate lockexit(3); 54717c478bd9Sstevel@tonic-gate } 54727c478bd9Sstevel@tonic-gate } 54737c478bd9Sstevel@tonic-gate 54747c478bd9Sstevel@tonic-gate /* 54757c478bd9Sstevel@tonic-gate * Attempt to be somewhat graceful about being interrupted, rather than 54767c478bd9Sstevel@tonic-gate * just silently leaving the filesystem in an unusable state. 54777c478bd9Sstevel@tonic-gate * 54787c478bd9Sstevel@tonic-gate * The kernel has blocked SIGINT upon entry, so we don't have to worry 54797c478bd9Sstevel@tonic-gate * about recursion if the user starts pounding on the keyboard. 54807c478bd9Sstevel@tonic-gate */ 54817c478bd9Sstevel@tonic-gate static void 54827c478bd9Sstevel@tonic-gate recover_from_sigint(int signum) 54837c478bd9Sstevel@tonic-gate { 54847c478bd9Sstevel@tonic-gate if (fso > -1) { 54857c478bd9Sstevel@tonic-gate if ((Nflag != 0) || confirm_abort()) { 54867c478bd9Sstevel@tonic-gate lockexit(4); 54877c478bd9Sstevel@tonic-gate } 54887c478bd9Sstevel@tonic-gate } 54897c478bd9Sstevel@tonic-gate } 54907c478bd9Sstevel@tonic-gate 54917c478bd9Sstevel@tonic-gate static int 54927c478bd9Sstevel@tonic-gate confirm_abort(void) 54937c478bd9Sstevel@tonic-gate { 54947c478bd9Sstevel@tonic-gate char line[80]; 54957c478bd9Sstevel@tonic-gate 54967c478bd9Sstevel@tonic-gate printf(gettext("\n\nAborting at this point will leave the filesystem " 5497d50c8f90Svsakar "in an inconsistent\nstate. If you do choose to stop, " 5498d50c8f90Svsakar "you will be given instructions on how to\nrecover " 5499d50c8f90Svsakar "the filesystem. Do you wish to cancel the filesystem " 5500d50c8f90Svsakar "grow\noperation (y/n)?")); 5501*23a1cceaSRoger A. Faulkner if (getaline(stdin, line, sizeof (line)) == EOF) 55027c478bd9Sstevel@tonic-gate line[0] = 'y'; 55037c478bd9Sstevel@tonic-gate 55047c478bd9Sstevel@tonic-gate printf("\n"); 55057c478bd9Sstevel@tonic-gate if (line[0] == 'y' || line[0] == 'Y') 55067c478bd9Sstevel@tonic-gate return (1); 55077c478bd9Sstevel@tonic-gate else { 55087c478bd9Sstevel@tonic-gate return (0); 55097c478bd9Sstevel@tonic-gate } 55107c478bd9Sstevel@tonic-gate } 55117c478bd9Sstevel@tonic-gate 55127c478bd9Sstevel@tonic-gate static int 5513*23a1cceaSRoger A. Faulkner getaline(FILE *fp, char *loc, int maxlen) 55147c478bd9Sstevel@tonic-gate { 55157c478bd9Sstevel@tonic-gate int n; 55167c478bd9Sstevel@tonic-gate char *p, *lastloc; 55177c478bd9Sstevel@tonic-gate 55187c478bd9Sstevel@tonic-gate p = loc; 55197c478bd9Sstevel@tonic-gate lastloc = &p[maxlen-1]; 55207c478bd9Sstevel@tonic-gate while ((n = getc(fp)) != '\n') { 55217c478bd9Sstevel@tonic-gate if (n == EOF) 55227c478bd9Sstevel@tonic-gate return (EOF); 55237c478bd9Sstevel@tonic-gate if (!isspace(n) && p < lastloc) 55247c478bd9Sstevel@tonic-gate *p++ = n; 55257c478bd9Sstevel@tonic-gate } 55267c478bd9Sstevel@tonic-gate *p = 0; 55277c478bd9Sstevel@tonic-gate return (p - loc); 55287c478bd9Sstevel@tonic-gate } 55297c478bd9Sstevel@tonic-gate 55307c478bd9Sstevel@tonic-gate /* 55317c478bd9Sstevel@tonic-gate * Calculate the maximum value of cylinders-per-group for a file 55327c478bd9Sstevel@tonic-gate * system with the characteristics: 55337c478bd9Sstevel@tonic-gate * 55347c478bd9Sstevel@tonic-gate * bsize - file system block size 55357c478bd9Sstevel@tonic-gate * fragsize - frag size 55367c478bd9Sstevel@tonic-gate * nbpi - number of bytes of disk space per inode 55377c478bd9Sstevel@tonic-gate * nrpos - number of rotational positions 55387c478bd9Sstevel@tonic-gate * spc - sectors per cylinder 55397c478bd9Sstevel@tonic-gate * 55407c478bd9Sstevel@tonic-gate * These five characteristic are not adjustable (by this function). 55417c478bd9Sstevel@tonic-gate * The only attribute of the file system which IS adjusted by this 55427c478bd9Sstevel@tonic-gate * function in order to maximize cylinders-per-group is the proportion 55437c478bd9Sstevel@tonic-gate * of the cylinder group overhead block used for the inode map. The 55447c478bd9Sstevel@tonic-gate * inode map cannot occupy more than one-third of the cylinder group 55457c478bd9Sstevel@tonic-gate * overhead block, but it's OK for it to occupy less than one-third 55467c478bd9Sstevel@tonic-gate * of the overhead block. 55477c478bd9Sstevel@tonic-gate * 55487c478bd9Sstevel@tonic-gate * The setting of nbpi determines one possible value for the maximum 55497c478bd9Sstevel@tonic-gate * size of a cylinder group. It does so because it determines the total 55507c478bd9Sstevel@tonic-gate * number of inodes in the file system (file system size is fixed, and 55517c478bd9Sstevel@tonic-gate * nbpi is fixed, so the total number of inodes is fixed too). The 55527c478bd9Sstevel@tonic-gate * cylinder group has to be small enough so that the number of inodes 55537c478bd9Sstevel@tonic-gate * in the cylinder group is less than or equal to the number of bits 55547c478bd9Sstevel@tonic-gate * in one-third (or whatever proportion is assumed) of a file system 55557c478bd9Sstevel@tonic-gate * block. The details of the calculation are: 55567c478bd9Sstevel@tonic-gate * 55577c478bd9Sstevel@tonic-gate * The macro MAXIpG_B(bsize, inode_divisor) determines the maximum 55587c478bd9Sstevel@tonic-gate * number of inodes that can be in a cylinder group, given the 55597c478bd9Sstevel@tonic-gate * proportion of the cylinder group overhead block used for the 55607c478bd9Sstevel@tonic-gate * inode bitmaps (an inode_divisor of 3 means that 1/3 of the 55617c478bd9Sstevel@tonic-gate * block is used for inode bitmaps; an inode_divisor of 12 means 55627c478bd9Sstevel@tonic-gate * that 1/12 of the block is used for inode bitmaps.) 55637c478bd9Sstevel@tonic-gate * 55647c478bd9Sstevel@tonic-gate * Once the number of inodes per cylinder group is known, the 55657c478bd9Sstevel@tonic-gate * maximum value of cylinders-per-group (determined by nbpi) 55667c478bd9Sstevel@tonic-gate * is calculated by the formula 55677c478bd9Sstevel@tonic-gate * 55687c478bd9Sstevel@tonic-gate * maxcpg_given_nbpi = (size of a cylinder group)/(size of a cylinder) 55697c478bd9Sstevel@tonic-gate * 55707c478bd9Sstevel@tonic-gate * = (inodes-per-cg * nbpi)/(spc * DEV_BSIZE) 55717c478bd9Sstevel@tonic-gate * 55727c478bd9Sstevel@tonic-gate * (Interestingly, the size of the file system never enters 55737c478bd9Sstevel@tonic-gate * into this calculation.) 55747c478bd9Sstevel@tonic-gate * 55757c478bd9Sstevel@tonic-gate * Another possible value for the maximum cylinder group size is determined 55767c478bd9Sstevel@tonic-gate * by frag_size and nrpos. The frags in the cylinder group must be 55777c478bd9Sstevel@tonic-gate * representable in the frag bitmaps in the cylinder overhead block and the 55787c478bd9Sstevel@tonic-gate * rotational positions for each cylinder must be represented in the 55797c478bd9Sstevel@tonic-gate * rotational position tables. The calculation of the maximum cpg 55807c478bd9Sstevel@tonic-gate * value, given the frag and nrpos vales, is: 55817c478bd9Sstevel@tonic-gate * 55827c478bd9Sstevel@tonic-gate * maxcpg_given_fragsize = 55837c478bd9Sstevel@tonic-gate * (available space in the overhead block) / (size of per-cylinder data) 55847c478bd9Sstevel@tonic-gate * 55857c478bd9Sstevel@tonic-gate * The available space in the overhead block = 55867c478bd9Sstevel@tonic-gate * bsize - sizeof (struct cg) - space_used_for_inode_bitmaps 55877c478bd9Sstevel@tonic-gate * 55887c478bd9Sstevel@tonic-gate * The size of the per-cylinder data is: 55897c478bd9Sstevel@tonic-gate * sizeof(long) # for the "blocks avail per cylinder" field 55907c478bd9Sstevel@tonic-gate * + nrpos * sizeof(short) # for the rotational position table entry 55917c478bd9Sstevel@tonic-gate * + frags-per-cylinder/NBBY # number of bytes to represent this 55927c478bd9Sstevel@tonic-gate * # cylinder in the frag bitmap 55937c478bd9Sstevel@tonic-gate * 55947c478bd9Sstevel@tonic-gate * The two calculated maximum values of cylinder-per-group will typically 55957c478bd9Sstevel@tonic-gate * turn out to be different, since they are derived from two different 55967c478bd9Sstevel@tonic-gate * constraints. Usually, maxcpg_given_nbpi is much bigger than 55977c478bd9Sstevel@tonic-gate * maxcpg_given_fragsize. But they can be brought together by 55987c478bd9Sstevel@tonic-gate * adjusting the proportion of the overhead block dedicated to 55997c478bd9Sstevel@tonic-gate * the inode bitmaps. Decreasing the proportion of the cylinder 56007c478bd9Sstevel@tonic-gate * group overhead block used for inode maps will decrease 56017c478bd9Sstevel@tonic-gate * maxcpg_given_nbpi and increase maxcpg_given_fragsize. 56027c478bd9Sstevel@tonic-gate * 56037c478bd9Sstevel@tonic-gate * This function calculates the initial values of maxcpg_given_nbpi 56047c478bd9Sstevel@tonic-gate * and maxcpg_given_fragsize assuming that 1/3 of the cg overhead 56057c478bd9Sstevel@tonic-gate * block is used for inode bitmaps. Then it decreases the proportion 56067c478bd9Sstevel@tonic-gate * of the cg overhead block used for inode bitmaps (by increasing 56077c478bd9Sstevel@tonic-gate * the value of inode_divisor) until maxcpg_given_nbpi and 56087c478bd9Sstevel@tonic-gate * maxcpg_given_fragsize are the same, or stop changing, or 56097c478bd9Sstevel@tonic-gate * maxcpg_given_nbpi is less than maxcpg_given_fragsize. 56107c478bd9Sstevel@tonic-gate * 56117c478bd9Sstevel@tonic-gate * The loop terminates when any of the following occur: 56127c478bd9Sstevel@tonic-gate * * maxcpg_given_fragsize is greater than or equal to 56137c478bd9Sstevel@tonic-gate * maxcpg_given_nbpi 56147c478bd9Sstevel@tonic-gate * * neither maxcpg_given_fragsize nor maxcpg_given_nbpi 56157c478bd9Sstevel@tonic-gate * change in the expected direction 56167c478bd9Sstevel@tonic-gate * 56177c478bd9Sstevel@tonic-gate * The loop is guaranteed to terminate because it only continues 56187c478bd9Sstevel@tonic-gate * while maxcpg_given_fragsize and maxcpg_given_nbpi are approaching 56197c478bd9Sstevel@tonic-gate * each other. As soon they cross each other, or neither one changes 56207c478bd9Sstevel@tonic-gate * in the direction of the other, or one of them moves in the wrong 56217c478bd9Sstevel@tonic-gate * direction, the loop completes. 56227c478bd9Sstevel@tonic-gate */ 56237c478bd9Sstevel@tonic-gate 56247c478bd9Sstevel@tonic-gate static long 56257c478bd9Sstevel@tonic-gate compute_maxcpg(long bsize, long fragsize, long nbpi, long nrpos, long spc) 56267c478bd9Sstevel@tonic-gate { 56277c478bd9Sstevel@tonic-gate int maxcpg_given_nbpi; /* in cylinders */ 56287c478bd9Sstevel@tonic-gate int maxcpg_given_fragsize; /* in cylinders */ 56297c478bd9Sstevel@tonic-gate int spf; /* sectors per frag */ 56307c478bd9Sstevel@tonic-gate int inode_divisor; 56317c478bd9Sstevel@tonic-gate int old_max_given_frag = 0; 56327c478bd9Sstevel@tonic-gate int old_max_given_nbpi = INT_MAX; 56337c478bd9Sstevel@tonic-gate 56347c478bd9Sstevel@tonic-gate spf = fragsize / DEV_BSIZE; 56357c478bd9Sstevel@tonic-gate inode_divisor = 3; 56367c478bd9Sstevel@tonic-gate 56377c478bd9Sstevel@tonic-gate while (1) { 56387c478bd9Sstevel@tonic-gate maxcpg_given_nbpi = 56397c478bd9Sstevel@tonic-gate (((int64_t)(MAXIpG_B(bsize, inode_divisor))) * nbpi) / 56407c478bd9Sstevel@tonic-gate (DEV_BSIZE * ((int64_t)spc)); 56417c478bd9Sstevel@tonic-gate maxcpg_given_fragsize = 56427c478bd9Sstevel@tonic-gate (bsize - (sizeof (struct cg)) - (bsize / inode_divisor)) / 56437c478bd9Sstevel@tonic-gate (sizeof (long) + nrpos * sizeof (short) + 5644d50c8f90Svsakar (spc / spf) / NBBY); 56457c478bd9Sstevel@tonic-gate 56467c478bd9Sstevel@tonic-gate if (maxcpg_given_fragsize >= maxcpg_given_nbpi) 56477c478bd9Sstevel@tonic-gate return (maxcpg_given_nbpi); 56487c478bd9Sstevel@tonic-gate 56497c478bd9Sstevel@tonic-gate /* 56507c478bd9Sstevel@tonic-gate * If neither value moves toward the other, return the 56517c478bd9Sstevel@tonic-gate * least of the old values (we use the old instead of the 56527c478bd9Sstevel@tonic-gate * new because: if the old is the same as the new, it 56537c478bd9Sstevel@tonic-gate * doesn't matter which ones we use. If one of the 56547c478bd9Sstevel@tonic-gate * values changed, but in the wrong direction, the 56557c478bd9Sstevel@tonic-gate * new values are suspect. Better use the old. This 56567c478bd9Sstevel@tonic-gate * shouldn't happen, but it's best to check. 56577c478bd9Sstevel@tonic-gate */ 56587c478bd9Sstevel@tonic-gate 56597c478bd9Sstevel@tonic-gate if (!(maxcpg_given_nbpi < old_max_given_nbpi) && 56607c478bd9Sstevel@tonic-gate !(maxcpg_given_fragsize > old_max_given_frag)) 56617c478bd9Sstevel@tonic-gate return (MIN(old_max_given_nbpi, old_max_given_frag)); 56627c478bd9Sstevel@tonic-gate 56637c478bd9Sstevel@tonic-gate /* 56647c478bd9Sstevel@tonic-gate * This is probably impossible, but if one of the maxcpg 56657c478bd9Sstevel@tonic-gate * values moved in the "right" direction and one moved 56667c478bd9Sstevel@tonic-gate * in the "wrong" direction (that is, the two values moved 56677c478bd9Sstevel@tonic-gate * in the same direction), the previous conditional won't 56687c478bd9Sstevel@tonic-gate * recognize that the values aren't converging (since at 56697c478bd9Sstevel@tonic-gate * least one value moved in the "right" direction, the 56707c478bd9Sstevel@tonic-gate * last conditional says "keep going"). 56717c478bd9Sstevel@tonic-gate * 56727c478bd9Sstevel@tonic-gate * Just to make absolutely certain that the loop terminates, 56737c478bd9Sstevel@tonic-gate * check for one of the values moving in the "wrong" direction 56747c478bd9Sstevel@tonic-gate * and terminate the loop if it happens. 56757c478bd9Sstevel@tonic-gate */ 56767c478bd9Sstevel@tonic-gate 56777c478bd9Sstevel@tonic-gate if (maxcpg_given_nbpi > old_max_given_nbpi || 56787c478bd9Sstevel@tonic-gate maxcpg_given_fragsize < old_max_given_frag) 56797c478bd9Sstevel@tonic-gate return (MIN(old_max_given_nbpi, old_max_given_frag)); 56807c478bd9Sstevel@tonic-gate 56817c478bd9Sstevel@tonic-gate old_max_given_nbpi = maxcpg_given_nbpi; 56827c478bd9Sstevel@tonic-gate old_max_given_frag = maxcpg_given_fragsize; 56837c478bd9Sstevel@tonic-gate 56847c478bd9Sstevel@tonic-gate inode_divisor++; 56857c478bd9Sstevel@tonic-gate } 56867c478bd9Sstevel@tonic-gate } 56877c478bd9Sstevel@tonic-gate 56887c478bd9Sstevel@tonic-gate static int 56897c478bd9Sstevel@tonic-gate in_64bit_mode(void) 56907c478bd9Sstevel@tonic-gate { 56917c478bd9Sstevel@tonic-gate /* cmd must be an absolute path, for security */ 56927c478bd9Sstevel@tonic-gate char *cmd = "/usr/bin/isainfo -b"; 56937c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 56947c478bd9Sstevel@tonic-gate FILE *ptr; 56957c478bd9Sstevel@tonic-gate int retval = 0; 56967c478bd9Sstevel@tonic-gate 56977c478bd9Sstevel@tonic-gate putenv("IFS= \t"); 56987c478bd9Sstevel@tonic-gate if ((ptr = popen(cmd, "r")) != NULL) { 56997c478bd9Sstevel@tonic-gate if (fgets(buf, BUFSIZ, ptr) != NULL && 57007c478bd9Sstevel@tonic-gate strncmp(buf, "64", 2) == 0) 57017c478bd9Sstevel@tonic-gate retval = 1; 57027c478bd9Sstevel@tonic-gate (void) pclose(ptr); 57037c478bd9Sstevel@tonic-gate } 57047c478bd9Sstevel@tonic-gate return (retval); 57057c478bd9Sstevel@tonic-gate } 57067c478bd9Sstevel@tonic-gate 57077c478bd9Sstevel@tonic-gate /* 57087c478bd9Sstevel@tonic-gate * validate_size 57097c478bd9Sstevel@tonic-gate * 57107c478bd9Sstevel@tonic-gate * Return 1 if the device appears to be at least "size" sectors long. 57117c478bd9Sstevel@tonic-gate * Return 0 if it's shorter or we can't read it. 57127c478bd9Sstevel@tonic-gate */ 57137c478bd9Sstevel@tonic-gate 57147c478bd9Sstevel@tonic-gate static int 57157c478bd9Sstevel@tonic-gate validate_size(int fd, diskaddr_t size) 57167c478bd9Sstevel@tonic-gate { 57177c478bd9Sstevel@tonic-gate char buf[DEV_BSIZE]; 57187c478bd9Sstevel@tonic-gate int rc; 57197c478bd9Sstevel@tonic-gate 57207c478bd9Sstevel@tonic-gate if ((llseek(fd, (offset_t)((size - 1) * DEV_BSIZE), SEEK_SET) == -1) || 57217c478bd9Sstevel@tonic-gate (read(fd, buf, DEV_BSIZE)) != DEV_BSIZE) 57227c478bd9Sstevel@tonic-gate rc = 0; 57237c478bd9Sstevel@tonic-gate else 57247c478bd9Sstevel@tonic-gate rc = 1; 57257c478bd9Sstevel@tonic-gate return (rc); 57267c478bd9Sstevel@tonic-gate } 5727355d6bb5Sswilcox 5728355d6bb5Sswilcox /* 5729355d6bb5Sswilcox * Print every field of the calculated superblock, along with 5730355d6bb5Sswilcox * its value. To make parsing easier on the caller, the value 5731355d6bb5Sswilcox * is printed first, then the name. Additionally, there's only 5732355d6bb5Sswilcox * one name/value pair per line. All values are reported in 5733355d6bb5Sswilcox * hexadecimal (with the traditional 0x prefix), as that's slightly 5734355d6bb5Sswilcox * easier for humans to read. Not that they're expected to, but 5735355d6bb5Sswilcox * debugging happens. 5736355d6bb5Sswilcox */ 5737355d6bb5Sswilcox static void 5738355d6bb5Sswilcox dump_sblock(void) 5739355d6bb5Sswilcox { 5740355d6bb5Sswilcox int row, column, pending, written; 5741355d6bb5Sswilcox caddr_t source; 5742355d6bb5Sswilcox 5743355d6bb5Sswilcox if (Rflag) { 5744355d6bb5Sswilcox pending = sizeof (sblock); 5745355d6bb5Sswilcox source = (caddr_t)&sblock; 5746355d6bb5Sswilcox do { 5747355d6bb5Sswilcox written = write(fileno(stdout), source, pending); 5748355d6bb5Sswilcox pending -= written; 5749355d6bb5Sswilcox source += written; 5750355d6bb5Sswilcox } while ((pending > 0) && (written > 0)); 5751355d6bb5Sswilcox 5752355d6bb5Sswilcox if (written < 0) { 5753355d6bb5Sswilcox perror(gettext("Binary dump of superblock failed")); 5754355d6bb5Sswilcox lockexit(1); 5755355d6bb5Sswilcox } 5756355d6bb5Sswilcox return; 5757355d6bb5Sswilcox } else { 5758355d6bb5Sswilcox printf("0x%x sblock.fs_link\n", sblock.fs_link); 5759355d6bb5Sswilcox printf("0x%x sblock.fs_rolled\n", sblock.fs_rolled); 5760355d6bb5Sswilcox printf("0x%x sblock.fs_sblkno\n", sblock.fs_sblkno); 5761355d6bb5Sswilcox printf("0x%x sblock.fs_cblkno\n", sblock.fs_cblkno); 5762355d6bb5Sswilcox printf("0x%x sblock.fs_iblkno\n", sblock.fs_iblkno); 5763355d6bb5Sswilcox printf("0x%x sblock.fs_dblkno\n", sblock.fs_dblkno); 5764355d6bb5Sswilcox printf("0x%x sblock.fs_cgoffset\n", sblock.fs_cgoffset); 5765355d6bb5Sswilcox printf("0x%x sblock.fs_cgmask\n", sblock.fs_cgmask); 5766355d6bb5Sswilcox printf("0x%x sblock.fs_time\n", sblock.fs_time); 5767355d6bb5Sswilcox printf("0x%x sblock.fs_size\n", sblock.fs_size); 5768355d6bb5Sswilcox printf("0x%x sblock.fs_dsize\n", sblock.fs_dsize); 5769355d6bb5Sswilcox printf("0x%x sblock.fs_ncg\n", sblock.fs_ncg); 5770355d6bb5Sswilcox printf("0x%x sblock.fs_bsize\n", sblock.fs_bsize); 5771355d6bb5Sswilcox printf("0x%x sblock.fs_fsize\n", sblock.fs_fsize); 5772355d6bb5Sswilcox printf("0x%x sblock.fs_frag\n", sblock.fs_frag); 5773355d6bb5Sswilcox printf("0x%x sblock.fs_minfree\n", sblock.fs_minfree); 5774355d6bb5Sswilcox printf("0x%x sblock.fs_rotdelay\n", sblock.fs_rotdelay); 5775355d6bb5Sswilcox printf("0x%x sblock.fs_rps\n", sblock.fs_rps); 5776355d6bb5Sswilcox printf("0x%x sblock.fs_bmask\n", sblock.fs_bmask); 5777355d6bb5Sswilcox printf("0x%x sblock.fs_fmask\n", sblock.fs_fmask); 5778355d6bb5Sswilcox printf("0x%x sblock.fs_bshift\n", sblock.fs_bshift); 5779355d6bb5Sswilcox printf("0x%x sblock.fs_fshift\n", sblock.fs_fshift); 5780355d6bb5Sswilcox printf("0x%x sblock.fs_maxcontig\n", sblock.fs_maxcontig); 5781355d6bb5Sswilcox printf("0x%x sblock.fs_maxbpg\n", sblock.fs_maxbpg); 5782355d6bb5Sswilcox printf("0x%x sblock.fs_fragshift\n", sblock.fs_fragshift); 5783355d6bb5Sswilcox printf("0x%x sblock.fs_fsbtodb\n", sblock.fs_fsbtodb); 5784355d6bb5Sswilcox printf("0x%x sblock.fs_sbsize\n", sblock.fs_sbsize); 5785355d6bb5Sswilcox printf("0x%x sblock.fs_csmask\n", sblock.fs_csmask); 5786355d6bb5Sswilcox printf("0x%x sblock.fs_csshift\n", sblock.fs_csshift); 5787355d6bb5Sswilcox printf("0x%x sblock.fs_nindir\n", sblock.fs_nindir); 5788355d6bb5Sswilcox printf("0x%x sblock.fs_inopb\n", sblock.fs_inopb); 5789355d6bb5Sswilcox printf("0x%x sblock.fs_nspf\n", sblock.fs_nspf); 5790355d6bb5Sswilcox printf("0x%x sblock.fs_optim\n", sblock.fs_optim); 5791355d6bb5Sswilcox #ifdef _LITTLE_ENDIAN 5792355d6bb5Sswilcox printf("0x%x sblock.fs_state\n", sblock.fs_state); 5793355d6bb5Sswilcox #else 5794355d6bb5Sswilcox printf("0x%x sblock.fs_npsect\n", sblock.fs_npsect); 5795355d6bb5Sswilcox #endif 5796355d6bb5Sswilcox printf("0x%x sblock.fs_si\n", sblock.fs_si); 5797355d6bb5Sswilcox printf("0x%x sblock.fs_trackskew\n", sblock.fs_trackskew); 5798355d6bb5Sswilcox printf("0x%x sblock.fs_id[0]\n", sblock.fs_id[0]); 5799355d6bb5Sswilcox printf("0x%x sblock.fs_id[1]\n", sblock.fs_id[1]); 5800355d6bb5Sswilcox printf("0x%x sblock.fs_csaddr\n", sblock.fs_csaddr); 5801355d6bb5Sswilcox printf("0x%x sblock.fs_cssize\n", sblock.fs_cssize); 5802355d6bb5Sswilcox printf("0x%x sblock.fs_cgsize\n", sblock.fs_cgsize); 5803355d6bb5Sswilcox printf("0x%x sblock.fs_ntrak\n", sblock.fs_ntrak); 5804355d6bb5Sswilcox printf("0x%x sblock.fs_nsect\n", sblock.fs_nsect); 5805355d6bb5Sswilcox printf("0x%x sblock.fs_spc\n", sblock.fs_spc); 5806355d6bb5Sswilcox printf("0x%x sblock.fs_ncyl\n", sblock.fs_ncyl); 5807355d6bb5Sswilcox printf("0x%x sblock.fs_cpg\n", sblock.fs_cpg); 5808355d6bb5Sswilcox printf("0x%x sblock.fs_ipg\n", sblock.fs_ipg); 5809355d6bb5Sswilcox printf("0x%x sblock.fs_fpg\n", sblock.fs_fpg); 5810355d6bb5Sswilcox printf("0x%x sblock.fs_cstotal\n", sblock.fs_cstotal); 5811355d6bb5Sswilcox printf("0x%x sblock.fs_fmod\n", sblock.fs_fmod); 5812355d6bb5Sswilcox printf("0x%x sblock.fs_clean\n", sblock.fs_clean); 5813355d6bb5Sswilcox printf("0x%x sblock.fs_ronly\n", sblock.fs_ronly); 5814355d6bb5Sswilcox printf("0x%x sblock.fs_flags\n", sblock.fs_flags); 5815355d6bb5Sswilcox printf("0x%x sblock.fs_fsmnt\n", sblock.fs_fsmnt); 5816355d6bb5Sswilcox printf("0x%x sblock.fs_cgrotor\n", sblock.fs_cgrotor); 5817355d6bb5Sswilcox printf("0x%x sblock.fs_u.fs_csp\n", sblock.fs_u.fs_csp); 5818355d6bb5Sswilcox printf("0x%x sblock.fs_cpc\n", sblock.fs_cpc); 5819355d6bb5Sswilcox 5820355d6bb5Sswilcox /* 5821355d6bb5Sswilcox * No macros are defined for the dimensions of the 5822355d6bb5Sswilcox * opostbl array. 5823355d6bb5Sswilcox */ 5824355d6bb5Sswilcox for (row = 0; row < 16; row++) { 5825355d6bb5Sswilcox for (column = 0; column < 8; column++) { 5826355d6bb5Sswilcox printf("0x%x sblock.fs_opostbl[%d][%d]\n", 5827355d6bb5Sswilcox sblock.fs_opostbl[row][column], 5828355d6bb5Sswilcox row, column); 5829355d6bb5Sswilcox } 5830355d6bb5Sswilcox } 5831355d6bb5Sswilcox 5832355d6bb5Sswilcox /* 5833355d6bb5Sswilcox * Ditto the size of sparecon. 5834355d6bb5Sswilcox */ 5835355d6bb5Sswilcox for (row = 0; row < 51; row++) { 5836355d6bb5Sswilcox printf("0x%x sblock.fs_sparecon[%d]\n", 5837355d6bb5Sswilcox sblock.fs_sparecon[row], row); 5838355d6bb5Sswilcox } 5839355d6bb5Sswilcox 5840355d6bb5Sswilcox printf("0x%x sblock.fs_version\n", sblock.fs_version); 5841355d6bb5Sswilcox printf("0x%x sblock.fs_logbno\n", sblock.fs_logbno); 5842355d6bb5Sswilcox printf("0x%x sblock.fs_reclaim\n", sblock.fs_reclaim); 5843355d6bb5Sswilcox printf("0x%x sblock.fs_sparecon2\n", sblock.fs_sparecon2); 5844355d6bb5Sswilcox #ifdef _LITTLE_ENDIAN 5845355d6bb5Sswilcox printf("0x%x sblock.fs_npsect\n", sblock.fs_npsect); 5846355d6bb5Sswilcox #else 5847355d6bb5Sswilcox printf("0x%x sblock.fs_state\n", sblock.fs_state); 5848355d6bb5Sswilcox #endif 5849355d6bb5Sswilcox printf("0x%llx sblock.fs_qbmask\n", sblock.fs_qbmask); 5850355d6bb5Sswilcox printf("0x%llx sblock.fs_qfmask\n", sblock.fs_qfmask); 5851355d6bb5Sswilcox printf("0x%x sblock.fs_postblformat\n", sblock.fs_postblformat); 5852355d6bb5Sswilcox printf("0x%x sblock.fs_nrpos\n", sblock.fs_nrpos); 5853355d6bb5Sswilcox printf("0x%x sblock.fs_postbloff\n", sblock.fs_postbloff); 5854355d6bb5Sswilcox printf("0x%x sblock.fs_rotbloff\n", sblock.fs_rotbloff); 5855355d6bb5Sswilcox printf("0x%x sblock.fs_magic\n", sblock.fs_magic); 5856355d6bb5Sswilcox 5857355d6bb5Sswilcox /* 5858355d6bb5Sswilcox * fs_space isn't of much use in this context, so we'll 5859355d6bb5Sswilcox * just ignore it for now. 5860355d6bb5Sswilcox */ 5861355d6bb5Sswilcox } 5862355d6bb5Sswilcox } 5863