1685a6bf8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2b484b26cSGeorge Zhang /*
3b484b26cSGeorge Zhang  * VMware VMCI Driver
4b484b26cSGeorge Zhang  *
5b484b26cSGeorge Zhang  * Copyright (C) 2012 VMware, Inc. All rights reserved.
6b484b26cSGeorge Zhang  */
7b484b26cSGeorge Zhang 
8b484b26cSGeorge Zhang #include <linux/slab.h>
9b484b26cSGeorge Zhang #include "vmci_handle_array.h"
10b484b26cSGeorge Zhang 
11b484b26cSGeorge Zhang static size_t handle_arr_calc_size(size_t capacity)
12b484b26cSGeorge Zhang {
13b484b26cSGeorge Zhang 	return sizeof(struct vmci_handle_arr) +
14b484b26cSGeorge Zhang 	    capacity * sizeof(struct vmci_handle);
15b484b26cSGeorge Zhang }
16b484b26cSGeorge Zhang 
17b484b26cSGeorge Zhang struct vmci_handle_arr *vmci_handle_arr_create(size_t capacity)
18b484b26cSGeorge Zhang {
19b484b26cSGeorge Zhang 	struct vmci_handle_arr *array;
20b484b26cSGeorge Zhang 
21b484b26cSGeorge Zhang 	if (capacity == 0)
22b484b26cSGeorge Zhang 		capacity = VMCI_HANDLE_ARRAY_DEFAULT_SIZE;
23b484b26cSGeorge Zhang 
24b484b26cSGeorge Zhang 	array = kmalloc(handle_arr_calc_size(capacity), GFP_ATOMIC);
25b484b26cSGeorge Zhang 	if (!array)
26b484b26cSGeorge Zhang 		return NULL;
27b484b26cSGeorge Zhang 
28b484b26cSGeorge Zhang 	array->capacity = capacity;
29b484b26cSGeorge Zhang 	array->size = 0;
30b484b26cSGeorge Zhang 
31b484b26cSGeorge Zhang 	return array;
32b484b26cSGeorge Zhang }
33b484b26cSGeorge Zhang 
34b484b26cSGeorge Zhang void vmci_handle_arr_destroy(struct vmci_handle_arr *array)
35b484b26cSGeorge Zhang {
36b484b26cSGeorge Zhang 	kfree(array);
37b484b26cSGeorge Zhang }
38b484b26cSGeorge Zhang 
39b484b26cSGeorge Zhang void vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr,
40b484b26cSGeorge Zhang 				  struct vmci_handle handle)
41b484b26cSGeorge Zhang {
42b484b26cSGeorge Zhang 	struct vmci_handle_arr *array = *array_ptr;
43b484b26cSGeorge Zhang 
44b484b26cSGeorge Zhang 	if (unlikely(array->size >= array->capacity)) {
45b484b26cSGeorge Zhang 		/* reallocate. */
46b484b26cSGeorge Zhang 		struct vmci_handle_arr *new_array;
47b484b26cSGeorge Zhang 		size_t new_capacity = array->capacity * VMCI_ARR_CAP_MULT;
48b484b26cSGeorge Zhang 		size_t new_size = handle_arr_calc_size(new_capacity);
49b484b26cSGeorge Zhang 
50b484b26cSGeorge Zhang 		new_array = krealloc(array, new_size, GFP_ATOMIC);
51b484b26cSGeorge Zhang 		if (!new_array)
52b484b26cSGeorge Zhang 			return;
53b484b26cSGeorge Zhang 
54b484b26cSGeorge Zhang 		new_array->capacity = new_capacity;
55b484b26cSGeorge Zhang 		*array_ptr = array = new_array;
56b484b26cSGeorge Zhang 	}
57b484b26cSGeorge Zhang 
58b484b26cSGeorge Zhang 	array->entries[array->size] = handle;
59b484b26cSGeorge Zhang 	array->size++;
60b484b26cSGeorge Zhang }
61b484b26cSGeorge Zhang 
62b484b26cSGeorge Zhang /*
63b484b26cSGeorge Zhang  * Handle that was removed, VMCI_INVALID_HANDLE if entry not found.
64b484b26cSGeorge Zhang  */
65b484b26cSGeorge Zhang struct vmci_handle vmci_handle_arr_remove_entry(struct vmci_handle_arr *array,
66b484b26cSGeorge Zhang 						struct vmci_handle entry_handle)
67b484b26cSGeorge Zhang {
68b484b26cSGeorge Zhang 	struct vmci_handle handle = VMCI_INVALID_HANDLE;
69b484b26cSGeorge Zhang 	size_t i;
70b484b26cSGeorge Zhang 
71b484b26cSGeorge Zhang 	for (i = 0; i < array->size; i++) {
72b484b26cSGeorge Zhang 		if (vmci_handle_is_equal(array->entries[i], entry_handle)) {
73b484b26cSGeorge Zhang 			handle = array->entries[i];
74b484b26cSGeorge Zhang 			array->size--;
75b484b26cSGeorge Zhang 			array->entries[i] = array->entries[array->size];
76b484b26cSGeorge Zhang 			array->entries[array->size] = VMCI_INVALID_HANDLE;
77b484b26cSGeorge Zhang 			break;
78b484b26cSGeorge Zhang 		}
79b484b26cSGeorge Zhang 	}
80b484b26cSGeorge Zhang 
81b484b26cSGeorge Zhang 	return handle;
82b484b26cSGeorge Zhang }
83b484b26cSGeorge Zhang 
84b484b26cSGeorge Zhang /*
85b484b26cSGeorge Zhang  * Handle that was removed, VMCI_INVALID_HANDLE if array was empty.
86b484b26cSGeorge Zhang  */
87b484b26cSGeorge Zhang struct vmci_handle vmci_handle_arr_remove_tail(struct vmci_handle_arr *array)
88b484b26cSGeorge Zhang {
89b484b26cSGeorge Zhang 	struct vmci_handle handle = VMCI_INVALID_HANDLE;
90b484b26cSGeorge Zhang 
91b484b26cSGeorge Zhang 	if (array->size) {
92b484b26cSGeorge Zhang 		array->size--;
93b484b26cSGeorge Zhang 		handle = array->entries[array->size];
94b484b26cSGeorge Zhang 		array->entries[array->size] = VMCI_INVALID_HANDLE;
95b484b26cSGeorge Zhang 	}
96b484b26cSGeorge Zhang 
97b484b26cSGeorge Zhang 	return handle;
98b484b26cSGeorge Zhang }
99b484b26cSGeorge Zhang 
100b484b26cSGeorge Zhang /*
101b484b26cSGeorge Zhang  * Handle at given index, VMCI_INVALID_HANDLE if invalid index.
102b484b26cSGeorge Zhang  */
103b484b26cSGeorge Zhang struct vmci_handle
104b484b26cSGeorge Zhang vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, size_t index)
105b484b26cSGeorge Zhang {
106b484b26cSGeorge Zhang 	if (unlikely(index >= array->size))
107b484b26cSGeorge Zhang 		return VMCI_INVALID_HANDLE;
108b484b26cSGeorge Zhang 
109b484b26cSGeorge Zhang 	return array->entries[index];
110b484b26cSGeorge Zhang }
111b484b26cSGeorge Zhang 
112b484b26cSGeorge Zhang bool vmci_handle_arr_has_entry(const struct vmci_handle_arr *array,
113b484b26cSGeorge Zhang 			       struct vmci_handle entry_handle)
114b484b26cSGeorge Zhang {
115b484b26cSGeorge Zhang 	size_t i;
116b484b26cSGeorge Zhang 
117b484b26cSGeorge Zhang 	for (i = 0; i < array->size; i++)
118b484b26cSGeorge Zhang 		if (vmci_handle_is_equal(array->entries[i], entry_handle))
119b484b26cSGeorge Zhang 			return true;
120b484b26cSGeorge Zhang 
121b484b26cSGeorge Zhang 	return false;
122b484b26cSGeorge Zhang }
123b484b26cSGeorge Zhang 
124b484b26cSGeorge Zhang /*
125b484b26cSGeorge Zhang  * NULL if the array is empty. Otherwise, a pointer to the array
126b484b26cSGeorge Zhang  * of VMCI handles in the handle array.
127b484b26cSGeorge Zhang  */
128b484b26cSGeorge Zhang struct vmci_handle *vmci_handle_arr_get_handles(struct vmci_handle_arr *array)
129b484b26cSGeorge Zhang {
130b484b26cSGeorge Zhang 	if (array->size)
131b484b26cSGeorge Zhang 		return array->entries;
132b484b26cSGeorge Zhang 
133b484b26cSGeorge Zhang 	return NULL;
134b484b26cSGeorge Zhang }
135