]> sourceware.org Git - lvm2.git/commitdiff
Add ability to create mirrored logs for mirror LVs.
authorJonathan Earl Brassow <jbrassow@redhat.com>
Fri, 26 Mar 2010 22:15:43 +0000 (22:15 +0000)
committerJonathan Earl Brassow <jbrassow@redhat.com>
Fri, 26 Mar 2010 22:15:43 +0000 (22:15 +0000)
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.

16 files changed:
WHATS_NEW
daemons/dmeventd/plugins/mirror/dmeventd_mirror.c
lib/activate/activate.c
lib/metadata/lv_alloc.h
lib/metadata/lv_manip.c
lib/metadata/mirror.c
man/lvconvert.8.in
man/lvcreate.8.in
test/t-lvconvert-repair-policy.sh
test/t-lvconvert-repair.sh
test/t-lvcreate-operation.sh
test/t-mirror-lvconvert.sh
test/t-snapshots-of-mirrors.sh
tools/commands.h
tools/lvconvert.c
tools/lvcreate.c

index 32748f8909ccb05ff5a2187a34a5b447eadde323..bf6c8e69daf1640ef2474c612ddb12efda4975df 100644 (file)
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -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.
index c715e75723a39aec60ff063e3b93232d8a9a7bcd..e5d81ee2093cd7866cf30325f46beabb5c553b50 100644 (file)
@@ -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 */
index eb94ac0110aad65e5e0eec2bfe55a8c65a9e09bd..1844cea793a4f1705fb8cd917a4aa79114b35730 100644 (file)
@@ -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);
 
index ac4053997838bacb8076538d34b60c7b6e42f921..994da612a4a18ac0cbc1fd3a20fe420e9f027502 100644 (file)
@@ -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);
 
index 613175d405910c1cd070d4cf76cd5050325dd3b7..97df5a710a5cd93c44f0a95c6db27e3f647496ca 100644 (file)
@@ -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,
index fe563fc33c77a1b9ae4ee9f7037431e3c5601aec..97b498914806d4f60b4e267dd3e571a41296de2a 100644 (file)
@@ -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;
index d595dc2774230e0e7a4f668afef0d5b8f19e4327..45ea2c6aa372ca685f9420d6b34f9ccee57b8144 100644 (file)
@@ -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".
index 56df7226d3a854e913eba07faeb5aeefe06ac5d7..3c36b9721073ee7a36d3182b0a474b5ce8c73724 100644 (file)
@@ -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.
 
index 046f3dcdd6a112d46cfdf471ba2928cb2aed1286..96305ff4dd16028a09d18b36e8cda909e018ad39 100644 (file)
 
 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
index db26b3f49ca9ebca42765d44329754cf126d4da6..796833b6f1c1f5753e6e0c1e666a400fa8ebd879 100644 (file)
@@ -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
index e76f29446b326aec9be954d2c3b5dc6140cd210b..15cd99554f1656844d5e9230d5dad731290358ce 100644 (file)
@@ -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
index 02dfdfeeff5db350cd2c9c0b098aee8b2eff3022..016da4d87eb717bd9ffeea1bb875368b82df743e 100755 (executable)
@@ -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
 
index 86a28c81d858686f7469ee45f4dbc2e5b8d16220..7ee8249b85ed3a965637286cd36da117eac68f3c 100644 (file)
@@ -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
index 58d6d7b9fc98b739309793a2ca9576ec8841f577..9b611de20277cfea097cf478885f1b4a3d93ceff 100644 (file)
@@ -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"
index 1f78a77ee5f758596d4c7692737fa70ee1158862..7ce31356537b16d459d666edc4109829cc4a949f 100644 (file)
@@ -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))
+                                   region_size, operable_pvs, lp->alloc))
                        return_0;
-       } else if (!_using_corelog(lv) && !log_count) {
-               if (!remove_mirror_log(cmd, original_lv,
-                                      lp->pv_count ? lp->pvh : NULL))
+               return 1;
+       }
+
+       /* Remove an existing log completely */
+       if (!log_count) {
+               if (!remove_mirror_log(cmd, original_lv, operable_pvs))
                        return_0;
+               return 1;
        }
-       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;
-
-       seg = first_seg(lv);
-       existing_mirrors = lv_mirror_count(lv);
+       const char *mirrorlog;
+       *old_mimage_count = lv_mirror_count(lv);
+       *old_log_count = _get_log_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;
        }
 
-       /*
-        * 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.
-        */
-       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;
+       /* 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 (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;
+       /*
+        * 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 (*old_mimage_count != *new_mimage_count)
+               log_verbose("Adjusting mirror image count of %s", lv->name);
 
-               mirrorlog = arg_str_value(cmd, mirrorlog_ARG,
-                                         !log_count ? "core" : DEFAULT_MIRRORLOG);
+       /*
+        * 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 (strcmp("core", mirrorlog) && !log_count) {
-                       log_error("--mirrorlog disk and --corelog "
-                                 "are incompatible");
-                       return 0;
-               }
+       if (arg_count(cmd, corelog_ARG))
+               *new_log_count = 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;
-               }
+       mirrorlog = arg_str_value(cmd, mirrorlog_ARG,
+                                 !*new_log_count ? "core" : DEFAULT_MIRRORLOG);
 
-               log_verbose("Setting logging type to %s", 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;
        }
 
+       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;
        }
 
-       /*
-        * Downconversion.
-        */
-       if (lp->mirrors < existing_mirrors) {
-               /* Reduce number of mirrors */
-               if (repair || lp->pv_count)
-                       remove_pvs = lp->pvh;
+       region_size = adjusted_mirror_region_size(lv->vg->extent_size,
+                                                 lv->le_count,
+                                                 lp->region_size);
 
-               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 (!operable_pvs)
+               operable_pvs = lp->pvh;
 
-               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
-                */
+       seg = first_seg(lv);
 
+       /*
+        * Up-convert 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;
+       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 (replace_mirrors)
-                       lp->mirrors += failed_mirrors;
-               failed_mirrors = 0;
-               existing_mirrors = lv_mirror_count(lv);
+       }
+       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)) {
                /*
-                * Ignore failure in upconversion if this is a policy-driven
-                * action. If we got this far, only unexpected failures are
-                * reported.
+                * If we are up-converting the log from linear to
+                * mirrored, then we must use '_lvconvert_mirrors_aux'
                 */
-               if (arg_count(cmd, use_policies_ARG))
-                       failure_code = 1;
-               /* Now replace missing devices. */
-               if (replace_log || replace_mirrors)
-                       goto restart;
+               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,
index 10b5aa5910fc196aafddfe2557feb25a1c0e372e..a2480cdd1fa3d867a9193c6f057305ad4e7e78bf 100644 (file)
@@ -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;
This page took 0.081163 seconds and 5 git commands to generate.