virtio_blk: don't crash, report error if virtqueue is broken.
authorRusty Russell <rusty@rustcorp.com.au>
Thu, 13 Mar 2014 00:53:39 +0000 (11:23 +1030)
committerRusty Russell <rusty@rustcorp.com.au>
Thu, 13 Mar 2014 00:57:56 +0000 (11:27 +1030)
A bad implementation of virtio might cause us to mark the virtqueue
broken: we'll dev_err() in that case, and the device is useless, but
let's not BUG_ON().

ENOMEM or ENOSPC implies the ring is full, and we should try again
later (-ENOMEM is documented to happen, but doesn't, as we fall
through to ENOSPC).

EIO means it's broken.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
drivers/block/virtio_blk.c

index b1cb3f4c4db45543c653fd86ce28e75b67522430..a2db9ed288f200c3c594f039f1cba59a3dce9baf 100644 (file)
@@ -158,6 +158,7 @@ static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req)
        unsigned long flags;
        unsigned int num;
        const bool last = (req->cmd_flags & REQ_END) != 0;
+       int err;
 
        BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems);
 
@@ -198,11 +199,16 @@ static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req)
        }
 
        spin_lock_irqsave(&vblk->vq_lock, flags);
-       if (__virtblk_add_req(vblk->vq, vbr, vbr->sg, num) < 0) {
+       err = __virtblk_add_req(vblk->vq, vbr, vbr->sg, num);
+       if (err) {
                virtqueue_kick(vblk->vq);
                spin_unlock_irqrestore(&vblk->vq_lock, flags);
                blk_mq_stop_hw_queue(hctx);
-               return BLK_MQ_RQ_QUEUE_BUSY;
+               /* Out of mem doesn't actually happen, since we fall back
+                * to direct descriptors */
+               if (err == -ENOMEM || err == -ENOSPC)
+                       return BLK_MQ_RQ_QUEUE_BUSY;
+               return BLK_MQ_RQ_QUEUE_ERROR;
        }
 
        if (last)