1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

thin: lvconvert support for external origin

Add basic support for converting LV into an external origin volume.

Syntax:

lvconvert --thinpool vg/pool  --originname renamed_origin -T origin

It will convert volume  'origin' into a thin volume, which will
use 'renamed_origin' as an external read-only origin.
All read/write into origin will go via 'pool'.

renamed_origin volume is read-only volume, that could be activated
only in read-only mode, and cannot be modified.
This commit is contained in:
Zdenek Kabelac 2013-02-05 11:26:27 +01:00
parent 2cba0ea9f9
commit b73de73151
6 changed files with 213 additions and 12 deletions

View File

@ -1,5 +1,6 @@
Version 2.02.99 -
===================================
Initial support for lvconvert of thin external origin.
Add _lv_remove_segs_using_this_lv() for removal of dependent lvs.
Improve activation code for better support of stacked devices.
Add _add_layer_target_to_dtree() for adding linear layer into dtree.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@ -1580,6 +1580,10 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
(lv_is_origin(lv_pre) || lv_is_cow(lv_pre)))
lockfs = 1;
/* Converting non-thin LV to thin external origin ? */
if (!lv_is_thin_volume(lv) && lv_is_thin_volume(lv_pre))
lockfs = 1; /* Sync before conversion */
if (laopts->origin_only && lv_is_thin_volume(lv) && lv_is_thin_volume(lv_pre))
lockfs = 1;

View File

