From: Stefano Garzarella <sgarz...@redhat.com>

To allow other transports to be loaded with vmci_transport,
we register the vmci_transport as G2H or H2G only when a VMCI guest
or host is active.

To do that, this patch adds a callback registered in the vmci driver
that will be called when the host or guest becomes active.
This callback will register the vmci_transport in the VSOCK core.

Cc: Jorgen Hansen <jhan...@vmware.com>
Signed-off-by: Stefano Garzarella <sgarz...@redhat.com>
Signed-off-by: David S. Miller <da...@davemloft.net>

https://jira.sw.ru/browse/PSBM-128702
(cherry picked from commit b1bba80a4376aef34de2b57bfb8834bd095703ed)
Signed-off-by: Konstantin Khorenko <khore...@virtuozzo.com>
---
 drivers/misc/vmw_vmci/vmci_driver.c | 67 +++++++++++++++++++++++++++++
 drivers/misc/vmw_vmci/vmci_driver.h |  2 +
 drivers/misc/vmw_vmci/vmci_guest.c  |  2 +
 drivers/misc/vmw_vmci/vmci_host.c   |  7 +++
 include/linux/vmw_vmci_api.h        |  2 +
 net/vmw_vsock/vmci_transport.c      | 33 +++++++++-----
 6 files changed, 102 insertions(+), 11 deletions(-)

diff --git a/drivers/misc/vmw_vmci/vmci_driver.c 
b/drivers/misc/vmw_vmci/vmci_driver.c
index 003bfba40758..64e540cfb749 100644
--- a/drivers/misc/vmw_vmci/vmci_driver.c
+++ b/drivers/misc/vmw_vmci/vmci_driver.c
@@ -36,6 +36,10 @@ MODULE_PARM_DESC(disable_guest,
 static bool vmci_guest_personality_initialized;
 static bool vmci_host_personality_initialized;
 
+static DEFINE_MUTEX(vmci_vsock_mutex); /* protects vmci_vsock_transport_cb */
+static vmci_vsock_cb vmci_vsock_transport_cb;
+bool vmci_vsock_cb_host_called;
+
 /*
  * vmci_get_context_id() - Gets the current context ID.
  *
@@ -53,6 +57,69 @@ u32 vmci_get_context_id(void)
 }
 EXPORT_SYMBOL_GPL(vmci_get_context_id);
 
+/*
+ * vmci_register_vsock_callback() - Register the VSOCK vmci_transport callback.
+ *
+ * The callback will be called when the first host or guest becomes active,
+ * or if they are already active when this function is called.
+ * To unregister the callback, call this function with NULL parameter.
+ *
+ * Returns 0 on success. -EBUSY if a callback is already registered.
+ */
+int vmci_register_vsock_callback(vmci_vsock_cb callback)
+{
+       int err = 0;
+
+       mutex_lock(&vmci_vsock_mutex);
+
+       if (vmci_vsock_transport_cb && callback) {
+               err = -EBUSY;
+               goto out;
+       }
+
+       vmci_vsock_transport_cb = callback;
+
+       if (!vmci_vsock_transport_cb) {
+               vmci_vsock_cb_host_called = false;
+               goto out;
+       }
+
+       if (vmci_guest_code_active())
+               vmci_vsock_transport_cb(false);
+
+       if (vmci_host_users() > 0) {
+               vmci_vsock_cb_host_called = true;
+               vmci_vsock_transport_cb(true);
+       }
+
+out:
+       mutex_unlock(&vmci_vsock_mutex);
+       return err;
+}
+EXPORT_SYMBOL_GPL(vmci_register_vsock_callback);
+
+void vmci_call_vsock_callback(bool is_host)
+{
+       mutex_lock(&vmci_vsock_mutex);
+
+       if (!vmci_vsock_transport_cb)
+               goto out;
+
+       /* In the host, this function could be called multiple times,
+        * but we want to register it only once.
+        */
+       if (is_host) {
+               if (vmci_vsock_cb_host_called)
+                       goto out;
+
+               vmci_vsock_cb_host_called = true;
+       }
+
+       vmci_vsock_transport_cb(is_host);
+out:
+       mutex_unlock(&vmci_vsock_mutex);
+}
+
 static int __init vmci_drv_init(void)
 {
        int vmci_err;
diff --git a/drivers/misc/vmw_vmci/vmci_driver.h 
b/drivers/misc/vmw_vmci/vmci_driver.h
index cee9e977d318..8bc7806f552e 100644
--- a/drivers/misc/vmw_vmci/vmci_driver.h
+++ b/drivers/misc/vmw_vmci/vmci_driver.h
@@ -44,10 +44,12 @@ extern struct pci_dev *vmci_pdev;
 
 u32 vmci_get_context_id(void);
 int vmci_send_datagram(struct vmci_datagram *dg);
+void vmci_call_vsock_callback(bool is_host);
 
 int vmci_host_init(void);
 void vmci_host_exit(void);
 bool vmci_host_code_active(void);
+int vmci_host_users(void);
 
 int vmci_guest_init(void);
 void vmci_guest_exit(void);
diff --git a/drivers/misc/vmw_vmci/vmci_guest.c 
b/drivers/misc/vmw_vmci/vmci_guest.c
index c2ea93778b50..7c8c2652d4cd 100644
--- a/drivers/misc/vmw_vmci/vmci_guest.c
+++ b/drivers/misc/vmw_vmci/vmci_guest.c
@@ -647,6 +647,8 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
                  vmci_dev->iobase + VMCI_CONTROL_ADDR);
 
        pci_set_drvdata(pdev, vmci_dev);
+
+       vmci_call_vsock_callback(false);
        return 0;
 
 err_free_irq:
diff --git a/drivers/misc/vmw_vmci/vmci_host.c 
b/drivers/misc/vmw_vmci/vmci_host.c
index a721b5d8a9da..dec56cf914db 100644
--- a/drivers/misc/vmw_vmci/vmci_host.c
+++ b/drivers/misc/vmw_vmci/vmci_host.c
@@ -116,6 +116,11 @@ bool vmci_host_code_active(void)
             atomic_read(&vmci_host_active_users) > 0);
 }
 
