* Copyright (c) 2022 Huawei Technologies Co., Ltd. All rights reserved.
*
* DSS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
*
* dss_vtable.c
*
*
* IDENTIFICATION
* src/common/dss_vtable.c
*
* -------------------------------------------------------------------------
*/
#include "dss_defs.h"
#include "cm_log.h"
#include "cm_utils.h"
#include "dlfcn.h"
#include "dss_vtable.h"
vtable_func_t g_vtable_func = {0};
#define VTABLE_LOAD_SYMBOL_FUNC(func) \
cm_load_symbol(g_vtable_func.vtableHandle, #func, (void**)&g_vtable_func.func)
#define VTABLE_LOAD_SYMBOL_FUNC_ADAPTER(func) \
cm_load_symbol(g_vtable_func.vtableAdapterHandle, #func, (void**)&g_vtable_func.func)
#define IP_FIELD_LENGTH 16
#define DEFAULT_PAGE_SIZE (8 * 1024)
status_t vtable_func_init()
{
if (g_vtable_func.symbolnited) {
return CM_SUCCESS;
}
DSS_RETURN_IF_ERROR(cm_open_dl(&g_vtable_func.vtableHandle, LIB_VTABLE_NAME));
DSS_RETURN_IF_ERROR(VTABLE_LOAD_SYMBOL_FUNC(BdevExit));
DSS_RETURN_IF_ERROR(VTABLE_LOAD_SYMBOL_FUNC(Initialize));
DSS_RETURN_IF_ERROR(VTABLE_LOAD_SYMBOL_FUNC(CreateVolume));
DSS_RETURN_IF_ERROR(VTABLE_LOAD_SYMBOL_FUNC(DestroyVolume));
DSS_RETURN_IF_ERROR(VTABLE_LOAD_SYMBOL_FUNC(Fence));
DSS_RETURN_IF_ERROR(VTABLE_LOAD_SYMBOL_FUNC(FenceQuery));
DSS_RETURN_IF_ERROR(VTABLE_LOAD_SYMBOL_FUNC(Write));
DSS_RETURN_IF_ERROR(VTABLE_LOAD_SYMBOL_FUNC(Read));
DSS_RETURN_IF_ERROR(VTABLE_LOAD_SYMBOL_FUNC(List));
DSS_RETURN_IF_ERROR(VTABLE_LOAD_SYMBOL_FUNC(PtInfoListDestroy));
DSS_RETURN_IF_ERROR(VTABLE_LOAD_SYMBOL_FUNC(PtInfoListCreate));
DSS_RETURN_IF_ERROR(VTABLE_LOAD_SYMBOL_FUNC(GetMasterNodeIPByOffset));
DSS_RETURN_IF_ERROR(cm_open_dl(&g_vtable_func.vtableAdapterHandle, LIB_VTABLE_ADAPTER_NAME));
DSS_RETURN_IF_ERROR(VTABLE_LOAD_SYMBOL_FUNC_ADAPTER(VtableAdapterAppend));
DSS_RETURN_IF_ERROR(VTABLE_LOAD_SYMBOL_FUNC_ADAPTER(VtableAdapterInit));
DSS_RETURN_IF_ERROR(VTABLE_LOAD_SYMBOL_FUNC_ADAPTER(VtableAdapterWrite));
g_vtable_func.symbolnited = true;
return CM_SUCCESS;
}
void VtableExit(void)
{
g_vtable_func.BdevExit();
}
status_t VtableInitAdapter()
{
return (status_t)g_vtable_func.VtableAdapterInit();
}
status_t VtableInitialize(WorkerMode mode, ClientOptionsConfig *optConf)
{
return (status_t)g_vtable_func.Initialize(mode, optConf);
}
status_t VtableCreateVolume(uint16_t volumeType, uint64_t cap, uint32_t alignedSize, uint64_t* volumeId)
{
return (status_t)g_vtable_func.CreateVolume(volumeType, cap, alignedSize, volumeId);
}
status_t VtableDestroyVolume(uint64_t volumeId)
{
return (status_t)g_vtable_func.DestroyVolume(volumeId);
}
status_t VtableWrite(uint64_t volumeId, uint64_t offset, uint32_t length, char *value)
{
return (status_t)g_vtable_func.Write(volumeId, offset, length, value);
}
status_t VtableRead(uint64_t volumeId, uint64_t offset, uint32_t length, char *value)
{
return (status_t)g_vtable_func.Read(volumeId, offset, length, value);
}
status_t VtableList(uint64_t volumeId, bool* exist, uint64_t* cap, uint32_t* alignedSize, uint16_t* type)
{
return (status_t)g_vtable_func.List(volumeId, exist, cap, alignedSize, type);
}
status_t VtableAppendAdapter(uint64_t volumeId, uint64_t offset, uint32_t length, char *value)
{
return (status_t)g_vtable_func.VtableAdapterAppend(volumeId, offset, length, value);
}
status_t VtableWriteAdapte(uint64_t volumeId, uint64_t offset, uint32_t length, char *value)
{
return (status_t)g_vtable_func.VtableAdapterWrite(volumeId, offset, length, value);
}
status_t VtableFence(const char *ip, uint64_t volumeId, uint16_t operateType, bool fullOperate)
{
return (status_t)g_vtable_func.Fence(ip, volumeId, operateType, fullOperate);
}
status_t VtableFenceQuery(const char *ip, uint64_t volumeId, uint16_t *isFenced)
{
return (status_t)g_vtable_func.FenceQuery(ip, volumeId, isFenced);
}
status_t VtableGetMasterNodeIPByOffset(uint64_t volumeId, uint64_t offset, char *ip)
{
PtInfoList* list = g_vtable_func.PtInfoListCreate(8);
g_vtable_func.GetMasterNodeIPByOffset(volumeId, offset, DEFAULT_PAGE_SIZE, list);
errno_t errcode = memcpy_s(ip, IP_FIELD_LENGTH, list->ipList[0], IP_FIELD_LENGTH);
securec_check_ret(errcode);
g_vtable_func.PtInfoListDestroy(list);
return CM_SUCCESS;
}
status_t dss_init_vtable(void)
{
if (g_vtable_func.isInitialize) {
return CM_SUCCESS;
}
int status = 0;
WorkerMode mode = SEPARATES;
ClientOptionsConfig config;
config.enable = false;
config.logType = FILE_TYPE;
config.isDriverServer = false;
LOG_RUN_INF("DSS VtableInitialize start.");
errno_t err = strcpy_s(config.logFilePath, PATH_MAX, "/var/log/turboio");
DSS_SECUREC_SS_RETURN_IF_ERROR(err, CM_ERROR);
status = vtable_func_init();
DSS_RETURN_IFERR2(status, DSS_PRINT_ERROR("DSS load vtable failed!\n"));
status = VtableInitialize(mode, &config);
DSS_RETURN_IFERR2(status, DSS_PRINT_ERROR("DSS VtableInitialize failed!\n"));
LOG_RUN_INF("DSS VtableInitialize success.");
status = VtableInitAdapter();
DSS_RETURN_IFERR2(status, DSS_PRINT_ERROR("DSS VtableInitAgain failed!\n"));
LOG_RUN_INF("DSS VtableInitAgain success.");
g_vtable_func.isInitialize = true;
return CM_SUCCESS;
}
uint64 vtable_name_to_ptid(const char* name)
{
uint64 res = 0;
if (sscanf_s(name, "%llu", &res) != 1) {
cm_panic(0);
}
return res;
}
status_t dss_open_volume_vtable(const char *name, const char *code, int flags, dss_volume_t *volume)
{
volume->handle = vtable_name_to_ptid(name);
if (volume->handle <= 0) {
DSS_THROW_ERROR(ERR_DSS_VOLUME_OPEN, name, cm_get_os_error());
return CM_ERROR;
}
volume->unaligned_handle = vtable_name_to_ptid(name);
if (volume->unaligned_handle <= 0) {
DSS_THROW_ERROR(ERR_DSS_VOLUME_OPEN, name, cm_get_os_error());
return CM_ERROR;
}
errno_t ret = snprintf_s(volume->name, DSS_MAX_VOLUME_PATH_LEN, DSS_MAX_VOLUME_PATH_LEN - 1, "%s", name);
DSS_SECUREC_SS_RETURN_IF_ERROR(ret, CM_ERROR);
volume->name_p = volume->name;
return CM_SUCCESS;
}
status_t dss_open_simple_volume_vtable(const char *name, int flags, dss_simple_volume_t *volume)
{
volume->handle = vtable_name_to_ptid(name);
if (volume->handle <= 0) {
DSS_THROW_ERROR(ERR_DSS_VOLUME_OPEN, name, cm_get_os_error());
return CM_ERROR;
}
volume->unaligned_handle = vtable_name_to_ptid(name);
if (volume->unaligned_handle <= 0) {
DSS_THROW_ERROR(ERR_DSS_VOLUME_OPEN, name, cm_get_os_error());
return CM_ERROR;
}
return CM_SUCCESS;
}
void dss_close_volume_vtable(dss_volume_t *volume)
{
if (memset_s(volume, sizeof(dss_volume_t), 0, sizeof(dss_volume_t)) != EOK) {
cm_panic(0);
}
volume->handle = DSS_INVALID_HANDLE;
volume->unaligned_handle = DSS_INVALID_HANDLE;
}
void dss_close_simple_volume_vtable(dss_simple_volume_t *simple_volume)
{
simple_volume->handle = DSS_INVALID_HANDLE;
simple_volume->unaligned_handle = DSS_INVALID_HANDLE;
}
uint64 dss_get_volume_size_vtable(dss_volume_t *volume)
{
uint64_t size = 0;
uint32_t alignedSize = 0;
uint16_t type = 0;
bool exist = false;
status_t res = VtableList((uint64_t)volume->handle, &exist, &size, &alignedSize, &type);
if (res != CM_SUCCESS) {
DSS_LOG_WITH_OS_MSG("failed to get volume size vtable %s", volume->name_p);
DSS_THROW_ERROR(ERR_DSS_VOLUME_SEEK, volume->name_p, volume->id, res);
return DSS_INVALID_64;
}
return (uint64)size;
}
status_t dss_try_pread_volume_vtable(dss_volume_t *volume, int64 offset, char *buffer,
int32 size, int32 *read_size)
{
CResult res = VtableRead((uint64_t)volume->handle, (uint64_t)offset, size, buffer);
if (res != RET_CACHE_OK) {
DSS_THROW_ERROR(ERR_DSS_VOLUME_READ, volume->name_p, volume->id, cm_get_os_error());
LOG_RUN_ERR("Failed to read volume %s, vtable ptid:%lld, volume id:%u,size:%d, offset:%lld, vtable_errno:%d.",
volume->name_p, volume->handle, volume->id, size, offset, (int)res);
return CM_ERROR;
}
*read_size = size;
return CM_SUCCESS;
}
int32 dss_try_pwrite_volume_vtable(dss_volume_t *volume, int64 offset, char *buffer,
int32 size, int32 *written_size)
{
CResult res = VtableWriteAdapte((uint64_t)volume->handle, (uint64_t)offset, size, buffer);
if (res != RET_CACHE_OK) {
DSS_THROW_ERROR(ERR_DSS_VOLUME_WRITE, volume->name_p, volume->id, cm_get_os_error());
LOG_RUN_ERR("Failed to write volume %s, vtable ptid:%lld, volume id:%u,size:%d, offset:%lld, vtable_errno:%d.",
volume->name_p, volume->handle, volume->id, size, offset, (int)res);
return CM_ERROR;
}
*written_size = size;
return res;
}
int32 dss_try_append_volume_vtable(dss_volume_t *volume, int64 offset, char *buffer,
int32 size, int32 *written_size)
{
CResult res = VtableAppendAdapter((uint64_t)volume->handle, (uint64_t)offset, size, buffer);
if (res != RET_CACHE_OK) {
DSS_THROW_ERROR(ERR_DSS_VOLUME_WRITE, volume->name_p, volume->id, cm_get_os_error());
LOG_RUN_ERR("Failed to append volume %s, vtable ptid:%lld, volume id:%u,size:%d, offset:%lld, vtable_errno:%d.",
volume->name_p, volume->handle, volume->id, size, offset, (int)res);
return CM_ERROR;
}
*written_size = size;
return res;
}