pyocf: extend ErrorDevice to inject error on flush and discard
Signed-off-by: Adam Rutkowski <adam.j.rutkowski@intel.com>
This commit is contained in:
parent
8b83f0f164
commit
e2ea2b41e6
@ -431,12 +431,19 @@ class RamVolume(Volume):
|
|||||||
|
|
||||||
class ErrorDevice(Volume):
|
class ErrorDevice(Volume):
|
||||||
def __init__(
|
def __init__(
|
||||||
self, vol, error_sectors: set = None, error_seq_no: dict = None, armed=True, uuid=None,
|
self,
|
||||||
|
vol,
|
||||||
|
error_sectors: set = None,
|
||||||
|
error_seq_no: dict = None,
|
||||||
|
data_only=False,
|
||||||
|
armed=True,
|
||||||
|
uuid=None,
|
||||||
):
|
):
|
||||||
self.vol = vol
|
self.vol = vol
|
||||||
super().__init__(uuid)
|
super().__init__(uuid)
|
||||||
self.error_sectors = error_sectors
|
self.error_sectors = error_sectors or set()
|
||||||
self.error_seq_no = error_seq_no
|
self.error_seq_no = error_seq_no or {IoDir.WRITE: -1, IoDir.READ: -1}
|
||||||
|
self.data_only = data_only
|
||||||
self.armed = armed
|
self.armed = armed
|
||||||
self.io_seq_no = {IoDir.WRITE: 0, IoDir.READ: 0}
|
self.io_seq_no = {IoDir.WRITE: 0, IoDir.READ: 0}
|
||||||
self.error = False
|
self.error = False
|
||||||
@ -444,32 +451,44 @@ class ErrorDevice(Volume):
|
|||||||
def set_mapping(self, error_sectors: set):
|
def set_mapping(self, error_sectors: set):
|
||||||
self.error_sectors = error_sectors
|
self.error_sectors = error_sectors
|
||||||
|
|
||||||
def do_submit_io(self, io):
|
def should_forward_io(self, io):
|
||||||
if not self.armed:
|
if not self.armed:
|
||||||
self.vol.do_submit_io(io)
|
return True
|
||||||
return
|
|
||||||
|
|
||||||
direction = IoDir(io.contents._dir)
|
direction = IoDir(io.contents._dir)
|
||||||
seq_no_match = (
|
seq_no_match = (
|
||||||
self.error_seq_no is not None
|
self.error_seq_no[direction] >= 0
|
||||||
and direction in self.error_seq_no
|
|
||||||
and self.error_seq_no[direction] <= self.io_seq_no[direction]
|
and self.error_seq_no[direction] <= self.io_seq_no[direction]
|
||||||
)
|
)
|
||||||
sector_match = self.error_sectors is not None and io.contents._addr in self.error_sectors
|
sector_match = io.contents._addr in self.error_sectors
|
||||||
|
|
||||||
self.io_seq_no[direction] += 1
|
self.io_seq_no[direction] += 1
|
||||||
|
|
||||||
error = True
|
return not seq_no_match and not sector_match
|
||||||
if self.error_seq_no is not None and not seq_no_match:
|
|
||||||
error = False
|
def complete_with_error(self, io):
|
||||||
if self.error_sectors is not None and not sector_match:
|
self.error = True
|
||||||
error = False
|
direction = IoDir(io.contents._dir)
|
||||||
if error:
|
self.stats["errors"][direction] += 1
|
||||||
self.error = True
|
io.contents._end(io, -OcfErrorCode.OCF_ERR_IO)
|
||||||
io.contents._end(io, -OcfErrorCode.OCF_ERR_IO)
|
|
||||||
self.stats["errors"][direction] += 1
|
def do_submit_io(self, io):
|
||||||
else:
|
if self.should_forward_io(io):
|
||||||
self.vol.do_submit_io(io)
|
self.vol.do_submit_io(io)
|
||||||
|
else:
|
||||||
|
self.complete_with_error(io)
|
||||||
|
|
||||||
|
def do_submit_flush(self, flush):
|
||||||
|
if self.data_only and self.should_forward_io(flush):
|
||||||
|
self.vol.do_submit_flush(flush)
|
||||||
|
else:
|
||||||
|
self.complete_with_error(flush)
|
||||||
|
|
||||||
|
def do_submit_discard(self, discard):
|
||||||
|
if self.data_only and self.should_forward_io(discard):
|
||||||
|
self.vol.do_submit_discard(discard)
|
||||||
|
else:
|
||||||
|
self.complete_with_error(discard)
|
||||||
|
|
||||||
def arm(self):
|
def arm(self):
|
||||||
self.armed = True
|
self.armed = True
|
||||||
@ -491,12 +510,6 @@ class ErrorDevice(Volume):
|
|||||||
def get_max_io_size(self):
|
def get_max_io_size(self):
|
||||||
return self.vol.get_max_io_size()
|
return self.vol.get_max_io_size()
|
||||||
|
|
||||||
def do_submit_flush(self, flush):
|
|
||||||
return self.vol.do_submit_flush(flush)
|
|
||||||
|
|
||||||
def do_submit_discard(self, discard):
|
|
||||||
return self.vol.do_submit_discard(discard)
|
|
||||||
|
|
||||||
def dump(self, offset=0, size=0, ignore=VOLUME_POISON, **kwargs):
|
def dump(self, offset=0, size=0, ignore=VOLUME_POISON, **kwargs):
|
||||||
return self.vol.dump(offset, size, ignore=ignore, **kwargs)
|
return self.vol.dump(offset, size, ignore=ignore, **kwargs)
|
||||||
|
|
||||||
|
@ -70,7 +70,10 @@ def prepare_failover(pyocf_2_ctx, cache_backend_vol, error_io_seq_no):
|
|||||||
|
|
||||||
error_io = {IoDir.WRITE: error_io_seq_no}
|
error_io = {IoDir.WRITE: error_io_seq_no}
|
||||||
|
|
||||||
err_vol = ErrorDevice(cache2_exp_obj_vol, error_seq_no=error_io, armed=False)
|
# TODO: Adjust tests to work with error injection for flushes and discards (data_only=False
|
||||||
|
# below). Currently the test fails with data_only=False as it assumes metadata is not updated
|
||||||
|
# if error had been injected, which is not true in case of error in flush.
|
||||||
|
err_vol = ErrorDevice(cache2_exp_obj_vol, error_seq_no=error_io, data_only=True, armed=False)
|
||||||
cache = Cache.start_on_device(err_vol, cache_mode=CacheMode.WB, owner=ctx1)
|
cache = Cache.start_on_device(err_vol, cache_mode=CacheMode.WB, owner=ctx1)
|
||||||
|
|
||||||
return cache, cache2, err_vol
|
return cache, cache2, err_vol
|
||||||
@ -81,7 +84,7 @@ def prepare_normal(pyocf_2_ctx, cache_backend_vol, error_io_seq_no):
|
|||||||
|
|
||||||
error_io = {IoDir.WRITE: error_io_seq_no}
|
error_io = {IoDir.WRITE: error_io_seq_no}
|
||||||
|
|
||||||
err_vol = ErrorDevice(cache_backend_vol, error_seq_no=error_io, armed=False)
|
err_vol = ErrorDevice(cache_backend_vol, error_seq_no=error_io, data_only=True, armed=False)
|
||||||
cache = Cache.start_on_device(err_vol, cache_mode=CacheMode.WB, owner=ctx1)
|
cache = Cache.start_on_device(err_vol, cache_mode=CacheMode.WB, owner=ctx1)
|
||||||
|
|
||||||
return cache, err_vol
|
return cache, err_vol
|
||||||
@ -330,9 +333,11 @@ def test_surprise_shutdown_start_cache(pyocf_2_ctx, failover):
|
|||||||
cache2.start_cache()
|
cache2.start_cache()
|
||||||
cache2.standby_attach(ramdisk)
|
cache2.standby_attach(ramdisk)
|
||||||
cache2_exp_obj_vol = CacheVolume(cache2, open=True)
|
cache2_exp_obj_vol = CacheVolume(cache2, open=True)
|
||||||
err_device = ErrorDevice(cache2_exp_obj_vol, error_seq_no=error_io, armed=True)
|
err_device = ErrorDevice(
|
||||||
|
cache2_exp_obj_vol, error_seq_no=error_io, data_only=True, armed=True
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
err_device = ErrorDevice(ramdisk, error_seq_no=error_io, armed=True)
|
err_device = ErrorDevice(ramdisk, error_seq_no=error_io, data_only=True, armed=True)
|
||||||
|
|
||||||
# call tested management function
|
# call tested management function
|
||||||
try:
|
try:
|
||||||
@ -808,7 +813,7 @@ def test_surprise_shutdown_standby_activate(pyocf_ctx):
|
|||||||
# Start cache device without error injection
|
# Start cache device without error injection
|
||||||
error_io = {IoDir.WRITE: error_io_seq_no}
|
error_io = {IoDir.WRITE: error_io_seq_no}
|
||||||
ramdisk = RamVolume(mngmt_op_surprise_shutdown_test_cache_size)
|
ramdisk = RamVolume(mngmt_op_surprise_shutdown_test_cache_size)
|
||||||
device = ErrorDevice(ramdisk, error_seq_no=error_io, armed=False)
|
device = ErrorDevice(ramdisk, error_seq_no=error_io, data_only=True, rmed=False)
|
||||||
core_device = RamVolume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
|
|
||||||
device.disarm()
|
device.disarm()
|
||||||
@ -882,7 +887,7 @@ def test_surprise_shutdown_standby_init_clean(pyocf_ctx):
|
|||||||
# Start cache device without error injection
|
# Start cache device without error injection
|
||||||
error_io = {IoDir.WRITE: error_io_seq_no}
|
error_io = {IoDir.WRITE: error_io_seq_no}
|
||||||
ramdisk = RamVolume(mngmt_op_surprise_shutdown_test_cache_size)
|
ramdisk = RamVolume(mngmt_op_surprise_shutdown_test_cache_size)
|
||||||
device = ErrorDevice(ramdisk, error_seq_no=error_io, armed=True)
|
device = ErrorDevice(ramdisk, error_seq_no=error_io, data_only=True, armed=True)
|
||||||
|
|
||||||
cache = Cache(owner=OcfCtx.get_default())
|
cache = Cache(owner=OcfCtx.get_default())
|
||||||
cache.start_cache()
|
cache.start_cache()
|
||||||
@ -942,7 +947,7 @@ def test_surprise_shutdown_standby_init_force_1(pyocf_ctx):
|
|||||||
# Start cache device without error injection
|
# Start cache device without error injection
|
||||||
error_io = {IoDir.WRITE: error_io_seq_no}
|
error_io = {IoDir.WRITE: error_io_seq_no}
|
||||||
ramdisk = RamVolume(mngmt_op_surprise_shutdown_test_cache_size)
|
ramdisk = RamVolume(mngmt_op_surprise_shutdown_test_cache_size)
|
||||||
device = ErrorDevice(ramdisk, error_seq_no=error_io, armed=False)
|
device = ErrorDevice(ramdisk, error_seq_no=error_io, data_only=True, armed=False)
|
||||||
|
|
||||||
# start and stop cache with cacheline inserted
|
# start and stop cache with cacheline inserted
|
||||||
cache = Cache.start_on_device(device, cache_mode=CacheMode.WB)
|
cache = Cache.start_on_device(device, cache_mode=CacheMode.WB)
|
||||||
@ -1032,7 +1037,7 @@ def test_surprise_shutdown_standby_init_force_2(pyocf_ctx):
|
|||||||
# Start cache device without error injection
|
# Start cache device without error injection
|
||||||
error_io = {IoDir.WRITE: error_io_seq_no}
|
error_io = {IoDir.WRITE: error_io_seq_no}
|
||||||
ramdisk = RamVolume(mngmt_op_surprise_shutdown_test_cache_size)
|
ramdisk = RamVolume(mngmt_op_surprise_shutdown_test_cache_size)
|
||||||
device = ErrorDevice(ramdisk, error_seq_no=error_io, armed=False)
|
device = ErrorDevice(ramdisk, error_seq_no=error_io, data_only=True, armed=False)
|
||||||
|
|
||||||
# start and stop cache with cacheline inserted
|
# start and stop cache with cacheline inserted
|
||||||
cache = Cache.start_on_device(device, cache_mode=CacheMode.WB)
|
cache = Cache.start_on_device(device, cache_mode=CacheMode.WB)
|
||||||
|
Loading…
Reference in New Issue
Block a user