aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/virtio/virtio_ring.c12
-rw-r--r--include/virtio_ring.h2
2 files changed, 14 insertions, 0 deletions
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 73671d79daf..f71bab78477 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -82,6 +82,9 @@ int virtqueue_add(struct virtqueue *vq, struct virtio_sg *sgs[],
/* Update free pointer */
vq->free_head = i;
+ /* Mark the descriptor as the head of a chain. */
+ vq->vring_desc_shadow[head].chain_head = true;
+
/*
* Put entry in available array (but don't update avail->idx
* until they do sync).
@@ -144,6 +147,9 @@ static void detach_buf(struct virtqueue *vq, unsigned int head)
{
unsigned int i;
+ /* Unmark the descriptor as the head of a chain. */
+ vq->vring_desc_shadow[head].chain_head = false;
+
/* Put back on free list: unmap first-level descriptors and find end */
i = head;
@@ -194,6 +200,12 @@ void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len)
return NULL;
}
+ if (unlikely(!vq->vring_desc_shadow[i].chain_head)) {
+ printf("(%s.%d): id %u is not a head\n",
+ vq->vdev->name, vq->index, i);
+ return NULL;
+ }
+
detach_buf(vq, i);
vq->last_used_idx++;
/*
diff --git a/include/virtio_ring.h b/include/virtio_ring.h
index 52cbe77c0a2..c77c212cffd 100644
--- a/include/virtio_ring.h
+++ b/include/virtio_ring.h
@@ -61,6 +61,8 @@ struct vring_desc_shadow {
u32 len;
u16 flags;
u16 next;
+ /* Metadata about the descriptor. */
+ bool chain_head;
};
struct vring_avail {