Home | History | Annotate | Line # | Download | only in tools
vgmerge.c revision 1.1
      1 /*	$NetBSD: vgmerge.c,v 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