162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * VMware VMCI Driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2012 VMware, Inc. All rights reserved. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/slab.h> 962306a36Sopenharmony_ci#include "vmci_handle_array.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistatic size_t handle_arr_calc_size(u32 capacity) 1262306a36Sopenharmony_ci{ 1362306a36Sopenharmony_ci return VMCI_HANDLE_ARRAY_HEADER_SIZE + 1462306a36Sopenharmony_ci capacity * sizeof(struct vmci_handle); 1562306a36Sopenharmony_ci} 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistruct vmci_handle_arr *vmci_handle_arr_create(u32 capacity, u32 max_capacity) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci struct vmci_handle_arr *array; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci if (max_capacity == 0 || capacity > max_capacity) 2262306a36Sopenharmony_ci return NULL; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci if (capacity == 0) 2562306a36Sopenharmony_ci capacity = min((u32)VMCI_HANDLE_ARRAY_DEFAULT_CAPACITY, 2662306a36Sopenharmony_ci max_capacity); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci array = kmalloc(handle_arr_calc_size(capacity), GFP_ATOMIC); 2962306a36Sopenharmony_ci if (!array) 3062306a36Sopenharmony_ci return NULL; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci array->capacity = capacity; 3362306a36Sopenharmony_ci array->max_capacity = max_capacity; 3462306a36Sopenharmony_ci array->size = 0; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci return array; 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_civoid vmci_handle_arr_destroy(struct vmci_handle_arr *array) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci kfree(array); 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ciint vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr, 4562306a36Sopenharmony_ci struct vmci_handle handle) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci struct vmci_handle_arr *array = *array_ptr; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (unlikely(array->size >= array->capacity)) { 5062306a36Sopenharmony_ci /* reallocate. */ 5162306a36Sopenharmony_ci struct vmci_handle_arr *new_array; 5262306a36Sopenharmony_ci u32 capacity_bump = min(array->max_capacity - array->capacity, 5362306a36Sopenharmony_ci array->capacity); 5462306a36Sopenharmony_ci size_t new_size = handle_arr_calc_size(array->capacity + 5562306a36Sopenharmony_ci capacity_bump); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (array->size >= array->max_capacity) 5862306a36Sopenharmony_ci return VMCI_ERROR_NO_MEM; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci new_array = krealloc(array, new_size, GFP_ATOMIC); 6162306a36Sopenharmony_ci if (!new_array) 6262306a36Sopenharmony_ci return VMCI_ERROR_NO_MEM; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci new_array->capacity += capacity_bump; 6562306a36Sopenharmony_ci *array_ptr = array = new_array; 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci array->entries[array->size] = handle; 6962306a36Sopenharmony_ci array->size++; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci return VMCI_SUCCESS; 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* 7562306a36Sopenharmony_ci * Handle that was removed, VMCI_INVALID_HANDLE if entry not found. 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_cistruct vmci_handle vmci_handle_arr_remove_entry(struct vmci_handle_arr *array, 7862306a36Sopenharmony_ci struct vmci_handle entry_handle) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci struct vmci_handle handle = VMCI_INVALID_HANDLE; 8162306a36Sopenharmony_ci u32 i; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci for (i = 0; i < array->size; i++) { 8462306a36Sopenharmony_ci if (vmci_handle_is_equal(array->entries[i], entry_handle)) { 8562306a36Sopenharmony_ci handle = array->entries[i]; 8662306a36Sopenharmony_ci array->size--; 8762306a36Sopenharmony_ci array->entries[i] = array->entries[array->size]; 8862306a36Sopenharmony_ci array->entries[array->size] = VMCI_INVALID_HANDLE; 8962306a36Sopenharmony_ci break; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci return handle; 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/* 9762306a36Sopenharmony_ci * Handle that was removed, VMCI_INVALID_HANDLE if array was empty. 9862306a36Sopenharmony_ci */ 9962306a36Sopenharmony_cistruct vmci_handle vmci_handle_arr_remove_tail(struct vmci_handle_arr *array) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci struct vmci_handle handle = VMCI_INVALID_HANDLE; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci if (array->size) { 10462306a36Sopenharmony_ci array->size--; 10562306a36Sopenharmony_ci handle = array->entries[array->size]; 10662306a36Sopenharmony_ci array->entries[array->size] = VMCI_INVALID_HANDLE; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci return handle; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/* 11362306a36Sopenharmony_ci * Handle at given index, VMCI_INVALID_HANDLE if invalid index. 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_cistruct vmci_handle 11662306a36Sopenharmony_civmci_handle_arr_get_entry(const struct vmci_handle_arr *array, u32 index) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci if (unlikely(index >= array->size)) 11962306a36Sopenharmony_ci return VMCI_INVALID_HANDLE; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci return array->entries[index]; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cibool vmci_handle_arr_has_entry(const struct vmci_handle_arr *array, 12562306a36Sopenharmony_ci struct vmci_handle entry_handle) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci u32 i; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci for (i = 0; i < array->size; i++) 13062306a36Sopenharmony_ci if (vmci_handle_is_equal(array->entries[i], entry_handle)) 13162306a36Sopenharmony_ci return true; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci return false; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci/* 13762306a36Sopenharmony_ci * NULL if the array is empty. Otherwise, a pointer to the array 13862306a36Sopenharmony_ci * of VMCI handles in the handle array. 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_cistruct vmci_handle *vmci_handle_arr_get_handles(struct vmci_handle_arr *array) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci if (array->size) 14362306a36Sopenharmony_ci return array->entries; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci return NULL; 14662306a36Sopenharmony_ci} 147