Allow cache r&w locks to be interrupted.
When context was allocated on the stack and waiting for completion was interrupted, completion function would attempt to save lock/unlock result in memory which might in use by other process. This would cause a system crash. To prevent such scenario, context is allocated dynamiclly and extended with reference counter. In case of interrupt, completion function doesn't have to save result in context, it can simply free it's memory. This commit is part of patch that will allow to interrupt waiting for OCF operations. Signed-off-by: Michal Mielewczyk <michal.mielewczyk@intel.com>
This commit is contained in:
parent
7af5d296e1
commit
de823b15fc
@ -15,53 +15,149 @@ extern u32 seq_cut_off_mb;
|
|||||||
extern u32 use_io_scheduler;
|
extern u32 use_io_scheduler;
|
||||||
|
|
||||||
struct _cache_mngt_sync_context {
|
struct _cache_mngt_sync_context {
|
||||||
struct completion compl;
|
struct completion cmpl;
|
||||||
int *result;
|
int *result;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _cache_mngt_async_context {
|
struct _cache_mngt_async_context {
|
||||||
struct completion compl;
|
struct completion cmpl;
|
||||||
atomic_t ref_count;
|
spinlock_t lock;
|
||||||
int result;
|
int result;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _cache_mngt_async_lock_context {
|
/*
|
||||||
struct completion compl;
|
* Value used to mark async call as completed. Used when OCF call already
|
||||||
int *result;
|
* finished, but complete function still has to be performed.
|
||||||
};
|
*/
|
||||||
|
#define ASYNC_CALL_FINISHED 1
|
||||||
|
|
||||||
static void _cache_mngt_lock_complete(ocf_cache_t cache, void *priv, int error)
|
static int _cache_mngt_async_callee_set_result(
|
||||||
|
struct _cache_mngt_async_context *context,
|
||||||
|
int error)
|
||||||
{
|
{
|
||||||
struct _cache_mngt_sync_context *context = priv;
|
bool interrupted;
|
||||||
|
int ret;
|
||||||
|
|
||||||
*context->result = error;
|
spin_lock(&context->lock);
|
||||||
complete(&context->compl);
|
|
||||||
|
interrupted = (context->result == -KCAS_ERR_WAITING_INTERRUPTED);
|
||||||
|
if (!interrupted)
|
||||||
|
context->result = error ?: ASYNC_CALL_FINISHED;
|
||||||
|
complete(&context->cmpl);
|
||||||
|
|
||||||
|
ret = context->result;
|
||||||
|
spin_unlock(&context->lock);
|
||||||
|
|
||||||
|
return ret == ASYNC_CALL_FINISHED ? 0 : ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _cache_mngt_lock_sync(ocf_cache_t cache)
|
static int _cache_mngt_async_callee_peek_result(
|
||||||
|
struct _cache_mngt_async_context *context)
|
||||||
{
|
{
|
||||||
struct _cache_mngt_sync_context context;
|
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
init_completion(&context.compl);
|
spin_lock(&context->lock);
|
||||||
context.result = &result;
|
result = context->result;
|
||||||
|
spin_unlock(&context->lock);
|
||||||
ocf_mngt_cache_lock(cache, _cache_mngt_lock_complete, &context);
|
|
||||||
wait_for_completion_interruptible(&context.compl);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _cache_mngt_read_lock_sync(ocf_cache_t cache)
|
static int _cache_mngt_async_caller_set_result(
|
||||||
|
struct _cache_mngt_async_context *context,
|
||||||
|
int error)
|
||||||
{
|
{
|
||||||
struct _cache_mngt_sync_context context;
|
unsigned long lock_flags = 0;
|
||||||
|
int result = error;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&context->lock, lock_flags);
|
||||||
|
if (context->result)
|
||||||
|
result = (context->result != ASYNC_CALL_FINISHED) ?
|
||||||
|
context->result : 0;
|
||||||
|
else if (result < 0)
|
||||||
|
result = context->result = -KCAS_ERR_WAITING_INTERRUPTED;
|
||||||
|
spin_unlock_irqrestore(&context->lock, lock_flags);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void _cache_mngt_async_context_init(
|
||||||
|
struct _cache_mngt_async_context *context)
|
||||||
|
{
|
||||||
|
init_completion(&context->cmpl);
|
||||||
|
spin_lock_init(&context->lock);
|
||||||
|
context->result = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _cache_mngt_lock_complete(ocf_cache_t cache, void *priv, int error)
|
||||||
|
{
|
||||||
|
struct _cache_mngt_async_context *context = priv;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
init_completion(&context.compl);
|
result = _cache_mngt_async_callee_set_result(context, error);
|
||||||
context.result = &result;
|
|
||||||
|
|
||||||
ocf_mngt_cache_read_lock(cache, _cache_mngt_lock_complete, &context);
|
if (result == -KCAS_ERR_WAITING_INTERRUPTED && error == 0)
|
||||||
wait_for_completion_interruptible(&context.compl);
|
ocf_mngt_cache_unlock(cache);
|
||||||
|
|
||||||
|
if (result == -KCAS_ERR_WAITING_INTERRUPTED)
|
||||||
|
kfree(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _cache_mngt_lock_sync(ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
struct _cache_mngt_async_context *context;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
context = kmalloc(sizeof(*context), GFP_KERNEL);
|
||||||
|
if (!context)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
_cache_mngt_async_context_init(context);
|
||||||
|
|
||||||
|
ocf_mngt_cache_lock(cache, _cache_mngt_lock_complete, context);
|
||||||
|
result = wait_for_completion_interruptible(&context->cmpl);
|
||||||
|
|
||||||
|
result = _cache_mngt_async_caller_set_result(context, result);
|
||||||
|
|
||||||
|
if (result != -KCAS_ERR_WAITING_INTERRUPTED)
|
||||||
|
kfree(context);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _cache_mngt_read_lock_complete(ocf_cache_t cache, void *priv,
|
||||||
|
int error)
|
||||||
|
{
|
||||||
|
struct _cache_mngt_async_context *context = priv;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
result = _cache_mngt_async_callee_set_result(context, error);
|
||||||
|
|
||||||
|
if (result == -KCAS_ERR_WAITING_INTERRUPTED && error == 0)
|
||||||
|
ocf_mngt_cache_read_unlock(cache);
|
||||||
|
|
||||||
|
if (result == -KCAS_ERR_WAITING_INTERRUPTED)
|
||||||
|
kfree(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _cache_mngt_read_lock_sync(ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
struct _cache_mngt_async_context *context;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
context = kmalloc(sizeof(*context), GFP_KERNEL);
|
||||||
|
if (!context)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
_cache_mngt_async_context_init(context);
|
||||||
|
|
||||||
|
ocf_mngt_cache_read_lock(cache, _cache_mngt_read_lock_complete, context);
|
||||||
|
result = wait_for_completion_interruptible(&context->cmpl);
|
||||||
|
|
||||||
|
result = _cache_mngt_async_caller_set_result(context, result);
|
||||||
|
|
||||||
|
if (result != -KCAS_ERR_WAITING_INTERRUPTED)
|
||||||
|
kfree(context);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user