[PATCH 1/1] null_blk: fix handling of BLKPREP_DEFER case

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



When we fail to allocate new cmd in null_rq_prep_fn we return BLKPREP_DEFER
which is not handled properly. In single-queue mode of null_blk the following
command hangs forever in io_schedule():
$ dd if=/dev/nullb0 of=/dev/null bs=8M count=5000 iflag=direct

The reason is that when 64 commands have been allocated, the 65th command
allocation will fail due to missing free tag. The request, however, will be
kept in the queue which will never be started again (unless you run another
command that does I/O to /dev/nullb0).

This small patch tries to solve the issue by stopping the queue when we
detect that all tags were exhausted and starting it again when we free the tag.

I've verified that the command mentioned above doesn't hang anymore and also
made sure that null_blk with my change survives fio-based stress tests.

Signed-off-by: Dmitry V. Krivenok <krivenok.dmitry@xxxxxxxxx>
---
 drivers/block/null_blk.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c
index 65cd61a..4ac684b 100644
--- a/drivers/block/null_blk.c
+++ b/drivers/block/null_blk.c
@@ -25,6 +25,7 @@ struct nullb_queue {
     unsigned int queue_depth;

     struct nullb_cmd *cmds;
+    bool no_cmds;
 };

 struct nullb {
@@ -171,6 +172,13 @@ static unsigned int get_tag(struct nullb_queue *nq)
 static void free_cmd(struct nullb_cmd *cmd)
 {
     put_tag(cmd->nq, cmd->tag);
+    if(cmd->nq->no_cmds) {
+        unsigned long flags;
+        cmd->nq->no_cmds = false;
+        spin_lock_irqsave(cmd->rq->q->queue_lock, flags);
+        blk_start_queue(cmd->rq->q);
+        spin_unlock_irqrestore(cmd->rq->q->queue_lock, flags);
+    }
 }

 static struct nullb_cmd *__alloc_cmd(struct nullb_queue *nq)
@@ -195,6 +203,9 @@ static struct nullb_cmd *alloc_cmd(struct
nullb_queue *nq, int can_wait)
     DEFINE_WAIT(wait);

     cmd = __alloc_cmd(nq);
+    if (!cmd && !can_wait) {
+        nq->no_cmds = true;
+    }
     if (cmd || !can_wait)
         return cmd;

@@ -341,6 +352,7 @@ static int null_rq_prep_fn(struct request_queue
*q, struct request *req)
 static void null_request_fn(struct request_queue *q)
 {
     struct request *rq;
+    struct nullb_queue *nq = nullb_to_queue(q->queuedata);

     while ((rq = blk_fetch_request(q)) != NULL) {
         struct nullb_cmd *cmd = rq->special;
@@ -349,6 +361,9 @@ static void null_request_fn(struct request_queue *q)
         null_handle_cmd(cmd);
         spin_lock_irq(q->queue_lock);
     }
+    if(nq->no_cmds) {
+        blk_stop_queue(q);
+    }
 }

 static int null_queue_rq(struct blk_mq_hw_ctx *hctx,
@@ -430,6 +445,7 @@ static int setup_commands(struct nullb_queue *nq)
     if (!nq->cmds)
         return -ENOMEM;

+    nq->no_cmds = false;
     tag_size = ALIGN(nq->queue_depth, BITS_PER_LONG) / BITS_PER_LONG;
     nq->tag_map = kzalloc(tag_size * sizeof(unsigned long), GFP_KERNEL);
     if (!nq->tag_map) {
-- 
2.3.5
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux