Skip to content

Commit 5aa6083

Browse files
vwaxgregkh
authored andcommitted
mic: vop: Fix broken virtqueues
VOP is broken in mainline since commit 1ce9e60 ("virtio_ring: introduce packed ring support"); attempting to use the virtqueues leads to various kernel crashes. I'm testing it with my not-yet-merged loopback patches, but even the in-tree MIC hardware cannot work. The problem is not in the referenced commit per se, but is due to the following hack in vop_find_vq() which depends on the layout of private structures in other source files, which that commit happened to change: /* * To reassign the used ring here we are directly accessing * struct vring_virtqueue which is a private data structure * in virtio_ring.c. At the minimum, a BUILD_BUG_ON() in * vring_new_virtqueue() would ensure that * (&vq->vring == (struct vring *) (&vq->vq + 1)); */ vr = (struct vring *)(vq + 1); vr->used = used; Fix vop by using __vring_new_virtqueue() to create the needed vring layout from the start, instead of attempting to patch in the used ring later. __vring_new_virtqueue() was added way back in commit 2a2d138 ("virtio: Add improved queue allocation API") in order to address mic's usecase, according to the commit message. Fixes: 1ce9e60 ("virtio_ring: introduce packed ring support") Signed-off-by: Vincent Whitchurch <vincent.whitchurch@axis.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent cee4c4d commit 5aa6083

File tree

1 file changed

+34
-26
lines changed

1 file changed

+34
-26
lines changed

drivers/misc/mic/vop/vop_main.c

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,26 @@ static void vop_del_vqs(struct virtio_device *dev)
283283
vop_del_vq(vq, idx++);
284284
}
285285

286+
static struct virtqueue *vop_new_virtqueue(unsigned int index,
287+
unsigned int num,
288+
struct virtio_device *vdev,
289+
bool context,
290+
void *pages,
291+
bool (*notify)(struct virtqueue *vq),
292+
void (*callback)(struct virtqueue *vq),
293+
const char *name,
294+
void *used)
295+
{
296+
bool weak_barriers = false;
297+
struct vring vring;
298+
299+
vring_init(&vring, num, pages, MIC_VIRTIO_RING_ALIGN);
300+
vring.used = used;
301+
302+
return __vring_new_virtqueue(index, vring, vdev, weak_barriers, context,
303+
notify, callback, name);
304+
}
305+
286306
/*
287307
* This routine will assign vring's allocated in host/io memory. Code in
288308
* virtio_ring.c however continues to access this io memory as if it were local
@@ -302,7 +322,6 @@ static struct virtqueue *vop_find_vq(struct virtio_device *dev,
302322
struct _mic_vring_info __iomem *info;
303323
void *used;
304324
int vr_size, _vr_size, err, magic;
305-
struct vring *vr;
306325
u8 type = ioread8(&vdev->desc->type);
307326

308327
if (index >= ioread8(&vdev->desc->num_vq))
@@ -322,17 +341,7 @@ static struct virtqueue *vop_find_vq(struct virtio_device *dev,
322341
return ERR_PTR(-ENOMEM);
323342
vdev->vr[index] = va;
324343
memset_io(va, 0x0, _vr_size);
325-
vq = vring_new_virtqueue(
326-
index,
327-
le16_to_cpu(config.num), MIC_VIRTIO_RING_ALIGN,
328-
dev,
329-
false,
330-
ctx,
331-
(void __force *)va, vop_notify, callback, name);
332-
if (!vq) {
333-
err = -ENOMEM;
334-
goto unmap;
335-
}
344+
336345
info = va + _vr_size;
337346
magic = ioread32(&info->magic);
338347

@@ -341,7 +350,6 @@ static struct virtqueue *vop_find_vq(struct virtio_device *dev,
341350
goto unmap;
342351
}
343352

344-
/* Allocate and reassign used ring now */
345353
vdev->used_size[index] = PAGE_ALIGN(sizeof(__u16) * 3 +
346354
sizeof(struct vring_used_elem) *
347355
le16_to_cpu(config.num));
@@ -351,35 +359,35 @@ static struct virtqueue *vop_find_vq(struct virtio_device *dev,
351359
err = -ENOMEM;
352360
dev_err(_vop_dev(vdev), "%s %d err %d\n",
353361
__func__, __LINE__, err);
354-
goto del_vq;
362+
goto unmap;
363+
}
364+
365+
vq = vop_new_virtqueue(index, le16_to_cpu(config.num), dev, ctx,
366+
(void __force *)va, vop_notify, callback,
367+
name, used);
368+
if (!vq) {
369+
err = -ENOMEM;
370+
goto free_used;
355371
}
372+
356373
vdev->used[index] = dma_map_single(&vpdev->dev, used,
357374
vdev->used_size[index],
358375
DMA_BIDIRECTIONAL);
359376
if (dma_mapping_error(&vpdev->dev, vdev->used[index])) {
360377
err = -ENOMEM;
361378
dev_err(_vop_dev(vdev), "%s %d err %d\n",
362379
__func__, __LINE__, err);
363-
goto free_used;
380+
goto del_vq;
364381
}
365382
writeq(vdev->used[index], &vqconfig->used_address);
366-
/*
367-
* To reassign the used ring here we are directly accessing
368-
* struct vring_virtqueue which is a private data structure
369-
* in virtio_ring.c. At the minimum, a BUILD_BUG_ON() in
370-
* vring_new_virtqueue() would ensure that
371-
* (&vq->vring == (struct vring *) (&vq->vq + 1));
372-
*/
373-
vr = (struct vring *)(vq + 1);
374-
vr->used = used;
375383

376384
vq->priv = vdev;
377385
return vq;
386+
del_vq:
387+
vring_del_virtqueue(vq);
378388
free_used:
379389
free_pages((unsigned long)used,
380390
get_order(vdev->used_size[index]));
381-
del_vq:
382-
vring_del_virtqueue(vq);
383391
unmap:
384392
vpdev->hw_ops->iounmap(vpdev, vdev->vr[index]);
385393
return ERR_PTR(err);

0 commit comments

Comments
 (0)