@ -99,6 +99,10 @@ lvconvert \- convert a logical volume from linear to mirror or snapshot
.RB [ \-h | \-? | \-\-help ]
.RB [ \-v | \-\-verbose ]
.RB [ \-\-version ]
.RB [ \-T | \-\-thin
.IR ExternalOriginLogicalVolume { Name | Path }
.RB [ \-\-originname
.IR NewExternalOriginVolumeName ]]
.RI [ PhysicalVolume [ Path ][ :PE [ -PE ]]...]
.sp
@ -230,6 +234,13 @@ merge finishes, the merged snapshot is removed. Multiple snapshots may
be specified on the commandline or a @tag may be used to specify
multiple snapshots be merged to their respective origin.
.TP
.B \-\-originname \fINewExternalOriginVolumeName\fP
The name for converted external origin volume.
.br
Without this option a default names of "lvol#" will be generated where
# is the LVM internal number of the logical volume.
Converted volume will be read-only.
.TP
.BR \-\-poolmetadata " " \fIThinPoolMetadataLogicalVolume { \fIName | \fIPath }
Specifies thin pool metadata logical volume.
The size should be in between 2MiB and 16GiB.
@ -288,6 +299,13 @@ StripeSize must be 2^n (n = 2 to 9) for metadata in LVM1 format.
For metadata in LVM2 format, the stripe size may be a larger
power of 2 but must not exceed the physical extent size.
.TP
.IR \fB\-T ", " \fB\-\-thin " " ExternalOriginLogicalVolume { Name | Path }
Changes the logical volume into a thin volume for the thin pool
specified with the option \fB\-\-thinpool\fP. \fIExternalOriginLogicalVolume\fP
is converted into a new read-only logical volume which will be used as an
external origin volume for unprovisioned areas.
The non-default name for this new volume can be specified with \fB\-\-originname\fP.
.TP
.IR \fB\-\-thinpool " " ThinPoolLogicalVolume { Name | Path }
Changes logical volume into a thin pool volume. The volume
will store the pool's data.
@ -379,6 +397,20 @@ available in the volume group.
.sp
.B lvconvert \-\-replace /dev/sdb1 vg00/my_raid1 /dev/sdf1
Convert the logical volume "vg00/lvpool" into a thin pool with chunk size 128KiB
and convert "vg00/lv1" into a thin volume using this pool. Original "vg00/lv1"
is used as an external read-only origin, where all writes to such volume
are stored in the "vg00/lvpool".
.sp
.B lvconvert \-\-thinpool vg00/lvpool -c 128 -T lv1
Convert the logical volume "vg00/origin" into a thin volume from the thin pool
"vg00/lvpool". This thin volume will use "vg00/origin" as an external origin
volume for unprovisioned areas in this volume.
For the read-only external origin use the new name "vg00/external".
.sp
.B lvconvert \-\-thinpool vg00/lvpool \-\-originname external -T vg00/origin
.SH SEE ALSO
.BR lvm (8),
.BR vgcreate (8),

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@ -69,6 +69,7 @@ arg(dataalignment_ARG, '\0', "dataalignment", size_kb_arg, 0)
arg(dataalignmentoffset_ARG, '\0', "dataalignmentoffset", size_kb_arg, 0)
arg(virtualoriginsize_ARG, '\0', "virtualoriginsize", size_mb_arg, 0)
arg(noudevsync_ARG, '\0', "noudevsync", NULL, 0)
arg(originname_ARG, '\0', "originname", string_arg, 0)
arg(poll_ARG, '\0', "poll", yes_no_arg, 0)
arg(poolmetadata_ARG, '\0', "poolmetadata", string_arg, 0)
arg(poolmetadatasize_ARG, '\0', "poolmetadatasize", size_mb_arg, 0)

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@ -151,6 +151,8 @@ xx(lvconvert,
"\t [--poolmetadatasize size]\n"
"\t [-r|--readahead ReadAheadSectors|auto|none]\n"
"\t [--stripes Stripes [-I|--stripesize StripeSize]]]\n"
"\t[-T|--thin ExternalLogicalVolume[Path]\n"
"\t [--originname NewExternalOriginVolumeName]]\n"
"\t[-Z|--zero {y|n}]\n"
"\t[-d|--debug] [-h|-?|--help] [-v|--verbose]\n",
@ -158,7 +160,8 @@ xx(lvconvert,
merge_ARG, mirrorlog_ARG, mirrors_ARG, name_ARG, noudevsync_ARG,
readahead_ARG, regionsize_ARG, repair_ARG, replace_ARG, snapshot_ARG, splitmirrors_ARG,
trackchanges_ARG, type_ARG, stripes_long_ARG, stripesize_ARG, test_ARG,
chunksize_ARG, discards_ARG, poolmetadata_ARG, poolmetadatasize_ARG, thinpool_ARG,
chunksize_ARG, discards_ARG, poolmetadata_ARG, poolmetadatasize_ARG,
originname_ARG, thin_ARG, thinpool_ARG,
use_policies_ARG, yes_ARG, force_ARG, zero_ARG)
xx(lvcreate,

View File

@ -57,6 +57,7 @@ struct lvconvert_params {
struct logical_volume *lv_to_poll;
uint64_t poolmetadata_size;
const char *origin_lv_name;
const char *pool_data_lv_name;
const char *pool_metadata_lv_name;
thin_discards_t discards;
@ -68,6 +69,7 @@ static int _lvconvert_name_params(struct lvconvert_params *lp,
{
char *ptr;
const char *vg_name = NULL;
const char *tmp_str;
if (lp->merge)
return 1;
@ -94,16 +96,35 @@ static int _lvconvert_name_params(struct lvconvert_params *lp,
if (lp->pool_data_lv_name) {
if (*pargc) {
log_error("More then one logical volume name name specified.");
return 0;
}
if (!arg_count(cmd, thin_ARG)) {
log_error("More then one logical volume name specified.");
return 0;
}
} else {
if (arg_count(cmd, thin_ARG)) {
log_error("External thin volume name is missing.");
return 0;
}
if (!lp->vg_name || !validate_name(lp->vg_name)) {
log_error("Please provide a valid volume group name.");
return 0;
if (!lp->vg_name || !validate_name(lp->vg_name)) {
log_error("Please provide a valid volume group name.");
return 0;
}
lp->lv_name = lp->pool_data_lv_name;
return 1;
}
}
if (lp->origin_lv_name) {
/* FIXME: Using generic routine */
if (strchr(lp->origin_lv_name, '/')) {
if (!(lp->vg_name = extract_vgname(cmd, lp->origin_lv_name)))
return_0;
/* Strip VG from origin_lv_name */
if ((tmp_str = strrchr(lp->origin_lv_name, '/')))
lp->origin_lv_name = tmp_str + 1;
}
lp->lv_name = lp->pool_data_lv_name;
return 1; /* Create metadata LV on it's own */
}
if (!*pargc) {
@ -219,6 +240,9 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
return 0;
}
lp->discards = (thin_discards_t) arg_uint_value(cmd, discards_ARG, THIN_DISCARDS_PASSDOWN);
} else if (arg_count(cmd, thin_ARG)) {
log_error("--thin is only valid with --thinpool.");
return 0;
} else if (arg_count(cmd, discards_ARG)) {
log_error("--discards is only valid with --thinpool.");
return 0;
@ -376,6 +400,13 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
lp->pool_data_lv_name = tmp_str + 1;
}
if (arg_count(cmd, originname_ARG)) {
if (!(lp->origin_lv_name = arg_str_value(cmd, originname_ARG, NULL))) {
log_error("--originname is invalid.");
return 0;
}
}
lp->segtype = get_segtype_from_string(cmd, arg_str_value(cmd, type_ARG, "thin-pool"));
if (!lp->segtype)
return_0;
@ -1825,6 +1856,116 @@ out:
return r;
}
/* Swap lvid and LV names */
static int _swap_lv(struct cmd_context *cmd,
struct logical_volume *a, struct logical_volume *b)
{
union lvid lvid;
const char *name;
lvid = a->lvid;
a->lvid = b->lvid;
b->lvid = lvid;
name = a->name;
a->name = b->name;
if (!lv_rename_update(cmd, b, name, 0))
return_0;
return 1;
}
static int _lvconvert_thinpool_external(struct cmd_context *cmd,
struct logical_volume *pool_lv,
struct logical_volume *external_lv,
struct lvconvert_params *lp)
{
struct logical_volume *torigin_lv;
struct volume_group *vg = pool_lv->vg;
struct lvcreate_params lvc = { 0 };
dm_list_init(&lvc.tags);
if (!(lvc.segtype = get_segtype_from_string(cmd, "thin")))
return_0;
lvc.activate = CHANGE_AE;
lvc.alloc = ALLOC_INHERIT;
lvc.lv_name = lp->origin_lv_name;
lvc.major = -1;
lvc.minor = -1;
lvc.permission = LVM_READ;
lvc.pool = pool_lv->name;
lvc.pvh = &vg->pvs;
lvc.read_ahead = DM_READ_AHEAD_AUTO;
lvc.stripes = 1;
lvc.vg_name = vg->name;
lvc.voriginextents = external_lv->le_count;
lvc.voriginsize = external_lv->size;
/* New thin LV needs to be created (all messages sent to pool) */
if (!(torigin_lv = lv_create_single(vg, &lvc)))
return_0;
/* Activate again via -torigin, so this active LV is not needed */
if (!deactivate_lv(cmd, torigin_lv)) {
log_error("Aborting. Unable to deactivate new LV. "
"Manual intervention required.");
return 0;
}
/*
* Crashing till this point will leave plain thin volume
* which could be easily removed by the user after i.e. power-off
*/
if (!_swap_lv(cmd, torigin_lv, external_lv)) {
stack;
goto revert_new_lv;
}
/* Preserve read-write status of original LV here */
torigin_lv->status |= (external_lv->status & LVM_WRITE);
if (!attach_thin_external_origin(first_seg(torigin_lv), external_lv)) {
stack;
goto revert_new_lv;
}
if (!_reload_lv(cmd, vg, torigin_lv)) {
stack;
goto deactivate_and_revert_new_lv;
}
log_print_unless_silent("Converted %s/%s to thin external origin.",
vg->name, external_lv->name);
return 1;
deactivate_and_revert_new_lv:
if (!_swap_lv(cmd, torigin_lv, external_lv))
stack;
if (!deactivate_lv(cmd, torigin_lv)) {
log_error("Unable to deactivate failed new LV. "
"Manual intervention required.");
return 0;
}
if (!detach_thin_external_origin(first_seg(torigin_lv)))
return_0;
revert_new_lv:
/* FIXME Better to revert to backup of metadata? */
if (!lv_remove(torigin_lv) || !vg_write(vg) || !vg_commit(vg))
log_error("Manual intervention may be required to remove "
"abandoned LV(s) before retrying.");
else
backup(vg);
return 0;
}
/*
* Thin lvconvert version which
* rename metadata
@ -1843,6 +1984,7 @@ static int _lvconvert_thinpool(struct cmd_context *cmd,
struct logical_volume *data_lv;
struct logical_volume *metadata_lv;
struct logical_volume *pool_metadata_lv;
struct logical_volume *external_lv = NULL;
if (!lv_is_visible(pool_lv)) {
log_error("Can't convert internal LV %s/%s.",
@ -1850,6 +1992,19 @@ static int _lvconvert_thinpool(struct cmd_context *cmd,
return 0;
}
if (arg_count(cmd, thin_ARG)) {
external_lv = pool_lv;
if (!(pool_lv = find_lv(external_lv->vg, lp->pool_data_lv_name))) {
log_error("Can't find pool LV %s/%s.",
external_lv->vg->name, lp->pool_data_lv_name);
return 0;
}
if (lv_is_thin_pool(pool_lv)) {
r = 1; /* Already existing thin pool */
goto out;
}
}
if (lv_is_thin_type(pool_lv) && !lp->pool_metadata_lv_name) {
log_error("Can't use thin logical volume %s/%s for thin pool data.",
pool_lv->vg->name, pool_lv->name);
@ -2064,7 +2219,12 @@ mda_write:
r = 1;
out:
if (r && external_lv &&
!(r = _lvconvert_thinpool_external(cmd, pool_lv, external_lv, lp)))
stack;
backup(pool_lv->vg);
return r;
}