commit 021a24460dc2 ("block: add QUEUE_FLAG_NOWAIT") added support
for checking whether a given bdev supports handling of REQ_NOWAIT or not.
Since then commit 6abc49468eea ("dm: add support for REQ_NOWAIT and enable
it for linear target") added support for REQ_NOWAIT for dm. This uses
a similar approach to incorporate REQ_NOWAIT for md based bios.
This patch was tested using t/io_uring tool within FIO. A nvme drive
was partitioned into 2 partitions and a simple raid 0 configuration
/dev/md0 was created.
md0 : active raid0 nvme4n1p1[1] nvme4n1p2[0]
937423872 blocks super 1.2 512k chunks
Before patch:
$ ./t/io_uring /dev/md0 -p 0 -a 0 -d 1 -r 100
Running top while the above runs:
$ ps -eL | grep $(pidof io_uring)
38396 38396 pts/2 00:00:00 io_uring
38396 38397 pts/2 00:00:15 io_uring
38396 38398 pts/2 00:00:13 iou-wrk-38397
We can see iou-wrk-38397 io worker thread created which gets created
when io_uring sees that the underlying device (/dev/md0 in this case)
doesn't support nowait.
After patch:
$ ./t/io_uring /dev/md0 -p 0 -a 0 -d 1 -r 100
Running top while the above runs:
$ ps -eL | grep $(pidof io_uring)
38341 38341 pts/2 00:10:22 io_uring
38341 38342 pts/2 00:10:37 io_uring
After running this patch, we don't see any io worker thread
being created which indicated that io_uring saw that the
underlying device does support nowait. This is the exact behaviour
noticed on a dm device which also supports nowait.
For all the other raid personalities except raid0, we would need
to train pieces which involves make_request fn in order for them
to correctly handle REQ_NOWAIT.
Signed-off-by: Vishal Verma <redacted>
---
drivers/md/md.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
@@ -419,6 +419,12 @@ void md_handle_request(struct mddev *mddev, struct bio *bio)if(is_suspended(mddev,bio)){DEFINE_WAIT(__wait);for(;;){+/* Bail out if REQ_NOWAIT is set for the bio */+if(bio->bi_opf&REQ_NOWAIT){+rcu_read_unlock();+bio_wouldblock_error(bio);+return;+}prepare_to_wait(&mddev->sb_wait,&__wait,TASK_UNINTERRUPTIBLE);if(!is_suspended(mddev,bio))
@@ -5787,6 +5793,7 @@ int md_run(struct mddev *mddev)interr;structmd_rdev*rdev;structmd_personality*pers;+boolnowait=true;if(list_empty(&mddev->disks))/* cannot run an array with no devices.. */
@@ -5857,8 +5864,13 @@ int md_run(struct mddev *mddev)}}sysfs_notify_dirent_safe(rdev->sysfs_state);+nowait=nowait&&blk_queue_nowait(bdev_get_queue(rdev->bdev));}+/* Set the NOWAIT flags if all underlying devices support it */+if(nowait)+blk_queue_flag_set(QUEUE_FLAG_NOWAIT,mddev->queue);+if(!bioset_initialized(&mddev->bio_set)){err=bioset_init(&mddev->bio_set,BIO_POOL_SIZE,0,BIOSET_NEED_BVECS);if(err)
@@ -7002,6 +7014,15 @@ static int hot_add_disk(struct mddev *mddev, dev_t dev)set_bit(MD_SB_CHANGE_DEVS,&mddev->sb_flags);if(!mddev->thread)md_update_sb(mddev,1);+/*+*IfthenewdiskdoesnotsupportREQ_NOWAIT,+*disableonthewholeMD.+*/+if(!blk_queue_nowait(bdev_get_queue(rdev->bdev))){+pr_info("%s: Disabling nowait because %s does not support nowait\n",+mdname(mddev),bdevname(rdev->bdev,b));+blk_queue_flag_clear(QUEUE_FLAG_NOWAIT,mddev->queue);+}/**Kickrecovery,maybethissparehastobeaddedtothe*arrayimmediately.
This adds nowait support to the RAID1 driver. It makes RAID1 driver
return with EAGAIN for situations where it could wait for eg:
- Waiting for the barrier,
- Array got frozen,
- Too many pending I/Os to be queued.
wait_barrier() fn is modified to return bool to support error for
wait barriers. It returns true in case of wait or if wait is not
required and returns false if wait was required but not performed
to support nowait.
Signed-off-by: Vishal Verma <redacted>
---
drivers/md/raid1.c | 74 +++++++++++++++++++++++++++++++++++-----------
1 file changed, 57 insertions(+), 17 deletions(-)
@@ -979,18 +980,27 @@ static void _wait_barrier(struct r1conf *conf, int idx)*/wake_up(&conf->wait_barrier);/* Wait for the barrier in same barrier unit bucket to drop. */-wait_event_lock_irq(conf->wait_barrier,-!conf->array_frozen&&-!atomic_read(&conf->barrier[idx]),-conf->resync_lock);+if(conf->array_frozen||atomic_read(&conf->barrier[idx])){+/* Return false when nowait flag is set */+if(nowait)+ret=false;+else{+wait_event_lock_irq(conf->wait_barrier,+!conf->array_frozen&&+!atomic_read(&conf->barrier[idx]),+conf->resync_lock);+}+}atomic_inc(&conf->nr_pending[idx]);atomic_dec(&conf->nr_waiting[idx]);spin_unlock_irq(&conf->resync_lock);+returnret;}-staticvoidwait_read_barrier(structr1conf*conf,sector_tsector_nr)+staticboolwait_read_barrier(structr1conf*conf,sector_tsector_nr,boolnowait){intidx=sector_to_idx(sector_nr);+boolret=true;/**Verysimilarto_wait_barrier().Thedifferenceis,forread
@@ -1013,19 +1023,27 @@ static void wait_read_barrier(struct r1conf *conf, sector_t sector_nr)*/wake_up(&conf->wait_barrier);/* Wait for array to be unfrozen */-wait_event_lock_irq(conf->wait_barrier,-!conf->array_frozen,-conf->resync_lock);+if(conf->array_frozen||atomic_read(&conf->barrier[idx])){+if(nowait)+/* Return false when nowait flag is set */+ret=false;+else{+wait_event_lock_irq(conf->wait_barrier,+!conf->array_frozen,+conf->resync_lock);+}+}atomic_inc(&conf->nr_pending[idx]);atomic_dec(&conf->nr_waiting[idx]);spin_unlock_irq(&conf->resync_lock);+returnret;}-staticvoidwait_barrier(structr1conf*conf,sector_tsector_nr)+staticboolwait_barrier(structr1conf*conf,sector_tsector_nr,boolnowait){intidx=sector_to_idx(sector_nr);-_wait_barrier(conf,idx);+return_wait_barrier(conf,idx,nowait);}staticvoid_allow_barrier(structr1conf*conf,intidx)
This adds nowait support to the RAID10 driver. Very similar to
raid1 driver changes. It makes RAID10 driver return with EAGAIN
for situations where it could wait for eg:
- Waiting for the barrier,
- Too many pending I/Os to be queued,
- Reshape operation,
- Discard operation.
wait_barrier() fn is modified to return bool to support error for
wait barriers. It returns true in case of wait or if wait is not
required and returns false if wait was required but not performed
to support nowait.
Signed-off-by: Vishal Verma <redacted>
---
drivers/md/raid10.c | 57 +++++++++++++++++++++++++++++++++++----------
1 file changed, 45 insertions(+), 12 deletions(-)
@@ -952,11 +952,18 @@ static void lower_barrier(struct r10conf *conf)wake_up(&conf->wait_barrier);}-staticvoidwait_barrier(structr10conf*conf)+staticboolwait_barrier(structr10conf*conf,boolnowait){spin_lock_irq(&conf->resync_lock);if(conf->barrier){structbio_list*bio_list=current->bio_list;++/* Return false when nowait flag is set */+if(nowait){+spin_unlock_irq(&conf->resync_lock);+returnfalse;+}+conf->nr_waiting++;/* Wait for the barrier to drop.*Howeveriftherearealreadypending
@@ -1101,17 +1109,25 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule)staticvoidregular_request_wait(structmddev*mddev,structr10conf*conf,structbio*bio,sector_tsectors){-wait_barrier(conf);+/* Bail out if REQ_NOWAIT is set for the bio */+if(!wait_barrier(conf,bio->bi_opf&REQ_NOWAIT)){+bio_wouldblock_error(bio);+return;+}while(test_bit(MD_RECOVERY_RESHAPE,&mddev->recovery)&&bio->bi_iter.bi_sector<conf->reshape_progress&&bio->bi_iter.bi_sector+sectors>conf->reshape_progress){raid10_log(conf->mddev,"wait reshape");+if(bio->bi_opf&REQ_NOWAIT){+bio_wouldblock_error(bio);+return;+}allow_barrier(conf);wait_event(conf->wait_barrier,conf->reshape_progress<=bio->bi_iter.bi_sector||conf->reshape_progress>=bio->bi_iter.bi_sector+sectors);-wait_barrier(conf);+wait_barrier(conf,false);}}
@@ -1357,6 +1373,11 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,bio_end_sector(bio)))){DEFINE_WAIT(w);for(;;){+/* Bail out if REQ_NOWAIT is set for the bio */+if(bio->bi_opf&REQ_NOWAIT){+bio_wouldblock_error(bio);+return;+}prepare_to_wait(&conf->wait_barrier,&w,TASK_IDLE);if(!md_cluster_ops->area_resyncing(mddev,WRITE,
@@ -1607,7 +1636,11 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio)if(test_bit(MD_RECOVERY_RESHAPE,&mddev->recovery))return-EAGAIN;-wait_barrier(conf);+if(bio->bi_opf&REQ_NOWAIT){+bio_wouldblock_error(bio);+return0;+}+wait_barrier(conf,false);/**Checkreshapeagaintoavoidreshapehappensafterchecking
@@ -1649,7 +1682,7 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio)allow_barrier(conf);/* Resend the fist split part */submit_bio_noacct(split);-wait_barrier(conf);+wait_barrier(conf,false);}div_u64_rem(bio_end,stripe_size,&remainder);if(remainder){
@@ -1660,7 +1693,7 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio)/* Resend the second split part */submit_bio_noacct(bio);bio=split;-wait_barrier(conf);+wait_barrier(conf,false);}bio_start=bio->bi_iter.bi_sector;
@@ -1816,7 +1849,7 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio)end_disk_offset+=geo->stride;atomic_inc(&first_r10bio->remaining);raid_end_discard_bio(r10_bio);-wait_barrier(conf);+wait_barrier(conf,false);gotoretry_discard;}
@@ -5715,6 +5715,11 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi)set_bit(R5_Overlap,&sh->dev[sh->pd_idx].flags);if(test_bit(STRIPE_SYNCING,&sh->state)){raid5_release_stripe(sh);+/* Bail out if REQ_NOWAIT is set */+if(bi->bi_opf&REQ_NOWAIT){+bio_wouldblock_error(bi);+return;+}schedule();gotoagain;}
@@ -5727,6 +5732,11 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi)set_bit(R5_Overlap,&sh->dev[d].flags);spin_unlock_irq(&sh->stripe_lock);raid5_release_stripe(sh);+/* Bail out if REQ_NOWAIT is set */+if(bi->bi_opf&REQ_NOWAIT){+bio_wouldblock_error(bi);+return;+}schedule();gotoagain;}
@@ -5820,6 +5830,16 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)bi->bi_next=NULL;md_account_bio(mddev,&bi);+/* Bail out if REQ_NOWAIT is set */+if((bi->bi_opf&REQ_NOWAIT)&&+(conf->reshape_progress!=MaxSector)&&+(mddev->reshape_backwards+?(logical_sector>conf->reshape_progress&&logical_sector<=conf->reshape_safe)+:(logical_sector>=conf->reshape_safe&&logical_sector<conf->reshape_progress))){+bio_wouldblock_error(bi);+returntrue;+}+prepare_to_wait(&conf->wait_for_overlap,&w,TASK_UNINTERRUPTIBLE);for(;logical_sector<last_sector;logical_sector+=RAID5_STRIPE_SECTORS(conf)){intprevious;
@@ -419,6 +419,12 @@ void md_handle_request(struct mddev *mddev, struct bio *bio)if(is_suspended(mddev,bio)){DEFINE_WAIT(__wait);for(;;){+/* Bail out if REQ_NOWAIT is set for the bio */+if(bio->bi_opf&REQ_NOWAIT){+rcu_read_unlock();+bio_wouldblock_error(bio);+return;+}
I moved this part to before the for (;;) loop. And applied to md-next.
Thanks,
Song
From: Song Liu <song@kernel.org> Date: 2021-12-15 20:33:51
On Tue, Dec 14, 2021 at 10:09 PM Vishal Verma [off-list ref] wrote:
This adds nowait support to the RAID1 driver. It makes RAID1 driver
return with EAGAIN for situations where it could wait for eg:
- Waiting for the barrier,
- Array got frozen,
- Too many pending I/Os to be queued.
wait_barrier() fn is modified to return bool to support error for
wait barriers. It returns true in case of wait or if wait is not
required and returns false if wait was required but not performed
to support nowait.
Please see some detailed comments below. But a general and more important
question: were you able to trigger these conditions (path that lead to
bio_wouldblock_error) in the tests?
Ideally, we should test all these conditions. If something is really
hard to trigger,
please highlight that in the commit log, so that I can run more tests on them.
Thanks,
Song
@@ -979,18 +980,27 @@ static void _wait_barrier(struct r1conf *conf, int idx)*/wake_up(&conf->wait_barrier);/* Wait for the barrier in same barrier unit bucket to drop. */-wait_event_lock_irq(conf->wait_barrier,-!conf->array_frozen&&-!atomic_read(&conf->barrier[idx]),-conf->resync_lock);+if(conf->array_frozen||atomic_read(&conf->barrier[idx])){
Do we really need this check?
+ /* Return false when nowait flag is set */
+ if (nowait)
+ ret = false;
+ else {
+ wait_event_lock_irq(conf->wait_barrier,
+ !conf->array_frozen &&
+ !atomic_read(&conf->barrier[idx]),
+ conf->resync_lock);
+ }
+ }
atomic_inc(&conf->nr_pending[idx]);
Were you able to trigger the condition in the tests? I think we should
only increase
nr_pending for ret == true. Otherwise, we will leak a nr_pending.
quoted hunk
atomic_dec(&conf->nr_waiting[idx]);
spin_unlock_irq(&conf->resync_lock);
+ return ret;
}
-static void wait_read_barrier(struct r1conf *conf, sector_t sector_nr)
+static bool wait_read_barrier(struct r1conf *conf, sector_t sector_nr, bool nowait)
{
int idx = sector_to_idx(sector_nr);
+ bool ret = true;
/*
* Very similar to _wait_barrier(). The difference is, for read
@@ -1236,7 +1254,11 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio, * Still need barrier for READ in case that whole * array is frozen. */- wait_read_barrier(conf, bio->bi_iter.bi_sector);+ if (!wait_read_barrier(conf, bio->bi_iter.bi_sector,+ bio->bi_opf & REQ_NOWAIT)) {+ bio_wouldblock_error(bio);+ return;+ } if (!r1_bio) r1_bio = alloc_r1bio(mddev, bio);
@@ -1336,6 +1358,10 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, bio->bi_iter.bi_sector, bio_end_sector(bio))) { DEFINE_WAIT(w);+ if (bio->bi_opf & REQ_NOWAIT) {+ bio_wouldblock_error(bio);+ return;+ } for (;;) { prepare_to_wait(&conf->wait_barrier, &w, TASK_IDLE);
@@ -1353,17 +1379,26 @@ 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. */- wait_barrier(conf, bio->bi_iter.bi_sector);+ if (!wait_barrier(conf, bio->bi_iter.bi_sector,+ bio->bi_opf & REQ_NOWAIT)) {+ bio_wouldblock_error(bio);+ return;+ } r1_bio = alloc_r1bio(mddev, bio); r1_bio->sectors = max_write_sectors; if (conf->pending_count >= max_queued_requests) { md_wakeup_thread(mddev->thread);+ if (bio->bi_opf & REQ_NOWAIT) {+ bio_wouldblock_error(bio);
I think we need to fix conf->nr_pending before returning.
quoted hunk
+ return;
+ }
raid1_log(mddev, "wait queued");
wait_event(conf->wait_barrier,
conf->pending_count < max_queued_requests);
}
+
/* first select target devices under rcu_lock and
* inc refcount on their rdev. Record them by setting
* bios[x] to bio
From: Song Liu <song@kernel.org> Date: 2021-12-15 20:42:31
On Tue, Dec 14, 2021 at 10:09 PM Vishal Verma [off-list ref] wrote:
quoted hunk
This adds nowait support to the RAID10 driver. Very similar to
raid1 driver changes. It makes RAID10 driver return with EAGAIN
for situations where it could wait for eg:
- Waiting for the barrier,
- Too many pending I/Os to be queued,
- Reshape operation,
- Discard operation.
wait_barrier() fn is modified to return bool to support error for
wait barriers. It returns true in case of wait or if wait is not
required and returns false if wait was required but not performed
to support nowait.
Signed-off-by: Vishal Verma <redacted>
---
drivers/md/raid10.c | 57 +++++++++++++++++++++++++++++++++++----------
1 file changed, 45 insertions(+), 12 deletions(-)
@@ -952,11 +952,18 @@ static void lower_barrier(struct r10conf *conf)wake_up(&conf->wait_barrier);}-staticvoidwait_barrier(structr10conf*conf)+staticboolwait_barrier(structr10conf*conf,boolnowait){spin_lock_irq(&conf->resync_lock);if(conf->barrier){structbio_list*bio_list=current->bio_list;++/* Return false when nowait flag is set */+if(nowait){+spin_unlock_irq(&conf->resync_lock);+returnfalse;+}+conf->nr_waiting++;/* Wait for the barrier to drop.*Howeveriftherearealreadypending
@@ -1101,17 +1109,25 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule)staticvoidregular_request_wait(structmddev*mddev,structr10conf*conf,structbio*bio,sector_tsectors){-wait_barrier(conf);+/* Bail out if REQ_NOWAIT is set for the bio */+if(!wait_barrier(conf,bio->bi_opf&REQ_NOWAIT)){+bio_wouldblock_error(bio);+return;+}
I think we also need regular_request_wait to return bool and handle it properly.
Thanks,
Song
@@ -1357,6 +1373,11 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio, bio_end_sector(bio)))) { DEFINE_WAIT(w); for (;;) {+ /* Bail out if REQ_NOWAIT is set for the bio */+ if (bio->bi_opf & REQ_NOWAIT) {+ bio_wouldblock_error(bio);+ return;+ } prepare_to_wait(&conf->wait_barrier, &w, TASK_IDLE); if (!md_cluster_ops->area_resyncing(mddev, WRITE,
@@ -1607,7 +1636,11 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio) if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) return -EAGAIN;- wait_barrier(conf);+ if (bio->bi_opf & REQ_NOWAIT) {+ bio_wouldblock_error(bio);+ return 0;+ }+ wait_barrier(conf, false); /* * Check reshape again to avoid reshape happens after checking
@@ -1649,7 +1682,7 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio) allow_barrier(conf); /* Resend the fist split part */ submit_bio_noacct(split);- wait_barrier(conf);+ wait_barrier(conf, false); } div_u64_rem(bio_end, stripe_size, &remainder); if (remainder) {
@@ -1660,7 +1693,7 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio) /* Resend the second split part */ submit_bio_noacct(bio); bio = split;- wait_barrier(conf);+ wait_barrier(conf, false); } bio_start = bio->bi_iter.bi_sector;
On Tue, Dec 14, 2021 at 10:09 PM Vishal Verma [off-list ref] wrote:
quoted
This adds nowait support to the RAID1 driver. It makes RAID1 driver
return with EAGAIN for situations where it could wait for eg:
- Waiting for the barrier,
- Array got frozen,
- Too many pending I/Os to be queued.
wait_barrier() fn is modified to return bool to support error for
wait barriers. It returns true in case of wait or if wait is not
required and returns false if wait was required but not performed
to support nowait.
Please see some detailed comments below. But a general and more important
question: were you able to trigger these conditions (path that lead to
bio_wouldblock_error) in the tests?
Ideally, we should test all these conditions. If something is really
hard to trigger,
please highlight that in the commit log, so that I can run more tests on them.
Thanks,
Song
@@ -979,18 +980,27 @@ static void _wait_barrier(struct r1conf *conf, int idx)*/wake_up(&conf->wait_barrier);/* Wait for the barrier in same barrier unit bucket to drop. */-wait_event_lock_irq(conf->wait_barrier,-!conf->array_frozen&&-!atomic_read(&conf->barrier[idx]),-conf->resync_lock);+if(conf->array_frozen||atomic_read(&conf->barrier[idx])){
Do we really need this check?
This was done when looking at the wait_event_lock_irq conditions.
I am not very sure about this.
quoted
+ /* Return false when nowait flag is set */
+ if (nowait)
+ ret = false;
+ else {
+ wait_event_lock_irq(conf->wait_barrier,
+ !conf->array_frozen &&
+ !atomic_read(&conf->barrier[idx]),
+ conf->resync_lock);
+ }
+ }
atomic_inc(&conf->nr_pending[idx]);
Were you able to trigger the condition in the tests? I think we should
only increase
nr_pending for ret == true. Otherwise, we will leak a nr_pending.
No I wasn't able to. Makes sense about nr_pending. Thanks for catching.
quoted
atomic_dec(&conf->nr_waiting[idx]);
spin_unlock_irq(&conf->resync_lock);
+ return ret;
}
-static void wait_read_barrier(struct r1conf *conf, sector_t sector_nr)
+static bool wait_read_barrier(struct r1conf *conf, sector_t sector_nr, bool nowait)
{
int idx = sector_to_idx(sector_nr);
+ bool ret = true;
/*
* Very similar to _wait_barrier(). The difference is, for read
@@ -1236,7 +1254,11 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio, * Still need barrier for READ in case that whole * array is frozen. */- wait_read_barrier(conf, bio->bi_iter.bi_sector);+ if (!wait_read_barrier(conf, bio->bi_iter.bi_sector,+ bio->bi_opf & REQ_NOWAIT)) {+ bio_wouldblock_error(bio);+ return;+ } if (!r1_bio) r1_bio = alloc_r1bio(mddev, bio);
@@ -1336,6 +1358,10 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, bio->bi_iter.bi_sector, bio_end_sector(bio))) { DEFINE_WAIT(w);+ if (bio->bi_opf & REQ_NOWAIT) {+ bio_wouldblock_error(bio);+ return;+ } for (;;) { prepare_to_wait(&conf->wait_barrier, &w, TASK_IDLE);
@@ -1353,17 +1379,26 @@ 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. */- wait_barrier(conf, bio->bi_iter.bi_sector);+ if (!wait_barrier(conf, bio->bi_iter.bi_sector,+ bio->bi_opf & REQ_NOWAIT)) {+ bio_wouldblock_error(bio);+ return;+ } r1_bio = alloc_r1bio(mddev, bio); r1_bio->sectors = max_write_sectors; if (conf->pending_count >= max_queued_requests) { md_wakeup_thread(mddev->thread);+ if (bio->bi_opf & REQ_NOWAIT) {+ bio_wouldblock_error(bio);
I think we need to fix conf->nr_pending before returning.
OK, this one I am not sure. You mean dec conf->nr_pending?
quoted
+ return;
+ }
raid1_log(mddev, "wait queued");
wait_event(conf->wait_barrier,
conf->pending_count < max_queued_requests);
}
+
/* first select target devices under rcu_lock and
* inc refcount on their rdev. Record them by setting
* bios[x] to bio
On Tue, Dec 14, 2021 at 10:09 PM Vishal Verma [off-list ref] wrote:
quoted
This adds nowait support to the RAID10 driver. Very similar to
raid1 driver changes. It makes RAID10 driver return with EAGAIN
for situations where it could wait for eg:
- Waiting for the barrier,
- Too many pending I/Os to be queued,
- Reshape operation,
- Discard operation.
wait_barrier() fn is modified to return bool to support error for
wait barriers. It returns true in case of wait or if wait is not
required and returns false if wait was required but not performed
to support nowait.
Signed-off-by: Vishal Verma <redacted>
---
drivers/md/raid10.c | 57 +++++++++++++++++++++++++++++++++++----------
1 file changed, 45 insertions(+), 12 deletions(-)
@@ -952,11 +952,18 @@ static void lower_barrier(struct r10conf *conf)wake_up(&conf->wait_barrier);}-staticvoidwait_barrier(structr10conf*conf)+staticboolwait_barrier(structr10conf*conf,boolnowait){spin_lock_irq(&conf->resync_lock);if(conf->barrier){structbio_list*bio_list=current->bio_list;++/* Return false when nowait flag is set */+if(nowait){+spin_unlock_irq(&conf->resync_lock);+returnfalse;+}+conf->nr_waiting++;/* Wait for the barrier to drop.*Howeveriftherearealreadypending
@@ -1101,17 +1109,25 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule)staticvoidregular_request_wait(structmddev*mddev,structr10conf*conf,structbio*bio,sector_tsectors){-wait_barrier(conf);+/* Bail out if REQ_NOWAIT is set for the bio */+if(!wait_barrier(conf,bio->bi_opf&REQ_NOWAIT)){+bio_wouldblock_error(bio);+return;+}
I think we also need regular_request_wait to return bool and handle it properly.
Thanks,
Song
@@ -1357,6 +1373,11 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio, bio_end_sector(bio)))) { DEFINE_WAIT(w); for (;;) {+ /* Bail out if REQ_NOWAIT is set for the bio */+ if (bio->bi_opf & REQ_NOWAIT) {+ bio_wouldblock_error(bio);+ return;+ } prepare_to_wait(&conf->wait_barrier, &w, TASK_IDLE); if (!md_cluster_ops->area_resyncing(mddev, WRITE,
@@ -1607,7 +1636,11 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio) if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) return -EAGAIN;- wait_barrier(conf);+ if (bio->bi_opf & REQ_NOWAIT) {+ bio_wouldblock_error(bio);+ return 0;+ }+ wait_barrier(conf, false); /* * Check reshape again to avoid reshape happens after checking
@@ -1649,7 +1682,7 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio) allow_barrier(conf); /* Resend the fist split part */ submit_bio_noacct(split);- wait_barrier(conf);+ wait_barrier(conf, false); } div_u64_rem(bio_end, stripe_size, &remainder); if (remainder) {
@@ -1660,7 +1693,7 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio) /* Resend the second split part */ submit_bio_noacct(bio); bio = split;- wait_barrier(conf);+ wait_barrier(conf, false); } bio_start = bio->bi_iter.bi_sector;
On Tue, Dec 14, 2021 at 10:09 PM Vishal Verma
[off-list ref] wrote:
quoted
This adds nowait support to the RAID10 driver. Very similar to
raid1 driver changes. It makes RAID10 driver return with EAGAIN
for situations where it could wait for eg:
- Waiting for the barrier,
- Too many pending I/Os to be queued,
- Reshape operation,
- Discard operation.
wait_barrier() fn is modified to return bool to support error for
wait barriers. It returns true in case of wait or if wait is not
required and returns false if wait was required but not performed
to support nowait.
Signed-off-by: Vishal Verma <redacted>
---
drivers/md/raid10.c | 57
+++++++++++++++++++++++++++++++++++----------
1 file changed, 45 insertions(+), 12 deletions(-)
*cb, bool from_schedule)
static void regular_request_wait(struct mddev *mddev, struct
r10conf *conf,
struct bio *bio, sector_t sectors)
{
- wait_barrier(conf);
+ /* Bail out if REQ_NOWAIT is set for the bio */
+ if (!wait_barrier(conf, bio->bi_opf & REQ_NOWAIT)) {
+ bio_wouldblock_error(bio);
+ return;
+ }
I think we also need regular_request_wait to return bool and handle
it properly.
Thanks,
Song
*mddev, struct bio *bio,
bio_end_sector(bio)))) {
DEFINE_WAIT(w);
for (;;) {
+ /* Bail out if REQ_NOWAIT is set for the bio */
+ if (bio->bi_opf & REQ_NOWAIT) {
+ bio_wouldblock_error(bio);
+ return;
+ }
prepare_to_wait(&conf->wait_barrier,
&w, TASK_IDLE);
if (!md_cluster_ops->area_resyncing(mddev,
WRITE,
*mddev, struct bio *bio,
bio_chain(split, bio);
allow_barrier(conf);
submit_bio_noacct(bio);
- wait_barrier(conf);
+ wait_barrier(conf, false);
bio = split;
r10_bio->master_bio = bio;
}
@@ -1607,7 +1636,11 @@ static int raid10_handle_discard(struct mddev
*mddev, struct bio *bio)
if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
return -EAGAIN;
- wait_barrier(conf);
+ if (bio->bi_opf & REQ_NOWAIT) {
+ bio_wouldblock_error(bio);
+ return 0;
+ }
+ wait_barrier(conf, false);
/*
* Check reshape again to avoid reshape happens after checking
@@ -1649,7 +1682,7 @@ static int raid10_handle_discard(struct mddev
*mddev, struct bio *bio)
allow_barrier(conf);
/* Resend the fist split part */
submit_bio_noacct(split);
- wait_barrier(conf);
+ wait_barrier(conf, false);
}
div_u64_rem(bio_end, stripe_size, &remainder);
if (remainder) {
@@ -1660,7 +1693,7 @@ static int raid10_handle_discard(struct mddev
*mddev, struct bio *bio)
/* Resend the second split part */
submit_bio_noacct(bio);
bio = split;
- wait_barrier(conf);
+ wait_barrier(conf, false);
}
bio_start = bio->bi_iter.bi_sector;
@@ -1816,7 +1849,7 @@ static int raid10_handle_discard(struct mddev
On Tue, Dec 14, 2021 at 10:09 PM Vishal Verma
[off-list ref] wrote:
quoted
This adds nowait support to the RAID10 driver. Very similar to
raid1 driver changes. It makes RAID10 driver return with EAGAIN
for situations where it could wait for eg:
- Waiting for the barrier,
- Too many pending I/Os to be queued,
- Reshape operation,
- Discard operation.
wait_barrier() fn is modified to return bool to support error for
wait barriers. It returns true in case of wait or if wait is not
required and returns false if wait was required but not performed
to support nowait.
Signed-off-by: Vishal Verma <redacted>
---
drivers/md/raid10.c | 57
+++++++++++++++++++++++++++++++++++----------
1 file changed, 45 insertions(+), 12 deletions(-)
blk_plug_cb *cb, bool from_schedule)
static void regular_request_wait(struct mddev *mddev, struct
r10conf *conf,
struct bio *bio, sector_t sectors)
{
- wait_barrier(conf);
+ /* Bail out if REQ_NOWAIT is set for the bio */
+ if (!wait_barrier(conf, bio->bi_opf & REQ_NOWAIT)) {
+ bio_wouldblock_error(bio);
+ return;
+ }
I think we also need regular_request_wait to return bool and handle
it properly.
Thanks,
Song
It seems this issue is triggering even when just using "md: add support
for REQ_NOWAIT" patch running t/io_uring against a raid10 volume with
very high iodepth (256).
mddev *mddev, struct bio *bio,
bio_end_sector(bio)))) {
DEFINE_WAIT(w);
for (;;) {
+ /* Bail out if REQ_NOWAIT is set for the
bio */
+ if (bio->bi_opf & REQ_NOWAIT) {
+ bio_wouldblock_error(bio);
+ return;
+ }
prepare_to_wait(&conf->wait_barrier,
&w, TASK_IDLE);
if (!md_cluster_ops->area_resyncing(mddev,
WRITE,
*mddev, struct bio *bio,
bio_chain(split, bio);
allow_barrier(conf);
submit_bio_noacct(bio);
- wait_barrier(conf);
+ wait_barrier(conf, false);
bio = split;
r10_bio->master_bio = bio;
}
@@ -1607,7 +1636,11 @@ static int raid10_handle_discard(struct
mddev *mddev, struct bio *bio)
if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
return -EAGAIN;
- wait_barrier(conf);
+ if (bio->bi_opf & REQ_NOWAIT) {
+ bio_wouldblock_error(bio);
+ return 0;
+ }
+ wait_barrier(conf, false);
/*
* Check reshape again to avoid reshape happens after
checking
@@ -1649,7 +1682,7 @@ static int raid10_handle_discard(struct mddev
*mddev, struct bio *bio)
allow_barrier(conf);
/* Resend the fist split part */
submit_bio_noacct(split);
- wait_barrier(conf);
+ wait_barrier(conf, false);
}
div_u64_rem(bio_end, stripe_size, &remainder);
if (remainder) {
@@ -1660,7 +1693,7 @@ static int raid10_handle_discard(struct mddev
*mddev, struct bio *bio)
/* Resend the second split part */
submit_bio_noacct(bio);
bio = split;
- wait_barrier(conf);
+ wait_barrier(conf, false);
}
bio_start = bio->bi_iter.bi_sector;
@@ -1816,7 +1849,7 @@ static int raid10_handle_discard(struct mddev
On Tue, Dec 14, 2021 at 10:09 PM Vishal Verma
[off-list ref] wrote:
quoted
This adds nowait support to the RAID10 driver. Very similar to
raid1 driver changes. It makes RAID10 driver return with EAGAIN
for situations where it could wait for eg:
- Waiting for the barrier,
- Too many pending I/Os to be queued,
- Reshape operation,
- Discard operation.
wait_barrier() fn is modified to return bool to support error for
wait barriers. It returns true in case of wait or if wait is not
required and returns false if wait was required but not performed
to support nowait.
Signed-off-by: Vishal Verma <redacted>
---
drivers/md/raid10.c | 57
+++++++++++++++++++++++++++++++++++----------
1 file changed, 45 insertions(+), 12 deletions(-)
@@ -952,11 +952,18 @@ static void lower_barrier(struct r10conf *conf)wake_up(&conf->wait_barrier);}-staticvoidwait_barrier(structr10conf*conf)+staticboolwait_barrier(structr10conf*conf,boolnowait){spin_lock_irq(&conf->resync_lock);if(conf->barrier){structbio_list*bio_list=current->bio_list;++/* Return false when nowait flag is set */+if(nowait){+spin_unlock_irq(&conf->resync_lock);+returnfalse;+}+conf->nr_waiting++;/* Wait for the barrier to drop.*Howeveriftherearealreadypending
*cb, bool from_schedule)
static void regular_request_wait(struct mddev *mddev, struct
r10conf *conf,
struct bio *bio, sector_t sectors)
{
- wait_barrier(conf);
+ /* Bail out if REQ_NOWAIT is set for the bio */
+ if (!wait_barrier(conf, bio->bi_opf & REQ_NOWAIT)) {
+ bio_wouldblock_error(bio);
+ return;
+ }
I think we also need regular_request_wait to return bool and handle
it properly.
Thanks,
Song
Do you have:
commit 75feae73a28020e492fbad2323245455ef69d687
Author: Pavel Begunkov [off-list ref]
Date: Tue Dec 7 20:16:36 2021 +0000
block: fix single bio async DIO error handling
in your tree?
--
Jens Axboe
On Tue, Dec 14, 2021 at 10:09 PM Vishal Verma
[off-list ref] wrote:
quoted
This adds nowait support to the RAID10 driver. Very similar to
raid1 driver changes. It makes RAID10 driver return with EAGAIN
for situations where it could wait for eg:
- Waiting for the barrier,
- Too many pending I/Os to be queued,
- Reshape operation,
- Discard operation.
wait_barrier() fn is modified to return bool to support error for
wait barriers. It returns true in case of wait or if wait is not
required and returns false if wait was required but not performed
to support nowait.
Signed-off-by: Vishal Verma <redacted>
---
drivers/md/raid10.c | 57
+++++++++++++++++++++++++++++++++++----------
1 file changed, 45 insertions(+), 12 deletions(-)
@@ -952,11 +952,18 @@ static void lower_barrier(struct r10conf *conf)wake_up(&conf->wait_barrier);}-staticvoidwait_barrier(structr10conf*conf)+staticboolwait_barrier(structr10conf*conf,boolnowait){spin_lock_irq(&conf->resync_lock);if(conf->barrier){structbio_list*bio_list=current->bio_list;++/* Return false when nowait flag is set */+if(nowait){+spin_unlock_irq(&conf->resync_lock);+returnfalse;+}+conf->nr_waiting++;/* Wait for the barrier to drop.*Howeveriftherearealreadypending
*cb, bool from_schedule)
static void regular_request_wait(struct mddev *mddev, struct
r10conf *conf,
struct bio *bio, sector_t sectors)
{
- wait_barrier(conf);
+ /* Bail out if REQ_NOWAIT is set for the bio */
+ if (!wait_barrier(conf, bio->bi_opf & REQ_NOWAIT)) {
+ bio_wouldblock_error(bio);
+ return;
+ }
I think we also need regular_request_wait to return bool and handle
it properly.
Thanks,
Song
Do you have:
commit 75feae73a28020e492fbad2323245455ef69d687
Author: Pavel Begunkov [off-list ref]
Date: Tue Dec 7 20:16:36 2021 +0000
block: fix single bio async DIO error handling
in your tree?
On Tue, Dec 14, 2021 at 10:09 PM Vishal Verma
[off-list ref] wrote:
quoted
This adds nowait support to the RAID10 driver. Very similar to
raid1 driver changes. It makes RAID10 driver return with EAGAIN
for situations where it could wait for eg:
- Waiting for the barrier,
- Too many pending I/Os to be queued,
- Reshape operation,
- Discard operation.
wait_barrier() fn is modified to return bool to support error for
wait barriers. It returns true in case of wait or if wait is not
required and returns false if wait was required but not performed
to support nowait.
Signed-off-by: Vishal Verma <redacted>
---
drivers/md/raid10.c | 57
+++++++++++++++++++++++++++++++++++----------
1 file changed, 45 insertions(+), 12 deletions(-)
@@ -952,11 +952,18 @@ static void lower_barrier(struct r10conf *conf)wake_up(&conf->wait_barrier);}-staticvoidwait_barrier(structr10conf*conf)+staticboolwait_barrier(structr10conf*conf,boolnowait){spin_lock_irq(&conf->resync_lock);if(conf->barrier){structbio_list*bio_list=current->bio_list;++/* Return false when nowait flag is set */+if(nowait){+spin_unlock_irq(&conf->resync_lock);+returnfalse;+}+conf->nr_waiting++;/* Wait for the barrier to drop.*Howeveriftherearealreadypending
*cb, bool from_schedule)
static void regular_request_wait(struct mddev *mddev, struct
r10conf *conf,
struct bio *bio, sector_t sectors)
{
- wait_barrier(conf);
+ /* Bail out if REQ_NOWAIT is set for the bio */
+ if (!wait_barrier(conf, bio->bi_opf & REQ_NOWAIT)) {
+ bio_wouldblock_error(bio);
+ return;
+ }
I think we also need regular_request_wait to return bool and handle
it properly.
Thanks,
Song
Do you have:
commit 75feae73a28020e492fbad2323245455ef69d687
Author: Pavel Begunkov [off-list ref]
Date: Tue Dec 7 20:16:36 2021 +0000
block: fix single bio async DIO error handling
in your tree?
On Tue, Dec 14, 2021 at 10:09 PM Vishal Verma
[off-list ref] wrote:
quoted
This adds nowait support to the RAID10 driver. Very similar to
raid1 driver changes. It makes RAID10 driver return with EAGAIN
for situations where it could wait for eg:
- Waiting for the barrier,
- Too many pending I/Os to be queued,
- Reshape operation,
- Discard operation.
wait_barrier() fn is modified to return bool to support error for
wait barriers. It returns true in case of wait or if wait is not
required and returns false if wait was required but not performed
to support nowait.
Signed-off-by: Vishal Verma <redacted>
---
drivers/md/raid10.c | 57
+++++++++++++++++++++++++++++++++++----------
1 file changed, 45 insertions(+), 12 deletions(-)
@@ -952,11 +952,18 @@ static void lower_barrier(struct r10conf *conf)wake_up(&conf->wait_barrier);}-staticvoidwait_barrier(structr10conf*conf)+staticboolwait_barrier(structr10conf*conf,boolnowait){spin_lock_irq(&conf->resync_lock);if(conf->barrier){structbio_list*bio_list=current->bio_list;++/* Return false when nowait flag is set */+if(nowait){+spin_unlock_irq(&conf->resync_lock);+returnfalse;+}+conf->nr_waiting++;/* Wait for the barrier to drop.*Howeveriftherearealreadypending
*cb, bool from_schedule)
static void regular_request_wait(struct mddev *mddev, struct
r10conf *conf,
struct bio *bio, sector_t sectors)
{
- wait_barrier(conf);
+ /* Bail out if REQ_NOWAIT is set for the bio */
+ if (!wait_barrier(conf, bio->bi_opf & REQ_NOWAIT)) {
+ bio_wouldblock_error(bio);
+ return;
+ }
I think we also need regular_request_wait to return bool and handle
it properly.
Thanks,
Song
Do you have:
commit 75feae73a28020e492fbad2323245455ef69d687
Author: Pavel Begunkov [off-list ref]
Date: Tue Dec 7 20:16:36 2021 +0000
block: fix single bio async DIO error handling
in your tree?
Nope. I will get it in and test. Thanks!
Might be worth re-running with KASAN enabled in your config to see if
that triggers anything.
--
Jens Axboe
On Tue, Dec 14, 2021 at 10:09 PM Vishal Verma
[off-list ref] wrote:
quoted
This adds nowait support to the RAID10 driver. Very similar to
raid1 driver changes. It makes RAID10 driver return with EAGAIN
for situations where it could wait for eg:
- Waiting for the barrier,
- Too many pending I/Os to be queued,
- Reshape operation,
- Discard operation.
wait_barrier() fn is modified to return bool to support error for
wait barriers. It returns true in case of wait or if wait is not
required and returns false if wait was required but not performed
to support nowait.
Signed-off-by: Vishal Verma <redacted>
---
drivers/md/raid10.c | 57
+++++++++++++++++++++++++++++++++++----------
1 file changed, 45 insertions(+), 12 deletions(-)
@@ -952,11 +952,18 @@ static void lower_barrier(struct r10conf *conf)wake_up(&conf->wait_barrier);}-staticvoidwait_barrier(structr10conf*conf)+staticboolwait_barrier(structr10conf*conf,boolnowait){spin_lock_irq(&conf->resync_lock);if(conf->barrier){structbio_list*bio_list=current->bio_list;++/* Return false when nowait flag is set */+if(nowait){+spin_unlock_irq(&conf->resync_lock);+returnfalse;+}+conf->nr_waiting++;/* Wait for the barrier to drop.*Howeveriftherearealreadypending
*cb, bool from_schedule)
static void regular_request_wait(struct mddev *mddev, struct
r10conf *conf,
struct bio *bio, sector_t sectors)
{
- wait_barrier(conf);
+ /* Bail out if REQ_NOWAIT is set for the bio */
+ if (!wait_barrier(conf, bio->bi_opf & REQ_NOWAIT)) {
+ bio_wouldblock_error(bio);
+ return;
+ }
I think we also need regular_request_wait to return bool and handle
it properly.
Thanks,
Song
Do you have:
commit 75feae73a28020e492fbad2323245455ef69d687
Author: Pavel Begunkov [off-list ref]
Date: Tue Dec 7 20:16:36 2021 +0000
block: fix single bio async DIO error handling
in your tree?
Nope. I will get it in and test. Thanks!
Might be worth re-running with KASAN enabled in your config to see if
that triggers anything.
From: Song Liu <song@kernel.org> Date: 2021-12-16 20:19:11
On Thu, Dec 16, 2021 at 11:40 AM Vishal Verma [off-list ref] wrote:
On 12/16/21 11:49 AM, Jens Axboe wrote:
quoted
On 12/16/21 9:45 AM, Vishal Verma wrote:
quoted
On 12/16/21 9:42 AM, Jens Axboe wrote:
quoted
On 12/15/21 5:30 PM, Vishal Verma wrote:
quoted
On 12/15/21 3:20 PM, Vishal Verma wrote:
quoted
On 12/15/21 1:42 PM, Song Liu wrote:
quoted
On Tue, Dec 14, 2021 at 10:09 PM Vishal Verma
[off-list ref] wrote:
quoted
This adds nowait support to the RAID10 driver. Very similar to
raid1 driver changes. It makes RAID10 driver return with EAGAIN
for situations where it could wait for eg:
- Waiting for the barrier,
- Too many pending I/Os to be queued,
- Reshape operation,
- Discard operation.
wait_barrier() fn is modified to return bool to support error for
wait barriers. It returns true in case of wait or if wait is not
required and returns false if wait was required but not performed
to support nowait.
Signed-off-by: Vishal Verma <redacted>
---
drivers/md/raid10.c | 57
+++++++++++++++++++++++++++++++++++----------
1 file changed, 45 insertions(+), 12 deletions(-)
@@ -952,11 +952,18 @@ static void lower_barrier(struct r10conf *conf)wake_up(&conf->wait_barrier);}-staticvoidwait_barrier(structr10conf*conf)+staticboolwait_barrier(structr10conf*conf,boolnowait){spin_lock_irq(&conf->resync_lock);if(conf->barrier){structbio_list*bio_list=current->bio_list;++/* Return false when nowait flag is set */+if(nowait){+spin_unlock_irq(&conf->resync_lock);+returnfalse;+}+conf->nr_waiting++;/* Wait for the barrier to drop.*Howeveriftherearealreadypending
*cb, bool from_schedule)
static void regular_request_wait(struct mddev *mddev, struct
r10conf *conf,
struct bio *bio, sector_t sectors)
{
- wait_barrier(conf);
+ /* Bail out if REQ_NOWAIT is set for the bio */
+ if (!wait_barrier(conf, bio->bi_opf & REQ_NOWAIT)) {
+ bio_wouldblock_error(bio);
+ return;
+ }
I think we also need regular_request_wait to return bool and handle
it properly.
Thanks,
Song
Do you have:
commit 75feae73a28020e492fbad2323245455ef69d687
Author: Pavel Begunkov [off-list ref]
Date: Tue Dec 7 20:16:36 2021 +0000
block: fix single bio async DIO error handling
in your tree?
Nope. I will get it in and test. Thanks!
Might be worth re-running with KASAN enabled in your config to see if
that triggers anything.
On Thu, Dec 16, 2021 at 11:40 AM Vishal Verma [off-list ref] wrote:
quoted
On 12/16/21 11:49 AM, Jens Axboe wrote:
quoted
On 12/16/21 9:45 AM, Vishal Verma wrote:
quoted
On 12/16/21 9:42 AM, Jens Axboe wrote:
quoted
On 12/15/21 5:30 PM, Vishal Verma wrote:
quoted
On 12/15/21 3:20 PM, Vishal Verma wrote:
quoted
On 12/15/21 1:42 PM, Song Liu wrote:
quoted
On Tue, Dec 14, 2021 at 10:09 PM Vishal Verma
[off-list ref] wrote:
quoted
This adds nowait support to the RAID10 driver. Very similar to
raid1 driver changes. It makes RAID10 driver return with EAGAIN
for situations where it could wait for eg:
- Waiting for the barrier,
- Too many pending I/Os to be queued,
- Reshape operation,
- Discard operation.
wait_barrier() fn is modified to return bool to support error for
wait barriers. It returns true in case of wait or if wait is not
required and returns false if wait was required but not performed
to support nowait.
Signed-off-by: Vishal Verma <redacted>
---
drivers/md/raid10.c | 57
+++++++++++++++++++++++++++++++++++----------
1 file changed, 45 insertions(+), 12 deletions(-)
@@ -952,11 +952,18 @@ static void lower_barrier(struct r10conf *conf)wake_up(&conf->wait_barrier);}-staticvoidwait_barrier(structr10conf*conf)+staticboolwait_barrier(structr10conf*conf,boolnowait){spin_lock_irq(&conf->resync_lock);if(conf->barrier){structbio_list*bio_list=current->bio_list;++/* Return false when nowait flag is set */+if(nowait){+spin_unlock_irq(&conf->resync_lock);+returnfalse;+}+conf->nr_waiting++;/* Wait for the barrier to drop.*Howeveriftherearealreadypending
*cb, bool from_schedule)
static void regular_request_wait(struct mddev *mddev, struct
r10conf *conf,
struct bio *bio, sector_t sectors)
{
- wait_barrier(conf);
+ /* Bail out if REQ_NOWAIT is set for the bio */
+ if (!wait_barrier(conf, bio->bi_opf & REQ_NOWAIT)) {
+ bio_wouldblock_error(bio);
+ return;
+ }
I think we also need regular_request_wait to return bool and handle
it properly.
Thanks,
Song
Do you have:
commit 75feae73a28020e492fbad2323245455ef69d687
Author: Pavel Begunkov [off-list ref]
Date: Tue Dec 7 20:16:36 2021 +0000
block: fix single bio async DIO error handling
in your tree?
Nope. I will get it in and test. Thanks!
Might be worth re-running with KASAN enabled in your config to see if
that triggers anything.
What's the exact command line that triggers this? I am not able to
trigger it with
either fio or t/io_uring.
Song
I only had 1 nvme so was creating 4 partitions on it and creating a
raid10 and doing:
mdadm -C /dev/md10 -l 10 -n 4 /dev/nvme4n1p1 /dev/nvme4n1p2
/dev/nvme4n1p3 /dev/nvme4n1p4
./t/io_uring /dev/md10-d 256 -p 0 -a 0 -r 100
on top of commit: c14704e1cb556 (md-next branch) + "md: add support for
REQ_NOWAIT" patch
Also, applied the commit (75feae73a28) Jens pointed earlier today.
What's the exact command line that triggers this? I am not able to
trigger it with
either fio or t/io_uring.
Song
I only had 1 nvme so was creating 4 partitions on it and creating a
raid10 and doing:
mdadm -C /dev/md10 -l 10 -n 4 /dev/nvme4n1p1 /dev/nvme4n1p2
/dev/nvme4n1p3 /dev/nvme4n1p4
./t/io_uring /dev/md10-d 256 -p 0 -a 0 -r 100
on top of commit: c14704e1cb556 (md-next branch) + "md: add support for
REQ_NOWAIT" patch
Also, applied the commit (75feae73a28) Jens pointed earlier today.
I am able to trigger the following error. I will look into it.
Thanks,
Song
[ 1583.149004] ==================================================================
[ 1583.150100] BUG: KASAN: use-after-free in raid10_end_read_request+0x91/0x310
[ 1583.151042] Read of size 8 at addr ffff888160a1c928 by task io_uring/1165
[ 1583.152016]
[ 1583.152247] CPU: 0 PID: 1165 Comm: io_uring Not tainted 5.16.0-rc3+ #660
[ 1583.153159] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
BIOS 1.13.0-2.module_el8.4.0+547+a85d02ba 04/01/2014
[ 1583.154572] Call Trace:
[ 1583.155005] <IRQ>
[ 1583.155338] dump_stack_lvl+0x44/0x57
[ 1583.155950] print_address_description.constprop.8.cold.17+0x12/0x339
[ 1583.156969] ? raid10_end_read_request+0x91/0x310
[ 1583.157578] ? raid10_end_read_request+0x91/0x310
[ 1583.158272] kasan_report.cold.18+0x83/0xdf
[ 1583.158889] ? raid10_end_read_request+0x91/0x310
[ 1583.159554] raid10_end_read_request+0x91/0x310
[ 1583.160201] ? raid10_resize+0x270/0x270
[ 1583.160724] ? bio_uninit+0xc7/0x1e0
[ 1583.161274] blk_update_request+0x21f/0x810
[ 1583.161893] blk_mq_end_request_batch+0x11c/0xa70
[ 1583.162497] ? blk_mq_end_request+0x460/0x460
[ 1583.163204] ? nvme_complete_batch_req+0x12/0x30
[ 1583.163888] nvme_irq+0x6ad/0x6f0
[ 1583.164354] ? io_queue_count_set+0xe0/0xe0
[ 1583.164980] ? nvme_unmap_data+0x1e0/0x1e0
[ 1583.165504] ? rcu_read_lock_bh_held+0xb0/0xb0
[ 1583.166149] ? io_queue_count_set+0xe0/0xe0
[ 1583.166721] __handle_irq_event_percpu+0x79/0x440
[ 1583.167446] handle_irq_event_percpu+0x6f/0xe0
[ 1583.168101] ? __handle_irq_event_percpu+0x440/0x440
[ 1583.168734] ? lock_contended+0x6e0/0x6e0
[ 1583.169349] ? do_raw_spin_unlock+0xa2/0x130
[ 1583.169961] handle_irq_event+0x54/0x90
[ 1583.170442] handle_edge_irq+0x121/0x300
[ 1583.171012] __common_interrupt+0x7d/0x170
[ 1583.171538] common_interrupt+0xa0/0xc0
[ 1583.172103] </IRQ>
[ 1583.172389] <TASK>
commit 021a24460dc2 ("block: add QUEUE_FLAG_NOWAIT") added support
for checking whether a given bdev supports handling of REQ_NOWAIT or not.
Since then commit 6abc49468eea ("dm: add support for REQ_NOWAIT and enable
it for linear target") added support for REQ_NOWAIT for dm. This uses
a similar approach to incorporate REQ_NOWAIT for md based bios.
This patch was tested using t/io_uring tool within FIO. A nvme drive
was partitioned into 2 partitions and a simple raid 0 configuration
/dev/md0 was created.
md0 : active raid0 nvme4n1p1[1] nvme4n1p2[0]
937423872 blocks super 1.2 512k chunks
Before patch:
$ ./t/io_uring /dev/md0 -p 0 -a 0 -d 1 -r 100
Running top while the above runs:
$ ps -eL | grep $(pidof io_uring)
38396 38396 pts/2 00:00:00 io_uring
38396 38397 pts/2 00:00:15 io_uring
38396 38398 pts/2 00:00:13 iou-wrk-38397
We can see iou-wrk-38397 io worker thread created which gets created
when io_uring sees that the underlying device (/dev/md0 in this case)
doesn't support nowait.
After patch:
$ ./t/io_uring /dev/md0 -p 0 -a 0 -d 1 -r 100
Running top while the above runs:
$ ps -eL | grep $(pidof io_uring)
38341 38341 pts/2 00:10:22 io_uring
38341 38342 pts/2 00:10:37 io_uring
After running this patch, we don't see any io worker thread
being created which indicated that io_uring saw that the
underlying device does support nowait. This is the exact behaviour
noticed on a dm device which also supports nowait.
For all the other raid personalities except raid0, we would need
to train pieces which involves make_request fn in order for them
to correctly handle REQ_NOWAIT.
Signed-off-by: Vishal Verma <redacted>
---
drivers/md/md.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
@@ -418,6 +418,11 @@ void md_handle_request(struct mddev *mddev, struct bio *bio)rcu_read_lock();if(is_suspended(mddev,bio)){DEFINE_WAIT(__wait);+/* Bail out if REQ_NOWAIT is set for the bio */+if(bio->bi_opf&REQ_NOWAIT){+bio_wouldblock_error(bio);+return;+}for(;;){prepare_to_wait(&mddev->sb_wait,&__wait,TASK_UNINTERRUPTIBLE);
@@ -5792,6 +5797,7 @@ int md_run(struct mddev *mddev)interr;structmd_rdev*rdev;structmd_personality*pers;+boolnowait=true;if(list_empty(&mddev->disks))/* cannot run an array with no devices.. */
@@ -5862,8 +5868,13 @@ int md_run(struct mddev *mddev)}}sysfs_notify_dirent_safe(rdev->sysfs_state);+nowait=nowait&&blk_queue_nowait(bdev_get_queue(rdev->bdev));}+/* Set the NOWAIT flags if all underlying devices support it */+if(nowait)+blk_queue_flag_set(QUEUE_FLAG_NOWAIT,mddev->queue);+if(!bioset_initialized(&mddev->bio_set)){err=bioset_init(&mddev->bio_set,BIO_POOL_SIZE,0,BIOSET_NEED_BVECS);if(err)
@@ -7007,6 +7018,15 @@ static int hot_add_disk(struct mddev *mddev, dev_t dev)set_bit(MD_SB_CHANGE_DEVS,&mddev->sb_flags);if(!mddev->thread)md_update_sb(mddev,1);+/*+*IfthenewdiskdoesnotsupportREQ_NOWAIT,+*disableonthewholeMD.+*/+if(!blk_queue_nowait(bdev_get_queue(rdev->bdev))){+pr_info("%s: Disabling nowait because %s does not support nowait\n",+mdname(mddev),bdevname(rdev->bdev,b));+blk_queue_flag_clear(QUEUE_FLAG_NOWAIT,mddev->queue);+}/**Kickrecovery,maybethissparehastobeaddedtothe*arrayimmediately.
This adds nowait support to the RAID1 driver. It makes RAID1 driver
return with EAGAIN for situations where it could wait for eg:
- Waiting for the barrier,
- Too many pending I/Os to be queued.
wait_barrier() fn is modified to return bool to support error for
wait barriers. It returns true in case of wait or if wait is not
required and returns false if wait was required but not performed
to support nowait.
Signed-off-by: Vishal Verma <redacted>
---
drivers/md/raid1.c | 83 +++++++++++++++++++++++++++++++++++-----------
1 file changed, 64 insertions(+), 19 deletions(-)
@@ -979,18 +980,29 @@ static void _wait_barrier(struct r1conf *conf, int idx)*/wake_up(&conf->wait_barrier);/* Wait for the barrier in same barrier unit bucket to drop. */-wait_event_lock_irq(conf->wait_barrier,-!conf->array_frozen&&-!atomic_read(&conf->barrier[idx]),-conf->resync_lock);-atomic_inc(&conf->nr_pending[idx]);++/* Return false when nowait flag is set */+if(nowait)+ret=false;+else{+wait_event_lock_irq(conf->wait_barrier,+!conf->array_frozen&&+!atomic_read(&conf->barrier[idx]),+conf->resync_lock);+}++/* Only increment nr_pending when we wait */+if(ret)+atomic_inc(&conf->nr_pending[idx]);atomic_dec(&conf->nr_waiting[idx]);spin_unlock_irq(&conf->resync_lock);+returnret;}-staticvoidwait_read_barrier(structr1conf*conf,sector_tsector_nr)+staticboolwait_read_barrier(structr1conf*conf,sector_tsector_nr,boolnowait){intidx=sector_to_idx(sector_nr);+boolret=true;/**Verysimilarto_wait_barrier().Thedifferenceis,forread
@@ -1013,19 +1025,30 @@ static void wait_read_barrier(struct r1conf *conf, sector_t sector_nr)*/wake_up(&conf->wait_barrier);/* Wait for array to be unfrozen */-wait_event_lock_irq(conf->wait_barrier,-!conf->array_frozen,-conf->resync_lock);-atomic_inc(&conf->nr_pending[idx]);++/* Return false when nowait flag is set */+if(nowait)+/* Return false when nowait flag is set */+ret=false;+else{+wait_event_lock_irq(conf->wait_barrier,+!conf->array_frozen,+conf->resync_lock);+}++/* Only increment nr_pending when we wait */+if(ret)+atomic_inc(&conf->nr_pending[idx]);atomic_dec(&conf->nr_waiting[idx]);spin_unlock_irq(&conf->resync_lock);+returnret;}-staticvoidwait_barrier(structr1conf*conf,sector_tsector_nr)+staticboolwait_barrier(structr1conf*conf,sector_tsector_nr,boolnowait){intidx=sector_to_idx(sector_nr);-_wait_barrier(conf,idx);+return_wait_barrier(conf,idx,nowait);}staticvoid_allow_barrier(structr1conf*conf,intidx)
This adds nowait support to the RAID10 driver. Very similar to
raid1 driver changes. It makes RAID10 driver return with EAGAIN
for situations where it could wait for eg:
- Waiting for the barrier,
- Too many pending I/Os to be queued,
- Reshape operation,
- Discard operation.
wait_barrier() and regular_request_wait() fn are modified to return bool
to support error for wait barriers. They returns true in case of wait
or if wait is not required and returns false if wait was required
but not performed to support nowait.
Signed-off-by: Vishal Verma <redacted>
---
drivers/md/raid10.c | 90 +++++++++++++++++++++++++++++++--------------
1 file changed, 62 insertions(+), 28 deletions(-)
@@ -968,26 +969,33 @@ static void wait_barrier(struct r10conf *conf)*countdown.*/raid10_log(conf->mddev,"wait barrier");-wait_event_lock_irq(conf->wait_barrier,-!conf->barrier||-(atomic_read(&conf->nr_pending)&&-bio_list&&-(!bio_list_empty(&bio_list[0])||-!bio_list_empty(&bio_list[1])))||-/* move on if recovery thread is-*blockedbyus-*/-(conf->mddev->thread->tsk==current&&-test_bit(MD_RECOVERY_RUNNING,-&conf->mddev->recovery)&&-conf->nr_queued>0),-conf->resync_lock);+/* Return false when nowait flag is set */+if(nowait)+ret=false;+else+wait_event_lock_irq(conf->wait_barrier,+!conf->barrier||+(atomic_read(&conf->nr_pending)&&+bio_list&&+(!bio_list_empty(&bio_list[0])||+!bio_list_empty(&bio_list[1])))||+/* move on if recovery thread is+*blockedbyus+*/+(conf->mddev->thread->tsk==current&&+test_bit(MD_RECOVERY_RUNNING,+&conf->mddev->recovery)&&+conf->nr_queued>0),+conf->resync_lock);conf->nr_waiting--;if(!conf->nr_waiting)wake_up(&conf->wait_barrier);}-atomic_inc(&conf->nr_pending);+/* Only increment nr_pending when we wait */+if(ret)+atomic_inc(&conf->nr_pending);spin_unlock_irq(&conf->resync_lock);+returnret;}staticvoidallow_barrier(structr10conf*conf)
@@ -1098,21 +1106,30 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule)*currently.*2.IfIOspansthereshapeposition.Needtowaitforreshapetopass.*/-staticvoidregular_request_wait(structmddev*mddev,structr10conf*conf,+staticboolregular_request_wait(structmddev*mddev,structr10conf*conf,structbio*bio,sector_tsectors){-wait_barrier(conf);+/* Bail out if REQ_NOWAIT is set for the bio */+if(!wait_barrier(conf,bio->bi_opf&REQ_NOWAIT)){+bio_wouldblock_error(bio);+returnfalse;+}while(test_bit(MD_RECOVERY_RESHAPE,&mddev->recovery)&&bio->bi_iter.bi_sector<conf->reshape_progress&&bio->bi_iter.bi_sector+sectors>conf->reshape_progress){raid10_log(conf->mddev,"wait reshape");+if(bio->bi_opf&REQ_NOWAIT){+bio_wouldblock_error(bio);+returnfalse;+}allow_barrier(conf);wait_event(conf->wait_barrier,conf->reshape_progress<=bio->bi_iter.bi_sector||conf->reshape_progress>=bio->bi_iter.bi_sector+sectors);-wait_barrier(conf);+wait_barrier(conf,false);}+returntrue;}staticvoidraid10_read_request(structmddev*mddev,structbio*bio,
@@ -1356,6 +1373,11 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,bio->bi_iter.bi_sector,bio_end_sector(bio)))){DEFINE_WAIT(w);+/* Bail out if REQ_NOWAIT is set for the bio */+if(bio->bi_opf&REQ_NOWAIT){+bio_wouldblock_error(bio);+return;+}for(;;){prepare_to_wait(&conf->wait_barrier,&w,TASK_IDLE);
@@ -1607,7 +1637,11 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio)if(test_bit(MD_RECOVERY_RESHAPE,&mddev->recovery))return-EAGAIN;-wait_barrier(conf);+if(bio->bi_opf&REQ_NOWAIT){+bio_wouldblock_error(bio);+return0;+}+wait_barrier(conf,false);/**Checkreshapeagaintoavoidreshapehappensafterchecking
@@ -1649,7 +1683,7 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio)allow_barrier(conf);/* Resend the fist split part */submit_bio_noacct(split);-wait_barrier(conf);+wait_barrier(conf,false);}div_u64_rem(bio_end,stripe_size,&remainder);if(remainder){
@@ -1660,7 +1694,7 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio)/* Resend the second split part */submit_bio_noacct(bio);bio=split;-wait_barrier(conf);+wait_barrier(conf,false);}bio_start=bio->bi_iter.bi_sector;
@@ -1816,7 +1850,7 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio)end_disk_offset+=geo->stride;atomic_inc(&first_r10bio->remaining);raid_end_discard_bio(r10_bio);-wait_barrier(conf);+wait_barrier(conf,false);gotoretry_discard;}
@@ -5715,6 +5715,11 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi)set_bit(R5_Overlap,&sh->dev[sh->pd_idx].flags);if(test_bit(STRIPE_SYNCING,&sh->state)){raid5_release_stripe(sh);+/* Bail out if REQ_NOWAIT is set */+if(bi->bi_opf&REQ_NOWAIT){+bio_wouldblock_error(bi);+return;+}schedule();gotoagain;}
@@ -5727,6 +5732,11 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi)set_bit(R5_Overlap,&sh->dev[d].flags);spin_unlock_irq(&sh->stripe_lock);raid5_release_stripe(sh);+/* Bail out if REQ_NOWAIT is set */+if(bi->bi_opf&REQ_NOWAIT){+bio_wouldblock_error(bi);+return;+}schedule();gotoagain;}
@@ -5820,6 +5830,16 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)bi->bi_next=NULL;md_account_bio(mddev,&bi);+/* Bail out if REQ_NOWAIT is set */+if((bi->bi_opf&REQ_NOWAIT)&&+(conf->reshape_progress!=MaxSector)&&+(mddev->reshape_backwards+?(logical_sector>conf->reshape_progress&&logical_sector<=conf->reshape_safe)+:(logical_sector>=conf->reshape_safe&&logical_sector<conf->reshape_progress))){+bio_wouldblock_error(bi);+returntrue;+}+prepare_to_wait(&conf->wait_for_overlap,&w,TASK_UNINTERRUPTIBLE);for(;logical_sector<last_sector;logical_sector+=RAID5_STRIPE_SECTORS(conf)){intprevious;
From: John Stoffel <hidden> Date: 2021-12-21 22:02:47
quoted
quoted
quoted
quoted
"Vishal" == Vishal Verma [off-list ref] writes:
Vishal> Returns EAGAIN in case the raid456 driver would block
Vishal> waiting for situations like:
Vishal> - Reshape operation,
Vishal> - Discard operation.
Vishal> Signed-off-by: Vishal Verma [off-list ref]
Are there any performance implications with this patch set? I didn't
see any discussion in the patch set (v6) and I was just wondering what
this buys us? Your patch 1/4 talks about using fio as a test, but
there's no mention of whether it's now faster or slower.
John
commit 021a24460dc2 ("block: add QUEUE_FLAG_NOWAIT") added support
for checking whether a given bdev supports handling of REQ_NOWAIT or not.
Since then commit 6abc49468eea ("dm: add support for REQ_NOWAIT and enable
it for linear target") added support for REQ_NOWAIT for dm. This uses
a similar approach to incorporate REQ_NOWAIT for md based bios.
This patch was tested using t/io_uring tool within FIO. A nvme drive
was partitioned into 2 partitions and a simple raid 0 configuration
/dev/md0 was created.
md0 : active raid0 nvme4n1p1[1] nvme4n1p2[0]
937423872 blocks super 1.2 512k chunks
Before patch:
$ ./t/io_uring /dev/md0 -p 0 -a 0 -d 1 -r 100
Running top while the above runs:
$ ps -eL | grep $(pidof io_uring)
38396 38396 pts/2 00:00:00 io_uring
38396 38397 pts/2 00:00:15 io_uring
38396 38398 pts/2 00:00:13 iou-wrk-38397
We can see iou-wrk-38397 io worker thread created which gets created
when io_uring sees that the underlying device (/dev/md0 in this case)
doesn't support nowait.
After patch:
$ ./t/io_uring /dev/md0 -p 0 -a 0 -d 1 -r 100
Running top while the above runs:
$ ps -eL | grep $(pidof io_uring)
38341 38341 pts/2 00:10:22 io_uring
38341 38342 pts/2 00:10:37 io_uring
After running this patch, we don't see any io worker thread
being created which indicated that io_uring saw that the
underlying device does support nowait. This is the exact behaviour
noticed on a dm device which also supports nowait.
For all the other raid personalities except raid0, we would need
to train pieces which involves make_request fn in order for them
to correctly handle REQ_NOWAIT.
1-4 look fine to me now:
Reviewed-by: Jens Axboe <axboe@kernel.dk>
--
Jens Axboe
From: Song Liu <song@kernel.org> Date: 2021-12-22 23:58:33
On Tue, Dec 21, 2021 at 12:06 PM Vishal Verma [off-list ref] wrote:
quoted hunk
This adds nowait support to the RAID10 driver. Very similar to
raid1 driver changes. It makes RAID10 driver return with EAGAIN
for situations where it could wait for eg:
- Waiting for the barrier,
- Too many pending I/Os to be queued,
- Reshape operation,
- Discard operation.
wait_barrier() and regular_request_wait() fn are modified to return bool
to support error for wait barriers. They returns true in case of wait
or if wait is not required and returns false if wait was required
but not performed to support nowait.
Signed-off-by: Vishal Verma <redacted>
---
drivers/md/raid10.c | 90 +++++++++++++++++++++++++++++++--------------
1 file changed, 62 insertions(+), 28 deletions(-)
@@ -968,26 +969,33 @@ static void wait_barrier(struct r10conf *conf)*countdown.*/raid10_log(conf->mddev,"wait barrier");-wait_event_lock_irq(conf->wait_barrier,-!conf->barrier||-(atomic_read(&conf->nr_pending)&&-bio_list&&-(!bio_list_empty(&bio_list[0])||-!bio_list_empty(&bio_list[1])))||-/* move on if recovery thread is-*blockedbyus-*/-(conf->mddev->thread->tsk==current&&-test_bit(MD_RECOVERY_RUNNING,-&conf->mddev->recovery)&&-conf->nr_queued>0),-conf->resync_lock);+/* Return false when nowait flag is set */+if(nowait)+ret=false;+else+wait_event_lock_irq(conf->wait_barrier,+!conf->barrier||+(atomic_read(&conf->nr_pending)&&+bio_list&&+(!bio_list_empty(&bio_list[0])||+!bio_list_empty(&bio_list[1])))||+/* move on if recovery thread is+*blockedbyus+*/+(conf->mddev->thread->tsk==current&&+test_bit(MD_RECOVERY_RUNNING,+&conf->mddev->recovery)&&+conf->nr_queued>0),+conf->resync_lock);conf->nr_waiting--;if(!conf->nr_waiting)wake_up(&conf->wait_barrier);}-atomic_inc(&conf->nr_pending);+/* Only increment nr_pending when we wait */+if(ret)+atomic_inc(&conf->nr_pending);spin_unlock_irq(&conf->resync_lock);+returnret;}staticvoidallow_barrier(structr10conf*conf)
From: Song Liu <song@kernel.org> Date: 2021-12-23 01:22:57
On Tue, Dec 21, 2021 at 12:06 PM Vishal Verma [off-list ref] wrote:
quoted hunk
commit 021a24460dc2 ("block: add QUEUE_FLAG_NOWAIT") added support
for checking whether a given bdev supports handling of REQ_NOWAIT or not.
Since then commit 6abc49468eea ("dm: add support for REQ_NOWAIT and enable
it for linear target") added support for REQ_NOWAIT for dm. This uses
a similar approach to incorporate REQ_NOWAIT for md based bios.
This patch was tested using t/io_uring tool within FIO. A nvme drive
was partitioned into 2 partitions and a simple raid 0 configuration
/dev/md0 was created.
md0 : active raid0 nvme4n1p1[1] nvme4n1p2[0]
937423872 blocks super 1.2 512k chunks
Before patch:
$ ./t/io_uring /dev/md0 -p 0 -a 0 -d 1 -r 100
Running top while the above runs:
$ ps -eL | grep $(pidof io_uring)
38396 38396 pts/2 00:00:00 io_uring
38396 38397 pts/2 00:00:15 io_uring
38396 38398 pts/2 00:00:13 iou-wrk-38397
We can see iou-wrk-38397 io worker thread created which gets created
when io_uring sees that the underlying device (/dev/md0 in this case)
doesn't support nowait.
After patch:
$ ./t/io_uring /dev/md0 -p 0 -a 0 -d 1 -r 100
Running top while the above runs:
$ ps -eL | grep $(pidof io_uring)
38341 38341 pts/2 00:10:22 io_uring
38341 38342 pts/2 00:10:37 io_uring
After running this patch, we don't see any io worker thread
being created which indicated that io_uring saw that the
underlying device does support nowait. This is the exact behaviour
noticed on a dm device which also supports nowait.
For all the other raid personalities except raid0, we would need
to train pieces which involves make_request fn in order for them
to correctly handle REQ_NOWAIT.
Signed-off-by: Vishal Verma <redacted>
---
drivers/md/md.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
@@ -418,6 +418,11 @@ void md_handle_request(struct mddev *mddev, struct bio *bio)rcu_read_lock();if(is_suspended(mddev,bio)){DEFINE_WAIT(__wait);+/* Bail out if REQ_NOWAIT is set for the bio */+if(bio->bi_opf&REQ_NOWAIT){
From: Song Liu <song@kernel.org> Date: 2021-12-23 01:47:41
On Tue, Dec 21, 2021 at 12:06 PM Vishal Verma [off-list ref] wrote:
quoted hunk
This adds nowait support to the RAID10 driver. Very similar to
raid1 driver changes. It makes RAID10 driver return with EAGAIN
for situations where it could wait for eg:
- Waiting for the barrier,
- Too many pending I/Os to be queued,
- Reshape operation,
- Discard operation.
wait_barrier() and regular_request_wait() fn are modified to return bool
to support error for wait barriers. They returns true in case of wait
or if wait is not required and returns false if wait was required
but not performed to support nowait.
Signed-off-by: Vishal Verma <redacted>
---
drivers/md/raid10.c | 90 +++++++++++++++++++++++++++++++--------------
1 file changed, 62 insertions(+), 28 deletions(-)
@@ -968,26 +969,33 @@ static void wait_barrier(struct r10conf *conf)*countdown.*/raid10_log(conf->mddev,"wait barrier");-wait_event_lock_irq(conf->wait_barrier,-!conf->barrier||-(atomic_read(&conf->nr_pending)&&-bio_list&&-(!bio_list_empty(&bio_list[0])||-!bio_list_empty(&bio_list[1])))||-/* move on if recovery thread is-*blockedbyus-*/-(conf->mddev->thread->tsk==current&&-test_bit(MD_RECOVERY_RUNNING,-&conf->mddev->recovery)&&-conf->nr_queued>0),-conf->resync_lock);+/* Return false when nowait flag is set */+if(nowait)+ret=false;+else+wait_event_lock_irq(conf->wait_barrier,+!conf->barrier||+(atomic_read(&conf->nr_pending)&&+bio_list&&+(!bio_list_empty(&bio_list[0])||+!bio_list_empty(&bio_list[1])))||+/* move on if recovery thread is+*blockedbyus+*/+(conf->mddev->thread->tsk==current&&+test_bit(MD_RECOVERY_RUNNING,+&conf->mddev->recovery)&&+conf->nr_queued>0),+conf->resync_lock);conf->nr_waiting--;if(!conf->nr_waiting)wake_up(&conf->wait_barrier);}-atomic_inc(&conf->nr_pending);+/* Only increment nr_pending when we wait */+if(ret)+atomic_inc(&conf->nr_pending);spin_unlock_irq(&conf->resync_lock);+returnret;}staticvoidallow_barrier(structr10conf*conf)
@@ -1098,21 +1106,30 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule)*currently.*2.IfIOspansthereshapeposition.Needtowaitforreshapetopass.*/-staticvoidregular_request_wait(structmddev*mddev,structr10conf*conf,+staticboolregular_request_wait(structmddev*mddev,structr10conf*conf,structbio*bio,sector_tsectors){-wait_barrier(conf);+/* Bail out if REQ_NOWAIT is set for the bio */+if(!wait_barrier(conf,bio->bi_opf&REQ_NOWAIT)){+bio_wouldblock_error(bio);+returnfalse;+}while(test_bit(MD_RECOVERY_RESHAPE,&mddev->recovery)&&bio->bi_iter.bi_sector<conf->reshape_progress&&bio->bi_iter.bi_sector+sectors>conf->reshape_progress){raid10_log(conf->mddev,"wait reshape");+if(bio->bi_opf&REQ_NOWAIT){+bio_wouldblock_error(bio);+returnfalse;+}allow_barrier(conf);wait_event(conf->wait_barrier,conf->reshape_progress<=bio->bi_iter.bi_sector||conf->reshape_progress>=bio->bi_iter.bi_sector+sectors);-wait_barrier(conf);+wait_barrier(conf,false);}+returntrue;}staticvoidraid10_read_request(structmddev*mddev,structbio*bio,
@@ -1356,6 +1373,11 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio, bio->bi_iter.bi_sector, bio_end_sector(bio)))) { DEFINE_WAIT(w);+ /* Bail out if REQ_NOWAIT is set for the bio */+ if (bio->bi_opf & REQ_NOWAIT) {+ bio_wouldblock_error(bio);+ return;+ } for (;;) { prepare_to_wait(&conf->wait_barrier, &w, TASK_IDLE);
@@ -1607,7 +1637,11 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio) if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) return -EAGAIN;- wait_barrier(conf);+ if (bio->bi_opf & REQ_NOWAIT) {+ bio_wouldblock_error(bio);+ return 0;
Shall we return -EAGAIN here?
quoted hunk
+ }
+ wait_barrier(conf, false);
/*
* Check reshape again to avoid reshape happens after checking
@@ -1649,7 +1683,7 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio) allow_barrier(conf); /* Resend the fist split part */ submit_bio_noacct(split);- wait_barrier(conf);+ wait_barrier(conf, false); } div_u64_rem(bio_end, stripe_size, &remainder); if (remainder) {
@@ -1660,7 +1694,7 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio) /* Resend the second split part */ submit_bio_noacct(bio); bio = split;- wait_barrier(conf);+ wait_barrier(conf, false); } bio_start = bio->bi_iter.bi_sector;
From: Song Liu <song@kernel.org> Date: 2021-12-23 02:57:50
On Tue, Dec 21, 2021 at 12:06 PM Vishal Verma [off-list ref] wrote:
commit 021a24460dc2 ("block: add QUEUE_FLAG_NOWAIT") added support
for checking whether a given bdev supports handling of REQ_NOWAIT or not.
Since then commit 6abc49468eea ("dm: add support for REQ_NOWAIT and enable
it for linear target") added support for REQ_NOWAIT for dm. This uses
a similar approach to incorporate REQ_NOWAIT for md based bios.
This patch was tested using t/io_uring tool within FIO. A nvme drive
was partitioned into 2 partitions and a simple raid 0 configuration
/dev/md0 was created.
md0 : active raid0 nvme4n1p1[1] nvme4n1p2[0]
937423872 blocks super 1.2 512k chunks
Before patch:
$ ./t/io_uring /dev/md0 -p 0 -a 0 -d 1 -r 100
Running top while the above runs:
$ ps -eL | grep $(pidof io_uring)
38396 38396 pts/2 00:00:00 io_uring
38396 38397 pts/2 00:00:15 io_uring
38396 38398 pts/2 00:00:13 iou-wrk-38397
We can see iou-wrk-38397 io worker thread created which gets created
when io_uring sees that the underlying device (/dev/md0 in this case)
doesn't support nowait.
After patch:
$ ./t/io_uring /dev/md0 -p 0 -a 0 -d 1 -r 100
Running top while the above runs:
$ ps -eL | grep $(pidof io_uring)
38341 38341 pts/2 00:10:22 io_uring
38341 38342 pts/2 00:10:37 io_uring
After running this patch, we don't see any io worker thread
being created which indicated that io_uring saw that the
underlying device does support nowait. This is the exact behaviour
noticed on a dm device which also supports nowait.
For all the other raid personalities except raid0, we would need
to train pieces which involves make_request fn in order for them
to correctly handle REQ_NOWAIT.
Signed-off-by: Vishal Verma <redacted>
I have made some changes and applied the set to md-next. However,
I think we don't yet have enough test coverage. Please continue testing
the code and send fixes on top of it. Based on the test results, we will
see whether we can ship it in the next merge window.
Note, md-next branch doesn't have [1], so we need to cherry-pick it
for testing.
Thanks,
Song
[1] a08ed9aae8a3 ("block: fix double bio queue when merging in cached
request path")
On Tue, Dec 21, 2021 at 12:06 PM Vishal Verma [off-list ref] wrote:
quoted
commit 021a24460dc2 ("block: add QUEUE_FLAG_NOWAIT") added support
for checking whether a given bdev supports handling of REQ_NOWAIT or not.
Since then commit 6abc49468eea ("dm: add support for REQ_NOWAIT and enable
it for linear target") added support for REQ_NOWAIT for dm. This uses
a similar approach to incorporate REQ_NOWAIT for md based bios.
This patch was tested using t/io_uring tool within FIO. A nvme drive
was partitioned into 2 partitions and a simple raid 0 configuration
/dev/md0 was created.
md0 : active raid0 nvme4n1p1[1] nvme4n1p2[0]
937423872 blocks super 1.2 512k chunks
Before patch:
$ ./t/io_uring /dev/md0 -p 0 -a 0 -d 1 -r 100
Running top while the above runs:
$ ps -eL | grep $(pidof io_uring)
38396 38396 pts/2 00:00:00 io_uring
38396 38397 pts/2 00:00:15 io_uring
38396 38398 pts/2 00:00:13 iou-wrk-38397
We can see iou-wrk-38397 io worker thread created which gets created
when io_uring sees that the underlying device (/dev/md0 in this case)
doesn't support nowait.
After patch:
$ ./t/io_uring /dev/md0 -p 0 -a 0 -d 1 -r 100
Running top while the above runs:
$ ps -eL | grep $(pidof io_uring)
38341 38341 pts/2 00:10:22 io_uring
38341 38342 pts/2 00:10:37 io_uring
After running this patch, we don't see any io worker thread
being created which indicated that io_uring saw that the
underlying device does support nowait. This is the exact behaviour
noticed on a dm device which also supports nowait.
For all the other raid personalities except raid0, we would need
to train pieces which involves make_request fn in order for them
to correctly handle REQ_NOWAIT.
Signed-off-by: Vishal Verma <redacted>
I have made some changes and applied the set to md-next. However,
I think we don't yet have enough test coverage. Please continue testing
the code and send fixes on top of it. Based on the test results, we will
see whether we can ship it in the next merge window.
Note, md-next branch doesn't have [1], so we need to cherry-pick it
for testing.
Thanks,
Song
[1] a08ed9aae8a3 ("block: fix double bio queue when merging in cached
request path")
Great, and I agree will continue testing this.
Just saw you already addressing some silly things
I missed in v6. Sorry about that.
Thank you!
From: Song Liu <song@kernel.org> Date: 2021-12-25 02:14:20
On Tue, Dec 21, 2021 at 12:06 PM Vishal Verma [off-list ref] wrote:
Returns EAGAIN in case the raid456 driver would block
waiting for situations like:
- Reshape operation,
- Discard operation.
Signed-off-by: Vishal Verma <redacted>
I think we will need the following fix for raid456:
============================ 8< ============================
*mddev, struct bio *bi)
raid5_release_stripe(sh);
/* Bail out if REQ_NOWAIT is set */
if (bi->bi_opf & REQ_NOWAIT) {
+ finish_wait(&conf->wait_for_overlap, &w);
bio_wouldblock_error(bi);
return;
}
*mddev, struct bio *bi)
raid5_release_stripe(sh);
/* Bail out if REQ_NOWAIT is set */
if (bi->bi_opf & REQ_NOWAIT) {
+
finish_wait(&conf->wait_for_overlap, &w);
bio_wouldblock_error(bi);
return;
}
*mddev, struct bio * bi)
? (logical_sector > conf->reshape_progress &&
logical_sector <= conf->reshape_safe)
: (logical_sector >= conf->reshape_safe && logical_sector
< conf->reshape_progress))) {
bio_wouldblock_error(bi);
+ if (rw == WRITE)
+ md_write_end(mddev);
return true;
}
-
+ md_account_bio(mddev, &bi);
prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE);
for (; logical_sector < last_sector; logical_sector +=
RAID5_STRIPE_SECTORS(conf)) {
int previous;
============================ 8< ============================
Vishal, please try to trigger all these conditions (including raid1,
raid10) and make sure
they work properly.
For example, I triggered raid5 reshape and used something like the
following to make
sure the logic is triggered:
From: Song Liu <song@kernel.org> Date: 2022-01-02 00:12:06
On Wed, Dec 22, 2021 at 6:57 PM Song Liu [off-list ref] wrote:
On Tue, Dec 21, 2021 at 12:06 PM Vishal Verma [off-list ref] wrote:
quoted
commit 021a24460dc2 ("block: add QUEUE_FLAG_NOWAIT") added support
for checking whether a given bdev supports handling of REQ_NOWAIT or not.
Since then commit 6abc49468eea ("dm: add support for REQ_NOWAIT and enable
it for linear target") added support for REQ_NOWAIT for dm. This uses
a similar approach to incorporate REQ_NOWAIT for md based bios.
This patch was tested using t/io_uring tool within FIO. A nvme drive
was partitioned into 2 partitions and a simple raid 0 configuration
/dev/md0 was created.
md0 : active raid0 nvme4n1p1[1] nvme4n1p2[0]
937423872 blocks super 1.2 512k chunks
Before patch:
$ ./t/io_uring /dev/md0 -p 0 -a 0 -d 1 -r 100
Running top while the above runs:
$ ps -eL | grep $(pidof io_uring)
38396 38396 pts/2 00:00:00 io_uring
38396 38397 pts/2 00:00:15 io_uring
38396 38398 pts/2 00:00:13 iou-wrk-38397
We can see iou-wrk-38397 io worker thread created which gets created
when io_uring sees that the underlying device (/dev/md0 in this case)
doesn't support nowait.
After patch:
$ ./t/io_uring /dev/md0 -p 0 -a 0 -d 1 -r 100
Running top while the above runs:
$ ps -eL | grep $(pidof io_uring)
38341 38341 pts/2 00:10:22 io_uring
38341 38342 pts/2 00:10:37 io_uring
After running this patch, we don't see any io worker thread
being created which indicated that io_uring saw that the
underlying device does support nowait. This is the exact behaviour
noticed on a dm device which also supports nowait.
For all the other raid personalities except raid0, we would need
to train pieces which involves make_request fn in order for them
to correctly handle REQ_NOWAIT.
Signed-off-by: Vishal Verma <redacted>
I have made some changes and applied the set to md-next. However,
I think we don't yet have enough test coverage. Please continue testing
the code and send fixes on top of it. Based on the test results, we will
see whether we can ship it in the next merge window.
Note, md-next branch doesn't have [1], so we need to cherry-pick it
for testing.
I went through all these changes again and tested many (but not all)
cases. The latest version is available in md-next branch.
Vishal, please run tests on this version and send fixes if anything
is broken.
Thanks,
Song
On Wed, Dec 22, 2021 at 6:57 PM Song Liu [off-list ref] wrote:
quoted
On Tue, Dec 21, 2021 at 12:06 PM Vishal Verma [off-list ref] wrote:
quoted
commit 021a24460dc2 ("block: add QUEUE_FLAG_NOWAIT") added support
for checking whether a given bdev supports handling of REQ_NOWAIT or not.
Since then commit 6abc49468eea ("dm: add support for REQ_NOWAIT and enable
it for linear target") added support for REQ_NOWAIT for dm. This uses
a similar approach to incorporate REQ_NOWAIT for md based bios.
This patch was tested using t/io_uring tool within FIO. A nvme drive
was partitioned into 2 partitions and a simple raid 0 configuration
/dev/md0 was created.
md0 : active raid0 nvme4n1p1[1] nvme4n1p2[0]
937423872 blocks super 1.2 512k chunks
Before patch:
$ ./t/io_uring /dev/md0 -p 0 -a 0 -d 1 -r 100
Running top while the above runs:
$ ps -eL | grep $(pidof io_uring)
38396 38396 pts/2 00:00:00 io_uring
38396 38397 pts/2 00:00:15 io_uring
38396 38398 pts/2 00:00:13 iou-wrk-38397
We can see iou-wrk-38397 io worker thread created which gets created
when io_uring sees that the underlying device (/dev/md0 in this case)
doesn't support nowait.
After patch:
$ ./t/io_uring /dev/md0 -p 0 -a 0 -d 1 -r 100
Running top while the above runs:
$ ps -eL | grep $(pidof io_uring)
38341 38341 pts/2 00:10:22 io_uring
38341 38342 pts/2 00:10:37 io_uring
After running this patch, we don't see any io worker thread
being created which indicated that io_uring saw that the
underlying device does support nowait. This is the exact behaviour
noticed on a dm device which also supports nowait.
For all the other raid personalities except raid0, we would need
to train pieces which involves make_request fn in order for them
to correctly handle REQ_NOWAIT.
Signed-off-by: Vishal Verma <redacted>
I have made some changes and applied the set to md-next. However,
I think we don't yet have enough test coverage. Please continue testing
the code and send fixes on top of it. Based on the test results, we will
see whether we can ship it in the next merge window.
Note, md-next branch doesn't have [1], so we need to cherry-pick it
for testing.
I went through all these changes again and tested many (but not all)
cases. The latest version is available in md-next branch.
Vishal, please run tests on this version and send fixes if anything
is broken.
Thanks,
Song
Thanks Song. This latest version looks good!
And yes, will report out if I notice any issues or anything.