mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
Add ability to create mirrored logs for mirror LVs.
This check-in enables the 'mirrored' log type. It can be specified by using the '--mirrorlog' option as follows: #> lvcreate -m1 --mirrorlog mirrored -L 5G -n lv vg I've also included a couple updates to the testsuite. These updates include tests for the new log type, and some fixes to some of the *lvconvert* tests.
This commit is contained in:
parent
217cb1aa84
commit
7a369d3704
@ -1,5 +1,6 @@
|
||||
Version 2.02.63 -
|
||||
================================
|
||||
Add ability to create mirrored logs for mirror LVs.
|
||||
Use a real socket for singlenode clvmd to fix clvmd's high cpu load.
|
||||
Fix clvmd cluster propagation of dmeventd monitoring mode.
|
||||
Allow ALLOC_ANYWHERE to split contiguous areas.
|
||||
|
@ -148,6 +148,11 @@ static int _remove_failed_devices(const char *device)
|
||||
return -ENOMEM; /* FIXME Replace with generic error return - reason for failure has already got logged */
|
||||
}
|
||||
|
||||
/* strip off the mirror component designations */
|
||||
layer = strstr(lv, "_mlog");
|
||||
if (layer)
|
||||
*layer = '\0';
|
||||
|
||||
/* FIXME Is any sanity-checking required on %s? */
|
||||
if (CMD_SIZE <= snprintf(cmd_str, CMD_SIZE, "lvconvert --config devices{ignore_suspended_devices=1} --repair --use-policies %s/%s", vg, lv)) {
|
||||
/* this error should be caught above, but doesn't hurt to check again */
|
||||
|
@ -703,6 +703,7 @@ int monitor_dev_for_events(struct cmd_context *cmd,
|
||||
int r = 1;
|
||||
struct dm_list *tmp, *snh, *snht;
|
||||
struct lv_segment *seg;
|
||||
struct lv_segment *log_seg;
|
||||
int (*monitor_fn) (struct lv_segment *s, int e);
|
||||
uint32_t s;
|
||||
|
||||
@ -738,6 +739,16 @@ int monitor_dev_for_events(struct cmd_context *cmd,
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the volume is mirrored and its log is also mirrored, monitor
|
||||
* the log volume as well.
|
||||
*/
|
||||
if ((seg = first_seg(lv)) != NULL && seg->log_lv != NULL &&
|
||||
(log_seg = first_seg(seg->log_lv)) != NULL &&
|
||||
seg_is_mirrored(log_seg))
|
||||
if (!monitor_dev_for_events(cmd, seg->log_lv, monitor))
|
||||
r = 0;
|
||||
|
||||
dm_list_iterate(tmp, &lv->segments) {
|
||||
seg = dm_list_item(tmp, struct lv_segment);
|
||||
|
||||
|
@ -68,7 +68,8 @@ int lv_add_mirror_lvs(struct logical_volume *lv,
|
||||
uint32_t num_extra_areas,
|
||||
uint64_t status, uint32_t region_size);
|
||||
|
||||
int lv_add_log_segment(struct alloc_handle *ah, struct logical_volume *log_lv);
|
||||
int lv_add_log_segment(struct alloc_handle *ah, uint32_t first_area,
|
||||
struct logical_volume *log_lv, uint64_t status);
|
||||
int lv_add_virtual_segment(struct logical_volume *lv, uint64_t status,
|
||||
uint32_t extents, const struct segment_type *segtype);
|
||||
|
||||
|
@ -1635,14 +1635,32 @@ int lv_add_mirror_lvs(struct logical_volume *lv,
|
||||
|
||||
/*
|
||||
* Turn an empty LV into a mirror log.
|
||||
*
|
||||
* FIXME: Mirrored logs are built inefficiently.
|
||||
* A mirrored log currently uses the same layout that a mirror
|
||||
* LV uses. The mirror layer sits on top of AREA_LVs which form the
|
||||
* legs, rather on AREA_PVs. This is done to allow re-use of the
|
||||
* various mirror functions to also handle the mirrored LV that makes
|
||||
* up the log.
|
||||
*
|
||||
* If we used AREA_PVs under the mirror layer of a log, we could
|
||||
* assemble it all at once by calling 'lv_add_segment' with the
|
||||
* appropriate segtype (mirror/stripe), like this:
|
||||
* lv_add_segment(ah, ah->area_count, ah->log_area_count,
|
||||
* log_lv, segtype, 0, MIRROR_LOG, 0);
|
||||
*
|
||||
* For now, we use the same mechanism to build a mirrored log as we
|
||||
* do for building a mirrored LV: 1) create initial LV, 2) add a
|
||||
* mirror layer, and 3) add the remaining copy LVs
|
||||
*/
|
||||
int lv_add_log_segment(struct alloc_handle *ah, struct logical_volume *log_lv)
|
||||
int lv_add_log_segment(struct alloc_handle *ah, uint32_t first_area,
|
||||
struct logical_volume *log_lv, uint64_t status)
|
||||
{
|
||||
const char *segtype_name = ah->log_area_count > 1 ? "mirror" : "striped";
|
||||
|
||||
return lv_add_segment(ah, ah->area_count, ah->log_area_count, log_lv,
|
||||
get_segtype_from_string(log_lv->vg->cmd, segtype_name),
|
||||
0, MIRROR_LOG, 0);
|
||||
return lv_add_segment(ah, ah->area_count + first_area, 1, log_lv,
|
||||
get_segtype_from_string(log_lv->vg->cmd,
|
||||
"striped"),
|
||||
0, status, 0);
|
||||
}
|
||||
|
||||
static int _lv_extend_mirror(struct alloc_handle *ah,
|
||||
|
@ -709,8 +709,8 @@ static int _split_mirror_images(struct logical_volume *lv,
|
||||
*
|
||||
* Arguments:
|
||||
* num_removed: the requested (maximum) number of mirrors to be removed
|
||||
* removable_pvs: if not NULL, only mirrors using PVs in this list
|
||||
* will be removed
|
||||
* removable_pvs: if not NULL and list not empty, only mirrors using PVs
|
||||
* in this list will be removed
|
||||
* remove_log: if non-zero, log_lv will be removed
|
||||
* (even if it's 0, log_lv will be removed if there is no
|
||||
* mirror remaining after the removal)
|
||||
@ -737,6 +737,7 @@ static int _remove_mirror_images(struct logical_volume *lv,
|
||||
{
|
||||
uint32_t m;
|
||||
uint32_t s;
|
||||
int removable_pvs_specified;
|
||||
struct logical_volume *sub_lv;
|
||||
struct logical_volume *detached_log_lv = NULL;
|
||||
struct logical_volume *temp_layer_lv = NULL;
|
||||
@ -746,6 +747,9 @@ static int _remove_mirror_images(struct logical_volume *lv,
|
||||
struct lv_list *lvl;
|
||||
struct dm_list tmp_orphan_lvs;
|
||||
|
||||
removable_pvs_specified = (removable_pvs &&
|
||||
!dm_list_empty(removable_pvs)) ? 1 : 0;
|
||||
|
||||
if (removed)
|
||||
*removed = 0;
|
||||
|
||||
@ -755,13 +759,13 @@ static int _remove_mirror_images(struct logical_volume *lv,
|
||||
remove_log ? " and no log volume" : "");
|
||||
|
||||
if (collapse &&
|
||||
(removable_pvs || (old_area_count - num_removed != 1))) {
|
||||
(removable_pvs_specified || (old_area_count - num_removed != 1))) {
|
||||
log_error("Incompatible parameters to _remove_mirror_images");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Move removable_pvs to end of array */
|
||||
if (removable_pvs) {
|
||||
if (removable_pvs_specified) {
|
||||
for (s = 0; s < mirrored_seg->area_count &&
|
||||
old_area_count - new_area_count < num_removed; s++) {
|
||||
sub_lv = seg_lv(mirrored_seg, s);
|
||||
@ -1171,7 +1175,8 @@ int reconfigure_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirr
|
||||
static int _create_mimage_lvs(struct alloc_handle *ah,
|
||||
uint32_t num_mirrors,
|
||||
struct logical_volume *lv,
|
||||
struct logical_volume **img_lvs)
|
||||
struct logical_volume **img_lvs,
|
||||
int log)
|
||||
{
|
||||
uint32_t m;
|
||||
char *img_name;
|
||||
@ -1199,14 +1204,23 @@ static int _create_mimage_lvs(struct alloc_handle *ah,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_add_segment(ah, m, 1, img_lvs[m],
|
||||
get_segtype_from_string(lv->vg->cmd,
|
||||
"striped"),
|
||||
0, 0, 0)) {
|
||||
log_error("Aborting. Failed to add mirror image segment "
|
||||
"to %s. Remove new LV and retry.",
|
||||
img_lvs[m]->name);
|
||||
return 0;
|
||||
if (log) {
|
||||
if (!lv_add_log_segment(ah, m + 1, img_lvs[m], 0)) {
|
||||
log_error("Aborting. Failed to add mirror image segment "
|
||||
"to %s. Remove new LV and retry.",
|
||||
img_lvs[m]->name);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (!lv_add_segment(ah, m, 1, img_lvs[m],
|
||||
get_segtype_from_string(lv->vg->cmd,
|
||||
"striped"),
|
||||
0, 0, 0)) {
|
||||
log_error("Aborting. Failed to add mirror image segment "
|
||||
"to %s. Remove new LV and retry.",
|
||||
img_lvs[m]->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1541,17 +1555,57 @@ static struct logical_volume *_create_mirror_log(struct logical_volume *lv,
|
||||
alloc, lv->vg)))
|
||||
return_NULL;
|
||||
|
||||
if (!lv_add_log_segment(ah, log_lv))
|
||||
if (!lv_add_log_segment(ah, 0, log_lv, MIRROR_LOG))
|
||||
return_NULL;
|
||||
|
||||
return log_lv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns: 1 on success, 0 on error
|
||||
*/
|
||||
static int _form_mirror(struct cmd_context *cmd, struct alloc_handle *ah,
|
||||
struct logical_volume *lv,
|
||||
uint32_t mirrors, uint32_t region_size, int log)
|
||||
{
|
||||
struct logical_volume **img_lvs;
|
||||
|
||||
/*
|
||||
* insert a mirror layer
|
||||
*/
|
||||
if (dm_list_size(&lv->segments) != 1 ||
|
||||
seg_type(first_seg(lv), 0) != AREA_LV)
|
||||
if (!insert_layer_for_lv(cmd, lv, 0, "_mimage_%d"))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* create mirror image LVs
|
||||
*/
|
||||
if (!(img_lvs = alloca(sizeof(*img_lvs) * mirrors))) {
|
||||
log_error("img_lvs allocation failed. "
|
||||
"Remove new LV and retry.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_create_mimage_lvs(ah, mirrors, lv, img_lvs, log))
|
||||
return 0;
|
||||
|
||||
if (!lv_add_mirror_lvs(lv, img_lvs, mirrors,
|
||||
MIRROR_IMAGE | (lv->status & LOCKED),
|
||||
region_size)) {
|
||||
log_error("Aborting. Failed to add mirror segment. "
|
||||
"Remove new LV and retry.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct logical_volume *_set_up_mirror_log(struct cmd_context *cmd,
|
||||
struct alloc_handle *ah,
|
||||
struct logical_volume *lv,
|
||||
uint32_t log_count,
|
||||
uint32_t region_size __attribute((unused)),
|
||||
uint32_t region_size,
|
||||
alloc_policy_t alloc,
|
||||
int in_sync)
|
||||
{
|
||||
@ -1563,11 +1617,6 @@ static struct logical_volume *_set_up_mirror_log(struct cmd_context *cmd,
|
||||
|
||||
init_mirror_in_sync(in_sync);
|
||||
|
||||
if (log_count != 1) {
|
||||
log_error("log_count != 1 is not supported.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Mirror log name is lv_name + suffix, determined as the following:
|
||||
* 1. suffix is:
|
||||
* o "_mlog" for the original mirror LV.
|
||||
@ -1600,6 +1649,12 @@ static struct logical_volume *_set_up_mirror_log(struct cmd_context *cmd,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((log_count > 1) &&
|
||||
!_form_mirror(cmd, ah, log_lv, log_count-1, region_size, 1)) {
|
||||
log_error("Failed to form mirrored log.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!_init_mirror_log(cmd, log_lv, in_sync, &lv->tags, 1)) {
|
||||
log_error("Failed to initialise mirror log.");
|
||||
return NULL;
|
||||
@ -1630,12 +1685,6 @@ int add_mirror_log(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
struct lvinfo info;
|
||||
int r = 0;
|
||||
|
||||
/* Unimplemented features */
|
||||
if (log_count > 1) {
|
||||
log_error("log_count > 1 is not supported");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dm_list_size(&lv->segments) != 1) {
|
||||
log_error("Multiple-segment mirror is not supported");
|
||||
return 0;
|
||||
@ -1707,7 +1756,6 @@ int add_mirror_images(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
struct alloc_handle *ah;
|
||||
const struct segment_type *segtype;
|
||||
struct dm_list *parallel_areas;
|
||||
struct logical_volume **img_lvs;
|
||||
struct logical_volume *log_lv = NULL;
|
||||
|
||||
if (stripes > 1) {
|
||||
@ -1747,33 +1795,8 @@ int add_mirror_images(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
So from here on, if failure occurs, the log must be explicitly
|
||||
removed and the updated vg metadata should be committed. */
|
||||
|
||||
/*
|
||||
* insert a mirror layer
|
||||
*/
|
||||
if (dm_list_size(&lv->segments) != 1 ||
|
||||
seg_type(first_seg(lv), 0) != AREA_LV)
|
||||
if (!insert_layer_for_lv(cmd, lv, 0, "_mimage_%d"))
|
||||
goto out_remove_log;
|
||||
|
||||
/*
|
||||
* create mirror image LVs
|
||||
*/
|
||||
if (!(img_lvs = alloca(sizeof(*img_lvs) * mirrors))) {
|
||||
log_error("img_lvs allocation failed. "
|
||||
"Remove new LV and retry.");
|
||||
if (!_form_mirror(cmd, ah, lv, mirrors, region_size, 0))
|
||||
goto out_remove_log;
|
||||
}
|
||||
|
||||
if (!_create_mimage_lvs(ah, mirrors, lv, img_lvs))
|
||||
goto out_remove_log;
|
||||
|
||||
if (!lv_add_mirror_lvs(lv, img_lvs, mirrors,
|
||||
MIRROR_IMAGE | (lv->status & LOCKED),
|
||||
region_size)) {
|
||||
log_error("Aborting. Failed to add mirror segment. "
|
||||
"Remove new LV and retry.");
|
||||
goto out_remove_images;
|
||||
}
|
||||
|
||||
if (log_count && !attach_mirror_log(first_seg(lv), log_lv))
|
||||
stack;
|
||||
|
@ -3,7 +3,7 @@
|
||||
lvconvert \- convert a logical volume from linear to mirror or snapshot
|
||||
.SH SYNOPSIS
|
||||
.B lvconvert
|
||||
\-m|\-\-mirrors Mirrors [\-\-mirrorlog {disk|core}] [\-\-corelog] [\-R|\-\-regionsize MirrorLogRegionSize]
|
||||
\-m|\-\-mirrors Mirrors [\-\-mirrorlog {disk|core|mirrored}] [\-\-corelog] [\-R|\-\-regionsize MirrorLogRegionSize]
|
||||
[\-A|\-\-alloc AllocationPolicy]
|
||||
[\-b|\-\-background] [\-f|\-\-force] [\-i|\-\-interval Seconds]
|
||||
[\-h|\-?|\-\-help]
|
||||
@ -83,6 +83,7 @@ from the data being mirrored.
|
||||
Core may be useful for short-lived mirrors: It means the mirror is
|
||||
regenerated by copying the data from the first device again every
|
||||
time the device is activated - perhaps, for example, after every reboot.
|
||||
Using "mirrored" will create a persistent log that is itself mirrored.
|
||||
.TP
|
||||
.I \-\-corelog
|
||||
The optional argument "--corelog" is the same as specifying "--mirrorlog core".
|
||||
|
@ -13,7 +13,7 @@ lvcreate \- create a logical volume in an existing volume group
|
||||
{\-l|\-\-extents LogicalExtentsNumber[%{VG|PVS|FREE}] |
|
||||
\-L|\-\-size LogicalVolumeSize[bBsSkKmMgGtTpPeE]}
|
||||
[\-M|\-\-persistent y|n] [\-\-minor minor]
|
||||
[\-m|\-\-mirrors Mirrors [\-\-nosync] [\-\-mirrorlog {disk|core}] [\-\-corelog]
|
||||
[\-m|\-\-mirrors Mirrors [\-\-nosync] [\-\-mirrorlog {disk|core|mirrored}] [\-\-corelog]
|
||||
[\-R|\-\-regionsize MirrorLogRegionSize]]
|
||||
[\-n|\-\-name LogicalVolumeName]
|
||||
[\-p|\-\-permission r|rw] [\-r|\-\-readahead ReadAheadSectors|auto|none]
|
||||
@ -113,9 +113,10 @@ intensive initial sync of an empty device.
|
||||
The optional argument --mirrorlog specifies the type of log to be used.
|
||||
The default is disk, which is persistent and requires
|
||||
a small amount of storage space, usually on a separate device from the
|
||||
data being mirrored. Using core means the mirror is regenerated
|
||||
data being mirrored. Using core means the mirror is regenerated
|
||||
by copying the data from the first device again each time the
|
||||
device is activated, for example, after every reboot.
|
||||
device is activated, for example, after every reboot. Using "mirrored"
|
||||
will create a persistent log that is itself mirrored.
|
||||
|
||||
The optional argument --corelog is equivalent to --mirrorlog core.
|
||||
|
||||
|
@ -13,12 +13,15 @@
|
||||
|
||||
prepare_vg 4
|
||||
|
||||
# Clean-up and create a 2-way mirror, where the the
|
||||
# leg devices are always on $dev[12] and the log
|
||||
# is always on $dev3. ($dev4 behaves as a spare)
|
||||
cleanup() {
|
||||
vgreduce --removemissing $vg
|
||||
for d in "$@"; do enable_dev $d; done
|
||||
for d in "$@"; do vgextend $vg $d; done
|
||||
lvremove -ff $vg/mirror
|
||||
lvcreate -m 1 -L 1 -n mirror $vg
|
||||
lvcreate -m 1 -l 2 -n mirror $vg $dev1 $dev2 $dev3:0
|
||||
}
|
||||
|
||||
repair() {
|
||||
@ -28,34 +31,42 @@ repair() {
|
||||
lvcreate -m 1 -L 1 -n mirror $vg
|
||||
lvchange -a n $vg/mirror
|
||||
|
||||
# Fail a leg of a mirror.
|
||||
# Expected result: linear
|
||||
disable_dev $dev1
|
||||
lvchange --partial -a y $vg/mirror
|
||||
repair 'activation { mirror_image_fault_policy = "remove" }'
|
||||
lvs | grep -- -wi-a- # non-mirror
|
||||
cleanup $dev1
|
||||
|
||||
# Fail a leg of a mirror.
|
||||
# Expected result: Mirror (leg replaced)
|
||||
disable_dev $dev1
|
||||
repair 'activation { mirror_image_fault_policy = "replace" }'
|
||||
lvs | grep -- mwi-a- # mirror
|
||||
lvs | grep mirror_mlog
|
||||
cleanup $dev1
|
||||
|
||||
# Fail a leg of a mirror (use old name for policy specification)
|
||||
# Expected result: Mirror (leg replaced)
|
||||
disable_dev $dev1
|
||||
repair 'activation { mirror_device_fault_policy = "replace" }'
|
||||
lvs | grep -- mwi-a- # mirror
|
||||
lvs | grep mirror_mlog
|
||||
cleanup $dev1
|
||||
|
||||
# Fail a leg of a mirror w/ no available spare
|
||||
# Expected result: linear
|
||||
disable_dev $dev2 $dev4
|
||||
# no room for repair, downconversion should happen
|
||||
repair 'activation { mirror_image_fault_policy = "replace" }'
|
||||
lvs | grep -- -wi-a-
|
||||
cleanup $dev2 $dev4
|
||||
|
||||
disable_dev $dev2 $dev4
|
||||
# no room for new log, corelog conversion should happen
|
||||
# Fail the log device of a mirror w/ no available spare
|
||||
# Expected result: mirror w/ corelog
|
||||
disable_dev $dev3 $dev4
|
||||
repair 'activation { mirror_image_fault_policy = "replace" }'
|
||||
lvs
|
||||
lvs | grep -- mwi-a-
|
||||
lvs | not grep mirror_mlog
|
||||
cleanup $dev2 $dev4
|
||||
cleanup $dev3 $dev4
|
||||
|
@ -69,5 +69,5 @@ vgextend $vg $dev3
|
||||
lvcreate -m 2 -l 1 -n mirror2 $vg $dev1 $dev2 $dev3 $dev4
|
||||
vgchange -a n $vg
|
||||
pvremove -ff -y $dev4
|
||||
echo 'y' | not lvconvert -y -i 1 --repair $vg/mirror2
|
||||
echo 'y' | lvconvert -y -i 1 --repair $vg/mirror2
|
||||
vgs
|
||||
|
@ -25,9 +25,18 @@ aux prepare_pvs 2
|
||||
aux pvcreate --metadatacopies 0 $dev1
|
||||
aux vgcreate -c n $vg $devs
|
||||
|
||||
#COMM create snapshots of LVs on --metadatacopies 0 PV (bz450651)
|
||||
# ---
|
||||
# Create snapshots of LVs on --metadatacopies 0 PV (bz450651)
|
||||
lvcreate -n$lv1 -l4 $vg $dev1
|
||||
lvcreate -n$lv2 -l4 -s $vg/$lv1
|
||||
#lvremove -f $vg/$lv2
|
||||
cleanup_lvs
|
||||
|
||||
# ---
|
||||
# Create mirror on two devices with mirrored log using --alloc anywhere
|
||||
lvcreate -m 1 -l4 -n $lv1 --mirrorlog mirrored $vg --alloc anywhere $dev1 $dev2
|
||||
cleanup_lvs
|
||||
|
||||
# --
|
||||
# Create mirror on one dev with mirrored log using --alloc anywhere, should fail
|
||||
lvcreate -m 1 -l4 -n $lv1 --mirrorlog mirrored $vg --alloc anywhere $dev1
|
||||
cleanup_lvs
|
||||
|
@ -280,6 +280,38 @@ mimages_are_redundant_ $vg $lv1
|
||||
mirrorlog_is_on_ $vg/$lv1 $dev3
|
||||
check_and_cleanup_lvs_
|
||||
|
||||
# ---
|
||||
# core log to mirrored log
|
||||
|
||||
# change the log type from 'core' to 'mirrored'
|
||||
prepare_lvs_
|
||||
lvcreate -l2 -m1 --mirrorlog core -n $lv1 $vg $dev1 $dev2
|
||||
check_mirror_count_ $vg/$lv1 2
|
||||
not_sh check_mirror_log_ $vg/$lv1
|
||||
lvconvert --mirrorlog mirrored -i1 $vg/$lv1 $dev3 $dev4
|
||||
check_no_tmplvs_ $vg/$lv1
|
||||
check_mirror_log_ $vg/$lv1
|
||||
mimages_are_redundant_ $vg $lv1
|
||||
|
||||
# ---
|
||||
# mirrored log to core log
|
||||
|
||||
# change the log type from 'mirrored' to 'core'
|
||||
lvconvert --mirrorlog core -i1 $vg/$lv1 $dev3 $dev4
|
||||
check_no_tmplvs_ $vg/$lv1
|
||||
not_sh check_mirror_log_ $vg/$lv1
|
||||
mimages_are_redundant_ $vg $lv1
|
||||
check_and_cleanup_lvs_
|
||||
|
||||
# ---
|
||||
# Linear to mirror with mirrored log using --alloc anywhere
|
||||
prepare_lvs_
|
||||
lvcreate -l2 -n $lv1 $vg $dev1
|
||||
lvconvert -m +1 --mirrorlog mirrored $vg/$lv1 $dev1 $dev2 --alloc anywhere
|
||||
mimages_are_redundant_ $vg $lv1
|
||||
check_and_cleanup_lvs_
|
||||
|
||||
|
||||
# ---
|
||||
# check polldaemon restarts
|
||||
|
||||
|
@ -21,11 +21,11 @@ not lvconvert -m2 $vg/lv
|
||||
# Log conversion (disk -> core)
|
||||
lvconvert --mirrorlog core $vg/lv
|
||||
|
||||
# Log conversion (core -> redundant)
|
||||
not lvconvert --mirrorlog redundant $vg/lv
|
||||
# Log conversion (core -> mirrored)
|
||||
lvconvert --mirrorlog mirrored $vg/lv
|
||||
|
||||
# Log conversion (redundant -> core)
|
||||
# lvconvert --mirrorlog core $vg/lv
|
||||
# Log conversion (mirrored -> core)
|
||||
lvconvert --mirrorlog core $vg/lv
|
||||
|
||||
# Log conversion (core -> disk)
|
||||
lvconvert --mirrorlog disk $vg/lv
|
||||
|
@ -96,7 +96,7 @@ xx(lvconvert,
|
||||
"Change logical volume layout",
|
||||
0,
|
||||
"lvconvert "
|
||||
"[-m|--mirrors Mirrors [{--mirrorlog {disk|core}|--corelog}]]\n"
|
||||
"[-m|--mirrors Mirrors [{--mirrorlog {disk|core|mirrored}|--corelog}]]\n"
|
||||
"\t[--repair [--use-policies]]\n"
|
||||
"\t[-R|--regionsize MirrorLogRegionSize]\n"
|
||||
"\t[--alloc AllocationPolicy]\n"
|
||||
@ -156,7 +156,7 @@ xx(lvcreate,
|
||||
"\t{-l|--extents LogicalExtentsNumber[%{VG|PVS|FREE}] |\n"
|
||||
"\t -L|--size LogicalVolumeSize[bBsSkKmMgGtTpPeE]}\n"
|
||||
"\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n"
|
||||
"\t[-m|--mirrors Mirrors [--nosync] [{--mirrorlog {disk|core}|--corelog}]]\n"
|
||||
"\t[-m|--mirrors Mirrors [--nosync] [{--mirrorlog {disk|core|mirrored}|--corelog}]]\n"
|
||||
"\t[-n|--name LogicalVolumeName]\n"
|
||||
"\t[--noudevsync]\n"
|
||||
"\t[-p|--permission {r|rw}]\n"
|
||||
|
@ -647,31 +647,72 @@ static void _lvconvert_mirrors_repair_ask(struct cmd_context *cmd,
|
||||
}
|
||||
}
|
||||
|
||||
static int _using_corelog(struct logical_volume *lv)
|
||||
/*
|
||||
* _get_log_count
|
||||
* @lv: the mirror LV
|
||||
*
|
||||
* Get the number of on-disk copies of the log.
|
||||
* 0 = 'core'
|
||||
* 1 = 'disk'
|
||||
* 2+ = 'mirrored'
|
||||
*/
|
||||
static int _get_log_count(struct logical_volume *lv)
|
||||
{
|
||||
return !first_seg(_original_lv(lv))->log_lv;
|
||||
struct logical_volume *log_lv;
|
||||
|
||||
log_lv = first_seg(_original_lv(lv))->log_lv;
|
||||
if (!log_lv)
|
||||
return 0;
|
||||
|
||||
return lv_mirror_count(log_lv);
|
||||
}
|
||||
|
||||
static int _lv_update_log_type(struct cmd_context *cmd,
|
||||
struct lvconvert_params *lp,
|
||||
struct logical_volume *lv,
|
||||
struct dm_list *operable_pvs,
|
||||
int log_count)
|
||||
{
|
||||
struct logical_volume *original_lv = _original_lv(lv);
|
||||
if (_using_corelog(lv) && log_count) {
|
||||
uint32_t region_size;
|
||||
int old_log_count;
|
||||
struct logical_volume *original_lv;
|
||||
struct logical_volume *log_lv;
|
||||
|
||||
old_log_count = _get_log_count(lv);
|
||||
if (old_log_count == log_count)
|
||||
return 1;
|
||||
|
||||
original_lv = _original_lv(lv);
|
||||
region_size = adjusted_mirror_region_size(lv->vg->extent_size,
|
||||
lv->le_count,
|
||||
lp->region_size);
|
||||
|
||||
/* Add a log where there is none */
|
||||
if (!old_log_count) {
|
||||
if (!add_mirror_log(cmd, original_lv, log_count,
|
||||
adjusted_mirror_region_size(
|
||||
lv->vg->extent_size,
|
||||
lv->le_count,
|
||||
lp->region_size),
|
||||
lp->pvh, lp->alloc))
|
||||
return_0;
|
||||
} else if (!_using_corelog(lv) && !log_count) {
|
||||
if (!remove_mirror_log(cmd, original_lv,
|
||||
lp->pv_count ? lp->pvh : NULL))
|
||||
region_size, operable_pvs, lp->alloc))
|
||||
return_0;
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
|
||||
/* Remove an existing log completely */
|
||||
if (!log_count) {
|
||||
if (!remove_mirror_log(cmd, original_lv, operable_pvs))
|
||||
return_0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
log_lv = first_seg(original_lv)->log_lv;
|
||||
|
||||
/* Adding redundancy to the log */
|
||||
if (old_log_count < log_count) {
|
||||
log_error("Adding log redundancy not supported yet.");
|
||||
log_error("Try converting the log to 'core' first.");
|
||||
return_0;
|
||||
}
|
||||
|
||||
/* Reducing redundancy of the log */
|
||||
return remove_mirror_images(log_lv, log_count, operable_pvs, 1U);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -712,138 +753,134 @@ static void _remove_missing_empty_pv(struct volume_group *vg, struct dm_list *re
|
||||
}
|
||||
}
|
||||
|
||||
static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
struct lvconvert_params *lp)
|
||||
/*
|
||||
* _lvconvert_mirrors_parse_params
|
||||
*
|
||||
* This function performs the following:
|
||||
* 1) Gets the old values of mimage and log counts
|
||||
* 2) Parses the CLI args to find the new desired values
|
||||
* 3) Adjusts 'lp->mirrors' to the appropriate absolute value.
|
||||
* (Remember, 'lp->mirrors' is specified in terms of the number of "copies"
|
||||
* vs. the number of mimages. It can also be a relative value.)
|
||||
* 4) Sets 'lp->need_polling' if collapsing
|
||||
* 5) Validates other mirror params
|
||||
*
|
||||
* Returns: 1 on success, 0 on error
|
||||
*/
|
||||
static int _lvconvert_mirrors_parse_params(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
struct lvconvert_params *lp,
|
||||
uint32_t *old_mimage_count,
|
||||
uint32_t *old_log_count,
|
||||
uint32_t *new_mimage_count,
|
||||
uint32_t *new_log_count)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
uint32_t existing_mirrors;
|
||||
const char *mirrorlog;
|
||||
unsigned log_count = 1;
|
||||
int r = 0;
|
||||
struct logical_volume *log_lv, *layer_lv;
|
||||
int failed_mirrors = 0, failed_log = 0;
|
||||
struct dm_list *old_pvh = NULL, *remove_pvs = NULL, *failed_pvs = NULL;
|
||||
|
||||
int repair = arg_count(cmd, repair_ARG);
|
||||
int replace_log = 1, replace_mirrors = 1;
|
||||
int failure_code = 0;
|
||||
const char *mirrorlog;
|
||||
*old_mimage_count = lv_mirror_count(lv);
|
||||
*old_log_count = _get_log_count(lv);
|
||||
|
||||
seg = first_seg(lv);
|
||||
existing_mirrors = lv_mirror_count(lv);
|
||||
|
||||
/* If called with no argument, try collapsing the resync layers */
|
||||
/*
|
||||
* Collapsing a stack of mirrors:
|
||||
*
|
||||
* If called with no argument, try collapsing the resync layers
|
||||
*/
|
||||
if (!arg_count(cmd, mirrors_ARG) && !arg_count(cmd, mirrorlog_ARG) &&
|
||||
!arg_count(cmd, corelog_ARG) && !arg_count(cmd, regionsize_ARG) &&
|
||||
!arg_count(cmd, splitmirrors_ARG) && !repair) {
|
||||
*new_mimage_count = *old_mimage_count;
|
||||
*new_log_count = *old_log_count;
|
||||
|
||||
if (find_temporary_mirror(lv) || (lv->status & CONVERTING))
|
||||
lp->need_polling = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, mirrors_ARG) && repair) {
|
||||
log_error("You may only use one of --mirrors and --repair.");
|
||||
if ((arg_count(cmd, mirrors_ARG) && repair) ||
|
||||
(arg_count(cmd, mirrorlog_ARG) && repair) ||
|
||||
(arg_count(cmd, corelog_ARG) && repair)) {
|
||||
log_error("--repair cannot be used with --mirrors, --mirrorlog,"
|
||||
" or --corelog");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, mirrorlog_ARG) && arg_count(cmd, corelog_ARG)) {
|
||||
log_error("--mirrorlog and --corelog are incompatible");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust required number of mirrors
|
||||
*
|
||||
* We check mirrors_ARG again to see if it
|
||||
* was supplied. If not, they want the mirror
|
||||
* count to remain the same. They may be changing
|
||||
* the logging type.
|
||||
* Adjusting mimage count?
|
||||
*/
|
||||
if (!arg_count(cmd, mirrors_ARG) && !arg_count(cmd, splitmirrors_ARG))
|
||||
lp->mirrors = existing_mirrors;
|
||||
lp->mirrors = *old_mimage_count;
|
||||
else if (lp->mirrors_sign == SIGN_PLUS)
|
||||
lp->mirrors = existing_mirrors + lp->mirrors;
|
||||
lp->mirrors = *old_mimage_count + lp->mirrors;
|
||||
else if (lp->mirrors_sign == SIGN_MINUS)
|
||||
lp->mirrors = existing_mirrors - lp->mirrors;
|
||||
lp->mirrors = *old_mimage_count - lp->mirrors;
|
||||
else
|
||||
lp->mirrors += 1;
|
||||
|
||||
*new_mimage_count = lp->mirrors;
|
||||
|
||||
/* Too many mimages? */
|
||||
if (lp->mirrors > DEFAULT_MIRROR_MAX_IMAGES) {
|
||||
log_error("Only up to %d images in mirror supported currently.",
|
||||
DEFAULT_MIRROR_MAX_IMAGES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Did the user try to subtract more legs than available? */
|
||||
if (lp->mirrors < 1) {
|
||||
log_error("Logical volume %s only has %" PRIu32 " mirrors.",
|
||||
lv->name, *old_mimage_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are converting from one type of mirror to another, and
|
||||
* the type of log wasn't specified, then let's keep the log type
|
||||
* the same.
|
||||
* FIXME: It would be nice to say what we are adjusting to, but
|
||||
* I really don't know whether to specify the # of copies or mimages.
|
||||
*/
|
||||
if ((existing_mirrors > 1) && (lp->mirrors > 1) &&
|
||||
(lp->mirrors != existing_mirrors) && !(lv->status & CONVERTING) &&
|
||||
!arg_count(cmd, mirrorlog_ARG) && !arg_count(cmd, corelog_ARG)) {
|
||||
log_count = (first_seg(lv)->log_lv) ?
|
||||
lv_mirror_count(first_seg(lv)->log_lv) : 0;
|
||||
if (*old_mimage_count != *new_mimage_count)
|
||||
log_verbose("Adjusting mirror image count of %s", lv->name);
|
||||
|
||||
/*
|
||||
* Adjust log type
|
||||
*
|
||||
* If we are converting from a mirror to another mirror or simply
|
||||
* changing the log type, we start by assuming they want the log
|
||||
* type the same and then parse the given args. OTOH, If we are
|
||||
* converting from linear to mirror, then we start from the default
|
||||
* position that the user would like a 'disk' log.
|
||||
*/
|
||||
*new_log_count = (*old_mimage_count > 1) ? *old_log_count : 1;
|
||||
if (!arg_count(cmd, corelog_ARG) && !arg_count(cmd, mirrorlog_ARG))
|
||||
return 1;
|
||||
|
||||
if (arg_count(cmd, corelog_ARG))
|
||||
*new_log_count = 0;
|
||||
|
||||
mirrorlog = arg_str_value(cmd, mirrorlog_ARG,
|
||||
!*new_log_count ? "core" : DEFAULT_MIRRORLOG);
|
||||
|
||||
if (!strcmp("mirrored", mirrorlog))
|
||||
*new_log_count = 2;
|
||||
else if (!strcmp("disk", mirrorlog))
|
||||
*new_log_count = 1;
|
||||
else if (!strcmp("core", mirrorlog))
|
||||
*new_log_count = 0;
|
||||
else {
|
||||
log_error("Unknown mirrorlog type: %s", mirrorlog);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (repair) {
|
||||
cmd->handles_missing_pvs = 1;
|
||||
cmd->partial_activation = 1;
|
||||
lp->need_polling = 0;
|
||||
if (!(lv->status & PARTIAL_LV)) {
|
||||
log_error("The mirror is consistent. Nothing to repair.");
|
||||
return 1;
|
||||
}
|
||||
if ((failed_mirrors = _failed_mirrors_count(lv)) < 0)
|
||||
return_0;
|
||||
lp->mirrors -= failed_mirrors;
|
||||
log_error("Mirror status: %d of %d images failed.",
|
||||
failed_mirrors, existing_mirrors);
|
||||
old_pvh = lp->pvh;
|
||||
if (!(failed_pvs = _failed_pv_list(lv->vg)))
|
||||
return_0;
|
||||
lp->pvh = lp->failed_pvs = failed_pvs;
|
||||
log_lv = first_seg(lv)->log_lv;
|
||||
if (!log_lv || log_lv->status & PARTIAL_LV) {
|
||||
failed_log = 1;
|
||||
log_count = 0;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Did the user try to subtract more legs than available?
|
||||
*/
|
||||
if (lp->mirrors < 1) {
|
||||
log_error("Logical volume %s only has %" PRIu32 " mirrors.",
|
||||
lv->name, existing_mirrors);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust log type
|
||||
*/
|
||||
if (arg_count(cmd, corelog_ARG))
|
||||
log_count = 0;
|
||||
|
||||
mirrorlog = arg_str_value(cmd, mirrorlog_ARG,
|
||||
!log_count ? "core" : DEFAULT_MIRRORLOG);
|
||||
|
||||
if (strcmp("core", mirrorlog) && !log_count) {
|
||||
log_error("--mirrorlog disk and --corelog "
|
||||
"are incompatible");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp("disk", mirrorlog))
|
||||
log_count = 1;
|
||||
else if (!strcmp("core", mirrorlog))
|
||||
log_count = 0;
|
||||
else {
|
||||
log_error("Unknown mirrorlog type: %s", mirrorlog);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_verbose("Setting logging type to %s", mirrorlog);
|
||||
}
|
||||
log_verbose("Setting logging type to %s", mirrorlog);
|
||||
|
||||
/*
|
||||
* Region size must not change on existing mirrors
|
||||
*/
|
||||
if (arg_count(cmd, regionsize_ARG) && (lv->status & MIRRORED) &&
|
||||
(lp->region_size != seg->region_size)) {
|
||||
(lp->region_size != first_seg(lv)->region_size)) {
|
||||
log_error("Mirror log region size cannot be changed on "
|
||||
"an existing mirror.");
|
||||
return 0;
|
||||
@ -859,48 +896,54 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (repair)
|
||||
_lvconvert_mirrors_repair_ask(cmd, failed_log, failed_mirrors,
|
||||
&replace_log, &replace_mirrors);
|
||||
return 1;
|
||||
}
|
||||
|
||||
restart:
|
||||
/*
|
||||
* Converting from mirror to linear
|
||||
*/
|
||||
if ((lp->mirrors == 1)) {
|
||||
if (!(lv->status & MIRRORED)) {
|
||||
log_error("Logical volume %s is already not mirrored.",
|
||||
lv->name);
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* _lvconvert_mirrors_aux
|
||||
*
|
||||
* Add/remove mirror images and adjust log type. 'operable_pvs'
|
||||
* are the set of PVs open to removal or allocation - depending
|
||||
* on the operation being performed.
|
||||
*
|
||||
* If 'allocation_failures_ok' is set, and there is a failure to
|
||||
* convert due to space, success will be returned.
|
||||
*/
|
||||
static int _lvconvert_mirrors_aux(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
struct lvconvert_params *lp,
|
||||
struct dm_list *operable_pvs,
|
||||
uint32_t new_mimage_count,
|
||||
uint32_t new_log_count,
|
||||
int allocation_failures_ok)
|
||||
{
|
||||
uint32_t region_size;
|
||||
struct dm_list *tmp;
|
||||
struct lv_segment *seg;
|
||||
struct logical_volume *layer_lv;
|
||||
uint32_t old_mimage_count = lv_mirror_count(lv);
|
||||
uint32_t old_log_count = _get_log_count(lv);
|
||||
int failure_code = (allocation_failures_ok) ? 1 : 0;
|
||||
|
||||
if ((lp->mirrors == 1) && !(lv->status & MIRRORED)) {
|
||||
log_error("Logical volume %s is already not mirrored.",
|
||||
lv->name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
region_size = adjusted_mirror_region_size(lv->vg->extent_size,
|
||||
lv->le_count,
|
||||
lp->region_size);
|
||||
|
||||
if (!operable_pvs)
|
||||
operable_pvs = lp->pvh;
|
||||
|
||||
seg = first_seg(lv);
|
||||
|
||||
/*
|
||||
* Downconversion.
|
||||
* Up-convert from linear to mirror
|
||||
*/
|
||||
if (lp->mirrors < existing_mirrors) {
|
||||
/* Reduce number of mirrors */
|
||||
if (repair || lp->pv_count)
|
||||
remove_pvs = lp->pvh;
|
||||
|
||||
if (lp->keep_mimages) {
|
||||
if (!lv_split_mirror_images(lv, lp->lv_split_name,
|
||||
existing_mirrors - lp->mirrors,
|
||||
remove_pvs))
|
||||
return 0;
|
||||
} else if (!lv_remove_mirrors(cmd, lv, existing_mirrors - lp->mirrors,
|
||||
(!log_count || lp->mirrors == 1) ? 1U : 0U,
|
||||
remove_pvs, 0))
|
||||
return_0;
|
||||
|
||||
if (lp->mirrors > 1 &&
|
||||
!_lv_update_log_type(cmd, lp, lv, log_count))
|
||||
return_0;
|
||||
} else if (!(lv->status & MIRRORED)) {
|
||||
/*
|
||||
* Converting from linear to mirror
|
||||
*/
|
||||
|
||||
if (!(lv->status & MIRRORED)) {
|
||||
/* FIXME Share code with lvcreate */
|
||||
|
||||
/* FIXME Why is this restriction here? Fix it! */
|
||||
@ -916,19 +959,22 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv
|
||||
* currently taken by the mirror? Would make more sense from
|
||||
* user perspective.
|
||||
*/
|
||||
if (!lv_add_mirrors(cmd, lv, lp->mirrors - 1, 1,
|
||||
adjusted_mirror_region_size(
|
||||
lv->vg->extent_size,
|
||||
lv->le_count,
|
||||
lp->region_size),
|
||||
log_count, lp->pvh, lp->alloc,
|
||||
MIRROR_BY_LV)) {
|
||||
if (!lv_add_mirrors(cmd, lv, new_mimage_count - 1, 1,
|
||||
region_size, new_log_count, operable_pvs,
|
||||
lp->alloc, MIRROR_BY_LV)) {
|
||||
stack;
|
||||
return failure_code;
|
||||
}
|
||||
if (lp->wait_completion)
|
||||
lp->need_polling = 1;
|
||||
} else if (lp->mirrors > existing_mirrors || failed_mirrors) {
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Up-convert m-way mirror to n-way mirror
|
||||
*/
|
||||
if (new_mimage_count > old_mimage_count) {
|
||||
if (lv->status & MIRROR_NOTSYNCED) {
|
||||
log_error("Can't add mirror to out-of-sync mirrored "
|
||||
"LV: use lvchange --resync first.");
|
||||
@ -953,23 +999,23 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv
|
||||
* insertion to make the end result consistent with
|
||||
* linear-to-mirror conversion.
|
||||
*/
|
||||
if (!_lv_update_log_type(cmd, lp, lv, log_count)) {
|
||||
if (!_lv_update_log_type(cmd, lp, lv,
|
||||
operable_pvs, new_log_count)) {
|
||||
stack;
|
||||
return failure_code;
|
||||
}
|
||||
|
||||
/* Insert a temporary layer for syncing,
|
||||
* only if the original lv is using disk log. */
|
||||
if (seg->log_lv && !_insert_lvconvert_layer(cmd, lv)) {
|
||||
log_error("Failed to insert resync layer");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: can't have multiple mlogs. force corelog. */
|
||||
if (!lv_add_mirrors(cmd, lv, lp->mirrors - existing_mirrors, 1,
|
||||
adjusted_mirror_region_size(
|
||||
lv->vg->extent_size,
|
||||
lv->le_count,
|
||||
lp->region_size),
|
||||
0U, lp->pvh, lp->alloc,
|
||||
if (!lv_add_mirrors(cmd, lv,
|
||||
new_mimage_count - old_mimage_count, 1,
|
||||
region_size, 0U, operable_pvs, lp->alloc,
|
||||
MIRROR_BY_LV)) {
|
||||
layer_lv = seg_lv(first_seg(lv), 0);
|
||||
if (!remove_layer_from_lv(lv, layer_lv) ||
|
||||
@ -989,24 +1035,45 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv
|
||||
if (seg->log_lv)
|
||||
lv->status |= CONVERTING;
|
||||
lp->need_polling = 1;
|
||||
|
||||
goto out_skip_log_convert;
|
||||
}
|
||||
|
||||
if (lp->mirrors == existing_mirrors) {
|
||||
if (_using_corelog(lv) != !log_count) {
|
||||
if (!_lv_update_log_type(cmd, lp, lv, log_count)) {
|
||||
stack;
|
||||
return failure_code;
|
||||
}
|
||||
} else {
|
||||
log_error("Logical volume %s already has %"
|
||||
PRIu32 " mirror(s).", lv->name,
|
||||
lp->mirrors - 1);
|
||||
if (lv->status & CONVERTING)
|
||||
lp->need_polling = 1;
|
||||
return 1;
|
||||
/*
|
||||
* Down-convert (reduce # of mimages).
|
||||
*/
|
||||
if (new_mimage_count < old_mimage_count) {
|
||||
uint32_t nmc = old_mimage_count - new_mimage_count;
|
||||
uint32_t nlc = (!new_log_count || lp->mirrors == 1) ? 1U : 0U;
|
||||
|
||||
/* FIXME: We did nlc used to be calculated that way? */
|
||||
|
||||
/* Reduce number of mirrors */
|
||||
if (lp->keep_mimages) {
|
||||
if (!lv_split_mirror_images(lv, lp->lv_split_name,
|
||||
nmc, operable_pvs))
|
||||
return 0;
|
||||
} else if (!lv_remove_mirrors(cmd, lv, nmc, nlc,
|
||||
operable_pvs, 0))
|
||||
return_0;
|
||||
|
||||
goto out; /* Just in case someone puts code between */
|
||||
}
|
||||
|
||||
out:
|
||||
/*
|
||||
* Converting the log type
|
||||
*/
|
||||
if (old_log_count != new_log_count) {
|
||||
if (!_lv_update_log_type(cmd, lp, lv,
|
||||
operable_pvs, new_log_count)) {
|
||||
stack;
|
||||
return failure_code;
|
||||
}
|
||||
}
|
||||
|
||||
out_skip_log_convert:
|
||||
|
||||
log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
|
||||
|
||||
if (!vg_write(lv->vg))
|
||||
@ -1031,35 +1098,170 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (failed_log || failed_mirrors) {
|
||||
lp->pvh = old_pvh;
|
||||
if (failed_log && replace_log) {
|
||||
failed_log = 0;
|
||||
log_count = 1;
|
||||
}
|
||||
if (replace_mirrors)
|
||||
lp->mirrors += failed_mirrors;
|
||||
failed_mirrors = 0;
|
||||
existing_mirrors = lv_mirror_count(lv);
|
||||
/*
|
||||
* Ignore failure in upconversion if this is a policy-driven
|
||||
* action. If we got this far, only unexpected failures are
|
||||
* reported.
|
||||
*/
|
||||
if (arg_count(cmd, use_policies_ARG))
|
||||
failure_code = 1;
|
||||
/* Now replace missing devices. */
|
||||
if (replace_log || replace_mirrors)
|
||||
goto restart;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* _lvconvert_mirrors_repair
|
||||
*
|
||||
* This function operates in two phases. First, all of the bad
|
||||
* devices are removed from the mirror. Then, if desired by the
|
||||
* user, the devices are replaced.
|
||||
*
|
||||
* 'old_mimage_count' and 'old_log_count' are there so we know
|
||||
* what to convert to after the removal of devices.
|
||||
*/
|
||||
static int _lvconvert_mirrors_repair(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
struct lvconvert_params *lp,
|
||||
uint32_t old_mimage_count,
|
||||
uint32_t old_log_count)
|
||||
{
|
||||
int failed_log = 0;
|
||||
int failed_mirrors = 0;
|
||||
int replace_log = 0;
|
||||
int replace_mirrors = 0;
|
||||
uint32_t new_log_count;
|
||||
struct dm_list *failed_pvs = NULL;
|
||||
struct logical_volume *log_lv;
|
||||
|
||||
cmd->handles_missing_pvs = 1;
|
||||
cmd->partial_activation = 1;
|
||||
lp->need_polling = 0;
|
||||
|
||||
if (!(lv->status & PARTIAL_LV)) {
|
||||
log_error("%s is consistent. Nothing to repair.", lv->name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Count the failed mimages - negative if 'lv' is not a mirror
|
||||
*/
|
||||
if ((failed_mirrors = _failed_mirrors_count(lv)) < 0)
|
||||
return_0;
|
||||
|
||||
lp->mirrors = old_mimage_count - failed_mirrors;
|
||||
|
||||
if (lp->mirrors != old_mimage_count)
|
||||
log_error("Mirror status: %d of %d images failed.",
|
||||
failed_mirrors, old_mimage_count);
|
||||
|
||||
/*
|
||||
* Count the failed log devices
|
||||
*/
|
||||
new_log_count = old_log_count;
|
||||
log_lv = first_seg(lv)->log_lv;
|
||||
if (log_lv) {
|
||||
new_log_count = lv_mirror_count(log_lv);
|
||||
if (log_lv->status & PARTIAL_LV) {
|
||||
failed_log = 1;
|
||||
if (log_lv->status & MIRRORED)
|
||||
new_log_count -= _failed_mirrors_count(log_lv);
|
||||
else
|
||||
new_log_count = 0;
|
||||
}
|
||||
}
|
||||
if (old_log_count != new_log_count)
|
||||
log_error("Mirror log status: %d of %d images failed%s",
|
||||
old_log_count - new_log_count, old_log_count,
|
||||
(!new_log_count) ? " - switching to core" : "");
|
||||
|
||||
/*
|
||||
* Find out our policies
|
||||
*/
|
||||
_lvconvert_mirrors_repair_ask(cmd, failed_log, failed_mirrors,
|
||||
&replace_log, &replace_mirrors);
|
||||
|
||||
/*
|
||||
* First phase - remove faulty devices
|
||||
*/
|
||||
if (!(failed_pvs = _failed_pv_list(lv->vg)))
|
||||
return_0;
|
||||
|
||||
/*
|
||||
* We must adjust the log first, or the entire mirror
|
||||
* will get stuck during a suspend.
|
||||
*/
|
||||
if (!_lv_update_log_type(cmd, lp, lv, failed_pvs, new_log_count))
|
||||
return 0;
|
||||
|
||||
if (!_lvconvert_mirrors_aux(cmd, lv, lp, failed_pvs,
|
||||
lp->mirrors, new_log_count, 0))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Second phase - replace faulty devices
|
||||
*
|
||||
* FIXME: It would be nice to do this all in one step, but
|
||||
* for simplicity, we replace mimages first and then
|
||||
* work on the log.
|
||||
*/
|
||||
if (replace_mirrors && (old_mimage_count != lp->mirrors)) {
|
||||
lp->mirrors = old_mimage_count;
|
||||
if (!_lvconvert_mirrors_aux(cmd, lv, lp, NULL,
|
||||
old_mimage_count, new_log_count, 1))
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_lv = first_seg(lv)->log_lv;
|
||||
if (replace_log && (old_log_count != new_log_count)) {
|
||||
/*
|
||||
* If we are up-converting the log from linear to
|
||||
* mirrored, then we must use '_lvconvert_mirrors_aux'
|
||||
*/
|
||||
if ((new_log_count == 1) && (old_log_count > 1)) {
|
||||
if (!_lvconvert_mirrors_aux(cmd, log_lv, lp, NULL,
|
||||
old_log_count, 0, 1))
|
||||
return 0;
|
||||
} else if (!_lv_update_log_type(cmd, lp, lv,
|
||||
lp->pvh, new_log_count))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* _lvconvert_mirrors
|
||||
*
|
||||
* Determine what is being done. Are we doing a conversion, repair, or
|
||||
* collapsing a stack? Once determined, call helper functions.
|
||||
*/
|
||||
static int _lvconvert_mirrors(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
struct lvconvert_params *lp)
|
||||
{
|
||||
int repair = arg_count(cmd, repair_ARG);
|
||||
uint32_t old_mimage_count;
|
||||
uint32_t old_log_count;
|
||||
uint32_t new_mimage_count;
|
||||
uint32_t new_log_count;
|
||||
|
||||
/* Adjust mimage and/or log count */
|
||||
if (!_lvconvert_mirrors_parse_params(cmd, lv, lp,
|
||||
&old_mimage_count, &old_log_count,
|
||||
&new_mimage_count, &new_log_count))
|
||||
return 0;
|
||||
|
||||
/* Nothing to do? (Probably finishing collapse.) */
|
||||
if ((old_mimage_count == new_mimage_count) &&
|
||||
(old_log_count == new_log_count) && !repair)
|
||||
return 1;
|
||||
|
||||
if (repair)
|
||||
return _lvconvert_mirrors_repair(cmd, lv, lp,
|
||||
old_mimage_count,
|
||||
old_log_count);
|
||||
|
||||
if (!_lvconvert_mirrors_aux(cmd, lv, lp, NULL,
|
||||
new_mimage_count, new_log_count, 0))
|
||||
return 0;
|
||||
|
||||
if (!lp->need_polling)
|
||||
log_print("Logical volume %s converted.", lv->name);
|
||||
|
||||
r = 1;
|
||||
out:
|
||||
backup(lv->vg);
|
||||
return r;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lvconvert_snapshot(struct cmd_context *cmd,
|
||||
|
@ -337,12 +337,14 @@ static int _read_mirror_params(struct lvcreate_params *lp,
|
||||
mirrorlog = arg_str_value(cmd, mirrorlog_ARG,
|
||||
corelog ? "core" : DEFAULT_MIRRORLOG);
|
||||
|
||||
if (!strcmp("disk", mirrorlog)) {
|
||||
if (corelog) {
|
||||
log_error("--mirrorlog disk and --corelog "
|
||||
"are incompatible");
|
||||
return 0;
|
||||
}
|
||||
if (strcmp("core", mirrorlog) && corelog) {
|
||||
log_error("Please use only one of --mirrorlog or --corelog");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp("mirrored", mirrorlog)) {
|
||||
lp->log_count = 2;
|
||||
} else if (!strcmp("disk", mirrorlog)) {
|
||||
lp->log_count = 1;
|
||||
} else if (!strcmp("core", mirrorlog))
|
||||
lp->log_count = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user