diff --git a/Jenkinsfile b/Jenkinsfile index 53f34c8a148..e218ad242b4 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -3,7 +3,7 @@ /* groovylint-disable DuplicateMapLiteral, DuplicateNumberLiteral */ /* groovylint-disable DuplicateStringLiteral, NestedBlockDepth, VariableName */ /* Copyright 2019-2024 Intel Corporation - * Copyright 2025 Hewlett Packard Enterprise Development LP + * Copyright 2025-2026 Hewlett Packard Enterprise Development LP * All rights reserved. * * This file is part of the DAOS Project. It is subject to the license terms @@ -1068,6 +1068,8 @@ pipeline { scm: 'daos-stack/daos', requiredResult: hudson.model.Result.UNSTABLE recordIssues enabledForFailure: true, + /* ignore warning/errors from PMDK logging system */ + filters: [excludeFile('pmdk/.+')], failOnError: false, ignoreQualityGate: true, qualityGates: [[threshold: 1, type: 'TOTAL_ERROR'], diff --git a/src/dtx/tests/SConscript b/src/dtx/tests/SConscript index 54a14127932..a6596fb008d 100644 --- a/src/dtx/tests/SConscript +++ b/src/dtx/tests/SConscript @@ -26,7 +26,8 @@ def scons(): # build dtx_ut - libraries = ['abt', 'bio', 'cmocka', 'daos_common_pmem', 'gurt', 'uuid', 'vea', 'pthread'] + libraries = ['abt', 'bio', 'cmocka', 'daos_common_pmem', 'gurt', 'uuid', 'vea', 'pthread', + 'pmemobj'] tenv = denv.Clone() tenv.Append(CPPPATH=[Dir('../../vos').srcnode()]) diff --git a/src/include/daos/debug.h b/src/include/daos/debug.h index bcf8834c517..bd1e12474d8 100644 --- a/src/include/daos/debug.h +++ b/src/include/daos/debug.h @@ -1,5 +1,6 @@ /** - * (C) Copyright 2015-2023 Intel Corporation. + * (C) Copyright 2015-2024 Intel Corporation. + * (C) Copyright 2025-2026 Hewlett Packard Enterprise Development LP * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -23,37 +24,37 @@ * predefined debug facilities (subsystems/modules), they have to be declared * before including any libgurt headers */ -#define DAOS_FOREACH_LOG_FAC(ACTION, arg) \ - ACTION(daos, daos, arg) \ - ACTION(array, array, arg) \ - ACTION(kv, kv, arg) \ - ACTION(common, common, arg) \ - ACTION(tree, tree, arg) \ - ACTION(vos, vos, arg) \ - ACTION(client, client, arg) \ - ACTION(server, server, arg) \ - ACTION(rdb, rdb, arg) \ - ACTION(rsvc, rsvc, arg) \ - ACTION(pool, pool, arg) \ - ACTION(container, container, arg) \ - ACTION(object, object, arg) \ - ACTION(placement, placement, arg) \ - ACTION(rebuild, rebuild, arg) \ - ACTION(mgmt, mgmt, arg) \ - ACTION(bio, bio, arg) \ - ACTION(tests, tests, arg) \ - ACTION(dfs, dfs, arg) \ - ACTION(duns, duns, arg) \ - ACTION(drpc, drpc, arg) \ - ACTION(security, security, arg) \ - ACTION(dtx, dtx, arg) \ - ACTION(chk, chk, arg) \ - ACTION(dfuse, dfuse, arg) \ - ACTION(il, il, arg) \ - ACTION(csum, csum, arg) \ - ACTION(pipeline, pipeline, arg) \ - ACTION(stack, stack, arg) - +#define DAOS_FOREACH_LOG_FAC(ACTION, arg) \ + ACTION(daos, daos, arg) \ + ACTION(array, array, arg) \ + ACTION(kv, kv, arg) \ + ACTION(common, common, arg) \ + ACTION(tree, tree, arg) \ + ACTION(vos, vos, arg) \ + ACTION(pmdk, pmdk, arg) \ + ACTION(client, client, arg) \ + ACTION(server, server, arg) \ + ACTION(rdb, rdb, arg) \ + ACTION(rsvc, rsvc, arg) \ + ACTION(pool, pool, arg) \ + ACTION(container, container, arg) \ + ACTION(object, object, arg) \ + ACTION(placement, placement, arg) \ + ACTION(rebuild, rebuild, arg) \ + ACTION(mgmt, mgmt, arg) \ + ACTION(bio, bio, arg) \ + ACTION(tests, tests, arg) \ + ACTION(dfs, dfs, arg) \ + ACTION(duns, duns, arg) \ + ACTION(drpc, drpc, arg) \ + ACTION(security, security, arg) \ + ACTION(dtx, dtx, arg) \ + ACTION(chk, chk, arg) \ + ACTION(dfuse, dfuse, arg) \ + ACTION(il, il, arg) \ + ACTION(csum, csum, arg) \ + ACTION(pipeline, pipeline, arg) \ + ACTION(stack, stack, arg) #define DAOS_FOREACH_DB(ACTION, arg) \ /** metadata operation */ \ diff --git a/src/include/gurt/debug.h b/src/include/gurt/debug.h index e47f4ab0cd9..64f73bef7a2 100644 --- a/src/include/gurt/debug.h +++ b/src/include/gurt/debug.h @@ -1,5 +1,7 @@ /* * (C) Copyright 2017-2023 Intel Corporation. + * (C) Copyright 2025 Google LLC + * (C) Copyright 2025-2026 Hewlett Packard Enterprise Development LP * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -97,20 +99,20 @@ extern void (*d_alt_assert)(const int, const char*, const char*, const int); _D_LOG_CHECK(func, __tmp_mask, mask, ##__VA_ARGS__); \ } while (0) -#define _D_DEBUG(func, flag, ...) \ - do { \ - if (__builtin_expect(DD_FLAG(flag, D_LOGFAC), 0)) { \ - if (DD_FLAG(flag, D_LOGFAC) == (int)DLOG_UNINIT) { \ - _D_LOG_CHECK(func, \ - DD_FLAG(flag, D_LOGFAC), \ - (flag) | D_LOGFAC, \ - ##__VA_ARGS__); \ - break; \ - } \ - func(DD_FLAG(flag, D_LOGFAC), ##__VA_ARGS__); \ - } \ +#define _D_DEBUG_W_SAVED_MASK(func, saved_mask, level, ...) \ + do { \ + if (__builtin_expect(saved_mask, 0)) { \ + if ((saved_mask) == (int)DLOG_UNINIT) { \ + _D_LOG_CHECK(func, saved_mask, (level) | D_LOGFAC, ##__VA_ARGS__); \ + break; \ + } \ + func(saved_mask, ##__VA_ARGS__); \ + } \ } while (0) +#define _D_DEBUG(func, flag, ...) \ + _D_DEBUG_W_SAVED_MASK(func, DD_FLAG(flag, D_LOGFAC), flag, ##__VA_ARGS__) + #define D_LOG_ENABLED(flag) \ ({ \ _D_DEBUG(D_NOOP, flag); \ diff --git a/src/utils/ddb/tests/SConscript b/src/utils/ddb/tests/SConscript index 14fa7f0cff5..dc29dc8f848 100644 --- a/src/utils/ddb/tests/SConscript +++ b/src/utils/ddb/tests/SConscript @@ -42,8 +42,8 @@ def scons(): # Build unit tests denv = env.Clone() - prereqs.require(denv, 'argobots', 'spdk') - libs = ['uuid', 'daos_common_pmem', 'gurt', 'vea', 'abt', 'bio', 'cmocka', 'pthread'] + prereqs.require(denv, 'argobots', 'spdk', 'pmdk') + libs = ['uuid', 'daos_common_pmem', 'gurt', 'vea', 'abt', 'bio', 'cmocka', 'pthread', 'pmemobj'] denv.AppendUnique(RPATH_FULL=['$PREFIX/lib64/daos_srv']) denv.AppendUnique(CPPPATH=[Dir('../').srcnode()]) denv.AppendUnique(CPPPATH=[Dir('../../../vos/').srcnode()]) diff --git a/src/vos/SConscript b/src/vos/SConscript index d91a2f3028a..0e4d69bbf9f 100644 --- a/src/vos/SConscript +++ b/src/vos/SConscript @@ -6,7 +6,7 @@ FILES = ["evt_iter.c", "vos_common.c", "vos_iterator.c", "vos_io.c", "vos_dtx.c", "vos_query.c", "vos_overhead.c", "vos_dtx_iter.c", "vos_gc.c", "vos_ilog.c", "ilog.c", "vos_ts.c", "lru_array.c", "vos_space.c", "sys_db.c", - "vos_csum_recalc.c", "vos_pool_scrub.c"] + "vos_csum_recalc.c", "vos_pool_scrub.c", "pmdk_log.c"] def build_vos(env, standalone): diff --git a/src/vos/pmdk_log.c b/src/vos/pmdk_log.c new file mode 100644 index 00000000000..5df3de18ae5 --- /dev/null +++ b/src/vos/pmdk_log.c @@ -0,0 +1,118 @@ +/** + * (C) Copyright 2024 Intel Corporation. + * (C) Copyright 2025 Google LLC + * (C) Copyright 2025-2026 Hewlett Packard Enterprise Development LP + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + */ +/** + * Connecting the PMDK's logging to DAOS logging. + * + * vos/pmdk_log.c + */ + +#define D_LOGFAC DD_FAC(pmdk) + +#ifdef DAOS_PMEM_BUILD +#include +#include +#include +#include + +#define PMDK_LOG_2_DAOS_LOG_INIT(PMDK_LEVEL, DAOS_LEVEL) \ + [PMDK_LEVEL] = {.level = DAOS_LEVEL, .saved_mask = &DD_FLAG(DAOS_LEVEL, D_LOGFAC)} + +static struct { + int level; + int *saved_mask; +} pmemobj_log_level_2_daos_log[] = { + PMDK_LOG_2_DAOS_LOG_INIT(PMEMOBJ_LOG_LEVEL_HARK, DLOG_INFO), + PMDK_LOG_2_DAOS_LOG_INIT(PMEMOBJ_LOG_LEVEL_FATAL, DLOG_CRIT), + PMDK_LOG_2_DAOS_LOG_INIT(PMEMOBJ_LOG_LEVEL_ERROR, DLOG_ERR), + PMDK_LOG_2_DAOS_LOG_INIT(PMEMOBJ_LOG_LEVEL_WARNING, DLOG_WARN), + PMDK_LOG_2_DAOS_LOG_INIT(PMEMOBJ_LOG_LEVEL_NOTICE, DLOG_NOTE), + PMDK_LOG_2_DAOS_LOG_INIT(PMEMOBJ_LOG_LEVEL_INFO, DLOG_INFO), + PMDK_LOG_2_DAOS_LOG_INIT(PMEMOBJ_LOG_LEVEL_DEBUG, DLOG_DBG), +}; + +#undef PMDK_LOG_2_DAOS_LOG_INIT + +static void +pmdk_log_function(enum pmemobj_log_level level, const char *file_name, unsigned line_no, + const char *function_name, const char *message) +{ +/* + * There is a set of handy macros for each of the message priorities + * that are used normally to report a message. They can't be used here + * directly since the file name, line number and the function name + * are provided via arguments to this callback function instead of + * via macro definitions (__FILE__, __LINE__, and __func__) as + * _D_LOG_NOCHECK() would like to consume them. So, the message here is + * provided a few macro-calls later via _D_DEBUG_W_SAVED_MASK() macro which allows + * to swap the _D_LOG_NOCHECK macro for a custom macro. + * + * D_ERROR(...) -> D_DEBUG(DLOG_ERR, ...) -> + * _D_DEBUG(_D_LOG_NOCHECK, DLOG_ERR, ...) -> + * _D_DEBUG_W_SAVED_MASK(_D_LOG_NOCHECK, DD_FLAG(DLOG_ERR, D_LOGFAC), DLOG_ERR, ...) + */ + +/* + * A custom variant of _D_LOG_NOCHECK() which passes the file name, + * line number and the function name from the local variables. + */ +#define PMDK_LOG_FUNCTION_MAX_FILENAME 255 +#define PMDK_LOG_NOCHECK(mask, fmt, ...) \ + do { \ + char file_name_buff[PMDK_LOG_FUNCTION_MAX_FILENAME] = "pmdk/"; \ + char *local_file_name = file_name_buff + sizeof("pmdk/") - 1; \ + \ + /* normalize file path - remove leading "../" */ \ + while ((*file_name == '.') && (*(file_name + 1) == '.') && \ + (*(file_name + 2) == '/')) { \ + file_name += 3; \ + } \ + \ + /* simplify file path by removing cyclic pattern "src/../src" */ \ + if (strncmp(file_name, "src/../src", sizeof("src/../src") - 1) == 0) { \ + file_name += sizeof("src/../") - 1; \ + } \ + /* Add "pmdk/" prefix to file name */ \ + /* Prefix is needed to filter out PMDK messages in NLT results analysis */ \ + /* as it is implemented in https://github.com/daos-stack/pipeline-lib/pull/457 */ \ + \ + while ((local_file_name < file_name_buff + PMDK_LOG_FUNCTION_MAX_FILENAME - 1) && \ + (*file_name != '\0')) { \ + *(local_file_name++) = *(file_name++); \ + } \ + *local_file_name = '\0'; \ + d_log(mask, "%s:%d %s() " fmt, file_name_buff, line_no, function_name, \ + ##__VA_ARGS__); \ + } while (0) + + int *saved_mask = pmemobj_log_level_2_daos_log[level].saved_mask; + _D_DEBUG_W_SAVED_MASK(PMDK_LOG_NOCHECK, *saved_mask, + pmemobj_log_level_2_daos_log[level].level, "%s\n", message); + +#undef PMDK_LOG_NOCHECK +} + +int +pmdk_log_attach(void) +{ + int rc = pmemobj_log_set_function(pmdk_log_function); + if (rc == 0) { + return 0; + } else { + return daos_errno2der(errno); + } +} + +#else + +int +pmdk_log_attach(void) +{ + ; +} + +#endif /* DAOS_PMEM_BUILD */ diff --git a/src/vos/pmdk_log.h b/src/vos/pmdk_log.h new file mode 100644 index 00000000000..1dd2f17ee61 --- /dev/null +++ b/src/vos/pmdk_log.h @@ -0,0 +1,18 @@ +/** + * (C) Copyright 2024 Intel Corporation. + * (C) Copyright 2025-2026 Hewlett Packard Enterprise Development LP + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + */ +/** + * Connecting the PMDK's logging to DAOS logging. + * vos/pmdk_log.h + */ + +#ifndef __PMDK_LOG__ +#define __PMDK_LOG__ + +int +pmdk_log_attach(void); + +#endif /* __PMDK_LOG__ */ diff --git a/src/vos/vos_common.c b/src/vos/vos_common.c index b9101cd07e4..6312629d19e 100644 --- a/src/vos/vos_common.c +++ b/src/vos/vos_common.c @@ -1,6 +1,6 @@ /** * (C) Copyright 2016-2024 Intel Corporation. - * (C) Copyright 2025 Hewlett Packard Enterprise Development LP + * (C) Copyright 2025-2026 Hewlett Packard Enterprise Development LP * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -24,6 +24,7 @@ #include #include #include "vos_internal.h" +#include "pmdk_log.h" struct vos_self_mode { struct vos_tls *self_tls; @@ -608,6 +609,12 @@ vos_mod_init(void) if (vos_start_epoch == DAOS_EPOCH_MAX) vos_start_epoch = d_hlc_get(); + rc = pmdk_log_attach(); + if (rc != 0) { + D_ERROR("PMDK log initialization error\n"); + return rc; + } + rc = vos_pool_settings_init(bio_nvme_configured(SMD_DEV_TYPE_META)); if (rc != 0) { D_ERROR("VOS pool setting initialization error\n");