186d7f5d3SJohn Marino /* $NetBSD: vgmerge.c,v 1.1.1.2 2009/12/02 00:25:57 haad Exp $ */
286d7f5d3SJohn Marino
386d7f5d3SJohn Marino /*
486d7f5d3SJohn Marino * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
586d7f5d3SJohn Marino * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
686d7f5d3SJohn Marino *
786d7f5d3SJohn Marino * This file is part of LVM2.
886d7f5d3SJohn Marino *
986d7f5d3SJohn Marino * This copyrighted material is made available to anyone wishing to use,
1086d7f5d3SJohn Marino * modify, copy, or redistribute it subject to the terms and conditions
1186d7f5d3SJohn Marino * of the GNU Lesser General Public License v.2.1.
1286d7f5d3SJohn Marino *
1386d7f5d3SJohn Marino * You should have received a copy of the GNU Lesser General Public License
1486d7f5d3SJohn Marino * along with this program; if not, write to the Free Software Foundation,
1586d7f5d3SJohn Marino * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1686d7f5d3SJohn Marino */
1786d7f5d3SJohn Marino
1886d7f5d3SJohn Marino #include "tools.h"
1986d7f5d3SJohn Marino
_vgmerge_vg_read(struct cmd_context * cmd,const char * vg_name)2086d7f5d3SJohn Marino static struct volume_group *_vgmerge_vg_read(struct cmd_context *cmd,
2186d7f5d3SJohn Marino const char *vg_name)
2286d7f5d3SJohn Marino {
2386d7f5d3SJohn Marino struct volume_group *vg;
2486d7f5d3SJohn Marino log_verbose("Checking for volume group \"%s\"", vg_name);
2586d7f5d3SJohn Marino vg = vg_read_for_update(cmd, vg_name, NULL, 0);
2686d7f5d3SJohn Marino if (vg_read_error(vg)) {
2786d7f5d3SJohn Marino vg_release(vg);
2886d7f5d3SJohn Marino return NULL;
2986d7f5d3SJohn Marino }
3086d7f5d3SJohn Marino return vg;
3186d7f5d3SJohn Marino }
3286d7f5d3SJohn Marino
_vgmerge_single(struct cmd_context * cmd,const char * vg_name_to,const char * vg_name_from)3386d7f5d3SJohn Marino static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
3486d7f5d3SJohn Marino const char *vg_name_from)
3586d7f5d3SJohn Marino {
3686d7f5d3SJohn Marino struct volume_group *vg_to, *vg_from;
3786d7f5d3SJohn Marino struct lv_list *lvl1, *lvl2;
3886d7f5d3SJohn Marino int r = ECMD_FAILED;
3986d7f5d3SJohn Marino int lock_vg_from_first = 0;
4086d7f5d3SJohn Marino
4186d7f5d3SJohn Marino if (!strcmp(vg_name_to, vg_name_from)) {
4286d7f5d3SJohn Marino log_error("Duplicate volume group name \"%s\"", vg_name_from);
4386d7f5d3SJohn Marino return ECMD_FAILED;
4486d7f5d3SJohn Marino }
4586d7f5d3SJohn Marino
4686d7f5d3SJohn Marino if (strcmp(vg_name_to, vg_name_from) > 0)
4786d7f5d3SJohn Marino lock_vg_from_first = 1;
4886d7f5d3SJohn Marino
4986d7f5d3SJohn Marino if (lock_vg_from_first) {
5086d7f5d3SJohn Marino vg_from = _vgmerge_vg_read(cmd, vg_name_from);
5186d7f5d3SJohn Marino if (!vg_from) {
5286d7f5d3SJohn Marino stack;
5386d7f5d3SJohn Marino return ECMD_FAILED;
5486d7f5d3SJohn Marino }
5586d7f5d3SJohn Marino vg_to = _vgmerge_vg_read(cmd, vg_name_to);
5686d7f5d3SJohn Marino if (!vg_to) {
5786d7f5d3SJohn Marino stack;
5886d7f5d3SJohn Marino unlock_and_release_vg(cmd, vg_from, vg_name_from);
5986d7f5d3SJohn Marino return ECMD_FAILED;
6086d7f5d3SJohn Marino }
6186d7f5d3SJohn Marino } else {
6286d7f5d3SJohn Marino vg_to = _vgmerge_vg_read(cmd, vg_name_to);
6386d7f5d3SJohn Marino if (!vg_to) {
6486d7f5d3SJohn Marino stack;
6586d7f5d3SJohn Marino return ECMD_FAILED;
6686d7f5d3SJohn Marino }
6786d7f5d3SJohn Marino
6886d7f5d3SJohn Marino vg_from = _vgmerge_vg_read(cmd, vg_name_from);
6986d7f5d3SJohn Marino if (!vg_from) {
7086d7f5d3SJohn Marino stack;
7186d7f5d3SJohn Marino unlock_and_release_vg(cmd, vg_to, vg_name_to);
7286d7f5d3SJohn Marino return ECMD_FAILED;
7386d7f5d3SJohn Marino }
7486d7f5d3SJohn Marino }
7586d7f5d3SJohn Marino
7686d7f5d3SJohn Marino if (!vgs_are_compatible(cmd, vg_from, vg_to))
7786d7f5d3SJohn Marino goto_bad;
7886d7f5d3SJohn Marino
7986d7f5d3SJohn Marino /* FIXME List arg: vg_show_with_pv_and_lv(vg_to); */
8086d7f5d3SJohn Marino
8186d7f5d3SJohn Marino if (!archive(vg_from) || !archive(vg_to))
8286d7f5d3SJohn Marino goto_bad;
8386d7f5d3SJohn Marino
8486d7f5d3SJohn Marino drop_cached_metadata(vg_from);
8586d7f5d3SJohn Marino
8686d7f5d3SJohn Marino /* Merge volume groups */
8786d7f5d3SJohn Marino while (!dm_list_empty(&vg_from->pvs)) {
8886d7f5d3SJohn Marino struct dm_list *pvh = vg_from->pvs.n;
8986d7f5d3SJohn Marino struct physical_volume *pv;
9086d7f5d3SJohn Marino
9186d7f5d3SJohn Marino dm_list_move(&vg_to->pvs, pvh);
9286d7f5d3SJohn Marino
9386d7f5d3SJohn Marino pv = dm_list_item(pvh, struct pv_list)->pv;
9486d7f5d3SJohn Marino pv->vg_name = dm_pool_strdup(cmd->mem, vg_to->name);
9586d7f5d3SJohn Marino }
9686d7f5d3SJohn Marino vg_to->pv_count += vg_from->pv_count;
9786d7f5d3SJohn Marino
9886d7f5d3SJohn Marino /* Fix up LVIDs */
9986d7f5d3SJohn Marino dm_list_iterate_items(lvl1, &vg_to->lvs) {
10086d7f5d3SJohn Marino union lvid *lvid1 = &lvl1->lv->lvid;
10186d7f5d3SJohn Marino char uuid[64] __attribute((aligned(8)));
10286d7f5d3SJohn Marino
10386d7f5d3SJohn Marino dm_list_iterate_items(lvl2, &vg_from->lvs) {
10486d7f5d3SJohn Marino union lvid *lvid2 = &lvl2->lv->lvid;
10586d7f5d3SJohn Marino
10686d7f5d3SJohn Marino if (id_equal(&lvid1->id[1], &lvid2->id[1])) {
10786d7f5d3SJohn Marino if (!id_create(&lvid2->id[1])) {
10886d7f5d3SJohn Marino log_error("Failed to generate new "
10986d7f5d3SJohn Marino "random LVID for %s",
11086d7f5d3SJohn Marino lvl2->lv->name);
11186d7f5d3SJohn Marino goto bad;
11286d7f5d3SJohn Marino }
11386d7f5d3SJohn Marino if (!id_write_format(&lvid2->id[1], uuid,
11486d7f5d3SJohn Marino sizeof(uuid)))
11586d7f5d3SJohn Marino goto_bad;
11686d7f5d3SJohn Marino
11786d7f5d3SJohn Marino log_verbose("Changed LVID for %s to %s",
11886d7f5d3SJohn Marino lvl2->lv->name, uuid);
11986d7f5d3SJohn Marino }
12086d7f5d3SJohn Marino }
12186d7f5d3SJohn Marino }
12286d7f5d3SJohn Marino
12386d7f5d3SJohn Marino while (!dm_list_empty(&vg_from->lvs)) {
12486d7f5d3SJohn Marino struct dm_list *lvh = vg_from->lvs.n;
12586d7f5d3SJohn Marino
12686d7f5d3SJohn Marino dm_list_move(&vg_to->lvs, lvh);
12786d7f5d3SJohn Marino }
12886d7f5d3SJohn Marino
12986d7f5d3SJohn Marino while (!dm_list_empty(&vg_from->fid->metadata_areas)) {
13086d7f5d3SJohn Marino struct dm_list *mdah = vg_from->fid->metadata_areas.n;
13186d7f5d3SJohn Marino
13286d7f5d3SJohn Marino dm_list_move(&vg_to->fid->metadata_areas, mdah);
13386d7f5d3SJohn Marino }
13486d7f5d3SJohn Marino
13586d7f5d3SJohn Marino vg_to->extent_count += vg_from->extent_count;
13686d7f5d3SJohn Marino vg_to->free_count += vg_from->free_count;
13786d7f5d3SJohn Marino
13886d7f5d3SJohn Marino /* store it on disks */
13986d7f5d3SJohn Marino log_verbose("Writing out updated volume group");
14086d7f5d3SJohn Marino if (!vg_write(vg_to) || !vg_commit(vg_to))
14186d7f5d3SJohn Marino goto_bad;
14286d7f5d3SJohn Marino
14386d7f5d3SJohn Marino /* FIXME Remove /dev/vgfrom */
14486d7f5d3SJohn Marino
14586d7f5d3SJohn Marino backup(vg_to);
14686d7f5d3SJohn Marino log_print("Volume group \"%s\" successfully merged into \"%s\"",
14786d7f5d3SJohn Marino vg_from->name, vg_to->name);
14886d7f5d3SJohn Marino r = ECMD_PROCESSED;
14986d7f5d3SJohn Marino bad:
15086d7f5d3SJohn Marino if (lock_vg_from_first) {
15186d7f5d3SJohn Marino unlock_and_release_vg(cmd, vg_to, vg_name_to);
15286d7f5d3SJohn Marino unlock_and_release_vg(cmd, vg_from, vg_name_from);
15386d7f5d3SJohn Marino } else {
15486d7f5d3SJohn Marino unlock_and_release_vg(cmd, vg_from, vg_name_from);
15586d7f5d3SJohn Marino unlock_and_release_vg(cmd, vg_to, vg_name_to);
15686d7f5d3SJohn Marino }
15786d7f5d3SJohn Marino return r;
15886d7f5d3SJohn Marino }
15986d7f5d3SJohn Marino
vgmerge(struct cmd_context * cmd,int argc,char ** argv)16086d7f5d3SJohn Marino int vgmerge(struct cmd_context *cmd, int argc, char **argv)
16186d7f5d3SJohn Marino {
16286d7f5d3SJohn Marino char *vg_name_to, *vg_name_from;
16386d7f5d3SJohn Marino int opt = 0;
16486d7f5d3SJohn Marino int ret = 0, ret_max = 0;
16586d7f5d3SJohn Marino
16686d7f5d3SJohn Marino if (argc < 2) {
16786d7f5d3SJohn Marino log_error("Please enter 2 or more volume groups to merge");
16886d7f5d3SJohn Marino return EINVALID_CMD_LINE;
16986d7f5d3SJohn Marino }
17086d7f5d3SJohn Marino
17186d7f5d3SJohn Marino vg_name_to = skip_dev_dir(cmd, argv[0], NULL);
17286d7f5d3SJohn Marino argc--;
17386d7f5d3SJohn Marino argv++;
17486d7f5d3SJohn Marino
17586d7f5d3SJohn Marino for (; opt < argc; opt++) {
17686d7f5d3SJohn Marino vg_name_from = skip_dev_dir(cmd, argv[opt], NULL);
17786d7f5d3SJohn Marino
17886d7f5d3SJohn Marino ret = _vgmerge_single(cmd, vg_name_to, vg_name_from);
17986d7f5d3SJohn Marino if (ret > ret_max)
18086d7f5d3SJohn Marino ret_max = ret;
18186d7f5d3SJohn Marino }
18286d7f5d3SJohn Marino
18386d7f5d3SJohn Marino return ret_max;
18486d7f5d3SJohn Marino }
185