
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>
105 lines
2.5 KiB
C
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));
|
|
}
|