mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-30 17:18:21 +03:00
config: add support for loading profiles
This patch adds --profile arg to lvm cmds and adds config/profile_dir configuration setting to select the directory where profiles are stored By default it's /etc/lvm/profile. The profiles are added by using new "add_profile" fn and then loaded using the "load_profile" fn. All profiles are stored in a cmd context within the new "struct profile_params": struct profile_params { const char *dir; struct profile *global_profile; struct dm_list profiles_to_load; struct dm_list profiles; }; ...where "dir" is the directory with profiles, "global_profile" is the profile that is set globally via the --profile arg (IOW, not set per VG/LV basis based on metadata record) and the "profiles" is the list with loaded profiles.
This commit is contained in:
parent
f89a8b81cf
commit
ebc236d085
@ -23,6 +23,9 @@ config {
|
||||
|
||||
# If enabled, any configuration mismatch aborts the LVM2 process.
|
||||
abort_on_errors = 0
|
||||
|
||||
# Directory where LVM looks for configuration profiles.
|
||||
profile_dir = "@DEFAULT_SYS_DIR@/@DEFAULT_PROFILE_SUBDIR"
|
||||
}
|
||||
|
||||
# This section allows you to configure which block devices should
|
||||
|
@ -595,6 +595,35 @@ static int _init_tag_configs(struct cmd_context *cmd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _init_profiles(struct cmd_context *cmd)
|
||||
{
|
||||
static char default_dir[PATH_MAX];
|
||||
const char *dir;
|
||||
struct profile_params *pp;
|
||||
|
||||
if (!(pp = dm_pool_zalloc(cmd->libmem, sizeof(*pp)))) {
|
||||
log_error("profile_params alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(dir = find_config_tree_str(cmd, config_profile_dir_CFG))) {
|
||||
if (dm_snprintf(default_dir, sizeof(default_dir), "%s/%s",
|
||||
cmd->system_dir, DEFAULT_PROFILE_SUBDIR) == -1) {
|
||||
log_error("Couldn't create default profile path '%s/%s'.",
|
||||
cmd->system_dir, DEFAULT_PROFILE_SUBDIR);
|
||||
return 0;
|
||||
}
|
||||
dir = default_dir;
|
||||
}
|
||||
|
||||
pp->dir = dm_pool_strdup(cmd->libmem, dir);
|
||||
dm_list_init(&pp->profiles_to_load);
|
||||
dm_list_init(&pp->profiles);
|
||||
|
||||
cmd->profile_params = pp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct dm_config_tree *_merge_config_files(struct cmd_context *cmd, struct dm_config_tree *cft)
|
||||
{
|
||||
struct config_tree_list *cfl;
|
||||
@ -641,10 +670,11 @@ static void _destroy_config(struct cmd_context *cmd)
|
||||
{
|
||||
struct config_tree_list *cfl;
|
||||
struct dm_config_tree *cft;
|
||||
struct profile *profile;
|
||||
|
||||
/*
|
||||
* Configuration cascade:
|
||||
* CONFIG_STRING -> CONFIG_FILE/CONFIG_MERGED_FILES
|
||||
* CONFIG_STRING -> CONFIG_PROFILE -> CONFIG_FILE/CONFIG_MERGED_FILES
|
||||
*/
|
||||
|
||||
/* CONFIG_FILE/CONFIG_MERGED_FILES */
|
||||
@ -657,6 +687,17 @@ static void _destroy_config(struct cmd_context *cmd)
|
||||
config_destroy(cfl->cft);
|
||||
dm_list_init(&cmd->config_files);
|
||||
|
||||
/* CONFIG_PROFILE */
|
||||
if (cmd->profile_params) {
|
||||
remove_config_tree_by_source(cmd, CONFIG_PROFILE);
|
||||
dm_list_iterate_items(profile, &cmd->profile_params->profiles_to_load)
|
||||
config_destroy(profile->cft);
|
||||
dm_list_iterate_items(profile, &cmd->profile_params->profiles)
|
||||
config_destroy(profile->cft);
|
||||
dm_list_init(&cmd->profile_params->profiles_to_load);
|
||||
dm_list_init(&cmd->profile_params->profiles);
|
||||
}
|
||||
|
||||
/* CONFIG_STRING */
|
||||
if ((cft = remove_config_tree_by_source(cmd, CONFIG_STRING)))
|
||||
config_destroy(cft);
|
||||
@ -1427,6 +1468,9 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||
if (!_process_config(cmd))
|
||||
goto_out;
|
||||
|
||||
if (!_init_profiles(cmd))
|
||||
goto_out;
|
||||
|
||||
if (!(cmd->dev_types = create_dev_types(cmd->proc_dir,
|
||||
find_config_tree_node(cmd, devices_types_CFG))))
|
||||
goto_out;
|
||||
@ -1470,6 +1514,7 @@ out:
|
||||
cmd = NULL;
|
||||
}
|
||||
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,7 @@ struct config_info {
|
||||
};
|
||||
|
||||
struct dm_config_tree;
|
||||
struct profile_params;
|
||||
struct archive_params;
|
||||
struct backup_params;
|
||||
struct arg_values;
|
||||
@ -104,6 +105,8 @@ struct cmd_context {
|
||||
struct config_info current_settings;
|
||||
struct dm_hash_table *cft_def_hash; /* cft definition hash used for validity check */
|
||||
|
||||
struct profile_params *profile_params;
|
||||
|
||||
struct archive_params *archive_params;
|
||||
struct backup_params *backup_params;
|
||||
const char *stripe_filler;
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "str_list.h"
|
||||
#include "toolcontext.h"
|
||||
#include "lvm-file.h"
|
||||
#include "memlock.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
@ -1302,3 +1303,77 @@ struct dm_config_tree *config_def_create_tree(struct config_def_tree_spec *spec)
|
||||
cft->root = root;
|
||||
return cft;
|
||||
}
|
||||
|
||||
struct profile *add_profile(struct cmd_context *cmd, const char *profile_name)
|
||||
{
|
||||
struct profile *profile;
|
||||
|
||||
/* Do some sanity checks first. */
|
||||
if (!profile_name || !*profile_name) {
|
||||
log_error("Undefined profile name.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strchr(profile_name, '/')) {
|
||||
log_error("%s: bad profile name, it contains '/'.", profile_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check if the profile is added already... */
|
||||
dm_list_iterate_items(profile, &cmd->profile_params->profiles_to_load) {
|
||||
if (!strcmp(profile->name, profile_name))
|
||||
return profile;
|
||||
}
|
||||
dm_list_iterate_items(profile, &cmd->profile_params->profiles) {
|
||||
if (!strcmp(profile->name, profile_name))
|
||||
return profile;
|
||||
}
|
||||
|
||||
if (!(profile = dm_pool_zalloc(cmd->libmem, sizeof(*profile)))) {
|
||||
log_error("profile allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
profile->name = dm_pool_strdup(cmd->libmem, profile_name);
|
||||
dm_list_add(&cmd->profile_params->profiles_to_load, &profile->list);
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
int load_profile(struct cmd_context *cmd, struct profile *profile) {
|
||||
static char profile_path[PATH_MAX];
|
||||
|
||||
if (critical_section()) {
|
||||
log_error(INTERNAL_ERROR "trying to load profile %s "
|
||||
"in critical section.", profile->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (profile->cft)
|
||||
return 1;
|
||||
|
||||
if (dm_snprintf(profile_path, sizeof(profile_path), "%s/%s.profile",
|
||||
cmd->profile_params->dir, profile->name) < 0) {
|
||||
log_error("LVM_SYSTEM_DIR or profile name too long");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(profile->cft = config_file_open_and_read(profile_path, CONFIG_PROFILE)))
|
||||
return 0;
|
||||
|
||||
dm_list_move(&cmd->profile_params->profiles, &profile->list);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int load_pending_profiles(struct cmd_context *cmd)
|
||||
{
|
||||
struct profile *profile, *temp_profile;
|
||||
|
||||
dm_list_iterate_items_safe(profile, temp_profile, &cmd->profile_params->profiles_to_load) {
|
||||
if (!load_profile(cmd, profile))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -34,6 +34,19 @@ typedef enum {
|
||||
CONFIG_PROFILE /* profile config */
|
||||
} config_source_t;
|
||||
|
||||
struct profile {
|
||||
struct dm_list list;
|
||||
const char *name;
|
||||
struct dm_config_tree *cft;
|
||||
};
|
||||
|
||||
struct profile_params {
|
||||
const char *dir; /* subdir in LVM_SYSTEM_DIR where LVM looks for profiles */
|
||||
struct profile *global_profile; /* profile that overrides any other VG/LV-based profile ('--profile' cmd line arg) */
|
||||
struct dm_list profiles_to_load;/* list of profiles which are only added, but still need to be loaded for any use */
|
||||
struct dm_list profiles; /* list of profiles which are loaded already and which are ready for use */
|
||||
};
|
||||
|
||||
#define CFG_PATH_MAX_LEN 64
|
||||
|
||||
/*
|
||||
@ -114,6 +127,10 @@ enum {
|
||||
#undef cfg_array
|
||||
};
|
||||
|
||||
struct profile *add_profile(struct cmd_context *cmd, const char *profile_name);
|
||||
int load_profile(struct cmd_context *cmd, struct profile *profile);
|
||||
int load_pending_profiles(struct cmd_context *cmd);
|
||||
|
||||
int config_def_get_path(char *buf, size_t buf_size, int id);
|
||||
int config_def_check(struct cmd_context *cmd, int force, int skip, int suppress_messages);
|
||||
|
||||
|
@ -68,6 +68,7 @@ cfg_section(tags_CFG_SECTION, "tags", root_CFG_SECTION, 0, vsn(1, 0, 18), NULL)
|
||||
|
||||
cfg(config_checks_CFG, "checks", config_CFG_SECTION, 0, CFG_TYPE_BOOL, 1, vsn(2, 2, 99), "Configuration tree check on each LVM command execution.")
|
||||
cfg(config_abort_on_errors_CFG, "abort_on_errors", config_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2,2,99), "Abort LVM command execution if configuration is invalid.")
|
||||
cfg(config_profile_dir_CFG, "profile_dir", config_CFG_SECTION, 0, CFG_TYPE_STRING, 0, vsn(2, 2, 99), "Directory with configuration profiles.")
|
||||
|
||||
cfg(devices_dir_CFG, "dir", devices_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_DEV_DIR, vsn(1, 0, 0), NULL)
|
||||
cfg_array(devices_scan_CFG, "scan", devices_CFG_SECTION, 0, CFG_TYPE_STRING, "#S/dev", vsn(1, 0, 0), NULL)
|
||||
|
@ -406,6 +406,13 @@ static void _unlock_mem_if_possible(struct cmd_context *cmd)
|
||||
|
||||
void critical_section_inc(struct cmd_context *cmd, const char *reason)
|
||||
{
|
||||
/*
|
||||
* Profiles are loaded on-demand so make sure that before
|
||||
* entering the critical section all needed profiles are
|
||||
* loaded to avoid the disk access later.
|
||||
*/
|
||||
load_pending_profiles(cmd);
|
||||
|
||||
if (!_critical_section) {
|
||||
_critical_section = 1;
|
||||
log_debug_mem("Entering critical section (%s).", reason);
|
||||
|
@ -91,6 +91,7 @@ arg(writemostly_ARG, '\0', "writemostly", string_arg, ARG_GROUPABLE)
|
||||
arg(writebehind_ARG, '\0', "writebehind", int_arg, 0)
|
||||
arg(minrecoveryrate_ARG, '\0', "minrecoveryrate", size_kb_arg, 0)
|
||||
arg(maxrecoveryrate_ARG, '\0', "maxrecoveryrate", size_kb_arg, 0)
|
||||
arg(profile_ARG, '\0', "profile", string_arg, 0)
|
||||
|
||||
/* Allow some variations */
|
||||
arg(resizable_ARG, '\0', "resizable", yes_no_arg, 0)
|
||||
|
@ -620,7 +620,8 @@ void lvm_register_commands(void)
|
||||
debug_ARG, help_ARG, help2_ARG, \
|
||||
version_ARG, verbose_ARG, \
|
||||
yes_ARG, \
|
||||
quiet_ARG, config_ARG, -1);
|
||||
quiet_ARG, config_ARG, \
|
||||
profile_ARG, -1);
|
||||
#include "commands.h"
|
||||
#undef xx
|
||||
}
|
||||
@ -1051,6 +1052,7 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
|
||||
int locking_type;
|
||||
int monitoring;
|
||||
struct dm_config_tree *old_cft;
|
||||
struct profile *profile;
|
||||
|
||||
init_error_message_produced(0);
|
||||
|
||||
@ -1089,6 +1091,16 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (arg_count(cmd, profile_ARG)) {
|
||||
if (!(profile = add_profile(cmd, arg_str_value(cmd, profile_ARG, NULL)))) {
|
||||
log_error("Failed to add configuration profile.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
log_debug("Setting global configuration profile \"%s\".", profile->name);
|
||||
/* This profile will override any VG/LV-based profile if present */
|
||||
cmd->profile_params->global_profile = profile;
|
||||
}
|
||||
|
||||
if ((ret = _get_settings(cmd)))
|
||||
goto_out;
|
||||
_apply_settings(cmd);
|
||||
|
Loading…
Reference in New Issue
Block a user