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