summaryrefslogtreecommitdiff
path: root/drivers/md
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-06-25 09:56:47 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-06-25 09:56:47 -0700
commita142da0b2d32b68a6d1b183343bbe43de8c222f9 (patch)
tree5a34a2353fa25d1b498f98e28a7776f7cdaec8d2 /drivers/md
parentc58ddac1aa507b71cb5a95a95c641bdd73a3f075 (diff)
parenta1c8bdbbd72564cebb0d02948c1ed57b80b2e773 (diff)
Merge tag 'block-7.2-20260625' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux
Pull block fixes from Jens Axboe: - blk-cgroup locking rework and fixes: - fix a use-after-free in __blkcg_rstat_flush() - defer freeing policy data until after an RCU grace period - defer the blkcg css_put until the blkg is unlinked from the queue - unwind the queue_lock nesting under RCU / blkcg->lock across the lookup, create, associate and destroy paths - NVMe fixes via Keith: - Fix a crash and memory leak during invalid cdev teardown, and related cdev cleanups (Maurizio, John) - nvmet fixes: handle TCP_CLOSING in the tcp state_change handler, reject short AUTH_RECEIVE buffers, handle inline data with a nonzero offset in rdma, fix an sq refcount leak, and allocate ana_state with the port (Maurizio, Michael, Bryam, Wentao, Rosen) - nvme-fc fix to not cancel requests on an IO target before it is initialized (Mohamed) - nvme-apple fix to prevent shared tags across queues on Apple A11 (Nick) - Various smaller fixes and cleanups (John) - MD fixes via Yu Kuai: - raid1/raid10 fixes for writes_pending and barrier reference leaks on write and discard failures, plus REQ_NOWAIT handling fixes (Abd-Alrhman) - raid5 discard accounting and validation, and a batch of fixes for stripe batch races (Yu Kuai, Chen) - Protect raid1 head_position during read balancing (Chen) - block bio-integrity fixes: correct an error injection static key decrement, fix GFP flag confusion in bio_integrity_alloc_buf(), and handle REQ_OP_ZONE_APPEND in __bio_integrity_action() (Christoph) - Fixes for bio_iov_iter_bounce_write(): revert the iov_iter after a short copy, and respect the iov_iter nofault flag (Qu) - Invalidate the cached plug timestamp after a task switch, and clear PF_BLOCK_TS in copy_process() (Usama) - Fix the IORING_URING_CMD_REISSUE flags check in blkdev_uring_cmd() (Yitang) - Remove a redundant plug in __submit_bio() (Wen) - Don't warn when reclassifying a busy socket lock in nbd (Deepanshu) * tag 'block-7.2-20260625' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux: (45 commits) block: handle REQ_OP_ZONE_APPEND in __bio_integrity_action block: fix GFP_ flags confusion in bio_integrity_alloc_buf block, bfq: don't grab queue_lock to initialize bfq mm/page_io: don't nest queue_lock under rcu in bio_associate_blkg_from_page() blk-cgroup: don't nest queue_lock under blkcg->lock in blkcg_destroy_blkgs() blk-cgroup: don't nest queue_lock under rcu in bio_associate_blkg() blk-cgroup: don't nest queue_lock under rcu in blkg_lookup_create() blk-cgroup: don't nest queue_lock under rcu in blkcg_print_blkgs() blk-cgroup: delay freeing policy data after rcu grace period blk-cgroup: protect iterating blkgs with blkcg->lock in blkcg_print_stat() md/raid5: avoid R5_Overlap races while breaking stripe batches md/raid5: use stripe state snapshot in break_stripe_batch_list() blk-cgroup: defer blkcg css_put until blkg is unlinked from queue blk-cgroup: fix UAF in __blkcg_rstat_flush() block, bfq: protect async queue reset with blkcg locks nbd: don't warn when reclassifying a busy socket lock block: fix incorrect error injection static key decrement md/raid5: let stripe batch bm_seq comparison wrap-safe md/raid1: protect head_position for read balance md/raid1: free r1_bio when REQ_NOWAIT is set and read would block on retry ...
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/md-bitmap.c9
-rw-r--r--drivers/md/md-bitmap.h2
-rw-r--r--drivers/md/md-llbitmap.c13
-rw-r--r--drivers/md/md.c2
-rw-r--r--drivers/md/raid1.c99
-rw-r--r--drivers/md/raid10.c28
-rw-r--r--drivers/md/raid5.c131
-rw-r--r--drivers/md/raid5.h1
8 files changed, 178 insertions, 107 deletions
diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
index 7d778fe1c47c..0f02e2956398 100644
--- a/drivers/md/md-bitmap.c
+++ b/drivers/md/md-bitmap.c
@@ -2064,18 +2064,23 @@ static void bitmap_end_behind_write(struct mddev *mddev)
bitmap->mddev->bitmap_info.max_write_behind);
}
-static void bitmap_wait_behind_writes(struct mddev *mddev)
+static bool bitmap_wait_behind_writes(struct mddev *mddev, bool nowait)
{
struct bitmap *bitmap = mddev->bitmap;
/* wait for behind writes to complete */
if (bitmap && atomic_read(&bitmap->behind_writes) > 0) {
+ if (nowait)
+ return false;
+
pr_debug("md:%s: behind writes in progress - waiting to stop.\n",
mdname(mddev));
/* need to kick something here to make sure I/O goes? */
wait_event(bitmap->behind_wait,
atomic_read(&bitmap->behind_writes) == 0);
}
+
+ return true;
}
static void bitmap_destroy(struct mddev *mddev)
@@ -2085,7 +2090,7 @@ static void bitmap_destroy(struct mddev *mddev)
if (!bitmap) /* there was no bitmap */
return;
- bitmap_wait_behind_writes(mddev);
+ bitmap_wait_behind_writes(mddev, false);
if (!test_bit(MD_SERIALIZE_POLICY, &mddev->flags))
mddev_destroy_serial_pool(mddev, NULL);
diff --git a/drivers/md/md-bitmap.h b/drivers/md/md-bitmap.h
index 214f623c7e79..f46674bdfeb9 100644
--- a/drivers/md/md-bitmap.h
+++ b/drivers/md/md-bitmap.h
@@ -98,7 +98,7 @@ struct bitmap_operations {
void (*start_behind_write)(struct mddev *mddev);
void (*end_behind_write)(struct mddev *mddev);
- void (*wait_behind_writes)(struct mddev *mddev);
+ bool (*wait_behind_writes)(struct mddev *mddev, bool nowait);
md_bitmap_fn *start_write;
md_bitmap_fn *end_write;
diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c
index 1adc5b117821..5a4e2abaa757 100644
--- a/drivers/md/md-llbitmap.c
+++ b/drivers/md/md-llbitmap.c
@@ -1574,16 +1574,19 @@ static void llbitmap_end_behind_write(struct mddev *mddev)
wake_up(&llbitmap->behind_wait);
}
-static void llbitmap_wait_behind_writes(struct mddev *mddev)
+static bool llbitmap_wait_behind_writes(struct mddev *mddev, bool nowait)
{
struct llbitmap *llbitmap = mddev->bitmap;
- if (!llbitmap)
- return;
+ if (llbitmap && atomic_read(&llbitmap->behind_writes) > 0) {
+ if (nowait)
+ return false;
- wait_event(llbitmap->behind_wait,
- atomic_read(&llbitmap->behind_writes) == 0);
+ wait_event(llbitmap->behind_wait,
+ atomic_read(&llbitmap->behind_writes) == 0);
+ }
+ return true;
}
static ssize_t bits_show(struct mddev *mddev, char *page)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 096bb64e87bd..d1465bcd86c8 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -7050,7 +7050,7 @@ EXPORT_SYMBOL_GPL(md_stop_writes);
static void mddev_detach(struct mddev *mddev)
{
if (md_bitmap_enabled(mddev, false))
- mddev->bitmap_ops->wait_behind_writes(mddev);
+ mddev->bitmap_ops->wait_behind_writes(mddev, false);
if (mddev->pers && mddev->pers->quiesce && !is_md_suspended(mddev)) {
mddev->pers->quiesce(mddev, 1);
mddev->pers->quiesce(mddev, 0);
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 5b9368bd9e70..afe2ca96ad8c 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -359,8 +359,8 @@ static inline void update_head_pos(int disk, struct r1bio *r1_bio)
{
struct r1conf *conf = r1_bio->mddev->private;
- conf->mirrors[disk].head_position =
- r1_bio->sector + (r1_bio->sectors);
+ WRITE_ONCE(conf->mirrors[disk].head_position,
+ r1_bio->sector + r1_bio->sectors);
}
/*
@@ -737,7 +737,7 @@ static bool is_sequential(struct r1conf *conf, int disk, struct r1bio *r1_bio)
{
/* TODO: address issues with this check and concurrency. */
return conf->mirrors[disk].next_seq_sect == r1_bio->sector ||
- conf->mirrors[disk].head_position == r1_bio->sector;
+ READ_ONCE(conf->mirrors[disk].head_position) == r1_bio->sector;
}
/*
@@ -814,7 +814,8 @@ static int choose_best_rdev(struct r1conf *conf, struct r1bio *r1_bio)
set_bit(R1BIO_FailFast, &r1_bio->state);
pending = atomic_read(&rdev->nr_pending);
- dist = abs(r1_bio->sector - conf->mirrors[disk].head_position);
+ dist = abs(r1_bio->sector -
+ READ_ONCE(conf->mirrors[disk].head_position));
/* Don't change to another disk for sequential reads */
if (is_sequential(conf, disk, r1_bio)) {
@@ -1341,6 +1342,7 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
int max_sectors;
int rdisk;
bool r1bio_existed = !!r1_bio;
+ bool nowait = bio->bi_opf & REQ_NOWAIT;
/*
* An md cloned bio indicates we are in the error path.
@@ -1360,9 +1362,14 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
* Still need barrier for READ in case that whole
* array is frozen.
*/
- if (!wait_read_barrier(conf, bio->bi_iter.bi_sector,
- bio->bi_opf & REQ_NOWAIT)) {
+ if (!wait_read_barrier(conf, bio->bi_iter.bi_sector, nowait)) {
bio_wouldblock_error(bio);
+
+ if (r1bio_existed) {
+ set_bit(R1BIO_Returned, &r1_bio->state);
+ raid_end_bio_io(r1_bio);
+ }
+
return;
}
@@ -1402,7 +1409,11 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
* over-take any writes that are 'behind'
*/
mddev_add_trace_msg(mddev, "raid1 wait behind writes");
- mddev->bitmap_ops->wait_behind_writes(mddev);
+ if (!mddev->bitmap_ops->wait_behind_writes(mddev, nowait)) {
+ bio_wouldblock_error(bio);
+ set_bit(R1BIO_Returned, &r1_bio->state);
+ goto err_handle;
+ }
}
if (max_sectors < bio_sectors(bio)) {
@@ -1501,29 +1512,30 @@ static void raid1_start_write_behind(struct mddev *mddev, struct r1bio *r1_bio,
}
-static void raid1_write_request(struct mddev *mddev, struct bio *bio,
- int max_write_sectors)
+static bool raid1_write_request(struct mddev *mddev, struct bio *bio,
+ int max_sectors)
{
struct r1conf *conf = mddev->private;
struct r1bio *r1_bio;
int i, disks, k;
unsigned long flags;
int first_clone;
- int max_sectors;
bool write_behind = false;
- bool is_discard = (bio_op(bio) == REQ_OP_DISCARD);
+ bool nowait = bio->bi_opf & REQ_NOWAIT;
+ bool is_discard = op_is_discard(bio->bi_opf);
+ sector_t sector = bio->bi_iter.bi_sector;
if (mddev_is_clustered(mddev) &&
- mddev->cluster_ops->area_resyncing(mddev, WRITE,
- bio->bi_iter.bi_sector, bio_end_sector(bio))) {
+ mddev->cluster_ops->area_resyncing(mddev, WRITE, sector,
+ bio_end_sector(bio))) {
- if (bio->bi_opf & REQ_NOWAIT) {
+ if (nowait) {
bio_wouldblock_error(bio);
- return;
+ return false;
}
wait_event_idle(conf->wait_barrier,
!mddev->cluster_ops->area_resyncing(mddev, WRITE,
- bio->bi_iter.bi_sector,
+ sector,
bio_end_sector(bio)));
}
@@ -1532,19 +1544,18 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
* thread has put up a bar for new requests.
* Continue immediately if no resync is active currently.
*/
- if (!wait_barrier(conf, bio->bi_iter.bi_sector,
- bio->bi_opf & REQ_NOWAIT)) {
+ if (!wait_barrier(conf, sector, nowait)) {
bio_wouldblock_error(bio);
- return;
+ return false;
}
if (!wait_blocked_rdev(mddev, bio)) {
bio_wouldblock_error(bio);
- return;
+ goto err_allow_barrier;
}
r1_bio = alloc_r1bio(mddev, bio);
- r1_bio->sectors = max_write_sectors;
+ r1_bio->sectors = max_sectors;
/* first select target devices under rcu_lock and
* inc refcount on their rdev. Record them by setting
@@ -1558,7 +1569,6 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
*/
disks = conf->raid_disks * 2;
- max_sectors = r1_bio->sectors;
for (i = 0; i < disks; i++) {
struct md_rdev *rdev = conf->mirrors[i].rdev;
@@ -1574,23 +1584,21 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
if (!rdev || test_bit(Faulty, &rdev->flags))
continue;
- atomic_inc(&rdev->nr_pending);
if (test_bit(WriteErrorSeen, &rdev->flags)) {
sector_t first_bad;
sector_t bad_sectors;
int is_bad;
- is_bad = is_badblock(rdev, r1_bio->sector, max_sectors,
+ is_bad = is_badblock(rdev, sector, max_sectors,
&first_bad, &bad_sectors);
- if (is_bad && first_bad <= r1_bio->sector) {
+ if (is_bad && first_bad <= sector) {
/* Cannot write here at all */
- bad_sectors -= (r1_bio->sector - first_bad);
+ bad_sectors -= (sector - first_bad);
if (bad_sectors < max_sectors)
/* mustn't write more than bad_sectors
* to other devices yet
*/
max_sectors = bad_sectors;
- rdev_dec_pending(rdev, mddev);
continue;
}
if (is_bad) {
@@ -1604,15 +1612,18 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
* the benefit.
*/
if (bio->bi_opf & REQ_ATOMIC) {
- rdev_dec_pending(rdev, mddev);
- goto err_handle;
+ bio->bi_status = BLK_STS_NOTSUPP;
+ bio_endio(bio);
+ goto err_dec_pending;
}
- good_sectors = first_bad - r1_bio->sector;
+ good_sectors = first_bad - sector;
if (good_sectors < max_sectors)
max_sectors = good_sectors;
}
}
+
+ atomic_inc(&rdev->nr_pending);
r1_bio->bios[i] = bio;
}
@@ -1628,10 +1639,8 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
if (max_sectors < bio_sectors(bio)) {
bio = bio_submit_split_bioset(bio, max_sectors,
&conf->bio_split);
- if (!bio) {
- set_bit(R1BIO_Returned, &r1_bio->state);
- goto err_handle;
- }
+ if (!bio)
+ goto err_dec_pending;
r1_bio->master_bio = bio;
r1_bio->sectors = max_sectors;
@@ -1675,7 +1684,7 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
mbio->bi_opf &= ~REQ_NOWAIT;
r1_bio->bios[i] = mbio;
- mbio->bi_iter.bi_sector = (r1_bio->sector + rdev->data_offset);
+ mbio->bi_iter.bi_sector = sector + rdev->data_offset;
mbio->bi_end_io = raid1_end_write_request;
if (test_bit(FailFast, &rdev->flags) &&
!test_bit(WriteMostly, &rdev->flags) &&
@@ -1684,7 +1693,7 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
mbio->bi_private = r1_bio;
atomic_inc(&r1_bio->remaining);
- mddev_trace_remap(mddev, mbio, r1_bio->sector);
+ mddev_trace_remap(mddev, mbio, sector);
/* flush_pending_writes() needs access to the rdev so...*/
mbio->bi_bdev = (void *)rdev;
if (!raid1_add_bio_to_plug(mddev, mbio, raid1_unplug, disks)) {
@@ -1699,8 +1708,10 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
/* In case raid1d snuck in to freeze_array */
wake_up_barrier(conf);
- return;
-err_handle:
+
+ return true;
+
+err_dec_pending:
for (k = 0; k < i; k++) {
if (r1_bio->bios[k]) {
rdev_dec_pending(conf->mirrors[k].rdev, mddev);
@@ -1708,7 +1719,12 @@ err_handle:
}
}
- raid_end_bio_io(r1_bio);
+ free_r1bio(r1_bio);
+
+err_allow_barrier:
+ allow_barrier(conf, sector);
+
+ return false;
}
static bool raid1_make_request(struct mddev *mddev, struct bio *bio)
@@ -1732,8 +1748,9 @@ static bool raid1_make_request(struct mddev *mddev, struct bio *bio)
if (bio_data_dir(bio) == READ)
raid1_read_request(mddev, bio, sectors, NULL);
else {
- md_write_start(mddev,bio);
- raid1_write_request(mddev, bio, sectors);
+ md_write_start(mddev, bio);
+ if (!raid1_write_request(mddev, bio, sectors))
+ md_write_end(mddev);
}
return true;
}
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index cee5a253a281..0a3cfdd3f5df 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1349,7 +1349,7 @@ retry_wait:
}
}
-static void raid10_write_request(struct mddev *mddev, struct bio *bio,
+static bool raid10_write_request(struct mddev *mddev, struct bio *bio,
struct r10bio *r10_bio)
{
struct r10conf *conf = mddev->private;
@@ -1365,7 +1365,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
/* Bail out if REQ_NOWAIT is set for the bio */
if (bio->bi_opf & REQ_NOWAIT) {
bio_wouldblock_error(bio);
- return;
+ return false;
}
for (;;) {
prepare_to_wait(&conf->wait_barrier,
@@ -1381,7 +1381,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
sectors = r10_bio->sectors;
if (!regular_request_wait(mddev, conf, bio, sectors)) {
free_r10bio(r10_bio);
- return;
+ return false;
}
if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
@@ -1398,7 +1398,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
if (bio->bi_opf & REQ_NOWAIT) {
allow_barrier(conf);
bio_wouldblock_error(bio);
- return;
+ return false;
}
mddev_add_trace_msg(conf->mddev,
"raid10 wait reshape metadata");
@@ -1514,7 +1514,8 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
raid10_write_one_disk(mddev, r10_bio, bio, true, i);
}
one_write_done(r10_bio);
- return;
+ return true;
+
err_handle:
for (k = 0; k < i; k++) {
int d = r10_bio->devs[k].devnum;
@@ -1532,10 +1533,12 @@ err_handle:
}
raid_end_bio_io(r10_bio);
+ return false;
}
-static void __make_request(struct mddev *mddev, struct bio *bio, int sectors)
+static bool __make_request(struct mddev *mddev, struct bio *bio, int sectors)
{
+ bool ret;
struct r10conf *conf = mddev->private;
struct r10bio *r10_bio;
@@ -1551,10 +1554,13 @@ static void __make_request(struct mddev *mddev, struct bio *bio, int sectors)
memset(r10_bio->devs, 0, sizeof(r10_bio->devs[0]) *
conf->geo.raid_disks);
+ ret = true;
if (bio_data_dir(bio) == READ)
raid10_read_request(mddev, bio, r10_bio);
else
- raid10_write_request(mddev, bio, r10_bio);
+ ret = raid10_write_request(mddev, bio, r10_bio);
+
+ return ret;
}
static void raid_end_discard_bio(struct r10bio *r10bio)
@@ -1633,6 +1639,7 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio)
if (!wait_barrier(conf, bio->bi_opf & REQ_NOWAIT)) {
bio_wouldblock_error(bio);
+ md_write_end(mddev);
return 0;
}
@@ -1675,6 +1682,8 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio)
if (IS_ERR(split)) {
bio->bi_status = errno_to_blk_status(PTR_ERR(split));
bio_endio(bio);
+ md_write_end(mddev);
+ allow_barrier(conf);
return 0;
}
@@ -1692,6 +1701,8 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio)
if (IS_ERR(split)) {
bio->bi_status = errno_to_blk_status(PTR_ERR(split));
bio_endio(bio);
+ md_write_end(mddev);
+ allow_barrier(conf);
return 0;
}
@@ -1900,7 +1911,8 @@ static bool raid10_make_request(struct mddev *mddev, struct bio *bio)
sectors = chunk_sects -
(bio->bi_iter.bi_sector &
(chunk_sects - 1));
- __make_request(mddev, bio, sectors);
+ if (!__make_request(mddev, bio, sectors))
+ md_write_end(mddev);
/* In case raid10d snuck in to freeze_array */
wake_up_barrier(conf);
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index d0d7f96fd7cd..ffb5fcde54a9 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -996,7 +996,7 @@ static void stripe_add_to_batch_list(struct r5conf *conf,
if (test_and_clear_bit(STRIPE_BIT_DELAY, &sh->state)) {
int seq = sh->bm_seq;
if (test_bit(STRIPE_BIT_DELAY, &sh->batch_head->state) &&
- sh->batch_head->bm_seq > seq)
+ sh->batch_head->bm_seq - seq > 0)
seq = sh->batch_head->bm_seq;
set_bit(STRIPE_BIT_DELAY, &sh->batch_head->state);
sh->batch_head->bm_seq = seq;
@@ -1134,6 +1134,21 @@ 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 (mddev->bitmap_id == ID_LLBITMAP)
+ return true;
+
+ 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
@@ -4837,55 +4852,62 @@ static void break_stripe_batch_list(struct stripe_head *head_sh,
{
struct stripe_head *sh, *next;
int i;
+ unsigned long state;
list_for_each_entry_safe(sh, next, &head_sh->batch_list, batch_list) {
list_del_init(&sh->batch_list);
- WARN_ONCE(sh->state & ((1 << STRIPE_ACTIVE) |
- (1 << STRIPE_SYNCING) |
- (1 << STRIPE_REPLACED) |
- (1 << STRIPE_DELAYED) |
- (1 << STRIPE_BIT_DELAY) |
- (1 << STRIPE_FULL_WRITE) |
- (1 << STRIPE_BIOFILL_RUN) |
- (1 << STRIPE_COMPUTE_RUN) |
- (1 << STRIPE_DISCARD) |
- (1 << STRIPE_BATCH_READY) |
- (1 << STRIPE_BATCH_ERR)),
- "stripe state: %lx\n", sh->state);
- WARN_ONCE(head_sh->state & ((1 << STRIPE_DISCARD) |
- (1 << STRIPE_REPLACED)),
- "head stripe state: %lx\n", head_sh->state);
+ state = READ_ONCE(sh->state);
+ WARN_ONCE(state & ((1 << STRIPE_ACTIVE) |
+ (1 << STRIPE_SYNCING) |
+ (1 << STRIPE_REPLACED) |
+ (1 << STRIPE_DELAYED) |
+ (1 << STRIPE_BIT_DELAY) |
+ (1 << STRIPE_FULL_WRITE) |
+ (1 << STRIPE_BIOFILL_RUN) |
+ (1 << STRIPE_COMPUTE_RUN) |
+ (1 << STRIPE_DISCARD) |
+ (1 << STRIPE_BATCH_READY) |
+ (1 << STRIPE_BATCH_ERR)),
+ "stripe state: %lx\n", state);
+
+ state = READ_ONCE(head_sh->state);
+ WARN_ONCE(state & ((1 << STRIPE_DISCARD) |
+ (1 << STRIPE_REPLACED)),
+ "head stripe state: %lx\n", state);
set_mask_bits(&sh->state, ~(STRIPE_EXPAND_SYNC_FLAGS |
(1 << STRIPE_PREREAD_ACTIVE) |
(1 << STRIPE_ON_UNPLUG_LIST)),
- head_sh->state & (1 << STRIPE_INSYNC));
+ state & (1 << STRIPE_INSYNC));
sh->check_state = head_sh->check_state;
sh->reconstruct_state = head_sh->reconstruct_state;
spin_lock_irq(&sh->stripe_lock);
- sh->batch_head = NULL;
- spin_unlock_irq(&sh->stripe_lock);
for (i = 0; i < sh->disks; i++) {
if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
wake_up_bit(&sh->dev[i].flags, R5_Overlap);
- sh->dev[i].flags = head_sh->dev[i].flags &
+ sh->dev[i].flags = READ_ONCE(head_sh->dev[i].flags) &
(~((1 << R5_WriteError) | (1 << R5_Overlap)));
}
- if (handle_flags == 0 ||
- sh->state & handle_flags)
+ sh->batch_head = NULL;
+ spin_unlock_irq(&sh->stripe_lock);
+
+ state = READ_ONCE(sh->state);
+ if (handle_flags == 0 || (state & handle_flags))
set_bit(STRIPE_HANDLE, &sh->state);
raid5_release_stripe(sh);
}
spin_lock_irq(&head_sh->stripe_lock);
- head_sh->batch_head = NULL;
- spin_unlock_irq(&head_sh->stripe_lock);
for (i = 0; i < head_sh->disks; i++)
if (test_and_clear_bit(R5_Overlap, &head_sh->dev[i].flags))
wake_up_bit(&head_sh->dev[i].flags, R5_Overlap);
- if (head_sh->state & handle_flags)
+ head_sh->batch_head = NULL;
+ spin_unlock_irq(&head_sh->stripe_lock);
+
+ state = READ_ONCE(head_sh->state);
+ if (state & handle_flags)
set_bit(STRIPE_HANDLE, &head_sh->state);
}
@@ -5690,7 +5712,10 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi)
{
struct r5conf *conf = mddev->private;
sector_t logical_sector, last_sector;
+ sector_t first_stripe, last_stripe;
struct stripe_head *sh;
+ struct bvec_iter bi_iter;
+ struct bio *orig_bi = bi;
int stripe_sectors;
/* We need to handle this when io_uring supports discard/trim */
@@ -5701,19 +5726,38 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi)
/* Skip discard while reshape is happening */
return;
- logical_sector = bi->bi_iter.bi_sector & ~((sector_t)RAID5_STRIPE_SECTORS(conf)-1);
- last_sector = bio_end_sector(bi);
-
- bi->bi_next = NULL;
+ if (!raid5_discard_limits(mddev, bi))
+ return;
stripe_sectors = conf->chunk_sectors *
(conf->raid_disks - conf->max_degraded);
- logical_sector = DIV_ROUND_UP_SECTOR_T(logical_sector,
- stripe_sectors);
- sector_div(last_sector, stripe_sectors);
+ first_stripe = DIV_ROUND_UP_SECTOR_T(bi->bi_iter.bi_sector,
+ stripe_sectors);
+ last_stripe = bio_end_sector(bi);
+ sector_div(last_stripe, stripe_sectors);
+
+ if (first_stripe >= last_stripe) {
+ bio_endio(bi);
+ return;
+ }
+
+ bi_iter = bi->bi_iter;
+ bi->bi_iter.bi_sector = first_stripe * stripe_sectors;
+ bi->bi_iter.bi_size = ((last_stripe - first_stripe) *
+ stripe_sectors) << 9;
+ md_account_bio(mddev, &bi);
+ orig_bi->bi_iter = bi_iter;
+ bi->bi_iter = bi_iter;
+ bi->bi_next = NULL;
+
+ if (mddev->bitmap_id == ID_LLBITMAP &&
+ conf->raid5_discard_unsupported) {
+ bio_endio(bi);
+ return;
+ }
- logical_sector *= conf->chunk_sectors;
- last_sector *= conf->chunk_sectors;
+ logical_sector = first_stripe * conf->chunk_sectors;
+ last_sector = last_stripe * conf->chunk_sectors;
for (; logical_sector < last_sector;
logical_sector += RAID5_STRIPE_SECTORS(conf)) {
@@ -7804,24 +7848,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.
@@ -7830,6 +7862,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;
diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h
index 1dfa60a41d91..cb5feae04db2 100644
--- a/drivers/md/raid5.h
+++ b/drivers/md/raid5.h
@@ -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;