Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mic: vop: Fix crash on remove

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 1ce9e6055fa0 ("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: 1ce9e6055fa0 ("virtio_ring: introduce packed ring support")
Signed-off-by: Vincent Whitchurch <vincent.whitchurch@axis.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Vincent Whitchurch and committed by
Greg Kroah-Hartman
4bf13fdb 70ed7148

+6 -3
+6 -3
drivers/misc/mic/vop/vop_main.c
··· 47 47 * @dc: Virtio device control 48 48 * @vpdev: VOP device which is the parent for this virtio device 49 49 * @vr: Buffer for accessing the VRING 50 - * @used: Buffer for used 50 + * @used_virt: Virtual address of used ring 51 + * @used: DMA address of used ring 51 52 * @used_size: Size of the used buffer 52 53 * @reset_done: Track whether VOP reset is complete 53 54 * @virtio_cookie: Cookie returned upon requesting a interrupt ··· 62 61 struct mic_device_ctrl __iomem *dc; 63 62 struct vop_device *vpdev; 64 63 void __iomem *vr[VOP_MAX_VRINGS]; 64 + void *used_virt[VOP_MAX_VRINGS]; 65 65 dma_addr_t used[VOP_MAX_VRINGS]; 66 66 int used_size[VOP_MAX_VRINGS]; 67 67 struct completion reset_done; ··· 262 260 static void vop_del_vq(struct virtqueue *vq, int n) 263 261 { 264 262 struct _vop_vdev *vdev = to_vopvdev(vq->vdev); 265 - struct vring *vr = (struct vring *)(vq + 1); 266 263 struct vop_device *vpdev = vdev->vpdev; 267 264 268 265 dma_unmap_single(&vpdev->dev, vdev->used[n], 269 266 vdev->used_size[n], DMA_BIDIRECTIONAL); 270 - free_pages((unsigned long)vr->used, get_order(vdev->used_size[n])); 267 + free_pages((unsigned long)vdev->used_virt[n], 268 + get_order(vdev->used_size[n])); 271 269 vring_del_virtqueue(vq); 272 270 vpdev->hw_ops->iounmap(vpdev, vdev->vr[n]); 273 271 vdev->vr[n] = NULL; ··· 357 355 le16_to_cpu(config.num)); 358 356 used = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 359 357 get_order(vdev->used_size[index])); 358 + vdev->used_virt[index] = used; 360 359 if (!used) { 361 360 err = -ENOMEM; 362 361 dev_err(_vop_dev(vdev), "%s %d err %d\n",