[lvm-devel] master - config: add support for loading profiles
Peter Rajnoha
prajnoha at fedoraproject.org
Tue Jul 2 13:32:31 UTC 2013
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=ebc236d085116e869b5873e2b5409674c2cd2a8d
Commit: ebc236d085116e869b5873e2b5409674c2cd2a8d
Parent: f89a8b81cf795d9e658341b4755046b3824acdaa
Author: Peter Rajnoha <prajnoha at redhat.com>
AuthorDate: Tue Jun 25 12:27:04 2013 +0200
Committer: Peter Rajnoha <prajnoha at redhat.com>
CommitterDate: Tue Jul 2 15:19:08 2013 +0200
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.
---
doc/example.conf.in | 3 ++
lib/commands/toolcontext.c | 47 +++++++++++++++++++++++++-
lib/commands/toolcontext.h | 3 ++
lib/config/config.c | 75 ++++++++++++++++++++++++++++++++++++++++++
lib/config/config.h | 17 +++++++++
lib/config/config_settings.h | 1 +
lib/mm/memlock.c | 7 ++++
tools/args.h | 1 +
tools/lvmcmdline.c | 14 +++++++-
9 files changed, 166 insertions(+), 2 deletions(-)
diff --git a/doc/example.conf.in b/doc/example.conf.in
index 1620721..3bc8c3c 100644
--- a/doc/example.conf.in
+++ b/doc/example.conf.in
@@ -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
diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c
index 718fa65..f8b861b 100644
--- a/lib/commands/toolcontext.c
+++ b/lib/commands/toolcontext.c
@@ -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;
}
diff --git a/lib/commands/toolcontext.h b/lib/commands/toolcontext.h
index f6a09a7..7551245 100644
--- a/lib/commands/toolcontext.h
+++ b/lib/commands/toolcontext.h
@@ -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;
diff --git a/lib/config/config.c b/lib/config/config.c
index df65d38..5711ead 100644
--- a/lib/config/config.c
+++ b/lib/config/config.c
@@ -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;
+}
diff --git a/lib/config/config.h b/lib/config/config.h
index f4c77ed..ef75580 100644
--- a/lib/config/config.h
+++ b/lib/config/config.h
@@ -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);
diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h
index 6229f2e..65d869b 100644
--- a/lib/config/config_settings.h
+++ b/lib/config/config_settings.h
@@ -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)
diff --git a/lib/mm/memlock.c b/lib/mm/memlock.c
index 08876b0..fda3bb8 100644
--- a/lib/mm/memlock.c
+++ b/lib/mm/memlock.c
@@ -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);
diff --git a/tools/args.h b/tools/args.h
index 2fed97e..cadd211 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -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)
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index 0372434..1111df6 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -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);
More information about the lvm-devel
mailing list