From 407470c25d33ac7bb1132a6c84b5481091fa32b5 Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Wed, 17 Apr 2019 23:05:24 -0400 Subject: [PATCH 1/2] Add reference counter init routine This is useful when reference counter is initialized in non-zeroed memory (or assuming atomic variable is not properly initialized by memseting to zero). Signed-off-by: Adam Rutkowski --- src/utils/utils_refcnt.c | 8 ++++++++ src/utils/utils_refcnt.h | 3 +++ 2 files changed, 11 insertions(+) diff --git a/src/utils/utils_refcnt.c b/src/utils/utils_refcnt.c index 045e952..450092a 100644 --- a/src/utils/utils_refcnt.c +++ b/src/utils/utils_refcnt.c @@ -5,6 +5,14 @@ #include "../utils/utils_refcnt.h" +void ocf_refcnt_init(struct ocf_refcnt *rc) +{ + env_atomic_set(&rc->counter, 0); + env_atomic_set(&rc->freeze, 0); + env_atomic_set(&rc->callback, 0); + rc->cb = NULL; +} + void ocf_refcnt_dec(struct ocf_refcnt *rc) { int val = env_atomic_dec_return(&rc->counter); diff --git a/src/utils/utils_refcnt.h b/src/utils/utils_refcnt.h index 5df2714..10bb24b 100644 --- a/src/utils/utils_refcnt.h +++ b/src/utils/utils_refcnt.h @@ -19,6 +19,9 @@ struct ocf_refcnt void *priv; }; +/* Initialize reference counter */ +void ocf_refcnt_init(struct ocf_refcnt *rc); + /* Try to increment counter. Returns true if successfull, false if freezed */ bool ocf_refcnt_inc(struct ocf_refcnt *rc); From 1efb3014620e054d8a9234eaa644374365f211a3 Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Wed, 17 Apr 2019 15:56:17 -0400 Subject: [PATCH 2/2] Wait for IO put in volume close Volume close should not close underlying device until all I/O targeting this volume are deallocated. To achieve this a reference counter is added to volume. Counter value matches number of I/O objects associated with volume. Counter is freezed when volume is closed, blocking allocation of new I/O objects. Signed-off-by: Adam Rutkowski --- src/ocf_io.c | 11 +++++++++-- src/ocf_volume.c | 24 +++++++++++++++++++++--- src/ocf_volume_priv.h | 2 ++ 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/ocf_io.c b/src/ocf_io.c index 1c4049d..12a0db2 100644 --- a/src/ocf_io.c +++ b/src/ocf_io.c @@ -54,10 +54,15 @@ struct ocf_io *ocf_io_new(ocf_volume_t volume) struct ocf_io_meta *io_meta; void *data; - data = env_allocator_new(volume->type->allocator); - if (!data) + if (!ocf_refcnt_inc(&volume->refcnt)) return NULL; + data = env_allocator_new(volume->type->allocator); + if (!data) { + ocf_refcnt_dec(&volume->refcnt); + return NULL; + } + io = data + sizeof(struct ocf_io_meta); io_meta = ocf_io_get_meta(io); @@ -92,6 +97,8 @@ void ocf_io_put(struct ocf_io *io) if (env_atomic_dec_return(&io_meta->ref_count)) return; + ocf_refcnt_dec(&io->volume->refcnt); + env_allocator_del(io->volume->type->allocator, (void *)io - sizeof(struct ocf_io_meta)); } diff --git a/src/ocf_volume.c b/src/ocf_volume.c index b5744cb..5459f46 100644 --- a/src/ocf_volume.c +++ b/src/ocf_volume.c @@ -79,6 +79,9 @@ int ocf_volume_init(ocf_volume_t volume, ocf_volume_type_t type, if (!volume->priv) return -OCF_ERR_NO_MEM; + ocf_refcnt_init(&volume->refcnt); + ocf_refcnt_freeze(&volume->refcnt); + if (!uuid) { volume->uuid.size = 0; volume->uuid.data = NULL; @@ -109,6 +112,7 @@ int ocf_volume_init(ocf_volume_t volume, ocf_volume_type_t type, return 0; err: + ocf_refcnt_unfreeze(&volume->refcnt); env_free(volume->priv); return -OCF_ERR_NO_MEM; } @@ -137,6 +141,7 @@ void ocf_volume_move(ocf_volume_t volume, ocf_volume_t from) volume->priv = from->priv; volume->cache = from->cache; volume->features = from->features; + volume->refcnt = from->refcnt; /* * Deinitialize original volume without freeing resources. @@ -221,9 +226,6 @@ int ocf_volume_is_atomic(ocf_volume_t volume) struct ocf_io *ocf_volume_new_io(ocf_volume_t volume) { - if (!volume->opened) - return NULL; - return ocf_io_new(volume); } @@ -276,16 +278,32 @@ int ocf_volume_open(ocf_volume_t volume, void *volume_params) if (ret) return ret; + ocf_refcnt_unfreeze(&volume->refcnt); volume->opened = true; return 0; } +static void ocf_volume_close_end(void *ctx) +{ + env_completion *cmpl = ctx; + + env_completion_complete(cmpl); +} + void ocf_volume_close(ocf_volume_t volume) { + env_completion cmpl; + ENV_BUG_ON(!volume->type->properties->ops.close); ENV_BUG_ON(!volume->opened); + env_completion_init(&cmpl); + ocf_refcnt_freeze(&volume->refcnt); + ocf_refcnt_register_zero_cb(&volume->refcnt, ocf_volume_close_end, + &cmpl); + env_completion_wait(&cmpl); + volume->type->properties->ops.close(volume); volume->opened = false; } diff --git a/src/ocf_volume_priv.h b/src/ocf_volume_priv.h index 9ea7bc7..de36153 100644 --- a/src/ocf_volume_priv.h +++ b/src/ocf_volume_priv.h @@ -8,6 +8,7 @@ #include "ocf_env.h" #include "ocf_io_priv.h" +#include "utils/utils_refcnt.h" struct ocf_volume_type { const struct ocf_volume_properties *properties; @@ -26,6 +27,7 @@ struct ocf_volume { unsigned discard_zeroes:1; /* true if reading discarded pages returns 0 */ } features; + struct ocf_refcnt refcnt; }; int ocf_volume_type_init(struct ocf_volume_type **type,