1 /* 2 * VMware VMCI Driver 3 * 4 * Copyright (C) 2012 VMware, Inc. All rights reserved. 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation version 2 and no later version. 9 * 10 * This program is distributed in the hope that it will be useful, but 11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * for more details. 14 */ 15 16 #include <linux/vmw_vmci_defs.h> 17 #include <linux/vmw_vmci_api.h> 18 #include <linux/list.h> 19 #include <linux/module.h> 20 #include <linux/sched.h> 21 #include <linux/slab.h> 22 23 #include "vmci_driver.h" 24 #include "vmci_event.h" 25 26 #define EVENT_MAGIC 0xEABE0000 27 #define VMCI_EVENT_MAX_ATTEMPTS 10 28 29 struct vmci_subscription { 30 u32 id; 31 u32 event; 32 vmci_event_cb callback; 33 void *callback_data; 34 struct list_head node; /* on one of subscriber lists */ 35 }; 36 37 static struct list_head subscriber_array[VMCI_EVENT_MAX]; 38 static DEFINE_MUTEX(subscriber_mutex); 39 40 int __init vmci_event_init(void) 41 { 42 int i; 43 44 for (i = 0; i < VMCI_EVENT_MAX; i++) 45 INIT_LIST_HEAD(&subscriber_array[i]); 46 47 return VMCI_SUCCESS; 48 } 49 50 void vmci_event_exit(void) 51 { 52 int e; 53 54 /* We free all memory at exit. */ 55 for (e = 0; e < VMCI_EVENT_MAX; e++) { 56 struct vmci_subscription *cur, *p2; 57 list_for_each_entry_safe(cur, p2, &subscriber_array[e], node) { 58 59 /* 60 * We should never get here because all events 61 * should have been unregistered before we try 62 * to unload the driver module. 63 */ 64 pr_warn("Unexpected free events occurring\n"); 65 list_del(&cur->node); 66 kfree(cur); 67 } 68 } 69 } 70 71 /* 72 * Find entry. Assumes subscriber_mutex is held. 73 */ 74 static struct vmci_subscription *event_find(u32 sub_id) 75 { 76 int e; 77 78 for (e = 0; e < VMCI_EVENT_MAX; e++) { 79 struct vmci_subscription *cur; 80 list_for_each_entry(cur, &subscriber_array[e], node) { 81 if (cur->id == sub_id) 82 return cur; 83 } 84 } 85 return NULL; 86 } 87 88 /* 89 * Actually delivers the events to the subscribers. 90 * The callback function for each subscriber is invoked. 91 */ 92 static void event_deliver(struct vmci_event_msg *event_msg) 93 { 94 struct vmci_subscription *cur; 95 struct list_head *subscriber_list; 96 97 rcu_read_lock(); 98 subscriber_list = &subscriber_array[event_msg->event_data.event]; 99 list_for_each_entry_rcu(cur, subscriber_list, node) { 100 cur->callback(cur->id, &event_msg->event_data, 101 cur->callback_data); 102 } 103 rcu_read_unlock(); 104 } 105 106 /* 107 * Dispatcher for the VMCI_EVENT_RECEIVE datagrams. Calls all 108 * subscribers for given event. 109 */ 110 int vmci_event_dispatch(struct vmci_datagram *msg) 111 { 112 struct vmci_event_msg *event_msg = (struct vmci_event_msg *)msg; 113 114 if (msg->payload_size < sizeof(u32) || 115 msg->payload_size > sizeof(struct vmci_event_data_max)) 116 return VMCI_ERROR_INVALID_ARGS; 117 118 if (!VMCI_EVENT_VALID(event_msg->event_data.event)) 119 return VMCI_ERROR_EVENT_UNKNOWN; 120 121 event_deliver(event_msg); 122 return VMCI_SUCCESS; 123 } 124 125 /* 126 * vmci_event_subscribe() - Subscribe to a given event. 127 * @event: The event to subscribe to. 128 * @callback: The callback to invoke upon the event. 129 * @callback_data: Data to pass to the callback. 130 * @subscription_id: ID used to track subscription. Used with 131 * vmci_event_unsubscribe() 132 * 133 * Subscribes to the provided event. The callback specified will be 134 * fired from RCU critical section and therefore must not sleep. 135 */ 136 int vmci_event_subscribe(u32 event, 137 vmci_event_cb callback, 138 void *callback_data, 139 u32 *new_subscription_id) 140 { 141 struct vmci_subscription *sub; 142 int attempts; 143 int retval; 144 bool have_new_id = false; 145 146 if (!new_subscription_id) { 147 pr_devel("%s: Invalid subscription (NULL)\n", __func__); 148 return VMCI_ERROR_INVALID_ARGS; 149 } 150 151 if (!VMCI_EVENT_VALID(event) || !callback) { 152 pr_devel("%s: Failed to subscribe to event (type=%d) (callback=%p) (data=%p)\n", 153 __func__, event, callback, callback_data); 154 return VMCI_ERROR_INVALID_ARGS; 155 } 156 157 sub = kzalloc(sizeof(*sub), GFP_KERNEL); 158 if (!sub) 159 return VMCI_ERROR_NO_MEM; 160 161 sub->id = VMCI_EVENT_MAX; 162 sub->event = event; 163 sub->callback = callback; 164 sub->callback_data = callback_data; 165 INIT_LIST_HEAD(&sub->node); 166 167 mutex_lock(&subscriber_mutex); 168 169 /* Creation of a new event is always allowed. */ 170 for (attempts = 0; attempts < VMCI_EVENT_MAX_ATTEMPTS; attempts++) { 171 static u32 subscription_id; 172 /* 173 * We try to get an id a couple of time before 174 * claiming we are out of resources. 175 */ 176 177 /* Test for duplicate id. */ 178 if (!event_find(++subscription_id)) { 179 sub->id = subscription_id; 180 have_new_id = true; 181 break; 182 } 183 } 184 185 if (have_new_id) { 186 list_add_rcu(&sub->node, &subscriber_array[event]); 187 retval = VMCI_SUCCESS; 188 } else { 189 retval = VMCI_ERROR_NO_RESOURCES; 190 } 191 192 mutex_unlock(&subscriber_mutex); 193 194 *new_subscription_id = sub->id; 195 return retval; 196 } 197 EXPORT_SYMBOL_GPL(vmci_event_subscribe); 198 199 /* 200 * vmci_event_unsubscribe() - unsubscribe from an event. 201 * @sub_id: A subscription ID as provided by vmci_event_subscribe() 202 * 203 * Unsubscribe from given event. Removes it from list and frees it. 204 * Will return callback_data if requested by caller. 205 */ 206 int vmci_event_unsubscribe(u32 sub_id) 207 { 208 struct vmci_subscription *s; 209 210 mutex_lock(&subscriber_mutex); 211 s = event_find(sub_id); 212 if (s) 213 list_del_rcu(&s->node); 214 mutex_unlock(&subscriber_mutex); 215 216 if (!s) 217 return VMCI_ERROR_NOT_FOUND; 218 219 synchronize_rcu(); 220 kfree(s); 221 222 return VMCI_SUCCESS; 223 } 224 EXPORT_SYMBOL_GPL(vmci_event_unsubscribe); 225