From 7003d38b44dc9526c84b7c64c9f04723235f4df4 Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Mon, 25 Mar 2019 18:45:53 -0400 Subject: [PATCH] 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 --- src/utils/utils_refcnt.c | 53 ++++++++++++++++++++++++++++++++++++++++ src/utils/utils_refcnt.h | 43 ++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 src/utils/utils_refcnt.c create mode 100644 src/utils/utils_refcnt.h diff --git a/src/utils/utils_refcnt.c b/src/utils/utils_refcnt.c new file mode 100644 index 0000000..045e952 --- /dev/null +++ b/src/utils/utils_refcnt.c @@ -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); +} diff --git a/src/utils/utils_refcnt.h b/src/utils/utils_refcnt.h new file mode 100644 index 0000000..5df2714 --- /dev/null +++ b/src/utils/utils_refcnt.h @@ -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__