linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/6] virtio_net: don't crash if virtqueue is broken.
@ 2014-01-15  2:36 Rusty Russell
  2014-01-15  2:36 ` [PATCH 2/6] virtio_blk: don't crash, report error " Rusty Russell
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Rusty Russell @ 2014-01-15  2:36 UTC (permalink / raw)
  To: linux-kernel; +Cc: Heinz Graalfs, Rusty Russell

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().

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 drivers/net/virtio_net.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 5d776447d9c3..0949688ae540 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -904,8 +904,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
 	sgs[out_num + in_num++] = &stat;
 
 	BUG_ON(out_num + in_num > ARRAY_SIZE(sgs));
-	BUG_ON(virtqueue_add_sgs(vi->cvq, sgs, out_num, in_num, vi, GFP_ATOMIC)
-	       < 0);
+	virtqueue_add_sgs(vi->cvq, sgs, out_num, in_num, vi, GFP_ATOMIC);
 
 	if (unlikely(!virtqueue_kick(vi->cvq)))
 		return status == VIRTIO_NET_OK;
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/6] virtio_blk: don't crash, report error if virtqueue is broken.
  2014-01-15  2:36 [PATCH 1/6] virtio_net: don't crash if virtqueue is broken Rusty Russell
@ 2014-01-15  2:36 ` Rusty Russell
  2014-01-30  9:09   ` Heinz Graalfs
  2014-01-15  2:36 ` [PATCH 3/6] virtio_balloon: don't crash " Rusty Russell
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Rusty Russell @ 2014-01-15  2:36 UTC (permalink / raw)
  To: linux-kernel; +Cc: Heinz Graalfs, Rusty Russell

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 | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 6a680d4de7f1..704d6c814c17 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)
 	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)
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/6] virtio_balloon: don't crash if virtqueue is broken.
  2014-01-15  2:36 [PATCH 1/6] virtio_net: don't crash if virtqueue is broken Rusty Russell
  2014-01-15  2:36 ` [PATCH 2/6] virtio_blk: don't crash, report error " Rusty Russell
@ 2014-01-15  2:36 ` Rusty Russell
  2014-01-15  2:36 ` [PATCH 4/6] virtio-rng: " Rusty Russell
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Rusty Russell @ 2014-01-15  2:36 UTC (permalink / raw)
  To: linux-kernel; +Cc: Heinz Graalfs, Rusty Russell

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().

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 drivers/virtio/virtio_balloon.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 5c4a95b516cf..fc1fb27dca49 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -108,8 +108,7 @@ static void tell_host(struct virtio_balloon *vb, struct virtqueue *vq)
 	sg_init_one(&sg, vb->pfns, sizeof(vb->pfns[0]) * vb->num_pfns);
 
 	/* We should always be able to add one buffer to an empty queue. */
-	if (virtqueue_add_outbuf(vq, &sg, 1, vb, GFP_KERNEL) < 0)
-		BUG();
+	virtqueue_add_outbuf(vq, &sg, 1, vb, GFP_KERNEL);
 	virtqueue_kick(vq);
 
 	/* When host has read buffer, this completes via balloon_ack */
@@ -258,8 +257,7 @@ static void stats_handle_request(struct virtio_balloon *vb)
 	if (!virtqueue_get_buf(vq, &len))
 		return;
 	sg_init_one(&sg, vb->stats, sizeof(vb->stats));
-	if (virtqueue_add_outbuf(vq, &sg, 1, vb, GFP_KERNEL) < 0)
-		BUG();
+	virtqueue_add_outbuf(vq, &sg, 1, vb, GFP_KERNEL);
 	virtqueue_kick(vq);
 }
 
@@ -338,7 +336,7 @@ static int init_vqs(struct virtio_balloon *vb)
 
 		/*
 		 * Prime this virtqueue with one buffer so the hypervisor can
-		 * use it to signal us later.
+		 * use it to signal us later (it can't be broken yet!).
 		 */
 		sg_init_one(&sg, vb->stats, sizeof vb->stats);
 		if (virtqueue_add_outbuf(vb->stats_vq, &sg, 1, vb, GFP_KERNEL)
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 4/6] virtio-rng: don't crash if virtqueue is broken.
  2014-01-15  2:36 [PATCH 1/6] virtio_net: don't crash if virtqueue is broken Rusty Russell
  2014-01-15  2:36 ` [PATCH 2/6] virtio_blk: don't crash, report error " Rusty Russell
  2014-01-15  2:36 ` [PATCH 3/6] virtio_balloon: don't crash " Rusty Russell
@ 2014-01-15  2:36 ` Rusty Russell
  2014-01-15  2:36 ` [PATCH 5/6] virtio: fail adding buffer on broken queues Rusty Russell
  2014-01-15  2:36 ` [PATCH 6/6] virtio: virtio_break_device() to mark all virtqueues broken Rusty Russell
  4 siblings, 0 replies; 8+ messages in thread
