Complete cache stop from kthread
To enable stopping management queue from completion context, last queue_put() have to be called from separate thread. After cache is fully deinitialized, thread calls module_put_and_exit() to prevent scenario when code is still executed, but there are no references to module. Signed-off-by: Michal Mielewczyk <michal.mielewczyk@intel.com>
This commit is contained in:
parent
9f6d407d10
commit
55d53867cc
@ -362,33 +362,45 @@ static void _cache_mngt_cache_priv_deinit(ocf_cache_t cache)
|
|||||||
vfree(cache_priv);
|
vfree(cache_priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int exit_instance_finish(ocf_cache_t cache, int error)
|
struct _cache_mngt_stop_context {
|
||||||
|
struct _cache_mngt_async_context async;
|
||||||
|
int error;
|
||||||
|
ocf_cache_t cache;
|
||||||
|
struct work_struct work;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int exit_instance_finish(void *data)
|
||||||
{
|
{
|
||||||
struct cache_priv *cache_priv;
|
struct cache_priv *cache_priv;
|
||||||
|
struct _cache_mngt_stop_context *ctx = data;
|
||||||
ocf_queue_t mngt_queue;
|
ocf_queue_t mngt_queue;
|
||||||
bool flush_status;
|
bool flush_status;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
flush_status = ocf_mngt_cache_is_dirty(cache);
|
flush_status = ocf_mngt_cache_is_dirty(ctx->cache);
|
||||||
cache_priv = ocf_cache_get_priv(cache);
|
cache_priv = ocf_cache_get_priv(ctx->cache);
|
||||||
mngt_queue = cache_priv->mngt_queue;
|
mngt_queue = cache_priv->mngt_queue;
|
||||||
|
|
||||||
if (error && error != -OCF_ERR_WRITE_CACHE)
|
if (ctx->error && ctx->error != -OCF_ERR_WRITE_CACHE)
|
||||||
BUG_ON(error);
|
BUG_ON(ctx->error);
|
||||||
|
|
||||||
if (!error && flush_status)
|
if (!ctx->error && flush_status)
|
||||||
error = -KCAS_ERR_STOPPED_DIRTY;
|
result = -KCAS_ERR_STOPPED_DIRTY;
|
||||||
|
|
||||||
module_put(THIS_MODULE);
|
cas_cls_deinit(ctx->cache);
|
||||||
|
|
||||||
cas_cls_deinit(cache);
|
|
||||||
|
|
||||||
vfree(cache_priv);
|
vfree(cache_priv);
|
||||||
|
|
||||||
ocf_mngt_cache_unlock(cache);
|
ocf_mngt_cache_unlock(ctx->cache);
|
||||||
ocf_mngt_cache_put(cache);
|
ocf_mngt_cache_put(ctx->cache);
|
||||||
ocf_queue_put(mngt_queue);
|
ocf_queue_put(mngt_queue);
|
||||||
|
|
||||||
return error;
|
result = _cache_mngt_async_callee_set_result(&ctx->async, result);
|
||||||
|
|
||||||
|
if (result == -KCAS_ERR_WAITING_INTERRUPTED)
|
||||||
|
kfree(ctx);
|
||||||
|
|
||||||
|
module_put_and_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct _cache_mngt_attach_context {
|
struct _cache_mngt_attach_context {
|
||||||
@ -406,12 +418,11 @@ struct _cache_mngt_attach_context {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void cache_start_rollback(struct work_struct *work)
|
static int cache_start_rollback(void *data)
|
||||||
{
|
{
|
||||||
struct cache_priv *cache_priv;
|
struct cache_priv *cache_priv;
|
||||||
ocf_queue_t mngt_queue = NULL;
|
ocf_queue_t mngt_queue = NULL;
|
||||||
struct _cache_mngt_attach_context *ctx =
|
struct _cache_mngt_attach_context *ctx = data;
|
||||||
container_of(work, struct _cache_mngt_attach_context, work);
|
|
||||||
ocf_cache_t cache = ctx->cache;
|
ocf_cache_t cache = ctx->cache;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
@ -429,58 +440,64 @@ static void cache_start_rollback(struct work_struct *work)
|
|||||||
if (mngt_queue)
|
if (mngt_queue)
|
||||||
ocf_queue_put(mngt_queue);
|
ocf_queue_put(mngt_queue);
|
||||||
|
|
||||||
module_put(THIS_MODULE);
|
|
||||||
|
|
||||||
result = _cache_mngt_async_callee_set_result(&ctx->async,
|
result = _cache_mngt_async_callee_set_result(&ctx->async,
|
||||||
ctx->ocf_start_error);
|
ctx->ocf_start_error);
|
||||||
|
|
||||||
if (result == -KCAS_ERR_WAITING_INTERRUPTED)
|
if (result == -KCAS_ERR_WAITING_INTERRUPTED)
|
||||||
kfree(ctx);
|
kfree(ctx);
|
||||||
|
|
||||||
|
module_put_and_exit(0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _cache_mngt_cache_stop_rollback_complete(ocf_cache_t cache,
|
static void _cache_mngt_cache_stop_rollback_complete(ocf_cache_t cache,
|
||||||
void *priv, int error)
|
void *priv, int error)
|
||||||
{
|
{
|
||||||
struct _cache_mngt_attach_context *ctx = priv;
|
struct _cache_mngt_attach_context *ctx = priv;
|
||||||
|
struct task_struct *thread;
|
||||||
|
|
||||||
if (error == -OCF_ERR_WRITE_CACHE)
|
if (error == -OCF_ERR_WRITE_CACHE)
|
||||||
printk(KERN_WARNING "Cannot save cache state\n");
|
printk(KERN_WARNING "Cannot save cache state\n");
|
||||||
else
|
else
|
||||||
BUG_ON(error);
|
BUG_ON(error);
|
||||||
|
|
||||||
INIT_WORK(&ctx->work, cache_start_rollback);
|
thread = kthread_run(cache_start_rollback, ctx,
|
||||||
schedule_work(&ctx->work);
|
"cas_cache_rollback_complete");
|
||||||
|
BUG_ON(IS_ERR(thread));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _cache_mngt_cache_stop_complete(ocf_cache_t cache, void *priv,
|
static void _cache_mngt_cache_stop_complete(ocf_cache_t cache, void *priv,
|
||||||
int error)
|
int error)
|
||||||
{
|
{
|
||||||
struct _cache_mngt_async_context *context = priv;
|
struct _cache_mngt_stop_context *context = priv;
|
||||||
int result = exit_instance_finish(cache, error);
|
struct task_struct *thread;
|
||||||
|
context->error = error;
|
||||||
|
|
||||||
result = _cache_mngt_async_callee_set_result(context, result);
|
thread = kthread_run(exit_instance_finish, context,
|
||||||
|
"cas_cache_stop_complete");
|
||||||
if (result == -KCAS_ERR_WAITING_INTERRUPTED)
|
BUG_ON(IS_ERR(thread));
|
||||||
kfree(context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _cache_mngt_cache_stop_sync(ocf_cache_t cache)
|
static int _cache_mngt_cache_stop_sync(ocf_cache_t cache)
|
||||||
{
|
{
|
||||||
struct _cache_mngt_async_context *context;
|
struct _cache_mngt_stop_context *context;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
context = env_malloc(sizeof(*context), GFP_KERNEL);
|
context = env_malloc(sizeof(*context), GFP_KERNEL);
|
||||||
if (!context)
|
if (!context)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
_cache_mngt_async_context_init(context);
|
_cache_mngt_async_context_init(&context->async);
|
||||||
|
context->error = 0;
|
||||||
|
context->cache = cache;
|
||||||
|
|
||||||
ocf_mngt_cache_stop(cache, _cache_mngt_cache_stop_complete, context);
|
ocf_mngt_cache_stop(cache, _cache_mngt_cache_stop_complete, context);
|
||||||
result = wait_for_completion_interruptible(&context->cmpl);
|
result = wait_for_completion_interruptible(&context->async.cmpl);
|
||||||
|
|
||||||
result = _cache_mngt_async_caller_set_result(context, result);
|
result = _cache_mngt_async_caller_set_result(&context->async, result);
|
||||||
|
|
||||||
if (context->result != -KCAS_ERR_WAITING_INTERRUPTED)
|
if (result != -KCAS_ERR_WAITING_INTERRUPTED)
|
||||||
kfree(context);
|
kfree(context);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -1786,7 +1803,6 @@ int cache_mngt_init_instance(struct ocf_mngt_cache_config *cfg,
|
|||||||
{
|
{
|
||||||
struct _cache_mngt_attach_context *context;
|
struct _cache_mngt_attach_context *context;
|
||||||
ocf_cache_t cache;
|
ocf_cache_t cache;
|
||||||
ocf_queue_t mngt_queue = NULL;
|
|
||||||
struct cache_priv *cache_priv;
|
struct cache_priv *cache_priv;
|
||||||
int result = 0, rollback_result = 0;
|
int result = 0, rollback_result = 0;
|
||||||
bool load = (cmd && cmd->init_cache == CACHE_INIT_LOAD);
|
bool load = (cmd && cmd->init_cache == CACHE_INIT_LOAD);
|
||||||
@ -1832,7 +1848,6 @@ int cache_mngt_init_instance(struct ocf_mngt_cache_config *cfg,
|
|||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
cache_priv = ocf_cache_get_priv(cache);
|
cache_priv = ocf_cache_get_priv(cache);
|
||||||
mngt_queue = cache_priv->mngt_queue;
|
|
||||||
|
|
||||||
if (load) {
|
if (load) {
|
||||||
ocf_mngt_cache_load(cache, device_cfg,
|
ocf_mngt_cache_load(cache, device_cfg,
|
||||||
|
Loading…
Reference in New Issue
Block a user