diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 73671d79da..f71bab7847 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 52cbe77c0a..c77c212cff 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 {