From 2abf01cc5a19a0583f5fc7c4fac35cfbbfd6bfe2 Mon Sep 17 00:00:00 2001
From: Emil Karlson <jekarlson@gmail.com>
Date: Sun, 23 Sep 2018 00:23:56 +0300
Subject: [PATCH 2/4] limit max_devs to max_stripes

---
 fs/btrfs/ctree.h   |  1 +
 fs/btrfs/disk-io.c |  1 +
 fs/btrfs/super.c   | 15 +++++++++++++++
 fs/btrfs/volumes.c |  2 ++
 4 files changed, 19 insertions(+)

diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 2cddfe7806a4..929392dfb960 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -815,6 +815,7 @@ struct btrfs_fs_info {
 	unsigned long compress_type:4;
 	unsigned int compress_level;
 	u32 commit_interval;
+	u32 max_stripes;
 	/*
 	 * It is a suggestive number, the read side is safe even it gets a
 	 * wrong number because we will write out the data into a regular
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 834a3f5ef642..f6062ac71b71 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2696,6 +2696,7 @@ int open_ctree(struct super_block *sb,
 	atomic64_set(&fs_info->free_chunk_space, 0);
 	fs_info->tree_mod_log = RB_ROOT;
 	fs_info->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL;
+	fs_info->max_stripes = 0;
 	fs_info->avg_delayed_ref_runtime = NSEC_PER_SEC >> 6; /* div by 64 */
 	/* readahead state */
 	INIT_RADIX_TREE(&fs_info->reada_tree, GFP_NOFS & ~__GFP_DIRECT_RECLAIM);
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 8ad145820ea8..0a0c0ad51a89 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -326,6 +326,7 @@ enum {
 	Opt_treelog, Opt_notreelog,
 	Opt_usebackuproot,
 	Opt_user_subvol_rm_allowed,
+	Opt_max_stripes,
 
 	/* Deprecated options */
 	Opt_alloc_start,
@@ -351,6 +352,7 @@ static const match_table_t tokens = {
 	{Opt_noacl, "noacl"},
 	{Opt_clear_cache, "clear_cache"},
 	{Opt_commit_interval, "commit=%u"},
+	{Opt_max_stripes, "max_stripes=%u"},
 	{Opt_compress, "compress"},
 	{Opt_compress_type, "compress=%s"},
 	{Opt_compress_force, "compress-force"},
@@ -822,6 +824,17 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
 			}
 			info->commit_interval = intarg;
 			break;
+		case Opt_max_stripes:
+			intarg = 0;
+			ret = match_int(&args[0], &intarg);
+			if (ret < 0 || intarg < 2) {
+				btrfs_err(info, "invalid max stripes");
+				ret = -EINVAL;
+				goto out;
+			}
+			info->max_stripes = intarg;
+			break;
+
 #ifdef CONFIG_BTRFS_DEBUG
 		case Opt_fragment_all:
 			btrfs_info(info, "fragmenting all space");
@@ -1352,6 +1365,8 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
 		seq_puts(seq, ",fatal_errors=panic");
 	if (info->commit_interval != BTRFS_DEFAULT_COMMIT_INTERVAL)
 		seq_printf(seq, ",commit=%u", info->commit_interval);
+	if (info->max_stripes != 0)
+		seq_printf(seq, ",max_stripes=%u", info->max_stripes);
 #ifdef CONFIG_BTRFS_DEBUG
 	if (btrfs_test_opt(info, FRAGMENT_DATA))
 		seq_puts(seq, ",fragment=data");
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 69077a96cd40..00af07fd532d 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -4670,6 +4670,8 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
 		       type);
 		BUG_ON(1);
 	}
+	if (info->max_stripes)
+		devs_max = min(devs_max, max(devs_min, (int)info->max_stripes));
 
 	/* we don't want a chunk larger than 10% of writeable space */
 	max_chunk_size = min(div_factor(fs_devices->total_rw_bytes, 1),
-- 
2.20.0.rc2

