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