/* * Copyright(c) 2019 Intel Corporation * SPDX-License-Identifier: BSD-3-Clause-Clear */ #include #include #include "ocf_env.h" #include "data.h" #include "dobj.h" #include "ctx.h" #define PAGE_SIZE 4096 /* * Allocate structure representing data for io operations. */ ctx_data_t *ctx_data_alloc(uint32_t pages) { struct dobj_data *data; data = malloc(sizeof(*data)); data->ptr = malloc(pages * PAGE_SIZE); data->offset = 0; return data; } /* * Free data structure. */ void ctx_data_free(ctx_data_t *ctx_data) { struct dobj_data *data = ctx_data; if (!data) return; free(data->ptr); free(data); } /* * This function is supposed to set protection of data pages against swapping. * Can be non-implemented if not needed. */ static int ctx_data_mlock(ctx_data_t *ctx_data) { return 0; } /* * Stop protecting data pages against swapping. */ static void ctx_data_munlock(ctx_data_t *ctx_data) { } /* * Read data into flat memory buffer. */ static uint32_t ctx_data_read(void *dst, ctx_data_t *src, uint32_t size) { struct dobj_data *data = src; memcpy(dst, data->ptr + data->offset, size); return size; } /* * Write data from flat memory buffer. */ static uint32_t ctx_data_write(ctx_data_t *dst, const void *src, uint32_t size) { struct dobj_data *data = dst; memcpy(data->ptr + data->offset, src, size); return size; } /* * Fill data with zeros. */ static uint32_t ctx_data_zero(ctx_data_t *dst, uint32_t size) { struct dobj_data *data = dst; memset(data->ptr + data->offset, 0, size); return size; } /* * Perform seek operation on data. */ static uint32_t ctx_data_seek(ctx_data_t *dst, ctx_data_seek_t seek, uint32_t offset) { struct dobj_data *data = dst; switch (seek) { case ctx_data_seek_begin: data->offset = offset; break; case ctx_data_seek_current: data->offset += offset; break; } return offset; } /* * Copy data from one structure to another. */ static uint64_t ctx_data_copy(ctx_data_t *dst, ctx_data_t *src, uint64_t to, uint64_t from, uint64_t bytes) { struct dobj_data *data_dst = dst; struct dobj_data *data_src = src; memcpy(data_dst->ptr + to, data_src->ptr + from, bytes); return bytes; } /* * Perform secure erase of data (e.g. fill pages with zeros). * Can be left non-implemented if not needed. */ static void ctx_data_secure_erase(ctx_data_t *ctx_data) { } /* * Initialize queue thread. To keep this example simple we handle queues * synchronously, thus it's left non-implemented. */ static int ctx_queue_init(ocf_queue_t q) { return 0; } /* * Trigger queue asynchronously. Made synchronous for simplicity. */ static inline void ctx_queue_kick_async(ocf_queue_t q) { ocf_queue_run(q); } /* * Trigger queue synchronously. May be implemented as asynchronous as well, * but in some environments kicking queue synchronously may reduce latency, * so to take advantage of such situations OCF call synchronous variant of * queue kick callback where possible. */ static void ctx_queue_kick_sync(ocf_queue_t q) { ocf_queue_run(q); } /* * Stop queue thread. To keep this example simple we handle queues * synchronously, thus it's left non-implemented. */ static void ctx_queue_stop(ocf_queue_t q) { } /* * Initialize cleaner thread. Cleaner thread is left non-implemented, * to keep this example as simple as possible. */ static int ctx_cleaner_init(ocf_cleaner_t c) { return 0; } /* * Stop cleaner thread. Cleaner thread is left non-implemented, to keep * this example as simple as possible. */ static void ctx_cleaner_stop(ocf_cleaner_t c) { } /* * Initialize metadata updater thread. Metadata updater thread is left * non-implemented to keep this example as simple as possible. */ static int ctx_metadata_updater_init(ocf_metadata_updater_t mu) { return 0; } /* * Kick metadata updater thread. Metadata updater thread is left * non-implemented to keep this example as simple as possible. */ static void ctx_metadata_updater_kick(ocf_metadata_updater_t mu) { } /* * Stop metadata updater thread. Metadata updater thread is left * non-implemented to keep this example as simple as possible. */ static void ctx_metadata_updater_stop(ocf_metadata_updater_t mu) { } /* * Function prividing interface for printing to log used by OCF internals. * It can handle differently messages at varous log levels. */ static int ctx_logger_printf(ocf_logger_t logger, ocf_logger_lvl_t lvl, const char *fmt, va_list args) { FILE *lfile = stdout; if (lvl > log_info) return 0; if (lvl <= log_warn) lfile = stderr; return vfprintf(lfile, fmt, args); } #define CTX_LOG_TRACE_DEPTH 16 /* * Function prividing interface for printing current stack. Used for debugging, * and for providing additional information in log in case of errors. */ static int ctx_logger_dump_stack(ocf_logger_t logger) { void *trace[CTX_LOG_TRACE_DEPTH]; char **messages = NULL; int i, size; size = backtrace(trace, CTX_LOG_TRACE_DEPTH); messages = backtrace_symbols(trace, size); printf("[stack trace]>>>\n"); for (i = 0; i < size; ++i) printf("%s\n", messages[i]); printf("<<<[stack trace]\n"); free(messages); return 0; } /* * This structure describes context ops. They are splitted into few categories: * - data ops, providing context specific data handing interface, * - queue ops, providing interface for starting, stoping and kicking * queue thread in both synchronous and asynchronous way, * - cleaner ops, providing interface to start and stop clener thread, * - metadata updater ops, providing interface for starting, stoping * and kicking metadata updater thread. */ static const struct ocf_ctx_ops ctx_ops = { .name = "OCF Example", .data = { .alloc = ctx_data_alloc, .free = ctx_data_free, .mlock = ctx_data_mlock, .munlock = ctx_data_munlock, .read = ctx_data_read, .write = ctx_data_write, .zero = ctx_data_zero, .seek = ctx_data_seek, .copy = ctx_data_copy, .secure_erase = ctx_data_secure_erase, }, .queue = { .init = ctx_queue_init, .kick_sync = ctx_queue_kick_sync, .kick = ctx_queue_kick_async, .stop = ctx_queue_stop, }, .cleaner = { .init = ctx_cleaner_init, .stop = ctx_cleaner_stop, }, .metadata_updater = { .init = ctx_metadata_updater_init, .kick = ctx_metadata_updater_kick, .stop = ctx_metadata_updater_stop, }, .logger = { .printf = ctx_logger_printf, .dump_stack = ctx_logger_dump_stack, }, }; /* * Function initializing context. Prepares context, sets logger and * registers data object type. */ int ctx_init(ocf_ctx_t *ctx) { int ret; ret = ocf_ctx_init(ctx, &ctx_ops); if (ret) return ret; ret = dobj_init(*ctx); if (ret) { ocf_ctx_exit(*ctx); return ret; } return 0; } /* * Function cleaning up context. Unregisters data object type and * deinitializes context. */ void ctx_cleanup(ocf_ctx_t ctx) { dobj_cleanup(ctx); ocf_ctx_exit(ctx); }