diff --git a/src/metadata/metadata_io.c b/src/metadata/metadata_io.c index 5e775b2..030bbb5 100644 --- a/src/metadata/metadata_io.c +++ b/src/metadata/metadata_io.c @@ -223,7 +223,7 @@ static int metadata_io_restart_req(struct ocf_request *req) io = ocf_new_cache_io(cache, req->io_queue, PAGES_TO_BYTES(m_req->page), PAGES_TO_BYTES(m_req->count), - m_req->req.rw, 0, 0); + m_req->req.rw, 0, m_req->asynch->flags); if (!io) { metadata_io_io_end(m_req, -OCF_ERR_NO_MEM); return 0; @@ -361,7 +361,7 @@ void metadata_io_req_complete(struct metadata_io_request *m_req) * Iterative write request asynchronously */ static int metadata_io_i_asynch(ocf_cache_t cache, ocf_queue_t queue, int dir, - void *context, uint32_t page, uint32_t count, + void *context, uint32_t page, uint32_t count, int flags, ocf_metadata_io_event_t io_hndl, ocf_metadata_io_end_t compl_hndl) { @@ -386,6 +386,7 @@ static int metadata_io_i_asynch(ocf_cache_t cache, ocf_queue_t queue, int dir, a_req->context = context; a_req->page = page; a_req->count = count; + a_req->flags = flags; /* IO Requests initialization */ for (i = 0; i < req_count; i++) { @@ -435,21 +436,21 @@ err: } int metadata_io_write_i_asynch(ocf_cache_t cache, ocf_queue_t queue, - void *context, uint32_t page, uint32_t count, + void *context, uint32_t page, uint32_t count, int flags, ocf_metadata_io_event_t fill_hndl, ocf_metadata_io_end_t compl_hndl) { return metadata_io_i_asynch(cache, queue, OCF_WRITE, context, - page, count, fill_hndl, compl_hndl); + page, count, flags, fill_hndl, compl_hndl); } int metadata_io_read_i_asynch(ocf_cache_t cache, ocf_queue_t queue, - void *context, uint32_t page, uint32_t count, + void *context, uint32_t page, uint32_t count, int flags, ocf_metadata_io_event_t drain_hndl, ocf_metadata_io_end_t compl_hndl) { return metadata_io_i_asynch(cache, queue, OCF_READ, context, - page, count, drain_hndl, compl_hndl); + page, count, flags, drain_hndl, compl_hndl); } int ocf_metadata_io_init(ocf_cache_t cache) diff --git a/src/metadata/metadata_io.h b/src/metadata/metadata_io.h index 7cd2e5b..9fc9f42 100644 --- a/src/metadata/metadata_io.h +++ b/src/metadata/metadata_io.h @@ -74,6 +74,7 @@ struct metadata_io_request_asynch { env_atomic req_current; uint32_t page; uint32_t count; + int flags; ocf_metadata_io_end_t on_complete; }; @@ -122,7 +123,7 @@ int metadata_io_read_i_atomic(ocf_cache_t cache, ocf_queue_t queue, * @return 0 - No errors, otherwise error occurred */ int metadata_io_write_i_asynch(ocf_cache_t cache, ocf_queue_t queue, - void *context, uint32_t page, uint32_t count, + void *context, uint32_t page, uint32_t count, int flags, ocf_metadata_io_event_t fill_hndl, ocf_metadata_io_end_t compl_hndl); @@ -140,7 +141,7 @@ int metadata_io_write_i_asynch(ocf_cache_t cache, ocf_queue_t queue, * @return 0 - No errors, otherwise error occurred */ int metadata_io_read_i_asynch(ocf_cache_t cache, ocf_queue_t queue, - void *context, uint32_t page, uint32_t count, + void *context, uint32_t page, uint32_t count, int flags, ocf_metadata_io_event_t drain_hndl, ocf_metadata_io_end_t compl_hndl); diff --git a/src/metadata/metadata_raw.c b/src/metadata/metadata_raw.c index 826c8c3..4c17078 100644 --- a/src/metadata/metadata_raw.c +++ b/src/metadata/metadata_raw.c @@ -259,7 +259,7 @@ static void _raw_ram_load_all(ocf_cache_t cache, struct ocf_metadata_raw *raw, context->priv = priv; result = metadata_io_read_i_asynch(cache, cache->mngt_queue, context, - raw->ssd_pages_offset, raw->ssd_pages, + raw->ssd_pages_offset, raw->ssd_pages, 0, _raw_ram_load_all_drain, _raw_ram_load_all_complete); if (result) _raw_ram_load_all_complete(cache, context, result); @@ -331,7 +331,7 @@ static void _raw_ram_flush_all(ocf_cache_t cache, struct ocf_metadata_raw *raw, context->priv = priv; result = metadata_io_write_i_asynch(cache, cache->mngt_queue, context, - raw->ssd_pages_offset, raw->ssd_pages, + raw->ssd_pages_offset, raw->ssd_pages, 0, _raw_ram_flush_all_fill, _raw_ram_flush_all_complete); if (result) _raw_ram_flush_all_complete(cache, context, result); @@ -536,6 +536,7 @@ static int _raw_ram_flush_do_asynch(ocf_cache_t cache, result |= metadata_io_write_i_asynch(cache, req->io_queue, ctx, raw->ssd_pages_offset + start_page, count, + req->ioi.io.flags, _raw_ram_flush_do_asynch_fill, _raw_ram_flush_do_asynch_io_complete); diff --git a/src/metadata/metadata_raw_dynamic.c b/src/metadata/metadata_raw_dynamic.c index 9e81271..a297b63 100644 --- a/src/metadata/metadata_raw_dynamic.c +++ b/src/metadata/metadata_raw_dynamic.c @@ -550,7 +550,7 @@ void raw_dynamic_flush_all(ocf_cache_t cache, struct ocf_metadata_raw *raw, context->priv = priv; result = metadata_io_write_i_asynch(cache, cache->mngt_queue, context, - raw->ssd_pages_offset, raw->ssd_pages, + raw->ssd_pages_offset, raw->ssd_pages, 0, raw_dynamic_flush_all_fill, raw_dynamic_flush_all_complete); if (result) diff --git a/tests/functional/tests/engine/test_io_flags.py b/tests/functional/tests/engine/test_io_flags.py new file mode 100644 index 0000000..aa19240 --- /dev/null +++ b/tests/functional/tests/engine/test_io_flags.py @@ -0,0 +1,126 @@ +# +# Copyright(c) 2020 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause-Clear +# + +from ctypes import c_int, memmove, cast, c_void_p +from enum import IntEnum +from itertools import product +import random + +import pytest + +from pyocf.types.cache import Cache, CacheMode +from pyocf.types.core import Core +from pyocf.types.volume import Volume +from pyocf.types.data import Data +from pyocf.types.io import IoDir +from pyocf.utils import Size +from pyocf.types.shared import OcfCompletion + + +def __io(io, queue, address, size, data, direction): + io.set_data(data, 0) + completion = OcfCompletion([("err", c_int)]) + io.callback = completion.callback + io.submit() + completion.wait() + return int(completion.results["err"]) + + +def _io(new_io, queue, address, size, data, offset, direction, flags): + io = new_io(queue, address, size, direction, 0, flags) + if direction == IoDir.READ: + _data = Data.from_bytes(bytes(size)) + else: + _data = Data.from_bytes(data, offset, size) + ret = __io(io, queue, address, size, _data, direction) + if not ret and direction == IoDir.READ: + memmove(cast(data, c_void_p).value + offset, _data.handle, size) + return ret + + +def io_to_exp_obj(core, address, size, data, offset, direction, flags): + return _io( + core.new_io, + core.cache.get_default_queue(), + address, + size, + data, + offset, + direction, + flags, + ) + + +class FlagsValVolume(Volume): + def __init__(self, size, flags): + self.flags = flags + self.check = False + self.fail = False + super().__init__(size) + + def set_check(self, check): + self.check = check + + def submit_io(self, io): + if self.check: + flags = io.contents._flags + if flags != self.flags: + self.fail = True + super().submit_io(io) + + +@pytest.mark.parametrize("cache_mode", CacheMode) +def test_io_flags(pyocf_ctx, cache_mode): + """ + Verify that I/O flags provided at the top volume interface + are propagated down to bottom volumes for all associated + I/Os (including metadata writes to cache volume). + """ + + flags = 0x239482 + block_size = 4096 + + data = bytes(block_size) + + cache_device = FlagsValVolume(Size.from_MiB(30), flags) + core_device = FlagsValVolume(Size.from_MiB(30), flags) + + cache = Cache.start_on_device(cache_device, cache_mode=cache_mode) + core = Core.using_device(core_device) + + cache.add_core(core) + + cache_device.set_check(True) + core_device.set_check(True) + + # write miss + io_to_exp_obj(core, block_size * 0, block_size, data, 0, IoDir.WRITE, flags) + assert not cache_device.fail + assert not core_device.fail + + # read miss + io_to_exp_obj(core, block_size * 1, block_size, data, 0, IoDir.READ, flags) + assert not cache_device.fail + assert not core_device.fail + + # "dirty" read hit + io_to_exp_obj(core, block_size * 0, block_size, data, 0, IoDir.READ, flags) + assert not cache_device.fail + assert not core_device.fail + + # "clean" read hit + io_to_exp_obj(core, block_size * 1, block_size, data, 0, IoDir.READ, flags) + assert not cache_device.fail + assert not core_device.fail + + # "dirty" write hit + io_to_exp_obj(core, block_size * 0, block_size, data, 0, IoDir.WRITE, flags) + assert not cache_device.fail + assert not core_device.fail + + # "clean" write hit + io_to_exp_obj(core, block_size * 1, block_size, data, 0, IoDir.WRITE, flags) + assert not cache_device.fail + assert not core_device.fail