summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZdenek Kabelac <zkabelac@redhat.com>2014-10-24 15:26:41 +0200
committerZdenek Kabelac <zkabelac@redhat.com>2014-10-24 16:39:32 +0200
commitd13239b0547e09def4b58b0f49bd0252f459d431 (patch)
treef5ab37e3fd6f04177d7e5816a361549935bbae07
parent51a29e60564d5379b38ee4688bca5eb9b844c410 (diff)
downloadlvm2-d13239b0547e09def4b58b0f49bd0252f459d431.tar.gz
lvcreate: new validation code
Refactor lvcreate code. Prefer to use arg_outside_list_is_set() so we get automatic 'white-list' validation of supported options with different segment types. Drop used lp->cache, lp->cache and use seg_is_cache(), seg_is_thin() Draw clear border where is the last moment we could change create segment type. When segment type is given with --type - do not allow it to be changed later. Put together tests related to individual segment types. Finish cache conversion at proper part of lv_manip code after the vg_metadata are written - so we could correcly clean-up created stripe LV for cache volume.
-rw-r--r--WHATS_NEW1
-rw-r--r--lib/metadata/lv_manip.c364
-rw-r--r--lib/metadata/metadata-exported.h3
-rw-r--r--liblvm/lvm_lv.c1
-rw-r--r--tools/lvcreate.c1061
5 files changed, 799 insertions, 631 deletions
diff --git a/WHATS_NEW b/WHATS_NEW
index fa88ddc2d..320bca307 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.112 -
=====================================
+ Refactor lvcreate towards more complete validation of all supported options.
Support lvcreate --type linear.
Improve _should_wipe_lv() to warn with message.
Inform about temporarily created volumes only in verbose mode.
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 277a51d43..f2cf40403 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -6604,6 +6604,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
struct cmd_context *cmd = vg->cmd;
uint32_t size_rest;
uint64_t status = lp->permission | VISIBLE_LV;
+ const struct segment_type *create_segtype = lp->segtype;
struct logical_volume *lv, *origin_lv = NULL;
struct logical_volume *pool_lv;
struct logical_volume *tmp_lv;
@@ -6672,7 +6673,58 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
lp->extents = lp->extents - size_rest + lp->stripes;
}
- if (seg_is_cache(lp)) {
+ if (!lp->extents && !seg_is_thin_volume(lp)) {
+ log_error(INTERNAL_ERROR "Unable to create new logical volume with no extents.");
+ return_NULL;
+ }
+
+ if (seg_is_pool(lp) &&
+ ((uint64_t)lp->extents * vg->extent_size < lp->chunk_size)) {
+ log_error("Unable to create %s smaller than 1 chunk.",
+ lp->segtype->name);
+ return NULL;
+ }
+
+ if (!seg_is_virtual(lp) && !lp->approx_alloc &&
+ (vg->free_count < lp->extents)) {
+ log_error("Volume group \"%s\" has insufficient free space "
+ "(%u extents): %u required.",
+ vg->name, vg->free_count, lp->extents);
+ return NULL;
+ }
+
+ if ((lp->alloc != ALLOC_ANYWHERE) && (lp->stripes > dm_list_size(lp->pvh))) {
+ log_error("Number of stripes (%u) must not exceed "
+ "number of physical volumes (%d)", lp->stripes,
+ dm_list_size(lp->pvh));
+ return NULL;
+ }
+
+ if (seg_is_pool(lp))
+ status |= LVM_WRITE; /* Pool is always writable */
+
+ if (seg_is_cache_pool(lp) && lp->origin_name) {
+ /* Converting exiting origin and creating cache pool */
+ if (!(origin_lv = find_lv(vg, lp->origin_name))) {
+ log_error("Cache origin volume %s not found in Volume group %s.",
+ lp->origin_name, vg->name);
+ return NULL;
+ }
+
+ if (!validate_lv_cache_create(NULL, origin_lv))
+ return_NULL;
+
+ /* Validate cache origin is exclusively active */
+ if (vg_is_clustered(origin_lv->vg) &&
+ locking_is_clustered() &&
+ locking_supports_remote_queries() &&
+ lv_is_active(origin_lv) &&
+ !lv_is_active_exclusive(origin_lv)) {
+ log_error("Cannot cache not exclusively active origin volume %s.",
+ display_lvname(origin_lv));
+ return NULL;
+ }
+ } else if (seg_is_cache(lp)) {
if (!lp->pool_name) {
log_error(INTERNAL_ERROR "Cannot create thin volume without thin pool.");
return NULL;
@@ -6683,47 +6735,83 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
return NULL;
}
- if (lv_is_locked(pool_lv)) {
- log_error("Caching locked devices is not supported.");
+ if (!lv_is_cache_pool(pool_lv)) {
+ log_error("Logical volume %s is not a cache pool.",
+ display_lvname(pool_lv));
return NULL;
}
- if (!lp->extents) {
- log_error("No size given for new cache origin LV.");
+ if (lv_is_locked(pool_lv)) {
+ log_error("Cannot use locked cache pool %s.",
+ display_lvname(pool_lv));
return NULL;
}
- if (!(lp->segtype = get_segtype_from_string(vg->cmd, "striped")))
+ /* Create cache origin for cache pool */
+ /* TODO: eventually support raid/mirrors with -m */
+ if (!(create_segtype = get_segtype_from_string(vg->cmd, "striped")))
return_0;
- } else if (seg_is_thin(lp) && lp->snapshot) {
- if (!lp->origin_name) {
- log_error(INTERNAL_ERROR "Origin LV is not defined.");
- return 0;
+ } else if (seg_is_mirrored(lp) || seg_is_raid(lp)) {
+ /* FIXME: this will not pass cluster lock! */
+ init_mirror_in_sync(lp->nosync);
+
+ if (lp->nosync) {
+ log_warn("WARNING: New %s won't be synchronised. "
+ "Don't read what you didn't write!",
+ lp->segtype->name);
+ status |= LV_NOTSYNCED;
}
- if (!(origin_lv = find_lv(vg, lp->origin_name))) {
- log_error("Couldn't find origin volume '%s'.",
- lp->origin_name);
+
+ lp->region_size = adjusted_mirror_region_size(vg->extent_size,
+ lp->extents,
+ lp->region_size, 0);
+ } else if (seg_is_thin_volume(lp)) {
+ if (!lp->pool_name) {
+ log_error(INTERNAL_ERROR "Cannot create thin volume without thin pool.");
return NULL;
}
- if (lv_is_locked(origin_lv)) {
- log_error("Snapshots of locked devices are not supported.");
+ if (!(pool_lv = find_lv(vg, lp->pool_name))) {
+ log_error("Unable to find existing pool LV %s in VG %s.",
+ lp->pool_name, vg->name);
return NULL;
}
- lp->voriginextents = origin_lv->le_count;
- } else if (lp->snapshot) {
- if (!activation()) {
- log_error("Can't create snapshot without using "
- "device-mapper kernel driver");
+ if (!lv_is_thin_pool(pool_lv)) {
+ log_error("Logical volume %s is not a thin pool.",
+ display_lvname(pool_lv));
return NULL;
}
- /* Must zero cow */
- status |= LVM_WRITE;
+ if (lv_is_locked(pool_lv)) {
+ log_error("Cannot use locked thin pool %s.",
+ display_lvname(pool_lv));
+ return NULL;
+ }
- if (!lp->voriginsize) {
+ thin_name = lp->pool_name;
+ if (lp->origin_name) {
+ if (!(origin_lv = find_lv(vg, lp->origin_name))) {
+ log_error("Couldn't find origin volume '%s'.",
+ lp->origin_name);
+ return NULL;
+ }
+
+ if (lv_is_locked(origin_lv)) {
+ log_error("Snapshots of locked devices are not supported.");
+ return NULL;
+ }
+
+ /* For thin snapshot we must have matching pool */
+ if (lv_is_thin_volume(origin_lv) &&
+ (strcmp(first_seg(origin_lv)->pool_lv->name, lp->pool_name) == 0))
+ thin_name = origin_lv->name;
+
+ lp->voriginextents = origin_lv->le_count;
+ }
+ } else if (lp->snapshot) {
+ if (!lp->voriginsize) {
if (!(origin_lv = find_lv(vg, lp->origin_name))) {
log_error("Couldn't find origin volume '%s'.",
lp->origin_name);
@@ -6771,86 +6859,28 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
return NULL;
}
}
- }
-
- if (!seg_is_thin_volume(lp) && !lp->extents) {
- log_error("Unable to create new logical volume with no extents");
- return NULL;
- }
-
- if (seg_is_pool(lp)) {
- if (((uint64_t)lp->extents * vg->extent_size < lp->chunk_size)) {
- log_error("Unable to create %s smaller than 1 chunk.",
- lp->segtype->name);
- return NULL;
- }
- }
- if (lp->snapshot && !seg_is_thin(lp) &&
- !cow_has_min_chunks(vg, lp->extents, lp->chunk_size))
- return NULL;
+ if (!cow_has_min_chunks(vg, lp->extents, lp->chunk_size))
+ return_NULL;
- if (!seg_is_virtual(lp) &&
- vg->free_count < lp->extents && !lp->approx_alloc) {
- log_error("Volume group \"%s\" has insufficient free space "
- "(%u extents): %u required.",
- vg->name, vg->free_count, lp->extents);
- return NULL;
- }
+ /* The snapshot segment gets created later */
+ if (!(create_segtype = get_segtype_from_string(cmd, "striped")))
+ return_NULL;
- if (lp->stripes > dm_list_size(lp->pvh) && lp->alloc != ALLOC_ANYWHERE) {
- log_error("Number of stripes (%u) must not exceed "
- "number of physical volumes (%d)", lp->stripes,
- dm_list_size(lp->pvh));
- return NULL;
+ /* Must zero cow */
+ status |= LVM_WRITE;
+ lp->zero = 1;
+ lp->wipe_signatures = 0;
}
- /* The snapshot segment gets created later */
- if (lp->snapshot && !seg_is_thin(lp) &&
- !(lp->segtype = get_segtype_from_string(cmd, "striped")))
- return_NULL;
-
if (!archive(vg))
return_NULL;
if (seg_is_thin_volume(lp)) {
/* Ensure all stacked messages are submitted */
- if (!lp->pool_name) {
- log_error(INTERNAL_ERROR "Undefined pool for thin volume segment.");
- return NULL;
- }
-
- if (!(pool_lv = find_lv(vg, lp->pool_name))) {
- log_error("Unable to find existing pool LV %s in VG %s.",
- lp->pool_name, vg->name);
- return NULL;
- }
-
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 */
- if (origin_lv && lv_is_thin_volume(origin_lv) && (!lp->pool_name ||
- (strcmp(first_seg(origin_lv)->pool_lv->name, lp->pool_name) == 0)))
- thin_name = origin_lv->name;
- else
- thin_name = lp->pool_name;
- }
-
- if (segtype_is_mirrored(lp->segtype) || segtype_is_raid(lp->segtype)) {
- init_mirror_in_sync(lp->nosync);
-
- if (lp->nosync) {
- log_warn("WARNING: New %s won't be synchronised. "
- "Don't read what you didn't write!",
- lp->segtype->name);
- status |= LV_NOTSYNCED;
- }
-
- lp->region_size = adjusted_mirror_region_size(vg->extent_size,
- lp->extents,
- lp->region_size, 0);
}
if (!(lv = lv_create_empty(new_lv_name ? : "lvol%d", NULL,
@@ -6862,7 +6892,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
log_debug_metadata("Setting read ahead sectors %u.", lv->read_ahead);
}
- if (!seg_is_thin_pool(lp) && lp->minor >= 0) {
+ if (!seg_is_pool(lp) && lp->minor >= 0) {
lv->major = lp->major;
lv->minor = lp->minor;
lv->status |= FIXED_MINOR;
@@ -6872,7 +6902,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
dm_list_splice(&lv->tags, &lp->tags);
- if (!lv_extend(lv, lp->segtype,
+ if (!lv_extend(lv, create_segtype,
lp->stripes, lp->stripe_size,
lp->mirrors,
seg_is_pool(lp) ? lp->pool_metadata_extents : lp->region_size,
@@ -6915,7 +6945,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
* Check if using 'external origin' or the 'normal' snapshot
* within the same thin pool
*/
- if (lp->snapshot && (first_seg(origin_lv)->pool_lv != pool_lv)) {
+ if (origin_lv && (first_seg(origin_lv)->pool_lv != pool_lv)) {
if (!pool_supports_external_origin(first_seg(pool_lv), origin_lv))
return_0;
if (origin_lv->status & LVM_WRITE) {
@@ -6960,56 +6990,6 @@ 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_name || (lp->pool_name && !lv_is_cache_pool(lv)))) {
- if (lp->origin_name) {
- if (!(origin_lv = find_lv(vg, lp->origin_name)))
- goto deactivate_and_revert_new_lv;
- pool_lv = lv; /* Cache pool is created */
- } else if (lp->pool_name) {
- if (!(pool_lv = find_lv(vg, lp->pool_name)))
- goto deactivate_and_revert_new_lv;
- origin_lv = lv; /* Cached origin is created */
- }
-
- if (!(tmp_lv = lv_cache_create(pool_lv, origin_lv)))
- 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_name && 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)) {
if (seg_is_pool(lp)) {
@@ -7027,11 +7007,6 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
goto out;
}
- if (lv_is_cache_pool(lv)) {
- log_verbose("Cache pool is prepared.");
- goto out;
- }
-
/* Do not scan this LV until properly zeroed/wiped. */
if (_should_wipe_lv(lp, lv, 0))
lv->status |= LV_NOSCAN;
@@ -7039,7 +7014,18 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
if (lp->temporary)
lv->status |= LV_TEMPORARY;
- if (lv_is_thin_volume(lv)) {
+ if (seg_is_cache(lp)) {
+ /* TODO: support remote exclusive activation? */
+ if (is_change_activating(lp->activate) &&
+ !activate_lv_excl_local(cmd, lv)) {
+ log_error("Aborting. Failed to activate LV %s locally exclusively.",
+ display_lvname(lv));
+ goto revert_new_lv;
+ }
+ } else if (lv_is_cache_pool(lv)) {
+ /* Cache pool cannot be actived and zeroed */
+ log_very_verbose("Cache pool is prepared.");
+ } else if (lv_is_thin_volume(lv)) {
/* For snapshot, suspend active thin origin first */
if (origin_lv && lv_is_active(origin_lv) && lv_is_thin_volume(origin_lv)) {
if (!suspend_lv_origin(cmd, origin_lv)) {
@@ -7083,11 +7069,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
}
} else if (!lv_active_change(cmd, lv, lp->activate)) {
log_error("Failed to activate new LV.");
- if (lp->zero || lp->wipe_signatures ||
- lv_is_thin_pool(lv) ||
- lv_is_cache_type(lv))
- goto deactivate_and_revert_new_lv;
- return NULL;
+ goto deactivate_and_revert_new_lv;
}
if (_should_wipe_lv(lp, lv, 1)) {
@@ -7104,7 +7086,30 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
}
}
- if (lp->snapshot && !seg_is_thin(lp)) {
+ if (seg_is_cache(lp) || (origin_lv && lv_is_cache_pool(lv))) {
+ /* Finish cache conversion magic */
+ if (origin_lv) {
+ /* Convert origin to cached LV */
+ if (!(tmp_lv = lv_cache_create(lv, origin_lv))) {
+ /* TODO: do a better revert */
+ log_error("Aborting. Leaving cache pool %s and uncached origin volume %s.",
+ display_lvname(lv), display_lvname(origin_lv));
+ return NULL;
+ }
+ } else {
+ if (!(tmp_lv = lv_cache_create(pool_lv, lv))) {
+ /* 'lv' still keeps created new LV */
+ stack;
+ goto deactivate_and_revert_new_lv;
+ }
+ }
+ lv = tmp_lv;
+ if (!lv_update_and_reload(lv)) {
+ /* TODO: do a better revert */
+ log_error("Aborting. Manual intervention required.");
+ return NULL; /* FIXME: revert */
+ }
+ } else if (lp->snapshot) {
/* Reset permission after zeroing */
if (!(lp->permission & LVM_WRITE))
lv->status &= ~LVM_WRITE;
@@ -7177,35 +7182,26 @@ revert_new_lv:
struct logical_volume *lv_create_single(struct volume_group *vg,
struct lvcreate_params *lp)
{
+ const struct segment_type *segtype;
struct logical_volume *lv;
/* 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 (lp->pool_name && !apply_lvname_restrictions(lp->pool_name))
+ if (lp->create_pool && !seg_is_pool(lp)) {
+ segtype = lp->segtype;
+ if (seg_is_thin_volume(lp)) {
+ if (!(lp->segtype = get_segtype_from_string(vg->cmd, "thin-pool")))
return_NULL;
if (!(lv = _lv_create_an_lv(vg, lp, lp->pool_name)))
return_NULL;
-
- if (!lp->thin && !lp->snapshot)
- goto out;
-
- lp->pool_name = lv->name;
-
- 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 (lp->pool_name && !apply_lvname_restrictions(lp->pool_name))
+ } else if (seg_is_cache(lp)) {
+ if (!lp->origin_name) {
+ /* Until we have --pooldatasize we are lost */
+ log_error(INTERNAL_ERROR "Unsupported creation of cache and cache pool volume.");
+ return NULL;
+ }
+ /* origin_name is defined -> creates cache LV with new cache pool */
+ if (!(lp->segtype = get_segtype_from_string(vg->cmd, "cache-pool")))
return_NULL;
if (!(lv = _lv_create_an_lv(vg, lp, lp->pool_name)))
@@ -7218,19 +7214,21 @@ struct logical_volume *lv_create_single(struct volume_group *vg,
return lv;
}
- if (!lp->cache)
- goto out;
-
- lp->pool_name = lv->name;
- log_error("Creation of cache pool and cached volume in one command is not yet supported.");
+ log_error(INTERNAL_ERROR "Logical volume is not cache %s.",
+ display_lvname(lv));
+ return NULL;
+ } else {
+ log_error(INTERNAL_ERROR "Creation of pool for unsupported segment type %s.",
+ lp->segtype->name);
return NULL;
}
+ lp->pool_name = lv->name;
+ lp->segtype = segtype;
}
if (!(lv = _lv_create_an_lv(vg, lp, lp->lv_name)))
return_NULL;
-out:
if (lp->temporary)
log_verbose("Temporary logical volume \"%s\" created.", lv->name);
else
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 3d656b70d..1100849a3 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -798,9 +798,7 @@ static inline int is_change_activating(activation_change_t change)
/* FIXME: refactor and reduce the size of this struct! */
struct lvcreate_params {
/* flags */
- int cache;
int snapshot; /* snap */
- int thin; /* thin */
int create_pool; /* pools */
int zero; /* all */
int wipe_signatures; /* all */
@@ -809,6 +807,7 @@ struct lvcreate_params {
int log_count; /* mirror */
int nosync; /* mirror */
int pool_metadata_spare; /* pools */
+ int type; /* type arg is given */
int temporary; /* temporary LV */
#define ACTIVATION_SKIP_SET 0x01 /* request to set LV activation skip flag state */
#define ACTIVATION_SKIP_SET_ENABLED 0x02 /* set the LV activation skip flag state to 'enabled' */
diff --git a/liblvm/lvm_lv.c b/liblvm/lvm_lv.c
index 76a31649d..f7f1596a8 100644
--- a/liblvm/lvm_lv.c
+++ b/liblvm/lvm_lv.c
@@ -611,7 +611,6 @@ static int _lv_set_thin_params(struct lvcreate_params *lp,
{
_lv_set_default_params(lp, vg, lvname, extents);
- lp->thin = 1;
lp->pool_name = pool_name;
lp->segtype = get_segtype_from_string(vg->cmd, "thin");
diff --git a/tools/lvcreate.c b/tools/lvcreate.c
index b6907f577..a789fb2d0 100644
--- a/tools/lvcreate.c
+++ b/tools/lvcreate.c
@@ -42,9 +42,9 @@ static int _set_vg_name(struct lvcreate_params *lp, const char *vg_name)
return 1;
}
-static int _lvcreate_name_params(struct lvcreate_params *lp,
- struct cmd_context *cmd,
- int *pargc, char ***pargv)
+static int _lvcreate_name_params(struct cmd_context *cmd,
+ int *pargc, char ***pargv,
+ struct lvcreate_params *lp)
{
int argc = *pargc;
char **argv = *pargv;
@@ -125,8 +125,6 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
"in one command is not yet supported.");
return 0;
}
-
- lp->cache = 1;
} else if (lp->snapshot && !arg_count(cmd, virtualsize_ARG)) {
/* argv[0] might be [vg/]origin */
if (!argc) {
@@ -379,167 +377,89 @@ static int _update_extents_params(struct volume_group *vg,
* Note: at this place all volume types needs to be already
* identified, do not change them here.
*/
-static int _read_size_params(struct lvcreate_params *lp,
- struct lvcreate_cmdline_params *lcp,
- struct cmd_context *cmd)
+static int _read_size_params(struct cmd_context *cmd,
+ struct lvcreate_params *lp,
+ struct lvcreate_cmdline_params *lcp)
{
- if (arg_count(cmd, extents_ARG) && arg_count(cmd, size_ARG)) {
- log_error("Please specify either size or extents (not both)");
- return 0;
- }
+ if (arg_from_list_is_negative(cmd, "may not be negative",
+ chunksize_ARG, extents_ARG,
+ mirrors_ARG,
+ maxrecoveryrate_ARG,
+ minrecoveryrate_ARG,
+ regionsize_ARG,
+ size_ARG,
+ stripes_ARG, stripesize_ARG,
+ virtualsize_ARG,
+ -1))
+ return_0;
- if (!lp->thin && !lp->snapshot && !arg_count(cmd, extents_ARG) && !arg_count(cmd, size_ARG)) {
- log_error("Please specify either size or extents");
- return 0;
- }
+ if (arg_from_list_is_zero(cmd, "may not be zero",
+ chunksize_ARG, extents_ARG,
+ regionsize_ARG,
+ size_ARG,
+ stripes_ARG, stripesize_ARG,
+ virtualsize_ARG,
+ -1))
+ return_0;
- /* poolmetadatasize_ARG is parsed in get_pool_params() */
- if (!lp->create_pool && arg_count(cmd, poolmetadatasize_ARG)) {
- log_error("--poolmetadatasize may only be specified when creating pools.");
- return 0;
- }
+ lp->voriginsize = arg_uint64_value(cmd, virtualsize_ARG, UINT64_C(0));
if (arg_count(cmd, extents_ARG)) {
- if (arg_sign_value(cmd, extents_ARG, SIGN_NONE) == SIGN_MINUS) {
- log_error("Negative number of extents is invalid.");
- return 0;
- }
- if (!(lp->extents = arg_uint_value(cmd, extents_ARG, 0))) {
- log_error("Number of extents may not be zero.");
+ if (arg_count(cmd, size_ARG)) {
+ log_error("Please specify either size or extents (not both).");
return 0;
}
+ lp->extents = arg_uint_value(cmd, extents_ARG, 0);
lcp->percent = arg_percent_value(cmd, extents_ARG, PERCENT_NONE);
- }
-
- /* Size returned in kilobyte units; held in sectors */
- if (arg_count(cmd, size_ARG)) {
- if (arg_sign_value(cmd, size_ARG, SIGN_NONE) == SIGN_MINUS) {
- log_error("Negative size is invalid.");
- return 0;
- }
- if (!(lcp->size = arg_uint64_value(cmd, size_ARG, UINT64_C(0)))) {
- log_error("Size may not be zero.");
- return 0;
- }
+ } else if (arg_count(cmd, size_ARG)) {
+ lcp->size = arg_uint64_value(cmd, size_ARG, UINT64_C(0));
lcp->percent = PERCENT_NONE;
- }
-
- if (arg_count(cmd, virtualsize_ARG)) {
- if (!lp->thin && !lp->snapshot) {
- log_error("--virtualsize may only be specified when creating thins or virtual snapshots.");
- return 0;
- }
- if (arg_sign_value(cmd, virtualsize_ARG, SIGN_NONE) == SIGN_MINUS) {
- log_error("Negative virtual origin size is invalid.");
- return 0;
- }
- /* Size returned in kilobyte units; held in sectors */
- if (!(lp->voriginsize = arg_uint64_value(cmd, virtualsize_ARG,
- UINT64_C(0)))) {
- log_error("Virtual origin size may not be zero.");
- return 0;
- }
+ } else if (!lp->snapshot && !seg_is_thin_volume(lp)) {
+ log_error("Please specify either size or extents.");
+ return 0;
}
return 1;
}
/*
- * Generic mirror parameter checks.
- * FIXME: Should eventually be moved into lvm library.
+ * Read parameters related to mirrors
*/
-static int _validate_mirror_params(const struct cmd_context *cmd __attribute__((unused)),
- const struct lvcreate_params *lp)
+static int _read_mirror_params(struct cmd_context *cmd,
+ struct lvcreate_params *lp)
{
- int pagesize = lvm_getpagesize();
-
- if (lp->region_size & (lp->region_size - 1)) {
- log_error("Region size (%" PRIu32 ") must be a power of 2",
- lp->region_size);
- return 0;
- }
-
- if (lp->region_size % (pagesize >> SECTOR_SHIFT)) {
- log_error("Region size (%" PRIu32 ") must be a multiple of "
- "machine memory page size (%d)",
- lp->region_size, pagesize >> SECTOR_SHIFT);
- return 0;
- }
-
- if (!lp->region_size) {
- log_error("Non-zero region size must be supplied.");
- return 0;
- }
-
- return 1;
-}
-
-static int _read_mirror_params(struct lvcreate_params *lp,
- struct cmd_context *cmd)
-{
- int region_size;
- const char *mirrorlog;
int corelog = arg_count(cmd, corelog_ARG);
+ const char *mirrorlog = arg_str_value(cmd, mirrorlog_ARG, corelog
+ ? "core" : DEFAULT_MIRRORLOG);
- mirrorlog = arg_str_value(cmd, mirrorlog_ARG,
- corelog ? "core" : DEFAULT_MIRRORLOG);
-
- if (strcmp("core", mirrorlog) && corelog) {
- log_error("Please use only one of --mirrorlog or --corelog");
- return 0;
- }
-
- if (!strcmp("mirrored", mirrorlog)) {
+ if (!strcmp("mirrored", mirrorlog))
lp->log_count = 2;
- } else if (!strcmp("disk", mirrorlog)) {
+ else if (!strcmp("disk", mirrorlog))
lp->log_count = 1;
- } else if (!strcmp("core", mirrorlog))
+ else if (!strcmp("core", mirrorlog)) {
lp->log_count = 0;
- else {
+ } else {
log_error("Unknown mirrorlog type: %s", mirrorlog);
return 0;
}
- log_verbose("Setting logging type to %s", mirrorlog);
-
- lp->nosync = arg_is_set(cmd, nosync_ARG);
-
- if (arg_count(cmd, regionsize_ARG)) {
- if (arg_sign_value(cmd, regionsize_ARG, SIGN_NONE) == SIGN_MINUS) {
- log_error("Negative regionsize is invalid");
- return 0;
- }
- lp->region_size = arg_uint_value(cmd, regionsize_ARG, 0);
- } else {
- region_size = get_default_region_size(cmd);
- if (region_size < 0) {
- log_error("Negative regionsize in configuration file "
- "is invalid");
- return 0;
- }
- lp->region_size = region_size;
+ if (corelog && (lp->log_count != 0)) {
+ log_error("Please use only one of --corelog or --mirrorlog.");
+ return 0;
}
- if (!_validate_mirror_params(cmd, lp))
- return 0;
+ log_verbose("Setting logging type to %s", mirrorlog);
return 1;
}
-static int _read_raid_params(struct lvcreate_params *lp,
- struct cmd_context *cmd)
+/*
+ * Read parameters related to raids
+ */
+static int _read_raid_params(struct cmd_context *cmd,
+ struct lvcreate_params *lp)
{
- if (!segtype_is_raid(lp->segtype))
- return 1;
-
- if (arg_count(cmd, corelog_ARG) ||
- arg_count(cmd, mirrorlog_ARG)) {
- log_error("Log options not applicable to %s segtype",
- lp->segtype->name);
- return 0;
- }
-
- if (!strcmp(lp->segtype->name, SEG_TYPE_NAME_RAID10) && (lp->stripes < 2)) {
+ if ((lp->stripes < 2) && !strcmp(lp->segtype->name, SEG_TYPE_NAME_RAID10)) {
if (arg_count(cmd, stripes_ARG)) {
/* User supplied the bad argument */
log_error("Segment type 'raid10' requires 2 or more stripes.");
@@ -551,16 +471,6 @@ static int _read_raid_params(struct lvcreate_params *lp,
}
/*
- * RAID types without a mirror component do not take '-m' arg
- */
- if (!segtype_is_mirrored(lp->segtype) &&
- arg_count(cmd, mirrors_ARG)) {
- log_error("Mirror argument cannot be used with segment type, %s",
- lp->segtype->name);
- return 0;
- }
-
- /*
* RAID1 does not take a stripe arg
*/
if ((lp->stripes > 1) && seg_is_mirrored(lp) &&
@@ -570,41 +480,90 @@ static int _read_raid_params(struct lvcreate_params *lp,
return 0;
}
- /*
- * _read_mirror_params is called before _read_raid_params
- * and already sets:
- * lp->nosync
- * lp->region_size
- *
- * But let's ensure that programmers don't reorder
- * that by checking and warning if they aren't set.
- */
- if (!lp->region_size) {
- log_error(INTERNAL_ERROR "region_size not set.");
+ /* Rates are recorded in kiB/sec/disk, not sectors/sec/disk */
+ lp->min_recovery_rate = arg_uint_value(cmd, minrecoveryrate_ARG, 0) / 2;
+ lp->max_recovery_rate = arg_uint_value(cmd, maxrecoveryrate_ARG, 0) / 2;
+
+ if (lp->min_recovery_rate > lp->max_recovery_rate) {
+ log_error("Minimum recovery rate cannot be higher than maximum.");
return 0;
}
- if (arg_count(cmd, minrecoveryrate_ARG))
- lp->min_recovery_rate = arg_uint_value(cmd,
- minrecoveryrate_ARG, 0);
- if (arg_count(cmd, maxrecoveryrate_ARG))
- lp->max_recovery_rate = arg_uint_value(cmd,
- maxrecoveryrate_ARG, 0);
+ return 1;
+}
- /* Rates are recorded in kiB/sec/disk, not sectors/sec/disk */
- lp->min_recovery_rate /= 2;
- lp->max_recovery_rate /= 2;
+/*
+ * Read parameters related to mirrors and raids
+ */
+static int _read_mirror_and_raid_params(struct cmd_context *cmd,
+ struct lvcreate_params *lp)
+{
+ int pagesize = lvm_getpagesize();
- if (lp->max_recovery_rate &&
- (lp->max_recovery_rate < lp->min_recovery_rate)) {
- log_error("Minimum recovery rate cannot be higher than maximum.");
+ /* Common mirror and raid params */
+ if (arg_count(cmd, mirrors_ARG)) {
+ lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1;
+
+ if (lp->mirrors > DEFAULT_MIRROR_MAX_IMAGES) {
+ log_error("Only up to " DM_TO_STRING(DEFAULT_MIRROR_MAX_IMAGES)
+ " images in mirror supported currently.");
+ return 0;
+ }
+
+ if ((lp->mirrors > 2) && !strcmp(lp->segtype->name, SEG_TYPE_NAME_RAID10)) {
+ /*
+ * FIXME: When RAID10 is no longer limited to
+ * 2-way mirror, 'lv_mirror_count()'
+ * must also change for RAID10.
+ */
+ log_error("RAID10 currently supports "
+ "only 2-way mirroring (i.e. '-m 1')");
+ return 0;
+ }
+
+ if (lp->mirrors == 1) {
+ if (seg_is_mirrored(lp)) {
+ log_error("--mirrors must be at least 1 with segment type %s.", lp->segtype->name);
+ return 0;
+ }
+ log_print_unless_silent("Redundant mirrors argument: default is 0");
+ }
+ } else
+ /* Default to 2 mirrored areas if '--type mirror|raid1|raid10' */
+ lp->mirrors = seg_is_mirrored(lp) ? 2 : 1;
+
+ lp->nosync = arg_is_set(cmd, nosync_ARG);
+
+ if (!(lp->region_size = arg_uint_value(cmd, regionsize_ARG, 0)) &&
+ ((lp->region_size = get_default_region_size(cmd)) <= 0)) {
+ log_error("regionsize in configuration file is invalid.");
+ return 0;
+ }
+
+ if (lp->region_size & (lp->region_size - 1)) {
+ log_error("Region size (%" PRIu32 ") must be a power of 2",
+ lp->region_size);
return 0;
}
+
+ if (lp->region_size % (pagesize >> SECTOR_SHIFT)) {
+ log_error("Region size (%" PRIu32 ") must be a multiple of "
+ "machine memory page size (%d)",
+ lp->region_size, pagesize >> SECTOR_SHIFT);
+ return 0;
+ }
+
+ if (seg_is_mirror(lp) && !_read_mirror_params(cmd, lp))
+ return_0;
+
+ if (seg_is_raid(lp) && !_read_raid_params(cmd, lp))
+ return_0;
+
return 1;
}
-static int _read_cache_pool_params(struct lvcreate_params *lp,
- struct cmd_context *cmd)
+static int _read_cache_params(struct cmd_context *cmd,
+ struct lvcreate_params *lp)
{
const char *cachemode;
@@ -620,9 +579,9 @@ static int _read_cache_pool_params(struct lvcreate_params *lp,
return 1;
}
-static int _read_activation_params(struct lvcreate_params *lp,
- struct cmd_context *cmd,
- struct volume_group *vg)
+static int _read_activation_params(struct cmd_context *cmd,
+ struct volume_group *vg,
+ struct lvcreate_params *lp)
{
unsigned pagesize;
@@ -658,14 +617,7 @@ static int _read_activation_params(struct lvcreate_params *lp,
}
/* Permissions */
- lp->permission = arg_uint_value(cmd, permission_ARG,
- LVM_READ | LVM_WRITE);
-
- if (lp->snapshot) {
- /* Snapshot has to zero COW header */
- lp->zero = 1;
- lp->wipe_signatures = 0;
- } else if (!(lp->permission & LVM_WRITE)) {
+ if (!(lp->permission & LVM_WRITE)) {
/* Must not zero/wipe read only volume */
lp->zero = 0;
lp->wipe_signatures = 0;
@@ -673,7 +625,7 @@ static int _read_activation_params(struct lvcreate_params *lp,
/* Persistent minor (and major) */
if (arg_is_set(cmd, persistent_ARG)) {
- if (lp->create_pool && !lp->thin) {
+ if (lp->create_pool && !seg_is_thin_volume(lp)) {
log_error("--persistent is not permitted when creating a thin pool device.");
return 0;
}
@@ -705,52 +657,58 @@ static int _read_activation_params(struct lvcreate_params *lp,
return 1;
}
-static int _lvcreate_params(struct lvcreate_params *lp,
- struct lvcreate_cmdline_params *lcp,
- struct cmd_context *cmd,
- int argc, char **argv)
+static int _lvcreate_params(struct cmd_context *cmd,
+ int argc, char **argv,
+ struct lvcreate_params *lp,
+ struct lvcreate_cmdline_params *lcp)
{
int contiguous;
struct arg_value_group_list *current_group;
const char *segtype_str;
const char *tag;
int only_linear = 0;
+ int mirror_default_cfg;
memset(lcp, 0, sizeof(*lcp));
dm_list_init(&lp->tags);
lp->target_attr = ~0;
lp->yes = arg_count(cmd, yes_ARG);
lp->force = (force_t) arg_count(cmd, force_ARG);
+ lp->permission = arg_uint_value(cmd, permission_ARG,
+ LVM_READ | LVM_WRITE);
- /* Set default segtype - remember, '-m 0' implies stripe. */
- if (arg_count(cmd, mirrors_ARG) &&
- arg_uint_value(cmd, mirrors_ARG, 0))
- if (arg_uint_value(cmd, arg_count(cmd, stripes_long_ARG) ?
- stripes_long_ARG : stripes_ARG, 1) > 1) {
- segtype_str = find_config_tree_str(cmd, global_raid10_segtype_default_CFG, NULL);;
- } else {
- segtype_str = find_config_tree_str(cmd, global_mirror_segtype_default_CFG, NULL);
+ /*
+ * --type is the top most rule
+ *
+ * Ordering of following type tests is IMPORTANT
+ */
+ if ((segtype_str = arg_str_value(cmd, type_ARG, NULL))) {
+ lp->type = 1;
+ if (!strcmp(segtype_str, "linear")) {
+ segtype_str = "striped";
+ only_linear = 1; /* User requested linear only target */
}
- else if (arg_count(cmd, snapshot_ARG))
- segtype_str = "snapshot";
- else if (arg_count(cmd, cache_ARG))
- segtype_str = "cache";
- else if (arg_count(cmd, thin_ARG))
- segtype_str = "thin";
- /* estimations after valid shortcuts */
- else if (arg_count(cmd, cachepool_ARG))
+ if (arg_from_list_is_set(cmd, "is conflicting with option --type",
+ cache_ARG, thin_ARG, snapshot_ARG,
+ -1))
+ return_0;
+ /* More estimations from options after shortcuts */
+ } else if (arg_is_set(cmd, snapshot_ARG))
+ /* Snapshot has higher priority then thin */
+ segtype_str = "snapshot"; /* --thinpool makes thin volume */
+ else if (arg_is_set(cmd, cache_ARG) || arg_count(cmd, cachepool_ARG))
segtype_str = "cache";
- else if (arg_count(cmd, thinpool_ARG))
+ else if (arg_count(cmd, thin_ARG) || arg_count(cmd, thinpool_ARG) ||
+ arg_is_set(cmd, virtualsize_ARG))
segtype_str = "thin";
- else
+ else if (arg_uint_value(cmd, mirrors_ARG, 0)) {
+ /* Remember, '-m 0' implies stripe */
+ mirror_default_cfg = (arg_uint_value(cmd, stripes_ARG, 1) > 1)
+ ? global_raid10_segtype_default_CFG : global_mirror_segtype_default_CFG;
+ segtype_str = find_config_tree_str(cmd, mirror_default_cfg, NULL);
+ } else
segtype_str = "striped";
- segtype_str = arg_str_value(cmd, type_ARG, segtype_str);
- if (!strcmp(segtype_str, "linear")) {
- segtype_str = "striped";
- only_linear = 1; /* User requested linear only target */
- }
-
if (!(lp->segtype = get_segtype_from_string(cmd, segtype_str)))
return_0;
@@ -759,108 +717,269 @@ static int _lvcreate_params(struct lvcreate_params *lp,
return 0;
}
- if (seg_is_snapshot(lp) ||
- (!seg_is_thin(lp) && arg_count(cmd, virtualsize_ARG))) {
- if (arg_from_list_is_set(cmd, "is unsupported with snapshots",
- cache_ARG, cachepool_ARG,
- mirrors_ARG,
- thin_ARG,
- zero_ARG,
- -1))
+ /* Starts basic option validation for every segment type */
+
+ /* TODO: Use these ARGS macros also in commands.h ? */
+ /* ARGS are disjoint! sets of options */
+#define LVCREATE_ARGS \
+ activate_ARG,\
+ addtag_ARG,\
+ alloc_ARG,\
+ autobackup_ARG,\
+ available_ARG,\
+ contiguous_ARG,\
+ ignoreactivationskip_ARG,\
+ ignoremonitoring_ARG,\
+ name_ARG,\
+ noudevsync_ARG,\
+ permission_ARG,\
+ setactivationskip_ARG,\
+ test_ARG,\
+ type_ARG
+
+#define CACHE_POOL_ARGS \
+ cachemode_ARG,\
+ cachepool_ARG
+
+#define MIRROR_ARGS \
+ corelog_ARG,\
+ mirrorlog_ARG
+
+#define MIRROR_RAID_ARGS \
+ mirrors_ARG,\
+ nosync_ARG,\
+ regionsize_ARG
+
+#define PERSISTENT_ARGS \
+ major_ARG,\
+ minor_ARG,\
+ persistent_ARG
+
+#define POOL_ARGS \
+ pooldatasize_ARG,\
+ poolmetadatasize_ARG,\
+ poolmetadataspare_ARG
+
+#define RAID_ARGS \
+ maxrecoveryrate_ARG,\
+ minrecoveryrate_ARG,\
+ raidmaxrecoveryrate_ARG,\
+ raidminrecoveryrate_ARG
+
+#define SIZE_ARGS \
+ extents_ARG,\
+ size_ARG,\
+ stripes_ARG,\
+ stripesize_ARG
+
+#define THIN_POOL_ARGS \
+ discards_ARG,\
+ thinpool_ARG
+
+ /* Cache and cache-pool segment type */
+ if (seg_is_cache(lp)) {
+ /* Only supported with --type cache, -H, --cache */
+ if (arg_outside_list_is_set(cmd, "is unsupported with cache",
+ CACHE_POOL_ARGS,
+ LVCREATE_ARGS,
+ PERSISTENT_ARGS,
+ POOL_ARGS,
+ SIZE_ARGS,
+ cache_ARG,
+ chunksize_ARG,
+ wipesignatures_ARG, zero_ARG,
+ -1))
return_0;
-
- if (seg_is_pool(lp)) {
- log_error("Snapshots are incompatible with pool segment types.");
+ lp->create_pool = 1; /* Confirmed when opened VG */
+ } else if (seg_is_cache_pool(lp)) {
+ if (arg_outside_list_is_set(cmd, "is unsupported with cache pools",
+ CACHE_POOL_ARGS,
+ LVCREATE_ARGS,
+ POOL_ARGS,
+ SIZE_ARGS,
+ chunksize_ARG,
+ -1))
+ return_0;
+ if (!(lp->permission & LVM_WRITE)) {
+ log_error("Cannot create read-only cache pool.");
return 0;
}
+ lp->create_pool = 1;
+ } else if (arg_from_list_is_set(cmd, "is supported only with cache",
+ cache_ARG, CACHE_POOL_ARGS,
+ -1))
+ return_0;
+
+ /* Snapshot segment type */
+ if (seg_is_snapshot(lp)) {
+ /* Only supported with --type snapshot, -s, --snapshot */
+ if (arg_outside_list_is_set(cmd, "is unsupported with snapshots",
+ LVCREATE_ARGS,
+ PERSISTENT_ARGS,
+ SIZE_ARGS,
+ chunksize_ARG,
+ snapshot_ARG,
+ thinpool_ARG,
+ virtualoriginsize_ARG,
+ virtualsize_ARG,
+ -1))
+ return_0;
+
+ /* TODO: resolve this ambiguous case with --pooldatasize */
+ if (arg_is_set(cmd, thinpool_ARG)) {
+ if (lp->type) {
+ /* Unsupported with --type snapshot */
+ log_error("Snapshot segment type is incompatible with thin pools.");
+ return 0;
+ }
+
+ if (arg_from_list_is_set(cmd, "is unsupported with snapshots and --thinpool",
+ SIZE_ARGS,
+ chunksize_ARG,
+ virtualoriginsize_ARG,
+ virtualsize_ARG,
+ -1))
+ return_0;
+ }
- if (arg_is_set(cmd, thinpool_ARG) &&
- (arg_is_set(cmd, extents_ARG) || arg_is_set(cmd, size_ARG))) {
- log_error("Cannot specify snapshot size and thin pool.");
+ /* Snapshot segment type needs size/extents */
+ if (lp->type && !arg_is_set(cmd, size_ARG) && !arg_is_set(cmd, extents_ARG)) {
+ log_error("Snapshot segment type requires size or extents.");
return 0;
}
- lp->snapshot = 1;
- }
+ lp->snapshot = 1; /* Free arg is snapshot origin */
+ } else if (arg_from_list_is_set(cmd, "is supported only with sparse snapshots",
+ virtualoriginsize_ARG,
+ -1))
+ return_0;
+
+ /* Mirror segment type */
+ if (seg_is_mirror(lp)) {
+ if (arg_outside_list_is_set(cmd, "is unsupported with mirrors",
+ LVCREATE_ARGS,
+ MIRROR_ARGS,
+ MIRROR_RAID_ARGS,
+ PERSISTENT_ARGS,
+ SIZE_ARGS,
+ wipesignatures_ARG, zero_ARG,
+ -1))
+ return_0;
+ } else if (arg_from_list_is_set(cmd, "is supported only with mirrors",
+ MIRROR_ARGS,
+ -1))
+ return_0;
+ /* Raid segment type */
+ if (seg_is_raid(lp)) {
+ if (arg_outside_list_is_set(cmd, "is unsupported with raids",
+ LVCREATE_ARGS,
+ MIRROR_RAID_ARGS,
+ PERSISTENT_ARGS,
+ RAID_ARGS,
+ SIZE_ARGS,
+ wipesignatures_ARG, zero_ARG,
+ -1))
+ return_0;
+ } else if (arg_from_list_is_set(cmd, "is supported only with raids",
+ RAID_ARGS,
+ -1))
+ return_0;
+
+ /* Thin and thin-pool segment type */
if (seg_is_thin_volume(lp)) {
- if (arg_is_set(cmd, virtualsize_ARG))
- lp->thin = 1;
- else if (arg_is_set(cmd, name_ARG)) {
- log_error("Missing --virtualsize when specified --name of thin volume.");
- return 0;
- /* When no virtual size -> create thin-pool only */
- } else if (!(lp->segtype = get_segtype_from_string(cmd, "thin-pool")))
+ /* Only supported with --type thin, -T, --thin, -V */
+ if (arg_outside_list_is_set(cmd, "is unsupported with thins",
+ LVCREATE_ARGS,
+ PERSISTENT_ARGS,
+ POOL_ARGS,
+ SIZE_ARGS,
+ THIN_POOL_ARGS,
+ chunksize_ARG,
+ thin_ARG,
+ virtualsize_ARG,
+ wipesignatures_ARG, zero_ARG,
+ -1))
return_0;
- /* If size/extents given with thin, then we are creating a thin pool */
- if (arg_count(cmd, size_ARG) || arg_count(cmd, extents_ARG)) {
- if (lp->snapshot &&
- (arg_is_set(cmd, cachepool_ARG) || arg_is_set(cmd, thinpool_ARG))) {
- log_error("Size or extents cannot be specified with pool name.");
+ /* If size/extents given with thin, then we are also creating a thin-pool */
+ if (arg_is_set(cmd, size_ARG) || arg_is_set(cmd, extents_ARG)) {
+ if (arg_is_set(cmd, pooldatasize_ARG)) {
+ log_error("Please specify either size or pooldatasize.");
return 0;
}
lp->create_pool = 1;
- }
- } else if (seg_is_pool(lp)) {
- if (arg_from_list_is_set(cmd, "is unsupported with pool segment type",
- cache_ARG, mirrors_ARG, snapshot_ARG, thin_ARG,
- virtualsize_ARG,
- -1))
+ } else if (arg_from_list_is_set(cmd, "is supported only with thin pool creation",
+ POOL_ARGS,
+ SIZE_ARGS,
+ chunksize_ARG,
+ discards_ARG,
+ zero_ARG,
+ -1))
return_0;
- lp->create_pool = 1;
- }
- if (seg_is_mirrored(lp) || seg_is_raid(lp)) {
- /* Note: snapshots have snapshot_ARG or virtualsize_ARG */
- if (arg_from_list_is_set(cmd, "is unsupported with mirrored segment type",
- cache_ARG, cachepool_ARG,
- snapshot_ARG,
- thin_ARG, thinpool_ARG,
- virtualsize_ARG,
- -1))
+ if (!arg_is_set(cmd, virtualsize_ARG)) {
+ /* Without virtual size could be creation of thin-pool or snapshot */
+ if (lp->create_pool) {
+ if (lp->type) {
+ log_error("Thin segment type requires --virtualsize.");
+ return 0;
+ }
+
+ log_debug_metadata("Switching from thin to thin pool segment type.");
+ if (!(lp->segtype = get_segtype_from_string(cmd, "thin-pool")))
+ return_0;
+ } else /* Parse free arg as snapshot origin */
+ lp->snapshot = 1;
+ }
+ } else if (seg_is_thin_pool(lp)) {
+ if (arg_outside_list_is_set(cmd, "is unsupported with thin pools",
+ LVCREATE_ARGS,
+ POOL_ARGS,
+ SIZE_ARGS,
+ THIN_POOL_ARGS,
+ chunksize_ARG,
+ zero_ARG,
+ -1))
return_0;
- } else if (arg_from_list_is_set(cmd, "is unsupported without mirrored segment type",
- corelog_ARG, mirrorlog_ARG, nosync_ARG,
+ if (!(lp->permission & LVM_WRITE)) {
+ log_error("Cannot create read-only thin pool.");
+ return 0;
+ }
+ lp->create_pool = 1;
+ } else if (!lp->snapshot &&
+ arg_from_list_is_set(cmd, "is supported only with thins",
+ thin_ARG, THIN_POOL_ARGS,
-1))
return_0;
- /* Default to 2 mirrored areas if '--type mirror|raid1|raid10' */
- lp->mirrors = segtype_is_mirrored(lp->segtype) ? 2 : 1;
-
- if (arg_count(cmd, mirrors_ARG)) {
- if (arg_sign_value(cmd, mirrors_ARG, SIGN_NONE) == SIGN_MINUS) {
- log_error("Mirrors argument may not be negative");
+ /* Check options shared between more segment types */
+ if (!seg_is_mirror(lp) && !seg_is_raid(lp)) {
+ if (arg_from_list_is_set(cmd, "is supported only with mirrors or raids",
+ nosync_ARG,
+ regionsize_ARG,
+ -1))
+ return_0;
+ /* Let -m0 pass */
+ if (arg_int_value(cmd, mirrors_ARG, 0)) {
+ log_error("--mirrors is supported only with mirrors or raids");
return 0;
}
+ }
- lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1;
-
- if (lp->mirrors > DEFAULT_MIRROR_MAX_IMAGES) {
- log_error("Only up to " DM_TO_STRING(DEFAULT_MIRROR_MAX_IMAGES)
- " images in mirror supported currently.");
- return 0;
- }
+ if (!lp->create_pool && !lp->snapshot &&
+ arg_from_list_is_set(cmd, "is supported only with pools and snapshots",
+ chunksize_ARG,
+ -1))
+ return_0;
- if (lp->mirrors == 1) {
- if (segtype_is_mirrored(lp->segtype)) {
- log_error("--mirrors must be at least 1 with segment type %s.", lp->segtype->name);
- return 0;
- }
- log_print_unless_silent("Redundant mirrors argument: default is 0");
- }
+ if (!lp->snapshot && !seg_is_thin_volume(lp) &&
+ arg_from_list_is_set(cmd, "is supported only with sparse snapshots and thins",
+ virtualsize_ARG,
+ -1))
+ return_0;
- if ((lp->mirrors > 2) && !strcmp(lp->segtype->name, SEG_TYPE_NAME_RAID10)) {
- /*
- * FIXME: When RAID10 is no longer limited to
- * 2-way mirror, 'lv_mirror_count()'
- * must also change for RAID10.
- */
- log_error("RAID10 currently supports "
- "only 2-way mirroring (i.e. '-m 1')");
- return 0;
- }
- }
+ /* Basic segment type validation finished here */
if (activation() && lp->segtype->ops->target_present) {
if (!lp->segtype->ops->target_present(cmd, NULL, &lp->target_attr)) {
@@ -898,22 +1017,15 @@ static int _lvcreate_params(struct lvcreate_params *lp,
lp->wipe_signatures = 0;
}
- if (arg_count(cmd, chunksize_ARG) &&
- (arg_sign_value(cmd, chunksize_ARG, SIGN_NONE) == SIGN_MINUS)) {
- log_error("Negative chunk size is invalid.");
- return 0;
- }
-
- if (!_lvcreate_name_params(lp, cmd, &argc, &argv) ||
- !_read_size_params(lp, lcp, cmd) ||
+ if (!_lvcreate_name_params(cmd, &argc, &argv, lp) ||
+ !_read_size_params(cmd, lp, lcp) ||
!get_stripe_params(cmd, &lp->stripes, &lp->stripe_size) ||
(lp->create_pool &&
!get_pool_params(cmd, lp->segtype, &lp->passed_args,
&lp->pool_metadata_size, &lp->pool_metadata_spare,
&lp->chunk_size, &lp->discards, &lp->zero)) ||
- !_read_mirror_params(lp, cmd) ||
- !_read_raid_params(lp, cmd) ||
- !_read_cache_pool_params(lp, cmd))
+ !_read_cache_params(cmd, lp) ||
+ !_read_mirror_and_raid_params(cmd, lp))
return_0;
if (only_linear && lp->stripes > 1) {
@@ -930,22 +1042,9 @@ static int _lvcreate_params(struct lvcreate_params *lp,
return 0;
}
log_verbose("Setting chunksize to %s.", display_size(cmd, lp->chunk_size));
-
- if (!(lp->segtype = get_segtype_from_string(cmd, "snapshot")))
- return_0;
- } else if (!lp->create_pool && arg_count(cmd, chunksize_ARG)) {
- log_error("--chunksize is only available with snapshots and pools.");
- return 0;
}
- if (!lp->create_pool &&
- arg_count(cmd, poolmetadataspare_ARG)) {
- log_error("--poolmetadataspare is only available with pool creation.");
- return 0;
- }
- /*
- * Allocation parameters
- */
+ /* Allocation parameters */
contiguous = arg_int_value(cmd, contiguous_ARG, 0);
lp->alloc = contiguous ? ALLOC_CONTIGUOUS : ALLOC_INHERIT;
lp->alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, lp->alloc);
@@ -991,31 +1090,59 @@ static int _determine_cache_argument(struct volume_group *vg,
{
struct logical_volume *lv;
- if (!seg_is_cache(lp)) {
- log_error(INTERNAL_ERROR
- "Unable to determine cache argument on %s segtype",
- lp->segtype->name);
- return 0;
- }
-
if (!lp->pool_name) {
lp->pool_name = lp->lv_name;
- } else if (lp->pool_name == lp->origin_name) {
- if (!(lv = find_lv(vg, lp->pool_name))) {
- /* Cache pool nor origin volume exists */
- lp->cache = 0;
- lp->origin_name = 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_name = lp->lv_name;
- /* We were given origin for caching */
- } else {
- /* FIXME error on pool args */
- lp->create_pool = 0;
- lp->origin_name = NULL;
+ } else if ((lv = find_lv(vg, lp->pool_name)) && lv_is_cache_pool(lv)) {
+ /* Pool exists, create cache volume */
+ lp->create_pool = 0;
+ lp->origin_name = NULL;
+ } else if (lv) {
+ /* Origin exists, create cache pool volume */
+ if (!validate_lv_cache_create_origin(lv))
+ return_0;
+
+ if (arg_is_set(vg->cmd, permission_ARG) &&
+ ((lp->permission & LVM_WRITE) != (lv->status & LVM_WRITE))) {
+ /* Reverting permissions on all error path is very complicated */
+ log_error("Change of volume permission is unsupported with cache conversion, use lvchange.");
+ return 0;
}
+ /* FIXME: how to handle skip flag */
+ if (arg_from_list_is_set(vg->cmd, "is unsupported with cache conversion",
+ setactivationskip_ARG,
+ ignoreactivationskip_ARG,
+ -1))
+ return_0; /* TODO FIX THIS */
+
+ /* Put origin into resulting activation state first */
+ if (is_change_activating(lp->activate)) {
+ if ((lp->activate == CHANGE_AAY) &&
+ !lv_passes_auto_activation_filter(vg->cmd, lv)) {
+ log_verbose("Skipping activation of cache origin %s.",
+ display_lvname(lv));
+ return 1;
+ } else if (!activate_lv_excl_local(vg->cmd, lv)) {
+ log_error("Cannot activate cache origin %s.",
+ display_lvname(lv));
+ return 0;
+ }
+ } else if (!deactivate_lv(vg->cmd, lv)) {
+ log_error("Cannot deactivate activate cache origin %s.",
+ display_lvname(lv));
+ return 0;
+ }
+
+ /* lp->origin_name is already equal to lp->pool_name */
+ lp->pool_name = lp->lv_name; /* --name is cache pool name */
+ /* No zeroing of an existing origin! */
+ lp->zero = lp->wipe_signatures = 0;
+ } else {
+ /* Cache pool and cache volume needs to be created */
+ lp->origin_name = NULL;
+ /* --pooldatasize is needed here */
+ log_error("Ambiguous syntax, please create --type cache-pool %s separately.",
+ lp->pool_name);
+ return 0;
}
return 1;
@@ -1025,21 +1152,20 @@ static int _determine_cache_argument(struct volume_group *vg,
* Normal snapshot or thinly-provisioned snapshot?
*/
static int _determine_snapshot_type(struct volume_group *vg,
- struct lvcreate_params *lp)
+ struct lvcreate_params *lp,
+ struct lvcreate_cmdline_params *lcp)
{
- struct logical_volume *lv, *pool_lv = NULL;
+ struct logical_volume *origin_lv, *pool_lv = NULL;
- if (!(lv = find_lv(vg, lp->origin_name))) {
+ if (!(origin_lv = find_lv(vg, lp->origin_name))) {
log_error("Snapshot origin LV %s not found in Volume group %s.",
lp->origin_name, vg->name);
return 0;
}
+ if (lp->extents || lcp->size)
+ return 1; /* Size specified */
- if (lv_is_cache(lv)) {
- log_error("Snapshot of cache LV is not yet supported.");
- return 0;
- }
-
+ /* Check if we could make thin snapshot */
if (lp->pool_name) {
if (!(pool_lv = find_lv(vg, lp->pool_name))) {
log_error("Thin pool volume %s not found in Volume group %s.",
@@ -1052,24 +1178,63 @@ static int _determine_snapshot_type(struct volume_group *vg,
display_lvname(pool_lv));
return 0;
}
+ } else {
+ if (!lv_is_thin_volume(origin_lv)) {
+ if (!seg_is_thin(lp))
+ log_error("Please specify either size or extents with snapshots.");
+ else
+ log_error("Logical volume %s is not a thin volume. "
+ "Thin snapshot supports only thin origins.",
+ display_lvname(origin_lv));
+ return 0;
+ }
+ /* Origin thin volume without size makes thin segment */
+ lp->pool_name = first_seg(origin_lv)->pool_lv->name;
}
- if (!arg_count(vg->cmd, extents_ARG) && !arg_count(vg->cmd, size_ARG)) {
- if (lv_is_thin_volume(lv) && !lp->pool_name)
- lp->pool_name = first_seg(lv)->pool_lv->name;
+ log_debug_metadata("Switching from snapshot to thin segment type.");
+ if (!(lp->segtype = get_segtype_from_string(vg->cmd, "thin")))
+ return_0;
+ lp->snapshot = 0;
- if (seg_is_thin(lp) || lp->pool_name) {
- if (!(lp->segtype = get_segtype_from_string(vg->cmd, "thin")))
- return_0;
- return 1;
- }
+ return 1;
+}
- log_error("Please specify either size or extents with snapshots.");
- return 0;
- } else if (lp->pool_name) {
- log_error("Cannot specify size with thin pool snapshot.");
- return 0;
+static int _check_raid_parameters(struct volume_group *vg,
+ struct lvcreate_params *lp,
+ struct lvcreate_cmdline_params *lcp)
+{
+ unsigned devs = lcp->pv_count ? : dm_list_size(&vg->pvs);
+ struct cmd_context *cmd = vg->cmd;
+
+ /*
+ * If number of devices was not supplied, we can infer from
+ * the PVs given.
+ */
+ if (!seg_is_mirrored(lp)) {
+ if (!arg_count(cmd, stripes_ARG) &&
+ (devs > 2 * lp->segtype->parity_devs))
+ lp->stripes = devs - lp->segtype->parity_devs;
+
+ if (!lp->stripe_size)
+ lp->stripe_size = find_config_tree_int(cmd, metadata_stripesize_CFG, NULL) * 2;
+
+ if (lp->stripes <= lp->segtype->parity_devs) {
+ log_error("Number of stripes must be at least %d for %s",
+ lp->segtype->parity_devs + 1,
+ lp->segtype->name);
+ return 0;
+ }
+ } else if (!strcmp(lp->segtype->name, SEG_TYPE_NAME_RAID10)) {
+ if (!arg_count(cmd, stripes_ARG))
+ lp->stripes = devs / lp->mirrors;
+ if (lp->stripes < 2) {
+ log_error("Unable to create RAID10 LV,"
+ " insufficient number of devices.");
+ return 0;
+ }
}
+ /* 'mirrors' defaults to 2 - not the number of PVs supplied */
return 1;
}
@@ -1077,74 +1242,110 @@ static int _determine_snapshot_type(struct volume_group *vg,
static int _check_thin_parameters(struct volume_group *vg, struct lvcreate_params *lp,
struct lvcreate_cmdline_params *lcp)
{
- struct logical_volume *pool_lv = NULL;
-
- if (!lp->thin && !lp->create_pool && !lp->snapshot) {
- log_error("Please specify device size(s).");
- return 0;
- }
-
- if (lp->thin && lp->snapshot) {
+ if (seg_is_thin_volume(lp) && lp->snapshot) {
log_error("Please either create snapshot or thin volume.");
return 0;
}
- if (lp->pool_name)
- pool_lv = find_lv(vg, lp->pool_name);
-
- if (!lp->create_pool) {
- if (arg_from_list_is_set(vg->cmd, "is only available with thin pool creation",
+ if (!seg_is_thin_volume(lp) && !lp->snapshot) {
+ /* Not creating thin volume nor snapshot */
+ if (arg_from_list_is_set(vg->cmd, "may only be given when creating a new thin Logical volume or snapshot",
+ permission_ARG,
+ persistent_ARG,
+ readahead_ARG,
+ -1))
+ return_0;
+ if (!lp->create_pool) {
+ /* Not even creating thin pool? */
+ log_error("Please specify device size(s).");
+ return 0;
+ }
+ } else if (!lp->create_pool) {
+ if (arg_from_list_is_set(vg->cmd, "is only available when creating thin pool",
alloc_ARG,
chunksize_ARG,
contiguous_ARG,
- discards_ARG,
- poolmetadatasize_ARG,
- poolmetadataspare_ARG,
stripes_ARG,
- stripesize_ARG,
zero_ARG,
-1))
return_0;
if (lcp->pv_count) {
- log_error("Only specify Physical volumes when allocating the thin pool.");
+ log_error("Only specify Physical volumes when allocating thin pool.");
return 0;
}
+ }
- if (!lp->pool_name) {
- log_error("Please specify name of existing thin pool.");
- return 0;
- }
+ return 1;
+}
+
+static int _check_pool_parameters(struct cmd_context *cmd,
+ struct volume_group *vg,
+ struct lvcreate_params *lp,
+ struct lvcreate_cmdline_params *lcp)
+{
+ struct logical_volume *pool_lv;
- if (!pool_lv) {
- log_error("Thin pool %s not found in Volume group %s.", lp->pool_name, vg->name);
+ if (!lp->create_pool &&
+ arg_from_list_is_set(cmd, "is only available with pools",
+ POOL_ARGS,
+ discards_ARG,
+ -1))
+ return_0;
+
+ if (!seg_is_cache(lp) &&
+ !seg_is_thin_volume(lp) &&
+ !seg_is_pool(lp)) {
+ if (lp->pool_name && !lp->snapshot) {
+ log_error("Segment type %s cannot use pool %s.",
+ lp->segtype->name, lp->pool_name);
return 0;
}
+ return 1; /* Pool unrelated types */
+ }
- if (!lv_is_thin_pool(pool_lv)) {
- log_error("Logical volume %s is not a thin pool.", display_lvname(pool_lv));
- return 0;
+ if (lp->create_pool) {
+ /* Given pool name needs to follow restrictions for created LV */
+ if (lp->pool_name) {
+ if (!apply_lvname_restrictions(lp->pool_name))
+ return_0;
+ /* We could check existance only when we have vg */
+ if (vg && find_lv(vg, lp->pool_name)) {
+ log_error("Logical volume %s already exists in Volume group %s.",
+ lp->pool_name, vg->name);
+ return 0;
+ }
}
- } else if (pool_lv) {
- log_error("Logical volume %s already exists in Volume group %s.", lp->pool_name, vg->name);
+ /* When creating just pool the pool_name needs to be in lv_name */
+ if (seg_is_pool(lp))
+ lp->lv_name = lp->pool_name;
+
+ return 1;
+ }
+ /* Not creating new pool, but existing pool is needed */
+ if (!lp->pool_name) {
+ if (lp->snapshot)
+ /* Taking snapshot via 'lvcreate -T vg/origin' */
+ return 1;
+ log_error("Please specify name of existing pool.");
return 0;
}
- if (!lp->thin && !lp->snapshot) {
- if (lp->lv_name) {
- log_error("--name may only be given when creating a new thin Logical volume or snapshot.");
- return 0;
- }
- if (arg_count(vg->cmd, readahead_ARG)) {
- log_error("--readhead may only be given when creating a new thin Logical volume or snapshot.");
+ if (vg) {
+ /* Validate pool has matching type */
+ if (!(pool_lv = find_lv(vg, lp->pool_name))) {
+ log_error("Pool %s not found in Volume group %s.",
+ lp->pool_name, vg->name);
return 0;
}
- if (arg_count(vg->cmd, permission_ARG)) {
- log_error("--permission may only be given when creating a new thin Logical volume or snapshot.");
+ if (seg_is_cache(lp) && !lv_is_cache_pool(pool_lv)) {
+ log_error("Logical volume %s is not a cache pool.",
+ display_lvname(pool_lv));
return 0;
}
- if (arg_count(vg->cmd, persistent_ARG)) {
- log_error("--persistent may only be given when creating a new thin Logical volume or snapshot.");
+ if (seg_is_thin_volume(lp) && !lv_is_thin_pool(pool_lv)) {
+ log_error("Logical volume %s is not a thin pool.",
+ display_lvname(pool_lv));
return 0;
}
}
@@ -1152,44 +1353,6 @@ static int _check_thin_parameters(struct volume_group *vg, struct lvcreate_param
return 1;
}
-static int _check_raid_parameters(struct volume_group *vg,
- struct lvcreate_params *lp,
- struct lvcreate_cmdline_params *lcp)
-{
- unsigned devs = lcp->pv_count ? : dm_list_size(&vg->pvs);
- struct cmd_context *cmd = vg->cmd;
-
- /*
- * If number of devices was not supplied, we can infer from
- * the PVs given.
- */
- if (!seg_is_mirrored(lp)) {
- if (!arg_count(cmd, stripes_ARG) &&
- (devs > 2 * lp->segtype->parity_devs))
- lp->stripes = devs - lp->segtype->parity_devs;
-
- if (!lp->stripe_size)
- lp->stripe_size = find_config_tree_int(cmd, metadata_stripesize_CFG, NULL) * 2;
-
- if (lp->stripes <= lp->segtype->parity_devs) {
- log_error("Number of stripes must be at least %d for %s",
- lp->segtype->parity_devs + 1,
- lp->segtype->name);
- return 0;
- }
- } else if (!strcmp(lp->segtype->name, SEG_TYPE_NAME_RAID10)) {
- if (!arg_count(cmd, stripes_ARG))
- lp->stripes = devs / lp->mirrors;
- if (lp->stripes < 2) {
- log_error("Unable to create RAID10 LV,"
- " insufficient number of devices.");
- return 0;
- }
- }
- /* 'mirrors' defaults to 2 - not the number of PVs supplied */
-
- return 1;
-}
/*
* Ensure the set of thin parameters extracted from the command line is consistent.
@@ -1212,21 +1375,17 @@ static int _validate_internal_thin_processing(const struct lvcreate_params *lp)
r = 0;
}
- if ((lp->snapshot && !lp->origin_name) || (!lp->snapshot && lp->origin_name)) {
+ if ((!lp->origin_name && lp->snapshot) ||
+ (lp->origin_name && !lp->snapshot && !seg_is_thin_volume(lp))) {
log_error(INTERNAL_ERROR "Inconsistent snapshot and origin parameters identified.");
r = 0;
}
- if (!lp->thin && !lp->create_pool && !lp->snapshot) {
+ if (!lp->create_pool && !lp->snapshot && !seg_is_thin_volume(lp)) {
log_error(INTERNAL_ERROR "Failed to identify what type of thin target to use.");
r = 0;
}
- if (seg_is_thin_pool(lp) && lp->thin) {
- log_error(INTERNAL_ERROR "Thin volume cannot be created with thin pool segment type.");
- r = 0;
- }
-
return r;
}
@@ -1240,8 +1399,15 @@ int lvcreate(struct cmd_context *cmd, int argc, char **argv)
struct lvcreate_cmdline_params lcp;
struct volume_group *vg;
- if (!_lvcreate_params(&lp, &lcp, cmd, argc, argv))
+ if (!_lvcreate_params(cmd, argc, argv, &lp, &lcp)) {
+ stack;
return EINVALID_CMD_LINE;
+ }
+
+ if (!_check_pool_parameters(cmd, NULL, &lp, &lcp)) {
+ stack;
+ return EINVALID_CMD_LINE;
+ }
log_verbose("Finding volume group \"%s\"", lp.vg_name);
vg = vg_read_for_update(cmd, lp.vg_name, NULL, 0);
@@ -1250,23 +1416,28 @@ int lvcreate(struct cmd_context *cmd, int argc, char **argv)
return_ECMD_FAILED;
}
- if (lp.snapshot && lp.origin_name && !_determine_snapshot_type(vg, &lp))
- goto_out;
-
- if (seg_is_thin(&lp) && !_check_thin_parameters(vg, &lp, &lcp))
+ /* Resolve segment types with opened VG */
+ if (lp.snapshot && lp.origin_name && !_determine_snapshot_type(vg, &lp, &lcp))
goto_out;
if (seg_is_cache(&lp) && !_determine_cache_argument(vg, &lp))
goto_out;
+ /* All types resolved at this point, now only validation steps */
if (seg_is_raid(&lp) && !_check_raid_parameters(vg, &lp, &lcp))
goto_out;
+ if (seg_is_thin(&lp) && !_check_thin_parameters(vg, &lp, &lcp))
+ goto_out;
+
+ if (!_check_pool_parameters(cmd, vg, &lp, &lcp))
+ goto_out;
+
/*
* Check activation parameters to support inactive thin snapshot creation
* FIXME: anything else needs to be moved past _determine_snapshot_type()?
*/
- if (!_read_activation_params(&lp, cmd, vg))
+ if (!_read_activation_params(cmd, vg, &lp))
goto_out;
if (!_update_extents_params(vg, &lp, &lcp))
@@ -1284,7 +1455,7 @@ int lvcreate(struct cmd_context *cmd, int argc, char **argv)
lp.pool_name ? : "with generated name", lp.vg_name, lp.segtype->name);
}
- if (lp.thin)
+ if (seg_is_thin_volume(&lp))
log_verbose("Making thin LV %s in pool %s in VG %s%s%s using segtype %s",
lp.lv_name ? : "with generated name",
lp.pool_name ? : "with generated name", lp.vg_name,