Merge tag 'v3.18-rc1' into v4l_for_linus
[cascardo/linux.git] / drivers / md / dm-raid.c
index 4880b69..4857fa4 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2010-2011 Neil Brown
- * Copyright (C) 2010-2011 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2010-2014 Red Hat, Inc. All rights reserved.
  *
  * This file is released under the GPL.
  */
@@ -18,6 +18,8 @@
 
 #define DM_MSG_PREFIX "raid"
 
+static bool devices_handle_discard_safely = false;
+
 /*
  * The following flags are used by dm-raid.c to set up the array state.
  * They must be cleared before md_run is called.
@@ -475,6 +477,8 @@ too_many:
  *                                      will form the "stripe"
  *    [[no]sync]                       Force or prevent recovery of the
  *                                      entire array
+ *    [devices_handle_discard_safely]  Allow discards on RAID4/5/6; useful if RAID
+ *                                     member device(s) properly support TRIM/UNMAP
  *    [rebuild <idx>]                  Rebuild the drive indicated by the index
  *    [daemon_sleep <ms>]              Time between bitmap daemon work to
  *                                      clear bits
@@ -1149,6 +1153,49 @@ static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs)
        return 0;
 }
 
+/*
+ * Enable/disable discard support on RAID set depending on
+ * RAID level and discard properties of underlying RAID members.
+ */
+static void configure_discard_support(struct dm_target *ti, struct raid_set *rs)
+{
+       int i;
+       bool raid456;
+
+       /* Assume discards not supported until after checks below. */
+       ti->discards_supported = false;
+
+       /* RAID level 4,5,6 require discard_zeroes_data for data integrity! */
+       raid456 = (rs->md.level == 4 || rs->md.level == 5 || rs->md.level == 6);
+
+       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))
+                       return;
+
+               if (raid456) {
+                       if (!q->limits.discard_zeroes_data)
+                               return;
+                       if (!devices_handle_discard_safely) {
+                               DMERR("raid456 discard support disabled due to discard_zeroes_data uncertainty.");
+                               DMERR("Set dm-raid.devices_handle_discard_safely=Y to override.");
+                               return;
+                       }
+               }
+       }
+
+       /* All RAID members properly support discards */
+       ti->discards_supported = true;
+
+       /*
+        * 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;
+}
+
 /*
  * Construct a RAID4/5/6 mapping:
  * Args:
@@ -1231,6 +1278,11 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
        ti->private = rs;
        ti->num_flush_bios = 1;
 
+       /*
+        * Disable/enable discard support on RAID set.
+        */
+       configure_discard_support(ti, rs);
+
        mutex_lock(&rs->md.reconfig_mutex);
        ret = md_run(&rs->md);
        rs->md.in_sync = 0; /* Assume already marked dirty */
@@ -1652,7 +1704,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,
@@ -1683,6 +1735,10 @@ static void __exit dm_raid_exit(void)
 module_init(dm_raid_init);
 module_exit(dm_raid_exit);
 
+module_param(devices_handle_discard_safely, bool, 0644);
+MODULE_PARM_DESC(devices_handle_discard_safely,
+                "Set to Y if all devices in each array reliably return zeroes on reads from discarded regions");
+
 MODULE_DESCRIPTION(DM_NAME " raid4/5/6 target");
 MODULE_ALIAS("dm-raid1");
 MODULE_ALIAS("dm-raid10");