Home | History | Annotate | Line # | Download | only in tools
      1      1.1  haad /*	$NetBSD: vgsplit.c,v 1.1.1.2 2009/12/02 00:25:46 haad Exp $	*/
      2      1.1  haad 
      3      1.1  haad /*
      4      1.1  haad  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
      5  1.1.1.2  haad  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
      6      1.1  haad  *
      7      1.1  haad  * This file is part of LVM2.
      8      1.1  haad  *
      9      1.1  haad  * This copyrighted material is made available to anyone wishing to use,
     10      1.1  haad  * modify, copy, or redistribute it subject to the terms and conditions
     11      1.1  haad  * of the GNU Lesser General Public License v.2.1.
     12      1.1  haad  *
     13      1.1  haad  * You should have received a copy of the GNU Lesser General Public License
     14      1.1  haad  * along with this program; if not, write to the Free Software Foundation,
     15      1.1  haad  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     16      1.1  haad  */
     17      1.1  haad 
     18      1.1  haad #include "tools.h"
     19      1.1  haad 
     20      1.1  haad /* FIXME Why not (lv->vg == vg) ? */
     21      1.1  haad static int _lv_is_in_vg(struct volume_group *vg, struct logical_volume *lv)
     22      1.1  haad {
     23      1.1  haad 	struct lv_list *lvl;
     24      1.1  haad 
     25      1.1  haad 	dm_list_iterate_items(lvl, &vg->lvs)
     26      1.1  haad 		if (lv == lvl->lv)
     27      1.1  haad 			 return 1;
     28      1.1  haad 
     29      1.1  haad 	return 0;
     30      1.1  haad }
     31      1.1  haad 
     32      1.1  haad static int _move_one_lv(struct volume_group *vg_from,
     33      1.1  haad 			 struct volume_group *vg_to,
     34      1.1  haad 			 struct dm_list *lvh)
     35      1.1  haad {
     36      1.1  haad 	struct logical_volume *lv = dm_list_item(lvh, struct lv_list)->lv;
     37      1.1  haad 
     38      1.1  haad 	dm_list_move(&vg_to->lvs, lvh);
     39  1.1.1.2  haad 
     40      1.1  haad 	if (lv_is_active(lv)) {
     41      1.1  haad 		log_error("Logical volume \"%s\" must be inactive", lv->name);
     42      1.1  haad 		return 0;
     43      1.1  haad 	}
     44      1.1  haad 
     45      1.1  haad 	return 1;
     46  1.1.1.2  haad }
     47      1.1  haad 
     48      1.1  haad static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to)
     49      1.1  haad {
     50      1.1  haad 	struct dm_list *lvh, *lvht;
     51      1.1  haad 	struct logical_volume *lv;
     52      1.1  haad 	struct lv_segment *seg;
     53      1.1  haad 	struct physical_volume *pv;
     54      1.1  haad 	struct volume_group *vg_with;
     55      1.1  haad 	unsigned s;
     56      1.1  haad 
     57      1.1  haad 	dm_list_iterate_safe(lvh, lvht, &vg_from->lvs) {
     58      1.1  haad 		lv = dm_list_item(lvh, struct lv_list)->lv;
     59      1.1  haad 
     60      1.1  haad 		if ((lv->status & SNAPSHOT))
     61      1.1  haad 			continue;
     62      1.1  haad 
     63      1.1  haad 		if ((lv->status & MIRRORED))
     64      1.1  haad 			continue;
     65      1.1  haad 
     66      1.1  haad 		/* Ensure all the PVs used by this LV remain in the same */
     67      1.1  haad 		/* VG as each other */
     68      1.1  haad 		vg_with = NULL;
     69      1.1  haad 		dm_list_iterate_items(seg, &lv->segments) {
     70      1.1  haad 			for (s = 0; s < seg->area_count; s++) {
     71      1.1  haad 				/* FIXME Check AREA_LV too */
     72      1.1  haad 				if (seg_type(seg, s) != AREA_PV)
     73      1.1  haad 					continue;
     74      1.1  haad 
     75      1.1  haad 				pv = seg_pv(seg, s);
     76      1.1  haad 				if (vg_with) {
     77      1.1  haad 					if (!pv_is_in_vg(vg_with, pv)) {
     78      1.1  haad 						log_error("Can't split Logical "
     79      1.1  haad 							  "Volume %s between "
     80      1.1  haad 							  "two Volume Groups",
     81      1.1  haad 							  lv->name);
     82      1.1  haad 						return 0;
     83      1.1  haad 					}
     84      1.1  haad 					continue;
     85      1.1  haad 				}
     86      1.1  haad 
     87      1.1  haad 				if (pv_is_in_vg(vg_from, pv)) {
     88      1.1  haad 					vg_with = vg_from;
     89      1.1  haad 					continue;
     90      1.1  haad 				}
     91      1.1  haad 				if (pv_is_in_vg(vg_to, pv)) {
     92      1.1  haad 					vg_with = vg_to;
     93      1.1  haad 					continue;
     94      1.1  haad 				}
     95      1.1  haad 				log_error("Physical Volume %s not found",
     96      1.1  haad 					  pv_dev_name(pv));
     97      1.1  haad 				return 0;
     98      1.1  haad 			}
     99      1.1  haad 
    100      1.1  haad 		}
    101  1.1.1.2  haad 
    102      1.1  haad 		if (vg_with == vg_from)
    103      1.1  haad 			continue;
    104      1.1  haad 
    105      1.1  haad 		/* Move this LV */
    106      1.1  haad 		if (!_move_one_lv(vg_from, vg_to, lvh))
    107      1.1  haad 			return_0;
    108      1.1  haad 	}
    109      1.1  haad 
    110      1.1  haad 	/* FIXME Ensure no LVs contain segs pointing at LVs in the other VG */
    111      1.1  haad 
    112      1.1  haad 	return 1;
    113      1.1  haad }
    114      1.1  haad 
    115      1.1  haad /*
    116      1.1  haad  * Move the hidden / internal "snapshotN" LVs.from 'vg_from' to 'vg_to'.
    117      1.1  haad  */
    118      1.1  haad static int _move_snapshots(struct volume_group *vg_from,
    119      1.1  haad 			   struct volume_group *vg_to)
    120      1.1  haad {
    121      1.1  haad 	struct dm_list *lvh, *lvht;
    122      1.1  haad 	struct logical_volume *lv;
    123      1.1  haad 	struct lv_segment *seg;
    124      1.1  haad 	int cow_from = 0;
    125      1.1  haad 	int origin_from = 0;
    126      1.1  haad 
    127      1.1  haad 	dm_list_iterate_safe(lvh, lvht, &vg_from->lvs) {
    128      1.1  haad 		lv = dm_list_item(lvh, struct lv_list)->lv;
    129      1.1  haad 
    130      1.1  haad 		if (!(lv->status & SNAPSHOT))
    131      1.1  haad 			continue;
    132      1.1  haad 
    133      1.1  haad 		dm_list_iterate_items(seg, &lv->segments) {
    134      1.1  haad 			cow_from = _lv_is_in_vg(vg_from, seg->cow);
    135      1.1  haad 			origin_from = _lv_is_in_vg(vg_from, seg->origin);
    136      1.1  haad 
    137      1.1  haad 			if (cow_from && origin_from)
    138      1.1  haad 				continue;
    139      1.1  haad 			if ((!cow_from && origin_from) ||
    140      1.1  haad 			     (cow_from && !origin_from)) {
    141      1.1  haad 				log_error("Can't split snapshot %s between"
    142      1.1  haad 					  " two Volume Groups", seg->cow->name);
    143      1.1  haad 				return 0;
    144      1.1  haad 			}
    145      1.1  haad 
    146      1.1  haad 			/*
    147      1.1  haad 			 * At this point, the cow and origin should already be
    148      1.1  haad 			 * in vg_to.
    149      1.1  haad 			 */
    150      1.1  haad 			if (_lv_is_in_vg(vg_to, seg->cow) &&
    151      1.1  haad 			    _lv_is_in_vg(vg_to, seg->origin)) {
    152      1.1  haad 				if (!_move_one_lv(vg_from, vg_to, lvh))
    153      1.1  haad 					return_0;
    154      1.1  haad 			}
    155      1.1  haad 		}
    156      1.1  haad 
    157      1.1  haad 	}
    158      1.1  haad 
    159      1.1  haad 	return 1;
    160      1.1  haad }
    161      1.1  haad 
    162      1.1  haad static int _move_mirrors(struct volume_group *vg_from,
    163      1.1  haad 			 struct volume_group *vg_to)
    164      1.1  haad {
    165      1.1  haad 	struct dm_list *lvh, *lvht;
    166      1.1  haad 	struct logical_volume *lv;
    167      1.1  haad 	struct lv_segment *seg;
    168      1.1  haad 	unsigned s, seg_in, log_in;
    169      1.1  haad 
    170      1.1  haad 	dm_list_iterate_safe(lvh, lvht, &vg_from->lvs) {
    171      1.1  haad 		lv = dm_list_item(lvh, struct lv_list)->lv;
    172      1.1  haad 
    173      1.1  haad 		if (!(lv->status & MIRRORED))
    174      1.1  haad 			continue;
    175      1.1  haad 
    176      1.1  haad 		seg = first_seg(lv);
    177      1.1  haad 
    178      1.1  haad 		seg_in = 0;
    179      1.1  haad 		for (s = 0; s < seg->area_count; s++)
    180      1.1  haad 			if (_lv_is_in_vg(vg_to, seg_lv(seg, s)))
    181      1.1  haad 			    seg_in++;
    182      1.1  haad 
    183      1.1  haad 		log_in = (!seg->log_lv || _lv_is_in_vg(vg_to, seg->log_lv));
    184  1.1.1.2  haad 
    185      1.1  haad 		if ((seg_in && seg_in < seg->area_count) ||
    186      1.1  haad 		    (seg_in && seg->log_lv && !log_in) ||
    187      1.1  haad 		    (!seg_in && seg->log_lv && log_in)) {
    188      1.1  haad 			log_error("Can't split mirror %s between "
    189      1.1  haad 				  "two Volume Groups", lv->name);
    190      1.1  haad 			return 0;
    191      1.1  haad 		}
    192      1.1  haad 
    193      1.1  haad 		if (seg_in == seg->area_count && log_in) {
    194      1.1  haad 			if (!_move_one_lv(vg_from, vg_to, lvh))
    195      1.1  haad 				return_0;
    196      1.1  haad 		}
    197      1.1  haad 	}
    198      1.1  haad 
    199      1.1  haad 	return 1;
    200      1.1  haad }
    201      1.1  haad 
    202      1.1  haad /*
    203  1.1.1.2  haad  * Create or open the destination of the vgsplit operation.
    204  1.1.1.2  haad  * Returns
    205  1.1.1.2  haad  * - non-NULL: VG handle w/VG lock held
    206  1.1.1.2  haad  * - NULL: no VG lock held
    207  1.1.1.2  haad  */
    208  1.1.1.2  haad static struct volume_group *_vgsplit_to(struct cmd_context *cmd,
    209  1.1.1.2  haad 					const char *vg_name_to,
    210  1.1.1.2  haad 					int *existing_vg)
    211  1.1.1.2  haad {
    212  1.1.1.2  haad 	struct volume_group *vg_to = NULL;
    213  1.1.1.2  haad 
    214  1.1.1.2  haad 	log_verbose("Checking for new volume group \"%s\"", vg_name_to);
    215  1.1.1.2  haad 	/*
    216  1.1.1.2  haad 	 * First try to create a new VG.  If we cannot create it,
    217  1.1.1.2  haad 	 * and we get FAILED_EXIST (we will not be holding a lock),
    218  1.1.1.2  haad 	 * a VG must already exist with this name.  We then try to
    219  1.1.1.2  haad 	 * read the existing VG - the vgsplit will be into an existing VG.
    220  1.1.1.2  haad 	 *
    221  1.1.1.2  haad 	 * Otherwise, if the lock was successful, it must be the case that
    222  1.1.1.2  haad 	 * we obtained a WRITE lock and could not find the vgname in the
    223  1.1.1.2  haad 	 * system.  Thus, the split will be into a new VG.
    224  1.1.1.2  haad 	 */
    225  1.1.1.2  haad 	vg_to = vg_create(cmd, vg_name_to);
    226  1.1.1.2  haad 	if (vg_read_error(vg_to) == FAILED_LOCKING) {
    227  1.1.1.2  haad 		log_error("Can't get lock for %s", vg_name_to);
    228  1.1.1.2  haad 		vg_release(vg_to);
    229  1.1.1.2  haad 		return NULL;
    230  1.1.1.2  haad 	}
    231  1.1.1.2  haad 	if (vg_read_error(vg_to) == FAILED_EXIST) {
    232  1.1.1.2  haad 		*existing_vg = 1;
    233  1.1.1.2  haad 		vg_release(vg_to);
    234  1.1.1.2  haad 		vg_to = vg_read_for_update(cmd, vg_name_to, NULL, 0);
    235  1.1.1.2  haad 
    236  1.1.1.2  haad 		if (vg_read_error(vg_to)) {
    237  1.1.1.2  haad 			vg_release(vg_to);
    238  1.1.1.2  haad 			stack;
    239  1.1.1.2  haad 			return NULL;
    240  1.1.1.2  haad 		}
    241  1.1.1.2  haad 
    242  1.1.1.2  haad 	} else if (vg_read_error(vg_to) == SUCCESS) {
    243  1.1.1.2  haad 		*existing_vg = 0;
    244  1.1.1.2  haad 	}
    245  1.1.1.2  haad 	return vg_to;
    246  1.1.1.2  haad }
    247  1.1.1.2  haad 
    248  1.1.1.2  haad /*
    249  1.1.1.2  haad  * Open the source of the vgsplit operation.
    250  1.1.1.2  haad  * Returns
    251  1.1.1.2  haad  * - non-NULL: VG handle w/VG lock held
    252  1.1.1.2  haad  * - NULL: no VG lock held
    253  1.1.1.2  haad  */
    254  1.1.1.2  haad static struct volume_group *_vgsplit_from(struct cmd_context *cmd,
    255  1.1.1.2  haad 					  const char *vg_name_from)
    256  1.1.1.2  haad {
    257  1.1.1.2  haad 	struct volume_group *vg_from;
    258  1.1.1.2  haad 
    259  1.1.1.2  haad 	log_verbose("Checking for volume group \"%s\"", vg_name_from);
    260  1.1.1.2  haad 
    261  1.1.1.2  haad 	vg_from = vg_read_for_update(cmd, vg_name_from, NULL, 0);
    262  1.1.1.2  haad 	if (vg_read_error(vg_from)) {
    263  1.1.1.2  haad 		vg_release(vg_from);
    264  1.1.1.2  haad 		return NULL;
    265  1.1.1.2  haad 	}
    266  1.1.1.2  haad 	return vg_from;
    267  1.1.1.2  haad }
    268  1.1.1.2  haad 
    269  1.1.1.2  haad /*
    270      1.1  haad  * Has the user given an option related to a new vg as the split destination?
    271      1.1  haad  */
    272      1.1  haad static int new_vg_option_specified(struct cmd_context *cmd)
    273      1.1  haad {
    274      1.1  haad 	return(arg_count(cmd, clustered_ARG) ||
    275      1.1  haad 	       arg_count(cmd, alloc_ARG) ||
    276      1.1  haad 	       arg_count(cmd, maxphysicalvolumes_ARG) ||
    277      1.1  haad 	       arg_count(cmd, maxlogicalvolumes_ARG));
    278      1.1  haad }
    279      1.1  haad 
    280      1.1  haad int vgsplit(struct cmd_context *cmd, int argc, char **argv)
    281      1.1  haad {
    282      1.1  haad 	struct vgcreate_params vp_new;
    283      1.1  haad 	struct vgcreate_params vp_def;
    284      1.1  haad 	char *vg_name_from, *vg_name_to;
    285  1.1.1.2  haad 	struct volume_group *vg_to = NULL, *vg_from = NULL;
    286      1.1  haad 	int opt;
    287  1.1.1.2  haad 	int existing_vg = 0;
    288  1.1.1.2  haad 	int r = ECMD_FAILED;
    289      1.1  haad 	const char *lv_name;
    290  1.1.1.2  haad 	int lock_vg_from_first = 1;
    291      1.1  haad 
    292      1.1  haad 	if ((arg_count(cmd, name_ARG) + argc) < 3) {
    293      1.1  haad 		log_error("Existing VG, new VG and either physical volumes "
    294      1.1  haad 			  "or logical volume required.");
    295      1.1  haad 		return EINVALID_CMD_LINE;
    296      1.1  haad 	}
    297      1.1  haad 
    298      1.1  haad 	if (arg_count(cmd, name_ARG) && (argc > 2)) {
    299      1.1  haad 		log_error("A logical volume name cannot be given with "
    300      1.1  haad 			  "physical volumes.");
    301      1.1  haad 		return ECMD_FAILED;
    302      1.1  haad 	}
    303      1.1  haad 
    304      1.1  haad 	if (arg_count(cmd, name_ARG))
    305      1.1  haad 		lv_name = arg_value(cmd, name_ARG);
    306      1.1  haad 	else
    307      1.1  haad 		lv_name = NULL;
    308      1.1  haad 
    309      1.1  haad 	vg_name_from = skip_dev_dir(cmd, argv[0], NULL);
    310      1.1  haad 	vg_name_to = skip_dev_dir(cmd, argv[1], NULL);
    311      1.1  haad 	argc -= 2;
    312      1.1  haad 	argv += 2;
    313      1.1  haad 
    314      1.1  haad 	if (!strcmp(vg_name_to, vg_name_from)) {
    315      1.1  haad 		log_error("Duplicate volume group name \"%s\"", vg_name_from);
    316      1.1  haad 		return ECMD_FAILED;
    317      1.1  haad 	}
    318      1.1  haad 
    319  1.1.1.2  haad 	if (strcmp(vg_name_to, vg_name_from) < 0)
    320  1.1.1.2  haad 		lock_vg_from_first = 0;
    321      1.1  haad 
    322  1.1.1.2  haad 	if (lock_vg_from_first) {
    323  1.1.1.2  haad 		vg_from = _vgsplit_from(cmd, vg_name_from);
    324  1.1.1.2  haad 		if (!vg_from) {
    325  1.1.1.2  haad 			stack;
    326  1.1.1.2  haad 			return ECMD_FAILED;
    327  1.1.1.2  haad 		}
    328  1.1.1.2  haad 		/*
    329  1.1.1.2  haad 		 * Set metadata format of original VG.
    330  1.1.1.2  haad 		 * NOTE: We must set the format before calling vg_create()
    331  1.1.1.2  haad 		 * since vg_create() calls the per-format constructor.
    332  1.1.1.2  haad 		 */
    333  1.1.1.2  haad 		cmd->fmt = vg_from->fid->fmt;
    334  1.1.1.2  haad 
    335  1.1.1.2  haad 		vg_to = _vgsplit_to(cmd, vg_name_to, &existing_vg);
    336  1.1.1.2  haad 		if (!vg_to) {
    337  1.1.1.2  haad 			unlock_and_release_vg(cmd, vg_from, vg_name_from);
    338  1.1.1.2  haad 			stack;
    339  1.1.1.2  haad 			return ECMD_FAILED;
    340  1.1.1.2  haad 		}
    341  1.1.1.2  haad 	} else {
    342  1.1.1.2  haad 		vg_to = _vgsplit_to(cmd, vg_name_to, &existing_vg);
    343  1.1.1.2  haad 		if (!vg_to) {
    344  1.1.1.2  haad 			stack;
    345  1.1.1.2  haad 			return ECMD_FAILED;
    346  1.1.1.2  haad 		}
    347  1.1.1.2  haad 		vg_from = _vgsplit_from(cmd, vg_name_from);
    348  1.1.1.2  haad 		if (!vg_from) {
    349  1.1.1.2  haad 			unlock_and_release_vg(cmd, vg_to, vg_name_to);
    350  1.1.1.2  haad 			stack;
    351  1.1.1.2  haad 			return ECMD_FAILED;
    352  1.1.1.2  haad 		}
    353  1.1.1.2  haad 
    354  1.1.1.2  haad 		if (cmd->fmt != vg_from->fid->fmt) {
    355  1.1.1.2  haad 			/* In this case we don't know the vg_from->fid->fmt */
    356  1.1.1.2  haad 			log_error("Unable to set new VG metadata type based on "
    357  1.1.1.2  haad 				  "source VG format - use -M option.");
    358  1.1.1.2  haad 			goto bad;
    359  1.1.1.2  haad 		}
    360      1.1  haad 	}
    361      1.1  haad 
    362  1.1.1.2  haad 	if (existing_vg) {
    363      1.1  haad 		if (new_vg_option_specified(cmd)) {
    364      1.1  haad 			log_error("Volume group \"%s\" exists, but new VG "
    365      1.1  haad 				    "option specified", vg_name_to);
    366  1.1.1.2  haad 			goto bad;
    367      1.1  haad 		}
    368      1.1  haad 		if (!vgs_are_compatible(cmd, vg_from,vg_to))
    369      1.1  haad 			goto_bad;
    370      1.1  haad 	} else {
    371  1.1.1.2  haad 		vgcreate_params_set_defaults(&vp_def, vg_from);
    372  1.1.1.2  haad 		vp_def.vg_name = vg_name_to;
    373  1.1.1.2  haad 		if (vgcreate_params_set_from_args(cmd, &vp_new, &vp_def)) {
    374  1.1.1.2  haad 			r = EINVALID_CMD_LINE;
    375  1.1.1.2  haad 			goto_bad;
    376  1.1.1.2  haad 		}
    377      1.1  haad 
    378  1.1.1.2  haad 		if (vgcreate_params_validate(cmd, &vp_new)) {
    379  1.1.1.2  haad 			r = EINVALID_CMD_LINE;
    380      1.1  haad 			goto_bad;
    381  1.1.1.2  haad 		}
    382      1.1  haad 
    383  1.1.1.2  haad 		if (!vg_set_extent_size(vg_to, vp_new.extent_size) ||
    384  1.1.1.2  haad 		    !vg_set_max_lv(vg_to, vp_new.max_lv) ||
    385  1.1.1.2  haad 		    !vg_set_max_pv(vg_to, vp_new.max_pv) ||
    386  1.1.1.2  haad 		    !vg_set_alloc_policy(vg_to, vp_new.alloc) ||
    387  1.1.1.2  haad 		    !vg_set_clustered(vg_to, vp_new.clustered))
    388  1.1.1.2  haad 			goto_bad;
    389      1.1  haad 	}
    390      1.1  haad 
    391      1.1  haad 	/* Archive vg_from before changing it */
    392      1.1  haad 	if (!archive(vg_from))
    393      1.1  haad 		goto_bad;
    394      1.1  haad 
    395      1.1  haad 	/* Move PVs across to new structure */
    396      1.1  haad 	for (opt = 0; opt < argc; opt++) {
    397  1.1.1.2  haad 		if (!move_pv(vg_from, vg_to, argv[opt]))
    398      1.1  haad 			goto_bad;
    399      1.1  haad 	}
    400      1.1  haad 
    401      1.1  haad 	/* If an LV given on the cmdline, move used_by PVs */
    402  1.1.1.2  haad 	if (lv_name && !move_pvs_used_by_lv(vg_from, vg_to, lv_name))
    403      1.1  haad 		goto_bad;
    404      1.1  haad 
    405      1.1  haad 	/* Move required LVs across, checking consistency */
    406      1.1  haad 	if (!(_move_lvs(vg_from, vg_to)))
    407      1.1  haad 		goto_bad;
    408      1.1  haad 
    409  1.1.1.2  haad 	/* FIXME Separate the 'move' from the 'validation' to fix dev stacks */
    410      1.1  haad 	/* Move required mirrors across */
    411      1.1  haad 	if (!(_move_mirrors(vg_from, vg_to)))
    412      1.1  haad 		goto_bad;
    413      1.1  haad 
    414  1.1.1.2  haad 	/* Move required snapshots across */
    415  1.1.1.2  haad 	if (!(_move_snapshots(vg_from, vg_to)))
    416  1.1.1.2  haad 		goto_bad;
    417  1.1.1.2  haad 
    418      1.1  haad 	/* Split metadata areas and check if both vgs have at least one area */
    419      1.1  haad 	if (!(vg_split_mdas(cmd, vg_from, vg_to)) && vg_from->pv_count) {
    420      1.1  haad 		log_error("Cannot split: Nowhere to store metadata for new Volume Group");
    421  1.1.1.2  haad 		goto bad;
    422      1.1  haad 	}
    423      1.1  haad 
    424      1.1  haad 	/* Set proper name for all PVs in new VG */
    425      1.1  haad 	if (!vg_rename(cmd, vg_to, vg_name_to))
    426      1.1  haad 		goto_bad;
    427      1.1  haad 
    428      1.1  haad 	/* store it on disks */
    429      1.1  haad 	log_verbose("Writing out updated volume groups");
    430      1.1  haad 
    431      1.1  haad 	/*
    432      1.1  haad 	 * First, write out the new VG as EXPORTED.  We do this first in case
    433      1.1  haad 	 * there is a crash - we will still have the new VG information, in an
    434      1.1  haad 	 * exported state.  Recovery after this point would be removal of the
    435      1.1  haad 	 * new VG and redoing the vgsplit.
    436      1.1  haad 	 * FIXME: recover automatically or instruct the user?
    437      1.1  haad 	 */
    438      1.1  haad 	vg_to->status |= EXPORTED_VG;
    439      1.1  haad 
    440      1.1  haad 	if (!archive(vg_to))
    441      1.1  haad 		goto_bad;
    442      1.1  haad 
    443      1.1  haad 	if (!vg_write(vg_to) || !vg_commit(vg_to))
    444      1.1  haad 		goto_bad;
    445      1.1  haad 
    446      1.1  haad 	backup(vg_to);
    447      1.1  haad 
    448      1.1  haad 	/*
    449      1.1  haad 	 * Next, write out the updated old VG.  If we crash after this point,
    450      1.1  haad 	 * recovery is a vgimport on the new VG.
    451      1.1  haad 	 * FIXME: recover automatically or instruct the user?
    452      1.1  haad 	 */
    453      1.1  haad 	if (vg_from->pv_count) {
    454      1.1  haad 		if (!vg_write(vg_from) || !vg_commit(vg_from))
    455      1.1  haad 			goto_bad;
    456      1.1  haad 
    457      1.1  haad 		backup(vg_from);
    458      1.1  haad 	}
    459      1.1  haad 
    460      1.1  haad 	/*
    461      1.1  haad 	 * Finally, remove the EXPORTED flag from the new VG and write it out.
    462      1.1  haad 	 */
    463  1.1.1.2  haad 	if (!test_mode()) {
    464  1.1.1.2  haad 		vg_release(vg_to);
    465  1.1.1.2  haad 		vg_to = vg_read_for_update(cmd, vg_name_to, NULL,
    466  1.1.1.2  haad 					   READ_ALLOW_EXPORTED);
    467  1.1.1.2  haad 		if (vg_read_error(vg_to)) {
    468  1.1.1.2  haad 			log_error("Volume group \"%s\" became inconsistent: "
    469  1.1.1.2  haad 				  "please fix manually", vg_name_to);
    470  1.1.1.2  haad 			goto bad;
    471  1.1.1.2  haad 		}
    472      1.1  haad 	}
    473      1.1  haad 
    474      1.1  haad 	vg_to->status &= ~EXPORTED_VG;
    475      1.1  haad 
    476      1.1  haad 	if (!vg_write(vg_to) || !vg_commit(vg_to))
    477      1.1  haad 		goto_bad;
    478      1.1  haad 
    479      1.1  haad 	backup(vg_to);
    480      1.1  haad 
    481      1.1  haad 	log_print("%s volume group \"%s\" successfully split from \"%s\"",
    482      1.1  haad 		  existing_vg ? "Existing" : "New",
    483      1.1  haad 		  vg_to->name, vg_from->name);
    484      1.1  haad 
    485  1.1.1.2  haad 	r = ECMD_PROCESSED;
    486  1.1.1.2  haad 
    487  1.1.1.2  haad bad:
    488  1.1.1.2  haad 	if (lock_vg_from_first) {
    489  1.1.1.2  haad 		unlock_and_release_vg(cmd, vg_to, vg_name_to);
    490  1.1.1.2  haad 		unlock_and_release_vg(cmd, vg_from, vg_name_from);
    491  1.1.1.2  haad 	} else {
    492  1.1.1.2  haad 		unlock_and_release_vg(cmd, vg_from, vg_name_from);
    493  1.1.1.2  haad 		unlock_and_release_vg(cmd, vg_to, vg_name_to);
    494  1.1.1.2  haad 	}
    495  1.1.1.2  haad 	return r;
    496      1.1  haad }
    497