master - cache: improve creation code
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=d46c2f1c946e21...
Commit: d46c2f1c946e21393537a730eaa624665cb96bbc
Parent: 189d0f8e1deb2ad8b985696d9925f5259ab30baa
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Oct 3 23:51:54 2014 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Oct 6 15:18:06 2014 +0200
cache: improve creation code
Move code to better locations.
Improve test and remove invalid ones
(i.e. no reason to require cache size to be >= then origin).
Correctly comment where the code is doing actual conversion
of other existing volume - we do already a similar thing with
external origins.
Lots of new command line options and combinations is now supported.
Hopefully older syntax still works as well.
lvcreate --cache --cachepool vg/pool -l1
lvcreate --type cache --cachepool vg/pool -l1
lvcreate --type cache-pool vg/pool -l1
lvcreate --type cache-pool --name pool vg -l1
... and many many more ...
---
WHATS_NEW | 1 +
lib/metadata/lv_manip.c | 189 ++++++++++++++++++++++++----------------------
tools/lvcreate.c | 116 +++++++++++++++++++----------
3 files changed, 175 insertions(+), 131 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 8a4fa13..0ffb048 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.112 -
=====================================
+ Improve code for creation of cache and cache pool volumes.
Check cluster-wide (not local) active status before removing LV.
Properly check if activation of removed cached LV really activated.
Lvremoving cached LV removes cachepool (keep with lvconvert --splitcache).
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 1edb0a0..0aa6521 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -6557,7 +6557,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
uint64_t status = UINT64_C(0);
struct logical_volume *lv, *org = NULL;
struct logical_volume *pool_lv;
- struct lv_list *lvl;
+ struct logical_volume *tmp_lv;
const char *thin_name = NULL;
if (new_lv_name && find_lv_in_vg(vg, new_lv_name)) {
@@ -6638,11 +6638,15 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
status |= lp->permission | VISIBLE_LV;
- if (segtype_is_cache(lp->segtype) && lp->pool) {
+ if (seg_is_cache(lp)) {
+ if (!lp->pool) {
+ log_error(INTERNAL_ERROR "Cannot create cached volume without cache pool.");
+ return NULL;
+ }
/* We have the cache_pool, create the origin with cache */
if (!(pool_lv = find_lv(vg, lp->pool))) {
- log_error("Couldn't find origin volume '%s'.",
- lp->pool);
+ log_error("Couldn't find cache pool volume %s in "
+ "volume group %s.", lp->pool, vg->name);
return NULL;
}
@@ -6652,44 +6656,12 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
}
if (!lp->extents) {
- log_error("No size given for new cache origin LV");
- return NULL;
- }
-
- if (lp->extents < pool_lv->le_count) {
- log_error("Origin size cannot be smaller than"
- " the cache_pool");
+ log_error("No size given for new cache origin LV.");
return NULL;
}
if (!(lp->segtype = get_segtype_from_string(vg->cmd, "striped")))
return_0;
- } else if (segtype_is_cache(lp->segtype) && lp->origin) {
- /* We have the origin, create the cache_pool and cache */
- if (!(org = find_lv(vg, lp->origin))) {
- log_error("Couldn't find origin volume '%s'.",
- lp->origin);
- return NULL;
- }
-
- if (lv_is_locked(org)) {
- log_error("Caching locked devices is not supported.");
- return NULL;
- }
-
- if (!lp->extents) {
- log_error("No size given for new cache_pool LV");
- return NULL;
- }
-
- if (lp->extents > org->le_count) {
- log_error("cache-pool size cannot be larger than"
- " the origin");
- return NULL;
- }
- if (!(lp->segtype = get_segtype_from_string(vg->cmd,
- "cache-pool")))
- return_0;
} else if (seg_is_thin(lp) && lp->snapshot) {
if (!lp->origin) {
log_error(INTERNAL_ERROR "Origin LV is not defined.");
@@ -6840,14 +6812,14 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
return NULL;
}
- if (!(lvl = find_lv_in_vg(vg, lp->pool))) {
+ if (!(pool_lv = find_lv(vg, lp->pool))) {
log_error("Unable to find existing pool LV %s in VG %s.",
lp->pool, vg->name);
return NULL;
}
- if ((pool_is_active(lvl->lv) || is_change_activating(lp->activate)) &&
- !update_pool_lv(lvl->lv, 1))
+ if ((pool_is_active(pool_lv) || is_change_activating(lp->activate)) &&
+ !update_pool_lv(pool_lv, 1))
return_NULL;
/* For thin snapshot we must have matching pool */
@@ -6951,43 +6923,6 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
first_seg(lv)->max_recovery_rate = lp->max_recovery_rate;
}
- if (lp->cache) {
- struct logical_volume *tmp_lv;
-
- if (lp->origin) {
- /*
- * FIXME: At this point, create_pool has created
- * the pool and added the data and metadata sub-LVs,
- * but only the metadata sub-LV is in the kernel -
- * a suspend/resume cycle is still necessary on the
- * cache_pool to actualize it in the kernel.
- *
- * Should the suspend/resume be added to create_pool?
- * I say that would be cleaner, but I'm not sure
- * about the effects on thinpool yet...
- */
- if (!lv_update_and_reload(lv)) {
- stack;
- goto deactivate_and_revert_new_lv;
- }
-
- if (!(lvl = find_lv_in_vg(vg, lp->origin)))
- goto deactivate_and_revert_new_lv;
- org = lvl->lv;
- pool_lv = lv;
- } else {
- if (!(lvl = find_lv_in_vg(vg, lp->pool)))
- goto deactivate_and_revert_new_lv;
- pool_lv = lvl->lv;
- org = lv;
- }
-
- if (!(tmp_lv = lv_cache_create(pool_lv, org)))
- goto deactivate_and_revert_new_lv;
-
- lv = tmp_lv;
- }
-
/* FIXME Log allocation and attachment should have happened inside lv_extend. */
if (lp->log_count &&
!seg_is_raid(first_seg(lv)) && seg_is_mirrored(first_seg(lv))) {
@@ -7013,6 +6948,56 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
if (lv_activation_skip(lv, lp->activate, lp->activation_skip & ACTIVATION_SKIP_IGNORE))
lp->activate = CHANGE_AN;
+ /*
+ * Check if this is conversion inside lvcreate
+ * Either we have origin or pool and created cache origin LV
+ */
+ if (lp->cache &&
+ (lp->origin || (lp->pool && !lv_is_cache_pool(lv)))) {
+ if (lp->origin) {
+ if (!(org = find_lv(vg, lp->origin)))
+ goto deactivate_and_revert_new_lv;
+ pool_lv = lv; /* Cache pool is created */
+ } else if (lp->pool) {
+ if (!(pool_lv = find_lv(vg, lp->pool)))
+ goto deactivate_and_revert_new_lv;
+ org = lv; /* Cached origin is created */
+ }
+
+ if (!(tmp_lv = lv_cache_create(pool_lv, org)))
+ goto deactivate_and_revert_new_lv;
+
+ /* From here we cannot deactive_and_revert! */
+ lv = tmp_lv;
+
+ /*
+ * We need to check if origin is active and in
+ * that case reload cached LV.
+ * There is no such problem with cache pool
+ * since it cannot be activated.
+ */
+ if (lp->origin && lv_is_active(lv)) {
+ if (!is_change_activating(lp->activate)) {
+ /* User requested to create inactive cached volume */
+ if (deactivate_lv(cmd, lv)) {
+ log_error("Failed to deactivate %s.", display_lvname(lv));
+ return NULL;
+ }
+ } else if (vg_is_clustered(lv->vg) &&
+ locking_is_clustered() &&
+ locking_supports_remote_queries() &&
+ !lv_is_active_exclusive(lv)) {
+ log_error("Only exclusively active %s could be converted.", display_lvname(lv));
+ return NULL;
+ } else {
+ /* With exclusively active origin just reload */
+ if (!lv_update_and_reload(lv))
+ return_NULL;
+ goto out; /* converted */
+ }
+ }
+ }
+
/* store vg on disk(s) */
if (!vg_write(vg) || !vg_commit(vg))
return_NULL;
@@ -7180,26 +7165,50 @@ struct logical_volume *lv_create_single(struct volume_group *vg,
{
struct logical_volume *lv;
- /* Create thin pool first if necessary */
- if (lp->create_pool && !seg_is_cache_pool(lp) && !seg_is_cache(lp)) {
- if (!seg_is_thin_pool(lp) &&
- !(lp->segtype = get_segtype_from_string(vg->cmd, "thin-pool")))
- return_0;
+ /* Create pool first if necessary */
+ if (lp->create_pool) {
+ if (seg_is_thin(lp)) {
+ if (!seg_is_thin_pool(lp) &&
+ !(lp->segtype = get_segtype_from_string(vg->cmd, "thin-pool")))
+ return_NULL;
- if (!(lv = _lv_create_an_lv(vg, lp, lp->pool)))
- return_0;
+ if (!(lv = _lv_create_an_lv(vg, lp, lp->pool)))
+ return_NULL;
- if (!lp->thin && !lp->snapshot)
- goto out;
+ if (!lp->thin && !lp->snapshot)
+ goto out;
- lp->pool = lv->name;
+ lp->pool = lv->name;
- if (!(lp->segtype = get_segtype_from_string(vg->cmd, "thin")))
- return_0;
+ if (!(lp->segtype = get_segtype_from_string(vg->cmd, "thin")))
+ return_NULL;
+ } else if (seg_is_cache(lp) || seg_is_cache_pool(lp)) {
+ if (!seg_is_cache_pool(lp) &&
+ !(lp->segtype = get_segtype_from_string(vg->cmd,
+ "cache-pool")))
+ return_NULL;
+
+ if (!(lv = _lv_create_an_lv(vg, lp, lp->pool)))
+ return_NULL;
+
+ if (lv_is_cache(lv)) {
+ /* Here it's been converted via lvcreate */
+ log_print_unless_silent("Logical volume %s is now cached.",
+ display_lvname(lv));
+ return lv;
+ }
+
+ if (!lp->cache)
+ goto out;
+
+ lp->pool = lv->name;
+ log_error("Creation of cache pool and cached volume in one command is not yet supported.");
+ return NULL;
+ }
}
if (!(lv = _lv_create_an_lv(vg, lp, lp->lv_name)))
- return_0;
+ return_NULL;
out:
log_print_unless_silent("Logical volume \"%s\" created", lv->name);
diff --git a/tools/lvcreate.c b/tools/lvcreate.c
index 3db2c85..0a0ce1d 100644
--- a/tools/lvcreate.c
+++ b/tools/lvcreate.c
@@ -47,7 +47,7 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
int *pargc, char ***pargv)
{
int argc = *pargc;
- char **argv = *pargv, *ptr;
+ char **argv = *pargv;
const char *vg_name;
lp->lv_name = arg_str_value(cmd, name_ARG, NULL);
@@ -61,28 +61,54 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
if (seg_is_cache(lp)) {
/*
- * We are looking for the origin or cache_pool LV.
- * Could be in the form 'lv' or 'vg/lv'
+ * We allowed somewhat hard to 'parse' syntax
+ * (usage of lvcreate to convert LV to a cached LV).
+ * So let's try to do our best to avoid wrong steps.
*
- * We store the lv name in 'lp->origin' for now, but
+ * We are looking for the vgname or cache pool or cache origin LV.
+ *
+ * We store the lv name in 'lp->pool', but
* it must be accessed later (when we can look-up the
- * LV in the VG) whether it is truly the origin that
- * was specified, or whether it is the cache_pool.
+ * LV in the VG) whether it is truly the cache pool
+ * or whether it is the origin for cached LV.
*/
if (!argc) {
- log_error("Please specify a logical volume to act as "
- "the origin or cache_pool.");
- return 0;
- }
-
- lp->origin = skip_dev_dir(cmd, argv[0], NULL);
- if (strrchr(lp->origin, '/')) {
- if (!_set_vg_name(lp, extract_vgname(cmd, lp->origin)))
- return_0;
-
- /* Strip the volume group from the origin */
- if ((ptr = strrchr(lp->origin, (int) '/')))
- lp->origin = ptr + 1;
+ if (!lp->pool) {
+ /* Don't advertise we could handle cache origin */
+ log_error("Please specify a logical volume to act as the cache pool.");
+ return 0;
+ }
+ } else {
+ vg_name = skip_dev_dir(cmd, argv[0], NULL);
+ if (!strchr(vg_name, '/')) {
+ /* Lucky part - only vgname is here */
+ if (!_set_vg_name(lp, vg_name))
+ return_0;
+ } else {
+ /* Lets pretend it's cache origin for now */
+ lp->origin = vg_name;
+ if (!validate_lvname_param(cmd, &lp->vg_name, &lp->origin))
+ return_0;
+
+ if (lp->pool) {
+ if (strcmp(lp->pool, lp->origin)) {
+ log_error("Unsupported syntax, cannot use cache origin %s and --cachepool %s.",
+ lp->origin, lp->pool);
+ /* Stop here, only older form remains supported */
+ return 0;
+ }
+ lp->origin = NULL;
+ } else {
+ /*
+ * Gambling here, could be cache pool or cache origin,
+ * detection is possible after openning vg,
+ * yet we need to parse pool args
+ */
+ lp->pool = lp->origin;
+ lp->create_pool = 1;
+ }
+ }
+ (*pargv)++, (*pargc)--;
}
if (!lp->vg_name &&
@@ -90,13 +116,18 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
return_0;
if (!lp->vg_name) {
- log_error("The origin or cache_pool name should include"
- " the volume group.");
+ log_error("The cache pool or cache origin name should "
+ "include the volume group.");
+ return 0;
+ }
+
+ if (!lp->pool) {
+ log_error("Creation of cached volume and cache pool "
+ "in one command is not yet supported.");
return 0;
}
lp->cache = 1;
- (*pargv)++, (*pargc)--;
} else if (lp->snapshot && !arg_count(cmd, virtualsize_ARG)) {
/* argv[0] might be [vg/]origin */
if (!argc) {
@@ -268,15 +299,15 @@ static int _lvcreate_update_pool_params(struct volume_group *vg,
* @vg
* @lp
*
- * 'lp->origin' is set with an LV that could be either the origin
- * or the cache_pool of the cached LV which is being created. This
+ * 'lp->pool' is set with an LV that could be either the cache_pool
+ * or the origin of the cached LV which is being created. This
* function determines which it is and sets 'lp->origin' or
* 'lp->pool' appropriately.
*/
static int _determine_cache_argument(struct volume_group *vg,
struct lvcreate_params *lp)
{
- struct lv_list *lvl;
+ struct logical_volume *lv;
if (!seg_is_cache(lp)) {
log_error(INTERNAL_ERROR
@@ -284,22 +315,25 @@ static int _determine_cache_argument(struct volume_group *vg,
lp->segtype->name);
return 0;
}
- if (!lp->origin) {
- log_error(INTERNAL_ERROR "Origin LV is not defined.");
- return 0;
- }
- if (!(lvl = find_lv_in_vg(vg, lp->origin))) {
- log_error("LV %s not found in Volume group %s.",
- lp->origin, vg->name);
- return 0;
- }
- if (lv_is_cache_pool(lvl->lv)) {
- lp->pool = lp->origin;
- lp->origin = NULL;
- } else {
- lp->pool = NULL;
- lp->create_pool = 1;
+ if (!lp->pool) {
+ lp->pool = lp->lv_name;
+ } else if (lp->pool == lp->origin) {
+ if (!(lv = find_lv(vg, lp->pool))) {
+ /* Cache pool nor origin volume exists */
+ lp->cache = 0;
+ lp->origin = NULL;
+ if (!(lp->segtype = get_segtype_from_string(vg->cmd, "cache-pool")))
+ return_0;
+ } else if (!lv_is_cache_pool(lv)) {
+ /* Name arg in this case is for pool name */
+ lp->pool = lp->lv_name;
+ /* We were given origin for caching */
+ } else {
+ /* FIXME error on pool args */
+ lp->create_pool = 0;
+ lp->origin = NULL;
+ }
}
return 1;
@@ -1246,7 +1280,7 @@ int lvcreate(struct cmd_context *cmd, int argc, char **argv)
lp.pvh, lp.poolmetadataspare))
goto_out;
- log_verbose("Making thin pool %s in VG %s using segtype %s",
+ log_verbose("Making pool %s in VG %s using segtype %s",
lp.pool ? : "with generated name", lp.vg_name, lp.segtype->name);
}
9 years, 6 months
master - lvremove: detect cluster wide active state
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=189d0f8e1deb2a...
Commit: 189d0f8e1deb2ad8b985696d9925f5259ab30baa
Parent: b37203c8193ea47d2de1033b5e57ae5bd1360df4
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Oct 3 23:49:57 2014 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Oct 6 15:18:06 2014 +0200
lvremove: detect cluster wide active state
If the LV is active remotely do not skip question for deactivation.
---
WHATS_NEW | 1 +
lib/metadata/lv_manip.c | 3 ++-
2 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 275d666..8a4fa13 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.112 -
=====================================
+ Check cluster-wide (not local) active status before removing LV.
Properly check if activation of removed cached LV really activated.
Lvremoving cached LV removes cachepool (keep with lvconvert --splitcache).
Always remove spare LV with last removed pool volume.
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 168ce05..1edb0a0 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -5429,7 +5429,8 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
/* FIXME Ensure not referred to by another existing LVs */
ask_discard = find_config_tree_bool(cmd, devices_issue_discards_CFG, NULL);
- if (!lv_is_cache_pool(lv) && lv_is_active_locally(lv)) {
+ if (!lv_is_cache_pool(lv) && /* cache pool cannot be active */
+ lv_is_active(lv)) {
if (!lv_check_not_in_use(lv))
return_0;
9 years, 6 months
master - cache: check activation of volume activated
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=b37203c8193ea4...
Commit: b37203c8193ea47d2de1033b5e57ae5bd1360df4
Parent: 75119d85b3dfe9f53187f37130fd6d215705c166
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Oct 3 23:48:42 2014 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Oct 6 15:18:06 2014 +0200
cache: check activation of volume activated
volume_list may silently skip activation which is then still reported as
success.
---
WHATS_NEW | 1 +
lib/metadata/cache_manip.c | 15 ++++++++++-----
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index a11fa16..275d666 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.112 -
=====================================
+ Properly check if activation of removed cached LV really activated.
Lvremoving cached LV removes cachepool (keep with lvconvert --splitcache).
Always remove spare LV with last removed pool volume.
Support lvconvert --splitcache and --uncache of cached LV.
diff --git a/lib/metadata/cache_manip.c b/lib/metadata/cache_manip.c
index 80214c9..ed08726 100644
--- a/lib/metadata/cache_manip.c
+++ b/lib/metadata/cache_manip.c
@@ -229,11 +229,16 @@ int lv_cache_remove(struct logical_volume *cache_lv)
return 0;
}
- /* Active volume is needed (writeback only?) */
- if (!lv_is_active_locally(cache_lv) &&
- !activate_lv_excl_local(cache_lv->vg->cmd, cache_lv)) {
- log_error("Failed to active cache locally %s.", cache_lv->name);
- return 0;
+ /* Localy active volume is needed (writeback only?) */
+ if (!lv_is_active_locally(cache_lv)) {
+ cache_lv->status |= LV_TEMPORARY;
+ if (!activate_lv_excl_local(cache_lv->vg->cmd, cache_lv) ||
+ !lv_is_active_locally(cache_lv)) {
+ log_error("Failed to active cache locally %s.",
+ display_lvname(cache_lv));
+ return 0;
+ }
+ cache_lv->status &= ~LV_TEMPORARY;
}
/*
9 years, 6 months
master - cache: lvremoved cached LV removes cache pool
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=75119d85b3dfe9...
Commit: 75119d85b3dfe9f53187f37130fd6d215705c166
Parent: cb273fe16423a2868c0bdde7c8e56cb21131338d
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Oct 3 23:36:11 2014 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Oct 6 15:18:06 2014 +0200
cache: lvremoved cached LV removes cache pool
When we remove cached volume, whole tree must go down.
There is 'lvconvert --splitcache' to preserve cache pool.
---
WHATS_NEW | 1 +
lib/metadata/lv_manip.c | 23 +++++++++++++++++++++--
2 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 3d5f9c4..a11fa16 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.112 -
=====================================
+ Lvremoving cached LV removes cachepool (keep with lvconvert --splitcache).
Always remove spare LV with last removed pool volume.
Support lvconvert --splitcache and --uncache of cached LV.
Option --cache has also shortcut -H (i.e. lvcreate -H).
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 00f0fbc..168ce05 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -1272,6 +1272,7 @@ static int _lv_reduce(struct logical_volume *lv, uint32_t extents, int delete)
struct lv_segment *seg;
uint32_t count = extents;
uint32_t reduction;
+ struct logical_volume *pool_lv;
if (lv_is_merging_origin(lv)) {
log_debug_metadata("Dropping snapshot merge of %s to removed origin %s.",
@@ -1302,8 +1303,13 @@ static int _lv_reduce(struct logical_volume *lv, uint32_t extents, int delete)
if (delete && seg_is_cache(seg) && !lv_remove(seg_lv(seg, 0)))
return_0;
- if (seg->pool_lv && !detach_pool_lv(seg))
- return_0;
+ if ((pool_lv = seg->pool_lv)) {
+ if (!detach_pool_lv(seg))
+ return_0;
+ /* When removing cached LV, remove pool as well */
+ if (seg_is_cache(seg) && !lv_remove(pool_lv))
+ return_0;
+ }
dm_list_del(&seg->list);
reduction = seg->len;
@@ -5454,6 +5460,19 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
if (!archive(vg))
return 0;
+ if (lv_is_cache(lv)) {
+ if (!lv_remove_single(cmd, first_seg(lv)->pool_lv, force,
+ suppress_remove_message)) {
+ if (force < DONT_PROMPT_OVERRIDE) {
+ log_error("Failed to uncache %s.", display_lvname(lv));
+ return 0;
+ }
+ /* Proceed with -ff */
+ log_print_unless_silent("Ignoring uncache failure of %s.",
+ display_lvname(lv));
+ }
+ }
+
if (lv_is_cow(lv)) {
/* Old format1 code */
if (!(lv->vg->fid->fmt->features & FMT_MDAS))
9 years, 6 months
master - pools: move removal of _pmspare
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=cb273fe16423a2...
Commit: cb273fe16423a2868c0bdde7c8e56cb21131338d
Parent: 20803f2275d9eb08344c4882e62381cf23454eba
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Oct 3 23:34:16 2014 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Oct 6 15:18:06 2014 +0200
pools: move removal of _pmspare
Since _pmspare is internal volume move it to
lv_remove_single - so it's automatically removed with
last remove thin-pool.
lv_remove_with_dependencies() is not always used for pool removal.
---
WHATS_NEW | 1 +
lib/metadata/lv_manip.c | 43 +++++++++++++++++++++++--------------------
2 files changed, 24 insertions(+), 20 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 8341d8d..3d5f9c4 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.112 -
=====================================
+ Always remove spare LV with last removed pool volume.
Support lvconvert --splitcache and --uncache of cached LV.
Option --cache has also shortcut -H (i.e. lvcreate -H).
Refactor lvcreate code and better preserve --type argument.
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 25342d6..00f0fbc 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -5369,6 +5369,8 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
struct logical_volume *pool_lv = NULL;
struct lv_segment *cache_seg = NULL;
int ask_discard;
+ struct lv_list *lvl;
+ int is_last_pool;
vg = lv->vg;
@@ -5463,6 +5465,27 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
return_0;
}
+ if (lv_is_pool(lv) && lv->vg->pool_metadata_spare_lv) {
+ /* When removing last pool, also remove the spare */
+ is_last_pool = 1;
+ dm_list_iterate_items(lvl, &lv->vg->lvs)
+ if (lv_is_pool(lvl->lv) &&
+ lvl->lv != lv) {
+ is_last_pool = 0;
+ break;
+ }
+ if (is_last_pool) {
+ /* This is purely internal LV volume, no question */
+ if (!deactivate_lv(cmd, lv->vg->pool_metadata_spare_lv)) {
+ log_error("Unable to deactivate logical volume %s",
+ display_lvname(lv->vg->pool_metadata_spare_lv));
+ return 0;
+ }
+ if (!lv_remove(lv->vg->pool_metadata_spare_lv))
+ return_0;
+ }
+ }
+
if (lv_is_cache_pool(lv)) {
/* Cache pool removal drops cache layer
* If the cache pool is not linked, we can simply remove it. */
@@ -5580,10 +5603,8 @@ int lv_remove_with_dependencies(struct cmd_context *cmd, struct logical_volume *
{
dm_percent_t snap_percent;
struct dm_list *snh, *snht;
- struct lv_list *lvl;
struct lvinfo info;
struct logical_volume *origin;
- int is_last_pool;
if (lv_is_cow(lv)) {
/*
@@ -5661,24 +5682,6 @@ int lv_remove_with_dependencies(struct cmd_context *cmd, struct logical_volume *
!_lv_remove_segs_using_this_lv(cmd, lv, force, level, "pool"))
return_0;
- if ((lv_is_thin_pool(lv) || lv_is_cache_pool(lv)) &&
- lv->vg->pool_metadata_spare_lv) {
- /* When removing last pool, also remove the spare */
- is_last_pool = 1;
- dm_list_iterate_items(lvl, &lv->vg->lvs)
- if ((lv_is_thin_pool(lvl->lv) ||
- lv_is_cache_pool(lvl->lv)) &&
- lvl->lv != lv) {
- is_last_pool = 0;
- break;
- }
-
- if (is_last_pool &&
- !lv_remove_with_dependencies(cmd, lv->vg->pool_metadata_spare_lv,
- DONT_PROMPT, level + 1))
- return_0;
- }
-
if (lv_is_pool_metadata_spare(lv) &&
(force == PROMPT) &&
(yes_no_prompt("Removal of pool metadata spare logical volume"
9 years, 6 months
master - lvcreate: reuse validation of names
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=20803f2275d9eb...
Commit: 20803f2275d9eb08344c4882e62381cf23454eba
Parent: 0662391ff60c5fbdf4b941bad92de31558ecd89b
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Oct 3 19:04:45 2014 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Oct 6 15:18:06 2014 +0200
lvcreate: reuse validation of names
Use validate_lvname_param() for name validation.
---
tools/lvcreate.c | 111 ++++++++++++++++++++----------------------------------
1 files changed, 41 insertions(+), 70 deletions(-)
diff --git a/tools/lvcreate.c b/tools/lvcreate.c
index a3f07f3..3db2c85 100644
--- a/tools/lvcreate.c
+++ b/tools/lvcreate.c
@@ -50,28 +50,14 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
char **argv = *pargv, *ptr;
const char *vg_name;
- lp->pool = arg_str_value(cmd, thinpool_ARG, NULL);
-
- /* If --thinpool contains VG name, extract it. */
- if (lp->pool && strchr(lp->pool, '/')) {
- if (!(lp->vg_name = extract_vgname(cmd, lp->pool)))
- return 0;
- /* Strip VG from pool */
- if ((ptr = strrchr(lp->pool, (int) '/')))
- lp->pool = ptr + 1;
- }
-
lp->lv_name = arg_str_value(cmd, name_ARG, NULL);
+ if (!validate_lvname_param(cmd, &lp->vg_name, &lp->lv_name))
+ return_0;
- /* If --name contains VG name, extract it. */
- if (lp->lv_name && strchr(lp->lv_name, '/')) {
- if (!_set_vg_name(lp, extract_vgname(cmd, lp->lv_name)))
- return_0;
-
- /* Strip VG from lv_name */
- if ((ptr = strrchr(lp->lv_name, (int) '/')))
- lp->lv_name = ptr + 1;
- }
+ lp->pool = arg_str_value(cmd, thinpool_ARG, NULL)
+ ? : arg_str_value(cmd, cachepool_ARG, NULL);
+ if (!validate_lvname_param(cmd, &lp->vg_name, &lp->pool))
+ return_0;
if (seg_is_cache(lp)) {
/*
@@ -112,22 +98,16 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
lp->cache = 1;
(*pargv)++, (*pargc)--;
} else if (lp->snapshot && !arg_count(cmd, virtualsize_ARG)) {
- /* argv[0] might be origin or vg/origin */
+ /* argv[0] might be [vg/]origin */
if (!argc) {
log_error("Please specify a logical volume to act as "
"the snapshot origin.");
return 0;
}
- lp->origin = skip_dev_dir(cmd, argv[0], NULL);
- if (strrchr(lp->origin, '/')) {
- if (!_set_vg_name(lp, extract_vgname(cmd, lp->origin)))
- return_0;
-
- /* Strip the volume group from the origin */
- if ((ptr = strrchr(lp->origin, (int) '/')))
- lp->origin = ptr + 1;
- }
+ lp->origin = argv[0];
+ if (!validate_lvname_param(cmd, &lp->vg_name, &lp->origin))
+ return_0;
if (!lp->vg_name &&
!_set_vg_name(lp, extract_vgname(cmd, NULL)))
@@ -140,33 +120,35 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
}
(*pargv)++, (*pargc)--;
- } else if (seg_is_thin(lp) && !lp->pool && argc) {
- /* argv[0] might be vg or vg/Pool */
+ } else if ((seg_is_thin(lp) || seg_is_pool(lp)) && argc) {
+ /* argv[0] might be [/dev.../]vg or [/dev../]vg/pool */
vg_name = skip_dev_dir(cmd, argv[0], NULL);
- if (!strrchr(vg_name, '/')) {
+ if (!strchr(vg_name, '/')) {
if (!_set_vg_name(lp, vg_name))
return_0;
} else {
- lp->pool = vg_name;
- if (!_set_vg_name(lp, extract_vgname(cmd, lp->pool)))
+ if (!validate_lvname_param(cmd, &lp->vg_name, &vg_name))
return_0;
+ if (lp->pool &&
+ (strcmp(vg_name, lp->pool) != 0)) {
+ log_error("Ambiguous %s name specified, %s and %s.",
+ lp->segtype->name, vg_name, lp->pool);
+ return 0;
+ }
+ lp->pool = vg_name;
+
if (!lp->vg_name &&
!_set_vg_name(lp, extract_vgname(cmd, NULL)))
return_0;
if (!lp->vg_name) {
- log_error("The pool name should include the "
- "volume group.");
+ log_error("The %s name should include the "
+ "volume group.", lp->segtype->name);
return 0;
}
-
- /* Strip the volume group */
- if ((ptr = strrchr(lp->pool, (int) '/')))
- lp->pool = ptr + 1;
}
-
(*pargv)++, (*pargc)--;
} else {
/*
@@ -179,7 +161,7 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
}
} else {
vg_name = skip_dev_dir(cmd, argv[0], NULL);
- if (strrchr(vg_name, '/')) {
+ if (strchr(vg_name, '/')) {
log_error("Volume group name expected "
"(no slash)");
return 0;
@@ -192,38 +174,27 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
}
}
- if (!validate_name(lp->vg_name)) {
- log_error("Volume group name %s has invalid characters",
- lp->vg_name);
- return 0;
- }
-
- if (lp->lv_name) {
- if (!apply_lvname_restrictions(lp->lv_name))
- return_0;
-
- if (!validate_name(lp->lv_name)) {
- log_error("Logical volume name \"%s\" is invalid",
- lp->lv_name);
+ /* support --name & --type {thin|cache}-pool */
+ if (seg_is_pool(lp) && lp->lv_name) {
+ if (lp->pool && (strcmp(lp->lv_name, lp->pool) != 0)) {
+ log_error("Ambiguous %s name specified, %s and %s.",
+ lp->segtype->name, lp->lv_name, lp->pool);
return 0;
}
+ lp->pool = lp->lv_name;
+ lp->lv_name = NULL;
}
- if (lp->pool) {
- if (!apply_lvname_restrictions(lp->pool))
- return_0;
-
- if (!validate_name(lp->pool)) {
- log_error("Logical volume name \"%s\" is invalid",
- lp->pool);
- return 0;
- }
+ if (lp->pool && lp->lv_name && !strcmp(lp->pool, lp->lv_name)) {
+ log_error("Logical volume name %s and pool name must be different.",
+ lp->lv_name);
+ return 0;
+ }
- if (lp->lv_name && !strcmp(lp->lv_name, lp->pool)) {
- log_error("Logical volume name %s and pool name %s must be different.",
- lp->lv_name, lp->pool);
- return 0;
- }
+ if (!validate_name(lp->vg_name)) {
+ log_error("Volume group name %s has invalid characters",
+ lp->vg_name);
+ return 0;
}
return 1;
9 years, 6 months
master - lv_manip: fix out of order backup
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=0662391ff60c5f...
Commit: 0662391ff60c5fbdf4b941bad92de31558ecd89b
Parent: a0cfc5eee2763b7e68c028b517db1825c1f3cce7
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Oct 3 18:39:54 2014 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Oct 6 15:18:05 2014 +0200
lv_manip: fix out of order backup
We had only 2 remaining places that were leaving unbackuped metadata.
---
lib/metadata/lv_manip.c | 7 +++++--
1 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 6136b43..25342d6 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -7031,6 +7031,8 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
stack;
goto revert_new_lv;
}
+
+ backup(vg);
}
if (is_change_activating(lp->activate)) {
/* Send message so that table preload knows new thin */
@@ -7038,6 +7040,9 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
stack;
goto revert_new_lv;
}
+
+ backup(vg);
+
if (!lv_active_change(cmd, lv, lp->activate)) {
log_error("Failed to activate thin %s.", lv->name);
goto deactivate_and_revert_new_lv;
@@ -7125,8 +7130,6 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
if (!lv_update_and_reload(org))
return_0;
}
- /* FIXME out of sequence */
- backup(vg);
out:
return lv;
9 years, 6 months
master - lvconvert: reuse cache validation
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=a0cfc5eee2763b...
Commit: a0cfc5eee2763b7e68c028b517db1825c1f3cce7
Parent: 5a366918432bf4f825d2ddbb00780943c0761a0d
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Oct 3 18:52:08 2014 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Oct 6 15:18:05 2014 +0200
lvconvert: reuse cache validation
Validation is now already in
validate_lv_cache_create() so reuse it.
Also properly rename var origin -> origin_lv.
---
tools/lvconvert.c | 41 +++++------------------------------------
1 files changed, 5 insertions(+), 36 deletions(-)
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 03118cb..11a10f7 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -3168,50 +3168,19 @@ revert_new_lv:
* Convert origin into a cache LV by attaching a cache pool.
*/
static int _lvconvert_cache(struct cmd_context *cmd,
- struct logical_volume *origin,
+ struct logical_volume *origin_lv,
struct lvconvert_params *lp)
{
struct logical_volume *pool_lv = lp->pool_data_lv;
struct logical_volume *cache_lv;
- if (origin == pool_lv) {
- log_error("Can't use same LV %s for cache pool and cache volume.",
- display_lvname(pool_lv));
- return 0;
- }
-
- if (lv_is_pool(origin) || lv_is_cache_type(origin)) {
- log_error("Can't cache pool or cache type volume %s.",
- display_lvname(origin));
- return 0;
- }
-
- /* We support conversion of _tdata */
- if (!lv_is_visible(origin) && !lv_is_thin_pool_data(origin)) {
- log_error("Can't convert internal LV %s.", display_lvname(origin));
- return 0;
- }
-
- /*
- * Only linear, striped or raid supported.
- * FIXME Tidy up all these type restrictions.
- */
- if (lv_is_cache_origin(origin) ||
- lv_is_mirror_type(origin) ||
- lv_is_thin_volume(origin) || lv_is_thin_pool_metadata(origin) ||
- lv_is_origin(origin) || lv_is_merging_origin(origin) ||
- lv_is_cow(origin) || lv_is_merging_cow(origin) ||
- lv_is_external_origin(origin) ||
- lv_is_virtual(origin)) {
- log_error("Cache is not supported with origin LV %s type.",
- display_lvname(origin));
- return 0;
- }
+ if (!validate_lv_cache_create(pool_lv, origin_lv))
+ return_0;
- if (!archive(origin->vg))
+ if (!archive(origin_lv->vg))
return_0;
- if (!(cache_lv = lv_cache_create(pool_lv, origin)))
+ if (!(cache_lv = lv_cache_create(pool_lv, origin_lv)))
return_0;
if (!lv_update_and_reload(cache_lv))
9 years, 6 months
master - cache: add validate_lv_cache_create
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=5a366918432bf4...
Commit: 5a366918432bf4f825d2ddbb00780943c0761a0d
Parent: a8497e329b3c70c88feb5f0121e05464d32b2433
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Oct 3 18:37:11 2014 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Oct 6 15:18:05 2014 +0200
cache: add validate_lv_cache_create
Move validation tests into separate function.
---
lib/metadata/cache_manip.c | 98 +++++++++++++++++++++++++-------------
lib/metadata/metadata-exported.h | 2 +
2 files changed, 67 insertions(+), 33 deletions(-)
diff --git a/lib/metadata/cache_manip.c b/lib/metadata/cache_manip.c
index a44bba8..80214c9 100644
--- a/lib/metadata/cache_manip.c
+++ b/lib/metadata/cache_manip.c
@@ -90,6 +90,63 @@ int update_cache_pool_params(struct volume_group *vg, unsigned attr,
}
/*
+ * Validate arguments for converting origin into cached volume with given cache pool.
+ *
+ * Always validates origin_lv, and when it is known also cache pool_lv
+ */
+int validate_lv_cache_create(const struct logical_volume *pool_lv,
+ const struct logical_volume *origin_lv)
+{
+ struct lv_segment *seg;
+
+ if (pool_lv) {
+ if (!lv_is_cache_pool(pool_lv)) {
+ log_error("Logical volume %s is not a cache pool.",
+ display_lvname(pool_lv));
+ return 0;
+ }
+
+ if (origin_lv == pool_lv) {
+ log_error("Can't use same LV %s for cache pool and cache volume.",
+ display_lvname(pool_lv));
+ return 0;
+ }
+
+ if (!dm_list_empty(&pool_lv->segs_using_this_lv)) {
+ seg = get_only_segment_using_this_lv(pool_lv);
+ log_error("Logical volume %s is already in use by %s",
+ display_lvname(pool_lv),
+ seg ? display_lvname(seg->lv) : "another LV");
+ return 0;
+ }
+ }
+
+ /* For now we only support conversion of thin pool data volume */
+ if (!lv_is_visible(origin_lv) && !lv_is_thin_pool_data(origin_lv)) {
+ log_error("Can't convert internal LV %s.", display_lvname(origin_lv));
+ return 0;
+ }
+
+ /*
+ * Only linear, striped or raid supported.
+ * FIXME Tidy up all these type restrictions.
+ */
+ if (lv_is_cache_type(origin_lv) ||
+ lv_is_mirror_type(origin_lv) ||
+ lv_is_thin_volume(origin_lv) || lv_is_thin_pool_metadata(origin_lv) ||
+ lv_is_origin(origin_lv) || lv_is_merging_origin(origin_lv) ||
+ lv_is_cow(origin_lv) || lv_is_merging_cow(origin_lv) ||
+ lv_is_external_origin(origin_lv) ||
+ lv_is_virtual(origin_lv)) {
+ log_error("Cache is not supported with origin LV %s type.",
+ display_lvname(origin_lv));
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
* lv_cache_create
* @pool
* @origin
@@ -99,57 +156,32 @@ int update_cache_pool_params(struct volume_group *vg, unsigned attr,
*
* Returns: cache LV on success, NULL on failure
*/
-struct logical_volume *lv_cache_create(struct logical_volume *pool,
- struct logical_volume *origin)
+struct logical_volume *lv_cache_create(struct logical_volume *pool_lv,
+ struct logical_volume *origin_lv)
{
const struct segment_type *segtype;
- struct cmd_context *cmd = pool->vg->cmd;
- struct logical_volume *cache_lv;
+ struct cmd_context *cmd = pool_lv->vg->cmd;
+ struct logical_volume *cache_lv = origin_lv;
struct lv_segment *seg;
- if (!lv_is_cache_pool(pool)) {
- log_error(INTERNAL_ERROR
- "%s is not a cache_pool LV", pool->name);
- return NULL;
- }
-
- if (!dm_list_empty(&pool->segs_using_this_lv)) {
- seg = get_only_segment_using_this_lv(pool);
- log_error("%s is already in use by %s",
- pool->name, seg ? seg->lv->name : "another LV");
- return NULL;
- }
-
- if (lv_is_cache_type(origin)) {
- /*
- * FIXME: We can layer caches, insert_layer_for_lv() would
- * have to do a better job renaming the LVs in the stack
- * first so that there isn't a name collision with <name>_corig.
- * The origin under the origin would become *_corig_corig
- * before renaming the origin above to *_corig.
- */
- log_error("Creating a cache LV from an existing cache LV is"
- "not yet supported.");
- return NULL;
- }
+ if (!validate_lv_cache_create(pool_lv, origin_lv))
+ return_NULL;
if (!(segtype = get_segtype_from_string(cmd, "cache")))
return_NULL;
- cache_lv = origin;
- if (!(origin = insert_layer_for_lv(cmd, cache_lv, CACHE, "_corig")))
+ if (!insert_layer_for_lv(cmd, cache_lv, CACHE, "_corig"))
return_NULL;
seg = first_seg(cache_lv);
seg->segtype = segtype;
- if (!attach_pool_lv(seg, pool, NULL, NULL))
+ if (!attach_pool_lv(seg, pool_lv, NULL, NULL))
return_NULL;
return cache_lv;
}
-
/*
* Cleanup orphan device in the table with temporary activation
* since in the suspend() we can't deactivate unused nodes
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index b392bde..d04d987 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -1074,6 +1074,8 @@ int update_cache_pool_params(struct volume_group *vg, unsigned attr,
int passed_args, uint32_t data_extents,
uint64_t *pool_metadata_size,
int *chunk_size_calc_method, uint32_t *chunk_size);
+int validate_lv_cache_create(const struct logical_volume *pool_lv,
+ const struct logical_volume *origin_lv);
struct logical_volume *lv_cache_create(struct logical_volume *pool,
struct logical_volume *origin);
int lv_cache_remove(struct logical_volume *cache_lv);
9 years, 6 months
master - lvconvert: options splitcache, split, uncache
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=a8497e329b3c70...
Commit: a8497e329b3c70c88feb5f0121e05464d32b2433
Parent: 4e9fbb4b96ad4beed5dd004f221cdbfb874e1094
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Sat Oct 4 15:32:24 2014 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Oct 6 15:18:05 2014 +0200
lvconvert: options splitcache, split, uncache
--splitcache
Splits only cached LV (also pool could be specified).
Detaches cachepool from cached LV.
--split
Should be univerzal command to split various complex targets.
At this moment it knows cache.
--uncache
Opposite command to --cache. Detaches and DELETES cachepool for
cached LV.
Note: we support thin pool cached metadata device for uncaching.
Also use may specify wither cached LV or association cachepool device
to request split of cache.
---
WHATS_NEW | 1 +
tools/args.h | 3 +
tools/commands.h | 23 ++++++-
tools/lvconvert.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 205 insertions(+), 4 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 9847730..8341d8d 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.112 -
=====================================
+ Support lvconvert --splitcache and --uncache of cached LV.
Option --cache has also shortcut -H (i.e. lvcreate -H).
Refactor lvcreate code and better preserve --type argument.
Refactor process_each_vg in toollib.
diff --git a/tools/args.h b/tools/args.h
index c1999bd..531148c 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -108,6 +108,9 @@ arg(detachprofile_ARG, '\0', "detachprofile", NULL, 0)
arg(mergedconfig_ARG, '\0', "mergedconfig", NULL, 0)
arg(ignoreskippedcluster_ARG, '\0', "ignoreskippedcluster", NULL, 0)
arg(splitsnapshot_ARG, '\0', "splitsnapshot", NULL, 0)
+arg(splitcache_ARG, '\0', "splitcache", NULL, 0)
+arg(uncache_ARG, '\0', "uncache", NULL, 0)
+arg(split_ARG, '\0', "split", NULL, 0)
arg(readonly_ARG, '\0', "readonly", NULL, 0)
arg(atomic_ARG, '\0', "atomic", NULL, 0)
arg(activationmode_ARG, '\0', "activationmode", string_arg, 0)
diff --git a/tools/commands.h b/tools/commands.h
index ed911fa..2e99fb1 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -184,7 +184,23 @@ xx(lvconvert,
"--splitsnapshot\n"
COMMON_OPTS
"\tSnapshotLogicalVolume[Path]\n\n"
-
+
+ "lvconvert "
+ "--splitcache\n"
+ COMMON_OPTS
+ "\tCacheLogicalVolume[Path]\n\n"
+
+ "lvconvert "
+ "--split\n"
+ "\t[--name SplitLogicalVolumeName]\n"
+ COMMON_OPTS
+ "\tSplitableLogicalVolume[Path]\n\n"
+
+ "lvconvert "
+ "--uncache\n"
+ COMMON_OPTS
+ "\tCacheLogicalVolume[Path]\n\n"
+
"lvconvert "
"[--type snapshot|-s|--snapshot]\n"
"\t[-c|--chunksize]\n"
@@ -229,9 +245,10 @@ xx(lvconvert,
corelog_ARG, discards_ARG, force_ARG, interval_ARG, merge_ARG, mirrorlog_ARG,
mirrors_ARG, name_ARG, noudevsync_ARG, originname_ARG, poolmetadata_ARG,
poolmetadatasize_ARG, poolmetadataspare_ARG, readahead_ARG, regionsize_ARG,
- repair_ARG, replace_ARG, snapshot_ARG, splitmirrors_ARG, splitsnapshot_ARG,
+ repair_ARG, replace_ARG, snapshot_ARG,
+ split_ARG, splitcache_ARG, splitmirrors_ARG, splitsnapshot_ARG,
stripes_long_ARG, stripesize_ARG, test_ARG, thin_ARG, thinpool_ARG,
- trackchanges_ARG, type_ARG, use_policies_ARG, zero_ARG)
+ trackchanges_ARG, type_ARG, uncache_ARG, use_policies_ARG, zero_ARG)
xx(lvcreate,
"Create a logical volume",
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 0d800ec..03118cb 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -20,11 +20,14 @@ struct lvconvert_params {
int cache;
int force;
int snapshot;
+ int split;
+ int splitcache;
int splitsnapshot;
int merge;
int merge_mirror;
int poolmetadataspare;
int thin;
+ int uncache;
int yes;
int zero;
@@ -102,6 +105,18 @@ static int _lvconvert_name_params(struct lvconvert_params *lp,
"the snapshot exception store.");
return 0;
}
+ if (lp->split) {
+ log_error("Logical volume for split is missing.");
+ return 0;
+ }
+ if (lp->splitcache) {
+ log_error("Cache logical volume for split is missing.");
+ return 0;
+ }
+ if (lp->uncache) {
+ log_error("Cache logical volume for uncache is missing.");
+ return 0;
+ }
if (!lp->lv_name_full) {
log_error("Please provide logical volume path.");
return 0;
@@ -159,6 +174,18 @@ static int _lvconvert_name_params(struct lvconvert_params *lp,
log_error("Too many arguments provided with --splitsnapshot.");
return 0;
}
+ if (lp->splitcache) {
+ log_error("Too many arguments provided with --splitcache.");
+ return 0;
+ }
+ if (lp->split) {
+ log_error("Too many arguments provided with --split.");
+ return 0;
+ }
+ if (lp->uncache) {
+ log_error("Too many arguments provided with --uncache.");
+ return 0;
+ }
if (lp->pool_data_lv_name && lp->pool_metadata_lv_name) {
log_error("Too many arguments provided for pool.");
return 0;
@@ -345,6 +372,34 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
lp->splitsnapshot = 1;
}
+ if (arg_is_set(cmd, split_ARG)) {
+ if (arg_outside_list_is_set(cmd, "cannot be used with --split",
+ split_ARG,
+ name_ARG,
+ force_ARG, noudevsync_ARG, test_ARG,
+ -1))
+ return_0;
+ lp->split = 1;
+ }
+
+ if (arg_is_set(cmd, splitcache_ARG)) {
+ if (arg_outside_list_is_set(cmd, "cannot be used with --splitcache",
+ splitcache_ARG,
+ force_ARG, noudevsync_ARG, test_ARG,
+ -1))
+ return_0;
+ lp->splitcache = 1;
+ }
+
+ if (arg_is_set(cmd, uncache_ARG)) {
+ if (arg_outside_list_is_set(cmd, "cannot be used with --uncache",
+ uncache_ARG,
+ force_ARG, noudevsync_ARG, test_ARG,
+ -1))
+ return_0;
+ lp->uncache = 1;
+ }
+
if ((_snapshot_type_requested(cmd, type_str) || arg_count(cmd, merge_ARG)) &&
(arg_count(cmd, mirrorlog_ARG) || _mirror_or_raid_type_requested(cmd, type_str) ||
arg_count(cmd, repair_ARG) || arg_count(cmd, thinpool_ARG))) {
@@ -404,13 +459,15 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
lp->snapshot = 1;
}
+ if (lp->split) {
+ lp->lv_split_name = arg_str_value(cmd, name_ARG, NULL);
/*
* The '--splitmirrors n' argument is equivalent to '--mirrors -n'
* (note the minus sign), except that it signifies the additional
* intent to keep the mimage that is detached, rather than
* discarding it.
*/
- if (arg_count(cmd, splitmirrors_ARG)) {
+ } else if (arg_count(cmd, splitmirrors_ARG)) {
if (_mirror_or_raid_type_requested(cmd, type_str)) {
log_error("--mirrors/--type mirror/--type raid* and --splitmirrors are "
"mutually exclusive.");
@@ -1971,6 +2028,111 @@ static int _lvconvert_splitsnapshot(struct cmd_context *cmd, struct logical_volu
return ECMD_PROCESSED;
}
+
+static int _lvconvert_split_cached(struct cmd_context *cmd,
+ struct logical_volume *lv)
+{
+ struct logical_volume *cache_pool_lv = first_seg(lv)->pool_lv;
+
+ log_debug("Detaching cache pool %s from cached LV %s.",
+ display_lvname(cache_pool_lv), display_lvname(lv));
+
+ if (!archive(lv->vg))
+ return_0;
+
+ if (!lv_cache_remove(lv))
+ return_0;
+
+ if (!vg_write(lv->vg) || !vg_commit(lv->vg))
+ return_0;
+
+ backup(lv->vg);
+
+ log_print_unless_silent("Logical volume %s is not cached and cache pool %s is unused.",
+ display_lvname(lv), display_lvname(cache_pool_lv));
+
+ return 1;
+}
+
+static int _lvconvert_splitcache(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ struct lvconvert_params *lp)
+{
+ struct lv_segment *seg;
+
+ if (lv_is_thin_pool(lv))
+ lv = seg_lv(first_seg(lv), 0); /* cached _tdata ? */
+
+ /* When passed used cache-pool of used cached LV -> split cached LV */
+ if (lv_is_cache_pool(lv) &&
+ (dm_list_size(&lv->segs_using_this_lv) == 1) &&
+ (seg = get_only_segment_using_this_lv(lv)) &&
+ seg_is_cache(seg))
+ lv = seg->lv;
+
+ /* Supported LV types for split */
+ if (!lv_is_cache(lv)) {
+ log_error("Split of %s is not cache.", display_lvname(lv));
+ return 0;
+ }
+
+ if (!_lvconvert_split_cached(cmd, lv))
+ return_0;
+
+ return 1;
+}
+
+static int _lvconvert_split(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ struct lvconvert_params *lp)
+{
+ struct lv_segment *seg;
+
+ if (lv_is_thin_pool(lv) &&
+ lv_is_cache(seg_lv(first_seg(lv), 0)))
+ lv = seg_lv(first_seg(lv), 0); /* cached _tdata ? */
+
+ /* When passed used cache-pool of used cached LV -> split cached LV */
+ if (lv_is_cache_pool(lv) &&
+ (dm_list_size(&lv->segs_using_this_lv) == 1) &&
+ (seg = get_only_segment_using_this_lv(lv)) &&
+ seg_is_cache(seg))
+ lv = seg->lv;
+
+ /* Supported LV types for split */
+ if (lv_is_cache(lv)) {
+ if (!_lvconvert_split_cached(cmd, lv))
+ return_0;
+ /* Add more types here */
+ } else {
+ log_error("Split of %s is unsupported.", display_lvname(lv));
+ return 0;
+ }
+
+ return 1;
+}
+
+static int _lvconvert_uncache(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ struct lvconvert_params *lp)
+{
+ if (lv_is_thin_pool(lv))
+ lv = seg_lv(first_seg(lv), 0); /* cached _tdata ? */
+
+ if (!lv_is_cache(lv)) {
+ log_error("Cannot uncache non-cached logical volume %s.",
+ display_lvname(lv));
+ return 0;
+ }
+
+ if (!lv_remove_single(cmd, first_seg(lv)->pool_lv, lp->force, 0))
+ return_0;
+
+ log_print_unless_silent("Logical volume %s is not cached.", display_lvname(lv));
+
+ return 1;
+}
+
static int _lvconvert_snapshot(struct cmd_context *cmd,
struct logical_volume *lv,
struct lvconvert_params *lp)
@@ -3087,6 +3249,24 @@ static int _lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
if (lp->splitsnapshot)
return _lvconvert_splitsnapshot(cmd, lv, lp);
+ if (lp->splitcache) {
+ if (!_lvconvert_splitcache(cmd, lv, lp))
+ return_ECMD_FAILED;
+ return ECMD_PROCESSED;
+ }
+
+ if (lp->split) {
+ if (!_lvconvert_split(cmd, lv, lp))
+ return_ECMD_FAILED;
+ return ECMD_PROCESSED;
+ }
+
+ if (lp->uncache) {
+ if (!_lvconvert_uncache(cmd, lv, lp))
+ return_ECMD_FAILED;
+ return ECMD_PROCESSED;
+ }
+
if (arg_count(cmd, repair_ARG)) {
if (lv_is_pool(lv)) {
if (!_lvconvert_pool_repair(cmd, lv, lp))
9 years, 6 months