Merge pull request #873 from mmichal10/fix-detach-cmpl

Fix detach cmpl
This commit is contained in:
Robert Baldyga 2025-03-27 08:59:32 +01:00 committed by GitHub
commit c7e47e226a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 239 additions and 10 deletions

View File

@ -1,6 +1,6 @@
/* /*
* Copyright(c) 2012-2022 Intel Corporation * Copyright(c) 2012-2022 Intel Corporation
* Copyright(c) 2024 Huawei Technologies * Copyright(c) 2024-2025 Huawei Technologies
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*/ */
#include "ocf/ocf.h" #include "ocf/ocf.h"
@ -33,7 +33,10 @@ int ocf_d2c_io_fast(struct ocf_request *req)
{ {
OCF_DEBUG_TRACE(req->cache); OCF_DEBUG_TRACE(req->cache);
/* Get OCF request - increase reference counter */ /* Increase reference counter - once for submission and second time to
* avoid freeing the request before updating stats
*/
ocf_req_get(req);
ocf_req_get(req); ocf_req_get(req);
ocf_engine_forward_core_io_req(req, _ocf_d2c_completion); ocf_engine_forward_core_io_req(req, _ocf_d2c_completion);
@ -46,6 +49,8 @@ int ocf_d2c_io_fast(struct ocf_request *req)
ocf_core_stats_request_pt_update(req->core, req->part_id, req->rw, ocf_core_stats_request_pt_update(req->core, req->part_id, req->rw,
req->info.hit_no, req->core_line_count); req->info.hit_no, req->core_line_count);
ocf_req_put(req);
return 0; return 0;
} }

View File

@ -3860,14 +3860,14 @@ static void ocf_mngt_cache_detach_finish(ocf_pipeline_t pipeline,
} }
_ocf_mngt_cache_set_detached(cache); _ocf_mngt_cache_set_detached(cache);
ocf_pipeline_destroy(cache->stop_pipeline);
cache->stop_pipeline = NULL;
} else { } else {
ocf_cache_log(cache, log_err, ocf_cache_log(cache, log_err,
"Detaching device failed\n"); "Detaching device failed\n");
} }
ocf_pipeline_destroy(cache->stop_pipeline);
cache->stop_pipeline = NULL;
context->cmpl(cache, context->priv, context->cmpl(cache, context->priv,
error ?: context->cache_write_error); error ?: context->cache_write_error);

View File

