1 /* $NetBSD: vgmerge.c,v 1.1.1.1 2008/12/22 00:19:09 haad Exp $ */ 2 3 /* 4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. 5 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. 6 * 7 * This file is part of LVM2. 8 * 9 * This copyrighted material is made available to anyone wishing to use, 10 * modify, copy, or redistribute it subject to the terms and conditions 11 * of the GNU Lesser General Public License v.2.1. 12 * 13 * You should have received a copy of the GNU Lesser General Public License 14 * along with this program; if not, write to the Free Software Foundation, 15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16 */ 17 18 #include "tools.h" 19 20 static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to, 21 const char *vg_name_from) 22 { 23 struct volume_group *vg_to, *vg_from; 24 struct lv_list *lvl1, *lvl2; 25 26 if (!strcmp(vg_name_to, vg_name_from)) { 27 log_error("Duplicate volume group name \"%s\"", vg_name_from); 28 return ECMD_FAILED; 29 } 30 31 log_verbose("Checking for volume group \"%s\"", vg_name_to); 32 if (!(vg_to = vg_lock_and_read(cmd, vg_name_to, NULL, LCK_VG_WRITE, 33 CLUSTERED | EXPORTED_VG | LVM_WRITE, 34 CORRECT_INCONSISTENT | FAIL_INCONSISTENT))) 35 return ECMD_FAILED; 36 37 log_verbose("Checking for volume group \"%s\"", vg_name_from); 38 if (!(vg_from = vg_lock_and_read(cmd, vg_name_from, NULL, 39 LCK_VG_WRITE | LCK_NONBLOCK, 40 CLUSTERED | EXPORTED_VG | LVM_WRITE, 41 CORRECT_INCONSISTENT | FAIL_INCONSISTENT))) { 42 unlock_vg(cmd, vg_name_to); 43 return ECMD_FAILED; 44 } 45 46 if (!vgs_are_compatible(cmd, vg_from, vg_to)) 47 goto_bad; 48 49 /* FIXME List arg: vg_show_with_pv_and_lv(vg_to); */ 50 51 if (!archive(vg_from) || !archive(vg_to)) 52 goto_bad; 53 54 drop_cached_metadata(vg_from); 55 56 /* Merge volume groups */ 57 while (!dm_list_empty(&vg_from->pvs)) { 58 struct dm_list *pvh = vg_from->pvs.n; 59 struct physical_volume *pv; 60 61 dm_list_move(&vg_to->pvs, pvh); 62 63 pv = dm_list_item(pvh, struct pv_list)->pv; 64 pv->vg_name = dm_pool_strdup(cmd->mem, vg_to->name); 65 } 66 vg_to->pv_count += vg_from->pv_count; 67 68 /* Fix up LVIDs */ 69 dm_list_iterate_items(lvl1, &vg_to->lvs) { 70 union lvid *lvid1 = &lvl1->lv->lvid; 71 char uuid[64] __attribute((aligned(8))); 72 73 dm_list_iterate_items(lvl2, &vg_from->lvs) { 74 union lvid *lvid2 = &lvl2->lv->lvid; 75 76 if (id_equal(&lvid1->id[1], &lvid2->id[1])) { 77 if (!id_create(&lvid2->id[1])) { 78 log_error("Failed to generate new " 79 "random LVID for %s", 80 lvl2->lv->name); 81 goto bad; 82 } 83 if (!id_write_format(&lvid2->id[1], uuid, 84 sizeof(uuid))) 85 goto_bad; 86 87 log_verbose("Changed LVID for %s to %s", 88 lvl2->lv->name, uuid); 89 } 90 } 91 } 92 93 while (!dm_list_empty(&vg_from->lvs)) { 94 struct dm_list *lvh = vg_from->lvs.n; 95 96 dm_list_move(&vg_to->lvs, lvh); 97 } 98 99 while (!dm_list_empty(&vg_from->fid->metadata_areas)) { 100 struct dm_list *mdah = vg_from->fid->metadata_areas.n; 101 102 dm_list_move(&vg_to->fid->metadata_areas, mdah); 103 } 104 105 vg_to->lv_count += vg_from->lv_count; 106 vg_to->snapshot_count += vg_from->snapshot_count; 107 108 vg_to->extent_count += vg_from->extent_count; 109 vg_to->free_count += vg_from->free_count; 110 111 /* store it on disks */ 112 log_verbose("Writing out updated volume group"); 113 if (!vg_write(vg_to) || !vg_commit(vg_to)) 114 goto_bad; 115 116 /* FIXME Remove /dev/vgfrom */ 117 118 backup(vg_to); 119 120 unlock_vg(cmd, vg_name_from); 121 unlock_vg(cmd, vg_name_to); 122 123 log_print("Volume group \"%s\" successfully merged into \"%s\"", 124 vg_from->name, vg_to->name); 125 return ECMD_PROCESSED; 126 127 bad: 128 unlock_vg(cmd, vg_name_from); 129 unlock_vg(cmd, vg_name_to); 130 return ECMD_FAILED; 131 } 132 133 int vgmerge(struct cmd_context *cmd, int argc, char **argv) 134 { 135 char *vg_name_to, *vg_name_from; 136 int opt = 0; 137 int ret = 0, ret_max = 0; 138 139 if (argc < 2) { 140 log_error("Please enter 2 or more volume groups to merge"); 141 return EINVALID_CMD_LINE; 142 } 143 144 vg_name_to = skip_dev_dir(cmd, argv[0], NULL); 145 argc--; 146 argv++; 147 148 for (; opt < argc; opt++) { 149 vg_name_from = skip_dev_dir(cmd, argv[opt], NULL); 150 151 ret = _vgmerge_single(cmd, vg_name_to, vg_name_from); 152 if (ret > ret_max) 153 ret_max = ret; 154 } 155 156 return ret_max; 157 } 158