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