]> sourceware.org Git - lvm2.git/commitdiff
more lvconvert mirror code
authorAlasdair Kergon <agk@redhat.com>
Tue, 29 Nov 2005 18:20:23 +0000 (18:20 +0000)
committerAlasdair Kergon <agk@redhat.com>
Tue, 29 Nov 2005 18:20:23 +0000 (18:20 +0000)
WHATS_NEW
lib/metadata/metadata.h
lib/metadata/mirror.c
tools/commands.h
tools/lvconvert.c
tools/vgreduce.c

index aad71cc996da3f6695b21eb0243bccbecee62291..dcf9c80bfb18d498e3700196ac177374995a90a9 100644 (file)
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,10 @@
 Version 2.02.02
 ====================================
+  Add some activation logic to remove_mirror_images().
+  lvconvert can remove specified PVs from a mirror.
+  lvconvert turns an existing LV into a mirror.
+  Allow signed mirrors arguments.
+  Move create_mirror_log() into toollib.
   Determine parallel PVs to avoid with ALLOC_NORMAL allocation.
   Fix lv_empty.
 
index 0ffde9b1e492e66f8a234c46d2d1e4bc09e66234..3e0a73c5bc5a8a9381895c65a19c9b55216c4129 100644 (file)
@@ -561,8 +561,14 @@ int create_mirror_layers(struct alloc_handle *ah,
                         uint32_t status,
                         uint32_t region_size,
                         struct logical_volume *log_lv);
-int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors);
-int remove_all_mirror_images(struct logical_volume *lv);
+int add_mirror_layers(struct alloc_handle *ah,
+                     uint32_t num_mirrors,
+                     uint32_t existing_mirrors,
+                     struct logical_volume *lv,
+                     struct segment_type *segtype);
+
+int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
+                        struct list *removable_pvs, int remove_log);
 /*
  * Given mirror image or mirror log segment, find corresponding mirror segment 
  */
index b6b5e4e21db340661dd653d3038fefb6ef354301..eeecedc8a5346206b085742ebfb43506c17c3784 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.  
- * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -21,6 +21,7 @@
 #include "activate.h"
 #include "lv_alloc.h"
 #include "lvm-string.h"
