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

vsock/vmci: register vmci_transport only when VMCI guest/host are active

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 <jhansen@vmware.com>
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Stefano Garzarella and committed by
David S. Miller
b1bba80a c0cfa2d8

+103 -12
+67
drivers/misc/vmw_vmci/vmci_driver.c
··· 28 28 static bool vmci_guest_personality_initialized; 29 29 static bool vmci_host_personality_initialized; 30 30 31 + static DEFINE_MUTEX(vmci_vsock_mutex); /* protects vmci_vsock_transport_cb */ 32 + static vmci_vsock_cb vmci_vsock_transport_cb; 33 + bool vmci_vsock_cb_host_called; 34 + 31 35 /* 32 36 * vmci_get_context_id() - Gets the current context ID. 33 37 * ··· 48 44 return VMCI_INVALID_ID; 49 45 } 50 46 EXPORT_SYMBOL_GPL(vmci_get_context_id); 47 + 48 + /* 49 + * vmci_register_vsock_callback() - Register the VSOCK vmci_transport callback. 50 + * 51 + * The callback will be called when the first host or guest becomes active, 52 + * or if they are already active when this function is called. 53 + * To unregister the callback, call this function with NULL parameter. 54 + * 55 + * Returns 0 on success. -EBUSY if a callback is already registered. 56 + */ 57 + int vmci_register_vsock_callback(vmci_vsock_cb callback) 58 + { 59 + int err = 0; 60 + 61 + mutex_lock(&vmci_vsock_mutex); 62 + 63 + if (vmci_vsock_transport_cb && callback) { 64 + err = -EBUSY; 65 + goto out; 66 + } 67 + 68 + vmci_vsock_transport_cb = callback; 69 + 70 + if (!vmci_vsock_transport_cb) { 71 + vmci_vsock_cb_host_called = false; 72 + goto out; 73 + } 74 + 75 + if (vmci_guest_code_active()) 76 + vmci_vsock_transport_cb(false); 77 + 78 + if (vmci_host_users() > 0) { 79 + vmci_vsock_cb_host_called = true; 80 + vmci_vsock_transport_cb(true); 81 + } 82 + 83 + out: 84 + mutex_unlock(&vmci_vsock_mutex); 85 + return err; 86 + } 87 + EXPORT_SYMBOL_GPL(vmci_register_vsock_callback); 88 + 89 + void vmci_call_vsock_callback(bool is_host) 90 + { 91 + mutex_lock(&vmci_vsock_mutex); 92 + 93 + if (!vmci_vsock_transport_cb) 94 + goto out; 95 + 96 + /* In the host, this function could be called multiple times, 97 + * but we want to register it only once. 98 + */ 99 + if (is_host) { 100 + if (vmci_vsock_cb_host_called) 101 + goto out; 102 + 103 + vmci_vsock_cb_host_called = true; 104 + } 105 + 106 + vmci_vsock_transport_cb(is_host); 107 + out: 108 + mutex_unlock(&vmci_vsock_mutex); 109 + } 51 110 52 111 static int __init vmci_drv_init(void) 53 112 {
+2
drivers/misc/vmw_vmci/vmci_driver.h
··· 36 36 37 37 u32 vmci_get_context_id(void); 38 38 int vmci_send_datagram(struct vmci_datagram *dg); 39 + void vmci_call_vsock_callback(bool is_host); 39 40 40 41 int vmci_host_init(void); 41 42 void vmci_host_exit(void); 42 43 bool vmci_host_code_active(void); 44 + int vmci_host_users(void); 43 45 44 46 int vmci_guest_init(void); 45 47 void vmci_guest_exit(void);
+2
drivers/misc/vmw_vmci/vmci_guest.c
··· 637 637 vmci_dev->iobase + VMCI_CONTROL_ADDR); 638 638 639 639 pci_set_drvdata(pdev, vmci_dev); 640 + 641 + vmci_call_vsock_callback(false); 640 642 return 0; 641 643 642 644 err_free_irq:
+7
drivers/misc/vmw_vmci/vmci_host.c
··· 108 108 atomic_read(&vmci_host_active_users) > 0); 109 109 } 110 110 111 + int vmci_host_users(void) 112 + { 113 + return atomic_read(&vmci_host_active_users); 114 + } 115 + 111 116 /* 112 117 * Called on open of /dev/vmci. 113 118 */ ··· 342 337 343 338 vmci_host_dev->ct_type = VMCIOBJ_CONTEXT; 344 339 atomic_inc(&vmci_host_active_users); 340 + 341 + vmci_call_vsock_callback(true); 345 342 346 343 retval = 0; 347 344
+2
include/linux/vmw_vmci_api.h
··· 19 19 struct msghdr; 20 20 typedef void (vmci_device_shutdown_fn) (void *device_registration, 21 21 void *user_data); 22 + typedef void (*vmci_vsock_cb) (bool is_host); 22 23 23 24 int vmci_datagram_create_handle(u32 resource_id, u32 flags, 24 25 vmci_datagram_recv_cb recv_cb, ··· 38 37 int vmci_doorbell_notify(struct vmci_handle handle, u32 priv_flags); 39 38 u32 vmci_get_context_id(void); 40 39 bool vmci_is_context_owner(u32 context_id, kuid_t uid); 40 + int vmci_register_vsock_callback(vmci_vsock_cb callback); 41 41 42 42 int vmci_event_subscribe(u32 event, 43 43 vmci_event_cb callback, void *callback_data,
+23 -12
net/vmw_vsock/vmci_transport.c
··· 2054 2054 return vsk->transport == &vmci_transport; 2055 2055 } 2056 2056 2057 + void vmci_vsock_transport_cb(bool is_host) 2058 + { 2059 + int features; 2060 + 2061 + if (is_host) 2062 + features = VSOCK_TRANSPORT_F_H2G; 2063 + else 2064 + features = VSOCK_TRANSPORT_F_G2H; 2065 + 2066 + vsock_core_register(&vmci_transport, features); 2067 + } 2068 + 2057 2069 static int __init vmci_transport_init(void) 2058 2070 { 2059 - int features = VSOCK_TRANSPORT_F_DGRAM | VSOCK_TRANSPORT_F_H2G; 2060 - int cid; 2061 2071 int err; 2062 - 2063 - cid = vmci_get_context_id(); 2064 - 2065 - if (cid == VMCI_INVALID_ID) 2066 - return -EINVAL; 2067 - 2068 - if (cid != VMCI_HOST_CONTEXT_ID) 2069 - features |= VSOCK_TRANSPORT_F_G2H; 2070 2072 2071 2073 /* Create the datagram handle that we will use to send and receive all 2072 2074 * VSocket control messages for this context. ··· 2082 2080 pr_err("Unable to create datagram handle. (%d)\n", err); 2083 2081 return vmci_transport_error_to_vsock_error(err); 2084 2082 } 2085 - 2086 2083 err = vmci_event_subscribe(VMCI_EVENT_QP_RESUMED, 2087 2084 vmci_transport_qp_resumed_cb, 2088 2085 NULL, &vmci_transport_qp_resumed_sub_id); ··· 2092 2091 goto err_destroy_stream_handle; 2093 2092 } 2094 2093 2095 - err = vsock_core_register(&vmci_transport, features); 2094 + /* Register only with dgram feature, other features (H2G, G2H) will be 2095 + * registered when the first host or guest becomes active. 2096 + */ 2097 + err = vsock_core_register(&vmci_transport, VSOCK_TRANSPORT_F_DGRAM); 2096 2098 if (err < 0) 2097 2099 goto err_unsubscribe; 2098 2100 2101 + err = vmci_register_vsock_callback(vmci_vsock_transport_cb); 2102 + if (err < 0) 2103 + goto err_unregister; 2104 + 2099 2105 return 0; 2100 2106 2107 + err_unregister: 2108 + vsock_core_unregister(&vmci_transport); 2101 2109 err_unsubscribe: 2102 2110 vmci_event_unsubscribe(vmci_transport_qp_resumed_sub_id); 2103 2111 err_destroy_stream_handle: ··· 2132 2122 vmci_transport_qp_resumed_sub_id = VMCI_INVALID_ID; 2133 2123 } 2134 2124 2125 + vmci_register_vsock_callback(NULL); 2135 2126 vsock_core_unregister(&vmci_transport); 2136 2127 } 2137 2128 module_exit(vmci_transport_exit);