Merge pull request #310 from mmichal10/fix-flush-interrupting
Fix flush interrupting
This commit is contained in:
commit
7b0e8168d1
@ -23,6 +23,7 @@ struct _cache_mngt_async_context {
|
||||
struct completion cmpl;
|
||||
spinlock_t lock;
|
||||
int result;
|
||||
void (*compl_func)(ocf_cache_t cache);
|
||||
};
|
||||
|
||||
/*
|
||||
@ -87,6 +88,7 @@ static inline void _cache_mngt_async_context_init(
|
||||
init_completion(&context->cmpl);
|
||||
spin_lock_init(&context->lock);
|
||||
context->result = 0;
|
||||
context->compl_func = NULL;
|
||||
}
|
||||
|
||||
static void _cache_mngt_lock_complete(ocf_cache_t cache, void *priv, int error)
|
||||
@ -196,19 +198,55 @@ static int _cache_mngt_save_sync(ocf_cache_t cache)
|
||||
return result;
|
||||
}
|
||||
|
||||
static void _cache_mngt_cache_flush_uninterruptible_complete(ocf_cache_t cache,
|
||||
void *priv, int error)
|
||||
{
|
||||
struct _cache_mngt_sync_context *context = priv;
|
||||
|
||||
*context->result = error;
|
||||
complete(&context->cmpl);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since wait_for_completion() is used, hang tasks may occure if flush would
|
||||
* take long time.
|
||||
*/
|
||||
static int _cache_mngt_cache_flush_uninterruptible(ocf_cache_t cache)
|
||||
{
|
||||
int result;
|
||||
struct _cache_mngt_sync_context context;
|
||||
struct cache_priv *cache_priv = ocf_cache_get_priv(cache);
|
||||
|
||||
init_completion(&context.cmpl);
|
||||
context.result = &result;
|
||||
atomic_set(&cache_priv->flush_interrupt_enabled, 0);
|
||||
|
||||
ocf_mngt_cache_flush(cache, _cache_mngt_cache_flush_uninterruptible_complete,
|
||||
&context);
|
||||
wait_for_completion(&context.cmpl);
|
||||
|
||||
atomic_set(&cache_priv->flush_interrupt_enabled, 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void _cache_mngt_cache_flush_complete(ocf_cache_t cache, void *priv,
|
||||
int error)
|
||||
{
|
||||
struct _cache_mngt_async_context *context = priv;
|
||||
int result;
|
||||
|
||||
if (context->compl_func)
|
||||
context->compl_func(cache);
|
||||
|
||||
result = _cache_mngt_async_callee_set_result(context, error);
|
||||
|
||||
if (result == -KCAS_ERR_WAITING_INTERRUPTED)
|
||||
kfree(context);
|
||||
}
|
||||
|
||||
static int _cache_mngt_cache_flush_sync(ocf_cache_t cache, bool interruption)
|
||||
static int _cache_mngt_cache_flush_sync(ocf_cache_t cache, bool interruption,
|
||||
void (*compl)(ocf_cache_t cache))
|
||||
{
|
||||
int result;
|
||||
struct _cache_mngt_async_context *context;
|
||||
@ -219,6 +257,7 @@ static int _cache_mngt_cache_flush_sync(ocf_cache_t cache, bool interruption)
|
||||
return -ENOMEM;
|
||||
|
||||
_cache_mngt_async_context_init(context);
|
||||
context->compl_func = compl;
|
||||
atomic_set(&cache_priv->flush_interrupt_enabled, interruption);
|
||||
|
||||
ocf_mngt_cache_flush(cache, _cache_mngt_cache_flush_complete, context);
|
||||
@ -228,6 +267,8 @@ static int _cache_mngt_cache_flush_sync(ocf_cache_t cache, bool interruption)
|
||||
|
||||
if (result != -KCAS_ERR_WAITING_INTERRUPTED)
|
||||
kfree(context);
|
||||
else if (result == -KCAS_ERR_WAITING_INTERRUPTED && interruption)
|
||||
ocf_mngt_cache_flush_interrupt(cache);
|
||||
|
||||
atomic_set(&cache_priv->flush_interrupt_enabled, 1);
|
||||
|
||||
@ -239,6 +280,10 @@ static void _cache_mngt_core_flush_complete(ocf_core_t core, void *priv,
|
||||
{
|
||||
struct _cache_mngt_async_context *context = priv;
|
||||
int result;
|
||||
ocf_cache_t cache = ocf_core_get_cache(core);
|
||||
|
||||
if (context->compl_func)
|
||||
context->compl_func(cache);
|
||||
|
||||
result = _cache_mngt_async_callee_set_result(context, error);
|
||||
|
||||
@ -246,7 +291,8 @@ static void _cache_mngt_core_flush_complete(ocf_core_t core, void *priv,
|
||||
kfree(context);
|
||||
}
|
||||
|
||||
static int _cache_mngt_core_flush_sync(ocf_core_t core, bool interruption)
|
||||
static int _cache_mngt_core_flush_sync(ocf_core_t core, bool interruption,
|
||||
void (*compl)(ocf_cache_t cache))
|
||||
{
|
||||
int result;
|
||||
struct _cache_mngt_async_context *context;
|
||||
@ -258,6 +304,7 @@ static int _cache_mngt_core_flush_sync(ocf_core_t core, bool interruption)
|
||||
return -ENOMEM;
|
||||
|
||||
_cache_mngt_async_context_init(context);
|
||||
context->compl_func = compl;
|
||||
atomic_set(&cache_priv->flush_interrupt_enabled, interruption);
|
||||
|
||||
ocf_mngt_core_flush(core, _cache_mngt_core_flush_complete, context);
|
||||
@ -267,6 +314,41 @@ static int _cache_mngt_core_flush_sync(ocf_core_t core, bool interruption)
|
||||
|
||||
if (result != -KCAS_ERR_WAITING_INTERRUPTED)
|
||||
kfree(context);
|
||||
else if (result == -KCAS_ERR_WAITING_INTERRUPTED && interruption)
|
||||
ocf_mngt_cache_flush_interrupt(cache);
|
||||
|
||||
atomic_set(&cache_priv->flush_interrupt_enabled, 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void _cache_mngt_core_flush_uninterruptible_complete(ocf_core_t core,
|
||||
void *priv, int error)
|
||||
{
|
||||
struct _cache_mngt_sync_context *context = priv;
|
||||
|
||||
*context->result = error;
|
||||
complete(&context->cmpl);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since wait_for_completion() is used, hang tasks may occure if flush would
|
||||
* take long time.
|
||||
*/
|
||||
static int _cache_mngt_core_flush_uninterruptible(ocf_core_t core)
|
||||
{
|
||||
int result;
|
||||
struct _cache_mngt_sync_context context;
|
||||
ocf_cache_t cache = ocf_core_get_cache(core);
|
||||
struct cache_priv *cache_priv = ocf_cache_get_priv(cache);
|
||||
|
||||
init_completion(&context.cmpl);
|
||||
context.result = &result;
|
||||
atomic_set(&cache_priv->flush_interrupt_enabled, 0);
|
||||
|
||||
ocf_mngt_core_flush(core, _cache_mngt_core_flush_uninterruptible_complete,
|
||||
&context);
|
||||
wait_for_completion(&context.cmpl);
|
||||
|
||||
atomic_set(&cache_priv->flush_interrupt_enabled, 1);
|
||||
|
||||
@ -466,6 +548,12 @@ static void mark_core_id_free(uint64_t *bitmap, uint16_t core_id)
|
||||
clear_bit(core_id, (unsigned long *)bitmap);
|
||||
}
|
||||
|
||||
static void _cache_read_unlock_put_cmpl(ocf_cache_t cache)
|
||||
{
|
||||
ocf_mngt_cache_read_unlock(cache);
|
||||
ocf_mngt_cache_put(cache);
|
||||
}
|
||||
|
||||
int cache_mngt_flush_object(const char *cache_name, size_t cache_name_len,
|
||||
const char *core_name, size_t core_name_len)
|
||||
{
|
||||
@ -478,21 +566,22 @@ int cache_mngt_flush_object(const char *cache_name, size_t cache_name_len,
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
result = _cache_mngt_lock_sync(cache);
|
||||
result = _cache_mngt_read_lock_sync(cache);
|
||||
if (result) {
|
||||
ocf_mngt_cache_put(cache);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = ocf_core_get_by_name(cache, core_name, core_name_len, &core);
|
||||
if (result)
|
||||
goto out;
|
||||
if (result) {
|
||||
ocf_mngt_cache_read_unlock(cache);
|
||||
ocf_mngt_cache_put(cache);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = _cache_mngt_core_flush_sync(core, true);
|
||||
result = _cache_mngt_core_flush_sync(core, true,
|
||||
_cache_read_unlock_put_cmpl);
|
||||
|
||||
out:
|
||||
ocf_mngt_cache_unlock(cache);
|
||||
ocf_mngt_cache_put(cache);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -506,16 +595,15 @@ int cache_mngt_flush_device(const char *cache_name, size_t name_len)
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
result = _cache_mngt_lock_sync(cache);
|
||||
result = _cache_mngt_read_lock_sync(cache);
|
||||
if (result) {
|
||||
ocf_mngt_cache_put(cache);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = _cache_mngt_cache_flush_sync(cache, true);
|
||||
result = _cache_mngt_cache_flush_sync(cache, true,
|
||||
_cache_read_unlock_put_cmpl);
|
||||
|
||||
ocf_mngt_cache_unlock(cache);
|
||||
ocf_mngt_cache_put(cache);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1071,8 +1159,11 @@ int _cache_mngt_remove_core_prepare(ocf_cache_t cache, ocf_core_t core,
|
||||
if (!cmd->force_no_flush) {
|
||||
if (core_active) {
|
||||
/* Flush core */
|
||||
flush_result = _cache_mngt_core_flush_sync(core,
|
||||
flush_interruptible);
|
||||
if (flush_interruptible)
|
||||
flush_result = _cache_mngt_core_flush_sync(core,
|
||||
flush_interruptible, _cache_read_unlock_put_cmpl);
|
||||
else
|
||||
flush_result = _cache_mngt_core_flush_uninterruptible(core);
|
||||
} else if (!ocf_mngt_core_is_dirty(core)) {
|
||||
/* Clean core is always "flushed" */
|
||||
flush_result = 0;
|
||||
@ -1117,20 +1208,28 @@ int cache_mngt_remove_core_from_cache(struct kcas_remove_core *cmd)
|
||||
if (!cmd->force_no_flush) {
|
||||
/* First check state and flush data (if requested by user)
|
||||
under read lock */
|
||||
result = _cache_mngt_read_lock_sync(cache);
|
||||
/* Getting cache twice is workaround to make flush error handling easier
|
||||
and avoid dealing with synchronizing issues */
|
||||
result = ocf_mngt_cache_get(cache);
|
||||
if (result)
|
||||
goto put;
|
||||
result = _cache_mngt_read_lock_sync(cache);
|
||||
if (result) {
|
||||
ocf_mngt_cache_put(cache);
|
||||
goto put;
|
||||
}
|
||||
|
||||
result = get_core_by_id(cache, cmd->core_id, &core);
|
||||
if (result < 0)
|
||||
goto rd_unlock;
|
||||
if (result < 0) {
|
||||
ocf_mngt_cache_unlock(cache);
|
||||
ocf_mngt_cache_put(cache);
|
||||
goto put;
|
||||
}
|
||||
|
||||
result = _cache_mngt_remove_core_prepare(cache, core, cmd,
|
||||
false);
|
||||
if (result)
|
||||
goto rd_unlock;
|
||||
|
||||
ocf_mngt_cache_read_unlock(cache);
|
||||
goto put;
|
||||
}
|
||||
|
||||
/* Acquire write lock */
|
||||
@ -1186,11 +1285,6 @@ unlock:
|
||||
put:
|
||||
ocf_mngt_cache_put(cache);
|
||||
return result;
|
||||
|
||||
rd_unlock:
|
||||
ocf_mngt_cache_read_unlock(cache);
|
||||
ocf_mngt_cache_put(cache);
|
||||
return result;
|
||||
}
|
||||
|
||||
int cache_mngt_reset_stats(const char *cache_name, size_t cache_name_len,
|
||||
@ -1921,7 +2015,7 @@ int cache_mngt_set_cache_mode(const char *cache_name, size_t name_len,
|
||||
goto out;
|
||||
|
||||
if (flush) {
|
||||
result = _cache_mngt_cache_flush_sync(cache, true);
|
||||
result = _cache_mngt_cache_flush_sync(cache, true, NULL);
|
||||
if (result) {
|
||||
ocf_mngt_cache_set_mode(cache, old_mode);
|
||||
goto out;
|
||||
@ -1952,7 +2046,6 @@ int cache_mngt_exit_instance(const char *cache_name, size_t name_len, int flush)
|
||||
ocf_queue_t mngt_queue;
|
||||
int status, flush_status = 0;
|
||||
|
||||
/* Get cache */
|
||||
status = ocf_mngt_cache_get_by_name(cas_ctx, cache_name,
|
||||
name_len, &cache);
|
||||
if (status)
|
||||
@ -1961,9 +2054,6 @@ int cache_mngt_exit_instance(const char *cache_name, size_t name_len, int flush)
|
||||
cache_priv = ocf_cache_get_priv(cache);
|
||||
mngt_queue = cache_priv->mngt_queue;
|
||||
|
||||
status = _cache_mngt_read_lock_sync(cache);
|
||||
if (status)
|
||||
goto put;
|
||||
/*
|
||||
* Flush cache. Flushing may take a long time, so we allow user
|
||||
* to interrupt this operation. Hence we do first flush before
|
||||
@ -1974,11 +2064,24 @@ int cache_mngt_exit_instance(const char *cache_name, size_t name_len, int flush)
|
||||
* exported object. The second flush should be much faster.
|
||||
*/
|
||||
if (flush) {
|
||||
status = _cache_mngt_cache_flush_sync(cache, true);
|
||||
/* Getting cache twice is workaround to make flush error handling easier
|
||||
and avoid dealing with synchronizing issues */
|
||||
status = ocf_mngt_cache_get(cache);
|
||||
if (status)
|
||||
goto put;
|
||||
|
||||
status = _cache_mngt_read_lock_sync(cache);
|
||||
if (status) {
|
||||
ocf_mngt_cache_put(cache);
|
||||
goto put;
|
||||
}
|
||||
|
||||
status = _cache_mngt_cache_flush_sync(cache, true,
|
||||
_cache_read_unlock_put_cmpl);
|
||||
switch (status) {
|
||||
case -OCF_ERR_CACHE_IN_INCOMPLETE_STATE:
|
||||
case -OCF_ERR_FLUSHING_INTERRUPTED:
|
||||
ocf_mngt_cache_read_unlock(cache);
|
||||
case -KCAS_ERR_WAITING_INTERRUPTED:
|
||||
goto put;
|
||||
default:
|
||||
flush_status = status;
|
||||
@ -1986,8 +2089,6 @@ int cache_mngt_exit_instance(const char *cache_name, size_t name_len, int flush)
|
||||
}
|
||||
}
|
||||
|
||||
ocf_mngt_cache_read_unlock(cache);
|
||||
|
||||
/* get cache write lock */
|
||||
status = _cache_mngt_lock_sync(cache);
|
||||
if (status)
|
||||
@ -2015,7 +2116,7 @@ int cache_mngt_exit_instance(const char *cache_name, size_t name_len, int flush)
|
||||
|
||||
/* Flush cache again. This time we don't allow interruption. */
|
||||
if (flush)
|
||||
flush_status = _cache_mngt_cache_flush_sync(cache, false);
|
||||
flush_status = _cache_mngt_cache_flush_uninterruptible(cache);
|
||||
|
||||
if (flush && !flush_status)
|
||||
BUG_ON(ocf_mngt_cache_is_dirty(cache));
|
||||
|
Loading…
Reference in New Issue
Block a user