diff options
-rw-r--r-- | lib/commands/toolcontext.h | 2 | ||||
-rw-r--r-- | lib/locking/lvmlockd.c | 360 | ||||
-rw-r--r-- | lib/locking/lvmlockd.h | 24 | ||||
-rw-r--r-- | lib/metadata/lv.c | 22 | ||||
-rw-r--r-- | lib/metadata/lv_manip.c | 26 | ||||
-rw-r--r-- | lib/metadata/metadata-exported.h | 3 | ||||
-rw-r--r-- | tools/args.h | 1 | ||||
-rw-r--r-- | tools/lvchange.c | 19 | ||||
-rw-r--r-- | tools/lvconvert.c | 65 | ||||
-rw-r--r-- | tools/lvcreate.c | 3 | ||||
-rw-r--r-- | tools/lvmcmdline.c | 10 |
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; |