diff --git a/tests/functional/pyocf/types/volume.py b/tests/functional/pyocf/types/volume.py index 86a888f..7e21ae6 100644 --- a/tests/functional/pyocf/types/volume.py +++ b/tests/functional/pyocf/types/volume.py @@ -88,19 +88,13 @@ class VolumeOps(Structure): class VolumeProperties(Structure): _fields_ = [ ("_name", c_char_p), - ("_io_priv_size", c_uint32), ("_volume_priv_size", c_uint32), ("_caps", VolumeCaps), - ("_io_ops", IoOps), ("_deinit", c_char_p), ("_ops_", VolumeOps), ] -class VolumeIoPriv(Structure): - _fields_ = [("_data", c_void_p), ("_offset", c_uint64)] - - VOLUME_POISON = 0x13 @@ -243,11 +237,9 @@ class Volume: Volume._props_[cls] = VolumeProperties( _name=str(cls.__name__).encode("ascii"), - _io_priv_size=sizeof(VolumeIoPriv), _volume_priv_size=0, _caps=VolumeCaps(_atomic_writes=0), _ops_=cls.get_ops(), - _io_ops=cls.get_io_ops(), _deinit=0, ) return Volume._props_[cls] @@ -267,22 +259,6 @@ class Volume: def get_by_uuid(cls, uuid): return cls._uuid_[uuid] - @staticmethod - @IoOps.SET_DATA - def _io_set_data(io, data, offset): - io_priv = cast(OcfLib.getInstance().ocf_io_get_priv(io), POINTER(VolumeIoPriv)) - data = Data.get_instance(data) - io_priv.contents._offset = offset - io_priv.contents._data = data.handle - - return 0 - - @staticmethod - @IoOps.GET_DATA - def _io_get_data(io): - io_priv = cast(OcfLib.getInstance().ocf_io_get_priv(io), POINTER(VolumeIoPriv)) - return io_priv.contents._data - def __init__(self, uuid=None): if uuid: if uuid in type(self)._uuid_: @@ -499,8 +475,7 @@ class RamVolume(Volume): return try: - io_priv = cast(OcfLib.getInstance().ocf_io_get_priv(io), POINTER(VolumeIoPriv)) - offset = io_priv.contents._offset + offset = OcfLib.getInstance().ocf_io_get_offset(io) if io.contents._dir == IoDir.WRITE: src_ptr = cast(OcfLib.getInstance().ocf_io_get_data(io), c_void_p) @@ -512,7 +487,6 @@ class RamVolume(Volume): src = self.data_ptr + io.contents._addr memmove(dst, src, io.contents._bytes) - io_priv.contents._offset += io.contents._bytes io.contents._end(io, 0) except: # noqa E722 @@ -597,7 +571,6 @@ class ErrorDevice(Volume): def should_forward_io(self, rw, addr): if not self.armed: return True - direction = IoDir(rw) seq_no_match = ( self.error_seq_no[direction] >= 0 @@ -633,7 +606,7 @@ class ErrorDevice(Volume): else: self.complete_submit_with_error(io) - def complete_forward_with_error(self, token, rw): + def complete_forward_with_error(self, token, rw=IoDir.WRITE): self.error = True direction = IoDir(rw) self.stats["errors"][direction] += 1 @@ -646,16 +619,16 @@ class ErrorDevice(Volume): self.complete_forward_with_error(token, rw) def do_forward_flush(self, token): - if self.data_only or self.should_forward_io(0, 0): + if self.data_only or self.should_forward_io(IoDir.WRITE, 0): self.vol.do_forward_flush(token) else: - self.complete_forward_with_error(token, rw) + self.complete_forward_with_error(token) def do_forward_discard(self, token, addr, nbytes): - if self.data_only or self.should_forward_io(0, addr): + if self.data_only or self.should_forward_io(IoDir.WRITE, addr): self.vol.do_forward_discard(token, addr, nbytes) else: - self.complete_forward_with_error(token, rw) + self.complete_forward_with_error(token) def arm(self): self.armed = True @@ -812,7 +785,7 @@ class TraceDevice(Volume): lib = OcfLib.getInstance() -lib.ocf_io_get_priv.restype = POINTER(VolumeIoPriv) +lib.ocf_io_get_offset.restype = c_uint32 lib.ocf_io_get_volume.argtypes = [c_void_p] lib.ocf_io_get_volume.restype = c_void_p lib.ocf_io_get_data.argtypes = [c_void_p] diff --git a/tests/functional/tests/engine/test_io_flags.py b/tests/functional/tests/engine/test_io_flags.py index b95b235..0e5359a 100644 --- a/tests/functional/tests/engine/test_io_flags.py +++ b/tests/functional/tests/engine/test_io_flags.py @@ -4,10 +4,7 @@ # SPDX-License-Identifier: BSD-3-Clause # -from ctypes import c_int, memmove, cast, c_void_p -from enum import IntEnum -from itertools import product -import random +from ctypes import memmove, cast, c_void_p, c_uint64 import pytest @@ -18,6 +15,7 @@ from pyocf.types.volume_core import CoreVolume from pyocf.types.data import Data from pyocf.types.io import IoDir, Sync from pyocf.utils import Size +from pyocf.ocf import OcfLib def __io(io, data): @@ -48,19 +46,19 @@ class FlagsValVolume(RamVolume): self.fail = False super().__init__(size) - def set_check(self, check): - self.check = check + def set_check(self): + self.check = True + self.fail = True - def submit_io(self, io): + def do_forward_io(self, token, rw, addr, nbytes, offset): if self.check: - flags = io.contents._flags - if flags != self.flags: - self.fail = True - super().submit_io(io) + flags = lib.ocf_forward_get_flags(token) + if flags == self.flags: + self.fail = False + super().do_forward_io(token, rw, addr, nbytes, offset) -@pytest.mark.parametrize("cache_mode", CacheMode) -def test_io_flags(pyocf_ctx, cache_mode): +def test_io_flags(pyocf_ctx): """ Verify that I/O flags provided at the top volume interface are propagated down to bottom volumes for all associated @@ -74,44 +72,54 @@ def test_io_flags(pyocf_ctx, cache_mode): pyocf_ctx.register_volume_type(FlagsValVolume) - cache_device = FlagsValVolume(Size.from_MiB(50), flags) + cache_device = FlagsValVolume(Size.from_MiB(50), 0) core_device = FlagsValVolume(Size.from_MiB(50), flags) - cache = Cache.start_on_device(cache_device, cache_mode=cache_mode) + cache = Cache.start_on_device(cache_device, cache_mode=CacheMode.WB) core = Core.using_device(core_device) cache.add_core(core) vol = CoreVolume(core) - cache_device.set_check(True) - core_device.set_check(True) + def set_check(): + cache_device.set_check() + core_device.set_check() # write miss + set_check() io_to_exp_obj(vol, block_size * 0, block_size, data, 0, IoDir.WRITE, flags) assert not cache_device.fail - assert not core_device.fail # read miss + set_check() io_to_exp_obj(vol, block_size * 1, block_size, data, 0, IoDir.READ, flags) - assert not cache_device.fail assert not core_device.fail # "dirty" read hit + set_check() io_to_exp_obj(vol, block_size * 0, block_size, data, 0, IoDir.READ, flags) assert not cache_device.fail - assert not core_device.fail # "clean" read hit + set_check() io_to_exp_obj(vol, block_size * 1, block_size, data, 0, IoDir.READ, flags) assert not cache_device.fail - assert not core_device.fail + + cache.change_cache_mode(CacheMode.WT) # "dirty" write hit + set_check() io_to_exp_obj(vol, block_size * 0, block_size, data, 0, IoDir.WRITE, flags) assert not cache_device.fail assert not core_device.fail # "clean" write hit + set_check() io_to_exp_obj(vol, block_size * 1, block_size, data, 0, IoDir.WRITE, flags) assert not cache_device.fail assert not core_device.fail + + +lib = OcfLib.getInstance() +lib.ocf_forward_get_flags.argtypes = [c_uint64] +lib.ocf_forward_get_flags.restype = c_uint64 diff --git a/tests/functional/tests/management/test_composite_volume.py b/tests/functional/tests/management/test_composite_volume.py index f7b0607..b61d604 100644 --- a/tests/functional/tests/management/test_composite_volume.py +++ b/tests/functional/tests/management/test_composite_volume.py @@ -12,7 +12,7 @@ from threading import Event from collections import namedtuple from pyocf.ocf import OcfLib -from pyocf.types.volume import RamVolume, ErrorDevice, TraceDevice, IoFlags, VolumeIoPriv +from pyocf.types.volume import RamVolume, ErrorDevice, TraceDevice, IoFlags from pyocf.types.cvolume import CVolume from pyocf.types.data import Data from pyocf.types.io import IoDir @@ -287,19 +287,25 @@ def test_io_propagation_basic(pyocf_ctx): ret = cvol_submit_data_io(cvol, addr, io_size) assert ret == 0 - ret = cvol_submit_flush_io(cvol, addr, io_size, IoFlags.FLUSH) + ret = cvol_submit_flush_io(cvol, addr, io_size) assert ret == 0 ret = cvol_submit_discard_io(cvol, addr, io_size) assert ret == 0 - for io_type in TraceDevice.IoType: - ios = io_trace[vol][io_type] - assert len(ios) == 1 - io = ios[0] - assert io.dir == IoDir.WRITE - assert io.addr == addr.B - int(vol_begin[i]) - assert io.bytes == io_size.B + ios = io_trace[vol][TraceDevice.IoType.Data] + assert len(ios) == 1 + assert ios[0].dir == IoDir.WRITE + assert ios[0].addr == addr.B - int(vol_begin[i]) + assert ios[0].bytes == io_size.B + + ios = io_trace[vol][TraceDevice.IoType.Flush] + assert len(ios) == i + 1 + + ios = io_trace[vol][TraceDevice.IoType.Discard] + assert len(ios) == 1 + assert ios[0].addr == addr.B - int(vol_begin[i]) + assert ios[0].bytes == io_size.B cvol.close() cvol.destroy() @@ -355,27 +361,36 @@ def test_io_propagation_cross_boundary(pyocf_ctx): ret = cvol_submit_data_io(cvol, addr, io_size) assert ret == 0 - ret = cvol_submit_flush_io(cvol, addr, io_size, IoFlags.FLUSH) + ret = cvol_submit_flush_io(cvol, addr, io_size) assert ret == 0 ret = cvol_submit_discard_io(cvol, addr, io_size) assert ret == 0 - for io_type in TraceDevice.IoType: - ios1 = io_trace[vols[i]][io_type] - ios2 = io_trace[vols[i + 1]][io_type] + ios1 = io_trace[vols[i]][TraceDevice.IoType.Data] + ios2 = io_trace[vols[i + 1]][TraceDevice.IoType.Data] + assert len(ios1) == 1 + assert ios1[0].dir == IoDir.WRITE + assert ios1[0].addr == int(vols[i].vol.size - (io_size / 2)) + assert ios1[0].bytes == io_size.B / 2 + assert len(ios2) == 1 + assert ios2[0].dir == IoDir.WRITE + assert ios2[0].addr == 0 + assert ios2[0].bytes == io_size.B / 2 - assert len(ios1) == 1 - io = ios1[0] - assert io.dir == IoDir.WRITE - assert io.addr == int(vols[i].vol.size - (io_size / 2)) - assert io.bytes == io_size.B / 2 + ios1 = io_trace[vols[i]][TraceDevice.IoType.Flush] + ios2 = io_trace[vols[i + 1]][TraceDevice.IoType.Flush] + assert len(ios1) == 1 + assert len(ios2) == 1 - assert len(ios2) == 1 - io = ios2[0] - assert io.dir == IoDir.WRITE - assert io.addr == 0 - assert io.bytes == io_size.B / 2 + ios1 = io_trace[vols[i]][TraceDevice.IoType.Discard] + ios2 = io_trace[vols[i + 1]][TraceDevice.IoType.Discard] + assert len(ios1) == 1 + assert ios1[0].addr == int(vols[i].vol.size - (io_size / 2)) + assert ios1[0].bytes == io_size.B / 2 + assert len(ios2) == 1 + assert ios2[0].addr == 0 + assert ios2[0].bytes == io_size.B / 2 cvol.close() cvol.destroy() @@ -483,25 +498,51 @@ def test_io_propagation_multiple_subvolumes(pyocf_ctx, rand_seed): ret = cvol_submit_data_io(cvol, addr, size) assert ret == 0 - ret = cvol_submit_flush_io(cvol, addr, size, IoFlags.FLUSH) + ret = cvol_submit_flush_io(cvol, addr, size) assert ret == 0 ret = cvol_submit_discard_io(cvol, addr, size) assert ret == 0 for vol in middle: - for io in io_trace[vol].values(): - assert len(io) == 1 - assert io[0].addr == 0 - assert io[0].bytes == int(vol.vol.size) + ios = io_trace[vol][TraceDevice.IoType.Data] + assert len(ios) == 1 + assert ios[0].addr == 0 + assert ios[0].bytes == int(vol.vol.size) - for io in io_trace[first].values(): - assert io[0].addr == int(start_offset) - assert io[0].bytes == int(vol_size - start_offset) + ios = io_trace[first][TraceDevice.IoType.Data] + assert len(ios) == 1 + assert ios[0].addr == int(start_offset) + assert ios[0].bytes == int(vol_size - start_offset) - for io in io_trace[last].values(): - assert io[0].addr == 0 - assert io[0].bytes == int(end_offset) + ios = io_trace[last][TraceDevice.IoType.Data] + assert len(ios) == 1 + assert ios[0].addr == 0 + assert ios[0].bytes == int(end_offset) + + ios = io_trace[vol][TraceDevice.IoType.Flush] + assert len(ios) == 1 + + ios = io_trace[first][TraceDevice.IoType.Flush] + assert len(ios) == 1 + + ios = io_trace[last][TraceDevice.IoType.Flush] + assert len(ios) == 1 + + ios = io_trace[vol][TraceDevice.IoType.Discard] + assert len(ios) == 1 + assert ios[0].addr == 0 + assert ios[0].bytes == int(vol.vol.size) + + ios = io_trace[first][TraceDevice.IoType.Discard] + assert len(ios) == 1 + assert ios[0].addr == int(start_offset) + assert ios[0].bytes == int(vol_size - start_offset) + + ios = io_trace[last][TraceDevice.IoType.Discard] + assert len(ios) == 1 + assert ios[0].addr == 0 + assert ios[0].bytes == int(end_offset) cvol.close() cvol.destroy() @@ -538,16 +579,16 @@ def test_io_completion(pyocf_ctx, rand_seed): self.pending_ios = [] self.io_submitted = Event() - def do_submit_io(self, io): - self.pending_ios.append(("io", io)) + def do_forward_io(self, token, rw, addr, nbytes, offset): + self.pending_ios.append(("io", token, rw, addr, nbytes, offset)) self.io_submitted.set() - def do_submit_flush(self, flush): - self.pending_ios.append(("flush", flush)) + def do_forward_flush(self, token): + self.pending_ios.append(("flush", token)) self.io_submitted.set() - def do_submit_discard(self, discard): - self.pending_ios.append(("discard", discard)) + def do_forward_discard(self, token, addr, nbytes): + self.pending_ios.append(("discard", token, addr, nbytes)) self.io_submitted.set() def wait_submitted(self): @@ -558,13 +599,13 @@ def test_io_completion(pyocf_ctx, rand_seed): if not self.pending_ios: return False - io_type, io = self.pending_ios.pop() + io_type, token, *params = self.pending_ios.pop() if io_type == "io": - super().do_submit_io(io) + super().do_forward_io(token, *params) elif io_type == "flush": - super().do_submit_flush(io) + super().do_forward_flush(token) elif io_type == "discard": - super().do_submit_discard(io) + super().do_forward_discard(token, *params) else: assert False @@ -586,14 +627,18 @@ def test_io_completion(pyocf_ctx, rand_seed): addr = vol_size / 2 size = (subvol_count - 1) * vol_size - for op, flags in [("submit", 0), ("submit_flush", IoFlags.FLUSH), ("submit_discard", 0)]: + for op, cnt in [ + ("submit", subvol_count), + ("submit_flush", len(vols)), + ("submit_discard", subvol_count) + ]: io = cvol.new_io( queue=None, addr=addr, length=size, direction=IoDir.WRITE, io_class=0, - flags=flags, + flags=0, ) completion = OcfCompletion([("err", c_int)]) io.callback = completion.callback @@ -604,7 +649,7 @@ def test_io_completion(pyocf_ctx, rand_seed): submit_fn = getattr(io, op) submit_fn() - pending_vols = vols[:subvol_count] + pending_vols = vols[:cnt] for v in pending_vols: v.wait_submitted() @@ -674,7 +719,7 @@ def test_io_error(pyocf_ctx, rand_seed): assert ret == -OcfErrorCode.OCF_ERR_IO # verify flush properly propagated - ret = cvol_submit_flush_io(cvol, addr, size, IoFlags.FLUSH) + ret = cvol_submit_flush_io(cvol, addr, size) assert ret == -OcfErrorCode.OCF_ERR_IO # verdiscard discard properly propagated