1b484b26cSGeorge Zhang /*
2b484b26cSGeorge Zhang  * VMware VMCI Driver
3b484b26cSGeorge Zhang  *
4b484b26cSGeorge Zhang  * Copyright (C) 2012 VMware, Inc. All rights reserved.
5b484b26cSGeorge Zhang  *
6b484b26cSGeorge Zhang  * This program is free software; you can redistribute it and/or modify it
7b484b26cSGeorge Zhang  * under the terms of the GNU General Public License as published by the
8b484b26cSGeorge Zhang  * Free Software Foundation version 2 and no later version.
9b484b26cSGeorge Zhang  *
10b484b26cSGeorge Zhang  * This program is distributed in the hope that it will be useful, but
11b484b26cSGeorge Zhang  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12b484b26cSGeorge Zhang  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13b484b26cSGeorge Zhang  * for more details.
14b484b26cSGeorge Zhang  */
15b484b26cSGeorge Zhang 
16b484b26cSGeorge Zhang #include <linux/slab.h>
17b484b26cSGeorge Zhang #include "vmci_handle_array.h"
18b484b26cSGeorge Zhang 
19b484b26cSGeorge Zhang static size_t handle_arr_calc_size(size_t capacity)
20b484b26cSGeorge Zhang {
21b484b26cSGeorge Zhang 	return sizeof(struct vmci_handle_arr) +
22b484b26cSGeorge Zhang 	    capacity * sizeof(struct vmci_handle);
23b484b26cSGeorge Zhang }
24b484b26cSGeorge Zhang 
25b484b26cSGeorge Zhang struct vmci_handle_arr *vmci_handle_arr_create(size_t capacity)
26b484b26cSGeorge Zhang {
27b484b26cSGeorge Zhang 	struct vmci_handle_arr *array;
28b484b26cSGeorge Zhang 
29b484b26cSGeorge Zhang 	if (capacity == 0)
30b484b26cSGeorge Zhang 		capacity = VMCI_HANDLE_ARRAY_DEFAULT_SIZE;
31b484b26cSGeorge Zhang 
32b484b26cSGeorge Zhang 	array = kmalloc(handle_arr_calc_size(capacity), GFP_ATOMIC);
33b484b26cSGeorge Zhang 	if (!array)
34b484b26cSGeorge Zhang 		return NULL;
35b484b26cSGeorge Zhang 
36b484b26cSGeorge Zhang 	array->capacity = capacity;
37b484b26cSGeorge Zhang 	array->size = 0;
38b484b26cSGeorge Zhang 
39b484b26cSGeorge Zhang 	return array;
40b484b26cSGeorge Zhang }
41b484b26cSGeorge Zhang 
42b484b26cSGeorge Zhang void vmci_handle_arr_destroy(struct vmci_handle_arr *array)
43b484b26cSGeorge Zhang {
44b484b26cSGeorge Zhang 	kfree(array);
45b484b26cSGeorge Zhang }
46b484b26cSGeorge Zhang 
47b484b26cSGeorge Zhang void vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr,
48b484b26cSGeorge Zhang 				  struct vmci_handle handle)
49b484b26cSGeorge Zhang {
50b484b26cSGeorge Zhang 	struct vmci_handle_arr *array = *array_ptr;
51b484b26cSGeorge Zhang 
52b484b26cSGeorge Zhang 	if (unlikely(array->size >= array->capacity)) {
53b484b26cSGeorge Zhang 		/* reallocate. */
54b484b26cSGeorge Zhang 		struct vmci_handle_arr *new_array;
55b484b26cSGeorge Zhang 		size_t new_capacity = array->capacity * VMCI_ARR_CAP_MULT;
56b484b26cSGeorge Zhang 		size_t new_size = handle_arr_calc_size(new_capacity);
57b484b26cSGeorge Zhang 
58b484b26cSGeorge Zhang 		new_array = krealloc(array, new_size, GFP_ATOMIC);
59b484b26cSGeorge Zhang 		if (!new_array)
60b484b26cSGeorge Zhang 			return;
61b484b26cSGeorge Zhang 
62b484b26cSGeorge Zhang 		new_array->capacity = new_capacity;
63b484b26cSGeorge Zhang 		*array_ptr = array = new_array;
64b484b26cSGeorge Zhang 	}
65b484b26cSGeorge Zhang 
66b484b26cSGeorge Zhang 	array->entries[array->size] = handle;
67b484b26cSGeorge Zhang 	array->size++;
68b484b26cSGeorge Zhang }
69b484b26cSGeorge Zhang 
70b484b26cSGeorge Zhang /*
71b484b26cSGeorge Zhang  * Handle that was removed, VMCI_INVALID_HANDLE if entry not found.
72b484b26cSGeorge Zhang  */
73b484b26cSGeorge Zhang struct vmci_handle vmci_handle_arr_remove_entry(struct vmci_handle_arr *array,
74b484b26cSGeorge Zhang 						struct vmci_handle entry_handle)
75b484b26cSGeorge Zhang {
76b484b26cSGeorge Zhang 	struct vmci_handle handle = VMCI_INVALID_HANDLE;
77b484b26cSGeorge Zhang 	size_t i;
78b484b26cSGeorge Zhang 
79b484b26cSGeorge Zhang 	for (i = 0; i < array->size; i++) {
80b484b26cSGeorge Zhang 		if (vmci_handle_is_equal(array->entries[i], entry_handle)) {
81b484b26cSGeorge Zhang 			handle = array->entries[i];
82b484b26cSGeorge Zhang 			array->size--;
83b484b26cSGeorge Zhang 			array->entries[i] = array->entries[array->size];
84b484b26cSGeorge Zhang 			array->entries[array->size] = VMCI_INVALID_HANDLE;
85b484b26cSGeorge Zhang 			break;
86b484b26cSGeorge Zhang 		}
87b484b26cSGeorge Zhang 	}
88b484b26cSGeorge Zhang 
89b484b26cSGeorge Zhang 	return handle;
90b484b26cSGeorge Zhang }
91b484b26cSGeorge Zhang 
92b484b26cSGeorge Zhang /*
93b484b26cSGeorge Zhang  * Handle that was removed, VMCI_INVALID_HANDLE if array was empty.
94b484b26cSGeorge Zhang  */
95b484b26cSGeorge Zhang struct vmci_handle vmci_handle_arr_remove_tail(struct vmci_handle_arr *array)
96b484b26cSGeorge Zhang {
97b484b26cSGeorge Zhang 	struct vmci_handle handle = VMCI_INVALID_HANDLE;
98b484b26cSGeorge Zhang 
99b484b26cSGeorge Zhang 	if (array->size) {
100b484b26cSGeorge Zhang 		array->size--;
101b484b26cSGeorge Zhang 		handle = array->entries[array->size];
102b484b26cSGeorge Zhang 		array->entries[array->size] = VMCI_INVALID_HANDLE;
103b484b26cSGeorge Zhang 	}
104b484b26cSGeorge Zhang 
105b484b26cSGeorge Zhang 	return handle;
106b484b26cSGeorge Zhang }
107b484b26cSGeorge Zhang 
108b484b26cSGeorge Zhang /*
109b484b26cSGeorge Zhang  * Handle at given index, VMCI_INVALID_HANDLE if invalid index.
110b484b26cSGeorge Zhang  */
111b484b26cSGeorge Zhang struct vmci_handle
112b484b26cSGeorge Zhang vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, size_t index)
113b484b26cSGeorge Zhang {
114b484b26cSGeorge Zhang 	if (unlikely(index >= array->size))
115b484b26cSGeorge Zhang 		return VMCI_INVALID_HANDLE;
116b484b26cSGeorge Zhang 
117b484b26cSGeorge Zhang 	return array->entries[index];
118b484b26cSGeorge Zhang }
119b484b26cSGeorge Zhang 
120b484b26cSGeorge Zhang bool vmci_handle_arr_has_entry(const struct vmci_handle_arr *array,
121b484b26cSGeorge Zhang 			       struct vmci_handle entry_handle)
122b484b26cSGeorge Zhang {
123b484b26cSGeorge Zhang 	size_t i;
124b484b26cSGeorge Zhang 
125b484b26cSGeorge Zhang 	for (i = 0; i < array->size; i++)
126b484b26cSGeorge Zhang 		if (vmci_handle_is_equal(array->entries[i], entry_handle))
127b484b26cSGeorge Zhang 			return true;
128b484b26cSGeorge Zhang 
129b484b26cSGeorge Zhang 	return false;
130b484b26cSGeorge Zhang }
131b484b26cSGeorge Zhang 
132b484b26cSGeorge Zhang /*
133b484b26cSGeorge Zhang  * NULL if the array is empty. Otherwise, a pointer to the array
134b484b26cSGeorge Zhang  * of VMCI handles in the handle array.
135b484b26cSGeorge Zhang  */
136b484b26cSGeorge Zhang struct vmci_handle *vmci_handle_arr_get_handles(struct vmci_handle_arr *array)
137b484b26cSGeorge Zhang {
138b484b26cSGeorge Zhang 	if (array->size)
139b484b26cSGeorge Zhang 		return array->entries;
140b484b26cSGeorge Zhang 
141b484b26cSGeorge Zhang 	return NULL;
142b484b26cSGeorge Zhang }
143