mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
Merge branch 'md-7.2' of https://git.kernel.org/pub/scm/linux/kernel/git/mdraid/linux into block-7.2
Pull MD fixes from Yu Kuai: "Bug Fixes: - Fix raid1 writes_pending and barrier reference leaks on write failures. (Abd-Alrhman Masalkhi) - Fix raid10 writes_pending leak on write request failures. (Abd-Alrhman Masalkhi) - Fix raid10 writes_pending and barrier reference leaks on discard failures. (Abd-Alrhman Masalkhi) - Fix raid1 REQ_NOWAIT handling while waiting for behind writes. (Abd-Alrhman Masalkhi) - Fix raid1 r1_bio leak when a REQ_NOWAIT retry would block. (Abd-Alrhman Masalkhi) - Fix raid1 read-balance head_position data race. (Chen Cheng) - Fix raid5 stripe batch bm_seq wraparound comparison. (Chen Cheng) - Fix raid5 stripe batch state snapshot KCSAN noise. (Chen Cheng) - Fix raid5 R5_Overlap races while breaking stripe batches. (Chen Cheng) Improvements: - Add raid5 discard IO accounting. (Yu Kuai) - Always convert raid5 llbitmap bits for discard. (Yu Kuai) Cleanups: - Simplify raid1_write_request() error handling. (Abd-Alrhman Masalkhi)" * 'md-7.2' of https://git.kernel.org/pub/scm/linux/kernel/git/mdraid/linux: md/raid5: avoid R5_Overlap races while breaking stripe batches md/raid5: use stripe state snapshot in break_stripe_batch_list() 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 md/raid1: honor REQ_NOWAIT when waiting for behind writes md/raid5: always convert llbitmap bits for discard md/raid5: validate discard support at request time md/raid5: account discard IO md/raid1: simplify raid1_write_request() error handling md/raid10: fix writes_pending and barrier reference leaks on discard failures md/raid10: fix writes_pending leak on write request failures md/raid1: fix writes_pending and barrier reference leaks on write failures
This commit is contained in:
commit
8a901e629e
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1349,7 +1349,7 @@ static void wait_blocked_dev(struct mddev *mddev, struct r10bio *r10_bio)
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
|
|||
}
|
||||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
logical_sector *= conf->chunk_sectors;
|
||||
last_sector *= conf->chunk_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 = 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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user