mirror of
git://sourceware.org/git/lvm2.git
synced 2025-03-11 20:58:50 +03:00
lvconvert: use command defs for thin and cache
This commit is contained in:
parent
072ef008ea
commit
fdf3d0501d
@ -388,6 +388,8 @@ lvconvert --type thin --thinpool LV LV_linear_striped_raid
|
||||
OO: --thin, --originname LV_new, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT
|
||||
ID: lvconvert_to_thin_with_external
|
||||
DESC: Convert LV to type thin with an external origin.
|
||||
RULE: all and lv_is_visible
|
||||
RULE: all not lv_is_locked
|
||||
|
||||
# alternate form of lvconvert --type thin
|
||||
lvconvert --thin --thinpool LV LV_linear_striped_raid
|
||||
@ -396,6 +398,8 @@ ID: lvconvert_to_thin_with_external
|
||||
DESC: Convert LV to type thin with an external origin
|
||||
DESC: (variant, infers --type thin).
|
||||
FLAGS: SECONDARY_SYNTAX
|
||||
RULE: all and lv_is_visible
|
||||
RULE: all not lv_is_locked
|
||||
|
||||
---
|
||||
|
||||
@ -404,6 +408,7 @@ OO: --cache, --cachemode CacheMode, --cachepolicy String,
|
||||
--cachesettings String, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT
|
||||
ID: lvconvert_to_cache_vol
|
||||
DESC: Convert LV to type cache.
|
||||
RULE: all and lv_is_visible
|
||||
|
||||
# alternate form of lvconvert --type cache
|
||||
lvconvert --cache --cachepool LV LV_linear_striped_raid_thinpool
|
||||
@ -412,6 +417,7 @@ OO: --type cache, --cachemode CacheMode, --cachepolicy String,
|
||||
ID: lvconvert_to_cache_vol
|
||||
DESC: Convert LV to type cache (variant, infers --type cache).
|
||||
FLAGS: SECONDARY_SYNTAX
|
||||
RULE: all and lv_is_visible
|
||||
|
||||
---
|
||||
|
||||
|
@ -2660,6 +2660,141 @@ revert_new_lv:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _lvconvert_to_thin_with_external(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
struct logical_volume *thinpool_lv)
|
||||
{
|
||||
struct volume_group *vg = lv->vg;
|
||||
struct logical_volume *thin_lv;
|
||||
const char *origin_name;
|
||||
|
||||
struct lvcreate_params lvc = {
|
||||
.activate = CHANGE_AEY,
|
||||
.alloc = ALLOC_INHERIT,
|
||||
.major = -1,
|
||||
.minor = -1,
|
||||
.suppress_zero_warn = 1, /* Suppress warning for this thin */
|
||||
.permission = LVM_READ,
|
||||
.pool_name = thinpool_lv->name,
|
||||
.pvh = &vg->pvs,
|
||||
.read_ahead = DM_READ_AHEAD_AUTO,
|
||||
.stripes = 1,
|
||||
.virtual_extents = lv->le_count,
|
||||
};
|
||||
|
||||
if (lv == thinpool_lv) {
|
||||
log_error("Can't use same LV %s for thin pool and thin volume.",
|
||||
display_lvname(thinpool_lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
origin_name = arg_str_value(cmd, originname_ARG, NULL);
|
||||
|
||||
/* FIXME: check origin_name doesn't match other names */
|
||||
|
||||
/* If NULL, an auto-generated 'lvol' name is used. */
|
||||
lvc.lv_name = origin_name;
|
||||
|
||||
if (is_lockd_type(vg->lock_type)) {
|
||||
/*
|
||||
* FIXME: external origins don't work in lockd VGs.
|
||||
* Prior to the lvconvert, there's a lock associated with
|
||||
* the uuid of the external origin LV. After the convert,
|
||||
* that uuid belongs to the new thin LV, and a new LV with
|
||||
* a new uuid exists as the non-thin, readonly external LV.
|
||||
* We'd need to remove the lock for the previous uuid
|
||||
* (the new thin LV will have no lock), and create a new
|
||||
* lock for the new LV uuid used by the external LV.
|
||||
*/
|
||||
log_error("Can't use lock_type %s LV as external origin.",
|
||||
vg->lock_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dm_list_init(&lvc.tags);
|
||||
|
||||
if (!pool_supports_external_origin(first_seg(thinpool_lv), lv))
|
||||
return_0;
|
||||
|
||||
if (!(lvc.segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_THIN)))
|
||||
return_0;
|
||||
|
||||
if (!archive(vg))
|
||||
return_0;
|
||||
|
||||
/*
|
||||
* New thin LV needs to be created (all messages sent to pool) In this
|
||||
* case thin volume is created READ-ONLY and also warn about not
|
||||
* zeroing is suppressed.
|
||||
*
|
||||
* The new thin LV is created with the origin_name, or an autogenerated
|
||||
* 'lvol' name. Then the names and ids are swapped between the thin LV
|
||||
* and the original/external LV. So, the thin LV gets the name and id
|
||||
* of the original LV arg, and the original LV arg gets the origin_name
|
||||
* or the autogenerated name.
|
||||
*/
|
||||
|
||||
if (!(thin_lv = lv_create_single(vg, &lvc)))
|
||||
return_0;
|
||||
|
||||
if (!deactivate_lv(cmd, thin_lv)) {
|
||||
log_error("Aborting. Unable to deactivate new LV. "
|
||||
"Manual intervention required.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Crashing till this point will leave plain thin volume
|
||||
* which could be easily removed by the user after i.e. power-off
|
||||
*/
|
||||
|
||||
if (!swap_lv_identifiers(cmd, thin_lv, lv)) {
|
||||
stack;
|
||||
goto revert_new_lv;
|
||||
}
|
||||
|
||||
/* Preserve read-write status of original LV here */
|
||||
thin_lv->status |= (lv->status & LVM_WRITE);
|
||||
|
||||
if (!attach_thin_external_origin(first_seg(thin_lv), lv)) {
|
||||
stack;
|
||||
goto revert_new_lv;
|
||||
}
|
||||
|
||||
if (!lv_update_and_reload(thin_lv)) {
|
||||
stack;
|
||||
goto deactivate_and_revert_new_lv;
|
||||
}
|
||||
|
||||
log_print_unless_silent("Converted %s to thin volume with external origin %s.",
|
||||
display_lvname(thin_lv), display_lvname(lv));
|
||||
|
||||
return 1;
|
||||
|
||||
deactivate_and_revert_new_lv:
|
||||
if (!swap_lv_identifiers(cmd, thin_lv, lv))
|
||||
stack;
|
||||
|
||||
if (!deactivate_lv(cmd, thin_lv)) {
|
||||
log_error("Unable to deactivate failed new LV. "
|
||||
"Manual intervention required.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!detach_thin_external_origin(first_seg(thin_lv)))
|
||||
return_0;
|
||||
|
||||
revert_new_lv:
|
||||
/* FIXME Better to revert to backup of metadata? */
|
||||
if (!lv_remove(thin_lv) || !vg_write(vg) || !vg_commit(vg))
|
||||
log_error("Manual intervention may be required to remove "
|
||||
"abandoned LV(s) before retrying.");
|
||||
else
|
||||
backup(vg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _lvconvert_update_pool_params(struct logical_volume *pool_lv,
|
||||
struct lvconvert_params *lp)
|
||||
{
|
||||
@ -3779,6 +3914,46 @@ static int _lvconvert_cache(struct cmd_context *cmd,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lvconvert_to_cache_vol(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
struct logical_volume *cachepool_lv)
|
||||
{
|
||||
struct logical_volume *cache_lv;
|
||||
cache_mode_t cache_mode = 0;
|
||||
const char *policy_name = NULL;
|
||||
struct dm_config_tree *policy_settings = NULL;
|
||||
|
||||
if (!validate_lv_cache_create_pool(cachepool_lv))
|
||||
return_0;
|
||||
|
||||
if (!get_cache_params(cmd, &cache_mode, &policy_name, &policy_settings))
|
||||
return_0;
|
||||
|
||||
if (!archive(lv->vg))
|
||||
return_0;
|
||||
|
||||
if (!(cache_lv = lv_cache_create(cachepool_lv, lv)))
|
||||
return_0;
|
||||
|
||||
if (cache_mode &&
|
||||
!cache_set_cache_mode(first_seg(cache_lv), cache_mode))
|
||||
return_0;
|
||||
|
||||
if ((policy_name || policy_settings) &&
|
||||
!cache_set_policy(first_seg(cache_lv), policy_name, policy_settings))
|
||||
return_0;
|
||||
|
||||
cache_check_for_warns(first_seg(cache_lv));
|
||||
|
||||
if (!lv_update_and_reload(cache_lv))
|
||||
return_0;
|
||||
|
||||
log_print_unless_silent("Logical volume %s is now cached.",
|
||||
display_lvname(cache_lv));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Functions called to perform a specific operation on a specific LV type.
|
||||
*
|
||||
@ -5510,3 +5685,112 @@ int lvconvert_to_pool_noarg_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||
return lvconvert_to_pool_cmd(cmd, argc, argv);
|
||||
}
|
||||
|
||||
static int _lvconvert_to_cache_vol_single(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
struct processing_handle *handle)
|
||||
{
|
||||
struct volume_group *vg = lv->vg;
|
||||
struct logical_volume *cachepool_lv;
|
||||
const char *cachepool_name;
|
||||
|
||||
/* if the cachepool arg is not a cachepool, first convert it to one */
|
||||
|
||||
if (!(cachepool_name = arg_str_value(cmd, cachepool_ARG, NULL)))
|
||||
return_0;
|
||||
|
||||
/* FIXME: remove optional vg prefix */
|
||||
|
||||
if (!(cachepool_lv = find_lv(vg, cachepool_name))) {
|
||||
log_error("Cache pool %s not found.", cachepool_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: cachepool_lv can only be certain LV types */
|
||||
|
||||
if (!lv_is_cache_pool(cachepool_lv)) {
|
||||
_lvconvert_to_pool(cmd, cachepool_lv, 0, 1, &vg->pvs);
|
||||
|
||||
if (!(cachepool_lv = find_lv(vg, cachepool_name))) {
|
||||
/* fail */
|
||||
}
|
||||
|
||||
if (!lv_is_cache_pool(cachepool_lv)) {
|
||||
/* fail */
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* FIXME: When creating a cache vol using an existing cache pool:
|
||||
* . the cache pool chunk_size can be changed (--chunksize used)
|
||||
* . the cache pool is wiped (with confirm) (--zero used)
|
||||
* . warn if cache pool is not wiped
|
||||
*/
|
||||
}
|
||||
|
||||
/* when the lv arg is a thinpool, redirect command to data sub lv */
|
||||
|
||||
if (lv_is_thin_pool(lv)) {
|
||||
/* set lv to data sublv */
|
||||
}
|
||||
|
||||
/* convert lv to cache vol using cachepool_lv */
|
||||
|
||||
if (!_lvconvert_to_cache_vol(cmd, lv, cachepool_lv))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
||||
int lvconvert_to_cache_vol_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
return process_each_lv(cmd, 1, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE,
|
||||
NULL, NULL, &_lvconvert_to_cache_vol_single);
|
||||
}
|
||||
|
||||
static int _lvconvert_to_thin_with_external_single(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
struct processing_handle *handle)
|
||||
{
|
||||
struct volume_group *vg = lv->vg;
|
||||
struct logical_volume *thinpool_lv;
|
||||
const char *thinpool_name;
|
||||
|
||||
/* if the thinpool arg is not a thinpool, first convert it to one */
|
||||
|
||||
if (!(thinpool_name = arg_str_value(cmd, thinpool_ARG, NULL)))
|
||||
return_0;
|
||||
|
||||
/* FIXME: remove optional vg prefix */
|
||||
|
||||
if (!(thinpool_lv = find_lv(vg, thinpool_name))) {
|
||||
log_error("Thin pool %s not found.", thinpool_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: thinpool_lv can only be certain LV types */
|
||||
|
||||
if (!lv_is_thin_pool(thinpool_lv)) {
|
||||
_lvconvert_to_pool(cmd, thinpool_lv, 1, 0, &vg->pvs);
|
||||
|
||||
if (!(thinpool_lv = find_lv(vg, thinpool_name))) {
|
||||
/* fail */
|
||||
}
|
||||
|
||||
if (!lv_is_thin_pool(thinpool_lv)) {
|
||||
/* fail */
|
||||
}
|
||||
}
|
||||
|
||||
/* convert lv to thin with external using thinpool_lv */
|
||||
|
||||
if (!_lvconvert_to_thin_with_external(cmd, lv, thinpool_lv))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
||||
int lvconvert_to_thin_with_external_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
return process_each_lv(cmd, 1, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE,
|
||||
NULL, NULL, &_lvconvert_to_thin_with_external_single);
|
||||
}
|
||||
|
||||
|
@ -140,10 +140,8 @@ struct command_function command_functions[COMMAND_ID_COUNT] = {
|
||||
{ lvconvert_to_thinpool_noarg_CMD, lvconvert_to_pool_noarg_cmd },
|
||||
{ lvconvert_to_cachepool_CMD, lvconvert_to_pool_cmd },
|
||||
{ lvconvert_to_cachepool_noarg_CMD, lvconvert_to_pool_noarg_cmd },
|
||||
#if 0
|
||||
{ lvconvert_to_thin_with_external_CMD, lvconvert_to_thin_with_external_cmd },
|
||||
{ lvconvert_to_cache_vol_CMD, lvconvert_to_cache_vol_cmd },
|
||||
#endif
|
||||
};
|
||||
|
||||
#if 0
|
||||
|
@ -262,5 +262,7 @@ int lvconvert_start_poll_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||
|
||||
int lvconvert_to_pool_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||
int lvconvert_to_pool_noarg_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||
int lvconvert_to_cache_vol_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||
int lvconvert_to_thin_with_external_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user