X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=misc%2Fmke2fs.c;h=b62252ad19198595555215e473371af33c2da02d;hb=refs%2Fchanges%2F91%2F52091%2F4;hp=800a9688856c0c1cbe0c71de787dcfed8fcf7849;hpb=79ffbf251e9795c685407b0baabe8a1721ec6909;p=tools%2Fe2fsprogs.git diff --git a/misc/mke2fs.c b/misc/mke2fs.c index 800a968..b62252a 100644 --- a/misc/mke2fs.c +++ b/misc/mke2fs.c @@ -16,7 +16,7 @@ * enforced (but it's not much fun on a character device :-). */ -#define _XOPEN_SOURCE 600 /* for inclusion of PATH_MAX */ +#define _XOPEN_SOURCE 600 #include "config.h" #include @@ -24,10 +24,6 @@ #include #include #include -#ifdef __linux__ -#include -#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) -#endif #ifdef HAVE_GETOPT_H #include #else @@ -43,7 +39,9 @@ extern int optind; #ifdef HAVE_ERRNO_H #include #endif +#ifdef HAVE_SYS_IOCTL_H #include +#endif #include #include #include @@ -69,8 +67,6 @@ extern int optind; #define ZAP_BOOTBLOCK #endif -#define DISCARD_STEP_MB (2048) - extern int isatty(int); extern FILE *fpopen(const char *cmd, const char *mode); @@ -91,17 +87,27 @@ static uid_t root_uid; static gid_t root_gid; int journal_size; int journal_flags; +int journal_fc_size; +static e2_blkcnt_t orphan_file_blocks; static int lazy_itable_init; +static int assume_storage_prezeroed; static int packed_meta_blocks; +int no_copy_xattrs; static char *bad_blocks_filename = NULL; static __u32 fs_stride; -static int quotatype = -1; /* Initialize both user and group quotas by default */ +/* Initialize usr/grp quotas by default */ +static unsigned int quotatype_bits = (QUOTA_USR_BIT | QUOTA_GRP_BIT); static __u64 offset; static blk64_t journal_location = ~0LL; static int proceed_delay = -1; static blk64_t dev_size; +blk64_t iops_array[64]; +unsigned int iops_size = sizeof(iops_array); +unsigned int iops_count = 0; +blk64_t *iops_range = iops_array; static struct ext2_super_block fs_param; +static __u32 zero_buf[4]; static char *fs_uuid = NULL; static char *creator_os; static char *volume_label; @@ -109,9 +115,11 @@ static char *mount_dir; char *journal_device; static int sync_kludge; /* Set using the MKE2FS_SYNC env. option */ char **fs_types; -const char *root_dir; /* Copy files from the specified directory */ +const char *src_root_dir; /* Copy files from the specified directory */ static char *undo_file; +static int android_sparse_file; /* -E android_sparse */ + static profile_t profile; static int sys_page_size = 4096; @@ -131,7 +139,7 @@ static void usage(void) "[-r fs-revision] [-E extended-option[,...]]\n" "\t[-t fs-type] [-T usage-type ] [-U UUID] [-e errors_behavior]" "[-z undo_file]\n" - "\t[-jnqvDFKSV] device [blocks-count]\n"), + "\t[-jnqvDFSV] device [blocks-count]\n"), program_name); exit(1); } @@ -157,54 +165,6 @@ int int_log10(unsigned long long arg) return l; } -#ifdef __linux__ -static int parse_version_number(const char *s) -{ - int major, minor, rev; - char *endptr; - const char *cp = s; - - if (!s) - return 0; - major = strtol(cp, &endptr, 10); - if (cp == endptr || *endptr != '.') - return 0; - cp = endptr + 1; - minor = strtol(cp, &endptr, 10); - if (cp == endptr || *endptr != '.') - return 0; - cp = endptr + 1; - rev = strtol(cp, &endptr, 10); - if (cp == endptr) - return 0; - return KERNEL_VERSION(major, minor, rev); -} - -static int is_before_linux_ver(unsigned int major, unsigned int minor, - unsigned int rev) -{ - struct utsname ut; - static int linux_version_code = -1; - - if (uname(&ut)) { - perror("uname"); - exit(1); - } - if (linux_version_code < 0) - linux_version_code = parse_version_number(ut.release); - if (linux_version_code == 0) - return 0; - - return linux_version_code < (int) KERNEL_VERSION(major, minor, rev); -} -#else -static int is_before_linux_ver(unsigned int major, unsigned int minor, - unsigned int rev) -{ - return 0; -} -#endif - /* * Helper function for read_bb_file and test_disk */ @@ -249,7 +209,8 @@ static void test_disk(ext2_filsys fs, badblocks_list *bb_list) sprintf(buf, "badblocks -b %d -X %s%s%s %llu", fs->blocksize, quiet ? "" : "-s ", (cflag > 1) ? "-w " : "", - fs->device_name, ext2fs_blocks_count(fs->super)-1); + fs->device_name, + (unsigned long long) ext2fs_blocks_count(fs->super)-1); if (verbose) printf(_("Running command: %s\n"), buf); f = popen(buf, "r"); @@ -337,7 +298,7 @@ _("Warning: the backup superblock/group descriptors at block %u contain\n" exit(1); } while (ext2fs_badblocks_list_iterate(bb_iter, &blk)) - ext2fs_mark_block_bitmap2(fs->block_map, EXT2FS_B2C(fs, blk)); + ext2fs_mark_block_bitmap2(fs->block_map, blk); ext2fs_badblocks_list_iterate_end(bb_iter); } @@ -353,9 +314,15 @@ static void write_reserved_inodes(ext2_filsys fs) exit(1); } - for (ino = 1; ino < EXT2_FIRST_INO(fs->super); ino++) - ext2fs_write_inode_full(fs, ino, inode, - EXT2_INODE_SIZE(fs->super)); + for (ino = 1; ino < EXT2_FIRST_INO(fs->super); ino++) { + retval = ext2fs_write_inode_full(fs, ino, inode, + EXT2_INODE_SIZE(fs->super)); + if (retval) { + com_err("ext2fs_write_inode_full", retval, + _("while writing reserved inodes")); + exit(1); + } + } ext2fs_free_mem(&inode); } @@ -428,23 +395,23 @@ static void write_inode_tables(ext2_filsys fs, int lazy_flag, int itable_zeroed) if (retval) { fprintf(stderr, _("\nCould not write %d " "blocks in inode table starting at %llu: %s\n"), - num, blk, error_message(retval)); + num, (unsigned long long) blk, + error_message(retval)); exit(1); } } if (sync_kludge) { if (sync_kludge == 1) - sync(); + io_channel_flush(fs->io); else if ((i % sync_kludge) == 0) - sync(); + io_channel_flush(fs->io); } } ext2fs_numeric_progress_close(fs, &progress, _("done \n")); /* Reserved inodes must always have correct checksums */ - if (fs->super->s_creator_os == EXT2_OS_LINUX && - ext2fs_has_feature_metadata_csum(fs->super)) + if (ext2fs_has_feature_metadata_csum(fs->super)) write_reserved_inodes(fs); } @@ -553,7 +520,7 @@ static void zap_sector(ext2_filsys fs, int sect, int nsect) int retval; unsigned int *magic; - buf = malloc(512*nsect); + buf = calloc(512, nsect); if (!buf) { printf(_("Out of memory erasing sectors %d-%d\n"), sect, sect + nsect - 1); @@ -570,8 +537,10 @@ static void zap_sector(ext2_filsys fs, int sect, int nsect) else { magic = (unsigned int *) (buf + BSD_LABEL_OFFSET); if ((*magic == BSD_DISKMAGIC) || - (*magic == BSD_MAGICDISK)) + (*magic == BSD_MAGICDISK)) { + free(buf); return; + } } } @@ -592,9 +561,16 @@ static void create_journal_dev(ext2_filsys fs) char *buf; blk64_t blk, err_blk; int c, count, err_count; + struct ext2fs_journal_params jparams; + + retval = ext2fs_get_journal_params(&jparams, fs); + if (retval) { + com_err("create_journal_dev", retval, "%s", + _("while splitting the journal size")); + exit(1); + } - retval = ext2fs_create_journal_superblock(fs, - ext2fs_blocks_count(fs->super), 0, &buf); + retval = ext2fs_create_journal_superblock2(fs, &jparams, 0, &buf); if (retval) { com_err("create_journal_dev", retval, "%s", _("while initializing journal superblock")); @@ -619,7 +595,7 @@ static void create_journal_dev(ext2_filsys fs) com_err("create_journal_dev", retval, _("while zeroing journal device " "(block %llu, count %d)"), - err_blk, err_count); + (unsigned long long) err_blk, err_count); exit(1); } blk += c; @@ -632,6 +608,7 @@ write_superblock: retval = io_channel_write_blk64(fs->io, fs->super->s_first_data_block+1, 1, buf); + (void) ext2fs_free_mem(&buf); if (retval) { com_err("create_journal_dev", retval, "%s", _("while writing journal superblock")); @@ -642,7 +619,6 @@ write_superblock: static void show_stats(ext2_filsys fs) { struct ext2_super_block *s = fs->super; - char buf[80]; char *os; blk64_t group_block; dgrp_t i; @@ -651,18 +627,18 @@ static void show_stats(ext2_filsys fs) if (!verbose) { printf(_("Creating filesystem with %llu %dk blocks and " "%u inodes\n"), - ext2fs_blocks_count(s), fs->blocksize >> 10, - s->s_inodes_count); + (unsigned long long) ext2fs_blocks_count(s), + fs->blocksize >> 10, s->s_inodes_count); goto skip_details; } if (ext2fs_blocks_count(&fs_param) != ext2fs_blocks_count(s)) fprintf(stderr, _("warning: %llu blocks unused.\n\n"), - ext2fs_blocks_count(&fs_param) - ext2fs_blocks_count(s)); + (unsigned long long) (ext2fs_blocks_count(&fs_param) - + ext2fs_blocks_count(s))); + + printf(_("Filesystem label=%.*s\n"), EXT2_LEN_STR(s->s_volume_name)); - memset(buf, 0, sizeof(buf)); - strncpy(buf, s->s_volume_name, sizeof(s->s_volume_name)); - printf(_("Filesystem label=%s\n"), buf); os = e2p_os2string(fs->super->s_creator_os); if (os) printf(_("OS type: %s\n"), os); @@ -679,9 +655,9 @@ static void show_stats(ext2_filsys fs) printf(_("Stride=%u blocks, Stripe width=%u blocks\n"), s->s_raid_stride, s->s_raid_stripe_width); printf(_("%u inodes, %llu blocks\n"), s->s_inodes_count, - ext2fs_blocks_count(s)); + (unsigned long long) ext2fs_blocks_count(s)); printf(_("%llu blocks (%2.2f%%) reserved for the super user\n"), - ext2fs_r_blocks_count(s), + (unsigned long long) ext2fs_r_blocks_count(s), 100.0 * ext2fs_r_blocks_count(s) / ext2fs_blocks_count(s)); printf(_("First data block=%u\n"), s->s_first_data_block); if (root_uid != 0 || root_gid != 0) @@ -725,7 +701,7 @@ skip_details: col_left = 72; } col_left -= need; - printf("%llu", group_block); + printf("%llu", (unsigned long long) group_block); } printf("\n\n"); } @@ -768,6 +744,54 @@ static int set_os(struct ext2_super_block *sb, char *os) return 1; } +static int parse_range(char *p_start, char *p_end, char *p_hyphen) +{ + blk64_t start, end; + blk64_t *new_array; + + /** + * e.g 0-1024G + * ^ ^ + * | | + * p_start p_end + */ + end = parse_num_blocks(p_hyphen + 1, -1); + + if (!isdigit(*(p_end - 1)) && isdigit(*(p_hyphen -1))) { + /* copy G/M/K unit to start value */ + *p_hyphen = *(p_end - 1); + p_hyphen++; + } + *p_hyphen = 0; + + start = parse_num_blocks(p_start, -1); + + /* add to iops_range */ + if (iops_count == iops_size) { + iops_size <<= 1; + if (iops_size == 0) { + iops_size = iops_count; + return -E2BIG; + } + if (iops_range == iops_array) + new_array = malloc(iops_size * sizeof(blk64_t)); + else + new_array = realloc(iops_range, + iops_size * sizeof(blk64_t)); + if (!new_array) { + iops_size >>= 1; + return -ENOMEM; + } else { + iops_range = new_array; + } + } + + iops_range[iops_count++] = start; + iops_range[iops_count++] = end; + + return 0; +} + #define PATH_SET "PATH=/sbin" static void parse_extended_opts(struct ext2_super_block *param, @@ -776,6 +800,9 @@ static void parse_extended_opts(struct ext2_super_block *param, char *buf, *token, *next, *p, *arg, *badopt = 0; int len; int r_usage = 0; + int ret; + int encoding = -1; + char *encoding_flags = NULL; len = strlen(opts); buf = malloc(len+1); @@ -827,6 +854,19 @@ static void parse_extended_opts(struct ext2_super_block *param, continue; } param->s_desc_size = desc_size; + } else if (strcmp(token, "hash_seed") == 0) { + if (!arg) { + r_usage++; + badopt = token; + continue; + } + if (uuid_parse(arg, + (unsigned char *)param->s_hash_seed) != 0) { + fprintf(stderr, + _("Invalid hash seed: %s\n"), arg); + r_usage++; + continue; + } } else if (strcmp(token, "offset") == 0) { if (!arg) { r_usage++; @@ -854,6 +894,9 @@ static void parse_extended_opts(struct ext2_super_block *param, r_usage++; continue; } + } else if (strcmp(token, "no_copy_xattrs") == 0) { + no_copy_xattrs = 1; + continue; } else if (strcmp(token, "num_backup_sb") == 0) { if (!arg) { r_usage++; @@ -969,6 +1012,11 @@ static void parse_extended_opts(struct ext2_super_block *param, lazy_itable_init = strtoul(arg, &p, 0); else lazy_itable_init = 1; + } else if (!strcmp(token, "assume_storage_prezeroed")) { + if (arg) + assume_storage_prezeroed = strtoul(arg, &p, 0); + else + assume_storage_prezeroed = 1; } else if (!strcmp(token, "lazy_journal_init")) { if (arg) journal_flags |= strtoul(arg, &p, 0) ? @@ -1003,22 +1051,120 @@ static void parse_extended_opts(struct ext2_super_block *param, } else if (!strcmp(token, "nodiscard")) { discard = 0; } else if (!strcmp(token, "quotatype")) { + char *errtok = NULL; + if (!arg) { r_usage++; badopt = token; continue; } - if (!strncmp(arg, "usr", 3)) { - quotatype = 0; - } else if (!strncmp(arg, "grp", 3)) { - quotatype = 1; - } else { + quotatype_bits = 0; + ret = parse_quota_types(arg, "atype_bits, &errtok); + if (ret) { + if (errtok) { + fprintf(stderr, + "Failed to parse quota type at %s", errtok); + free(errtok); + } else + com_err(program_name, ret, + "while parsing quota type"); + r_usage++; + badopt = token; + continue; + } + } else if (!strcmp(token, "android_sparse")) { + android_sparse_file = 1; + } else if (!strcmp(token, "encoding")) { + if (!arg) { + r_usage++; + continue; + } + + encoding = e2p_str2encoding(arg); + if (encoding < 0) { + fprintf(stderr, _("Invalid encoding: %s"), arg); + r_usage++; + continue; + } + param->s_encoding = encoding; + ext2fs_set_feature_casefold(param); + } else if (!strcmp(token, "encoding_flags")) { + if (!arg) { + r_usage++; + continue; + } + encoding_flags = arg; + } else if (!strcmp(token, "orphan_file_size")) { + if (!arg) { + r_usage++; + badopt = token; + continue; + } + orphan_file_blocks = parse_num_blocks2(arg, + fs_param.s_log_block_size); + if (orphan_file_blocks == 0) { fprintf(stderr, - _("Invalid quotatype parameter: %s\n"), + _("Invalid size of orphan file %s\n"), arg); r_usage++; continue; } + } else if (!strcmp(token, "iops")) { + char *p_colon, *p_hyphen; + blk64_t start, end; + + /* example: iops=0-1024G:4096-8192G */ + + if (!arg) { + r_usage++; + badopt = token; + continue; + } + p_colon = strchr(arg, ':'); + while (p_colon != NULL) { + *p_colon = 0; + + p_hyphen = strchr(arg, '-'); + if (p_hyphen == NULL) { + fprintf(stderr, + _("error: parse iops %s\n"), + arg); + r_usage++; + badopt = token; + break; + } + + ret = parse_range(arg, p_colon, p_hyphen); + if (ret < 0) { + fprintf(stderr, + _("error: parse iops %s:%d\n"), + arg, ret); + r_usage++; + badopt = token; + break; + } + + arg = p_colon + 1; + p_colon = strchr(arg, ':'); + } + p_hyphen = strchr(arg, '-'); + if (p_hyphen == NULL) { + fprintf(stderr, + _("error: parse iops %s\n"), arg); + r_usage++; + badopt = token; + continue; + } + + ret = parse_range(arg, arg + strlen(arg), p_hyphen); + if (ret < 0) { + fprintf(stderr, + _("error: parse iops %s:%d\n"), + arg, ret); + r_usage++; + badopt = token; + continue; + } } else { r_usage++; badopt = token; @@ -1039,14 +1185,19 @@ static void parse_extended_opts(struct ext2_super_block *param, "\tpacked_meta_blocks=<0 to disable, 1 to enable>\n" "\tlazy_itable_init=<0 to disable, 1 to enable>\n" "\tlazy_journal_init=<0 to disable, 1 to enable>\n" - "\troot_uid=\n" - "\troot_gid=\n" + "\troot_owner=:\n" "\ttest_fs\n" "\tdiscard\n" "\tnodiscard\n" - "\tquotatype=\n\n"), + "\tencoding=\n" + "\tencoding_flags=\n" + "\tiops=\n" + "\tquotatype=\n" + "\tassume_storage_prezeroed=<0 to disable, 1 to enable>\n\n"), badopt ? badopt : ""); free(buf); + if (iops_range != iops_array) + free(iops_range); exit(1); } if (param->s_raid_stride && @@ -1055,6 +1206,25 @@ static void parse_extended_opts(struct ext2_super_block *param, "multiple of stride %u.\n\n"), param->s_raid_stripe_width, param->s_raid_stride); + if (ext2fs_has_feature_casefold(param)) { + param->s_encoding_flags = + e2p_get_encoding_flags(param->s_encoding); + + if (encoding_flags && + e2p_str2encoding_flags(param->s_encoding, encoding_flags, + ¶m->s_encoding_flags)) { + fprintf(stderr, _("error: Invalid encoding flag: %s\n"), + encoding_flags); + free(buf); + exit(1); + } + } else if (encoding_flags) { + fprintf(stderr, _("error: An encoding must be explicitly " + "specified when passing encoding-flags\n")); + free(buf); + exit(1); + } + free(buf); } @@ -1064,17 +1234,25 @@ static __u32 ok_features[3] = { EXT2_FEATURE_COMPAT_RESIZE_INODE | EXT2_FEATURE_COMPAT_DIR_INDEX | EXT2_FEATURE_COMPAT_EXT_ATTR | - EXT4_FEATURE_COMPAT_SPARSE_SUPER2, + EXT4_FEATURE_COMPAT_SPARSE_SUPER2 | + EXT4_FEATURE_COMPAT_FAST_COMMIT | + EXT4_FEATURE_COMPAT_STABLE_INODES | + EXT4_FEATURE_COMPAT_ORPHAN_FILE, /* Incompat */ EXT2_FEATURE_INCOMPAT_FILETYPE| EXT3_FEATURE_INCOMPAT_EXTENTS| EXT3_FEATURE_INCOMPAT_JOURNAL_DEV| EXT2_FEATURE_INCOMPAT_META_BG| EXT4_FEATURE_INCOMPAT_FLEX_BG| + EXT4_FEATURE_INCOMPAT_EA_INODE| EXT4_FEATURE_INCOMPAT_MMP | + EXT4_FEATURE_INCOMPAT_DIRDATA| EXT4_FEATURE_INCOMPAT_64BIT| EXT4_FEATURE_INCOMPAT_INLINE_DATA| - EXT4_FEATURE_INCOMPAT_ENCRYPT, + EXT4_FEATURE_INCOMPAT_ENCRYPT | + EXT4_FEATURE_INCOMPAT_CASEFOLD | + EXT4_FEATURE_INCOMPAT_CSUM_SEED | + EXT4_FEATURE_INCOMPAT_LARGEDIR, /* R/O compat */ EXT2_FEATURE_RO_COMPAT_LARGE_FILE| EXT4_FEATURE_RO_COMPAT_HUGE_FILE| @@ -1084,7 +1262,9 @@ static __u32 ok_features[3] = { EXT4_FEATURE_RO_COMPAT_GDT_CSUM| EXT4_FEATURE_RO_COMPAT_BIGALLOC| EXT4_FEATURE_RO_COMPAT_QUOTA| - EXT4_FEATURE_RO_COMPAT_METADATA_CSUM + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM| + EXT4_FEATURE_RO_COMPAT_PROJECT| + EXT4_FEATURE_RO_COMPAT_VERITY }; @@ -1131,7 +1311,7 @@ struct str_list { static errcode_t init_list(struct str_list *sl) { sl->num = 0; - sl->max = 0; + sl->max = 1; sl->list = malloc((sl->max+1) * sizeof(char *)); if (!sl->list) return ENOMEM; @@ -1383,23 +1563,33 @@ int get_bool_from_profile(char **types, const char *opt, int def_val) extern const char *mke2fs_default_profile; static const char *default_files[] = { "", 0 }; +struct device_param { + unsigned long min_io; /* preferred minimum IO size */ + unsigned long opt_io; /* optimal IO size */ + unsigned long alignment_offset; /* alignment offset wrt physical block size */ + unsigned int dax:1; /* supports dax? */ +}; + +#define OPTIMIZED_STRIPE_WIDTH 512 +#define OPTIMIZED_STRIDE 512 + #ifdef HAVE_BLKID_PROBE_GET_TOPOLOGY /* * Sets the geometry of a device (stripe/stride), and returns the * device's alignment offset, if any, or a negative error. */ static int get_device_geometry(const char *file, - struct ext2_super_block *param, - unsigned int psector_size) + unsigned int blocksize, + unsigned int psector_size, + struct device_param *dev_param) { int rc = -1; - unsigned int blocksize; blkid_probe pr; blkid_topology tp; - unsigned long min_io; - unsigned long opt_io; struct stat statbuf; + memset(dev_param, 0, sizeof(*dev_param)); + /* Nothing to do for a regular file */ if (!stat(file, &statbuf) && S_ISREG(statbuf.st_mode)) return 0; @@ -1412,23 +1602,32 @@ static int get_device_geometry(const char *file, if (!tp) goto out; - min_io = blkid_topology_get_minimum_io_size(tp); - opt_io = blkid_topology_get_optimal_io_size(tp); - blocksize = EXT2_BLOCK_SIZE(param); - if ((min_io == 0) && (psector_size > blocksize)) - min_io = psector_size; - if ((opt_io == 0) && min_io) - opt_io = min_io; - if ((opt_io == 0) && (psector_size > blocksize)) - opt_io = psector_size; - - /* setting stripe/stride to blocksize is pointless */ - if (min_io > blocksize) - param->s_raid_stride = min_io / blocksize; - if (opt_io > blocksize) - param->s_raid_stripe_width = opt_io / blocksize; - - rc = blkid_topology_get_alignment_offset(tp); + dev_param->min_io = blkid_topology_get_minimum_io_size(tp); + if (dev_param->min_io > OPTIMIZED_STRIDE) { + fprintf(stdout, + "detected raid stride %lu too large, use optimum %lu\n", + dev_param->min_io, OPTIMIZED_STRIDE); + dev_param->min_io = OPTIMIZED_STRIDE; + } + dev_param->opt_io = blkid_topology_get_optimal_io_size(tp); + if (dev_param->opt_io > OPTIMIZED_STRIPE_WIDTH) { + fprintf(stdout, + "detected raid stripe width %lu too large, use optimum %lu\n", + dev_param->opt_io, OPTIMIZED_STRIPE_WIDTH); + dev_param->opt_io = OPTIMIZED_STRIPE_WIDTH; + } + if ((dev_param->min_io == 0) && (psector_size > blocksize)) + dev_param->min_io = psector_size; + if ((dev_param->opt_io == 0) && dev_param->min_io > 0) + dev_param->opt_io = dev_param->min_io; + if ((dev_param->opt_io == 0) && (psector_size > blocksize)) + dev_param->opt_io = psector_size; + + dev_param->alignment_offset = blkid_topology_get_alignment_offset(tp); +#ifdef HAVE_BLKID_TOPOLOGY_GET_DAX + dev_param->dax = blkid_topology_get_dax(tp); +#endif + rc = 0; out: blkid_free_probe(pr); return rc; @@ -1440,6 +1639,7 @@ static void PRS(int argc, char *argv[]) int b, c, flags; int cluster_size = 0; char *tmp, **cpp; + int explicit_fssize = 0; int blocksize = 0; int inode_ratio = 0; int inode_size = 0; @@ -1448,6 +1648,8 @@ static void PRS(int argc, char *argv[]) int lsector_size = 0, psector_size = 0; int show_version_only = 0, is_device = 0; unsigned long long num_inodes = 0; /* unsigned long long to catch too-large input */ + int default_orphan_file = 0; + int default_csum_seed = 0; errcode_t retval; char * oldpath = getenv("PATH"); char * extended_opts = 0; @@ -1469,12 +1671,15 @@ static void PRS(int argc, char *argv[]) * Finally, we complain about fs_blocks_count > 2^32 on a non-64bit fs. */ blk64_t fs_blocks_count = 0; - long sysval; int s_opt = -1, r_opt = -1; char *fs_features = 0; + int fs_features_size = 0; int use_bsize; char *newpath; int pathlen = sizeof(PATH_SET) + 1; +#ifdef HAVE_BLKID_PROBE_GET_TOPOLOGY + struct device_param dev_param; +#endif if (oldpath) pathlen += strlen(oldpath); @@ -1493,19 +1698,18 @@ static void PRS(int argc, char *argv[]) } putenv (newpath); - tmp = getenv("MKE2FS_SYNC"); - if (tmp) - sync_kludge = atoi(tmp); - /* Determine the system page size if possible */ #ifdef HAVE_SYSCONF #if (!defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE)) #define _SC_PAGESIZE _SC_PAGE_SIZE #endif #ifdef _SC_PAGESIZE - sysval = sysconf(_SC_PAGESIZE); - if (sysval > 0) - sys_page_size = sysval; + { + long sysval = sysconf(_SC_PAGESIZE); + + if (sysval > 0) + sys_page_size = sysval; + } #endif /* _SC_PAGESIZE */ #endif /* HAVE_SYSCONF */ @@ -1534,7 +1738,7 @@ profile_error: memset(&fs_param, 0, sizeof(struct ext2_super_block)); fs_param.s_rev_level = 1; /* Create revision 1 filesystems now */ - if (is_before_linux_ver(2, 2, 0)) + if (ext2fs_is_before_linux_ver(2, 2, 0)) fs_param.s_rev_level = 0; if (argc && *argv) { @@ -1547,7 +1751,7 @@ profile_error: } while ((c = getopt (argc, argv, - "b:ce:g:i:jl:m:no:qr:s:t:d:vC:DE:FG:I:J:KL:M:N:O:R:ST:U:Vz:")) != EOF) { + "b:cd:e:g:i:jl:m:no:qr:s:t:vC:DE:FG:I:J:KL:M:N:O:R:ST:U:Vz:")) != EOF) { switch (c) { case 'b': blocksize = parse_num_blocks2(optarg, -1); @@ -1580,6 +1784,9 @@ profile_error: exit(1); } break; + case 'd': + src_root_dir = optarg; + break; case 'D': direct_io = 1; break; @@ -1662,6 +1869,8 @@ profile_error: case 'j': if (!journal_size) journal_size = -1; + if (!journal_fc_size) + journal_fc_size = -1; break; case 'J': parse_journal_opts(optarg); @@ -1686,6 +1895,11 @@ profile_error: break; case 'L': volume_label = optarg; + if (strlen(volume_label) > EXT2_LABEL_LEN) { + volume_label[EXT2_LABEL_LEN] = '\0'; + fprintf(stderr, _("Warning: label too long; will be truncated to '%s'\n\n"), + volume_label); + } break; case 'm': reserved_ratio = strtod(optarg, &tmp); @@ -1715,7 +1929,20 @@ profile_error: creator_os = optarg; break; case 'O': - fs_features = optarg; + retval = ext2fs_resize_mem(fs_features_size, + fs_features_size + 1 + strlen(optarg), + &fs_features); + if (retval) { + com_err(program_name, retval, + _("while allocating fs_feature string")); + exit(1); + } + if (fs_features_size) + strcat(fs_features, ","); + else + fs_features[0] = 0; + strcat(fs_features, optarg); + fs_features_size += 1 + strlen(optarg); break; case 'q': quiet = 1; @@ -1759,9 +1986,6 @@ profile_error: case 'U': fs_uuid = optarg; break; - case 'd': - root_dir = optarg; - break; case 'v': verbose = 1; break; @@ -1801,10 +2025,10 @@ profile_error: #ifdef CONFIG_TESTIO_DEBUG if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) { io_ptr = test_io_manager; - test_io_backing_manager = unix_io_manager; + test_io_backing_manager = default_io_manager; } else #endif - io_ptr = unix_io_manager; + io_ptr = default_io_manager; retval = ext2fs_open(journal_device, EXT2_FLAG_JOURNAL_DEV_OK, 0, 0, io_ptr, &jfs); @@ -1841,19 +2065,17 @@ profile_error: if (optind < argc) usage(); + profile_get_integer(profile, "options", "sync_kludge", 0, 0, + &sync_kludge); + tmp = getenv("MKE2FS_SYNC"); + if (tmp) + sync_kludge = atoi(tmp); + profile_get_integer(profile, "options", "proceed_delay", 0, 0, &proceed_delay); - /* The isatty() test is so we don't break existing scripts */ - flags = CREATE_FILE; - if (isatty(0) && isatty(1)) - flags |= CHECK_FS_EXIST; - if (!quiet) - flags |= VERBOSE_CREATE; - if (fs_blocks_count == 0) - flags |= NO_SIZE; - if (!check_plausibility(device_name, flags, &is_device) && !force) - proceed_question(proceed_delay); + if (fs_blocks_count) + explicit_fssize = 1; check_mount(device_name, force, _("filesystem")); @@ -1865,7 +2087,26 @@ profile_error: retval = ext2fs_get_device_size2(device_name, EXT2_BLOCK_SIZE(&fs_param), &dev_size); + if (retval == ENOENT) { + int fd; + if (!explicit_fssize) { + fprintf(stderr, + _("The file %s does not exist and no " + "size was specified.\n"), device_name); + exit(1); + } + fd = ext2fs_open_file(device_name, + O_CREAT | O_WRONLY, 0666); + if (fd < 0) { + retval = errno; + } else { + dev_size = 0; + retval = 0; + close(fd); + printf(_("Creating regular file %s\n"), device_name); + } + } if (retval && (retval != EXT2_ET_UNIMPLEMENTED)) { com_err(program_name, retval, "%s", _("while trying to determine filesystem size")); @@ -1908,6 +2149,9 @@ profile_error: if (!usage_types) profile_get_string(profile, "devices", device_name, "usage_types", 0, &usage_types); + if (!creator_os) + profile_get_string(profile, "defaults", "creator_os", 0, + 0, &creator_os); /* * We have the file system (or device) size, so we can now @@ -1915,8 +2159,7 @@ profile_error: * be appropriately configured. */ fs_types = parse_fs_type(fs_type, usage_types, &fs_param, - fs_blocks_count ? fs_blocks_count : dev_size, - argv[0]); + fs_blocks_count, argv[0]); if (!fs_types) { fprintf(stderr, "%s", _("Failed to parse fs types list\n")); exit(1); @@ -1955,11 +2198,30 @@ profile_error: ext2fs_clear_feature_filetype(&fs_param); ext2fs_clear_feature_huge_file(&fs_param); ext2fs_clear_feature_metadata_csum(&fs_param); + ext2fs_clear_feature_ea_inode(&fs_param); + ext2fs_clear_feature_casefold(&fs_param); } - edit_feature(fs_features ? fs_features : tmp, - &fs_param.s_feature_compat); + if (!fs_features && tmp) + edit_feature(tmp, &fs_param.s_feature_compat); + /* + * Now all the defaults are incorporated in fs_param. Check the state + * of orphan_file feature so that we know whether we should silently + * disabled in case journal gets disabled. + */ + if (ext2fs_has_feature_orphan_file(&fs_param)) + default_orphan_file = 1; + if (ext2fs_has_feature_csum_seed(&fs_param)) + default_csum_seed = 1; + if (fs_features) + edit_feature(fs_features, &fs_param.s_feature_compat); + /* Silently disable orphan_file if user chose fs without journal */ + if (default_orphan_file && !ext2fs_has_feature_journal(&fs_param)) + ext2fs_clear_feature_orphan_file(&fs_param); + if (default_csum_seed && !ext2fs_has_feature_metadata_csum(&fs_param)) + ext2fs_clear_feature_csum_seed(&fs_param); if (tmp) free(tmp); + (void) ext2fs_free_mem(&fs_features); /* * If the user specified features incompatible with the Hurd, complain */ @@ -1979,6 +2241,11 @@ profile_error: "metadata_csum feature.\n")); exit(1); } + if (ext2fs_has_feature_ea_inode(&fs_param)) { + fprintf(stderr, "%s", _("The HURD does not support the " + "ea_inode feature.\n")); + exit(1); + } } /* Get the hardware sector sizes, if available */ @@ -2011,7 +2278,8 @@ profile_error: if (use_bsize == -1) { use_bsize = sys_page_size; - if (is_before_linux_ver(2, 6, 0) && use_bsize > 4096) + if (ext2fs_is_before_linux_ver(2, 6, 0) && + use_bsize > 4096) use_bsize = 4096; } if (lsector_size && use_bsize < lsector_size) @@ -2041,28 +2309,49 @@ profile_error: * We now need to do a sanity check of fs_blocks_count for * 32-bit vs 64-bit block number support. */ - if ((fs_blocks_count > MAX_32_NUM) && - ext2fs_has_feature_64bit(&fs_param)) - ext2fs_clear_feature_resize_inode(&fs_param); - if ((fs_blocks_count > MAX_32_NUM) && - !ext2fs_has_feature_64bit(&fs_param) && - get_bool_from_profile(fs_types, "auto_64-bit_support", 0)) { - ext2fs_set_feature_64bit(&fs_param); - ext2fs_clear_feature_resize_inode(&fs_param); - } - if ((fs_blocks_count > MAX_32_NUM) && - !ext2fs_has_feature_64bit(&fs_param)) { - fprintf(stderr, _("%s: Size of device (0x%llx blocks) %s " + if (fs_blocks_count > MAX_32_NUM) { + if (!ext2fs_has_feature_64bit(&fs_param) && + get_bool_from_profile(fs_types, "auto_64-bit_support", 0)) + ext2fs_set_feature_64bit(&fs_param); + + if (ext2fs_has_feature_64bit(&fs_param)) { + ext2fs_clear_feature_resize_inode(&fs_param); + } else { + fprintf(stderr, + _("%s: Size of device (0x%llx blocks) %s " "too big to be expressed\n\t" "in 32 bits using a blocksize of %d.\n"), - program_name, fs_blocks_count, device_name, - EXT2_BLOCK_SIZE(&fs_param)); + program_name, + (unsigned long long) fs_blocks_count, + device_name, EXT2_BLOCK_SIZE(&fs_param)); + exit(1); + } + } + + /* + * Guard against group descriptor count overflowing... Mostly to avoid + * strange results for absurdly large devices. This is in log2: + * (blocksize) * (bits per byte) * (maximum number of block groups) + */ + if (fs_blocks_count > + (1ULL << (EXT2_BLOCK_SIZE_BITS(&fs_param) + 3 + 32)) - 1) { + fprintf(stderr, _("%s: Size of device (0x%llx blocks) %s " + "too big to create\n\t" + "a filesystem using a blocksize of %d.\n"), + program_name, (unsigned long long) fs_blocks_count, + device_name, EXT2_BLOCK_SIZE(&fs_param)); exit(1); } ext2fs_blocks_count_set(&fs_param, fs_blocks_count); if (ext2fs_has_feature_journal_dev(&fs_param)) { + int i; + + for (i=0; fs_types[i]; i++) { + free(fs_types[i]); + fs_types[i] = 0; + } fs_types[0] = strdup("journal"); fs_types[1] = 0; } @@ -2118,13 +2407,13 @@ profile_error: fs_param.s_feature_compat = 0; fs_param.s_feature_ro_compat &= EXT4_FEATURE_RO_COMPAT_METADATA_CSUM; - } + } /* Check the user's mkfs options for 64bit */ - if (ext2fs_has_feature_64bit(&fs_param) && + if (fs_blocks_count > MAX_32_NUM && !ext2fs_has_feature_extents(&fs_param)) { - printf("%s", _("Extents MUST be enabled for a 64-bit " - "filesystem. Pass -O extents to rectify.\n")); + printf("%s", _("Extents MUST be enabled for filesystems with " + "over 2^32 blocks. Use '-O extents' to fix.\n")); exit(1); } @@ -2165,17 +2454,35 @@ profile_error: } #ifdef HAVE_BLKID_PROBE_GET_TOPOLOGY - retval = get_device_geometry(device_name, &fs_param, - (unsigned int) psector_size); + retval = get_device_geometry(device_name, blocksize, + psector_size, &dev_param); if (retval < 0) { fprintf(stderr, _("warning: Unable to get device geometry for %s\n"), device_name); - } else if (retval) { - printf(_("%s alignment is offset by %lu bytes.\n"), - device_name, retval); - printf(_("This may result in very poor performance, " - "(re)-partitioning suggested.\n")); + } else { + /* setting stripe/stride to blocksize is pointless */ + if (dev_param.min_io > (unsigned) blocksize) + fs_param.s_raid_stride = dev_param.min_io / blocksize; + if (dev_param.opt_io > (unsigned) blocksize) { + fs_param.s_raid_stripe_width = + dev_param.opt_io / blocksize; + } + + if (dev_param.alignment_offset) { + printf(_("%s alignment is offset by %lu bytes.\n"), + device_name, dev_param.alignment_offset); + printf(_("This may result in very poor performance, " + "(re)-partitioning suggested.\n")); + } + + if (dev_param.dax && blocksize != sys_page_size) { + fprintf(stderr, + _("%s is capable of DAX but current block size " + "%u is different from system page size %u so " + "filesystem will not support DAX.\n"), + device_name, blocksize, sys_page_size); + } } #endif @@ -2205,7 +2512,7 @@ profile_error: } /* Metadata checksumming wasn't totally stable before 3.18. */ - if (is_before_linux_ver(3, 18, 0) && + if (ext2fs_is_before_linux_ver(3, 18, 0) && ext2fs_has_feature_metadata_csum(&fs_param)) fprintf(stderr, _("Suggestion: Use Linux kernel >= 3.18 for " "improved stability of the metadata and journal " @@ -2215,7 +2522,7 @@ profile_error: * On newer kernels we do have lazy_itable_init support. So pick the * right default in case ext4 module is not loaded. */ - if (is_before_linux_ver(2, 6, 37)) + if (ext2fs_is_before_linux_ver(2, 6, 37)) lazy_itable_init = 0; else lazy_itable_init = 1; @@ -2246,6 +2553,33 @@ profile_error: if (packed_meta_blocks) journal_location = 0; + if (ext2fs_has_feature_casefold(&fs_param)) { + char *ef, *en = get_string_from_profile(fs_types, + "encoding", "utf8"); + int encoding = e2p_str2encoding(en); + + if (encoding < 0) { + com_err(program_name, 0, + _("Unknown filename encoding from profile: %s"), + en); + exit(1); + } + free(en); + fs_param.s_encoding = encoding; + ef = get_string_from_profile(fs_types, "encoding_flags", NULL); + if (ef) { + if (e2p_str2encoding_flags(encoding, ef, + &fs_param.s_encoding_flags) < 0) { + com_err(program_name, 0, + _("Unknown encoding flags from profile: %s"), ef); + exit(1); + } + free(ef); + } else + fs_param.s_encoding_flags = + e2p_get_encoding_flags(encoding); + } + /* Get options from profile */ for (cpp = fs_types; *cpp; cpp++) { tmp = NULL; @@ -2258,6 +2592,38 @@ profile_error: if (extended_opts) parse_extended_opts(&fs_param, extended_opts); + if (explicit_fssize == 0 && offset > 0) { + fs_blocks_count -= offset / EXT2_BLOCK_SIZE(&fs_param); + ext2fs_blocks_count_set(&fs_param, fs_blocks_count); + fprintf(stderr, + _("\nWarning: offset specified without an " + "explicit file system size.\n" + "Creating a file system with %llu blocks " + "but this might\n" + "not be what you want.\n\n"), + (unsigned long long) fs_blocks_count); + } + + if (quotatype_bits & QUOTA_PRJ_BIT) + ext2fs_set_feature_project(&fs_param); + + if (ext2fs_has_feature_project(&fs_param)) { + quotatype_bits |= QUOTA_PRJ_BIT; + if (inode_size == EXT2_GOOD_OLD_INODE_SIZE) { + com_err(program_name, 0, + _("%d byte inodes are too small for " + "project quota"), + inode_size); + exit(1); + } + if (inode_size == 0) { + inode_size = get_int_from_profile(fs_types, + "inode_size", 0); + if (inode_size <= EXT2_GOOD_OLD_INODE_SIZE*2) + inode_size = EXT2_GOOD_OLD_INODE_SIZE*2; + } + } + /* Don't allow user to set both metadata_csum and uninit_bg bits. */ if (ext2fs_has_feature_metadata_csum(&fs_param) && ext2fs_has_feature_gdt_csum(&fs_param)) @@ -2281,11 +2647,12 @@ profile_error: exit(1); } - if (!quiet && ext2fs_has_feature_bigalloc(&fs_param)) - fprintf(stderr, "%s", _("\nWarning: the bigalloc feature is " - "still under development\n" - "See https://ext4.wiki.kernel.org/" - "index.php/Bigalloc for more information\n\n")); + if (!quiet && ext2fs_has_feature_bigalloc(&fs_param) && + EXT2_CLUSTER_SIZE(&fs_param) > 16 * EXT2_BLOCK_SIZE(&fs_param)) + fprintf(stderr, "%s", _("\nWarning: bigalloc file systems " + "with a cluster size greater than\n" + "16 times the block size is considered " + "experimental\n")); /* * Since sparse_super is the default, we would only have a problem @@ -2358,24 +2725,32 @@ profile_error: exit(1); } + /* + * Warn the user that filesystems with 128-byte inodes will + * not work properly beyond 2038. This can be suppressed via + * a boolean in the mke2fs.conf file, and we will disable this + * warning for file systems created for the GNU Hurd. + */ + if (inode_size == EXT2_GOOD_OLD_INODE_SIZE && + get_bool_from_profile(fs_types, "warn_y2038_dates", 1)) + printf( +_("128-byte inodes cannot handle dates beyond 2038 and are deprecated\n")); + /* Make sure number of inodes specified will fit in 32 bits */ if (num_inodes == 0) { unsigned long long n; n = ext2fs_blocks_count(&fs_param) * blocksize / inode_ratio; if (n > MAX_32_NUM) { - if (ext2fs_has_feature_64bit(&fs_param)) - num_inodes = MAX_32_NUM; - else { + num_inodes = MAX_32_NUM; + if (!ext2fs_has_feature_64bit(&fs_param)) com_err(program_name, 0, - _("too many inodes (%llu), raise " - "inode ratio?"), n); - exit(1); - } + _("too many inodes (%llu), reduced to " + "%llu"), n, MAX_32_NUM); } } else if (num_inodes > MAX_32_NUM) { com_err(program_name, 0, _("too many inodes (%llu), specify < 2^32 inodes"), - num_inodes); + (unsigned long long) num_inodes); exit(1); } /* @@ -2414,6 +2789,17 @@ profile_error: free(fs_type); free(usage_types); + + /* The isatty() test is so we don't break existing scripts */ + flags = CREATE_FILE; + if (isatty(0) && isatty(1) && !offset) + flags |= CHECK_FS_EXIST; + if (!quiet) + flags |= VERBOSE_CREATE; + if (!explicit_fssize) + flags |= NO_SIZE; + if (!check_plausibility(device_name, flags, &is_device) && !force) + proceed_question(proceed_delay); } static int should_do_undo(const char *name) @@ -2422,7 +2808,7 @@ static int should_do_undo(const char *name) io_channel channel; __u16 s_magic; struct ext2_super_block super; - io_manager manager = unix_io_manager; + io_manager manager = default_io_manager; int csum_flag, force_undo; csum_flag = ext2fs_has_feature_metadata_csum(&fs_param) || @@ -2556,9 +2942,7 @@ err: static int mke2fs_discard_device(ext2_filsys fs) { struct ext2fs_numeric_progress_struct progress; - blk64_t blocks = ext2fs_blocks_count(fs->super); - blk64_t count = DISCARD_STEP_MB; - blk64_t cur; + dgrp_t group; int retval = 0; /* @@ -2566,27 +2950,30 @@ static int mke2fs_discard_device(ext2_filsys fs) * we do not print numeric progress resulting in failure * afterwards. */ - retval = io_channel_discard(fs->io, 0, fs->blocksize); + retval = io_channel_discard(fs->io, 0, 1); if (retval) return retval; - cur = fs->blocksize; - - count *= (1024 * 1024); - count /= fs->blocksize; ext2fs_numeric_progress_init(fs, &progress, _("Discarding device blocks: "), - blocks); - while (cur < blocks) { - ext2fs_numeric_progress_update(fs, &progress, cur); + ext2fs_blocks_count(fs->super)); - if (cur + count > blocks) - count = blocks - cur; + for (group = 0; group < fs->group_desc_count; group++) { + blk64_t start = ext2fs_group_first_block2(fs, group); + blk64_t count = ext2fs_group_blocks_count(fs, group); + int retval_discard = 0; - retval = io_channel_discard(fs->io, cur, count); - if (retval) - break; - cur += count; + retval_discard = io_channel_discard(fs->io, start, count); + if (!retval_discard) { + ext2fs_bg_flags_set(fs, group, EXT2_BG_TRIMMED); + ext2fs_group_desc_csum_set(fs, group); + fs->super->s_flags |= EXT2_FLAGS_TRACK_TRIM; + } else if (!retval) { + retval = retval_discard; + } + + ext2fs_numeric_progress_update(fs, &progress, + ext2fs_group_last_block2(fs, group)); } if (retval) { @@ -2645,10 +3032,21 @@ static void fix_cluster_bg_counts(ext2_filsys fs) static int create_quota_inodes(ext2_filsys fs) { quota_ctx_t qctx; + errcode_t retval; - quota_init_context(&qctx, fs, -1); + retval = quota_init_context(&qctx, fs, quotatype_bits); + if (retval) { + com_err(program_name, retval, + _("while initializing quota context")); + exit(1); + } quota_compute_usage(qctx); - quota_write_inode(qctx, quotatype); + retval = quota_write_inode(qctx, quotatype_bits); + if (retval) { + com_err(program_name, retval, + _("while writing quota inodes")); + exit(1); + } quota_release_context(&qctx); return 0; @@ -2691,7 +3089,9 @@ int main (int argc, char *argv[]) errcode_t retval = 0; ext2_filsys fs; badblocks_list bb_list = 0; - unsigned int journal_blocks = 0; + badblocks_iterate bb_iter; + blk_t blk; + struct ext2fs_journal_params jparams = {0}; unsigned int i, checkinterval; int max_mnt_count; int val, hash_alg; @@ -2701,6 +3101,7 @@ int main (int argc, char *argv[]) char opt_string[40]; char *hash_alg_str; int itable_zeroed = 0; + blk64_t overhead; #ifdef ENABLE_NLS setlocale(LC_MESSAGES, ""); @@ -2714,10 +3115,10 @@ int main (int argc, char *argv[]) #ifdef CONFIG_TESTIO_DEBUG if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) { io_ptr = test_io_manager; - test_io_backing_manager = unix_io_manager; + test_io_backing_manager = default_io_manager; } else #endif - io_ptr = unix_io_manager; + io_ptr = default_io_manager; if (undo_file != NULL || should_do_undo(device_name)) { retval = mke2fs_setup_tdb(device_name, &io_ptr); @@ -2742,12 +3143,38 @@ int main (int argc, char *argv[]) */ if (!quiet) flags |= EXT2_FLAG_PRINT_PROGRESS; - retval = ext2fs_initialize(device_name, flags, &fs_param, io_ptr, &fs); + if (android_sparse_file) { + char *android_sparse_params = malloc(strlen(device_name) + 48); + + if (!android_sparse_params) { + com_err(program_name, ENOMEM, "%s", + _("in malloc for android_sparse_params")); + exit(1); + } + sprintf(android_sparse_params, "(%s):%u:%u", + device_name, fs_param.s_blocks_count, + 1024 << fs_param.s_log_block_size); + retval = ext2fs_initialize(android_sparse_params, flags, + &fs_param, sparse_io_manager, &fs); + free(android_sparse_params); + } else + retval = ext2fs_initialize(device_name, flags, &fs_param, + io_ptr, &fs); if (retval) { com_err(device_name, retval, "%s", _("while setting up superblock")); exit(1); } + + if (iops_range && iops_count) { + ext2fs_set_iops_group(fs, iops_range, iops_count); + fs->super->s_flags |= EXT2_FLAGS_HAS_IOPS; + ext2fs_mark_super_dirty(fs); + + if (iops_range != iops_array) + free(iops_range); + } + fs->progress_ops = &ext2fs_numeric_progress_ops; /* Set the error behavior */ @@ -2774,10 +3201,50 @@ int main (int argc, char *argv[]) "Pass -O 64bit to rectify.\n")); } + if (ext2fs_has_feature_csum_seed(fs->super) && + !ext2fs_has_feature_metadata_csum(fs->super)) { + printf("%s", _("The metadata_csum_seed feature " + "requires the metadata_csum feature.\n")); + exit(1); + } + + if (ext2fs_has_feature_dirdata(fs->super)) { + if (ext2fs_has_feature_inline_data(fs->super)) { + printf("%s", _("The dirdata feature can not enabled " + "with inline data feature.\n")); + exit(1); + } + if (ext2fs_has_feature_casefold(fs->super)) { + printf("%s", _("The dirdata feature can not enabled " + "with casefold feature.\n")); + exit(1); + } + } + /* Calculate journal blocks */ if (!journal_device && ((journal_size) || ext2fs_has_feature_journal(&fs_param))) - journal_blocks = figure_journal_size(journal_size, fs); + figure_journal_size(&jparams, journal_size, journal_fc_size, fs); + + sprintf(opt_string, "tdb_data_size=%d", fs->blocksize <= 4096 ? + 32768 : fs->blocksize * 8); + io_channel_set_options(fs->io, opt_string); + if (offset) { + sprintf(opt_string, "offset=%llu", (unsigned long long) offset); + io_channel_set_options(fs->io, opt_string); + } + + if (assume_storage_prezeroed) { + if (verbose) + printf("%s", + _("Assuming the storage device is prezeroed " + "- skipping inode table and journal wipe\n")); + + lazy_itable_init = 1; + itable_zeroed = 1; + zero_hugefile = 0; + journal_flags |= EXT2_MKJOURNAL_LAZYINIT; + } /* Can't undo discard ... */ if (!noaction && discard && dev_size && (io_ptr != undo_io_manager)) { @@ -2793,14 +3260,6 @@ int main (int argc, char *argv[]) } } - sprintf(opt_string, "tdb_data_size=%d", fs->blocksize <= 4096 ? - 32768 : fs->blocksize * 8); - io_channel_set_options(fs->io, opt_string); - if (offset) { - sprintf(opt_string, "offset=%llu", offset); - io_channel_set_options(fs->io, opt_string); - } - if (fs_param.s_flags & EXT2_FLAGS_TEST_FILESYS) fs->super->s_flags |= EXT2_FLAGS_TEST_FILESYS; @@ -2822,13 +3281,25 @@ int main (int argc, char *argv[]) * Parse or generate a UUID for the filesystem */ if (fs_uuid) { - if (uuid_parse(fs_uuid, fs->super->s_uuid) !=0) { + if ((strcasecmp(fs_uuid, "null") == 0) || + (strcasecmp(fs_uuid, "clear") == 0)) { + uuid_clear(fs->super->s_uuid); + } else if (strcasecmp(fs_uuid, "time") == 0) { + uuid_generate_time(fs->super->s_uuid); + } else if (strcasecmp(fs_uuid, "random") == 0) { + uuid_generate(fs->super->s_uuid); + } else if (uuid_parse(fs_uuid, fs->super->s_uuid) != 0) { com_err(device_name, 0, "could not parse UUID: %s\n", fs_uuid); exit(1); } } else uuid_generate(fs->super->s_uuid); + + if (ext2fs_has_feature_csum_seed(fs->super)) + fs->super->s_checksum_seed = ext2fs_crc32c_le(~0, + fs->super->s_uuid, sizeof(fs->super->s_uuid)); + ext2fs_init_csum_seed(fs); /* @@ -2840,7 +3311,13 @@ int main (int argc, char *argv[]) free(hash_alg_str); fs->super->s_def_hash_version = (hash_alg >= 0) ? hash_alg : EXT2_HASH_HALF_MD4; - uuid_generate((unsigned char *) fs->super->s_hash_seed); + + if (memcmp(fs_param.s_hash_seed, zero_buf, + sizeof(fs_param.s_hash_seed)) != 0) { + memcpy(fs->super->s_hash_seed, fs_param.s_hash_seed, + sizeof(fs->super->s_hash_seed)); + } else + uuid_generate((unsigned char *) fs->super->s_hash_seed); /* * Periodic checks can be enabled/disabled via config file. @@ -2891,7 +3368,7 @@ int main (int argc, char *argv[]) if (volume_label) { memset(fs->super->s_volume_name, 0, sizeof(fs->super->s_volume_name)); - strncpy(fs->super->s_volume_name, volume_label, + strncpy((char *) fs->super->s_volume_name, volume_label, sizeof(fs->super->s_volume_name)); } @@ -2901,7 +3378,7 @@ int main (int argc, char *argv[]) if (mount_dir) { memset(fs->super->s_last_mounted, 0, sizeof(fs->super->s_last_mounted)); - strncpy(fs->super->s_last_mounted, mount_dir, + strncpy((char *) fs->super->s_last_mounted, mount_dir, sizeof(fs->super->s_last_mounted)); } @@ -2951,6 +3428,23 @@ int main (int argc, char *argv[]) if (!quiet) printf("%s", _("done \n")); + /* + * Unmark bad blocks to calculate overhead, because metadata + * blocks and bad blocks can land on the same allocation cluster. + */ + if (bb_list) { + retval = ext2fs_badblocks_list_iterate_begin(bb_list, + &bb_iter); + if (retval) { + com_err("ext2fs_badblocks_list_iterate_begin", retval, + "%s", _("while unmarking bad blocks")); + exit(1); + } + while (ext2fs_badblocks_list_iterate(bb_iter, &blk)) + ext2fs_unmark_block_bitmap2(fs->block_map, blk); + ext2fs_badblocks_list_iterate_end(bb_iter); + } + retval = ext2fs_convert_subcluster_bitmap(fs, &fs->block_map); if (retval) { com_err(program_name, retval, "%s", @@ -2958,6 +3452,28 @@ int main (int argc, char *argv[]) exit(1); } + retval = ext2fs_count_used_clusters(fs, fs->super->s_first_data_block, + ext2fs_blocks_count(fs->super) - 1, + &overhead); + if (retval) { + com_err(program_name, retval, "%s", + _("while calculating overhead")); + exit(1); + } + + if (bb_list) { + retval = ext2fs_badblocks_list_iterate_begin(bb_list, + &bb_iter); + if (retval) { + com_err("ext2fs_badblocks_list_iterate_begin", retval, + "%s", _("while marking bad blocks as used")); + exit(1); + } + while (ext2fs_badblocks_list_iterate(bb_iter, &blk)) + ext2fs_mark_block_bitmap2(fs->block_map, blk); + ext2fs_badblocks_list_iterate_end(bb_iter); + } + if (super_only) { check_plausibility(device_name, CHECK_FS_EXIST, NULL); printf(_("%s may be further corrupted by superblock rewrite\n"), @@ -3002,7 +3518,7 @@ int main (int argc, char *argv[]) if (retval) { com_err(program_name, retval, _("while zeroing block %llu at end of filesystem"), - ret_blk); + (unsigned long long) ret_blk); } write_inode_tables(fs, lazy_itable_init, itable_zeroed); create_root_dir(fs); @@ -3030,7 +3546,7 @@ int main (int argc, char *argv[]) retval = ext2fs_open(journal_device, EXT2_FLAG_RW| EXT2_FLAG_JOURNAL_DEV_OK, 0, - fs->blocksize, unix_io_manager, &jfs); + fs->blocksize, default_io_manager, &jfs); if (retval) { com_err(program_name, retval, _("while trying to open journal device %s\n"), @@ -3055,22 +3571,26 @@ int main (int argc, char *argv[]) free(journal_device); } else if ((journal_size) || ext2fs_has_feature_journal(&fs_param)) { + overhead += EXT2FS_NUM_B2C(fs, jparams.num_journal_blocks + jparams.num_fc_blocks); if (super_only) { printf("%s", _("Skipping journal creation in super-only mode\n")); fs->super->s_journal_inum = EXT2_JOURNAL_INO; goto no_journal; } - if (!journal_blocks) { + if (!jparams.num_journal_blocks) { ext2fs_clear_feature_journal(fs->super); + ext2fs_clear_feature_orphan_file(fs->super); + ext2fs_clear_feature_journal(&fs_param); + ext2fs_clear_feature_orphan_file(&fs_param); goto no_journal; } if (!quiet) { printf(_("Creating journal (%u blocks): "), - journal_blocks); + jparams.num_journal_blocks + jparams.num_fc_blocks); fflush(stdout); } - retval = ext2fs_add_journal_inode2(fs, journal_blocks, + retval = ext2fs_add_journal_inode3(fs, &jparams, journal_location, journal_flags); if (retval) { @@ -3097,20 +3617,41 @@ no_journal: fs->super->s_mmp_update_interval); } + overhead += fs->super->s_first_data_block; + if (!super_only) + fs->super->s_overhead_clusters = overhead; + if (ext2fs_has_feature_bigalloc(&fs_param)) fix_cluster_bg_counts(fs); if (ext2fs_has_feature_quota(&fs_param)) create_quota_inodes(fs); + if (ext2fs_has_feature_orphan_file(&fs_param)) { + if (!ext2fs_has_feature_journal(&fs_param)) { + com_err(program_name, 0, _("cannot set orphan_file " + "feature without a journal.")); + exit(1); + } + if (!orphan_file_blocks) { + orphan_file_blocks = + ext2fs_default_orphan_file_blocks(fs); + } + retval = ext2fs_create_orphan_file(fs, orphan_file_blocks); + if (retval) { + com_err(program_name, retval, + _("while creating orphan file")); + exit(1); + } + } retval = mk_hugefiles(fs, device_name); if (retval) com_err(program_name, retval, "while creating huge files"); /* Copy files from the specified directory */ - if (root_dir) { + if (src_root_dir) { if (!quiet) printf("%s", _("Copying files into the device: ")); - retval = populate_fs(fs, EXT2_ROOT_INO, root_dir, + retval = populate_fs(fs, EXT2_ROOT_INO, src_root_dir, EXT2_ROOT_INO); if (retval) { com_err(program_name, retval, "%s", @@ -3127,8 +3668,9 @@ no_journal: max_mnt_count = fs->super->s_max_mnt_count; retval = ext2fs_close_free(&fs); if (retval) { - fprintf(stderr, "%s", - _("\nWarning, had trouble writing out superblocks.")); + com_err(program_name, retval, "%s", + _("while writing out and closing file system")); + retval = 1; } else if (!quiet) { printf("%s", _("done\n\n")); if (!getenv("MKE2FS_SKIP_CHECK_MSG"))