1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 /*
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
33 *
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
37 */
38
39 /*
40 * Copyright (c) 2018, Joyent, Inc.
41 */
42
43 /*
44 * The maximum supported file system size (in sectors) is the
45 * number of frags that can be represented in an int32_t field
46 * (INT_MAX) times the maximum number of sectors per frag. Since
47 * the maximum frag size is MAXBSIZE, the maximum number of sectors
48 * per frag is MAXBSIZE/DEV_BSIZE.
49 */
50 #define FS_MAX (((diskaddr_t)INT_MAX) * (MAXBSIZE/DEV_BSIZE))
51
52 /*
53 * make file system for cylinder-group style file systems
54 *
55 * usage:
56 *
57 * mkfs [-F FSType] [-V] [-G [-P]] [-M dirname] [-m] [options]
58 * [-o specific_options] special size
59 * [nsect ntrack bsize fsize cpg minfree rps nbpi opt apc rotdelay
60 * 2 3 4 5 6 7 8 9 10 11 12
61 * nrpos maxcontig mtb]
62 * 13 14 15
63 *
64 * where specific_options are:
65 * N - no create
66 * nsect - The number of sectors per track
67 * ntrack - The number of tracks per cylinder
68 * bsize - block size
69 * fragsize - fragment size
70 * cgsize - The number of disk cylinders per cylinder group.
71 * free - minimum free space
72 * rps - rotational speed (rev/sec).
73 * nbpi - number of data bytes per allocated inode
74 * opt - optimization (space, time)
75 * apc - number of alternates
76 * gap - gap size
77 * nrpos - number of rotational positions
78 * maxcontig - maximum number of logical blocks that will be
79 * allocated contiguously before inserting rotational delay
80 * mtb - if "y", set up file system for eventual growth to over a
81 * a terabyte
82 * -P Do not grow the file system, but print on stdout the maximal
83 * size in sectors to which the file system can be increased. The calculated
84 * size is limited by the value provided by the operand size.
85 *
86 * Note that -P is a project-private interface and together with -G intended
87 * to be used only by the growfs script. It is therefore purposely not
88 * documented in the man page.
89 * The -P option is covered by PSARC case 2003/422.
90 */
91
92 /*
93 * The following constants set the defaults used for the number
94 * of sectors/track (fs_nsect), and number of tracks/cyl (fs_ntrak).
95 *
96 * NSECT NTRAK
97 * 72MB CDC 18 9
98 * 30MB CDC 18 5
99 * 720KB Diskette 9 2
100 *
101 * However the defaults will be different for disks larger than CHSLIMIT.
102 */
103
104 #define DFLNSECT 32
105 #define DFLNTRAK 16
106
107 /*
108 * The following default sectors and tracks values are used for
109 * non-efi disks that are larger than the CHS addressing limit. The
110 * existing default cpg of 16 (DESCPG) holds good for larger disks too.
111 */
112 #define DEF_SECTORS_EFI 128
113 #define DEF_TRACKS_EFI 48
114
115 /*
116 * The maximum number of cylinders in a group depends upon how much
117 * information can be stored on a single cylinder. The default is to
118 * use 16 cylinders per group. This is effectively tradition - it was
119 * the largest value acceptable under SunOs 4.1
120 */
121 #define DESCPG 16 /* desired fs_cpg */
122
123 /*
124 * The following two constants set the default block and fragment sizes.
125 * Both constants must be a power of 2 and meet the following constraints:
126 * MINBSIZE <= DESBLKSIZE <= MAXBSIZE
127 * DEV_BSIZE <= DESFRAGSIZE <= DESBLKSIZE
128 * DESBLKSIZE / DESFRAGSIZE <= 8
129 */
130 #define DESBLKSIZE 8192
131 #define DESFRAGSIZE 1024
132
133 /*
134 * MINFREE gives the minimum acceptable percentage of file system
135 * blocks which may be free. If the freelist drops below this level
136 * only the superuser may continue to allocate blocks. This may
137 * be set to 0 if no reserve of free blocks is deemed necessary,
138 * however throughput drops by fifty percent if the file system
139 * is run at between 90% and 100% full; thus the default value of
140 * fs_minfree is 10%. With 10% free space, fragmentation is not a
141 * problem, so we choose to optimize for time.
142 */
143 #define MINFREE 10
144 #define DEFAULTOPT FS_OPTTIME
145
146 /*
147 * ROTDELAY gives the minimum number of milliseconds to initiate
148 * another disk transfer on the same cylinder. It is no longer used
149 * and will always default to 0.
150 */
151 #define ROTDELAY 0
152
153 /*
154 * MAXBLKPG determines the maximum number of data blocks which are
155 * placed in a single cylinder group. The default is one indirect
156 * block worth of data blocks.
157 */
158 #define MAXBLKPG(bsize) ((bsize) / sizeof (daddr32_t))
159
160 /*
161 * Each file system has a number of inodes statically allocated.
162 * We allocate one inode slot per NBPI bytes, expecting this
163 * to be far more than we will ever need.
164 */
165 #define NBPI 2048 /* Number Bytes Per Inode */
166 #define MTB_NBPI (MB) /* Number Bytes Per Inode for multi-terabyte */
167
168 /*
169 * Disks are assumed to rotate at 60HZ, unless otherwise specified.
170 */
171 #define DEFHZ 60
172
173 /*
174 * Cylinder group related limits.
175 *
176 * For each cylinder we keep track of the availability of blocks at different
177 * rotational positions, so that we can lay out the data to be picked
178 * up with minimum rotational latency. NRPOS is the number of rotational
179 * positions which we distinguish. With NRPOS 8 the resolution of our
180 * summary information is 2ms for a typical 3600 rpm drive.
181 */
182 #define NRPOS 8 /* number distinct rotational positions */
183
184 #ifdef DEBUG
185 #define dprintf(x) printf x
186 #else
187 #define dprintf(x)
188 #endif
189
190 /*
191 * For the -N option, when calculating the backup superblocks, do not print
192 * them if we are not really sure. We may have to try an alternate method of
193 * arriving at the superblocks. So defer printing till a handful of superblocks
194 * look good.
195 */
196 #define tprintf(x) if (Nflag && retry) \
197 (void) strncat(tmpbuf, x, strlen(x)); \
198 else \
199 (void) fprintf(stderr, x);
200
201 #define ALTSB 32 /* Location of first backup superblock */
202
203 /*
204 * range_check "user_supplied" flag values.
205 */
206 #define RC_DEFAULT 0
207 #define RC_KEYWORD 1
208 #define RC_POSITIONAL 2
209
210 /*
211 * ufs hole
212 */
213 #define UFS_HOLE -1
214
215 #ifndef STANDALONE
216 #include <stdio.h>
217 #include <sys/mnttab.h>
218 #endif
219
220 #include <stdlib.h>
221 #include <unistd.h>
222 #include <malloc.h>
223 #include <string.h>
224 #include <strings.h>
225 #include <ctype.h>
226 #include <errno.h>
227 #include <sys/param.h>
228 #include <time.h>
229 #include <sys/types.h>
230 #include <sys/sysmacros.h>
231 #include <sys/vnode.h>
232 #include <sys/fs/ufs_fsdir.h>
233 #include <sys/fs/ufs_inode.h>
234 #include <sys/fs/ufs_fs.h>
235 #include <sys/fs/ufs_log.h>
236 #include <sys/mntent.h>
237 #include <sys/filio.h>
238 #include <limits.h>
239 #include <sys/int_const.h>
240 #include <signal.h>
241 #include <sys/efi_partition.h>
242 #include <fslib.h>
243 #include "roll_log.h"
244
245 #define bcopy(f, t, n) (void) memcpy(t, f, n)
246 #define bzero(s, n) (void) memset(s, 0, n)
247 #define bcmp(s, d, n) memcmp(s, d, n)
248
249 #define index(s, r) strchr(s, r)
250 #define rindex(s, r) strrchr(s, r)
251
252 #include <sys/stat.h>
253 #include <sys/statvfs.h>
254 #include <locale.h>
255 #include <fcntl.h>
256 #include <sys/isa_defs.h> /* for ENDIAN defines */
257 #include <sys/vtoc.h>
258
259 #include <sys/dkio.h>
260 #include <sys/asynch.h>
261
262 extern offset_t llseek();
263 extern char *getfullblkname();
264 extern long lrand48();
265
266 extern int optind;
267 extern char *optarg;
268
269
270 /*
271 * The size of a cylinder group is calculated by CGSIZE. The maximum size
272 * is limited by the fact that cylinder groups are at most one block.
273 * Its size is derived from the size of the maps maintained in the
274 * cylinder group and the (struct cg) size.
275 */
276 #define CGSIZE(fs) \
277 /* base cg */ (sizeof (struct cg) + \
278 /* blktot size */ (fs)->fs_cpg * sizeof (long) + \
279 /* blks size */ (fs)->fs_cpg * (fs)->fs_nrpos * sizeof (short) + \
280 /* inode map */ howmany((fs)->fs_ipg, NBBY) + \
281 /* block map */ howmany((fs)->fs_cpg * (fs)->fs_spc / NSPF(fs), NBBY))
282
283 /*
284 * We limit the size of the inode map to be no more than a
285 * third of the cylinder group space, since we must leave at
286 * least an equal amount of space for the block map.
287 *
288 * N.B.: MAXIpG must be a multiple of INOPB(fs).
289 */
290 #define MAXIpG(fs) roundup((fs)->fs_bsize * NBBY / 3, INOPB(fs))
291
292 /*
293 * Same as MAXIpG, but parameterized by the block size (b) and the
294 * cylinder group divisor (d), which is the reciprocal of the fraction of the
295 * cylinder group overhead block that is used for the inode map. So for
296 * example, if d = 5, the macro's computation assumes that 1/5 of the
297 * cylinder group overhead block can be dedicated to the inode map.
298 */
299 #define MAXIpG_B(b, d) roundup((b) * NBBY / (d), (b) / sizeof (struct dinode))
300
301 #define UMASK 0755
302 #define MAXINOPB (MAXBSIZE / sizeof (struct dinode))
303 #define POWEROF2(num) (((num) & ((num) - 1)) == 0)
304 #define MB (1024*1024)
305 #define BETWEEN(x, l, h) ((x) >= (l) && (x) <= (h))
306
307 /*
308 * Used to set the inode generation number. Since both inodes and dinodes
309 * are dealt with, we really need a pointer to an icommon here.
310 */
311 #define IRANDOMIZE(icp) (icp)->ic_gen = lrand48();
312
313 /*
314 * Flags for number()
315 */
316 #define ALLOW_PERCENT 0x01 /* allow trailing `%' on number */
317 #define ALLOW_MS1 0x02 /* allow trailing `ms', state 1 */
318 #define ALLOW_MS2 0x04 /* allow trailing `ms', state 2 */
319 #define ALLOW_END_ONLY 0x08 /* must be at end of number & suffixes */
320
321 #define MAXAIO 1000 /* maximum number of outstanding I/O's we'll manage */
322 #define BLOCK 1 /* block in aiowait */
323 #define NOBLOCK 0 /* don't block in aiowait */
324
325 #define RELEASE 1 /* free an aio buffer after use */
326 #define SAVE 0 /* don't free the buffer */
327
328 typedef struct aio_trans {
329 aio_result_t resultbuf;
330 diskaddr_t bno;
331 char *buffer;
332 int size;
333 int release;
334 struct aio_trans *next;
335 } aio_trans;
336
337 typedef struct aio_results {
338 int max;
339 int outstanding;
340 int maxpend;
341 aio_trans *trans;
342 } aio_results;
343
344 int aio_inited = 0;
345 aio_results results;
346
347 /*
348 * Allow up to MAXBUF aio requests that each have a unique buffer.
349 * More aio's might be done, but not using memory through the getbuf()
350 * interface. This can be raised, but you run into the potential of
351 * using more memory than is physically available on the machine,
352 * and if you start swapping, you can forget about performance.
353 * To prevent this, we also limit the total memory used for a given
354 * type of buffer to MAXBUFMEM.
355 *
356 * Tests indicate a cylinder group's worth of inodes takes:
357 *
358 * NBPI Size of Inode Buffer
359 * 2k 1688k
360 * 8k 424k
361 *
362 * initcg() stores all the inodes for a cylinder group in one buffer,
363 * so allowing 20 buffers could take 32 MB if not limited by MAXBUFMEM.
364 */
365 #define MAXBUF 20
366 #define MAXBUFMEM (8 * 1024 * 1024)
367
368 /*
369 * header information for buffers managed by getbuf() and freebuf()
370 */
371 typedef struct bufhdr {
372 struct bufhdr *head;
373 struct bufhdr *next;
374 } bufhdr;
375
376 int bufhdrsize;
377
378 bufhdr inodebuf = { NULL, NULL };
379 bufhdr cgsumbuf = { NULL, NULL };
380
381 #define SECTORS_PER_TERABYTE (1LL << 31)
382 /*
383 * The following constant specifies an upper limit for file system size
384 * that is actually a lot bigger than we expect to support with UFS. (Since
385 * it's specified in sectors, the file system size would be 2**44 * 512,
386 * which is 2**53, which is 8192 Terabytes.) However, it's useful
387 * for checking the basic sanity of a size value that is input on the
388 * command line.
389 */
390 #define FS_SIZE_UPPER_LIMIT 0x100000000000LL
391
392 /*
393 * Forward declarations
394 */
395 static char *getbuf(bufhdr *bufhead, int size);
396 static void freebuf(char *buf);
397 static void freetrans(aio_trans *transp);
398 static aio_trans *get_aiop();
399 static aio_trans *wait_for_write(int block);
400 static void initcg(int cylno);
401 static void fsinit();
402 static int makedir(struct direct *protodir, int entries);
403 static void iput(struct inode *ip);
404 static void rdfs(diskaddr_t bno, int size, char *bf);
405 static void wtfs(diskaddr_t bno, int size, char *bf);
406 static void awtfs(diskaddr_t bno, int size, char *bf, int release);
407 static void wtfs_breakup(diskaddr_t bno, int size, char *bf);
408 static int isblock(struct fs *fs, unsigned char *cp, int h);
409 static void clrblock(struct fs *fs, unsigned char *cp, int h);
410 static void setblock(struct fs *fs, unsigned char *cp, int h);
411 static void usage(void) __NORETURN;
412 static void dump_fscmd(char *fsys, int fsi);
413 static uint64_t number(uint64_t d_value, char *param, int flags);
414 static int match(char *s);
415 static char checkopt(char *optim);
416 static char checkmtb(char *mtbarg);
417 static void range_check(long *varp, char *name, long minimum,
418 long maximum, long def_val, int user_supplied);
419 static void range_check_64(uint64_t *varp, char *name, uint64_t minimum,
420 uint64_t maximum, uint64_t def_val, int user_supplied);
421 static daddr32_t alloc(int size, int mode);
422 static diskaddr_t get_max_size(int fd);
423 static long get_max_track_size(int fd);
424 static void block_sigint(sigset_t *old_mask);
425 static void unblock_sigint(sigset_t *old_mask);
426 static void recover_from_sigint(int signum);
427 static int confirm_abort(void);
428 static int getaline(FILE *fp, char *loc, int maxlen);
429 static void flush_writes(void);
430 static long compute_maxcpg(long, long, long, long, long);
431 static int in_64bit_mode(void);
432 static int validate_size(int fd, diskaddr_t size);
433 static void dump_sblock(void);
434
435 /*
436 * Workaround for mkfs to function properly on disks attached to XMIT 2.X
437 * controller. If the address is not aligned at 8 byte boundary, mkfs on
438 * disks attached to XMIT 2.X controller exhibts un-predictable behaviour.
439 */
440 #define XMIT_2_X_ALIGN 8
441 #pragma align XMIT_2_X_ALIGN(fsun, altfsun, cgun)
442
443 union {
444 struct fs fs;
445 char pad[SBSIZE];
446 } fsun, altfsun;
447 #define sblock fsun.fs
448 #define altsblock altfsun.fs
449
450 struct csum *fscs;
451
452 union cgun {
453 struct cg cg;
454 char pad[MAXBSIZE];
455 } cgun;
456
457 #define acg cgun.cg
458 /*
459 * Size of screen in cols in which to fit output
460 */
461 #define WIDTH 80
462
463 struct dinode zino[MAXBSIZE / sizeof (struct dinode)];
464
465 /*
466 * file descriptors used for rdfs(fsi) and wtfs(fso).
467 * Initialized to an illegal file descriptor number.
468 */
469 int fsi = -1;
470 int fso = -1;
471
472 /*
473 * The BIG parameter is machine dependent. It should be a longlong integer
474 * constant that can be used by the number parser to check the validity
475 * of numeric parameters.
476 */
477
478 #define BIG 0x7fffffffffffffffLL
479
480 /* Used to indicate to number() that a bogus value should cause us to exit */
481 #define NO_DEFAULT LONG_MIN
482
483 /*
484 * INVALIDSBLIMIT is the number of bad backup superblocks that will be
485 * tolerated before we decide to try arriving at a different set of them
486 * using a different logic. This is applicable for non-EFI disks only.
487 */
488 #define INVALIDSBLIMIT 10
489
490 /*
491 * The *_flag variables are used to indicate that the user specified
492 * the values, rather than that we made them up ourselves. We can
493 * complain about the user giving us bogus values.
494 */
495
496 /* semi-constants */
497 long sectorsize = DEV_BSIZE; /* bytes/sector from param.h */
498 long bbsize = BBSIZE; /* boot block size */
499 long sbsize = SBSIZE; /* superblock size */
500
501 /* parameters */
502 diskaddr_t fssize_db; /* file system size in disk blocks */
503 diskaddr_t fssize_frag; /* file system size in frags */
504 long cpg; /* cylinders/cylinder group */
505 int cpg_flag = RC_DEFAULT;
506 long rotdelay = -1; /* rotational delay between blocks */
507 int rotdelay_flag = RC_DEFAULT;
508 long maxcontig; /* max contiguous blocks to allocate */
509 int maxcontig_flag = RC_DEFAULT;
510 long nsect = DFLNSECT; /* sectors per track */
511 int nsect_flag = RC_DEFAULT;
512 long ntrack = DFLNTRAK; /* tracks per cylinder group */
513 int ntrack_flag = RC_DEFAULT;
514 long bsize = DESBLKSIZE; /* filesystem block size */
515 int bsize_flag = RC_DEFAULT;
516 long fragsize = DESFRAGSIZE; /* filesystem fragment size */
517 int fragsize_flag = RC_DEFAULT;
518 long minfree = MINFREE; /* fs_minfree */
519 int minfree_flag = RC_DEFAULT;
520 long rps = DEFHZ; /* revolutions/second of drive */
521 int rps_flag = RC_DEFAULT;
522 long nbpi = NBPI; /* number of bytes per inode */
523 int nbpi_flag = RC_DEFAULT;
524 long nrpos = NRPOS; /* number of rotational positions */
525 int nrpos_flag = RC_DEFAULT;
526 long apc = 0; /* alternate sectors per cylinder */
527 int apc_flag = RC_DEFAULT;
528 char opt = 't'; /* optimization style, `t' or `s' */
529 char mtb = 'n'; /* multi-terabyte format, 'y' or 'n' */
530 #define DEFAULT_SECT_TRAK_CPG (nsect_flag == RC_DEFAULT && \
531 ntrack_flag == RC_DEFAULT && \
532 cpg_flag == RC_DEFAULT)
533
534 long debug = 0; /* enable debugging output */
535
536 int spc_flag = 0; /* alternate sectors specified or */
537 /* found */
538
539 /* global state */
540 int Nflag; /* do not write to disk */
541 int mflag; /* return the command line used to create this FS */
542 int rflag; /* report the superblock in an easily-parsed form */
543 int Rflag; /* dump the superblock in binary */
544 char *fsys;
545 time_t mkfstime;
546 char *string;
547 int label_type;
548
549 /*
550 * logging support
551 */
552 int islog; /* true if ufs logging is enabled */
553 int islogok; /* true if ufs log state is good */
554 int waslog; /* true when ufs logging disabled during grow */
555
556 /*
557 * growfs defines, globals, and forward references
558 */
559 #define NOTENOUGHSPACE 33
560 int grow;
561 #define GROW_WITH_DEFAULT_TRAK (grow && ntrack_flag == RC_DEFAULT)
562
563 static int Pflag; /* probe to which size the fs can be grown */
564 int ismounted;
565 char *directory;
566 diskaddr_t grow_fssize;
567 long grow_fs_size;
568 long grow_fs_ncg;
569 diskaddr_t grow_fs_csaddr;
570 long grow_fs_cssize;
571 int grow_fs_clean;
572 struct csum *grow_fscs;
573 diskaddr_t grow_sifrag;
574 int test;
575 int testforce;
576 diskaddr_t testfrags;
577 int inlockexit;
578 int isbad;
579
580 void lockexit(int) __NORETURN;
581 void randomgeneration(void);
582 void checksummarysize(void);
583 int checksblock(struct fs, int);
584 void growinit(char *);
585 void checkdev(char *, char *);
586 void checkmount(struct mnttab *, char *);
587 struct dinode *gdinode(ino_t);
588 int csfraginrange(daddr32_t);
589 struct csfrag *findcsfrag(daddr32_t, struct csfrag **);
590 void checkindirect(ino_t, daddr32_t *, daddr32_t, int);
591 void addcsfrag(ino_t, daddr32_t, struct csfrag **);
592 void delcsfrag(daddr32_t, struct csfrag **);
593 void checkdirect(ino_t, daddr32_t *, daddr32_t *, int);
594 void findcsfragino(void);
595 void fixindirect(daddr32_t, int);
596 void fixdirect(caddr_t, daddr32_t, daddr32_t *, int);
597 void fixcsfragino(void);
598 void extendsummaryinfo(void);
599 int notenoughspace(void);
600 void unalloccsfragino(void);
601 void unalloccsfragfree(void);
602 void findcsfragfree(void);
603 void copycsfragino(void);
604 void rdcg(long);
605 void wtcg(void);
606 void flcg(void);
607 void allocfrags(long, daddr32_t *, long *);
608 void alloccsfragino(void);
609 void alloccsfragfree(void);
610 void freefrags(daddr32_t, long, long);
611 int findfreerange(long *, long *);
612 void resetallocinfo(void);
613 void extendcg(long);
614 void ulockfs(void);
615 void wlockfs(void);
616 void clockfs(void);
617 void wtsb(void);
618 static int64_t checkfragallocated(daddr32_t);
619 static struct csum *read_summaryinfo(struct fs *);
620 static diskaddr_t probe_summaryinfo();
621
622 int
main(int argc,char * argv[])623 main(int argc, char *argv[])
624 {
625 long i, mincpc, mincpg, ibpcl;
626 long cylno, rpos, blk, j, warn = 0;
627 long mincpgcnt, maxcpg;
628 uint64_t used, bpcg, inospercg;
629 long mapcramped, inodecramped;
630 long postblsize, rotblsize, totalsbsize;
631 FILE *mnttab;
632 struct mnttab mntp;
633 char *special;
634 struct statvfs64 fs;
635 struct dk_geom dkg;
636 struct dk_minfo dkminfo;
637 char pbuf[sizeof (uint64_t) * 3 + 1];
638 char *tmpbuf;
639 int width, plen;
640 uint64_t num;
641 int c, saverr;
642 diskaddr_t max_fssize;
643 long tmpmaxcontig = -1;
644 struct sigaction sigact;
645 uint64_t nbytes64;
646 int remaining_cg;
647 int do_dot = 0;
648 int use_efi_dflts = 0, retry = 0, isremovable = 0, ishotpluggable = 0;
649 int invalid_sb_cnt, ret, skip_this_sb, cg_too_small;
650 int geom_nsect, geom_ntrack, geom_cpg;
651
652 (void) setlocale(LC_ALL, "");
653
654 #if !defined(TEXT_DOMAIN)
655 #define TEXT_DOMAIN "SYS_TEST"
656 #endif
657 (void) textdomain(TEXT_DOMAIN);
658
659 while ((c = getopt(argc, argv, "F:bmo:VPGM:T:t:")) != EOF) {
660 switch (c) {
661
662 case 'F':
663 string = optarg;
664 if (strcmp(string, "ufs") != 0)
665 usage();
666 break;
667
668 case 'm': /* return command line used to create this FS */
669 mflag++;
670 break;
671
672 case 'o':
673 /*
674 * ufs specific options.
675 */
676 string = optarg;
677 while (*string != '\0') {
678 if (match("nsect=")) {
679 nsect = number(DFLNSECT, "nsect", 0);
680 nsect_flag = RC_KEYWORD;
681 } else if (match("ntrack=")) {
682 ntrack = number(DFLNTRAK, "ntrack", 0);
683 ntrack_flag = RC_KEYWORD;
684 } else if (match("bsize=")) {
685 bsize = number(DESBLKSIZE, "bsize", 0);
686 bsize_flag = RC_KEYWORD;
687 } else if (match("fragsize=")) {
688 fragsize = number(DESFRAGSIZE,
689 "fragsize", 0);
690 fragsize_flag = RC_KEYWORD;
691 } else if (match("cgsize=")) {
692 cpg = number(DESCPG, "cgsize", 0);
693 cpg_flag = RC_KEYWORD;
694 } else if (match("free=")) {
695 minfree = number(MINFREE, "free",
696 ALLOW_PERCENT);
697 minfree_flag = RC_KEYWORD;
698 } else if (match("maxcontig=")) {
699 tmpmaxcontig =
700 number(-1, "maxcontig", 0);
701 maxcontig_flag = RC_KEYWORD;
702 } else if (match("nrpos=")) {
703 nrpos = number(NRPOS, "nrpos", 0);
704 nrpos_flag = RC_KEYWORD;
705 } else if (match("rps=")) {
706 rps = number(DEFHZ, "rps", 0);
707 rps_flag = RC_KEYWORD;
708 } else if (match("nbpi=")) {
709 nbpi = number(NBPI, "nbpi", 0);
710 nbpi_flag = RC_KEYWORD;
711 } else if (match("opt=")) {
712 opt = checkopt(string);
713 } else if (match("mtb=")) {
714 mtb = checkmtb(string);
715 } else if (match("apc=")) {
716 apc = number(0, "apc", 0);
717 apc_flag = RC_KEYWORD;
718 } else if (match("gap=")) {
719 (void) number(0, "gap", ALLOW_MS1);
720 rotdelay = ROTDELAY;
721 rotdelay_flag = RC_DEFAULT;
722 } else if (match("debug=")) {
723 debug = number(0, "debug", 0);
724 } else if (match("N")) {
725 Nflag++;
726 } else if (match("calcsb")) {
727 rflag++;
728 Nflag++;
729 } else if (match("calcbinsb")) {
730 rflag++;
731 Rflag++;
732 Nflag++;
733 } else if (*string == '\0') {
734 break;
735 } else {
736 (void) fprintf(stderr, gettext(
737 "illegal option: %s\n"), string);
738 usage();
739 }
740
741 if (*string == ',') string++;
742 if (*string == ' ') string++;
743 }
744 break;
745
746 case 'V':
747 {
748 char *opt_text;
749 int opt_count;
750
751 (void) fprintf(stdout, gettext("mkfs -F ufs "));
752 for (opt_count = 1; opt_count < argc;
753 opt_count++) {
754 opt_text = argv[opt_count];
755 if (opt_text)
756 (void) fprintf(stdout, " %s ",
757 opt_text);
758 }
759 (void) fprintf(stdout, "\n");
760 }
761 break;
762
763 case 'b': /* do nothing for this */
764 break;
765
766 case 'M': /* grow the mounted file system */
767 directory = optarg;
768
769 /* FALLTHROUGH */
770 case 'G': /* grow the file system */
771 grow = 1;
772 break;
773 case 'P': /* probe the file system growing size */
774 Pflag = 1;
775 grow = 1; /* probe mode implies fs growing */
776 break;
777 case 'T': /* For testing */
778 testforce = 1;
779
780 /* FALLTHROUGH */
781 case 't':
782 test = 1;
783 string = optarg;
784 testfrags = number(NO_DEFAULT, "testfrags", 0);
785 break;
786
787 case '?':
788 usage();
789 break;
790 }
791 }
792 #ifdef MKFS_DEBUG
793 /*
794 * Turning on MKFS_DEBUG causes mkfs to produce a filesystem
795 * that can be reproduced by setting the time to 0 and seeding
796 * the random number generator to a constant.
797 */
798 mkfstime = 0; /* reproducible results */
799 #else
800 (void) time(&mkfstime);
801 #endif
802
803 if (optind >= (argc - 1)) {
804 if (optind > (argc - 1)) {
805 (void) fprintf(stderr,
806 gettext("special not specified\n"));
807 usage();
808 } else if (mflag == 0) {
809 (void) fprintf(stderr,
810 gettext("size not specified\n"));
811 usage();
812 }
813 }
814 argc -= optind;
815 argv = &argv[optind];
816
817 fsys = argv[0];
818 fsi = open64(fsys, O_RDONLY);
819 if (fsi < 0) {
820 (void) fprintf(stderr, gettext("%s: cannot open\n"), fsys);
821 lockexit(32);
822 }
823
824 if (mflag) {
825 dump_fscmd(fsys, fsi);
826 lockexit(0);
827 }
828
829 /*
830 * The task of setting all of the configuration parameters for a
831 * UFS file system is basically a matter of solving n equations
832 * in m variables. Typically, m is greater than n, so there is
833 * usually more than one valid solution. Since this is usually
834 * an under-constrained problem, it's not always obvious what the
835 * "best" configuration is.
836 *
837 * In general, the approach is to
838 * 1. Determine the values for the file system parameters
839 * that are externally contrained and therefore not adjustable
840 * by mkfs (such as the device's size and maxtransfer size).
841 * 2. Acquire the user's requested setting for all configuration
842 * values that can be set on the command line.
843 * 3. Determine the final value of all configuration values, by
844 * the following approach:
845 * - set the file system block size (fs_bsize). Although
846 * this could be regarded as an adjustable parameter, in
847 * fact, it's pretty much a constant. At this time, it's
848 * generally set to 8k (with older hardware, it can
849 * sometimes make sense to set it to 4k, but those
850 * situations are pretty rare now).
851 * - re-adjust the maximum file system size based on the
852 * value of the file system block size. Since the
853 * frag size can't be any larger than a file system
854 * block, and the number of frags in the file system
855 * has to fit into 31 bits, the file system block size
856 * affects the maximum file system size.
857 * - now that the real maximum file system is known, set the
858 * actual size of the file system to be created to
859 * MIN(requested size, maximum file system size).
860 * - now validate, and if necessary, adjust the following
861 * values:
862 * rotdelay
863 * nsect
864 * maxcontig
865 * apc
866 * frag_size
867 * rps
868 * minfree
869 * nrpos
870 * nrack
871 * nbpi
872 * - calculate maxcpg (the maximum value of the cylinders-per-
873 * cylinder-group configuration parameters). There are two
874 * algorithms for calculating maxcpg: an old one, which is
875 * used for file systems of less than 1 terabyte, and a
876 * new one, implemented in the function compute_maxcpg(),
877 * which is used for file systems of greater than 1 TB.
878 * The difference between them is that compute_maxcpg()
879 * really tries to maximize the cpg value. The old
880 * algorithm fails to take advantage of smaller frags and
881 * lower inode density when determining the maximum cpg,
882 * and thus comes up with much lower numbers in some
883 * configurations. At some point, we might use the
884 * new algorithm for determining maxcpg for all file
885 * systems, but at this time, the changes implemented for
886 * multi-terabyte UFS are NOT being automatically applied
887 * to UFS file systems of less than a terabyte (in the
888 * interest of not changing existing UFS policy too much
889 * until the ramifications of the changes are well-understood
890 * and have been evaluated for their effects on performance.)
891 * - check the current values of the configuration parameters
892 * against the various constraints imposed by UFS. These
893 * include:
894 * * There must be at least one inode in each
895 * cylinder group.
896 * * The cylinder group overhead block, which
897 * contains the inode and frag bigmaps, must fit
898 * within one file system block.
899 * * The space required for inode maps should
900 * occupy no more than a third of the cylinder
901 * group overhead block.
902 * * The rotational position tables have to fit
903 * within the available space in the super block.
904 * Adjust the configuration values that can be adjusted
905 * so that these constraints are satisfied. The
906 * configuration values that are adjustable are:
907 * * frag size
908 * * cylinders per group
909 * * inode density (can be increased)
910 * * number of rotational positions (the rotational
911 * position tables are eliminated altogether if
912 * there isn't enough room for them.)
913 * 4. Set the values for all the dependent configuration
914 * values (those that aren't settable on the command
915 * line and which are completely dependent on the
916 * adjustable parameters). This include cpc (cycles
917 * per cylinder, spc (sectors-per-cylinder), and many others.
918 */
919
920 /*
921 * Figure out the partition size and initialize the label_type.
922 */
923 max_fssize = get_max_size(fsi);
924
925 /*
926 * Get and check positional arguments, if any.
927 */
928 switch (argc - 1) {
929 default:
930 usage();
931 /*NOTREACHED*/
932 case 15:
933 mtb = checkmtb(argv[15]);
934 /* FALLTHROUGH */
935 case 14:
936 string = argv[14];
937 tmpmaxcontig = number(-1, "maxcontig", 0);
938 maxcontig_flag = RC_POSITIONAL;
939 /* FALLTHROUGH */
940 case 13:
941 string = argv[13];
942 nrpos = number(NRPOS, "nrpos", 0);
943 nrpos_flag = RC_POSITIONAL;
944 /* FALLTHROUGH */
945 case 12:
946 string = argv[12];
947 rotdelay = ROTDELAY;
948 rotdelay_flag = RC_DEFAULT;
949 /* FALLTHROUGH */
950 case 11:
951 string = argv[11];
952 apc = number(0, "apc", 0);
953 apc_flag = RC_POSITIONAL;
954 /* FALLTHROUGH */
955 case 10:
956 opt = checkopt(argv[10]);
957 /* FALLTHROUGH */
958 case 9:
959 string = argv[9];
960 nbpi = number(NBPI, "nbpi", 0);
961 nbpi_flag = RC_POSITIONAL;
962 /* FALLTHROUGH */
963 case 8:
964 string = argv[8];
965 rps = number(DEFHZ, "rps", 0);
966 rps_flag = RC_POSITIONAL;
967 /* FALLTHROUGH */
968 case 7:
969 string = argv[7];
970 minfree = number(MINFREE, "free", ALLOW_PERCENT);
971 minfree_flag = RC_POSITIONAL;
972 /* FALLTHROUGH */
973 case 6:
974 string = argv[6];
975 cpg = number(DESCPG, "cgsize", 0);
976 cpg_flag = RC_POSITIONAL;
977 /* FALLTHROUGH */
978 case 5:
979 string = argv[5];
980 fragsize = number(DESFRAGSIZE, "fragsize", 0);
981 fragsize_flag = RC_POSITIONAL;
982 /* FALLTHROUGH */
983 case 4:
984 string = argv[4];
985 bsize = number(DESBLKSIZE, "bsize", 0);
986 bsize_flag = RC_POSITIONAL;
987 /* FALLTHROUGH */
988 case 3:
989 string = argv[3];
990 ntrack = number(DFLNTRAK, "ntrack", 0);
991 ntrack_flag = RC_POSITIONAL;
992 /* FALLTHROUGH */
993 case 2:
994 string = argv[2];
995 nsect = number(DFLNSECT, "nsect", 0);
996 nsect_flag = RC_POSITIONAL;
997 /* FALLTHROUGH */
998 case 1:
999 string = argv[1];
1000 fssize_db = number(max_fssize, "size", 0);
1001 }
1002
1003 /*
1004 * Initialize the parameters in the same way as newfs so that
1005 * newfs and mkfs would result in the same file system layout
1006 * for EFI labelled disks. Do this only in the absence of user
1007 * specified values for these parameters.
1008 */
1009 if (label_type == LABEL_TYPE_EFI) {
1010 if (apc_flag == RC_DEFAULT) apc = 0;
1011 if (nrpos_flag == RC_DEFAULT) nrpos = 1;
1012 if (ntrack_flag == RC_DEFAULT) ntrack = DEF_TRACKS_EFI;
1013 if (rps_flag == RC_DEFAULT) rps = DEFHZ;
1014 if (nsect_flag == RC_DEFAULT) nsect = DEF_SECTORS_EFI;
1015 }
1016
1017 if ((maxcontig_flag == RC_DEFAULT) || (tmpmaxcontig == -1) ||
1018 (maxcontig == -1)) {
1019 long maxtrax = get_max_track_size(fsi);
1020 maxcontig = maxtrax / bsize;
1021
1022 } else {
1023 maxcontig = tmpmaxcontig;
1024 }
1025 dprintf(("DeBuG maxcontig : %ld\n", maxcontig));
1026
1027 if (rotdelay == -1) { /* default by newfs and mkfs */
1028 rotdelay = ROTDELAY;
1029 }
1030
1031 if (cpg_flag == RC_DEFAULT) { /* If not explicity set, use default */
1032 cpg = DESCPG;
1033 }
1034 dprintf(("DeBuG cpg : %ld\n", cpg));
1035
1036 /*
1037 * Now that we have the semi-sane args, either positional, via -o,
1038 * or by defaulting, handle inter-dependencies and range checks.
1039 */
1040
1041 /*
1042 * Settle the file system block size first, since it's a fixed
1043 * parameter once set and so many other parameters, including
1044 * max_fssize, depend on it.
1045 */
1046 range_check(&bsize, "bsize", MINBSIZE, MAXBSIZE, DESBLKSIZE,
1047 bsize_flag);
1048
1049 if (!POWEROF2(bsize)) {
1050 (void) fprintf(stderr,
1051 gettext("block size must be a power of 2, not %ld\n"),
1052 bsize);
1053 bsize = DESBLKSIZE;
1054 (void) fprintf(stderr,
1055 gettext("mkfs: bsize reset to default %ld\n"),
1056 bsize);
1057 }
1058
1059 if (fssize_db > max_fssize && validate_size(fsi, fssize_db)) {
1060 (void) fprintf(stderr, gettext(
1061 "Warning: the requested size of this file system\n"
1062 "(%lld sectors) is greater than the size of the\n"
1063 "device reported by the driver (%lld sectors).\n"
1064 "However, a read of the device at the requested size\n"
1065 "does succeed, so the requested size will be used.\n"),
1066 fssize_db, max_fssize);
1067 max_fssize = fssize_db;
1068 }
1069 /*
1070 * Since the maximum allocatable unit (the frag) must be less than
1071 * or equal to bsize, and the number of frags must be less than or
1072 * equal to INT_MAX, the total size of the file system (in
1073 * bytes) must be less than or equal to bsize * INT_MAX.
1074 */
1075
1076 if (max_fssize > ((diskaddr_t)bsize/DEV_BSIZE) * INT_MAX)
1077 max_fssize = ((diskaddr_t)bsize/DEV_BSIZE) * INT_MAX;
1078
1079 range_check_64(&fssize_db, "size", 1024LL, max_fssize, max_fssize, 1);
1080
1081 if (fssize_db >= SECTORS_PER_TERABYTE) {
1082 mtb = 'y';
1083 if (!in_64bit_mode()) {
1084 (void) fprintf(stderr, gettext(
1085 "mkfs: Warning: Creating a file system greater than 1 terabyte on a\n"
1086 " system running a 32-bit kernel. This file system will not be\n"
1087 " accessible until the system is rebooted with a 64-bit kernel.\n"));
1088 }
1089 }
1090 dprintf(("DeBuG mtb : %c\n", mtb));
1091
1092 /*
1093 * With newer and much larger disks, the newfs(8) and mkfs_ufs(8)
1094 * commands had problems in correctly handling the "native" geometries
1095 * for various storage devices.
1096 *
1097 * To handle the new age disks, mkfs_ufs(8) will use the EFI style
1098 * for non-EFI disks that are larger than the CHS addressing limit
1099 * ( > 8GB approx ) and ignore the disk geometry information for
1100 * these drives. This is what is currently done for multi-terrabyte
1101 * filesystems on EFI disks.
1102 *
1103 * However if the user asked for a specific layout by supplying values
1104 * for even one of the three parameters (nsect, ntrack, cpg), honour
1105 * the user supplied parameters.
1106 *
1107 * Choosing EFI style or native geometry style can make a lot of
1108 * difference, because the size of a cylinder group is dependent on
1109 * this choice. This in turn means that the position of alternate
1110 * superblocks varies depending on the style chosen. It is not
1111 * necessary that all disks of size > CHSLIMIT have EFI style layout.
1112 * There can be disks which are > CHSLIMIT size, but have native
1113 * geometry style layout, thereby warranting the need for alternate
1114 * logic in superblock detection.
1115 */
1116 if (mtb != 'y' && (ntrack == -1 || GROW_WITH_DEFAULT_TRAK ||
1117 DEFAULT_SECT_TRAK_CPG)) {
1118 /*
1119 * "-1" indicates that we were called from newfs and ntracks
1120 * was not specified in newfs command line. Calculate nsect
1121 * and ntrack in the same manner as newfs.
1122 *
1123 * This is required because, the defaults for nsect and ntrack
1124 * is hardcoded in mkfs, whereas to generate the alternate
1125 * superblock locations for the -N option, there is a need for
1126 * the geometry based values that newfs would have arrived at.
1127 * Newfs would have arrived at these values as below.
1128 */
1129 if (label_type == LABEL_TYPE_EFI ||
1130 label_type == LABEL_TYPE_OTHER) {
1131 use_efi_dflts = 1;
1132 retry = 1;
1133 } else if (ioctl(fsi, DKIOCGGEOM, &dkg)) {
1134 dprintf(("%s: Unable to read Disk geometry", fsys));
1135 perror(gettext("Unable to read Disk geometry"));
1136 lockexit(32);
1137 } else {
1138 nsect = dkg.dkg_nsect;
1139 ntrack = dkg.dkg_nhead;
1140 #ifdef i386 /* Bug 1170182 */
1141 if (ntrack > 32 && (ntrack % 16) != 0) {
1142 ntrack -= (ntrack % 16);
1143 }
1144 #endif
1145 if (ioctl(fsi, DKIOCREMOVABLE, &isremovable)) {
1146 dprintf(("DeBuG Unable to determine if %s is"
1147 " Removable Media. Proceeding with system"
1148 " determined parameters.\n", fsys));
1149 isremovable = 0;
1150 }
1151 if (ioctl(fsi, DKIOCHOTPLUGGABLE, &ishotpluggable)) {
1152 dprintf(("DeBuG Unable to determine if %s is"
1153 " Hotpluggable Media. Proceeding with "
1154 "system determined parameters.\n", fsys));
1155 ishotpluggable = 0;
1156 }
1157 if ((((diskaddr_t)dkg.dkg_ncyl * dkg.dkg_nhead *
1158 dkg.dkg_nsect) > CHSLIMIT) || isremovable ||
1159 ishotpluggable) {
1160 use_efi_dflts = 1;
1161 retry = 1;
1162 }
1163 }
1164 }
1165 dprintf(("DeBuG CHSLIMIT = %d geom = %llu\n", CHSLIMIT,
1166 (diskaddr_t)dkg.dkg_ncyl * dkg.dkg_nhead * dkg.dkg_nsect));
1167 dprintf(("DeBuG label_type = %d isremovable = %d ishotpluggable = %d "
1168 "use_efi_dflts = %d\n", label_type, isremovable, ishotpluggable,
1169 use_efi_dflts));
1170
1171 /*
1172 * For the newfs -N case, even if the disksize is > CHSLIMIT, do not
1173 * blindly follow EFI style. If the fs_version indicates a geometry
1174 * based layout, try that one first. If it fails we can always try the
1175 * other logic.
1176 *
1177 * If we were called from growfs, we will have a problem if we mix
1178 * and match the filesystem creation and growth styles. For example,
1179 * if we create using EFI style, we have to also grow using EFI
1180 * style. So follow the style indicated by the fs_version.
1181 *
1182 * Read and verify the primary superblock. If it looks sane, use the
1183 * fs_version from the superblock. If the primary superblock does
1184 * not look good, read and verify the first alternate superblock at
1185 * ALTSB. Use the fs_version to decide whether to use the
1186 * EFI style logic or the old geometry based logic to calculate
1187 * the alternate superblock locations.
1188 */
1189 if ((Nflag && use_efi_dflts) || (grow)) {
1190 if (grow && ntrack_flag != RC_DEFAULT)
1191 goto start_fs_creation;
1192 rdfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize,
1193 (char *)&altsblock);
1194 ret = checksblock(altsblock, 1);
1195
1196 if (!ret) {
1197 if (altsblock.fs_magic == MTB_UFS_MAGIC) {
1198 mtb = 'y';
1199 goto start_fs_creation;
1200 }
1201 use_efi_dflts = (altsblock.fs_version ==
1202 UFS_EFISTYLE4NONEFI_VERSION_2) ? 1 : 0;
1203 } else {
1204 /*
1205 * The primary superblock didn't help in determining
1206 * the fs_version. Try the first alternate superblock.
1207 */
1208 dprintf(("DeBuG checksblock() failed - error : %d"
1209 " for sb : %d\n", ret, SBOFF/sectorsize));
1210 rdfs((diskaddr_t)ALTSB, (int)sbsize,
1211 (char *)&altsblock);
1212 ret = checksblock(altsblock, 1);
1213
1214 if (!ret) {
1215 if (altsblock.fs_magic == MTB_UFS_MAGIC) {
1216 mtb = 'y';
1217 goto start_fs_creation;
1218 }
1219 use_efi_dflts = (altsblock.fs_version ==
1220 UFS_EFISTYLE4NONEFI_VERSION_2) ? 1 : 0;
1221 }
1222 dprintf(("DeBuG checksblock() returned : %d"
1223 " for sb : %d\n", ret, ALTSB));
1224 }
1225 }
1226
1227 geom_nsect = nsect;
1228 geom_ntrack = ntrack;
1229 geom_cpg = cpg;
1230 dprintf(("DeBuG geom_nsect=%d, geom_ntrack=%d, geom_cpg=%d\n",
1231 geom_nsect, geom_ntrack, geom_cpg));
1232
1233 start_fs_creation:
1234 retry_alternate_logic:
1235 invalid_sb_cnt = 0;
1236 cg_too_small = 0;
1237 if (use_efi_dflts) {
1238 nsect = DEF_SECTORS_EFI;
1239 ntrack = DEF_TRACKS_EFI;
1240 cpg = DESCPG;
1241 dprintf(("\nDeBuG Using EFI defaults\n"));
1242 } else {
1243 nsect = geom_nsect;
1244 ntrack = geom_ntrack;
1245 cpg = geom_cpg;
1246 dprintf(("\nDeBuG Using Geometry\n"));
1247 /*
1248 * 32K based on max block size of 64K, and rotational layout
1249 * test of nsect <= (256 * sectors/block). Current block size
1250 * limit is not 64K, but it's growing soon.
1251 */
1252 range_check(&nsect, "nsect", 1, 32768, DFLNSECT, nsect_flag);
1253 /*
1254 * ntrack is the number of tracks per cylinder.
1255 * The ntrack value must be between 1 and the total number of
1256 * sectors in the file system.
1257 */
1258 range_check(&ntrack, "ntrack", 1,
1259 fssize_db > INT_MAX ? INT_MAX : (uint32_t)fssize_db,
1260 DFLNTRAK, ntrack_flag);
1261 }
1262
1263 range_check(&apc, "apc", 0, nsect - 1, 0, apc_flag);
1264
1265 if (mtb == 'y')
1266 fragsize = bsize;
1267
1268 range_check(&fragsize, "fragsize", sectorsize, bsize,
1269 MAX(bsize / MAXFRAG, MIN(DESFRAGSIZE, bsize)), fragsize_flag);
1270
1271 if ((bsize / MAXFRAG) > fragsize) {
1272 (void) fprintf(stderr, gettext(
1273 "fragment size %ld is too small, minimum with block size %ld is %ld\n"),
1274 fragsize, bsize, bsize / MAXFRAG);
1275 (void) fprintf(stderr,
1276 gettext("mkfs: fragsize reset to minimum %ld\n"),
1277 bsize / MAXFRAG);
1278 fragsize = bsize / MAXFRAG;
1279 }
1280
1281 if (!POWEROF2(fragsize)) {
1282 (void) fprintf(stderr,
1283 gettext("fragment size must be a power of 2, not %ld\n"),
1284 fragsize);
1285 fragsize = MAX(bsize / MAXFRAG, MIN(DESFRAGSIZE, bsize));
1286 (void) fprintf(stderr,
1287 gettext("mkfs: fragsize reset to %ld\n"),
1288 fragsize);
1289 }
1290
1291 /* At this point, bsize must be >= fragsize, so no need to check it */
1292
1293 if (bsize < PAGESIZE) {
1294 (void) fprintf(stderr, gettext(
1295 "WARNING: filesystem block size (%ld) is smaller than "
1296 "memory page size (%ld).\nResulting filesystem can not be "
1297 "mounted on this system.\n\n"),
1298 bsize, (long)PAGESIZE);
1299 }
1300
1301 range_check(&rps, "rps", 1, 1000, DEFHZ, rps_flag);
1302 range_check(&minfree, "free", 0, 99, MINFREE, minfree_flag);
1303 range_check(&nrpos, "nrpos", 1, nsect, MIN(nsect, NRPOS), nrpos_flag);
1304
1305 /*
1306 * nbpi is variable, but 2MB seems a reasonable upper limit,
1307 * as 4MB tends to cause problems (using otherwise-default
1308 * parameters). The true limit is where we end up with one
1309 * inode per cylinder group. If this file system is being
1310 * configured for multi-terabyte access, nbpi must be at least 1MB.
1311 */
1312 if (mtb == 'y' && nbpi < MTB_NBPI) {
1313 if (nbpi_flag != RC_DEFAULT)
1314 (void) fprintf(stderr, gettext("mkfs: bad value for "
1315 "nbpi: must be at least 1048576 for multi-terabyte,"
1316 " nbpi reset to default 1048576\n"));
1317 nbpi = MTB_NBPI;
1318 }
1319
1320 if (mtb == 'y')
1321 range_check(&nbpi, "nbpi", MTB_NBPI, 2 * MB, MTB_NBPI,
1322 nbpi_flag);
1323 else
1324 range_check(&nbpi, "nbpi", DEV_BSIZE, 2 * MB, NBPI, nbpi_flag);
1325
1326 /*
1327 * maxcpg is another variably-limited parameter. Calculate
1328 * the limit based on what we've got for its dependent
1329 * variables. Effectively, it's how much space is left in the
1330 * superblock after all the other bits are accounted for. We
1331 * only fill in sblock fields so we can use MAXIpG.
1332 *
1333 * If the calculation of maxcpg below (for the mtb == 'n'
1334 * case) is changed, update newfs as well.
1335 *
1336 * For old-style, non-MTB format file systems, use the old
1337 * algorithm for calculating the maximum cylinder group size,
1338 * even though it limits the cylinder group more than necessary.
1339 * Since layout can affect performance, we don't want to change
1340 * the default layout for non-MTB file systems at this time.
1341 * However, for MTB file systems, use the new maxcpg calculation,
1342 * which really maxes out the cylinder group size.
1343 */
1344
1345 sblock.fs_bsize = bsize;
1346 sblock.fs_inopb = sblock.fs_bsize / sizeof (struct dinode);
1347
1348 if (mtb == 'n') {
1349 maxcpg = (bsize - sizeof (struct cg) -
1350 howmany(MAXIpG(&sblock), NBBY)) /
1351 (sizeof (long) + nrpos * sizeof (short) +
1352 nsect / (MAXFRAG * NBBY));
1353 } else {
1354 maxcpg = compute_maxcpg(bsize, fragsize, nbpi, nrpos,
1355 nsect * ntrack);
1356 }
1357
1358 dprintf(("DeBuG cpg : %ld\n", cpg));
1359 /*
1360 * Increase the cpg to maxcpg if either newfs was invoked
1361 * with -T option or if mkfs wants to create a mtb file system
1362 * and if the user has not specified the cpg.
1363 */
1364 if (cpg == -1 || (mtb == 'y' && cpg_flag == RC_DEFAULT))
1365 cpg = maxcpg;
1366 dprintf(("DeBuG cpg : %ld\n", cpg));
1367
1368 /*
1369 * mincpg is variable in complex ways, so we really can't
1370 * do a sane lower-end limit check at this point.
1371 */
1372 range_check(&cpg, "cgsize", 1, maxcpg, MIN(maxcpg, DESCPG), cpg_flag);
1373
1374 /*
1375 * get the controller info
1376 */
1377 islog = 0;
1378 islogok = 0;
1379 waslog = 0;
1380
1381 /*
1382 * Do not grow the file system, but print on stdout the maximum
1383 * size in sectors to which the file system can be increased.
1384 * The calculated size is limited by fssize_db.
1385 * Note that we don't lock the filesystem and therefore under rare
1386 * conditions (the filesystem is mounted, the free block count is
1387 * almost zero, and the superuser is still changing it) the calculated
1388 * size can be imprecise.
1389 */
1390 if (Pflag) {
1391 (void) printf("%llu\n", probe_summaryinfo());
1392 exit(0);
1393 }
1394
1395 /*
1396 * If we're growing an existing filesystem, then we're about
1397 * to start doing things that can require recovery efforts if
1398 * we get interrupted, so make sure we get a chance to do so.
1399 */
1400 if (grow) {
1401 sigact.sa_handler = recover_from_sigint;
1402 sigemptyset(&sigact.sa_mask);
1403 sigact.sa_flags = SA_RESTART;
1404
1405 if (sigaction(SIGINT, &sigact, (struct sigaction *)NULL) < 0) {
1406 perror(gettext("Could not register SIGINT handler"));
1407 lockexit(3);
1408 }
1409 }
1410
1411 if (!Nflag) {
1412 /*
1413 * Check if MNTTAB is trustable
1414 */
1415 if (statvfs64(MNTTAB, &fs) < 0) {
1416 (void) fprintf(stderr, gettext("can't statvfs %s\n"),
1417 MNTTAB);
1418 exit(32);
1419 }
1420
1421 if (strcmp(MNTTYPE_MNTFS, fs.f_basetype) != 0) {
1422 (void) fprintf(stderr, gettext(
1423 "%s file system type is not %s, can't mkfs\n"),
1424 MNTTAB, MNTTYPE_MNTFS);
1425 exit(32);
1426 }
1427
1428 special = getfullblkname(fsys);
1429 checkdev(fsys, special);
1430
1431 /*
1432 * If we found the block device name,
1433 * then check the mount table.
1434 * if mounted, and growing write lock the file system
1435 *
1436 */
1437 if ((special != NULL) && (*special != '\0')) {
1438 if ((mnttab = fopen(MNTTAB, "r")) == NULL) {
1439 (void) fprintf(stderr, gettext(
1440 "can't open %s\n"), MNTTAB);
1441 exit(32);
1442 }
1443 while ((getmntent(mnttab, &mntp)) == 0) {
1444 if (grow) {
1445 checkmount(&mntp, special);
1446 continue;
1447 }
1448 if (strcmp(special, mntp.mnt_special) == 0) {
1449 (void) fprintf(stderr, gettext(
1450 "%s is mounted, can't mkfs\n"),
1451 special);
1452 exit(32);
1453 }
1454 }
1455 (void) fclose(mnttab);
1456 }
1457
1458 if (directory && (ismounted == 0)) {
1459 (void) fprintf(stderr, gettext("%s is not mounted\n"),
1460 special);
1461 lockexit(32);
1462 }
1463
1464 fso = (grow) ? open64(fsys, O_WRONLY) : creat64(fsys, 0666);
1465 if (fso < 0) {
1466 saverr = errno;
1467 (void) fprintf(stderr,
1468 gettext("%s: cannot create: %s\n"),
1469 fsys, strerror(saverr));
1470 lockexit(32);
1471 }
1472
1473 } else {
1474
1475 /*
1476 * For the -N case, a file descriptor is needed for the llseek()
1477 * in wtfs(). See the comment in wtfs() for more information.
1478 *
1479 * Get a file descriptor that's read-only so that this code
1480 * doesn't accidentally write to the file.
1481 */
1482 fso = open64(fsys, O_RDONLY);
1483 if (fso < 0) {
1484 saverr = errno;
1485 (void) fprintf(stderr, gettext("%s: cannot open: %s\n"),
1486 fsys, strerror(saverr));
1487 lockexit(32);
1488 }
1489 }
1490
1491 /*
1492 * Check the media sector size
1493 */
1494 if (ioctl(fso, DKIOCGMEDIAINFO, &dkminfo) != -1) {
1495 if (dkminfo.dki_lbsize != 0 &&
1496 POWEROF2(dkminfo.dki_lbsize / DEV_BSIZE) &&
1497 dkminfo.dki_lbsize != DEV_BSIZE) {
1498 fprintf(stderr,
1499 gettext("The device sector size %u is not "
1500 "supported by ufs!\n"), dkminfo.dki_lbsize);
1501 (void) close(fso);
1502 exit(1);
1503 }
1504 }
1505
1506 /*
1507 * seed random # generator (for ic_generation)
1508 */
1509 #ifdef MKFS_DEBUG
1510 srand48(12962); /* reproducible results */
1511 #else
1512 srand48((long)(time((time_t *)NULL) + getpid()));
1513 #endif
1514
1515 if (grow) {
1516 growinit(fsys);
1517 goto grow00;
1518 }
1519
1520 /*
1521 * Validate the given file system size.
1522 * Verify that its last block can actually be accessed.
1523 *
1524 * Note: it's ok to use sblock as a buffer because it is immediately
1525 * overwritten by the rdfs() of the superblock in the next line.
1526 *
1527 * ToDo: Because the size checking is done in rdfs()/wtfs(), the
1528 * error message for specifying an illegal size is very unfriendly.
1529 * In the future, one could replace the rdfs()/wtfs() calls
1530 * below with in-line calls to read() or write(). This allows better
1531 * error messages to be put in place.
1532 */
1533 rdfs(fssize_db - 1, (int)sectorsize, (char *)&sblock);
1534
1535 /*
1536 * make the fs unmountable
1537 */
1538 rdfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize, (char *)&sblock);
1539 sblock.fs_magic = -1;
1540 sblock.fs_clean = FSBAD;
1541 sblock.fs_state = FSOKAY - sblock.fs_time;
1542 wtfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize, (char *)&sblock);
1543 bzero(&sblock, (size_t)sbsize);
1544
1545 sblock.fs_nsect = nsect;
1546 sblock.fs_ntrak = ntrack;
1547
1548 /*
1549 * Validate specified/determined spc
1550 * and calculate minimum cylinders per group.
1551 */
1552
1553 /*
1554 * sectors/cyl = tracks/cyl * sectors/track
1555 */
1556 sblock.fs_spc = sblock.fs_ntrak * sblock.fs_nsect;
1557
1558 grow00:
1559 if (apc_flag) {
1560 sblock.fs_spc -= apc;
1561 }
1562 /*
1563 * Have to test for this separately from apc_flag, due to
1564 * the growfs case....
1565 */
1566 if (sblock.fs_spc != sblock.fs_ntrak * sblock.fs_nsect) {
1567 spc_flag = 1;
1568 }
1569 if (grow)
1570 goto grow10;
1571
1572 sblock.fs_nrpos = nrpos;
1573 sblock.fs_bsize = bsize;
1574 sblock.fs_fsize = fragsize;
1575 sblock.fs_minfree = minfree;
1576
1577 grow10:
1578 if (nbpi < sblock.fs_fsize) {
1579 (void) fprintf(stderr, gettext(
1580 "warning: wasteful data byte allocation / inode (nbpi):\n"));
1581 (void) fprintf(stderr, gettext(
1582 "%ld smaller than allocatable fragment size of %d\n"),
1583 nbpi, sblock.fs_fsize);
1584 }
1585 if (grow)
1586 goto grow20;
1587
1588 if (opt == 's')
1589 sblock.fs_optim = FS_OPTSPACE;
1590 else
1591 sblock.fs_optim = FS_OPTTIME;
1592
1593 sblock.fs_bmask = ~(sblock.fs_bsize - 1);
1594 sblock.fs_fmask = ~(sblock.fs_fsize - 1);
1595 /*
1596 * Planning now for future expansion.
1597 */
1598 #if defined(_BIG_ENDIAN)
1599 sblock.fs_qbmask.val[0] = 0;
1600 sblock.fs_qbmask.val[1] = ~sblock.fs_bmask;
1601 sblock.fs_qfmask.val[0] = 0;
1602 sblock.fs_qfmask.val[1] = ~sblock.fs_fmask;
1603 #endif
1604 #if defined(_LITTLE_ENDIAN)
1605 sblock.fs_qbmask.val[0] = ~sblock.fs_bmask;
1606 sblock.fs_qbmask.val[1] = 0;
1607 sblock.fs_qfmask.val[0] = ~sblock.fs_fmask;
1608 sblock.fs_qfmask.val[1] = 0;
1609 #endif
1610 for (sblock.fs_bshift = 0, i = sblock.fs_bsize; i > 1; i >>= 1)
1611 sblock.fs_bshift++;
1612 for (sblock.fs_fshift = 0, i = sblock.fs_fsize; i > 1; i >>= 1)
1613 sblock.fs_fshift++;
1614 sblock.fs_frag = numfrags(&sblock, sblock.fs_bsize);
1615 for (sblock.fs_fragshift = 0, i = sblock.fs_frag; i > 1; i >>= 1)
1616 sblock.fs_fragshift++;
1617 if (sblock.fs_frag > MAXFRAG) {
1618 (void) fprintf(stderr, gettext(
1619 "fragment size %d is too small, minimum with block size %d is %d\n"),
1620 sblock.fs_fsize, sblock.fs_bsize,
1621 sblock.fs_bsize / MAXFRAG);
1622 lockexit(32);
1623 }
1624 sblock.fs_nindir = sblock.fs_bsize / sizeof (daddr32_t);
1625 sblock.fs_inopb = sblock.fs_bsize / sizeof (struct dinode);
1626 sblock.fs_nspf = sblock.fs_fsize / sectorsize;
1627 for (sblock.fs_fsbtodb = 0, i = NSPF(&sblock); i > 1; i >>= 1)
1628 sblock.fs_fsbtodb++;
1629
1630 /*
1631 * Compute the super-block, cylinder group, and inode blocks.
1632 * Note that these "blkno" are really fragment addresses.
1633 * For example, on an 8K/1K (block/fragment) system, fs_sblkno is 16,
1634 * fs_cblkno is 24, and fs_iblkno is 32. This is why CGSIZE is so
1635 * important: only 1 FS block is allocated for the cg struct (fragment
1636 * numbers 24 through 31).
1637 */
1638 sblock.fs_sblkno =
1639 roundup(howmany(bbsize + sbsize, sblock.fs_fsize), sblock.fs_frag);
1640 sblock.fs_cblkno = (daddr32_t)(sblock.fs_sblkno +
1641 roundup(howmany(sbsize, sblock.fs_fsize), sblock.fs_frag));
1642 sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag;
1643
1644 sblock.fs_cgoffset = roundup(
1645 howmany(sblock.fs_nsect, NSPF(&sblock)), sblock.fs_frag);
1646 for (sblock.fs_cgmask = -1, i = sblock.fs_ntrak; i > 1; i >>= 1)
1647 sblock.fs_cgmask <<= 1;
1648 if (!POWEROF2(sblock.fs_ntrak))
1649 sblock.fs_cgmask <<= 1;
1650 /*
1651 * Validate specified/determined spc
1652 * and calculate minimum cylinders per group.
1653 */
1654
1655 for (sblock.fs_cpc = NSPB(&sblock), i = sblock.fs_spc;
1656 sblock.fs_cpc > 1 && (i & 1) == 0;
1657 sblock.fs_cpc >>= 1, i >>= 1)
1658 /* void */;
1659 mincpc = sblock.fs_cpc;
1660
1661 /* if these calculations are changed, check dump_fscmd also */
1662 bpcg = (uint64_t)sblock.fs_spc * sectorsize;
1663 inospercg = (uint64_t)roundup(bpcg / sizeof (struct dinode),
1664 INOPB(&sblock));
1665 if (inospercg > MAXIpG(&sblock))
1666 inospercg = MAXIpG(&sblock);
1667 used = (uint64_t)(sblock.fs_iblkno + inospercg /
1668 INOPF(&sblock)) * NSPF(&sblock);
1669 mincpgcnt = (long)howmany((uint64_t)sblock.fs_cgoffset *
1670 (~sblock.fs_cgmask) + used, sblock.fs_spc);
1671 mincpg = roundup(mincpgcnt, mincpc);
1672 /*
1673 * Insure that cylinder group with mincpg has enough space
1674 * for block maps
1675 */
1676 sblock.fs_cpg = mincpg;
1677 sblock.fs_ipg = (int32_t)inospercg;
1678 mapcramped = 0;
1679
1680 /*
1681 * Make sure the cg struct fits within the file system block.
1682 * Use larger block sizes until it fits
1683 */
1684 while (CGSIZE(&sblock) > sblock.fs_bsize) {
1685 mapcramped = 1;
1686 if (sblock.fs_bsize < MAXBSIZE) {
1687 sblock.fs_bsize <<= 1;
1688 if ((i & 1) == 0) {
1689 i >>= 1;
1690 } else {
1691 sblock.fs_cpc <<= 1;
1692 mincpc <<= 1;
1693 mincpg = roundup(mincpgcnt, mincpc);
1694 sblock.fs_cpg = mincpg;
1695 }
1696 sblock.fs_frag <<= 1;
1697 sblock.fs_fragshift += 1;
1698 if (sblock.fs_frag <= MAXFRAG)
1699 continue;
1700 }
1701
1702 /*
1703 * Looped far enough. The fragment is now as large as the
1704 * filesystem block!
1705 */
1706 if (sblock.fs_fsize == sblock.fs_bsize) {
1707 (void) fprintf(stderr, gettext(
1708 "There is no block size that can support this disk\n"));
1709 lockexit(32);
1710 }
1711
1712 /*
1713 * Try a larger fragment. Double the fragment size.
1714 */
1715 sblock.fs_frag >>= 1;
1716 sblock.fs_fragshift -= 1;
1717 sblock.fs_fsize <<= 1;
1718 sblock.fs_nspf <<= 1;
1719 }
1720 /*
1721 * Insure that cylinder group with mincpg has enough space for inodes
1722 */
1723 inodecramped = 0;
1724 used *= sectorsize;
1725 nbytes64 = (uint64_t)mincpg * bpcg - used;
1726 inospercg = (uint64_t)roundup((nbytes64 / nbpi), INOPB(&sblock));
1727 sblock.fs_ipg = (int32_t)inospercg;
1728 while (inospercg > MAXIpG(&sblock)) {
1729 inodecramped = 1;
1730 if (mincpc == 1 || sblock.fs_frag == 1 ||
1731 sblock.fs_bsize == MINBSIZE)
1732 break;
1733 nbytes64 = (uint64_t)mincpg * bpcg - used;
1734 (void) fprintf(stderr,
1735 gettext("With a block size of %d %s %lu\n"),
1736 sblock.fs_bsize, gettext("minimum bytes per inode is"),
1737 (uint32_t)(nbytes64 / MAXIpG(&sblock) + 1));
1738 sblock.fs_bsize >>= 1;
1739 sblock.fs_frag >>= 1;
1740 sblock.fs_fragshift -= 1;
1741 mincpc >>= 1;
1742 sblock.fs_cpg = roundup(mincpgcnt, mincpc);
1743 if (CGSIZE(&sblock) > sblock.fs_bsize) {
1744 sblock.fs_bsize <<= 1;
1745 break;
1746 }
1747 mincpg = sblock.fs_cpg;
1748 nbytes64 = (uint64_t)mincpg * bpcg - used;
1749 inospercg = (uint64_t)roundup((nbytes64 / nbpi),
1750 INOPB(&sblock));
1751 sblock.fs_ipg = (int32_t)inospercg;
1752 }
1753 if (inodecramped) {
1754 if (inospercg > MAXIpG(&sblock)) {
1755 nbytes64 = (uint64_t)mincpg * bpcg - used;
1756 (void) fprintf(stderr, gettext(
1757 "Minimum bytes per inode is %d\n"),
1758 (uint32_t)(nbytes64 / MAXIpG(&sblock) + 1));
1759 } else if (!mapcramped) {
1760 (void) fprintf(stderr, gettext(
1761 "With %ld bytes per inode, minimum cylinders per group is %ld\n"),
1762 nbpi, mincpg);
1763 }
1764 }
1765 if (mapcramped) {
1766 (void) fprintf(stderr, gettext(
1767 "With %d sectors per cylinder, minimum cylinders "
1768 "per group is %ld\n"),
1769 sblock.fs_spc, mincpg);
1770 }
1771 if (inodecramped || mapcramped) {
1772 /*
1773 * To make this at least somewhat comprehensible in
1774 * the world of i18n, figure out what we're going to
1775 * say and then say it all at one time. The days of
1776 * needing to scrimp on string space are behind us....
1777 */
1778 if ((sblock.fs_bsize != bsize) &&
1779 (sblock.fs_fsize != fragsize)) {
1780 (void) fprintf(stderr, gettext(
1781 "This requires the block size to be changed from %ld to %d\n"
1782 "and the fragment size to be changed from %ld to %d\n"),
1783 bsize, sblock.fs_bsize,
1784 fragsize, sblock.fs_fsize);
1785 } else if (sblock.fs_bsize != bsize) {
1786 (void) fprintf(stderr, gettext(
1787 "This requires the block size to be changed from %ld to %d\n"),
1788 bsize, sblock.fs_bsize);
1789 } else if (sblock.fs_fsize != fragsize) {
1790 (void) fprintf(stderr, gettext(
1791 "This requires the fragment size to be changed from %ld to %d\n"),
1792 fragsize, sblock.fs_fsize);
1793 } else {
1794 (void) fprintf(stderr, gettext(
1795 "Unable to make filesystem fit with the given constraints\n"));
1796 }
1797 (void) fprintf(stderr, gettext(
1798 "Please re-run mkfs with corrected parameters\n"));
1799 lockexit(32);
1800 }
1801 /*
1802 * Calculate the number of cylinders per group
1803 */
1804 sblock.fs_cpg = cpg;
1805 if (sblock.fs_cpg % mincpc != 0) {
1806 (void) fprintf(stderr, gettext(
1807 "Warning: cylinder groups must have a multiple "
1808 "of %ld cylinders with the given\n parameters\n"),
1809 mincpc);
1810 sblock.fs_cpg = roundup(sblock.fs_cpg, mincpc);
1811 (void) fprintf(stderr, gettext("Rounded cgsize up to %d\n"),
1812 sblock.fs_cpg);
1813 }
1814 /*
1815 * Must insure there is enough space for inodes
1816 */
1817 /* if these calculations are changed, check dump_fscmd also */
1818 nbytes64 = (uint64_t)sblock.fs_cpg * bpcg - used;
1819 sblock.fs_ipg = roundup((uint32_t)(nbytes64 / nbpi), INOPB(&sblock));
1820
1821 /*
1822 * Slim down cylinders per group, until the inodes can fit.
1823 */
1824 while (sblock.fs_ipg > MAXIpG(&sblock)) {
1825 inodecramped = 1;
1826 sblock.fs_cpg -= mincpc;
1827 nbytes64 = (uint64_t)sblock.fs_cpg * bpcg - used;
1828 sblock.fs_ipg = roundup((uint32_t)(nbytes64 / nbpi),
1829 INOPB(&sblock));
1830 }
1831 /*
1832 * Must insure there is enough space to hold block map.
1833 * Cut down on cylinders per group, until the cg struct fits in a
1834 * filesystem block.
1835 */
1836 while (CGSIZE(&sblock) > sblock.fs_bsize) {
1837 mapcramped = 1;
1838 sblock.fs_cpg -= mincpc;
1839 nbytes64 = (uint64_t)sblock.fs_cpg * bpcg - used;
1840 sblock.fs_ipg = roundup((uint32_t)(nbytes64 / nbpi),
1841 INOPB(&sblock));
1842 }
1843 sblock.fs_fpg = (sblock.fs_cpg * sblock.fs_spc) / NSPF(&sblock);
1844 if ((sblock.fs_cpg * sblock.fs_spc) % NSPB(&sblock) != 0) {
1845 (void) fprintf(stderr,
1846 gettext("newfs: panic (fs_cpg * fs_spc) %% NSPF != 0\n"));
1847 lockexit(32);
1848 }
1849 if (sblock.fs_cpg < mincpg) {
1850 (void) fprintf(stderr, gettext(
1851 "With the given parameters, cgsize must be at least %ld; please re-run mkfs\n"),
1852 mincpg);
1853 lockexit(32);
1854 }
1855 sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock));
1856 grow20:
1857 /*
1858 * Now have size for file system and nsect and ntrak.
1859 * Determine number of cylinders and blocks in the file system.
1860 */
1861 fssize_frag = (int64_t)dbtofsb(&sblock, fssize_db);
1862 if (fssize_frag > INT_MAX) {
1863 (void) fprintf(stderr, gettext(
1864 "There are too many fragments in the system, increase fragment size\n"),
1865 mincpg);
1866 lockexit(32);
1867 }
1868 sblock.fs_size = (int32_t)fssize_frag;
1869 sblock.fs_ncyl = (int32_t)(fssize_frag * NSPF(&sblock) / sblock.fs_spc);
1870 if (fssize_frag * NSPF(&sblock) >
1871 (uint64_t)sblock.fs_ncyl * sblock.fs_spc) {
1872 sblock.fs_ncyl++;
1873 warn = 1;
1874 }
1875 if (sblock.fs_ncyl < 1) {
1876 (void) fprintf(stderr, gettext(
1877 "file systems must have at least one cylinder\n"));
1878 lockexit(32);
1879 }
1880 if (grow)
1881 goto grow30;
1882 /*
1883 * Determine feasability/values of rotational layout tables.
1884 *
1885 * The size of the rotational layout tables is limited by the size
1886 * of the file system block, fs_bsize. The amount of space
1887 * available for tables is calculated as (fs_bsize - sizeof (struct
1888 * fs)). The size of these tables is inversely proportional to the
1889 * block size of the file system. The size increases if sectors per
1890 * track are not powers of two, because more cylinders must be
1891 * described by the tables before the rotational pattern repeats
1892 * (fs_cpc).
1893 */
1894 sblock.fs_postblformat = FS_DYNAMICPOSTBLFMT;
1895 sblock.fs_sbsize = fragroundup(&sblock, sizeof (struct fs));
1896 sblock.fs_npsect = sblock.fs_nsect;
1897 if (sblock.fs_ntrak == 1) {
1898 sblock.fs_cpc = 0;
1899 goto next;
1900 }
1901 postblsize = sblock.fs_nrpos * sblock.fs_cpc * sizeof (short);
1902 rotblsize = sblock.fs_cpc * sblock.fs_spc / NSPB(&sblock);
1903 totalsbsize = sizeof (struct fs) + rotblsize;
1904
1905 /* do static allocation if nrpos == 8 and fs_cpc == 16 */
1906 if (sblock.fs_nrpos == 8 && sblock.fs_cpc <= 16) {
1907 /* use old static table space */
1908 sblock.fs_postbloff = (char *)(&sblock.fs_opostbl[0][0]) -
1909 (char *)(&sblock.fs_link);
1910 sblock.fs_rotbloff = &sblock.fs_space[0] -
1911 (uchar_t *)(&sblock.fs_link);
1912 } else {
1913 /* use 4.3 dynamic table space */
1914 sblock.fs_postbloff = &sblock.fs_space[0] -
1915 (uchar_t *)(&sblock.fs_link);
1916 sblock.fs_rotbloff = sblock.fs_postbloff + postblsize;
1917 totalsbsize += postblsize;
1918 }
1919 if (totalsbsize > sblock.fs_bsize ||
1920 sblock.fs_nsect > (1 << NBBY) * NSPB(&sblock)) {
1921 (void) fprintf(stderr, gettext(
1922 "Warning: insufficient space in super block for\n"
1923 "rotational layout tables with nsect %d, ntrack %d, "
1924 "and nrpos %d.\nOmitting tables - file system "
1925 "performance may be impaired.\n"),
1926 sblock.fs_nsect, sblock.fs_ntrak, sblock.fs_nrpos);
1927
1928 /*
1929 * Setting fs_cpc to 0 tells alloccgblk() in ufs_alloc.c to
1930 * ignore the positional layout table and rotational
1931 * position table.
1932 */
1933 sblock.fs_cpc = 0;
1934 goto next;
1935 }
1936 sblock.fs_sbsize = fragroundup(&sblock, totalsbsize);
1937
1938
1939 /*
1940 * calculate the available blocks for each rotational position
1941 */
1942 for (cylno = 0; cylno < sblock.fs_cpc; cylno++)
1943 for (rpos = 0; rpos < sblock.fs_nrpos; rpos++)
1944 fs_postbl(&sblock, cylno)[rpos] = -1;
1945 for (i = (rotblsize - 1) * sblock.fs_frag;
1946 i >= 0; i -= sblock.fs_frag) {
1947 cylno = cbtocylno(&sblock, i);
1948 rpos = cbtorpos(&sblock, i);
1949 blk = fragstoblks(&sblock, i);
1950 if (fs_postbl(&sblock, cylno)[rpos] == -1)
1951 fs_rotbl(&sblock)[blk] = 0;
1952 else
1953 fs_rotbl(&sblock)[blk] =
1954 fs_postbl(&sblock, cylno)[rpos] - blk;
1955 fs_postbl(&sblock, cylno)[rpos] = blk;
1956 }
1957 next:
1958 grow30:
1959 /*
1960 * Compute/validate number of cylinder groups.
1961 * Note that if an excessively large filesystem is specified
1962 * (e.g., more than 16384 cylinders for an 8K filesystem block), it
1963 * does not get detected until checksummarysize()
1964 */
1965 sblock.fs_ncg = sblock.fs_ncyl / sblock.fs_cpg;
1966 if (sblock.fs_ncyl % sblock.fs_cpg)
1967 sblock.fs_ncg++;
1968 sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock);
1969 i = MIN(~sblock.fs_cgmask, sblock.fs_ncg - 1);
1970 ibpcl = cgdmin(&sblock, i) - cgbase(&sblock, i);
1971 if (ibpcl >= sblock.fs_fpg) {
1972 (void) fprintf(stderr, gettext(
1973 "inode blocks/cyl group (%d) >= data blocks (%d)\n"),
1974 cgdmin(&sblock, i) - cgbase(&sblock, i) / sblock.fs_frag,
1975 sblock.fs_fpg / sblock.fs_frag);
1976 if ((ibpcl < 0) || (sblock.fs_fpg < 0)) {
1977 (void) fprintf(stderr, gettext(
1978 "number of cylinders per cylinder group (%d) must be decreased.\n"),
1979 sblock.fs_cpg);
1980 } else {
1981 (void) fprintf(stderr, gettext(
1982 "number of cylinders per cylinder group (%d) must be increased.\n"),
1983 sblock.fs_cpg);
1984 }
1985 (void) fprintf(stderr, gettext(
1986 "Note that cgsize may have been adjusted to allow struct cg to fit.\n"));
1987 lockexit(32);
1988 }
1989 j = sblock.fs_ncg - 1;
1990 if ((i = fssize_frag - j * sblock.fs_fpg) < sblock.fs_fpg &&
1991 cgdmin(&sblock, j) - cgbase(&sblock, j) > i) {
1992 (void) fprintf(stderr, gettext(
1993 "Warning: inode blocks/cyl group (%d) >= data "
1994 "blocks (%ld) in last\n cylinder group. This "
1995 "implies %ld sector(s) cannot be allocated.\n"),
1996 (cgdmin(&sblock, j) - cgbase(&sblock, j)) / sblock.fs_frag,
1997 i / sblock.fs_frag, i * NSPF(&sblock));
1998 /*
1999 * If there is only one cylinder group and that is not even
2000 * big enough to hold the inodes, exit.
2001 */
2002 if (sblock.fs_ncg == 1)
2003 cg_too_small = 1;
2004 sblock.fs_ncg--;
2005 sblock.fs_ncyl = sblock.fs_ncg * sblock.fs_cpg;
2006 sblock.fs_size = fssize_frag =
2007 (int64_t)sblock.fs_ncyl * (int64_t)sblock.fs_spc /
2008 (int64_t)NSPF(&sblock);
2009 warn = 0;
2010 }
2011 if (warn && !spc_flag) {
2012 (void) fprintf(stderr, gettext(
2013 "Warning: %d sector(s) in last cylinder unallocated\n"),
2014 sblock.fs_spc - (uint32_t)(fssize_frag * NSPF(&sblock) -
2015 (uint64_t)(sblock.fs_ncyl - 1) * sblock.fs_spc));
2016 }
2017 /*
2018 * fill in remaining fields of the super block
2019 */
2020
2021 /*
2022 * The csum records are stored in cylinder group 0, starting at
2023 * cgdmin, the first data block.
2024 */
2025 sblock.fs_csaddr = cgdmin(&sblock, 0);
2026 sblock.fs_cssize =
2027 fragroundup(&sblock, sblock.fs_ncg * sizeof (struct csum));
2028 i = sblock.fs_bsize / sizeof (struct csum);
2029 sblock.fs_csmask = ~(i - 1);
2030 for (sblock.fs_csshift = 0; i > 1; i >>= 1)
2031 sblock.fs_csshift++;
2032 fscs = (struct csum *)calloc(1, sblock.fs_cssize);
2033
2034 checksummarysize();
2035 if (mtb == 'y') {
2036 sblock.fs_magic = MTB_UFS_MAGIC;
2037 sblock.fs_version = MTB_UFS_VERSION_1;
2038 } else {
2039 sblock.fs_magic = FS_MAGIC;
2040 if (use_efi_dflts)
2041 sblock.fs_version = UFS_EFISTYLE4NONEFI_VERSION_2;
2042 else
2043 sblock.fs_version = UFS_VERSION_MIN;
2044 }
2045
2046 if (grow) {
2047 bcopy((caddr_t)grow_fscs, (caddr_t)fscs, (int)grow_fs_cssize);
2048 extendsummaryinfo();
2049 goto grow40;
2050 }
2051 sblock.fs_rotdelay = rotdelay;
2052 sblock.fs_maxcontig = maxcontig;
2053 sblock.fs_maxbpg = MAXBLKPG(sblock.fs_bsize);
2054
2055 sblock.fs_rps = rps;
2056 sblock.fs_cgrotor = 0;
2057 sblock.fs_cstotal.cs_ndir = 0;
2058 sblock.fs_cstotal.cs_nbfree = 0;
2059 sblock.fs_cstotal.cs_nifree = 0;
2060 sblock.fs_cstotal.cs_nffree = 0;
2061 sblock.fs_fmod = 0;
2062 sblock.fs_ronly = 0;
2063 sblock.fs_time = mkfstime;
2064 sblock.fs_state = FSOKAY - sblock.fs_time;
2065 sblock.fs_clean = FSCLEAN;
2066 grow40:
2067
2068 /*
2069 * If all that's needed is a dump of the superblock we
2070 * would use by default, we've got it now. So, splat it
2071 * out and leave.
2072 */
2073 if (rflag) {
2074 dump_sblock();
2075 lockexit(0);
2076 }
2077 /*
2078 * Dump out summary information about file system.
2079 */
2080 (void) fprintf(stderr, gettext(
2081 "%s:\t%lld sectors in %d cylinders of %d tracks, %d sectors\n"),
2082 fsys, (uint64_t)sblock.fs_size * NSPF(&sblock), sblock.fs_ncyl,
2083 sblock.fs_ntrak, sblock.fs_nsect);
2084 (void) fprintf(stderr, gettext(
2085 "\t%.1fMB in %d cyl groups (%d c/g, %.2fMB/g, %d i/g)\n"),
2086 (float)sblock.fs_size * sblock.fs_fsize / MB, sblock.fs_ncg,
2087 sblock.fs_cpg, (float)sblock.fs_fpg * sblock.fs_fsize / MB,
2088 sblock.fs_ipg);
2089
2090 tmpbuf = calloc(sblock.fs_ncg / 50 + 500, 1);
2091 if (tmpbuf == NULL) {
2092 perror("calloc");
2093 lockexit(32);
2094 }
2095 if (cg_too_small) {
2096 (void) fprintf(stderr, gettext("File system creation failed. "
2097 "There is only one cylinder group and\nthat is "
2098 "not even big enough to hold the inodes.\n"));
2099 lockexit(32);
2100 }
2101 /*
2102 * Now build the cylinders group blocks and
2103 * then print out indices of cylinder groups.
2104 */
2105 tprintf(gettext(
2106 "super-block backups (for fsck -F ufs -o b=#) at:\n"));
2107 for (width = cylno = 0; cylno < sblock.fs_ncg && cylno < 10; cylno++) {
2108 if ((grow == 0) || (cylno >= grow_fs_ncg))
2109 initcg(cylno);
2110 num = fsbtodb(&sblock, (uint64_t)cgsblock(&sblock, cylno));
2111 /*
2112 * If Nflag and if the disk is larger than the CHSLIMIT,
2113 * then sanity test the superblocks before reporting. If there
2114 * are too many superblocks which look insane, we have
2115 * to retry with alternate logic. If both methods have
2116 * failed, then our efforts to arrive at alternate
2117 * superblocks failed, so complain and exit.
2118 */
2119 if (Nflag && retry) {
2120 skip_this_sb = 0;
2121 rdfs((diskaddr_t)num, sbsize, (char *)&altsblock);
2122 ret = checksblock(altsblock, 1);
2123 if (ret) {
2124 skip_this_sb = 1;
2125 invalid_sb_cnt++;
2126 dprintf(("DeBuG checksblock() failed - error :"
2127 " %d for sb : %llu invalid_sb_cnt : %d\n",
2128 ret, num, invalid_sb_cnt));
2129 } else {
2130 /*
2131 * Though the superblock looks sane, verify if
2132 * the fs_version in the superblock and the
2133 * logic that we are using to arrive at the
2134 * superblocks match.
2135 */
2136 if (use_efi_dflts && altsblock.fs_version
2137 != UFS_EFISTYLE4NONEFI_VERSION_2) {
2138 skip_this_sb = 1;
2139 invalid_sb_cnt++;
2140 }
2141 }
2142 if (invalid_sb_cnt >= INVALIDSBLIMIT) {
2143 if (retry > 1) {
2144 (void) fprintf(stderr, gettext(
2145 "Error determining alternate "
2146 "superblock locations\n"));
2147 free(tmpbuf);
2148 lockexit(32);
2149 }
2150 retry++;
2151 use_efi_dflts = !use_efi_dflts;
2152 free(tmpbuf);
2153 goto retry_alternate_logic;
2154 }
2155 if (skip_this_sb)
2156 continue;
2157 }
2158 (void) sprintf(pbuf, " %llu,", num);
2159 plen = strlen(pbuf);
2160 if ((width + plen) > (WIDTH - 1)) {
2161 width = plen;
2162 tprintf("\n");
2163 } else {
2164 width += plen;
2165 }
2166 if (Nflag && retry)
2167 (void) strncat(tmpbuf, pbuf, strlen(pbuf));
2168 else
2169 (void) fprintf(stderr, "%s", pbuf);
2170 }
2171 tprintf("\n");
2172
2173 remaining_cg = sblock.fs_ncg - cylno;
2174
2175 /*
2176 * If there are more than 300 cylinder groups still to be
2177 * initialized, print a "." for every 50 cylinder groups.
2178 */
2179 if (remaining_cg > 300) {
2180 tprintf(gettext("Initializing cylinder groups:\n"));
2181 do_dot = 1;
2182 }
2183
2184 /*
2185 * Now initialize all cylinder groups between the first ten
2186 * and the last ten.
2187 *
2188 * If the number of cylinder groups was less than 10, all of the
2189 * cylinder group offsets would have printed in the last loop
2190 * and cylno will already be equal to sblock.fs_ncg and so this
2191 * loop will not be entered. If there are less than 20 cylinder
2192 * groups, cylno is already less than fs_ncg - 10, so this loop
2193 * won't be entered in that case either.
2194 */
2195
2196 i = 0;
2197 for (; cylno < sblock.fs_ncg - 10; cylno++) {
2198 if ((grow == 0) || (cylno >= grow_fs_ncg))
2199 initcg(cylno);
2200 if (do_dot && cylno % 50 == 0) {
2201 tprintf(".");
2202 i++;
2203 if (i == WIDTH - 1) {
2204 tprintf("\n");
2205 i = 0;
2206 }
2207 }
2208 }
2209
2210 /*
2211 * Now print the cylinder group offsets for the last 10
2212 * cylinder groups, if any are left.
2213 */
2214
2215 if (do_dot) {
2216 tprintf(gettext(
2217 "\nsuper-block backups for last 10 cylinder groups at:\n"));
2218 }
2219 for (width = 0; cylno < sblock.fs_ncg; cylno++) {
2220 if ((grow == 0) || (cylno >= grow_fs_ncg))
2221 initcg(cylno);
2222 num = fsbtodb(&sblock, (uint64_t)cgsblock(&sblock, cylno));
2223 if (Nflag && retry) {
2224 skip_this_sb = 0;
2225 rdfs((diskaddr_t)num, sbsize, (char *)&altsblock);
2226 ret = checksblock(altsblock, 1);
2227 if (ret) {
2228 skip_this_sb = 1;
2229 invalid_sb_cnt++;
2230 dprintf(("DeBuG checksblock() failed - error :"
2231 " %d for sb : %llu invalid_sb_cnt : %d\n",
2232 ret, num, invalid_sb_cnt));
2233 } else {
2234 /*
2235 * Though the superblock looks sane, verify if
2236 * the fs_version in the superblock and the
2237 * logic that we are using to arrive at the
2238 * superblocks match.
2239 */
2240 if (use_efi_dflts && altsblock.fs_version
2241 != UFS_EFISTYLE4NONEFI_VERSION_2) {
2242 skip_this_sb = 1;
2243 invalid_sb_cnt++;
2244 }
2245 }
2246 if (invalid_sb_cnt >= INVALIDSBLIMIT) {
2247 if (retry > 1) {
2248 (void) fprintf(stderr, gettext(
2249 "Error determining alternate "
2250 "superblock locations\n"));
2251 free(tmpbuf);
2252 lockexit(32);
2253 }
2254 retry++;
2255 use_efi_dflts = !use_efi_dflts;
2256 free(tmpbuf);
2257 goto retry_alternate_logic;
2258 }
2259 if (skip_this_sb)
2260 continue;
2261 }
2262 /* Don't print ',' for the last superblock */
2263 if (cylno == sblock.fs_ncg-1)
2264 (void) sprintf(pbuf, " %llu", num);
2265 else
2266 (void) sprintf(pbuf, " %llu,", num);
2267 plen = strlen(pbuf);
2268 if ((width + plen) > (WIDTH - 1)) {
2269 width = plen;
2270 tprintf("\n");
2271 } else {
2272 width += plen;
2273 }
2274 if (Nflag && retry)
2275 (void) strncat(tmpbuf, pbuf, strlen(pbuf));
2276 else
2277 (void) fprintf(stderr, "%s", pbuf);
2278 }
2279 tprintf("\n");
2280 if (Nflag) {
2281 if (retry)
2282 (void) fprintf(stderr, "%s", tmpbuf);
2283 free(tmpbuf);
2284 lockexit(0);
2285 }
2286
2287 free(tmpbuf);
2288 if (grow)
2289 goto grow50;
2290
2291 /*
2292 * Now construct the initial file system,
2293 * then write out the super-block.
2294 */
2295 fsinit();
2296 grow50:
2297 /*
2298 * write the superblock and csum information
2299 */
2300 wtsb();
2301
2302 /*
2303 * extend the last cylinder group in the original file system
2304 */
2305 if (grow) {
2306 extendcg(grow_fs_ncg-1);
2307 wtsb();
2308 }
2309
2310 /*
2311 * Write out the duplicate super blocks to the first 10
2312 * cylinder groups (or fewer, if there are fewer than 10
2313 * cylinder groups).
2314 */
2315 for (cylno = 0; cylno < sblock.fs_ncg && cylno < 10; cylno++)
2316 awtfs(fsbtodb(&sblock, (uint64_t)cgsblock(&sblock, cylno)),
2317 (int)sbsize, (char *)&sblock, SAVE);
2318
2319 /*
2320 * Now write out duplicate super blocks to the remaining
2321 * cylinder groups. In the case of multi-terabyte file
2322 * systems, just write out the super block to the last ten
2323 * cylinder groups (or however many are left).
2324 */
2325 if (mtb == 'y') {
2326 if (sblock.fs_ncg <= 10)
2327 cylno = sblock.fs_ncg;
2328 else if (sblock.fs_ncg <= 20)
2329 cylno = 10;
2330 else
2331 cylno = sblock.fs_ncg - 10;
2332 }
2333
2334 for (; cylno < sblock.fs_ncg; cylno++)
2335 awtfs(fsbtodb(&sblock, (uint64_t)cgsblock(&sblock, cylno)),
2336 (int)sbsize, (char *)&sblock, SAVE);
2337
2338 /*
2339 * Flush out all the AIO writes we've done. It's not
2340 * necessary to do this explicitly, but it's the only
2341 * way to report any errors from those writes.
2342 */
2343 flush_writes();
2344
2345 /*
2346 * set clean flag
2347 */
2348 if (grow)
2349 sblock.fs_clean = grow_fs_clean;
2350 else
2351 sblock.fs_clean = FSCLEAN;
2352 sblock.fs_time = mkfstime;
2353 sblock.fs_state = FSOKAY - sblock.fs_time;
2354 wtfs((diskaddr_t)(SBOFF / sectorsize), sbsize, (char *)&sblock);
2355 isbad = 0;
2356
2357 if (fsync(fso) == -1) {
2358 saverr = errno;
2359 (void) fprintf(stderr,
2360 gettext("mkfs: fsync failed on write disk: %s\n"),
2361 strerror(saverr));
2362 /* we're just cleaning up, so keep going */
2363 }
2364 if (close(fsi) == -1) {
2365 saverr = errno;
2366 (void) fprintf(stderr,
2367 gettext("mkfs: close failed on read disk: %s\n"),
2368 strerror(saverr));
2369 /* we're just cleaning up, so keep going */
2370 }
2371 if (close(fso) == -1) {
2372 saverr = errno;
2373 (void) fprintf(stderr,
2374 gettext("mkfs: close failed on write disk: %s\n"),
2375 strerror(saverr));
2376 /* we're just cleaning up, so keep going */
2377 }
2378 fsi = fso = -1;
2379
2380 #ifndef STANDALONE
2381 lockexit(0);
2382 #endif
2383
2384 return (0);
2385 }
2386
2387 static diskaddr_t
get_device_size(int fd)2388 get_device_size(int fd)
2389 {
2390 struct dk_minfo disk_info;
2391
2392 if ((ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info)) == -1)
2393 return (0);
2394
2395 return (disk_info.dki_capacity);
2396 }
2397
2398 /*
2399 * Figure out how big the partition we're dealing with is.
2400 * The value returned is in disk blocks (sectors);
2401 */
2402 static diskaddr_t
get_max_size(int fd)2403 get_max_size(int fd)
2404 {
2405 struct extvtoc vtoc;
2406 dk_gpt_t *efi_vtoc;
2407 diskaddr_t slicesize;
2408
2409 int index = read_extvtoc(fd, &vtoc);
2410
2411 if (index >= 0) {
2412 label_type = LABEL_TYPE_VTOC;
2413 } else {
2414 if (index == VT_ENOTSUP || index == VT_ERROR) {
2415 /* it might be an EFI label */
2416 index = efi_alloc_and_read(fd, &efi_vtoc);
2417 label_type = LABEL_TYPE_EFI;
2418 }
2419 }
2420
2421 if (index < 0) {
2422 /*
2423 * Since both attempts to read the label failed, we're
2424 * going to use DKIOCGMEDIAINFO to get device size.
2425 */
2426
2427 label_type = LABEL_TYPE_OTHER;
2428 slicesize = get_device_size(fd);
2429 if (slicesize == 0) {
2430 switch (index) {
2431 case VT_ERROR:
2432 break;
2433 case VT_EIO:
2434 errno = EIO;
2435 break;
2436 case VT_EINVAL:
2437 errno = EINVAL;
2438 }
2439 perror(gettext("Can not determine partition size"));
2440 lockexit(32);
2441 }
2442 }
2443
2444 if (label_type == LABEL_TYPE_EFI) {
2445 slicesize = efi_vtoc->efi_parts[index].p_size;
2446 efi_free(efi_vtoc);
2447 } else if (label_type == LABEL_TYPE_VTOC) {
2448 /*
2449 * In the vtoc struct, p_size is a 32-bit signed quantity.
2450 * In the dk_gpt struct (efi's version of the vtoc), p_size
2451 * is an unsigned 64-bit quantity. By casting the vtoc's
2452 * psize to an unsigned 32-bit quantity, it will be copied
2453 * to 'slicesize' (an unsigned 64-bit diskaddr_t) without
2454 * sign extension.
2455 */
2456
2457 slicesize = (uint32_t)vtoc.v_part[index].p_size;
2458 }
2459
2460 dprintf(("DeBuG get_max_size index = %d, p_size = %lld, dolimit = %d\n",
2461 index, slicesize, (slicesize > FS_MAX)));
2462
2463 /*
2464 * The next line limits a UFS file system to the maximum
2465 * supported size.
2466 */
2467
2468 if (slicesize > FS_MAX)
2469 return (FS_MAX);
2470 return (slicesize);
2471 }
2472
2473 static long
get_max_track_size(int fd)2474 get_max_track_size(int fd)
2475 {
2476 struct dk_cinfo ci;
2477 long track_size = -1;
2478
2479 if (ioctl(fd, DKIOCINFO, &ci) == 0) {
2480 track_size = ci.dki_maxtransfer * DEV_BSIZE;
2481 }
2482
2483 if ((track_size < 0)) {
2484 int error = 0;
2485 int maxphys;
2486 int gotit = 0;
2487
2488 gotit = fsgetmaxphys(&maxphys, &error);
2489 if (gotit) {
2490 track_size = MIN(MB, maxphys);
2491 } else {
2492 (void) fprintf(stderr, gettext(
2493 "Warning: Could not get system value for maxphys. The value for\n"
2494 "maxcontig will default to 1MB.\n"));
2495 track_size = MB;
2496 }
2497 }
2498 return (track_size);
2499 }
2500
2501 /*
2502 * Initialize a cylinder group.
2503 */
2504 static void
initcg(int cylno)2505 initcg(int cylno)
2506 {
2507 diskaddr_t cbase, d;
2508 diskaddr_t dlower; /* last data block before cg metadata */
2509 diskaddr_t dupper; /* first data block after cg metadata */
2510 diskaddr_t dmax;
2511 int64_t i;
2512 struct csum *cs;
2513 struct dinode *inode_buffer;
2514 int size;
2515
2516 /*
2517 * Variables used to store intermediate results as a part of
2518 * the internal implementation of the cbtocylno() macros.
2519 */
2520 diskaddr_t bno; /* UFS block number (not sector number) */
2521 int cbcylno; /* current cylinder number */
2522 int cbcylno_sect; /* sector offset within cylinder */
2523 int cbsect_incr; /* amount to increment sector offset */
2524
2525 /*
2526 * Variables used to store intermediate results as a part of
2527 * the internal implementation of the cbtorpos() macros.
2528 */
2529 short *cgblks; /* pointer to array of free blocks in cg */
2530 int trackrpos; /* tmp variable for rotation position */
2531 int trackoff; /* offset within a track */
2532 int trackoff_incr; /* amount to increment trackoff */
2533 int rpos; /* rotation position of current block */
2534 int rpos_incr; /* amount to increment rpos per block */
2535
2536 union cgun *icgun; /* local pointer to a cg summary block */
2537 #define icg (icgun->cg)
2538
2539 icgun = (union cgun *)getbuf(&cgsumbuf, sizeof (union cgun));
2540
2541 /*
2542 * Determine block bounds for cylinder group.
2543 * Allow space for super block summary information in first
2544 * cylinder group.
2545 */
2546 cbase = cgbase(&sblock, cylno);
2547 dmax = cbase + sblock.fs_fpg;
2548 if (dmax > sblock.fs_size) /* last cg may be smaller than normal */
2549 dmax = sblock.fs_size;
2550 dlower = cgsblock(&sblock, cylno) - cbase;
2551 dupper = cgdmin(&sblock, cylno) - cbase;
2552 if (cylno == 0)
2553 dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
2554 cs = fscs + cylno;
2555 icg.cg_time = mkfstime;
2556 icg.cg_magic = CG_MAGIC;
2557 icg.cg_cgx = cylno;
2558 /* last one gets whatever's left */
2559 if (cylno == sblock.fs_ncg - 1)
2560 icg.cg_ncyl = sblock.fs_ncyl - (sblock.fs_cpg * cylno);
2561 else
2562 icg.cg_ncyl = sblock.fs_cpg;
2563 icg.cg_niblk = sblock.fs_ipg;
2564 icg.cg_ndblk = dmax - cbase;
2565 icg.cg_cs.cs_ndir = 0;
2566 icg.cg_cs.cs_nffree = 0;
2567 icg.cg_cs.cs_nbfree = 0;
2568 icg.cg_cs.cs_nifree = 0;
2569 icg.cg_rotor = 0;
2570 icg.cg_frotor = 0;
2571 icg.cg_irotor = 0;
2572 icg.cg_btotoff = &icg.cg_space[0] - (uchar_t *)(&icg.cg_link);
2573 icg.cg_boff = icg.cg_btotoff + sblock.fs_cpg * sizeof (long);
2574 icg.cg_iusedoff = icg.cg_boff +
2575 sblock.fs_cpg * sblock.fs_nrpos * sizeof (short);
2576 icg.cg_freeoff = icg.cg_iusedoff + howmany(sblock.fs_ipg, NBBY);
2577 icg.cg_nextfreeoff = icg.cg_freeoff +
2578 howmany(sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock), NBBY);
2579 for (i = 0; i < sblock.fs_frag; i++) {
2580 icg.cg_frsum[i] = 0;
2581 }
2582 bzero((caddr_t)cg_inosused(&icg), icg.cg_freeoff - icg.cg_iusedoff);
2583 icg.cg_cs.cs_nifree += sblock.fs_ipg;
2584 if (cylno == 0)
2585 for (i = 0; i < UFSROOTINO; i++) {
2586 setbit(cg_inosused(&icg), i);
2587 icg.cg_cs.cs_nifree--;
2588 }
2589
2590 /*
2591 * Initialize all the inodes in the cylinder group using
2592 * random numbers.
2593 */
2594 size = sblock.fs_ipg * sizeof (struct dinode);
2595 inode_buffer = (struct dinode *)getbuf(&inodebuf, size);
2596
2597 for (i = 0; i < sblock.fs_ipg; i++) {
2598 IRANDOMIZE(&(inode_buffer[i].di_ic));
2599 }
2600
2601 /*
2602 * Write all inodes in a single write for performance.
2603 */
2604 awtfs(fsbtodb(&sblock, (uint64_t)cgimin(&sblock, cylno)), (int)size,
2605 (char *)inode_buffer, RELEASE);
2606
2607 bzero((caddr_t)cg_blktot(&icg), icg.cg_boff - icg.cg_btotoff);
2608 bzero((caddr_t)cg_blks(&sblock, &icg, 0),
2609 icg.cg_iusedoff - icg.cg_boff);
2610 bzero((caddr_t)cg_blksfree(&icg), icg.cg_nextfreeoff - icg.cg_freeoff);
2611
2612 if (cylno > 0) {
2613 for (d = 0; d < dlower; d += sblock.fs_frag) {
2614 setblock(&sblock, cg_blksfree(&icg), d/sblock.fs_frag);
2615 icg.cg_cs.cs_nbfree++;
2616 cg_blktot(&icg)[cbtocylno(&sblock, d)]++;
2617 cg_blks(&sblock, &icg, cbtocylno(&sblock, d))
2618 [cbtorpos(&sblock, d)]++;
2619 }
2620 sblock.fs_dsize += dlower;
2621 }
2622 sblock.fs_dsize += icg.cg_ndblk - dupper;
2623 if ((i = dupper % sblock.fs_frag) != 0) {
2624 icg.cg_frsum[sblock.fs_frag - i]++;
2625 for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) {
2626 setbit(cg_blksfree(&icg), dupper);
2627 icg.cg_cs.cs_nffree++;
2628 }
2629 }
2630
2631 /*
2632 * WARNING: The following code is somewhat confusing, but
2633 * results in a substantial performance improvement in mkfs.
2634 *
2635 * Instead of using cbtocylno() and cbtorpos() macros, we
2636 * keep track of all the intermediate state of those macros
2637 * in some variables. This allows simple addition to be
2638 * done to calculate the results as we step through the
2639 * blocks in an orderly fashion instead of the slower
2640 * multiplication and division the macros are forced to
2641 * used so they can support random input. (Multiplication,
2642 * division, and remainder operations typically take about
2643 * 10x as many processor cycles as other operations.)
2644 *
2645 * The basic idea is to take code:
2646 *
2647 * for (x = starting_x; x < max; x++)
2648 * y = (x * c) / z
2649 *
2650 * and rewrite it to take advantage of the fact that
2651 * the variable x is incrementing in an orderly way:
2652 *
2653 * intermediate = starting_x * c
2654 * yval = intermediate / z
2655 * for (x = starting_x; x < max; x++) {
2656 * y = yval;
2657 * intermediate += c
2658 * if (intermediate > z) {
2659 * yval++;
2660 * intermediate -= z
2661 * }
2662 * }
2663 *
2664 * Performance has improved as much as 4X using this code.
2665 */
2666
2667 /*
2668 * Initialize the starting points for all the cbtocylno()
2669 * macro variables and figure out the increments needed each
2670 * time through the loop.
2671 */
2672 cbcylno_sect = dupper * NSPF(&sblock);
2673 cbsect_incr = sblock.fs_frag * NSPF(&sblock);
2674 cbcylno = cbcylno_sect / sblock.fs_spc;
2675 cbcylno_sect %= sblock.fs_spc;
2676 cgblks = cg_blks(&sblock, &icg, cbcylno);
2677 bno = dupper / sblock.fs_frag;
2678
2679 /*
2680 * Initialize the starting points for all the cbtorpos()
2681 * macro variables and figure out the increments needed each
2682 * time through the loop.
2683 *
2684 * It's harder to simplify the cbtorpos() macro if there were
2685 * alternate sectors specified (or if they previously existed
2686 * in the growfs case). Since this is rare, we just revert to
2687 * using the macros in this case and skip the variable setup.
2688 */
2689 if (!spc_flag) {
2690 trackrpos = (cbcylno_sect % sblock.fs_nsect) * sblock.fs_nrpos;
2691 rpos = trackrpos / sblock.fs_nsect;
2692 trackoff = trackrpos % sblock.fs_nsect;
2693 trackoff_incr = cbsect_incr * sblock.fs_nrpos;
2694 rpos_incr = (trackoff_incr / sblock.fs_nsect) % sblock.fs_nrpos;
2695 trackoff_incr = trackoff_incr % sblock.fs_nsect;
2696 }
2697
2698 /*
2699 * Loop through all the blocks, marking them free and
2700 * updating totals kept in the superblock and cg summary.
2701 */
2702 for (d = dupper; d + sblock.fs_frag <= dmax - cbase; ) {
2703 setblock(&sblock, cg_blksfree(&icg), bno);
2704 icg.cg_cs.cs_nbfree++;
2705
2706 cg_blktot(&icg)[cbcylno]++;
2707
2708 if (!spc_flag)
2709 cgblks[rpos]++;
2710 else
2711 cg_blks(&sblock, &icg, cbtocylno(&sblock, d))
2712 [cbtorpos(&sblock, d)]++;
2713
2714 d += sblock.fs_frag;
2715 bno++;
2716
2717 /*
2718 * Increment the sector offset within the cylinder
2719 * for the cbtocylno() macro reimplementation. If
2720 * we're beyond the end of the cylinder, update the
2721 * cylinder number, calculate the offset in the
2722 * new cylinder, and update the cgblks pointer
2723 * to the next rotational position.
2724 */
2725 cbcylno_sect += cbsect_incr;
2726 if (cbcylno_sect >= sblock.fs_spc) {
2727 cbcylno++;
2728 cbcylno_sect -= sblock.fs_spc;
2729 cgblks += sblock.fs_nrpos;
2730 }
2731
2732 /*
2733 * If there aren't alternate sectors, increment the
2734 * rotational position variables for the cbtorpos()
2735 * reimplementation. Note that we potentially
2736 * increment rpos twice. Once by rpos_incr, and one
2737 * more time when we wrap to a new track because
2738 * trackoff >= fs_nsect.
2739 */
2740 if (!spc_flag) {
2741 trackoff += trackoff_incr;
2742 rpos += rpos_incr;
2743 if (trackoff >= sblock.fs_nsect) {
2744 trackoff -= sblock.fs_nsect;
2745 rpos++;
2746 }
2747 if (rpos >= sblock.fs_nrpos)
2748 rpos -= sblock.fs_nrpos;
2749 }
2750 }
2751
2752 if (d < dmax - cbase) {
2753 icg.cg_frsum[dmax - cbase - d]++;
2754 for (; d < dmax - cbase; d++) {
2755 setbit(cg_blksfree(&icg), d);
2756 icg.cg_cs.cs_nffree++;
2757 }
2758 }
2759 sblock.fs_cstotal.cs_ndir += icg.cg_cs.cs_ndir;
2760 sblock.fs_cstotal.cs_nffree += icg.cg_cs.cs_nffree;
2761 sblock.fs_cstotal.cs_nbfree += icg.cg_cs.cs_nbfree;
2762 sblock.fs_cstotal.cs_nifree += icg.cg_cs.cs_nifree;
2763 *cs = icg.cg_cs;
2764 awtfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, cylno)),
2765 sblock.fs_bsize, (char *)&icg, RELEASE);
2766 }
2767
2768 /*
2769 * initialize the file system
2770 */
2771 struct inode node;
2772
2773 #define LOSTDIR
2774 #ifdef LOSTDIR
2775 #define PREDEFDIR 3
2776 #else
2777 #define PREDEFDIR 2
2778 #endif
2779
2780 struct direct root_dir[] = {
2781 { UFSROOTINO, sizeof (struct direct), 1, "." },
2782 { UFSROOTINO, sizeof (struct direct), 2, ".." },
2783 #ifdef LOSTDIR
2784 { LOSTFOUNDINO, sizeof (struct direct), 10, "lost+found" },
2785 #endif
2786 };
2787 #ifdef LOSTDIR
2788 struct direct lost_found_dir[] = {
2789 { LOSTFOUNDINO, sizeof (struct direct), 1, "." },
2790 { UFSROOTINO, sizeof (struct direct), 2, ".." },
2791 { 0, DIRBLKSIZ, 0, 0 },
2792 };
2793 #endif
2794 char buf[MAXBSIZE];
2795
2796 static void
fsinit()2797 fsinit()
2798 {
2799 int i;
2800
2801
2802 /*
2803 * initialize the node
2804 */
2805 node.i_atime = mkfstime;
2806 node.i_mtime = mkfstime;
2807 node.i_ctime = mkfstime;
2808 #ifdef LOSTDIR
2809 /*
2810 * create the lost+found directory
2811 */
2812 (void) makedir(lost_found_dir, 2);
2813 for (i = DIRBLKSIZ; i < sblock.fs_bsize; i += DIRBLKSIZ) {
2814 bcopy(&lost_found_dir[2], &buf[i], DIRSIZ(&lost_found_dir[2]));
2815 }
2816 node.i_number = LOSTFOUNDINO;
2817 node.i_smode = IFDIR | 0700;
2818 node.i_nlink = 2;
2819 node.i_size = sblock.fs_bsize;
2820 node.i_db[0] = alloc((int)node.i_size, node.i_mode);
2821 node.i_blocks = btodb(fragroundup(&sblock, (int)node.i_size));
2822 IRANDOMIZE(&node.i_ic);
2823 wtfs(fsbtodb(&sblock, (uint64_t)node.i_db[0]), (int)node.i_size, buf);
2824 iput(&node);
2825 #endif
2826 /*
2827 * create the root directory
2828 */
2829 node.i_number = UFSROOTINO;
2830 node.i_mode = IFDIR | UMASK;
2831 node.i_nlink = PREDEFDIR;
2832 node.i_size = makedir(root_dir, PREDEFDIR);
2833 node.i_db[0] = alloc(sblock.fs_fsize, node.i_mode);
2834 /* i_size < 2GB because we are initializing the file system */
2835 node.i_blocks = btodb(fragroundup(&sblock, (int)node.i_size));
2836 IRANDOMIZE(&node.i_ic);
2837 wtfs(fsbtodb(&sblock, (uint64_t)node.i_db[0]), sblock.fs_fsize, buf);
2838 iput(&node);
2839 }
2840
2841 /*
2842 * construct a set of directory entries in "buf".
2843 * return size of directory.
2844 */
2845 static int
makedir(struct direct * protodir,int entries)2846 makedir(struct direct *protodir, int entries)
2847 {
2848 char *cp;
2849 int i;
2850 ushort_t spcleft;
2851
2852 spcleft = DIRBLKSIZ;
2853 for (cp = buf, i = 0; i < entries - 1; i++) {
2854 protodir[i].d_reclen = DIRSIZ(&protodir[i]);
2855 bcopy(&protodir[i], cp, protodir[i].d_reclen);
2856 cp += protodir[i].d_reclen;
2857 spcleft -= protodir[i].d_reclen;
2858 }
2859 protodir[i].d_reclen = spcleft;
2860 bcopy(&protodir[i], cp, DIRSIZ(&protodir[i]));
2861 return (DIRBLKSIZ);
2862 }
2863
2864 /*
2865 * allocate a block or frag
2866 */
2867 static daddr32_t
alloc(int size,int mode)2868 alloc(int size, int mode)
2869 {
2870 int i, frag;
2871 daddr32_t d;
2872
2873 rdfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, 0)), sblock.fs_cgsize,
2874 (char *)&acg);
2875 if (acg.cg_magic != CG_MAGIC) {
2876 (void) fprintf(stderr, gettext("cg 0: bad magic number\n"));
2877 lockexit(32);
2878 }
2879 if (acg.cg_cs.cs_nbfree == 0) {
2880 (void) fprintf(stderr,
2881 gettext("first cylinder group ran out of space\n"));
2882 lockexit(32);
2883 }
2884 for (d = 0; d < acg.cg_ndblk; d += sblock.fs_frag)
2885 if (isblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag))
2886 goto goth;
2887 (void) fprintf(stderr,
2888 gettext("internal error: can't find block in cyl 0\n"));
2889 lockexit(32);
2890 goth:
2891 clrblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag);
2892 acg.cg_cs.cs_nbfree--;
2893 sblock.fs_cstotal.cs_nbfree--;
2894 fscs[0].cs_nbfree--;
2895 if (mode & IFDIR) {
2896 acg.cg_cs.cs_ndir++;
2897 sblock.fs_cstotal.cs_ndir++;
2898 fscs[0].cs_ndir++;
2899 }
2900 cg_blktot(&acg)[cbtocylno(&sblock, d)]--;
2901 cg_blks(&sblock, &acg, cbtocylno(&sblock, d))[cbtorpos(&sblock, d)]--;
2902 if (size != sblock.fs_bsize) {
2903 frag = howmany(size, sblock.fs_fsize);
2904 fscs[0].cs_nffree += sblock.fs_frag - frag;
2905 sblock.fs_cstotal.cs_nffree += sblock.fs_frag - frag;
2906 acg.cg_cs.cs_nffree += sblock.fs_frag - frag;
2907 acg.cg_frsum[sblock.fs_frag - frag]++;
2908 for (i = frag; i < sblock.fs_frag; i++)
2909 setbit(cg_blksfree(&acg), d + i);
2910 }
2911 wtfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, 0)), sblock.fs_cgsize,
2912 (char *)&acg);
2913 return (d);
2914 }
2915
2916 /*
2917 * Allocate an inode on the disk
2918 */
2919 static void
iput(struct inode * ip)2920 iput(struct inode *ip)
2921 {
2922 struct dinode buf[MAXINOPB];
2923 diskaddr_t d;
2924
2925 rdfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, 0)), sblock.fs_cgsize,
2926 (char *)&acg);
2927 if (acg.cg_magic != CG_MAGIC) {
2928 (void) fprintf(stderr, gettext("cg 0: bad magic number\n"));
2929 lockexit(32);
2930 }
2931 acg.cg_cs.cs_nifree--;
2932 setbit(cg_inosused(&acg), ip->i_number);
2933 wtfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, 0)), sblock.fs_cgsize,
2934 (char *)&acg);
2935 sblock.fs_cstotal.cs_nifree--;
2936 fscs[0].cs_nifree--;
2937 if ((int)ip->i_number >= sblock.fs_ipg * sblock.fs_ncg) {
2938 (void) fprintf(stderr,
2939 gettext("fsinit: inode value out of range (%d).\n"),
2940 ip->i_number);
2941 lockexit(32);
2942 }
2943 d = fsbtodb(&sblock, (uint64_t)itod(&sblock, (int)ip->i_number));
2944 rdfs(d, sblock.fs_bsize, (char *)buf);
2945 buf[itoo(&sblock, (int)ip->i_number)].di_ic = ip->i_ic;
2946 wtfs(d, sblock.fs_bsize, (char *)buf);
2947 }
2948
2949 /*
2950 * getbuf() -- Get a buffer for use in an AIO operation. Buffer
2951 * is zero'd the first time returned, left with whatever
2952 * was in memory after that. This function actually gets
2953 * enough memory the first time it's called to support
2954 * MAXBUF buffers like a slab allocator. When all the
2955 * buffers are in use, it waits for an aio to complete
2956 * and make a buffer available.
2957 *
2958 * Never returns an error. Either succeeds or exits.
2959 */
2960 static char *
getbuf(bufhdr * bufhead,int size)2961 getbuf(bufhdr *bufhead, int size)
2962 {
2963 bufhdr *pbuf;
2964 bufhdr *prev;
2965 int i;
2966 int buf_size, max_bufs;
2967
2968 /*
2969 * Initialize all the buffers
2970 */
2971 if (bufhead->head == NULL) {
2972 /*
2973 * round up the size of our buffer header to a
2974 * 16 byte boundary so the address we return to
2975 * the caller is "suitably aligned".
2976 */
2977 bufhdrsize = (sizeof (bufhdr) + 15) & ~15;
2978
2979 /*
2980 * Add in our header to the buffer and round it all up to
2981 * a 16 byte boundry so each member of the slab is aligned.
2982 */
2983 buf_size = (size + bufhdrsize + 15) & ~15;
2984
2985 /*
2986 * Limit number of buffers to lesser of MAXBUFMEM's worth
2987 * or MAXBUF, whichever is less.
2988 */
2989 max_bufs = MAXBUFMEM / buf_size;
2990 if (max_bufs > MAXBUF)
2991 max_bufs = MAXBUF;
2992
2993 pbuf = (bufhdr *)calloc(max_bufs, buf_size);
2994 if (pbuf == NULL) {
2995 perror("calloc");
2996 lockexit(32);
2997 }
2998
2999 bufhead->head = bufhead;
3000 prev = bufhead;
3001 for (i = 0; i < max_bufs; i++) {
3002 pbuf->head = bufhead;
3003 prev->next = pbuf;
3004 prev = pbuf;
3005 pbuf = (bufhdr *)((char *)pbuf + buf_size);
3006 }
3007 }
3008
3009 /*
3010 * Get an available buffer, waiting for I/O if necessary
3011 */
3012 wait_for_write(NOBLOCK);
3013 while (bufhead->next == NULL)
3014 wait_for_write(BLOCK);
3015
3016 /*
3017 * Take the buffer off the list
3018 */
3019 pbuf = bufhead->next;
3020 bufhead->next = pbuf->next;
3021 pbuf->next = NULL;
3022
3023 /*
3024 * return the empty buffer space just past the header
3025 */
3026 return ((char *)pbuf + bufhdrsize);
3027 }
3028
3029 /*
3030 * freebuf() -- Free a buffer gotten previously through getbuf.
3031 * Puts the buffer back on the appropriate list for
3032 * later use. Never calls free().
3033 *
3034 * Assumes that SIGINT is blocked.
3035 */
3036 static void
freebuf(char * buf)3037 freebuf(char *buf)
3038 {
3039 bufhdr *pbuf;
3040 bufhdr *bufhead;
3041
3042 /*
3043 * get the header for this buffer
3044 */
3045 pbuf = (bufhdr *)(buf - bufhdrsize);
3046
3047 /*
3048 * Put it back on the list of available buffers
3049 */
3050 bufhead = pbuf->head;
3051 pbuf->next = bufhead->next;
3052 bufhead->next = pbuf;
3053 }
3054
3055 /*
3056 * freetrans() -- Free a transaction gotten previously through getaiop.
3057 * Puts the transaction struct back on the appropriate list for
3058 * later use. Never calls free().
3059 *
3060 * Assumes that SIGINT is blocked.
3061 */
3062 static void
freetrans(aio_trans * transp)3063 freetrans(aio_trans *transp)
3064 {
3065 /*
3066 * free the buffer associated with this AIO if needed
3067 */
3068 if (transp->release == RELEASE)
3069 freebuf(transp->buffer);
3070
3071 /*
3072 * Put transaction on the free list
3073 */
3074 transp->next = results.trans;
3075 results.trans = transp;
3076 }
3077
3078 /*
3079 * wait_for_write() -- Wait for an aio write to complete. Return
3080 * the transaction structure for that write.
3081 *
3082 * Blocks SIGINT if necessary.
3083 */
3084 aio_trans *
wait_for_write(int block)3085 wait_for_write(int block)
3086 {
3087 aio_trans *transp;
3088 aio_result_t *resultp;
3089 static struct timeval zero_wait = { 0, 0 };
3090 sigset_t old_mask;
3091
3092 /*
3093 * If we know there aren't any outstanding transactions, just return
3094 */
3095 if (results.outstanding == 0)
3096 return ((aio_trans *) 0);
3097
3098 block_sigint(&old_mask);
3099
3100 resultp = aiowait(block ? NULL : &zero_wait);
3101 if (resultp == NULL ||
3102 (resultp == (aio_result_t *)-1 && errno == EINVAL)) {
3103 unblock_sigint(&old_mask);
3104 return ((aio_trans *) 0);
3105 }
3106
3107 results.outstanding--;
3108 transp = (aio_trans *)resultp;
3109
3110 if (resultp->aio_return != transp->size) {
3111 if (resultp->aio_return == -1) {
3112 /*
3113 * The aiowrite() may have failed because the
3114 * kernel didn't have enough memory to do the job.
3115 * Flush all pending writes and try a normal
3116 * write(). wtfs_breakup() will call exit if it
3117 * fails, so we don't worry about errors here.
3118 */
3119 flush_writes();
3120 wtfs_breakup(transp->bno, transp->size, transp->buffer);
3121 } else {
3122 (void) fprintf(stderr, gettext(
3123 "short write (%d of %d bytes) on sector %lld\n"),
3124 resultp->aio_return, transp->size,
3125 transp->bno);
3126 /*
3127 * Don't unblock SIGINT, to avoid potential
3128 * looping due to queued interrupts and
3129 * error handling.
3130 */
3131 lockexit(32);
3132 }
3133 }
3134
3135 resultp->aio_return = 0;
3136 freetrans(transp);
3137 unblock_sigint(&old_mask);
3138 return (transp);
3139 }
3140
3141 /*
3142 * flush_writes() -- flush all the outstanding aio writes.
3143 */
3144 static void
flush_writes(void)3145 flush_writes(void)
3146 {
3147 while (wait_for_write(BLOCK))
3148 ;
3149 }
3150
3151 /*
3152 * get_aiop() -- find and return an aio_trans structure on which a new
3153 * aio can be done. Blocks on aiowait() if needed. Reaps
3154 * all outstanding completed aio's.
3155 *
3156 * Assumes that SIGINT is blocked.
3157 */
3158 aio_trans *
get_aiop()3159 get_aiop()
3160 {
3161 int i;
3162 aio_trans *transp;
3163 aio_trans *prev;
3164
3165 /*
3166 * initialize aio stuff
3167 */
3168 if (!aio_inited) {
3169 aio_inited = 1;
3170
3171 results.maxpend = 0;
3172 results.outstanding = 0;
3173 results.max = MAXAIO;
3174
3175 results.trans = (aio_trans *)calloc(results.max,
3176 sizeof (aio_trans));
3177 if (results.trans == NULL) {
3178 perror("calloc");
3179 lockexit(32);
3180 }
3181
3182 /*
3183 * Initialize the linked list of aio transaction
3184 * structures. Note that the final "next" pointer
3185 * will be NULL since we got the buffer from calloc().
3186 */
3187 prev = results.trans;
3188 for (i = 1; i < results.max; i++) {
3189 prev->next = &(results.trans[i]);
3190 prev = prev->next;
3191 }
3192 }
3193
3194 wait_for_write(NOBLOCK);
3195 while (results.trans == NULL)
3196 wait_for_write(BLOCK);
3197 transp = results.trans;
3198 results.trans = results.trans->next;
3199
3200 transp->next = 0;
3201 transp->resultbuf.aio_return = AIO_INPROGRESS;
3202 return (transp);
3203 }
3204
3205 /*
3206 * read a block from the file system
3207 */
3208 static void
rdfs(diskaddr_t bno,int size,char * bf)3209 rdfs(diskaddr_t bno, int size, char *bf)
3210 {
3211 int n, saverr;
3212
3213 /*
3214 * In case we need any data that's pending in an aiowrite(),
3215 * we wait for them all to complete before doing a read.
3216 */
3217 flush_writes();
3218
3219 /*
3220 * Note: the llseek() can succeed, even if the offset is out of range.
3221 * It's not until the file i/o operation (the read()) that one knows
3222 * for sure if the raw device can handle the offset.
3223 */
3224 if (llseek(fsi, (offset_t)bno * sectorsize, 0) < 0) {
3225 saverr = errno;
3226 (void) fprintf(stderr,
3227 gettext("seek error on sector %lld: %s\n"),
3228 bno, strerror(saverr));
3229 lockexit(32);
3230 }
3231 n = read(fsi, bf, size);
3232 if (n != size) {
3233 saverr = errno;
3234 if (n == -1)
3235 (void) fprintf(stderr,
3236 gettext("read error on sector %lld: %s\n"),
3237 bno, strerror(saverr));
3238 else
3239 (void) fprintf(stderr, gettext(
3240 "short read (%d of %d bytes) on sector %lld\n"),
3241 n, size, bno);
3242 lockexit(32);
3243 }
3244 }
3245
3246 /*
3247 * write a block to the file system
3248 */
3249 static void
wtfs(diskaddr_t bno,int size,char * bf)3250 wtfs(diskaddr_t bno, int size, char *bf)
3251 {
3252 int n, saverr;
3253
3254 if (fso == -1)
3255 return;
3256
3257 /*
3258 * Note: the llseek() can succeed, even if the offset is out of range.
3259 * It's not until the file i/o operation (the write()) that one knows
3260 * for sure if the raw device can handle the offset.
3261 */
3262 if (llseek(fso, (offset_t)bno * sectorsize, 0) < 0) {
3263 saverr = errno;
3264 (void) fprintf(stderr,
3265 gettext("seek error on sector %lld: %s\n"),
3266 bno, strerror(saverr));
3267 lockexit(32);
3268 }
3269 if (Nflag)
3270 return;
3271 n = write(fso, bf, size);
3272 if (n != size) {
3273 saverr = errno;
3274 if (n == -1)
3275 (void) fprintf(stderr,
3276 gettext("write error on sector %lld: %s\n"),
3277 bno, strerror(saverr));
3278 else
3279 (void) fprintf(stderr, gettext(
3280 "short write (%d of %d bytes) on sector %lld\n"),
3281 n, size, bno);
3282 lockexit(32);
3283 }
3284 }
3285
3286 /*
3287 * write a block to the file system -- buffered with aio
3288 */
3289 static void
awtfs(diskaddr_t bno,int size,char * bf,int release)3290 awtfs(diskaddr_t bno, int size, char *bf, int release)
3291 {
3292 int n;
3293 aio_trans *transp;
3294 sigset_t old_mask;
3295
3296 if (fso == -1)
3297 return;
3298
3299 /*
3300 * We need to keep things consistent if we get interrupted,
3301 * so defer any expected interrupts for the time being.
3302 */
3303 block_sigint(&old_mask);
3304
3305 if (Nflag) {
3306 if (release == RELEASE)
3307 freebuf(bf);
3308 } else {
3309 transp = get_aiop();
3310 transp->bno = bno;
3311 transp->buffer = bf;
3312 transp->size = size;
3313 transp->release = release;
3314
3315 n = aiowrite(fso, bf, size, (off_t)bno * sectorsize,
3316 SEEK_SET, &transp->resultbuf);
3317
3318 if (n < 0) {
3319 /*
3320 * The aiowrite() may have failed because the
3321 * kernel didn't have enough memory to do the job.
3322 * Flush all pending writes and try a normal
3323 * write(). wtfs_breakup() will call exit if it
3324 * fails, so we don't worry about errors here.
3325 */
3326 flush_writes();
3327 wtfs_breakup(transp->bno, transp->size, transp->buffer);
3328 freetrans(transp);
3329 } else {
3330 /*
3331 * Keep track of our pending writes.
3332 */
3333 results.outstanding++;
3334 if (results.outstanding > results.maxpend)
3335 results.maxpend = results.outstanding;
3336 }
3337 }
3338
3339 unblock_sigint(&old_mask);
3340 }
3341
3342
3343 /*
3344 * write a block to the file system, but break it up into sbsize
3345 * chunks to avoid forcing a large amount of memory to be locked down.
3346 * Only used as a fallback when an aio write has failed.
3347 */
3348 static void
wtfs_breakup(diskaddr_t bno,int size,char * bf)3349 wtfs_breakup(diskaddr_t bno, int size, char *bf)
3350 {
3351 int n, saverr;
3352 int wsize;
3353 int block_incr = sbsize / sectorsize;
3354
3355 if (size < sbsize)
3356 wsize = size;
3357 else
3358 wsize = sbsize;
3359
3360 n = 0;
3361 while (size) {
3362 /*
3363 * Note: the llseek() can succeed, even if the offset is
3364 * out of range. It's not until the file i/o operation
3365 * (the write()) that one knows for sure if the raw device
3366 * can handle the offset.
3367 */
3368 if (llseek(fso, (offset_t)bno * sectorsize, 0) < 0) {
3369 saverr = errno;
3370 (void) fprintf(stderr,
3371 gettext("seek error on sector %lld: %s\n"),
3372 bno, strerror(saverr));
3373 lockexit(32);
3374 }
3375
3376 n = write(fso, bf, wsize);
3377 if (n == -1) {
3378 saverr = errno;
3379 (void) fprintf(stderr,
3380 gettext("write error on sector %lld: %s\n"),
3381 bno, strerror(saverr));
3382 lockexit(32);
3383 }
3384 if (n != wsize) {
3385 saverr = errno;
3386 (void) fprintf(stderr, gettext(
3387 "short write (%d of %d bytes) on sector %lld\n"),
3388 n, size, bno);
3389 lockexit(32);
3390 }
3391
3392 bno += block_incr;
3393 bf += wsize;
3394 size -= wsize;
3395 if (size < wsize)
3396 wsize = size;
3397 }
3398 }
3399
3400
3401 /*
3402 * check if a block is available
3403 */
3404 static int
isblock(struct fs * fs,unsigned char * cp,int h)3405 isblock(struct fs *fs, unsigned char *cp, int h)
3406 {
3407 unsigned char mask;
3408
3409 switch (fs->fs_frag) {
3410 case 8:
3411 return (cp[h] == 0xff);
3412 case 4:
3413 mask = 0x0f << ((h & 0x1) << 2);
3414 return ((cp[h >> 1] & mask) == mask);
3415 case 2:
3416 mask = 0x03 << ((h & 0x3) << 1);
3417 return ((cp[h >> 2] & mask) == mask);
3418 case 1:
3419 mask = 0x01 << (h & 0x7);
3420 return ((cp[h >> 3] & mask) == mask);
3421 default:
3422 (void) fprintf(stderr, "isblock bad fs_frag %d\n", fs->fs_frag);
3423 return (0);
3424 }
3425 }
3426
3427 /*
3428 * take a block out of the map
3429 */
3430 static void
clrblock(struct fs * fs,unsigned char * cp,int h)3431 clrblock(struct fs *fs, unsigned char *cp, int h)
3432 {
3433 switch ((fs)->fs_frag) {
3434 case 8:
3435 cp[h] = 0;
3436 return;
3437 case 4:
3438 cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
3439 return;
3440 case 2:
3441 cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
3442 return;
3443 case 1:
3444 cp[h >> 3] &= ~(0x01 << (h & 0x7));
3445 return;
3446 default:
3447 (void) fprintf(stderr,
3448 gettext("clrblock: bad fs_frag value %d\n"), fs->fs_frag);
3449 return;
3450 }
3451 }
3452
3453 /*
3454 * put a block into the map
3455 */
3456 static void
setblock(struct fs * fs,unsigned char * cp,int h)3457 setblock(struct fs *fs, unsigned char *cp, int h)
3458 {
3459 switch (fs->fs_frag) {
3460 case 8:
3461 cp[h] = 0xff;
3462 return;
3463 case 4:
3464 cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
3465 return;
3466 case 2:
3467 cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
3468 return;
3469 case 1:
3470 cp[h >> 3] |= (0x01 << (h & 0x7));
3471 return;
3472 default:
3473 (void) fprintf(stderr,
3474 gettext("setblock: bad fs_frag value %d\n"), fs->fs_frag);
3475 return;
3476 }
3477 }
3478
3479 static void
usage(void)3480 usage(void)
3481 {
3482 (void) fprintf(stderr,
3483 gettext("ufs usage: mkfs [-F FSType] [-V] [-m] [-o options] "
3484 "special " /* param 0 */
3485 "size(sectors) \\ \n")); /* param 1 */
3486 (void) fprintf(stderr,
3487 "[nsect " /* param 2 */
3488 "ntrack " /* param 3 */
3489 "bsize " /* param 4 */
3490 "fragsize " /* param 5 */
3491 "cpg " /* param 6 */
3492 "free " /* param 7 */
3493 "rps " /* param 8 */
3494 "nbpi " /* param 9 */
3495 "opt " /* param 10 */
3496 "apc " /* param 11 */
3497 "gap " /* param 12 */
3498 "nrpos " /* param 13 */
3499 "maxcontig " /* param 14 */
3500 "mtb]\n"); /* param 15 */
3501 (void) fprintf(stderr,
3502 gettext(" -m : dump fs cmd line used to make this partition\n"
3503 " -V :print this command line and return\n"
3504 " -o :ufs options: :nsect=%d,ntrack=%d,bsize=%d,fragsize=%d\n"
3505 " -o :ufs options: :cgsize=%d,free=%d,rps=%d,nbpi=%d,opt=%c\n"
3506 " -o :ufs options: :apc=%d,gap=%d,nrpos=%d,maxcontig=%d\n"
3507 " -o :ufs options: :mtb=%c,calcsb,calcbinsb\n"
3508 "NOTE that all -o suboptions: must be separated only by commas so as to\n"
3509 "be parsed as a single argument\n"),
3510 nsect, ntrack, bsize, fragsize, cpg, sblock.fs_minfree, rps,
3511 nbpi, opt, apc, (rotdelay == -1) ? 0 : rotdelay,
3512 sblock.fs_nrpos, maxcontig, mtb);
3513 lockexit(32);
3514 }
3515
3516 /*ARGSUSED*/
3517 static void
dump_fscmd(char * fsys,int fsi)3518 dump_fscmd(char *fsys, int fsi)
3519 {
3520 int64_t used, bpcg, inospercg;
3521 int64_t nbpi;
3522 uint64_t nbytes64;
3523
3524 bzero((char *)&sblock, sizeof (sblock));
3525 rdfs((diskaddr_t)SBLOCK, SBSIZE, (char *)&sblock);
3526
3527 /*
3528 * ensure a valid file system and if not, exit with error or else
3529 * we will end up computing block numbers etc and dividing by zero
3530 * which will cause floating point errors in this routine.
3531 */
3532
3533 if ((sblock.fs_magic != FS_MAGIC) &&
3534 (sblock.fs_magic != MTB_UFS_MAGIC)) {
3535 (void) fprintf(stderr, gettext(
3536 "[not currently a valid file system - bad superblock]\n"));
3537 lockexit(32);
3538 }
3539
3540 if (sblock.fs_magic == FS_MAGIC &&
3541 (sblock.fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 &&
3542 sblock.fs_version != UFS_VERSION_MIN)) {
3543 (void) fprintf(stderr, gettext(
3544 "Unknown version of UFS format: %d\n"), sblock.fs_version);
3545 lockexit(32);
3546 }
3547
3548 if (sblock.fs_magic == MTB_UFS_MAGIC &&
3549 (sblock.fs_version > MTB_UFS_VERSION_1 ||
3550 sblock.fs_version < MTB_UFS_VERSION_MIN)) {
3551 (void) fprintf(stderr, gettext(
3552 "Unknown version of UFS format: %d\n"), sblock.fs_version);
3553 lockexit(32);
3554 }
3555
3556 /*
3557 * Compute a reasonable nbpi value.
3558 * The algorithm for "used" is copied from code
3559 * in main() verbatim.
3560 * The nbpi equation is taken from main where the
3561 * fs_ipg value is set for the last time. The INOPB(...) - 1
3562 * is used to account for the roundup.
3563 * The problem is that a range of nbpi values map to
3564 * the same file system layout. So it is not possible
3565 * to calculate the exact value specified when the file
3566 * system was created. So instead we determine the top
3567 * end of the range of values.
3568 */
3569 bpcg = sblock.fs_spc * sectorsize;
3570 inospercg = (int64_t)roundup(bpcg / sizeof (struct dinode),
3571 INOPB(&sblock));
3572 if (inospercg > MAXIpG(&sblock))
3573 inospercg = MAXIpG(&sblock);
3574 used = (int64_t)
3575 (sblock.fs_iblkno + inospercg / INOPF(&sblock)) * NSPF(&sblock);
3576 used *= sectorsize;
3577 nbytes64 = (uint64_t)sblock.fs_cpg * bpcg - used;
3578
3579 /*
3580 * The top end of the range of values for nbpi may not be
3581 * a valid command line value for mkfs. Report the bottom
3582 * end instead.
3583 */
3584 nbpi = (int64_t)(nbytes64 / (sblock.fs_ipg));
3585
3586 (void) fprintf(stdout, gettext("mkfs -F ufs -o "), fsys);
3587 (void) fprintf(stdout, "nsect=%d,ntrack=%d,",
3588 sblock.fs_nsect, sblock.fs_ntrak);
3589 (void) fprintf(stdout, "bsize=%d,fragsize=%d,cgsize=%d,free=%d,",
3590 sblock.fs_bsize, sblock.fs_fsize, sblock.fs_cpg, sblock.fs_minfree);
3591 (void) fprintf(stdout, "rps=%d,nbpi=%lld,opt=%c,apc=%d,gap=%d,",
3592 sblock.fs_rps, nbpi, (sblock.fs_optim == FS_OPTSPACE) ? 's' : 't',
3593 (sblock.fs_ntrak * sblock.fs_nsect) - sblock.fs_spc,
3594 sblock.fs_rotdelay);
3595 (void) fprintf(stdout, "nrpos=%d,maxcontig=%d,mtb=%c ",
3596 sblock.fs_nrpos, sblock.fs_maxcontig,
3597 ((sblock.fs_magic == MTB_UFS_MAGIC) ? 'y' : 'n'));
3598 (void) fprintf(stdout, "%s %lld\n", fsys,
3599 fsbtodb(&sblock, sblock.fs_size));
3600
3601 bzero((char *)&sblock, sizeof (sblock));
3602 }
3603
3604 /* number ************************************************************* */
3605 /* */
3606 /* Convert a numeric string arg to binary */
3607 /* */
3608 /* Args: d_value - default value, if have parse error */
3609 /* param - the name of the argument, for error messages */
3610 /* flags - parser state and what's allowed in the arg */
3611 /* Global arg: string - pointer to command arg */
3612 /* */
3613 /* Valid forms: 123 | 123k | 123*123 | 123x123 */
3614 /* */
3615 /* Return: converted number */
3616 /* */
3617 /* ******************************************************************** */
3618
3619 static uint64_t
number(uint64_t d_value,char * param,int flags)3620 number(uint64_t d_value, char *param, int flags)
3621 {
3622 char *cs;
3623 uint64_t n, t;
3624 uint64_t cut = BIG / 10; /* limit to avoid overflow */
3625 int minus = 0;
3626
3627 cs = string;
3628 if (*cs == '-') {
3629 minus = 1;
3630 cs += 1;
3631 }
3632 if ((*cs < '0') || (*cs > '9')) {
3633 goto bail_out;
3634 }
3635 n = 0;
3636 while ((*cs >= '0') && (*cs <= '9') && (n <= cut)) {
3637 n = n*10 + *cs++ - '0';
3638 }
3639 if (minus)
3640 n = -n;
3641 for (;;) {
3642 switch (*cs++) {
3643 case 'k':
3644 if (flags & ALLOW_END_ONLY)
3645 goto bail_out;
3646 if (n > (BIG / 1024))
3647 goto overflow;
3648 n *= 1024;
3649 continue;
3650
3651 case '*':
3652 case 'x':
3653 if (flags & ALLOW_END_ONLY)
3654 goto bail_out;
3655 string = cs;
3656 t = number(d_value, param, flags);
3657 if (n > (BIG / t))
3658 goto overflow;
3659 n *= t;
3660 cs = string + 1; /* adjust for -- below */
3661
3662 /* recursion has read rest of expression */
3663 /* FALLTHROUGH */
3664
3665 case ',':
3666 case '\0':
3667 cs--;
3668 string = cs;
3669 return (n);
3670
3671 case '%':
3672 if (flags & ALLOW_END_ONLY)
3673 goto bail_out;
3674 if (flags & ALLOW_PERCENT) {
3675 flags &= ~ALLOW_PERCENT;
3676 flags |= ALLOW_END_ONLY;
3677 continue;
3678 }
3679 goto bail_out;
3680
3681 case 'm':
3682 if (flags & ALLOW_END_ONLY)
3683 goto bail_out;
3684 if (flags & ALLOW_MS1) {
3685 flags &= ~ALLOW_MS1;
3686 flags |= ALLOW_MS2;
3687 continue;
3688 }
3689 goto bail_out;
3690
3691 case 's':
3692 if (flags & ALLOW_END_ONLY)
3693 goto bail_out;
3694 if (flags & ALLOW_MS2) {
3695 flags &= ~ALLOW_MS2;
3696 flags |= ALLOW_END_ONLY;
3697 continue;
3698 }
3699 goto bail_out;
3700
3701 case '0': case '1': case '2': case '3': case '4':
3702 case '5': case '6': case '7': case '8': case '9':
3703 overflow:
3704 (void) fprintf(stderr,
3705 gettext("mkfs: value for %s overflowed\n"),
3706 param);
3707 while ((*cs != '\0') && (*cs != ','))
3708 cs++;
3709 string = cs;
3710 return (BIG);
3711
3712 default:
3713 bail_out:
3714 (void) fprintf(stderr, gettext(
3715 "mkfs: bad numeric arg for %s: \"%s\"\n"),
3716 param, string);
3717 while ((*cs != '\0') && (*cs != ','))
3718 cs++;
3719 string = cs;
3720 if (d_value != NO_DEFAULT) {
3721 (void) fprintf(stderr,
3722 gettext("mkfs: %s reset to default %lld\n"),
3723 param, d_value);
3724 return (d_value);
3725 }
3726 lockexit(2);
3727
3728 }
3729 } /* never gets here */
3730 }
3731
3732 /* match ************************************************************** */
3733 /* */
3734 /* Compare two text strings for equality */
3735 /* */
3736 /* Arg: s - pointer to string to match with a command arg */
3737 /* Global arg: string - pointer to command arg */
3738 /* */
3739 /* Return: 1 if match, 0 if no match */
3740 /* If match, also reset `string' to point to the text */
3741 /* that follows the matching text. */
3742 /* */
3743 /* ******************************************************************** */
3744
3745 static int
match(char * s)3746 match(char *s)
3747 {
3748 char *cs;
3749
3750 cs = string;
3751 while (*cs++ == *s) {
3752 if (*s++ == '\0') {
3753 goto true;
3754 }
3755 }
3756 if (*s != '\0') {
3757 return (0);
3758 }
3759
3760 true:
3761 cs--;
3762 string = cs;
3763 return (1);
3764 }
3765
3766 /*
3767 * GROWFS ROUTINES
3768 */
3769
3770 /* ARGSUSED */
3771 void
lockexit(int exitstatus)3772 lockexit(int exitstatus)
3773 {
3774 if (Pflag) {
3775 /* the probe mode neither changes nor locks the filesystem */
3776 exit(exitstatus);
3777 }
3778
3779 /*
3780 * flush the dirty cylinder group
3781 */
3782 if (inlockexit == 0) {
3783 inlockexit = 1;
3784 flcg();
3785 }
3786
3787 if (aio_inited) {
3788 flush_writes();
3789 }
3790
3791 /*
3792 * make sure the file system is unlocked before exiting
3793 */
3794 if ((inlockexit == 1) && (!isbad)) {
3795 inlockexit = 2;
3796 ulockfs();
3797 /*
3798 * if logging was enabled, then re-enable it
3799 */
3800 if (waslog) {
3801 if (rl_log_control(fsys, _FIOLOGENABLE) != RL_SUCCESS) {
3802 (void) fprintf(stderr, gettext(
3803 "failed to re-enable logging\n"));
3804 }
3805 }
3806 } else if (grow) {
3807 if (isbad) {
3808 (void) fprintf(stderr, gettext(
3809 "Filesystem is currently inconsistent. It "
3810 "must be repaired with fsck(8)\nbefore being "
3811 "used. Use the following command to "
3812 "do this:\n\n\tfsck %s\n\n"), fsys);
3813
3814 if (ismounted) {
3815 (void) fprintf(stderr, gettext(
3816 "You will be told that the filesystem "
3817 "is already mounted, and asked if you\n"
3818 "wish to continue. Answer `yes' to "
3819 "this question.\n\n"));
3820 }
3821
3822 (void) fprintf(stderr, gettext(
3823 "One problem should be reported, that the summary "
3824 "information is bad.\nYou will then be asked if it "
3825 "should be salvaged. Answer `yes' to\nthis "
3826 "question.\n\n"));
3827 }
3828
3829 if (ismounted) {
3830 /*
3831 * In theory, there's no way to get here without
3832 * isbad also being set, but be robust in the
3833 * face of future code changes.
3834 */
3835 (void) fprintf(stderr, gettext(
3836 "The filesystem is currently mounted "
3837 "read-only and write-locked. "));
3838 if (isbad) {
3839 (void) fprintf(stderr, gettext(
3840 "After\nrunning fsck, unlock the "
3841 "filesystem and "));
3842 } else {
3843 (void) fprintf(stderr, gettext(
3844 "Unlock the filesystem\nand "));
3845 }
3846
3847 (void) fprintf(stderr, gettext(
3848 "re-enable writing with\nthe following "
3849 "command:\n\n\tlockfs -u %s\n\n"), directory);
3850 }
3851 }
3852
3853 exit(exitstatus);
3854 }
3855
3856 void
randomgeneration()3857 randomgeneration()
3858 {
3859 int i;
3860 struct dinode *dp;
3861
3862 /*
3863 * always perform fsirand(1) function... newfs will notice that
3864 * the inodes have been randomized and will not call fsirand itself
3865 */
3866 for (i = 0, dp = zino; i < sblock.fs_inopb; ++i, ++dp)
3867 IRANDOMIZE(&dp->di_ic);
3868 }
3869
3870 /*
3871 * Check the size of the summary information.
3872 * Fields in sblock are not changed in this function.
3873 *
3874 * For an 8K filesystem block, the maximum number of cylinder groups is 16384.
3875 * MAXCSBUFS {32} * 8K {FS block size}
3876 * divided by (sizeof csum) {16}
3877 *
3878 * Note that MAXCSBUFS is not used in the kernel; as of Solaris 2.6 build 32,
3879 * this is the only place where it's referenced.
3880 */
3881 void
checksummarysize()3882 checksummarysize()
3883 {
3884 diskaddr_t dmax;
3885 diskaddr_t dmin;
3886 int64_t cg0frags;
3887 int64_t cg0blocks;
3888 int64_t maxncg;
3889 int64_t maxfrags;
3890 uint64_t fs_size;
3891 uint64_t maxfs_blocks; /* filesystem blocks for max filesystem size */
3892
3893 /*
3894 * compute the maximum summary info size
3895 */
3896 dmin = cgdmin(&sblock, 0);
3897 dmax = cgbase(&sblock, 0) + sblock.fs_fpg;
3898 fs_size = (grow) ? grow_fs_size : sblock.fs_size;
3899 if (dmax > fs_size)
3900 dmax = fs_size;
3901 cg0frags = dmax - dmin;
3902 cg0blocks = cg0frags / sblock.fs_frag;
3903 cg0frags = cg0blocks * sblock.fs_frag;
3904 maxncg = (longlong_t)cg0blocks *
3905 (longlong_t)(sblock.fs_bsize / sizeof (struct csum));
3906
3907 maxfs_blocks = FS_MAX;
3908
3909 if (maxncg > ((longlong_t)maxfs_blocks / (longlong_t)sblock.fs_fpg) + 1)
3910 maxncg = ((longlong_t)maxfs_blocks /
3911 (longlong_t)sblock.fs_fpg) + 1;
3912
3913 maxfrags = maxncg * (longlong_t)sblock.fs_fpg;
3914
3915 if (maxfrags > maxfs_blocks)
3916 maxfrags = maxfs_blocks;
3917
3918
3919 /*
3920 * remember for later processing in extendsummaryinfo()
3921 */
3922 if (test)
3923 grow_sifrag = dmin + (cg0blocks * sblock.fs_frag);
3924 if (testfrags == 0)
3925 testfrags = cg0frags;
3926 if (testforce)
3927 if (testfrags > cg0frags) {
3928 (void) fprintf(stderr,
3929 gettext("Too many test frags (%lld); "
3930 "try %lld\n"), testfrags, cg0frags);
3931 lockexit(32);
3932 }
3933
3934 /*
3935 * if summary info is too large (too many cg's) tell the user and exit
3936 */
3937 if ((longlong_t)sblock.fs_size > maxfrags) {
3938 (void) fprintf(stderr, gettext(
3939 "Too many cylinder groups with %llu sectors;\n try "
3940 "increasing cgsize, or decreasing fssize to %llu\n"),
3941 fsbtodb(&sblock, (uint64_t)sblock.fs_size),
3942 fsbtodb(&sblock, (uint64_t)maxfrags));
3943 lockexit(32);
3944 }
3945 }
3946
3947 /*
3948 * checksblock() has two uses:
3949 * - One is to sanity test the superblock and is used when newfs(8)
3950 * is invoked with the "-N" option. If any discrepancy was found,
3951 * just return whatever error was found and do not exit.
3952 * - the other use of it is in places where you expect the superblock
3953 * to be sane, and if it isn't, then we exit.
3954 * Which of the above two actions to take is indicated with the second argument.
3955 */
3956
3957 int
checksblock(struct fs sb,int proceed)3958 checksblock(struct fs sb, int proceed)
3959 {
3960 int err = 0;
3961 char *errmsg;
3962
3963 if ((sb.fs_magic != FS_MAGIC) && (sb.fs_magic != MTB_UFS_MAGIC)) {
3964 err = 1;
3965 errmsg = gettext("Bad superblock; magic number wrong\n");
3966 } else if ((sb.fs_magic == FS_MAGIC &&
3967 (sb.fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 &&
3968 sb.fs_version != UFS_VERSION_MIN)) ||
3969 (sb.fs_magic == MTB_UFS_MAGIC &&
3970 (sb.fs_version > MTB_UFS_VERSION_1 ||
3971 sb.fs_version < MTB_UFS_VERSION_MIN))) {
3972 err = 2;
3973 errmsg = gettext("Unrecognized version of UFS\n");
3974 } else if (sb.fs_ncg < 1) {
3975 err = 3;
3976 errmsg = gettext("Bad superblock; ncg out of range\n");
3977 } else if (sb.fs_cpg < 1) {
3978 err = 4;
3979 errmsg = gettext("Bad superblock; cpg out of range\n");
3980 } else if (sb.fs_ncg * sb.fs_cpg < sb.fs_ncyl ||
3981 (sb.fs_ncg - 1) * sb.fs_cpg >= sb.fs_ncyl) {
3982 err = 5;
3983 errmsg = gettext("Bad superblock; ncyl out of range\n");
3984 } else if (sb.fs_sbsize <= 0 || sb.fs_sbsize > sb.fs_bsize) {
3985 err = 6;
3986 errmsg = gettext("Bad superblock; superblock size out of "
3987 "range\n");
3988 }
3989
3990 if (proceed) {
3991 if (err) dprintf(("%s", errmsg));
3992 return (err);
3993 }
3994
3995 if (err) {
3996 fprintf(stderr, "%s", errmsg);
3997 lockexit(32);
3998 }
3999 return (32);
4000 }
4001
4002 /*
4003 * Roll the embedded log, if any, and set up the global variables
4004 * islog and islogok.
4005 */
4006 static void
logsetup(char * devstr)4007 logsetup(char *devstr)
4008 {
4009 void *buf, *ud_buf;
4010 extent_block_t *ebp;
4011 ml_unit_t *ul;
4012 ml_odunit_t *ud;
4013
4014 /*
4015 * Does the superblock indicate that we are supposed to have a log ?
4016 */
4017 if (sblock.fs_logbno == 0) {
4018 /*
4019 * No log present, nothing to do.
4020 */
4021 islog = 0;
4022 islogok = 0;
4023 return;
4024 } else {
4025 /*
4026 * There's a log in a yet unknown state, attempt to roll it.
4027 */
4028 islogok = 0;
4029
4030 /*
4031 * We failed to roll the log, bail out.
4032 */
4033 if (rl_roll_log(devstr) != RL_SUCCESS)
4034 return;
4035
4036 islog = 1;
4037
4038 /* log is not okay; check the fs */
4039 if ((FSOKAY != (sblock.fs_state + sblock.fs_time)) ||
4040 (sblock.fs_clean != FSLOG))
4041 return;
4042
4043 /* get the log allocation block */
4044 buf = (void *)malloc(DEV_BSIZE);
4045 if (buf == (void *) NULL)
4046 return;
4047
4048 ud_buf = (void *)malloc(DEV_BSIZE);
4049 if (ud_buf == (void *) NULL) {
4050 free(buf);
4051 return;
4052 }
4053
4054 rdfs((diskaddr_t)logbtodb(&sblock, sblock.fs_logbno),
4055 DEV_BSIZE, buf);
4056 ebp = (extent_block_t *)buf;
4057
4058 /* log allocation block is not okay; check the fs */
4059 if (ebp->type != LUFS_EXTENTS) {
4060 free(buf);
4061 free(ud_buf);
4062 return;
4063 }
4064
4065 /* get the log state block(s) */
4066 rdfs((diskaddr_t)logbtodb(&sblock, ebp->extents[0].pbno),
4067 DEV_BSIZE, ud_buf);
4068 ud = (ml_odunit_t *)ud_buf;
4069 ul = (ml_unit_t *)malloc(sizeof (*ul));
4070 ul->un_ondisk = *ud;
4071
4072 /* log state is okay */
4073 if ((ul->un_chksum == ul->un_head_ident + ul->un_tail_ident) &&
4074 (ul->un_version == LUFS_VERSION_LATEST) &&
4075 (ul->un_badlog == 0))
4076 islogok = 1;
4077 free(ud_buf);
4078 free(buf);
4079 free(ul);
4080 }
4081 }
4082
4083 void
growinit(char * devstr)4084 growinit(char *devstr)
4085 {
4086 int i;
4087 char buf[DEV_BSIZE];
4088
4089 /*
4090 * Read and verify the superblock
4091 */
4092 rdfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize, (char *)&sblock);
4093 (void) checksblock(sblock, 0);
4094 if (sblock.fs_postblformat != FS_DYNAMICPOSTBLFMT) {
4095 (void) fprintf(stderr,
4096 gettext("old file system format; can't growfs\n"));
4097 lockexit(32);
4098 }
4099
4100 /*
4101 * can't shrink a file system
4102 */
4103 grow_fssize = fsbtodb(&sblock, (uint64_t)sblock.fs_size);
4104 if (fssize_db < grow_fssize) {
4105 (void) fprintf(stderr,
4106 gettext("%lld sectors < current size of %lld sectors\n"),
4107 fssize_db, grow_fssize);
4108 lockexit(32);
4109 }
4110
4111 /*
4112 * can't grow a system to over a terabyte unless it was set up
4113 * as an MTB UFS file system.
4114 */
4115 if (mtb == 'y' && sblock.fs_magic != MTB_UFS_MAGIC) {
4116 if (fssize_db >= SECTORS_PER_TERABYTE) {
4117 (void) fprintf(stderr, gettext(
4118 "File system was not set up with the multi-terabyte format.\n"));
4119 (void) fprintf(stderr, gettext(
4120 "Its size cannot be increased to a terabyte or more.\n"));
4121 } else {
4122 (void) fprintf(stderr, gettext(
4123 "Cannot convert file system to multi-terabyte format.\n"));
4124 }
4125 lockexit(32);
4126 }
4127
4128 logsetup(devstr);
4129
4130 /*
4131 * can't growfs when logging device has errors
4132 */
4133 if ((islog && !islogok) ||
4134 ((FSOKAY == (sblock.fs_state + sblock.fs_time)) &&
4135 (sblock.fs_clean == FSLOG && !islog))) {
4136 (void) fprintf(stderr,
4137 gettext("logging device has errors; can't growfs\n"));
4138 lockexit(32);
4139 }
4140
4141 /*
4142 * disable ufs logging for growing
4143 */
4144 if (islog) {
4145 if (rl_log_control(devstr, _FIOLOGDISABLE) != RL_SUCCESS) {
4146 (void) fprintf(stderr, gettext(
4147 "failed to disable logging\n"));
4148 lockexit(32);
4149 }
4150 islog = 0;
4151 waslog = 1;
4152 }
4153
4154 /*
4155 * if mounted write lock the file system to be grown
4156 */
4157 if (ismounted)
4158 wlockfs();
4159
4160 /*
4161 * refresh dynamic superblock state - disabling logging will have
4162 * changed the amount of free space available in the file system
4163 */
4164 rdfs((diskaddr_t)(SBOFF / sectorsize), sbsize, (char *)&sblock);
4165
4166 /*
4167 * make sure device is big enough
4168 */
4169 rdfs((diskaddr_t)fssize_db - 1, DEV_BSIZE, buf);
4170 wtfs((diskaddr_t)fssize_db - 1, DEV_BSIZE, buf);
4171
4172 /*
4173 * read current summary information
4174 */
4175 grow_fscs = read_summaryinfo(&sblock);
4176
4177 /*
4178 * save some current size related fields from the superblock
4179 * These are used in extendsummaryinfo()
4180 */
4181 grow_fs_size = sblock.fs_size;
4182 grow_fs_ncg = sblock.fs_ncg;
4183 grow_fs_csaddr = (diskaddr_t)sblock.fs_csaddr;
4184 grow_fs_cssize = sblock.fs_cssize;
4185
4186 /*
4187 * save and reset the clean flag
4188 */
4189 if (FSOKAY == (sblock.fs_state + sblock.fs_time))
4190 grow_fs_clean = sblock.fs_clean;
4191 else
4192 grow_fs_clean = FSBAD;
4193 sblock.fs_clean = FSBAD;
4194 sblock.fs_state = FSOKAY - sblock.fs_time;
4195 isbad = 1;
4196 wtfs((diskaddr_t)(SBOFF / sectorsize), sbsize, (char *)&sblock);
4197 }
4198
4199 void
checkdev(char * rdev,char * bdev)4200 checkdev(char *rdev, char *bdev)
4201 {
4202 struct stat64 statarea;
4203
4204 if (stat64(bdev, &statarea) < 0) {
4205 (void) fprintf(stderr, gettext("can't check mount point; "));
4206 (void) fprintf(stderr, gettext("can't stat %s\n"), bdev);
4207 lockexit(32);
4208 }
4209 if ((statarea.st_mode & S_IFMT) != S_IFBLK) {
4210 (void) fprintf(stderr, gettext(
4211 "can't check mount point; %s is not a block device\n"),
4212 bdev);
4213 lockexit(32);
4214 }
4215 if (stat64(rdev, &statarea) < 0) {
4216 (void) fprintf(stderr, gettext("can't stat %s\n"), rdev);
4217 lockexit(32);
4218 }
4219 if ((statarea.st_mode & S_IFMT) != S_IFCHR) {
4220 (void) fprintf(stderr,
4221 gettext("%s is not a character device\n"), rdev);
4222 lockexit(32);
4223 }
4224 }
4225
4226 void
checkmount(struct mnttab * mntp,char * bdevname)4227 checkmount(struct mnttab *mntp, char *bdevname)
4228 {
4229 struct stat64 statdir;
4230 struct stat64 statdev;
4231
4232 if (strcmp(bdevname, mntp->mnt_special) == 0) {
4233 if (stat64(mntp->mnt_mountp, &statdir) == -1) {
4234 (void) fprintf(stderr, gettext("can't stat %s\n"),
4235 mntp->mnt_mountp);
4236 lockexit(32);
4237 }
4238 if (stat64(mntp->mnt_special, &statdev) == -1) {
4239 (void) fprintf(stderr, gettext("can't stat %s\n"),
4240 mntp->mnt_special);
4241 lockexit(32);
4242 }
4243 if (statdir.st_dev != statdev.st_rdev) {
4244 (void) fprintf(stderr, gettext(
4245 "%s is not mounted on %s; mnttab(5) wrong\n"),
4246 mntp->mnt_special, mntp->mnt_mountp);
4247 lockexit(32);
4248 }
4249 ismounted = 1;
4250 if (directory) {
4251 if (strcmp(mntp->mnt_mountp, directory) != 0) {
4252 (void) fprintf(stderr,
4253 gettext("%s is mounted on %s, not %s\n"),
4254 bdevname, mntp->mnt_mountp, directory);
4255 lockexit(32);
4256 }
4257 } else {
4258 if (grow)
4259 (void) fprintf(stderr, gettext(
4260 "%s is mounted on %s; can't growfs\n"),
4261 bdevname, mntp->mnt_mountp);
4262 else
4263 (void) fprintf(stderr,
4264 gettext("%s is mounted, can't mkfs\n"),
4265 bdevname);
4266 lockexit(32);
4267 }
4268 }
4269 }
4270
4271 struct dinode *dibuf = 0;
4272 diskaddr_t difrag = 0;
4273
4274 struct dinode *
gdinode(ino_t ino)4275 gdinode(ino_t ino)
4276 {
4277 /*
4278 * read the block of inodes containing inode number ino
4279 */
4280 if (dibuf == 0)
4281 dibuf = (struct dinode *)malloc((unsigned)sblock.fs_bsize);
4282 if (itod(&sblock, ino) != difrag) {
4283 difrag = itod(&sblock, ino);
4284 rdfs(fsbtodb(&sblock, (uint64_t)difrag), (int)sblock.fs_bsize,
4285 (char *)dibuf);
4286 }
4287 return (dibuf + (ino % INOPB(&sblock)));
4288 }
4289
4290 /*
4291 * structure that manages the frags we need for extended summary info
4292 * These frags can be:
4293 * free
4294 * data block
4295 * alloc block
4296 */
4297 struct csfrag {
4298 struct csfrag *next; /* next entry */
4299 daddr32_t ofrag; /* old frag */
4300 daddr32_t nfrag; /* new frag */
4301 long cylno; /* cylno of nfrag */
4302 long frags; /* number of frags */
4303 long size; /* size in bytes */
4304 ino_t ino; /* inode number */
4305 long fixed; /* Boolean - Already fixed? */
4306 };
4307 struct csfrag *csfrag; /* state unknown */
4308 struct csfrag *csfragino; /* frags belonging to an inode */
4309 struct csfrag *csfragfree; /* frags that are free */
4310
4311 daddr32_t maxcsfrag = 0; /* maximum in range */
4312 daddr32_t mincsfrag = 0x7fffffff; /* minimum in range */
4313
4314 int
csfraginrange(daddr32_t frag)4315 csfraginrange(daddr32_t frag)
4316 {
4317 return ((frag >= mincsfrag) && (frag <= maxcsfrag));
4318 }
4319
4320 struct csfrag *
findcsfrag(daddr32_t frag,struct csfrag ** cfap)4321 findcsfrag(daddr32_t frag, struct csfrag **cfap)
4322 {
4323 struct csfrag *cfp;
4324
4325 if (!csfraginrange(frag))
4326 return (NULL);
4327
4328 for (cfp = *cfap; cfp; cfp = cfp->next)
4329 if (cfp->ofrag == frag)
4330 return (cfp);
4331 return (NULL);
4332 }
4333
4334 void
checkindirect(ino_t ino,daddr32_t * fragsp,daddr32_t frag,int level)4335 checkindirect(ino_t ino, daddr32_t *fragsp, daddr32_t frag, int level)
4336 {
4337 int i;
4338 int ne = sblock.fs_bsize / sizeof (daddr32_t);
4339 daddr32_t fsb[MAXBSIZE / sizeof (daddr32_t)];
4340
4341 if (frag == 0)
4342 return;
4343
4344 rdfs(fsbtodb(&sblock, frag), (int)sblock.fs_bsize,
4345 (char *)fsb);
4346
4347 checkdirect(ino, fragsp, fsb, sblock.fs_bsize / sizeof (daddr32_t));
4348
4349 if (level)
4350 for (i = 0; i < ne && *fragsp; ++i)
4351 checkindirect(ino, fragsp, fsb[i], level-1);
4352 }
4353
4354 void
addcsfrag(ino_t ino,daddr32_t frag,struct csfrag ** cfap)4355 addcsfrag(ino_t ino, daddr32_t frag, struct csfrag **cfap)
4356 {
4357 struct csfrag *cfp, *curr, *prev;
4358
4359 /*
4360 * establish a range for faster checking in csfraginrange()
4361 */
4362 if (frag > maxcsfrag)
4363 maxcsfrag = frag;
4364 if (frag < mincsfrag)
4365 mincsfrag = frag;
4366
4367 /*
4368 * if this frag belongs to an inode and is not the start of a block
4369 * then see if it is part of a frag range for this inode
4370 */
4371 if (ino && (frag % sblock.fs_frag))
4372 for (cfp = *cfap; cfp; cfp = cfp->next) {
4373 if (ino != cfp->ino)
4374 continue;
4375 if (frag != cfp->ofrag + cfp->frags)
4376 continue;
4377 cfp->frags++;
4378 cfp->size += sblock.fs_fsize;
4379 return;
4380 }
4381 /*
4382 * allocate a csfrag entry and insert it in an increasing order into the
4383 * specified list
4384 */
4385 cfp = (struct csfrag *)calloc(1, sizeof (struct csfrag));
4386 cfp->ino = ino;
4387 cfp->ofrag = frag;
4388 cfp->frags = 1;
4389 cfp->size = sblock.fs_fsize;
4390 for (prev = NULL, curr = *cfap; curr != NULL;
4391 prev = curr, curr = curr->next) {
4392 if (frag < curr->ofrag) {
4393 cfp->next = curr;
4394 if (prev)
4395 prev->next = cfp; /* middle element */
4396 else
4397 *cfap = cfp; /* first element */
4398 break;
4399 }
4400 if (curr->next == NULL) {
4401 curr->next = cfp; /* last element */
4402 break;
4403 }
4404 }
4405 if (*cfap == NULL) /* will happen only once */
4406 *cfap = cfp;
4407 }
4408
4409 void
delcsfrag(daddr32_t frag,struct csfrag ** cfap)4410 delcsfrag(daddr32_t frag, struct csfrag **cfap)
4411 {
4412 struct csfrag *cfp;
4413 struct csfrag **cfpp;
4414
4415 /*
4416 * free up entry whose beginning frag matches
4417 */
4418 for (cfpp = cfap; *cfpp; cfpp = &(*cfpp)->next) {
4419 if (frag == (*cfpp)->ofrag) {
4420 cfp = *cfpp;
4421 *cfpp = (*cfpp)->next;
4422 free((char *)cfp);
4423 return;
4424 }
4425 }
4426 }
4427
4428 /*
4429 * See whether any of the direct blocks in the array pointed by "db" and of
4430 * length "ne" are within the range of frags needed to extend the cylinder
4431 * summary. If so, remove those frags from the "as-yet-unclassified" list
4432 * (csfrag) and add them to the "owned-by-inode" list (csfragino).
4433 * For each such frag found, decrement the frag count pointed to by fragsp.
4434 * "ino" is the inode that contains (either directly or indirectly) the frags
4435 * being checked.
4436 */
4437 void
checkdirect(ino_t ino,daddr32_t * fragsp,daddr32_t * db,int ne)4438 checkdirect(ino_t ino, daddr32_t *fragsp, daddr32_t *db, int ne)
4439 {
4440 int i;
4441 int j;
4442 int found;
4443 diskaddr_t frag;
4444
4445 /*
4446 * scan for allocation within the new summary info range
4447 */
4448 for (i = 0; i < ne && *fragsp; ++i) {
4449 if ((frag = *db++) != 0) {
4450 found = 0;
4451 for (j = 0; j < sblock.fs_frag && *fragsp; ++j) {
4452 if (found || (found = csfraginrange(frag))) {
4453 addcsfrag(ino, frag, &csfragino);
4454 delcsfrag(frag, &csfrag);
4455 }
4456 ++frag;
4457 --(*fragsp);
4458 }
4459 }
4460 }
4461 }
4462
4463 void
findcsfragino()4464 findcsfragino()
4465 {
4466 int i;
4467 int j;
4468 daddr32_t frags;
4469 struct dinode *dp;
4470
4471 /*
4472 * scan all old inodes looking for allocations in the new
4473 * summary info range. Move the affected frag from the
4474 * generic csfrag list onto the `owned-by-inode' list csfragino.
4475 */
4476 for (i = UFSROOTINO; i < grow_fs_ncg*sblock.fs_ipg && csfrag; ++i) {
4477 dp = gdinode((ino_t)i);
4478 switch (dp->di_mode & IFMT) {
4479 case IFSHAD :
4480 case IFLNK :
4481 case IFDIR :
4482 case IFREG : break;
4483 default : continue;
4484 }
4485
4486 frags = dbtofsb(&sblock, dp->di_blocks);
4487
4488 checkdirect((ino_t)i, &frags, &dp->di_db[0], NDADDR+NIADDR);
4489 for (j = 0; j < NIADDR && frags; ++j) {
4490 /* Negate the block if its an fallocate'd block */
4491 if (dp->di_ib[j] < 0 && dp->di_ib[j] != UFS_HOLE)
4492 checkindirect((ino_t)i, &frags,
4493 -(dp->di_ib[j]), j);
4494 else
4495 checkindirect((ino_t)i, &frags,
4496 dp->di_ib[j], j);
4497 }
4498 }
4499 }
4500
4501 void
fixindirect(daddr32_t frag,int level)4502 fixindirect(daddr32_t frag, int level)
4503 {
4504 int i;
4505 int ne = sblock.fs_bsize / sizeof (daddr32_t);
4506 daddr32_t fsb[MAXBSIZE / sizeof (daddr32_t)];
4507
4508 if (frag == 0)
4509 return;
4510
4511 rdfs(fsbtodb(&sblock, (uint64_t)frag), (int)sblock.fs_bsize,
4512 (char *)fsb);
4513
4514 fixdirect((caddr_t)fsb, frag, fsb, ne);
4515
4516 if (level)
4517 for (i = 0; i < ne; ++i)
4518 fixindirect(fsb[i], level-1);
4519 }
4520
4521 void
fixdirect(caddr_t bp,daddr32_t frag,daddr32_t * db,int ne)4522 fixdirect(caddr_t bp, daddr32_t frag, daddr32_t *db, int ne)
4523 {
4524 int i;
4525 struct csfrag *cfp;
4526
4527 for (i = 0; i < ne; ++i, ++db) {
4528 if (*db == 0)
4529 continue;
4530 if ((cfp = findcsfrag(*db, &csfragino)) == NULL)
4531 continue;
4532 *db = cfp->nfrag;
4533 cfp->fixed = 1;
4534 wtfs(fsbtodb(&sblock, (uint64_t)frag), (int)sblock.fs_bsize,
4535 bp);
4536 }
4537 }
4538
4539 void
fixcsfragino()4540 fixcsfragino()
4541 {
4542 int i;
4543 struct dinode *dp;
4544 struct csfrag *cfp;
4545
4546 for (cfp = csfragino; cfp; cfp = cfp->next) {
4547 if (cfp->fixed)
4548 continue;
4549 dp = gdinode((ino_t)cfp->ino);
4550 fixdirect((caddr_t)dibuf, difrag, dp->di_db, NDADDR+NIADDR);
4551 for (i = 0; i < NIADDR; ++i)
4552 fixindirect(dp->di_ib[i], i);
4553 }
4554 }
4555
4556 /*
4557 * Read the cylinders summary information specified by settings in the
4558 * passed 'fs' structure into a new allocated array of csum structures.
4559 * The caller is responsible for freeing the returned array.
4560 * Return a pointer to an array of csum structures.
4561 */
4562 static struct csum *
read_summaryinfo(struct fs * fsp)4563 read_summaryinfo(struct fs *fsp)
4564 {
4565 struct csum *csp;
4566 int i;
4567
4568 if ((csp = malloc((size_t)fsp->fs_cssize)) == NULL) {
4569 (void) fprintf(stderr, gettext("cannot create csum list,"
4570 " not enough memory\n"));
4571 exit(32);
4572 }
4573
4574 for (i = 0; i < fsp->fs_cssize; i += fsp->fs_bsize) {
4575 rdfs(fsbtodb(fsp,
4576 (uint64_t)(fsp->fs_csaddr + numfrags(fsp, i))),
4577 (int)(fsp->fs_cssize - i < fsp->fs_bsize ?
4578 fsp->fs_cssize - i : fsp->fs_bsize), ((caddr_t)csp) + i);
4579 }
4580
4581 return (csp);
4582 }
4583
4584 /*
4585 * Check the allocation of fragments that are to be made part of a csum block.
4586 * A fragment is allocated if it is either in the csfragfree list or, it is
4587 * in the csfragino list and has new frags associated with it.
4588 * Return the number of allocated fragments.
4589 */
4590 int64_t
checkfragallocated(daddr32_t frag)4591 checkfragallocated(daddr32_t frag)
4592 {
4593 struct csfrag *cfp;
4594 /*
4595 * Since the lists are sorted we can break the search if the asked
4596 * frag is smaller then the one in the list.
4597 */
4598 for (cfp = csfragfree; cfp != NULL && frag >= cfp->ofrag;
4599 cfp = cfp->next) {
4600 if (frag == cfp->ofrag)
4601 return (1);
4602 }
4603 for (cfp = csfragino; cfp != NULL && frag >= cfp->ofrag;
4604 cfp = cfp->next) {
4605 if (frag == cfp->ofrag && cfp->nfrag != 0)
4606 return (cfp->frags);
4607 }
4608
4609 return (0);
4610 }
4611
4612 /*
4613 * Figure out how much the filesystem can be grown. The limiting factor is
4614 * the available free space needed to extend the cg summary info block.
4615 * The free space is determined in three steps:
4616 * - Try to extend the cg summary block to the required size.
4617 * - Find free blocks in last cg.
4618 * - Find free space in the last already allocated fragment of the summary info
4619 * block, and use it for additional csum structures.
4620 * Return the maximum size of the new filesystem or 0 if it can't be grown.
4621 * Please note that this function leaves the global list pointers csfrag,
4622 * csfragfree, and csfragino initialized, and the caller is responsible for
4623 * freeing the lists.
4624 */
4625 diskaddr_t
probe_summaryinfo()4626 probe_summaryinfo()
4627 {
4628 /* fragments by which the csum block can be extended. */
4629 int64_t growth_csum_frags = 0;
4630 /* fragments by which the filesystem can be extended. */
4631 int64_t growth_fs_frags = 0;
4632 int64_t new_fs_cssize; /* size of csum blk in the new FS */
4633 int64_t new_fs_ncg; /* number of cg in the new FS */
4634 int64_t spare_csum;
4635 daddr32_t oldfrag_daddr;
4636 daddr32_t newfrag_daddr;
4637 daddr32_t daddr;
4638 int i;
4639
4640 /*
4641 * read and verify the superblock
4642 */
4643 rdfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize, (char *)&sblock);
4644 (void) checksblock(sblock, 0);
4645
4646 /*
4647 * check how much we can extend the cg summary info block
4648 */
4649
4650 /*
4651 * read current summary information
4652 */
4653 fscs = read_summaryinfo(&sblock);
4654
4655 /*
4656 * build list of frags needed for cg summary info block extension
4657 */
4658 oldfrag_daddr = howmany(sblock.fs_cssize, sblock.fs_fsize) +
4659 sblock.fs_csaddr;
4660 new_fs_ncg = howmany(dbtofsb(&sblock, fssize_db), sblock.fs_fpg);
4661 new_fs_cssize = fragroundup(&sblock, new_fs_ncg * sizeof (struct csum));
4662 newfrag_daddr = howmany(new_fs_cssize, sblock.fs_fsize) +
4663 sblock.fs_csaddr;
4664 /*
4665 * add all of the frags that are required to grow the cyl summary to the
4666 * csfrag list, which is the generic/unknown list, since at this point
4667 * we don't yet know the state of those frags.
4668 */
4669 for (daddr = oldfrag_daddr; daddr < newfrag_daddr; daddr++)
4670 addcsfrag((ino_t)0, daddr, &csfrag);
4671
4672 /*
4673 * filter free fragments and allocate them. Note that the free frags
4674 * must be allocated first otherwise they could be grabbed by
4675 * alloccsfragino() for data frags.
4676 */
4677 findcsfragfree();
4678 alloccsfragfree();
4679
4680 /*
4681 * filter fragments owned by inodes and allocate them
4682 */
4683 grow_fs_ncg = sblock.fs_ncg; /* findcsfragino() needs this glob. var. */
4684 findcsfragino();
4685 alloccsfragino();
4686
4687 if (notenoughspace()) {
4688 /*
4689 * check how many consecutive fragments could be allocated
4690 * in both lists.
4691 */
4692 int64_t tmp_frags;
4693 for (daddr = oldfrag_daddr; daddr < newfrag_daddr;
4694 daddr += tmp_frags) {
4695 if ((tmp_frags = checkfragallocated(daddr)) > 0)
4696 growth_csum_frags += tmp_frags;
4697 else
4698 break;
4699 }
4700 } else {
4701 /*
4702 * We have all we need for the new desired size,
4703 * so clean up and report back.
4704 */
4705 return (fssize_db);
4706 }
4707
4708 /*
4709 * given the number of fragments by which the csum block can be grown
4710 * compute by how many new fragments the FS can be increased.
4711 * It is the number of csum instances per fragment multiplied by
4712 * `growth_csum_frags' and the number of fragments per cylinder group.
4713 */
4714 growth_fs_frags = howmany(sblock.fs_fsize, sizeof (struct csum)) *
4715 growth_csum_frags * sblock.fs_fpg;
4716
4717 /*
4718 * compute free fragments in the last cylinder group
4719 */
4720 rdcg(sblock.fs_ncg - 1);
4721 growth_fs_frags += sblock.fs_fpg - acg.cg_ndblk;
4722
4723 /*
4724 * compute how many csum instances are unused in the old csum block.
4725 * For each unused csum instance the FS can be grown by one cylinder
4726 * group without extending the csum block.
4727 */
4728 spare_csum = howmany(sblock.fs_cssize, sizeof (struct csum)) -
4729 sblock.fs_ncg;
4730 if (spare_csum > 0)
4731 growth_fs_frags += spare_csum * sblock.fs_fpg;
4732
4733 /*
4734 * recalculate the new filesystem size in sectors, shorten it by
4735 * the requested size `fssize_db' if necessary.
4736 */
4737 if (growth_fs_frags > 0) {
4738 diskaddr_t sect;
4739 sect = (sblock.fs_size + growth_fs_frags) * sblock.fs_nspf;
4740 return ((sect > fssize_db) ? fssize_db : sect);
4741 }
4742
4743 return (0);
4744 }
4745
4746 void
extendsummaryinfo()4747 extendsummaryinfo()
4748 {
4749 int64_t i;
4750 int localtest = test;
4751 int64_t frags;
4752 daddr32_t oldfrag;
4753 daddr32_t newfrag;
4754
4755 /*
4756 * if no-write (-N), don't bother
4757 */
4758 if (Nflag)
4759 return;
4760
4761 again:
4762 flcg();
4763 /*
4764 * summary info did not change size -- do nothing unless in test mode
4765 */
4766 if (grow_fs_cssize == sblock.fs_cssize)
4767 if (!localtest)
4768 return;
4769
4770 /*
4771 * build list of frags needed for additional summary information
4772 */
4773 oldfrag = howmany(grow_fs_cssize, sblock.fs_fsize) + grow_fs_csaddr;
4774 newfrag = howmany(sblock.fs_cssize, sblock.fs_fsize) + grow_fs_csaddr;
4775 /*
4776 * add all of the frags that are required to grow the cyl summary to the
4777 * csfrag list, which is the generic/unknown list, since at this point
4778 * we don't yet know the state of those frags.
4779 */
4780 for (i = oldfrag, frags = 0; i < newfrag; ++i, ++frags)
4781 addcsfrag((ino_t)0, (diskaddr_t)i, &csfrag);
4782 /*
4783 * reduce the number of data blocks in the file system (fs_dsize) by
4784 * the number of frags that need to be added to the cyl summary
4785 */
4786 sblock.fs_dsize -= (newfrag - oldfrag);
4787
4788 /*
4789 * In test mode, we move more data than necessary from
4790 * cylinder group 0. The lookup/allocate/move code can be
4791 * better stressed without having to create HUGE file systems.
4792 */
4793 if (localtest)
4794 for (i = newfrag; i < grow_sifrag; ++i) {
4795 if (frags >= testfrags)
4796 break;
4797 frags++;
4798 addcsfrag((ino_t)0, (diskaddr_t)i, &csfrag);
4799 }
4800
4801 /*
4802 * move frags to free or inode lists, depending on owner
4803 */
4804 findcsfragfree();
4805 findcsfragino();
4806
4807 /*
4808 * if not all frags can be located, file system must be inconsistent
4809 */
4810 if (csfrag) {
4811 isbad = 1; /* should already be set, but make sure */
4812 lockexit(32);
4813 }
4814
4815 /*
4816 * allocate the free frags. Note that the free frags must be allocated
4817 * first otherwise they could be grabbed by alloccsfragino() for data
4818 * frags.
4819 */
4820 alloccsfragfree();
4821 /*
4822 * allocate extra space for inode frags
4823 */
4824 alloccsfragino();
4825
4826 /*
4827 * not enough space
4828 */
4829 if (notenoughspace()) {
4830 unalloccsfragfree();
4831 unalloccsfragino();
4832 if (localtest && !testforce) {
4833 localtest = 0;
4834 goto again;
4835 }
4836 (void) fprintf(stderr, gettext("Not enough free space\n"));
4837 lockexit(NOTENOUGHSPACE);
4838 }
4839
4840 /*
4841 * copy the data from old frags to new frags
4842 */
4843 copycsfragino();
4844
4845 /*
4846 * fix the inodes to point to the new frags
4847 */
4848 fixcsfragino();
4849
4850 /*
4851 * We may have moved more frags than we needed. Free them.
4852 */
4853 rdcg((long)0);
4854 for (i = newfrag; i <= maxcsfrag; ++i)
4855 setbit(cg_blksfree(&acg), i-cgbase(&sblock, 0));
4856 wtcg();
4857
4858 flcg();
4859 }
4860
4861 /*
4862 * Check if all fragments in the `csfragino' list were reallocated.
4863 */
4864 int
notenoughspace()4865 notenoughspace()
4866 {
4867 struct csfrag *cfp;
4868
4869 /*
4870 * If any element in the csfragino array has a "new frag location"
4871 * of 0, the allocfrags() function was unsuccessful in allocating
4872 * space for moving the frag represented by this array element.
4873 */
4874 for (cfp = csfragino; cfp; cfp = cfp->next)
4875 if (cfp->nfrag == 0)
4876 return (1);
4877 return (0);
4878 }
4879
4880 void
unalloccsfragino()4881 unalloccsfragino()
4882 {
4883 struct csfrag *cfp;
4884
4885 while ((cfp = csfragino) != NULL) {
4886 if (cfp->nfrag)
4887 freefrags(cfp->nfrag, cfp->frags, cfp->cylno);
4888 delcsfrag(cfp->ofrag, &csfragino);
4889 }
4890 }
4891
4892 void
unalloccsfragfree()4893 unalloccsfragfree()
4894 {
4895 struct csfrag *cfp;
4896
4897 while ((cfp = csfragfree) != NULL) {
4898 freefrags(cfp->ofrag, cfp->frags, cfp->cylno);
4899 delcsfrag(cfp->ofrag, &csfragfree);
4900 }
4901 }
4902
4903 /*
4904 * For each frag in the "as-yet-unclassified" list (csfrag), see if
4905 * it's free (i.e., its bit is set in the free frag bit map). If so,
4906 * move it from the "as-yet-unclassified" list to the csfragfree list.
4907 */
4908 void
findcsfragfree()4909 findcsfragfree()
4910 {
4911 struct csfrag *cfp;
4912 struct csfrag *cfpnext;
4913
4914 /*
4915 * move free frags onto the free-frag list
4916 */
4917 rdcg((long)0);
4918 for (cfp = csfrag; cfp; cfp = cfpnext) {
4919 cfpnext = cfp->next;
4920 if (isset(cg_blksfree(&acg), cfp->ofrag - cgbase(&sblock, 0))) {
4921 addcsfrag(cfp->ino, cfp->ofrag, &csfragfree);
4922 delcsfrag(cfp->ofrag, &csfrag);
4923 }
4924 }
4925 }
4926
4927 void
copycsfragino()4928 copycsfragino()
4929 {
4930 struct csfrag *cfp;
4931 char buf[MAXBSIZE];
4932
4933 /*
4934 * copy data from old frags to newly allocated frags
4935 */
4936 for (cfp = csfragino; cfp; cfp = cfp->next) {
4937 rdfs(fsbtodb(&sblock, (uint64_t)cfp->ofrag), (int)cfp->size,
4938 buf);
4939 wtfs(fsbtodb(&sblock, (uint64_t)cfp->nfrag), (int)cfp->size,
4940 buf);
4941 }
4942 }
4943
4944 long curcylno = -1;
4945 int cylnodirty = 0;
4946
4947 void
rdcg(long cylno)4948 rdcg(long cylno)
4949 {
4950 if (cylno != curcylno) {
4951 flcg();
4952 curcylno = cylno;
4953 rdfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, curcylno)),
4954 (int)sblock.fs_cgsize, (char *)&acg);
4955 }
4956 }
4957
4958 void
flcg()4959 flcg()
4960 {
4961 if (cylnodirty) {
4962 if (debug && Pflag) {
4963 (void) fprintf(stderr,
4964 "Assert: cylnodirty set in probe mode\n");
4965 return;
4966 }
4967 resetallocinfo();
4968 wtfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, curcylno)),
4969 (int)sblock.fs_cgsize, (char *)&acg);
4970 cylnodirty = 0;
4971 }
4972 curcylno = -1;
4973 }
4974
4975 void
wtcg()4976 wtcg()
4977 {
4978 if (!Pflag) {
4979 /* probe mode should never write to disk */
4980 cylnodirty = 1;
4981 }
4982 }
4983
4984 void
allocfrags(long frags,daddr32_t * fragp,long * cylnop)4985 allocfrags(long frags, daddr32_t *fragp, long *cylnop)
4986 {
4987 int i;
4988 int j;
4989 long bits;
4990 long bit;
4991
4992 /*
4993 * Allocate a free-frag range in an old cylinder group
4994 */
4995 for (i = 0, *fragp = 0; i < grow_fs_ncg; ++i) {
4996 if (((fscs+i)->cs_nffree < frags) && ((fscs+i)->cs_nbfree == 0))
4997 continue;
4998 rdcg((long)i);
4999 bit = bits = 0;
5000 while (findfreerange(&bit, &bits)) {
5001 if (frags <= bits) {
5002 for (j = 0; j < frags; ++j)
5003 clrbit(cg_blksfree(&acg), bit+j);
5004 wtcg();
5005 *cylnop = i;
5006 *fragp = bit + cgbase(&sblock, i);
5007 return;
5008 }
5009 bit += bits;
5010 }
5011 }
5012 }
5013
5014 /*
5015 * Allocate space for frags that need to be moved in order to free up space for
5016 * expanding the cylinder summary info.
5017 * For each frag that needs to be moved (each frag or range of frags in
5018 * the csfragino list), allocate a new location and store the frag number
5019 * of that new location in the nfrag field of the csfrag struct.
5020 * If a new frag can't be allocated for any element in the csfragino list,
5021 * set the new frag number for that element to 0 and return immediately.
5022 * The notenoughspace() function will detect this condition.
5023 */
5024 void
alloccsfragino()5025 alloccsfragino()
5026 {
5027 struct csfrag *cfp;
5028
5029 /*
5030 * allocate space for inode frag ranges
5031 */
5032 for (cfp = csfragino; cfp; cfp = cfp->next) {
5033 allocfrags(cfp->frags, &cfp->nfrag, &cfp->cylno);
5034 if (cfp->nfrag == 0)
5035 break;
5036 }
5037 }
5038
5039 void
alloccsfragfree()5040 alloccsfragfree()
5041 {
5042 struct csfrag *cfp;
5043
5044 /*
5045 * allocate the free frags needed for extended summary info
5046 */
5047 rdcg((long)0);
5048
5049 for (cfp = csfragfree; cfp; cfp = cfp->next)
5050 clrbit(cg_blksfree(&acg), cfp->ofrag - cgbase(&sblock, 0));
5051
5052 wtcg();
5053 }
5054
5055 void
freefrags(daddr32_t frag,long frags,long cylno)5056 freefrags(daddr32_t frag, long frags, long cylno)
5057 {
5058 int i;
5059
5060 /*
5061 * free frags
5062 */
5063 rdcg(cylno);
5064 for (i = 0; i < frags; ++i) {
5065 setbit(cg_blksfree(&acg), (frag+i) - cgbase(&sblock, cylno));
5066 }
5067 wtcg();
5068 }
5069
5070 int
findfreerange(long * bitp,long * bitsp)5071 findfreerange(long *bitp, long *bitsp)
5072 {
5073 long bit;
5074
5075 /*
5076 * find a range of free bits in a cylinder group bit map
5077 */
5078 for (bit = *bitp, *bitsp = 0; bit < acg.cg_ndblk; ++bit)
5079 if (isset(cg_blksfree(&acg), bit))
5080 break;
5081
5082 if (bit >= acg.cg_ndblk)
5083 return (0);
5084
5085 *bitp = bit;
5086 *bitsp = 1;
5087 for (++bit; bit < acg.cg_ndblk; ++bit, ++(*bitsp)) {
5088 if ((bit % sblock.fs_frag) == 0)
5089 break;
5090 if (isclr(cg_blksfree(&acg), bit))
5091 break;
5092 }
5093 return (1);
5094 }
5095
5096 void
resetallocinfo()5097 resetallocinfo()
5098 {
5099 long cno;
5100 long bit;
5101 long bits;
5102
5103 /*
5104 * Compute the free blocks/frags info and update the appropriate
5105 * inmemory superblock, summary info, and cylinder group fields
5106 */
5107 sblock.fs_cstotal.cs_nffree -= acg.cg_cs.cs_nffree;
5108 sblock.fs_cstotal.cs_nbfree -= acg.cg_cs.cs_nbfree;
5109
5110 acg.cg_cs.cs_nffree = 0;
5111 acg.cg_cs.cs_nbfree = 0;
5112
5113 bzero((caddr_t)acg.cg_frsum, sizeof (acg.cg_frsum));
5114 bzero((caddr_t)cg_blktot(&acg), (int)(acg.cg_iusedoff-acg.cg_btotoff));
5115
5116 bit = bits = 0;
5117 while (findfreerange(&bit, &bits)) {
5118 if (bits == sblock.fs_frag) {
5119 acg.cg_cs.cs_nbfree++;
5120 cno = cbtocylno(&sblock, bit);
5121 cg_blktot(&acg)[cno]++;
5122 cg_blks(&sblock, &acg, cno)[cbtorpos(&sblock, bit)]++;
5123 } else {
5124 acg.cg_cs.cs_nffree += bits;
5125 acg.cg_frsum[bits]++;
5126 }
5127 bit += bits;
5128 }
5129
5130 *(fscs + acg.cg_cgx) = acg.cg_cs;
5131
5132 sblock.fs_cstotal.cs_nffree += acg.cg_cs.cs_nffree;
5133 sblock.fs_cstotal.cs_nbfree += acg.cg_cs.cs_nbfree;
5134 }
5135
5136 void
extendcg(long cylno)5137 extendcg(long cylno)
5138 {
5139 int i;
5140 diskaddr_t dupper;
5141 diskaddr_t cbase;
5142 diskaddr_t dmax;
5143
5144 /*
5145 * extend the cylinder group at the end of the old file system
5146 * if it was partially allocated becase of lack of space
5147 */
5148 flcg();
5149 rdcg(cylno);
5150
5151 dupper = acg.cg_ndblk;
5152 if (cylno == sblock.fs_ncg - 1)
5153 acg.cg_ncyl = sblock.fs_ncyl - (sblock.fs_cpg * cylno);
5154 else
5155 acg.cg_ncyl = sblock.fs_cpg;
5156 cbase = cgbase(&sblock, cylno);
5157 dmax = cbase + sblock.fs_fpg;
5158 if (dmax > sblock.fs_size)
5159 dmax = sblock.fs_size;
5160 acg.cg_ndblk = dmax - cbase;
5161
5162 for (i = dupper; i < acg.cg_ndblk; ++i)
5163 setbit(cg_blksfree(&acg), i);
5164
5165 sblock.fs_dsize += (acg.cg_ndblk - dupper);
5166
5167 wtcg();
5168 flcg();
5169 }
5170
5171 struct lockfs lockfs;
5172 int lockfd;
5173 int islocked;
5174 int lockfskey;
5175 char lockfscomment[128];
5176
5177 void
ulockfs()5178 ulockfs()
5179 {
5180 /*
5181 * if the file system was locked, unlock it before exiting
5182 */
5183 if (islocked == 0)
5184 return;
5185
5186 /*
5187 * first, check if the lock held
5188 */
5189 lockfs.lf_flags = LOCKFS_MOD;
5190 if (ioctl(lockfd, _FIOLFSS, &lockfs) == -1) {
5191 perror(directory);
5192 lockexit(32);
5193 }
5194
5195 if (LOCKFS_IS_MOD(&lockfs)) {
5196 (void) fprintf(stderr,
5197 gettext("FILE SYSTEM CHANGED DURING GROWFS!\n"));
5198 (void) fprintf(stderr,
5199 gettext(" See lockfs(1), umount(1), and fsck(1)\n"));
5200 lockexit(32);
5201 }
5202 /*
5203 * unlock the file system
5204 */
5205 lockfs.lf_lock = LOCKFS_ULOCK;
5206 lockfs.lf_flags = 0;
5207 lockfs.lf_key = lockfskey;
5208 clockfs();
5209 if (ioctl(lockfd, _FIOLFS, &lockfs) == -1) {
5210 perror(directory);
5211 lockexit(32);
5212 }
5213 }
5214
5215 void
wlockfs()5216 wlockfs()
5217 {
5218
5219 /*
5220 * if no-write (-N), don't bother
5221 */
5222 if (Nflag)
5223 return;
5224 /*
5225 * open the mountpoint, and write lock the file system
5226 */
5227 if ((lockfd = open64(directory, O_RDONLY)) == -1) {
5228 perror(directory);
5229 lockexit(32);
5230 }
5231
5232 /*
5233 * check if it is already locked
5234 */
5235 if (ioctl(lockfd, _FIOLFSS, &lockfs) == -1) {
5236 perror(directory);
5237 lockexit(32);
5238 }
5239
5240 if (lockfs.lf_lock != LOCKFS_WLOCK) {
5241 lockfs.lf_lock = LOCKFS_WLOCK;
5242 lockfs.lf_flags = 0;
5243 lockfs.lf_key = 0;
5244 clockfs();
5245 if (ioctl(lockfd, _FIOLFS, &lockfs) == -1) {
5246 perror(directory);
5247 lockexit(32);
5248 }
5249 }
5250 islocked = 1;
5251 lockfskey = lockfs.lf_key;
5252 }
5253
5254 void
clockfs()5255 clockfs()
5256 {
5257 time_t t;
5258 char *ct;
5259
5260 (void) time(&t);
5261 ct = ctime(&t);
5262 ct[strlen(ct)-1] = '\0';
5263
5264 (void) sprintf(lockfscomment, "%s -- mkfs pid %d", ct, getpid());
5265 lockfs.lf_comlen = strlen(lockfscomment)+1;
5266 lockfs.lf_comment = lockfscomment;
5267 }
5268
5269 /*
5270 * Write the csum records and the superblock
5271 */
5272 void
wtsb()5273 wtsb()
5274 {
5275 long i;
5276
5277 /*
5278 * write summary information
5279 */
5280 for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize)
5281 wtfs(fsbtodb(&sblock, (uint64_t)(sblock.fs_csaddr +
5282 numfrags(&sblock, i))),
5283 (int)(sblock.fs_cssize - i < sblock.fs_bsize ?
5284 sblock.fs_cssize - i : sblock.fs_bsize),
5285 ((char *)fscs) + i);
5286
5287 /*
5288 * write superblock
5289 */
5290 sblock.fs_time = mkfstime;
5291 wtfs((diskaddr_t)(SBOFF / sectorsize), sbsize, (char *)&sblock);
5292 }
5293
5294 /*
5295 * Verify that the optimization selection is reasonable, and advance
5296 * the global "string" appropriately.
5297 */
5298 static char
checkopt(char * optim)5299 checkopt(char *optim)
5300 {
5301 char opt;
5302 int limit = strcspn(optim, ",");
5303
5304 switch (limit) {
5305 case 0: /* missing indicator (have comma or nul) */
5306 (void) fprintf(stderr, gettext(
5307 "mkfs: missing optimization flag reset to `t' (time)\n"));
5308 opt = 't';
5309 break;
5310
5311 case 1: /* single-character indicator */
5312 opt = *optim;
5313 if ((opt != 's') && (opt != 't')) {
5314 (void) fprintf(stderr, gettext(
5315 "mkfs: bad optimization value `%c' reset to `t' (time)\n"),
5316 opt);
5317 opt = 't';
5318 }
5319 break;
5320
5321 default: /* multi-character indicator */
5322 (void) fprintf(stderr, gettext(
5323 "mkfs: bad optimization value `%*.*s' reset to `t' (time)\n"),
5324 limit, limit, optim);
5325 opt = 't';
5326 break;
5327 }
5328
5329 string += limit;
5330
5331 return (opt);
5332 }
5333
5334 /*
5335 * Verify that the mtb selection is reasonable, and advance
5336 * the global "string" appropriately.
5337 */
5338 static char
checkmtb(char * mtbarg)5339 checkmtb(char *mtbarg)
5340 {
5341 char mtbc;
5342 int limit = strcspn(mtbarg, ",");
5343
5344 switch (limit) {
5345 case 0: /* missing indicator (have comma or nul) */
5346 (void) fprintf(stderr, gettext(
5347 "mkfs: missing mtb flag reset to `n' (no mtb support)\n"));
5348 mtbc = 'n';
5349 break;
5350
5351 case 1: /* single-character indicator */
5352 mtbc = tolower(*mtbarg);
5353 if ((mtbc != 'y') && (mtbc != 'n')) {
5354 (void) fprintf(stderr, gettext(
5355 "mkfs: bad mtb value `%c' reset to `n' (no mtb support)\n"),
5356 mtbc);
5357 mtbc = 'n';
5358 }
5359 break;
5360
5361 default: /* multi-character indicator */
5362 (void) fprintf(stderr, gettext(
5363 "mkfs: bad mtb value `%*.*s' reset to `n' (no mtb support)\n"),
5364 limit, limit, mtbarg);
5365 opt = 'n';
5366 break;
5367 }
5368
5369 string += limit;
5370
5371 return (mtbc);
5372 }
5373
5374 /*
5375 * Verify that a value is in a range. If it is not, resets it to
5376 * its default value if one is supplied, exits otherwise.
5377 *
5378 * When testing, can compare user_supplied to RC_KEYWORD or RC_POSITIONAL.
5379 */
5380 static void
range_check(long * varp,char * name,long minimum,long maximum,long def_val,int user_supplied)5381 range_check(long *varp, char *name, long minimum, long maximum,
5382 long def_val, int user_supplied)
5383 {
5384 dprintf(("DeBuG %s : %ld (%ld %ld %ld)\n",
5385 name, *varp, minimum, maximum, def_val));
5386
5387 if ((*varp < minimum) || (*varp > maximum)) {
5388 if (user_supplied != RC_DEFAULT) {
5389 (void) fprintf(stderr, gettext(
5390 "mkfs: bad value for %s: %ld must be between %ld and %ld\n"),
5391 name, *varp, minimum, maximum);
5392 }
5393 if (def_val != NO_DEFAULT) {
5394 if (user_supplied) {
5395 (void) fprintf(stderr,
5396 gettext("mkfs: %s reset to default %ld\n"),
5397 name, def_val);
5398 }
5399 *varp = def_val;
5400 dprintf(("DeBuG %s : %ld\n", name, *varp));
5401 return;
5402 }
5403 lockexit(2);
5404 /*NOTREACHED*/
5405 }
5406 }
5407
5408 /*
5409 * Verify that a value is in a range. If it is not, resets it to
5410 * its default value if one is supplied, exits otherwise.
5411 *
5412 * When testing, can compare user_supplied to RC_KEYWORD or RC_POSITIONAL.
5413 */
5414 static void
range_check_64(uint64_t * varp,char * name,uint64_t minimum,uint64_t maximum,uint64_t def_val,int user_supplied)5415 range_check_64(uint64_t *varp, char *name, uint64_t minimum, uint64_t maximum,
5416 uint64_t def_val, int user_supplied)
5417 {
5418 if ((*varp < minimum) || (*varp > maximum)) {
5419 if (user_supplied != RC_DEFAULT) {
5420 (void) fprintf(stderr, gettext(
5421 "mkfs: bad value for %s: %lld must be between %lld and %lld\n"),
5422 name, *varp, minimum, maximum);
5423 }
5424 if (def_val != NO_DEFAULT) {
5425 if (user_supplied) {
5426 (void) fprintf(stderr,
5427 gettext("mkfs: %s reset to default %lld\n"),
5428 name, def_val);
5429 }
5430 *varp = def_val;
5431 return;
5432 }
5433 lockexit(2);
5434 /*NOTREACHED*/
5435 }
5436 }
5437
5438 /*
5439 * Blocks SIGINT from delivery. Returns the previous mask in the
5440 * buffer provided, so that mask may be later restored.
5441 */
5442 static void
block_sigint(sigset_t * old_mask)5443 block_sigint(sigset_t *old_mask)
5444 {
5445 sigset_t block_mask;
5446
5447 if (sigemptyset(&block_mask) < 0) {
5448 fprintf(stderr, gettext("Could not clear signal mask\n"));
5449 lockexit(3);
5450 }
5451 if (sigaddset(&block_mask, SIGINT) < 0) {
5452 fprintf(stderr, gettext("Could not set signal mask\n"));
5453 lockexit(3);
5454 }
5455 if (sigprocmask(SIG_BLOCK, &block_mask, old_mask) < 0) {
5456 fprintf(stderr, gettext("Could not block SIGINT\n"));
5457 lockexit(3);
5458 }
5459 }
5460
5461 /*
5462 * Restores the signal mask that was in force before a call
5463 * to block_sigint(). This may actually still have SIGINT blocked,
5464 * if we've been recursively invoked.
5465 */
5466 static void
unblock_sigint(sigset_t * old_mask)5467 unblock_sigint(sigset_t *old_mask)
5468 {
5469 if (sigprocmask(SIG_UNBLOCK, old_mask, (sigset_t *)NULL) < 0) {
5470 fprintf(stderr, gettext("Could not restore signal mask\n"));
5471 lockexit(3);
5472 }
5473 }
5474
5475 /*
5476 * Attempt to be somewhat graceful about being interrupted, rather than
5477 * just silently leaving the filesystem in an unusable state.
5478 *
5479 * The kernel has blocked SIGINT upon entry, so we don't have to worry
5480 * about recursion if the user starts pounding on the keyboard.
5481 */
5482 static void
recover_from_sigint(int signum)5483 recover_from_sigint(int signum)
5484 {
5485 if (fso > -1) {
5486 if ((Nflag != 0) || confirm_abort()) {
5487 lockexit(4);
5488 }
5489 }
5490 }
5491
5492 static int
confirm_abort(void)5493 confirm_abort(void)
5494 {
5495 char line[80];
5496
5497 printf(gettext("\n\nAborting at this point will leave the filesystem "
5498 "in an inconsistent\nstate. If you do choose to stop, "
5499 "you will be given instructions on how to\nrecover "
5500 "the filesystem. Do you wish to cancel the filesystem "
5501 "grow\noperation (y/n)?"));
5502 if (getaline(stdin, line, sizeof (line)) == EOF)
5503 line[0] = 'y';
5504
5505 printf("\n");
5506 if (line[0] == 'y' || line[0] == 'Y')
5507 return (1);
5508 else {
5509 return (0);
5510 }
5511 }
5512
5513 static int
getaline(FILE * fp,char * loc,int maxlen)5514 getaline(FILE *fp, char *loc, int maxlen)
5515 {
5516 int n;
5517 char *p, *lastloc;
5518
5519 p = loc;
5520 lastloc = &p[maxlen-1];
5521 while ((n = getc(fp)) != '\n') {
5522 if (n == EOF)
5523 return (EOF);
5524 if (!isspace(n) && p < lastloc)
5525 *p++ = n;
5526 }
5527 *p = 0;
5528 return (p - loc);
5529 }
5530
5531 /*
5532 * Calculate the maximum value of cylinders-per-group for a file
5533 * system with the characteristics:
5534 *
5535 * bsize - file system block size
5536 * fragsize - frag size
5537 * nbpi - number of bytes of disk space per inode
5538 * nrpos - number of rotational positions
5539 * spc - sectors per cylinder
5540 *
5541 * These five characteristic are not adjustable (by this function).
5542 * The only attribute of the file system which IS adjusted by this
5543 * function in order to maximize cylinders-per-group is the proportion
5544 * of the cylinder group overhead block used for the inode map. The
5545 * inode map cannot occupy more than one-third of the cylinder group
5546 * overhead block, but it's OK for it to occupy less than one-third
5547 * of the overhead block.
5548 *
5549 * The setting of nbpi determines one possible value for the maximum
5550 * size of a cylinder group. It does so because it determines the total
5551 * number of inodes in the file system (file system size is fixed, and
5552 * nbpi is fixed, so the total number of inodes is fixed too). The
5553 * cylinder group has to be small enough so that the number of inodes
5554 * in the cylinder group is less than or equal to the number of bits
5555 * in one-third (or whatever proportion is assumed) of a file system
5556 * block. The details of the calculation are:
5557 *
5558 * The macro MAXIpG_B(bsize, inode_divisor) determines the maximum
5559 * number of inodes that can be in a cylinder group, given the
5560 * proportion of the cylinder group overhead block used for the
5561 * inode bitmaps (an inode_divisor of 3 means that 1/3 of the
5562 * block is used for inode bitmaps; an inode_divisor of 12 means
5563 * that 1/12 of the block is used for inode bitmaps.)
5564 *
5565 * Once the number of inodes per cylinder group is known, the
5566 * maximum value of cylinders-per-group (determined by nbpi)
5567 * is calculated by the formula
5568 *
5569 * maxcpg_given_nbpi = (size of a cylinder group)/(size of a cylinder)
5570 *
5571 * = (inodes-per-cg * nbpi)/(spc * DEV_BSIZE)
5572 *
5573 * (Interestingly, the size of the file system never enters
5574 * into this calculation.)
5575 *
5576 * Another possible value for the maximum cylinder group size is determined
5577 * by frag_size and nrpos. The frags in the cylinder group must be
5578 * representable in the frag bitmaps in the cylinder overhead block and the
5579 * rotational positions for each cylinder must be represented in the
5580 * rotational position tables. The calculation of the maximum cpg
5581 * value, given the frag and nrpos vales, is:
5582 *
5583 * maxcpg_given_fragsize =
5584 * (available space in the overhead block) / (size of per-cylinder data)
5585 *
5586 * The available space in the overhead block =
5587 * bsize - sizeof (struct cg) - space_used_for_inode_bitmaps
5588 *
5589 * The size of the per-cylinder data is:
5590 * sizeof(long) # for the "blocks avail per cylinder" field
5591 * + nrpos * sizeof(short) # for the rotational position table entry
5592 * + frags-per-cylinder/NBBY # number of bytes to represent this
5593 * # cylinder in the frag bitmap
5594 *
5595 * The two calculated maximum values of cylinder-per-group will typically
5596 * turn out to be different, since they are derived from two different
5597 * constraints. Usually, maxcpg_given_nbpi is much bigger than
5598 * maxcpg_given_fragsize. But they can be brought together by
5599 * adjusting the proportion of the overhead block dedicated to
5600 * the inode bitmaps. Decreasing the proportion of the cylinder
5601 * group overhead block used for inode maps will decrease
5602 * maxcpg_given_nbpi and increase maxcpg_given_fragsize.
5603 *
5604 * This function calculates the initial values of maxcpg_given_nbpi
5605 * and maxcpg_given_fragsize assuming that 1/3 of the cg overhead
5606 * block is used for inode bitmaps. Then it decreases the proportion
5607 * of the cg overhead block used for inode bitmaps (by increasing
5608 * the value of inode_divisor) until maxcpg_given_nbpi and
5609 * maxcpg_given_fragsize are the same, or stop changing, or
5610 * maxcpg_given_nbpi is less than maxcpg_given_fragsize.
5611 *
5612 * The loop terminates when any of the following occur:
5613 * * maxcpg_given_fragsize is greater than or equal to
5614 * maxcpg_given_nbpi
5615 * * neither maxcpg_given_fragsize nor maxcpg_given_nbpi
5616 * change in the expected direction
5617 *
5618 * The loop is guaranteed to terminate because it only continues
5619 * while maxcpg_given_fragsize and maxcpg_given_nbpi are approaching
5620 * each other. As soon they cross each other, or neither one changes
5621 * in the direction of the other, or one of them moves in the wrong
5622 * direction, the loop completes.
5623 */
5624
5625 static long
compute_maxcpg(long bsize,long fragsize,long nbpi,long nrpos,long spc)5626 compute_maxcpg(long bsize, long fragsize, long nbpi, long nrpos, long spc)
5627 {
5628 int maxcpg_given_nbpi; /* in cylinders */
5629 int maxcpg_given_fragsize; /* in cylinders */
5630 int spf; /* sectors per frag */
5631 int inode_divisor;
5632 int old_max_given_frag = 0;
5633 int old_max_given_nbpi = INT_MAX;
5634
5635 spf = fragsize / DEV_BSIZE;
5636 inode_divisor = 3;
5637
5638 while (1) {
5639 maxcpg_given_nbpi =
5640 (((int64_t)(MAXIpG_B(bsize, inode_divisor))) * nbpi) /
5641 (DEV_BSIZE * ((int64_t)spc));
5642 maxcpg_given_fragsize =
5643 (bsize - (sizeof (struct cg)) - (bsize / inode_divisor)) /
5644 (sizeof (long) + nrpos * sizeof (short) +
5645 (spc / spf) / NBBY);
5646
5647 if (maxcpg_given_fragsize >= maxcpg_given_nbpi)
5648 return (maxcpg_given_nbpi);
5649
5650 /*
5651 * If neither value moves toward the other, return the
5652 * least of the old values (we use the old instead of the
5653 * new because: if the old is the same as the new, it
5654 * doesn't matter which ones we use. If one of the
5655 * values changed, but in the wrong direction, the
5656 * new values are suspect. Better use the old. This
5657 * shouldn't happen, but it's best to check.
5658 */
5659
5660 if (!(maxcpg_given_nbpi < old_max_given_nbpi) &&
5661 !(maxcpg_given_fragsize > old_max_given_frag))
5662 return (MIN(old_max_given_nbpi, old_max_given_frag));
5663
5664 /*
5665 * This is probably impossible, but if one of the maxcpg
5666 * values moved in the "right" direction and one moved
5667 * in the "wrong" direction (that is, the two values moved
5668 * in the same direction), the previous conditional won't
5669 * recognize that the values aren't converging (since at
5670 * least one value moved in the "right" direction, the
5671 * last conditional says "keep going").
5672 *
5673 * Just to make absolutely certain that the loop terminates,
5674 * check for one of the values moving in the "wrong" direction
5675 * and terminate the loop if it happens.
5676 */
5677
5678 if (maxcpg_given_nbpi > old_max_given_nbpi ||
5679 maxcpg_given_fragsize < old_max_given_frag)
5680 return (MIN(old_max_given_nbpi, old_max_given_frag));
5681
5682 old_max_given_nbpi = maxcpg_given_nbpi;
5683 old_max_given_frag = maxcpg_given_fragsize;
5684
5685 inode_divisor++;
5686 }
5687 }
5688
5689 static int
in_64bit_mode(void)5690 in_64bit_mode(void)
5691 {
5692 /* cmd must be an absolute path, for security */
5693 char *cmd = "/usr/bin/isainfo -b";
5694 char buf[BUFSIZ];
5695 FILE *ptr;
5696 int retval = 0;
5697
5698 putenv("IFS= \t");
5699 if ((ptr = popen(cmd, "r")) != NULL) {
5700 if (fgets(buf, BUFSIZ, ptr) != NULL &&
5701 strncmp(buf, "64", 2) == 0)
5702 retval = 1;
5703 (void) pclose(ptr);
5704 }
5705 return (retval);
5706 }
5707
5708 /*
5709 * validate_size
5710 *
5711 * Return 1 if the device appears to be at least "size" sectors long.
5712 * Return 0 if it's shorter or we can't read it.
5713 */
5714
5715 static int
validate_size(int fd,diskaddr_t size)5716 validate_size(int fd, diskaddr_t size)
5717 {
5718 char buf[DEV_BSIZE];
5719 int rc;
5720
5721 if ((llseek(fd, (offset_t)((size - 1) * DEV_BSIZE), SEEK_SET) == -1) ||
5722 (read(fd, buf, DEV_BSIZE)) != DEV_BSIZE)
5723 rc = 0;
5724 else
5725 rc = 1;
5726 return (rc);
5727 }
5728
5729 /*
5730 * Print every field of the calculated superblock, along with
5731 * its value. To make parsing easier on the caller, the value
5732 * is printed first, then the name. Additionally, there's only
5733 * one name/value pair per line. All values are reported in
5734 * hexadecimal (with the traditional 0x prefix), as that's slightly
5735 * easier for humans to read. Not that they're expected to, but
5736 * debugging happens.
5737 */
5738 static void
dump_sblock(void)5739 dump_sblock(void)
5740 {
5741 int row, column, pending, written;
5742 caddr_t source;
5743
5744 if (Rflag) {
5745 pending = sizeof (sblock);
5746 source = (caddr_t)&sblock;
5747 do {
5748 written = write(fileno(stdout), source, pending);
5749 pending -= written;
5750 source += written;
5751 } while ((pending > 0) && (written > 0));
5752
5753 if (written < 0) {
5754 perror(gettext("Binary dump of superblock failed"));
5755 lockexit(1);
5756 }
5757 return;
5758 } else {
5759 printf("0x%x sblock.fs_link\n", sblock.fs_link);
5760 printf("0x%x sblock.fs_rolled\n", sblock.fs_rolled);
5761 printf("0x%x sblock.fs_sblkno\n", sblock.fs_sblkno);
5762 printf("0x%x sblock.fs_cblkno\n", sblock.fs_cblkno);
5763 printf("0x%x sblock.fs_iblkno\n", sblock.fs_iblkno);
5764 printf("0x%x sblock.fs_dblkno\n", sblock.fs_dblkno);
5765 printf("0x%x sblock.fs_cgoffset\n", sblock.fs_cgoffset);
5766 printf("0x%x sblock.fs_cgmask\n", sblock.fs_cgmask);
5767 printf("0x%x sblock.fs_time\n", sblock.fs_time);
5768 printf("0x%x sblock.fs_size\n", sblock.fs_size);
5769 printf("0x%x sblock.fs_dsize\n", sblock.fs_dsize);
5770 printf("0x%x sblock.fs_ncg\n", sblock.fs_ncg);
5771 printf("0x%x sblock.fs_bsize\n", sblock.fs_bsize);
5772 printf("0x%x sblock.fs_fsize\n", sblock.fs_fsize);
5773 printf("0x%x sblock.fs_frag\n", sblock.fs_frag);
5774 printf("0x%x sblock.fs_minfree\n", sblock.fs_minfree);
5775 printf("0x%x sblock.fs_rotdelay\n", sblock.fs_rotdelay);
5776 printf("0x%x sblock.fs_rps\n", sblock.fs_rps);
5777 printf("0x%x sblock.fs_bmask\n", sblock.fs_bmask);
5778 printf("0x%x sblock.fs_fmask\n", sblock.fs_fmask);
5779 printf("0x%x sblock.fs_bshift\n", sblock.fs_bshift);
5780 printf("0x%x sblock.fs_fshift\n", sblock.fs_fshift);
5781 printf("0x%x sblock.fs_maxcontig\n", sblock.fs_maxcontig);
5782 printf("0x%x sblock.fs_maxbpg\n", sblock.fs_maxbpg);
5783 printf("0x%x sblock.fs_fragshift\n", sblock.fs_fragshift);
5784 printf("0x%x sblock.fs_fsbtodb\n", sblock.fs_fsbtodb);
5785 printf("0x%x sblock.fs_sbsize\n", sblock.fs_sbsize);
5786 printf("0x%x sblock.fs_csmask\n", sblock.fs_csmask);
5787 printf("0x%x sblock.fs_csshift\n", sblock.fs_csshift);
5788 printf("0x%x sblock.fs_nindir\n", sblock.fs_nindir);
5789 printf("0x%x sblock.fs_inopb\n", sblock.fs_inopb);
5790 printf("0x%x sblock.fs_nspf\n", sblock.fs_nspf);
5791 printf("0x%x sblock.fs_optim\n", sblock.fs_optim);
5792 #ifdef _LITTLE_ENDIAN
5793 printf("0x%x sblock.fs_state\n", sblock.fs_state);
5794 #else
5795 printf("0x%x sblock.fs_npsect\n", sblock.fs_npsect);
5796 #endif
5797 printf("0x%x sblock.fs_si\n", sblock.fs_si);
5798 printf("0x%x sblock.fs_trackskew\n", sblock.fs_trackskew);
5799 printf("0x%x sblock.fs_id[0]\n", sblock.fs_id[0]);
5800 printf("0x%x sblock.fs_id[1]\n", sblock.fs_id[1]);
5801 printf("0x%x sblock.fs_csaddr\n", sblock.fs_csaddr);
5802 printf("0x%x sblock.fs_cssize\n", sblock.fs_cssize);
5803 printf("0x%x sblock.fs_cgsize\n", sblock.fs_cgsize);
5804 printf("0x%x sblock.fs_ntrak\n", sblock.fs_ntrak);
5805 printf("0x%x sblock.fs_nsect\n", sblock.fs_nsect);
5806 printf("0x%x sblock.fs_spc\n", sblock.fs_spc);
5807 printf("0x%x sblock.fs_ncyl\n", sblock.fs_ncyl);
5808 printf("0x%x sblock.fs_cpg\n", sblock.fs_cpg);
5809 printf("0x%x sblock.fs_ipg\n", sblock.fs_ipg);
5810 printf("0x%x sblock.fs_fpg\n", sblock.fs_fpg);
5811 printf("0x%x sblock.fs_cstotal\n", sblock.fs_cstotal);
5812 printf("0x%x sblock.fs_fmod\n", sblock.fs_fmod);
5813 printf("0x%x sblock.fs_clean\n", sblock.fs_clean);
5814 printf("0x%x sblock.fs_ronly\n", sblock.fs_ronly);
5815 printf("0x%x sblock.fs_flags\n", sblock.fs_flags);
5816 printf("0x%x sblock.fs_fsmnt\n", sblock.fs_fsmnt);
5817 printf("0x%x sblock.fs_cgrotor\n", sblock.fs_cgrotor);
5818 printf("0x%x sblock.fs_u.fs_csp\n", sblock.fs_u.fs_csp);
5819 printf("0x%x sblock.fs_cpc\n", sblock.fs_cpc);
5820
5821 /*
5822 * No macros are defined for the dimensions of the
5823 * opostbl array.
5824 */
5825 for (row = 0; row < 16; row++) {
5826 for (column = 0; column < 8; column++) {
5827 printf("0x%x sblock.fs_opostbl[%d][%d]\n",
5828 sblock.fs_opostbl[row][column],
5829 row, column);
5830 }
5831 }
5832
5833 /*
5834 * Ditto the size of sparecon.
5835 */
5836 for (row = 0; row < 51; row++) {
5837 printf("0x%x sblock.fs_sparecon[%d]\n",
5838 sblock.fs_sparecon[row], row);
5839 }
5840
5841 printf("0x%x sblock.fs_version\n", sblock.fs_version);
5842 printf("0x%x sblock.fs_logbno\n", sblock.fs_logbno);
5843 printf("0x%x sblock.fs_reclaim\n", sblock.fs_reclaim);
5844 printf("0x%x sblock.fs_sparecon2\n", sblock.fs_sparecon2);
5845 #ifdef _LITTLE_ENDIAN
5846 printf("0x%x sblock.fs_npsect\n", sblock.fs_npsect);
5847 #else
5848 printf("0x%x sblock.fs_state\n", sblock.fs_state);
5849 #endif
5850 printf("0x%llx sblock.fs_qbmask\n", sblock.fs_qbmask);
5851 printf("0x%llx sblock.fs_qfmask\n", sblock.fs_qfmask);
5852 printf("0x%x sblock.fs_postblformat\n", sblock.fs_postblformat);
5853 printf("0x%x sblock.fs_nrpos\n", sblock.fs_nrpos);
5854 printf("0x%x sblock.fs_postbloff\n", sblock.fs_postbloff);
5855 printf("0x%x sblock.fs_rotbloff\n", sblock.fs_rotbloff);
5856 printf("0x%x sblock.fs_magic\n", sblock.fs_magic);
5857
5858 /*
5859 * fs_space isn't of much use in this context, so we'll
5860 * just ignore it for now.
5861 */
5862 }
5863 }
5864