11d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang/* 21d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * VMware VMCI Driver 31d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * 41d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * Copyright (C) 2012 VMware, Inc. All rights reserved. 51d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * 61d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * This program is free software; you can redistribute it and/or modify it 71d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * under the terms of the GNU General Public License as published by the 81d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * Free Software Foundation version 2 and no later version. 91d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * 101d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * This program is distributed in the hope that it will be useful, but 111d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 121d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 131d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * for more details. 141d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang */ 151d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 161d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang#include <linux/vmw_vmci_defs.h> 171d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang#include <linux/vmw_vmci_api.h> 181d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang#include <linux/list.h> 191d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang#include <linux/module.h> 201d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang#include <linux/sched.h> 211d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang#include <linux/slab.h> 221d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 231d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang#include "vmci_driver.h" 241d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang#include "vmci_event.h" 251d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 261d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang#define EVENT_MAGIC 0xEABE0000 271d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang#define VMCI_EVENT_MAX_ATTEMPTS 10 281d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 291d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhangstruct vmci_subscription { 301d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang u32 id; 311d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang u32 event; 321d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang vmci_event_cb callback; 331d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang void *callback_data; 341d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang struct list_head node; /* on one of subscriber lists */ 351d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang}; 361d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 371d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhangstatic struct list_head subscriber_array[VMCI_EVENT_MAX]; 381d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhangstatic DEFINE_MUTEX(subscriber_mutex); 391d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 401d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhangint __init vmci_event_init(void) 411d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang{ 421d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang int i; 431d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 441d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang for (i = 0; i < VMCI_EVENT_MAX; i++) 451d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang INIT_LIST_HEAD(&subscriber_array[i]); 461d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 471d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang return VMCI_SUCCESS; 481d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang} 491d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 501d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhangvoid vmci_event_exit(void) 511d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang{ 521d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang int e; 531d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 541d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang /* We free all memory at exit. */ 551d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang for (e = 0; e < VMCI_EVENT_MAX; e++) { 561d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang struct vmci_subscription *cur, *p2; 571d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang list_for_each_entry_safe(cur, p2, &subscriber_array[e], node) { 581d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 591d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang /* 601d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * We should never get here because all events 611d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * should have been unregistered before we try 621d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * to unload the driver module. 631d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang */ 641d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang pr_warn("Unexpected free events occurring\n"); 651d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang list_del(&cur->node); 661d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang kfree(cur); 671d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang } 681d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang } 691d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang} 701d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 711d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang/* 721d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * Find entry. Assumes subscriber_mutex is held. 731d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang */ 741d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhangstatic struct vmci_subscription *event_find(u32 sub_id) 751d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang{ 761d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang int e; 771d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 781d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang for (e = 0; e < VMCI_EVENT_MAX; e++) { 791d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang struct vmci_subscription *cur; 801d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang list_for_each_entry(cur, &subscriber_array[e], node) { 811d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang if (cur->id == sub_id) 821d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang return cur; 831d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang } 841d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang } 851d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang return NULL; 861d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang} 871d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 881d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang/* 891d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * Actually delivers the events to the subscribers. 901d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * The callback function for each subscriber is invoked. 911d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang */ 921d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhangstatic void event_deliver(struct vmci_event_msg *event_msg) 931d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang{ 941d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang struct vmci_subscription *cur; 951d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang struct list_head *subscriber_list; 961d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 971d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang rcu_read_lock(); 981d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang subscriber_list = &subscriber_array[event_msg->event_data.event]; 991d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang list_for_each_entry_rcu(cur, subscriber_list, node) { 1001d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang cur->callback(cur->id, &event_msg->event_data, 1011d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang cur->callback_data); 1021d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang } 1031d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang rcu_read_unlock(); 1041d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang} 1051d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 1061d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang/* 1071d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * Dispatcher for the VMCI_EVENT_RECEIVE datagrams. Calls all 1081d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * subscribers for given event. 1091d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang */ 1101d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhangint vmci_event_dispatch(struct vmci_datagram *msg) 1111d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang{ 1121d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang struct vmci_event_msg *event_msg = (struct vmci_event_msg *)msg; 1131d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 1141d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang if (msg->payload_size < sizeof(u32) || 1151d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang msg->payload_size > sizeof(struct vmci_event_data_max)) 1161d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang return VMCI_ERROR_INVALID_ARGS; 1171d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 1181d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang if (!VMCI_EVENT_VALID(event_msg->event_data.event)) 1191d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang return VMCI_ERROR_EVENT_UNKNOWN; 1201d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 1211d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang event_deliver(event_msg); 1221d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang return VMCI_SUCCESS; 1231d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang} 1241d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 1251d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang/* 1261d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * vmci_event_subscribe() - Subscribe to a given event. 1271d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * @event: The event to subscribe to. 1281d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * @callback: The callback to invoke upon the event. 1291d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * @callback_data: Data to pass to the callback. 1301d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * @subscription_id: ID used to track subscription. Used with 1311d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * vmci_event_unsubscribe() 1321d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * 1331d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * Subscribes to the provided event. The callback specified will be 1341d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * fired from RCU critical section and therefore must not sleep. 1351d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang */ 1361d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhangint vmci_event_subscribe(u32 event, 1371d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang vmci_event_cb callback, 1381d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang void *callback_data, 1391d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang u32 *new_subscription_id) 1401d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang{ 1411d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang struct vmci_subscription *sub; 1421d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang int attempts; 1431d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang int retval; 1441d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang bool have_new_id = false; 1451d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 1461d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang if (!new_subscription_id) { 1471d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang pr_devel("%s: Invalid subscription (NULL)\n", __func__); 1481d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang return VMCI_ERROR_INVALID_ARGS; 1491d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang } 1501d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 1511d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang if (!VMCI_EVENT_VALID(event) || !callback) { 1521d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang pr_devel("%s: Failed to subscribe to event (type=%d) (callback=%p) (data=%p)\n", 1531d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang __func__, event, callback, callback_data); 1541d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang return VMCI_ERROR_INVALID_ARGS; 1551d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang } 1561d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 1571d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang sub = kzalloc(sizeof(*sub), GFP_KERNEL); 1581d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang if (!sub) 1591d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang return VMCI_ERROR_NO_MEM; 1601d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 1611d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang sub->id = VMCI_EVENT_MAX; 1621d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang sub->event = event; 1631d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang sub->callback = callback; 1641d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang sub->callback_data = callback_data; 1651d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang INIT_LIST_HEAD(&sub->node); 1661d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 1671d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang mutex_lock(&subscriber_mutex); 1681d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 1691d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang /* Creation of a new event is always allowed. */ 1701d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang for (attempts = 0; attempts < VMCI_EVENT_MAX_ATTEMPTS; attempts++) { 1711d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang static u32 subscription_id; 1721d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang /* 1731d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * We try to get an id a couple of time before 1741d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * claiming we are out of resources. 1751d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang */ 1761d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 1771d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang /* Test for duplicate id. */ 1781d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang if (!event_find(++subscription_id)) { 1791d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang sub->id = subscription_id; 1801d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang have_new_id = true; 1811d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang break; 1821d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang } 1831d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang } 1841d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 1851d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang if (have_new_id) { 1861d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang list_add_rcu(&sub->node, &subscriber_array[event]); 1871d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang retval = VMCI_SUCCESS; 1881d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang } else { 1891d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang retval = VMCI_ERROR_NO_RESOURCES; 1901d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang } 1911d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 1921d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang mutex_unlock(&subscriber_mutex); 1931d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 1941d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang *new_subscription_id = sub->id; 1951d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang return retval; 1961d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang} 1971d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge ZhangEXPORT_SYMBOL_GPL(vmci_event_subscribe); 1981d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 1991d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang/* 2001d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * vmci_event_unsubscribe() - unsubscribe from an event. 2011d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * @sub_id: A subscription ID as provided by vmci_event_subscribe() 2021d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * 2031d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * Unsubscribe from given event. Removes it from list and frees it. 2041d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang * Will return callback_data if requested by caller. 2051d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang */ 2061d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhangint vmci_event_unsubscribe(u32 sub_id) 2071d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang{ 2081d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang struct vmci_subscription *s; 2091d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 2101d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang mutex_lock(&subscriber_mutex); 2111d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang s = event_find(sub_id); 2121d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang if (s) 2131d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang list_del_rcu(&s->node); 2141d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang mutex_unlock(&subscriber_mutex); 2151d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 2161d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang if (!s) 2171d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang return VMCI_ERROR_NOT_FOUND; 2181d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 2191d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang synchronize_rcu(); 2201d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang kfree(s); 2211d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang 2221d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang return VMCI_SUCCESS; 2231d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge Zhang} 2241d990201f9bb499b7c76ab00abeb7e803c0bcb2aGeorge ZhangEXPORT_SYMBOL_GPL(vmci_event_unsubscribe); 225