1
/*********************************************************
2
* Copyright (C) 2006 VMware, Inc. All rights reserved.
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms of the GNU General Public License as published by the
6
* Free Software Foundation version 2 and no later version.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13
* You should have received a copy of the GNU General Public License along
14
* with this program; if not, write to the Free Software Foundation, Inc.,
15
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
*********************************************************/
22
* Implementation of the VMCI Resource Access Control API.
25
#include "vmci_kernel_if.h"
26
#include "vm_assert.h"
27
#include "vmci_defs.h"
28
#include "vmci_infrastructure.h"
29
#include "vmciCommonInt.h"
30
#include "vmciHashtable.h"
31
#include "vmciResource.h"
33
# include "vmciVmkInt.h"
35
# include "helper_ext.h"
36
# include "vmciDriver.h"
38
# include "vmciDriver.h"
41
#define LGPFX "VMCIResource: "
43
/* 0 through VMCI_RESERVED_RESOURCE_ID_MAX are reserved. */
44
static uint32 resourceID = VMCI_RESERVED_RESOURCE_ID_MAX + 1;
45
static VMCILock resourceIdLock;
47
static void VMCIResourceDoRemove(VMCIResource *resource);
49
static VMCIHashTable *resourceTable = NULL;
52
/* Public Resource Access Control API. */
55
*------------------------------------------------------------------------------
57
* VMCIResource_Init --
59
* Initializes the VMCI Resource Access Control API. Creates a hashtable
60
* to hold all resources, and registers vectors and callbacks for
69
*------------------------------------------------------------------------------
73
VMCIResource_Init(void)
75
resourceTable = VMCIHashTable_Create(128);
76
if (resourceTable == NULL) {
77
VMCI_WARNING((LGPFX"Failed creating a resource hash table for VMCI.\n"));
78
return VMCI_ERROR_NO_MEM;
81
VMCI_InitLock(&resourceIdLock, "VMCIRIDLock", VMCI_LOCK_RANK_HIGHEST);
88
*------------------------------------------------------------------------------
90
* VMCIResource_Exit --
92
* Cleans up resources.
100
*------------------------------------------------------------------------------
104
VMCIResource_Exit(void)
106
/* Cleanup resources.*/
107
VMCI_CleanupLock(&resourceIdLock);
110
VMCIHashTable_Destroy(resourceTable);
116
*------------------------------------------------------------------------------
118
* VMCIResource_GetID --
120
* Return resource ID. The first VMCI_RESERVED_RESOURCE_ID_MAX are
121
* reserved so we start from its value + 1.
124
* VMCI resource id on success, VMCI_INVALID_ID on failure.
130
*------------------------------------------------------------------------------
134
VMCIResource_GetID(VMCIId contextID)
136
VMCIId oldRID = resourceID;
138
Bool foundRID = FALSE;
141
* Generate a unique resource ID. Keep on trying until we wrap around
144
ASSERT(oldRID > VMCI_RESERVED_RESOURCE_ID_MAX);
150
VMCI_GrabLock(&resourceIdLock, &flags);
151
currentRID = resourceID;
152
handle = VMCI_MAKE_HANDLE(contextID, currentRID);
154
if (UNLIKELY(resourceID == VMCI_INVALID_ID)) {
156
* Skip the reserved rids.
159
resourceID = VMCI_RESERVED_RESOURCE_ID_MAX + 1;
161
VMCI_ReleaseLock(&resourceIdLock, flags);
162
foundRID = !VMCIHashTable_EntryExists(resourceTable, handle);
163
} while (!foundRID && resourceID != oldRID);
165
if (UNLIKELY(!foundRID)) {
166
return VMCI_INVALID_ID;
174
*------------------------------------------------------------------------------
176
* VMCIResource_Add --
179
* VMCI_SUCCESS if successful, error code if not.
184
*------------------------------------------------------------------------------
188
VMCIResource_Add(VMCIResource *resource, // IN
189
VMCIResourceType resourceType, // IN
190
VMCIHandle resourceHandle, // IN
191
VMCIResourceFreeCB containerFreeCB, // IN
192
void *containerObject) // IN
198
if (VMCI_HANDLE_EQUAL(resourceHandle, VMCI_INVALID_HANDLE)) {
199
VMCI_DEBUG_LOG(4, (LGPFX"Invalid argument resource (handle=0x%x:0x%x).\n",
200
resourceHandle.context, resourceHandle.resource));
201
return VMCI_ERROR_INVALID_ARGS;
204
VMCIHashTable_InitEntry(&resource->hashEntry, resourceHandle);
205
resource->type = resourceType;
206
resource->containerFreeCB = containerFreeCB;
207
resource->containerObject = containerObject;
208
resource->handle = resourceHandle;
210
/* Add resource to hashtable. */
211
result = VMCIHashTable_AddEntry(resourceTable, &resource->hashEntry);
212
if (result != VMCI_SUCCESS) {
213
VMCI_DEBUG_LOG(4, (LGPFX"Failed to add entry to hash table "
214
"(result=%d).\n", result));
223
*------------------------------------------------------------------------------
225
* VMCIResource_Remove --
233
*------------------------------------------------------------------------------
237
VMCIResource_Remove(VMCIHandle resourceHandle, // IN:
238
VMCIResourceType resourceType) // IN:
240
VMCIResource *resource = VMCIResource_Get(resourceHandle, resourceType);
241
if (resource == NULL) {
245
/* Remove resource from hashtable. */
246
VMCIHashTable_RemoveEntry(resourceTable, &resource->hashEntry);
248
VMCIResource_Release(resource);
249
/* resource could be freed by now. */
254
*------------------------------------------------------------------------------
256
* VMCIResource_Get --
259
* Resource is successful. Otherwise NULL.
264
*------------------------------------------------------------------------------
268
VMCIResource_Get(VMCIHandle resourceHandle, // IN
269
VMCIResourceType resourceType) // IN
271
VMCIResource *resource;
272
VMCIHashEntry *entry = VMCIHashTable_GetEntry(resourceTable, resourceHandle);
276
resource = RESOURCE_CONTAINER(entry, VMCIResource, hashEntry);
277
if (resourceType == VMCI_RESOURCE_TYPE_ANY ||
278
resource->type == resourceType) {
281
VMCIHashTable_ReleaseEntry(resourceTable, entry);
287
*------------------------------------------------------------------------------
289
* VMCIResource_Hold --
291
* Hold the given resource. This will hold the hashtable entry. This
292
* is like doing a Get() but without having to lookup the resource by
301
*------------------------------------------------------------------------------
305
VMCIResource_Hold(VMCIResource *resource)
308
VMCIHashTable_HoldEntry(resourceTable, &resource->hashEntry);
313
*------------------------------------------------------------------------------
315
* VMCIResourceDoRemove --
317
* Deallocates data structures associated with the given resource
318
* and invoke any call back registered for the resource.
324
* May deallocate memory and invoke a callback for the removed resource.
326
*------------------------------------------------------------------------------
330
VMCIResourceDoRemove(VMCIResource *resource)
334
if (resource->containerFreeCB) {
335
resource->containerFreeCB(resource->containerObject);
336
/* Resource has been freed don't dereference it. */
342
*------------------------------------------------------------------------------
344
* VMCIResource_Release --
350
* resource's containerFreeCB will get called if last reference.
352
*------------------------------------------------------------------------------
356
VMCIResource_Release(VMCIResource *resource)
362
result = VMCIHashTable_ReleaseEntry(resourceTable, &resource->hashEntry);
363
if (result == VMCI_SUCCESS_ENTRY_DEAD) {
364
VMCIResourceDoRemove(resource);
368
* We propagate the information back to caller in case it wants to know
369
* whether entry was freed.
376
*------------------------------------------------------------------------------
378
* VMCIResource_Sync --
380
* Use this as a synchronization point when setting globals, for example,
381
* during device shutdown.
389
*------------------------------------------------------------------------------
393
VMCIResource_Sync(void)
395
VMCIHashTable_Sync(resourceTable);