GNU Linux-libre 6.8.7-gnu
[releases.git] / drivers / misc / vmw_vmci / vmci_handle_array.c
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 }