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:
Adam Rutkowski
2019-03-25 18:45:53 -04:00
parent 1a234744ef
commit 7003d38b44
2 changed files with 96 additions and 0 deletions

53
src/utils/utils_refcnt.c Normal file
View 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);
}