diff --git a/src/ucp/core/ucp_context.c b/src/ucp/core/ucp_context.c index eaee414dd8c..7d76f69f32d 100644 --- a/src/ucp/core/ucp_context.c +++ b/src/ucp/core/ucp_context.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -863,6 +864,47 @@ ucs_status_t ucp_config_modify_internal(ucp_config_t *config, const char *name, value); } +static void ucp_config_query_uct_components(void) +{ + static ucs_init_once_t init_once = UCS_INIT_ONCE_INITIALIZER; + uct_component_h *components; + unsigned num_components; + ucs_status_t status; + + UCS_INIT_ONCE(&init_once) { + status = uct_query_components(&components, &num_components); + if (status == UCS_OK) { + uct_release_component_list(components); + } else { + ucs_warn("failed to query UCT components: %s", + ucs_status_string(status)); + } + } +} + +static int ucp_config_global_list_has_field(const char *name) +{ + const ucs_config_global_list_entry_t *entry; + const char *field_name; + size_t prefix_len; + + ucs_list_for_each(entry, &ucs_config_global_list, list) { + field_name = name; + if (entry->prefix != NULL) { + prefix_len = strlen(entry->prefix); + if (!strncmp(entry->prefix, field_name, prefix_len)) { + field_name += prefix_len; + } + } + + if (ucs_config_parser_has_field(entry->table, field_name)) { + return 1; + } + } + + return 0; +} + ucs_status_t ucp_config_modify(ucp_config_t *config, const char *name, const char *value) { @@ -878,6 +920,18 @@ ucs_status_t ucp_config_modify(ucp_config_t *config, const char *name, return status; } + if (ucs_global_opts_is_unmodifiable(name)) { + ucs_debug("%s configuration cannot be changed, the change is only " + "available through the environment variable", + name); + return UCS_ERR_UNSUPPORTED; + } + + ucp_config_query_uct_components(); + if (!ucp_config_global_list_has_field(name)) { + return UCS_ERR_NO_ELEM; + } + return ucp_config_cached_key_add(&config->cached_key_list, name, value); } diff --git a/src/ucs/config/global_opts.c b/src/ucs/config/global_opts.c index 3cb8a8128bb..32fc8e54c3c 100644 --- a/src/ucs/config/global_opts.c +++ b/src/ucs/config/global_opts.c @@ -368,6 +368,11 @@ ucs_status_t ucs_global_opts_set_value_modifiable(const char *name, NULL, name, value); } +int ucs_global_opts_is_unmodifiable(const char *name) +{ + return ucs_config_parser_has_field(ucs_global_opts_read_only_table, name); +} + ucs_status_t ucs_global_opts_get_value(const char *name, char *value, size_t max) { diff --git a/src/ucs/config/global_opts.h b/src/ucs/config/global_opts.h index f1d4540e8a6..49b5cc81904 100644 --- a/src/ucs/config/global_opts.h +++ b/src/ucs/config/global_opts.h @@ -180,6 +180,14 @@ ucs_status_t ucs_global_opts_clone(void *dst); void ucs_global_opts_release(void); void ucs_global_opts_print(FILE *stream, ucs_config_print_flags_t print_flags); +/** + * Check if a field is unmodifiable. + * + * @param name Field name to check. + * @return 1 if the field is unmodifiable, 0 otherwise. + */ +int ucs_global_opts_is_unmodifiable(const char *name); + END_C_DECLS #endif diff --git a/src/ucs/config/parser.c b/src/ucs/config/parser.c index 696a4ebd218..5a01a114f27 100644 --- a/src/ucs/config/parser.c +++ b/src/ucs/config/parser.c @@ -2461,3 +2461,31 @@ void ucs_config_parser_cleanup() }) kh_destroy_inplace(ucs_config_map, &ucs_config_file_vars); } + +int ucs_config_parser_has_field(const ucs_config_field_t *fields, + const char *name) +{ + const ucs_config_field_t *field; + size_t table_name_len; + + if (!fields || !name) { + return 0; + } + + for (field = fields; !ucs_config_field_is_last(field); ++field) { + if (!strncmp(field->name, name, strlen(name))) { + return 1; + } + + if (ucs_config_is_table_field(field)) { + table_name_len = strlen(field->name); + if (!strncmp(field->name, name, table_name_len) && + ucs_config_parser_has_field(field->parser.arg, + name + table_name_len)) { + return 1; + } + } + } + + return 0; +} diff --git a/src/ucs/config/parser.h b/src/ucs/config/parser.h index 6b3f013a257..3c9a5299790 100644 --- a/src/ucs/config/parser.h +++ b/src/ucs/config/parser.h @@ -640,6 +640,16 @@ void ucs_config_parser_get_env_vars(ucs_string_buffer_t *env_strb, void ucs_config_parser_cleanup(void); +/** + * Check if a field exists in the configuration table. + * + * @param fields Array of fields which define the configuration table. + * @param name Field name to check. + * @return 1 if the field exists, 0 otherwise. + */ +int ucs_config_parser_has_field(const ucs_config_field_t *fields, + const char *name); + END_C_DECLS #endif diff --git a/test/gtest/ucp/test_ucp_worker.cc b/test/gtest/ucp/test_ucp_worker.cc index 943e1e769fb..9ee28aec16b 100644 --- a/test/gtest/ucp/test_ucp_worker.cc +++ b/test/gtest/ucp/test_ucp_worker.cc @@ -826,8 +826,13 @@ UCP_INSTANTIATE_TEST_CASE_TLS(test_ucp_worker_address_version, self, "self") class test_ucp_modify_uct_cfg : public test_ucp_context { public: test_ucp_modify_uct_cfg() : m_seg_size((ucs::rand() & 0x3ff) + 1024) { - ucp_config_modify(m_ucp_config, "IB_SEG_SIZE", - ucs::to_string(m_seg_size).c_str()); + const auto status = ucp_config_modify( + m_ucp_config, "IB_SEG_SIZE", + ucs::to_string(m_seg_size).c_str()); + if (status != UCS_OK) { + UCS_TEST_ABORT("Failed to set IB_SEG_SIZE: " << + ucs_status_string(status)); + } } void verify_seg_size(ucp_worker_h worker) const { @@ -838,7 +843,8 @@ class test_ucp_modify_uct_cfg : public test_ucp_context { if (wiface->attr.cap.flags & UCT_IFACE_FLAG_PUT_BCOPY) { EXPECT_EQ(m_seg_size, wiface->attr.cap.put.max_bcopy) - << "tl : " << worker->context->tl_rscs[tl_id].tl_rsc.tl_name; + << "tl : " << worker->context->tl_rscs[tl_id].tl_rsc.tl_name + << "dev : " << worker->context->tl_rscs[tl_id].tl_rsc.dev_name; } } }