The remove path contains a hack which depends on internal structures in
other source files, similar to the one which was recently removed from
the registration path.  Since commit 1ce9e6055f ("virtio_ring:
introduce packed ring support"), this leads to a crash when vop devices
are removed.

The structure in question is only examined to get the virtual address of
the allocated used page.  Store that pointer locally instead to fix the
crash.

Fixes: 1ce9e6055f ("virtio_ring: introduce packed ring support")
Signed-off-by: Vincent Whitchurch <vincent.whitchurch@axis.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Vincent Whitchurch 2019-02-01 09:45:09 +01:00 коммит произвёл Greg Kroah-Hartman
Родитель 70ed7148da
Коммит 4bf13fdbc3
1 изменённых файлов: 6 добавлений и 3 удалений

Просмотреть файл

@ -47,7 +47,8 @@
* @dc: Virtio device control * @dc: Virtio device control
* @vpdev: VOP device which is the parent for this virtio device * @vpdev: VOP device which is the parent for this virtio device
* @vr: Buffer for accessing the VRING * @vr: Buffer for accessing the VRING
* @used: Buffer for used * @used_virt: Virtual address of used ring
* @used: DMA address of used ring
* @used_size: Size of the used buffer * @used_size: Size of the used buffer
* @reset_done: Track whether VOP reset is complete * @reset_done: Track whether VOP reset is complete
* @virtio_cookie: Cookie returned upon requesting a interrupt * @virtio_cookie: Cookie returned upon requesting a interrupt
@ -61,6 +62,7 @@ struct _vop_vdev {
struct mic_device_ctrl __iomem *dc; struct mic_device_ctrl __iomem *dc;
struct vop_device *vpdev; struct vop_device *vpdev;
void __iomem *vr[VOP_MAX_VRINGS]; void __iomem *vr[VOP_MAX_VRINGS];
void *used_virt[VOP_MAX_VRINGS];
dma_addr_t used[VOP_MAX_VRINGS]; dma_addr_t used[VOP_MAX_VRINGS];
int used_size[VOP_MAX_VRINGS]; int used_size[VOP_MAX_VRINGS];
struct completion reset_done; struct completion reset_done;
@ -260,12 +262,12 @@ static bool vop_notify(struct virtqueue *vq)
static void vop_del_vq(struct virtqueue *vq, int n) static void vop_del_vq(struct virtqueue *vq, int n)
{ {
struct _vop_vdev *vdev = to_vopvdev(vq->vdev); struct _vop_vdev *vdev = to_vopvdev(vq->vdev);
struct vring *vr = (struct vring *)(vq + 1);
struct vop_device *vpdev = vdev->vpdev; struct vop_device *vpdev = vdev->vpdev;
dma_unmap_single(&vpdev->dev, vdev->used[n], dma_unmap_single(&vpdev->dev, vdev->used[n],
vdev->used_size[n], DMA_BIDIRECTIONAL); vdev->used_size[n], DMA_BIDIRECTIONAL);
free_pages((unsigned long)vr->used, get_order(vdev->used_size[n])); free_pages((unsigned long)vdev->used_virt[n],
get_order(vdev->used_size[n]));
vring_del_virtqueue(vq); vring_del_virtqueue(vq);
vpdev->hw_ops->iounmap(vpdev, vdev->vr[n]); vpdev->hw_ops->iounmap(vpdev, vdev->vr[n]);
vdev->vr[n] = NULL; vdev->vr[n] = NULL;
@ -355,6 +357,7 @@ static struct virtqueue *vop_find_vq(struct virtio_device *dev,
le16_to_cpu(config.num)); le16_to_cpu(config.num));
used = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, used = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
get_order(vdev->used_size[index])); get_order(vdev->used_size[index]));
vdev->used_virt[index] = used;
if (!used) { if (!used) {
err = -ENOMEM; err = -ENOMEM;
dev_err(_vop_dev(vdev), "%s %d err %d\n", dev_err(_vop_dev(vdev), "%s %d err %d\n",