mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 01:08:13 -04:00
md/raid5: validate discard support at request time
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. Link: https://patch.msgid.link/20260605072639.2434847-3-yukuai@kernel.org Signed-off-by: Yu Kuai <yukuai@fygo.io>
This commit is contained in:
@@ -1134,6 +1134,18 @@ static void defer_issue_bios(struct r5conf *conf, sector_t sector,
|
||||
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
|
||||
@@ -5704,6 +5716,9 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi)
|
||||
/* 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,
|
||||
@@ -7817,24 +7832,12 @@ static int raid5_set_limits(struct mddev *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.
|
||||
@@ -7843,6 +7846,7 @@ static int raid5_set_limits(struct mddev *mddev)
|
||||
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;
|
||||
|
||||
@@ -689,6 +689,7 @@ struct r5conf {
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user