From: Rusty Russell @ 2014-01-15  2:36 UTC (permalink / raw)
  To: linux-kernel; +Cc: Heinz Graalfs, Rusty Russell

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().

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 drivers/char/hw_random/virtio-rng.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
index c12398d1517c..2ce0e225e58c 100644
--- a/drivers/char/hw_random/virtio-rng.c
+++ b/drivers/char/hw_random/virtio-rng.c
@@ -47,8 +47,7 @@ static void register_buffer(u8 *buf, size_t size)
 	sg_init_one(&sg, buf, size);
 
 	/* There should always be room for one buffer. */
-	if (virtqueue_add_inbuf(vq, &sg, 1, buf, GFP_KERNEL) < 0)
-		BUG();
+	virtqueue_add_inbuf(vq, &sg, 1, buf, GFP_KERNEL);
 
 	virtqueue_kick(vq);
 }
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 5/6] virtio: fail adding buffer on broken queues.
  2014-01-15  2:36 [PATCH 1/6] virtio_net: don't crash if virtqueue is broken Rusty Russell
                   ` (2 preceding siblings ...)
  2014-01-15  2:36 ` [PATCH 4/6] virtio-rng: " Rusty Russell
@ 2014-01-15  2:36 ` Rusty Russell
  2014-01-15  2:36 ` [PATCH 6/6] virtio: virtio_break_device() to mark all virtqueues broken Rusty Russell
  4 siblings, 0 replies; 8+ messages in thread
From: Rusty Russell @ 2014-01-15  2:36 UTC (permalink / raw)
  To: linux-kernel; +Cc: Heinz Graalfs, Rusty Russell

Heinz points out that adding buffers to a broken virtqueue (which
should "never happen") still works.  Failing allows drivers to detect
and complain about broken devices.

Now drivers are robust, we can add this extra check.

