2019-05-29 16:57:36 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2013-01-08 15:54:39 -08:00
/*
* VMware VMCI Driver
*
* Copyright ( C ) 2012 VMware , Inc . All rights reserved .
*/
# include <linux/slab.h>
# include "vmci_handle_array.h"
2019-05-24 15:13:10 +00:00
static size_t handle_arr_calc_size ( u32 capacity )
2013-01-08 15:54:39 -08:00
{
2019-05-24 15:13:10 +00:00
return VMCI_HANDLE_ARRAY_HEADER_SIZE +
2013-01-08 15:54:39 -08:00
capacity * sizeof ( struct vmci_handle ) ;
}
2019-05-24 15:13:10 +00:00
struct vmci_handle_arr * vmci_handle_arr_create ( u32 capacity , u32 max_capacity )
2013-01-08 15:54:39 -08:00
{
struct vmci_handle_arr * array ;
2019-05-24 15:13:10 +00:00
if ( max_capacity = = 0 | | capacity > max_capacity )
return NULL ;
2013-01-08 15:54:39 -08:00
if ( capacity = = 0 )
2019-05-24 15:13:10 +00:00
capacity = min ( ( u32 ) VMCI_HANDLE_ARRAY_DEFAULT_CAPACITY ,
max_capacity ) ;
2013-01-08 15:54:39 -08:00
array = kmalloc ( handle_arr_calc_size ( capacity ) , GFP_ATOMIC ) ;
if ( ! array )
return NULL ;
array - > capacity = capacity ;
2019-05-24 15:13:10 +00:00
array - > max_capacity = max_capacity ;
2013-01-08 15:54:39 -08:00
array - > size = 0 ;
return array ;
}
void vmci_handle_arr_destroy ( struct vmci_handle_arr * array )
{
kfree ( array ) ;
}
2019-05-24 15:13:10 +00:00
int vmci_handle_arr_append_entry ( struct vmci_handle_arr * * array_ptr ,
struct vmci_handle handle )
2013-01-08 15:54:39 -08:00
{
struct vmci_handle_arr * array = * array_ptr ;
if ( unlikely ( array - > size > = array - > capacity ) ) {
/* reallocate. */
struct vmci_handle_arr * new_array ;
2019-05-24 15:13:10 +00:00
u32 capacity_bump = min ( array - > max_capacity - array - > capacity ,
array - > capacity ) ;
size_t new_size = handle_arr_calc_size ( array - > capacity +
capacity_bump ) ;
if ( array - > size > = array - > max_capacity )
return VMCI_ERROR_NO_MEM ;
2013-01-08 15:54:39 -08:00
new_array = krealloc ( array , new_size , GFP_ATOMIC ) ;
if ( ! new_array )
2019-05-24 15:13:10 +00:00
return VMCI_ERROR_NO_MEM ;
2013-01-08 15:54:39 -08:00
2019-05-24 15:13:10 +00:00
new_array - > capacity + = capacity_bump ;
2013-01-08 15:54:39 -08:00
* array_ptr = array = new_array ;
}
array - > entries [ array - > size ] = handle ;
array - > size + + ;
2019-05-24 15:13:10 +00:00
return VMCI_SUCCESS ;
2013-01-08 15:54:39 -08:00
}
/*
* 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 ;
2019-05-24 15:13:10 +00:00
u32 i ;
2013-01-08 15:54:39 -08:00
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
2019-05-24 15:13:10 +00:00
vmci_handle_arr_get_entry ( const struct vmci_handle_arr * array , u32 index )
2013-01-08 15:54:39 -08:00
{
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 )
{
2019-05-24 15:13:10 +00:00
u32 i ;
2013-01-08 15:54:39 -08:00
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 ;
}