diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2014-03-12 20:53:39 -0400 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2014-03-12 20:57:56 -0400 |
commit | 5261b85e586afe6ebe54e16e0a8acc32fc6d4902 (patch) | |
tree | 10ec38ad40d5e80e527b397c9f086d89d7175175 /drivers/block/virtio_blk.c | |
parent | a7c58146cf9a782113629021ba5420582fef265e (diff) |
virtio_blk: don't crash, report error if virtqueue is broken.
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>
Diffstat (limited to 'drivers/block/virtio_blk.c')
-rw-r--r-- | drivers/block/virtio_blk.c | 10 |
1 files changed, 8 insertions, 2 deletions
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index b1cb3f4c4db4..a2db9ed288f2 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c | |||
@@ -158,6 +158,7 @@ static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req) | |||
158 | unsigned long flags; | 158 | unsigned long flags; |
159 | unsigned int num; | 159 | unsigned int num; |
160 | const bool last = (req->cmd_flags & REQ_END) != 0; | 160 | const bool last = (req->cmd_flags & REQ_END) != 0; |
161 | int err; | ||
161 | 162 | ||
162 | BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems); | 163 | BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems); |
163 | 164 | ||
@@ -198,11 +199,16 @@ static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req) | |||
198 | } | 199 | } |
199 | 200 | ||
200 | spin_lock_irqsave(&vblk->vq_lock, flags); | 201 | spin_lock_irqsave(&vblk->vq_lock, flags); |
201 | if (__virtblk_add_req(vblk->vq, vbr, vbr->sg, num) < 0) { | 202 | err = __virtblk_add_req(vblk->vq, vbr, vbr->sg, num); |
203 | if (err) { | ||
202 | virtqueue_kick(vblk->vq); | 204 | virtqueue_kick(vblk->vq); |
203 | spin_unlock_irqrestore(&vblk->vq_lock, flags); | 205 | spin_unlock_irqrestore(&vblk->vq_lock, flags); |
204 | blk_mq_stop_hw_queue(hctx); | 206 | blk_mq_stop_hw_queue(hctx); |
205 | return BLK_MQ_RQ_QUEUE_BUSY; | 207 | /* Out of mem doesn't actually happen, since we fall back |
208 | * to direct descriptors */ | ||
209 | if (err == -ENOMEM || err == -ENOSPC) | ||
210 | return BLK_MQ_RQ_QUEUE_BUSY; | ||
211 | return BLK_MQ_RQ_QUEUE_ERROR; | ||
206 | } | 212 | } |
207 | 213 | ||
208 | if (last) | 214 | if (last) |