Reported-by: Heinz Graalfs <graalfs@linux.vnet.ibm.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 drivers/virtio/virtio_ring.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 28b5338fff71..b74033dca384 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -203,6 +203,11 @@ static inline int virtqueue_add(struct virtqueue *_vq,
 
 	BUG_ON(data == NULL);
 
+	if (unlikely(vq->broken)) {
+		END_USE(vq);
+		return -EIO;
+	}
+
 #ifdef DEBUG
 	{
 		ktime_t now = ktime_get();
@@ -309,7 +314,7 @@ add_head:
  * Caller must ensure we don't call this with other virtqueue operations
  * at the same time (except where noted).
  *
- * Returns zero or a negative error (ie. ENOSPC, ENOMEM).
+ * Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).
  */
 int virtqueue_add_sgs(struct virtqueue *_vq,
 		      struct scatterlist *sgs[],
@@ -347,7 +352,7 @@ EXPORT_SYMBOL_GPL(virtqueue_add_sgs);
  * Caller must ensure we don't call this with other virtqueue operations
  * at the same time (except where noted).
  *
- * Returns zero or a negative error (ie. ENOSPC, ENOMEM).
+ * Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).
  */
 int virtqueue_add_outbuf(struct virtqueue *vq,
 			 struct scatterlist sg[], unsigned int num,
@@ -369,7 +374,7 @@ EXPORT_SYMBOL_GPL(virtqueue_add_outbuf);
  * Caller must ensure we don't call this with other virtqueue operations
  * at the same time (except where noted).
  *
- * Returns zero or a negative error (ie. ENOSPC, ENOMEM).
+ * Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).
  */
 int virtqueue_add_inbuf(struct virtqueue *vq,
 			struct scatterlist sg[], unsigned int num,
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 6/6] virtio: virtio_break_device() to mark all virtqueues broken.
  2014-01-15  2:36 [PATCH 1/6] virtio_net: don't crash if virtqueue is broken Rusty Russell
                   ` (3 preceding siblings ...)
  2014-01-15  2:36 ` [PATCH 5/6] virtio: fail adding buffer on broken queues Rusty Russell
@ 2014-01-15  2:36 ` Rusty Russell
  4 siblings, 0 replies; 8+ messages in thread
From: Rusty Russell @ 2014-01-15  2:36 UTC (permalink / raw)
  To: linux-kernel; +Cc: Heinz Graalfs, Rusty Russell

Good for post-apocalyptic scenarios, like S/390 hotplug.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 drivers/virtio/virtio_ring.c | 15 +++++++++++++++
 include/linux/virtio.h       |  2 ++
 2 files changed, 17 insertions(+)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index b74033dca384..a84350019f62 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -864,4 +864,19 @@ bool virtqueue_is_broken(struct virtqueue *_vq)
 }
 EXPORT_SYMBOL_GPL(virtqueue_is_broken);
 
+/*
+ * This should prevent the device from being used, allowing drivers to
+ * recover.  You may need to grab appropriate locks to flush.
+ */
+void virtio_break_device(struct virtio_device *dev)
+{
+	struct virtqueue *_vq;
+
+	list_for_each_entry(_vq, &dev->vqs, list) {
+		struct vring_virtqueue *vq = to_vvq(_vq);
+		vq->broken = true;
+	}
+}
+EXPORT_SYMBOL_GPL(virtio_break_device);
+
 MODULE_LICENSE("GPL");
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index e4abb84199be..b46671e28de2 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -106,6 +106,8 @@ static inline struct virtio_device *dev_to_virtio(struct device *_dev)
 int register_virtio_device(struct virtio_device *dev);
 void unregister_virtio_device(struct virtio_device *dev);
 
+void virtio_break_device(struct virtio_device *dev);
+
 /**
  * virtio_driver - operations for a virtio I/O driver
  * @driver: underlying device driver (populate name and owner).
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/6] virtio_blk: don't crash, report error if virtqueue is broken.
  2014-01-15  2:36 ` [PATCH 2/6] virtio_blk: don't crash, report error " Rusty Russell
@ 2014-01-30  9:09   ` Heinz Graalfs
  2014-01-31  5:00     ` Rusty Russell
  0 siblings, 1 reply; 8+ messages in thread
From: Heinz Graalfs @ 2014-01-30  9:09 UTC (permalink / raw)
  To: Rusty Russell, linux-kernel

On 15/01/14 03:36, Rusty Russell wrote:
> 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 | 10 ++++++++--
>   1 file changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
> index 6a680d4de7f1..704d6c814c17 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)
>   	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);

the kick might fail here after a request was successfully added.

>   		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)
>


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/6] virtio_blk: don't crash, report error if virtqueue is broken.
  2014-01-30  9:09   ` Heinz Graalfs
@ 2014-01-31  5:00     ` Rusty Russell
  0 siblings, 0 replies; 8+ messages in thread
From: Rusty Russell @ 2014-01-31  5:00 UTC (permalink / raw)
  To: Heinz Graalfs, linux-kernel

Heinz Graalfs <graalfs@linux.vnet.ibm.com> writes:
> On 15/01/14 03:36, Rusty Russell wrote:
>> 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 | 10 ++++++++--
>>   1 file changed, 8 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
>> index 6a680d4de7f1..704d6c814c17 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)
>>   	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);
>
> the kick might fail here after a request was successfully added.

It could, but it we're already in the error path, so we can't do
anything about it.

>>   		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)
>>

Cheers,
Rusty.

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2014-02-01  8:06 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-01-15  2:36 [PATCH 1/6] virtio_net: don't crash if virtqueue is broken Rusty Russell
2014-01-15  2:36 ` [PATCH 2/6] virtio_blk: don't crash, report error " Rusty Russell
2014-01-30  9:09   ` Heinz Graalfs
2014-01-31  5:00     ` Rusty Russell
2014-01-15  2:36 ` [PATCH 3/6] virtio_balloon: don't crash " Rusty Russell
2014-01-15  2:36 ` [PATCH 4/6] virtio-rng: " Rusty Russell
2014-01-15  2:36 ` [PATCH 5/6] virtio: fail adding buffer on broken queues Rusty Russell
2014-01-15  2:36 ` [PATCH 6/6] virtio: virtio_break_device() to mark all virtqueues broken Rusty Russell

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).