Encapsulate request reference counting logic in utils_refcnt
In order to synchronize management operations with I/O OCF maintains in-flight request counters. For example such ref counters are used during ocf_mngt_detach to drain requests accessing cache metadata (cache requests counter) and in ocf_mngt_flush where we wait for outstanding requests sent in write back mode (dirty requests counter). Typically I/O threads increment cache/dirty counter when creating request and decrement counter on request completion. Management thread sets atomic variable to signal the start of management operation. I/O threads react to this by changing I/O requests mode so that the cache/dirty reference counter is not incremented. As a result reference counter keeps getting decremented. Management thread waits for the counter to drop to 0 and proceeds with management operation with assumption that no cache/dirty requests are in progress. This patch introduces a handy utility for requests reference counting logic. ocf_refcnt_inc / dec are used to increment/ decrement counter. ocf_refcnt_freeze() makes subsequent ocf_refcnt_inc() calls to return false, indicating that counter cannot be incremented at this moment. ocf_refcnt_register_zero_cb can be used to asynchronously wait for counter to drop to 0. Signed-off-by: Adam Rutkowski <adam.j.rutkowski@intel.com>
This commit is contained in:
parent
1a234744ef
commit
7003d38b44
53
src/utils/utils_refcnt.c
Normal file
53
src/utils/utils_refcnt.c
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright(c) 2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#include "../utils/utils_refcnt.h"
|
||||
|
||||
void ocf_refcnt_dec(struct ocf_refcnt *rc)
|
||||
{
|
||||
int val = env_atomic_dec_return(&rc->counter);
|
||||
ENV_BUG_ON(val < 0);
|
||||
|
||||
if (!val && env_atomic_cmpxchg(&rc->callback, 1, 0))
|
||||
rc->cb(rc->priv);
|
||||
}
|
||||
|
||||
bool ocf_refcnt_inc(struct ocf_refcnt *rc)
|
||||
{
|
||||
if (!env_atomic_read(&rc->freeze)) {
|
||||
env_atomic_inc(&rc->counter);
|
||||
if (!env_atomic_read(&rc->freeze))
|
||||
return true;
|
||||
else
|
||||
ocf_refcnt_dec(rc);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void ocf_refcnt_freeze(struct ocf_refcnt *rc)
|
||||
{
|
||||
env_atomic_inc(&rc->freeze);
|
||||
}
|
||||
|
||||
void ocf_refcnt_register_zero_cb(struct ocf_refcnt *rc, ocf_refcnt_cb_t cb,
|
||||
void *priv)
|
||||
{
|
||||
ENV_BUG_ON(!env_atomic_read(&rc->freeze));
|
||||
ENV_BUG_ON(env_atomic_read(&rc->callback));
|
||||
|
||||
env_atomic_inc(&rc->counter);
|
||||
rc->cb = cb;
|
||||
rc->priv = priv;
|
||||
env_atomic_set(&rc->callback, 1);
|
||||
ocf_refcnt_dec(rc);
|
||||
}
|
||||
|
||||
void ocf_refcnt_unfreeze(struct ocf_refcnt *rc)
|
||||
{
|
||||
int val = env_atomic_dec_return(&rc->freeze);
|
||||
ENV_BUG_ON(val < 0);
|
||||
}
|
43
src/utils/utils_refcnt.h
Normal file
43
src/utils/utils_refcnt.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright(c) 2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __OCF_REFCNT_H__
|
||||
#define __OCF_REFCNT_H__
|
||||
|
||||
#include "ocf_env.h"
|
||||
|
||||
typedef void (*ocf_refcnt_cb_t)(void *priv);
|
||||
|
||||
struct ocf_refcnt
|
||||
{
|
||||
env_atomic counter;
|
||||
env_atomic freeze;
|
||||
env_atomic callback;
|
||||
ocf_refcnt_cb_t cb;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
/* Try to increment counter. Returns true if successfull, false if freezed */
|
||||
bool ocf_refcnt_inc(struct ocf_refcnt *rc);
|
||||
|
||||
/* Decrement reference counter */
|
||||
void ocf_refcnt_dec(struct ocf_refcnt *rc);
|
||||
|
||||
/* Disallow incrementing of underlying counter - attempts to increment counter
|
||||
* will be failing until ocf_refcnt_unfreeze is calleed.
|
||||
* It's ok to call freeze multiple times, in which case counter is freezed
|
||||
* until all freeze calls are offset by a corresponding unfreeze.*/
|
||||
void ocf_refcnt_freeze(struct ocf_refcnt *rc);
|
||||
|
||||
/* Cancel the effect of single ocf_refcnt_freeze call */
|
||||
void ocf_refcnt_unfreeze(struct ocf_refcnt *rc);
|
||||
|
||||
/* Register callback to be called when reference counter drops to 0.
|
||||
* Must be called after counter is freezed.
|
||||
* Cannot be called until previously regsitered callback had fired. */
|
||||
void ocf_refcnt_register_zero_cb(struct ocf_refcnt *rc, ocf_refcnt_cb_t cb,
|
||||
void *priv);
|
||||
|
||||
#endif // __OCF_REFCNT_H__
|
Loading…
Reference in New Issue
Block a user