xref: /freebsd/sys/dev/vmware/vmci/vmci_hashtable.c (revision 8c302b2e8685a9887a4be126b2ff32c41fbce1e1)
163a93856SMark Peek /*-
263a93856SMark Peek  * Copyright (c) 2018 VMware, Inc. All Rights Reserved.
363a93856SMark Peek  *
4*8c302b2eSMark Peek  * SPDX-License-Identifier: (BSD-2-Clause OR GPL-2.0)
563a93856SMark Peek  */
663a93856SMark Peek 
763a93856SMark Peek /* Implementation of the VMCI Hashtable. */
863a93856SMark Peek 
963a93856SMark Peek #include <sys/cdefs.h>
1063a93856SMark Peek __FBSDID("$FreeBSD$");
1163a93856SMark Peek 
1263a93856SMark Peek #include "vmci.h"
1363a93856SMark Peek #include "vmci_driver.h"
1463a93856SMark Peek #include "vmci_hashtable.h"
1563a93856SMark Peek #include "vmci_kernel_defs.h"
1663a93856SMark Peek #include "vmci_utils.h"
1763a93856SMark Peek 
1863a93856SMark Peek #define LGPFX	"vmci_hashtable: "
1963a93856SMark Peek 
2063a93856SMark Peek #define VMCI_HASHTABLE_HASH(_h, _sz)					\
2163a93856SMark Peek 	vmci_hash_id(VMCI_HANDLE_TO_RESOURCE_ID(_h), (_sz))
2263a93856SMark Peek 
2363a93856SMark Peek static int	hashtable_unlink_entry(struct vmci_hashtable *table,
2463a93856SMark Peek 		    struct vmci_hash_entry *entry);
2563a93856SMark Peek static bool	vmci_hashtable_entry_exists_locked(struct vmci_hashtable *table,
2663a93856SMark Peek 		    struct vmci_handle handle);
2763a93856SMark Peek 
2863a93856SMark Peek /*
2963a93856SMark Peek  *------------------------------------------------------------------------------
3063a93856SMark Peek  *
3163a93856SMark Peek  * vmci_hashtable_create --
3263a93856SMark Peek  *
3363a93856SMark Peek  *     Creates a hashtable.
3463a93856SMark Peek  *
3563a93856SMark Peek  * Result:
3663a93856SMark Peek  *     None.
3763a93856SMark Peek  *
3863a93856SMark Peek  * Side effects:
3963a93856SMark Peek  *     None.
4063a93856SMark Peek  *
4163a93856SMark Peek  *------------------------------------------------------------------------------
4263a93856SMark Peek  */
4363a93856SMark Peek 
4463a93856SMark Peek struct vmci_hashtable *
4563a93856SMark Peek vmci_hashtable_create(int size)
4663a93856SMark Peek {
4763a93856SMark Peek 	struct vmci_hashtable *table;
4863a93856SMark Peek 
4963a93856SMark Peek 	table = vmci_alloc_kernel_mem(sizeof(*table),
5063a93856SMark Peek 	    VMCI_MEMORY_NORMAL);
5163a93856SMark Peek 	if (table == NULL)
5263a93856SMark Peek 		return (NULL);
5363a93856SMark Peek 	memset(table, 0, sizeof(*table));
5463a93856SMark Peek 
5563a93856SMark Peek 	table->entries = vmci_alloc_kernel_mem(sizeof(*table->entries) * size,
5663a93856SMark Peek 	    VMCI_MEMORY_NORMAL);
5763a93856SMark Peek 	if (table->entries == NULL) {
5863a93856SMark Peek 		vmci_free_kernel_mem(table, sizeof(*table));
5963a93856SMark Peek 		return (NULL);
6063a93856SMark Peek 	}
6163a93856SMark Peek 	memset(table->entries, 0, sizeof(*table->entries) * size);
6263a93856SMark Peek 	table->size = size;
6363a93856SMark Peek 	if (vmci_init_lock(&table->lock, "VMCI Hashtable lock") <
6463a93856SMark Peek 	    VMCI_SUCCESS) {
6563a93856SMark Peek 		vmci_free_kernel_mem(table->entries, sizeof(*table->entries) * size);
6663a93856SMark Peek 		vmci_free_kernel_mem(table, sizeof(*table));
6763a93856SMark Peek 		return (NULL);
6863a93856SMark Peek 	}
6963a93856SMark Peek 
7063a93856SMark Peek 	return (table);
7163a93856SMark Peek }
7263a93856SMark Peek 
7363a93856SMark Peek /*
7463a93856SMark Peek  *------------------------------------------------------------------------------
7563a93856SMark Peek  *
7663a93856SMark Peek  * vmci_hashtable_destroy --
7763a93856SMark Peek  *
7863a93856SMark Peek  *     This function should be called at module exit time. We rely on the
7963a93856SMark Peek  *     module ref count to insure that no one is accessing any hash table
8063a93856SMark Peek  *     entries at this point in time. Hence we should be able to just remove
8163a93856SMark Peek  *     all entries from the hash table.
8263a93856SMark Peek  *
8363a93856SMark Peek  * Result:
8463a93856SMark Peek  *     None.
8563a93856SMark Peek  *
8663a93856SMark Peek  * Side effects:
8763a93856SMark Peek  *     None.
8863a93856SMark Peek  *
8963a93856SMark Peek  *------------------------------------------------------------------------------
9063a93856SMark Peek  */
9163a93856SMark Peek 
9263a93856SMark Peek void
9363a93856SMark Peek vmci_hashtable_destroy(struct vmci_hashtable *table)
9463a93856SMark Peek {
9563a93856SMark Peek 
9663a93856SMark Peek 	ASSERT(table);
9763a93856SMark Peek 
9863a93856SMark Peek 	vmci_grab_lock_bh(&table->lock);
9963a93856SMark Peek 	vmci_free_kernel_mem(table->entries, sizeof(*table->entries) *
10063a93856SMark Peek 	    table->size);
10163a93856SMark Peek 	table->entries = NULL;
10263a93856SMark Peek 	vmci_release_lock_bh(&table->lock);
10363a93856SMark Peek 	vmci_cleanup_lock(&table->lock);
10463a93856SMark Peek 	vmci_free_kernel_mem(table, sizeof(*table));
10563a93856SMark Peek }
10663a93856SMark Peek 
10763a93856SMark Peek /*
10863a93856SMark Peek  *------------------------------------------------------------------------------
10963a93856SMark Peek  *
11063a93856SMark Peek  * vmci_hashtable_init_entry --
11163a93856SMark Peek  *
11263a93856SMark Peek  *     Initializes a hash entry.
11363a93856SMark Peek  *
11463a93856SMark Peek  * Result:
11563a93856SMark Peek  *     None.
11663a93856SMark Peek  *
11763a93856SMark Peek  * Side effects:
11863a93856SMark Peek  *     None.
11963a93856SMark Peek  *
12063a93856SMark Peek  *------------------------------------------------------------------------------
12163a93856SMark Peek  */
12263a93856SMark Peek void
12363a93856SMark Peek vmci_hashtable_init_entry(struct vmci_hash_entry *entry,
12463a93856SMark Peek     struct vmci_handle handle)
12563a93856SMark Peek {
12663a93856SMark Peek 
12763a93856SMark Peek 	ASSERT(entry);
12863a93856SMark Peek 	entry->handle = handle;
12963a93856SMark Peek 	entry->ref_count = 0;
13063a93856SMark Peek }
13163a93856SMark Peek 
13263a93856SMark Peek /*
13363a93856SMark Peek  *------------------------------------------------------------------------------
13463a93856SMark Peek  *
13563a93856SMark Peek  * vmci_hashtable_add_entry --
13663a93856SMark Peek  *
13763a93856SMark Peek  *     Adds an entry to the hashtable.
13863a93856SMark Peek  *
13963a93856SMark Peek  * Result:
14063a93856SMark Peek  *     None.
14163a93856SMark Peek  *
14263a93856SMark Peek  * Side effects:
14363a93856SMark Peek  *     None.
14463a93856SMark Peek  *
14563a93856SMark Peek  *------------------------------------------------------------------------------
14663a93856SMark Peek  */
14763a93856SMark Peek 
14863a93856SMark Peek int
14963a93856SMark Peek vmci_hashtable_add_entry(struct vmci_hashtable *table,
15063a93856SMark Peek     struct vmci_hash_entry *entry)
15163a93856SMark Peek {
15263a93856SMark Peek 	int idx;
15363a93856SMark Peek 
15463a93856SMark Peek 	ASSERT(entry);
15563a93856SMark Peek 	ASSERT(table);
15663a93856SMark Peek 
15763a93856SMark Peek 	vmci_grab_lock_bh(&table->lock);
15863a93856SMark Peek 
15963a93856SMark Peek 	if (vmci_hashtable_entry_exists_locked(table, entry->handle)) {
16063a93856SMark Peek 		VMCI_LOG_DEBUG(LGPFX"Entry (handle=0x%x:0x%x) already "
16163a93856SMark Peek 		    "exists.\n", entry->handle.context,
16263a93856SMark Peek 		    entry->handle.resource);
16363a93856SMark Peek 		vmci_release_lock_bh(&table->lock);
16463a93856SMark Peek 		return (VMCI_ERROR_DUPLICATE_ENTRY);
16563a93856SMark Peek 	}
16663a93856SMark Peek 
16763a93856SMark Peek 	idx = VMCI_HASHTABLE_HASH(entry->handle, table->size);
16863a93856SMark Peek 	ASSERT(idx < table->size);
16963a93856SMark Peek 
17063a93856SMark Peek 	/* New entry is added to top/front of hash bucket. */
17163a93856SMark Peek 	entry->ref_count++;
17263a93856SMark Peek 	entry->next = table->entries[idx];
17363a93856SMark Peek 	table->entries[idx] = entry;
17463a93856SMark Peek 	vmci_release_lock_bh(&table->lock);
17563a93856SMark Peek 
17663a93856SMark Peek 	return (VMCI_SUCCESS);
17763a93856SMark Peek }
17863a93856SMark Peek 
17963a93856SMark Peek /*
18063a93856SMark Peek  *------------------------------------------------------------------------------
18163a93856SMark Peek  *
18263a93856SMark Peek  * vmci_hashtable_remove_entry --
18363a93856SMark Peek  *
18463a93856SMark Peek  *     Removes an entry from the hashtable.
18563a93856SMark Peek  *
18663a93856SMark Peek  * Result:
18763a93856SMark Peek  *     None.
18863a93856SMark Peek  *
18963a93856SMark Peek  * Side effects:
19063a93856SMark Peek  *     None.
19163a93856SMark Peek  *
19263a93856SMark Peek  *------------------------------------------------------------------------------
19363a93856SMark Peek  */
19463a93856SMark Peek 
19563a93856SMark Peek int
19663a93856SMark Peek vmci_hashtable_remove_entry(struct vmci_hashtable *table,
19763a93856SMark Peek     struct vmci_hash_entry *entry)
19863a93856SMark Peek {
19963a93856SMark Peek 	int result;
20063a93856SMark Peek 
20163a93856SMark Peek 	ASSERT(table);
20263a93856SMark Peek 	ASSERT(entry);
20363a93856SMark Peek 
20463a93856SMark Peek 	vmci_grab_lock_bh(&table->lock);
20563a93856SMark Peek 
20663a93856SMark Peek 	/* First unlink the entry. */
20763a93856SMark Peek 	result = hashtable_unlink_entry(table, entry);
20863a93856SMark Peek 	if (result != VMCI_SUCCESS) {
20963a93856SMark Peek 		/* We failed to find the entry. */
21063a93856SMark Peek 		goto done;
21163a93856SMark Peek 	}
21263a93856SMark Peek 
21363a93856SMark Peek 	/* Decrement refcount and check if this is last reference. */
21463a93856SMark Peek 	entry->ref_count--;
21563a93856SMark Peek 	if (entry->ref_count == 0) {
21663a93856SMark Peek 		result = VMCI_SUCCESS_ENTRY_DEAD;
21763a93856SMark Peek 		goto done;
21863a93856SMark Peek 	}
21963a93856SMark Peek 
22063a93856SMark Peek done:
22163a93856SMark Peek 	vmci_release_lock_bh(&table->lock);
22263a93856SMark Peek 
22363a93856SMark Peek 	return (result);
22463a93856SMark Peek }
22563a93856SMark Peek 
22663a93856SMark Peek /*
22763a93856SMark Peek  *------------------------------------------------------------------------------
22863a93856SMark Peek  *
22963a93856SMark Peek  * vmci_hashtable_get_entry_locked --
23063a93856SMark Peek  *
23163a93856SMark Peek  *     Looks up an entry in the hash table, that is already locked.
23263a93856SMark Peek  *
23363a93856SMark Peek  * Result:
23463a93856SMark Peek  *     If the element is found, a pointer to the element is returned.
23563a93856SMark Peek  *     Otherwise NULL is returned.
23663a93856SMark Peek  *
23763a93856SMark Peek  * Side effects:
23863a93856SMark Peek  *     The reference count of the returned element is increased.
23963a93856SMark Peek  *
24063a93856SMark Peek  *------------------------------------------------------------------------------
24163a93856SMark Peek  */
24263a93856SMark Peek 
24363a93856SMark Peek static struct vmci_hash_entry *
24463a93856SMark Peek vmci_hashtable_get_entry_locked(struct vmci_hashtable *table,
24563a93856SMark Peek     struct vmci_handle handle)
24663a93856SMark Peek {
24763a93856SMark Peek 	struct vmci_hash_entry *cur = NULL;
24863a93856SMark Peek 	int idx;
24963a93856SMark Peek 
25063a93856SMark Peek 	ASSERT(!VMCI_HANDLE_EQUAL(handle, VMCI_INVALID_HANDLE));
25163a93856SMark Peek 	ASSERT(table);
25263a93856SMark Peek 
25363a93856SMark Peek 	idx = VMCI_HASHTABLE_HASH(handle, table->size);
25463a93856SMark Peek 
25563a93856SMark Peek 	cur = table->entries[idx];
25663a93856SMark Peek 	while (true) {
25763a93856SMark Peek 		if (cur == NULL)
25863a93856SMark Peek 			break;
25963a93856SMark Peek 
26063a93856SMark Peek 		if (VMCI_HANDLE_TO_RESOURCE_ID(cur->handle) ==
26163a93856SMark Peek 		    VMCI_HANDLE_TO_RESOURCE_ID(handle)) {
26263a93856SMark Peek 			if ((VMCI_HANDLE_TO_CONTEXT_ID(cur->handle) ==
26363a93856SMark Peek 			    VMCI_HANDLE_TO_CONTEXT_ID(handle)) ||
26463a93856SMark Peek 			    (VMCI_INVALID_ID == VMCI_HANDLE_TO_CONTEXT_ID(cur->handle))) {
26563a93856SMark Peek 				cur->ref_count++;
26663a93856SMark Peek 				break;
26763a93856SMark Peek 			}
26863a93856SMark Peek 		}
26963a93856SMark Peek 		cur = cur->next;
27063a93856SMark Peek 	}
27163a93856SMark Peek 
27263a93856SMark Peek 	return (cur);
27363a93856SMark Peek }
27463a93856SMark Peek 
27563a93856SMark Peek /*
27663a93856SMark Peek  *------------------------------------------------------------------------------
27763a93856SMark Peek  *
27863a93856SMark Peek  * vmci_hashtable_get_entry --
27963a93856SMark Peek  *
28063a93856SMark Peek  *     Gets an entry from the hashtable.
28163a93856SMark Peek  *
28263a93856SMark Peek  * Result:
28363a93856SMark Peek  *     None.
28463a93856SMark Peek  *
28563a93856SMark Peek  * Side effects:
28663a93856SMark Peek  *     None.
28763a93856SMark Peek  *
28863a93856SMark Peek  *------------------------------------------------------------------------------
28963a93856SMark Peek  */
29063a93856SMark Peek 
29163a93856SMark Peek struct vmci_hash_entry *
29263a93856SMark Peek vmci_hashtable_get_entry(struct vmci_hashtable *table,
29363a93856SMark Peek     struct vmci_handle handle)
29463a93856SMark Peek {
29563a93856SMark Peek 	struct vmci_hash_entry *entry;
29663a93856SMark Peek 
29763a93856SMark Peek 	if (VMCI_HANDLE_EQUAL(handle, VMCI_INVALID_HANDLE))
29863a93856SMark Peek 		return (NULL);
29963a93856SMark Peek 
30063a93856SMark Peek 	ASSERT(table);
30163a93856SMark Peek 
30263a93856SMark Peek 	vmci_grab_lock_bh(&table->lock);
30363a93856SMark Peek 	entry = vmci_hashtable_get_entry_locked(table, handle);
30463a93856SMark Peek 	vmci_release_lock_bh(&table->lock);
30563a93856SMark Peek 
30663a93856SMark Peek 	return (entry);
30763a93856SMark Peek }
30863a93856SMark Peek 
30963a93856SMark Peek /*
31063a93856SMark Peek  *------------------------------------------------------------------------------
31163a93856SMark Peek  *
31263a93856SMark Peek  * vmci_hashtable_hold_entry --
31363a93856SMark Peek  *
31463a93856SMark Peek  *     Hold the given entry. This will increment the entry's reference count.
31563a93856SMark Peek  *     This is like a GetEntry() but without having to lookup the entry by
31663a93856SMark Peek  *     handle.
31763a93856SMark Peek  *
31863a93856SMark Peek  * Result:
31963a93856SMark Peek  *     None.
32063a93856SMark Peek  *
32163a93856SMark Peek  * Side effects:
32263a93856SMark Peek  *     None.
32363a93856SMark Peek  *
32463a93856SMark Peek  *------------------------------------------------------------------------------
32563a93856SMark Peek  */
32663a93856SMark Peek 
32763a93856SMark Peek void
32863a93856SMark Peek vmci_hashtable_hold_entry(struct vmci_hashtable *table,
32963a93856SMark Peek     struct vmci_hash_entry *entry)
33063a93856SMark Peek {
33163a93856SMark Peek 
33263a93856SMark Peek 	ASSERT(table);
33363a93856SMark Peek 	ASSERT(entry);
33463a93856SMark Peek 
33563a93856SMark Peek 	vmci_grab_lock_bh(&table->lock);
33663a93856SMark Peek 	entry->ref_count++;
33763a93856SMark Peek 	vmci_release_lock_bh(&table->lock);
33863a93856SMark Peek }
33963a93856SMark Peek 
34063a93856SMark Peek /*
34163a93856SMark Peek  *------------------------------------------------------------------------------
34263a93856SMark Peek  *
34363a93856SMark Peek  * vmci_hashtable_release_entry_locked --
34463a93856SMark Peek  *
34563a93856SMark Peek  *     Releases an element previously obtained with
34663a93856SMark Peek  *     vmci_hashtable_get_entry_locked.
34763a93856SMark Peek  *
34863a93856SMark Peek  * Result:
34963a93856SMark Peek  *     If the entry is removed from the hash table, VMCI_SUCCESS_ENTRY_DEAD
35063a93856SMark Peek  *     is returned. Otherwise, VMCI_SUCCESS is returned.
35163a93856SMark Peek  *
35263a93856SMark Peek  * Side effects:
35363a93856SMark Peek  *     The reference count of the entry is decreased and the entry is removed
35463a93856SMark Peek  *     from the hash table on 0.
35563a93856SMark Peek  *
35663a93856SMark Peek  *------------------------------------------------------------------------------
35763a93856SMark Peek  */
35863a93856SMark Peek 
35963a93856SMark Peek static int
36063a93856SMark Peek vmci_hashtable_release_entry_locked(struct vmci_hashtable *table,
36163a93856SMark Peek     struct vmci_hash_entry *entry)
36263a93856SMark Peek {
36363a93856SMark Peek 	int result = VMCI_SUCCESS;
36463a93856SMark Peek 
36563a93856SMark Peek 	ASSERT(table);
36663a93856SMark Peek 	ASSERT(entry);
36763a93856SMark Peek 
36863a93856SMark Peek 	entry->ref_count--;
36963a93856SMark Peek 	/* Check if this is last reference and report if so. */
37063a93856SMark Peek 	if (entry->ref_count == 0) {
37163a93856SMark Peek 
37263a93856SMark Peek 		/*
37363a93856SMark Peek 		 * Remove entry from hash table if not already removed. This
37463a93856SMark Peek 		 * could have happened already because VMCIHashTable_RemoveEntry
37563a93856SMark Peek 		 * was called to unlink it. We ignore if it is not found.
37663a93856SMark Peek 		 * Datagram handles will often have RemoveEntry called, whereas
37763a93856SMark Peek 		 * SharedMemory regions rely on ReleaseEntry to unlink the entry
37863a93856SMark Peek 		 * , since the creator does not call RemoveEntry when it
37963a93856SMark Peek 		 * detaches.
38063a93856SMark Peek 		 */
38163a93856SMark Peek 
38263a93856SMark Peek 		hashtable_unlink_entry(table, entry);
38363a93856SMark Peek 		result = VMCI_SUCCESS_ENTRY_DEAD;
38463a93856SMark Peek 	}
38563a93856SMark Peek 
38663a93856SMark Peek 	return (result);
38763a93856SMark Peek }
38863a93856SMark Peek 
38963a93856SMark Peek /*
39063a93856SMark Peek  *------------------------------------------------------------------------------
39163a93856SMark Peek  *
39263a93856SMark Peek  * vmci_hashtable_release_entry --
39363a93856SMark Peek  *
39463a93856SMark Peek  *     Releases an entry from the hashtable.
39563a93856SMark Peek  *
39663a93856SMark Peek  * Result:
39763a93856SMark Peek  *     None.
39863a93856SMark Peek  *
39963a93856SMark Peek  * Side effects:
40063a93856SMark Peek  *     None.
40163a93856SMark Peek  *
40263a93856SMark Peek  *------------------------------------------------------------------------------
40363a93856SMark Peek  */
40463a93856SMark Peek 
40563a93856SMark Peek int
40663a93856SMark Peek vmci_hashtable_release_entry(struct vmci_hashtable *table,
40763a93856SMark Peek     struct vmci_hash_entry *entry)
40863a93856SMark Peek {
40963a93856SMark Peek 	int result;
41063a93856SMark Peek 
41163a93856SMark Peek 	ASSERT(table);
41263a93856SMark Peek 	vmci_grab_lock_bh(&table->lock);
41363a93856SMark Peek 	result = vmci_hashtable_release_entry_locked(table, entry);
41463a93856SMark Peek 	vmci_release_lock_bh(&table->lock);
41563a93856SMark Peek 
41663a93856SMark Peek 	return (result);
41763a93856SMark Peek }
41863a93856SMark Peek 
41963a93856SMark Peek /*
42063a93856SMark Peek  *------------------------------------------------------------------------------
42163a93856SMark Peek  *
42263a93856SMark Peek  * vmci_hashtable_entry_exists --
42363a93856SMark Peek  *
42463a93856SMark Peek  *     Returns whether an entry exists in the hashtable
42563a93856SMark Peek  *
42663a93856SMark Peek  * Result:
42763a93856SMark Peek  *     true if handle already in hashtable. false otherwise.
42863a93856SMark Peek  *
42963a93856SMark Peek  * Side effects:
43063a93856SMark Peek  *     None.
43163a93856SMark Peek  *
43263a93856SMark Peek  *------------------------------------------------------------------------------
43363a93856SMark Peek  */
43463a93856SMark Peek 
43563a93856SMark Peek bool
43663a93856SMark Peek vmci_hashtable_entry_exists(struct vmci_hashtable *table,
43763a93856SMark Peek     struct vmci_handle handle)
43863a93856SMark Peek {
43963a93856SMark Peek 	bool exists;
44063a93856SMark Peek 
44163a93856SMark Peek 	ASSERT(table);
44263a93856SMark Peek 
44363a93856SMark Peek 	vmci_grab_lock_bh(&table->lock);
44463a93856SMark Peek 	exists = vmci_hashtable_entry_exists_locked(table, handle);
44563a93856SMark Peek 	vmci_release_lock_bh(&table->lock);
44663a93856SMark Peek 
44763a93856SMark Peek 	return (exists);
44863a93856SMark Peek }
44963a93856SMark Peek 
45063a93856SMark Peek /*
45163a93856SMark Peek  *------------------------------------------------------------------------------
45263a93856SMark Peek  *
45363a93856SMark Peek  * vmci_hashtable_entry_exists_locked --
45463a93856SMark Peek  *
45563a93856SMark Peek  *     Unlocked version of vmci_hashtable_entry_exists.
45663a93856SMark Peek  *
45763a93856SMark Peek  * Result:
45863a93856SMark Peek  *     true if handle already in hashtable. false otherwise.
45963a93856SMark Peek  *
46063a93856SMark Peek  * Side effects:
46163a93856SMark Peek  *     None.
46263a93856SMark Peek  *
46363a93856SMark Peek  *------------------------------------------------------------------------------
46463a93856SMark Peek  */
46563a93856SMark Peek 
46663a93856SMark Peek static bool
46763a93856SMark Peek vmci_hashtable_entry_exists_locked(struct vmci_hashtable *table,
46863a93856SMark Peek     struct vmci_handle handle)
46963a93856SMark Peek 
47063a93856SMark Peek {
47163a93856SMark Peek 	struct vmci_hash_entry *entry;
47263a93856SMark Peek 	int idx;
47363a93856SMark Peek 
47463a93856SMark Peek 	ASSERT(table);
47563a93856SMark Peek 
47663a93856SMark Peek 	idx = VMCI_HASHTABLE_HASH(handle, table->size);
47763a93856SMark Peek 
47863a93856SMark Peek 	entry = table->entries[idx];
47963a93856SMark Peek 	while (entry) {
48063a93856SMark Peek 		if (VMCI_HANDLE_TO_RESOURCE_ID(entry->handle) ==
48163a93856SMark Peek 		    VMCI_HANDLE_TO_RESOURCE_ID(handle))
48263a93856SMark Peek 			if ((VMCI_HANDLE_TO_CONTEXT_ID(entry->handle) ==
48363a93856SMark Peek 			    VMCI_HANDLE_TO_CONTEXT_ID(handle)) ||
48463a93856SMark Peek 			    (VMCI_INVALID_ID == VMCI_HANDLE_TO_CONTEXT_ID(handle)) ||
48563a93856SMark Peek 			    (VMCI_INVALID_ID == VMCI_HANDLE_TO_CONTEXT_ID(entry->handle)))
48663a93856SMark Peek 				return (true);
48763a93856SMark Peek 		entry = entry->next;
48863a93856SMark Peek 	}
48963a93856SMark Peek 
49063a93856SMark Peek 	return (false);
49163a93856SMark Peek }
49263a93856SMark Peek 
49363a93856SMark Peek /*
49463a93856SMark Peek  *------------------------------------------------------------------------------
49563a93856SMark Peek  *
49663a93856SMark Peek  * hashtable_unlink_entry --
49763a93856SMark Peek  *
49863a93856SMark Peek  *     Assumes caller holds table lock.
49963a93856SMark Peek  *
50063a93856SMark Peek  * Result:
50163a93856SMark Peek  *     None.
50263a93856SMark Peek  *
50363a93856SMark Peek  * Side effects:
50463a93856SMark Peek  *     None.
50563a93856SMark Peek  *
50663a93856SMark Peek  *------------------------------------------------------------------------------
50763a93856SMark Peek  */
50863a93856SMark Peek 
50963a93856SMark Peek static int
51063a93856SMark Peek hashtable_unlink_entry(struct vmci_hashtable *table,
51163a93856SMark Peek     struct vmci_hash_entry *entry)
51263a93856SMark Peek {
51363a93856SMark Peek 	int result;
51463a93856SMark Peek 	struct vmci_hash_entry *prev, *cur;
51563a93856SMark Peek 	int idx;
51663a93856SMark Peek 
51763a93856SMark Peek 	idx = VMCI_HASHTABLE_HASH(entry->handle, table->size);
51863a93856SMark Peek 
51963a93856SMark Peek 	prev = NULL;
52063a93856SMark Peek 	cur = table->entries[idx];
52163a93856SMark Peek 	while (true) {
52263a93856SMark Peek 		if (cur == NULL) {
52363a93856SMark Peek 			result = VMCI_ERROR_NOT_FOUND;
52463a93856SMark Peek 			break;
52563a93856SMark Peek 		}
52663a93856SMark Peek 		if (VMCI_HANDLE_EQUAL(cur->handle, entry->handle)) {
52763a93856SMark Peek 			ASSERT(cur == entry);
52863a93856SMark Peek 
52963a93856SMark Peek 			/* Remove entry and break. */
53063a93856SMark Peek 			if (prev)
53163a93856SMark Peek 				prev->next = cur->next;
53263a93856SMark Peek 			else
53363a93856SMark Peek 				table->entries[idx] = cur->next;
53463a93856SMark Peek 			cur->next = NULL;
53563a93856SMark Peek 			result = VMCI_SUCCESS;
53663a93856SMark Peek 			break;
53763a93856SMark Peek 		}
53863a93856SMark Peek 		prev = cur;
53963a93856SMark Peek 		cur = cur->next;
54063a93856SMark Peek 	}
54163a93856SMark Peek 	return (result);
54263a93856SMark Peek }
54363a93856SMark Peek 
54463a93856SMark Peek /*
54563a93856SMark Peek  *------------------------------------------------------------------------------
54663a93856SMark Peek  *
54763a93856SMark Peek  * vmci_hashtable_sync --
54863a93856SMark Peek  *
54963a93856SMark Peek  *     Use this as a synchronization point when setting globals, for example,
55063a93856SMark Peek  *     during device shutdown.
55163a93856SMark Peek  *
55263a93856SMark Peek  * Results:
55363a93856SMark Peek  *     None.
55463a93856SMark Peek  *
55563a93856SMark Peek  * Side effects:
55663a93856SMark Peek  *     None.
55763a93856SMark Peek  *
55863a93856SMark Peek  *------------------------------------------------------------------------------
55963a93856SMark Peek  */
56063a93856SMark Peek 
56163a93856SMark Peek void
56263a93856SMark Peek vmci_hashtable_sync(struct vmci_hashtable *table)
56363a93856SMark Peek {
56463a93856SMark Peek 
56563a93856SMark Peek 	ASSERT(table);
56663a93856SMark Peek 	vmci_grab_lock_bh(&table->lock);
56763a93856SMark Peek 	vmci_release_lock_bh(&table->lock);
56863a93856SMark Peek }
569