Commit cf8ecc5a authored by Arianna Avanzini's avatar Arianna Avanzini Committed by Jens Axboe

null_blk: guarantee device restart in all irq modes

In single-queue (block layer) mode,the function null_rq_prep_fn stops
the device if alloc_cmd fails. Then, once stopped, the device must be
restarted on the next command completion, so that the request(s) for
which alloc_cmd failed can be requeued. Otherwise the device hangs.

Unfortunately, device restart is currently performed only for delayed
completions, i.e., in irqmode==2. This fact causes hangs, for the
above reasons, with the other irqmodes in combination with single-queue
block layer.

This commits addresses this issue by making sure that, if stopped, the
device is properly restarted for all irqmodes on completions.
Signed-off-by: default avatarPaolo Valente <paolo.valente@unimore.it>
Signed-off-by: default avatarArianna AVanzini <avanzini@google.com>
Signed-off-by: default avatarJens Axboe <axboe@fb.com>
parent 3c395a96
...@@ -217,6 +217,8 @@ static struct nullb_cmd *alloc_cmd(struct nullb_queue *nq, int can_wait) ...@@ -217,6 +217,8 @@ static struct nullb_cmd *alloc_cmd(struct nullb_queue *nq, int can_wait)
static void end_cmd(struct nullb_cmd *cmd) static void end_cmd(struct nullb_cmd *cmd)
{ {
struct request_queue *q = NULL;
switch (queue_mode) { switch (queue_mode) {
case NULL_Q_MQ: case NULL_Q_MQ:
blk_mq_end_request(cmd->rq, 0); blk_mq_end_request(cmd->rq, 0);
...@@ -227,27 +229,28 @@ static void end_cmd(struct nullb_cmd *cmd) ...@@ -227,27 +229,28 @@ static void end_cmd(struct nullb_cmd *cmd)
break; break;
case NULL_Q_BIO: case NULL_Q_BIO:
bio_endio(cmd->bio); bio_endio(cmd->bio);
break; goto free_cmd;
} }
free_cmd(cmd);
}
static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer)
{
struct nullb_cmd *cmd = container_of(timer, struct nullb_cmd, timer);
struct request_queue *q = NULL;
if (cmd->rq) if (cmd->rq)
q = cmd->rq->q; q = cmd->rq->q;
/* Restart queue if needed, as we are freeing a tag */
if (q && !q->mq_ops && blk_queue_stopped(q)) { if (q && !q->mq_ops && blk_queue_stopped(q)) {
spin_lock(q->queue_lock); unsigned long flags;
spin_lock_irqsave(q->queue_lock, flags);
if (blk_queue_stopped(q)) if (blk_queue_stopped(q))
blk_start_queue(q); blk_start_queue(q);
spin_unlock(q->queue_lock); spin_unlock_irqrestore(q->queue_lock, flags);
} }
end_cmd(cmd); free_cmd:
free_cmd(cmd);
}
static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer)
{
end_cmd(container_of(timer, struct nullb_cmd, timer));
return HRTIMER_NORESTART; return HRTIMER_NORESTART;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment