From 1a1f3d3efe350396103af50136ec212df0ff7ea6 Mon Sep 17 00:00:00 2001 From: Alasdair Kergon Date: Mon, 6 Jun 2005 17:12:08 +0000 Subject: [PATCH] Introduce lvconvert. So far only removes mirror images. --- WHATS_NEW | 1 + lib/metadata/mirror.c | 69 +++++++++++++ tools/Makefile.in | 1 + tools/commands.h | 13 +++ tools/lvconvert.c | 230 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 314 insertions(+) create mode 100644 tools/lvconvert.c diff --git a/WHATS_NEW b/WHATS_NEW index 5c8f49c2f..300262658 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,6 @@ Version 2.01.11 - ============================== + Introduce lvconvert. So far only removes mirror images. Allow mirror images to be resized. Allow mirror images to have more than one segment. Centralise restrictions on LV names. diff --git a/lib/metadata/mirror.c b/lib/metadata/mirror.c index 9a0a8a14d..e55803639 100644 --- a/lib/metadata/mirror.c +++ b/lib/metadata/mirror.c @@ -22,6 +22,75 @@ #include "lv_alloc.h" #include "lvm-string.h" +/* + * Reduce mirrored_seg to num_mirrors images. + */ +int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors) +{ + uint32_t m; + + for (m = num_mirrors; m < mirrored_seg->area_count; m++) { + if (!lv_remove(seg_lv(mirrored_seg, m))) { + stack; + return 0; + } + } + + mirrored_seg->area_count = num_mirrors; + + return 1; +} + +int remove_all_mirror_images(struct logical_volume *lv) +{ + struct lv_segment *first_seg, *seg; + struct logical_volume *lv1; + + list_iterate_items(first_seg, &lv->segments) + break; + + if (!remove_mirror_images(first_seg, 1)) { + stack; + return 0; + } + + if (!lv_remove(first_seg->log_lv)) { + stack; + return 0; + } + + lv1 = seg_lv(first_seg, 0); + + lv->segments = lv1->segments; + lv->segments.n->p = &lv->segments; + lv->segments.p->n = &lv->segments; + + list_init(&lv1->segments); + lv1->le_count = 0; + lv1->size = 0; + if (!lv_remove(lv1)) { + stack; + return 0; + } + + lv->status &= ~MIRRORED; + + list_iterate_items(seg, &lv->segments) + seg->lv = lv; + + return 1; +} + +/* + * Add mirror images to an existing mirror + */ +int add_mirror_images(struct alloc_handle *ah, + uint32_t first_area, + uint32_t num_areas, + struct logical_volume *lv) +{ +} + int create_mirror_layers(struct alloc_handle *ah, uint32_t first_area, uint32_t num_mirrors, diff --git a/tools/Makefile.in b/tools/Makefile.in index 232dff01a..471cb02ee 100644 --- a/tools/Makefile.in +++ b/tools/Makefile.in @@ -24,6 +24,7 @@ SOURCES =\ dumpconfig.c \ formats.c \ lvchange.c \ + lvconvert.c \ lvcreate.c \ lvdisplay.c \ lvextend.c \ diff --git a/tools/commands.h b/tools/commands.h index 42d591822..f699e0522 100644 --- a/tools/commands.h +++ b/tools/commands.h @@ -78,6 +78,19 @@ xx(lvchange, persistent_ARG, readahead_ARG, refresh_ARG, addtag_ARG, deltag_ARG, test_ARG) +xx(lvconvert, + "Change logical volume layout", + "lvconvert " "\n" + "\t[--alloc AllocationPolicy]\n" + "\t[-d|--debug]\n" + "\t[-h|-?|--help]\n" + "\t[-m|--mirrors Mirrors]\n" + "\t[-v|--verbose]\n" + "\t[--version]" "\n" + "\tLogicalVolume[Path] [LogicalVolume[Path]...]\n", + + alloc_ARG, mirrors_ARG, test_ARG) + xx(lvcreate, "Create a logical volume", "lvcreate " "\n" diff --git a/tools/lvconvert.c b/tools/lvconvert.c new file mode 100644 index 000000000..8f2ba8e51 --- /dev/null +++ b/tools/lvconvert.c @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2005 Red Hat, Inc. All rights reserved. + * + * This file is part of LVM2. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "tools.h" + +struct lvconvert_params { + struct list *pvh; +}; + +static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * lv, + struct list *allocatable_pvs) +{ + struct lv_segment *first_seg; + uint32_t mirrors, existing_mirrors; + alloc_policy_t alloc = ALLOC_INHERIT; + // struct alloc_handle *ah = NULL; + // struct logical_volume *log_lv; + + if (arg_count(cmd, alloc_ARG)) + alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, alloc); + + mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1; + + if ((mirrors == 1)) { + if (!(lv->status & MIRRORED)) { + log_error("Logical volume %s is already not mirrored.", + lv->name); + return 1; + } + /* FIXME If allocatable_pvs supplied only remove those */ + if (!remove_all_mirror_images(lv)) { + stack; + return 0; + } + } else { /* mirrors > 1 */ + if ((lv->status & MIRRORED)) { + if (list_size(&lv->segments) != 1) { + log_error("Logical volume %s has multiple " + "mirror segments.", lv->name); + return 0; + } + list_iterate_items(first_seg, &lv->segments) + break; + existing_mirrors = first_seg->area_count; + if (mirrors == existing_mirrors) { + log_error("Logical volume %s already has %" + PRIu32 " mirror(s).", lv->name, + mirrors - 1); + return 1; + } + if (mirrors > existing_mirrors) { + /* FIXME Unless anywhere, remove PV of log_lv + * from allocatable_pvs & allocate + * (mirrors - existing_mirrors) new areas + */ + /* FIXME Create mirror hierarchy to sync */ + log_error("Adding mirror images is not " + "supported yet."); + return 0; + } else { + if (!remove_mirror_images(first_seg, mirrors)) { + stack; + return 0; + } + } + } else { + /* 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; + } + } + + log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name); + + if (!vg_write(lv->vg)) { + stack; + return 0; + } + + backup(lv->vg); + + if (!suspend_lv(cmd, lv->lvid.s)) { + log_error("Failed to lock %s", lv->name); + vg_revert(lv->vg); + return 0; + } + + if (!vg_commit(lv->vg)) { + resume_lv(cmd, lv->lvid.s); + return 0; + } + + log_very_verbose("Updating \"%s\" in kernel", lv->name); + + if (!resume_lv(cmd, lv->lvid.s)) { + log_error("Problem reactivating %s", lv->name); + return 0; + } + + log_print("Logical volume %s converted.", lv->name); + + return 1; +} + +static int lvconvert_single(struct cmd_context * cmd, struct logical_volume * lv, + int argc, char **argv, void *handle) +{ + struct lvconvert_params *lp = handle; + + if (lv->status & LOCKED) { + log_error("Cannot convert locked LV %s", lv->name); + return ECMD_FAILED; + } + + if (lv_is_origin(lv)) { + log_error("Can't convert logical volume \"%s\" under snapshot", + lv->name); + return ECMD_FAILED; + } + + if (lv_is_cow(lv)) { + log_error("Can't convert snapshot logical volume \"%s\"", + lv->name); + return ECMD_FAILED; + } + + if (lv->status & PVMOVE) { + log_error("Unable to convert pvmove LV %s", lv->name); + return ECMD_FAILED; + } + + if (arg_count(cmd, mirrors_ARG)) { + if (!archive(lv->vg)) + return ECMD_FAILED; + if (!lvconvert_mirrors(cmd, lv, lp->pvh)) + return ECMD_FAILED; + } + + return ECMD_PROCESSED; +} + +int lvconvert(struct cmd_context * cmd, int argc, char **argv) +{ + const char *vg_name, *lv_name; + char *st; + int consistent = 1; + struct volume_group *vg; + struct lv_list *lvl; + struct lvconvert_params lp; + int ret = ECMD_FAILED; + + if (!arg_count(cmd, mirrors_ARG)) { + log_error("--mirrors argument required"); + return EINVALID_CMD_LINE; + } + + if (!argc) { + log_error("Please give logical volume path(s)"); + return EINVALID_CMD_LINE; + } + + lv_name = argv[0]; + argv++, argc--; + + vg_name = extract_vgname(cmd, lv_name); + + if (!validate_name(vg_name)) { + log_error("Please provide a valid volume group name"); + return EINVALID_CMD_LINE; + } + + if ((st = strrchr(lv_name, '/'))) + lv_name = st + 1; + + log_verbose("Checking for existing volume group \"%s\"", vg_name); + + if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) { + log_error("Can't get lock for %s", vg_name); + return ECMD_FAILED; + } + + if (!(vg = vg_read(cmd, vg_name, &consistent))) { + log_error("Volume group \"%s\" doesn't exist", vg_name); + goto error; + } + + if (vg->status & EXPORTED_VG) { + log_error("Volume group \"%s\" is exported", vg_name); + goto error; + } + + if (!(vg->status & LVM_WRITE)) { + log_error("Volume group \"%s\" is read-only", vg_name); + goto error; + } + + if (!(lvl = find_lv_in_vg(vg, lv_name))) { + log_error("Logical volume \"%s\" not found in " + "volume group \"%s\"", lv_name, vg_name); + goto error; + } + + if (argc) { + if (!(lp.pvh = create_pv_list(cmd->mem, vg, argc, argv, 1))) { + stack; + goto error; + } + } else + lp.pvh = &vg->pvs; + + ret = lvconvert_single(cmd, lvl->lv, argc, argv, &lp); + +error: + unlock_vg(cmd, vg_name); + return ret; +}