md: separate request handling
With commit cc27b0c78c
, pers->make_request could bail out without handling
the bio. If that happens, we should retry. The commit fixes md_make_request
but not other call sites. Separate the request handling part, so other call
sites can use it.
Reported-by: Nate Dailey <nate.dailey@stratus.com>
Fix: cc27b0c78c79(md: fix deadlock between mddev_suspend() and md_write_start())
Cc: stable@vger.kernel.org
Reviewed-by: NeilBrown <neilb@suse.com>
Signed-off-by: Shaohua Li <shli@fb.com>
This commit is contained in:
parent
4a704d6db0
commit
393debc23c
|
@ -266,6 +266,37 @@ static DEFINE_SPINLOCK(all_mddevs_lock);
|
|||
* call has finished, the bio has been linked into some internal structure
|
||||
* and so is visible to ->quiesce(), so we don't need the refcount any more.
|
||||
*/
|
||||
void md_handle_request(struct mddev *mddev, struct bio *bio)
|
||||
{
|
||||
check_suspended:
|
||||
rcu_read_lock();
|
||||
if (mddev->suspended) {
|
||||
DEFINE_WAIT(__wait);
|
||||
for (;;) {
|
||||
prepare_to_wait(&mddev->sb_wait, &__wait,
|
||||
TASK_UNINTERRUPTIBLE);
|
||||
if (!mddev->suspended)
|
||||
break;
|
||||
rcu_read_unlock();
|
||||
schedule();
|
||||
rcu_read_lock();
|
||||
}
|
||||
finish_wait(&mddev->sb_wait, &__wait);
|
||||
}
|
||||
atomic_inc(&mddev->active_io);
|
||||
rcu_read_unlock();
|
||||
|
||||
if (!mddev->pers->make_request(mddev, bio)) {
|
||||
atomic_dec(&mddev->active_io);
|
||||
wake_up(&mddev->sb_wait);
|
||||
goto check_suspended;
|
||||
}
|
||||
|
||||
if (atomic_dec_and_test(&mddev->active_io) && mddev->suspended)
|
||||
wake_up(&mddev->sb_wait);
|
||||
}
|
||||
EXPORT_SYMBOL(md_handle_request);
|
||||
|
||||
static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio)
|
||||
{
|
||||
const int rw = bio_data_dir(bio);
|
||||
|
@ -285,23 +316,6 @@ static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio)
|
|||
bio_endio(bio);
|
||||
return BLK_QC_T_NONE;
|
||||
}
|
||||
check_suspended:
|
||||
rcu_read_lock();
|
||||
if (mddev->suspended) {
|
||||
DEFINE_WAIT(__wait);
|
||||
for (;;) {
|
||||
prepare_to_wait(&mddev->sb_wait, &__wait,
|
||||
TASK_UNINTERRUPTIBLE);
|
||||
if (!mddev->suspended)
|
||||
break;
|
||||
rcu_read_unlock();
|
||||
schedule();
|
||||
rcu_read_lock();
|
||||
}
|
||||
finish_wait(&mddev->sb_wait, &__wait);
|
||||
}
|
||||
atomic_inc(&mddev->active_io);
|
||||
rcu_read_unlock();
|
||||
|
||||
/*
|
||||
* save the sectors now since our bio can
|
||||
|
@ -310,20 +324,14 @@ check_suspended:
|
|||
sectors = bio_sectors(bio);
|
||||
/* bio could be mergeable after passing to underlayer */
|
||||
bio->bi_opf &= ~REQ_NOMERGE;
|
||||
if (!mddev->pers->make_request(mddev, bio)) {
|
||||
atomic_dec(&mddev->active_io);
|
||||
wake_up(&mddev->sb_wait);
|
||||
goto check_suspended;
|
||||
}
|
||||
|
||||
md_handle_request(mddev, bio);
|
||||
|
||||
cpu = part_stat_lock();
|
||||
part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]);
|
||||
part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw], sectors);
|
||||
part_stat_unlock();
|
||||
|
||||
if (atomic_dec_and_test(&mddev->active_io) && mddev->suspended)
|
||||
wake_up(&mddev->sb_wait);
|
||||
|
||||
return BLK_QC_T_NONE;
|
||||
}
|
||||
|
||||
|
|
|
@ -692,6 +692,7 @@ extern void md_stop_writes(struct mddev *mddev);
|
|||
extern int md_rdev_init(struct md_rdev *rdev);
|
||||
extern void md_rdev_clear(struct md_rdev *rdev);
|
||||
|
||||
extern void md_handle_request(struct mddev *mddev, struct bio *bio);
|
||||
extern void mddev_suspend(struct mddev *mddev);
|
||||
extern void mddev_resume(struct mddev *mddev);
|
||||
extern struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs,
|
||||
|
|
Loading…
Reference in New Issue