summaryrefslogtreecommitdiff
path: root/mkfs
diff options
context:
space:
mode:
authorQu Wenruo <wqu@suse.com>2017-10-12 14:24:34 +0800
committerDavid Sterba <dsterba@suse.com>2018-01-03 17:10:11 +0100
commit31d228a2eb98d95637338bf77b5abcd375614d15 (patch)
tree8a22f1014b9be4c945582df1def60b566ce3b2ce /mkfs
parent2c2db167c79bee6c0ce88f55f964135908654f74 (diff)
btrfs-progs: mkfs: Enhance minimal device size calculation to fix mkfs failure on small file
Since commit c11e36a29e84 ("Btrfs-progs: Do not force mixed block group creation unless '-M' option is specified"), mkfs no longer use mixed block group unless specified manually. This breaks the minimal device size calculation, which only considered mixed block group use case. This patch enhances minimal device size calculation for mkfs, by using different minimal stripe length (calculated from code) for different profiles, and use them to calculate minimal device size. Reported-by: Wesley Aptekar-Cassels <W.Aptekar@gmail.com> Fixes: c11e36a29e84 ("Btrfs-progs: Do not force mixed block group creation unless '-M' option is specified") Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: Lu Fengqi <lufq.fnst@cn.fujitsu.com> [ updated comments ] Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'mkfs')
-rw-r--r--mkfs/common.c69
-rw-r--r--mkfs/common.h4
-rw-r--r--mkfs/main.c3
3 files changed, 66 insertions, 10 deletions
diff --git a/mkfs/common.c b/mkfs/common.c
index ba47684b..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)
diff --git a/mkfs/common.h b/mkfs/common.h
index d63c5ebb..f6b60c28 100644
--- a/mkfs/common.h
+++ b/mkfs/common.h
@@ -66,8 +66,8 @@ 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);
+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,
diff --git a/mkfs/main.c b/mkfs/main.c
index e405e5a2..90fab59b 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -1668,7 +1668,8 @@ int main(int argc, char **argv)
goto error;
}
- min_dev_size = btrfs_min_dev_size(nodesize);
+ 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 < min_dev_size) {
error("size %llu is too small to make a usable filesystem",