| From abb026a3646e2be78d055389eeff6f8b1c20faec Mon Sep 17 00:00:00 2001 |
| From: Stefano Garzarella <sgarzare@redhat.com> |
| Date: Fri, 1 Feb 2019 12:42:06 +0100 |
| Subject: vsock/virtio: fix kernel panic after device hot-unplug |
| |
| [ Upstream commit 22b5c0b63f32568e130fa2df4ba23efce3eb495b ] |
| |
| virtio_vsock_remove() invokes the vsock_core_exit() also if there |
| are opened sockets for the AF_VSOCK protocol family. In this way |
| the vsock "transport" pointer is set to NULL, triggering the |
| kernel panic at the first socket activity. |
| |
| This patch move the vsock_core_init()/vsock_core_exit() in the |
| virtio_vsock respectively in module_init and module_exit functions, |
| that cannot be invoked until there are open sockets. |
| |
| Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1609699 |
| Reported-by: Yan Fu <yafu@redhat.com> |
| Signed-off-by: Stefano Garzarella <sgarzare@redhat.com> |
| Acked-by: Stefan Hajnoczi <stefanha@redhat.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/vmw_vsock/virtio_transport.c | 26 ++++++++++++++++++-------- |
| 1 file changed, 18 insertions(+), 8 deletions(-) |
| |
| diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c |
| index 5d3cce9e8744..9dae54698737 100644 |
| --- a/net/vmw_vsock/virtio_transport.c |
| +++ b/net/vmw_vsock/virtio_transport.c |
| @@ -75,6 +75,9 @@ static u32 virtio_transport_get_local_cid(void) |
| { |
| struct virtio_vsock *vsock = virtio_vsock_get(); |
| |
| + if (!vsock) |
| + return VMADDR_CID_ANY; |
| + |
| return vsock->guest_cid; |
| } |
| |
| @@ -584,10 +587,6 @@ static int virtio_vsock_probe(struct virtio_device *vdev) |
| |
| virtio_vsock_update_guest_cid(vsock); |
| |
| - ret = vsock_core_init(&virtio_transport.transport); |
| - if (ret < 0) |
| - goto out_vqs; |
| - |
| vsock->rx_buf_nr = 0; |
| vsock->rx_buf_max_nr = 0; |
| atomic_set(&vsock->queued_replies, 0); |
| @@ -618,8 +617,6 @@ static int virtio_vsock_probe(struct virtio_device *vdev) |
| mutex_unlock(&the_virtio_vsock_mutex); |
| return 0; |
| |
| -out_vqs: |
| - vsock->vdev->config->del_vqs(vsock->vdev); |
| out: |
| kfree(vsock); |
| mutex_unlock(&the_virtio_vsock_mutex); |
| @@ -669,7 +666,6 @@ static void virtio_vsock_remove(struct virtio_device *vdev) |
| |
| mutex_lock(&the_virtio_vsock_mutex); |
| the_virtio_vsock = NULL; |
| - vsock_core_exit(); |
| mutex_unlock(&the_virtio_vsock_mutex); |
| |
| vdev->config->del_vqs(vdev); |
| @@ -702,14 +698,28 @@ static int __init virtio_vsock_init(void) |
| virtio_vsock_workqueue = alloc_workqueue("virtio_vsock", 0, 0); |
| if (!virtio_vsock_workqueue) |
| return -ENOMEM; |
| + |
| ret = register_virtio_driver(&virtio_vsock_driver); |
| if (ret) |
| - destroy_workqueue(virtio_vsock_workqueue); |
| + goto out_wq; |
| + |
| + ret = vsock_core_init(&virtio_transport.transport); |
| + if (ret) |
| + goto out_vdr; |
| + |
| + return 0; |
| + |
| +out_vdr: |
| + unregister_virtio_driver(&virtio_vsock_driver); |
| +out_wq: |
| + destroy_workqueue(virtio_vsock_workqueue); |
| return ret; |
| + |
| } |
| |
| static void __exit virtio_vsock_exit(void) |
| { |
| + vsock_core_exit(); |
| unregister_virtio_driver(&virtio_vsock_driver); |
| destroy_workqueue(virtio_vsock_workqueue); |
| } |
| -- |
| 2.19.1 |
| |