diff options
| author | Heinz Mauelshagen <heinzm@redhat.com> | 2014-09-24 17:47:19 +0200 |
|---|---|---|
| committer | Mike Snitzer <snitzer@redhat.com> | 2014-10-02 13:45:26 -0400 |
| commit | bfc3f335f9886b68d281240aab751b96259d8860 (patch) | |
| tree | 4db056dcca547d9e42e0dae3cfc29e484574bb10 | |
| parent | df01e0d7b89039d38659c55612e475dd3459d52f (diff) | |
| download | linux-dm-bfc3f335f9886b68d281240aab751b96259d8860.tar.gz | |
dm raid: add discard support for RAID levels 4, 5 and 6
Notice: this object is not reachable from any branch.
In case of RAID levels 4, 5 and 6 we have to verify each RAID members'
ability to zero data on discards to avoid stripe data corruption -- if
discard_zeroes_data is not set for each RAID member discard support must
be disabled. But given the uncertainty of whether or not a RAID member
properly supports zeroing data on discard we require the user to
explicitly allow discard support on RAID levels 4, 5, and 6 by setting
the 'devices_handle_discard_safely' parameter on dm-raid table load.
Otherwise, discards could cause data corruption in RAID4/5/6.
Signed-off-by: Heinz Mauelshagen <heinzm@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Notice: this object is not reachable from any branch.
| -rw-r--r-- | drivers/md/dm-raid.c | 39 |
1 files changed, 35 insertions, 4 deletions
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 030e2d6bc2614..6c79bc2c19804 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_ALLOW_DISCARD 0x800 struct raid_set { struct dm_target *ti; @@ -475,6 +476,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 @@ -559,6 +562,10 @@ static int parse_raid_params(struct raid_set *rs, char **argv, rs->print_flags |= DMPF_SYNC; continue; } + if (!strcasecmp(argv[i], "devices_handle_discard_safely")) { + rs->print_flags |= DMPF_ALLOW_DISCARD; + continue; + } /* The rest of the optional arguments come in key/value pairs */ if ((i + 1) >= num_raid_params) { @@ -1150,23 +1157,45 @@ static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs) } /* - * Enable/disable discard support on RAID set depending on RAID level. + * 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! */ - if (rs->md.level == 4 || rs->md.level == 5 || rs->md.level == 6) - return; /* discard_zeroes_data cannot be trusted as reliable */ + 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 (!(rs->print_flags & DMPF_ALLOW_DISCARD)) { + DMERR("raid456 discard support disabled due to discard_zeroes_data uncertainty."); + DMERR("set 'devices_handle_discard_safely' parameter 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 = true; + ti->split_discard_bios = !!(rs->md.level == 1 || rs->md.level == 10); ti->num_discard_bios = 1; } @@ -1442,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_ALLOW_DISCARD) + DMEMIT(" devices_handle_discard_safely"); for (i = 0; i < rs->md.raid_disks; i++) if ((rs->print_flags & DMPF_REBUILD) && |
