18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * VMware VMCI Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2012 VMware, Inc. All rights reserved. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include "vmci_handle_array.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_cistatic size_t handle_arr_calc_size(u32 capacity) 128c2ecf20Sopenharmony_ci{ 138c2ecf20Sopenharmony_ci return VMCI_HANDLE_ARRAY_HEADER_SIZE + 148c2ecf20Sopenharmony_ci capacity * sizeof(struct vmci_handle); 158c2ecf20Sopenharmony_ci} 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistruct vmci_handle_arr *vmci_handle_arr_create(u32 capacity, u32 max_capacity) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci struct vmci_handle_arr *array; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci if (max_capacity == 0 || capacity > max_capacity) 228c2ecf20Sopenharmony_ci return NULL; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci if (capacity == 0) 258c2ecf20Sopenharmony_ci capacity = min((u32)VMCI_HANDLE_ARRAY_DEFAULT_CAPACITY, 268c2ecf20Sopenharmony_ci max_capacity); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci array = kmalloc(handle_arr_calc_size(capacity), GFP_ATOMIC); 298c2ecf20Sopenharmony_ci if (!array) 308c2ecf20Sopenharmony_ci return NULL; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci array->capacity = capacity; 338c2ecf20Sopenharmony_ci array->max_capacity = max_capacity; 348c2ecf20Sopenharmony_ci array->size = 0; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci return array; 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_civoid vmci_handle_arr_destroy(struct vmci_handle_arr *array) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci kfree(array); 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ciint vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr, 458c2ecf20Sopenharmony_ci struct vmci_handle handle) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci struct vmci_handle_arr *array = *array_ptr; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (unlikely(array->size >= array->capacity)) { 508c2ecf20Sopenharmony_ci /* reallocate. */ 518c2ecf20Sopenharmony_ci struct vmci_handle_arr *new_array; 528c2ecf20Sopenharmony_ci u32 capacity_bump = min(array->max_capacity - array->capacity, 538c2ecf20Sopenharmony_ci array->capacity); 548c2ecf20Sopenharmony_ci size_t new_size = handle_arr_calc_size(array->capacity + 558c2ecf20Sopenharmony_ci capacity_bump); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (array->size >= array->max_capacity) 588c2ecf20Sopenharmony_ci return VMCI_ERROR_NO_MEM; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci new_array = krealloc(array, new_size, GFP_ATOMIC); 618c2ecf20Sopenharmony_ci if (!new_array) 628c2ecf20Sopenharmony_ci return VMCI_ERROR_NO_MEM; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci new_array->capacity += capacity_bump; 658c2ecf20Sopenharmony_ci *array_ptr = array = new_array; 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci array->entries[array->size] = handle; 698c2ecf20Sopenharmony_ci array->size++; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci return VMCI_SUCCESS; 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* 758c2ecf20Sopenharmony_ci * Handle that was removed, VMCI_INVALID_HANDLE if entry not found. 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_cistruct vmci_handle vmci_handle_arr_remove_entry(struct vmci_handle_arr *array, 788c2ecf20Sopenharmony_ci struct vmci_handle entry_handle) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci struct vmci_handle handle = VMCI_INVALID_HANDLE; 818c2ecf20Sopenharmony_ci u32 i; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci for (i = 0; i < array->size; i++) { 848c2ecf20Sopenharmony_ci if (vmci_handle_is_equal(array->entries[i], entry_handle)) { 858c2ecf20Sopenharmony_ci handle = array->entries[i]; 868c2ecf20Sopenharmony_ci array->size--; 878c2ecf20Sopenharmony_ci array->entries[i] = array->entries[array->size]; 888c2ecf20Sopenharmony_ci array->entries[array->size] = VMCI_INVALID_HANDLE; 898c2ecf20Sopenharmony_ci break; 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return handle; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* 978c2ecf20Sopenharmony_ci * Handle that was removed, VMCI_INVALID_HANDLE if array was empty. 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_cistruct vmci_handle vmci_handle_arr_remove_tail(struct vmci_handle_arr *array) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci struct vmci_handle handle = VMCI_INVALID_HANDLE; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci if (array->size) { 1048c2ecf20Sopenharmony_ci array->size--; 1058c2ecf20Sopenharmony_ci handle = array->entries[array->size]; 1068c2ecf20Sopenharmony_ci array->entries[array->size] = VMCI_INVALID_HANDLE; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci return handle; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/* 1138c2ecf20Sopenharmony_ci * Handle at given index, VMCI_INVALID_HANDLE if invalid index. 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_cistruct vmci_handle 1168c2ecf20Sopenharmony_civmci_handle_arr_get_entry(const struct vmci_handle_arr *array, u32 index) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci if (unlikely(index >= array->size)) 1198c2ecf20Sopenharmony_ci return VMCI_INVALID_HANDLE; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci return array->entries[index]; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cibool vmci_handle_arr_has_entry(const struct vmci_handle_arr *array, 1258c2ecf20Sopenharmony_ci struct vmci_handle entry_handle) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci u32 i; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci for (i = 0; i < array->size; i++) 1308c2ecf20Sopenharmony_ci if (vmci_handle_is_equal(array->entries[i], entry_handle)) 1318c2ecf20Sopenharmony_ci return true; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci return false; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci/* 1378c2ecf20Sopenharmony_ci * NULL if the array is empty. Otherwise, a pointer to the array 1388c2ecf20Sopenharmony_ci * of VMCI handles in the handle array. 1398c2ecf20Sopenharmony_ci */ 1408c2ecf20Sopenharmony_cistruct vmci_handle *vmci_handle_arr_get_handles(struct vmci_handle_arr *array) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci if (array->size) 1438c2ecf20Sopenharmony_ci return array->entries; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci return NULL; 1468c2ecf20Sopenharmony_ci} 147