mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-04-27 11:31:05 +00:00
kernel: Fix vsock packets drop when the vsock driver starts
The virtio vsock driver has a small window during initialization where it can silently drop replies to connection requests. Because no reply is sent, kata waits for 10 seconds and in the end it generates a connection timeout error in HybridVSockDialer. Fixes: #8291 Signed-off-by: Alexandru Matei <alexandru.matei@uipath.com>
This commit is contained in:
parent
dffc6f611c
commit
bfd1ce30e1
@ -1 +1 @@
|
||||
116
|
||||
117
|
||||
|
@ -0,0 +1,73 @@
|
||||
From d03fb89b5e6dcaf399480708ee2d5a32dca70e7a Mon Sep 17 00:00:00 2001
|
||||
From: "Longpeng(Mike)" <longpeng2@huawei.com>
|
||||
Date: Thu, 12 Aug 2021 13:30:56 +0800
|
||||
Subject: [PATCH 1/7] vsock/virtio: avoid potential deadlock when vsock device
|
||||
remove
|
||||
|
||||
There's a potential deadlock case when remove the vsock device or
|
||||
process the RESET event:
|
||||
|
||||
vsock_for_each_connected_socket:
|
||||
spin_lock_bh(&vsock_table_lock) ----------- (1)
|
||||
...
|
||||
virtio_vsock_reset_sock:
|
||||
lock_sock(sk) --------------------- (2)
|
||||
...
|
||||
spin_unlock_bh(&vsock_table_lock)
|
||||
|
||||
lock_sock() may do initiative schedule when the 'sk' is owned by
|
||||
other thread at the same time, we would receivce a warning message
|
||||
that "scheduling while atomic".
|
||||
|
||||
Even worse, if the next task (selected by the scheduler) try to
|
||||
release a 'sk', it need to request vsock_table_lock and the deadlock
|
||||
occur, cause the system into softlockup state.
|
||||
Call trace:
|
||||
queued_spin_lock_slowpath
|
||||
vsock_remove_bound
|
||||
vsock_remove_sock
|
||||
virtio_transport_release
|
||||
__vsock_release
|
||||
vsock_release
|
||||
__sock_release
|
||||
sock_close
|
||||
__fput
|
||||
____fput
|
||||
|
||||
So we should not require sk_lock in this case, just like the behavior
|
||||
in vhost_vsock or vmci.
|
||||
|
||||
Fixes: 0ea9e1d3a9e3 ("VSOCK: Introduce virtio_transport.ko")
|
||||
Cc: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Signed-off-by: Longpeng(Mike) <longpeng2@huawei.com>
|
||||
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
|
||||
Link: https://lore.kernel.org/r/20210812053056.1699-1-longpeng2@huawei.com
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
net/vmw_vsock/virtio_transport.c | 7 +++++--
|
||||
1 file changed, 5 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
|
||||
index 2700a63ab095..3a056f8affd1 100644
|
||||
--- a/net/vmw_vsock/virtio_transport.c
|
||||
+++ b/net/vmw_vsock/virtio_transport.c
|
||||
@@ -356,11 +356,14 @@ static void virtio_vsock_event_fill(struct virtio_vsock *vsock)
|
||||
|
||||
static void virtio_vsock_reset_sock(struct sock *sk)
|
||||
{
|
||||
- lock_sock(sk);
|
||||
+ /* vmci_transport.c doesn't take sk_lock here either. At least we're
|
||||
+ * under vsock_table_lock so the sock cannot disappear while we're
|
||||
+ * executing.
|
||||
+ */
|
||||
+
|
||||
sk->sk_state = TCP_CLOSE;
|
||||
sk->sk_err = ECONNRESET;
|
||||
sk->sk_error_report(sk);
|
||||
- release_sock(sk);
|
||||
}
|
||||
|
||||
static void virtio_vsock_update_guest_cid(struct virtio_vsock *vsock)
|
||||
--
|
||||
2.34.1
|
||||
|
@ -0,0 +1,151 @@
|
||||
From a44b98fc926521d6cf642ed945e1d0781973d0d8 Mon Sep 17 00:00:00 2001
|
||||
From: Jiyong Park <jiyong@google.com>
|
||||
Date: Fri, 11 Mar 2022 11:00:16 +0900
|
||||
Subject: [PATCH 2/7] vsock: each transport cycles only on its own sockets
|
||||
|
||||
When iterating over sockets using vsock_for_each_connected_socket, make
|
||||
sure that a transport filters out sockets that don't belong to the
|
||||
transport.
|
||||
|
||||
There actually was an issue caused by this; in a nested VM
|
||||
configuration, destroying the nested VM (which often involves the
|
||||
closing of /dev/vhost-vsock if there was h2g connections to the nested
|
||||
VM) kills not only the h2g connections, but also all existing g2h
|
||||
connections to the (outmost) host which are totally unrelated.
|
||||
|
||||
Tested: Executed the following steps on Cuttlefish (Android running on a
|
||||
VM) [1]: (1) Enter into an `adb shell` session - to have a g2h
|
||||
connection inside the VM, (2) open and then close /dev/vhost-vsock by
|
||||
`exec 3< /dev/vhost-vsock && exec 3<&-`, (3) observe that the adb
|
||||
session is not reset.
|
||||
|
||||
[1] https://android.googlesource.com/device/google/cuttlefish/
|
||||
|
||||
Fixes: c0cfa2d8a788 ("vsock: add multi-transports support")
|
||||
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
|
||||
Acked-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Signed-off-by: Jiyong Park <jiyong@google.com>
|
||||
Link: https://lore.kernel.org/r/20220311020017.1509316-1-jiyong@google.com
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/vhost/vsock.c | 3 ++-
|
||||
include/net/af_vsock.h | 3 ++-
|
||||
net/vmw_vsock/af_vsock.c | 9 +++++++--
|
||||
net/vmw_vsock/virtio_transport.c | 7 +++++--
|
||||
net/vmw_vsock/vmci_transport.c | 5 ++++-
|
||||
5 files changed, 20 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
|
||||
index a483cec31d5c..e413aaaca8f9 100644
|
||||
--- a/drivers/vhost/vsock.c
|
||||
+++ b/drivers/vhost/vsock.c
|
||||
@@ -695,7 +695,8 @@ static int vhost_vsock_dev_release(struct inode *inode, struct file *file)
|
||||
|
||||
/* Iterating over all connections for all CIDs to find orphans is
|
||||
* inefficient. Room for improvement here. */
|
||||
- vsock_for_each_connected_socket(vhost_vsock_reset_orphans);
|
||||
+ vsock_for_each_connected_socket(&vhost_transport.transport,
|
||||
+ vhost_vsock_reset_orphans);
|
||||
|
||||
vhost_vsock_stop(vsock);
|
||||
vhost_vsock_flush(vsock);
|
||||
diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h
|
||||
index b1c717286993..4d8589244dc7 100644
|
||||
--- a/include/net/af_vsock.h
|
||||
+++ b/include/net/af_vsock.h
|
||||
@@ -197,7 +197,8 @@ struct sock *vsock_find_bound_socket(struct sockaddr_vm *addr);
|
||||
struct sock *vsock_find_connected_socket(struct sockaddr_vm *src,
|
||||
struct sockaddr_vm *dst);
|
||||
void vsock_remove_sock(struct vsock_sock *vsk);
|
||||
-void vsock_for_each_connected_socket(void (*fn)(struct sock *sk));
|
||||
+void vsock_for_each_connected_socket(struct vsock_transport *transport,
|
||||
+ void (*fn)(struct sock *sk));
|
||||
int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk);
|
||||
bool vsock_find_cid(unsigned int cid);
|
||||
|
||||
diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
|
||||
index 791955f5e7ec..bc3b85838158 100644
|
||||
--- a/net/vmw_vsock/af_vsock.c
|
||||
+++ b/net/vmw_vsock/af_vsock.c
|
||||
@@ -333,7 +333,8 @@ void vsock_remove_sock(struct vsock_sock *vsk)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vsock_remove_sock);
|
||||
|
||||
-void vsock_for_each_connected_socket(void (*fn)(struct sock *sk))
|
||||
+void vsock_for_each_connected_socket(struct vsock_transport *transport,
|
||||
+ void (*fn)(struct sock *sk))
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -342,8 +343,12 @@ void vsock_for_each_connected_socket(void (*fn)(struct sock *sk))
|
||||
for (i = 0; i < ARRAY_SIZE(vsock_connected_table); i++) {
|
||||
struct vsock_sock *vsk;
|
||||
list_for_each_entry(vsk, &vsock_connected_table[i],
|
||||
- connected_table)
|
||||
+ connected_table) {
|
||||
+ if (vsk->transport != transport)
|
||||
+ continue;
|
||||
+
|
||||
fn(sk_vsock(vsk));
|
||||
+ }
|
||||
}
|
||||
|
||||
spin_unlock_bh(&vsock_table_lock);
|
||||
diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
|
||||
index 3a056f8affd1..e131121533ad 100644
|
||||
--- a/net/vmw_vsock/virtio_transport.c
|
||||
+++ b/net/vmw_vsock/virtio_transport.c
|
||||
@@ -24,6 +24,7 @@
|
||||
static struct workqueue_struct *virtio_vsock_workqueue;
|
||||
static struct virtio_vsock __rcu *the_virtio_vsock;
|
||||
static DEFINE_MUTEX(the_virtio_vsock_mutex); /* protects the_virtio_vsock */
|
||||
+static struct virtio_transport virtio_transport; /* forward declaration */
|
||||
|
||||
struct virtio_vsock {
|
||||
struct virtio_device *vdev;
|
||||
@@ -383,7 +384,8 @@ static void virtio_vsock_event_handle(struct virtio_vsock *vsock,
|
||||
switch (le32_to_cpu(event->id)) {
|
||||
case VIRTIO_VSOCK_EVENT_TRANSPORT_RESET:
|
||||
virtio_vsock_update_guest_cid(vsock);
|
||||
- vsock_for_each_connected_socket(virtio_vsock_reset_sock);
|
||||
+ vsock_for_each_connected_socket(&virtio_transport.transport,
|
||||
+ virtio_vsock_reset_sock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -635,7 +637,8 @@ static void virtio_vsock_remove(struct virtio_device *vdev)
|
||||
synchronize_rcu();
|
||||
|
||||
/* Reset all connected sockets when the device disappear */
|
||||
- vsock_for_each_connected_socket(virtio_vsock_reset_sock);
|
||||
+ vsock_for_each_connected_socket(&virtio_transport.transport,
|
||||
+ virtio_vsock_reset_sock);
|
||||
|
||||
/* Stop all work handlers to make sure no one is accessing the device,
|
||||
* so we can safely call vdev->config->reset().
|
||||
diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c
|
||||
index 8b65323207db..87de3477cb6d 100644
|
||||
--- a/net/vmw_vsock/vmci_transport.c
|
||||
+++ b/net/vmw_vsock/vmci_transport.c
|
||||
@@ -75,6 +75,8 @@ static u32 vmci_transport_qp_resumed_sub_id = VMCI_INVALID_ID;
|
||||
|
||||
static int PROTOCOL_OVERRIDE = -1;
|
||||
|
||||
+static struct vsock_transport vmci_transport; /* forward declaration */
|
||||
+
|
||||
/* Helper function to convert from a VMCI error code to a VSock error code. */
|
||||
|
||||
static s32 vmci_transport_error_to_vsock_error(s32 vmci_error)
|
||||
@@ -883,7 +885,8 @@ static void vmci_transport_qp_resumed_cb(u32 sub_id,
|
||||
const struct vmci_event_data *e_data,
|
||||
void *client_data)
|
||||
{
|
||||
- vsock_for_each_connected_socket(vmci_transport_handle_detach);
|
||||
+ vsock_for_each_connected_socket(&vmci_transport,
|
||||
+ vmci_transport_handle_detach);
|
||||
}
|
||||
|
||||
static void vmci_transport_recv_pkt_work(struct work_struct *work)
|
||||
--
|
||||
2.34.1
|
||||
|
@ -0,0 +1,43 @@
|
||||
From d57616af2cfcd67e964f91867cdcc20124b49091 Mon Sep 17 00:00:00 2001
|
||||
From: Stefano Garzarella <sgarzare@redhat.com>
|
||||
Date: Wed, 23 Mar 2022 18:36:23 +0100
|
||||
Subject: [PATCH 3/7] vsock/virtio: initialize vdev->priv before using VQs
|
||||
|
||||
When we fill VQs with empty buffers and kick the host, it may send
|
||||
an interrupt. `vdev->priv` must be initialized before this since it
|
||||
is used in the virtqueue callbacks.
|
||||
|
||||
Fixes: 0deab087b16a ("vsock/virtio: use RCU to avoid use-after-free on the_virtio_vsock")
|
||||
Suggested-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
|
||||
Acked-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
net/vmw_vsock/virtio_transport.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
|
||||
index e131121533ad..0711aaed17da 100644
|
||||
--- a/net/vmw_vsock/virtio_transport.c
|
||||
+++ b/net/vmw_vsock/virtio_transport.c
|
||||
@@ -599,6 +599,8 @@ static int virtio_vsock_probe(struct virtio_device *vdev)
|
||||
INIT_WORK(&vsock->event_work, virtio_transport_event_work);
|
||||
INIT_WORK(&vsock->send_pkt_work, virtio_transport_send_pkt_work);
|
||||
|
||||
+ vdev->priv = vsock;
|
||||
+
|
||||
mutex_lock(&vsock->tx_lock);
|
||||
vsock->tx_run = true;
|
||||
mutex_unlock(&vsock->tx_lock);
|
||||
@@ -613,7 +615,6 @@ static int virtio_vsock_probe(struct virtio_device *vdev)
|
||||
vsock->event_run = true;
|
||||
mutex_unlock(&vsock->event_lock);
|
||||
|
||||
- vdev->priv = vsock;
|
||||
rcu_assign_pointer(the_virtio_vsock, vsock);
|
||||
|
||||
mutex_unlock(&the_virtio_vsock_mutex);
|
||||
--
|
||||
2.34.1
|
||||
|
@ -0,0 +1,38 @@
|
||||
From cbb4f49c1f4e761d1d35dab0bbed3b6aed52d456 Mon Sep 17 00:00:00 2001
|
||||
From: Stefano Garzarella <sgarzare@redhat.com>
|
||||
Date: Wed, 23 Mar 2022 18:36:25 +0100
|
||||
Subject: [PATCH 4/7] vsock/virtio: enable VQs early on probe
|
||||
|
||||
virtio spec requires drivers to set DRIVER_OK before using VQs.
|
||||
This is set automatically after probe returns, but virtio-vsock
|
||||
driver uses VQs in the probe function to fill rx and event VQs
|
||||
with new buffers.
|
||||
|
||||
Let's fix this, calling virtio_device_ready() before using VQs
|
||||
in the probe function.
|
||||
|
||||
Fixes: 0ea9e1d3a9e3 ("VSOCK: Introduce virtio_transport.ko")
|
||||
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
|
||||
Acked-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
net/vmw_vsock/virtio_transport.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
|
||||
index 0711aaed17da..ae22cc8e1b27 100644
|
||||
--- a/net/vmw_vsock/virtio_transport.c
|
||||
+++ b/net/vmw_vsock/virtio_transport.c
|
||||
@@ -601,6 +601,8 @@ static int virtio_vsock_probe(struct virtio_device *vdev)
|
||||
|
||||
vdev->priv = vsock;
|
||||
|
||||
+ virtio_device_ready(vdev);
|
||||
+
|
||||
mutex_lock(&vsock->tx_lock);
|
||||
vsock->tx_run = true;
|
||||
mutex_unlock(&vsock->tx_lock);
|
||||
--
|
||||
2.34.1
|
||||
|
@ -0,0 +1,210 @@
|
||||
From 31098c59b505a031470341a519e3233987b8b0c9 Mon Sep 17 00:00:00 2001
|
||||
From: Stefano Garzarella <sgarzare@redhat.com>
|
||||
Date: Thu, 28 Apr 2022 15:22:40 +0200
|
||||
Subject: [PATCH 5/7] vsock/virtio: factor our the code to initialize and
|
||||
delete VQs
|
||||
|
||||
Add virtio_vsock_vqs_init() and virtio_vsock_vqs_del() with the code
|
||||
that was in virtio_vsock_probe() and virtio_vsock_remove to initialize
|
||||
and delete VQs.
|
||||
|
||||
These new functions will be used in the next commit to support device
|
||||
suspend/resume
|
||||
|
||||
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
|
||||
Acked-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
net/vmw_vsock/virtio_transport.c | 143 +++++++++++++++++--------------
|
||||
1 file changed, 81 insertions(+), 62 deletions(-)
|
||||
|
||||
diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
|
||||
index ae22cc8e1b27..dd4af6a56cad 100644
|
||||
--- a/net/vmw_vsock/virtio_transport.c
|
||||
+++ b/net/vmw_vsock/virtio_transport.c
|
||||
@@ -543,64 +543,28 @@ static void virtio_transport_rx_work(struct work_struct *work)
|
||||
mutex_unlock(&vsock->rx_lock);
|
||||
}
|
||||
|
||||
-static int virtio_vsock_probe(struct virtio_device *vdev)
|
||||
+static int virtio_vsock_vqs_init(struct virtio_vsock *vsock)
|
||||
{
|
||||
- vq_callback_t *callbacks[] = {
|
||||
- virtio_vsock_rx_done,
|
||||
- virtio_vsock_tx_done,
|
||||
- virtio_vsock_event_done,
|
||||
- };
|
||||
+ struct virtio_device *vdev = vsock->vdev;
|
||||
static const char * const names[] = {
|
||||
"rx",
|
||||
"tx",
|
||||
"event",
|
||||
};
|
||||
- struct virtio_vsock *vsock = NULL;
|
||||
+ vq_callback_t *callbacks[] = {
|
||||
+ virtio_vsock_rx_done,
|
||||
+ virtio_vsock_tx_done,
|
||||
+ virtio_vsock_event_done,
|
||||
+ };
|
||||
int ret;
|
||||
|
||||
- ret = mutex_lock_interruptible(&the_virtio_vsock_mutex);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
- /* Only one virtio-vsock device per guest is supported */
|
||||
- if (rcu_dereference_protected(the_virtio_vsock,
|
||||
- lockdep_is_held(&the_virtio_vsock_mutex))) {
|
||||
- ret = -EBUSY;
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- vsock = kzalloc(sizeof(*vsock), GFP_KERNEL);
|
||||
- if (!vsock) {
|
||||
- ret = -ENOMEM;
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- vsock->vdev = vdev;
|
||||
-
|
||||
- ret = virtio_find_vqs(vsock->vdev, VSOCK_VQ_MAX,
|
||||
- vsock->vqs, callbacks, names,
|
||||
+ ret = virtio_find_vqs(vdev, VSOCK_VQ_MAX, vsock->vqs, callbacks, names,
|
||||
NULL);
|
||||
if (ret < 0)
|
||||
- goto out;
|
||||
+ return ret;
|
||||
|
||||
virtio_vsock_update_guest_cid(vsock);
|
||||
|
||||
- vsock->rx_buf_nr = 0;
|
||||
- vsock->rx_buf_max_nr = 0;
|
||||
- atomic_set(&vsock->queued_replies, 0);
|
||||
-
|
||||
- mutex_init(&vsock->tx_lock);
|
||||
- mutex_init(&vsock->rx_lock);
|
||||
- mutex_init(&vsock->event_lock);
|
||||
- spin_lock_init(&vsock->send_pkt_list_lock);
|
||||
- INIT_LIST_HEAD(&vsock->send_pkt_list);
|
||||
- INIT_WORK(&vsock->rx_work, virtio_transport_rx_work);
|
||||
- INIT_WORK(&vsock->tx_work, virtio_transport_tx_work);
|
||||
- INIT_WORK(&vsock->event_work, virtio_transport_event_work);
|
||||
- INIT_WORK(&vsock->send_pkt_work, virtio_transport_send_pkt_work);
|
||||
-
|
||||
- vdev->priv = vsock;
|
||||
-
|
||||
virtio_device_ready(vdev);
|
||||
|
||||
mutex_lock(&vsock->tx_lock);
|
||||
@@ -617,29 +581,15 @@ static int virtio_vsock_probe(struct virtio_device *vdev)
|
||||
vsock->event_run = true;
|
||||
mutex_unlock(&vsock->event_lock);
|
||||
|
||||
- rcu_assign_pointer(the_virtio_vsock, vsock);
|
||||
-
|
||||
- mutex_unlock(&the_virtio_vsock_mutex);
|
||||
return 0;
|
||||
-
|
||||
-out:
|
||||
- kfree(vsock);
|
||||
- mutex_unlock(&the_virtio_vsock_mutex);
|
||||
- return ret;
|
||||
}
|
||||
|
||||
-static void virtio_vsock_remove(struct virtio_device *vdev)
|
||||
+static void virtio_vsock_vqs_del(struct virtio_vsock *vsock)
|
||||
{
|
||||
- struct virtio_vsock *vsock = vdev->priv;
|
||||
+ struct virtio_device *vdev = vsock->vdev;
|
||||
struct virtio_vsock_pkt *pkt;
|
||||
|
||||
- mutex_lock(&the_virtio_vsock_mutex);
|
||||
-
|
||||
- vdev->priv = NULL;
|
||||
- rcu_assign_pointer(the_virtio_vsock, NULL);
|
||||
- synchronize_rcu();
|
||||
-
|
||||
- /* Reset all connected sockets when the device disappear */
|
||||
+ /* Reset all connected sockets when the VQs disappear */
|
||||
vsock_for_each_connected_socket(&virtio_transport.transport,
|
||||
virtio_vsock_reset_sock);
|
||||
|
||||
@@ -684,6 +634,75 @@ static void virtio_vsock_remove(struct virtio_device *vdev)
|
||||
|
||||
/* Delete virtqueues and flush outstanding callbacks if any */
|
||||
vdev->config->del_vqs(vdev);
|
||||
+}
|
||||
+
|
||||
+static int virtio_vsock_probe(struct virtio_device *vdev)
|
||||
+{
|
||||
+ struct virtio_vsock *vsock = NULL;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = mutex_lock_interruptible(&the_virtio_vsock_mutex);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Only one virtio-vsock device per guest is supported */
|
||||
+ if (rcu_dereference_protected(the_virtio_vsock,
|
||||
+ lockdep_is_held(&the_virtio_vsock_mutex))) {
|
||||
+ ret = -EBUSY;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ vsock = kzalloc(sizeof(*vsock), GFP_KERNEL);
|
||||
+ if (!vsock) {
|
||||
+ ret = -ENOMEM;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ vsock->vdev = vdev;
|
||||
+
|
||||
+ vsock->rx_buf_nr = 0;
|
||||
+ vsock->rx_buf_max_nr = 0;
|
||||
+ atomic_set(&vsock->queued_replies, 0);
|
||||
+
|
||||
+ mutex_init(&vsock->tx_lock);
|
||||
+ mutex_init(&vsock->rx_lock);
|
||||
+ mutex_init(&vsock->event_lock);
|
||||
+ spin_lock_init(&vsock->send_pkt_list_lock);
|
||||
+ INIT_LIST_HEAD(&vsock->send_pkt_list);
|
||||
+ INIT_WORK(&vsock->rx_work, virtio_transport_rx_work);
|
||||
+ INIT_WORK(&vsock->tx_work, virtio_transport_tx_work);
|
||||
+ INIT_WORK(&vsock->event_work, virtio_transport_event_work);
|
||||
+ INIT_WORK(&vsock->send_pkt_work, virtio_transport_send_pkt_work);
|
||||
+
|
||||
+ vdev->priv = vsock;
|
||||
+
|
||||
+ ret = virtio_vsock_vqs_init(vsock);
|
||||
+ if (ret < 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ rcu_assign_pointer(the_virtio_vsock, vsock);
|
||||
+
|
||||
+ mutex_unlock(&the_virtio_vsock_mutex);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+out:
|
||||
+ kfree(vsock);
|
||||
+ mutex_unlock(&the_virtio_vsock_mutex);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void virtio_vsock_remove(struct virtio_device *vdev)
|
||||
+{
|
||||
+ struct virtio_vsock *vsock = vdev->priv;
|
||||
+
|
||||
+ mutex_lock(&the_virtio_vsock_mutex);
|
||||
+
|
||||
+ vdev->priv = NULL;
|
||||
+ rcu_assign_pointer(the_virtio_vsock, NULL);
|
||||
+ synchronize_rcu();
|
||||
+
|
||||
+ virtio_vsock_vqs_del(vsock);
|
||||
|
||||
/* Other works can be queued before 'config->del_vqs()', so we flush
|
||||
* all works before to free the vsock object to avoid use after free.
|
||||
--
|
||||
2.34.1
|
||||
|
@ -0,0 +1,87 @@
|
||||
From bca7681a7c3461da21ceac2aab05b38a190f8a43 Mon Sep 17 00:00:00 2001
|
||||
From: Stefano Garzarella <sgarzare@redhat.com>
|
||||
Date: Thu, 28 Apr 2022 15:22:41 +0200
|
||||
Subject: [PATCH 6/7] vsock/virtio: add support for device suspend/resume
|
||||
|
||||
Implement .freeze and .restore callbacks of struct virtio_driver
|
||||
to support device suspend/resume.
|
||||
|
||||
During suspension all connected sockets are reset and VQs deleted.
|
||||
During resume the VQs are re-initialized.
|
||||
|
||||
Reported by: Vilas R K <vilas.r.k@intel.com>
|
||||
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
|
||||
Acked-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
net/vmw_vsock/virtio_transport.c | 47 ++++++++++++++++++++++++++++++++
|
||||
1 file changed, 47 insertions(+)
|
||||
|
||||
diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
|
||||
index dd4af6a56cad..793c4b1325f1 100644
|
||||
--- a/net/vmw_vsock/virtio_transport.c
|
||||
+++ b/net/vmw_vsock/virtio_transport.c
|
||||
@@ -717,6 +717,49 @@ static void virtio_vsock_remove(struct virtio_device *vdev)
|
||||
kfree(vsock);
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_PM_SLEEP
|
||||
+static int virtio_vsock_freeze(struct virtio_device *vdev)
|
||||
+{
|
||||
+ struct virtio_vsock *vsock = vdev->priv;
|
||||
+
|
||||
+ mutex_lock(&the_virtio_vsock_mutex);
|
||||
+
|
||||
+ rcu_assign_pointer(the_virtio_vsock, NULL);
|
||||
+ synchronize_rcu();
|
||||
+
|
||||
+ virtio_vsock_vqs_del(vsock);
|
||||
+
|
||||
+ mutex_unlock(&the_virtio_vsock_mutex);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int virtio_vsock_restore(struct virtio_device *vdev)
|
||||
+{
|
||||
+ struct virtio_vsock *vsock = vdev->priv;
|
||||
+ int ret;
|
||||
+
|
||||
+ mutex_lock(&the_virtio_vsock_mutex);
|
||||
+
|
||||
+ /* Only one virtio-vsock device per guest is supported */
|
||||
+ if (rcu_dereference_protected(the_virtio_vsock,
|
||||
+ lockdep_is_held(&the_virtio_vsock_mutex))) {
|
||||
+ ret = -EBUSY;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ ret = virtio_vsock_vqs_init(vsock);
|
||||
+ if (ret < 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ rcu_assign_pointer(the_virtio_vsock, vsock);
|
||||
+
|
||||
+out:
|
||||
+ mutex_unlock(&the_virtio_vsock_mutex);
|
||||
+ return ret;
|
||||
+}
|
||||
+#endif /* CONFIG_PM_SLEEP */
|
||||
+
|
||||
static struct virtio_device_id id_table[] = {
|
||||
{ VIRTIO_ID_VSOCK, VIRTIO_DEV_ANY_ID },
|
||||
{ 0 },
|
||||
@@ -733,6 +776,10 @@ static struct virtio_driver virtio_vsock_driver = {
|
||||
.id_table = id_table,
|
||||
.probe = virtio_vsock_probe,
|
||||
.remove = virtio_vsock_remove,
|
||||
+#ifdef CONFIG_PM_SLEEP
|
||||
+ .freeze = virtio_vsock_freeze,
|
||||
+ .restore = virtio_vsock_restore,
|
||||
+#endif
|
||||
};
|
||||
|
||||
static int __init virtio_vsock_init(void)
|
||||
--
|
||||
2.34.1
|
||||
|
@ -0,0 +1,77 @@
|
||||
From a3f1a29e4d773c9a7f2236c623d7567587c1204d Mon Sep 17 00:00:00 2001
|
||||
From: Alexandru Matei <alexandru.matei@uipath.com>
|
||||
Date: Tue, 24 Oct 2023 22:17:42 +0300
|
||||
Subject: [PATCH 7/7] vsock/virtio: initialize the_virtio_vsock before using
|
||||
VQs
|
||||
|
||||
Once VQs are filled with empty buffers and we kick the host, it can send
|
||||
connection requests. If the_virtio_vsock is not initialized before,
|
||||
replies are silently dropped and do not reach the host.
|
||||
|
||||
virtio_transport_send_pkt() can queue packets once the_virtio_vsock is
|
||||
set, but they won't be processed until vsock->tx_run is set to true. We
|
||||
queue vsock->send_pkt_work when initialization finishes to send those
|
||||
packets queued earlier.
|
||||
|
||||
Fixes: 0deab087b16a ("vsock/virtio: use RCU to avoid use-after-free on the_virtio_vsock")
|
||||
Signed-off-by: Alexandru Matei <alexandru.matei@uipath.com>
|
||||
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
|
||||
Link: https://lore.kernel.org/r/20231024191742.14259-1-alexandru.matei@uipath.com
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
net/vmw_vsock/virtio_transport.c | 18 +++++++++++++++++-
|
||||
1 file changed, 17 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
|
||||
index 793c4b1325f1..25a9f03f0027 100644
|
||||
--- a/net/vmw_vsock/virtio_transport.c
|
||||
+++ b/net/vmw_vsock/virtio_transport.c
|
||||
@@ -567,6 +567,11 @@ static int virtio_vsock_vqs_init(struct virtio_vsock *vsock)
|
||||
|
||||
virtio_device_ready(vdev);
|
||||
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void virtio_vsock_vqs_start(struct virtio_vsock *vsock)
|
||||
+{
|
||||
mutex_lock(&vsock->tx_lock);
|
||||
vsock->tx_run = true;
|
||||
mutex_unlock(&vsock->tx_lock);
|
||||
@@ -581,7 +586,16 @@ static int virtio_vsock_vqs_init(struct virtio_vsock *vsock)
|
||||
vsock->event_run = true;
|
||||
mutex_unlock(&vsock->event_lock);
|
||||
|
||||
- return 0;
|
||||
+ /* virtio_transport_send_pkt() can queue packets once
|
||||
+ * the_virtio_vsock is set, but they won't be processed until
|
||||
+ * vsock->tx_run is set to true. We queue vsock->send_pkt_work
|
||||
+ * when initialization finishes to send those packets queued
|
||||
+ * earlier.
|
||||
+ * We don't need to queue the other workers (rx, event) because
|
||||
+ * as long as we don't fill the queues with empty buffers, the
|
||||
+ * host can't send us any notification.
|
||||
+ */
|
||||
+ queue_work(virtio_vsock_workqueue, &vsock->send_pkt_work);
|
||||
}
|
||||
|
||||
static void virtio_vsock_vqs_del(struct virtio_vsock *vsock)
|
||||
@@ -681,6 +695,7 @@ static int virtio_vsock_probe(struct virtio_device *vdev)
|
||||
goto out;
|
||||
|
||||
rcu_assign_pointer(the_virtio_vsock, vsock);
|
||||
+ virtio_vsock_vqs_start(vsock);
|
||||
|
||||
mutex_unlock(&the_virtio_vsock_mutex);
|
||||
|
||||
@@ -753,6 +768,7 @@ static int virtio_vsock_restore(struct virtio_device *vdev)
|
||||
goto out;
|
||||
|
||||
rcu_assign_pointer(the_virtio_vsock, vsock);
|
||||
+ virtio_vsock_vqs_start(vsock);
|
||||
|
||||
out:
|
||||
mutex_unlock(&the_virtio_vsock_mutex);
|
||||
--
|
||||
2.34.1
|
||||
|
@ -0,0 +1,76 @@
|
||||
From 0b992e5760051b2083bf7542b84c917b91ec4d41 Mon Sep 17 00:00:00 2001
|
||||
From: Alexandru Matei <alexandru.matei@uipath.com>
|
||||
Date: Tue, 24 Oct 2023 22:17:42 +0300
|
||||
Subject: [PATCH] vsock/virtio: initialize the_virtio_vsock before using VQs
|
||||
|
||||
Once VQs are filled with empty buffers and we kick the host, it can send
|
||||
connection requests. If the_virtio_vsock is not initialized before,
|
||||
replies are silently dropped and do not reach the host.
|
||||
|
||||
virtio_transport_send_pkt() can queue packets once the_virtio_vsock is
|
||||
set, but they won't be processed until vsock->tx_run is set to true. We
|
||||
queue vsock->send_pkt_work when initialization finishes to send those
|
||||
packets queued earlier.
|
||||
|
||||
Fixes: 0deab087b16a ("vsock/virtio: use RCU to avoid use-after-free on the_virtio_vsock")
|
||||
Signed-off-by: Alexandru Matei <alexandru.matei@uipath.com>
|
||||
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
|
||||
Link: https://lore.kernel.org/r/20231024191742.14259-1-alexandru.matei@uipath.com
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
net/vmw_vsock/virtio_transport.c | 18 +++++++++++++++++-
|
||||
1 file changed, 17 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
|
||||
index ad64f403536a..460e7fbb42da 100644
|
||||
--- a/net/vmw_vsock/virtio_transport.c
|
||||
+++ b/net/vmw_vsock/virtio_transport.c
|
||||
@@ -590,6 +590,11 @@ static int virtio_vsock_vqs_init(struct virtio_vsock *vsock)
|
||||
|
||||
virtio_device_ready(vdev);
|
||||
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void virtio_vsock_vqs_start(struct virtio_vsock *vsock)
|
||||
+{
|
||||
mutex_lock(&vsock->tx_lock);
|
||||
vsock->tx_run = true;
|
||||
mutex_unlock(&vsock->tx_lock);
|
||||
@@ -604,7 +609,16 @@ static int virtio_vsock_vqs_init(struct virtio_vsock *vsock)
|
||||
vsock->event_run = true;
|
||||
mutex_unlock(&vsock->event_lock);
|
||||
|
||||
- return 0;
|
||||
+ /* virtio_transport_send_pkt() can queue packets once
|
||||
+ * the_virtio_vsock is set, but they won't be processed until
|
||||
+ * vsock->tx_run is set to true. We queue vsock->send_pkt_work
|
||||
+ * when initialization finishes to send those packets queued
|
||||
+ * earlier.
|
||||
+ * We don't need to queue the other workers (rx, event) because
|
||||
+ * as long as we don't fill the queues with empty buffers, the
|
||||
+ * host can't send us any notification.
|
||||
+ */
|
||||
+ queue_work(virtio_vsock_workqueue, &vsock->send_pkt_work);
|
||||
}
|
||||
|
||||
static void virtio_vsock_vqs_del(struct virtio_vsock *vsock)
|
||||
@@ -707,6 +721,7 @@ static int virtio_vsock_probe(struct virtio_device *vdev)
|
||||
goto out;
|
||||
|
||||
rcu_assign_pointer(the_virtio_vsock, vsock);
|
||||
+ virtio_vsock_vqs_start(vsock);
|
||||
|
||||
mutex_unlock(&the_virtio_vsock_mutex);
|
||||
|
||||
@@ -779,6 +794,7 @@ static int virtio_vsock_restore(struct virtio_device *vdev)
|
||||
goto out;
|
||||
|
||||
rcu_assign_pointer(the_virtio_vsock, vsock);
|
||||
+ virtio_vsock_vqs_start(vsock);
|
||||
|
||||
out:
|
||||
mutex_unlock(&the_virtio_vsock_mutex);
|
||||
--
|
||||
2.34.1
|
||||
|
@ -0,0 +1,76 @@
|
||||
From 04ae44b5b30465588074f3475fb37d7cbcdec3fa Mon Sep 17 00:00:00 2001
|
||||
From: Alexandru Matei <alexandru.matei@uipath.com>
|
||||
Date: Tue, 24 Oct 2023 22:17:42 +0300
|
||||
Subject: [PATCH] vsock/virtio: initialize the_virtio_vsock before using VQs
|
||||
|
||||
Once VQs are filled with empty buffers and we kick the host, it can send
|
||||
connection requests. If the_virtio_vsock is not initialized before,
|
||||
replies are silently dropped and do not reach the host.
|
||||
|
||||
virtio_transport_send_pkt() can queue packets once the_virtio_vsock is
|
||||
set, but they won't be processed until vsock->tx_run is set to true. We
|
||||
queue vsock->send_pkt_work when initialization finishes to send those
|
||||
packets queued earlier.
|
||||
|
||||
Fixes: 0deab087b16a ("vsock/virtio: use RCU to avoid use-after-free on the_virtio_vsock")
|
||||
Signed-off-by: Alexandru Matei <alexandru.matei@uipath.com>
|
||||
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
|
||||
Link: https://lore.kernel.org/r/20231024191742.14259-1-alexandru.matei@uipath.com
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
net/vmw_vsock/virtio_transport.c | 18 +++++++++++++++++-
|
||||
1 file changed, 17 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
|
||||
index ad64f403536a..460e7fbb42da 100644
|
||||
--- a/net/vmw_vsock/virtio_transport.c
|
||||
+++ b/net/vmw_vsock/virtio_transport.c
|
||||
@@ -590,6 +590,11 @@ static int virtio_vsock_vqs_init(struct virtio_vsock *vsock)
|
||||
|
||||
virtio_device_ready(vdev);
|
||||
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void virtio_vsock_vqs_start(struct virtio_vsock *vsock)
|
||||
+{
|
||||
mutex_lock(&vsock->tx_lock);
|
||||
vsock->tx_run = true;
|
||||
mutex_unlock(&vsock->tx_lock);
|
||||
@@ -604,7 +609,16 @@ static int virtio_vsock_vqs_init(struct virtio_vsock *vsock)
|
||||
vsock->event_run = true;
|
||||
mutex_unlock(&vsock->event_lock);
|
||||
|
||||
- return 0;
|
||||
+ /* virtio_transport_send_pkt() can queue packets once
|
||||
+ * the_virtio_vsock is set, but they won't be processed until
|
||||
+ * vsock->tx_run is set to true. We queue vsock->send_pkt_work
|
||||
+ * when initialization finishes to send those packets queued
|
||||
+ * earlier.
|
||||
+ * We don't need to queue the other workers (rx, event) because
|
||||
+ * as long as we don't fill the queues with empty buffers, the
|
||||
+ * host can't send us any notification.
|
||||
+ */
|
||||
+ queue_work(virtio_vsock_workqueue, &vsock->send_pkt_work);
|
||||
}
|
||||
|
||||
static void virtio_vsock_vqs_del(struct virtio_vsock *vsock)
|
||||
@@ -707,6 +721,7 @@ static int virtio_vsock_probe(struct virtio_device *vdev)
|
||||
goto out;
|
||||
|
||||
rcu_assign_pointer(the_virtio_vsock, vsock);
|
||||
+ virtio_vsock_vqs_start(vsock);
|
||||
|
||||
mutex_unlock(&the_virtio_vsock_mutex);
|
||||
|
||||
@@ -779,6 +794,7 @@ static int virtio_vsock_restore(struct virtio_device *vdev)
|
||||
goto out;
|
||||
|
||||
rcu_assign_pointer(the_virtio_vsock, vsock);
|
||||
+ virtio_vsock_vqs_start(vsock);
|
||||
|
||||
out:
|
||||
mutex_unlock(&the_virtio_vsock_mutex);
|
||||
--
|
||||
2.34.1
|
||||
|
@ -169,7 +169,7 @@ assets:
|
||||
kernel:
|
||||
description: "Linux kernel optimised for virtual machines"
|
||||
url: "https://cdn.kernel.org/pub/linux/kernel/v6.x/"
|
||||
version: "v6.1.52"
|
||||
version: "v6.1.62"
|
||||
sev:
|
||||
description: "Linux kernel that supports SEV and SNP"
|
||||
url: "https://cdn.kernel.org/pub/linux/kernel/v5.x/"
|
||||
@ -182,7 +182,7 @@ assets:
|
||||
kernel-arm-experimental:
|
||||
description: "Linux kernel with cpu/mem hotplug support on arm64"
|
||||
url: "https://cdn.kernel.org/pub/linux/kernel/v5.x/"
|
||||
version: "v5.15.7"
|
||||
version: "v5.15.138"
|
||||
|
||||
kernel-dragonball-experimental:
|
||||
description: "Linux kernel with Dragonball VMM optimizations like upcall"
|
||||
|
Loading…
Reference in New Issue
Block a user