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