[PATCH v2 2/3] md/raid5: validate discard support at request time
Yu Kuai <[email protected]>
| Newsgroups | gmane.linux.raid,gmane.linux.kernel |
|---|---|
| Message-ID | <[email protected]> |
From: Yu Kuai <[email protected]> Raid5 used to disable discard limits when devices_handle_discard_safely was not set or when stacked member limits could not support a full-stripe discard. That hides discard from userspace before raid5 can decide whether a request can be handled safely. Follow other virtual drivers and advertise a UINT_MAX discard limit for the md device. Cache lower discard support in r5conf when setting queue limits, and reject unsupported discard bios before queuing stripe work. Signed-off-by: Yu Kuai <[email protected]> --- drivers/md/raid5.c | 34 +++++++++++++++++++--------------- drivers/md/raid5.h | 1 + 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index debf35342ae0..76e736ee48d3 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1132,10 +1132,22 @@ static void defer_issue_bios(struct r5conf *conf, sector_t sector, spin_unlock(&conf->pending_bios_lock); dispatch_bio_list(&tmp); } +static bool raid5_discard_limits(struct mddev *mddev, struct bio *bi) +{ + struct r5conf *conf = mddev->private; + + if (!conf->raid5_discard_unsupported) + return true; + + bi->bi_status = BLK_STS_NOTSUPP; + bio_endio(bi); + return false; +} + static void raid5_end_read_request(struct bio *bi); static void raid5_end_write_request(struct bio *bi); @@ -5702,10 +5714,13 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi) if (mddev->reshape_position != MaxSector) /* Skip discard while reshape is happening */ return; + if (!raid5_discard_limits(mddev, bi)) + return; + stripe_sectors = conf->chunk_sectors * (conf->raid_disks - conf->max_degraded); first_stripe = DIV_ROUND_UP_SECTOR_T(bi->bi_iter.bi_sector, stripe_sectors); last_stripe = bio_end_sector(bi); @@ -7815,36 +7830,25 @@ static int raid5_set_limits(struct mddev *mddev) mddev_stack_rdev_limits(mddev, &lim, 0); rdev_for_each(rdev, mddev) queue_limits_stack_bdev(&lim, rdev->bdev, rdev->new_data_offset, mddev->gendisk->disk_name); - /* - * Zeroing is required for discard, otherwise data could be lost. - * - * Consider a scenario: discard a stripe (the stripe could be - * inconsistent if discard_zeroes_data is 0); write one disk of the - * stripe (the stripe could be inconsistent again depending on which - * disks are used to calculate parity); the disk is broken; The stripe - * data of this disk is lost. - * - * We only allow DISCARD if the sysadmin has confirmed that only safe - * devices are in use by setting a module parameter. A better idea - * might be to turn DISCARD into WRITE_ZEROES requests, as that is - * required to be safe. - */ if (!devices_handle_discard_safely || lim.max_discard_sectors < (stripe >> 9) || lim.discard_granularity < stripe) - lim.max_hw_discard_sectors = 0; + conf->raid5_discard_unsupported = true; + else + conf->raid5_discard_unsupported = false; /* * Requests require having a bitmap for each stripe. * Limit the max sectors based on this. */ lim.max_hw_sectors = RAID5_MAX_REQ_STRIPES << RAID5_STRIPE_SHIFT(conf); if ((lim.max_hw_sectors << 9) < lim.io_opt) lim.max_hw_sectors = lim.io_opt >> 9; + lim.max_hw_discard_sectors = UINT_MAX; /* No restrictions on the number of segments in the request */ lim.max_segments = USHRT_MAX; return queue_limits_set(mddev->gendisk->queue, &lim); diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index 1c7b710fc9c1..ba06cf88aa24 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -687,10 +687,11 @@ struct r5conf { struct r5pending_data *pending_data; struct list_head free_list; struct list_head pending_list; int pending_data_cnt; struct r5pending_data *next_pending_data; + bool raid5_discard_unsupported; mempool_t *ctx_pool; int ctx_size; }; -- 2.51.0