/* * VMware VMCI Driver * * Copyright (C) 2012 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include <linux/slab.h> #include "vmci_handle_array.h" static size_t handle_arr_calc_size(size_t capacity) { return sizeof(struct vmci_handle_arr) + capacity * sizeof(struct vmci_handle); } struct vmci_handle_arr *vmci_handle_arr_create(size_t capacity) { struct vmci_handle_arr *array; if (capacity == 0) capacity = VMCI_HANDLE_ARRAY_DEFAULT_SIZE; array = kmalloc(handle_arr_calc_size(capacity), GFP_ATOMIC); if (!array) return NULL; array->capacity = capacity; array->size = 0; return array; } void vmci_handle_arr_destroy(struct vmci_handle_arr *array) { kfree(array); } void vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr, struct vmci_handle handle) { struct vmci_handle_arr *array = *array_ptr; if (unlikely(array->size >= array->capacity)) { /* reallocate. */ struct vmci_handle_arr *new_array; size_t new_capacity = array->capacity * VMCI_ARR_CAP_MULT; size_t new_size = handle_arr_calc_size(new_capacity); new_array = krealloc(array, new_size, GFP_ATOMIC); if (!new_array) return; new_array->capacity = new_capacity; *array_ptr = array = new_array; } array->entries[array->size] = handle; array->size++; } /* * Handle that was removed, VMCI_INVALID_HANDLE if entry not found. */ struct vmci_handle vmci_handle_arr_remove_entry(struct vmci_handle_arr *array, struct vmci_handle entry_handle) { struct vmci_handle handle = VMCI_INVALID_HANDLE; size_t i; for (i = 0; i < array->size; i++) { if (vmci_handle_is_equal(array->entries[i], entry_handle)) { handle = array->entries[i]; array->size--; array->entries[i] = array->entries[array->size]; array->entries[array->size] = VMCI_INVALID_HANDLE; break; } } return handle; } /* * Handle that was removed, VMCI_INVALID_HANDLE if array was empty. */ struct vmci_handle vmci_handle_arr_remove_tail(struct vmci_handle_arr *array) { struct vmci_handle handle = VMCI_INVALID_HANDLE; if (array->size) { array->size--; handle = array->entries[array->size]; array->entries[array->size] = VMCI_INVALID_HANDLE; } return handle; } /* * Handle at given index, VMCI_INVALID_HANDLE if invalid index. */ struct vmci_handle vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, size_t index) { if (unlikely(index >= array->size)) return VMCI_INVALID_HANDLE; return array->entries[index]; } bool vmci_handle_arr_has_entry(const struct vmci_handle_arr *array, struct vmci_handle entry_handle) { size_t i; for (i = 0; i < array->size; i++) if (vmci_handle_is_equal(array->entries[i], entry_handle)) return true; return false; } /* * NULL if the array is empty. Otherwise, a pointer to the array * of VMCI handles in the handle array. */ struct vmci_handle *vmci_handle_arr_get_handles(struct vmci_handle_arr *array) { if (array->size) return array->entries; return NULL; }