+#include "locking.h"   /* FIXME Should not be used in this file */
 
 struct lv_segment *find_mirror_seg(struct lv_segment *seg)
 {
@@ -62,6 +63,9 @@ static void _move_lv_segments(struct logical_volume *lv_to, struct logical_volum
 
        list_init(&lv_from->segments);
 
+       lv_to->le_count = lv_from->le_count;
+       lv_to->size = lv_from->size;
+
        lv_from->le_count = 0;
        lv_from->size = 0;
 }
@@ -69,64 +73,162 @@ static void _move_lv_segments(struct logical_volume *lv_to, struct logical_volum
 /*
  * Reduce mirrored_seg to num_mirrors images.
  */
-int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors)
+int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
+                        struct list *removable_pvs, int remove_log)
 {
        uint32_t m;
-
-       for (m = num_mirrors; m < mirrored_seg->area_count; m++) {
-               if (!lv_remove(seg_lv(mirrored_seg, m))) {
-                       stack;
+       uint32_t s, s1;
+       struct logical_volume *sub_lv;
+       struct logical_volume *log_lv = NULL;
+       struct logical_volume *lv1 = NULL;
+       struct physical_volume *pv;
+       struct lv_segment *seg;
+       struct lv_segment_area area;
+       int all_pvs_removable, pv_found;
+       struct pv_list *pvl;
+       uint32_t old_area_count = mirrored_seg->area_count;
+       uint32_t new_area_count = mirrored_seg->area_count;
+
+       log_very_verbose("Reducing mirror set from %" PRIu32 " to %"
+                        PRIu32 " image(s)%s.",
+                        old_area_count, num_mirrors,
+                        remove_log ? " and no log volume" : "");
+
+       /* Move removable_pvs to end of array */
+       if (removable_pvs) {
+               for (s = 0; s < mirrored_seg->area_count; s++) {
+                       all_pvs_removable = 1;
+                       sub_lv = seg_lv(mirrored_seg, s);
+                       list_iterate_items(seg, &sub_lv->segments) {
+                               for (s1 = 0; s1 < seg->area_count; s1++) {
+                                       if (seg_type(seg, s1) != AREA_PV)
+                                               /* FIXME Recurse for AREA_LV */
+                                               continue;
+
+                                       pv = seg_pv(seg, s1);
+
+                                       pv_found = 0;
+                                       list_iterate_items(pvl, removable_pvs) {
+                                               if (pv->dev->dev == pvl->pv->dev->dev) {
+                                                       pv_found = 1;
+                                                       break;
+                                               }
+                                       }
+                                       if (!pv_found) {
+                                               all_pvs_removable = 0;
+                                               break;
+                                       }
+                               }
+                               if (!all_pvs_removable)
+                                       break;
+                       }
+                       if (all_pvs_removable) {
+                               /* Swap segment to end */
+                               new_area_count--;
+                               area = mirrored_seg->areas[new_area_count];
+                               mirrored_seg->areas[new_area_count] = mirrored_seg->areas[s];
+                               mirrored_seg->areas[s] = area;
+                       }
+                       /* Found enough matches? */
+                       if (new_area_count == num_mirrors)
+                               break;
+               }
+               if (new_area_count == mirrored_seg->area_count) {
+                       log_error("No mirror images found using specified PVs.");
                        return 0;
                }
        }
 
+       for (m = num_mirrors; m < mirrored_seg->area_count; m++) {
+               seg_lv(mirrored_seg, m)->status &= ~MIRROR_IMAGE;
+               seg_lv(mirrored_seg, m)->status |= VISIBLE_LV;
+       }
+
        mirrored_seg->area_count = num_mirrors;
 
-       return 1;
-}
+       /* If no more mirrors, remove mirror layer */
+       if (num_mirrors == 1) {
+               lv1 = seg_lv(mirrored_seg, 0);
+               _move_lv_segments(mirrored_seg->lv, lv1);
+               mirrored_seg->lv->status &= ~MIRRORED;
+               remove_log = 1;
+       }
 
-int remove_all_mirror_images(struct logical_volume *lv)
-{
-       struct lv_segment *seg;
-       struct logical_volume *lv1;
+       if (remove_log) {
+               log_lv = mirrored_seg->log_lv;
+               mirrored_seg->log_lv = NULL;
+       }
 
-       seg = first_seg(lv);
+       /*
+        * To successfully remove these unwanted LVs we need to
+        * remove the LVs from the mirror set, commit that metadata
+        * then deactivate and remove them fully.
+        */
 
-       if (!remove_mirror_images(seg, 1)) {
-               stack;
+       /* FIXME lv1 has no segments here so shouldn't be written to disk! */
+
+       if (!vg_write(mirrored_seg->lv->vg)) {
+               log_error("intermediate VG write failed.");
                return 0;
        }
 
-       if (seg->log_lv && !lv_remove(seg->log_lv)) {
-               stack;
+       if (!suspend_lv(mirrored_seg->lv->vg->cmd, mirrored_seg->lv)) {
+               log_error("Failed to lock %s", mirrored_seg->lv->name);
+               vg_revert(mirrored_seg->lv->vg);
                return 0;
        }
 
-       lv1 = seg_lv(seg, 0);
+       if (!vg_commit(mirrored_seg->lv->vg)) {
+               resume_lv(mirrored_seg->lv->vg->cmd, mirrored_seg->lv);
+               return 0;
+       }
 
-       _move_lv_segments(lv, lv1);
+       log_very_verbose("Updating \"%s\" in kernel", mirrored_seg->lv->name);
 
-       if (!lv_remove(lv1)) {
-               stack;
+       if (!resume_lv(mirrored_seg->lv->vg->cmd, mirrored_seg->lv)) {
+               log_error("Problem reactivating %s", mirrored_seg->lv->name);
                return 0;
        }
 
-       lv->status &= ~MIRRORED;
+       /* Delete the 'orphan' LVs */
+       for (m = num_mirrors; m < old_area_count; m++) {
+               if (!deactivate_lv(mirrored_seg->lv->vg->cmd, seg_lv(mirrored_seg, m))) {
+                       stack;
+                       return 0;
+               }
 
-       return 1;
-}
+               if (!lv_remove(seg_lv(mirrored_seg, m))) {
+                       stack;
+                       return 0;
+               }
+       }
 
-/*
- * Add mirror images to an existing mirror
- */
-/* FIXME
-int add_mirror_images(struct alloc_handle *ah,
-                     uint32_t first_area,
-                     uint32_t num_areas,
-                     struct logical_volume *lv)
-{
+       if (lv1) {
+               if (!deactivate_lv(mirrored_seg->lv->vg->cmd, lv1)) {
+                       stack;
+                       return 0;
+               }
+
+               if (!lv_remove(lv1)) {
+                       stack;
+                       return 0;
+               }
+       }
+
+       if (log_lv) {
+               if (!deactivate_lv(mirrored_seg->lv->vg->cmd, log_lv)) {
+                       stack;
+                       return 0;
+               }
+
+               if (!lv_remove(log_lv)) {
+                       stack;
+                       return 0;
+               }
+       }
+
+       return 1;
 }
-*/
 
 static int _create_layers_for_mirror(struct alloc_handle *ah,
                                     uint32_t first_area,
@@ -161,7 +263,10 @@ static int _create_layers_for_mirror(struct alloc_handle *ah,
                        return 0;
                }
 
-               if (!lv_add_segment(ah, m, 1, img_lvs[m],
+               if (m < first_area)
+                       continue;
+
+               if (!lv_add_segment(ah, m - first_area, 1, img_lvs[m],
                                    get_segtype_from_string(lv->vg->cmd,
                                                            "striped"),
                                    0, NULL, 0, 0, 0, NULL)) {
@@ -219,6 +324,30 @@ int create_mirror_layers(struct alloc_handle *ah,
        return 1;
 }
 
+int add_mirror_layers(struct alloc_handle *ah,
+                     uint32_t num_mirrors,
+                     uint32_t existing_mirrors,
+                     struct logical_volume *lv,
+                     struct segment_type *segtype)
+{
+       struct logical_volume **img_lvs;
+
+       if (!(img_lvs = alloca(sizeof(*img_lvs) * num_mirrors))) {
+               log_error("img_lvs allocation failed. "
+                         "Remove new LV and retry.");
+               return 0;
+       }
+
+       if (!_create_layers_for_mirror(ah, 0, num_mirrors,
+                                      lv, segtype,
+                                      img_lvs)) {
+               stack;
+               return 0;
+       }
+
+       return lv_add_more_mirrored_areas(lv, img_lvs, num_mirrors, 0);
+}
+
 /* 
  * Replace any LV segments on given PV with temporary mirror.
  * Returns list of LVs changed.
index 1adfd724d19ebe05184c4d211b0b886f133a4514..65af4061348376b587e34db5be6c512886c42b8f 100644 (file)
@@ -85,11 +85,12 @@ xx(lvconvert,
    "\t[-d|--debug]\n"
    "\t[-h|-?|--help]\n"
    "\t[-m|--mirrors Mirrors]\n"
+   "\t[-R|--regionsize MirrorLogRegionSize]\n"
    "\t[-v|--verbose]\n"
    "\t[--version]" "\n"
    "\tLogicalVolume[Path] [PhysicalVolume[Path]...]\n",
 
-   alloc_ARG, mirrors_ARG, test_ARG)
+   alloc_ARG, mirrors_ARG, regionsize_ARG, test_ARG)
 
 xx(lvcreate,
    "Create a logical volume",
index 5f11e185b48ebe8b1002736eb944ae8bcf4858e2..61ad73221542fe79437ffd74bd7d464d046dec0c 100644 (file)
  */
 
 #include "tools.h"
+#include "lv_alloc.h"
 
 struct lvconvert_params {
        const char *lv_name;
        uint32_t mirrors;
+       sign_t mirrors_sign;
+       uint32_t region_size;
 
        alloc_policy_t alloc;
 
@@ -40,7 +43,29 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
                return 0;
        }
 
-       lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1;
+       lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0);
+       lp->mirrors_sign = arg_sign_value(cmd, mirrors_ARG, 0);
+
+       /*
+        * --regionsize is only valid when converting an LV into a mirror.
+        * This is checked when we know the state of the LV being converted.
+        */
+       if (arg_count(cmd, regionsize_ARG)) {
+               if (arg_sign_value(cmd, regionsize_ARG, 0) == SIGN_MINUS) {
+                       log_error("Negative regionsize is invalid");
+                       return 0;
+               }
+               lp->region_size = 2 * arg_uint_value(cmd, regionsize_ARG, 0);
+       } else
+               lp->region_size = 2 * find_config_int(cmd->cft->root,
+                                       "activation/mirror_region_size",
+                                       DEFAULT_MIRROR_REGION_SIZE);
+
+       if (lp->region_size & (lp->region_size - 1)) {
+               log_error("Region size (%" PRIu32 ") must be a power of 2",
+                         lp->region_size);
+               return 0;
+       }
 
        if (!argc) {
                log_error("Please give logical volume path");
@@ -61,8 +86,33 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
 {
        struct lv_segment *seg;
        uint32_t existing_mirrors;
-       // struct alloc_handle *ah = NULL;
-       // struct logical_volume *log_lv;
+       struct alloc_handle *ah = NULL;
+       struct logical_volume *log_lv;
+       struct list *parallel_areas;
+       struct segment_type *segtype;
+
+       seg = first_seg(lv);
+       existing_mirrors = seg->area_count;
+
+       /* Adjust required number of mirrors */
+       if (lp->mirrors_sign == SIGN_PLUS)
+               lp->mirrors = existing_mirrors + lp->mirrors;
+       else if (lp->mirrors_sign == SIGN_MINUS) {
+               if (lp->mirrors >= existing_mirrors) {
+                       log_error("Logical volume %s only has %" PRIu32 " mirrors.",
+                                 lv->name, existing_mirrors);
+                       return 0;
+               }
+               lp->mirrors = existing_mirrors - lp->mirrors;
+       } else
+               lp->mirrors += 1;
+
+       if (arg_count(cmd, regionsize_ARG) && (lv->status & MIRRORED) &&
+           (lp->region_size != seg->region_size)) {
+               log_error("Mirror log region size cannot be changed on "
+                         "an existing mirror.");
+               return 0;
+       }
 
        if ((lp->mirrors == 1)) {
                if (!(lv->status & MIRRORED)) {
@@ -70,8 +120,8 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
                                  lv->name);
                        return 1;
                }
-               /* FIXME If allocatable_pvs supplied only remove those */
-               if (!remove_all_mirror_images(lv)) {
+
+               if (!remove_mirror_images(seg, 1, lp->pv_count ? lp->pvh : NULL, 1)) {
                        stack;
                        return 0;
                }
@@ -82,8 +132,6 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
                                          "mirror segments.", lv->name);
                                return 0;
                        }
-                       seg = first_seg(lv);
-                       existing_mirrors = seg->area_count;
                        if (lp->mirrors == existing_mirrors) {
                                log_error("Logical volume %s already has %"
                                          PRIu32 " mirror(s).", lv->name,
@@ -100,18 +148,58 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
                                          "supported yet.");
                                return 0;
                        } else {
-                               if (!remove_mirror_images(seg, lp->mirrors)) {
+                               /* Reduce number of mirrors */
+                               if (!remove_mirror_images(seg, lp->mirrors, lp->pv_count ? lp->pvh : NULL, 0)) {
                                        stack;
                                        return 0;
                                }
                        }
                } else {
+                       /* Make existing LV into mirror set */
                        /* FIXME Share code with lvcreate */
-                       /* region size, log_name, create log_lv, zero it */
-                       // Allocate (mirrors) new areas & log - replace mirrored_pv with mirrored_lv
-                       // Restructure as mirror - add existing param to create_mirror_layers
-                       log_error("Adding mirror images is not supported yet.");
-                       return 0;
+
+                       /* FIXME Why is this restriction here?  Fix it! */
+                       list_iterate_items(seg, &lv->segments) {
+                               if (seg_is_striped(seg) && seg->area_count > 1) {
+                                       log_error("Mirrors of striped volumes are not yet supported.");
+                                       return 0;
+                               }
+                       }
+
+                       if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv))) {
+                               stack;
+                               return 0;
+                       }
+
+                       segtype = get_segtype_from_string(cmd, "striped");
+
+                       if (!(ah = allocate_extents(lv->vg, NULL, segtype, 1,
+                                                   lp->mirrors - 1, 1,
+                                                   lv->le_count * (lp->mirrors - 1),
+                                                   NULL, 0, 0, lp->pvh,
+                                                   lp->alloc,
+                                                   parallel_areas))) {
+                               stack;
+                               return 0;
+                       }
+
+                       lp->region_size = adjusted_mirror_region_size(lv->vg->extent_size,
+                                                                     lv->le_count,
+                                                                     lp->region_size);
+
+                       if (!(log_lv = create_mirror_log(cmd, lv->vg, ah,
+                                                        lp->alloc,
+                                                        lv->name))) {
+                               log_error("Failed to create mirror log.");
+                               return 0;
+                       }
+
+                       if (!create_mirror_layers(ah, 1, lp->mirrors, lv,
+                                                 segtype, 0, lp->region_size,
+                                                 log_lv)) {
+                               stack;
+                               return 0;
+                       }
                }
        }
 
index c75b195a5b5d85318ff87ab6d53ab3c6d3530070..cb0a0c5e4e2e0f0ad310fcc9e694d27a25c73460 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. 
- * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
This page took 0.052682 seconds and 5 git commands to generate.