+int vmci_host_users(void)
+{
+       return atomic_read(&vmci_host_active_users);
+}
+
 /*
  * Called on open of /dev/vmci.
  */
@@ -346,6 +351,8 @@ static int vmci_host_do_init_context(struct vmci_host_dev 
*vmci_host_dev,
        vmci_host_dev->ct_type = VMCIOBJ_CONTEXT;
        atomic_inc(&vmci_host_active_users);
 
+       vmci_call_vsock_callback(true);
+
        retval = 0;
 
 out:
diff --git a/include/linux/vmw_vmci_api.h b/include/linux/vmw_vmci_api.h
index 023430e265fe..73df207e67e1 100644
--- a/include/linux/vmw_vmci_api.h
+++ b/include/linux/vmw_vmci_api.h
@@ -26,6 +26,7 @@
 
 typedef void (vmci_device_shutdown_fn) (void *device_registration,
                                        void *user_data);
+typedef void (*vmci_vsock_cb) (bool is_host);
 
 int vmci_datagram_create_handle(u32 resource_id, u32 flags,
                                vmci_datagram_recv_cb recv_cb,
@@ -44,6 +45,7 @@ int vmci_doorbell_destroy(struct vmci_handle handle);
 int vmci_doorbell_notify(struct vmci_handle handle, u32 priv_flags);
 u32 vmci_get_context_id(void);
 bool vmci_is_context_owner(u32 context_id, kuid_t uid);
+int vmci_register_vsock_callback(vmci_vsock_cb callback);
 
 int vmci_event_subscribe(u32 event,
                         vmci_event_cb callback, void *callback_data,
diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c
index 97055652038e..ff9741932abb 100644
--- a/net/vmw_vsock/vmci_transport.c
+++ b/net/vmw_vsock/vmci_transport.c
@@ -2033,19 +2033,21 @@ static bool vmci_check_transport(struct vsock_sock *vsk)
        return vsk->transport == &vmci_transport;
 }
 
-static int __init vmci_transport_init(void)
+void vmci_vsock_transport_cb(bool is_host)
 {
-       int features = VSOCK_TRANSPORT_F_DGRAM | VSOCK_TRANSPORT_F_H2G;
-       int cid;
-       int err;
+       int features;
 
-       cid = vmci_get_context_id();
+       if (is_host)
+               features = VSOCK_TRANSPORT_F_H2G;
+       else
+               features = VSOCK_TRANSPORT_F_G2H;
 
-       if (cid == VMCI_INVALID_ID)
-               return -EINVAL;
+       vsock_core_register(&vmci_transport, features);
+}
 
-       if (cid != VMCI_HOST_CONTEXT_ID)
-               features |= VSOCK_TRANSPORT_F_G2H;
+static int __init vmci_transport_init(void)
+{
+       int err;
 
        /* Create the datagram handle that we will use to send and receive all
         * VSocket control messages for this context.
@@ -2059,7 +2061,6 @@ static int __init vmci_transport_init(void)
                pr_err("Unable to create datagram handle. (%d)\n", err);
                return vmci_transport_error_to_vsock_error(err);
        }
-
        err = vmci_event_subscribe(VMCI_EVENT_QP_RESUMED,
                                   vmci_transport_qp_resumed_cb,
                                   NULL, &vmci_transport_qp_resumed_sub_id);
@@ -2070,12 +2071,21 @@ static int __init vmci_transport_init(void)
                goto err_destroy_stream_handle;
        }
 
-       err = vsock_core_register(&vmci_transport, features);
+       /* Register only with dgram feature, other features (H2G, G2H) will be
+        * registered when the first host or guest becomes active.
+        */
+       err = vsock_core_register(&vmci_transport, VSOCK_TRANSPORT_F_DGRAM);
        if (err < 0)
                goto err_unsubscribe;
 
+       err = vmci_register_vsock_callback(vmci_vsock_transport_cb);
+       if (err < 0)
+               goto err_unregister;
+
        return 0;
 
+err_unregister:
+       vsock_core_unregister(&vmci_transport);
 err_unsubscribe:
        vmci_event_unsubscribe(vmci_transport_qp_resumed_sub_id);
 err_destroy_stream_handle:
@@ -2101,6 +2111,7 @@ static void __exit vmci_transport_exit(void)
                vmci_transport_qp_resumed_sub_id = VMCI_INVALID_ID;
        }
 
+       vmci_register_vsock_callback(NULL);
        vsock_core_unregister(&vmci_transport);
 }
 module_exit(vmci_transport_exit);
-- 
2.24.3

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to