ocf/tests/functional/tests/security/test_secure_erase.py
Robert Baldyga 98cb9bff70 pyocf: Use bigger cache device size in tests
As amount of fixed size metadata allocated by OCF grows, we need to adjust
test to not try to start cache on device that is too small.

Signed-off-by: Robert Baldyga <robert.baldyga@intel.com>
2021-12-15 15:30:34 +01:00

213 lines
5.7 KiB
Python

#
# Copyright(c) 2019-2021 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause
#
import pytest
from ctypes import c_int
from pyocf.types.cache import Cache, CacheMode
from pyocf.types.core import Core
from pyocf.types.volume import Volume
from pyocf.utils import Size as S
from pyocf.types.data import Data, DataOps
from pyocf.types.ctx import OcfCtx
from pyocf.types.logger import DefaultLogger, LogLevel
from pyocf.ocf import OcfLib
from pyocf.types.cleaner import Cleaner
from pyocf.types.io import IoDir
from pyocf.types.shared import OcfCompletion
class DataCopyTracer(Data):
"""
This class enables tracking whether each copied over Data instance is
then securely erased.
"""
needs_erase = set()
locked_instances = set()
@staticmethod
@DataOps.ALLOC
def _alloc(pages):
data = DataCopyTracer.pages(pages)
Data._ocf_instances_.append(data)
return data.handle.value
def mlock(self):
DataCopyTracer.locked_instances.add(self)
DataCopyTracer.needs_erase.add(self)
return super().mlock()
def munlock(self):
if self in DataCopyTracer.needs_erase:
assert 0, "Erase should be called first on locked Data!"
DataCopyTracer.locked_instances.remove(self)
return super().munlock()
def secure_erase(self):
DataCopyTracer.needs_erase.remove(self)
return super().secure_erase()
def copy(self, src, end, start, size):
DataCopyTracer.needs_erase.add(self)
return super().copy(src, end, start, size)
@pytest.mark.security
@pytest.mark.parametrize(
"cache_mode", [CacheMode.WT, CacheMode.WB, CacheMode.WA, CacheMode.WI]
)
def test_secure_erase_simple_io_read_misses(cache_mode):
"""
Perform simple IO which will trigger read misses, which in turn should
trigger backfill. Track all the data locked/copied for backfill and make
sure OCF calls secure erase and unlock on them.
"""
ctx = OcfCtx(
OcfLib.getInstance(),
b"Security tests ctx",
DefaultLogger(LogLevel.WARN),
DataCopyTracer,
Cleaner,
)
ctx.register_volume_type(Volume)
cache_device = Volume(S.from_MiB(50))
cache = Cache.start_on_device(cache_device, cache_mode=cache_mode)
core_device = Volume(S.from_MiB(50))
core = Core.using_device(core_device)
cache.add_core(core)
write_data = DataCopyTracer(S.from_sector(1))
io = core.new_io(
cache.get_default_queue(),
S.from_sector(1).B,
write_data.size,
IoDir.WRITE,
0,
0,
)
io.set_data(write_data)
cmpl = OcfCompletion([("err", c_int)])
io.callback = cmpl.callback
io.submit()
cmpl.wait()
cmpls = []
for i in range(100):
read_data = DataCopyTracer(S.from_sector(1))
io = core.new_io(
cache.get_default_queue(),
i * S.from_sector(1).B,
read_data.size,
IoDir.READ,
0,
0,
)
io.set_data(read_data)
cmpl = OcfCompletion([("err", c_int)])
io.callback = cmpl.callback
cmpls.append(cmpl)
io.submit()
for c in cmpls:
c.wait()
write_data = DataCopyTracer.from_string("TEST DATA" * 100)
io = core.new_io(
cache.get_default_queue(), S.from_sector(1), write_data.size, IoDir.WRITE, 0, 0
)
io.set_data(write_data)
cmpl = OcfCompletion([("err", c_int)])
io.callback = cmpl.callback
io.submit()
cmpl.wait()
stats = cache.get_stats()
ctx.exit()
assert (
len(DataCopyTracer.needs_erase) == 0
), "Not all locked Data instances were secure erased!"
assert (
len(DataCopyTracer.locked_instances) == 0
), "Not all locked Data instances were unlocked!"
assert (
stats["req"]["rd_partial_misses"]["value"]
+ stats["req"]["rd_full_misses"]["value"]
) > 0
@pytest.mark.security
def test_secure_erase_simple_io_cleaning():
"""
Perform simple IO which will trigger WB cleaning. Track all the data from
cleaner (locked) and make sure they are erased and unlocked after use.
1. Start cache in WB mode
2. Write single sector at LBA 0
3. Read whole cache line at LBA 0
4. Assert that 3. triggered cleaning
5. Check if all locked Data copies were erased and unlocked
"""
ctx = OcfCtx(
OcfLib.getInstance(),
b"Security tests ctx",
DefaultLogger(LogLevel.WARN),
DataCopyTracer,
Cleaner,
)
ctx.register_volume_type(Volume)
cache_device = Volume(S.from_MiB(50))
cache = Cache.start_on_device(cache_device, cache_mode=CacheMode.WB)
core_device = Volume(S.from_MiB(100))
core = Core.using_device(core_device)
cache.add_core(core)
read_data = Data(S.from_sector(1).B)
io = core.new_io(
cache.get_default_queue(), S.from_sector(1).B, read_data.size, IoDir.WRITE, 0, 0
)
io.set_data(read_data)
cmpl = OcfCompletion([("err", c_int)])
io.callback = cmpl.callback
io.submit()
cmpl.wait()
read_data = Data(S.from_sector(8).B)
io = core.new_io(
cache.get_default_queue(), S.from_sector(1).B, read_data.size, IoDir.READ, 0, 0
)
io.set_data(read_data)
cmpl = OcfCompletion([("err", c_int)])
io.callback = cmpl.callback
io.submit()
cmpl.wait()
stats = cache.get_stats()
ctx.exit()
assert (
len(DataCopyTracer.needs_erase) == 0
), "Not all locked Data instances were secure erased!"
assert (
len(DataCopyTracer.locked_instances) == 0
), "Not all locked Data instances were unlocked!"
assert (stats["usage"]["clean"]["value"]) > 0, "Cleaner didn't run!"