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(objp: 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(objp: 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(h1: array->entries[i], h2: 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(h1: array->entries[i], h2: 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 | |