ocf/src/ocf_io.c
Adam Rutkowski 1efb301462 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 <adam.j.rutkowski@intel.com>
2019-04-17 23:12:04 -04:00

105 lines
2.5 KiB
C

/*
* Copyright(c) 2012-2018 Intel Corporation
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#include "ocf/ocf.h"
#include "ocf_io_priv.h"
#include "ocf_volume_priv.h"
/*
* This is io allocator dedicated for bottom devices.
* Out IO structure looks like this:
* --------------> +-------------------------+
* | OCF is aware | |
* | of this part. | struct ocf_io_meta |
* | | |
* | +-------------------------+ <----------------
* | | | Bottom adapter |
* | | struct ocf_io | is aware of |
* | | | this part. |
* --------------> +-------------------------+ |
* | | |
* | Bottom adapter specific | |
* | context data structure. | |
* | | |
* +-------------------------+ <----------------
*/
#define OCF_IO_TOTAL_SIZE(priv_size) (sizeof(struct ocf_io_meta) + \
sizeof(struct ocf_io) + priv_size)
env_allocator *ocf_io_allocator_create(uint32_t size, const char *name)
{
return env_allocator_create(OCF_IO_TOTAL_SIZE(size), name);
}
void ocf_io_allocator_destroy(env_allocator *allocator)
{
env_allocator_destroy(allocator);
}
/*
* IO internal API
*/
void *ocf_io_get_meta(struct ocf_io* io)
{
return (void *)io - sizeof(struct ocf_io_meta);
}
struct ocf_io *ocf_io_new(ocf_volume_t volume)
{
struct ocf_io *io;
struct ocf_io_meta *io_meta;
void *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);
io->volume = volume;
io->ops = &volume->type->properties->io_ops;
env_atomic_set(&io_meta->ref_count, 1);
return io;
}
/*
* IO external API
*/
void *ocf_io_get_priv(struct ocf_io* io)
{
return (void *)io + sizeof(struct ocf_io);
}
void ocf_io_get(struct ocf_io *io)
{
struct ocf_io_meta *io_meta = ocf_io_get_meta(io);
env_atomic_inc_return(&io_meta->ref_count);
}
void ocf_io_put(struct ocf_io *io)
{
struct ocf_io_meta *io_meta = ocf_io_get_meta(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));
}