From c53112c4cd10e81724d5dac797f88a182f18342a Mon Sep 17 00:00:00 2001
From: Emil Karlson <jekarlson@gmail.com>
Date: Sat, 22 Sep 2018 23:54:31 +0300
Subject: [PATCH 1/4] prefer nonrot devs for metadata alloc

---
 fs/btrfs/volumes.c | 36 ++++++++++++++++++++++++++++++++++--
 1 file changed, 34 insertions(+), 2 deletions(-)

diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index f4405e430da6..69077a96cd40 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -4557,6 +4557,30 @@ static int btrfs_cmp_device_info(const void *a, const void *b)
 		return 1;
 	return 0;
 }
+/*
+ * sort the devices in descending order by max_avail, total_avail or by rotation spec
+ */
+static int btrfs_cmp_device_info_nonrot(const void *a, const void *b, u64 max_stripe)
+{
+	const struct btrfs_device_info *di_a = a;
+	const struct btrfs_device_info *di_b = b;
+	if (di_a->max_avail != max_stripe || di_b->max_avail != max_stripe)
+		return btrfs_cmp_device_info(a, b);
+
+	if (blk_queue_nonrot(bdev_get_queue(di_a->dev->bdev)) && !blk_queue_nonrot(bdev_get_queue(di_b->dev->bdev)))
+		return -1;
+	if (!blk_queue_nonrot(bdev_get_queue(di_a->dev->bdev)) && blk_queue_nonrot(bdev_get_queue(di_b->dev->bdev)))
+		return 1;
+	return btrfs_cmp_device_info(a, b);
+}
+static int btrfs_cmp_device_info_meta(const void *a, const void *b)
+{
+	return btrfs_cmp_device_info_nonrot(a, b, SZ_1G);
+}
+static int btrfs_cmp_device_info_system(const void *a, const void *b)
+{
+	return btrfs_cmp_device_info_nonrot(a, b, SZ_32M);
+}
 
 static void check_raid56_incompat_flag(struct btrfs_fs_info *info, u64 type)
 {
@@ -4718,8 +4742,16 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
 	/*
 	 * now sort the devices by hole size / available space
 	 */
-	sort(devices_info, ndevs, sizeof(struct btrfs_device_info),
-	     btrfs_cmp_device_info, NULL);
+	if (type & BTRFS_BLOCK_GROUP_DATA) {
+		sort(devices_info, ndevs, sizeof(struct btrfs_device_info),
+		     btrfs_cmp_device_info, NULL);
+	} else if (type & BTRFS_BLOCK_GROUP_METADATA) {
+		sort(devices_info, ndevs, sizeof(struct btrfs_device_info),
+		     btrfs_cmp_device_info_meta, NULL);
+	} else {
+		sort(devices_info, ndevs, sizeof(struct btrfs_device_info),
+		     btrfs_cmp_device_info_system, NULL);
+	}
 
 	/* round down to number of usable stripes */
 	ndevs = round_down(ndevs, devs_increment);
-- 
2.20.0.rc2

