Home | History | Annotate | Line # | Download | only in tools
pvmove.c revision 1.1.1.2
      1      1.1  haad /*	$NetBSD: pvmove.c,v 1.1.1.2 2009/12/02 00:25:54 haad Exp $	*/
      2      1.1  haad 
      3      1.1  haad /*
      4      1.1  haad  * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
      5      1.1  haad  * Copyright (C) 2004-2007 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 #include "polldaemon.h"
     20      1.1  haad #include "display.h"
     21      1.1  haad 
     22      1.1  haad #define PVMOVE_FIRST_TIME   0x00000001      /* Called for first time */
     23      1.1  haad 
     24      1.1  haad static int _pvmove_target_present(struct cmd_context *cmd, int clustered)
     25      1.1  haad {
     26      1.1  haad 	const struct segment_type *segtype;
     27      1.1  haad 	unsigned attr = 0;
     28      1.1  haad 	int found = 1;
     29      1.1  haad 	static int _clustered_found = -1;
     30      1.1  haad 
     31      1.1  haad 	if (clustered && _clustered_found >= 0)
     32      1.1  haad 		return _clustered_found;
     33      1.1  haad 
     34      1.1  haad 	if (!(segtype = get_segtype_from_string(cmd, "mirror")))
     35      1.1  haad 		return_0;
     36      1.1  haad 
     37      1.1  haad 	if (activation() && segtype->ops->target_present &&
     38  1.1.1.2  haad 	    !segtype->ops->target_present(cmd, NULL, clustered ? &attr : NULL))
     39      1.1  haad 		found = 0;
     40      1.1  haad 
     41      1.1  haad 	if (activation() && clustered) {
     42      1.1  haad 		if (found && (attr & MIRROR_LOG_CLUSTERED))
     43      1.1  haad 			_clustered_found = found = 1;
     44      1.1  haad 		else
     45      1.1  haad 			_clustered_found = found = 0;
     46      1.1  haad 	}
     47      1.1  haad 
     48      1.1  haad 	return found;
     49      1.1  haad }
     50      1.1  haad 
     51      1.1  haad static unsigned _pvmove_is_exclusive(struct cmd_context *cmd,
     52      1.1  haad 				     struct volume_group *vg)
     53      1.1  haad {
     54      1.1  haad 	if (vg_is_clustered(vg))
     55      1.1  haad 		if (!_pvmove_target_present(cmd, 1))
     56      1.1  haad 			return 1;
     57      1.1  haad 
     58      1.1  haad 	return 0;
     59      1.1  haad }
     60      1.1  haad 
     61      1.1  haad /* Allow /dev/vgname/lvname, vgname/lvname or lvname */
     62      1.1  haad static const char *_extract_lvname(struct cmd_context *cmd, const char *vgname,
     63      1.1  haad 				   const char *arg)
     64      1.1  haad {
     65      1.1  haad 	const char *lvname;
     66      1.1  haad 
     67      1.1  haad 	/* Is an lvname supplied directly? */
     68      1.1  haad 	if (!strchr(arg, '/'))
     69      1.1  haad 		return arg;
     70      1.1  haad 
     71      1.1  haad 	lvname = skip_dev_dir(cmd, arg, NULL);
     72      1.1  haad 	while (*lvname == '/')
     73      1.1  haad 		lvname++;
     74      1.1  haad 	if (!strchr(lvname, '/')) {
     75      1.1  haad 		log_error("--name takes a logical volume name");
     76      1.1  haad 		return NULL;
     77      1.1  haad 	}
     78      1.1  haad 	if (strncmp(vgname, lvname, strlen(vgname)) ||
     79      1.1  haad 	    (lvname += strlen(vgname), *lvname != '/')) {
     80      1.1  haad 		log_error("Named LV and old PV must be in the same VG");
     81      1.1  haad 		return NULL;
     82      1.1  haad 	}
     83      1.1  haad 	while (*lvname == '/')
     84      1.1  haad 		lvname++;
     85      1.1  haad 	if (!*lvname) {
     86      1.1  haad 		log_error("Incomplete LV name supplied with --name");
     87      1.1  haad 		return NULL;
     88      1.1  haad 	}
     89      1.1  haad 	return lvname;
     90      1.1  haad }
     91      1.1  haad 
     92      1.1  haad static struct volume_group *_get_vg(struct cmd_context *cmd, const char *vgname)
     93      1.1  haad {
     94      1.1  haad 	dev_close_all();
     95      1.1  haad 
     96  1.1.1.2  haad 	return vg_read_for_update(cmd, vgname, NULL, 0);
     97      1.1  haad }
     98      1.1  haad 
     99      1.1  haad /* Create list of PVs for allocation of replacement extents */
    100      1.1  haad static struct dm_list *_get_allocatable_pvs(struct cmd_context *cmd, int argc,
    101      1.1  haad 					 char **argv, struct volume_group *vg,
    102      1.1  haad 					 struct physical_volume *pv,
    103      1.1  haad 					 alloc_policy_t alloc)
    104      1.1  haad {
    105      1.1  haad 	struct dm_list *allocatable_pvs, *pvht, *pvh;
    106      1.1  haad 	struct pv_list *pvl;
    107      1.1  haad 
    108      1.1  haad 	if (argc)
    109      1.1  haad 		allocatable_pvs = create_pv_list(cmd->mem, vg, argc, argv, 1);
    110      1.1  haad 	else
    111      1.1  haad 		allocatable_pvs = clone_pv_list(cmd->mem, &vg->pvs);
    112      1.1  haad 
    113      1.1  haad 	if (!allocatable_pvs)
    114      1.1  haad 		return_NULL;
    115      1.1  haad 
    116      1.1  haad 	dm_list_iterate_safe(pvh, pvht, allocatable_pvs) {
    117      1.1  haad 		pvl = dm_list_item(pvh, struct pv_list);
    118      1.1  haad 
    119      1.1  haad 		/* Don't allocate onto the PV we're clearing! */
    120      1.1  haad 		if ((alloc != ALLOC_ANYWHERE) && (pvl->pv->dev == pv_dev(pv))) {
    121      1.1  haad 			dm_list_del(&pvl->list);
    122      1.1  haad 			continue;
    123      1.1  haad 		}
    124      1.1  haad 
    125      1.1  haad 		/* Remove PV if full */
    126      1.1  haad 		if ((pvl->pv->pe_count == pvl->pv->pe_alloc_count))
    127      1.1  haad 			dm_list_del(&pvl->list);
    128      1.1  haad 	}
    129      1.1  haad 
    130      1.1  haad 	if (dm_list_empty(allocatable_pvs)) {
    131      1.1  haad 		log_error("No extents available for allocation");
    132      1.1  haad 		return NULL;
    133      1.1  haad 	}
    134      1.1  haad 
    135      1.1  haad 	return allocatable_pvs;
    136      1.1  haad }
    137      1.1  haad 
    138      1.1  haad /*
    139      1.1  haad  * Replace any LV segments on given PV with temporary mirror.
    140      1.1  haad  * Returns list of LVs changed.
    141      1.1  haad  */
    142      1.1  haad static int _insert_pvmove_mirrors(struct cmd_context *cmd,
    143      1.1  haad 				  struct logical_volume *lv_mirr,
    144      1.1  haad 				  struct dm_list *source_pvl,
    145      1.1  haad 				  struct logical_volume *lv,
    146      1.1  haad 				  struct dm_list *lvs_changed)
    147      1.1  haad 
    148      1.1  haad {
    149      1.1  haad 	struct pv_list *pvl;
    150      1.1  haad 	uint32_t prev_le_count;
    151      1.1  haad 
    152      1.1  haad 	/* Only 1 PV may feature in source_pvl */
    153      1.1  haad 	pvl = dm_list_item(source_pvl->n, struct pv_list);
    154      1.1  haad 
    155      1.1  haad 	prev_le_count = lv_mirr->le_count;
    156      1.1  haad 	if (!insert_layer_for_segments_on_pv(cmd, lv, lv_mirr, PVMOVE,
    157      1.1  haad 					     pvl, lvs_changed))
    158      1.1  haad 		return_0;
    159      1.1  haad 
    160      1.1  haad 	/* check if layer was inserted */
    161      1.1  haad 	if (lv_mirr->le_count - prev_le_count) {
    162      1.1  haad 		lv->status |= LOCKED;
    163      1.1  haad 
    164      1.1  haad 		log_verbose("Moving %u extents of logical volume %s/%s",
    165      1.1  haad 			    lv_mirr->le_count - prev_le_count,
    166      1.1  haad 			    lv->vg->name, lv->name);
    167      1.1  haad 	}
    168      1.1  haad 
    169      1.1  haad 	return 1;
    170      1.1  haad }
    171      1.1  haad 
    172      1.1  haad /* Create new LV with mirror segments for the required copies */
    173      1.1  haad static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
    174      1.1  haad 						struct volume_group *vg,
    175      1.1  haad 						struct dm_list *source_pvl,
    176      1.1  haad 						const char *lv_name,
    177      1.1  haad 						struct dm_list *allocatable_pvs,
    178      1.1  haad 						alloc_policy_t alloc,
    179      1.1  haad 						struct dm_list **lvs_changed)
    180      1.1  haad {
    181      1.1  haad 	struct logical_volume *lv_mirr, *lv;
    182      1.1  haad 	struct lv_list *lvl;
    183      1.1  haad 	uint32_t log_count = 0;
    184      1.1  haad 	int lv_found = 0;
    185      1.1  haad 
    186      1.1  haad 	/* FIXME Cope with non-contiguous => splitting existing segments */
    187      1.1  haad 	if (!(lv_mirr = lv_create_empty("pvmove%d", NULL,
    188      1.1  haad 					LVM_READ | LVM_WRITE,
    189  1.1.1.2  haad 					ALLOC_CONTIGUOUS, vg))) {
    190      1.1  haad 		log_error("Creation of temporary pvmove LV failed");
    191      1.1  haad 		return NULL;
    192      1.1  haad 	}
    193      1.1  haad 
    194      1.1  haad 	lv_mirr->status |= (PVMOVE | LOCKED);
    195      1.1  haad 
    196      1.1  haad 	if (!(*lvs_changed = dm_pool_alloc(cmd->mem, sizeof(**lvs_changed)))) {
    197      1.1  haad 		log_error("lvs_changed list struct allocation failed");
    198      1.1  haad 		return NULL;
    199      1.1  haad 	}
    200      1.1  haad 
    201      1.1  haad 	dm_list_init(*lvs_changed);
    202      1.1  haad 
    203      1.1  haad 	/* Find segments to be moved and set up mirrors */
    204      1.1  haad 	dm_list_iterate_items(lvl, &vg->lvs) {
    205      1.1  haad 		lv = lvl->lv;
    206      1.1  haad 		if ((lv == lv_mirr))
    207      1.1  haad 			continue;
    208      1.1  haad 		if (lv_name) {
    209      1.1  haad 			if (strcmp(lv->name, lv_name))
    210      1.1  haad 				continue;
    211      1.1  haad 			lv_found = 1;
    212      1.1  haad 		}
    213      1.1  haad 		if (lv_is_origin(lv) || lv_is_cow(lv)) {
    214      1.1  haad 			log_print("Skipping snapshot-related LV %s", lv->name);
    215      1.1  haad 			continue;
    216      1.1  haad 		}
    217      1.1  haad 		if (lv->status & MIRRORED) {
    218      1.1  haad 			log_print("Skipping mirror LV %s", lv->name);
    219      1.1  haad 			continue;
    220      1.1  haad 		}
    221      1.1  haad 		if (lv->status & MIRROR_LOG) {
    222      1.1  haad 			log_print("Skipping mirror log LV %s", lv->name);
    223      1.1  haad 			continue;
    224      1.1  haad 		}
    225      1.1  haad 		if (lv->status & MIRROR_IMAGE) {
    226      1.1  haad 			log_print("Skipping mirror image LV %s", lv->name);
    227      1.1  haad 			continue;
    228      1.1  haad 		}
    229      1.1  haad 		if (lv->status & LOCKED) {
    230      1.1  haad 			log_print("Skipping locked LV %s", lv->name);
    231      1.1  haad 			continue;
    232      1.1  haad 		}
    233      1.1  haad 		if (!_insert_pvmove_mirrors(cmd, lv_mirr, source_pvl, lv,
    234      1.1  haad 					    *lvs_changed))
    235      1.1  haad 			return_NULL;
    236      1.1  haad 	}
    237      1.1  haad 
    238      1.1  haad 	if (lv_name && !lv_found) {
    239      1.1  haad 		log_error("Logical volume %s not found.", lv_name);
    240      1.1  haad 		return NULL;
    241      1.1  haad 	}
    242      1.1  haad 
    243      1.1  haad 	/* Is temporary mirror empty? */
    244      1.1  haad 	if (!lv_mirr->le_count) {
    245      1.1  haad 		log_error("No data to move for %s", vg->name);
    246      1.1  haad 		return NULL;
    247      1.1  haad 	}
    248      1.1  haad 
    249      1.1  haad 	if (!lv_add_mirrors(cmd, lv_mirr, 1, 1, 0, log_count,
    250      1.1  haad 			    allocatable_pvs, alloc, MIRROR_BY_SEG)) {
    251      1.1  haad 		log_error("Failed to convert pvmove LV to mirrored");
    252      1.1  haad 		return_NULL;
    253      1.1  haad 	}
    254      1.1  haad 
    255      1.1  haad 	if (!split_parent_segments_for_layer(cmd, lv_mirr)) {
    256      1.1  haad 		log_error("Failed to split segments being moved");
    257      1.1  haad 		return_NULL;
    258      1.1  haad 	}
    259      1.1  haad 
    260      1.1  haad 	return lv_mirr;
    261      1.1  haad }
    262      1.1  haad 
    263      1.1  haad static int _activate_lv(struct cmd_context *cmd, struct logical_volume *lv_mirr,
    264      1.1  haad 			unsigned exclusive)
    265      1.1  haad {
    266      1.1  haad 	if (exclusive)
    267      1.1  haad 		return activate_lv_excl(cmd, lv_mirr);
    268      1.1  haad 
    269      1.1  haad 	return activate_lv(cmd, lv_mirr);
    270      1.1  haad }
    271      1.1  haad 
    272  1.1.1.2  haad static int _finish_pvmove(struct cmd_context *cmd, struct volume_group *vg,
    273  1.1.1.2  haad 			  struct logical_volume *lv_mirr,
    274  1.1.1.2  haad 			  struct dm_list *lvs_changed);
    275  1.1.1.2  haad 
    276      1.1  haad static int _update_metadata(struct cmd_context *cmd, struct volume_group *vg,
    277      1.1  haad 			    struct logical_volume *lv_mirr,
    278      1.1  haad 			    struct dm_list *lvs_changed, unsigned flags)
    279      1.1  haad {
    280      1.1  haad 	unsigned exclusive = _pvmove_is_exclusive(cmd, vg);
    281      1.1  haad 	unsigned first_time = (flags & PVMOVE_FIRST_TIME) ? 1 : 0;
    282  1.1.1.2  haad 	int r = 0;
    283      1.1  haad 
    284      1.1  haad 	log_verbose("Updating volume group metadata");
    285      1.1  haad 	if (!vg_write(vg)) {
    286      1.1  haad 		log_error("ABORTING: Volume group metadata update failed.");
    287      1.1  haad 		return 0;
    288      1.1  haad 	}
    289      1.1  haad 
    290      1.1  haad 	/* Suspend lvs_changed */
    291      1.1  haad 	if (!suspend_lvs(cmd, lvs_changed))
    292  1.1.1.2  haad 		goto_out;
    293      1.1  haad 
    294      1.1  haad 	/* Suspend mirrors on subsequent calls */
    295      1.1  haad 	if (!first_time) {
    296      1.1  haad 		if (!suspend_lv(cmd, lv_mirr)) {
    297      1.1  haad 			resume_lvs(cmd, lvs_changed);
    298      1.1  haad 			vg_revert(vg);
    299  1.1.1.2  haad 			goto_out;
    300      1.1  haad 		}
    301      1.1  haad 	}
    302      1.1  haad 
    303      1.1  haad 	/* Commit on-disk metadata */
    304      1.1  haad 	if (!vg_commit(vg)) {
    305      1.1  haad 		log_error("ABORTING: Volume group metadata update failed.");
    306      1.1  haad 		if (!first_time)
    307      1.1  haad 			resume_lv(cmd, lv_mirr);
    308      1.1  haad 		resume_lvs(cmd, lvs_changed);
    309  1.1.1.2  haad 		goto out;
    310      1.1  haad 	}
    311      1.1  haad 
    312      1.1  haad 	/* Activate the temporary mirror LV */
    313      1.1  haad 	/* Only the first mirror segment gets activated as a mirror */
    314      1.1  haad 	/* FIXME: Add option to use a log */
    315      1.1  haad 	if (first_time) {
    316      1.1  haad 		if (!_activate_lv(cmd, lv_mirr, exclusive)) {
    317  1.1.1.2  haad 			if (test_mode())
    318  1.1.1.2  haad 				goto out;
    319  1.1.1.2  haad 
    320  1.1.1.2  haad 			/*
    321  1.1.1.2  haad 			 * Nothing changed yet, try to revert pvmove.
    322  1.1.1.2  haad 			 */
    323  1.1.1.2  haad 			log_error("Temporary pvmove mirror activation failed.");
    324  1.1.1.2  haad 			if (!_finish_pvmove(cmd, vg, lv_mirr, lvs_changed))
    325  1.1.1.2  haad 				log_error("ABORTING: Restoring original configuration "
    326  1.1.1.2  haad 					  "before pvmove failed. Run pvmove --abort.");
    327  1.1.1.2  haad 			goto out;
    328      1.1  haad 		}
    329      1.1  haad 	} else if (!resume_lv(cmd, lv_mirr)) {
    330      1.1  haad 		log_error("Unable to reactivate logical volume \"%s\"",
    331      1.1  haad 			  lv_mirr->name);
    332      1.1  haad 		resume_lvs(cmd, lvs_changed);
    333  1.1.1.2  haad 		goto out;
    334      1.1  haad 	}
    335      1.1  haad 
    336      1.1  haad 	/* Unsuspend LVs */
    337      1.1  haad 	if (!resume_lvs(cmd, lvs_changed)) {
    338      1.1  haad 		log_error("Unable to resume logical volumes");
    339  1.1.1.2  haad 		goto out;
    340      1.1  haad 	}
    341      1.1  haad 
    342  1.1.1.2  haad 	r = 1;
    343  1.1.1.2  haad out:
    344  1.1.1.2  haad 	backup(vg);
    345  1.1.1.2  haad 	return r;
    346      1.1  haad }
    347      1.1  haad 
    348      1.1  haad static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
    349      1.1  haad 			  int argc, char **argv)
    350      1.1  haad {
    351      1.1  haad 	const char *lv_name = NULL;
    352      1.1  haad 	char *pv_name_arg;
    353      1.1  haad 	struct volume_group *vg;
    354      1.1  haad 	struct dm_list *source_pvl;
    355      1.1  haad 	struct dm_list *allocatable_pvs;
    356      1.1  haad 	alloc_policy_t alloc;
    357      1.1  haad 	struct dm_list *lvs_changed;
    358      1.1  haad 	struct physical_volume *pv;
    359      1.1  haad 	struct logical_volume *lv_mirr;
    360      1.1  haad 	unsigned first_time = 1;
    361      1.1  haad 	unsigned exclusive;
    362  1.1.1.2  haad 	int r = ECMD_FAILED;
    363      1.1  haad 
    364      1.1  haad 	pv_name_arg = argv[0];
    365      1.1  haad 	argc--;
    366      1.1  haad 	argv++;
    367      1.1  haad 
    368      1.1  haad 	/* Find PV (in VG) */
    369      1.1  haad 	if (!(pv = find_pv_by_name(cmd, pv_name))) {
    370      1.1  haad 		stack;
    371      1.1  haad 		return EINVALID_CMD_LINE;
    372      1.1  haad 	}
    373      1.1  haad 
    374      1.1  haad 	if (arg_count(cmd, name_ARG)) {
    375      1.1  haad 		if (!(lv_name = _extract_lvname(cmd, pv_vg_name(pv),
    376      1.1  haad 						arg_value(cmd, name_ARG)))) {
    377      1.1  haad 			stack;
    378      1.1  haad 			return EINVALID_CMD_LINE;
    379      1.1  haad 		}
    380      1.1  haad 
    381      1.1  haad 		if (!validate_name(lv_name)) {
    382      1.1  haad 			log_error("Logical volume name %s is invalid", lv_name);
    383      1.1  haad 			return EINVALID_CMD_LINE;
    384      1.1  haad 		}
    385      1.1  haad 	}
    386      1.1  haad 
    387      1.1  haad 	/* Read VG */
    388      1.1  haad 	log_verbose("Finding volume group \"%s\"", pv_vg_name(pv));
    389      1.1  haad 
    390  1.1.1.2  haad 	vg = _get_vg(cmd, pv_vg_name(pv));
    391  1.1.1.2  haad 	if (vg_read_error(vg)) {
    392  1.1.1.2  haad 		vg_release(vg);
    393      1.1  haad 		stack;
    394      1.1  haad 		return ECMD_FAILED;
    395      1.1  haad 	}
    396      1.1  haad 
    397      1.1  haad 	exclusive = _pvmove_is_exclusive(cmd, vg);
    398      1.1  haad 
    399      1.1  haad 	if ((lv_mirr = find_pvmove_lv(vg, pv_dev(pv), PVMOVE))) {
    400      1.1  haad 		log_print("Detected pvmove in progress for %s", pv_name);
    401      1.1  haad 		if (argc || lv_name)
    402      1.1  haad 			log_error("Ignoring remaining command line arguments");
    403      1.1  haad 
    404      1.1  haad 		if (!(lvs_changed = lvs_using_lv(cmd, vg, lv_mirr))) {
    405  1.1.1.2  haad 			log_error("ABORTING: Failed to generate list of moving LVs");
    406  1.1.1.2  haad 			goto out;
    407      1.1  haad 		}
    408      1.1  haad 
    409      1.1  haad 		/* Ensure mirror LV is active */
    410      1.1  haad 		if (!_activate_lv(cmd, lv_mirr, exclusive)) {
    411  1.1.1.2  haad 			log_error("ABORTING: Temporary mirror activation failed.");
    412  1.1.1.2  haad 			goto out;
    413      1.1  haad 		}
    414      1.1  haad 
    415      1.1  haad 		first_time = 0;
    416      1.1  haad 	} else {
    417      1.1  haad 		/* Determine PE ranges to be moved */
    418      1.1  haad 		if (!(source_pvl = create_pv_list(cmd->mem, vg, 1,
    419  1.1.1.2  haad 						  &pv_name_arg, 0)))
    420  1.1.1.2  haad 			goto_out;
    421      1.1  haad 
    422      1.1  haad 		alloc = arg_uint_value(cmd, alloc_ARG, ALLOC_INHERIT);
    423      1.1  haad 		if (alloc == ALLOC_INHERIT)
    424      1.1  haad 			alloc = vg->alloc;
    425      1.1  haad 
    426      1.1  haad 		/* Get PVs we can use for allocation */
    427      1.1  haad 		if (!(allocatable_pvs = _get_allocatable_pvs(cmd, argc, argv,
    428  1.1.1.2  haad 							     vg, pv, alloc)))
    429  1.1.1.2  haad 			goto_out;
    430      1.1  haad 
    431  1.1.1.2  haad 		if (!archive(vg))
    432  1.1.1.2  haad 			goto_out;
    433      1.1  haad 
    434      1.1  haad 		if (!(lv_mirr = _set_up_pvmove_lv(cmd, vg, source_pvl, lv_name,
    435      1.1  haad 						  allocatable_pvs, alloc,
    436  1.1.1.2  haad 						  &lvs_changed)))
    437  1.1.1.2  haad 			goto_out;
    438      1.1  haad 	}
    439      1.1  haad 
    440      1.1  haad 	/* Lock lvs_changed and activate (with old metadata) */
    441  1.1.1.2  haad 	if (!activate_lvs(cmd, lvs_changed, exclusive))
    442  1.1.1.2  haad 		goto_out;
    443      1.1  haad 
    444      1.1  haad 	/* FIXME Presence of a mirror once set PVMOVE - now remove associated logic */
    445      1.1  haad 	/* init_pvmove(1); */
    446      1.1  haad 	/* vg->status |= PVMOVE; */
    447      1.1  haad 
    448      1.1  haad 	if (first_time) {
    449      1.1  haad 		if (!_update_metadata
    450  1.1.1.2  haad 		    (cmd, vg, lv_mirr, lvs_changed, PVMOVE_FIRST_TIME))
    451  1.1.1.2  haad 			goto_out;
    452      1.1  haad 	}
    453      1.1  haad 
    454      1.1  haad 	/* LVs are all in status LOCKED */
    455  1.1.1.2  haad 	r = ECMD_PROCESSED;
    456  1.1.1.2  haad out:
    457  1.1.1.2  haad 	unlock_and_release_vg(cmd, vg, pv_vg_name(pv));
    458  1.1.1.2  haad 	return r;
    459      1.1  haad }
    460      1.1  haad 
    461      1.1  haad static int _finish_pvmove(struct cmd_context *cmd, struct volume_group *vg,
    462      1.1  haad 			  struct logical_volume *lv_mirr,
    463      1.1  haad 			  struct dm_list *lvs_changed)
    464      1.1  haad {
    465      1.1  haad 	int r = 1;
    466      1.1  haad 	struct dm_list lvs_completed;
    467      1.1  haad 	struct lv_list *lvl;
    468      1.1  haad 
    469      1.1  haad 	/* Update metadata to remove mirror segments and break dependencies */
    470      1.1  haad 	dm_list_init(&lvs_completed);
    471      1.1  haad 	if (!lv_remove_mirrors(cmd, lv_mirr, 1, 0, NULL, PVMOVE) ||
    472      1.1  haad 	    !remove_layers_for_segments_all(cmd, lv_mirr, PVMOVE,
    473      1.1  haad 					    &lvs_completed)) {
    474      1.1  haad 		log_error("ABORTING: Removal of temporary mirror failed");
    475      1.1  haad 		return 0;
    476      1.1  haad 	}
    477      1.1  haad 
    478      1.1  haad 	dm_list_iterate_items(lvl, &lvs_completed)
    479      1.1  haad 		/* FIXME Assumes only one pvmove at a time! */
    480      1.1  haad 		lvl->lv->status &= ~LOCKED;
    481      1.1  haad 
    482      1.1  haad 	/* Store metadata without dependencies on mirror segments */
    483      1.1  haad 	if (!vg_write(vg)) {
    484      1.1  haad 		log_error("ABORTING: Failed to write new data locations "
    485      1.1  haad 			  "to disk.");
    486      1.1  haad 		return 0;
    487      1.1  haad 	}
    488      1.1  haad 
    489      1.1  haad 	/* Suspend LVs changed */
    490      1.1  haad 	if (!suspend_lvs(cmd, lvs_changed)) {
    491      1.1  haad 		log_error("Locking LVs to remove temporary mirror failed");
    492      1.1  haad 		r = 0;
    493      1.1  haad 	}
    494      1.1  haad 
    495      1.1  haad 	/* Suspend mirror LV to flush pending I/O */
    496      1.1  haad 	if (!suspend_lv(cmd, lv_mirr)) {
    497      1.1  haad 		log_error("Suspension of temporary mirror LV failed");
    498      1.1  haad 		r = 0;
    499      1.1  haad 	}
    500      1.1  haad 
    501      1.1  haad 	/* Store metadata without dependencies on mirror segments */
    502      1.1  haad 	if (!vg_commit(vg)) {
    503      1.1  haad 		log_error("ABORTING: Failed to write new data locations "
    504      1.1  haad 			  "to disk.");
    505      1.1  haad 		vg_revert(vg);
    506      1.1  haad 		resume_lv(cmd, lv_mirr);
    507      1.1  haad 		resume_lvs(cmd, lvs_changed);
    508      1.1  haad 		return 0;
    509      1.1  haad 	}
    510      1.1  haad 
    511      1.1  haad 	/* Release mirror LV.  (No pending I/O because it's been suspended.) */
    512      1.1  haad 	if (!resume_lv(cmd, lv_mirr)) {
    513      1.1  haad 		log_error("Unable to reactivate logical volume \"%s\"",
    514      1.1  haad 			  lv_mirr->name);
    515      1.1  haad 		r = 0;
    516      1.1  haad 	}
    517      1.1  haad 
    518      1.1  haad 	/* Unsuspend LVs */
    519      1.1  haad 	resume_lvs(cmd, lvs_changed);
    520      1.1  haad 
    521      1.1  haad 	/* Deactivate mirror LV */
    522      1.1  haad 	if (!deactivate_lv(cmd, lv_mirr)) {
    523      1.1  haad 		log_error("ABORTING: Unable to deactivate temporary logical "
    524      1.1  haad 			  "volume \"%s\"", lv_mirr->name);
    525      1.1  haad 		r = 0;
    526      1.1  haad 	}
    527      1.1  haad 
    528      1.1  haad 	log_verbose("Removing temporary pvmove LV");
    529      1.1  haad 	if (!lv_remove(lv_mirr)) {
    530      1.1  haad 		log_error("ABORTING: Removal of temporary pvmove LV failed");
    531      1.1  haad 		return 0;
    532      1.1  haad 	}
    533      1.1  haad 
    534      1.1  haad 	/* Store it on disks */
    535      1.1  haad 	log_verbose("Writing out final volume group after pvmove");
    536      1.1  haad 	if (!vg_write(vg) || !vg_commit(vg)) {
    537      1.1  haad 		log_error("ABORTING: Failed to write new data locations "
    538      1.1  haad 			  "to disk.");
    539      1.1  haad 		return 0;
    540      1.1  haad 	}
    541      1.1  haad 
    542      1.1  haad 	/* FIXME backup positioning */
    543      1.1  haad 	backup(vg);
    544      1.1  haad 
    545      1.1  haad 	return r;
    546      1.1  haad }
    547      1.1  haad 
    548      1.1  haad static struct volume_group *_get_move_vg(struct cmd_context *cmd,
    549  1.1.1.2  haad 					 const char *name, const char *uuid)
    550      1.1  haad {
    551      1.1  haad 	struct physical_volume *pv;
    552      1.1  haad 
    553      1.1  haad 	/* Reread all metadata in case it got changed */
    554      1.1  haad 	if (!(pv = find_pv_by_name(cmd, name))) {
    555      1.1  haad 		log_error("ABORTING: Can't reread PV %s", name);
    556      1.1  haad 		/* What more could we do here? */
    557      1.1  haad 		return NULL;
    558      1.1  haad 	}
    559      1.1  haad 
    560      1.1  haad 	return _get_vg(cmd, pv_vg_name(pv));
    561      1.1  haad }
    562      1.1  haad 
    563      1.1  haad static struct poll_functions _pvmove_fns = {
    564      1.1  haad 	.get_copy_name_from_lv = get_pvmove_pvname_from_lv_mirr,
    565      1.1  haad 	.get_copy_vg = _get_move_vg,
    566      1.1  haad 	.get_copy_lv = find_pvmove_lv_from_pvname,
    567  1.1.1.2  haad 	.poll_progress = poll_mirror_progress,
    568      1.1  haad 	.update_metadata = _update_metadata,
    569      1.1  haad 	.finish_copy = _finish_pvmove,
    570      1.1  haad };
    571      1.1  haad 
    572      1.1  haad int pvmove_poll(struct cmd_context *cmd, const char *pv_name,
    573      1.1  haad 		unsigned background)
    574      1.1  haad {
    575  1.1.1.2  haad 	return poll_daemon(cmd, pv_name, NULL, background, PVMOVE, &_pvmove_fns,
    576      1.1  haad 			   "Moved");
    577      1.1  haad }
    578      1.1  haad 
    579      1.1  haad int pvmove(struct cmd_context *cmd, int argc, char **argv)
    580      1.1  haad {
    581      1.1  haad 	char *pv_name = NULL;
    582      1.1  haad 	char *colon;
    583      1.1  haad 	int ret;
    584      1.1  haad 
    585      1.1  haad 	/* dm raid1 target must be present in every case */
    586      1.1  haad 	if (!_pvmove_target_present(cmd, 0)) {
    587      1.1  haad 		log_error("Required device-mapper target(s) not "
    588      1.1  haad 			  "detected in your kernel");
    589      1.1  haad 		return ECMD_FAILED;
    590      1.1  haad 	}
    591      1.1  haad 
    592      1.1  haad 	if (argc) {
    593      1.1  haad 		pv_name = argv[0];
    594      1.1  haad 
    595      1.1  haad 		/* Drop any PE lists from PV name */
    596      1.1  haad 		if ((colon = strchr(pv_name, ':'))) {
    597      1.1  haad 			if (!(pv_name = dm_pool_strndup(cmd->mem, pv_name,
    598      1.1  haad 						     (unsigned) (colon -
    599      1.1  haad 								 pv_name)))) {
    600      1.1  haad 				log_error("Failed to clone PV name");
    601      1.1  haad 				return ECMD_FAILED;
    602      1.1  haad 			}
    603      1.1  haad 		}
    604      1.1  haad 
    605      1.1  haad 		if (!arg_count(cmd, abort_ARG) &&
    606      1.1  haad 		    (ret = _set_up_pvmove(cmd, pv_name, argc, argv)) !=
    607      1.1  haad 		    ECMD_PROCESSED) {
    608      1.1  haad 			stack;
    609      1.1  haad 			return ret;
    610      1.1  haad 		}
    611      1.1  haad 	}
    612      1.1  haad 
    613  1.1.1.2  haad 	return pvmove_poll(cmd, pv_name, arg_is_set(cmd, background_ARG));
    614      1.1  haad }
    615