[dm-devel] [PATCH 2/2] dm-raid: add 'ignore_discard' table argument

heinzm at redhat.com heinzm at redhat.com
Wed Sep 24 15:47:19 UTC 2014


From: Heinz Mauelshagen <heinzm at redhat.com>

Add the 'ignore_discard' table line argument to the target in order
to ignore discard processing completely on a RAID array, hence not
passing down discards to MD personalities
(this is in line with our other targets thin and cache).


This addresses:

o prohibit discards in case of _potential_ data corruptions in RAID4/5/6
  (i.e. discard_zeroes_data not processing properly when
   RAID4/5/6 relies on zeroed data)

o avoid discard processing overhead


Signed-off-by: Heinz Mauelshagen <heinzm at redhat.com>

---
 drivers/md/dm-raid.c | 51 +++++++++++++++++++++++++++++++++------------------
 1 file changed, 33 insertions(+), 18 deletions(-)

diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index 4edb2c7..b9614ae 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -56,6 +56,7 @@ struct raid_dev {
 #define DMPF_REGION_SIZE       0x100
 #define DMPF_RAID10_COPIES     0x200
 #define DMPF_RAID10_FORMAT     0x400
+#define DMPF_IGNORE_DISCARD    0x800
 
 struct raid_set {
 	struct dm_target *ti;
@@ -475,6 +476,10 @@ too_many:
  *                                      will form the "stripe"
  *    [[no]sync]			Force or prevent recovery of the
  *                                      entire array
+ *    [ignore_discard]                  Ignore any discards;
+ *                                      can be used in cases of bogus TRIM/UNMAP
+ *                                      support on array legs (e.g. discard_zeroes_data
+ *                                      flaw causing RAID4/5/6 corruption)
  *    [rebuild <idx>]			Rebuild the drive indicated by the index
  *    [daemon_sleep <ms>]		Time between bitmap daemon work to
  *                                      clear bits
@@ -559,6 +564,10 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
 			rs->print_flags |= DMPF_SYNC;
 			continue;
 		}
+		if (!strcasecmp(argv[i], "ignore_discard")) {
+			rs->print_flags |= DMPF_IGNORE_DISCARD;
+			continue;
+		}
 
 		/* The rest of the optional arguments come in key/value pairs */
 		if ((i + 1) >= num_raid_params) {
@@ -1157,33 +1166,37 @@ static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs)
 static void raid_check_discard(struct dm_target *ti, struct raid_set *rs)
 {
 	int i;
-	bool discard_supported = true;
+	bool discard_supported, raid456;
+
+	/* Assume not supported until after checks below. */
+	ti->discards_supported = false;
+
+	/* Assume 'discard_supported = true' unless table argument 'ignore_discard' given */
+	discard_supported = !(rs->print_flags & DMPF_IGNORE_DISCARD);
+	if (!discard_supported)
+		return;
+
 	/* RAID level 4,5,6 request discard_zeroes_data for data integrity! */
-	bool raid1_or_10 = rs->md.level == 1 || rs->md.level == 10;
-	bool zeroes_data_mandatory = !raid1_or_10;
+	raid456 = (rs->md.level == 5 || rs->md.level == 6 || rs->md.level == 4);
 
 	for (i = 0; i < rs->md.raid_disks; i++) {
 		struct request_queue *q = bdev_get_queue(rs->dev[i].rdev.bdev);
 
 		if (!q ||
 		    !blk_queue_discard(q) ||
-		    (zeroes_data_mandatory && !q->limits.discard_zeroes_data)) {
-			discard_supported = false;
-			break;
-		}
+		    (raid456 && !q->limits.discard_zeroes_data))
+			return;
 	}
 
-	if (discard_supported) {
-		ti->discards_supported = true;
-		/*
-		 * raid1 and raid10 personalities require bio splitting,
-		 * raid4/5/6 don't and process large discard bios properly.
-		 */
-		ti->split_discard_bios = raid1_or_10;
-		ti->num_discard_bios = 1;
+	/* Passed check on array legs -> enable discard */
+	ti->discards_supported = true;
 
-	} else
-		ti->discards_supported = false;
+	/*
+	 * RAID1 and RAID10 personalities require bio splitting,
+	 * RAID0/4/5/6 don't and process large discard bios properly
+	 */
+	ti->split_discard_bios = (rs->md.level == 1 || rs->md.level == 10);
+	ti->num_discard_bios = 1;
 }
 
 /*
@@ -1458,6 +1471,8 @@ static void raid_status(struct dm_target *ti, status_type_t type,
 			DMEMIT(" sync");
 		if (rs->print_flags & DMPF_NOSYNC)
 			DMEMIT(" nosync");
+		if (rs->print_flags & DMPF_IGNORE_DISCARD)
+			DMEMIT(" ignore_discard");
 
 		for (i = 0; i < rs->md.raid_disks; i++)
 			if ((rs->print_flags & DMPF_REBUILD) &&
@@ -1694,7 +1709,7 @@ static void raid_resume(struct dm_target *ti)
 
 static struct target_type raid_target = {
 	.name = "raid",
-	.version = {1, 5, 2},
+	.version = {1, 6, 0},
 	.module = THIS_MODULE,
 	.ctr = raid_ctr,
 	.dtr = raid_dtr,
-- 
1.9.3




More information about the dm-devel mailing list