Merge pull request #877 from robertbaldyga/lazy-thread

Introduce lazy helper thread abstraction to avoid hung task
This commit is contained in:
Robert Baldyga 2021-07-13 14:46:40 +02:00 committed by GitHub
commit 7a498a10b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -14,6 +14,84 @@ extern u32 unaligned_io;
extern u32 seq_cut_off_mb; extern u32 seq_cut_off_mb;
extern u32 use_io_scheduler; extern u32 use_io_scheduler;
struct cas_lazy_thread {
char name[64];
struct task_struct *thread;
int (*threadfn)(void *data);
void *data;
wait_queue_head_t wq;
atomic_t run;
atomic_t stop;
};
static int cas_lazy_thread_fn(void *data)
{
struct cas_lazy_thread *clt = data;
int (*threadfn)(void *data) = clt->threadfn;
void *threaddata = clt->data;
while (wait_event_interruptible(clt->wq,
atomic_read(&clt->stop) || atomic_read(&clt->run)));
if (atomic_read(&clt->stop)) {
kfree(clt);
return 0;
}
kfree(clt);
return threadfn(threaddata);
}
static struct cas_lazy_thread *cas_lazy_thread_create(
int (*threadfn)(void *data), void *data, const char *fmt, ...)
{
struct cas_lazy_thread *clt;
va_list args;
int error;
clt = kmalloc(sizeof(*clt), GFP_KERNEL);
if (!clt)
return ERR_PTR(-ENOMEM);
va_start(args, fmt);
vsnprintf(clt->name, sizeof(clt->name), fmt, args);
va_end(args);
clt->thread = kthread_create(cas_lazy_thread_fn, clt, "%s", clt->name);
if (IS_ERR(clt->thread)) {
error = PTR_ERR(clt->thread);
kfree(clt);
return ERR_PTR(error);
}
clt->threadfn = threadfn;
clt->data = data;
init_waitqueue_head(&clt->wq);
atomic_set(&clt->run, 0);
atomic_set(&clt->stop, 0);
wake_up_process(clt->thread);
return clt;
}
/*
* The caller must ensure that cas_lazy_thread wasn't released.
*/
static void cas_lazy_thread_stop(struct cas_lazy_thread *clt)
{
atomic_set(&clt->stop, 1);
wake_up(&clt->wq);
}
/*
* The caller must ensure that cas_lazy_thread wasn't released.
*/
static void cas_lazy_thread_wake_up(struct cas_lazy_thread *clt)
{
atomic_set(&clt->run, 1);
wake_up(&clt->wq);
}
struct _cache_mngt_sync_context { struct _cache_mngt_sync_context {
struct completion cmpl; struct completion cmpl;
int *result; int *result;
@ -468,7 +546,7 @@ struct _cache_mngt_stop_context {
int error; int error;
int flush_status; int flush_status;
ocf_cache_t cache; ocf_cache_t cache;
struct task_struct *finish_thread; struct cas_lazy_thread *finish_thread;
}; };
static void _cache_mngt_cache_priv_deinit(ocf_cache_t cache) static void _cache_mngt_cache_priv_deinit(ocf_cache_t cache)
@ -487,9 +565,6 @@ static int exit_instance_finish(void *data)
ocf_queue_t mngt_queue; ocf_queue_t mngt_queue;
int result = 0; int result = 0;
if (kthread_should_stop())
return 0;
cache_priv = ocf_cache_get_priv(ctx->cache); cache_priv = ocf_cache_get_priv(ctx->cache);
mngt_queue = cache_priv->mngt_queue; mngt_queue = cache_priv->mngt_queue;
@ -523,7 +598,7 @@ struct _cache_mngt_attach_context {
struct ocf_mngt_cache_device_config *device_cfg; struct ocf_mngt_cache_device_config *device_cfg;
ocf_cache_t cache; ocf_cache_t cache;
int ocf_start_error; int ocf_start_error;
struct task_struct *rollback_thread; struct cas_lazy_thread *rollback_thread;
struct { struct {
bool priv_inited:1; bool priv_inited:1;
@ -540,9 +615,6 @@ static int cache_start_rollback(void *data)
ocf_cache_t cache = ctx->cache; ocf_cache_t cache = ctx->cache;
int result; int result;
if (kthread_should_stop())
return 0;
if (ctx->cls_inited) if (ctx->cls_inited)
cas_cls_deinit(cache); cas_cls_deinit(cache);
@ -578,15 +650,16 @@ static void _cache_mngt_cache_stop_rollback_complete(ocf_cache_t cache,
else else
BUG_ON(error); BUG_ON(error);
BUG_ON(!wake_up_process(ctx->rollback_thread)); cas_lazy_thread_wake_up(ctx->rollback_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_stop_context *context = priv; struct _cache_mngt_stop_context *context = priv;
context->error = error; context->error = error;
BUG_ON(!wake_up_process(context->finish_thread)); cas_lazy_thread_wake_up(context->finish_thread);
} }
static int _cache_mngt_cache_stop_sync(ocf_cache_t cache) static int _cache_mngt_cache_stop_sync(ocf_cache_t cache)
@ -2031,8 +2104,8 @@ int cache_mngt_init_instance(struct ocf_mngt_cache_config *cfg,
return -ENOMEM; return -ENOMEM;
} }
context->rollback_thread = kthread_create(cache_start_rollback, context, context->rollback_thread = cas_lazy_thread_create(cache_start_rollback,
"cas_cache_rollback_complete"); context, "cas_cache_rollback_complete");
if (IS_ERR(context->rollback_thread)) { if (IS_ERR(context->rollback_thread)) {
result = PTR_ERR(context->rollback_thread); result = PTR_ERR(context->rollback_thread);
kfree(context); kfree(context);
@ -2049,7 +2122,7 @@ int cache_mngt_init_instance(struct ocf_mngt_cache_config *cfg,
*/ */
result = ocf_mngt_cache_start(cas_ctx, &cache, cfg, NULL); result = ocf_mngt_cache_start(cas_ctx, &cache, cfg, NULL);
if (result) { if (result) {
kthread_stop(context->rollback_thread); cas_lazy_thread_stop(context->rollback_thread);
kfree(context); kfree(context);
module_put(THIS_MODULE); module_put(THIS_MODULE);
return result; return result;
@ -2088,7 +2161,7 @@ int cache_mngt_init_instance(struct ocf_mngt_cache_config *cfg,
if (result) if (result)
goto err; goto err;
kthread_stop(context->rollback_thread); cas_lazy_thread_stop(context->rollback_thread);
kfree(context); kfree(context);
cache_priv->attach_context = NULL; cache_priv->attach_context = NULL;
@ -2417,7 +2490,7 @@ int cache_mngt_exit_instance(const char *cache_name, size_t name_len, int flush)
if (status) if (status)
goto put; goto put;
context->finish_thread = kthread_create(exit_instance_finish, context->finish_thread = cas_lazy_thread_create(exit_instance_finish,
context, "cas_%s_stop", cache_name); context, "cas_%s_stop", cache_name);
if (IS_ERR(context->finish_thread)) { if (IS_ERR(context->finish_thread)) {
status = PTR_ERR(context->finish_thread); status = PTR_ERR(context->finish_thread);
@ -2465,7 +2538,7 @@ int cache_mngt_exit_instance(const char *cache_name, size_t name_len, int flush)
return status; return status;
stop_thread: stop_thread:
kthread_stop(context->finish_thread); cas_lazy_thread_stop(context->finish_thread);
unlock: unlock:
ocf_mngt_cache_unlock(cache); ocf_mngt_cache_unlock(cache);
put: put: