diff options
author | Dimitri John Ledkov <xnox@ubuntu.com> | 2018-01-11 15:44:55 +0000 |
---|---|---|
committer | Dimitri John Ledkov <xnox@ubuntu.com> | 2018-01-11 15:44:55 +0000 |
commit | d78d642bffff6ea49d62c19f26052ed6d3dcc467 (patch) | |
tree | db0f470018ee6f4b93fb8fd601401fa157e5dbe3 /mkfs | |
parent | b309a4dfbe8130b9fef087df59dd18a487a9c18e (diff) |
New upstream release.
Diffstat (limited to 'mkfs')
-rw-r--r-- | mkfs/common.c | 119 | ||||
-rw-r--r-- | mkfs/common.h | 7 | ||||
-rw-r--r-- | mkfs/main.c | 59 |
3 files changed, 143 insertions, 42 deletions
diff --git a/mkfs/common.c b/mkfs/common.c index c9ce10d4..dd5e7ecf 100644 --- a/mkfs/common.c +++ b/mkfs/common.c @@ -438,12 +438,6 @@ out: return ret; } -u64 btrfs_min_dev_size(u32 nodesize) -{ - return 2 * (BTRFS_MKFS_SYSTEM_GROUP_SIZE + - btrfs_min_global_blk_rsv_size(nodesize)); -} - /* * Btrfs minimum size calculation is complicated, it should include at least: * 1. system group size @@ -454,11 +448,72 @@ u64 btrfs_min_dev_size(u32 nodesize) * To avoid the overkill calculation, (system group + global block rsv) * 2 * for *EACH* device should be good enough. */ -u64 btrfs_min_global_blk_rsv_size(u32 nodesize) +static u64 btrfs_min_global_blk_rsv_size(u32 nodesize) { return (u64)nodesize << 10; } +u64 btrfs_min_dev_size(u32 nodesize, int mixed, u64 meta_profile, + u64 data_profile) +{ + u64 reserved = 0; + u64 meta_size; + u64 data_size; + + if (mixed) + return 2 * (BTRFS_MKFS_SYSTEM_GROUP_SIZE + + btrfs_min_global_blk_rsv_size(nodesize)); + + /* + * Minimal size calculation is complex due to several factors: + * 1) Temporary chunk reuse + * If specified chunk profile is SINGLE, we can reuse + * temporary chunks, no need to allocate new chunks. + * + * 2) Different minimal chunk size for different profiles: + * For initial sys chunk, chunk size is fixed to 4M. + * For single profile, minimal chunk size is 8M for all. + * For other profiles, minimal chunk and stripe size ranges from 8M + * to 64M. + * + * To calculate it a little easier, here we assume we don't reuse any + * temporary chunk, and calculate the size completely by ourselves. + * + * Temporary chunks sizes are always fixed: + * One initial sys chunk, one SINGLE meta, and one SINGLE data. + * The latter two are all 8M, accroding to @calc_size of + * btrfs_alloc_chunk(). + */ + reserved += BTRFS_MKFS_SYSTEM_GROUP_SIZE + SZ_8M * 2; + + /* + * For real chunks, we need to select different sizes: + * For SINGLE, it's still fixed to 8M (@calc_size). + * For other profiles, refer to max(@min_stripe_size, @calc_size). + * + * And use the stripe size to calculate its physical used space. + */ + if (meta_profile & BTRFS_BLOCK_GROUP_PROFILE_MASK) + meta_size = SZ_8M + SZ_32M; + else + meta_size = SZ_8M + SZ_8M; + /* For DUP/metadata, 2 stripes on one disk */ + if (meta_profile & BTRFS_BLOCK_GROUP_DUP) + meta_size *= 2; + reserved += meta_size; + + if (data_profile & BTRFS_BLOCK_GROUP_PROFILE_MASK) + data_size = SZ_64M; + else + data_size = SZ_8M; + /* For DUP/data, 2 stripes on one disk */ + if (data_profile & BTRFS_BLOCK_GROUP_DUP) + data_size *= 2; + reserved += data_size; + + return reserved; +} + #define isoctal(c) (((c) & ~7) == '0') static inline void translate(char *f, char *t) @@ -632,23 +687,9 @@ int test_dev_for_mkfs(const char *file, int force_overwrite) error("%s is a swap device", file); return 1; } - if (!force_overwrite) { - if (check_overwrite(file)) { - error("use the -f option to force overwrite of %s", - file); - return 1; - } - } - ret = check_mounted(file); - if (ret < 0) { - error("cannot check mount status of %s: %s", file, - strerror(-ret)); + ret = test_status_for_mkfs(file, force_overwrite); + if (ret) return 1; - } - if (ret == 1) { - error("%s is mounted", file); - return 1; - } /* check if the device is busy */ fd = open(file, O_RDWR|O_EXCL); if (fd < 0) { @@ -669,6 +710,34 @@ int test_dev_for_mkfs(const char *file, int force_overwrite) return 0; } +/* + * check if the file (device) is formatted or mounted + */ +int test_status_for_mkfs(const char *file, bool force_overwrite) +{ + int ret; + + if (!force_overwrite) { + if (check_overwrite(file)) { + error("use the -f option to force overwrite of %s", + file); + return 1; + } + } + ret = check_mounted(file); + if (ret < 0) { + error("cannot check mount status of %s: %s", file, + strerror(-ret)); + return 1; + } + if (ret == 1) { + error("%s is mounted", file); + return 1; + } + + return 0; +} + int is_vol_small(const char *file) { int fd = -1; @@ -698,7 +767,7 @@ int is_vol_small(const char *file) } } -int test_minimum_size(const char *file, u32 nodesize) +int test_minimum_size(const char *file, u64 min_dev_size) { int fd; struct stat statbuf; @@ -710,7 +779,7 @@ int test_minimum_size(const char *file, u32 nodesize) close(fd); return -errno; } - if (btrfs_device_size(fd, &statbuf) < btrfs_min_dev_size(nodesize)) { + if (btrfs_device_size(fd, &statbuf) < min_dev_size) { close(fd); return 1; } diff --git a/mkfs/common.h b/mkfs/common.h index dee0ea97..f6b60c28 100644 --- a/mkfs/common.h +++ b/mkfs/common.h @@ -66,12 +66,13 @@ struct btrfs_mkfs_config { }; int make_btrfs(int fd, struct btrfs_mkfs_config *cfg); -u64 btrfs_min_dev_size(u32 nodesize); -u64 btrfs_min_global_blk_rsv_size(u32 nodesize); -int test_minimum_size(const char *file, u32 nodesize); +u64 btrfs_min_dev_size(u32 nodesize, int mixed, u64 meta_profile, + u64 data_profile); +int test_minimum_size(const char *file, u64 min_dev_size); int is_vol_small(const char *file); int test_num_disk_vs_raid(u64 metadata_profile, u64 data_profile, u64 dev_cnt, int mixed, int ssd); +int test_status_for_mkfs(const char *file, bool force_overwrite); int test_dev_for_mkfs(const char *file, int force_overwrite); #endif diff --git a/mkfs/main.c b/mkfs/main.c index 1b4cabc1..d817ad8d 100644 --- a/mkfs/main.c +++ b/mkfs/main.c @@ -1073,6 +1073,19 @@ static int make_image(const char *source_dir, struct btrfs_root *root) printf("Making image is completed.\n"); return 0; fail: + /* + * Since we don't have btrfs_abort_transaction() yet, uncommitted trans + * will trigger a BUG_ON(). + * + * However before mkfs is fully finished, the magic number is invalid, + * so even we commit transaction here, the fs still can't be mounted. + * + * To do a graceful error out, here we commit transaction as a + * workaround. + * Since we have already hit some problem, the return value doesn't + * matter now. + */ + btrfs_commit_transaction(trans, root); while (!list_empty(&dir_head.list)) { dir_entry = list_entry(dir_head.list.next, struct directory_name_entry, list); @@ -1148,18 +1161,25 @@ static int zero_output_file(int out_fd, u64 size) { int loop_num; u64 location = 0; - char buf[4096]; + char buf[SZ_4K]; int ret = 0, i; ssize_t written; - memset(buf, 0, 4096); - loop_num = size / 4096; + memset(buf, 0, SZ_4K); + + /* Only zero out the first 1M */ + loop_num = SZ_1M / SZ_4K; for (i = 0; i < loop_num; i++) { - written = pwrite64(out_fd, buf, 4096, location); - if (written != 4096) + written = pwrite64(out_fd, buf, SZ_4K, location); + if (written != SZ_4K) ret = -EIO; - location += 4096; + location += SZ_4K; } + + /* Then enlarge the file to size */ + written = pwrite64(out_fd, buf, 1, size - 1); + if (written < 1) + ret = -EIO; return ret; } @@ -1350,6 +1370,9 @@ static int cleanup_temp_chunks(struct btrfs_fs_info *fs_info, ret = btrfs_search_slot(trans, root, &key, &path, 0, 0); if (ret < 0) goto out; + /* Don't pollute ret for >0 case */ + if (ret > 0) + ret = 0; btrfs_item_key_to_cpu(path.nodes[0], &found_key, path.slots[0]); @@ -1423,6 +1446,7 @@ int main(int argc, char **argv) int zero_end = 1; int fd = -1; int ret; + int close_ret; int i; int mixed = 0; int nodesize_forced = 0; @@ -1436,6 +1460,7 @@ int main(int argc, char **argv) u64 num_of_meta_chunks = 0; u64 size_of_data = 0; u64 source_dir_size = 0; + u64 min_dev_size; int dev_cnt = 0; int saved_optind; char fs_uuid[BTRFS_UUID_UNPARSED_SIZE] = { 0 }; @@ -1580,8 +1605,12 @@ int main(int argc, char **argv) while (dev_cnt-- > 0) { file = argv[optind++]; if (is_block_device(file) == 1) - if (test_dev_for_mkfs(file, force_overwrite)) - goto error; + ret = test_dev_for_mkfs(file, force_overwrite); + else + ret = test_status_for_mkfs(file, force_overwrite); + + if (ret) + goto error; } optind = saved_optind; @@ -1646,19 +1675,21 @@ int main(int argc, char **argv) goto error; } + min_dev_size = btrfs_min_dev_size(nodesize, mixed, metadata_profile, + data_profile); /* Check device/block_count after the nodesize is determined */ - if (block_count && block_count < btrfs_min_dev_size(nodesize)) { + if (block_count && block_count < min_dev_size) { error("size %llu is too small to make a usable filesystem", block_count); error("minimum size for btrfs filesystem is %llu", - btrfs_min_dev_size(nodesize)); + min_dev_size); goto error; } for (i = saved_optind; i < saved_optind + dev_cnt; i++) { char *path; path = argv[i]; - ret = test_minimum_size(path, nodesize); + ret = test_minimum_size(path, min_dev_size); if (ret < 0) { error("failed to check size for %s: %s", path, strerror(-ret)); @@ -1668,7 +1699,7 @@ int main(int argc, char **argv) error("'%s' is too small to make a usable filesystem", path); error("minimum size for each btrfs device is %llu", - btrfs_min_dev_size(nodesize)); + min_dev_size); goto error; } } @@ -1938,9 +1969,9 @@ raid_groups: */ fs_info->finalize_on_close = 1; out: - ret = close_ctree(root); + close_ret = close_ctree(root); - if (!ret) { + if (!close_ret) { optind = saved_optind; dev_cnt = argc - optind; while (dev_cnt-- > 0) { |