diff mbox

[09/12] RAID 4/5/6: Fine-grained TRIM enable for ZDM

Message ID 1459746376-27983-10-git-send-email-shaun@tancheff.com (mailing list archive)
State New, archived
Headers show

Commit Message

Shaun Tancheff April 4, 2016, 5:06 a.m. UTC
Currently RAID 4/5/6 requires an module parameter to enable
discard bios.

This was done due the to general inadequacies of relying on
hardware to correctly self identify.

Since ZDM does not rely on lower level device support to for
TRIM handling it seems reasonable to allow another method to
communicate to MD-RAID that enabling discard is safe.

This method is also more targeted. Devices are not expected
to set this parameter directly. And the kernel module parameter
which assumes devices are unsafe remains intact.

Signed-off-by: Shaun Tancheff <shaun.tancheff@seagate.com>
---
 block/blk-settings.c   |  1 +
 block/blk-sysfs.c      | 11 +++++++++++
 drivers/md/dm-zoned.c  |  4 ++++
 drivers/md/dm-zoned.h  |  1 +
 drivers/md/raid5.c     |  4 +++-
 include/linux/blkdev.h | 22 ++++++++++++++++++----
 6 files changed, 38 insertions(+), 5 deletions(-)
diff mbox

Patch

diff --git a/block/blk-settings.c b/block/blk-settings.c
index c7bb666..04bd7a4 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -101,6 +101,7 @@  void blk_set_default_limits(struct queue_limits *lim)
 	lim->discard_alignment = 0;
 	lim->discard_misaligned = 0;
 	lim->discard_zeroes_data = 0;
+	lim->raid_discard_safe = 0;
 	lim->logical_block_size = lim->physical_block_size = lim->io_min = 512;
 	lim->bounce_pfn = (unsigned long)(BLK_BOUNCE_ANY >> PAGE_SHIFT);
 	lim->alignment_offset = 0;
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index dd93763..c12618a 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -186,6 +186,11 @@  static ssize_t queue_discard_zeroes_data_show(struct request_queue *q, char *pag
 	return queue_var_show(queue_discard_zeroes_data(q), page);
 }
 
+static ssize_t queue_raid_discard_safe_show(struct request_queue *q, char *page)
+{
+	return queue_var_show(queue_raid_discard_safe(q), page);
+}
+
 static ssize_t queue_write_same_max_show(struct request_queue *q, char *page)
 {
 	return sprintf(page, "%llu\n",
@@ -437,6 +442,11 @@  static struct queue_sysfs_entry queue_discard_zeroes_data_entry = {
 	.show = queue_discard_zeroes_data_show,
 };
 
+static struct queue_sysfs_entry queue_raid_discard_safe_entry = {
+	.attr = {.name = "raid_discard_safe", .mode = S_IRUGO },
+	.show = queue_raid_discard_safe_show,
+};
+
 static struct queue_sysfs_entry queue_write_same_max_entry = {
 	.attr = {.name = "write_same_max_bytes", .mode = S_IRUGO },
 	.show = queue_write_same_max_show,
@@ -496,6 +506,7 @@  static struct attribute *default_attrs[] = {
 	&queue_discard_max_entry.attr,
 	&queue_discard_max_hw_entry.attr,
 	&queue_discard_zeroes_data_entry.attr,
+	&queue_raid_discard_safe_entry.attr,
 	&queue_write_same_max_entry.attr,
 	&queue_nonrot_entry.attr,
 	&queue_nomerges_entry.attr,
diff --git a/drivers/md/dm-zoned.c b/drivers/md/dm-zoned.c
index 4e04464..6cab33e 100644
--- a/drivers/md/dm-zoned.c
+++ b/drivers/md/dm-zoned.c
@@ -663,6 +663,7 @@  static int zoned_ctr(struct dm_target *ti, unsigned argc, char **argv)
 	}
 
 	znd->trim = 1;
+	znd->raid5_trim = 0;
 
 	if (argc < 1) {
 		ti->error = "Invalid argument count";
@@ -692,6 +693,8 @@  static int zoned_ctr(struct dm_target *ti, unsigned argc, char **argv)
 			znd->trim = 1;
 		if (!strcasecmp("nodiscard", argv[r]))
 			znd->trim = 0;
+		if (!strcasecmp("raid5_trim", argv[r]))
+			znd->raid5_trim = 1;
 
 		if (!strncasecmp("reserve=", argv[r], 8)) {
 			long long mz_resv;
@@ -2021,6 +2024,7 @@  static void zoned_io_hints(struct dm_target *ti, struct queue_limits *limits)
 		limits->max_discard_sectors = 1 << 30;
 		limits->max_hw_discard_sectors = 1 << 30;
 		limits->discard_zeroes_data = 1;
+		limits->raid_discard_safe = znd->raid5_trim;
 	}
 }
 
diff --git a/drivers/md/dm-zoned.h b/drivers/md/dm-zoned.h
index c73ddea..67f8190 100644
--- a/drivers/md/dm-zoned.h
+++ b/drivers/md/dm-zoned.h
@@ -663,6 +663,7 @@  struct zoned {
 	unsigned issue_close_zone:1;
 	unsigned is_empty:1;
 	unsigned trim:1;
+	unsigned raid5_trim:1;
 
 };
 
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index c96655e..a101399 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -7001,12 +7001,14 @@  static int raid5_run(struct mddev *mddev)
 			    !bdev_get_queue(rdev->bdev)->
 						limits.discard_zeroes_data)
 				discard_supported = false;
+
 			/* Unfortunately, discard_zeroes_data is not currently
 			 * a guarantee - just a hint.  So we only allow DISCARD
 			 * if the sysadmin has confirmed that only safe devices
 			 * are in use by setting a module parameter.
 			 */
-			if (!devices_handle_discard_safely) {
+			if (!devices_handle_discard_safely &&
+			    !bdev_discard_raid_safe(rdev->bdev)) {
 				if (discard_supported) {
 					pr_info("md/raid456: discard support disabled due to uncertainty.\n");
 					pr_info("Set raid456.devices_handle_discard_safely=Y to override.\n");
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 413c84f..ecd50f5 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -273,11 +273,12 @@  struct queue_limits {
 	unsigned short		max_segments;
 	unsigned short		max_integrity_segments;
 
-	unsigned char		misaligned;
-	unsigned char		discard_misaligned;
-	unsigned char		cluster;
-	unsigned char		discard_zeroes_data;
 	unsigned char		raid_partial_stripes_expensive;
+	unsigned		misaligned:1;
+	unsigned		discard_misaligned:1;
+	unsigned		cluster:1;
+	unsigned		discard_zeroes_data:1;
+	unsigned		raid_discard_safe:1;
 };
 
 struct request_queue {
@@ -1320,6 +1321,19 @@  static inline unsigned int bdev_discard_zeroes_data(struct block_device *bdev)
 	return queue_discard_zeroes_data(bdev_get_queue(bdev));
 }
 
+static inline unsigned int queue_raid_discard_safe(struct request_queue *q)
+{
+	if (queue_discard_zeroes_data(q) && q->limits.raid_discard_safe)
+		return 1;
+
+	return 0;
+}
+
+static inline unsigned int bdev_discard_raid_safe(struct block_device *bdev)
+{
+	return queue_raid_discard_safe(bdev_get_queue(bdev));
+}
+
 static inline unsigned int bdev_write_same(struct block_device *bdev)
 {
 	struct request_queue *q = bdev_get_queue(bdev);