Projects
Eulaceura:Mainline
ocf
_service:obs_scm:0002-ocf-overwrite-IO-path-of-...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:obs_scm:0002-ocf-overwrite-IO-path-of-OCF-while-reusing-metadata-.patch of Package ocf
From 6f553019521eda9eb01cdb4eade4770eefcc3d40 Mon Sep 17 00:00:00 2001 From: Kemeng Shi <shikemeng@huawei.com> Date: Tue, 10 Jan 2023 23:21:25 +0800 Subject: [PATCH 2/4] ocf: overwrite IO path of OCF while reusing metadata and control We overwrite IO path of OCF for: 1. OCF is designed to run at different context while xcache is designed as part of HSAK, so we can remove adaptor cost in OCF and accelerate xcache by being aware of upper SPDK. 2. With a new IO path, it's more convinient to add some new framework like prefetch, qos and so on which may have confilict with original ocf code. 3. add evicting framework to support flexible eviction policy in future while a simple deadline policy is provided for temporal. Signed-off-by: Kemeng Shi <shikemeng@huawei.com> --- inc/ocf.h | 1 + inc/ocf_def.h | 1 + inc/xcache.h | 7 + inc/xcache_cleaner.h | 6 + inc/xcache_io.h | 74 ++++ src/engine/xcache_engine.c | 28 ++ src/engine/xcache_engine.h | 8 + src/engine/xcache_engine_common.c | 399 +++++++++++++++++++++ src/engine/xcache_engine_common.h | 153 ++++++++ src/engine/xcache_engine_flush.c | 140 ++++++++ src/engine/xcache_engine_flush.h | 25 ++ src/engine/xcache_engine_rd.c | 347 ++++++++++++++++++ src/engine/xcache_engine_rd.h | 6 + src/engine/xcache_engine_wb.c | 197 ++++++++++ src/engine/xcache_engine_wb.h | 6 + src/engine/xcache_engine_wt.c | 200 +++++++++++ src/engine/xcache_engine_wt.h | 6 + src/evicting/deadline.c | 172 +++++++++ src/evicting/deadline.h | 6 + src/evicting/evicting.c | 3 + src/evicting/evicting_helper.h | 32 ++ src/evicting/evicting_ops.h | 61 ++++ src/metadata/xcache_metadata.c | 88 +++++ src/metadata/xcache_metadata.h | 47 +++ src/mngt/ocf_mngt_cache.c | 11 + src/ocf_cache_priv.h | 1 + src/ocf_queue.c | 12 +- src/ocf_queue_priv.h | 2 + src/utils/utils_alock.c | 8 +- src/utils/utils_alock.h | 4 +- src/utils/utils_cache_line.c | 6 +- src/xcache.c | 29 ++ src/xcache.h | 55 +++ src/xcache_cleaner.c | 572 ++++++++++++++++++++++++++++++ src/xcache_cleaner.h | 69 ++++ src/xcache_lru.c | 199 +++++++++++ src/xcache_lru.h | 9 + src/xcache_ocf_core.c | 41 +++ src/xcache_queue.c | 315 ++++++++++++++++ src/xcache_queue.h | 29 ++ 40 files changed, 3364 insertions(+), 11 deletions(-) create mode 100644 inc/xcache.h create mode 100644 inc/xcache_cleaner.h create mode 100644 inc/xcache_io.h create mode 100644 src/engine/xcache_engine.c create mode 100644 src/engine/xcache_engine.h create mode 100644 src/engine/xcache_engine_common.c create mode 100644 src/engine/xcache_engine_common.h create mode 100644 src/engine/xcache_engine_flush.c create mode 100644 src/engine/xcache_engine_flush.h create mode 100644 src/engine/xcache_engine_rd.c create mode 100644 src/engine/xcache_engine_rd.h create mode 100644 src/engine/xcache_engine_wb.c create mode 100644 src/engine/xcache_engine_wb.h create mode 100644 src/engine/xcache_engine_wt.c create mode 100644 src/engine/xcache_engine_wt.h create mode 100644 src/evicting/deadline.c create mode 100644 src/evicting/deadline.h create mode 100644 src/evicting/evicting.c create mode 100644 src/evicting/evicting_helper.h create mode 100644 src/evicting/evicting_ops.h create mode 100644 src/metadata/xcache_metadata.c create mode 100644 src/metadata/xcache_metadata.h create mode 100644 src/xcache.c create mode 100644 src/xcache.h create mode 100644 src/xcache_cleaner.c create mode 100644 src/xcache_cleaner.h create mode 100644 src/xcache_lru.c create mode 100644 src/xcache_lru.h create mode 100644 src/xcache_ocf_core.c create mode 100644 src/xcache_queue.c create mode 100644 src/xcache_queue.h diff --git a/inc/ocf.h b/inc/ocf.h index 416d743..31137fc 100644 --- a/inc/ocf.h +++ b/inc/ocf.h @@ -32,5 +32,6 @@ #include "ocf_ctx.h" #include "ocf_err.h" #include "ocf_trace.h" +#include "xcache.h" #endif /* __OCF_H__ */ diff --git a/inc/ocf_def.h b/inc/ocf_def.h index 89fb2e0..3466c3f 100644 --- a/inc/ocf_def.h +++ b/inc/ocf_def.h @@ -332,6 +332,7 @@ typedef enum { */ #define OCF_READ 0 #define OCF_WRITE 1 +#define OCF_FLUSH 2 /** * @} */ diff --git a/inc/xcache.h b/inc/xcache.h new file mode 100644 index 0000000..1080ba8 --- /dev/null +++ b/inc/xcache.h @@ -0,0 +1,7 @@ +#ifndef XCACHE_H__ +#define XCACHE_H__ + +#include "xcache_io.h" +#include "xcache_cleaner.h" + +#endif diff --git a/inc/xcache_cleaner.h b/inc/xcache_cleaner.h new file mode 100644 index 0000000..88c2760 --- /dev/null +++ b/inc/xcache_cleaner.h @@ -0,0 +1,6 @@ +#ifndef XCACHE_CLEANER_H__ +#define XCACHE_CLEANER_H__ + +void xcache_cleaner_run(ocf_cleaner_t cleaner, ocf_queue_t queue); + +#endif diff --git a/inc/xcache_io.h b/inc/xcache_io.h new file mode 100644 index 0000000..a8acb67 --- /dev/null +++ b/inc/xcache_io.h @@ -0,0 +1,74 @@ +#ifndef XCACHE_IO_H__ +#define XCACHE_IO_H__ + +#include "ocf_env.h" + +enum entry_type { + XCACHE_IO_ENTRY, + XCACHE_BACKDEV_IO_ENTRY, + OCF_REQ_ENTRY, +}; + +struct queue_entry { + enum entry_type type; + struct list_head list; +}; + +#define INLINE_FLUSH_LINES 4 +struct xcache_io; +typedef void (*xcache_io_end_fn)(struct xcache_io *io, int error); +typedef int (*xcache_io_if)(struct xcache_io *io); +struct xcache_io { + // queue_entry + enum entry_type type; + struct list_head queue_list; + + xcache_io_end_fn end; + xcache_io_if io_if; + env_atomic remaining; + ctx_data_t *data; + int error; + + ocf_queue_t io_queue; + ocf_cache_t cache; + ocf_core_t core; + uint64_t start_addr; + uint64_t size; + uint8_t rw; + uint8_t flags; + + ocf_cache_line_t flush_lines[INLINE_FLUSH_LINES]; + uint64_t flush_line_num; +}; + +struct backdev_io_end_arg { + uint64_t addr; + uint64_t size; + int error; +}; +struct xcache_backdev_io; +typedef int (*backdev_io_end_fn)(struct xcache_backdev_io *io, struct backdev_io_end_arg *arg); +typedef void (*backdev_io_res_fn)(struct xcache_backdev_io *io); +struct xcache_backdev_io { + // queue_entry + enum entry_type type; + struct list_head free_list; + + struct xcache_io *xcache_io; + backdev_io_end_fn end; + + ocf_cache_line_t line; + ctx_data_t *data; + + backdev_io_res_fn io_res; + uint64_t addr; + uint64_t size; + + void *priv; +}; + +void xcache_backdev_io_end(struct xcache_backdev_io *bd_io, struct backdev_io_end_arg *arg); +void xcache_submit_io(struct xcache_io *io); +void spdk_backdev_submit_io(struct xcache_backdev_io *io_base, bool to_cache, uint64_t addr, uint64_t len, uint64_t offset, uint8_t dir); + +#endif diff --git a/src/engine/xcache_engine.c b/src/engine/xcache_engine.c new file mode 100644 index 0000000..089afa4 --- /dev/null +++ b/src/engine/xcache_engine.c @@ -0,0 +1,28 @@ +#include "ocf/ocf.h" + +#include "xcache_engine.h" +#include "xcache_engine_common.h" +#include "xcache_engine_rd.h" +#include "xcache_engine_wt.h" +#include "xcache_engine_wb.h" +#include "xcache_engine_flush.h" + +void xcache_get_io_if(struct xcache_io *io, ocf_cache_mode_t mode) +{ + if (io->rw == OCF_WRITE) { + switch (mode) { + case ocf_cache_mode_wb: + io->io_if = xcache_wb; + return; + case ocf_cache_mode_wt: + io->io_if = xcache_wt; + return; + default: + return; + } + } else if (io->rw == OCF_READ) { + io->io_if = xcache_read_generic; + } else { + io->io_if = xcache_flush; + } +} diff --git a/src/engine/xcache_engine.h b/src/engine/xcache_engine.h new file mode 100644 index 0000000..f20444a --- /dev/null +++ b/src/engine/xcache_engine.h @@ -0,0 +1,8 @@ +#ifndef __XCACHE_ENGINE_H_ +#define __XCACHE_ENGINE_H_ + +#include "ocf/xcache.h" + +void xcache_get_io_if(struct xcache_io *io, ocf_cache_mode_t mode); + +#endif diff --git a/src/engine/xcache_engine_common.c b/src/engine/xcache_engine_common.c new file mode 100644 index 0000000..f1bf022 --- /dev/null +++ b/src/engine/xcache_engine_common.c @@ -0,0 +1,399 @@ +#include "ocf/ocf.h" +#include "../ocf_cache_priv.h" +#include "../ocf_queue_priv.h" +#include "../utils/utils_cache_line.h" +#include "../metadata/metadata.h" + +#include "xcache_engine_common.h" +#include "../xcache_lru.h" +#include "../xcache_queue.h" +#include "../evicting/evicting_ops.h" + +uint64_t cache_line_to_addr(ocf_cache_t cache, ocf_cache_line_t line, uint64_t line_offset) +{ + uint64_t addr; + + addr = ocf_metadata_map_lg2phy(cache, line); + addr = xcache_line_to_addr(cache, addr); + addr += cache->device->metadata_offset; + addr += line_offset; + return addr; +} + +ocf_cache_line_t addr_to_cache_line(ocf_cache_t cache, uint64_t addr) +{ + ocf_cache_line_t line; + + addr -= cache->device->metadata_offset; + line = xcache_addr_to_line(cache, addr); + line = ocf_metadata_map_phy2lg(cache, line); + return line; +} + +ocf_cache_line_t xcache_engine_lookup_line(struct ocf_cache *cache, + ocf_core_id_t core_id, uint64_t core_line) +{ + ocf_cache_line_t line; + ocf_cache_line_t hash; + + hash = ocf_metadata_hash_func(cache, core_line, core_id); + line = ocf_metadata_get_hash(cache, hash); + + while (line != cache->device->collision_table_entries) { + ocf_core_id_t curr_core_id; + uint64_t curr_core_line; + + ocf_metadata_get_core_info(cache, line, &curr_core_id, + &curr_core_line); + + if (core_id == curr_core_id && curr_core_line == core_line) { + return line; + } + + line = ocf_metadata_get_collision_next(cache, line); + } + + return INVALID_LINE; +} + +void xcache_map_cache_line(struct xcache_io_context *ctx, + ocf_cache_line_t cache_line) +{ + ocf_cache_t cache = xcache_ctx_cache(ctx); + ocf_core_id_t core_id = ocf_core_get_id(xcache_ctx_core(ctx)); + unsigned int hash_index = ctx->hash; + uint64_t core_line = ctx->core_line; + + /* Add the block to the corresponding collision list */ + ocf_metadata_start_collision_shared_access(cache, cache_line); + ocf_metadata_add_to_collision(cache, core_id, core_line, hash_index, + cache_line); + ocf_metadata_end_collision_shared_access(cache, cache_line); +} + +static void xcache_engine_prepare_wait(void *io) +{ + struct xcache_backdev_io *base_io = (struct xcache_backdev_io *)io; + struct xcache_io *ocf_io = base_io->xcache_io; + + // avoid xcache_io finish when waiting for lock + xcache_io_get(ocf_io); +} + +static void xcache_engine_prepare_wake(void *io) +{ + struct xcache_backdev_io *base_io = (struct xcache_backdev_io *)io; + + xcache_queue_push_backdev_io_front(base_io, false); +} + +static void xcache_get_core_range(struct xcache_io_context *ctx, + uint64_t start_core_line, uint64_t end_core_line, + uint64_t *addr, uint64_t *size) +{ + struct xcache_io *io = ctx->io; + ocf_cache_t cache = xcache_ctx_cache(ctx); + uint64_t start_addr, end_addr, end; + + start_addr = xcache_io_start_addr(io); + end_addr = start_addr + xcache_io_size(io); + + *addr = xcache_line_to_addr(cache, start_core_line); + end = xcache_line_to_addr(cache, end_core_line); + + if (*addr < start_addr) { + *addr = start_addr; + } + if (end > end_addr) { + end = end_addr; + } + + *size = end - *addr; +} + +static inline int xcache_engine_lock_wr(struct xcache_io_context *ctx, struct ocf_alock *alock, + uint64_t core_line, ocf_cache_line_t line, + backdev_io_res_fn io_res) +{ + ocf_queue_t q = xcache_ctx_queue(ctx); + struct xcache_backdev_io *base_io = xcache_queue_alloc_backdev_io(q); + int ret; + + if (base_io == NULL) { + ocf_cache_log(xcache_ctx_cache(ctx), log_err, "alloc base io failed\n"); + return -ENOMEM; + } + + base_io->xcache_io = ctx->io; + base_io->line = line; + base_io->io_res = io_res; + base_io->data = ctx->io->data; + xcache_get_core_range(ctx, core_line, core_line + 1, &base_io->addr, &base_io->size); + + ret = xcache_lock_wr(alock, line, xcache_engine_prepare_wait, + xcache_engine_prepare_wake, base_io); + if (ret != OCF_LOCK_NOT_ACQUIRED) { + xcache_queue_free_backdev_io(q, base_io); + } + + return ret; +} + +static inline void xcache_hash_lock_rd(ocf_cache_t cache, ocf_cache_line_t hash, uint8_t lock_idx) +{ + ocf_metadata_start_shared_access(&cache->metadata.lock, + lock_idx); + ocf_hb_id_naked_lock(&cache->metadata.lock, hash, + OCF_METADATA_RD); +} + +static inline void xcache_hash_unlock_rd(ocf_cache_t cache, ocf_cache_line_t hash, uint8_t lock_idx) +{ + ocf_hb_id_naked_unlock(&cache->metadata.lock, hash, + OCF_METADATA_RD); + ocf_metadata_end_shared_access(&cache->metadata.lock, + lock_idx); +} + +static inline void xcache_hash_lock_upgrade(ocf_cache_t cache, ocf_cache_line_t hash) +{ + ocf_hb_id_naked_unlock(&cache->metadata.lock, hash, + OCF_METADATA_RD); + ocf_hb_id_naked_lock(&cache->metadata.lock, hash, + OCF_METADATA_WR); +} + +static inline void xcache_hash_unlock_wr(ocf_cache_t cache, ocf_cache_line_t hash, uint8_t lock_idx) +{ + ocf_hb_id_naked_unlock(&cache->metadata.lock, hash, + OCF_METADATA_WR); + ocf_metadata_end_shared_access(&cache->metadata.lock, + lock_idx); +} + +int xcache_engine_get_line(struct xcache_io_context *ctx, + uint64_t core_line, ocf_cache_line_t *line, + backdev_io_res_fn io_res) +{ + ocf_cache_t cache = xcache_ctx_cache(ctx); + ocf_core_t core = xcache_ctx_core(ctx); + ocf_queue_t q = xcache_ctx_queue(ctx); + ocf_core_id_t core_id = ocf_core_get_id(core); + unsigned lock_idx = ocf_metadata_concurrency_next_idx(q); + ocf_cache_line_t hash = ocf_metadata_hash_func(cache, core_line, core_id); + struct ocf_alock *alock = ocf_cache_line_concurrency(cache); + + int lock; + + xcache_hash_lock_rd(cache, hash, lock_idx); + *line = xcache_engine_lookup_line(cache, core_id, core_line); + if (*line != INVALID_LINE) { + lock = xcache_engine_lock_wr(ctx, alock, core_line, *line, io_res); + xcache_hash_unlock_rd(cache, hash, lock_idx); + goto found; + } + + xcache_hash_lock_upgrade(cache, hash); + *line = xcache_engine_lookup_line(cache, core_id, core_line); + if (unlikely(*line) != INVALID_LINE) { + lock = xcache_engine_lock_wr(ctx, alock, core_line, *line, io_res); + xcache_hash_unlock_wr(cache, hash, lock_idx); + goto found; + } + + ctx->core_line = core_line; + ctx->hash = hash; + *line = xcache_get_cline(ctx); + lock = OCF_LOCK_ACQUIRED; + xcache_hash_unlock_wr(cache, hash, lock_idx); + if (*line == INVALID_LINE) { + xcache_clean(ctx, 128); + return lock; + } + +found: + evicting_line_accessed(xcache_get_ctx(cache), *line); + return lock; +} + +void xcache_init_io_ctx(struct xcache_io_context *ctx, struct xcache_io *io) +{ + uint64_t addr = xcache_io_start_addr(io); + uint64_t size = xcache_io_size(io); + + ctx->io = io; + ctx->part_id = PARTITION_DEFAULT; + ctx->offset = 0; + ctx->start_miss_line = INVALID_CORE_LINE; + ctx->hit_no = 0; + ctx->cache_bytes = 0; + ctx->core_bytes = 0; + xcache_io_get_line_range(xcache_io_cache(io), addr, size, + &ctx->core_line_first, &ctx->core_line_last); +} + +void xcache_update_stat(struct xcache_io_context *ctx) +{ + struct xcache_io *io = ctx->io; + uint64_t len = xcache_io_size(io); + + ocf_core_stats_request_update(xcache_ctx_core(ctx), PARTITION_DEFAULT, + io->rw, ctx->hit_no, ctx->core_line_last - ctx->core_line_first + 1); + ocf_core_stats_vol_block_update(xcache_ctx_core(ctx), PARTITION_DEFAULT, + io->rw, len); + ocf_core_stats_core_block_update(xcache_ctx_core(ctx), PARTITION_DEFAULT, + io->rw, ctx->core_bytes); + ocf_core_stats_cache_block_update(xcache_ctx_core(ctx), PARTITION_DEFAULT, + io->rw, ctx->cache_bytes); +} + +static void xcache_queue_miss_line(struct xcache_io_context *ctx, uint64_t core_line) +{ + if (ctx->start_miss_line == INVALID_CORE_LINE) { + ctx->start_miss_line = core_line; + } +} + +static int xcache_submit_miss_line(struct xcache_io_context *ctx, uint64_t end_miss_line, xcache_line_miss_fn submit_func) +{ + struct xcache_io *io = ctx->io; + + struct xcache_backdev_io *base_io; + uint64_t start_addr, end_addr; + uint64_t addr, end; + + if (submit_func == NULL) { + ctx->start_miss_line = INVALID_CORE_LINE; + return 0; + } + + if (ctx->start_miss_line == INVALID_CORE_LINE) { + return 0; + } + + base_io = xcache_queue_alloc_backdev_io(xcache_ctx_queue(ctx)); + if (base_io == NULL) { + ocf_cache_log(xcache_ctx_cache(ctx), log_err, "alloc base io failed\n"); + io->error = -ENOMEM; + return -ENOMEM; + } + base_io->xcache_io = io; + base_io->data = io->data; + + start_addr = xcache_io_start_addr(io); + end_addr = start_addr + xcache_io_size(io); + addr = xcache_line_to_addr(xcache_ctx_cache(ctx), ctx->start_miss_line); + end = xcache_line_to_addr(xcache_ctx_cache(ctx), end_miss_line); + if (addr < start_addr) { + addr = start_addr; + } + if (end > end_addr) { + end = end_addr; + } + + submit_func(base_io, addr, end - addr, addr - start_addr); + + ctx->start_miss_line = INVALID_CORE_LINE; + return 0; +} + +int xcache_foreach_line(struct xcache_io_context *ctx, xcache_line_handle_func func, void *priv) +{ + int ret = 0; + struct xcache_io *io = ctx->io; + uint64_t start_addr = xcache_io_start_addr(io); + uint64_t len = xcache_io_size(io); + + uint64_t addr, line_end, line_size, size; + uint8_t start_sector, end_sector, line_sectors; + uint64_t core_line_first, core_line_last, core_line_cur; + + core_line_first = ctx->core_line_first; + core_line_last = ctx->core_line_last; + addr = start_addr; + line_size = ocf_line_size(xcache_ctx_cache(ctx)); + line_sectors = BYTES_TO_SECTORS(line_size); + line_end = xcache_line_to_addr(xcache_ctx_cache(ctx), core_line_first + 1); + start_sector = xcache_sector_offset(xcache_ctx_cache(ctx), BYTES_TO_SECTORS(addr)); + + for (core_line_cur = core_line_first; + core_line_cur <= core_line_last; + core_line_cur++) { + if (core_line_cur == core_line_last) { + end_sector = xcache_sector_offset(xcache_ctx_cache(ctx), BYTES_TO_SECTORS(start_addr + len - 1)); + size = start_addr + len - addr; + } else { + end_sector = line_sectors - 1; + size = line_end - addr; + } + + ret = func(priv, core_line_cur, + addr, size, start_sector, end_sector); + if (ret) { + io->error = ret; + break; + } + ctx->offset += size; + addr += size; + line_end += line_size; + start_sector = 0; + } + + return 0; +} + +static int xcache_handle_line(void *priv, + uint64_t core_line, uint64_t addr, uint64_t size, + uint8_t start_sector, uint8_t last_sector) +{ + struct xcache_io_handler *handler = (struct xcache_io_handler *)priv; + struct xcache_io_context *ctx = handler->ctx; + struct xcache_io *io = ctx->io; + ocf_cache_t cache = xcache_ctx_cache(ctx); + struct xcache_backdev_io *base_io; + ocf_cache_line_t line; + int lock; + + lock = xcache_engine_get_line(ctx, core_line, &line, handler->res_fn); + if (lock < 0) { + ocf_cache_log(cache, log_err, "try to wait for lock failed\n"); + return -ENOMEM; + } + + if (line == INVALID_LINE || (lock == OCF_LOCK_ACQUIRED && + handler->valid_fn != NULL && handler->valid_fn(cache, line, start_sector, last_sector))) { + xcache_queue_miss_line(ctx, core_line); + ctx->core_bytes += size; + return 0; + } + + xcache_submit_miss_line(ctx, core_line, handler->miss_fn); + ctx->hit_no++; + ctx->cache_bytes += size; + + if (lock == OCF_LOCK_NOT_ACQUIRED) { + return 0; + } + + base_io = xcache_queue_alloc_backdev_io(xcache_io_queue(io)); + if (base_io == NULL) { + ocf_cache_log(cache, log_err, "alloc base io failed\n"); + return -ENOMEM; + } + base_io->xcache_io = io; + base_io->data = io->data; + handler->hit_fn(base_io, line, SECTORS_TO_BYTES(start_sector), size, ctx->offset); + return 0; +} + +int xcache_handle_io(struct xcache_io_handler *handler) +{ + struct xcache_io_context *ctx = handler->ctx; + int ret; + + ret = xcache_foreach_line(ctx, xcache_handle_line, (void *)handler); + if (ret != 0) { + return ret; + } + return xcache_submit_miss_line(ctx, ctx->core_line_last + 1, handler->miss_fn); +} diff --git a/src/engine/xcache_engine_common.h b/src/engine/xcache_engine_common.h new file mode 100644 index 0000000..3fc168d --- /dev/null +++ b/src/engine/xcache_engine_common.h @@ -0,0 +1,153 @@ +#ifndef XCACHE_ENGINE_COMMON_H_ +#define XCACHE_ENGINE_COMMON_H_ + +#include "../ocf_cache_priv.h" +#include "../utils/utils_cache_line.h" + +#include "../xcache.h" + +#define INVALID_CORE_LINE ((uint64_t)-1) +#define INVALID_LINE ((ocf_cache_line_t)-1) + +struct xcache_io_context { + struct xcache_io *io; + ocf_queue_t queue; + ocf_part_id_t part_id; + uint64_t offset; + uint64_t core_line_first; + uint64_t core_line_last; + uint64_t core_line; + ocf_cache_line_t hash; + + uint64_t start_miss_line; + + uint64_t hit_no; + uint64_t cache_bytes; + uint64_t core_bytes; +}; + +static inline uint8_t xcache_addr_offset(ocf_cache_t cache, uint64_t addr) +{ + return addr & (ocf_line_size(cache) - 1); +} + +static inline uint8_t xcache_sector_offset(ocf_cache_t cache, uint64_t sector) +{ + return sector & (ocf_line_sectors(cache) - 1); +} + +static inline void xcache_io_get_line_range(ocf_cache_t cache, uint64_t addr, uint64_t size, + uint64_t *line_first, uint64_t *line_last) +{ + *line_first = xcache_addr_to_line(cache, addr); + *line_last = xcache_addr_to_line(cache, addr + size - 1); +} + +ocf_cache_line_t xcache_engine_lookup_line(struct ocf_cache *cache, + ocf_core_id_t core_id, uint64_t core_line); +int xcache_engine_get_line(struct xcache_io_context *ctx, + uint64_t core_line, ocf_cache_line_t *line, + backdev_io_res_fn io_res); + +void xcache_map_cache_line(struct xcache_io_context *ctx, + ocf_cache_line_t cache_line); + +uint64_t cache_line_to_addr(ocf_cache_t cache, ocf_cache_line_t line, uint64_t line_offset); +ocf_cache_line_t addr_to_cache_line(ocf_cache_t cache, uint64_t addr); + +typedef int (*xcache_line_handle_func)(void *priv, + uint64_t core_line, uint64_t addr, uint64_t size, + uint8_t start_sector, uint8_t last_sector); + +void xcache_init_io_ctx(struct xcache_io_context *ctx, struct xcache_io *io); +int xcache_foreach_line(struct xcache_io_context *ctx, xcache_line_handle_func func, void *priv); +void xcache_update_stat(struct xcache_io_context *ctx); + +static inline uint64_t xcache_io_start_addr(struct xcache_io *io) +{ + return io->start_addr; +} + +static inline uint64_t xcache_io_size(struct xcache_io *io) +{ + return io->size; +} + +static inline uint8_t xcache_io_flags(struct xcache_io *io) +{ + return io->flags; +} + +static inline ocf_core_t xcache_io_core(struct xcache_io *io) +{ + return io->core; +} + +static inline ocf_cache_t xcache_io_cache(struct xcache_io *io) +{ + return io->cache; +} + +static inline ocf_queue_t xcache_io_queue(struct xcache_io *io) +{ + return io->io_queue; +} + +static inline ocf_core_t xcache_ctx_core(struct xcache_io_context *ctx) +{ + return xcache_io_core(ctx->io); +} + +static inline ocf_cache_t xcache_ctx_cache(struct xcache_io_context *ctx) +{ + return xcache_io_cache(ctx->io); +} + +static inline ocf_queue_t xcache_ctx_queue(struct xcache_io_context *ctx) +{ + return xcache_io_queue(ctx->io); +} + +typedef int (*xcache_line_valid_fn)(ocf_cache_t cache, ocf_cache_line_t line, + uint8_t start_sector, uint8_t last_sector); +typedef int (*xcache_line_hit_fn)(struct xcache_backdev_io *base_io, ocf_cache_line_t line, + uint64_t offset, uint64_t size, uint64_t buf_offset); +typedef int (*xcache_line_miss_fn)(struct xcache_backdev_io *base_io, uint64_t addr, + uint64_t size, uint64_t buf_offset); + +struct xcache_io_handler { + struct xcache_io_context *ctx; + xcache_line_valid_fn valid_fn; + xcache_line_hit_fn hit_fn; + xcache_line_miss_fn miss_fn; + backdev_io_res_fn res_fn; +}; +int xcache_handle_io(struct xcache_io_handler *handler); + +static inline void xcache_io_get(struct xcache_io *io) +{ + env_atomic_inc_return(&io->remaining); +} + +static inline void xcache_io_end(struct xcache_io *io, int error) +{ + if (io->end) + io->end(io, error); + +} + +static inline void xcache_io_put(struct xcache_io *io) +{ + if (env_atomic_dec_return(&io->remaining)) + return; + + xcache_io_end(io, io->error); +} + +static inline void xcache_backdev_submit_io(struct xcache_backdev_io *io_base, bool cached, uint64_t addr, uint64_t size, uint64_t buf_offset, uint8_t dir) +{ + struct xcache_io *io = io_base->xcache_io; + xcache_io_get(io); + spdk_backdev_submit_io(io_base, cached, addr, size, buf_offset, dir); +} +#endif /* XCACHE_ENGINE_COMMON_H_ */ diff --git a/src/engine/xcache_engine_flush.c b/src/engine/xcache_engine_flush.c new file mode 100644 index 0000000..6aaf28a --- /dev/null +++ b/src/engine/xcache_engine_flush.c @@ -0,0 +1,140 @@ +#include "ocf/ocf.h" +#include "../ocf_cache_priv.h" +#include "../ocf_queue_priv.h" +#include "../xcache_queue.h" + +#include "xcache_engine_common.h" +#include "xcache_engine_flush.h" + +env_atomic g_need_flush = 0; + +static inline int xcache_do_flush(struct xcache_io *io); + +static inline int xcache_push_flush_io(struct xcache_io *io) +{ + ocf_queue_t q = xcache_io_queue(io); + struct xcache_queue_ctx *queue_ctx = xcache_get_queue_ctx(q); + + INIT_LIST_HEAD(&io->queue_list); + list_add_tail(&io->queue_list, &queue_ctx->flush_io_list); + env_atomic_inc(&queue_ctx->flush_io_no); + return env_atomic_read(&queue_ctx->flush_io_no); +} + +static inline struct xcache_io *xcache_pop_flush_io(ocf_queue_t q) +{ + struct xcache_queue_ctx *queue_ctx = xcache_get_queue_ctx(q); + struct xcache_io *flush_io = list_first_entry(&queue_ctx->flush_io_list, + struct xcache_io, queue_list); + + env_atomic_dec(&queue_ctx->flush_io_no); + list_del(&flush_io->queue_list); + + return flush_io; +} + +static void xcache_flush_finish(struct xcache_io *io) +{ + ocf_queue_t q = io->io_queue; + struct xcache_queue_ctx *queue_ctx = xcache_get_queue_ctx(q); + struct xcache_io *finish_io; + struct xcache_io *flush_io; + + for (finish_io = xcache_pop_flush_io(q); + finish_io != io; + finish_io = xcache_pop_flush_io(q)) + { + xcache_io_put(finish_io); + } + xcache_io_put(io); + + if (env_atomic_read(&queue_ctx->flush_io_no) != 0) { + flush_io = list_entry(queue_ctx->flush_io_list.prev, struct xcache_io, queue_list); + xcache_do_flush(flush_io); + } +} + +static int xcache_flush_cb(struct xcache_backdev_io *base_io, struct backdev_io_end_arg *cb_arg) +{ + struct xcache_io *io = base_io->xcache_io; + ocf_cache_t cache = xcache_io_cache(io); + + if (cb_arg->error != 0) { + ocf_cache_log(cache, log_err, "flush with error %d\n", cb_arg->error); + io->error = cb_arg->error; + } + xcache_queue_free_backdev_io(xcache_io_queue(io), base_io); + + if (env_atomic_read(&io->remaining) == 2) { + xcache_flush_finish(io); + } + return 0; +} + +static int xcache_flush_core(struct xcache_io *io) +{ + uint64_t addr = xcache_io_start_addr(io); + uint64_t size = xcache_io_size(io); + ocf_cache_t cache = xcache_io_cache(io); + struct xcache_backdev_io *base_io = NULL; + + base_io = xcache_queue_alloc_backdev_io(xcache_io_queue(io)); + if (base_io == NULL) { + ocf_cache_log(cache, log_err, "alloc base io failed\n"); + return -ENOMEM; + } + + base_io->xcache_io = io; + base_io->end = xcache_flush_cb; + xcache_backdev_submit_io(base_io, false, addr, size, 0, OCF_FLUSH); + return 0; +} + +static int xcache_flush_cache(struct xcache_io *io) +{ + ocf_cache_t cache = xcache_io_cache(io); + struct xcache_backdev_io *base_io = NULL; + + base_io = xcache_queue_alloc_backdev_io(xcache_io_queue(io)); + if (base_io == NULL) { + ocf_cache_log(cache, log_err, "alloc base io failed\n"); + return -ENOMEM; + } + + base_io->xcache_io = io; + base_io->end = xcache_flush_cb; + xcache_backdev_submit_io(base_io, true, 0, 0, 0, OCF_FLUSH); + return 0; +} + +static inline int xcache_do_flush(struct xcache_io *io) +{ + if (xcache_flush_core(io) != 0) { + io->error = -ENOMEM; + return -ENOMEM; + } + + if (xcache_flush_cache(io) != 0) { + io->error = -ENOMEM; + return -ENOMEM; + } + + return 0; +} + +int xcache_flush(struct xcache_io *io) +{ + io->error = 0; + + if (!need_flush()) { + return 0; + } + clear_flush(); + + xcache_io_get(io); + if (xcache_push_flush_io(io) != 1) { + return 0; + } + + return xcache_do_flush(io); +} diff --git a/src/engine/xcache_engine_flush.h b/src/engine/xcache_engine_flush.h new file mode 100644 index 0000000..91738d8 --- /dev/null +++ b/src/engine/xcache_engine_flush.h @@ -0,0 +1,25 @@ +#ifndef XCACHE_ENGINE_FLUSH_H_ +#define XCACHE_ENGINE_FLUSH_H_ + +#include "ocf/ocf.h" + +extern env_atomic g_need_flush; + +static inline void mark_flush(void) +{ + env_atomic_set(&g_need_flush, 1); +} + +static inline void clear_flush(void) +{ + env_atomic_set(&g_need_flush, 0); +} + +static inline bool need_flush(void) +{ + return (env_atomic_read(&g_need_flush) == 1); +} + +int xcache_flush(struct xcache_io *io); + +#endif diff --git a/src/engine/xcache_engine_rd.c b/src/engine/xcache_engine_rd.c new file mode 100644 index 0000000..ffe06d2 --- /dev/null +++ b/src/engine/xcache_engine_rd.c @@ -0,0 +1,347 @@ +#include "ocf/ocf.h" +#include "../ocf_cache_priv.h" +#include "../concurrency/ocf_concurrency.h" +#include "../utils/utils_cache_line.h" +#include "../metadata/metadata.h" +#include "../ocf_def_priv.h" + +#include "../xcache.h" +#include "xcache_engine_rd.h" +#include "xcache_engine_common.h" +#include "../xcache_queue.h" + +static void xcache_read_bf_done(ocf_cache_t cache, struct xcache_backdev_io *base_io) +{ + xcache_unlock_wr(ocf_cache_line_concurrency(cache), base_io->line); + xcache_queue_free_backdev_io(xcache_io_queue(base_io->xcache_io), base_io); +} + +static int xcache_read_bf_cb(struct xcache_backdev_io *base_io, struct backdev_io_end_arg *cb_arg) +{ + struct xcache_io *bf_io = base_io->xcache_io; + ocf_cache_t cache = xcache_io_cache(bf_io); + ocf_core_t core = xcache_io_core(bf_io); + + if (cb_arg->error) { + ocf_cache_log(cache, log_err, "read bf failed\n"); + ocf_core_stats_cache_error_update(core, OCF_WRITE); + } + if (env_atomic_read(&bf_io->remaining) == 1) { + ctx_data_free(cache->owner, base_io->data); + } + base_io->data = NULL; + xcache_read_bf_done(cache, base_io); + return 0; +} + +static int xcache_read_bf_update_metadata(struct xcache_backdev_io *base_io, uint64_t addr, uint64_t size) +{ + ocf_core_t core = xcache_io_core(base_io->xcache_io); + ocf_cache_t cache = ocf_core_get_cache(core); + ocf_cache_line_t line = base_io->line; + ocf_part_id_t part_id = PARTITION_DEFAULT; + uint8_t start_sector = xcache_sector_offset(cache, BYTES_TO_SECTORS(addr)); + uint8_t end_sector = xcache_sector_offset(cache, BYTES_TO_SECTORS(addr + size - 1)); + + // set_cache_line_valid + ocf_metadata_start_collision_shared_access(cache, line); + if (unlikely(metadata_test_valid_sec(cache, line, start_sector, end_sector))) { + ocf_metadata_end_collision_shared_access(cache, line); + return -1; + } + + if (metadata_set_valid_sec_changed(cache, line, start_sector, end_sector)) { + /* + * Update the number of cached data for that core object + */ + env_atomic_inc(&core->runtime_meta->cached_clines); + env_atomic_inc(&core->runtime_meta-> + part_counters[part_id].cached_clines); + } + ocf_metadata_end_collision_shared_access(cache, line); + return 0; +} + +static ctx_data_t *xcache_get_bf_data(struct xcache_io *io, uint64_t addr, uint64_t size) +{ + ocf_cache_t cache = xcache_io_cache(io); + uint64_t start_byte = xcache_io_start_addr(io); + uint64_t from = addr - start_byte; + ctx_data_t *dst; + + dst = ctx_data_alloc(cache->owner, ((size + PAGE_SIZE - 1) / PAGE_SIZE)); + if (dst == NULL) { + return NULL; + } + + ctx_data_cpy(cache->owner, dst, io->data, 0, from, size); + return dst; +} + +static void xcache_free_bf_data(struct xcache_io *io, ctx_data_t *data) +{ + ocf_cache_t cache = xcache_io_cache(io); + + ctx_data_free(cache->owner, data); +} + +static int xcache_do_read_bf(struct xcache_backdev_io *base_io, uint64_t addr, uint64_t size, uint64_t buf_offset) +{ + struct xcache_io *bf_io = base_io->xcache_io; + ocf_cache_t cache = xcache_io_cache(bf_io); + ocf_cache_line_t line = base_io->line; + + int ret; + uint64_t cache_addr; + + ret = xcache_read_bf_update_metadata(base_io, addr, size); + if (ret != 0) { + goto out; + } + + cache_addr = cache_line_to_addr(cache, line, xcache_addr_offset(cache, addr)); + base_io->end = xcache_read_bf_cb; + xcache_backdev_submit_io(base_io, true, cache_addr, size, buf_offset, OCF_WRITE); + return 0; + +out: + xcache_read_bf_done(cache, base_io); + return ret; +} + +static void xcache_read_bf_error(struct xcache_io *io, uint64_t addr, uint64_t size) +{ + ocf_cache_t cache = xcache_io_cache(io); + ocf_core_t core = xcache_io_core(io); + ocf_core_id_t core_id = ocf_core_get_id(core); + struct ocf_alock *alock = ocf_cache_line_concurrency(cache); + + uint64_t core_line_first, core_line_last, core_line; + ocf_cache_line_t line; + + xcache_io_get_line_range(cache, addr, size, &core_line_first, &core_line_last); + for (core_line = core_line_first; core_line <= core_line_last; core_line++) { + line = xcache_engine_lookup_line(cache, core_id, core_line); + if (line != INVALID_LINE) { + xcache_unlock_wr(alock, line); + } + } + + ocf_core_stats_core_error_update(core, OCF_READ); +} + +static void bf_io_end(struct xcache_io *bf_io, int error) +{ + xcache_queue_free_xcache_io(bf_io->io_queue, bf_io); +} + +static struct xcache_io *xcache_get_bf_io(struct xcache_io *ori_io) +{ + struct xcache_io *bf_io = xcache_queue_alloc_xcache_io(ori_io->io_queue); + + if (bf_io == NULL) { + ocf_cache_log(xcache_io_cache(ori_io), log_err, "alloc bf io failed\n"); + return NULL; + } + bf_io->io_queue = ori_io->io_queue; + bf_io->cache = ori_io->cache; + bf_io->core = ori_io->core; + bf_io->error = 0; + bf_io->end = bf_io_end; + env_atomic_set(&bf_io->remaining, 1); + return bf_io; +} + +static void xcache_free_bf_io(struct xcache_io *bf_io) +{ + xcache_queue_free_xcache_io(bf_io->io_queue, bf_io); +} + +static void xcache_submit_read_bf(struct xcache_io *io, uint64_t addr, uint64_t size) +{ + ocf_cache_t cache = xcache_io_cache(io); + ocf_core_t core = xcache_io_core(io); + ocf_core_id_t core_id = ocf_core_get_id(core); + uint64_t line_size = ocf_line_size(cache); + bool bf_submit = false; + + uint64_t core_line_first, core_line_last, core_line; + ocf_cache_line_t line; + uint64_t bf_addr, bf_size; + struct xcache_backdev_io *base_io; + struct xcache_io *bf_io; + ctx_data_t *bf_data; + + bf_io = xcache_get_bf_io(io); + if (bf_io == NULL) { + ocf_cache_log(cache, log_err, "alloc bf_io failed\n"); + xcache_read_bf_error(io, addr, size); + return; + } + + bf_data = xcache_get_bf_data(io, addr, size); + if (bf_data == NULL) { + ocf_cache_log(cache, log_err, "alloc bf_data failed\n"); + xcache_free_bf_io(bf_io); + xcache_read_bf_error(io, addr, size); + return; + } + + xcache_io_get_line_range(cache, addr, size, &core_line_first, &core_line_last); + bf_addr = addr; + bf_size = xcache_line_to_addr(cache, core_line_first + 1) - bf_addr; + for (core_line = core_line_first; core_line <= core_line_last; + core_line++, bf_addr += bf_size, bf_size = line_size) { + if (core_line == core_line_last) { + bf_size = (addr + size) - bf_addr; + } + + line = xcache_engine_lookup_line(cache, core_id, core_line); + if (line == INVALID_LINE) { + continue; + } + + base_io = xcache_queue_alloc_backdev_io(xcache_io_queue(io)); + if (base_io == NULL) { + ocf_cache_log(cache, log_err, "alloc bf base_io failed\n"); + xcache_unlock_wr(ocf_cache_line_concurrency(cache), line); + continue; + } + base_io->xcache_io = bf_io; + base_io->line = line; + base_io->data = bf_data; + if (xcache_do_read_bf(base_io, bf_addr, bf_size, bf_addr - addr) == 0) { + bf_submit = true; + } + } + + if (!bf_submit) { + xcache_free_bf_data(io, bf_data); + } + xcache_io_put(bf_io); +} + +static int xcache_read_bf(struct xcache_backdev_io *parent_base_io, struct backdev_io_end_arg *cb_arg) +{ + struct xcache_io *io = parent_base_io->xcache_io; + + xcache_queue_free_backdev_io(xcache_io_queue(parent_base_io->xcache_io), parent_base_io); + + if (cb_arg->error) { + ocf_cache_log(xcache_io_cache(io), log_err, "read_miss failed with error %d\n", + cb_arg->error); + + xcache_read_bf_error(io, cb_arg->addr, cb_arg->size); + io->error = cb_arg->error; + return cb_arg->error; + } + + xcache_submit_read_bf(io, cb_arg->addr, cb_arg->size); + + return 0; +} + +static int xcache_read_miss(struct xcache_backdev_io *base_io, + uint64_t addr, uint64_t size, uint64_t buf_offset) +{ + base_io->end = xcache_read_bf; + + xcache_backdev_submit_io(base_io, false, addr, size, buf_offset, OCF_READ); + return 0; +} + +static int xcache_read_pt_cb(struct xcache_backdev_io *base_io, struct backdev_io_end_arg *cb_arg) +{ + struct xcache_io *io = base_io->xcache_io; + ocf_cache_t cache = xcache_io_cache(io); + ocf_core_t core = xcache_io_core(io); + + if (cb_arg->error) { + ocf_cache_log(cache, log_err, "read pt failed\n"); + ocf_core_stats_core_error_update(core, OCF_READ); + } + + xcache_queue_free_backdev_io(xcache_io_queue(base_io->xcache_io), base_io); + return 0; +} + +static int xcache_read_hit_cb(struct xcache_backdev_io *base_io, struct backdev_io_end_arg *cb_arg) +{ + struct xcache_io *io = base_io->xcache_io; + ocf_cache_t cache = xcache_io_cache(io); + ocf_core_t core = xcache_io_core(io); + ocf_cache_line_t line = base_io->line; + + if (cb_arg->error) { + ocf_cache_log(cache, log_err, "read hit failed\n"); + io->error = cb_arg->error; + ocf_core_stats_cache_error_update(core, OCF_READ); + } + xcache_unlock_wr(ocf_cache_line_concurrency(cache), line); + xcache_queue_free_backdev_io(xcache_io_queue(base_io->xcache_io), base_io); + return 0; +} + +static int xcache_read_hit(struct xcache_backdev_io *base_io, ocf_cache_line_t line, + uint64_t offset, uint64_t size, uint64_t buf_offset) +{ + struct xcache_io *io = base_io->xcache_io; + ocf_cache_t cache = xcache_io_cache(io); + uint64_t addr = cache_line_to_addr(cache, line, offset); + + base_io->end = xcache_read_hit_cb; + base_io->line = line; + + xcache_backdev_submit_io(base_io, true, addr, size, buf_offset, OCF_READ); + return 0; +} + +static void xcache_read_res(struct xcache_backdev_io *base_io) +{ + struct xcache_io *io = base_io->xcache_io; + ocf_cache_t cache = xcache_io_cache(io); + uint64_t start_addr = xcache_io_start_addr(io); + + uint8_t start_sector, last_sector; + uint64_t buf_offset = base_io->addr - start_addr; + + start_sector = BYTES_TO_SECTORS(xcache_addr_offset(cache, base_io->addr)); + last_sector = start_sector + BYTES_TO_SECTORS(base_io->size - 1); + + if (metadata_test_valid_sec(cache, base_io->line, start_sector, last_sector)) { + xcache_read_hit(base_io, base_io->line, SECTORS_TO_BYTES(start_sector), + base_io->size, buf_offset); + } else { + xcache_read_miss(base_io, base_io->addr, base_io->size, buf_offset); + } +} + +static int xcache_read_line_valid(ocf_cache_t cache, ocf_cache_line_t line, + uint8_t start_sector, uint8_t last_sector) +{ + return !metadata_test_valid_sec(cache, line, start_sector, last_sector); +} + +int xcache_read_generic(struct xcache_io *io) +{ + int ret; + struct xcache_io_context ctx; + struct xcache_io_handler read_handler = { + .ctx = &ctx, + .res_fn = xcache_read_res, + .valid_fn = xcache_read_line_valid, + .miss_fn = xcache_read_miss, + .hit_fn = xcache_read_hit, + }; + + xcache_init_io_ctx(&ctx, io); + + ret = xcache_handle_io(&read_handler); + if (ret != 0) { + io->error = ret; + return ret; + } + + xcache_update_stat(&ctx); + return 0; +} diff --git a/src/engine/xcache_engine_rd.h b/src/engine/xcache_engine_rd.h new file mode 100644 index 0000000..3b939d4 --- /dev/null +++ b/src/engine/xcache_engine_rd.h @@ -0,0 +1,6 @@ +#ifndef XCACHE_ENGINE_RD_H_ +#define XCACHE_ENGINE_RD_H_ + +int xcache_read_generic(struct xcache_io *io); + +#endif /* XCACHE_ENGINE_RD_H_ */ diff --git a/src/engine/xcache_engine_wb.c b/src/engine/xcache_engine_wb.c new file mode 100644 index 0000000..064f650 --- /dev/null +++ b/src/engine/xcache_engine_wb.c @@ -0,0 +1,197 @@ +#include "ocf/ocf.h" +#include "../ocf_cache_priv.h" +#include "../metadata/metadata.h" +#include "../utils/utils_cache_line.h" +#include "../concurrency/ocf_cache_line_concurrency.h" + +#include "xcache_engine_common.h" +#include "xcache_engine_wb.h" +#include "xcache_engine_flush.h" +#include "../xcache_queue.h" +#include "../metadata/xcache_metadata.h" + +static bool xcache_wb_update_metadata(ocf_cache_t cache, ocf_core_t core, + ocf_cache_line_t line, uint8_t start_sector, uint8_t last_sector) +{ + ocf_part_id_t part_id = PARTITION_DEFAULT; + struct ocf_part *part = &cache->user_parts[part_id].part; + bool need_flush = false; + + bool line_was_dirty; + + ocf_metadata_start_collision_shared_access(cache, line); + if (metadata_set_valid_sec_changed(cache, line, start_sector, last_sector)) { + env_atomic_inc(&core->runtime_meta->cached_clines); + env_atomic_inc(&core->runtime_meta-> + part_counters[part_id].cached_clines); + } + + if (metadata_set_dirty_sec_changed(cache, line, start_sector, last_sector, + &line_was_dirty)) { + if (!line_was_dirty) { + /* + * If this is first dirty cline set dirty timestamp + */ + if (!env_atomic64_read(&core->runtime_meta->dirty_since)) + env_atomic64_cmpxchg( + &core->runtime_meta->dirty_since, 0, + env_ticks_to_secs(env_get_tick_count())); + + /* + * Update the number of dirty cached data for that + * core object + */ + env_atomic_inc(&core->runtime_meta->dirty_clines); + + /* + * increment dirty clines statistic for given cline + */ + env_atomic_inc(&core->runtime_meta-> + part_counters[part_id].dirty_clines); + + need_flush = true; + } + } + ocf_metadata_end_collision_shared_access(cache, line); + return need_flush; +} + +static void xcache_wb_flush_metadata_end(void *flush_io, int error) +{ + struct xcache_io *io = (struct xcache_io *)flush_io; + ocf_cache_t cache = xcache_io_cache(io); + struct ocf_alock *lock = ocf_cache_line_concurrency(cache); + ocf_cache_line_t *flush_lines = xcache_io_get_flush_line(io); + uint64_t i; + + for (i = 0; i < io->flush_line_num; i++) { + xcache_unlock_wr(lock, flush_lines[i]); + } + xcache_io_free_flush_line(io); + + if (error) { + ocf_cache_log(cache, log_err, "wb flush metadata failed with error %d\n", error); + io->error = error; + } + + xcache_io_put(io); +} + +static int xcache_wb_hit_cb(struct xcache_backdev_io *base_io, struct backdev_io_end_arg *cb_arg) +{ + uint64_t addr = cb_arg->addr; + uint64_t len = cb_arg->size; + struct xcache_io *io = base_io->xcache_io; + ocf_core_t core = xcache_io_core(io); + ocf_cache_t cache = ocf_core_get_cache(core); + int ret = 0; + ocf_cache_line_t line = addr_to_cache_line(cache, addr); + + uint64_t offset; + uint8_t start_sector, last_sector; + + xcache_queue_free_backdev_io(xcache_io_queue(base_io->xcache_io), base_io); + + if (cb_arg->error) { + ocf_cache_log(cache, log_err, "wb write hit failed with error %d\n", cb_arg->error); + ret = cb_arg->error; + io->error = cb_arg->error; + ocf_core_stats_cache_error_update(core, OCF_WRITE); + goto out; + } + + offset = xcache_addr_offset(cache, addr); + start_sector = BYTES_TO_SECTORS(offset); + last_sector = BYTES_TO_SECTORS(offset + len - 1); + + if (xcache_wb_update_metadata(cache, core, line, start_sector, last_sector)) { + ret = xcache_io_add_flush_line(io, line); + if (ret != 0) { + ocf_cache_log(cache, log_err, "wb metadata add flush line failed with error %d\n", ret); + io->error = ret; + goto out; + } + if (xcache_metadata_should_flush(io)) { + xcache_io_metadata_flush(io, xcache_wb_flush_metadata_end); + } + return 0; + } + +out: + xcache_unlock_wr(ocf_cache_line_concurrency(cache), line); + return ret; +} + +static int xcache_wb_hit(struct xcache_backdev_io *base_io, ocf_cache_line_t line, + uint64_t offset, uint64_t size, uint64_t buf_offset) +{ + struct xcache_io *io = base_io->xcache_io; + ocf_cache_t cache = xcache_io_cache(io); + + uint64_t addr; + + addr = cache_line_to_addr(cache, line, offset); + base_io->end = xcache_wb_hit_cb; + xcache_backdev_submit_io(base_io, true, addr, size, buf_offset, OCF_WRITE); + return 0; +} + +static int xcache_wb_miss_cb(struct xcache_backdev_io *base_io, struct backdev_io_end_arg *cb_arg) +{ + struct xcache_io *io = base_io->xcache_io; + ocf_cache_t cache = xcache_io_cache(io); + ocf_core_t core = xcache_io_core(io); + + if (cb_arg->error != 0) { + ocf_cache_log(cache, log_err, "wb miss with error %d\n", cb_arg->error); + io->error = cb_arg->error; + ocf_core_stats_core_error_update(core, OCF_WRITE); + } + xcache_queue_free_backdev_io(xcache_io_queue(base_io->xcache_io), base_io); + return 0; +} + +static int xcache_wb_miss(struct xcache_backdev_io *base_io, uint64_t addr, + uint64_t size, uint64_t buf_offset) +{ + base_io->end = xcache_wb_miss_cb; + xcache_backdev_submit_io(base_io, false, addr, size, buf_offset, OCF_WRITE); + return 0; +} + +static void xcache_wb_res(struct xcache_backdev_io *base_io) +{ + struct xcache_io *io = base_io->xcache_io; + ocf_cache_t cache = xcache_io_cache(io); + uint64_t offset = xcache_addr_offset(cache, base_io->addr); + uint64_t start_addr = xcache_io_start_addr(io); + uint64_t buf_offset = base_io->addr - start_addr; + + xcache_wb_hit(base_io, base_io->line, offset, base_io->size, buf_offset); +} + +int xcache_wb(struct xcache_io *io) +{ + int ret; + struct xcache_io_context ctx; + struct xcache_io_handler wb_handler = { + .ctx = &ctx, + .res_fn = xcache_wb_res, + .valid_fn = NULL, + .miss_fn = xcache_wb_miss, + .hit_fn = xcache_wb_hit, + }; + + mark_flush(); + + io->flush_line_num = 0; + xcache_init_io_ctx(&ctx, io); + + ret = xcache_handle_io(&wb_handler); + if (ret != 0) { + return ret; + } + + xcache_update_stat(&ctx); + return 0; +} diff --git a/src/engine/xcache_engine_wb.h b/src/engine/xcache_engine_wb.h new file mode 100644 index 0000000..26dba02 --- /dev/null +++ b/src/engine/xcache_engine_wb.h @@ -0,0 +1,6 @@ +#ifndef XCACHE_ENGINE_WB_H_ +#define XCACHE_ENGINE_WB_H_ + +int xcache_wb(struct xcache_io *io); + +#endif /* XCACHE_ENGINE_WB_H_ */ diff --git a/src/engine/xcache_engine_wt.c b/src/engine/xcache_engine_wt.c new file mode 100644 index 0000000..234608d --- /dev/null +++ b/src/engine/xcache_engine_wt.c @@ -0,0 +1,200 @@ +#include "ocf/ocf.h" +#include "../ocf_cache_priv.h" +#include "../utils/utils_cache_line.h" +#include "../metadata/metadata.h" + +#include "xcache_engine_wt.h" +#include "xcache_engine_common.h" +#include "xcache_engine_flush.h" +#include "../xcache_queue.h" + +static void xcache_wt_udpate_metadata(ocf_cache_t cache, ocf_core_t core, + ocf_cache_line_t line, uint8_t start_sector, uint8_t last_sector) +{ + ocf_part_id_t part_id = PARTITION_DEFAULT; + struct ocf_part *part = &cache->user_parts[part_id].part; + + bool line_is_clean; + + ocf_metadata_start_collision_shared_access(cache, line); + if (metadata_set_valid_sec_changed(cache, line, start_sector, last_sector)) { + env_atomic_inc(&core->runtime_meta->cached_clines); + env_atomic_inc(&core->runtime_meta-> + part_counters[part_id].cached_clines); + } + + if (metadata_clear_dirty_sec_changed(cache, line, start_sector, last_sector, + &line_is_clean)) { + if (line_is_clean) { + /* + * Update the number of dirty cached data for that + * core object + */ + if (env_atomic_dec_and_test(&core->runtime_meta-> + dirty_clines)) { + /* + * If this is last dirty cline reset dirty + * timestamp + */ + env_atomic64_set(&core->runtime_meta-> + dirty_since, 0); + } + + /* + * decrement dirty clines statistic for given cline + */ + env_atomic_dec(&core->runtime_meta-> + part_counters[part_id].dirty_clines); + } + } + ocf_metadata_end_collision_shared_access(cache, line); +} + +static int xcache_wt_hit_core_cb(struct xcache_backdev_io *base_io, struct backdev_io_end_arg *cb_arg) +{ + struct xcache_io *io = base_io->xcache_io; + ocf_core_t core = xcache_io_core(io); + ocf_cache_t cache = ocf_core_get_cache(core); + int ret = 0; + + + if (cb_arg->error) { + ret = cb_arg->error; + ocf_cache_log(cache, log_err, "wt hit core failed with error %d\n", cb_arg->error); + io->error = cb_arg->error; + ocf_core_stats_core_error_update(core, OCF_WRITE); + } + + xcache_queue_free_backdev_io(xcache_io_queue(io), base_io); + return ret; +} + +static int xcache_wt_hit_cache_cb(struct xcache_backdev_io *base_io, struct backdev_io_end_arg *cb_arg) +{ + uint64_t addr = cb_arg->addr; + uint64_t len = cb_arg->size; + struct xcache_io *io = base_io->xcache_io; + ocf_cache_t cache = xcache_io_cache(io); + ocf_core_t core = xcache_io_core(io); + ocf_cache_line_t line = base_io->line; + int ret = 0; + + uint64_t offset; + uint8_t start_sector, last_sector; + + if (cb_arg->error != 0) { + ocf_cache_log(cache, log_err, "wt hit cache with error %d\n", cb_arg->error); + io->error = cb_arg->error; + ocf_core_stats_cache_error_update(core, OCF_WRITE); + ret = cb_arg->error; + goto out; + } + + offset = xcache_addr_offset(cache, addr); + start_sector = BYTES_TO_SECTORS(offset); + last_sector = BYTES_TO_SECTORS(offset + len - 1); + + xcache_wt_udpate_metadata(cache, core, line, start_sector, last_sector); + +out: + xcache_unlock_wr(ocf_cache_line_concurrency(cache), line); + xcache_queue_free_backdev_io(xcache_io_queue(base_io->xcache_io), base_io); + return ret; +} + +static int xcache_wt_hit_cache(struct xcache_backdev_io *base_io, ocf_cache_line_t line, + uint64_t offset, uint64_t size, uint64_t buf_offset) +{ + struct xcache_io *io = base_io->xcache_io; + ocf_cache_t cache = xcache_io_cache(io); + uint64_t addr = cache_line_to_addr(cache, line, offset); + + base_io->line = line; + base_io->end = xcache_wt_hit_cache_cb; + xcache_backdev_submit_io(base_io, true, addr, size, buf_offset, OCF_WRITE); + return 0; +} + +static inline int xcache_wt_hit(struct xcache_backdev_io *base_io, ocf_cache_line_t line, + uint64_t addr, uint64_t offset, uint64_t size, uint64_t buf_offset) +{ + return xcache_wt_hit_cache(base_io, line, offset, size, buf_offset); +} + +static void xcache_wt_res(struct xcache_backdev_io *base_io) +{ + struct xcache_io *io = base_io->xcache_io; + ocf_cache_t cache = xcache_io_cache(io); + uint64_t offset = xcache_addr_offset(cache, base_io->addr); + uint64_t start_addr = xcache_io_start_addr(io); + uint64_t buf_offset = base_io->addr - start_addr; + + xcache_wt_hit(base_io, base_io->line, base_io->addr, offset, base_io->size, buf_offset); +} + +static int xcache_wt_miss_cb(struct xcache_backdev_io *base_io, struct backdev_io_end_arg *cb_arg) +{ + struct xcache_io *io = base_io->xcache_io; + ocf_cache_t cache = xcache_io_cache(io); + ocf_core_t core = xcache_io_core(io); + + if (cb_arg->error != 0) { + ocf_cache_log(cache, log_err, "wt miss with error %d\n", cb_arg->error); + io->error = cb_arg->error; + ocf_core_stats_core_error_update(core, OCF_WRITE); + } + xcache_queue_free_backdev_io(xcache_io_queue(base_io->xcache_io), base_io); + return 0; +} + +static int xcache_wt_core(struct xcache_io_context *ctx) +{ + struct xcache_io *io = ctx->io; + uint64_t addr = xcache_io_start_addr(io); + uint64_t size = xcache_io_size(io); + ocf_cache_t cache = xcache_io_cache(io); + struct xcache_backdev_io *base_io = NULL; + + base_io = xcache_queue_alloc_backdev_io(xcache_io_queue(io)); + if (base_io == NULL) { + ocf_cache_log(cache, log_err, "alloc base io failed\n"); + return -ENOMEM; + } + base_io->xcache_io = io; + base_io->data = io->data; + base_io->end = xcache_wt_miss_cb; + xcache_backdev_submit_io(base_io, false, addr, size, 0, OCF_WRITE); + return 0; +} + +int xcache_wt(struct xcache_io *io) +{ + struct xcache_io_context ctx; + struct xcache_io_handler wt_handler = { + .ctx = &ctx, + .res_fn = xcache_wt_res, + .valid_fn = NULL, + .miss_fn = NULL, + .hit_fn = xcache_wt_hit_cache, + }; + int ret; + + mark_flush(); + + xcache_init_io_ctx(&ctx, io); + + if (xcache_wt_core(&ctx) != 0) { + io->error = -ENOMEM; + return -ENOMEM; + } + + ret = xcache_handle_io(&wt_handler); + if (ret != 0) { + io->error = ret; + return ret; + } + + ctx.core_bytes = xcache_io_size(io); + xcache_update_stat(&ctx); + return 0; +} diff --git a/src/engine/xcache_engine_wt.h b/src/engine/xcache_engine_wt.h new file mode 100644 index 0000000..d2cc7e7 --- /dev/null +++ b/src/engine/xcache_engine_wt.h @@ -0,0 +1,6 @@ +#ifndef XCACHE_ENGINE_WT_H_ +#define XCACHE_ENGINE_WT_H_ + +int xcache_wt(struct xcache_io *io); + +#endif /* XCACHE_ENGINE_WT_H_ */ diff --git a/src/evicting/deadline.c b/src/evicting/deadline.c new file mode 100644 index 0000000..0050faf --- /dev/null +++ b/src/evicting/deadline.c @@ -0,0 +1,172 @@ +#include <stdint.h> + +#include "deadline.h" +#include "evicting_ops.h" +#include "evicting_helper.h" +#include "../xcache.h" + +#define STALE_SECS 600 +#define EVICT_BUNCH 10 +#define CLEAN_BUNCH 32 + +struct deadline_ctrl { + uint32_t *access_tick; + uint64_t line_num; + xcache_line_t evict_iter_line; + xcache_line_t clean_iter_line; +}; + +struct deadline_iter { + xcache_line_t *lines; + int line_num; + int iter_bunch; + xcache_line_t *iter_start; + bool line_dirty; +}; + +static int deadline_init(xcache_context_t *ctx) +{ + struct deadline_ctrl *ctrl = env_malloc(sizeof(struct deadline_ctrl), 0); + + if (ctrl == NULL) { + return -1; + } + ctrl->line_num = evicting_line_num(ctx); + + ctrl->access_tick = env_zalloc(sizeof(uint32_t) * ctrl->line_num, 0); + if (ctrl->access_tick == NULL) { + goto alloc_tick_fail; + } + + ctrl->evict_iter_line = 0; + ctrl->clean_iter_line = 0; + xcache_set_evicting(ctx, (void *)ctrl); + return 0; + +alloc_tick_fail: + env_free(ctrl); + return -1; +} + +static void deadline_fini(xcache_context_t *ctx) +{ + struct deadline_ctrl *ctrl = (struct deadline_ctrl *)xcache_get_evicting(ctx); + + if (ctrl == NULL) { + return; + } + + xcache_set_evicting(ctx, NULL); + + if (ctrl->access_tick != NULL) { + env_free(ctrl->access_tick); + ctrl->access_tick = NULL; + } + + env_free(ctrl); +} + +static void deadline_line_accessed(xcache_context_t *ctx, xcache_line_t line) +{ + struct deadline_ctrl *ctrl = (struct deadline_ctrl *)xcache_get_evicting(ctx); + + ctrl->access_tick[line] = env_ticks_to_secs(env_get_tick_count()); +} + +static void deadline_line_dirty(xcache_context_t *ctx, xcache_line_t line) +{ + return; +} + +static void deadline_line_clean(xcache_context_t *ctx, xcache_line_t line) +{ + return; +} + +static int deadline_get_lines(xcache_context_t *ctx, struct deadline_iter *iter) +{ + struct deadline_ctrl *ctrl = xcache_get_evicting(ctx); + uint32_t stale = env_ticks_to_secs(env_get_tick_count()) - STALE_SECS; + uint64_t i, j; + xcache_line_t cline; + + j = 0; + for (i = 0, cline = *(iter->iter_start); + i < iter->iter_bunch; + i++, cline = (cline + 1) % ctrl->line_num) + { + if (ctrl->access_tick[cline] > stale) { + continue; + } + + if (!evicting_trylock_line(ctx, cline)) { + continue; + } + + if (evicting_test_dirty(ctx, cline) != iter->line_dirty) { + evicting_unlock_line(ctx, cline); + continue; + } + + iter->lines[j++] = cline; + if (j >= iter->line_num) { + *(iter->iter_start) = (cline + 1) % ctrl->line_num; + return j; + } + } + + *(iter->iter_start) = cline; + return j; +} + +static int deadline_line_to_clean(xcache_context_t *ctx, xcache_line_t *lines, int line_num) +{ + struct deadline_ctrl *ctrl = xcache_get_evicting(ctx); + + struct deadline_iter iter = { + .lines = lines, + .line_num = line_num, + .iter_bunch = CLEAN_BUNCH, + .iter_start = &(ctrl->clean_iter_line), + .line_dirty = true, + }; + return deadline_get_lines(ctx, &iter); +} + + +static int deadline_line_to_evict(xcache_context_t *ctx, xcache_line_t *lines, int line_num) +{ + struct deadline_ctrl *ctrl = xcache_get_evicting(ctx); + + struct deadline_iter iter = { + .lines = lines, + .line_num = line_num, + .iter_bunch = EVICT_BUNCH, + .iter_start = &(ctrl->evict_iter_line), + .line_dirty = false, + }; + return deadline_get_lines(ctx, &iter); +} + +static void deadline_destroy(xcache_context_t *ctx) +{ + struct deadline_ctrl *ctrl = (struct deadline_ctrl *)ctx->xcache_evicting; + + env_free(ctrl->access_tick); + env_free(ctrl); +} + +static struct evicting_policy_ops g_deadline_ops = { + .init = deadline_init, + .fini = deadline_fini, + .line_accessed = deadline_line_accessed, + .line_dirty = deadline_line_dirty, + .line_clean = deadline_line_clean, + .line_to_clean = deadline_line_to_clean, + .line_to_evict = deadline_line_to_evict, +}; + +void set_deadline_policy(void) +{ + evicting_set(&g_deadline_ops); +} diff --git a/src/evicting/deadline.h b/src/evicting/deadline.h new file mode 100644 index 0000000..887737b --- /dev/null +++ b/src/evicting/deadline.h @@ -0,0 +1,6 @@ +#ifndef DEADLINE_H_ +#define DEADLINE_H_ + +void set_deadline_policy(void); + +#endif diff --git a/src/evicting/evicting.c b/src/evicting/evicting.c new file mode 100644 index 0000000..542693f --- /dev/null +++ b/src/evicting/evicting.c @@ -0,0 +1,3 @@ +#include "evicting_ops.h" + +struct evicting_policy_ops *g_evicting_policy = NULL; diff --git a/src/evicting/evicting_helper.h b/src/evicting/evicting_helper.h new file mode 100644 index 0000000..e6defa1 --- /dev/null +++ b/src/evicting/evicting_helper.h @@ -0,0 +1,32 @@ +#ifndef EVICTING_HELPER_H_ +#define EVICTING_HELPER_H_ + +#include "../utils/utils_alock.h" +#include "../concurrency/ocf_cache_line_concurrency.h" +#include "../ocf_cache_priv.h" +#include "../metadata/metadata_status.h" + +static inline bool evicting_test_dirty(xcache_context_t *ctx, xcache_line_t line) +{ + return metadata_test_dirty(ctx->cache, line); +} + +static inline bool evicting_trylock_line(xcache_context_t *ctx, xcache_line_t line) +{ + struct ocf_alock *lock = ocf_cache_line_concurrency(ctx->cache); + + return ocf_alock_trylock_entry_wr(lock, line); +} + +static inline void evicting_unlock_line(xcache_context_t *ctx, xcache_line_t line) +{ + struct ocf_alock *lock = ocf_cache_line_concurrency(ctx->cache); + + xcache_unlock_wr(lock, line); +} + +static inline uint64_t evicting_line_num(xcache_context_t *ctx) +{ + return ctx->cache->device->collision_table_entries; +} +#endif diff --git a/src/evicting/evicting_ops.h b/src/evicting/evicting_ops.h new file mode 100644 index 0000000..bd9c3ec --- /dev/null +++ b/src/evicting/evicting_ops.h @@ -0,0 +1,61 @@ +#ifndef EVICTING_OPS_H_ +#define EVICTING_OPS_H_ + +#include <stddef.h> +#include "../xcache.h" + +struct evicting_policy_ops { + int (*init)(xcache_context_t *ctx); + void (*line_accessed)(xcache_context_t *ctx, xcache_line_t line); + void (*line_dirty)(xcache_context_t *ctx, xcache_line_t line); + void (*line_clean)(xcache_context_t *ctx, xcache_line_t line); + int (*line_to_clean)(xcache_context_t *ctx, xcache_line_t *lines, int line_num); + int (*line_to_evict)(xcache_context_t *ctx, xcache_line_t *lines, int line_num); + void (*fini)(xcache_context_t *ctx); +}; + +extern struct evicting_policy_ops *g_evicting_policy; + +static inline void evicting_set(struct evicting_policy_ops *policy) +{ + g_evicting_policy = policy; +} + +static inline void evicting_init(xcache_context_t *ctx) +{ + g_evicting_policy->init(ctx); +} + +static inline void evicting_line_accessed(xcache_context_t *ctx, xcache_line_t line) +{ + g_evicting_policy->line_accessed(ctx, line); +} + +static inline void evicting_line_dirty(xcache_context_t *ctx, xcache_line_t line) +{ + g_evicting_policy->line_dirty(ctx, line); +} + +static inline void evicting_line_clean(xcache_context_t *ctx, xcache_line_t line) +{ + g_evicting_policy->line_clean(ctx, line); +} + +static inline xcache_line_t evicting_line_to_clean(xcache_context_t *ctx, + xcache_line_t *lines, int line_num) +{ + return g_evicting_policy->line_to_clean(ctx, lines, line_num); +} + +static inline xcache_line_t evicting_line_to_evict(xcache_context_t *ctx, + xcache_line_t *lines, int line_num) +{ + return g_evicting_policy->line_to_evict(ctx, lines, line_num); +} + +static inline void evicting_fini(xcache_context_t *ctx) +{ + return g_evicting_policy->fini(ctx); +} + +#endif diff --git a/src/metadata/xcache_metadata.c b/src/metadata/xcache_metadata.c new file mode 100644 index 0000000..53f385c --- /dev/null +++ b/src/metadata/xcache_metadata.c @@ -0,0 +1,88 @@ +#include "ocf/ocf.h" + +#include "xcache_metadata.h" +#include "metadata.h" +#include "metadata_internal.h" +#include "../engine/xcache_engine_common.h" /* xcache_io_xxx */ +#include "../ocf_cache_priv.h" + +void xcache_metadata_flush_asynch(struct ocf_cache *cache, + struct ocf_metadata_io_context *io_ctx, + struct ocf_metadata_line_getter *line_getter) +{ + int result = 0; + struct ocf_metadata_ctrl *ctrl = NULL; + + ctrl = (struct ocf_metadata_ctrl *) cache->metadata.priv; + result |= ocf_metadata_raw_flush_do_asynch_common(cache, + &(ctrl->raw_desc[metadata_segment_collision]), + io_ctx, line_getter); + if (result) { + ocf_metadata_error(cache); + ocf_cache_log(cache, log_err, "Metadata Flush ERROR\n"); + } +} + +static inline bool is_power_of_two(uint64_t n) +{ + return (((n - 1) & n) == 0); +} + +int xcache_io_add_flush_line(struct xcache_io *io, ocf_cache_line_t line) +{ + ocf_cache_line_t *flush_lines; + int i; + + if (io->flush_line_num < INLINE_FLUSH_LINES) { + flush_lines = io->flush_lines; + } else if (is_power_of_two(io->flush_line_num)) { + flush_lines = env_malloc(sizeof(ocf_cache_line_t) * (io->flush_line_num << 1), 0); + if (flush_lines == NULL) { + return -ENOMEM; + } + for (i = 0; i < io->flush_line_num; i++) { + flush_lines[i] = io->flush_lines[i]; + } + *(ocf_cache_line_t **)io->flush_lines = flush_lines; + } else { + flush_lines = *(ocf_cache_line_t **)io->flush_lines; + } + + flush_lines[io->flush_line_num++] = line; + return 0; +} + +static int io_line_num(void *getter) +{ + struct xcache_io *io = (struct xcache_io *)getter; + + return io->flush_line_num; +} + +static bool io_flush_line(void *getter, int index, ocf_cache_line_t *line) +{ + struct xcache_io *io = (struct xcache_io *)getter; + ocf_cache_line_t *flush_lines; + + flush_lines = xcache_io_get_flush_line(io); + *line = io->flush_lines[index]; + return true; +} + +void xcache_io_metadata_flush(struct xcache_io *io, ocf_metadata_io_ctx_end_t io_end) +{ + struct ocf_metadata_io_context io_ctx = { + .io = (void *)io, + .io_flags = xcache_io_flags(io), + .io_end = io_end, + .queue = xcache_io_queue(io), + }; + struct ocf_metadata_line_getter line_getter = { + .getter = (void *)io, + .get_line_num = io_line_num, + .get_flush_line = io_flush_line, + }; + + xcache_io_get(io); + xcache_metadata_flush_asynch(xcache_io_cache(io), &io_ctx, &line_getter); +} diff --git a/src/metadata/xcache_metadata.h b/src/metadata/xcache_metadata.h new file mode 100644 index 0000000..e82580e --- /dev/null +++ b/src/metadata/xcache_metadata.h @@ -0,0 +1,47 @@ +#ifndef __XCACHE_METADATA_H__ +#define __XCACHE_METADATA_H__ + +#include "ocf/ocf.h" +#include "metadata_raw.h" + +#include "ocf/xcache.h" + +void xcache_metadata_flush_asynch(struct ocf_cache *cache, + struct ocf_metadata_io_context *io_ctx, + struct ocf_metadata_line_getter *line_getter); + +int xcache_io_add_flush_line(struct xcache_io *io, ocf_cache_line_t line); +static inline void xcache_io_free_flush_line(struct xcache_io *io) +{ + if (io->flush_line_num <= INLINE_FLUSH_LINES) { + return; + } + env_free(*(ocf_cache_line_t **)io->flush_lines); +} + +static inline ocf_cache_line_t *get_inline_flush_lines(struct xcache_io *io) +{ + return io->flush_lines; +} + +static inline ocf_cache_line_t *get_alloc_flush_lines(struct xcache_io *io) +{ + return *(ocf_cache_line_t **)io->flush_lines; +} + +static inline ocf_cache_line_t *xcache_io_get_flush_line(struct xcache_io *io) +{ + if (io->flush_line_num <= INLINE_FLUSH_LINES) { + return get_inline_flush_lines(io); + } else { + return get_alloc_flush_lines(io); + } +} + +static inline bool xcache_metadata_should_flush(struct xcache_io *io) +{ + return (env_atomic_read(&io->remaining) == 1); +} + +void xcache_io_metadata_flush(struct xcache_io *io, ocf_metadata_io_ctx_end_t io_end); +#endif diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index 54a2a67..591ffcd 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -124,6 +124,8 @@ struct ocf_cache_attach_context { */ bool concurrency_inited : 1; + + bool xcache_inited : 1; } flags; struct { @@ -975,6 +977,12 @@ static void _ocf_mngt_attach_prepare_metadata(ocf_pipeline_t pipeline, context->flags.attached_metadata_inited = true; + ret = xcache_init(cache); + if (ret != 0) { + OCF_PL_FINISH_RET(pipeline, ret); + } + context->flags.xcache_inited = 1; + ret = ocf_concurrency_init(cache); if (ret) OCF_PL_FINISH_RET(pipeline, ret); @@ -1126,6 +1134,9 @@ static void _ocf_mngt_attach_handle_error( if (context->flags.device_alloc) env_vfree(cache->device); + if (context->flags.xcache_inited) + xcache_fini(cache); + ocf_pipeline_destroy(cache->stop_pipeline); } diff --git a/src/ocf_cache_priv.h b/src/ocf_cache_priv.h index b0a6f77..07fcd63 100644 --- a/src/ocf_cache_priv.h +++ b/src/ocf_cache_priv.h @@ -139,6 +139,7 @@ struct ocf_cache { } __attribute__((aligned(64))); // This should be on it's own cacheline ideally env_atomic last_access_ms; + void *xcache_ctx; }; static inline ocf_core_t ocf_cache_get_core(ocf_cache_t cache, diff --git a/src/ocf_queue.c b/src/ocf_queue.c index a754d6e..b37ef0c 100644 --- a/src/ocf_queue.c +++ b/src/ocf_queue.c @@ -51,10 +51,16 @@ int ocf_queue_create(ocf_cache_t cache, ocf_queue_t *queue, return result; } - list_add(&tmp_queue->list, &cache->io_queues); + result = xcache_queue_ctx_init(tmp_queue); + if (result) { + ocf_queue_seq_cutoff_deinit(tmp_queue); + ocf_mngt_cache_put(cache); + env_free(tmp_queue); + return result; + } + list_add(&tmp_queue->list, &cache->io_queues); *queue = tmp_queue; - return 0; } @@ -91,7 +97,7 @@ void ocf_io_handle(struct ocf_io *io, void *opaque) req->io_if->read(req); } -void ocf_queue_run_single(ocf_queue_t q) +void __attribute__((weak)) ocf_queue_run_single(ocf_queue_t q) { struct ocf_request *io_req = NULL; diff --git a/src/ocf_queue_priv.h b/src/ocf_queue_priv.h index def5d08..62bf900 100644 --- a/src/ocf_queue_priv.h +++ b/src/ocf_queue_priv.h @@ -36,6 +36,8 @@ struct ocf_queue { env_atomic ref_count; env_spinlock io_list_lock; + + void *priv1; } __attribute__((__aligned__(64))); static inline void ocf_queue_kick(ocf_queue_t queue, bool allow_sync) diff --git a/src/utils/utils_alock.c b/src/utils/utils_alock.c index 183682a..7cecacf 100644 --- a/src/utils/utils_alock.c +++ b/src/utils/utils_alock.c @@ -800,7 +800,7 @@ uint32_t ocf_alock_waitlist_count(struct ocf_alock *alock) return env_atomic_read(&alock->waiting); } -int ocf_io_alock_lock_wr(struct ocf_alock *alock, +int xcache_lock_wr(struct ocf_alock *alock, const ocf_cache_line_t entry, ocf_io_lock_prepare_wait prepare_wait_fn, ocf_io_lock_prepare_wake prepare_wake_fn, @@ -847,7 +847,7 @@ unlock: return ret; } -static inline void ocf_io_alock_unlock_wr_common(struct ocf_alock *alock, +static inline void xcache_unlock_wr_common(struct ocf_alock *alock, const ocf_cache_line_t entry) { bool locked = false; @@ -909,7 +909,7 @@ static inline void ocf_io_alock_unlock_wr_common(struct ocf_alock *alock, } } -void ocf_io_alock_unlock_wr(struct ocf_alock *alock, +void xcache_unlock_wr(struct ocf_alock *alock, const ocf_cache_line_t entry) { unsigned long flags = 0; @@ -918,6 +918,6 @@ void ocf_io_alock_unlock_wr(struct ocf_alock *alock, /* Lock waiters list */ ocf_alock_waitlist_lock(alock, entry, flags); - ocf_io_alock_unlock_wr_common(alock, entry); + xcache_unlock_wr_common(alock, entry); ocf_alock_waitlist_unlock(alock, entry, flags); } diff --git a/src/utils/utils_alock.h b/src/utils/utils_alock.h index 3670c25..80188e3 100644 --- a/src/utils/utils_alock.h +++ b/src/utils/utils_alock.h @@ -89,13 +89,13 @@ bool ocf_alock_trylock_entry_rd_idle(struct ocf_alock *alock, typedef void (*ocf_io_lock_prepare_wait)(void *io); typedef void (*ocf_io_lock_prepare_wake)(void *io); -int ocf_io_alock_lock_wr(struct ocf_alock *alock, +int xcache_lock_wr(struct ocf_alock *alock, const ocf_cache_line_t entry, ocf_io_lock_prepare_wait prepare_wait_fn, ocf_io_lock_prepare_wake prepare_wake_fn, void *io); -void ocf_io_alock_unlock_wr(struct ocf_alock *alock, +void xcache_unlock_wr(struct ocf_alock *alock, const ocf_cache_line_t entry); #endif diff --git a/src/utils/utils_cache_line.c b/src/utils/utils_cache_line.c index 281ff59..bc58054 100644 --- a/src/utils/utils_cache_line.c +++ b/src/utils/utils_cache_line.c @@ -119,8 +119,10 @@ void set_cache_line_clean(struct ocf_cache *cache, uint8_t start_bit, */ env_atomic_dec(&req->core->runtime_meta-> part_counters[part_id].dirty_clines); - ocf_lru_clean_cline(cache, part, line); - ocf_purge_cleaning_policy(cache, line); + if (cache->xcache_ctx == NULL) { + ocf_lru_clean_cline(cache, part, line); + ocf_purge_cleaning_policy(cache, line); + } } } diff --git a/src/xcache.c b/src/xcache.c new file mode 100644 index 0000000..e8d1f2d --- /dev/null +++ b/src/xcache.c @@ -0,0 +1,29 @@ +#include "xcache.h" +#include "evicting/evicting_ops.h" +#include "evicting/deadline.h" +#include "utils/utils_cache_line.h" + +int xcache_init(ocf_cache_t cache) +{ + xcache_context_t *ctx = env_malloc(sizeof(xcache_context_t), 0); + + if (ctx == NULL) { + return -1; + } + + ctx->cache = cache; + cache->xcache_ctx = ctx; + + set_deadline_policy(); + evicting_init(ctx); + ctx->line_size_shift = __builtin_ffsll(ocf_line_size(cache)) - 1; + + return 0; +} + +void xcache_fini(ocf_cache_t cache) +{ + evicting_fini(cache->xcache_ctx); + env_free(cache->xcache_ctx); + cache->xcache_ctx = NULL; +} diff --git a/src/xcache.h b/src/xcache.h new file mode 100644 index 0000000..f31ec15 --- /dev/null +++ b/src/xcache.h @@ -0,0 +1,55 @@ +#ifndef XCACHE_H_ +#define XCACHE_H_ + +#include <stdint.h> +#include "ocf/ocf_types.h" +#include "./ocf_cache_priv.h" + +#include "xcache_cleaner.h" + +typedef ocf_cache_line_t xcache_line_t; + +typedef struct xcache_context { + uint8_t line_size_shift; + void *xcache_evicting; + ocf_cache_t cache; + struct xcache_cleaning_ctx cleaning_ctx; +} xcache_context_t; + +static inline xcache_context_t *xcache_get_ctx(ocf_cache_t cache) +{ + return cache->xcache_ctx; +} + +static inline void *xcache_get_evicting(xcache_context_t *ctx) +{ + return ctx->xcache_evicting; +} + +static inline void xcache_set_evicting(xcache_context_t *ctx, void *evicting) +{ + ctx->xcache_evicting = evicting; +} + +static inline uint64_t xcache_addr_to_line(ocf_cache_t cache, uint64_t addr) +{ + xcache_context_t *ctx = cache->xcache_ctx; + return addr >> ctx->line_size_shift; +} + +static inline uint64_t xcache_line_to_addr(ocf_cache_t cache, uint64_t line) +{ + xcache_context_t *ctx = cache->xcache_ctx; + return line << ctx->line_size_shift; +} + +static inline struct xcache_cleaning_ctx *xcache_get_cleaning_ctx(ocf_cache_t cache) +{ + xcache_context_t *xcache_ctx = cache->xcache_ctx; + return &xcache_ctx->cleaning_ctx; +} + +int xcache_init(ocf_cache_t cache); +void xcache_fini(ocf_cache_t cache); + +#endif diff --git a/src/xcache_cleaner.c b/src/xcache_cleaner.c new file mode 100644 index 0000000..5de3369 --- /dev/null +++ b/src/xcache_cleaner.c @@ -0,0 +1,572 @@ +#include "metadata/metadata.h" +#include "concurrency/ocf_concurrency.h" +#include "utils/utils_cleaner.h" +#include "utils/utils_cache_line.h" +#include "ocf_queue_priv.h" +#include "cleaning/cleaning.h" + +#include "ocf/xcache.h" + +#include "xcache_cleaner.h" +#include "xcache.h" +#include "engine/xcache_engine_common.h" +#include "xcache_queue.h" +#include "evicting/evicting_ops.h" +#include "metadata/xcache_metadata.h" + +static inline uint8_t get_first_sector(ocf_cache_t cache, ocf_cache_line_t line, uint8_t start_sector, bool dirty) +{ + uint8_t sector; + + for (sector = start_sector; sector < ocf_line_sectors(cache); sector++) { + if (metadata_test_dirty_one(cache, line, sector) == dirty) { + break; + } + } + return sector; +} + +static inline uint8_t get_first_clean_sector(ocf_cache_t cache, ocf_cache_line_t line, uint8_t start_sector) +{ + return get_first_sector(cache, line, start_sector, false); +} + +static inline uint8_t get_first_dirty_sector(ocf_cache_t cache, ocf_cache_line_t line, uint8_t start_sector) +{ + return get_first_sector(cache, line, start_sector, true); +} + +static inline void get_dirty_sectors(ocf_cache_t cache, ocf_cache_line_t line, + uint8_t *start_sector, uint8_t *end_sector) +{ + bool dirty; + + uint8_t sector = *start_sector; + uint8_t line_sectors = ocf_line_sectors(cache); + + // fast path + if (*start_sector == 0 && metadata_test_dirty_all(cache, line)) { + *end_sector = line_sectors - 1; + return; + } + + *start_sector = get_first_dirty_sector(cache, line, *start_sector); + if (*start_sector >= line_sectors) { + return; + } + + *end_sector = get_first_clean_sector(cache, line, *start_sector + 1) - 1; +} + +static inline void xcache_clean_unlock_line(struct xcache_cleaning_ctx *cleaning_ctx) +{ + struct clean_sort_data *data = cleaning_ctx->data; + struct ocf_alock *c = ocf_cache_line_concurrency(cleaning_ctx->cache); + int i; + + for (i = 0; i < cleaning_ctx->count; i++) { + xcache_unlock_wr(c, data[i].line); + } +} + +static inline void xcache_clean_cleanup(struct xcache_cleaning_ctx *cleaning_ctx) +{ + struct xcache_backdev_io *base_io = &cleaning_ctx->base_io; + ocf_cache_t cache = cleaning_ctx->cache; + + int i; + + if (base_io->data != NULL) { + ctx_data_free(cache->owner, base_io->data); + base_io->data = NULL; + } + + xcache_cleaner_complete(cleaning_ctx); +} + +static inline void xcache_clean_cb(struct xcache_cleaning_ctx *cleaning_ctx) +{ + if (cleaning_ctx->end) { + cleaning_ctx->end(cleaning_ctx->arg); + cleaning_ctx->end = NULL; + } +} + +static void xcache_clean_end(struct xcache_cleaning_ctx *cleaning_ctx) +{ + xcache_clean_unlock_line(cleaning_ctx); + xcache_clean_cleanup(cleaning_ctx); + xcache_clean_cb(cleaning_ctx); +} + +static void xcache_clean_update_metadata(ocf_cache_t cache, ocf_core_t core, + ocf_cache_line_t line) +{ + ocf_part_id_t part_id = PARTITION_DEFAULT; + struct ocf_part *part = &cache->user_parts[part_id].part; + + ocf_metadata_start_collision_shared_access(cache, line); + metadata_clear_dirty(cache, line); + + if (env_atomic_dec_and_test(&core->runtime_meta-> + dirty_clines)) { + env_atomic64_set(&core->runtime_meta-> + dirty_since, 0); + } + + env_atomic_dec(&core->runtime_meta-> + part_counters[part_id].dirty_clines); + ocf_metadata_end_collision_shared_access(cache, + line); +} + +static int clean_line_num(void *clean_io) +{ + struct xcache_cleaning_ctx *cleaning_ctx = (struct xcache_cleaning_ctx *)clean_io; + + return cleaning_ctx->count; +} + +static bool clean_flush_line(void *clean_io, int index, ocf_cache_line_t *line) +{ + struct xcache_cleaning_ctx *cleaning_ctx = (struct xcache_cleaning_ctx *)clean_io; + + *line = cleaning_ctx->data[index].line; + return true; +} + +static void xcache_clean_flush_metadata_end(void *clean_io, int error) +{ + struct xcache_cleaning_ctx *cleaning_ctx = (struct xcache_cleaning_ctx *)clean_io; + + xcache_clean_end(cleaning_ctx); +} + +static void xcache_clean_metadata_flush(struct xcache_cleaning_ctx *cleaning_ctx) +{ + struct xcache_io *io = &cleaning_ctx->io; + struct ocf_metadata_io_context io_ctx = { + .io = (void *)cleaning_ctx, + .io_flags = 0, + .io_end = xcache_clean_flush_metadata_end, + .queue = xcache_io_queue(io), + }; + struct ocf_metadata_line_getter line_getter = { + .getter = (void *)cleaning_ctx, + .get_line_num = clean_line_num, + .get_flush_line = clean_flush_line, + }; + + xcache_metadata_flush_asynch(cleaning_ctx->cache, &io_ctx, &line_getter); +} + +static void xcache_clean_bf_end(struct xcache_io *io, int error) +{ + struct xcache_cleaning_ctx *cleaning_ctx = container_of(io, struct xcache_cleaning_ctx, + io); + struct clean_sort_data *data = cleaning_ctx->data; + ocf_cache_t cache = cleaning_ctx->cache; + struct ocf_alock *c = ocf_cache_line_concurrency(cleaning_ctx->cache); + + ocf_core_t core; + ocf_cache_line_t line; + int i, j; + + if (error != 0) { + xcache_clean_end(cleaning_ctx); + return; + } + + for (i = 0, j = 0; i < cleaning_ctx->count; i++) { + // core_line write failed + if (data[i].core_line == ULLONG_MAX) { + xcache_unlock_wr(c, data[i].line); + continue; + } + + core = ocf_cache_get_core(cache, data[i].core_id); + line = data[i].line; + xcache_clean_update_metadata(cache, core, line); + // record line to flush + data[j++].line = data[i].line; + } + cleaning_ctx->count = j; + + if (j == 0) { + xcache_clean_end(cleaning_ctx); + } else { + xcache_clean_metadata_flush(cleaning_ctx); + } +} + +static void remove_failed_line(struct xcache_cleaning_ctx *cleaning_ctx) +{ + int l, r; + + l = 0; + for (r = 0; r < cleaning_ctx->count; r++) { + if (cleaning_ctx->data[r].line == INVALID_LINE) { + continue; + } + if (l != r) { + cleaning_ctx->data[l] = cleaning_ctx->data[r]; + } + l++; + } + cleaning_ctx->count = l; +} + +static int xcache_clean_write_cb(struct xcache_backdev_io *base_io, struct backdev_io_end_arg *cb_arg) +{ + struct xcache_cleaning_ctx *cleaning_ctx = container_of(base_io, + struct xcache_cleaning_ctx, base_io); + struct clean_sort_data *data = cleaning_ctx->data; + ocf_cache_t cache = cleaning_ctx->cache; + + uint64_t first_line, last_line; + int i; + ocf_core_t core; + + if (cb_arg->error == 0) { + return 0; + } + + // core_line in data array is sorted in xcache_cleaner_clean + first_line = xcache_addr_to_line(cache, cb_arg->addr); + last_line = xcache_addr_to_line(cache, cb_arg->addr + cb_arg->size - 1); + for (i = 0; i < cleaning_ctx->count; i++) { + if (data[i].core_line >= first_line) { + break; + } + } + + for (; i < cleaning_ctx->count; i++) { + if (data[i].core_line > last_line) { + break; + } + // cache line alock is still hold, don't touch data[i].line + data[i].core_line = ULLONG_MAX; + core = ocf_cache_get_core(cache, data[i].core_id); + ocf_core_stats_core_error_update(core, OCF_WRITE); + } + + return 0; +} + +struct dirty_range { + uint8_t start_sector; + uint8_t last_sector; + int idx; + uint64_t core_line; +}; + +struct clear_range { + uint8_t start_sector; + uint8_t last_sector; + int start_idx; + uint64_t start_line; + uint64_t last_line; +}; + +static void get_dirty_range(ocf_cache_t cache, struct xcache_cleaning_ctx *cleaning_ctx, struct dirty_range *range) +{ + struct clean_sort_data *data = cleaning_ctx->data; + + for (; range->idx < cleaning_ctx->count; range->idx++) { + get_dirty_sectors(cache, data[range->idx].line, &range->start_sector, &range->last_sector); + if (range->start_sector < ocf_line_sectors(cache)) { + range->core_line = data[range->idx].core_line; + break; + } + + range->start_sector = 0; + } +} + +static void dirty_range_next(ocf_cache_t cache, struct dirty_range *range) +{ + if (range->start_sector >= ocf_line_sectors(cache)) { + range->start_sector = 0; + range->idx++; + } else { + range->start_sector++; + } +} + +static int merge_dirty_range(ocf_cache_t cache, struct clear_range *clear_range, struct dirty_range *dirty_range) +{ + if (clear_range->last_sector != ocf_line_sectors(cache) - 1) { + return -1; + } + + if (dirty_range->start_sector != 0) { + return -1; + } + + if (dirty_range->core_line != clear_range->last_line + 1) { + return -1; + } + + clear_range->last_line = dirty_range->core_line; + clear_range->last_sector = dirty_range->last_sector; + return 0; +} + +static void submit_dirty_range(ocf_cache_t cache, struct xcache_cleaning_ctx *cleaning_ctx, struct clear_range *clear_range) +{ + struct xcache_backdev_io *base_io = &cleaning_ctx->base_io; + struct xcache_io *io = &cleaning_ctx->io; + uint64_t addr, size, buf_offset; + + addr = xcache_line_to_addr(cache, clear_range->start_line) + SECTORS_TO_BYTES(clear_range->start_sector); + size = xcache_line_to_addr(cache, clear_range->last_line - clear_range->start_line) + SECTORS_TO_BYTES((int)clear_range->last_sector - (int)clear_range->start_sector + 1); + buf_offset = xcache_line_to_addr(cache, clear_range->start_idx) + SECTORS_TO_BYTES(clear_range->start_sector); + xcache_backdev_submit_io(base_io, false, addr, size, buf_offset, OCF_WRITE); +} + +static void xcache_clean_bf(struct xcache_io *io, int error) +{ + struct xcache_cleaning_ctx *cleaning_ctx = container_of(io, + struct xcache_cleaning_ctx, io); + struct xcache_backdev_io *base_io = &cleaning_ctx->base_io; + struct clean_sort_data *data = cleaning_ctx->data; + ocf_cache_t cache = cleaning_ctx->cache; + + struct dirty_range dirty_range; + struct clear_range clear_range; + + remove_failed_line(cleaning_ctx); + + if (error) { + xcache_clean_bf_end(io, error); + } + + env_atomic_set(&io->remaining, 1); + io->end = xcache_clean_bf_end; + base_io->end = xcache_clean_write_cb; + + dirty_range.start_sector = 0; + dirty_range.idx = 0; + get_dirty_range(cache, cleaning_ctx, &dirty_range); + while (dirty_range.idx < cleaning_ctx->count) { + clear_range.start_sector = dirty_range.start_sector; + clear_range.start_line = data[dirty_range.idx].core_line; + clear_range.start_idx = dirty_range.idx; + clear_range.last_sector = dirty_range.last_sector; + clear_range.last_line = data[dirty_range.idx].core_line; + + for (dirty_range_next(cache, &dirty_range); + dirty_range.idx < cleaning_ctx->count; + dirty_range_next(cache, &dirty_range)) { + get_dirty_range(cache, cleaning_ctx, &dirty_range); + if (merge_dirty_range(cache, &clear_range, &dirty_range) != 0) { + break; + } + } + submit_dirty_range(cache, cleaning_ctx, &clear_range); + } + + xcache_io_put(io); +} + +static int xcache_clean_read_cb(struct xcache_backdev_io *base_io, struct backdev_io_end_arg *cb_arg) +{ + struct xcache_cleaning_ctx *cleaning_ctx = container_of(base_io, + struct xcache_cleaning_ctx, base_io); + struct ocf_alock *c = ocf_cache_line_concurrency(cleaning_ctx->cache); + + ocf_cache_line_t line; + ocf_core_t core; + int i; + + if (cb_arg->error == 0) { + return 0; + } + + line = addr_to_cache_line(cleaning_ctx->cache, cb_arg->addr); + for (i = 0; i < cleaning_ctx->count; i++) { + if (cleaning_ctx->data[i].line == line) { + xcache_unlock_wr(c, line); + cleaning_ctx->data[i].line = INVALID_LINE; + core = ocf_cache_get_core(cleaning_ctx->cache, cleaning_ctx->data[i].core_id); + ocf_core_stats_cache_error_update(core, OCF_READ); + break; + } + } + + return 0; +} + +static int xcache_clean_if(struct xcache_io *io) +{ + struct xcache_cleaning_ctx *cleaning_ctx = container_of(io, + struct xcache_cleaning_ctx, io); + struct xcache_backdev_io *base_io = &cleaning_ctx->base_io; + ocf_cache_t cache = cleaning_ctx->cache; + uint64_t line_size = ocf_line_size(cache); + uint64_t buf_offset = 0; + + ocf_cache_line_t line; + uint64_t addr; + int i; + + io->end = xcache_clean_bf; + base_io->end = xcache_clean_read_cb; + for (i = 0; i < cleaning_ctx->count; i++) { + line = cleaning_ctx->data[i].line; + addr = cache_line_to_addr(cache, line, 0); + xcache_backdev_submit_io(base_io, true, addr, line_size, buf_offset, OCF_READ); + buf_offset += line_size; + } + return 0; +} + +static inline int sort_data_cmp(struct clean_sort_data *l, struct clean_sort_data *r) +{ + if (l->core_id != r->core_id) { + return l->core_id - r->core_id; + } + return l->core_line - r->core_line; +} + +static inline void swap_sort_data(struct clean_sort_data *l, struct clean_sort_data *r) +{ + struct clean_sort_data tmp; + + tmp = *l; + *l = *r; + *r = tmp; +} + +static void clean_quick_sort(struct clean_sort_data *data, int start, int end) +{ + int i, j; + + if (start >= end) { + return; + } + + j = start; + for (i = start; i < end; i++) { + if (sort_data_cmp(&data[i], &data[end]) < 0) { + if (i != j) { + swap_sort_data(&data[i], &data[j]); + } + j++; + } + } + if (j != end) { + swap_sort_data(&data[j], &data[end]); + } + + clean_quick_sort(data, start, j - 1); + clean_quick_sort(data, j + 1, end); +} + +static int xcache_clean_sort(ocf_cache_t cache, struct xcache_cleaning_ctx *cleaning_ctx) +{ + struct clean_sort_data *data = cleaning_ctx->data; + int count = cleaning_ctx->count; + int i; + + for (i = 0; i < count; i++) { + ocf_metadata_get_core_info(cache, data[i].line, &data[i].core_id, + &data[i].core_line); + } + clean_quick_sort(data, 0, count - 1); + + return 0; +} + +/* + * 1. we can't use spdk_io_to_* here + * 2. xcache_cleaner_prepare must be called + */ +int xcache_cleaner_clean(ocf_cache_t cache, ocf_queue_t q, + struct xcache_cleaning_ctx *cleaning_ctx) +{ + struct xcache_io *io = &cleaning_ctx->io; + struct xcache_backdev_io *base_io = &cleaning_ctx->base_io; + + cleaning_ctx->cache = cache; + + if (cleaning_ctx->count == 0) { + goto err_out; + } + + if (xcache_clean_sort(cache, cleaning_ctx) != 0) { + goto err_out; + } + + base_io->data = ctx_data_alloc(cache->owner, ocf_line_pages(cache) * cleaning_ctx->count); + if (base_io->data == NULL) { + goto err_out; + } + + base_io->xcache_io = io; + base_io->end = NULL; + + io->io_if = xcache_clean_if; + io->io_queue = q; + io->error = 0; + env_atomic_set(&io->remaining, 1); + xcache_queue_push_xcache_io_back(io, true); + return 0; + +err_out: + xcache_clean_end(cleaning_ctx); + return -1; +} + +#define CLEAN_INTERVAL 600000 // 600 seconds + +static void xcache_cleaner_run_complete(void *arg) +{ + ocf_cleaner_t cleaner = (ocf_cleaner_t)arg; + + ocf_cleaner_run_complete(cleaner, CLEAN_INTERVAL); +} + +void xcache_cleaner_run(ocf_cleaner_t cleaner, ocf_queue_t queue) +{ + ocf_cache_t cache; + struct xcache_cleaning_ctx *cleaning_ctx; + xcache_context_t *xcache_ctx; + ocf_cache_line_t cline[XCACHE_CLEAN_SIZE]; + int cline_num; + unsigned lock_idx; + + if (cleaner == NULL || queue == NULL) { + return; + } + + cache = ocf_cleaner_get_cache(cleaner); + cleaning_ctx = xcache_get_cleaning_ctx(cache); + xcache_ctx = xcache_get_ctx(cache); + + if (xcache_cleaner_prepare(cleaning_ctx) != 0) { + return; + } + + if (ocf_cleaner_run_prepare(cleaner, queue) != 0) { + xcache_cleaner_complete(cleaning_ctx); + return; + } + + lock_idx = ocf_metadata_concurrency_next_idx(queue); + ocf_metadata_start_shared_access(&cache->metadata.lock, lock_idx); + + cline_num = evicting_line_to_clean(xcache_ctx, cline, XCACHE_CLEAN_SIZE); + + ocf_metadata_end_shared_access(&cache->metadata.lock, lock_idx); + + if (cline_num == 0) { + ocf_cleaner_run_complete(cleaner, CLEAN_INTERVAL); + xcache_cleaner_complete(cleaning_ctx); + return; + } + + xcache_cleaner_set_end(cleaning_ctx, xcache_cleaner_run_complete, (void *)cleaner); + xcache_cleaner_fill(cleaning_ctx, cline, cline_num); + xcache_cleaner_clean(cache, queue, cleaning_ctx); +} diff --git a/src/xcache_cleaner.h b/src/xcache_cleaner.h new file mode 100644 index 0000000..d7c9e4d --- /dev/null +++ b/src/xcache_cleaner.h @@ -0,0 +1,69 @@ +#ifndef XCACHE_CLEANER_H_ +#define XCACHE_CLEANER_H_ + +#include "ocf/ocf_io.h" +#include "ocf/ocf_types.h" +#include "utils/utils_refcnt.h" + +#include "ocf/xcache.h" + +#define XCACHE_CLEAN_SIZE 32 + +struct clean_sort_data { + ocf_core_id_t core_id; + uint64_t core_line; + ocf_cache_line_t line; +}; + +typedef void (*cleaning_end_t)(void *arg); +struct xcache_cleaning_ctx { + ocf_cache_t cache; + struct ocf_refcnt counter; + struct xcache_io io; + struct xcache_backdev_io base_io; + struct clean_sort_data data[XCACHE_CLEAN_SIZE]; + int count; + cleaning_end_t end; + void *arg; +}; + +int xcache_cleaner_clean(ocf_cache_t cache, ocf_queue_t q, + struct xcache_cleaning_ctx *cleaning_ctx); + +static inline int xcache_cleaner_prepare(struct xcache_cleaning_ctx *cleaning_ctx) +{ + if (ocf_refcnt_inc(&cleaning_ctx->counter) == 1) { + return 0; + } + + ocf_refcnt_dec(&cleaning_ctx->counter); + return -1; +} + +static inline void xcache_cleaner_complete(struct xcache_cleaning_ctx *cleaning_ctx) +{ + ocf_refcnt_dec(&cleaning_ctx->counter); +} + +static inline int xcache_cleaner_fill(struct xcache_cleaning_ctx *cleaning_ctx, + ocf_cache_line_t *clines, int line_num) +{ + struct clean_sort_data *data = cleaning_ctx->data; + int num = line_num < XCACHE_CLEAN_SIZE ? line_num : XCACHE_CLEAN_SIZE; + int i; + + for (i = 0; i < num; i++) { + data[i].line = clines[i]; + } + cleaning_ctx->count = num; + return num; +} + +static inline void xcache_cleaner_set_end(struct xcache_cleaning_ctx *cleaning_ctx, + cleaning_end_t end, void *arg) +{ + cleaning_ctx->end = end; + cleaning_ctx->arg = arg; +} + +#endif /* XCACHE_CLEANER_H_ */ diff --git a/src/xcache_lru.c b/src/xcache_lru.c new file mode 100644 index 0000000..32f9605 --- /dev/null +++ b/src/xcache_lru.c @@ -0,0 +1,199 @@ +/* + * Copyright(c) 2012-2021 Intel Corporation + * SPDX-License-Identifier: BSD-3-Clause-Clear + */ + +#include "ocf_cache_priv.h" +#include "ocf_lru.h" +#include "metadata/metadata.h" +#include "utils/utils_alock.h" +#include "concurrency/ocf_cache_line_concurrency.h" + +#include "xcache_cleaner.h" +#include "engine/xcache_engine_common.h" +#include "xcache_lru.h" +#include "evicting/evicting_ops.h" + +static inline bool xcache_trylock_hash(struct xcache_io_context *ctx, + ocf_core_id_t core_id, uint64_t core_line) +{ + if (ocf_metadata_hash_func(xcache_ctx_cache(ctx), core_line, core_id) == + ctx->hash) + return true; + + return ocf_hb_cline_naked_trylock_wr( + &xcache_ctx_cache(ctx)->metadata.lock, + core_id, core_line); +} + +static inline void xcache_unlock_hash(struct xcache_io_context *ctx, + ocf_core_id_t core_id, uint64_t core_line) +{ + if (ocf_metadata_hash_func(xcache_ctx_cache(ctx), core_line, core_id) != + ctx->hash) { + ocf_hb_cline_naked_unlock_wr( + &xcache_ctx_cache(ctx)->metadata.lock, + core_id, core_line); + + } +} + +static inline bool xcache_eviction_lock(struct xcache_io_context *ctx, + ocf_cache_line_t cache_line, + ocf_core_id_t *core_id, uint64_t *core_line) + +{ + struct ocf_alock *lock = ocf_cache_line_concurrency(xcache_ctx_cache(ctx)); + + ocf_metadata_get_core_info(xcache_ctx_cache(ctx), cache_line, + core_id, core_line); + + if (*core_id == ocf_core_get_id(xcache_ctx_core(ctx)) && + *core_line >= ctx->core_line_first && + *core_line <= ctx->core_line_last) { + xcache_unlock_wr(lock, cache_line); + return false; + } + + if (!xcache_trylock_hash(ctx, *core_id, *core_line)) { + xcache_unlock_wr(lock, cache_line); + return false; + } + + return true; +} + +#define EVICT_RETRY_LOCK 3 +static inline ocf_cache_line_t xcache_evict_line(struct xcache_io_context *io_ctx) +{ + ocf_cache_t cache = xcache_ctx_cache(io_ctx); + xcache_context_t *ctx = xcache_get_ctx(cache); + ocf_core_id_t core_id; + uint64_t core_line; + ocf_cache_line_t cline; + int cline_num; + int i; + + for (i = 0; i < EVICT_RETRY_LOCK; i++) { + cline_num = evicting_line_to_evict(ctx, &cline, 1); + if (cline_num == 0) { + break; + } + if (xcache_eviction_lock(io_ctx, + cline, &core_id, &core_line)) { + goto found; + } + } + return INVALID_LINE; + +found: + ocf_lru_invalidate(cache, cline, core_id, io_ctx->part_id); + xcache_unlock_hash(io_ctx, core_id, core_line); + + xcache_map_cache_line(io_ctx, cline); + return cline; +} + +static inline ocf_cache_line_t xcache_free_list_line(ocf_cache_t cache, uint32_t list_idx, + struct ocf_part *dst_part) +{ + struct ocf_part *free = &cache->free; + struct ocf_alock *lock = ocf_cache_line_concurrency(cache); + struct ocf_lru_list *list; + ocf_cache_line_t cline; + + ocf_metadata_lru_wr_lock(&cache->metadata.lock, list_idx); + + list = ocf_lru_get_list(free, list_idx, true); + for (cline = list->tail; cline != INVALID_LINE; + cline = ocf_metadata_get_lru(cache, cline)->prev) { + if (ocf_alock_trylock_entry_wr(lock, cline)) { + break; + } + } + + if (cline != INVALID_LINE) { + ocf_lru_repart_locked(cache, cline, free, dst_part); + } + + ocf_metadata_lru_wr_unlock(&cache->metadata.lock, + list_idx); + + return cline; +} + +static ocf_cache_line_t xcache_get_free_line(struct xcache_io_context *ctx) +{ + struct ocf_part *dst_part; + uint32_t start_idx, iter_idx; + ocf_cache_line_t cline; + + dst_part = &xcache_ctx_cache(ctx)->user_parts[ctx->part_id].part; + + start_idx = xcache_ctx_queue(ctx)->lru_idx++ % OCF_NUM_LRU_LISTS; + for (iter_idx = start_idx; iter_idx < OCF_NUM_LRU_LISTS; iter_idx++) { + cline = xcache_free_list_line(xcache_ctx_cache(ctx), iter_idx, dst_part); + if (cline != INVALID_LINE) { + goto found; + } + } + + for (iter_idx = 0; iter_idx < start_idx; iter_idx++) { + cline = xcache_free_list_line(xcache_ctx_cache(ctx), iter_idx, dst_part); + if (cline != INVALID_LINE) { + goto found; + } + } + + return INVALID_LINE; + +found: + ENV_BUG_ON(metadata_test_dirty(xcache_ctx_cache(ctx), cline)); + xcache_map_cache_line(ctx, cline); + return cline; +} + +ocf_cache_line_t xcache_get_cline(struct xcache_io_context *ctx) +{ + ocf_cache_t cache = xcache_ctx_cache(ctx); + ocf_cache_line_t line; + + if (ocf_lru_num_free(cache) > 0) { + line = xcache_get_free_line(ctx); + if (line != INVALID_LINE) { + return line; + } + } + + return xcache_evict_line(ctx); +} + +void xcache_clean(struct xcache_io_context *io_ctx, uint32_t count) +{ + ocf_cache_t cache = xcache_ctx_cache(io_ctx); + struct xcache_cleaning_ctx *cleaning_ctx = xcache_get_cleaning_ctx(cache); + xcache_context_t *ctx = xcache_get_ctx(cache); + ocf_cache_line_t cline[XCACHE_CLEAN_SIZE]; + int cline_num; + + unsigned i; + unsigned lock_idx; + + if (ocf_mngt_cache_is_locked(cache)) + return; + + if (xcache_cleaner_prepare(cleaning_ctx) != 0) { + return; + } + + lock_idx = ocf_metadata_concurrency_next_idx(xcache_ctx_queue(io_ctx)); + ocf_metadata_start_shared_access(&cache->metadata.lock, lock_idx); + + count = count < XCACHE_CLEAN_SIZE ? count : XCACHE_CLEAN_SIZE; + cline_num = evicting_line_to_clean(ctx, cline, count); + xcache_cleaner_fill(cleaning_ctx, cline, cline_num); + + ocf_metadata_end_shared_access(&cache->metadata.lock, lock_idx); + + xcache_cleaner_clean(cache, xcache_ctx_queue(io_ctx), cleaning_ctx); +} diff --git a/src/xcache_lru.h b/src/xcache_lru.h new file mode 100644 index 0000000..87e592e --- /dev/null +++ b/src/xcache_lru.h @@ -0,0 +1,9 @@ +#ifndef __XCACHE_LRU_H__ +#define __XCACHE_LRU_H__ + +#include "ocf/xcache.h" + +ocf_cache_line_t xcache_get_cline(struct xcache_io_context *ctx); +void xcache_clean(struct xcache_io_context *ctx, uint32_t count); + +#endif diff --git a/src/xcache_ocf_core.c b/src/xcache_ocf_core.c new file mode 100644 index 0000000..a3d5c1c --- /dev/null +++ b/src/xcache_ocf_core.c @@ -0,0 +1,41 @@ +#include "ocf/ocf.h" +#include "ocf_cache_priv.h" +#include "metadata/metadata.h" +#include "engine/xcache_engine.h" +#include "engine/xcache_engine_common.h" + +#include "ocf/xcache.h" +#include "xcache_queue.h" + +void xcache_submit_io(struct xcache_io *io) +{ + ocf_core_t core = xcache_io_core(io); + ocf_cache_t cache = xcache_io_cache(io); + int ret; + + OCF_CHECK_NULL(io); + + if (unlikely(!env_bit_test(ocf_cache_state_running, + &cache->cache_state))) { + xcache_io_end(io, -OCF_ERR_CACHE_NOT_AVAIL); + return; + } + + xcache_get_io_if(io, cache->conf_meta->cache_mode); + if (io->io_if == NULL) { + xcache_io_end(io, -OCF_ERR_INVAL); + return; + } + + env_atomic_set(&io->remaining, 1); + xcache_queue_push_xcache_io_back(io, true); +} + +void xcache_backdev_io_end(struct xcache_backdev_io *bd_io, struct backdev_io_end_arg *arg) +{ + struct xcache_io *io = bd_io->xcache_io; + + io->error |= arg->error; + bd_io->end(bd_io, arg); + xcache_io_put(io); +} diff --git a/src/xcache_queue.c b/src/xcache_queue.c new file mode 100644 index 0000000..e2c3926 --- /dev/null +++ b/src/xcache_queue.c @@ -0,0 +1,315 @@ +#include "ocf/ocf.h" +#include "ocf_queue_priv.h" +#include "ocf_priv.h" +#include "ocf_cache_priv.h" + +#include "ocf/xcache.h" +#include "xcache_queue.h" +#include "engine/xcache_engine.h" +#include "engine/xcache_engine_common.h" + +#define ENTRY_MASK ((uintptr_t)0x7) + +int xcache_queue_ctx_init(ocf_queue_t queue) +{ + struct xcache_queue_ctx *queue_ctx = env_malloc(sizeof(struct xcache_queue_ctx), 0); + + if (queue_ctx == NULL) { + return -ENOMEM; + } + + INIT_LIST_HEAD(&queue_ctx->backdev_io_list); + queue_ctx->backdev_io_no = 0; + + INIT_LIST_HEAD(&queue_ctx->flush_io_list); + queue_ctx->flush_io_no = 0; + + INIT_LIST_HEAD(&queue_ctx->xcache_io_list); + queue_ctx->xcache_io_no = 0; + + queue->priv1 = (void *)queue_ctx; + return 0; +} + +void xcache_queue_ctx_deinit(ocf_queue_t queue) +{ + env_free(queue->priv1); + queue->priv1 = NULL; +} + +static inline void set_entry_type(struct queue_entry *entry, + enum entry_type type) +{ + if (type == OCF_REQ_ENTRY) { + entry->list.next = (struct list_head *)(((uintptr_t)entry->list.next) | (uintptr_t)1); + return; + } + + entry->type = type; +} + +static inline enum entry_type get_entry_type(struct queue_entry *entry) +{ + if (((uintptr_t)entry->list.next & ENTRY_MASK) != 0) { + return OCF_REQ_ENTRY; + } + + return entry->type; +} + +static inline void list_add_entry(struct list_head *list, struct list_head *head) +{ + list_add(list, head); +} + +static inline void list_add_tail_entry(struct list_head *list, struct list_head *head) +{ + struct list_head *prev = head->prev; + uintptr_t bits = (uintptr_t)prev->next & ENTRY_MASK; + + list->next = head; + list->prev = prev; + + prev->next = (struct list_head *)((uintptr_t)list | bits); + head->prev = list; +} + +static inline void list_pop_front_entry(struct queue_entry *entry) +{ + struct list_head *next = (struct list_head *)((uintptr_t)entry->list.next & ~ENTRY_MASK); + + entry->list.prev->next = next; + next->prev = entry->list.prev; +} + +static inline struct queue_entry *xcache_io_to_entry(struct xcache_io *io) +{ + return (struct queue_entry *)io; +} + +static inline struct xcache_io *entry_to_xcache_io(struct queue_entry *entry) +{ + return (struct xcache_io *)entry; +} + +static inline struct queue_entry *backdev_io_to_entry(struct xcache_backdev_io *base_io) +{ + return (struct queue_entry *)base_io; +} + +static inline struct xcache_backdev_io *entry_to_backdev_io(struct queue_entry *entry) +{ + return (struct xcache_backdev_io *)entry; +} + +static inline struct queue_entry *ocf_req_to_entry(struct ocf_request *req) +{ + return (struct queue_entry *)container_of(&req->list, struct queue_entry, list); +} + +static inline struct ocf_request *entry_to_ocf_req(struct queue_entry *entry) +{ + return (struct ocf_request *)container_of(&(entry->list), struct ocf_request, list); +} + +static void xcache_io_run(struct queue_entry *entry) +{ + struct xcache_io *io = entry_to_xcache_io(entry); + + io->io_if(io); + + xcache_io_put(io); +} + +static void backdev_io_run(struct queue_entry *entry) +{ + struct xcache_backdev_io *base_io = entry_to_backdev_io(entry); + struct xcache_io *io = base_io->xcache_io; + + base_io->io_res(base_io); + + xcache_io_put(io); +} + +static void ocf_req_run(struct queue_entry *entry) +{ + struct ocf_request *req = entry_to_ocf_req(entry); + + if (req->ioi.io.handle) + req->ioi.io.handle(&req->ioi.io, req); + else + ocf_io_handle(&req->ioi.io, req); +} + +static struct queue_entry_ops { + void (*entry_run)(struct queue_entry *entry); +} queue_entry_ops[] = { + [XCACHE_IO_ENTRY] = { + .entry_run = xcache_io_run, + }, + [XCACHE_BACKDEV_IO_ENTRY] = { + .entry_run = backdev_io_run, + }, + [OCF_REQ_ENTRY] = { + .entry_run = ocf_req_run, + }, +}; + +static inline void queue_entry_run(enum entry_type type, struct queue_entry *entry) +{ + queue_entry_ops[type].entry_run(entry); +} + +static struct queue_entry *xcache_queue_pop_entry(ocf_queue_t q) +{ + unsigned long lock_flags = 0; + struct queue_entry *entry; + + OCF_CHECK_NULL(q); + + env_spinlock_lock_irqsave(&q->io_list_lock, lock_flags); + + if (list_empty(&q->io_list)) { + /* No items on the list */ + env_spinlock_unlock_irqrestore(&q->io_list_lock, + lock_flags); + return NULL; + } + + /* Get the first request and remove it from the list */ + entry = list_first_entry(&q->io_list, struct queue_entry, list); + + env_atomic_dec(&q->io_no); + list_pop_front_entry(entry); + + env_spinlock_unlock_irqrestore(&q->io_list_lock, lock_flags); + + OCF_CHECK_NULL(entry); + + return entry; +} + +// overwrite ocf_queue_run_single +void ocf_queue_run_single(ocf_queue_t q) +{ + struct queue_entry *entry = NULL; + + OCF_CHECK_NULL(q); + + entry = xcache_queue_pop_entry(q); + + if (!entry) + return; + + queue_entry_run(get_entry_type(entry), entry); +} + +#define QUEUE_CACHE_SIZE 128 +// only called by request in queue to avoid lock +struct xcache_backdev_io *xcache_queue_alloc_backdev_io(ocf_queue_t q) +{ + struct xcache_queue_ctx *queue_ctx = xcache_get_queue_ctx(q); + struct xcache_backdev_io *io; + + if (queue_ctx->backdev_io_no == 0) { + return env_malloc(sizeof(struct xcache_backdev_io), 0); + } + + io = list_first_entry(&queue_ctx->backdev_io_list, struct xcache_backdev_io, free_list); + list_del(&io->free_list); + queue_ctx->backdev_io_no--; + return io; +} + +void xcache_queue_free_backdev_io(ocf_queue_t q, struct xcache_backdev_io *io) +{ + struct xcache_queue_ctx *queue_ctx = xcache_get_queue_ctx(q); + + if (queue_ctx->backdev_io_no > QUEUE_CACHE_SIZE) { + env_free(io); + return; + } + + list_add_tail(&io->free_list, &queue_ctx->backdev_io_list); + queue_ctx->backdev_io_no++; +} + +struct xcache_io *xcache_queue_alloc_xcache_io(ocf_queue_t q) +{ + struct xcache_queue_ctx *queue_ctx = xcache_get_queue_ctx(q); + struct xcache_io *io; + + if (queue_ctx->xcache_io_no == 0) { + return env_malloc(sizeof(struct xcache_io), 0); + } + + io = list_first_entry(&queue_ctx->xcache_io_list, struct xcache_io, queue_list); + list_del(&io->queue_list); + queue_ctx->xcache_io_no--; + return io; +} + +void xcache_queue_free_xcache_io(ocf_queue_t q, struct xcache_io *io) +{ + struct xcache_queue_ctx *queue_ctx = xcache_get_queue_ctx(q); + + if (queue_ctx->xcache_io_no > QUEUE_CACHE_SIZE) { + env_free(io); + return; + } + + list_add_tail(&io->queue_list, &queue_ctx->xcache_io_list); + queue_ctx->xcache_io_no++; +} + +static void xcache_queue_push_entry(ocf_queue_t q, struct queue_entry *entry, bool at_head, bool allow_sync, enum entry_type type) +{ + ocf_cache_t cache = ocf_queue_get_cache(q); + unsigned long lock_flags = 0; + + INIT_LIST_HEAD(&entry->list); + + env_atomic_set(&cache->last_access_ms, + env_ticks_to_msecs(env_get_tick_count())); + + env_spinlock_lock_irqsave(&q->io_list_lock, lock_flags); + + if (at_head) { + list_add_entry(&entry->list, &q->io_list); + } else { + list_add_tail_entry(&entry->list, &q->io_list); + } + // type set must under lock + set_entry_type(entry, type); + env_atomic_inc(&q->io_no); + + env_spinlock_unlock_irqrestore(&q->io_list_lock, lock_flags); + + ocf_queue_kick(q, allow_sync); +} + +void xcache_queue_push_xcache_io_back(struct xcache_io *io, bool allow_sync) +{ + struct queue_entry *entry = xcache_io_to_entry(io); + xcache_queue_push_entry(xcache_io_queue(io), entry, false, allow_sync, XCACHE_IO_ENTRY); +} + +void xcache_queue_push_backdev_io_front(struct xcache_backdev_io *base_io, bool allow_sync) +{ + struct queue_entry *entry = backdev_io_to_entry(base_io); + xcache_queue_push_entry(xcache_io_queue(base_io->xcache_io), entry, true, allow_sync, XCACHE_BACKDEV_IO_ENTRY); +} + +// overwrite ocf_engine_push_req_front +void ocf_engine_push_req_front(struct ocf_request *req, bool allow_sync) +{ + struct queue_entry *entry = ocf_req_to_entry(req); + xcache_queue_push_entry(req->io_queue, entry, true, allow_sync, OCF_REQ_ENTRY); +} + +// overwrite ocf_engine_push_req_back +void ocf_engine_push_req_back(struct ocf_request *req, bool allow_sync) +{ + struct queue_entry *entry = ocf_req_to_entry(req); + xcache_queue_push_entry(req->io_queue, entry, false, allow_sync, OCF_REQ_ENTRY); +} diff --git a/src/xcache_queue.h b/src/xcache_queue.h new file mode 100644 index 0000000..3412a2a --- /dev/null +++ b/src/xcache_queue.h @@ -0,0 +1,29 @@ +#ifndef XCACHE_QUEUE_H_ +#define XCACHE_QUEUE_H_ + +#include "ocf/xcache.h" + +struct xcache_queue_ctx { + struct list_head backdev_io_list; + int backdev_io_no; + struct list_head flush_io_list; + int flush_io_no; + struct list_head xcache_io_list; + int xcache_io_no; +}; + +int xcache_queue_ctx_init(ocf_queue_t queue); +void xcache_queue_ctx_deinit(ocf_queue_t queue); +static inline struct xcache_queue_ctx *xcache_get_queue_ctx(ocf_queue_t queue) +{ + return (struct xcache_queue_ctx *)(queue->priv1); +} + +struct xcache_backdev_io *xcache_queue_alloc_backdev_io(ocf_queue_t q); +void xcache_queue_free_backdev_io(ocf_queue_t q, struct xcache_backdev_io *io); +void xcache_queue_push_xcache_io_back(struct xcache_io *io, bool allow_sync); +void xcache_queue_push_backdev_io_front(struct xcache_backdev_io *base_io, bool allow_sync); +struct xcache_io *xcache_queue_alloc_xcache_io(ocf_queue_t q); +void xcache_queue_free_xcache_io(ocf_queue_t q, struct xcache_io *io); + +#endif -- 2.30.0
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2