Merge pull request #60 from robertbaldyga/make-cleaner-async
Make cleaner asynchronous
This commit is contained in:
commit
435cc6209a
@ -12,15 +12,38 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief OCF Cleaner completion
|
||||||
|
*
|
||||||
|
* @note Completion function for cleaner
|
||||||
|
*
|
||||||
|
* @param[in] cleaner Cleaner instance
|
||||||
|
* @param[in] interval Time to sleep before next cleaner iteration
|
||||||
|
*/
|
||||||
|
typedef void (*ocf_cleaner_end_t)(ocf_cleaner_t cleaner, uint32_t interval);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set cleaner completion function
|
||||||
|
*
|
||||||
|
* @param[in] cleaner Cleaner instance
|
||||||
|
* @param[in] fn Completion function
|
||||||
|
*/
|
||||||
|
void ocf_cleaner_set_cmpl(ocf_cleaner_t cleaner, ocf_cleaner_end_t fn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set cleaner queue
|
||||||
|
*
|
||||||
|
* @param[in] cleaner Cleaner instance
|
||||||
|
* @param[in] io_queue Queue number
|
||||||
|
*/
|
||||||
|
void ocf_cleaner_set_io_queue(ocf_cleaner_t cleaner, uint32_t io_queue);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Run cleaner
|
* @brief Run cleaner
|
||||||
*
|
*
|
||||||
* @param[in] c Cleaner instance to run
|
* @param[in] c Cleaner instance to run
|
||||||
* @param[in] io_queue I/O queue to which cleaner requests should be submitted
|
|
||||||
*
|
|
||||||
* @retval Hint when to run cleaner next time. Value expressed in miliseconds.
|
|
||||||
*/
|
*/
|
||||||
uint32_t ocf_cleaner_run(ocf_cleaner_t c, uint32_t io_queue);
|
void ocf_cleaner_run(ocf_cleaner_t c);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set cleaner private data
|
* @brief Set cleaner private data
|
||||||
|
@ -123,6 +123,12 @@ struct acp_context {
|
|||||||
perform_cleaning */
|
perform_cleaning */
|
||||||
struct acp_state state;
|
struct acp_state state;
|
||||||
|
|
||||||
|
/* cache handle */
|
||||||
|
ocf_cache_t cache;
|
||||||
|
|
||||||
|
/* cleaner completion callback */
|
||||||
|
ocf_cleaner_end_t cmpl;
|
||||||
|
|
||||||
#if 1 == OCF_ACP_DEBUG
|
#if 1 == OCF_ACP_DEBUG
|
||||||
/* debug only */
|
/* debug only */
|
||||||
uint64_t checksum;
|
uint64_t checksum;
|
||||||
@ -146,7 +152,7 @@ struct acp_core_line_info
|
|||||||
|
|
||||||
static struct acp_context *_acp_get_ctx_from_cache(struct ocf_cache *cache)
|
static struct acp_context *_acp_get_ctx_from_cache(struct ocf_cache *cache)
|
||||||
{
|
{
|
||||||
return cache->cleaning_policy_context;
|
return cache->cleaner.cleaning_policy_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct acp_cleaning_policy_meta* _acp_meta_get(
|
static struct acp_cleaning_policy_meta* _acp_meta_get(
|
||||||
@ -227,8 +233,8 @@ void cleaning_policy_acp_deinitialize(struct ocf_cache *cache)
|
|||||||
{
|
{
|
||||||
_acp_remove_cores(cache);
|
_acp_remove_cores(cache);
|
||||||
|
|
||||||
env_vfree(cache->cleaning_policy_context);
|
env_vfree(cache->cleaner.cleaning_policy_context);
|
||||||
cache->cleaning_policy_context = NULL;
|
cache->cleaner.cleaning_policy_context = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _acp_rebuild(struct ocf_cache *cache)
|
static void _acp_rebuild(struct ocf_cache *cache)
|
||||||
@ -282,14 +288,15 @@ int cleaning_policy_acp_initialize(struct ocf_cache *cache,
|
|||||||
1U << (sizeof(acp->chunk_info[0][0].num_dirty) * 8));
|
1U << (sizeof(acp->chunk_info[0][0].num_dirty) * 8));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ENV_BUG_ON(cache->cleaning_policy_context);
|
ENV_BUG_ON(cache->cleaner.cleaning_policy_context);
|
||||||
|
|
||||||
cache->cleaning_policy_context = env_vzalloc(sizeof(struct acp_context));
|
acp = env_vzalloc(sizeof(*acp));
|
||||||
if (!cache->cleaning_policy_context) {
|
if (!acp) {
|
||||||
ocf_cache_log(cache, log_err, "acp context allocation error\n");
|
ocf_cache_log(cache, log_err, "acp context allocation error\n");
|
||||||
return -OCF_ERR_NO_MEM;
|
return -OCF_ERR_NO_MEM;
|
||||||
}
|
}
|
||||||
acp = cache->cleaning_policy_context;
|
cache->cleaner.cleaning_policy_context = acp;
|
||||||
|
acp->cache = cache;
|
||||||
|
|
||||||
env_rwsem_init(&acp->chunks_lock);
|
env_rwsem_init(&acp->chunks_lock);
|
||||||
|
|
||||||
@ -412,40 +419,6 @@ static void _acp_handle_flush_error(struct ocf_cache *cache,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called after flush request completed */
|
|
||||||
static void _acp_flush_end(
|
|
||||||
struct ocf_cache *cache,
|
|
||||||
struct acp_context *acp)
|
|
||||||
{
|
|
||||||
struct acp_flush_context *flush = &acp->flush;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < flush->size; i++) {
|
|
||||||
ocf_cache_line_unlock_rd(cache, flush->data[i].cache_line);
|
|
||||||
ACP_DEBUG_END(acp, flush->data[i].cache_line);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flush->error)
|
|
||||||
_acp_handle_flush_error(cache, acp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* flush data */
|
|
||||||
static void _acp_flush(struct ocf_cache *cache, struct acp_context *acp,
|
|
||||||
uint32_t io_queue, struct acp_flush_context *flush)
|
|
||||||
{
|
|
||||||
struct ocf_cleaner_attribs attribs = {
|
|
||||||
.cache_line_lock = false,
|
|
||||||
.metadata_locked = false,
|
|
||||||
.do_sort = false,
|
|
||||||
.io_queue = io_queue,
|
|
||||||
};
|
|
||||||
|
|
||||||
flush->error = ocf_cleaner_do_flush_data(cache, flush->data,
|
|
||||||
flush->size, &attribs);
|
|
||||||
|
|
||||||
_acp_flush_end(cache, acp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool _acp_can_clean_chunk(struct ocf_cache *cache,
|
static inline bool _acp_can_clean_chunk(struct ocf_cache *cache,
|
||||||
struct acp_chunk_info *chunk)
|
struct acp_chunk_info *chunk)
|
||||||
{
|
{
|
||||||
@ -456,12 +429,11 @@ static inline bool _acp_can_clean_chunk(struct ocf_cache *cache,
|
|||||||
!chunk->next_cleaning_timestamp));
|
!chunk->next_cleaning_timestamp));
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct acp_chunk_info *_acp_get_cleaning_candidate(
|
static struct acp_chunk_info *_acp_get_cleaning_candidate(ocf_cache_t cache)
|
||||||
struct ocf_cache *cache)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct acp_chunk_info *cur;
|
struct acp_chunk_info *cur;
|
||||||
struct acp_context *acp = cache->cleaning_policy_context;
|
struct acp_context *acp = cache->cleaner.cleaning_policy_context;
|
||||||
|
|
||||||
ACP_LOCK_CHUNKS_RD();
|
ACP_LOCK_CHUNKS_RD();
|
||||||
|
|
||||||
@ -480,72 +452,107 @@ static struct acp_chunk_info *_acp_get_cleaning_candidate(
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CHUNK_FINISHED -1
|
/* called after flush request completed */
|
||||||
|
static void _acp_flush_end(void *priv, int error)
|
||||||
|
{
|
||||||
|
struct acp_cleaning_policy_config *config;
|
||||||
|
struct acp_context *acp = priv;
|
||||||
|
struct acp_flush_context *flush = &acp->flush;
|
||||||
|
ocf_cache_t cache = acp->cache;
|
||||||
|
int i;
|
||||||
|
|
||||||
/* clean at most 'flush_max_buffers' cache lines from given chunk, starting
|
config = (void *)&cache->conf_meta->cleaning[ocf_cleaning_acp].data;
|
||||||
* at given cache line */
|
|
||||||
static int _acp_clean(struct ocf_cache *cache, uint32_t io_queue,
|
for (i = 0; i < flush->size; i++) {
|
||||||
struct acp_chunk_info *chunk, unsigned start,
|
ocf_cache_line_unlock_rd(cache, flush->data[i].cache_line);
|
||||||
|
ACP_DEBUG_END(acp, flush->data[i].cache_line);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
flush->error = error;
|
||||||
|
_acp_handle_flush_error(cache, acp);
|
||||||
|
}
|
||||||
|
|
||||||
|
ACP_DEBUG_CHECK(acp);
|
||||||
|
|
||||||
|
acp->cmpl(&cache->cleaner, config->thread_wakeup_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flush data */
|
||||||
|
static void _acp_flush(struct acp_context *acp)
|
||||||
|
{
|
||||||
|
ocf_cache_t cache = acp->cache;
|
||||||
|
struct ocf_cleaner_attribs attribs = {
|
||||||
|
.cmpl_context = acp,
|
||||||
|
.cmpl_fn = _acp_flush_end,
|
||||||
|
.cache_line_lock = false,
|
||||||
|
.do_sort = false,
|
||||||
|
.io_queue = cache->cleaner.io_queue,
|
||||||
|
};
|
||||||
|
|
||||||
|
ocf_cleaner_do_flush_data_async(cache, acp->flush.data,
|
||||||
|
acp->flush.size, &attribs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _acp_prepare_flush_data(struct acp_context *acp,
|
||||||
uint32_t flush_max_buffers)
|
uint32_t flush_max_buffers)
|
||||||
{
|
{
|
||||||
struct acp_context *acp = _acp_get_ctx_from_cache(cache);
|
ocf_cache_t cache = acp->cache;
|
||||||
size_t lines_per_chunk = ACP_CHUNK_SIZE /
|
struct acp_state *state = &acp->state;
|
||||||
ocf_line_size(cache);
|
struct acp_chunk_info *chunk = state->chunk;
|
||||||
|
size_t lines_per_chunk = ACP_CHUNK_SIZE / ocf_line_size(cache);
|
||||||
uint64_t first_core_line = chunk->chunk_id * lines_per_chunk;
|
uint64_t first_core_line = chunk->chunk_id * lines_per_chunk;
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
OCF_DEBUG_PARAM(cache, "lines per chunk %llu chunk %llu "
|
OCF_DEBUG_PARAM(cache, "lines per chunk %llu chunk %llu "
|
||||||
"first_core_line %llu\n",
|
"first_core_line %llu\n", (uint64_t)lines_per_chunk,
|
||||||
(uint64_t)lines_per_chunk,
|
chunk->chunk_id, first_core_line);
|
||||||
chunk->chunk_id,
|
|
||||||
first_core_line);
|
|
||||||
|
|
||||||
ACP_DEBUG_INIT(acp);
|
|
||||||
|
|
||||||
acp->flush.size = 0;
|
acp->flush.size = 0;
|
||||||
acp->flush.chunk = chunk;
|
acp->flush.chunk = chunk;
|
||||||
for (i = start; i < lines_per_chunk && acp->flush.size < flush_max_buffers ; i++) {
|
for (; state->iter < lines_per_chunk &&
|
||||||
uint64_t core_line = first_core_line + i;
|
acp->flush.size < flush_max_buffers; state->iter++) {
|
||||||
|
uint64_t core_line = first_core_line + state->iter;
|
||||||
ocf_cache_line_t cache_line;
|
ocf_cache_line_t cache_line;
|
||||||
|
|
||||||
cache_line = _acp_trylock_dirty(cache, chunk->core_id, core_line);
|
cache_line = _acp_trylock_dirty(cache, chunk->core_id, core_line);
|
||||||
if (cache_line == cache->device->collision_table_entries)
|
if (cache_line == cache->device->collision_table_entries)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
ACP_DEBUG_BEGIN(acp, cache_line);
|
||||||
|
|
||||||
acp->flush.data[acp->flush.size].core_id = chunk->core_id;
|
acp->flush.data[acp->flush.size].core_id = chunk->core_id;
|
||||||
acp->flush.data[acp->flush.size].core_line = core_line;
|
acp->flush.data[acp->flush.size].core_line = core_line;
|
||||||
acp->flush.data[acp->flush.size].cache_line = cache_line;
|
acp->flush.data[acp->flush.size].cache_line = cache_line;
|
||||||
acp->flush.size++;
|
acp->flush.size++;
|
||||||
ACP_DEBUG_BEGIN(acp, cache_line);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (acp->flush.size > 0) {
|
if (state->iter == lines_per_chunk) {
|
||||||
_acp_flush(cache, acp, io_queue, &acp->flush);
|
/* reached end of chunk - reset state */
|
||||||
|
state->in_progress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ACP_DEBUG_CHECK(acp);
|
return (acp->flush.size > 0);
|
||||||
|
|
||||||
return (i == lines_per_chunk) ? CHUNK_FINISHED : i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NOTHING_TO_CLEAN 0
|
|
||||||
#define MORE_TO_CLEAN 1
|
|
||||||
|
|
||||||
/* Clean at most 'flush_max_buffers' cache lines from current or newly
|
/* Clean at most 'flush_max_buffers' cache lines from current or newly
|
||||||
* selected chunk */
|
* selected chunk */
|
||||||
static int _acp_clean_iteration(struct ocf_cache *cache, uint32_t io_queue,
|
void cleaning_policy_acp_perform_cleaning(struct ocf_cache *cache,
|
||||||
uint32_t flush_max_buffers)
|
ocf_cleaner_end_t cmpl)
|
||||||
{
|
{
|
||||||
|
struct acp_cleaning_policy_config *config;
|
||||||
struct acp_context *acp = _acp_get_ctx_from_cache(cache);
|
struct acp_context *acp = _acp_get_ctx_from_cache(cache);
|
||||||
struct acp_state *state = &acp->state;
|
struct acp_state *state = &acp->state;
|
||||||
|
|
||||||
|
acp->cmpl = cmpl;
|
||||||
|
|
||||||
if (!state->in_progress) {
|
if (!state->in_progress) {
|
||||||
/* get next chunk to clean */
|
/* get next chunk to clean */
|
||||||
state->chunk = _acp_get_cleaning_candidate(cache);
|
state->chunk = _acp_get_cleaning_candidate(cache);
|
||||||
|
|
||||||
if (!state->chunk) {
|
if (!state->chunk) {
|
||||||
/* nothing co clean */
|
/* nothing co clean */
|
||||||
return NOTHING_TO_CLEAN;
|
cmpl(&cache->cleaner, ACP_BACKOFF_TIME_MS);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* new cleaning cycle - reset state */
|
/* new cleaning cycle - reset state */
|
||||||
@ -553,34 +560,14 @@ static int _acp_clean_iteration(struct ocf_cache *cache, uint32_t io_queue,
|
|||||||
state->in_progress = true;
|
state->in_progress = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
state->iter = _acp_clean(cache, io_queue, state->chunk, state->iter,
|
ACP_DEBUG_INIT(acp);
|
||||||
flush_max_buffers);
|
|
||||||
|
|
||||||
if (state->iter == CHUNK_FINISHED) {
|
|
||||||
/* reached end of chunk - reset state */
|
|
||||||
state->in_progress = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return MORE_TO_CLEAN;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cleaning_policy_acp_perform_cleaning(struct ocf_cache *cache,
|
|
||||||
uint32_t io_queue)
|
|
||||||
{
|
|
||||||
struct acp_cleaning_policy_config *config;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
config = (void *)&cache->conf_meta->cleaning[ocf_cleaning_acp].data;
|
config = (void *)&cache->conf_meta->cleaning[ocf_cleaning_acp].data;
|
||||||
|
|
||||||
if (NOTHING_TO_CLEAN == _acp_clean_iteration(cache, io_queue,
|
if (_acp_prepare_flush_data(acp, config->flush_max_buffers))
|
||||||
config->flush_max_buffers)) {
|
_acp_flush(acp);
|
||||||
ret = ACP_BACKOFF_TIME_MS;
|
else
|
||||||
} else {
|
_acp_flush_end(acp, 0);
|
||||||
ret = config->thread_wakeup_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _acp_update_bucket(struct acp_context *acp,
|
static void _acp_update_bucket(struct acp_context *acp,
|
||||||
|
@ -8,32 +8,30 @@
|
|||||||
|
|
||||||
#include "cleaning.h"
|
#include "cleaning.h"
|
||||||
|
|
||||||
void cleaning_policy_acp_setup(struct ocf_cache *cache);
|
void cleaning_policy_acp_setup(ocf_cache_t cache);
|
||||||
|
|
||||||
int cleaning_policy_acp_initialize(struct ocf_cache *cache,
|
int cleaning_policy_acp_initialize(ocf_cache_t cache, int init_metadata);
|
||||||
int init_metadata);
|
|
||||||
|
|
||||||
void cleaning_policy_acp_deinitialize(struct ocf_cache *cache);
|
void cleaning_policy_acp_deinitialize(ocf_cache_t cache);
|
||||||
|
|
||||||
int cleaning_policy_acp_perform_cleaning(struct ocf_cache *cache,
|
void cleaning_policy_acp_perform_cleaning(ocf_cache_t cache,
|
||||||
uint32_t io_queue);
|
ocf_cleaner_end_t cmpl);
|
||||||
|
|
||||||
void cleaning_policy_acp_init_cache_block(struct ocf_cache *cache,
|
void cleaning_policy_acp_init_cache_block(ocf_cache_t cache,
|
||||||
uint32_t cache_line);
|
uint32_t cache_line);
|
||||||
|
|
||||||
void cleaning_policy_acp_set_hot_cache_line(struct ocf_cache *cache,
|
void cleaning_policy_acp_set_hot_cache_line(ocf_cache_t cache,
|
||||||
uint32_t cache_line);
|
uint32_t cache_line);
|
||||||
|
|
||||||
void cleaning_policy_acp_purge_block(struct ocf_cache *cache,
|
void cleaning_policy_acp_purge_block(ocf_cache_t cache, uint32_t cache_line);
|
||||||
uint32_t cache_line);
|
|
||||||
|
|
||||||
int cleaning_policy_acp_purge_range(struct ocf_cache *cache,
|
int cleaning_policy_acp_purge_range(ocf_cache_t cache,
|
||||||
int core_id, uint64_t start_byte, uint64_t end_byte);
|
int core_id, uint64_t start_byte, uint64_t end_byte);
|
||||||
|
|
||||||
int cleaning_policy_acp_set_cleaning_param(struct ocf_cache *cache,
|
int cleaning_policy_acp_set_cleaning_param(ocf_cache_t cache,
|
||||||
uint32_t param_id, uint32_t param_value);
|
uint32_t param_id, uint32_t param_value);
|
||||||
|
|
||||||
int cleaning_policy_acp_get_cleaning_param(struct ocf_cache *cache,
|
int cleaning_policy_acp_get_cleaning_param(ocf_cache_t cache,
|
||||||
uint32_t param_id, uint32_t *param_value);
|
uint32_t param_id, uint32_t *param_value);
|
||||||
|
|
||||||
int cleaning_policy_acp_add_core(ocf_cache_t cache, ocf_core_id_t core_id);
|
int cleaning_policy_acp_add_core(ocf_cache_t cache, ocf_core_id_t core_id);
|
||||||
|
@ -49,6 +49,17 @@ struct flush_merge_struct {
|
|||||||
uint64_t core_sector;
|
uint64_t core_sector;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct alru_flush_ctx {
|
||||||
|
struct ocf_cleaner_attribs attribs;
|
||||||
|
struct ocf_user_part *parts[OCF_IO_CLASS_MAX];
|
||||||
|
int part_id;
|
||||||
|
uint32_t clines_no;
|
||||||
|
ocf_cache_t cache;
|
||||||
|
ocf_cleaner_end_t cmpl;
|
||||||
|
struct flush_data *flush_data;
|
||||||
|
size_t flush_data_limit;
|
||||||
|
};
|
||||||
|
|
||||||
/* -- Start of ALRU functions -- */
|
/* -- Start of ALRU functions -- */
|
||||||
|
|
||||||
|
|
||||||
@ -412,7 +423,6 @@ static void _alru_rebuild(struct ocf_cache *cache)
|
|||||||
static int cleaning_policy_alru_initialize_part(struct ocf_cache *cache,
|
static int cleaning_policy_alru_initialize_part(struct ocf_cache *cache,
|
||||||
struct ocf_user_part *part, int init_metadata)
|
struct ocf_user_part *part, int init_metadata)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (init_metadata) {
|
if (init_metadata) {
|
||||||
/* ALRU initialization */
|
/* ALRU initialization */
|
||||||
env_atomic_set(&part->runtime->cleaning.policy.alru.size, 0);
|
env_atomic_set(&part->runtime->cleaning.policy.alru.size, 0);
|
||||||
@ -443,6 +453,15 @@ int cleaning_policy_alru_initialize(struct ocf_cache *cache, int init_metadata)
|
|||||||
{
|
{
|
||||||
struct ocf_user_part *part;
|
struct ocf_user_part *part;
|
||||||
ocf_part_id_t part_id;
|
ocf_part_id_t part_id;
|
||||||
|
struct alru_flush_ctx *fctx;
|
||||||
|
|
||||||
|
fctx = env_vzalloc(sizeof(*fctx));
|
||||||
|
if (!fctx) {
|
||||||
|
ocf_cache_log(cache, log_err, "alru ctx allocation error\n");
|
||||||
|
return -OCF_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache->cleaner.cleaning_policy_context = fctx;
|
||||||
|
|
||||||
for_each_part(cache, part, part_id) {
|
for_each_part(cache, part, part_id) {
|
||||||
cleaning_policy_alru_initialize_part(cache,
|
cleaning_policy_alru_initialize_part(cache,
|
||||||
@ -455,6 +474,12 @@ int cleaning_policy_alru_initialize(struct ocf_cache *cache, int init_metadata)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cleaning_policy_alru_deinitialize(struct ocf_cache *cache)
|
||||||
|
{
|
||||||
|
env_vfree(cache->cleaner.cleaning_policy_context);
|
||||||
|
cache->cleaner.cleaning_policy_context = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
int cleaning_policy_alru_set_cleaning_param(ocf_cache_t cache,
|
int cleaning_policy_alru_set_cleaning_param(ocf_cache_t cache,
|
||||||
uint32_t param_id, uint32_t param_value)
|
uint32_t param_id, uint32_t param_value)
|
||||||
{
|
{
|
||||||
@ -590,7 +615,7 @@ static void get_parts_sorted(struct ocf_user_part **parts,
|
|||||||
cmp_ocf_user_parts, swp_ocf_user_part);
|
cmp_ocf_user_parts, swp_ocf_user_part);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int clean_later(ocf_cache_t cache, uint32_t *delta)
|
static bool clean_later(ocf_cache_t cache, uint32_t *delta)
|
||||||
{
|
{
|
||||||
struct alru_cleaning_policy_config *config;
|
struct alru_cleaning_policy_config *config;
|
||||||
|
|
||||||
@ -604,6 +629,33 @@ static int clean_later(ocf_cache_t cache, uint32_t *delta)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool is_cleanup_possible(ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
struct alru_cleaning_policy_config *config;
|
||||||
|
uint32_t delta;
|
||||||
|
|
||||||
|
config = (void *)&cache->conf_meta->cleaning[ocf_cleaning_alru].data;
|
||||||
|
|
||||||
|
if (check_for_io_activity(cache, config)) {
|
||||||
|
OCF_DEBUG_PARAM(cache, "IO activity detected");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clean_later(cache, &delta)) {
|
||||||
|
OCF_DEBUG_PARAM(cache,
|
||||||
|
"Cleaning policy configured to clean later "
|
||||||
|
"delta=%u wake_up=%u", delta,
|
||||||
|
config->thread_wakeup_time);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Cleaning policy configured to not clean anything
|
||||||
|
if (config->flush_max_buffers == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void get_block_to_flush(struct flush_data* dst,
|
static void get_block_to_flush(struct flush_data* dst,
|
||||||
ocf_cache_line_t cache_line, struct ocf_cache* cache)
|
ocf_cache_line_t cache_line, struct ocf_cache* cache)
|
||||||
{
|
{
|
||||||
@ -618,7 +670,7 @@ static void get_block_to_flush(struct flush_data* dst,
|
|||||||
dst->core_line = core_line;
|
dst->core_line = core_line;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int more_blocks_to_flush(struct ocf_cache *cache,
|
static bool more_blocks_to_flush(struct ocf_cache *cache,
|
||||||
ocf_cache_line_t cache_line, uint32_t last_access)
|
ocf_cache_line_t cache_line, uint32_t last_access)
|
||||||
{
|
{
|
||||||
struct cleaning_policy_meta policy;
|
struct cleaning_policy_meta policy;
|
||||||
@ -634,7 +686,7 @@ static int more_blocks_to_flush(struct ocf_cache *cache,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int block_is_busy(struct ocf_cache *cache,
|
static bool block_is_busy(struct ocf_cache *cache,
|
||||||
ocf_cache_line_t cache_line)
|
ocf_cache_line_t cache_line)
|
||||||
{
|
{
|
||||||
ocf_core_id_t core_id;
|
ocf_core_id_t core_id;
|
||||||
@ -687,116 +739,99 @@ static int get_data_to_flush(struct flush_data *dst, uint32_t clines_no,
|
|||||||
return to_flush;
|
return to_flush;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int perform_flushing(int clines_no, struct ocf_cache *cache, uint32_t io_queue,
|
static bool alru_do_clean(ocf_cache_t cache, struct alru_flush_ctx *fctx)
|
||||||
struct flush_data *flush_data, struct ocf_user_part *part)
|
|
||||||
{
|
{
|
||||||
int to_clean = get_data_to_flush(flush_data, clines_no, cache, part);
|
struct ocf_user_part *part = fctx->parts[fctx->part_id];
|
||||||
|
int to_clean;
|
||||||
|
|
||||||
|
if (!is_cleanup_possible(cache))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (OCF_METADATA_LOCK_WR_TRY())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
OCF_REALLOC(&fctx->flush_data, sizeof(fctx->flush_data[0]),
|
||||||
|
fctx->clines_no, &fctx->flush_data_limit);
|
||||||
|
if (!fctx->flush_data) {
|
||||||
|
OCF_METADATA_UNLOCK_WR();
|
||||||
|
ocf_cache_log(cache, log_warn, "No memory to allocate flush "
|
||||||
|
"data for ALRU cleaning policy");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
to_clean = get_data_to_flush(fctx->flush_data, fctx->clines_no,
|
||||||
|
cache, part);
|
||||||
if (to_clean > 0) {
|
if (to_clean > 0) {
|
||||||
struct ocf_cleaner_attribs attribs = {
|
fctx->clines_no -= to_clean;
|
||||||
.cache_line_lock = true,
|
ocf_cleaner_do_flush_data_async(cache, fctx->flush_data,
|
||||||
.metadata_locked = true,
|
to_clean, &fctx->attribs);
|
||||||
.do_sort = true,
|
|
||||||
.io_queue = io_queue
|
|
||||||
};
|
|
||||||
|
|
||||||
ocf_cleaner_do_flush_data(cache, flush_data,
|
|
||||||
to_clean, &attribs);
|
|
||||||
} else {
|
} else {
|
||||||
/* Update timestamp only if there are no items to be cleaned */
|
/* Update timestamp only if there are no items to be cleaned */
|
||||||
cache->device->runtime_meta->cleaning_thread_access =
|
cache->device->runtime_meta->cleaning_thread_access =
|
||||||
env_ticks_to_secs(env_get_tick_count());
|
env_ticks_to_secs(env_get_tick_count());
|
||||||
}
|
}
|
||||||
|
|
||||||
return to_clean;
|
OCF_METADATA_UNLOCK_WR();
|
||||||
|
|
||||||
|
return to_clean > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_cleanup_possible(ocf_cache_t cache)
|
static void alru_clean(void *priv, int error)
|
||||||
{
|
{
|
||||||
struct alru_cleaning_policy_config *config;
|
struct alru_cleaning_policy_config *config;
|
||||||
uint32_t delta;
|
struct alru_flush_ctx *fctx = priv;
|
||||||
|
ocf_cache_t cache = fctx->cache;
|
||||||
|
int interval;
|
||||||
|
|
||||||
|
while (fctx->clines_no > 0 && --fctx->part_id >= 0) {
|
||||||
|
/*
|
||||||
|
* The alru_do_clean() function returns true when submitting
|
||||||
|
* flush request for the io class succeeded. In such case we
|
||||||
|
* return and wait until flush finishes - then this function
|
||||||
|
* will be called as completion callback and iteration over
|
||||||
|
* io classes will continue.
|
||||||
|
*
|
||||||
|
* If the processed io class contains nothing to clean, the
|
||||||
|
* alru_do_clean() function returns false, and then we try to
|
||||||
|
* clean another io class until we reach last io class or until
|
||||||
|
* requested number of cache lines will be flushed - then we
|
||||||
|
* call the completion and finish.
|
||||||
|
*/
|
||||||
|
if (alru_do_clean(cache, fctx))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OCF_REALLOC_DEINIT(&fctx->flush_data, &fctx->flush_data_limit);
|
||||||
|
|
||||||
config = (void *)&cache->conf_meta->cleaning[ocf_cleaning_alru].data;
|
config = (void *)&cache->conf_meta->cleaning[ocf_cleaning_alru].data;
|
||||||
|
|
||||||
if (check_for_io_activity(cache, config)) {
|
interval = (fctx->clines_no > 0) ?
|
||||||
OCF_DEBUG_PARAM(cache, "IO activity detected");
|
config->thread_wakeup_time * 1000 : 0;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clean_later(cache, &delta)) {
|
fctx->cmpl(&fctx->cache->cleaner, interval);
|
||||||
OCF_DEBUG_PARAM(cache,
|
|
||||||
"Cleaning policy configured to clean later "
|
|
||||||
"delta=%u wake_up=%u", delta,
|
|
||||||
config->thread_wakeup_time);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Cleaning policy configured to not clean anything
|
|
||||||
if (config->flush_max_buffers == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cleanup(struct ocf_cache *cache, uint32_t clines_no,
|
void cleaning_alru_perform_cleaning(ocf_cache_t cache, ocf_cleaner_end_t cmpl)
|
||||||
struct ocf_user_part *part, uint32_t io_queue)
|
|
||||||
{
|
{
|
||||||
struct flush_data *flush_data;
|
struct alru_flush_ctx *fctx = cache->cleaner.cleaning_policy_context;
|
||||||
size_t flush_data_limit;
|
|
||||||
int flushed_blocks = 0;
|
|
||||||
|
|
||||||
if (!is_cleanup_possible(cache))
|
|
||||||
return flushed_blocks;
|
|
||||||
|
|
||||||
if (OCF_METADATA_LOCK_WR_TRY())
|
|
||||||
return flushed_blocks;
|
|
||||||
|
|
||||||
OCF_REALLOC_INIT(&flush_data, &flush_data_limit);
|
|
||||||
OCF_REALLOC(&flush_data, sizeof(flush_data[0]), clines_no,
|
|
||||||
&flush_data_limit);
|
|
||||||
|
|
||||||
if (!flush_data) {
|
|
||||||
OCF_METADATA_UNLOCK_WR();
|
|
||||||
ocf_cache_log(cache, log_warn, "No memory to allocate flush "
|
|
||||||
"data for ALRU cleaning policy");
|
|
||||||
return flushed_blocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
flushed_blocks = perform_flushing(clines_no, cache, io_queue,
|
|
||||||
flush_data, part);
|
|
||||||
|
|
||||||
OCF_METADATA_UNLOCK_WR();
|
|
||||||
|
|
||||||
OCF_REALLOC_DEINIT(&flush_data, &flush_data_limit);
|
|
||||||
|
|
||||||
return flushed_blocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cleaning_alru_perform_cleaning(ocf_cache_t cache, uint32_t io_queue)
|
|
||||||
{
|
|
||||||
struct ocf_user_part *parts[OCF_IO_CLASS_MAX];
|
|
||||||
int part_id = OCF_IO_CLASS_MAX - 1;
|
|
||||||
struct alru_cleaning_policy_config *config;
|
struct alru_cleaning_policy_config *config;
|
||||||
uint32_t clines_no;
|
|
||||||
|
|
||||||
config = (void *)&cache->conf_meta->cleaning[ocf_cleaning_alru].data;
|
config = (void *)&cache->conf_meta->cleaning[ocf_cleaning_alru].data;
|
||||||
|
|
||||||
get_parts_sorted(parts, cache);
|
OCF_REALLOC_INIT(&fctx->flush_data, &fctx->flush_data_limit);
|
||||||
|
|
||||||
clines_no = config->flush_max_buffers;
|
fctx->attribs.cmpl_context = fctx;
|
||||||
|
fctx->attribs.cmpl_fn = alru_clean;
|
||||||
|
fctx->attribs.cache_line_lock = true;
|
||||||
|
fctx->attribs.do_sort = true;
|
||||||
|
fctx->attribs.io_queue = cache->cleaner.io_queue;
|
||||||
|
|
||||||
while (part_id >= 0) {
|
fctx->clines_no = config->flush_max_buffers;
|
||||||
clines_no -= cleanup(cache, clines_no,
|
fctx->cache = cache;
|
||||||
parts[part_id], io_queue);
|
fctx->cmpl = cmpl;
|
||||||
|
|
||||||
if (clines_no > 0)
|
get_parts_sorted(fctx->parts, cache);
|
||||||
part_id--;
|
fctx->part_id = OCF_IO_CLASS_MAX;
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clines_no > 0)
|
alru_clean(fctx, 0);
|
||||||
return config->thread_wakeup_time * 1000;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
@ -9,22 +9,22 @@
|
|||||||
#include "cleaning.h"
|
#include "cleaning.h"
|
||||||
#include "alru_structs.h"
|
#include "alru_structs.h"
|
||||||
|
|
||||||
void cleaning_policy_alru_setup(struct ocf_cache *cache);
|
void cleaning_policy_alru_setup(ocf_cache_t cache);
|
||||||
int cleaning_policy_alru_initialize(struct ocf_cache *cache,
|
int cleaning_policy_alru_initialize(ocf_cache_t cache, int init_metadata);
|
||||||
int init_metadata);
|
void cleaning_policy_alru_deinitialize(ocf_cache_t cache);
|
||||||
void cleaning_policy_alru_init_cache_block(struct ocf_cache *cache,
|
void cleaning_policy_alru_init_cache_block(ocf_cache_t cache,
|
||||||
uint32_t cache_line);
|
uint32_t cache_line);
|
||||||
void cleaning_policy_alru_purge_cache_block(struct ocf_cache *cache,
|
void cleaning_policy_alru_purge_cache_block(ocf_cache_t cache,
|
||||||
uint32_t cache_line);
|
uint32_t cache_line);
|
||||||
int cleaning_policy_alru_purge_range(struct ocf_cache *cache, int core_id,
|
int cleaning_policy_alru_purge_range(ocf_cache_t cache, int core_id,
|
||||||
uint64_t start_byte, uint64_t end_byte);
|
uint64_t start_byte, uint64_t end_byte);
|
||||||
void cleaning_policy_alru_set_hot_cache_line(struct ocf_cache *cache,
|
void cleaning_policy_alru_set_hot_cache_line(ocf_cache_t cache,
|
||||||
uint32_t cache_line);
|
uint32_t cache_line);
|
||||||
int cleaning_policy_alru_set_cleaning_param(struct ocf_cache *cache,
|
int cleaning_policy_alru_set_cleaning_param(ocf_cache_t cache,
|
||||||
uint32_t param_id, uint32_t param_value);
|
uint32_t param_id, uint32_t param_value);
|
||||||
int cleaning_policy_alru_get_cleaning_param(struct ocf_cache *cache,
|
int cleaning_policy_alru_get_cleaning_param(ocf_cache_t cache,
|
||||||
uint32_t param_id, uint32_t *param_value);
|
uint32_t param_id, uint32_t *param_value);
|
||||||
int cleaning_alru_perform_cleaning(struct ocf_cache *cache, uint32_t io_queue);
|
void cleaning_alru_perform_cleaning(ocf_cache_t cache, ocf_cleaner_end_t cmpl);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ struct cleaning_policy_ops cleaning_policy_ops[ocf_cleaning_max] = {
|
|||||||
.purge_range = cleaning_policy_alru_purge_range,
|
.purge_range = cleaning_policy_alru_purge_range,
|
||||||
.set_hot_cache_line = cleaning_policy_alru_set_hot_cache_line,
|
.set_hot_cache_line = cleaning_policy_alru_set_hot_cache_line,
|
||||||
.initialize = cleaning_policy_alru_initialize,
|
.initialize = cleaning_policy_alru_initialize,
|
||||||
|
.deinitialize = cleaning_policy_alru_deinitialize,
|
||||||
.set_cleaning_param = cleaning_policy_alru_set_cleaning_param,
|
.set_cleaning_param = cleaning_policy_alru_set_cleaning_param,
|
||||||
.get_cleaning_param = cleaning_policy_alru_get_cleaning_param,
|
.get_cleaning_param = cleaning_policy_alru_get_cleaning_param,
|
||||||
.perform_cleaning = cleaning_alru_perform_cleaning,
|
.perform_cleaning = cleaning_alru_perform_cleaning,
|
||||||
@ -47,16 +48,26 @@ struct cleaning_policy_ops cleaning_policy_ops[ocf_cleaning_max] = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
int ocf_start_cleaner(struct ocf_cache *cache)
|
int ocf_start_cleaner(ocf_cache_t cache)
|
||||||
{
|
{
|
||||||
return ctx_cleaner_init(cache->owner, &cache->cleaner);
|
return ctx_cleaner_init(cache->owner, &cache->cleaner);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ocf_stop_cleaner(struct ocf_cache *cache)
|
void ocf_stop_cleaner(ocf_cache_t cache)
|
||||||
{
|
{
|
||||||
ctx_cleaner_stop(cache->owner, &cache->cleaner);
|
ctx_cleaner_stop(cache->owner, &cache->cleaner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ocf_cleaner_set_cmpl(ocf_cleaner_t cleaner, ocf_cleaner_end_t fn)
|
||||||
|
{
|
||||||
|
cleaner->end = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ocf_cleaner_set_io_queue(ocf_cleaner_t cleaner, uint32_t io_queue)
|
||||||
|
{
|
||||||
|
cleaner->io_queue = io_queue;
|
||||||
|
}
|
||||||
|
|
||||||
void ocf_cleaner_set_priv(ocf_cleaner_t c, void *priv)
|
void ocf_cleaner_set_priv(ocf_cleaner_t c, void *priv)
|
||||||
{
|
{
|
||||||
OCF_CHECK_NULL(c);
|
OCF_CHECK_NULL(c);
|
||||||
@ -75,7 +86,7 @@ ocf_cache_t ocf_cleaner_get_cache(ocf_cleaner_t c)
|
|||||||
return container_of(c, struct ocf_cache, cleaner);
|
return container_of(c, struct ocf_cache, cleaner);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _ocf_cleaner_run_check_dirty_inactive(struct ocf_cache *cache)
|
static int _ocf_cleaner_run_check_dirty_inactive(ocf_cache_t cache)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -95,29 +106,37 @@ static int _ocf_cleaner_run_check_dirty_inactive(struct ocf_cache *cache)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ocf_cleaner_run(ocf_cleaner_t c, uint32_t io_queue)
|
static void ocf_cleaner_run_complete(ocf_cleaner_t cleaner, uint32_t interval)
|
||||||
{
|
{
|
||||||
struct ocf_cache *cache;
|
ocf_cache_t cache = ocf_cleaner_get_cache(cleaner);
|
||||||
ocf_cleaning_t clean_type;
|
|
||||||
int sleep = SLEEP_TIME_MS;
|
|
||||||
|
|
||||||
cache = ocf_cleaner_get_cache(c);
|
env_rwsem_up_write(&cache->lock);
|
||||||
|
cleaner->end(cleaner, interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ocf_cleaner_run(ocf_cleaner_t cleaner)
|
||||||
|
{
|
||||||
|
ocf_cache_t cache = ocf_cleaner_get_cache(cleaner);
|
||||||
|
ocf_cleaning_t clean_type;
|
||||||
|
|
||||||
/* Do not involve cleaning when cache is not running
|
/* Do not involve cleaning when cache is not running
|
||||||
* (error, etc.).
|
* (error, etc.).
|
||||||
*/
|
*/
|
||||||
if (!env_bit_test(ocf_cache_state_running, &cache->cache_state) ||
|
if (!env_bit_test(ocf_cache_state_running, &cache->cache_state) ||
|
||||||
ocf_mngt_is_cache_locked(cache)) {
|
ocf_mngt_is_cache_locked(cache)) {
|
||||||
return SLEEP_TIME_MS;
|
cleaner->end(cleaner, SLEEP_TIME_MS);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sleep in case there is management operation in progress. */
|
/* Sleep in case there is management operation in progress. */
|
||||||
if (env_rwsem_down_write_trylock(&cache->lock) == 0)
|
if (env_rwsem_down_write_trylock(&cache->lock) == 0) {
|
||||||
return SLEEP_TIME_MS;
|
cleaner->end(cleaner, SLEEP_TIME_MS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (_ocf_cleaner_run_check_dirty_inactive(cache)) {
|
if (_ocf_cleaner_run_check_dirty_inactive(cache)) {
|
||||||
env_rwsem_up_write(&cache->lock);
|
cleaner->end(cleaner, SLEEP_TIME_MS);
|
||||||
return SLEEP_TIME_MS;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
clean_type = cache->conf_meta->cleaning_policy_type;
|
clean_type = cache->conf_meta->cleaning_policy_type;
|
||||||
@ -126,12 +145,7 @@ uint32_t ocf_cleaner_run(ocf_cleaner_t c, uint32_t io_queue)
|
|||||||
|
|
||||||
/* Call cleaning. */
|
/* Call cleaning. */
|
||||||
if (cleaning_policy_ops[clean_type].perform_cleaning) {
|
if (cleaning_policy_ops[clean_type].perform_cleaning) {
|
||||||
sleep = cleaning_policy_ops[clean_type].
|
cleaning_policy_ops[clean_type].perform_cleaning(cache,
|
||||||
perform_cleaning(cache, io_queue);
|
ocf_cleaner_run_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
env_rwsem_up_write(&cache->lock);
|
|
||||||
|
|
||||||
return sleep;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "alru_structs.h"
|
#include "alru_structs.h"
|
||||||
#include "nop_structs.h"
|
#include "nop_structs.h"
|
||||||
#include "acp_structs.h"
|
#include "acp_structs.h"
|
||||||
|
#include "ocf/ocf_cleaner.h"
|
||||||
|
|
||||||
#define CLEANING_POLICY_CONFIG_BYTES 256
|
#define CLEANING_POLICY_CONFIG_BYTES 256
|
||||||
#define CLEANING_POLICY_TYPE_MAX 4
|
#define CLEANING_POLICY_TYPE_MAX 4
|
||||||
@ -17,7 +18,6 @@ struct ocf_request;
|
|||||||
|
|
||||||
struct cleaning_policy_config {
|
struct cleaning_policy_config {
|
||||||
uint8_t data[CLEANING_POLICY_CONFIG_BYTES];
|
uint8_t data[CLEANING_POLICY_CONFIG_BYTES];
|
||||||
struct acp_cleaning_policy_config acp;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cleaning_policy {
|
struct cleaning_policy {
|
||||||
@ -37,39 +37,35 @@ struct cleaning_policy_meta {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct cleaning_policy_ops {
|
struct cleaning_policy_ops {
|
||||||
void (*setup)(struct ocf_cache *cache);
|
void (*setup)(ocf_cache_t cache);
|
||||||
int (*initialize)(struct ocf_cache *cache, int init_metadata);
|
int (*initialize)(ocf_cache_t cache, int init_metadata);
|
||||||
void (*deinitialize)(struct ocf_cache *cache);
|
void (*deinitialize)(ocf_cache_t cache);
|
||||||
int (*add_core)(struct ocf_cache *cache, ocf_core_id_t core_id);
|
int (*add_core)(ocf_cache_t cache, ocf_core_id_t core_id);
|
||||||
void (*remove_core)(struct ocf_cache *cache, ocf_core_id_t core_id);
|
void (*remove_core)(ocf_cache_t cache, ocf_core_id_t core_id);
|
||||||
void (*init_cache_block)(struct ocf_cache *cache, uint32_t cache_line);
|
void (*init_cache_block)(ocf_cache_t cache, uint32_t cache_line);
|
||||||
void (*purge_cache_block)(struct ocf_cache *cache,
|
void (*purge_cache_block)(ocf_cache_t cache, uint32_t cache_line);
|
||||||
uint32_t cache_line);
|
int (*purge_range)(ocf_cache_t cache, int core_id,
|
||||||
int (*purge_range)(struct ocf_cache *cache, int core_id,
|
|
||||||
uint64_t start_byte, uint64_t end_byte);
|
uint64_t start_byte, uint64_t end_byte);
|
||||||
void (*set_hot_cache_line)(struct ocf_cache *cache,
|
void (*set_hot_cache_line)(ocf_cache_t cache, uint32_t cache_line);
|
||||||
uint32_t cache_line);
|
int (*set_cleaning_param)(ocf_cache_t cache, uint32_t param_id,
|
||||||
int (*set_cleaning_param)(struct ocf_cache *cache,
|
uint32_t param_value);
|
||||||
uint32_t param_id, uint32_t param_value);
|
int (*get_cleaning_param)(ocf_cache_t cache, uint32_t param_id,
|
||||||
int (*get_cleaning_param)(struct ocf_cache *cache,
|
uint32_t *param_value);
|
||||||
uint32_t param_id, uint32_t *param_value);
|
void (*perform_cleaning)(ocf_cache_t cache, ocf_cleaner_end_t cmpl);
|
||||||
/**
|
|
||||||
* @brief Performs cleaning.
|
|
||||||
* @return requested time (in ms) of next call
|
|
||||||
*/
|
|
||||||
int (*perform_cleaning)(struct ocf_cache *cache,
|
|
||||||
uint32_t io_queue);
|
|
||||||
const char *name;
|
const char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct cleaning_policy_ops cleaning_policy_ops[ocf_cleaning_max];
|
extern struct cleaning_policy_ops cleaning_policy_ops[ocf_cleaning_max];
|
||||||
|
|
||||||
struct ocf_cleaner {
|
struct ocf_cleaner {
|
||||||
|
void *cleaning_policy_context;
|
||||||
|
uint32_t io_queue;
|
||||||
|
ocf_cleaner_end_t end;
|
||||||
void *priv;
|
void *priv;
|
||||||
};
|
};
|
||||||
|
|
||||||
int ocf_start_cleaner(struct ocf_cache *cache);
|
int ocf_start_cleaner(ocf_cache_t cache);
|
||||||
|
|
||||||
void ocf_stop_cleaner(struct ocf_cache *cache);
|
void ocf_stop_cleaner(ocf_cache_t cache);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -316,7 +316,6 @@ static int _ocf_mngt_flush_containers(ocf_cache_t cache,
|
|||||||
|
|
||||||
for (i = 0; i < fcnum; i++) {
|
for (i = 0; i < fcnum; i++) {
|
||||||
fctbl[i].attribs.cache_line_lock = true;
|
fctbl[i].attribs.cache_line_lock = true;
|
||||||
fctbl[i].attribs.metadata_locked = true;
|
|
||||||
fctbl[i].attribs.cmpl_context = &fctbl[i];
|
fctbl[i].attribs.cmpl_context = &fctbl[i];
|
||||||
fctbl[i].attribs.cmpl_fn = _ocf_mngt_flush_end;
|
fctbl[i].attribs.cmpl_fn = _ocf_mngt_flush_end;
|
||||||
fctbl[i].attribs.io_queue = 0;
|
fctbl[i].attribs.io_queue = 0;
|
||||||
|
@ -223,8 +223,6 @@ struct ocf_cache {
|
|||||||
|
|
||||||
bool use_submit_io_fast;
|
bool use_submit_io_fast;
|
||||||
|
|
||||||
void *cleaning_policy_context;
|
|
||||||
|
|
||||||
struct ocf_trace trace;
|
struct ocf_trace trace;
|
||||||
|
|
||||||
void *priv;
|
void *priv;
|
||||||
|
@ -31,12 +31,6 @@
|
|||||||
#define OCF_DEBUG_PARAM(cache, format, ...)
|
#define OCF_DEBUG_PARAM(cache, format, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
struct ocf_cleaner_sync {
|
|
||||||
env_completion cmpl;
|
|
||||||
int error;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate cleaning request
|
* Allocate cleaning request
|
||||||
*/
|
*/
|
||||||
@ -948,17 +942,6 @@ void ocf_cleaner_fire(struct ocf_cache *cache,
|
|||||||
ocf_req_put(master);
|
ocf_req_put(master);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ocf_cleaner_sync_end(void *private_data, int error)
|
|
||||||
{
|
|
||||||
struct ocf_cleaner_sync *sync = private_data;
|
|
||||||
|
|
||||||
OCF_DEBUG_TRACE(req->cache);
|
|
||||||
if (error)
|
|
||||||
sync->error = error;
|
|
||||||
|
|
||||||
env_completion_complete(&sync->cmpl);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _ocf_cleaner_do_flush_data_getter(struct ocf_cache *cache,
|
static int _ocf_cleaner_do_flush_data_getter(struct ocf_cache *cache,
|
||||||
void *context, uint32_t item, ocf_cache_line_t *line)
|
void *context, uint32_t item, ocf_cache_line_t *line)
|
||||||
{
|
{
|
||||||
@ -972,34 +955,6 @@ static int _ocf_cleaner_do_flush_data_getter(struct ocf_cache *cache,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ocf_cleaner_do_flush_data(struct ocf_cache *cache,
|
|
||||||
struct flush_data *flush, uint32_t count,
|
|
||||||
struct ocf_cleaner_attribs *attribs)
|
|
||||||
{
|
|
||||||
struct ocf_cleaner_sync sync;
|
|
||||||
|
|
||||||
env_completion_init(&sync.cmpl);
|
|
||||||
sync.error = 0;
|
|
||||||
attribs->cmpl_context = &sync;
|
|
||||||
attribs->cmpl_fn = ocf_cleaner_sync_end;
|
|
||||||
attribs->getter = _ocf_cleaner_do_flush_data_getter;
|
|
||||||
attribs->getter_context = flush;
|
|
||||||
attribs->count = count;
|
|
||||||
|
|
||||||
ocf_cleaner_fire(cache, attribs);
|
|
||||||
|
|
||||||
if (attribs->metadata_locked)
|
|
||||||
OCF_METADATA_UNLOCK_WR();
|
|
||||||
|
|
||||||
env_completion_wait(&sync.cmpl);
|
|
||||||
|
|
||||||
if (attribs->metadata_locked)
|
|
||||||
OCF_METADATA_LOCK_WR();
|
|
||||||
|
|
||||||
attribs->cmpl_context = NULL;
|
|
||||||
return sync.error;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ocf_cleaner_do_flush_data_async(struct ocf_cache *cache,
|
int ocf_cleaner_do_flush_data_async(struct ocf_cache *cache,
|
||||||
struct flush_data *flush, uint32_t count,
|
struct flush_data *flush, uint32_t count,
|
||||||
struct ocf_cleaner_attribs *attribs)
|
struct ocf_cleaner_attribs *attribs)
|
||||||
|
@ -27,8 +27,6 @@ typedef int (*ocf_cleaner_get_item)(struct ocf_cache *cache,
|
|||||||
struct ocf_cleaner_attribs {
|
struct ocf_cleaner_attribs {
|
||||||
uint8_t cache_line_lock : 1; /*!< Clean under cache line lock */
|
uint8_t cache_line_lock : 1; /*!< Clean under cache line lock */
|
||||||
|
|
||||||
uint8_t metadata_locked : 1; /*< true if caller holds metadata lock */
|
|
||||||
|
|
||||||
uint8_t do_sort : 1; /*!< Sort cache lines which will be cleaned */
|
uint8_t do_sort : 1; /*!< Sort cache lines which will be cleaned */
|
||||||
|
|
||||||
uint32_t count; /*!< max number of cache lines to be cleaned */
|
uint32_t count; /*!< max number of cache lines to be cleaned */
|
||||||
@ -87,20 +85,6 @@ struct flush_container {
|
|||||||
void ocf_cleaner_fire(struct ocf_cache *cache,
|
void ocf_cleaner_fire(struct ocf_cache *cache,
|
||||||
const struct ocf_cleaner_attribs *attribs);
|
const struct ocf_cleaner_attribs *attribs);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Perform cleaning procedure for specified flush data synchronously.
|
|
||||||
* Only dirty cache lines will be cleaned.
|
|
||||||
*
|
|
||||||
* @param cache - Cache instance
|
|
||||||
* @param flush - flush data to be cleaned
|
|
||||||
* @param count - Count of cache lines to be cleaned
|
|
||||||
* @param attribs - Cleaning attributes
|
|
||||||
* @return - Cleaning result. 0 - no errors, non zero errors occurred
|
|
||||||
*/
|
|
||||||
int ocf_cleaner_do_flush_data(struct ocf_cache *cache,
|
|
||||||
struct flush_data *flush, uint32_t count,
|
|
||||||
struct ocf_cleaner_attribs *attribs);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Perform cleaning procedure for specified flush data. Only dirty
|
* @brief Perform cleaning procedure for specified flush data. Only dirty
|
||||||
* cache lines will be cleaned.
|
* cache lines will be cleaned.
|
||||||
|
@ -13,6 +13,9 @@
|
|||||||
|
|
||||||
//<tested_file_path>src/cleaning/cleaning.c</tested_file_path>
|
//<tested_file_path>src/cleaning/cleaning.c</tested_file_path>
|
||||||
//<tested_function>ocf_cleaner_run</tested_function>
|
//<tested_function>ocf_cleaner_run</tested_function>
|
||||||
|
//<functions_to_leave>
|
||||||
|
//ocf_cleaner_set_cmpl
|
||||||
|
//</functions_to_leave>
|
||||||
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
@ -133,6 +136,11 @@ int __wrap_cleaning_policy_alru_initialize(struct ocf_cache *cache, int partitio
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __wrap_cleaning_policy_alru_deinitialize(ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
int __wrap_cleaning_policy_alru_flush_block(struct ocf_cache *cache,
|
int __wrap_cleaning_policy_alru_flush_block(struct ocf_cache *cache,
|
||||||
uint32_t io_queue, uint32_t count, uint32_t *cache_lines,
|
uint32_t io_queue, uint32_t count, uint32_t *cache_lines,
|
||||||
int partition_id, int core_id, uint8_t do_lock)
|
int partition_id, int core_id, uint8_t do_lock)
|
||||||
@ -152,7 +160,7 @@ void __wrap_cleaning_policy_alru_get_cleaning_parameters(ocf_cache_t cache,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int __wrap_cleaning_alru_perform_cleaning(struct ocf_cache *cache, uint32_t io_queue)
|
int __wrap_cleaning_alru_perform_cleaning(struct ocf_cache *cache, ocf_cleaner_end_t cmpl)
|
||||||
{
|
{
|
||||||
function_called();
|
function_called();
|
||||||
return mock();
|
return mock();
|
||||||
@ -178,6 +186,11 @@ int __wrap__ocf_cleaner_run_check_dirty_inactive(struct ocf_cache *cache)
|
|||||||
return mock();
|
return mock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __wrap_ocf_cleaner_run_complete(ocf_cleaner_t cleaner, uint32_t interval)
|
||||||
|
{
|
||||||
|
function_called();
|
||||||
|
}
|
||||||
|
|
||||||
int __wrap_env_bit_test(int nr, const void *addr)
|
int __wrap_env_bit_test(int nr, const void *addr)
|
||||||
{
|
{
|
||||||
function_called();
|
function_called();
|
||||||
@ -195,6 +208,10 @@ void __wrap_env_rwsem_up_write(env_rwsem *s)
|
|||||||
function_called();
|
function_called();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cleaner_complete(ocf_cleaner_t cleaner, uint32_t interval)
|
||||||
|
{
|
||||||
|
function_called();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tests of functions. Every test name must be written to tests array in main().
|
* Tests of functions. Every test name must be written to tests array in main().
|
||||||
@ -233,10 +250,9 @@ static void ocf_cleaner_run_test01(void **state)
|
|||||||
expect_function_call(__wrap_cleaning_alru_perform_cleaning);
|
expect_function_call(__wrap_cleaning_alru_perform_cleaning);
|
||||||
will_return(__wrap_cleaning_alru_perform_cleaning, 0);
|
will_return(__wrap_cleaning_alru_perform_cleaning, 0);
|
||||||
|
|
||||||
expect_function_call(__wrap_env_rwsem_up_write);
|
ocf_cleaner_set_cmpl(&cache.cleaner, cleaner_complete);
|
||||||
|
|
||||||
result = ocf_cleaner_run(&cache.cleaner, io_queue);
|
ocf_cleaner_run(&cache.cleaner);
|
||||||
assert_int_equal(result, 0);
|
|
||||||
|
|
||||||
/* Release allocated memory if allocated with test_* functions */
|
/* Release allocated memory if allocated with test_* functions */
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user