From f29705c98ceee74636df19e53b7239481d268d49 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Fri, 7 Nov 2014 13:38:27 -0600 Subject: VG lock_type and lvmlockd setup The locking required to access a VG is a property of the VG, and is specified in the VG metadata as the "lock_type". When lvm sees a VG, it looks at the VG's lock_type to determine if locks are needed and from where: - If the VG has no lock_type, or lock_type "none", then no locks are needed. This a "local VG". If the VG is visible to multiple hosts, the VG system_id provides basic protection. A VG with an unmatching system_id is inaccessible. - If the VG has lock_type "sanlock" or "dlm", then locks are needed from lvmlockd, which acquires locks from either sanlock or dlm respectively. This is a "dlock VG". If lvmlockd or the supporting lock manager are not running, then the dlock VG is inaccessible. - If the VG has the CLUSTERED status flag (or lock_type "clvm"), then locks are needed from clvmd. This is a "clvm VG". If clvmd or the supporting clustering or locking are not running, then the clvm VG is inaccessible. Settings in lvm.conf tell lvm commands which locking daemon to use: - global/use_lvmlockd=1: tells lvm to use lvmlockd when accessing VGs with lock_type sanlock|dlm. - global/locking_type=3: tells lvm to use clvmd when accessing VGs with CLUSTERED flag (or lock_type clvm). LVM commands cannot use both lvmlockd and clvmd at the same time: - use_lvmlockd=1 should be combined with locking_type=1 - locking_type=3 (clvmd) should be combined with use_lvmlockd=0 So, different configurations allow access to different VG's: - When configured to use lvmlockd, lvm commands can access VG's with lock_type sanlock|dlm, and VG's with CLUSTERED are ignored. - When configured to use clvmd (locking_type 3), lvm commands can access VG's with the CLUSTERED flag, and VG's with lock_type sanlock|dlm are ignored. - When configured to use neither lvmlockd nor clvmd, lvm commands can access only local VG's. lvm will ignore VG's with lock_type sanlock|dlm, and will ignore VG's with CLUSTERED (or lock_type clvm). A VG is created with a specific lock_type: - vgcreate --lock_type is a new syntax that can specify the lock_type directly. may be: none, clvm, sanlock, dlm. sanlock|dlm require lvmlockd to be configured (in lvm.conf) and running. clvm requires clvmd to be configured (in lvm.conf) and running. - vgcreate --clustered y (or -cy) is the old syntax that still works, but it is not preferred because the lock_type is not explicit. When clvmd is configured, -cy creates a VG with lock_type clvm. When lvmlockd is configured, -cy creates a VG with lock_type sanlock, but this can be changed to dlm with lvm.conf vgcreate_cy_lock_type. Notes: The LOCK_TYPE status flag is not strictly necessary, but is an attempt to prevent old versions of lvm (pre-lvmlockd) from using a VG with a lock_type. In the VG metadata, the lock_type string is accompanied by a lock_args string. The lock_args string is lock-manager-specific data associated with the VG. For sanlock, the location on disk of the locks, or for dlm, the cluster name. In a VG with lock_type sanlock|dlm, each LV also has a lock_type and lock_args in the metadata. The LV lock_type currently always matches the lock_type of the VG. For sanlock, the LV lock_args specify the disk location of the LV lock. --- configure.in | 26 ++++++ daemons/lvmlockd/lvmlockd-client.h | 36 ++++++++ include/.symlinks.in | 2 + lib/Makefile.in | 5 + lib/commands/toolcontext.c | 31 +++++++ lib/config/config_settings.h | 4 + lib/config/defaults.h | 3 + lib/format1/disk-rep.h | 1 + lib/format1/import-export.c | 6 ++ lib/format_text/export.c | 12 +++ lib/format_text/flags.c | 1 + lib/format_text/import_vsn1.c | 20 ++++ lib/locking/lvmlockd.c | 107 +++++++++++++++++++++ lib/locking/lvmlockd.h | 86 +++++++++++++++++ lib/metadata/lv.h | 2 + lib/metadata/lv_manip.c | 10 ++ lib/metadata/metadata-exported.h | 7 ++ lib/metadata/metadata.c | 20 ++++ lib/metadata/vg.c | 17 ++++ lib/metadata/vg.h | 3 + tools/Makefile.in | 1 + tools/args.h | 1 + tools/commands.h | 2 +- tools/dlock.c | 17 ++++ tools/dlock.h | 14 +++ tools/lvmcmdline.c | 4 +- tools/toollib.c | 185 +++++++++++++++++++++++++++++++++++-- tools/tools.h | 2 + tools/vgcreate.c | 1 + 29 files changed, 616 insertions(+), 10 deletions(-) create mode 100644 daemons/lvmlockd/lvmlockd-client.h create mode 100644 lib/locking/lvmlockd.c create mode 100644 lib/locking/lvmlockd.h create mode 100644 tools/dlock.c create mode 100644 tools/dlock.h diff --git a/configure.in b/configure.in index 9e10dc365..064f6980d 100644 --- a/configure.in +++ b/configure.in @@ -39,6 +39,7 @@ case "$host_os" in LIB_SUFFIX=so DEVMAPPER=yes LVMETAD=no + LVMLOCKD=no ODIRECT=yes DM_IOCTLS=yes SELINUX=yes @@ -1066,6 +1067,29 @@ if test "$BUILD_LVMETAD" = yes; then [Path to lvmetad pidfile.]) fi +################################################################################ +dnl -- Build lvmlockd +AC_MSG_CHECKING(whether to build lvmlockd) +AC_ARG_ENABLE(lvmlockd, + AC_HELP_STRING([--enable-lvmlockd], + [enable the LVM Lock Daemon]), + LVMLOCKD=$enableval) +AC_MSG_RESULT($LVMLOCKD) + +BUILD_LVMLOCKD=$LVMLOCKD + +if test x$BUILD_LVMLOCKD = xyes; then + AC_DEFINE([LVMLOCKD_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd.]) + + AC_ARG_WITH(lvmlockd-pidfile, + AC_HELP_STRING([--with-lvmlockd-pidfile=PATH], + [lvmlockd pidfile [[PID_DIR/lvmlockd.pid]]]), + LVMLOCKD_PIDFILE=$withval, + LVMLOCKD_PIDFILE="$DEFAULT_PID_DIR/lvmlockd.pid") + AC_DEFINE_UNQUOTED(LVMLOCKD_PIDFILE, ["$LVMLOCKD_PIDFILE"], + [Path to lvmlockd pidfile.]) +fi + ################################################################################ dnl -- Enable blkid wiping functionality AC_MSG_CHECKING(whether to enable libblkid detection of signatures when wiping) @@ -1649,6 +1673,7 @@ AC_SUBST(BLKID_WIPING) AC_SUBST(BUILD_CMIRRORD) AC_SUBST(BUILD_DMEVENTD) AC_SUBST(BUILD_LVMETAD) +AC_SUBST(BUILD_LVMLOCKD) AC_SUBST(CACHE) AC_SUBST(CFLAGS) AC_SUBST(CFLOW_CMD) @@ -1765,6 +1790,7 @@ AC_SUBST(UDEV_HAS_BUILTIN_BLKID) AC_SUBST(WRITE_INSTALL) AC_SUBST(DMEVENTD_PIDFILE) AC_SUBST(LVMETAD_PIDFILE) +AC_SUBST(LVMLOCKD_PIDFILE) AC_SUBST(CLVMD_PIDFILE) AC_SUBST(CMIRRORD_PIDFILE) AC_SUBST(interface) diff --git a/daemons/lvmlockd/lvmlockd-client.h b/daemons/lvmlockd/lvmlockd-client.h new file mode 100644 index 000000000..97402cee5 --- /dev/null +++ b/daemons/lvmlockd/lvmlockd-client.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * This file is part of LVM2. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU Lesser General Public License v.2.1. + */ + +#ifndef _LVM_LVMLOCKD_CLIENT_H +#define _LVM_LVMLOCKD_CLIENT_H + +#include "daemon-client.h" + +/* Wrappers to open/close connection */ + +static inline daemon_handle lvmlockd_open(const char *socket) +{ + daemon_info lvmlockd_info = { + .path = "lvmlockd", + .socket = socket ?: DEFAULT_RUN_DIR "/lvmlockd.socket", + .protocol = "lvmlockd", + .protocol_version = 1, + .autostart = 0 + }; + + return daemon_open(lvmlockd_info); +} + +static inline void lvmlockd_close(daemon_handle h) +{ + return daemon_close(h); +} + +#endif diff --git a/include/.symlinks.in b/include/.symlinks.in index 48c4d9d9c..4e11877a9 100644 --- a/include/.symlinks.in +++ b/include/.symlinks.in @@ -1,11 +1,13 @@ @top_srcdir@/daemons/clvmd/clvm.h @top_srcdir@/daemons/dmeventd/libdevmapper-event.h @top_srcdir@/daemons/lvmetad/lvmetad-client.h +@top_srcdir@/daemons/lvmlockd/lvmlockd-client.h @top_srcdir@/liblvm/lvm2app.h @top_srcdir@/lib/activate/activate.h @top_srcdir@/lib/activate/targets.h @top_srcdir@/lib/cache/lvmcache.h @top_srcdir@/lib/cache/lvmetad.h +@top_srcdir@/lib/locking/lvmlockd.h @top_srcdir@/lib/commands/toolcontext.h @top_srcdir@/lib/config/config.h @top_srcdir@/lib/config/config_settings.h diff --git a/lib/Makefile.in b/lib/Makefile.in index bad5d8cd3..bd7a1e403 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -193,6 +193,11 @@ ifeq ("@BUILD_LVMETAD@", "yes") SOURCES +=\ cache/lvmetad.c endif + +ifeq ("@BUILD_LVMLOCKD@", "yes") + SOURCES +=\ + locking/lvmlockd.c +endif ifeq ("@DMEVENTD@", "yes") CLDFLAGS += -L$(top_builddir)/daemons/dmeventd diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c index 2a372c2c7..b6b212597 100644 --- a/lib/commands/toolcontext.c +++ b/lib/commands/toolcontext.c @@ -29,6 +29,7 @@ #include "segtype.h" #include "lvmcache.h" #include "lvmetad.h" +#include "lvmlockd.h" #include "archiver.h" #ifdef HAVE_LIBDL @@ -396,7 +397,10 @@ static int _process_config(struct cmd_context *cmd) const struct dm_config_value *cv; int64_t pv_min_kb; const char *lvmetad_socket; + const char *lvmlockd_socket; int udev_disabled = 0; + int locking_type; + int use_lvmlockd; char sysfs_dir[PATH_MAX]; if (!_check_config(cmd)) @@ -552,6 +556,32 @@ static int _process_config(struct cmd_context *cmd) lvmetad_init(cmd); + /* + * clvmd and lvmlockd cannot be used concurrently, it is + * one or the other. + * global/locking_type=3 is the clvmd configuration. + * global/use_lvmlockd=1 is the lvmlockd configuration. + * + * use_lvmlockd should be combined with locking_type 1 (local). + */ + + locking_type = find_config_tree_int(cmd, global_locking_type_CFG, NULL); + use_lvmlockd = find_config_tree_bool(cmd, global_use_lvmlockd_CFG, NULL); + + if (locking_type == 3 && use_lvmlockd) { + log_error("ERROR: configuration setting use_lvmlockd cannot be used with locking_type 3."); + return 0; + } + + lvmlockd_disconnect(); + lvmlockd_socket = getenv("LVM_LVMLOCKD_SOCKET"); + if (!lvmlockd_socket) + lvmlockd_socket = DEFAULT_RUN_DIR "/lvmlockd.socket"; + + lvmlockd_set_socket(lvmlockd_socket); + lvmlockd_set_active(!!use_lvmlockd); + lvmlockd_init(cmd); + return 1; } @@ -1990,6 +2020,7 @@ void destroy_toolcontext(struct cmd_context *cmd) #endif dm_free(cmd); + lvmlockd_disconnect(); lvmetad_release_token(); lvmetad_disconnect(); diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h index 58f0323ea..39e4b0e5a 100644 --- a/lib/config/config_settings.h +++ b/lib/config/config_settings.h @@ -180,6 +180,7 @@ cfg(global_raid10_segtype_default_CFG, "raid10_segtype_default", global_CFG_SECT cfg(global_sparse_segtype_default_CFG, "sparse_segtype_default", global_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_SPARSE_SEGTYPE, vsn(2, 2, 112), NULL) cfg(global_lvdisplay_shows_full_device_path_CFG, "lvdisplay_shows_full_device_path", global_CFG_SECTION, CFG_PROFILABLE, CFG_TYPE_BOOL, DEFAULT_LVDISPLAY_SHOWS_FULL_DEVICE_PATH, vsn(2, 2, 89), NULL) cfg(global_use_lvmetad_CFG, "use_lvmetad", global_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2, 2, 93), NULL) +cfg(global_use_lvmlockd_CFG, "use_lvmlockd", global_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2, 2, 113), NULL) cfg(global_thin_check_executable_CFG, "thin_check_executable", global_CFG_SECTION, CFG_ALLOW_EMPTY, CFG_TYPE_STRING, THIN_CHECK_CMD, vsn(2, 2, 94), NULL) cfg_array(global_thin_check_options_CFG, "thin_check_options", global_CFG_SECTION, 0, CFG_TYPE_STRING, "#S" DEFAULT_THIN_CHECK_OPTIONS, vsn(2, 2, 96), NULL) cfg_array(global_thin_disabled_features_CFG, "thin_disabled_features", global_CFG_SECTION, CFG_ALLOW_EMPTY, CFG_TYPE_STRING, NULL, vsn(2, 2, 99), NULL) @@ -225,6 +226,9 @@ cfg(activation_polling_interval_CFG, "polling_interval", activation_CFG_SECTION, cfg(activation_auto_set_activation_skip_CFG, "auto_set_activation_skip", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_AUTO_SET_ACTIVATION_SKIP, vsn(2,2,99), NULL) cfg(activation_mode_CFG, "activation_mode", activation_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_ACTIVATION_MODE, vsn(2,2,108), NULL) +cfg(metadata_vgcreate_cy_lock_type_CFG, "vgcreate_cy_lock_type", metadata_CFG_SECTION, CFG_ALLOW_EMPTY, CFG_TYPE_STRING, DEFAULT_CY_LOCK_TYPE, vsn(2, 2, 113), NULL) +cfg(metadata_vgcreate_default_lock_type_CFG, "vgcreate_default_lock_type", metadata_CFG_SECTION, CFG_ALLOW_EMPTY, CFG_TYPE_STRING, DEFAULT_LOCK_TYPE, vsn(2, 2, 113), NULL) + cfg(metadata_pvmetadatacopies_CFG, "pvmetadatacopies", metadata_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_INT, DEFAULT_PVMETADATACOPIES, vsn(1, 0, 0), NULL) cfg(metadata_vgmetadatacopies_CFG, "vgmetadatacopies", metadata_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_INT, DEFAULT_VGMETADATACOPIES, vsn(2, 2, 69), NULL) cfg(metadata_pvmetadatasize_CFG, "pvmetadatasize", metadata_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_INT, DEFAULT_PVMETADATASIZE, vsn(1, 0, 0), NULL) diff --git a/lib/config/defaults.h b/lib/config/defaults.h index ba5c6b8cd..db5db07ee 100644 --- a/lib/config/defaults.h +++ b/lib/config/defaults.h @@ -213,4 +213,7 @@ #define DEFAULT_THIN_POOL_AUTOEXTEND_THRESHOLD 100 #define DEFAULT_THIN_POOL_AUTOEXTEND_PERCENT 20 +#define DEFAULT_CY_LOCK_TYPE "sanlock" +#define DEFAULT_LOCK_TYPE "none" + #endif /* _LVM_DEFAULTS_H */ diff --git a/lib/format1/disk-rep.h b/lib/format1/disk-rep.h index 729601ee8..94d27894f 100644 --- a/lib/format1/disk-rep.h +++ b/lib/format1/disk-rep.h @@ -41,6 +41,7 @@ #define VG_WRITE 0x02 /* " */ #define VG_CLUSTERED 0x04 /* " */ #define VG_SHARED 0x08 /* " */ +#define VG_LOCK_TYPE 0x10 /* " */ /* logical volume */ #define LV_ACTIVE 0x01 /* lv_status */ diff --git a/lib/format1/import-export.c b/lib/format1/import-export.c index 9318945e2..34ed2b11d 100644 --- a/lib/format1/import-export.c +++ b/lib/format1/import-export.c @@ -253,6 +253,9 @@ int import_vg(struct dm_pool *mem, if (vgd->vg_access & VG_CLUSTERED) vg->status |= CLUSTERED; + if (vgd->vg_access & VG_LOCK_TYPE) + vg->status |= LOCK_TYPE; + if (vgd->vg_access & VG_SHARED) vg->status |= SHARED; @@ -280,6 +283,9 @@ int export_vg(struct vg_disk *vgd, struct volume_group *vg) if (vg_is_clustered(vg)) vgd->vg_access |= VG_CLUSTERED; + if (vg->status & LOCK_TYPE) + vgd->vg_access |= VG_LOCK_TYPE; + if (vg->status & SHARED) vgd->vg_access |= VG_SHARED; diff --git a/lib/format_text/export.c b/lib/format_text/export.c index c2453f2ba..2c8f5791c 100644 --- a/lib/format_text/export.c +++ b/lib/format_text/export.c @@ -410,6 +410,12 @@ static int _print_vg(struct formatter *f, struct volume_group *vg) if (vg->system_id && *vg->system_id) outf(f, "system_id = \"%s\"", vg->system_id); + if (vg->lock_type) { + outf(f, "lock_type = \"%s\"", vg->lock_type); + if (vg->lock_args) + outf(f, "lock_args = \"%s\"", vg->lock_args); + } + outsize(f, (uint64_t) vg->extent_size, "extent_size = %u", vg->extent_size); outf(f, "max_lv = %u", vg->max_lv); @@ -624,6 +630,12 @@ static int _print_lv(struct formatter *f, struct logical_volume *lv) lv->timestamp); } + if (lv->lock_type) { + outf(f, "lock_type = \"%s\"", lv->lock_type); + if (lv->lock_args) + outf(f, "lock_args = \"%s\"", lv->lock_args); + } + if (lv->alloc != ALLOC_INHERIT) outf(f, "allocation_policy = \"%s\"", get_alloc_string(lv->alloc)); diff --git a/lib/format_text/flags.c b/lib/format_text/flags.c index 55681d4f7..f0562b202 100644 --- a/lib/format_text/flags.c +++ b/lib/format_text/flags.c @@ -35,6 +35,7 @@ static const struct flag _vg_flags[] = { {LVM_READ, "READ", STATUS_FLAG}, {LVM_WRITE, "WRITE", STATUS_FLAG}, {CLUSTERED, "CLUSTERED", STATUS_FLAG}, + {LOCK_TYPE, "LOCK_TYPE", STATUS_FLAG}, {SHARED, "SHARED", STATUS_FLAG}, {PARTIAL_VG, NULL, 0}, {PRECOMMITTED, NULL, 0}, diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c index c6a0cf91f..838a16d31 100644 --- a/lib/format_text/import_vsn1.c +++ b/lib/format_text/import_vsn1.c @@ -567,6 +567,16 @@ static int _read_lvnames(struct format_instance *fid __attribute__((unused)), return 0; } + if (dm_config_get_str(lvn, "lock_type", &str)) { + if (!(lv->lock_type = dm_pool_strdup(mem, str))) + return_0; + } + + if (dm_config_get_str(lvn, "lock_args", &str)) { + if (!(lv->lock_args = dm_pool_strdup(mem, str))) + return_0; + } + lv->alloc = ALLOC_INHERIT; if (dm_config_get_str(lvn, "allocation_policy", &str)) { lv->alloc = get_alloc_from_string(str); @@ -777,6 +787,16 @@ static struct volume_group *_read_vg(struct format_instance *fid, strncpy(vg->system_id, str, NAME_LEN); } + if (dm_config_get_str(vgn, "lock_type", &str)) { + if (!(vg->lock_type = dm_pool_strdup(vg->vgmem, str))) + goto bad; + } + + if (dm_config_get_str(vgn, "lock_args", &str)) { + if (!(vg->lock_args = dm_pool_strdup(vg->vgmem, str))) + goto bad; + } + if (!_read_id(&vg->id, vgn, "id")) { log_error("Couldn't read uuid for volume group %s.", vg->name); goto bad; diff --git a/lib/locking/lvmlockd.c b/lib/locking/lvmlockd.c new file mode 100644 index 000000000..ab33b6e72 --- /dev/null +++ b/lib/locking/lvmlockd.c @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * This file is part of LVM2. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU Lesser General Public License v.2.1. + */ + +#include "lib.h" +#include "toolcontext.h" +#include "metadata.h" +#include "segtype.h" +#include "lvmetad.h" +#include "lvmlockd.h" +#include "lvmcache.h" +#include "lvmlockd-client.h" + +static daemon_handle _lvmlockd; +static int _lvmlockd_active; +static int _lvmlockd_connected; + +static const char *_lvmlockd_socket = NULL; +static struct cmd_context *_lvmlockd_cmd = NULL; + +void lvmlockd_disconnect(void) +{ + if (_lvmlockd_connected) + daemon_close(_lvmlockd); + _lvmlockd_connected = 0; + _lvmlockd_cmd = NULL; +} + +void lvmlockd_init(struct cmd_context *cmd) +{ + if (!_lvmlockd_active && !access(LVMLOCKD_PIDFILE, F_OK)) + log_warn("lvmlockd is not running."); + if (!_lvmlockd_active) + return; + _lvmlockd_cmd = cmd; +} + +static void _lvmlockd_connect(void) +{ + if (!_lvmlockd_active || !_lvmlockd_socket || _lvmlockd_connected) + return; + + _lvmlockd = lvmlockd_open(_lvmlockd_socket); + + if (_lvmlockd.socket_fd >= 0 && !_lvmlockd.error) { + log_debug("Successfully connected to lvmlockd on fd %d.", + _lvmlockd.socket_fd); + _lvmlockd_connected = 1; + } +} + +void lvmlockd_connect_or_warn(void) +{ + if (!_lvmlockd_active || _lvmlockd_connected) + return; + + _lvmlockd_connect(); + + if (!_lvmlockd_connected) { + log_warn("Failed to connect to lvmlockd: %s.", + strerror(_lvmlockd.error)); + } +} + +/* + * in command setup: + * + * 1. if use_lvmlockd is set in config, + * lvmlockd_set_active() sets _lvmlockd_active = 1 + * + * 2. lvmlockd_init() sees _lvmlockd_active, and sets _lvmlockd_cmd + * + * 3. lvmlockd_connect_or_warn()/_lvmlockd_connect() see _lvmlockd_active, + * create connection and if successful set _lvmlockd_connected = 1 + * + * in command processing: + * + * 1. dlock function calls lvmlockd_connected() which returns + * _lvmlockd_connected + * + * 2. if lvmlockd_connected() returns 0, dlock function fails + */ + +int lvmlockd_connected(void) +{ + if (_lvmlockd_connected) + return 1; + + return 0; +} + +void lvmlockd_set_active(int active) +{ + _lvmlockd_active = active; +} + +void lvmlockd_set_socket(const char *sock) +{ + _lvmlockd_socket = sock; +} + diff --git a/lib/locking/lvmlockd.h b/lib/locking/lvmlockd.h new file mode 100644 index 000000000..893730f18 --- /dev/null +++ b/lib/locking/lvmlockd.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. + * + * This file is part of LVM2. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU Lesser General Public License v.2.1. + */ + +#ifndef _LVMLOCKD_H +#define _LVMLOCKD_H + +#include "config-util.h" +#include "daemon-client.h" + +#define LOCK_TYPE_NONE 0 +#define LOCK_TYPE_CLVM 1 +#define LOCK_TYPE_DLM 2 +#define LOCK_TYPE_SANLOCK 3 + +/* + * lock_type lock_type_num + * "none" -> LOCK_TYPE_NONE + * "clvm" -> LOCK_TYPE_CLVM + * "dlm -> LOCK_TYPE_DLM + * "sanlock" -> LOCK_TYPE_SANLOCK + */ + +static inline int lock_type_to_num(const char *lock_type) +{ + if (!lock_type) + return LOCK_TYPE_NONE; + if (!strcmp(lock_type, "none")) + return LOCK_TYPE_NONE; + if (!strcmp(lock_type, "clvm")) + return LOCK_TYPE_CLVM; + if (!strcmp(lock_type, "dlm")) + return LOCK_TYPE_DLM; + if (!strcmp(lock_type, "sanlock")) + return LOCK_TYPE_SANLOCK; + return -1; +} + +/* + * Check if a lock_type uses lvmlockd. + * If not (none, clvm), return 0. + * If so (dlm, sanlock), return > 0 (LOCK_TYPE_) + */ + +static inline int is_dlock_type(const char *lock_type) +{ + if (!lock_type) + return 0; + + if (!strcmp(lock_type, "dlm")) + return LOCK_TYPE_DLM; + if (!strcmp(lock_type, "sanlock")) + return LOCK_TYPE_SANLOCK; + + return 0; +} + +#ifdef LVMLOCKD_SUPPORT + +/* daemon management */ + +void lvmlockd_init(struct cmd_context *); +void lvmlockd_set_active(int); +void lvmlockd_set_socket(const char *); +void lvmlockd_disconnect(void); +void lvmlockd_connect_or_warn(void); +int lvmlockd_connected(void); + +#else /* LVMLOCKD_SUPPORT */ + +#define lvmlockd_init(cmd) do { } while (0) +#define lvmlockd_set_active(int) do { } while (0) +#define lvmlockd_set_socket(str) do { } while (0) +#define lvmlockd_disconnect() do { } while (0) +#define lvmlockd_connect_or_warn() do { } while (0) + +#endif /* LVMLOCKD_SUPPORT */ + +#endif + diff --git a/lib/metadata/lv.h b/lib/metadata/lv.h index 8064ba22f..b15c31f4a 100644 --- a/lib/metadata/lv.h +++ b/lib/metadata/lv.h @@ -52,6 +52,8 @@ struct logical_volume { uint64_t timestamp; const char *hostname; + const char *lock_type; + const char *lock_args; }; uint64_t lv_size(const struct logical_volume *lv); diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c index 629262651..438da944f 100644 --- a/lib/metadata/lv_manip.c +++ b/lib/metadata/lv_manip.c @@ -6882,6 +6882,16 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, lv->major, lv->minor); } + if (lp->lock_type && !(lv->lock_type = dm_pool_strdup(cmd->mem, lp->lock_type))) { + log_error("Failed to allocate lock_type"); + return NULL; + } + + if (lp->lock_args && !(lv->lock_args = dm_pool_strdup(cmd->mem, lp->lock_args))) { + log_error("Failed to allocate lock_args"); + return NULL; + } + dm_list_splice(&lv->tags, &lp->tags); if (!lv_extend(lv, create_segtype, diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h index ee464eace..baf51d77f 100644 --- a/lib/metadata/metadata-exported.h +++ b/lib/metadata/metadata-exported.h @@ -61,6 +61,7 @@ #define CLUSTERED UINT64_C(0x0000000000000400) /* VG */ //#define SHARED UINT64_C(0x0000000000000800) /* VG */ +#define LOCK_TYPE UINT64_C(0x0000000000001000) /* VG */ /* FIXME Remove when metadata restructuring is completed */ #define SNAPSHOT UINT64_C(0x0000000000001000) /* LV - internal use only */ @@ -161,6 +162,7 @@ #define FAILED_ALLOCATION 0x00000080U #define FAILED_EXIST 0x00000100U #define FAILED_SYSTEMID 0x00000200U +#define FAILED_LOCK_TYPE 0x00000400U #define SUCCESS 0x00000000U #define VGMETADATACOPIES_ALL UINT32_MAX @@ -834,6 +836,9 @@ struct lvcreate_params { const char *origin_name; /* snap */ const char *pool_name; /* thin */ + const char *lock_type; + const char *lock_args; + /* Keep args given by the user on command line */ /* FIXME: create some more universal solution here */ #define PASS_ARG_CHUNK_SIZE 0x01 @@ -1167,6 +1172,8 @@ struct vgcreate_params { int clustered; /* FIXME: put this into a 'status' variable instead? */ uint32_t vgmetadatacopies; const char *system_id; + const char *lock_type; + const char *lock_args; }; int validate_major_minor(const struct cmd_context *cmd, diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c index ce41a47ba..9e1bb9e5f 100644 --- a/lib/metadata/metadata.c +++ b/lib/metadata/metadata.c @@ -31,6 +31,7 @@ #include "locking.h" #include "archiver.h" #include "defaults.h" +#include "lvmlockd.h" #include #include @@ -4326,6 +4327,20 @@ static int _access_vg_clustered(struct cmd_context *cmd, struct volume_group *vg return 1; } +static int _access_vg_lock_type(struct cmd_context *cmd, struct volume_group *vg) +{ + if (!is_real_vg(vg->name)) + return 1; + + if (is_dlock_type(vg->lock_type) && !find_config_tree_bool(cmd, global_use_lvmlockd_CFG, NULL)) { + log_warn("Cannot access VG %s which requires lvmlockd (lock_type %s).", + vg->name, vg->lock_type); + return 0; + } + + return 1; +} + static int _access_vg_systemid(struct cmd_context *cmd, struct volume_group *vg) { /* @@ -4384,6 +4399,11 @@ static int _access_vg(struct cmd_context *cmd, struct volume_group *vg, uint32_t return 0; } + if (!_access_vg_lock_type(cmd, vg)) { + *failure |= FAILED_LOCK_TYPE; + return 0; + } + if (!_access_vg_systemid(cmd, vg)) { *failure |= FAILED_SYSTEMID; return 0; diff --git a/lib/metadata/vg.c b/lib/metadata/vg.c index 57c9acfd9..99e51709c 100644 --- a/lib/metadata/vg.c +++ b/lib/metadata/vg.c @@ -20,6 +20,7 @@ #include "toolcontext.h" #include "lvmcache.h" #include "archiver.h" +#include "lvmlockd.h" struct volume_group *alloc_vg(const char *pool_name, struct cmd_context *cmd, const char *vg_name) @@ -619,6 +620,22 @@ int vg_set_system_id(struct volume_group *vg, const char *system_id) return 1; } +int vg_set_lock_type(struct volume_group *vg, const char *lock_type) +{ + if (!lock_type) + lock_type = "none"; + + if (!(vg->lock_type = dm_pool_strdup(vg->vgmem, lock_type))) { + log_error("vg_set_lock_type %s no mem", lock_type); + return 0; + } + + if (is_dlock_type(lock_type)) + vg->status |= LOCK_TYPE; + + return 1; +} + char *vg_attr_dup(struct dm_pool *mem, const struct volume_group *vg) { char *repstr; diff --git a/lib/metadata/vg.h b/lib/metadata/vg.h index 23d60acdd..3a8e1ed60 100644 --- a/lib/metadata/vg.h +++ b/lib/metadata/vg.h @@ -68,6 +68,8 @@ struct volume_group { const char *name; const char *old_name; /* Set during vgrename and vgcfgrestore */ char *system_id; + const char *lock_type; + const char *lock_args; uint32_t extent_size; uint32_t extent_count; @@ -145,6 +147,7 @@ uint64_t vg_status(const struct volume_group *vg); int vg_set_alloc_policy(struct volume_group *vg, alloc_policy_t alloc); int vg_set_clustered(struct volume_group *vg, int clustered); int vg_set_system_id(struct volume_group *vg, const char *system_id); +int vg_set_lock_type(struct volume_group *vg, const char *lock_type); uint64_t vg_size(const struct volume_group *vg); uint64_t vg_free(const struct volume_group *vg); uint64_t vg_extent_size(const struct volume_group *vg); diff --git a/tools/Makefile.in b/tools/Makefile.in index 1a8db36e5..30f5fba43 100644 --- a/tools/Makefile.in +++ b/tools/Makefile.in @@ -17,6 +17,7 @@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ SOURCES =\ + dlock.c \ dumpconfig.c \ formats.c \ lvchange.c \ diff --git a/tools/args.h b/tools/args.h index 4a8a56a4b..5a2230ad8 100644 --- a/tools/args.h +++ b/tools/args.h @@ -47,6 +47,7 @@ arg(ignoremonitoring_ARG, '\0', "ignoremonitoring", NULL, 0) arg(ignoreskippedcluster_ARG, '\0', "ignoreskippedcluster", NULL, 0) arg(ignoreunsupported_ARG, '\0', "ignoreunsupported", NULL, 0) arg(labelsector_ARG, '\0', "labelsector", int_arg, 0) +arg(locktype_ARG, '\0', "lock-type", string_arg, 0) arg(maxrecoveryrate_ARG, '\0', "maxrecoveryrate", size_kb_arg, 0) arg(merge_ARG, '\0', "merge", NULL, 0) arg(mergedconfig_ARG, '\0', "mergedconfig", NULL, 0) diff --git a/tools/commands.h b/tools/commands.h index eefd1fec4..563200428 100644 --- a/tools/commands.h +++ b/tools/commands.h @@ -1022,7 +1022,7 @@ xx(vgcreate, physicalextentsize_ARG, test_ARG, force_ARG, zero_ARG, labelsector_ARG, metadatasize_ARG, pvmetadatacopies_ARG, metadatacopies_ARG, vgmetadatacopies_ARG, dataalignment_ARG, dataalignmentoffset_ARG, - systemid_ARG, systemidsource_ARG) + systemid_ARG, systemidsource_ARG, locktype_ARG) xx(vgdisplay, "Display volume group information", diff --git a/tools/dlock.c b/tools/dlock.c new file mode 100644 index 000000000..a962b4c6a --- /dev/null +++ b/tools/dlock.c @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * This file is part of LVM2. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU Lesser General Public License v.2.1. + */ + +#include "tools.h" +#include "metadata.h" +#include "lvmetad.h" +#include "lvmlockd.h" +#include "lvmcache.h" +#include "lvmlockd-client.h" + diff --git a/tools/dlock.h b/tools/dlock.h new file mode 100644 index 000000000..3c852a844 --- /dev/null +++ b/tools/dlock.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * This file is part of LVM2. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU Lesser General Public License v.2.1. + */ + +#ifndef _DLOCK_H +#define _DLOCK_H + +#endif diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c index 1d3e993ad..9f9891fea 100644 --- a/tools/lvmcmdline.c +++ b/tools/lvmcmdline.c @@ -1063,8 +1063,10 @@ static int _get_settings(struct cmd_context *cmd) cmd->ignore_clustered_vgs = arg_count(cmd, ignoreskippedcluster_ARG) ? 1 : 0; - if (!arg_count(cmd, sysinit_ARG)) + if (!arg_count(cmd, sysinit_ARG)) { lvmetad_connect_or_warn(); + lvmlockd_connect_or_warn(); + } if (arg_count(cmd, nosuffix_ARG)) cmd->current_settings.suffix = 0; diff --git a/tools/toollib.c b/tools/toollib.c index 9291eb42a..8a7c6cc3e 100644 --- a/tools/toollib.c +++ b/tools/toollib.c @@ -191,6 +191,8 @@ static int ignore_vg(struct cmd_context *cmd, struct volume_group *vg, const cha *ret = ECMD_FAILED; else if (read_error == FAILED_CLUSTERED && vg->cmd->ignore_clustered_vgs) log_verbose("Skipping volume group %s", vg_name); + else if (read_error == FAILED_LOCK_TYPE) + log_verbose("Skipping volume group %s", vg_name); else { log_error("Skipping volume group %s", vg_name); *ret = ECMD_FAILED; @@ -653,6 +655,12 @@ int vgcreate_params_set_from_args(struct cmd_context *cmd, { const char *arg_str; const char *system_id_source; + const char *lock_type; + int locking_type; + int use_lvmlockd; + int use_clvmd; + int clustery; + int lock_type_num; /* LOCK_TYPE_ */ vp_new->vg_name = skip_dev_dir(cmd, vp_def->vg_name, NULL); vp_new->max_lv = arg_uint_value(cmd, maxlogicalvolumes_ARG, @@ -665,12 +673,6 @@ int vgcreate_params_set_from_args(struct cmd_context *cmd, vp_new->extent_size = arg_uint_value(cmd, physicalextentsize_ARG, vp_def->extent_size); - if (arg_count(cmd, clustered_ARG)) - vp_new->clustered = arg_int_value(cmd, clustered_ARG, vp_def->clustered); - else - /* Default depends on current locking type */ - vp_new->clustered = locking_is_clustered(); - if (arg_sign_value(cmd, physicalextentsize_ARG, SIGN_NONE) == SIGN_MINUS) { log_error(_pe_size_may_not_be_negative_msg); return 0; @@ -721,10 +723,177 @@ int vgcreate_params_set_from_args(struct cmd_context *cmd, } } - /* A clustered vg has no system_id. */ - if (vp_new->clustered) + /* + * Locking: what kind of locking should be used for the + * new VG, and is it compatible with current lvm.conf settings. + * + * The end result is to set vp_new->lock_type to: + * none | clvm | dlm | sanlock. + * + * If --lock-type is set, the answer is given directly by + * which is one of none|clvm|dlm|sanlock. + * + * If --clustered y is set, then lock_type will depend on + * settings found in lvm.conf (see selection logic below.) + * + * Relevant lvm.conf configurations include: + * + * global/use_lvmlockd = 0, global/locking_type = 1 + * ------------------------------------------------ + * - no locking is enabled + * - clvmd is not used + * - lvmlockd is not used + * - VGs with CLUSTERED set are ignored (requires clvmd) + * - VGs with lock_type set are ignored (requires lvmlockd) + * - vgcreate can create new VGs with lock_type = none + * + * global/use_lvmlockd = 0, global/locking_type = 3 + * ------------------------------------------------ + * - locking through clvmd is enabled (traditional clvm config) + * - clvmd is used + * - lvmlockd is not used + * - VGs with CLUSTERED set can be used + * - VGs with lock_type set are ignored (requires lvmlockd) + * - vgcreate can create new VGs with CLUSTERED status flag + * + * global/use_lvmlockd = 1, global/locking_type = 1 + * ------------------------------------------------ + * - locking through lvmlockd is enabled (new lvmlockd config) + * - clvmd is not used + * - lvmlockd is used + * - VGs with CLUSTERED set are ignored (requires clvmd) + * - VGs with lock_type set can be used + * - vgcreate can create new VGs with lock_type = none|sanlock|dlm + * + * VG metadata + * ----------- + * + * A VG with lock_type sanlock|dlm has the new metadata field: + * lock_type = "sanlock" or lock_type = "dlm", + * and the new status flag "LOCK_TYPE". + * + * A VG with lock_type clvm has the old metadata status flag CLUSTERED. + * + * A VG with lock_type none has no lock_type metadata field. + * + * A VG with lock_type sanlock|dlm also has a new metadata field + * lock_args = "..." where the specific string is set by the + * lock manager to lock-manager-specific data. + */ + + /* + * The --clustered option can have varying results depending + * on the lvm.conf settings. This is why --lock-type is the + * preferred option. When --clustered is used, it is translated + * to a lock_type as follows: + * + * When using lvmlockd: + * + * 1. --clustered n -> lock_type none + * + * 2. --clustered y -> lock_type sanlock + * + * The default is sanlock but can be set to sanlock|dlm with + * lvm.conf metadata/vgcreate_cy_lock_type (DEFAULT_CY_LOCK_TYPE) + * + * 3. Neither --clustered nor --lock-type specified -> lock_type none + * + * The default is none but can be set to none|sanlock|dlm with + * lvm.conf metadata/vgcreate_default_lock_type (DEFAULT_LOCK_TYPE) + * + * When using clvmd: + * + * 1. --clustered n -> lock_type none + * + * 2. --clustered y -> lock_type clvm + * + * 3. Neither --clustered nor --lock-type specified -> lock_type clvm + * + * The historical default is clvm. + */ + + locking_type = find_config_tree_int(cmd, global_locking_type_CFG, NULL); + use_lvmlockd = find_config_tree_bool(cmd, global_use_lvmlockd_CFG, NULL); + use_clvmd = (locking_type == 3); + + if (arg_is_set(cmd, locktype_ARG)) { + lock_type = arg_str_value(cmd, locktype_ARG, ""); + + } else if (arg_is_set(cmd, clustered_ARG)) { + arg_str = arg_str_value(cmd, clustered_ARG, ""); + + if (!strcmp(arg_str, "y")) { + clustery = 1; + } else if (!strcmp(arg_str, "n")) { + clustery = 0; + } else { + log_error("Unknown clustered value"); + return 0; + } + + if (use_lvmlockd) { + if (clustery) + lock_type = find_config_tree_str(cmd, metadata_vgcreate_cy_lock_type_CFG, NULL); + else + lock_type = "none"; + } else if (use_clvmd) { + if (clustery) + lock_type = "clvm"; + else + lock_type = "none"; + } else { + log_error("clustered vg requires use_lvmlockd or locking_type 3 (clvmd)"); + return 0; + } + + } else { + if (use_clvmd) + lock_type = locking_is_clustered() ? "clvm" : "none"; + else if (use_lvmlockd) + lock_type = find_config_tree_str(cmd, metadata_vgcreate_default_lock_type_CFG, NULL); + + /* + * lock_type NULL is when there is no --lock-type, + * no --clustered, locking_type is not 3, and + * vgcreate_default_lock_type is not set. + */ + if (!lock_type) + lock_type = "none"; + } + + /* + * Check that the lock_type is recognized, and is being + * used with the correct lvm.conf settings. + */ + lock_type_num = lock_type_to_num(lock_type); + + if (lock_type_num < 0) { + log_error("lock_type %s is invalid", lock_type); + return 0; + } else if ((lock_type_num == LOCK_TYPE_DLM || lock_type_num == LOCK_TYPE_SANLOCK) && !use_lvmlockd) { + log_error("lock_type %s requires use_lvmlockd configuration setting", lock_type); + return 0; + } else if ((lock_type_num == LOCK_TYPE_CLVM) && !use_clvmd) { + log_error("lock_type clvm requires locking_type 3 configuration setting"); + return 0; + } + + /* + * The vg is not owned by one host/system_id. + * Locking coordinates access from multiple hosts. + */ + if (lock_type_num == LOCK_TYPE_DLM || lock_type_num == LOCK_TYPE_SANLOCK || lock_type_num == LOCK_TYPE_CLVM) vp_new->system_id = NULL; + vp_new->lock_type = lock_type; + + if (lock_type_num == LOCK_TYPE_CLVM) + vp_new->clustered = 1; + else + vp_new->clustered = 0; + + log_debug("Setting lock_type to %s", vp_new->lock_type); + return 1; } diff --git a/tools/tools.h b/tools/tools.h index 5bcc95815..11a88afe0 100644 --- a/tools/tools.h +++ b/tools/tools.h @@ -28,12 +28,14 @@ #include "archiver.h" #include "lvmcache.h" #include "lvmetad.h" +#include "lvmlockd.h" #include "lvm-version.h" #include "config.h" #include "defaults.h" #include "dev-cache.h" #include "device.h" #include "display.h" +#include "dlock.h" #include "errors.h" #include "metadata-exported.h" #include "locking.h" diff --git a/tools/vgcreate.c b/tools/vgcreate.c index 5e038457b..7304064fa 100644 --- a/tools/vgcreate.c +++ b/tools/vgcreate.c @@ -71,6 +71,7 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv) !vg_set_max_pv(vg, vp_new.max_pv) || !vg_set_alloc_policy(vg, vp_new.alloc) || !vg_set_clustered(vg, vp_new.clustered) || + !vg_set_lock_type(vg, vp_new.lock_type) || !vg_set_system_id(vg, vp_new.system_id) || !vg_set_mda_copies(vg, vp_new.vgmetadatacopies)) goto bad_orphan; -- cgit v1.2.1