@ -170,11 +170,14 @@ static inline struct ocf_request *ocf_req_new_d2c(ocf_queue_t queue,
{ {
ocf_cache_t cache = ocf_core_get_cache(core); ocf_cache_t cache = ocf_core_get_cache(core);
struct ocf_request *req; struct ocf_request *req;
uint32_t request_size = 1;
req = env_mpool_new(cache->owner->resources.req, 1); req = env_mpool_new(cache->owner->resources.req, request_size);
if (unlikely(!req)) if (unlikely(!req))
return NULL; return NULL;
req->alloc_core_line_count = request_size;
ocf_req_init(req, cache, queue, core, addr, bytes, rw); ocf_req_init(req, cache, queue, core, addr, bytes, rw);
req->d2c = true; req->d2c = true;

View File

@ -1,6 +1,6 @@
# #
# Copyright(c) 2019-2022 Intel Corporation # Copyright(c) 2019-2022 Intel Corporation
# Copyright(c) 2024 Huawei Technologies # Copyright(c) 2024-2025 Huawei Technologies
# SPDX-License-Identifier: BSD-3-Clause # SPDX-License-Identifier: BSD-3-Clause
# #
@ -182,6 +182,17 @@ class Core:
if c.results["error"]: if c.results["error"]:
raise OcfError("Couldn't flush cache", c.results["error"]) raise OcfError("Couldn't flush cache", c.results["error"])
def detach(self):
self.cache.write_lock()
c = OcfCompletion([("priv", c_void_p), ("error", c_int)])
self.cache.owner.lib.ocf_mngt_cache_detach_core(self.handle, c, None)
c.wait()
self.cache.write_unlock()
if c.results["error"]:
raise OcfError("Couldn't detach core", c.results["error"])
def reset_stats(self): def reset_stats(self):
lib.ocf_core_stats_initialize(self.handle) lib.ocf_core_stats_initialize(self.handle)
@ -207,3 +218,5 @@ lib.ocf_core_stats_initialize.argtypes = [c_void_p]
lib.ocf_core_stats_initialize.restype = c_void_p lib.ocf_core_stats_initialize.restype = c_void_p
lib.ocf_mngt_core_flush.argtypes = [c_void_p, c_void_p, c_void_p] lib.ocf_mngt_core_flush.argtypes = [c_void_p, c_void_p, c_void_p]
lib.ocf_mngt_core_flush.restype = c_void_p lib.ocf_mngt_core_flush.restype = c_void_p
lib.ocf_mngt_cache_detach_core.argtypes = [c_void_p, c_void_p, c_void_p]
lib.ocf_mngt_cache_detach_core.restype = c_void_p

View File

@ -1,6 +1,6 @@
# #
# Copyright(c) 2019-2022 Intel Corporation # Copyright(c) 2019-2022 Intel Corporation
# Copyright(c) 2024 Huawei Technologies # Copyright(c) 2024-2025 Huawei Technologies
# SPDX-License-Identifier: BSD-3-Clause # SPDX-License-Identifier: BSD-3-Clause
# #
@ -8,7 +8,7 @@ import pytest
from ctypes import c_int from ctypes import c_int
from random import randint from random import randint
from pyocf.types.cache import Cache, CacheMode from pyocf.types.cache import Cache, CacheMode, CleaningPolicy, PromotionPolicy
from pyocf.types.core import Core from pyocf.types.core import Core
from pyocf.types.volume import RamVolume, Volume from pyocf.types.volume import RamVolume, Volume
from pyocf.types.volume_core import CoreVolume from pyocf.types.volume_core import CoreVolume
@ -16,7 +16,7 @@ from pyocf.types.data import Data
from pyocf.types.io import IoDir, Sync from pyocf.types.io import IoDir, Sync
from pyocf.types.queue import Queue from pyocf.types.queue import Queue
from pyocf.utils import Size as S from pyocf.utils import Size as S
from pyocf.types.shared import OcfError, OcfCompletion, CacheLineSize from pyocf.types.shared import OcfError, OcfErrorCode, OcfCompletion, CacheLineSize
@pytest.mark.parametrize("cache_mode", CacheMode) @pytest.mark.parametrize("cache_mode", CacheMode)
@ -89,6 +89,190 @@ def test_remove_dirty_no_flush(pyocf_ctx, cache_mode, cls):
cache.remove_core(core) cache.remove_core(core)
@pytest.mark.parametrize("cleaning_policy", CleaningPolicy)
@pytest.mark.parametrize("promotion_policy", PromotionPolicy)
def test_detach_core_detach_cache_cleaning(pyocf_ctx, cleaning_policy, promotion_policy):
cache_device = RamVolume(S.from_MiB(100))
core_device_1 = RamVolume(S.from_MiB(10))
core_device_2 = RamVolume(S.from_MiB(10))
cache = Cache.start_on_device(cache_device, cache_mode=CacheMode.WB)
core_1 = Core.using_device(core_device_1, name="core_1")
core_2 = Core.using_device(core_device_2, name="core_2")
cache.add_core(core_1)
cache.add_core(core_2)
cache.set_cleaning_policy(cleaning_policy)
cache.set_promotion_policy(promotion_policy)
core_1.detach()
with pytest.raises(OcfError, match="OCF_ERR_CACHE_IN_INCOMPLETE_STATE"):
cache.detach_device()
@pytest.mark.parametrize("cleaning_policy", CleaningPolicy)
@pytest.mark.parametrize("promotion_policy", PromotionPolicy)
def test_detach_core_stop_cache_cleaning(pyocf_ctx, cleaning_policy, promotion_policy):
cache_device = RamVolume(S.from_MiB(100))
core_device_1 = RamVolume(S.from_MiB(10))
core_device_2 = RamVolume(S.from_MiB(10))
cache = Cache.start_on_device(cache_device, cache_mode=CacheMode.WB)
core_1 = Core.using_device(core_device_1, name="core_1")
core_2 = Core.using_device(core_device_2, name="core_2")
cache.add_core(core_1)
cache.add_core(core_2)
cache.set_cleaning_policy(cleaning_policy)
cache.set_promotion_policy(promotion_policy)
core_1.detach()
cache.stop()
@pytest.mark.parametrize("cleaning_policy", CleaningPolicy)
@pytest.mark.parametrize("promotion_policy", PromotionPolicy)
def test_detach_cache_detach_core_cleaning(pyocf_ctx, cleaning_policy, promotion_policy):
cache_device = RamVolume(S.from_MiB(100))
core_device_1 = RamVolume(S.from_MiB(10))
core_device_2 = RamVolume(S.from_MiB(10))
cache = Cache.start_on_device(cache_device, cache_mode=CacheMode.WB)
core_1 = Core.using_device(core_device_1, name="core_1")
core_2 = Core.using_device(core_device_2, name="core_2")
cache.add_core(core_1)
cache.add_core(core_2)
cache.set_cleaning_policy(cleaning_policy)
cache.set_promotion_policy(promotion_policy)
for core in [core_1, core_2]:
vol = CoreVolume(core)
queue = core.cache.get_default_queue()
core_size = core.get_stats()["size"]
data = Data(core_size.B)
_io_to_core(vol, queue, data)
core_1.detach()
cache.stop()
@pytest.mark.parametrize("cleaning_policy", CleaningPolicy)
@pytest.mark.parametrize("promotion_policy", PromotionPolicy)
def test_detach_cache_retach_core_cleaning(pyocf_ctx, cleaning_policy, promotion_policy):
cache_device = RamVolume(S.from_MiB(100))
core_device_1 = RamVolume(S.from_MiB(10))
core_device_2 = RamVolume(S.from_MiB(10))
cache = Cache.start_on_device(cache_device, cache_mode=CacheMode.WB)
core_1 = Core.using_device(core_device_1, name="core_1")
core_2 = Core.using_device(core_device_2, name="core_2")
def _write_cores(cores_list):
for core in cores_list:
vol = CoreVolume(core)
queue = core.cache.get_default_queue()
core_size = core.get_stats()["size"]
data = Data(core_size.B)
_io_to_core(vol, queue, data)
cache.add_core(core_1)
cache.add_core(core_2)
cache.set_cleaning_policy(cleaning_policy)
cache.set_promotion_policy(promotion_policy)
cache.detach_device()
core_1.detach()
_write_cores([core_2])
cache.attach_device(cache_device)
_write_cores([core_2])
cache.add_core(core_1, try_add=True)
_write_cores([core_1, core_2])
cache.stop()
@pytest.mark.parametrize("cleaning_policy", CleaningPolicy)
@pytest.mark.parametrize("promotion_policy", PromotionPolicy)
def test_reattach_cache_reattach_core_cleaning(pyocf_ctx, cleaning_policy, promotion_policy):
cache_device = RamVolume(S.from_MiB(100))
core_device_1 = RamVolume(S.from_MiB(10))
core_device_2 = RamVolume(S.from_MiB(10))
cache = Cache.start_on_device(cache_device, cache_mode=CacheMode.WB)
core_1 = Core.using_device(core_device_1, name="core_1")
core_2 = Core.using_device(core_device_2, name="core_2")
def _write_cores(cores_list):
for core in cores_list:
vol = CoreVolume(core)
queue = core.cache.get_default_queue()
core_size = core.get_stats()["size"]
data = Data(core_size.B)
_io_to_core(vol, queue, data)
cache.add_core(core_1)
cache.add_core(core_2)
cache.set_cleaning_policy(cleaning_policy)
cache.set_promotion_policy(promotion_policy)
cache.detach_device()
core_1.detach()
cache.add_core(core_1, try_add=True)
cache.attach_device(cache_device)
_write_cores([core_1, core_2])
cache.stop()
@pytest.mark.parametrize("cleaning_policy", CleaningPolicy)
@pytest.mark.parametrize("promotion_policy", PromotionPolicy)
def test_detach_cache_detach_core_load_cleaning(pyocf_ctx, cleaning_policy, promotion_policy):
cache_device = RamVolume(S.from_MiB(100))
core_device_1 = RamVolume(S.from_MiB(10))
core_device_2 = RamVolume(S.from_MiB(10))
cache = Cache.start_on_device(cache_device, cache_mode=CacheMode.WB)
core_1 = Core.using_device(core_device_1, name="core_1")
core_2 = Core.using_device(core_device_2, name="core_2")
cache.add_core(core_1)
cache.add_core(core_2)
cache.set_cleaning_policy(cleaning_policy)
cache.set_promotion_policy(promotion_policy)
core_1.detach()
cache.stop()
cache = Cache.load_from_device(cache_device)
def test_30add_remove(pyocf_ctx): def test_30add_remove(pyocf_ctx):
# Start cache device # Start cache device
cache_device = RamVolume(S.from_MiB(50)) cache_device = RamVolume(S.from_MiB(50))

View File

@ -85,6 +85,30 @@ def test_detach_cache_with_cleaning(pyocf_ctx, cleaning_policy):
cache.stop() cache.stop()
def test_d2c_io(pyocf_ctx):
cache_device = RamVolume(Size.from_MiB(100))
core_device_1 = RamVolume(Size.from_MiB(10))
cache = Cache.start_on_device(cache_device, cache_mode=CacheMode.WB)
core_1 = Core.using_device(core_device_1, name="core_1")
cache.add_core(core_1)
cache.detach_device()
vol = CoreVolume(core_1)
queue = core_1.cache.get_default_queue()
data = Data(4096)
vol.open()
io = vol.new_io(queue, 0, data.size, IoDir.WRITE, 0, 0)
io.set_data(data)
completion = Sync(io).submit()
vol.close()
assert completion.results["err"] == 0
def test_detach_cache_zero_superblock(pyocf_ctx): def test_detach_cache_zero_superblock(pyocf_ctx):
"""Check if superblock is zeroed after detach and the cache device can be reattached without """Check if superblock is zeroed after detach and the cache device can be reattached without
--force option. --force option.