dm: do not use waitqueue for request-based DM
Given request-based DM now uses blk-mq's blk_mq_queue_inflight() to
determine if outstanding IO has completed (and DM has no control over
the blk-mq state machine used to track outstanding IO) it is unsafe to
wakeup waiter (dm_wait_for_completion) before blk-mq has cleared a
request's state bits (e.g. MQ_RQ_IN_FLIGHT or MQ_RQ_COMPLETE). As
such dm_wait_for_completion() could be left to wait indefinitely if no
other requests complete.
Fix this by eliminating request-based DM's use of waitqueue to wait
for blk-mq requests to complete in dm_wait_for_completion.
Signed-off-by: Ming Lei <ming.lei@redhat.com>
Depends-on: 3c94d83cb3
("blk-mq: change blk_mq_queue_busy() to blk_mq_queue_inflight()")
Cc: stable@vger.kernel.org
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
This commit is contained in:
parent
dcb7fd82c7
commit
85067747cf
@ -146,10 +146,6 @@ static void rq_end_stats(struct mapped_device *md, struct request *orig)
|
|||||||
*/
|
*/
|
||||||
static void rq_completed(struct mapped_device *md)
|
static void rq_completed(struct mapped_device *md)
|
||||||
{
|
{
|
||||||
/* nudge anyone waiting on suspend queue */
|
|
||||||
if (unlikely(wq_has_sleeper(&md->wait)))
|
|
||||||
wake_up(&md->wait);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* dm_put() must be at the end of this function. See the comment above
|
* dm_put() must be at the end of this function. See the comment above
|
||||||
*/
|
*/
|
||||||
|
@ -654,28 +654,6 @@ static void free_tio(struct dm_target_io *tio)
|
|||||||
bio_put(&tio->clone);
|
bio_put(&tio->clone);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool md_in_flight_bios(struct mapped_device *md)
|
|
||||||
{
|
|
||||||
int cpu;
|
|
||||||
struct hd_struct *part = &dm_disk(md)->part0;
|
|
||||||
long sum = 0;
|
|
||||||
|
|
||||||
for_each_possible_cpu(cpu) {
|
|
||||||
sum += part_stat_local_read_cpu(part, in_flight[0], cpu);
|
|
||||||
sum += part_stat_local_read_cpu(part, in_flight[1], cpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sum != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool md_in_flight(struct mapped_device *md)
|
|
||||||
{
|
|
||||||
if (queue_is_mq(md->queue))
|
|
||||||
return blk_mq_queue_inflight(md->queue);
|
|
||||||
else
|
|
||||||
return md_in_flight_bios(md);
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 dm_start_time_ns_from_clone(struct bio *bio)
|
u64 dm_start_time_ns_from_clone(struct bio *bio)
|
||||||
{
|
{
|
||||||
struct dm_target_io *tio = container_of(bio, struct dm_target_io, clone);
|
struct dm_target_io *tio = container_of(bio, struct dm_target_io, clone);
|
||||||
@ -2470,15 +2448,29 @@ void dm_put(struct mapped_device *md)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(dm_put);
|
EXPORT_SYMBOL_GPL(dm_put);
|
||||||
|
|
||||||
static int dm_wait_for_completion(struct mapped_device *md, long task_state)
|
static bool md_in_flight_bios(struct mapped_device *md)
|
||||||
|
{
|
||||||
|
int cpu;
|
||||||
|
struct hd_struct *part = &dm_disk(md)->part0;
|
||||||
|
long sum = 0;
|
||||||
|
|
||||||
|
for_each_possible_cpu(cpu) {
|
||||||
|
sum += part_stat_local_read_cpu(part, in_flight[0], cpu);
|
||||||
|
sum += part_stat_local_read_cpu(part, in_flight[1], cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dm_wait_for_bios_completion(struct mapped_device *md, long task_state)
|
||||||
{
|
{
|
||||||
int r = 0;
|
int r = 0;
|
||||||
DEFINE_WAIT(wait);
|
DEFINE_WAIT(wait);
|
||||||
|
|
||||||
while (1) {
|
while (true) {
|
||||||
prepare_to_wait(&md->wait, &wait, task_state);
|
prepare_to_wait(&md->wait, &wait, task_state);
|
||||||
|
|
||||||
if (!md_in_flight(md))
|
if (!md_in_flight_bios(md))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (signal_pending_state(task_state, current)) {
|
if (signal_pending_state(task_state, current)) {
|
||||||
@ -2493,6 +2485,28 @@ static int dm_wait_for_completion(struct mapped_device *md, long task_state)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dm_wait_for_completion(struct mapped_device *md, long task_state)
|
||||||
|
{
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
if (!queue_is_mq(md->queue))
|
||||||
|
return dm_wait_for_bios_completion(md, task_state);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (!blk_mq_queue_inflight(md->queue))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (signal_pending_state(task_state, current)) {
|
||||||
|
r = -EINTR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
msleep(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Process the deferred bios
|
* Process the deferred bios
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user