Merge pull request #133 from arutk/ajrutkow_async_counters
Extended reference counting
This commit is contained in:
commit
1c9fe96663
@ -160,27 +160,6 @@ bool ocf_cache_is_device_attached(ocf_cache_t cache);
|
|||||||
*/
|
*/
|
||||||
bool ocf_cache_is_running(ocf_cache_t cache);
|
bool ocf_cache_is_running(ocf_cache_t cache);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Wait for all IO to finish
|
|
||||||
*
|
|
||||||
* @param[in] cache Cache object
|
|
||||||
*/
|
|
||||||
void ocf_cache_wait_for_io_finish(ocf_cache_t cache);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Check if cache has any unfunished requests
|
|
||||||
*
|
|
||||||
* @param[in] cache Cache object
|
|
||||||
*/
|
|
||||||
bool ocf_cache_has_pending_requests(ocf_cache_t cache);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Check if cleaning triggered by eviction runs on the cache
|
|
||||||
*
|
|
||||||
* @param[in] cache Cache object
|
|
||||||
*/
|
|
||||||
bool ocf_cache_has_pending_cleaning(ocf_cache_t cache);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get cache mode of given cache object
|
* @brief Get cache mode of given cache object
|
||||||
*
|
*
|
||||||
|
@ -158,7 +158,7 @@ bool ocf_fallback_pt_is_on(ocf_cache_t cache)
|
|||||||
|
|
||||||
static inline bool ocf_seq_cutoff_is_on(ocf_cache_t cache)
|
static inline bool ocf_seq_cutoff_is_on(ocf_cache_t cache)
|
||||||
{
|
{
|
||||||
if (!env_atomic_read(&cache->attached))
|
if (!ocf_cache_is_device_attached(cache))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return (cache->device->freelist_part->curr_size <= SEQ_CUTOFF_FULL_MARGIN);
|
return (cache->device->freelist_part->curr_size <= SEQ_CUTOFF_FULL_MARGIN);
|
||||||
|
@ -273,9 +273,9 @@ void evp_lru_rm_cline(ocf_cache_t cache, ocf_cache_line_t cline)
|
|||||||
|
|
||||||
static void evp_lru_clean_end(void *private_data, int error)
|
static void evp_lru_clean_end(void *private_data, int error)
|
||||||
{
|
{
|
||||||
env_atomic *cleaning_in_progress = private_data;
|
struct ocf_refcnt *counter = private_data;
|
||||||
|
|
||||||
env_atomic_set(cleaning_in_progress, 0);
|
ocf_refcnt_dec(counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int evp_lru_clean_getter(ocf_cache_t cache,
|
static int evp_lru_clean_getter(ocf_cache_t cache,
|
||||||
@ -309,19 +309,13 @@ static int evp_lru_clean_getter(ocf_cache_t cache,
|
|||||||
static void evp_lru_clean(ocf_cache_t cache, ocf_queue_t io_queue,
|
static void evp_lru_clean(ocf_cache_t cache, ocf_queue_t io_queue,
|
||||||
ocf_part_id_t part_id, uint32_t count)
|
ocf_part_id_t part_id, uint32_t count)
|
||||||
{
|
{
|
||||||
env_atomic *progress = &cache->cleaning[part_id];
|
struct ocf_refcnt *counter = &cache->refcnt.cleaning[part_id];
|
||||||
struct ocf_user_part *part = &cache->user_parts[part_id];
|
struct ocf_user_part *part = &cache->user_parts[part_id];
|
||||||
|
|
||||||
if (ocf_mngt_is_cache_locked(cache))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (env_atomic_cmpxchg(progress, 0, 1) == 0) {
|
|
||||||
/* Initialize attributes for cleaner */
|
|
||||||
struct ocf_cleaner_attribs attribs = {
|
struct ocf_cleaner_attribs attribs = {
|
||||||
.cache_line_lock = true,
|
.cache_line_lock = true,
|
||||||
.do_sort = true,
|
.do_sort = true,
|
||||||
|
|
||||||
.cmpl_context = progress,
|
.cmpl_context = counter,
|
||||||
.cmpl_fn = evp_lru_clean_end,
|
.cmpl_fn = evp_lru_clean_end,
|
||||||
|
|
||||||
.getter = evp_lru_clean_getter,
|
.getter = evp_lru_clean_getter,
|
||||||
@ -332,10 +326,24 @@ static void evp_lru_clean(ocf_cache_t cache, ocf_queue_t io_queue,
|
|||||||
|
|
||||||
.io_queue = io_queue
|
.io_queue = io_queue
|
||||||
};
|
};
|
||||||
|
int cnt;
|
||||||
|
|
||||||
|
if (ocf_mngt_is_cache_locked(cache))
|
||||||
|
return;
|
||||||
|
|
||||||
|
cnt = ocf_refcnt_inc(counter);
|
||||||
|
if (!cnt) {
|
||||||
|
/* cleaner disabled by mngmt operation */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cnt > 1) {
|
||||||
|
/* cleaning already running for this partition */
|
||||||
|
ocf_refcnt_dec(counter);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ocf_cleaner_fire(cache, &attribs);
|
ocf_cleaner_fire(cache, &attribs);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void evp_lru_zero_line_complete(struct ocf_request *ocf_req, int error)
|
static void evp_lru_zero_line_complete(struct ocf_request *ocf_req, int error)
|
||||||
{
|
{
|
||||||
@ -354,7 +362,15 @@ static void evp_lru_zero_line(ocf_cache_t cache, ocf_queue_t io_queue,
|
|||||||
|
|
||||||
req = ocf_req_new(io_queue, &cache->core[id], addr,
|
req = ocf_req_new(io_queue, &cache->core[id], addr,
|
||||||
ocf_line_size(cache), OCF_WRITE);
|
ocf_line_size(cache), OCF_WRITE);
|
||||||
if (req) {
|
if (!req)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (req->d2c) {
|
||||||
|
/* cache device is being detached */
|
||||||
|
ocf_req_put(req);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
req->info.internal = true;
|
req->info.internal = true;
|
||||||
req->complete = evp_lru_zero_line_complete;
|
req->complete = evp_lru_zero_line_complete;
|
||||||
|
|
||||||
@ -362,7 +378,6 @@ static void evp_lru_zero_line(ocf_cache_t cache, ocf_queue_t io_queue,
|
|||||||
|
|
||||||
ocf_engine_zero_line(req);
|
ocf_engine_zero_line(req);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
bool evp_lru_can_evict(ocf_cache_t cache)
|
bool evp_lru_can_evict(ocf_cache_t cache)
|
||||||
{
|
{
|
||||||
|
@ -209,6 +209,8 @@ static void __init_partitions(ocf_cache_t cache)
|
|||||||
|
|
||||||
/* Add other partition to the cache and make it as dummy */
|
/* Add other partition to the cache and make it as dummy */
|
||||||
for (i_part = 0; i_part < OCF_IO_CLASS_MAX; i_part++) {
|
for (i_part = 0; i_part < OCF_IO_CLASS_MAX; i_part++) {
|
||||||
|
ocf_refcnt_freeze(&cache->refcnt.cleaning[i_part]);
|
||||||
|
|
||||||
if (i_part == PARTITION_DEFAULT)
|
if (i_part == PARTITION_DEFAULT)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -559,9 +561,12 @@ static int _ocf_mngt_init_new_cache(struct ocf_cachemng_init_params *params)
|
|||||||
|
|
||||||
INIT_LIST_HEAD(&cache->list);
|
INIT_LIST_HEAD(&cache->list);
|
||||||
list_add_tail(&cache->list, ¶ms->ctx->caches);
|
list_add_tail(&cache->list, ¶ms->ctx->caches);
|
||||||
env_atomic_set(&cache->ref_count, 1);
|
ocf_refcnt_inc(&cache->refcnt.cache);
|
||||||
cache->owner = params->ctx;
|
cache->owner = params->ctx;
|
||||||
|
|
||||||
|
/* start with freezed metadata ref counter to indicate detached device*/
|
||||||
|
ocf_refcnt_freeze(&cache->refcnt.metadata);
|
||||||
|
|
||||||
/* Copy all required initialization parameters */
|
/* Copy all required initialization parameters */
|
||||||
cache->cache_id = params->id;
|
cache->cache_id = params->id;
|
||||||
|
|
||||||
@ -1216,7 +1221,7 @@ static int _ocf_mngt_cache_start(ocf_ctx_t ctx, ocf_cache_t *cache,
|
|||||||
cache_unlock convention. User is expected to call
|
cache_unlock convention. User is expected to call
|
||||||
ocf_mngt_cache_unlock in future which would up the
|
ocf_mngt_cache_unlock in future which would up the
|
||||||
semaphore as well as decrement ref_count. */
|
semaphore as well as decrement ref_count. */
|
||||||
env_atomic_inc(&(*cache)->ref_count);
|
ocf_refcnt_inc(&(*cache)->refcnt.cache);
|
||||||
} else {
|
} else {
|
||||||
/* User did not request to lock cache instance after creation -
|
/* User did not request to lock cache instance after creation -
|
||||||
up the semaphore here since we have acquired the lock to
|
up the semaphore here since we have acquired the lock to
|
||||||
@ -1239,7 +1244,6 @@ static void _ocf_mng_cache_set_valid(ocf_cache_t cache)
|
|||||||
* Clear initialization state and set the valid bit so we know
|
* Clear initialization state and set the valid bit so we know
|
||||||
* its in use.
|
* its in use.
|
||||||
*/
|
*/
|
||||||
cache->valid_ocf_cache_device_t = 1;
|
|
||||||
env_bit_clear(ocf_cache_state_initializing, &cache->cache_state);
|
env_bit_clear(ocf_cache_state_initializing, &cache->cache_state);
|
||||||
env_bit_set(ocf_cache_state_running, &cache->cache_state);
|
env_bit_set(ocf_cache_state_running, &cache->cache_state);
|
||||||
}
|
}
|
||||||
@ -1511,9 +1515,8 @@ static void _ocf_mngt_attach_post_init(ocf_pipeline_t pipeline,
|
|||||||
context->flags.cleaner_started = true;
|
context->flags.cleaner_started = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
env_waitqueue_init(&cache->pending_cache_wq);
|
ocf_cleaner_refcnt_unfreeze(cache);
|
||||||
|
ocf_refcnt_unfreeze(&cache->refcnt.metadata);
|
||||||
env_atomic_set(&cache->attached, 1);
|
|
||||||
|
|
||||||
ocf_pipeline_next(context->pipeline);
|
ocf_pipeline_next(context->pipeline);
|
||||||
}
|
}
|
||||||
@ -1769,7 +1772,6 @@ static void _ocf_mngt_cache_unplug_complete(void *priv, int error)
|
|||||||
|
|
||||||
env_vfree(cache->device);
|
env_vfree(cache->device);
|
||||||
cache->device = NULL;
|
cache->device = NULL;
|
||||||
env_atomic_set(&cache->attached, 0);
|
|
||||||
|
|
||||||
/* TODO: this should be removed from detach after 'attached' stats
|
/* TODO: this should be removed from detach after 'attached' stats
|
||||||
are better separated in statistics */
|
are better separated in statistics */
|
||||||
@ -1907,15 +1909,22 @@ struct ocf_mngt_cache_stop_context {
|
|||||||
int cache_write_error;
|
int cache_write_error;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ocf_mngt_cache_stop_wait_io(ocf_pipeline_t pipeline,
|
static void ocf_mngt_cache_stop_wait_metadata_io_finish(void *priv)
|
||||||
|
{
|
||||||
|
struct ocf_mngt_cache_stop_context *context = priv;
|
||||||
|
|
||||||
|
ocf_pipeline_next(context->pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_mngt_cache_stop_wait_metadata_io(ocf_pipeline_t pipeline,
|
||||||
void *priv, ocf_pipeline_arg_t arg)
|
void *priv, ocf_pipeline_arg_t arg)
|
||||||
{
|
{
|
||||||
struct ocf_mngt_cache_stop_context *context = priv;
|
struct ocf_mngt_cache_stop_context *context = priv;
|
||||||
ocf_cache_t cache = context->cache;
|
ocf_cache_t cache = context->cache;
|
||||||
|
|
||||||
/* TODO: Make this asynchronous! */
|
ocf_refcnt_freeze(&cache->refcnt.metadata);
|
||||||
ocf_cache_wait_for_io_finish(cache);
|
ocf_refcnt_register_zero_cb(&cache->refcnt.metadata,
|
||||||
ocf_pipeline_next(pipeline);
|
ocf_mngt_cache_stop_wait_metadata_io_finish, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ocf_mngt_cache_stop_remove_cores(ocf_pipeline_t pipeline,
|
static void ocf_mngt_cache_stop_remove_cores(ocf_pipeline_t pipeline,
|
||||||
@ -1960,7 +1969,7 @@ static void ocf_mngt_cache_stop_unplug(ocf_pipeline_t pipeline,
|
|||||||
struct ocf_mngt_cache_stop_context *context = priv;
|
struct ocf_mngt_cache_stop_context *context = priv;
|
||||||
ocf_cache_t cache = context->cache;
|
ocf_cache_t cache = context->cache;
|
||||||
|
|
||||||
if (!env_atomic_read(&cache->attached))
|
if (!ocf_cache_is_device_attached(cache))
|
||||||
OCF_PL_NEXT_RET(pipeline);
|
OCF_PL_NEXT_RET(pipeline);
|
||||||
|
|
||||||
_ocf_mngt_cache_unplug(cache, true, &context->unplug_context,
|
_ocf_mngt_cache_unplug(cache, true, &context->unplug_context,
|
||||||
@ -1990,11 +1999,14 @@ static void ocf_mngt_cache_stop_finish(ocf_pipeline_t pipeline,
|
|||||||
if (!error) {
|
if (!error) {
|
||||||
env_mutex_lock(&ctx->lock);
|
env_mutex_lock(&ctx->lock);
|
||||||
/* Mark device uninitialized */
|
/* Mark device uninitialized */
|
||||||
cache->valid_ocf_cache_device_t = 0;
|
ocf_refcnt_freeze(&cache->refcnt.cache);
|
||||||
/* Remove cache from the list */
|
/* Remove cache from the list */
|
||||||
list_del(&cache->list);
|
list_del(&cache->list);
|
||||||
env_mutex_unlock(&ctx->lock);
|
env_mutex_unlock(&ctx->lock);
|
||||||
} else {
|
} else {
|
||||||
|
/* undo metadata counter freeze */
|
||||||
|
ocf_refcnt_unfreeze(&cache->refcnt.metadata);
|
||||||
|
|
||||||
env_bit_clear(ocf_cache_state_stopping, &cache->cache_state);
|
env_bit_clear(ocf_cache_state_stopping, &cache->cache_state);
|
||||||
env_bit_set(ocf_cache_state_running, &cache->cache_state);
|
env_bit_set(ocf_cache_state_running, &cache->cache_state);
|
||||||
}
|
}
|
||||||
@ -2028,7 +2040,7 @@ struct ocf_pipeline_properties ocf_mngt_cache_stop_pipeline_properties = {
|
|||||||
.priv_size = sizeof(struct ocf_mngt_cache_stop_context),
|
.priv_size = sizeof(struct ocf_mngt_cache_stop_context),
|
||||||
.finish = ocf_mngt_cache_stop_finish,
|
.finish = ocf_mngt_cache_stop_finish,
|
||||||
.steps = {
|
.steps = {
|
||||||
OCF_PL_STEP(ocf_mngt_cache_stop_wait_io),
|
OCF_PL_STEP(ocf_mngt_cache_stop_wait_metadata_io),
|
||||||
OCF_PL_STEP(ocf_mngt_cache_stop_remove_cores),
|
OCF_PL_STEP(ocf_mngt_cache_stop_remove_cores),
|
||||||
OCF_PL_STEP(ocf_mngt_cache_stop_unplug),
|
OCF_PL_STEP(ocf_mngt_cache_stop_unplug),
|
||||||
OCF_PL_STEP(ocf_mngt_cache_stop_put_io_queues),
|
OCF_PL_STEP(ocf_mngt_cache_stop_put_io_queues),
|
||||||
@ -2275,6 +2287,7 @@ struct ocf_mngt_cache_detach_context {
|
|||||||
ocf_pipeline_t pipeline;
|
ocf_pipeline_t pipeline;
|
||||||
ocf_cache_t cache;
|
ocf_cache_t cache;
|
||||||
int cache_write_error;
|
int cache_write_error;
|
||||||
|
struct ocf_cleaner_wait_context cleaner_wait;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ocf_mngt_cache_detach_flush_cmpl(ocf_cache_t cache,
|
static void ocf_mngt_cache_detach_flush_cmpl(ocf_cache_t cache,
|
||||||
@ -2294,19 +2307,39 @@ static void ocf_mngt_cache_detach_flush(ocf_pipeline_t pipeline,
|
|||||||
ocf_mngt_cache_flush(cache, ocf_mngt_cache_detach_flush_cmpl, context);
|
ocf_mngt_cache_flush(cache, ocf_mngt_cache_detach_flush_cmpl, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ocf_mngt_cache_detach_wait_pending(ocf_pipeline_t pipeline,
|
static void ocf_mngt_cache_detach_stop_cache_io_finish(void *priv)
|
||||||
|
{
|
||||||
|
struct ocf_mngt_cache_detach_context *context = priv;
|
||||||
|
ocf_pipeline_next(context->pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_mngt_cache_detach_stop_cache_io(ocf_pipeline_t pipeline,
|
||||||
void *priv, ocf_pipeline_arg_t arg)
|
void *priv, ocf_pipeline_arg_t arg)
|
||||||
{
|
{
|
||||||
struct ocf_mngt_cache_detach_context *context = priv;
|
struct ocf_mngt_cache_detach_context *context = priv;
|
||||||
ocf_cache_t cache = context->cache;
|
ocf_cache_t cache = context->cache;
|
||||||
|
|
||||||
env_atomic_set(&cache->attached, 0);
|
ocf_refcnt_freeze(&cache->refcnt.metadata);
|
||||||
|
ocf_refcnt_register_zero_cb(&cache->refcnt.metadata,
|
||||||
|
ocf_mngt_cache_detach_stop_cache_io_finish, context);
|
||||||
|
}
|
||||||
|
|
||||||
/* FIXME: This should be asynchronous! */
|
static void ocf_mngt_cache_detach_stop_cleaner_io_finish(void *priv)
|
||||||
env_waitqueue_wait(cache->pending_cache_wq,
|
{
|
||||||
!env_atomic_read(&cache->pending_cache_requests));
|
ocf_pipeline_t pipeline = priv;
|
||||||
|
ocf_pipeline_next(pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
ocf_pipeline_next(context->pipeline);
|
static void ocf_mngt_cache_detach_stop_cleaner_io(ocf_pipeline_t pipeline,
|
||||||
|
void *priv, ocf_pipeline_arg_t arg)
|
||||||
|
{
|
||||||
|
struct ocf_mngt_cache_detach_context *context = priv;
|
||||||
|
ocf_cache_t cache = context->cache;
|
||||||
|
|
||||||
|
ocf_cleaner_refcnt_freeze(cache);
|
||||||
|
ocf_cleaner_refcnt_register_zero_cb(cache, &context->cleaner_wait,
|
||||||
|
ocf_mngt_cache_detach_stop_cleaner_io_finish,
|
||||||
|
pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ocf_mngt_cache_detach_update_metadata(ocf_pipeline_t pipeline,
|
static void ocf_mngt_cache_detach_update_metadata(ocf_pipeline_t pipeline,
|
||||||
@ -2360,7 +2393,7 @@ static void ocf_mngt_cache_detach_finish(ocf_pipeline_t pipeline,
|
|||||||
struct ocf_mngt_cache_detach_context *context = priv;
|
struct ocf_mngt_cache_detach_context *context = priv;
|
||||||
ocf_cache_t cache = context->cache;
|
ocf_cache_t cache = context->cache;
|
||||||
|
|
||||||
ocf_refcnt_unfreeze(&cache->dirty);
|
ocf_refcnt_unfreeze(&cache->refcnt.dirty);
|
||||||
|
|
||||||
if (!error) {
|
if (!error) {
|
||||||
if (!context->cache_write_error) {
|
if (!context->cache_write_error) {
|
||||||
@ -2386,7 +2419,8 @@ struct ocf_pipeline_properties ocf_mngt_cache_detach_pipeline_properties = {
|
|||||||
.finish = ocf_mngt_cache_detach_finish,
|
.finish = ocf_mngt_cache_detach_finish,
|
||||||
.steps = {
|
.steps = {
|
||||||
OCF_PL_STEP(ocf_mngt_cache_detach_flush),
|
OCF_PL_STEP(ocf_mngt_cache_detach_flush),
|
||||||
OCF_PL_STEP(ocf_mngt_cache_detach_wait_pending),
|
OCF_PL_STEP(ocf_mngt_cache_detach_stop_cache_io),
|
||||||
|
OCF_PL_STEP(ocf_mngt_cache_detach_stop_cleaner_io),
|
||||||
OCF_PL_STEP(ocf_mngt_cache_detach_update_metadata),
|
OCF_PL_STEP(ocf_mngt_cache_detach_update_metadata),
|
||||||
OCF_PL_STEP(ocf_mngt_cache_detach_unplug),
|
OCF_PL_STEP(ocf_mngt_cache_detach_unplug),
|
||||||
OCF_PL_STEP_TERMINATOR(),
|
OCF_PL_STEP_TERMINATOR(),
|
||||||
@ -2405,7 +2439,7 @@ void ocf_mngt_cache_detach(ocf_cache_t cache,
|
|||||||
if (!cache->mngt_queue)
|
if (!cache->mngt_queue)
|
||||||
OCF_CMPL_RET(cache, priv, -OCF_ERR_INVAL);
|
OCF_CMPL_RET(cache, priv, -OCF_ERR_INVAL);
|
||||||
|
|
||||||
if (!env_atomic_read(&cache->attached))
|
if (!ocf_cache_is_device_attached(cache))
|
||||||
OCF_CMPL_RET(cache, priv, -OCF_ERR_INVAL);
|
OCF_CMPL_RET(cache, priv, -OCF_ERR_INVAL);
|
||||||
|
|
||||||
result = ocf_pipeline_create(&pipeline, cache,
|
result = ocf_pipeline_create(&pipeline, cache,
|
||||||
@ -2421,7 +2455,7 @@ void ocf_mngt_cache_detach(ocf_cache_t cache,
|
|||||||
context->cache = cache;
|
context->cache = cache;
|
||||||
|
|
||||||
/* prevent dirty io */
|
/* prevent dirty io */
|
||||||
ocf_refcnt_freeze(&cache->dirty);
|
ocf_refcnt_freeze(&cache->refcnt.dirty);
|
||||||
|
|
||||||
ocf_pipeline_next(pipeline);
|
ocf_pipeline_next(pipeline);
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ void ocf_mngt_cache_put(ocf_cache_t cache)
|
|||||||
{
|
{
|
||||||
OCF_CHECK_NULL(cache);
|
OCF_CHECK_NULL(cache);
|
||||||
|
|
||||||
if (env_atomic_dec_return(&cache->ref_count) == 0) {
|
if (ocf_refcnt_dec(&cache->refcnt.cache) == 0) {
|
||||||
ocf_metadata_deinit(cache);
|
ocf_metadata_deinit(cache);
|
||||||
env_vfree(cache);
|
env_vfree(cache);
|
||||||
}
|
}
|
||||||
@ -155,10 +155,7 @@ int ocf_mngt_cache_get_by_id(ocf_ctx_t ocf_ctx, ocf_cache_id_t id, ocf_cache_t *
|
|||||||
|
|
||||||
if (instance) {
|
if (instance) {
|
||||||
/* if cache is either fully initialized or during recovery */
|
/* if cache is either fully initialized or during recovery */
|
||||||
if (instance->valid_ocf_cache_device_t) {
|
if (!ocf_refcnt_inc(&instance->refcnt.cache)) {
|
||||||
/* Increase reference counter */
|
|
||||||
env_atomic_inc(&instance->ref_count);
|
|
||||||
} else {
|
|
||||||
/* Cache not initialized yet */
|
/* Cache not initialized yet */
|
||||||
instance = NULL;
|
instance = NULL;
|
||||||
}
|
}
|
||||||
@ -210,7 +207,8 @@ static int _ocf_mngt_cache_lock(ocf_cache_t cache, int (*lock_fn)(env_rwsem *s),
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Increment reference counter */
|
/* Increment reference counter */
|
||||||
env_atomic_inc(&cache->ref_count);
|
if (!ocf_refcnt_inc(&cache->refcnt.cache))
|
||||||
|
return -OCF_ERR_CACHE_NOT_EXIST;
|
||||||
|
|
||||||
env_atomic_inc(&cache->lock_waiter);
|
env_atomic_inc(&cache->lock_waiter);
|
||||||
ret = lock_fn(&cache->lock);
|
ret = lock_fn(&cache->lock);
|
||||||
@ -266,13 +264,7 @@ int ocf_mngt_cache_read_trylock(ocf_cache_t cache)
|
|||||||
/* if cache is either fully initialized or during recovery */
|
/* if cache is either fully initialized or during recovery */
|
||||||
static bool _ocf_mngt_cache_try_get(ocf_cache_t cache)
|
static bool _ocf_mngt_cache_try_get(ocf_cache_t cache)
|
||||||
{
|
{
|
||||||
if (!!cache->valid_ocf_cache_device_t) {
|
return !!ocf_refcnt_inc(&cache->refcnt.cache);
|
||||||
/* Increase reference counter */
|
|
||||||
env_atomic_inc(&cache->ref_count);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ocf_mngt_cache_get(ocf_cache_t cache)
|
int ocf_mngt_cache_get(ocf_cache_t cache)
|
||||||
|
@ -560,32 +560,14 @@ err_pipeline:
|
|||||||
OCF_CMPL_RET(cache, NULL, priv, result);
|
OCF_CMPL_RET(cache, NULL, priv, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Synchronously wait until cleaning triggered by eviction finishes.
|
|
||||||
* TODO: Replace it with asynchronous mechanism.
|
|
||||||
*/
|
|
||||||
static int _ocf_cleaning_wait_for_finish(ocf_cache_t cache, int32_t timeout_ms)
|
|
||||||
{
|
|
||||||
if (!ocf_cache_is_device_attached(cache))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
while (ocf_cache_has_pending_cleaning(cache)) {
|
|
||||||
env_msleep(20);
|
|
||||||
|
|
||||||
timeout_ms -= 20;
|
|
||||||
if (timeout_ms <= 0)
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ocf_mngt_cache_remove_core_context {
|
struct ocf_mngt_cache_remove_core_context {
|
||||||
ocf_mngt_cache_remove_core_end_t cmpl;
|
ocf_mngt_cache_remove_core_end_t cmpl;
|
||||||
void *priv;
|
void *priv;
|
||||||
ocf_pipeline_t pipeline;
|
ocf_pipeline_t pipeline;
|
||||||
ocf_cache_t cache;
|
ocf_cache_t cache;
|
||||||
|
ocf_core_t core;
|
||||||
const char *core_name;
|
const char *core_name;
|
||||||
|
struct ocf_cleaner_wait_context cleaner_wait;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ocf_mngt_cache_remove_core_finish(ocf_pipeline_t pipeline,
|
static void ocf_mngt_cache_remove_core_finish(ocf_pipeline_t pipeline,
|
||||||
@ -602,19 +584,13 @@ static void ocf_mngt_cache_remove_core_finish(ocf_pipeline_t pipeline,
|
|||||||
context->core_name);
|
context->core_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ocf_cleaner_refcnt_unfreeze(cache);
|
||||||
|
|
||||||
context->cmpl(context->priv, error);
|
context->cmpl(context->priv, error);
|
||||||
|
|
||||||
ocf_pipeline_destroy(context->pipeline);
|
ocf_pipeline_destroy(context->pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ocf_pipeline_properties ocf_mngt_cache_remove_core_pipeline_props = {
|
|
||||||
.priv_size = sizeof(struct ocf_mngt_cache_remove_core_context),
|
|
||||||
.finish = ocf_mngt_cache_remove_core_finish,
|
|
||||||
.steps = {
|
|
||||||
OCF_PL_STEP_TERMINATOR(),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static void ocf_mngt_cache_remove_core_flush_sb_complete(void *priv, int error)
|
static void ocf_mngt_cache_remove_core_flush_sb_complete(void *priv, int error)
|
||||||
{
|
{
|
||||||
struct ocf_mngt_cache_remove_core_context *context = priv;
|
struct ocf_mngt_cache_remove_core_context *context = priv;
|
||||||
@ -623,39 +599,13 @@ static void ocf_mngt_cache_remove_core_flush_sb_complete(void *priv, int error)
|
|||||||
error ? -OCF_ERR_WRITE_CACHE : 0);
|
error ? -OCF_ERR_WRITE_CACHE : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ocf_mngt_cache_remove_core(ocf_core_t core,
|
static void _ocf_mngt_cache_remove_core(ocf_pipeline_t pipeline, void *priv,
|
||||||
ocf_mngt_cache_remove_core_end_t cmpl, void *priv)
|
ocf_pipeline_arg_t arg)
|
||||||
{
|
{
|
||||||
struct ocf_mngt_cache_remove_core_context *context;
|
struct ocf_mngt_cache_remove_core_context *context = priv;
|
||||||
ocf_pipeline_t pipeline;
|
ocf_cache_t cache = context->cache;
|
||||||
ocf_cache_t cache;
|
ocf_core_t core = context->core;
|
||||||
ocf_core_id_t core_id;
|
ocf_core_id_t core_id = ocf_core_get_id(core);
|
||||||
int result;
|
|
||||||
|
|
||||||
OCF_CHECK_NULL(core);
|
|
||||||
|
|
||||||
cache = ocf_core_get_cache(core);
|
|
||||||
core_id = ocf_core_get_id(core);
|
|
||||||
|
|
||||||
if (!cache->mngt_queue)
|
|
||||||
OCF_CMPL_RET(cache, -OCF_ERR_INVAL);
|
|
||||||
|
|
||||||
/* TODO: Make this asynchronous */
|
|
||||||
if (_ocf_cleaning_wait_for_finish(cache, 60 * 1000))
|
|
||||||
OCF_CMPL_RET(priv, -OCF_ERR_CACHE_IN_USE);
|
|
||||||
|
|
||||||
result = ocf_pipeline_create(&pipeline, cache,
|
|
||||||
&ocf_mngt_cache_remove_core_pipeline_props);
|
|
||||||
if (result)
|
|
||||||
OCF_CMPL_RET(priv, result);
|
|
||||||
|
|
||||||
context = ocf_pipeline_get_priv(pipeline);
|
|
||||||
|
|
||||||
context->cmpl = cmpl;
|
|
||||||
context->priv = priv;
|
|
||||||
context->pipeline = pipeline;
|
|
||||||
context->cache = cache;
|
|
||||||
context->core_name = ocf_core_get_name(core);
|
|
||||||
|
|
||||||
ocf_core_log(core, log_debug, "Removing core\n");
|
ocf_core_log(core, log_debug, "Removing core\n");
|
||||||
|
|
||||||
@ -675,53 +625,183 @@ void ocf_mngt_cache_remove_core(ocf_core_t core,
|
|||||||
ocf_mngt_cache_remove_core_flush_sb_complete, context);
|
ocf_mngt_cache_remove_core_flush_sb_complete, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _ocf_mngt_cache_detach_core(ocf_core_t core)
|
static void ocf_mngt_cache_remove_core_wait_cleaning_complete(void *priv)
|
||||||
{
|
{
|
||||||
struct ocf_cache *cache = core->volume.cache;
|
ocf_pipeline_t pipeline = priv;
|
||||||
ocf_core_id_t core_id = ocf_core_get_id(core);
|
ocf_pipeline_next(pipeline);
|
||||||
int status;
|
|
||||||
|
|
||||||
status = cache_mng_core_close(cache, core_id);
|
|
||||||
if (!status) {
|
|
||||||
cache->ocf_core_inactive_count++;
|
|
||||||
env_bit_set(ocf_cache_state_incomplete,
|
|
||||||
&cache->cache_state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
static void ocf_mngt_cache_remove_core_wait_cleaning(ocf_pipeline_t pipeline,
|
||||||
|
void *priv, ocf_pipeline_arg_t arg)
|
||||||
|
{
|
||||||
|
struct ocf_mngt_cache_remove_core_context *context = priv;
|
||||||
|
ocf_cache_t cache = context->cache;
|
||||||
|
|
||||||
|
if (!ocf_cache_is_device_attached(cache))
|
||||||
|
OCF_PL_NEXT_RET(pipeline);
|
||||||
|
|
||||||
|
ocf_cleaner_refcnt_freeze(cache);
|
||||||
|
ocf_cleaner_refcnt_register_zero_cb(cache, &context->cleaner_wait,
|
||||||
|
ocf_mngt_cache_remove_core_wait_cleaning_complete,
|
||||||
|
pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ocf_mngt_cache_detach_core(ocf_core_t core,
|
struct ocf_pipeline_properties ocf_mngt_cache_remove_core_pipeline_props = {
|
||||||
ocf_mngt_cache_detach_core_end_t cmpl, void *priv)
|
.priv_size = sizeof(struct ocf_mngt_cache_remove_core_context),
|
||||||
|
.finish = ocf_mngt_cache_remove_core_finish,
|
||||||
|
.steps = {
|
||||||
|
OCF_PL_STEP(ocf_mngt_cache_remove_core_wait_cleaning),
|
||||||
|
OCF_PL_STEP(_ocf_mngt_cache_remove_core),
|
||||||
|
OCF_PL_STEP_TERMINATOR(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void ocf_mngt_cache_remove_core(ocf_core_t core,
|
||||||
|
ocf_mngt_cache_remove_core_end_t cmpl, void *priv)
|
||||||
{
|
{
|
||||||
|
struct ocf_mngt_cache_remove_core_context *context;
|
||||||
|
ocf_pipeline_t pipeline;
|
||||||
ocf_cache_t cache;
|
ocf_cache_t cache;
|
||||||
const char *core_name;
|
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
OCF_CHECK_NULL(core);
|
OCF_CHECK_NULL(core);
|
||||||
|
|
||||||
cache = ocf_core_get_cache(core);
|
cache = ocf_core_get_cache(core);
|
||||||
core_name = ocf_core_get_name(core);
|
|
||||||
|
|
||||||
if (!cache->mngt_queue)
|
if (!cache->mngt_queue)
|
||||||
OCF_CMPL_RET(cache, -OCF_ERR_INVAL);
|
OCF_CMPL_RET(cache, -OCF_ERR_INVAL);
|
||||||
|
|
||||||
/* TODO: Make this asynchronous */
|
result = ocf_pipeline_create(&pipeline, cache,
|
||||||
if (_ocf_cleaning_wait_for_finish(cache, 60 * 1000))
|
&ocf_mngt_cache_remove_core_pipeline_props);
|
||||||
OCF_CMPL_RET(priv, -OCF_ERR_CACHE_IN_USE);
|
if (result)
|
||||||
|
OCF_CMPL_RET(priv, result);
|
||||||
|
|
||||||
|
context = ocf_pipeline_get_priv(pipeline);
|
||||||
|
|
||||||
|
context->cmpl = cmpl;
|
||||||
|
context->priv = priv;
|
||||||
|
context->pipeline = pipeline;
|
||||||
|
context->cache = cache;
|
||||||
|
context->core = core;
|
||||||
|
context->core_name = ocf_core_get_name(core);
|
||||||
|
|
||||||
|
ocf_pipeline_next(pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ocf_mngt_cache_detach_core_context {
|
||||||
|
ocf_mngt_cache_detach_core_end_t cmpl;
|
||||||
|
void *priv;
|
||||||
|
ocf_pipeline_t pipeline;
|
||||||
|
ocf_cache_t cache;
|
||||||
|
ocf_core_t core;
|
||||||
|
const char *core_name;
|
||||||
|
struct ocf_cleaner_wait_context cleaner_wait;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void _ocf_mngt_cache_detach_core(ocf_pipeline_t pipeline,
|
||||||
|
void *priv, ocf_pipeline_arg_t arg)
|
||||||
|
{
|
||||||
|
struct ocf_mngt_cache_remove_core_context *context = priv;
|
||||||
|
ocf_cache_t cache = context->cache;
|
||||||
|
ocf_core_t core = context->core;
|
||||||
|
ocf_core_id_t core_id = ocf_core_get_id(core);
|
||||||
|
int status;
|
||||||
|
|
||||||
ocf_core_log(core, log_debug, "Detaching core\n");
|
ocf_core_log(core, log_debug, "Detaching core\n");
|
||||||
|
|
||||||
result = _ocf_mngt_cache_detach_core(core);
|
status = cache_mng_core_close(cache, core_id);
|
||||||
if (!result) {
|
|
||||||
ocf_cache_log(cache, log_info, "Core %s successfully detached\n",
|
if (status)
|
||||||
core_name);
|
OCF_PL_FINISH_RET(pipeline, status);
|
||||||
} else {
|
|
||||||
ocf_cache_log(cache, log_err, "Detaching core %s failed\n",
|
cache->ocf_core_inactive_count++;
|
||||||
core_name);
|
env_bit_set(ocf_cache_state_incomplete,
|
||||||
|
&cache->cache_state);
|
||||||
|
ocf_pipeline_next(pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ocf_mngt_cache_detach_core_finish(ocf_pipeline_t pipeline,
|
||||||
|
void *priv, int error)
|
||||||
|
{
|
||||||
|
struct ocf_mngt_cache_remove_core_context *context = priv;
|
||||||
|
ocf_cache_t cache = context->cache;
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
ocf_cache_log(cache, log_info, "Core %s successfully detached\n",
|
||||||
|
context->core_name);
|
||||||
|
} else {
|
||||||
|
ocf_cache_log(cache, log_err, "Detaching core %s failed\n",
|
||||||
|
context->core_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
ocf_cleaner_refcnt_unfreeze(context->cache);
|
||||||
|
|
||||||
|
context->cmpl(context->priv, error);
|
||||||
|
|
||||||
|
ocf_pipeline_destroy(context->pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_mngt_cache_detach_core_wait_cleaning_complete(void *priv)
|
||||||
|
{
|
||||||
|
ocf_pipeline_t pipeline = priv;
|
||||||
|
ocf_pipeline_next(pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_mngt_cache_detach_core_wait_cleaning(ocf_pipeline_t pipeline,
|
||||||
|
void *priv, ocf_pipeline_arg_t arg)
|
||||||
|
{
|
||||||
|
struct ocf_mngt_cache_remove_core_context *context = priv;
|
||||||
|
ocf_cache_t cache = context->cache;
|
||||||
|
|
||||||
|
if (!ocf_cache_is_device_attached(cache))
|
||||||
|
OCF_PL_NEXT_RET(pipeline);
|
||||||
|
|
||||||
|
ocf_cleaner_refcnt_freeze(cache);
|
||||||
|
ocf_cleaner_refcnt_register_zero_cb(cache, &context->cleaner_wait,
|
||||||
|
ocf_mngt_cache_detach_core_wait_cleaning_complete,
|
||||||
|
pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ocf_pipeline_properties ocf_mngt_cache_detach_core_pipeline_props = {
|
||||||
|
.priv_size = sizeof(struct ocf_mngt_cache_detach_core_context),
|
||||||
|
.finish = ocf_mngt_cache_detach_core_finish,
|
||||||
|
.steps = {
|
||||||
|
OCF_PL_STEP(ocf_mngt_cache_detach_core_wait_cleaning),
|
||||||
|
OCF_PL_STEP(_ocf_mngt_cache_detach_core),
|
||||||
|
OCF_PL_STEP_TERMINATOR(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void ocf_mngt_cache_detach_core(ocf_core_t core,
|
||||||
|
ocf_mngt_cache_detach_core_end_t cmpl, void *priv)
|
||||||
|
{
|
||||||
|
struct ocf_mngt_cache_detach_core_context *context;
|
||||||
|
ocf_pipeline_t pipeline;
|
||||||
|
ocf_cache_t cache;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
OCF_CHECK_NULL(core);
|
||||||
|
|
||||||
|
cache = ocf_core_get_cache(core);
|
||||||
|
|
||||||
|
if (!cache->mngt_queue)
|
||||||
|
OCF_CMPL_RET(cache, -OCF_ERR_INVAL);
|
||||||
|
|
||||||
|
result = ocf_pipeline_create(&pipeline, cache,
|
||||||
|
&ocf_mngt_cache_detach_core_pipeline_props);
|
||||||
|
if (result)
|
||||||
OCF_CMPL_RET(priv, result);
|
OCF_CMPL_RET(priv, result);
|
||||||
|
|
||||||
|
context = ocf_pipeline_get_priv(pipeline);
|
||||||
|
|
||||||
|
context->cmpl = cmpl;
|
||||||
|
context->priv = priv;
|
||||||
|
context->pipeline = pipeline;
|
||||||
|
context->cache = ocf_core_get_cache(core);
|
||||||
|
context->core = core;
|
||||||
|
context->core_name = ocf_core_get_name(core);
|
||||||
|
|
||||||
|
ocf_pipeline_next(pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ocf_mngt_core_set_uuid(ocf_core_t core, const struct ocf_volume_uuid *uuid)
|
int ocf_mngt_core_set_uuid(ocf_core_t core, const struct ocf_volume_uuid *uuid)
|
||||||
|
@ -92,15 +92,15 @@ static void _ocf_mngt_begin_flush(ocf_pipeline_t pipeline, void *priv,
|
|||||||
* finish */
|
* finish */
|
||||||
env_mutex_lock(&cache->flush_mutex);
|
env_mutex_lock(&cache->flush_mutex);
|
||||||
|
|
||||||
ocf_refcnt_freeze(&cache->dirty);
|
ocf_refcnt_freeze(&cache->refcnt.dirty);
|
||||||
|
|
||||||
ocf_refcnt_register_zero_cb(&cache->dirty,
|
ocf_refcnt_register_zero_cb(&cache->refcnt.dirty,
|
||||||
_ocf_mngt_begin_flush_complete, context);
|
_ocf_mngt_begin_flush_complete, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _ocf_mngt_end_flush(ocf_cache_t cache)
|
static void _ocf_mngt_end_flush(ocf_cache_t cache)
|
||||||
{
|
{
|
||||||
ocf_refcnt_unfreeze(&cache->dirty);
|
ocf_refcnt_unfreeze(&cache->refcnt.dirty);
|
||||||
|
|
||||||
env_mutex_unlock(&cache->flush_mutex);
|
env_mutex_unlock(&cache->flush_mutex);
|
||||||
}
|
}
|
||||||
|
@ -50,55 +50,7 @@ bool ocf_cache_is_running(ocf_cache_t cache)
|
|||||||
bool ocf_cache_is_device_attached(ocf_cache_t cache)
|
bool ocf_cache_is_device_attached(ocf_cache_t cache)
|
||||||
{
|
{
|
||||||
OCF_CHECK_NULL(cache);
|
OCF_CHECK_NULL(cache);
|
||||||
return env_atomic_read(&(cache)->attached);
|
return !ocf_refcnt_frozen(&cache->refcnt.metadata);
|
||||||
}
|
|
||||||
|
|
||||||
void ocf_cache_wait_for_io_finish(ocf_cache_t cache)
|
|
||||||
{
|
|
||||||
uint32_t req_active = 0;
|
|
||||||
|
|
||||||
OCF_CHECK_NULL(cache);
|
|
||||||
|
|
||||||
do {
|
|
||||||
req_active = ocf_req_get_allocated(cache);
|
|
||||||
if (req_active)
|
|
||||||
env_msleep(500);
|
|
||||||
} while (req_active);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ocf_cache_has_pending_requests(ocf_cache_t cache)
|
|
||||||
{
|
|
||||||
OCF_CHECK_NULL(cache);
|
|
||||||
|
|
||||||
return ocf_req_get_allocated(cache) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is temporary workaround allowing to check if cleaning triggered
|
|
||||||
* by eviction policy is running on the cache. This information is needed
|
|
||||||
* to remove core from cache properly.
|
|
||||||
*
|
|
||||||
* TODO: Replace this with asynchronous notification to which remove/detach
|
|
||||||
* core pipelines can subscribe.
|
|
||||||
*/
|
|
||||||
bool ocf_cache_has_pending_cleaning(ocf_cache_t cache)
|
|
||||||
{
|
|
||||||
struct ocf_user_part *curr_part;
|
|
||||||
ocf_part_id_t part_id;
|
|
||||||
bool cleaning_active = false;
|
|
||||||
|
|
||||||
OCF_CHECK_NULL(cache);
|
|
||||||
|
|
||||||
OCF_METADATA_LOCK_RD();
|
|
||||||
for_each_part(cache, curr_part, part_id) {
|
|
||||||
if (env_atomic_read(&cache->cleaning[part_id])) {
|
|
||||||
cleaning_active = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OCF_METADATA_UNLOCK_RD();
|
|
||||||
|
|
||||||
return cleaning_active;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ocf_cache_mode_t ocf_cache_get_mode(ocf_cache_t cache)
|
ocf_cache_mode_t ocf_cache_get_mode(ocf_cache_t cache)
|
||||||
|
@ -146,13 +146,10 @@ struct ocf_cache {
|
|||||||
ocf_ctx_t owner;
|
ocf_ctx_t owner;
|
||||||
|
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
/* set to make valid */
|
|
||||||
uint8_t valid_ocf_cache_device_t;
|
|
||||||
/* unset running to not serve any more I/O requests */
|
/* unset running to not serve any more I/O requests */
|
||||||
unsigned long cache_state;
|
unsigned long cache_state;
|
||||||
|
|
||||||
env_atomic ref_count;
|
|
||||||
|
|
||||||
struct ocf_superblock_config *conf_meta;
|
struct ocf_superblock_config *conf_meta;
|
||||||
|
|
||||||
struct ocf_cache_device *device;
|
struct ocf_cache_device *device;
|
||||||
@ -168,12 +165,17 @@ struct ocf_cache {
|
|||||||
|
|
||||||
char name[OCF_CACHE_NAME_SIZE];
|
char name[OCF_CACHE_NAME_SIZE];
|
||||||
|
|
||||||
env_atomic pending_requests;
|
struct {
|
||||||
|
/* cache get/put counter */
|
||||||
env_atomic pending_cache_requests;
|
struct ocf_refcnt cache;
|
||||||
env_waitqueue pending_cache_wq;
|
/* # of requests potentially dirtying cachelines */
|
||||||
|
|
||||||
struct ocf_refcnt dirty;
|
struct ocf_refcnt dirty;
|
||||||
|
/* # of requests accessing attached metadata, excluding
|
||||||
|
* management reqs */
|
||||||
|
struct ocf_refcnt metadata;
|
||||||
|
/* # of forced cleaning requests (eviction path) */
|
||||||
|
struct ocf_refcnt cleaning[OCF_IO_CLASS_MAX];
|
||||||
|
} refcnt;
|
||||||
|
|
||||||
uint32_t fallback_pt_error_threshold;
|
uint32_t fallback_pt_error_threshold;
|
||||||
env_atomic fallback_pt_error_counter;
|
env_atomic fallback_pt_error_counter;
|
||||||
@ -195,11 +197,6 @@ struct ocf_cache {
|
|||||||
|
|
||||||
env_atomic flush_in_progress;
|
env_atomic flush_in_progress;
|
||||||
|
|
||||||
/* 1 if cache device attached, 0 otherwise */
|
|
||||||
env_atomic attached;
|
|
||||||
|
|
||||||
env_atomic cleaning[OCF_IO_CLASS_MAX];
|
|
||||||
|
|
||||||
struct ocf_cleaner cleaner;
|
struct ocf_cleaner cleaner;
|
||||||
struct ocf_metadata_updater metadata_updater;
|
struct ocf_metadata_updater metadata_updater;
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ static inline ocf_core_t ocf_volume_to_core(ocf_volume_t volume)
|
|||||||
static inline int ocf_io_set_dirty(ocf_cache_t cache,
|
static inline int ocf_io_set_dirty(ocf_cache_t cache,
|
||||||
struct ocf_core_io *core_io)
|
struct ocf_core_io *core_io)
|
||||||
{
|
{
|
||||||
core_io->dirty = ocf_refcnt_inc(&cache->dirty);
|
core_io->dirty = !!ocf_refcnt_inc(&cache->refcnt.dirty);
|
||||||
return core_io->dirty ? 0 : -EBUSY;
|
return core_io->dirty ? 0 : -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,7 +167,7 @@ static inline void dec_counter_if_req_was_dirty(struct ocf_core_io *core_io,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
core_io->dirty = 0;
|
core_io->dirty = 0;
|
||||||
ocf_refcnt_dec(&cache->dirty);
|
ocf_refcnt_dec(&cache->refcnt.dirty);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ocf_core_validate_io(struct ocf_io *io)
|
static inline int ocf_core_validate_io(struct ocf_io *io)
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "../engine/engine_common.h"
|
#include "../engine/engine_common.h"
|
||||||
#include "../concurrency/ocf_concurrency.h"
|
#include "../concurrency/ocf_concurrency.h"
|
||||||
#include "utils_cleaner.h"
|
#include "utils_cleaner.h"
|
||||||
|
#include "utils_part.h"
|
||||||
#include "utils_req.h"
|
#include "utils_req.h"
|
||||||
#include "utils_io.h"
|
#include "utils_io.h"
|
||||||
#include "utils_cache_line.h"
|
#include "utils_cache_line.h"
|
||||||
@ -1014,3 +1015,49 @@ void ocf_cleaner_sort_flush_containers(struct flush_container *fctbl,
|
|||||||
_ocf_cleaner_swap);
|
_ocf_cleaner_swap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ocf_cleaner_refcnt_freeze(ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
struct ocf_user_part *curr_part;
|
||||||
|
ocf_part_id_t part_id;
|
||||||
|
|
||||||
|
for_each_part(cache, curr_part, part_id)
|
||||||
|
ocf_refcnt_freeze(&cache->refcnt.cleaning[part_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ocf_cleaner_refcnt_unfreeze(ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
struct ocf_user_part *curr_part;
|
||||||
|
ocf_part_id_t part_id;
|
||||||
|
|
||||||
|
for_each_part(cache, curr_part, part_id)
|
||||||
|
ocf_refcnt_unfreeze(&cache->refcnt.cleaning[part_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_cleaner_refcnt_register_zero_cb_finish(void *priv)
|
||||||
|
{
|
||||||
|
struct ocf_cleaner_wait_context *ctx = priv;
|
||||||
|
|
||||||
|
if (!env_atomic_dec_return(&ctx->waiting))
|
||||||
|
ctx->cb(ctx->priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ocf_cleaner_refcnt_register_zero_cb(ocf_cache_t cache,
|
||||||
|
struct ocf_cleaner_wait_context *ctx,
|
||||||
|
ocf_cleaner_refcnt_zero_cb_t cb, void *priv)
|
||||||
|
{
|
||||||
|
struct ocf_user_part *curr_part;
|
||||||
|
ocf_part_id_t part_id;
|
||||||
|
|
||||||
|
env_atomic_set(&ctx->waiting, 1);
|
||||||
|
ctx->cb = cb;
|
||||||
|
ctx->priv = priv;
|
||||||
|
|
||||||
|
for_each_part(cache, curr_part, part_id) {
|
||||||
|
env_atomic_inc(&ctx->waiting);
|
||||||
|
ocf_refcnt_register_zero_cb(&cache->refcnt.cleaning[part_id],
|
||||||
|
ocf_cleaner_refcnt_register_zero_cb_finish, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
ocf_cleaner_refcnt_register_zero_cb_finish(ctx);
|
||||||
|
}
|
||||||
|
@ -79,6 +79,18 @@ struct flush_container {
|
|||||||
struct ocf_mngt_cache_flush_context *context;
|
struct ocf_mngt_cache_flush_context *context;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef void (*ocf_cleaner_refcnt_zero_cb_t)(void *priv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Context for ocf_cleaner_refcnt_register_zero_cb
|
||||||
|
*/
|
||||||
|
struct ocf_cleaner_wait_context
|
||||||
|
{
|
||||||
|
env_atomic waiting;
|
||||||
|
ocf_cleaner_refcnt_zero_cb_t cb;
|
||||||
|
void *priv;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Run cleaning procedure
|
* @brief Run cleaning procedure
|
||||||
*
|
*
|
||||||
@ -119,4 +131,30 @@ void ocf_cleaner_sort_sectors(struct flush_data *tbl, uint32_t num);
|
|||||||
void ocf_cleaner_sort_flush_containers(struct flush_container *fctbl,
|
void ocf_cleaner_sort_flush_containers(struct flush_container *fctbl,
|
||||||
uint32_t num);
|
uint32_t num);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable incrementing of cleaner reference counters
|
||||||
|
*
|
||||||
|
* @param cache - Cache instance
|
||||||
|
*/
|
||||||
|
void ocf_cleaner_refcnt_freeze(ocf_cache_t cache);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable incrementing of cleaner reference counters
|
||||||
|
*
|
||||||
|
* @param cache - Cache instance
|
||||||
|
*/
|
||||||
|
void ocf_cleaner_refcnt_unfreeze(ocf_cache_t cache);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register callback for cleaner reference counters dropping to 0
|
||||||
|
*
|
||||||
|
* @param cache - Cache instance
|
||||||
|
* @param ctx - Routine private context, allocated by caller to avoid ENOMEM
|
||||||
|
* @param cb - Caller callback
|
||||||
|
* @param priv - Caller callback private data
|
||||||
|
*/
|
||||||
|
void ocf_cleaner_refcnt_register_zero_cb(ocf_cache_t cache,
|
||||||
|
struct ocf_cleaner_wait_context *ctx,
|
||||||
|
ocf_cleaner_refcnt_zero_cb_t cb, void *priv);
|
||||||
|
|
||||||
#endif /* UTILS_CLEANER_H_ */
|
#endif /* UTILS_CLEANER_H_ */
|
||||||
|
@ -13,26 +13,30 @@ void ocf_refcnt_init(struct ocf_refcnt *rc)
|
|||||||
rc->cb = NULL;
|
rc->cb = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ocf_refcnt_dec(struct ocf_refcnt *rc)
|
int ocf_refcnt_dec(struct ocf_refcnt *rc)
|
||||||
{
|
{
|
||||||
int val = env_atomic_dec_return(&rc->counter);
|
int val = env_atomic_dec_return(&rc->counter);
|
||||||
ENV_BUG_ON(val < 0);
|
ENV_BUG_ON(val < 0);
|
||||||
|
|
||||||
if (!val && env_atomic_cmpxchg(&rc->callback, 1, 0))
|
if (!val && env_atomic_cmpxchg(&rc->callback, 1, 0))
|
||||||
rc->cb(rc->priv);
|
rc->cb(rc->priv);
|
||||||
|
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ocf_refcnt_inc(struct ocf_refcnt *rc)
|
int ocf_refcnt_inc(struct ocf_refcnt *rc)
|
||||||
{
|
{
|
||||||
|
int val;
|
||||||
|
|
||||||
if (!env_atomic_read(&rc->freeze)) {
|
if (!env_atomic_read(&rc->freeze)) {
|
||||||
env_atomic_inc(&rc->counter);
|
val = env_atomic_inc_return(&rc->counter);
|
||||||
if (!env_atomic_read(&rc->freeze))
|
if (!env_atomic_read(&rc->freeze))
|
||||||
return true;
|
return val;
|
||||||
else
|
else
|
||||||
ocf_refcnt_dec(rc);
|
ocf_refcnt_dec(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -59,3 +63,8 @@ void ocf_refcnt_unfreeze(struct ocf_refcnt *rc)
|
|||||||
int val = env_atomic_dec_return(&rc->freeze);
|
int val = env_atomic_dec_return(&rc->freeze);
|
||||||
ENV_BUG_ON(val < 0);
|
ENV_BUG_ON(val < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ocf_refcnt_frozen(struct ocf_refcnt *rc)
|
||||||
|
{
|
||||||
|
return !!env_atomic_read(&rc->freeze);
|
||||||
|
}
|
||||||
|
@ -22,23 +22,26 @@ struct ocf_refcnt
|
|||||||
/* Initialize reference counter */
|
/* Initialize reference counter */
|
||||||
void ocf_refcnt_init(struct ocf_refcnt *rc);
|
void ocf_refcnt_init(struct ocf_refcnt *rc);
|
||||||
|
|
||||||
/* Try to increment counter. Returns true if successfull, false if freezed */
|
/* Try to increment counter. Returns counter value (> 0) if successfull, 0
|
||||||
bool ocf_refcnt_inc(struct ocf_refcnt *rc);
|
* if counter is frozen */
|
||||||
|
int ocf_refcnt_inc(struct ocf_refcnt *rc);
|
||||||
|
|
||||||
/* Decrement reference counter */
|
/* Decrement reference counter and return post-decrement value */
|
||||||
void ocf_refcnt_dec(struct ocf_refcnt *rc);
|
int ocf_refcnt_dec(struct ocf_refcnt *rc);
|
||||||
|
|
||||||
/* Disallow incrementing of underlying counter - attempts to increment counter
|
/* Disallow incrementing of underlying counter - attempts to increment counter
|
||||||
* will be failing until ocf_refcnt_unfreeze is calleed.
|
* will be failing until ocf_refcnt_unfreeze is calleed.
|
||||||
* It's ok to call freeze multiple times, in which case counter is freezed
|
* It's ok to call freeze multiple times, in which case counter is frozen
|
||||||
* until all freeze calls are offset by a corresponding unfreeze.*/
|
* until all freeze calls are offset by a corresponding unfreeze.*/
|
||||||
void ocf_refcnt_freeze(struct ocf_refcnt *rc);
|
void ocf_refcnt_freeze(struct ocf_refcnt *rc);
|
||||||
|
|
||||||
/* Cancel the effect of single ocf_refcnt_freeze call */
|
/* Cancel the effect of single ocf_refcnt_freeze call */
|
||||||
void ocf_refcnt_unfreeze(struct ocf_refcnt *rc);
|
void ocf_refcnt_unfreeze(struct ocf_refcnt *rc);
|
||||||
|
|
||||||
|
bool ocf_refcnt_frozen(struct ocf_refcnt *rc);
|
||||||
|
|
||||||
/* Register callback to be called when reference counter drops to 0.
|
/* Register callback to be called when reference counter drops to 0.
|
||||||
* Must be called after counter is freezed.
|
* Must be called after counter is frozen.
|
||||||
* Cannot be called until previously regsitered callback had fired. */
|
* Cannot be called until previously regsitered callback had fired. */
|
||||||
void ocf_refcnt_register_zero_cb(struct ocf_refcnt *rc, ocf_refcnt_cb_t cb,
|
void ocf_refcnt_register_zero_cb(struct ocf_refcnt *rc, ocf_refcnt_cb_t cb,
|
||||||
void *priv);
|
void *priv);
|
||||||
|
@ -151,21 +151,6 @@ static env_allocator *_ocf_req_get_allocator(
|
|||||||
return ocf_ctx->resources.req->allocator[idx];
|
return ocf_ctx->resources.req->allocator[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void start_cache_req(struct ocf_request *req)
|
|
||||||
{
|
|
||||||
ocf_cache_t cache = req->cache;
|
|
||||||
|
|
||||||
req->d2c = 1;
|
|
||||||
if (env_atomic_read(&cache->attached)) {
|
|
||||||
req->d2c = 0;
|
|
||||||
env_atomic_inc(&cache->pending_cache_requests);
|
|
||||||
if (!env_atomic_read(&cache->attached)) {
|
|
||||||
req->d2c = 1;
|
|
||||||
env_atomic_dec(&cache->pending_cache_requests);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ocf_request *ocf_req_new(ocf_queue_t queue, ocf_core_t core,
|
struct ocf_request *ocf_req_new(ocf_queue_t queue, ocf_core_t core,
|
||||||
uint64_t addr, uint32_t bytes, int rw)
|
uint64_t addr, uint32_t bytes, int rw)
|
||||||
{
|
{
|
||||||
@ -206,10 +191,8 @@ struct ocf_request *ocf_req_new(ocf_queue_t queue, ocf_core_t core,
|
|||||||
req->core_id = core ? ocf_core_get_id(core) : 0;
|
req->core_id = core ? ocf_core_get_id(core) : 0;
|
||||||
req->cache = cache;
|
req->cache = cache;
|
||||||
|
|
||||||
if (queue != cache->mngt_queue)
|
req->d2c = (queue != cache->mngt_queue) && !ocf_refcnt_inc(
|
||||||
env_atomic_inc(&cache->pending_requests);
|
&cache->refcnt.metadata);
|
||||||
|
|
||||||
start_cache_req(req);
|
|
||||||
|
|
||||||
env_atomic_set(&req->ref_count, 1);
|
env_atomic_set(&req->ref_count, 1);
|
||||||
|
|
||||||
@ -289,13 +272,8 @@ void ocf_req_put(struct ocf_request *req)
|
|||||||
|
|
||||||
OCF_DEBUG_TRACE(req->cache);
|
OCF_DEBUG_TRACE(req->cache);
|
||||||
|
|
||||||
if (!req->d2c && !env_atomic_dec_return(
|
if (!req->d2c && req->io_queue != req->cache->mngt_queue)
|
||||||
&req->cache->pending_cache_requests)) {
|
ocf_refcnt_dec(&req->cache->refcnt.metadata);
|
||||||
env_waitqueue_wake_up(&req->cache->pending_cache_wq);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req->io_queue != req->cache->mngt_queue)
|
|
||||||
env_atomic_dec(&req->cache->pending_requests);
|
|
||||||
|
|
||||||
allocator = _ocf_req_get_allocator(req->cache,
|
allocator = _ocf_req_get_allocator(req->cache,
|
||||||
req->alloc_core_line_count);
|
req->alloc_core_line_count);
|
||||||
@ -318,8 +296,3 @@ void ocf_req_clear_map(struct ocf_request *req)
|
|||||||
ENV_BUG_ON(env_memset(req->map,
|
ENV_BUG_ON(env_memset(req->map,
|
||||||
sizeof(req->map[0]) * req->core_line_count, 0));
|
sizeof(req->map[0]) * req->core_line_count, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ocf_req_get_allocated(struct ocf_cache *cache)
|
|
||||||
{
|
|
||||||
return env_atomic_read(&cache->pending_requests);
|
|
||||||
}
|
|
||||||
|
@ -83,15 +83,6 @@ struct ocf_request *ocf_req_new_extended(ocf_queue_t queue, ocf_core_t core,
|
|||||||
struct ocf_request *ocf_req_new_discard(ocf_queue_t queue, ocf_core_t core,
|
struct ocf_request *ocf_req_new_discard(ocf_queue_t queue, ocf_core_t core,
|
||||||
uint64_t addr, uint32_t bytes, int rw);
|
uint64_t addr, uint32_t bytes, int rw);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get number of allocated requests
|
|
||||||
*
|
|
||||||
* @param cache OCF cache instance
|
|
||||||
*
|
|
||||||
* @return Number of allocated requests
|
|
||||||
*/
|
|
||||||
uint32_t ocf_req_get_allocated(struct ocf_cache *cache);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Increment OCF request reference count
|
* @brief Increment OCF request reference count
|
||||||
*
|
*
|
||||||
|
@ -302,7 +302,7 @@ class Cache:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def start_on_device(cls, device, **kwargs):
|
def start_on_device(cls, device, **kwargs):
|
||||||
c = cls(locked=True, owner=device.owner, **kwargs)
|
c = cls(owner=device.owner, **kwargs)
|
||||||
|
|
||||||
c.start_cache()
|
c.start_cache()
|
||||||
try:
|
try:
|
||||||
@ -482,7 +482,6 @@ class Cache:
|
|||||||
[("cache", c_void_p), ("priv", c_void_p), ("error", c_int)]
|
[("cache", c_void_p), ("priv", c_void_p), ("error", c_int)]
|
||||||
)
|
)
|
||||||
|
|
||||||
self.owner.lib.ocf_cache_wait_for_io_finish(self.cache_handle)
|
|
||||||
self.owner.lib.ocf_mngt_cache_stop(self.cache_handle, c, None)
|
self.owner.lib.ocf_mngt_cache_stop(self.cache_handle, c, None)
|
||||||
|
|
||||||
c.wait()
|
c.wait()
|
||||||
@ -495,7 +494,6 @@ class Cache:
|
|||||||
self.started = False
|
self.started = False
|
||||||
|
|
||||||
self.put_and_write_unlock()
|
self.put_and_write_unlock()
|
||||||
self.put()
|
|
||||||
|
|
||||||
self.owner.caches.remove(self)
|
self.owner.caches.remove(self)
|
||||||
|
|
||||||
|
@ -188,7 +188,7 @@ void __wrap__ocf_mngt_attach_post_init(
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void __wrap_ocf_mngt_cache_stop_wait_io(
|
void __wrap_ocf_mngt_cache_stop_wait_metadata_io(
|
||||||
ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg)
|
ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -213,6 +213,17 @@ void __wrap_ocf_mngt_cache_detach_flush(
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ocf_mngt_cache_detach_stop_cache_io(ocf_pipeline_t pipeline,
|
||||||
|
void *priv, ocf_pipeline_arg_t arg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ocf_mngt_cache_detach_stop_cleaner_io(ocf_pipeline_t pipeline,
|
||||||
|
void *priv, ocf_pipeline_arg_t arg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void __wrap_ocf_mngt_cache_detach_wait_pending(
|
void __wrap_ocf_mngt_cache_detach_wait_pending(
|
||||||
ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg)
|
ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg)
|
||||||
{
|
{
|
||||||
|
@ -145,7 +145,7 @@ void __wrap__ocf_mngt_attach_post_init(
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void __wrap_ocf_mngt_cache_stop_wait_io(
|
void __wrap_ocf_mngt_cache_stop_wait_metadata_io(
|
||||||
ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg)
|
ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -170,6 +170,16 @@ void __wrap_ocf_mngt_cache_detach_flush(
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __wrap_ocf_mngt_cache_detach_stop_cache_io(ocf_pipeline_t pipeline,
|
||||||
|
void *priv, ocf_pipeline_arg_t arg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ocf_mngt_cache_detach_stop_cleaner_io(ocf_pipeline_t pipeline,
|
||||||
|
void *priv, ocf_pipeline_arg_t arg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void __wrap_ocf_mngt_cache_detach_wait_pending(
|
void __wrap_ocf_mngt_cache_detach_wait_pending(
|
||||||
ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg)
|
ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg)
|
||||||
{
|
{
|
||||||
|
62
tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_dec.c
Normal file
62
tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_dec.c
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* <tested_file_path>src/utils/utils_refcnt.c</tested_file_path>
|
||||||
|
* <tested_function>ocf_refcnt_dec</tested_function>
|
||||||
|
* <functions_to_leave>
|
||||||
|
* ocf_refcnt_init
|
||||||
|
* ocf_refcnt_inc
|
||||||
|
* </functions_to_leave>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#undef static
|
||||||
|
|
||||||
|
#undef inline
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <cmocka.h>
|
||||||
|
#include "print_desc.h"
|
||||||
|
|
||||||
|
#include "../utils/utils_refcnt.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void ocf_refcnt_dec_test01(void **state)
|
||||||
|
{
|
||||||
|
struct ocf_refcnt rc;
|
||||||
|
int val, val2;
|
||||||
|
|
||||||
|
print_test_description("Decrement subtracts 1 and returns proper value");
|
||||||
|
|
||||||
|
ocf_refcnt_init(&rc);
|
||||||
|
|
||||||
|
ocf_refcnt_inc(&rc);
|
||||||
|
ocf_refcnt_inc(&rc);
|
||||||
|
ocf_refcnt_inc(&rc);
|
||||||
|
|
||||||
|
val = ocf_refcnt_dec(&rc);
|
||||||
|
assert_int_equal(2, val);
|
||||||
|
val2 = env_atomic_read(&rc.counter);
|
||||||
|
assert_int_equal(2, val2);
|
||||||
|
|
||||||
|
val = ocf_refcnt_dec(&rc);
|
||||||
|
assert_int_equal(1, val);
|
||||||
|
val2 = env_atomic_read(&rc.counter);
|
||||||
|
assert_int_equal(1, val2);
|
||||||
|
|
||||||
|
val = ocf_refcnt_dec(&rc);
|
||||||
|
assert_int_equal(0, val);
|
||||||
|
val2 = env_atomic_read(&rc.counter);
|
||||||
|
assert_int_equal(0, val2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
const struct CMUnitTest tests[] = {
|
||||||
|
cmocka_unit_test(ocf_refcnt_dec_test01)
|
||||||
|
};
|
||||||
|
|
||||||
|
print_message("Unit test of src/utils/utils_refcnt.c");
|
||||||
|
|
||||||
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
}
|
116
tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_freeze.c
Normal file
116
tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_freeze.c
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* <tested_file_path>src/utils/utils_refcnt.c</tested_file_path>
|
||||||
|
* <tested_function>ocf_refcnt_freeze</tested_function>
|
||||||
|
* <functions_to_leave>
|
||||||
|
* ocf_refcnt_init
|
||||||
|
* ocf_refcnt_inc
|
||||||
|
* ocf_refcnt_dec
|
||||||
|
* </functions_to_leave>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#undef static
|
||||||
|
|
||||||
|
#undef inline
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <cmocka.h>
|
||||||
|
#include "print_desc.h"
|
||||||
|
|
||||||
|
#include "../utils/utils_refcnt.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void ocf_refcnt_freeze_test01(void **state)
|
||||||
|
{
|
||||||
|
struct ocf_refcnt rc;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
print_test_description("Freeze increments freeze counter");
|
||||||
|
|
||||||
|
ocf_refcnt_init(&rc);
|
||||||
|
|
||||||
|
ocf_refcnt_freeze(&rc);
|
||||||
|
assert_int_equal(1, env_atomic_read(&rc.freeze));
|
||||||
|
|
||||||
|
ocf_refcnt_freeze(&rc);
|
||||||
|
assert_int_equal(2, env_atomic_read(&rc.freeze));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_refcnt_freeze_test02(void **state)
|
||||||
|
{
|
||||||
|
struct ocf_refcnt rc;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
print_test_description("Increment returns 0 for frozen counter");
|
||||||
|
|
||||||
|
ocf_refcnt_init(&rc);
|
||||||
|
|
||||||
|
ocf_refcnt_inc(&rc);
|
||||||
|
ocf_refcnt_inc(&rc);
|
||||||
|
ocf_refcnt_inc(&rc);
|
||||||
|
|
||||||
|
ocf_refcnt_freeze(&rc);
|
||||||
|
|
||||||
|
val = ocf_refcnt_inc(&rc);
|
||||||
|
|
||||||
|
assert_int_equal(0, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_refcnt_freeze_test03(void **state)
|
||||||
|
{
|
||||||
|
struct ocf_refcnt rc;
|
||||||
|
int val, val2;
|
||||||
|
|
||||||
|
print_test_description("Freeze bocks increment");
|
||||||
|
|
||||||
|
ocf_refcnt_init(&rc);
|
||||||
|
|
||||||
|
val = ocf_refcnt_inc(&rc);
|
||||||
|
val = ocf_refcnt_inc(&rc);
|
||||||
|
val = ocf_refcnt_inc(&rc);
|
||||||
|
|
||||||
|
ocf_refcnt_freeze(&rc);
|
||||||
|
|
||||||
|
ocf_refcnt_inc(&rc);
|
||||||
|
|
||||||
|
val2 = env_atomic_read(&rc.counter);
|
||||||
|
|
||||||
|
assert_int_equal(val, val2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_refcnt_freeze_test04(void **state)
|
||||||
|
{
|
||||||
|
struct ocf_refcnt rc;
|
||||||
|
int val, val2;
|
||||||
|
|
||||||
|
print_test_description("Freeze allows decrement");
|
||||||
|
|
||||||
|
ocf_refcnt_init(&rc);
|
||||||
|
|
||||||
|
val = ocf_refcnt_inc(&rc);
|
||||||
|
val = ocf_refcnt_inc(&rc);
|
||||||
|
val = ocf_refcnt_inc(&rc);
|
||||||
|
|
||||||
|
ocf_refcnt_freeze(&rc);
|
||||||
|
|
||||||
|
val2 = ocf_refcnt_dec(&rc);
|
||||||
|
assert_int_equal(val2, val - 1);
|
||||||
|
|
||||||
|
val2 = ocf_refcnt_dec(&rc);
|
||||||
|
assert_int_equal(val2, val - 2);
|
||||||
|
}
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
const struct CMUnitTest tests[] = {
|
||||||
|
cmocka_unit_test(ocf_refcnt_freeze_test01),
|
||||||
|
cmocka_unit_test(ocf_refcnt_freeze_test02),
|
||||||
|
cmocka_unit_test(ocf_refcnt_freeze_test03),
|
||||||
|
cmocka_unit_test(ocf_refcnt_freeze_test04),
|
||||||
|
};
|
||||||
|
|
||||||
|
print_message("Unit test of src/utils/utils_refcnt.c");
|
||||||
|
|
||||||
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
}
|
51
tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_inc.c
Normal file
51
tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_inc.c
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* <tested_file_path>src/utils/utils_refcnt.c</tested_file_path>
|
||||||
|
* <tested_function>ocf_refcnt_inc</tested_function>
|
||||||
|
* <functions_to_leave>
|
||||||
|
* ocf_refcnt_init
|
||||||
|
* ocf_refcnt_dec
|
||||||
|
* </functions_to_leave>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#undef static
|
||||||
|
|
||||||
|
#undef inline
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <cmocka.h>
|
||||||
|
#include "print_desc.h"
|
||||||
|
|
||||||
|
#include "../utils/utils_refcnt.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void ocf_refcnt_inc_test(void **state)
|
||||||
|
{
|
||||||
|
struct ocf_refcnt rc;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
print_test_description("Increment adds 1 and returns proper value");
|
||||||
|
|
||||||
|
ocf_refcnt_init(&rc);
|
||||||
|
|
||||||
|
val = ocf_refcnt_inc(&rc);
|
||||||
|
assert_int_equal(1, val);
|
||||||
|
assert_int_equal(1, env_atomic_read(&rc.counter));
|
||||||
|
|
||||||
|
val = ocf_refcnt_inc(&rc);
|
||||||
|
assert_int_equal(2, val);
|
||||||
|
assert_int_equal(2, env_atomic_read(&rc.counter));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
const struct CMUnitTest tests[] = {
|
||||||
|
cmocka_unit_test(ocf_refcnt_inc_test)
|
||||||
|
};
|
||||||
|
|
||||||
|
print_message("Unit test of src/utils/utils_refcnt.c");
|
||||||
|
|
||||||
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
}
|
50
tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_init.c
Normal file
50
tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_init.c
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* <tested_file_path>src/utils/utils_refcnt.c</tested_file_path>
|
||||||
|
* <tested_function>ocf_refcnt_init</tested_function>
|
||||||
|
* <functions_to_leave>
|
||||||
|
* INSERT HERE LIST OF FUNCTIONS YOU WANT TO LEAVE
|
||||||
|
* ONE FUNCTION PER LINE
|
||||||
|
* </functions_to_leave>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#undef static
|
||||||
|
|
||||||
|
#undef inline
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <cmocka.h>
|
||||||
|
#include "print_desc.h"
|
||||||
|
|
||||||
|
#include "../utils/utils_refcnt.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void ocf_refcnt_init_test(void **state)
|
||||||
|
{
|
||||||
|
struct ocf_refcnt rc;
|
||||||
|
|
||||||
|
print_test_description("Reference counter is properly initialized");
|
||||||
|
|
||||||
|
env_atomic_set(&rc.counter, 1);
|
||||||
|
env_atomic_set(&rc.freeze, 1);
|
||||||
|
env_atomic_set(&rc.callback, 1);
|
||||||
|
|
||||||
|
ocf_refcnt_init(&rc);
|
||||||
|
|
||||||
|
assert_int_equal(0, env_atomic_read(&rc.counter));
|
||||||
|
assert_int_equal(0, env_atomic_read(&rc.freeze));
|
||||||
|
assert_int_equal(0, env_atomic_read(&rc.cb));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
const struct CMUnitTest tests[] = {
|
||||||
|
cmocka_unit_test(ocf_refcnt_init_test)
|
||||||
|
};
|
||||||
|
|
||||||
|
print_message("Unit test of src/utils/utils_refcnt.c");
|
||||||
|
|
||||||
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* <tested_file_path>src/utils/utils_refcnt.c</tested_file_path>
|
||||||
|
* <tested_function>ocf_refcnt_register_zero_cb</tested_function>
|
||||||
|
* <functions_to_leave>
|
||||||
|
* ocf_refcnt_init
|
||||||
|
* ocf_refcnt_inc
|
||||||
|
* ocf_refcnt_dec
|
||||||
|
* ocf_refcnt_freeze
|
||||||
|
* </functions_to_leave>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#undef static
|
||||||
|
|
||||||
|
#undef inline
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <cmocka.h>
|
||||||
|
#include "print_desc.h"
|
||||||
|
|
||||||
|
#include "../utils/utils_refcnt.h"
|
||||||
|
|
||||||
|
static void zero_cb(void *ctx)
|
||||||
|
{
|
||||||
|
function_called();
|
||||||
|
check_expected_ptr(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_refcnt_register_zero_cb_test01(void **state)
|
||||||
|
{
|
||||||
|
struct ocf_refcnt rc;
|
||||||
|
int val;
|
||||||
|
void *ptr = 0x12345678;
|
||||||
|
|
||||||
|
print_test_description("Callback fires when counter drops to 0");
|
||||||
|
|
||||||
|
/* cnt = 2 */
|
||||||
|
ocf_refcnt_init(&rc);
|
||||||
|
ocf_refcnt_inc(&rc);
|
||||||
|
ocf_refcnt_inc(&rc);
|
||||||
|
|
||||||
|
/* freeze and register cb */
|
||||||
|
ocf_refcnt_freeze(&rc);
|
||||||
|
ocf_refcnt_register_zero_cb(&rc, zero_cb, ptr);
|
||||||
|
|
||||||
|
/* 2 -> 1 */
|
||||||
|
ocf_refcnt_dec(&rc);
|
||||||
|
|
||||||
|
val = env_atomic_read(&rc.callback);
|
||||||
|
assert_int_equal(1, val);
|
||||||
|
|
||||||
|
/* expect callback now */
|
||||||
|
expect_function_calls(zero_cb, 1);
|
||||||
|
expect_value(zero_cb, ctx, ptr);
|
||||||
|
|
||||||
|
/* 1 -> 0 */
|
||||||
|
ocf_refcnt_dec(&rc);
|
||||||
|
|
||||||
|
val = env_atomic_read(&rc.callback);
|
||||||
|
assert_int_equal(0, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_refcnt_register_zero_cb_test02(void **state)
|
||||||
|
{
|
||||||
|
struct ocf_refcnt rc;
|
||||||
|
int val;
|
||||||
|
void *ptr = 0x12345678;
|
||||||
|
|
||||||
|
print_test_description("Callback fires when counter is already 0");
|
||||||
|
|
||||||
|
/* cnt = 0 */
|
||||||
|
ocf_refcnt_init(&rc);
|
||||||
|
|
||||||
|
/* freeze */
|
||||||
|
ocf_refcnt_freeze(&rc);
|
||||||
|
|
||||||
|
/* expect callback now */
|
||||||
|
expect_function_calls(zero_cb, 1);
|
||||||
|
expect_value(zero_cb, ctx, ptr);
|
||||||
|
|
||||||
|
/* regiser callback */
|
||||||
|
ocf_refcnt_register_zero_cb(&rc, zero_cb, ptr);
|
||||||
|
|
||||||
|
val = env_atomic_read(&rc.callback);
|
||||||
|
assert_int_equal(0, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
const struct CMUnitTest tests[] = {
|
||||||
|
cmocka_unit_test(ocf_refcnt_register_zero_cb_test01),
|
||||||
|
cmocka_unit_test(ocf_refcnt_register_zero_cb_test02),
|
||||||
|
};
|
||||||
|
|
||||||
|
print_message("Unit test of src/utils/utils_refcnt.c");
|
||||||
|
|
||||||
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
}
|
100
tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_unfreeze.c
Normal file
100
tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_unfreeze.c
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* <tested_file_path>src/utils/utils_refcnt.c</tested_file_path>
|
||||||
|
* <tested_function>ocf_refcnt_unfreeze</tested_function>
|
||||||
|
* <functions_to_leave>
|
||||||
|
* ocf_refcnt_init
|
||||||
|
* ocf_refcnt_inc
|
||||||
|
* ocf_refcnt_dec
|
||||||
|
* ocf_refcnt_freeze
|
||||||
|
* </functions_to_leave>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#undef static
|
||||||
|
|
||||||
|
#undef inline
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <cmocka.h>
|
||||||
|
#include "print_desc.h"
|
||||||
|
|
||||||
|
#include "../utils/utils_refcnt.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void ocf_refcnt_unfreeze_test01(void **state)
|
||||||
|
{
|
||||||
|
struct ocf_refcnt rc;
|
||||||
|
int val, val2;
|
||||||
|
|
||||||
|
print_test_description("Unfreeze decrements freeze counter");
|
||||||
|
|
||||||
|
ocf_refcnt_init(&rc);
|
||||||
|
|
||||||
|
ocf_refcnt_freeze(&rc);
|
||||||
|
ocf_refcnt_freeze(&rc);
|
||||||
|
val = env_atomic_read(&rc.freeze);
|
||||||
|
|
||||||
|
ocf_refcnt_unfreeze(&rc);
|
||||||
|
val2 = env_atomic_read(&rc.freeze);
|
||||||
|
assert_int_equal(val2, val - 1);
|
||||||
|
|
||||||
|
ocf_refcnt_unfreeze(&rc);
|
||||||
|
val2 = env_atomic_read(&rc.freeze);
|
||||||
|
assert_int_equal(val2, val - 2);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_refcnt_unfreeze_test02(void **state)
|
||||||
|
{
|
||||||
|
struct ocf_refcnt rc;
|
||||||
|
int val, val2;
|
||||||
|
|
||||||
|
print_test_description("Unfreezed counter can be incremented");
|
||||||
|
|
||||||
|
ocf_refcnt_init(&rc);
|
||||||
|
|
||||||
|
val = ocf_refcnt_inc(&rc);
|
||||||
|
ocf_refcnt_freeze(&rc);
|
||||||
|
ocf_refcnt_unfreeze(&rc);
|
||||||
|
val2 = ocf_refcnt_inc(&rc);
|
||||||
|
|
||||||
|
assert_int_equal(val2, val + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_refcnt_unfreeze_test03(void **state)
|
||||||
|
{
|
||||||
|
struct ocf_refcnt rc;
|
||||||
|
int val, val2;
|
||||||
|
|
||||||
|
print_test_description("Two freezes require two unfreezes");
|
||||||
|
|
||||||
|
ocf_refcnt_init(&rc);
|
||||||
|
|
||||||
|
val = ocf_refcnt_inc(&rc);
|
||||||
|
ocf_refcnt_freeze(&rc);
|
||||||
|
ocf_refcnt_freeze(&rc);
|
||||||
|
ocf_refcnt_unfreeze(&rc);
|
||||||
|
val2 = ocf_refcnt_inc(&rc);
|
||||||
|
|
||||||
|
assert_int_equal(0, val2);
|
||||||
|
|
||||||
|
ocf_refcnt_unfreeze(&rc);
|
||||||
|
val2 = ocf_refcnt_inc(&rc);
|
||||||
|
|
||||||
|
assert_int_equal(val2, val + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
const struct CMUnitTest tests[] = {
|
||||||
|
cmocka_unit_test(ocf_refcnt_unfreeze_test01),
|
||||||
|
cmocka_unit_test(ocf_refcnt_unfreeze_test02),
|
||||||
|
cmocka_unit_test(ocf_refcnt_unfreeze_test03),
|
||||||
|
};
|
||||||
|
|
||||||
|
print_message("Unit test of src/utils/utils_refcnt.c");
|
||||||
|
|
||||||
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user