Viewing: lu_tgt_pool.c
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved
* Use is subject to license terms.
*
* Copyright (c) 2012, 2017, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
*
* This file handles creation, lookup, and removal of pools themselves, as
* well as adding and removing targets to pools.
*
* Author: Jacques-Charles LAFOUCRIERE <jc.lafoucriere@cea.fr>
* Author: Alex Lyashkov <Alexey.Lyashkov@Sun.COM>
* Author: Nathaniel Rutman <Nathan.Rutman@Sun.COM>
*/
#define DEBUG_SUBSYSTEM S_CLASS
#include <obd_target.h>
#include <obd_support.h>
#include <lu_object.h>
#define POOL_INIT_COUNT 2
/**
* lu_tgt_pool_init() - Initialize the pool data structures at startup.
* @op: pool structure
* @count: initial size of the target op_array[] array
*
* Allocate and initialize the pool data structures with the specified
* array size. If pool count is not specified (\a count == 0), then
* POOL_INIT_COUNT will be used. Allocating a non-zero initial array
* size avoids the need to reallocate as new pools are added.
*
* Return:
* * %0 indicates successful pool initialization
* * %negative error number on failure
*/
int lu_tgt_pool_init(struct lu_tgt_pool *op, unsigned int count)
{
ENTRY;
if (count == 0)
count = POOL_INIT_COUNT;
op->op_array = NULL;
op->op_count = 0;
init_rwsem(&op->op_rw_sem);
op->op_size = count * sizeof(op->op_array[0]);
OBD_ALLOC(op->op_array, op->op_size);
if (op->op_array == NULL) {
op->op_size = 0;
RETURN(-ENOMEM);
}
EXIT;
return 0;
}
EXPORT_SYMBOL(lu_tgt_pool_init);
/**
* lu_tgt_pool_extend() - Inc op_array size to hold more targets in this pool
* @op: pool structure
* @min_count: minimum number of entries to handle
*
* The size is increased to at least @min_count, but may be larger
* for an existing pool since ->op_array[] is growing exponentially.
* Caller must hold write op_rwlock.
*
* Return:
* * %0 on success
* * %negative error number on failure.
*/
int lu_tgt_pool_extend(struct lu_tgt_pool *op, unsigned int min_count)
{
__u32 *new;
__u32 new_size;
LASSERT(min_count != 0);
if (op->op_count * sizeof(op->op_array[0]) < op->op_size)
return 0;
new_size = max_t(__u32, min_count * sizeof(op->op_array[0]),
2 * op->op_size);
OBD_ALLOC(new, new_size);
if (new == NULL)
return -ENOMEM;
/* copy old array to new one */
memcpy(new, op->op_array, op->op_size);
OBD_FREE(op->op_array, op->op_size);
op->op_array = new;
op->op_size = new_size;
return 0;
}
EXPORT_SYMBOL(lu_tgt_pool_extend);
/**
* lu_tgt_pool_add_lock() - Add a new target to an existing pool.
* @op: target pool to add new entry
* @idx: pool index number to add to the @op array
* @min_count: minimum number of entries to expect in the pool
* @lock: if true protect lu_tgt_pool use
*
* Add a new target device to the pool previously created and returned by
* lod_pool_new(). Each target can only be in each pool at most one time.
*
* Return:
* * %0 if target could be added to the pool
* * %negative error if target @idx was not added
*/
int lu_tgt_pool_add_lock(struct lu_tgt_pool *op, __u32 idx,
unsigned int min_count, bool lock)
{
unsigned int i;
int rc = 0;
ENTRY;
if (lock)
down_write(&op->op_rw_sem);
/* search ost in pool array */
for (i = 0; i < op->op_count; i++) {
if (op->op_array[i] == idx)
GOTO(out, rc = -EEXIST);
}
rc = lu_tgt_pool_extend(op, min_count);
if (rc)
GOTO(out, rc);
/* ost not found we add it */
op->op_array[op->op_count] = idx;
op->op_count++;
EXIT;
out:
if (lock)
up_write(&op->op_rw_sem);
return rc;
}
EXPORT_SYMBOL(lu_tgt_pool_add_lock);
/**
* lu_tgt_pool_remove() - Remove an existing pool from the system.
* @op: pointer to the original data structure
* @idx: target index to be removed
*
* The specified pool must have previously been allocated by
* lod_pool_new() and not have any target members in the pool.
* If the removed target is not the last, compact the array
* to remove empty spaces.
*
* Return:
* * %0 on success
* * %negative error number on failure
*/
int lu_tgt_pool_remove(struct lu_tgt_pool *op, __u32 idx)
{
unsigned int i;
ENTRY;
down_write(&op->op_rw_sem);
for (i = 0; i < op->op_count; i++) {
if (op->op_array[i] == idx) {
memmove(&op->op_array[i], &op->op_array[i + 1],
(op->op_count - i - 1) *
sizeof(op->op_array[0]));
op->op_count--;
up_write(&op->op_rw_sem);
EXIT;
return 0;
}
}
up_write(&op->op_rw_sem);
RETURN(-EINVAL);
}
EXPORT_SYMBOL(lu_tgt_pool_remove);
int lu_tgt_check_index(int idx, struct lu_tgt_pool *osts)
{
int i, rc = -ENOENT;
ENTRY;
down_read(&osts->op_rw_sem);
for (i = 0; i < osts->op_count; i++) {
if (osts->op_array[i] == idx)
GOTO(out, rc = 0);
}
EXIT;
out:
up_read(&osts->op_rw_sem);
return rc;
}
EXPORT_SYMBOL(lu_tgt_check_index);
/**
* lu_tgt_pool_free() - Free pool after it was emptied and removed from /proc.
* @op: pool to be freed.
*
* Note that all of the child/target entries referenced by this pool
* must have been removed by lod_ost_pool_remove() before it can be
* deleted from memory.
*/
void lu_tgt_pool_free(struct lu_tgt_pool *op)
{
ENTRY;
if (op->op_size == 0)
RETURN_EXIT;
down_write(&op->op_rw_sem);
OBD_FREE(op->op_array, op->op_size);
op->op_array = NULL;
op->op_count = 0;
op->op_size = 0;
up_write(&op->op_rw_sem);
EXIT;
}
EXPORT_SYMBOL(lu_tgt_pool_free);