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