xref: /freebsd-src/sys/dev/vmware/vmci/vmci_resource.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
163a93856SMark Peek /*-
2*3eeb7511SMark Peek  * Copyright (c) 2018 VMware, Inc.
363a93856SMark Peek  *
48c302b2eSMark Peek  * SPDX-License-Identifier: (BSD-2-Clause OR GPL-2.0)
563a93856SMark Peek  */
663a93856SMark Peek 
763a93856SMark Peek /* Implementation of the VMCI Resource Access Control API. */
863a93856SMark Peek 
963a93856SMark Peek #include <sys/cdefs.h>
1063a93856SMark Peek #include "vmci_driver.h"
1163a93856SMark Peek #include "vmci_kernel_defs.h"
1263a93856SMark Peek #include "vmci_resource.h"
1363a93856SMark Peek 
1463a93856SMark Peek #define LGPFX	"vmci_resource: "
1563a93856SMark Peek 
1663a93856SMark Peek /* 0 through VMCI_RESERVED_RESOURCE_ID_MAX are reserved. */
1763a93856SMark Peek static uint32_t resource_id = VMCI_RESERVED_RESOURCE_ID_MAX + 1;
1863a93856SMark Peek static vmci_lock resource_id_lock;
1963a93856SMark Peek 
2063a93856SMark Peek static void	vmci_resource_do_remove(struct vmci_resource *resource);
2163a93856SMark Peek 
2263a93856SMark Peek static struct vmci_hashtable *resource_table = NULL;
2363a93856SMark Peek 
2463a93856SMark Peek /* Public Resource Access Control API. */
2563a93856SMark Peek 
2663a93856SMark Peek /*
2763a93856SMark Peek  *------------------------------------------------------------------------------
2863a93856SMark Peek  *
2963a93856SMark Peek  * vmci_resource_init --
3063a93856SMark Peek  *
3163a93856SMark Peek  *     Initializes the VMCI Resource Access Control API. Creates a hashtable to
3263a93856SMark Peek  *     hold all resources, and registers vectors and callbacks for hypercalls.
3363a93856SMark Peek  *
3463a93856SMark Peek  * Results:
3563a93856SMark Peek  *     None.
3663a93856SMark Peek  *
3763a93856SMark Peek  * Side effects:
3863a93856SMark Peek  *     None.
3963a93856SMark Peek  *
4063a93856SMark Peek  *------------------------------------------------------------------------------
4163a93856SMark Peek  */
4263a93856SMark Peek 
4363a93856SMark Peek int
vmci_resource_init(void)4463a93856SMark Peek vmci_resource_init(void)
4563a93856SMark Peek {
4663a93856SMark Peek 	int err;
4763a93856SMark Peek 
4863a93856SMark Peek 	err = vmci_init_lock(&resource_id_lock, "VMCI RID lock");
4963a93856SMark Peek 	if (err < VMCI_SUCCESS)
5063a93856SMark Peek 		return (err);
5163a93856SMark Peek 
5263a93856SMark Peek 	resource_table = vmci_hashtable_create(128);
5363a93856SMark Peek 	if (resource_table == NULL) {
5463a93856SMark Peek 		VMCI_LOG_WARNING((LGPFX"Failed creating a resource hash table "
5563a93856SMark Peek 		    "for VMCI.\n"));
5663a93856SMark Peek 		vmci_cleanup_lock(&resource_id_lock);
5763a93856SMark Peek 		return (VMCI_ERROR_NO_MEM);
5863a93856SMark Peek 	}
5963a93856SMark Peek 
6063a93856SMark Peek 	return (VMCI_SUCCESS);
6163a93856SMark Peek }
6263a93856SMark Peek 
6363a93856SMark Peek /*
6463a93856SMark Peek  *------------------------------------------------------------------------------
6563a93856SMark Peek  *
6663a93856SMark Peek  * vmci_resource_exit --
6763a93856SMark Peek  *
6863a93856SMark Peek  *      Cleans up resources.
6963a93856SMark Peek  *
7063a93856SMark Peek  * Results:
7163a93856SMark Peek  *      None.
7263a93856SMark Peek  *
7363a93856SMark Peek  * Side effects:
7463a93856SMark Peek  *      None.
7563a93856SMark Peek  *
7663a93856SMark Peek  *------------------------------------------------------------------------------
7763a93856SMark Peek  */
7863a93856SMark Peek 
7963a93856SMark Peek void
vmci_resource_exit(void)8063a93856SMark Peek vmci_resource_exit(void)
8163a93856SMark Peek {
8263a93856SMark Peek 
8363a93856SMark Peek 	/* Cleanup resources.*/
8463a93856SMark Peek 	vmci_cleanup_lock(&resource_id_lock);
8563a93856SMark Peek 
8663a93856SMark Peek 	if (resource_table)
8763a93856SMark Peek 		vmci_hashtable_destroy(resource_table);
8863a93856SMark Peek }
8963a93856SMark Peek 
9063a93856SMark Peek /*
9163a93856SMark Peek  *------------------------------------------------------------------------------
9263a93856SMark Peek  *
9363a93856SMark Peek  *  vmci_resource_get_id --
9463a93856SMark Peek  *
9563a93856SMark Peek  *      Return resource ID. The first VMCI_RESERVED_RESOURCE_ID_MAX are reserved
9663a93856SMark Peek  *      so we start from its value + 1.
9763a93856SMark Peek  *
9863a93856SMark Peek  *  Result:
9963a93856SMark Peek  *      VMCI resource id on success, VMCI_INVALID_ID on failure.
10063a93856SMark Peek  *
10163a93856SMark Peek  *  Side effects:
10263a93856SMark Peek  *      None.
10363a93856SMark Peek  *
10463a93856SMark Peek  *
10563a93856SMark Peek  *------------------------------------------------------------------------------
10663a93856SMark Peek  */
10763a93856SMark Peek 
10863a93856SMark Peek vmci_id
vmci_resource_get_id(vmci_id context_id)10963a93856SMark Peek vmci_resource_get_id(vmci_id context_id)
11063a93856SMark Peek {
11163a93856SMark Peek 	vmci_id current_rid;
11263a93856SMark Peek 	vmci_id old_rid;
11363a93856SMark Peek 	bool found_rid;
11463a93856SMark Peek 
11563a93856SMark Peek 	old_rid = resource_id;
11663a93856SMark Peek 	found_rid = false;
11763a93856SMark Peek 
11863a93856SMark Peek 	/*
11963a93856SMark Peek 	 * Generate a unique resource ID. Keep on trying until we wrap around
12063a93856SMark Peek 	 * in the RID space.
12163a93856SMark Peek 	 */
12263a93856SMark Peek 	ASSERT(old_rid > VMCI_RESERVED_RESOURCE_ID_MAX);
12363a93856SMark Peek 
12463a93856SMark Peek 	do {
12563a93856SMark Peek 		struct vmci_handle handle;
12663a93856SMark Peek 
12763a93856SMark Peek 		vmci_grab_lock(&resource_id_lock);
12863a93856SMark Peek 		current_rid = resource_id;
12963a93856SMark Peek 		handle = VMCI_MAKE_HANDLE(context_id, current_rid);
13063a93856SMark Peek 		resource_id++;
13163a93856SMark Peek 		if (UNLIKELY(resource_id == VMCI_INVALID_ID)) {
13263a93856SMark Peek 			/* Skip the reserved rids. */
13363a93856SMark Peek 			resource_id = VMCI_RESERVED_RESOURCE_ID_MAX + 1;
13463a93856SMark Peek 		}
13563a93856SMark Peek 		vmci_release_lock(&resource_id_lock);
13663a93856SMark Peek 		found_rid = !vmci_hashtable_entry_exists(resource_table,
13763a93856SMark Peek 		    handle);
13863a93856SMark Peek 	} while (!found_rid && resource_id != old_rid);
13963a93856SMark Peek 
14063a93856SMark Peek 	if (UNLIKELY(!found_rid))
14163a93856SMark Peek 		return (VMCI_INVALID_ID);
14263a93856SMark Peek 	else
14363a93856SMark Peek 		return (current_rid);
14463a93856SMark Peek }
14563a93856SMark Peek 
14663a93856SMark Peek /*
14763a93856SMark Peek  *------------------------------------------------------------------------------
14863a93856SMark Peek  *
14963a93856SMark Peek  * vmci_resource_add --
15063a93856SMark Peek  *
15163a93856SMark Peek  *     Add resource to hashtable.
15263a93856SMark Peek  *
15363a93856SMark Peek  * Results:
15463a93856SMark Peek  *     VMCI_SUCCESS if successful, error code if not.
15563a93856SMark Peek  *
15663a93856SMark Peek  * Side effects:
15763a93856SMark Peek  *     None.
15863a93856SMark Peek  *
15963a93856SMark Peek  *------------------------------------------------------------------------------
16063a93856SMark Peek  */
16163a93856SMark Peek 
16263a93856SMark Peek int
vmci_resource_add(struct vmci_resource * resource,vmci_resource_type resource_type,struct vmci_handle resource_handle,vmci_resource_free_cb container_free_cb,void * container_object)16363a93856SMark Peek vmci_resource_add(struct vmci_resource *resource,
16463a93856SMark Peek     vmci_resource_type resource_type, struct vmci_handle resource_handle,
16563a93856SMark Peek     vmci_resource_free_cb container_free_cb, void *container_object)
16663a93856SMark Peek {
16763a93856SMark Peek 	int result;
16863a93856SMark Peek 
16963a93856SMark Peek 	ASSERT(resource);
17063a93856SMark Peek 
17163a93856SMark Peek 	if (VMCI_HANDLE_EQUAL(resource_handle, VMCI_INVALID_HANDLE)) {
17263a93856SMark Peek 		VMCI_LOG_DEBUG(LGPFX"Invalid argument resource "
17363a93856SMark Peek 		    "(handle=0x%x:0x%x).\n", resource_handle.context,
17463a93856SMark Peek 		    resource_handle.resource);
17563a93856SMark Peek 		return (VMCI_ERROR_INVALID_ARGS);
17663a93856SMark Peek 	}
17763a93856SMark Peek 
17863a93856SMark Peek 	vmci_hashtable_init_entry(&resource->hash_entry, resource_handle);
17963a93856SMark Peek 	resource->type = resource_type;
18063a93856SMark Peek 	resource->container_free_cb = container_free_cb;
18163a93856SMark Peek 	resource->container_object = container_object;
18263a93856SMark Peek 
18363a93856SMark Peek 	/* Add resource to hashtable. */
18463a93856SMark Peek 	result = vmci_hashtable_add_entry(resource_table,
18563a93856SMark Peek 	    &resource->hash_entry);
18663a93856SMark Peek 	if (result != VMCI_SUCCESS) {
18763a93856SMark Peek 		VMCI_LOG_DEBUG(LGPFX"Failed to add entry to hash table "
18863a93856SMark Peek 		    "(result=%d).\n", result);
18963a93856SMark Peek 		return (result);
19063a93856SMark Peek 	}
19163a93856SMark Peek 
19263a93856SMark Peek 	return (result);
19363a93856SMark Peek }
19463a93856SMark Peek 
19563a93856SMark Peek /*
19663a93856SMark Peek  *------------------------------------------------------------------------------
19763a93856SMark Peek  *
19863a93856SMark Peek  * vmci_resource_remove --
19963a93856SMark Peek  *
20063a93856SMark Peek  *     Remove resource from hashtable.
20163a93856SMark Peek  *
20263a93856SMark Peek  * Results:
20363a93856SMark Peek  *     None.
20463a93856SMark Peek  *
20563a93856SMark Peek  * Side effects:
20663a93856SMark Peek  *     None.
20763a93856SMark Peek  *
20863a93856SMark Peek  *------------------------------------------------------------------------------
20963a93856SMark Peek  */
21063a93856SMark Peek 
21163a93856SMark Peek void
vmci_resource_remove(struct vmci_handle resource_handle,vmci_resource_type resource_type)21263a93856SMark Peek vmci_resource_remove(struct vmci_handle resource_handle,
21363a93856SMark Peek     vmci_resource_type resource_type)
21463a93856SMark Peek {
21563a93856SMark Peek 	struct vmci_resource *resource;
21663a93856SMark Peek 
21763a93856SMark Peek 	resource = vmci_resource_get(resource_handle, resource_type);
21863a93856SMark Peek 	if (resource == NULL)
21963a93856SMark Peek 		return;
22063a93856SMark Peek 
22163a93856SMark Peek 	/* Remove resource from hashtable. */
22263a93856SMark Peek 	vmci_hashtable_remove_entry(resource_table, &resource->hash_entry);
22363a93856SMark Peek 
22463a93856SMark Peek 	vmci_resource_release(resource);
22563a93856SMark Peek 	/* resource could be freed by now. */
22663a93856SMark Peek }
22763a93856SMark Peek 
22863a93856SMark Peek /*
22963a93856SMark Peek  *------------------------------------------------------------------------------
23063a93856SMark Peek  *
23163a93856SMark Peek  * vmci_resource_get --
23263a93856SMark Peek  *
23363a93856SMark Peek  *     Get resource from hashtable.
23463a93856SMark Peek  *
23563a93856SMark Peek  * Results:
23663a93856SMark Peek  *     Resource if successful. Otherwise NULL.
23763a93856SMark Peek  *
23863a93856SMark Peek  * Side effects:
23963a93856SMark Peek  *     None.
24063a93856SMark Peek  *
24163a93856SMark Peek  *------------------------------------------------------------------------------
24263a93856SMark Peek  */
24363a93856SMark Peek 
24463a93856SMark Peek struct vmci_resource *
vmci_resource_get(struct vmci_handle resource_handle,vmci_resource_type resource_type)24563a93856SMark Peek vmci_resource_get(struct vmci_handle resource_handle,
24663a93856SMark Peek     vmci_resource_type resource_type)
24763a93856SMark Peek {
24863a93856SMark Peek 	struct vmci_hash_entry *entry;
24963a93856SMark Peek 	struct vmci_resource *resource;
25063a93856SMark Peek 
25163a93856SMark Peek 	entry = vmci_hashtable_get_entry(resource_table, resource_handle);
25263a93856SMark Peek 	if (entry == NULL)
25363a93856SMark Peek 		return (NULL);
25463a93856SMark Peek 	resource = RESOURCE_CONTAINER(entry, struct vmci_resource, hash_entry);
25563a93856SMark Peek 	if (resource_type == VMCI_RESOURCE_TYPE_ANY ||
25663a93856SMark Peek 		resource->type == resource_type) {
25763a93856SMark Peek 		return (resource);
25863a93856SMark Peek 	}
25963a93856SMark Peek 	vmci_hashtable_release_entry(resource_table, entry);
26063a93856SMark Peek 	return (NULL);
26163a93856SMark Peek }
26263a93856SMark Peek 
26363a93856SMark Peek /*
26463a93856SMark Peek  *------------------------------------------------------------------------------
26563a93856SMark Peek  *
26663a93856SMark Peek  * vmci_resource_hold --
26763a93856SMark Peek  *
26863a93856SMark Peek  *     Hold the given resource. This will hold the hashtable entry. This is like
26963a93856SMark Peek  *     doing a Get() but without having to lookup the resource by handle.
27063a93856SMark Peek  *
27163a93856SMark Peek  * Results:
27263a93856SMark Peek  *     None.
27363a93856SMark Peek  *
27463a93856SMark Peek  * Side effects:
27563a93856SMark Peek  *     None.
27663a93856SMark Peek  *
27763a93856SMark Peek  *------------------------------------------------------------------------------
27863a93856SMark Peek  */
27963a93856SMark Peek 
28063a93856SMark Peek void
vmci_resource_hold(struct vmci_resource * resource)28163a93856SMark Peek vmci_resource_hold(struct vmci_resource *resource)
28263a93856SMark Peek {
28363a93856SMark Peek 
28463a93856SMark Peek 	ASSERT(resource);
28563a93856SMark Peek 	vmci_hashtable_hold_entry(resource_table, &resource->hash_entry);
28663a93856SMark Peek }
28763a93856SMark Peek 
28863a93856SMark Peek /*
28963a93856SMark Peek  *------------------------------------------------------------------------------
29063a93856SMark Peek  *
29163a93856SMark Peek  * vmci_resource_do_remove --
29263a93856SMark Peek  *
29363a93856SMark Peek  *     Deallocates data structures associated with the given resource and
29463a93856SMark Peek  *     invoke any call back registered for the resource.
29563a93856SMark Peek  *
29663a93856SMark Peek  * Results:
29763a93856SMark Peek  *     None.
29863a93856SMark Peek  *
29963a93856SMark Peek  * Side effects:
30063a93856SMark Peek  *     May deallocate memory and invoke a callback for the removed resource.
30163a93856SMark Peek  *
30263a93856SMark Peek  *------------------------------------------------------------------------------
30363a93856SMark Peek  */
30463a93856SMark Peek 
30563a93856SMark Peek static void inline
vmci_resource_do_remove(struct vmci_resource * resource)30663a93856SMark Peek vmci_resource_do_remove(struct vmci_resource *resource)
30763a93856SMark Peek {
30863a93856SMark Peek 
30963a93856SMark Peek 	ASSERT(resource);
31063a93856SMark Peek 
31163a93856SMark Peek 	if (resource->container_free_cb) {
31263a93856SMark Peek 		resource->container_free_cb(resource->container_object);
31363a93856SMark Peek 		/* Resource has been freed don't dereference it. */
31463a93856SMark Peek 	}
31563a93856SMark Peek }
31663a93856SMark Peek 
31763a93856SMark Peek /*
31863a93856SMark Peek  *------------------------------------------------------------------------------
31963a93856SMark Peek  *
32063a93856SMark Peek  * vmci_resource_release --
32163a93856SMark Peek  *
32263a93856SMark Peek  * Results:
32363a93856SMark Peek  *     None.
32463a93856SMark Peek  *
32563a93856SMark Peek  * Side effects:
32663a93856SMark Peek  *     Resource's containerFreeCB will get called if last reference.
32763a93856SMark Peek  *
32863a93856SMark Peek  *------------------------------------------------------------------------------
32963a93856SMark Peek  */
33063a93856SMark Peek 
33163a93856SMark Peek int
vmci_resource_release(struct vmci_resource * resource)33263a93856SMark Peek vmci_resource_release(struct vmci_resource *resource)
33363a93856SMark Peek {
33463a93856SMark Peek 	int result;
33563a93856SMark Peek 
33663a93856SMark Peek 	ASSERT(resource);
33763a93856SMark Peek 
33863a93856SMark Peek 	result = vmci_hashtable_release_entry(resource_table,
33963a93856SMark Peek 	    &resource->hash_entry);
34063a93856SMark Peek 	if (result == VMCI_SUCCESS_ENTRY_DEAD)
34163a93856SMark Peek 		vmci_resource_do_remove(resource);
34263a93856SMark Peek 
34363a93856SMark Peek 	/*
34463a93856SMark Peek 	 * We propagate the information back to caller in case it wants to know
34563a93856SMark Peek 	 * whether entry was freed.
34663a93856SMark Peek 	 */
34763a93856SMark Peek 	return (result);
34863a93856SMark Peek }
34963a93856SMark Peek 
35063a93856SMark Peek /*
35163a93856SMark Peek  *------------------------------------------------------------------------------
35263a93856SMark Peek  *
35363a93856SMark Peek  * vmci_resource_handle --
35463a93856SMark Peek  *
35563a93856SMark Peek  *     Get the handle for the given resource.
35663a93856SMark Peek  *
35763a93856SMark Peek  * Results:
35863a93856SMark Peek  *     The resource's associated handle.
35963a93856SMark Peek  *
36063a93856SMark Peek  * Side effects:
36163a93856SMark Peek  *     None.
36263a93856SMark Peek  *
36363a93856SMark Peek  *------------------------------------------------------------------------------
36463a93856SMark Peek  */
36563a93856SMark Peek 
36663a93856SMark Peek struct vmci_handle
vmci_resource_handle(struct vmci_resource * resource)36763a93856SMark Peek vmci_resource_handle(struct vmci_resource *resource)
36863a93856SMark Peek {
36963a93856SMark Peek 
37063a93856SMark Peek 	ASSERT(resource);
37163a93856SMark Peek 	return (resource->hash_entry.handle);
37263a93856SMark Peek }
37363a93856SMark Peek 
37463a93856SMark Peek /*
37563a93856SMark Peek  *------------------------------------------------------------------------------
37663a93856SMark Peek  *
37763a93856SMark Peek  * vmci_resource_sync --
37863a93856SMark Peek  *
37963a93856SMark Peek  *     Use this as a synchronization point when setting globals, for example,
38063a93856SMark Peek  *     during device shutdown.
38163a93856SMark Peek  *
38263a93856SMark Peek  * Results:
38363a93856SMark Peek  *     None.
38463a93856SMark Peek  *
38563a93856SMark Peek  * Side effects:
38663a93856SMark Peek  *     None.
38763a93856SMark Peek  *
38863a93856SMark Peek  *------------------------------------------------------------------------------
38963a93856SMark Peek  */
39063a93856SMark Peek 
39163a93856SMark Peek void
vmci_resource_sync(void)39263a93856SMark Peek vmci_resource_sync(void)
39363a93856SMark Peek {
39463a93856SMark Peek 
39563a93856SMark Peek 	vmci_hashtable_sync(resource_table);
39663a93856SMark Peek }
397