summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/commands/toolcontext.h2
-rw-r--r--lib/locking/lvmlockd.c360
-rw-r--r--lib/locking/lvmlockd.h24
-rw-r--r--lib/metadata/lv.c22
-rw-r--r--lib/metadata/lv_manip.c26
-rw-r--r--lib/metadata/metadata-exported.h3
-rw-r--r--tools/args.h1
-rw-r--r--tools/lvchange.c19
-rw-r--r--tools/lvconvert.c65
-rw-r--r--tools/lvcreate.c3
-rw-r--r--tools/lvmcmdline.c10
11 files changed, 530 insertions, 5 deletions
diff --git a/lib/commands/toolcontext.h b/lib/commands/toolcontext.h
index 4bebbfd5c..c27907b6f 100644
--- a/lib/commands/toolcontext.h
+++ b/lib/commands/toolcontext.h
@@ -99,6 +99,7 @@ struct cmd_context {
unsigned unknown_system_id:1;
unsigned include_foreign_vgs:1;
unsigned lockd_vg_disable:1;
+ unsigned lockd_lv_disable:1;
unsigned lockd_vg_default_sh:1;
struct dev_types *dev_types;
@@ -145,6 +146,7 @@ struct cmd_context {
/* Locking */
const char *lock_gl_mode; /* gl mode, from --lock-gl */
const char *lock_vg_mode; /* vg mode, from --lock-vg */
+ const char *lock_lv_mode; /* lv mode, from --lock-lv */
const char *lib_dir; /* Cache value global/library_dir */
char system_dir[PATH_MAX];
diff --git a/lib/locking/lvmlockd.c b/lib/locking/lvmlockd.c
index 927244e00..8e47af5fe 100644
--- a/lib/locking/lvmlockd.c
+++ b/lib/locking/lvmlockd.c
@@ -1478,3 +1478,363 @@ int lockd_vg_update(struct volume_group *vg)
return ret;
}
+int lockd_lv_name(struct cmd_context *cmd, struct volume_group *vg,
+ const char *lv_name, const char *lock_args,
+ const char *def_mode, uint32_t flags)
+{
+ const char *mode = NULL;
+ const char *opts = NULL;
+ uint32_t result_flags;
+ int result;
+
+ if (!is_lockd_type(vg->lock_type))
+ return 1;
+
+ if (cmd->lockd_lv_disable)
+ return 1;
+
+ /*
+ * For lvchange/vgchange activation, def_mode is "sh" or "ex"
+ * according to the specific -a{e,s}y mode designation.
+ * No e,s designation gives NULL def_mode.
+ *
+ * The --lock-lv option is saved in cmd->lock_lv_mode.
+ *
+ * If both -a{e,s}y and --lock-lv mode are set, they should agree.
+ */
+
+ if (cmd->lock_lv_mode && def_mode && strcmp(cmd->lock_lv_mode, def_mode)) {
+ log_error("Different LV lock modes from activation %s and lock-lv %s",
+ def_mode, cmd->lock_lv_mode);
+ return 0;
+ }
+
+ if (cmd->lock_lv_mode && (_mode_compare(cmd->lock_lv_mode, "sh") < 0) &&
+ !find_config_tree_bool(cmd, global_allow_override_lock_modes_CFG, NULL)) {
+ log_error("Disallowed lock-lv mode \"%s\"", cmd->lock_lv_mode);
+ return 0;
+ }
+
+ if (cmd->lock_lv_mode)
+ mode = cmd->lock_lv_mode;
+ else if (def_mode)
+ mode = def_mode;
+
+ if (mode && !strcmp(mode, "sh") && (flags & LDLV_MODE_NO_SH)) {
+ log_error("Shared activation not compatible with LV type: %s/%s",
+ vg->name, lv_name);
+ return 0;
+ }
+
+ if (!mode)
+ mode = "ex";
+
+ if (flags & LDLV_PERSISTENT)
+ opts = "persistent";
+
+ if (!_lockd_request(cmd, "lock_lv",
+ vg->name, vg->lock_type, vg->lock_args,
+ lv_name, lock_args, mode, opts,
+ &result, &result_flags)) {
+ /* No result from lvmlockd, it is probably not running. */
+ log_error("Locking failed for LV %s/%s", vg->name, lv_name);
+ return 0;
+ }
+
+ /* The lv was not active/locked. */
+ if (result == -ENOENT && !strcmp(mode, "un"))
+ return 1;
+
+ if (result == -EALREADY)
+ return 1;
+
+ if (result == -EAGAIN) {
+ log_error("LV locked by other host: %s/%s", vg->name, lv_name);
+ return 0;
+ }
+
+ if (result < 0) {
+ log_error("LV lock %s error %d: %s/%s", mode, result, vg->name, lv_name);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Direct the lock request to the pool LV.
+ * For a thin pool and all its thin volumes, one ex lock is used.
+ * It is the one specified in metadata of the pool data lv.
+ */
+
+static int _lockd_lv_thin(struct cmd_context *cmd, struct logical_volume *lv,
+ const char *def_mode, uint32_t flags)
+{
+ struct logical_volume *pool_lv;
+
+ if (lv_is_thin_volume(lv)) {
+ struct lv_segment *pool_seg = first_seg(lv);
+ pool_lv = pool_seg ? pool_seg->pool_lv : NULL;
+
+ } else if (lv_is_thin_pool(lv)) {
+ pool_lv = lv;
+
+ } else {
+ /* This should not happen AFAIK. */
+ log_error("Lock on incorrect thin lv type %s/%s",
+ lv->vg->name, lv->name);
+ return 0;
+ }
+
+ if (!pool_lv) {
+ /* This should not happen. */
+ log_error("Cannot find thin pool for %s/%s",
+ lv->vg->name, lv->name);
+ return 0;
+ }
+
+ /*
+ * Locking a locked lv (pool in this case) is a no-op.
+ * Unlock when the pool is no longer active.
+ */
+
+ if (!strcmp(def_mode, "un") && pool_is_active(pool_lv))
+ return 1;
+
+ flags |= LDLV_MODE_NO_SH;
+
+ return lockd_lv_name(cmd, pool_lv->vg, pool_lv->name, pool_lv->lock_args,
+ def_mode, flags);
+}
+
+int lockd_lv(struct cmd_context *cmd, struct logical_volume *lv,
+ const char *def_mode, uint32_t flags)
+{
+ if (!is_lockd_type(lv->vg->lock_type))
+ return 1;
+
+ if (lv_is_thin_type(lv))
+ return _lockd_lv_thin(cmd, lv, def_mode, flags);
+
+ /*
+ * LV type cannot be active concurrently on multiple hosts,
+ * so shared mode activation is not allowed.
+ */
+ if (lv_is_external_origin(lv) ||
+ lv_is_thin_type(lv) ||
+ lv_is_mirror_type(lv) ||
+ lv_is_raid_type(lv) ||
+ lv_is_cache_type(lv)) {
+ flags |= LDLV_MODE_NO_SH;
+ }
+
+ return lockd_lv_name(cmd, lv->vg, lv->name, lv->lock_args, def_mode, flags);
+}
+
+static int _init_lv_sanlock(struct cmd_context *cmd, struct volume_group *vg,
+ const char *lv_name, const char **lock_args_ret)
+{
+ daemon_reply reply;
+ const char *reply_str;
+ const char *lv_lock_args = NULL;
+ int result;
+ int ret;
+
+ if (!_lvmlockd_active)
+ return 1;
+ if (!lvmlockd_connected())
+ return 0;
+
+ reply = _lockd_send("init_lv",
+ "pid = %d", getpid(),
+ "vg_name = %s", vg->name,
+ "lv_name = %s", lv_name,
+ "vg_lock_type = %s", "sanlock",
+ "vg_lock_args = %s", vg->lock_args,
+ NULL);
+
+ if (!_lockd_result(reply, &result, NULL)) {
+ ret = 0;
+ } else {
+ ret = (result < 0) ? 0 : 1;
+ }
+
+ if (result == -EEXIST) {
+ log_error("Lock already exists for LV %s/%s", vg->name, lv_name);
+ goto out;
+ }
+
+ if (!ret) {
+ log_error("_init_lv_sanlock lvmlockd result %d", result);
+ goto out;
+ }
+
+ reply_str = daemon_reply_str(reply, "lv_lock_args", NULL);
+ if (!reply_str) {
+ log_error("lv_lock_args not returned");
+ ret = 0;
+ goto out;
+ }
+
+ lv_lock_args = dm_pool_strdup(cmd->mem, reply_str);
+ if (!lv_lock_args) {
+ log_error("lv_lock_args allocation failed");
+ ret = 0;
+ }
+out:
+ daemon_reply_destroy(reply);
+
+ *lock_args_ret = lv_lock_args;
+ return ret;
+}
+
+static int _free_lv_sanlock(struct cmd_context *cmd, struct volume_group *vg,
+ const char *lv_name, const char *lock_args)
+{
+ daemon_reply reply;
+ int result;
+ int ret;
+
+ if (!_lvmlockd_active)
+ return 1;
+ if (!lvmlockd_connected())
+ return 0;
+
+ reply = _lockd_send("free_lv",
+ "pid = %d", getpid(),
+ "vg_name = %s", vg->name,
+ "lv_name = %s", lv_name,
+ "vg_lock_type = %s", "sanlock",
+ "vg_lock_args = %s", vg->lock_args,
+ "lv_lock_args = %s", lock_args ?: "none",
+ NULL);
+
+ if (!_lockd_result(reply, &result, NULL)) {
+ ret = 0;
+ } else {
+ ret = (result < 0) ? 0 : 1;
+ }
+
+ if (!ret) {
+ log_error("_free_lv_sanlock lvmlockd result %d", result);
+ }
+
+ daemon_reply_destroy(reply);
+
+ return ret;
+}
+
+/*
+ * lvcreate
+ *
+ * This can handle only a subset of LV types currently:
+ * - normal LV's
+ * - thin pool LV's (by themselves)
+ * - thin volumes/snapshots (under existing thin pool)
+ *
+ * Current limitations:
+ * - cache-type LV's in a lockd VG must be created with lvconvert.
+ * - old cow snapshots are not handled.
+ * - creating a thin pool and thin lv in one command is not allowed.
+ */
+
+int lockd_init_lv(struct cmd_context *cmd, struct volume_group *vg,
+ struct lvcreate_params *lp)
+{
+ const char *lv_name;
+ int lock_type_num = lock_type_to_num(lp->lock_type);
+
+ switch (lock_type_num) {
+ case LOCK_TYPE_NONE:
+ case LOCK_TYPE_CLVM:
+ return 1;
+ case LOCK_TYPE_SANLOCK:
+ case LOCK_TYPE_DLM:
+ break;
+ default:
+ log_error("lockd_init_lv: unknown lock_type.");
+ return 0;
+ }
+
+ if (seg_is_cache(lp) || seg_is_cache_pool(lp)) {
+ log_error("Use lvconvert for cache with lock type %s", lp->lock_type);
+ return 0;
+
+ } else if (!seg_is_thin_volume(lp) && lp->snapshot) {
+ log_error("Only thin snapshots are allowed with lock type %s", lp->lock_type);
+ return 0;
+
+ } else if (seg_is_thin(lp)) {
+ if ((seg_is_thin_volume(lp) && !lp->create_pool) ||
+ (!seg_is_thin_volume(lp) && lp->snapshot)) {
+ struct lv_list *lvl;
+
+ /*
+ * Creating a new thin lv or snapshot. These lvs do not get
+ * their own lock but use the pool lock.
+ */
+
+ if (!(lvl = find_lv_in_vg(vg, lp->pool_name))) {
+ log_error("Failed to find thin pool %s/%s", vg->name, lp->pool_name);
+ return 0;
+ }
+ if (!lockd_lv(cmd, lvl->lv, "ex", LDLV_PERSISTENT)) {
+ log_error("Failed to lock thin pool %s/%s", vg->name, lp->pool_name);
+ return 0;
+ }
+ return 1;
+
+ } else if (seg_is_thin_volume(lp) && lp->create_pool) {
+ /*
+ * Creating a thin pool and a thin lv in it. We could
+ * probably make this work by setting lp->lock_type and
+ * lp->lock_args to NULL in lv_create_single after
+ * creating the pool lv. Then we would just set
+ * lv_name = lp->pool_name here. Stop it at least for now
+ * to try to slow down some of the unnecessary complexity.
+ */
+ log_error("Create thin pool and thin lv separately with lock type %s",
+ lp->lock_type);
+ return 0;
+
+ } else if (!seg_is_thin_volume(lp) && lp->create_pool) {
+ /* Creating a thin pool only. */
+ lv_name = lp->pool_name;
+
+ } else {
+ log_error("Unknown thin options for lock init.");
+ return 0;
+ }
+
+ } else {
+ /* Creating a normal lv. */
+ lv_name = lp->lv_name;
+ }
+
+ if (lock_type_num == LOCK_TYPE_SANLOCK)
+ return _init_lv_sanlock(cmd, vg, lv_name, &lp->lock_args);
+
+ return 1;
+}
+
+/* lvremove */
+
+int lockd_free_lv(struct cmd_context *cmd, struct volume_group *vg,
+ const char *lv_name, const char *lock_args)
+{
+ if (cmd->lock_lv_mode && !strcmp(cmd->lock_lv_mode, "na"))
+ return 1;
+
+ switch (lock_type_to_num(vg->lock_type)) {
+ case LOCK_TYPE_NONE:
+ case LOCK_TYPE_CLVM:
+ case LOCK_TYPE_DLM:
+ return 1;
+ case LOCK_TYPE_SANLOCK:
+ return _free_lv_sanlock(cmd, vg, lv_name, lock_args);
+ default:
+ log_error("lockd_free_lv: unknown lock_type.");
+ return 0;
+ }
+}
+
diff --git a/lib/locking/lvmlockd.h b/lib/locking/lvmlockd.h
index 5641949ff..60f1173a5 100644
--- a/lib/locking/lvmlockd.h
+++ b/lib/locking/lvmlockd.h
@@ -27,6 +27,11 @@
/* lockd_vg flags */
#define LDVG_MODE_NOARG 0x00000001
+/* lockd_lv flags */
+#define LDLV_MODE_NOARG 0x00000001
+#define LDLV_MODE_NO_SH 0x00000002
+#define LDLV_PERSISTENT 0x00000004
+
/* lvmlockd result flags */
#define LD_RF_NO_LOCKSPACES 0x00000001
#define LD_RF_NO_GL_LS 0x00000002
@@ -108,6 +113,19 @@ int lockd_gl_vg(struct cmd_context *cmd, const char *vg_name,
const char *def_gl_mode, const char *def_vg_mode, uint32_t flags);
int lockd_vg_update(struct volume_group *vg);
+int lockd_lv_name(struct cmd_context *cmd, struct volume_group *vg,
+ const char *lv_name, const char *lock_args,
+ const char *def_mode, uint32_t flags);
+int lockd_lv(struct cmd_context *cmd, struct logical_volume *lv,
+ const char *def_mode, uint32_t flags);
+
+/* lvcreate/lvremove use init/free */
+
+int lockd_init_lv(struct cmd_context *cmd, struct volume_group *vg,
+ struct lvcreate_params *lp);
+int lockd_free_lv(struct cmd_context *cmd, struct volume_group *vg,
+ const char *lv_name, const char *lock_args);
+
#else /* LVMLOCKD_SUPPORT */
#define lvmlockd_init(cmd) do { } while (0)
@@ -130,6 +148,12 @@ int lockd_vg_update(struct volume_group *vg);
#define lockd_gl_vg(cmd, vg_name, def_gl_mode, def_vg_mode, flags) (1)
#define lockd_vg_update(struct volume_group *vg) (1)
+#define lockd_lv_name(cmd, vg, lv_name, lock_args, def_mode, flags) (1)
+#define lockd_lv(cmd, lv, def_mode, flags) (1)
+
+#define lockd_init_lv(cmd, vg, lp) (1)
+#define lockd_free_lv(cmd, vg, lv_name, lock_args) (1)
+
#endif /* LVMLOCKD_SUPPORT */
#endif
diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c
index fb1cd7823..e8a50d154 100644
--- a/lib/metadata/lv.c
+++ b/lib/metadata/lv.c
@@ -20,6 +20,7 @@
#include "toolcontext.h"
#include "segtype.h"
#include "str_list.h"
+#include "lvmlockd.h"
#include <time.h>
#include <sys/utsname.h>
@@ -880,6 +881,19 @@ static int _lv_is_exclusive(struct logical_volume *lv)
int lv_active_change(struct cmd_context *cmd, struct logical_volume *lv,
enum activation_change activate, int needs_exclusive)
{
+ const char *ay_with_mode = NULL;
+
+ if (activate == CHANGE_ASY)
+ ay_with_mode = "sh";
+ if (activate == CHANGE_AEY)
+ ay_with_mode = "ex";
+
+ if (is_change_activating(activate) &&
+ !lockd_lv(cmd, lv, ay_with_mode, LDLV_PERSISTENT)) {
+ log_error("Failed to lock logical volume %s/%s", lv->vg->name, lv->name);
+ return 0;
+ }
+
switch (activate) {
case CHANGE_AN:
deactivate:
@@ -922,7 +936,9 @@ exclusive:
if (!activate_lv_excl(cmd, lv))
return_0;
break;
- default: /* CHANGE_AY */
+ case CHANGE_ASY:
+ case CHANGE_AY:
+ default:
if (needs_exclusive || _lv_is_exclusive(lv))
goto exclusive;
log_verbose("Activating logical volume \"%s\".", lv->name);
@@ -930,6 +946,10 @@ exclusive:
return_0;
}
+ if (!is_change_activating(activate) &&
+ !lockd_lv(cmd, lv, "un", LDLV_PERSISTENT))
+ log_error("Failed to unlock logical volume %s/%s", lv->vg->name, lv->name);
+
return 1;
}
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index bf33e263b..2b218c2f2 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -30,6 +30,7 @@
#include "lvm-exec.h"
#include "lvm-signal.h"
#include "memlock.h"
+#include "lvmlockd.h"
typedef enum {
PREFERRED,
@@ -4989,6 +4990,13 @@ int lv_resize(struct cmd_context *cmd, struct logical_volume *lv,
return 0;
}
+ /*
+ * If the LV is locked from activation, this lock call is a no-op.
+ * Otherwise, this acquires a transient lock on the lv (not PERSISTENT).
+ */
+ if (!lockd_lv(cmd, lv, "ex", 0))
+ return_0;
+
if (lp->sizeargs &&
!(lock_lv = _lvresize_volume(cmd, lv, lp, pvh)))
return_0;
@@ -5335,6 +5343,7 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
int format1_reload_required = 0;
int visible;
struct logical_volume *pool_lv = NULL;
+ struct logical_volume *lock_lv = lv;
struct lv_segment *cache_seg = NULL;
int ask_discard;
struct lv_list *lvl;
@@ -5381,14 +5390,19 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
log_error("Can't remove logical volume %s used by a pool.",
lv->name);
return 0;
- } else if (lv_is_thin_volume(lv))
+ } else if (lv_is_thin_volume(lv)) {
pool_lv = first_seg(lv)->pool_lv;
+ lock_lv = pool_lv;
+ }
if (lv_is_locked(lv)) {
log_error("Can't remove locked LV %s", lv->name);
return 0;
}
+ if (!lockd_lv(cmd, lock_lv, "ex", LDLV_PERSISTENT))
+ return_0;
+
/* FIXME Ensure not referred to by another existing LVs */
ask_discard = find_config_tree_bool(cmd, devices_issue_discards_CFG, NULL);
@@ -5563,6 +5577,9 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
backup(vg);
+ lockd_lv(cmd, lock_lv, "un", LDLV_PERSISTENT | LDLV_MODE_NOARG);
+ lockd_free_lv(cmd, vg, lv->name, lv->lock_args);
+
if (!suppress_remove_message && visible)
log_print_unless_silent("Logical volume \"%s\" successfully removed", lv->name);
@@ -7257,6 +7274,9 @@ struct logical_volume *lv_create_single(struct volume_group *vg,
const struct segment_type *segtype;
struct logical_volume *lv;
+ if (lp->lock_type && !lockd_init_lv(vg->cmd, vg, lp))
+ return_NULL;
+
/* Create pool first if necessary */
if (lp->create_pool && !seg_is_pool(lp)) {
segtype = lp->segtype;
@@ -7298,8 +7318,10 @@ struct logical_volume *lv_create_single(struct volume_group *vg,
lp->segtype = segtype;
}
- if (!(lv = _lv_create_an_lv(vg, lp, lp->lv_name)))
+ if (!(lv = _lv_create_an_lv(vg, lp, lp->lv_name))) {
+ lockd_free_lv(vg->cmd, vg, lp->lv_name, lp->lock_args);
return_NULL;
+ }
if (lp->temporary)
log_verbose("Temporary logical volume \"%s\" created.", lv->name);
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 4fa1d9ed5..833b1244a 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -800,7 +800,8 @@ typedef enum activation_change {
CHANGE_AEY = 2, /* activate exclusively */
CHANGE_ALY = 3, /* activate locally */
CHANGE_ALN = 4, /* deactivate locally */
- CHANGE_AAY = 5 /* automatic activation */
+ CHANGE_AAY = 5, /* automatic activation */
+ CHANGE_ASY = 6 /* activate shared */
} activation_change_t;
/* Returns true, when change activates device */
diff --git a/tools/args.h b/tools/args.h
index 02ef25197..fa750bc88 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -49,6 +49,7 @@ arg(ignoreunsupported_ARG, '\0', "ignoreunsupported", NULL, 0)
arg(labelsector_ARG, '\0', "labelsector", int_arg, 0)
arg(lockgl_ARG, '\0', "lock-gl", string_arg, 0)
arg(lockvg_ARG, '\0', "lock-vg", string_arg, 0)
+arg(locklv_ARG, '\0', "lock-lv", string_arg, 0)
arg(lockstart_ARG, '\0', "lock-start", string_arg, 0)
arg(lockstop_ARG, '\0', "lock-stop", string_arg, 0)
arg(locktype_ARG, '\0', "lock-type", string_arg, 0)
diff --git a/tools/lvchange.c b/tools/lvchange.c
index ba974388d..7b9a55352 100644
--- a/tools/lvchange.c
+++ b/tools/lvchange.c
@@ -537,6 +537,9 @@ static int lvchange_persistent(struct cmd_context *cmd,
{
enum activation_change activate = CHANGE_AN;
+ /* The LV lock in lvmlockd should remain as it is. */
+ cmd->lockd_lv_disable = 1;
+
if (!get_and_validate_major_minor(cmd, lv->vg->fid->fmt,
&lv->major, &lv->minor))
return_0;
@@ -910,6 +913,22 @@ static int _lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
}
}
+ if (!arg_count(cmd, activate_ARG) && !arg_count(cmd, refresh_ARG)) {
+ /*
+ * If a persistent lv lock already exists from activation
+ * (with the needed mode or higher), this will be a no-op.
+ * Otherwise, the lv lock will be taken as non-persistent
+ * and released when this command exits.
+ *
+ * TODO: use "sh" if the options imply that the lvchange
+ * operation does not modify the LV.
+ */
+ if (!lockd_lv(cmd, lv, "ex", 0)) {
+ stack;
+ return ECMD_FAILED;
+ }
+ }
+
/*
* FIXME: DEFAULT_BACKGROUND_POLLING should be "unspecified".
* If --poll is explicitly provided use it; otherwise polling
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 213b0da95..e3a4ae635 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -2689,6 +2689,12 @@ static int _lvconvert_thin(struct cmd_context *cmd,
return 0;
}
+ if (is_lockd_type(lv->vg->lock_type)) {
+ log_error("Can't use lock_type %s LV as external origin.",
+ lv->vg->lock_type);
+ return 0;
+ }
+
dm_list_init(&lvc.tags);
if (!pool_supports_external_origin(first_seg(pool_lv), lv))
@@ -2801,6 +2807,8 @@ static int _lvconvert_pool(struct cmd_context *cmd,
{
int r = 0;
const char *old_name;
+ const char *lock_free_meta_name = NULL;
+ const char *lock_free_data_name = NULL;
struct lv_segment *seg;
struct volume_group *vg = pool_lv->vg;
struct logical_volume *data_lv;
@@ -3138,6 +3146,36 @@ static int _lvconvert_pool(struct cmd_context *cmd,
if (!attach_pool_data_lv(seg, data_lv))
return_0;
+ /*
+ * A thin pool lv adopts the lock from the data lv, and the lock for
+ * the meta lv is unlocked and freed. A cache pool lv has no lock, and
+ * the existing lock for both data and meta lvs are unlocked and freed.
+ */
+ if (is_lockd_type(pool_lv->vg->lock_type)) {
+ if (lp->pool_metadata_name) {
+ char *c;
+ if ((c = strchr(lp->pool_metadata_name, '/')))
+ lock_free_meta_name = c + 1;
+ else
+ lock_free_meta_name = lp->pool_metadata_name;
+ }
+
+ if (segtype_is_cache_pool(lp->segtype)) {
+ lock_free_data_name = pool_lv->name;
+ pool_lv->lock_type = NULL;
+ pool_lv->lock_args = NULL;
+ } else {
+ if (data_lv->lock_type)
+ pool_lv->lock_type = dm_pool_strdup(cmd->mem, data_lv->lock_type);
+ if (data_lv->lock_args)
+ pool_lv->lock_args = dm_pool_strdup(cmd->mem, data_lv->lock_args);
+ }
+ data_lv->lock_type = NULL;
+ data_lv->lock_args = NULL;
+ metadata_lv->lock_type = NULL;
+ metadata_lv->lock_args = NULL;
+ }
+
/* FIXME: revert renamed LVs in fail path? */
/* FIXME: any common code with metadata/thin_manip.c extend_pool() ? */
@@ -3195,6 +3233,22 @@ out:
(segtype_is_cache_pool(lp->segtype)) ?
"cache" : "thin");
+ if (lock_free_meta_name) {
+ if (!lockd_lv_name(cmd, pool_lv->vg, lock_free_meta_name, NULL, "un", LDLV_PERSISTENT)) {
+ log_error("Failed to unlock pool metadata LV %s/%s",
+ pool_lv->vg->name, lock_free_meta_name);
+ }
+ lockd_free_lv(cmd, pool_lv->vg, lock_free_meta_name, NULL);
+ }
+
+ if (lock_free_data_name) {
+ if (!lockd_lv_name(cmd, pool_lv->vg, lock_free_data_name, NULL, "un", LDLV_PERSISTENT)) {
+ log_error("Failed to unlock pool data LV %s/%s",
+ pool_lv->vg->name, lock_free_data_name);
+ }
+ lockd_free_lv(cmd, pool_lv->vg, lock_free_data_name, NULL);
+ }
+
return r;
#if 0
revert_new_lv:
@@ -3457,6 +3511,17 @@ static int lvconvert_single(struct cmd_context *cmd, struct lvconvert_params *lp
goto_out;
/*
+ * If the lv is inactive before and after the command, the
+ * use of PERSISTENT here means the lv will remain locked as
+ * an effect of running the lvconvert.
+ * To unlock it, it would need to be activated+deactivated.
+ * Or, we could identify the commands for which the lv remains
+ * inactive, and not use PERSISTENT here for those cases.
+ */
+ if (!lockd_lv(cmd, lv, "ex", LDLV_PERSISTENT))
+ goto_out;
+
+ /*
* lp->pvh holds the list of PVs available for allocation or removal
*/
if (lp->pv_count) {
diff --git a/tools/lvcreate.c b/tools/lvcreate.c
index 7d65b520f..ad452b2e7 100644
--- a/tools/lvcreate.c
+++ b/tools/lvcreate.c
@@ -1480,6 +1480,9 @@ int lvcreate(struct cmd_context *cmd, int argc, char **argv)
lp.snapshot ? " as snapshot of " : "",
lp.snapshot ? lp.origin_name : "", lp.segtype->name);
+ if (vg->lock_type && !(lp.lock_type = dm_pool_strdup(cmd->mem, vg->lock_type)))
+ goto_out;
+
if (!lv_create_single(vg, &lp))
goto_out;
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index 9f80de4cb..96b3ac974 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -282,6 +282,12 @@ int activation_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_v
av->ui_value = CHANGE_AEY;
}
+ else if (!strcmp(av->value, "s") || !strcmp(av->value, "sy") ||
+ !strcmp(av->value, "ys")) {
+ av->i_value = CHANGE_ASY;
+ av->ui_value = CHANGE_ASY;
+ }
+
else if (!strcmp(av->value, "y")) {
av->i_value = CHANGE_AY;
av->ui_value = CHANGE_AY;
@@ -761,7 +767,7 @@ void lvm_register_commands(void)
yes_ARG, \
quiet_ARG, config_ARG, \
commandprofile_ARG, \
- lockgl_ARG, lockvg_ARG, \
+ lockgl_ARG, lockvg_ARG, locklv_ARG, \
profile_ARG, -1);
#include "commands.h"
#undef xx
@@ -1047,6 +1053,8 @@ static int _get_settings(struct cmd_context *cmd)
cmd->lock_vg_mode = arg_str_value(cmd, lockvg_ARG, NULL);
if (cmd->command->flags & LOCKD_VG_SH)
cmd->lockd_vg_default_sh = 1;
+ if (arg_is_set(cmd, locklv_ARG))
+ cmd->lock_lv_mode = arg_str_value(cmd, locklv_ARG, NULL);
cmd->partial_activation = 0;
cmd->degraded_activation = 0;