mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
thin: lvcreate external origin snapshot support
This commit is contained in:
parent
435e0bb608
commit
d24c01a414
@ -324,10 +324,14 @@ struct lv_segment *alloc_lv_segment(const struct segment_type *segtype,
|
||||
/* Use the same external origin */
|
||||
if (!attach_thin_external_origin(seg, first_seg(thin_pool_lv)->external_lv))
|
||||
return_NULL;
|
||||
} else {
|
||||
} else if (lv_is_thin_pool(thin_pool_lv)) {
|
||||
seg->transaction_id = first_seg(thin_pool_lv)->transaction_id;
|
||||
if (!attach_pool_lv(seg, thin_pool_lv, NULL))
|
||||
return_NULL;
|
||||
} else {
|
||||
log_error(INTERNAL_ERROR "Volume %s is not thin volume or thin pool",
|
||||
thin_pool_lv->name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4302,6 +4306,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, struct l
|
||||
struct logical_volume *pool_lv;
|
||||
struct lv_list *lvl;
|
||||
int origin_active = 0;
|
||||
const char *thin_name = NULL;
|
||||
|
||||
if (new_lv_name && find_lv_in_vg(vg, new_lv_name)) {
|
||||
log_error("Logical volume \"%s\" already exists in "
|
||||
@ -4364,7 +4369,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, struct l
|
||||
|
||||
status |= lp->permission | VISIBLE_LV;
|
||||
|
||||
if (lp->snapshot && lp->thin) {
|
||||
if (seg_is_thin(lp) && lp->snapshot) {
|
||||
if (!(org = find_lv(vg, lp->origin))) {
|
||||
log_error("Couldn't find origin volume '%s'.",
|
||||
lp->origin);
|
||||
@ -4454,7 +4459,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, struct l
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (lp->snapshot && !lp->thin && ((uint64_t)lp->extents * vg->extent_size < 2 * lp->chunk_size)) {
|
||||
if (lp->snapshot && !seg_is_thin(lp) && ((uint64_t)lp->extents * vg->extent_size < 2 * lp->chunk_size)) {
|
||||
log_error("Unable to create a snapshot smaller than 2 chunks.");
|
||||
return NULL;
|
||||
}
|
||||
@ -4493,7 +4498,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, struct l
|
||||
}
|
||||
|
||||
/* The snapshot segment gets created later */
|
||||
if (lp->snapshot && !lp->thin &&
|
||||
if (lp->snapshot && !seg_is_thin(lp) &&
|
||||
!(lp->segtype = get_segtype_from_string(cmd, "striped")))
|
||||
return_NULL;
|
||||
|
||||
@ -4571,12 +4576,21 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, struct l
|
||||
|
||||
dm_list_splice(&lv->tags, &lp->tags);
|
||||
|
||||
if (seg_is_thin_volume(lp)) {
|
||||
/* For thin snapshot we must have matching pool */
|
||||
if (org && lv_is_thin_volume(org) && (!lp->pool ||
|
||||
(strcmp(first_seg(org)->pool_lv->name, lp->pool) == 0)))
|
||||
thin_name = org->name;
|
||||
else
|
||||
thin_name = lp->pool;
|
||||
}
|
||||
|
||||
if (!lv_extend(lv, lp->segtype,
|
||||
lp->stripes, lp->stripe_size,
|
||||
lp->mirrors,
|
||||
seg_is_thin_pool(lp) ? lp->poolmetadataextents : lp->region_size,
|
||||
seg_is_thin_volume(lp) ? lp->voriginextents : lp->extents,
|
||||
seg_is_thin_volume(lp) ? (org ? org->name : lp->pool) : NULL, lp->pvh, lp->alloc))
|
||||
thin_name, lp->pvh, lp->alloc))
|
||||
return_NULL;
|
||||
|
||||
if (seg_is_thin_pool(lp)) {
|
||||
@ -4587,12 +4601,29 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, struct l
|
||||
first_seg(lv)->low_water_mark = 0;
|
||||
} else if (seg_is_thin_volume(lp)) {
|
||||
pool_lv = first_seg(lv)->pool_lv;
|
||||
|
||||
if (!(first_seg(lv)->device_id =
|
||||
get_free_pool_device_id(first_seg(pool_lv)))) {
|
||||
stack;
|
||||
goto revert_new_lv;
|
||||
}
|
||||
/*
|
||||
* Check if using 'external origin' or the 'normal' snapshot
|
||||
* within the same thin pool
|
||||
*/
|
||||
if (lp->snapshot && (first_seg(org)->pool_lv != pool_lv)) {
|
||||
if (org->status & LVM_WRITE) {
|
||||
log_error("Cannot use writable LV as the external origin.");
|
||||
return 0; // TODO conversion for inactive
|
||||
}
|
||||
if (lv_is_active(org) && !lv_is_external_origin(org)) {
|
||||
log_error("Cannot use active LV for the external origin.");
|
||||
return 0; // We can't be sure device it is read-only
|
||||
}
|
||||
if (!attach_thin_external_origin(first_seg(lv), org)) {
|
||||
stack;
|
||||
goto revert_new_lv;
|
||||
}
|
||||
}
|
||||
|
||||
if (!attach_pool_message(first_seg(pool_lv),
|
||||
DM_THIN_MESSAGE_CREATE_THIN, lv, 0, 0)) {
|
||||
@ -4634,7 +4665,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, struct l
|
||||
|
||||
if (seg_is_thin(lp)) {
|
||||
/* For snapshot, suspend active thin origin first */
|
||||
if (org && lv_is_active(org)) {
|
||||
if (org && lv_is_active(org) && lv_is_thin_volume(org)) {
|
||||
if (!pool_below_threshold(first_seg(first_seg(org)->pool_lv))) {
|
||||
log_error("Cannot create thin snapshot. Pool %s/%s is filled "
|
||||
"over the autoextend threshold.",
|
||||
@ -4699,7 +4730,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, struct l
|
||||
goto deactivate_and_revert_new_lv;
|
||||
}
|
||||
|
||||
if (lp->snapshot && !lp->thin) {
|
||||
if (lp->snapshot && !seg_is_thin(lp)) {
|
||||
/* Reset permission after zeroing */
|
||||
if (!(lp->permission & LVM_WRITE))
|
||||
lv->status &= ~LVM_WRITE;
|
||||
@ -4788,7 +4819,7 @@ struct logical_volume *lv_create_single(struct volume_group *vg,
|
||||
if (!(lv = _lv_create_an_lv(vg, lp, lp->pool)))
|
||||
return_0;
|
||||
|
||||
if (!lp->thin)
|
||||
if (!lp->thin && !lp->snapshot)
|
||||
goto out;
|
||||
|
||||
lp->pool = lv->name;
|
||||
|
107
tools/lvcreate.c
107
tools/lvcreate.c
@ -207,12 +207,17 @@ static int _determine_snapshot_type(struct volume_group *vg,
|
||||
}
|
||||
|
||||
if (!arg_count(vg->cmd, extents_ARG) && !arg_count(vg->cmd, size_ARG)) {
|
||||
if (seg_is_thin(lp)) {
|
||||
if (!(lp->segtype = get_segtype_from_string(vg->cmd, "thin")))
|
||||
return_0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!lv_is_thin_volume(lvl->lv)) {
|
||||
log_error("Please specify either size or extents with snapshots.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lp->thin = 1;
|
||||
if (!(lp->segtype = get_segtype_from_string(vg->cmd, "thin")))
|
||||
return_0;
|
||||
|
||||
@ -355,7 +360,7 @@ static int _read_size_params(struct lvcreate_params *lp,
|
||||
}
|
||||
|
||||
/* If size/extents given with thin, then we are creating a thin pool */
|
||||
if (lp->thin && (arg_count(cmd, size_ARG) || arg_count(cmd, extents_ARG)))
|
||||
if (seg_is_thin(lp) && (arg_count(cmd, size_ARG) || arg_count(cmd, extents_ARG)))
|
||||
lp->create_thin_pool = 1;
|
||||
|
||||
if (arg_count(cmd, poolmetadatasize_ARG) && !seg_is_thin(lp)) {
|
||||
@ -380,8 +385,9 @@ static int _read_size_params(struct lvcreate_params *lp,
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
/* No virtual size given, so no thin LV to create. */
|
||||
if (seg_is_thin_volume(lp) && !(lp->segtype = get_segtype_from_string(cmd, "thin-pool")))
|
||||
/* No virtual size given and no snapshot, so no thin LV to create. */
|
||||
if (seg_is_thin_volume(lp) && !lp->snapshot &&
|
||||
!(lp->segtype = get_segtype_from_string(cmd, "thin-pool")))
|
||||
return_0;
|
||||
|
||||
lp->thin = 0;
|
||||
@ -651,6 +657,7 @@ static int _lvcreate_params(struct lvcreate_params *lp,
|
||||
struct arg_value_group_list *current_group;
|
||||
const char *segtype_str;
|
||||
const char *tag;
|
||||
unsigned i;
|
||||
|
||||
memset(lp, 0, sizeof(*lp));
|
||||
memset(lcp, 0, sizeof(*lcp));
|
||||
@ -660,7 +667,6 @@ static int _lvcreate_params(struct lvcreate_params *lp,
|
||||
/*
|
||||
* Check selected options are compatible and determine segtype
|
||||
*/
|
||||
// FIXME -m0 implies *striped*
|
||||
if ((arg_count(cmd, thin_ARG) || arg_count(cmd, thinpool_ARG)) &&
|
||||
arg_count(cmd,mirrors_ARG)) {
|
||||
log_error("--thin,--thinpool and --mirrors are incompatible.");
|
||||
@ -692,6 +698,12 @@ static int _lvcreate_params(struct lvcreate_params *lp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((arg_count(cmd, snapshot_ARG) || seg_is_snapshot(lp)) &&
|
||||
arg_count(cmd, thin_ARG)) {
|
||||
log_error("--thin and --snapshot are incompatible.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, snapshot_ARG) || seg_is_snapshot(lp) ||
|
||||
(!seg_is_thin(lp) && arg_count(cmd, virtualsize_ARG)))
|
||||
lp->snapshot = 1;
|
||||
@ -802,37 +814,43 @@ static int _lvcreate_params(struct lvcreate_params *lp,
|
||||
!_read_raid_params(lp, cmd))
|
||||
return_0;
|
||||
|
||||
if (!lp->create_thin_pool && arg_count(cmd, discards_ARG)) {
|
||||
log_error("--discards is only available for thin pool creation.");
|
||||
return 0;
|
||||
}
|
||||
if (!lp->create_thin_pool) {
|
||||
if (seg_is_thin(lp)) {
|
||||
static const int _argname[] = {
|
||||
chunksize_ARG, discards_ARG, poolmetadatasize_ARG, zero_ARG
|
||||
};
|
||||
for (i = 0; i < sizeof(_argname)/sizeof(_argname[0]); ++i) {
|
||||
if (arg_count(cmd, _argname[i])) {
|
||||
log_error("%s is only available for thin pool creation.",
|
||||
arg_long_option_name(_argname[i]));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else if (lp->snapshot) {
|
||||
if (arg_count(cmd, zero_ARG)) {
|
||||
log_error("-Z is incompatible with snapshots.");
|
||||
return 0;
|
||||
}
|
||||
if (arg_sign_value(cmd, chunksize_ARG, SIGN_NONE) == SIGN_MINUS) {
|
||||
log_error("Negative chunk size is invalid.");
|
||||
return 0;
|
||||
}
|
||||
lp->chunk_size = arg_uint_value(cmd, chunksize_ARG, 8);
|
||||
if (lp->chunk_size < 8 || lp->chunk_size > 1024 ||
|
||||
(lp->chunk_size & (lp->chunk_size - 1))) {
|
||||
log_error("Chunk size must be a power of 2 in the "
|
||||
"range 4K to 512K.");
|
||||
return 0;
|
||||
}
|
||||
log_verbose("Setting chunksize to %s.", display_size(cmd, lp->chunk_size));
|
||||
|
||||
if (lp->snapshot && lp->thin && arg_count(cmd, chunksize_ARG))
|
||||
log_warn("WARNING: Ignoring --chunksize with thin snapshots.");
|
||||
else if (lp->thin && !lp->create_thin_pool) {
|
||||
if (arg_count(cmd, chunksize_ARG))
|
||||
log_warn("WARNING: Ignoring --chunksize when using an existing pool.");
|
||||
} else if (lp->snapshot) {
|
||||
if (arg_sign_value(cmd, chunksize_ARG, SIGN_NONE) == SIGN_MINUS) {
|
||||
log_error("Negative chunk size is invalid");
|
||||
if (!(lp->segtype = get_segtype_from_string(cmd, "snapshot")))
|
||||
return_0;
|
||||
} else if (arg_count(cmd, chunksize_ARG)) {
|
||||
log_error("--chunksize is only available with snapshots and thin pools.");
|
||||
return 0;
|
||||
}
|
||||
lp->chunk_size = arg_uint_value(cmd, chunksize_ARG, 8);
|
||||
if (lp->chunk_size < 8 || lp->chunk_size > 1024 ||
|
||||
(lp->chunk_size & (lp->chunk_size - 1))) {
|
||||
log_error("Chunk size must be a power of 2 in the "
|
||||
"range 4K to 512K");
|
||||
return 0;
|
||||
}
|
||||
log_verbose("Setting chunksize to %s.", display_size(cmd, lp->chunk_size));
|
||||
|
||||
if (!lp->thin && lp->snapshot && !(lp->segtype = get_segtype_from_string(cmd, "snapshot")))
|
||||
return_0;
|
||||
} else if (arg_count(cmd, chunksize_ARG) && !lp->create_thin_pool) {
|
||||
log_error("-c is only available with snapshots and thin pools");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lp->mirrors > DEFAULT_MIRROR_MAX_IMAGES) {
|
||||
log_error("Only up to %d images in mirror supported currently.",
|
||||
DEFAULT_MIRROR_MAX_IMAGES);
|
||||
@ -879,11 +897,16 @@ static int _check_thin_parameters(struct volume_group *vg, struct lvcreate_param
|
||||
{
|
||||
struct lv_list *lvl;
|
||||
|
||||
if (!lp->thin && !lp->create_thin_pool) {
|
||||
if (!lp->thin && !lp->create_thin_pool && !lp->snapshot) {
|
||||
log_error("Please specify device size(s).");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lp->thin && lp->snapshot) {
|
||||
log_error("Please either creater snapshot or thin volume.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lp->thin && !lp->create_thin_pool) {
|
||||
if (arg_count(vg->cmd, chunksize_ARG)) {
|
||||
log_error("Only specify --chunksize when originally creating the thin pool.");
|
||||
@ -945,12 +968,11 @@ static int _check_thin_parameters(struct volume_group *vg, struct lvcreate_param
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lp->thin && lp->lv_name) {
|
||||
log_error("--name may only be given when creating a new thin Logical volume or snapshot.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lp->thin) {
|
||||
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.");
|
||||
return 0;
|
||||
@ -994,12 +1016,7 @@ static int _validate_internal_thin_processing(const struct lvcreate_params *lp)
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (lp->snapshot && (lp->create_thin_pool || !lp->thin)) {
|
||||
log_error(INTERNAL_ERROR "Inconsistent thin and snapshot parameters identified.");
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (!lp->thin && !lp->create_thin_pool) {
|
||||
if (!lp->thin && !lp->create_thin_pool && !lp->snapshot) {
|
||||
log_error(INTERNAL_ERROR "Failed to identify what type of thin target to use.");
|
||||
r = 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user