xref: /netbsd-src/external/gpl2/lvm2/dist/lib/metadata/mirror.c (revision 7c604eea85b4f330dc75ffe65e947f4d73758aa0)
1*7c604eeaShaad /*	$NetBSD: mirror.c,v 1.1.1.3 2009/12/02 00:26:41 haad Exp $	*/
256a34939Shaad 
356a34939Shaad /*
456a34939Shaad  * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
556a34939Shaad  * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
656a34939Shaad  *
756a34939Shaad  * This file is part of LVM2.
856a34939Shaad  *
956a34939Shaad  * This copyrighted material is made available to anyone wishing to use,
1056a34939Shaad  * modify, copy, or redistribute it subject to the terms and conditions
1156a34939Shaad  * of the GNU Lesser General Public License v.2.1.
1256a34939Shaad  *
1356a34939Shaad  * You should have received a copy of the GNU Lesser General Public License
1456a34939Shaad  * along with this program; if not, write to the Free Software Foundation,
1556a34939Shaad  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1656a34939Shaad  */
1756a34939Shaad 
1856a34939Shaad #include "lib.h"
1956a34939Shaad #include "metadata.h"
2056a34939Shaad #include "toolcontext.h"
2156a34939Shaad #include "segtype.h"
2256a34939Shaad #include "display.h"
2356a34939Shaad #include "archiver.h"
2456a34939Shaad #include "activate.h"
2556a34939Shaad #include "lv_alloc.h"
2656a34939Shaad #include "lvm-string.h"
2756a34939Shaad #include "str_list.h"
2856a34939Shaad #include "locking.h"	/* FIXME Should not be used in this file */
29*7c604eeaShaad #include "memlock.h"
3056a34939Shaad 
3156a34939Shaad #include "defaults.h" /* FIXME: should this be defaults.h? */
3256a34939Shaad 
3356a34939Shaad /* These are necessary for _write_log_header() */
3456a34939Shaad #include "xlate.h"
3556a34939Shaad #define MIRROR_MAGIC 0x4D695272
3656a34939Shaad #define MIRROR_DISK_VERSION 2
3756a34939Shaad 
3856a34939Shaad /* These are the flags that represent the mirror failure restoration policies */
3956a34939Shaad #define MIRROR_REMOVE		 0
4056a34939Shaad #define MIRROR_ALLOCATE		 1
4156a34939Shaad #define MIRROR_ALLOCATE_ANYWHERE 2
4256a34939Shaad 
4356a34939Shaad /*
4456a34939Shaad  * Returns true if the lv is temporary mirror layer for resync
4556a34939Shaad  */
is_temporary_mirror_layer(const struct logical_volume * lv)4656a34939Shaad int is_temporary_mirror_layer(const struct logical_volume *lv)
4756a34939Shaad {
4856a34939Shaad 	if (lv->status & MIRROR_IMAGE
4956a34939Shaad 	    && lv->status & MIRRORED
5056a34939Shaad 	    && !(lv->status & LOCKED))
5156a34939Shaad 		return 1;
5256a34939Shaad 
5356a34939Shaad 	return 0;
5456a34939Shaad }
5556a34939Shaad 
5656a34939Shaad /*
5756a34939Shaad  * Return a temporary LV for resyncing added mirror image.
5856a34939Shaad  * Add other mirror legs to lvs list.
5956a34939Shaad  */
find_temporary_mirror(const struct logical_volume * lv)6056a34939Shaad struct logical_volume *find_temporary_mirror(const struct logical_volume *lv)
6156a34939Shaad {
6256a34939Shaad 	struct lv_segment *seg;
6356a34939Shaad 
6456a34939Shaad 	if (!(lv->status & MIRRORED))
6556a34939Shaad 		return NULL;
6656a34939Shaad 
6756a34939Shaad 	seg = first_seg(lv);
6856a34939Shaad 
6956a34939Shaad 	/* Temporary mirror is always area_num == 0 */
7056a34939Shaad 	if (seg_type(seg, 0) == AREA_LV &&
7156a34939Shaad 	    is_temporary_mirror_layer(seg_lv(seg, 0)))
7256a34939Shaad 		return seg_lv(seg, 0);
7356a34939Shaad 
7456a34939Shaad 	return NULL;
7556a34939Shaad }
7656a34939Shaad 
7756a34939Shaad /*
7856a34939Shaad  * Returns the number of mirrors of the LV
7956a34939Shaad  */
lv_mirror_count(const struct logical_volume * lv)8056a34939Shaad uint32_t lv_mirror_count(const struct logical_volume *lv)
8156a34939Shaad {
8256a34939Shaad 	struct lv_segment *seg;
8356a34939Shaad 	uint32_t s, mirrors;
8456a34939Shaad 
8556a34939Shaad 	if (!(lv->status & MIRRORED))
8656a34939Shaad 		return 1;
8756a34939Shaad 
8856a34939Shaad 	seg = first_seg(lv);
8956a34939Shaad 	mirrors = seg->area_count;
9056a34939Shaad 
9156a34939Shaad 	for (s = 0; s < seg->area_count; s++) {
9256a34939Shaad 		if (seg_type(seg, s) != AREA_LV)
9356a34939Shaad 			continue;
9456a34939Shaad 		if (is_temporary_mirror_layer(seg_lv(seg, s)))
9556a34939Shaad 			mirrors += lv_mirror_count(seg_lv(seg, s)) - 1;
9656a34939Shaad 	}
9756a34939Shaad 
9856a34939Shaad 	return mirrors;
9956a34939Shaad }
10056a34939Shaad 
find_mirror_seg(struct lv_segment * seg)10156a34939Shaad struct lv_segment *find_mirror_seg(struct lv_segment *seg)
10256a34939Shaad {
10356a34939Shaad 	struct lv_segment *mirror_seg;
10456a34939Shaad 
10556a34939Shaad 	mirror_seg = get_only_segment_using_this_lv(seg->lv);
10656a34939Shaad 
10756a34939Shaad 	if (!mirror_seg) {
10856a34939Shaad 		log_error("Failed to find mirror_seg for %s", seg->lv->name);
10956a34939Shaad 		return NULL;
11056a34939Shaad 	}
11156a34939Shaad 
11256a34939Shaad 	if (!seg_is_mirrored(mirror_seg)) {
11356a34939Shaad 		log_error("%s on %s is not a mirror segments",
11456a34939Shaad 			  mirror_seg->lv->name, seg->lv->name);
11556a34939Shaad 		return NULL;
11656a34939Shaad 	}
11756a34939Shaad 
11856a34939Shaad 	return mirror_seg;
11956a34939Shaad }
12056a34939Shaad 
12156a34939Shaad /*
12256a34939Shaad  * Reduce the region size if necessary to ensure
12356a34939Shaad  * the volume size is a multiple of the region size.
12456a34939Shaad  */
adjusted_mirror_region_size(uint32_t extent_size,uint32_t extents,uint32_t region_size)12556a34939Shaad uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents,
12656a34939Shaad 				     uint32_t region_size)
12756a34939Shaad {
12856a34939Shaad 	uint64_t region_max;
12956a34939Shaad 
13056a34939Shaad 	region_max = (1 << (ffs((int)extents) - 1)) * (uint64_t) extent_size;
13156a34939Shaad 
13256a34939Shaad 	if (region_max < UINT32_MAX && region_size > region_max) {
13356a34939Shaad 		region_size = (uint32_t) region_max;
13456a34939Shaad 		log_print("Using reduced mirror region size of %" PRIu32
13556a34939Shaad 			  " sectors", region_size);
13656a34939Shaad 	}
13756a34939Shaad 
13856a34939Shaad 	return region_size;
13956a34939Shaad }
14056a34939Shaad 
14156a34939Shaad /*
14256a34939Shaad  * shift_mirror_images
14356a34939Shaad  * @mirrored_seg
14456a34939Shaad  * @mimage:  The position (index) of the image to move to the end
14556a34939Shaad  *
14656a34939Shaad  * When dealing with removal of legs, we often move a 'removable leg'
14756a34939Shaad  * to the back of the 'areas' array.  It is critically important not
14856a34939Shaad  * to simply swap it for the last area in the array.  This would have
14956a34939Shaad  * the affect of reordering the remaining legs - altering position of
15056a34939Shaad  * the primary.  So, we must shuffle all of the areas in the array
15156a34939Shaad  * to maintain their relative position before moving the 'removable
15256a34939Shaad  * leg' to the end.
15356a34939Shaad  *
15456a34939Shaad  * Short illustration of the problem:
15556a34939Shaad  *   - Mirror consists of legs A, B, C and we want to remove A
15656a34939Shaad  *   - We swap A and C and then remove A, leaving C, B
15756a34939Shaad  * This scenario is problematic in failure cases where A dies, because
15856a34939Shaad  * B becomes the primary.  If the above happens, we effectively throw
15956a34939Shaad  * away any changes made between the time of failure and the time of
16056a34939Shaad  * restructuring the mirror.
16156a34939Shaad  *
16256a34939Shaad  * So, any time we want to move areas to the end to be removed, use
16356a34939Shaad  * this function.
16456a34939Shaad  */
shift_mirror_images(struct lv_segment * mirrored_seg,unsigned mimage)16556a34939Shaad int shift_mirror_images(struct lv_segment *mirrored_seg, unsigned mimage)
16656a34939Shaad {
16756a34939Shaad 	int i;
16856a34939Shaad 	struct lv_segment_area area;
16956a34939Shaad 
17056a34939Shaad 	if (mimage >= mirrored_seg->area_count) {
17156a34939Shaad 		log_error("Invalid index (%u) of mirror image supplied "
17256a34939Shaad 			  "to shift_mirror_images()", mimage);
17356a34939Shaad 		return 0;
17456a34939Shaad 	}
17556a34939Shaad 
17656a34939Shaad 	area = mirrored_seg->areas[mimage];
17756a34939Shaad 
17856a34939Shaad 	/* Shift remaining images down to fill the hole */
17956a34939Shaad 	for (i = mimage + 1; i < mirrored_seg->area_count; i++)
18056a34939Shaad 		mirrored_seg->areas[i-1] = mirrored_seg->areas[i];
18156a34939Shaad 
18256a34939Shaad 	/* Place this one at the end */
18356a34939Shaad 	mirrored_seg->areas[i-1] = area;
18456a34939Shaad 
18556a34939Shaad 	return 1;
18656a34939Shaad }
18756a34939Shaad 
18856a34939Shaad /*
18956a34939Shaad  * This function writes a new header to the mirror log header to the lv
19056a34939Shaad  *
19156a34939Shaad  * Returns: 1 on success, 0 on failure
19256a34939Shaad  */
_write_log_header(struct cmd_context * cmd,struct logical_volume * lv)19356a34939Shaad static int _write_log_header(struct cmd_context *cmd, struct logical_volume *lv)
19456a34939Shaad {
19556a34939Shaad 	struct device *dev;
19656a34939Shaad 	char *name;
19756a34939Shaad 	struct { /* The mirror log header */
19856a34939Shaad 		uint32_t magic;
19956a34939Shaad 		uint32_t version;
20056a34939Shaad 		uint64_t nr_regions;
20156a34939Shaad 	} log_header;
20256a34939Shaad 
20356a34939Shaad 	log_header.magic = xlate32(MIRROR_MAGIC);
20456a34939Shaad 	log_header.version = xlate32(MIRROR_DISK_VERSION);
20556a34939Shaad 	log_header.nr_regions = xlate64((uint64_t)-1);
20656a34939Shaad 
20756a34939Shaad 	if (!(name = dm_pool_alloc(cmd->mem, PATH_MAX))) {
20856a34939Shaad 		log_error("Name allocation failed - log header not written (%s)",
20956a34939Shaad 			lv->name);
21056a34939Shaad 		return 0;
21156a34939Shaad 	}
21256a34939Shaad 
21356a34939Shaad 	if (dm_snprintf(name, PATH_MAX, "%s%s/%s", cmd->dev_dir,
21456a34939Shaad 			 lv->vg->name, lv->name) < 0) {
21556a34939Shaad 		log_error("Name too long - log header not written (%s)", lv->name);
21656a34939Shaad 		return 0;
21756a34939Shaad 	}
21856a34939Shaad 
21956a34939Shaad 	log_verbose("Writing log header to device, %s", lv->name);
22056a34939Shaad 
22156a34939Shaad 	if (!(dev = dev_cache_get(name, NULL))) {
22256a34939Shaad 		log_error("%s: not found: log header not written", name);
22356a34939Shaad 		return 0;
22456a34939Shaad 	}
22556a34939Shaad 
22656a34939Shaad 	if (!dev_open_quiet(dev))
22756a34939Shaad 		return 0;
22856a34939Shaad 
22956a34939Shaad 	if (!dev_write(dev, UINT64_C(0), sizeof(log_header), &log_header)) {
23056a34939Shaad 		log_error("Failed to write log header to %s", name);
23156a34939Shaad 		dev_close_immediate(dev);
23256a34939Shaad 		return 0;
23356a34939Shaad 	}
23456a34939Shaad 
23556a34939Shaad 	dev_close_immediate(dev);
23656a34939Shaad 
23756a34939Shaad 	return 1;
23856a34939Shaad }
23956a34939Shaad 
24056a34939Shaad /*
24156a34939Shaad  * Initialize mirror log contents
24256a34939Shaad  */
_init_mirror_log(struct cmd_context * cmd,struct logical_volume * log_lv,int in_sync,struct dm_list * tags,int remove_on_failure)24356a34939Shaad static int _init_mirror_log(struct cmd_context *cmd,
24456a34939Shaad 			    struct logical_volume *log_lv, int in_sync,
24556a34939Shaad 			    struct dm_list *tags, int remove_on_failure)
24656a34939Shaad {
24756a34939Shaad 	struct str_list *sl;
24856a34939Shaad 	struct lvinfo info;
24956a34939Shaad 	uint32_t orig_status = log_lv->status;
25056a34939Shaad 	int was_active = 0;
25156a34939Shaad 
25256a34939Shaad 	if (!activation() && in_sync) {
25356a34939Shaad 		log_error("Aborting. Unable to create in-sync mirror log "
25456a34939Shaad 			  "while activation is disabled.");
25556a34939Shaad 		return 0;
25656a34939Shaad 	}
25756a34939Shaad 
25856a34939Shaad 	/* If the LV is active, deactivate it first. */
25956a34939Shaad 	if (lv_info(cmd, log_lv, &info, 0, 0) && info.exists) {
26056a34939Shaad 		if (!deactivate_lv(cmd, log_lv))
26156a34939Shaad 			return_0;
26256a34939Shaad 		was_active = 1;
26356a34939Shaad 	}
26456a34939Shaad 
26556a34939Shaad 	/* Temporary make it visible for set_lv() */
266*7c604eeaShaad 	lv_set_visible(log_lv);
26756a34939Shaad 
26856a34939Shaad 	/* Temporary tag mirror log for activation */
26956a34939Shaad 	dm_list_iterate_items(sl, tags)
27056a34939Shaad 		if (!str_list_add(cmd->mem, &log_lv->tags, sl->str)) {
27156a34939Shaad 			log_error("Aborting. Unable to tag mirror log.");
27256a34939Shaad 			goto activate_lv;
27356a34939Shaad 		}
27456a34939Shaad 
27556a34939Shaad 	/* store mirror log on disk(s) */
276*7c604eeaShaad 	if (!vg_write(log_lv->vg) || !vg_commit(log_lv->vg))
27756a34939Shaad 		goto activate_lv;
27856a34939Shaad 
27956a34939Shaad 	backup(log_lv->vg);
28056a34939Shaad 
28156a34939Shaad 	if (!activate_lv(cmd, log_lv)) {
28256a34939Shaad 		log_error("Aborting. Failed to activate mirror log.");
28356a34939Shaad 		goto revert_new_lv;
28456a34939Shaad 	}
28556a34939Shaad 
28656a34939Shaad 	/* Remove the temporary tags */
28756a34939Shaad 	dm_list_iterate_items(sl, tags)
28856a34939Shaad 		if (!str_list_del(&log_lv->tags, sl->str))
28956a34939Shaad 			log_error("Failed to remove tag %s from mirror log.",
29056a34939Shaad 				  sl->str);
29156a34939Shaad 
29256a34939Shaad 	if (activation() && !set_lv(cmd, log_lv, log_lv->size,
29356a34939Shaad 				    in_sync ? -1 : 0)) {
29456a34939Shaad 		log_error("Aborting. Failed to wipe mirror log.");
29556a34939Shaad 		goto deactivate_and_revert_new_lv;
29656a34939Shaad 	}
29756a34939Shaad 
29856a34939Shaad 	if (activation() && !_write_log_header(cmd, log_lv)) {
29956a34939Shaad 		log_error("Aborting. Failed to write mirror log header.");
30056a34939Shaad 		goto deactivate_and_revert_new_lv;
30156a34939Shaad 	}
30256a34939Shaad 
30356a34939Shaad 	if (!deactivate_lv(cmd, log_lv)) {
30456a34939Shaad 		log_error("Aborting. Failed to deactivate mirror log. "
30556a34939Shaad 			  "Manual intervention required.");
30656a34939Shaad 		return 0;
30756a34939Shaad 	}
30856a34939Shaad 
309*7c604eeaShaad 	lv_set_hidden(log_lv);
31056a34939Shaad 
31156a34939Shaad 	if (was_active && !activate_lv(cmd, log_lv))
31256a34939Shaad 		return_0;
31356a34939Shaad 
31456a34939Shaad 	return 1;
31556a34939Shaad 
31656a34939Shaad deactivate_and_revert_new_lv:
31756a34939Shaad 	if (!deactivate_lv(cmd, log_lv)) {
31856a34939Shaad 		log_error("Unable to deactivate mirror log LV. "
31956a34939Shaad 			  "Manual intervention required.");
32056a34939Shaad 		return 0;
32156a34939Shaad 	}
32256a34939Shaad 
32356a34939Shaad revert_new_lv:
32456a34939Shaad 	log_lv->status = orig_status;
32556a34939Shaad 
32656a34939Shaad 	dm_list_iterate_items(sl, tags)
32756a34939Shaad 		if (!str_list_del(&log_lv->tags, sl->str))
32856a34939Shaad 			log_error("Failed to remove tag %s from mirror log.",
32956a34939Shaad 				  sl->str);
33056a34939Shaad 
33156a34939Shaad 	if (remove_on_failure && !lv_remove(log_lv)) {
33256a34939Shaad 		log_error("Manual intervention may be required to remove "
33356a34939Shaad 			  "abandoned log LV before retrying.");
33456a34939Shaad 		return 0;
33556a34939Shaad 	}
33656a34939Shaad 
337*7c604eeaShaad 	if (!vg_write(log_lv->vg) || !vg_commit(log_lv->vg))
33856a34939Shaad 		log_error("Manual intervention may be required to "
33956a34939Shaad 			  "remove/restore abandoned log LV before retrying.");
340*7c604eeaShaad 	else
341*7c604eeaShaad 		backup(log_lv->vg);
342*7c604eeaShaad 
34356a34939Shaad activate_lv:
34456a34939Shaad 	if (was_active && !remove_on_failure && !activate_lv(cmd, log_lv))
34556a34939Shaad 		return_0;
34656a34939Shaad 
34756a34939Shaad 	return 0;
34856a34939Shaad }
34956a34939Shaad 
35056a34939Shaad /*
35156a34939Shaad  * Delete independent/orphan LV, it must acquire lock.
35256a34939Shaad  */
_delete_lv(struct logical_volume * mirror_lv,struct logical_volume * lv)35356a34939Shaad static int _delete_lv(struct logical_volume *mirror_lv, struct logical_volume *lv)
35456a34939Shaad {
35556a34939Shaad 	struct cmd_context *cmd = mirror_lv->vg->cmd;
35656a34939Shaad 	struct str_list *sl;
35756a34939Shaad 
35856a34939Shaad 	/* Inherit tags - maybe needed for activation */
35956a34939Shaad 	if (!str_list_match_list(&mirror_lv->tags, &lv->tags)) {
36056a34939Shaad 		dm_list_iterate_items(sl, &mirror_lv->tags)
36156a34939Shaad 			if (!str_list_add(cmd->mem, &lv->tags, sl->str)) {
36256a34939Shaad 				log_error("Aborting. Unable to tag.");
36356a34939Shaad 				return 0;
36456a34939Shaad 			}
36556a34939Shaad 
36656a34939Shaad 		if (!vg_write(mirror_lv->vg) ||
36756a34939Shaad 		    !vg_commit(mirror_lv->vg)) {
36856a34939Shaad 			log_error("Intermediate VG commit for orphan volume failed.");
36956a34939Shaad 			return 0;
37056a34939Shaad 		}
37156a34939Shaad 	}
37256a34939Shaad 
37356a34939Shaad 	if (!activate_lv(cmd, lv))
37456a34939Shaad 		return_0;
37556a34939Shaad 
37656a34939Shaad 	if (!deactivate_lv(cmd, lv))
37756a34939Shaad 		return_0;
37856a34939Shaad 
37956a34939Shaad 	if (!lv_remove(lv))
38056a34939Shaad 		return_0;
38156a34939Shaad 
38256a34939Shaad 	return 1;
38356a34939Shaad }
38456a34939Shaad 
_merge_mirror_images(struct logical_volume * lv,const struct dm_list * mimages)38556a34939Shaad static int _merge_mirror_images(struct logical_volume *lv,
38656a34939Shaad 				const struct dm_list *mimages)
38756a34939Shaad {
38856a34939Shaad 	uint32_t addition = dm_list_size(mimages);
38956a34939Shaad 	struct logical_volume **img_lvs;
39056a34939Shaad 	struct lv_list *lvl;
39156a34939Shaad 	int i = 0;
39256a34939Shaad 
39356a34939Shaad 	if (!addition)
39456a34939Shaad 		return 1;
39556a34939Shaad 
39656a34939Shaad 	if (!(img_lvs = alloca(sizeof(*img_lvs) * addition)))
39756a34939Shaad 		return_0;
39856a34939Shaad 
39956a34939Shaad 	dm_list_iterate_items(lvl, mimages)
40056a34939Shaad 		img_lvs[i++] = lvl->lv;
40156a34939Shaad 
40256a34939Shaad 	return lv_add_mirror_lvs(lv, img_lvs, addition,
40356a34939Shaad 				 MIRROR_IMAGE, first_seg(lv)->region_size);
40456a34939Shaad }
40556a34939Shaad 
40656a34939Shaad /* Unlink the relationship between the segment and its log_lv */
detach_mirror_log(struct lv_segment * mirrored_seg)40756a34939Shaad struct logical_volume *detach_mirror_log(struct lv_segment *mirrored_seg)
40856a34939Shaad {
40956a34939Shaad 	struct logical_volume *log_lv;
41056a34939Shaad 
41156a34939Shaad 	if (!mirrored_seg->log_lv)
41256a34939Shaad 		return NULL;
41356a34939Shaad 
41456a34939Shaad 	log_lv = mirrored_seg->log_lv;
41556a34939Shaad 	mirrored_seg->log_lv = NULL;
416*7c604eeaShaad 	lv_set_visible(log_lv);
41756a34939Shaad 	log_lv->status &= ~MIRROR_LOG;
41856a34939Shaad 	remove_seg_from_segs_using_this_lv(log_lv, mirrored_seg);
41956a34939Shaad 
42056a34939Shaad 	return log_lv;
42156a34939Shaad }
42256a34939Shaad 
42356a34939Shaad /* Check if mirror image LV is removable with regard to given removable_pvs */
_is_mirror_image_removable(struct logical_volume * mimage_lv,struct dm_list * removable_pvs)42456a34939Shaad static int _is_mirror_image_removable(struct logical_volume *mimage_lv,
42556a34939Shaad 				      struct dm_list *removable_pvs)
42656a34939Shaad {
42756a34939Shaad 	struct physical_volume *pv;
42856a34939Shaad 	struct lv_segment *seg;
42956a34939Shaad 	int pv_found;
43056a34939Shaad 	struct pv_list *pvl;
43156a34939Shaad 	uint32_t s;
43256a34939Shaad 
43356a34939Shaad 	dm_list_iterate_items(seg, &mimage_lv->segments) {
43456a34939Shaad 		for (s = 0; s < seg->area_count; s++) {
43556a34939Shaad 			if (seg_type(seg, s) != AREA_PV) {
43656a34939Shaad 				/* FIXME Recurse for AREA_LV? */
43756a34939Shaad 				/* Structure of seg_lv is unknown.
43856a34939Shaad 				 * Not removing this LV for safety. */
43956a34939Shaad 				return 0;
44056a34939Shaad 			}
44156a34939Shaad 
44256a34939Shaad 			pv = seg_pv(seg, s);
44356a34939Shaad 
44456a34939Shaad 			pv_found = 0;
44556a34939Shaad 			dm_list_iterate_items(pvl, removable_pvs) {
446*7c604eeaShaad 				if (id_equal(&pv->id, &pvl->pv->id)) {
447*7c604eeaShaad 					pv_found = 1;
448*7c604eeaShaad 					break;
449*7c604eeaShaad 				}
450*7c604eeaShaad 				if (pvl->pv->dev && pv->dev &&
451*7c604eeaShaad 				    pv->dev->dev == pvl->pv->dev->dev) {
45256a34939Shaad 					pv_found = 1;
45356a34939Shaad 					break;
45456a34939Shaad 				}
45556a34939Shaad 			}
45656a34939Shaad 			if (!pv_found)
45756a34939Shaad 				return 0;
45856a34939Shaad 		}
45956a34939Shaad 	}
46056a34939Shaad 
46156a34939Shaad 	return 1;
46256a34939Shaad }
46356a34939Shaad 
46456a34939Shaad /*
46556a34939Shaad  * Remove num_removed images from mirrored_seg
46656a34939Shaad  *
46756a34939Shaad  * Arguments:
46856a34939Shaad  *   num_removed:   the requested (maximum) number of mirrors to be removed
46956a34939Shaad  *   removable_pvs: if not NULL, only mirrors using PVs in this list
47056a34939Shaad  *                  will be removed
47156a34939Shaad  *   remove_log:    if non-zero, log_lv will be removed
47256a34939Shaad  *                  (even if it's 0, log_lv will be removed if there is no
47356a34939Shaad  *                   mirror remaining after the removal)
47456a34939Shaad  *   collapse:      if non-zero, instead of removing, remove the temporary
47556a34939Shaad  *                  mirror layer and merge mirrors to the original LV.
47656a34939Shaad  *                  removable_pvs should be NULL and num_removed should be
47756a34939Shaad  *                  seg->area_count - 1.
47856a34939Shaad  *   removed:       if non NULL, the number of removed mirror images is set
47956a34939Shaad  *                  as a result
48056a34939Shaad  *
48156a34939Shaad  * If collapse is non-zero, <removed> is guaranteed to be equal to num_removed.
48256a34939Shaad  *
48356a34939Shaad  * Return values:
48456a34939Shaad  *   Failure (0) means something unexpected has happend and
48556a34939Shaad  *   the caller should abort.
48656a34939Shaad  *   Even if no mirror was removed (e.g. no LV matches to 'removable_pvs'),
48756a34939Shaad  *   returns success (1).
48856a34939Shaad  */
_remove_mirror_images(struct logical_volume * lv,uint32_t num_removed,struct dm_list * removable_pvs,unsigned remove_log,unsigned collapse,uint32_t * removed)48956a34939Shaad static int _remove_mirror_images(struct logical_volume *lv,
49056a34939Shaad 				 uint32_t num_removed,
49156a34939Shaad 				 struct dm_list *removable_pvs,
49256a34939Shaad 				 unsigned remove_log, unsigned collapse,
49356a34939Shaad 				 uint32_t *removed)
49456a34939Shaad {
49556a34939Shaad 	uint32_t m;
49656a34939Shaad 	uint32_t s;
49756a34939Shaad 	struct logical_volume *sub_lv;
49856a34939Shaad 	struct logical_volume *detached_log_lv = NULL;
49956a34939Shaad 	struct logical_volume *lv1 = NULL;
50056a34939Shaad 	struct lv_segment *mirrored_seg = first_seg(lv);
50156a34939Shaad 	uint32_t old_area_count = mirrored_seg->area_count;
50256a34939Shaad 	uint32_t new_area_count = mirrored_seg->area_count;
50356a34939Shaad 	struct lv_list *lvl;
50456a34939Shaad 	struct dm_list tmp_orphan_lvs;
50556a34939Shaad 
50656a34939Shaad 	if (removed)
50756a34939Shaad 		*removed = 0;
50856a34939Shaad 
50956a34939Shaad 	log_very_verbose("Reducing mirror set from %" PRIu32 " to %"
51056a34939Shaad 			 PRIu32 " image(s)%s.",
51156a34939Shaad 			 old_area_count, old_area_count - num_removed,
51256a34939Shaad 			 remove_log ? " and no log volume" : "");
51356a34939Shaad 
51456a34939Shaad 	if (collapse &&
51556a34939Shaad 	    (removable_pvs || (old_area_count - num_removed != 1))) {
51656a34939Shaad 		log_error("Incompatible parameters to _remove_mirror_images");
51756a34939Shaad 		return 0;
51856a34939Shaad 	}
51956a34939Shaad 
52056a34939Shaad 	/* Move removable_pvs to end of array */
52156a34939Shaad 	if (removable_pvs) {
52256a34939Shaad 		for (s = 0; s < mirrored_seg->area_count &&
52356a34939Shaad 			    old_area_count - new_area_count < num_removed; s++) {
52456a34939Shaad 			sub_lv = seg_lv(mirrored_seg, s);
52556a34939Shaad 
52656a34939Shaad 			if (!is_temporary_mirror_layer(sub_lv) &&
52756a34939Shaad 			    _is_mirror_image_removable(sub_lv, removable_pvs)) {
52856a34939Shaad 				if (!shift_mirror_images(mirrored_seg, s))
52956a34939Shaad 					return_0;
53056a34939Shaad 				new_area_count--;
53156a34939Shaad 			}
53256a34939Shaad 		}
53356a34939Shaad 		if (num_removed && old_area_count == new_area_count)
53456a34939Shaad 			return 1;
53556a34939Shaad 	} else
53656a34939Shaad 		new_area_count = old_area_count - num_removed;
53756a34939Shaad 
53856a34939Shaad 	/* Remove mimage LVs from the segment */
53956a34939Shaad 	dm_list_init(&tmp_orphan_lvs);
54056a34939Shaad 	for (m = new_area_count; m < mirrored_seg->area_count; m++) {
54156a34939Shaad 		seg_lv(mirrored_seg, m)->status &= ~MIRROR_IMAGE;
542*7c604eeaShaad 		lv_set_visible(seg_lv(mirrored_seg, m));
54356a34939Shaad 		if (!(lvl = dm_pool_alloc(lv->vg->cmd->mem, sizeof(*lvl)))) {
54456a34939Shaad 			log_error("lv_list alloc failed");
54556a34939Shaad 			return 0;
54656a34939Shaad 		}
54756a34939Shaad 		lvl->lv = seg_lv(mirrored_seg, m);
54856a34939Shaad 		dm_list_add(&tmp_orphan_lvs, &lvl->list);
54956a34939Shaad 		release_lv_segment_area(mirrored_seg, m, mirrored_seg->area_len);
55056a34939Shaad 	}
55156a34939Shaad 	mirrored_seg->area_count = new_area_count;
55256a34939Shaad 
55356a34939Shaad 	/* If no more mirrors, remove mirror layer */
55456a34939Shaad 	/* As an exceptional case, if the lv is temporary layer,
55556a34939Shaad 	 * leave the LV as mirrored and let the lvconvert completion
55656a34939Shaad 	 * to remove the layer. */
55756a34939Shaad 	if (new_area_count == 1 && !is_temporary_mirror_layer(lv)) {
55856a34939Shaad 		lv1 = seg_lv(mirrored_seg, 0);
55956a34939Shaad 		lv1->status &= ~MIRROR_IMAGE;
560*7c604eeaShaad 		lv_set_visible(lv1);
56156a34939Shaad 		detached_log_lv = detach_mirror_log(mirrored_seg);
56256a34939Shaad 		if (!remove_layer_from_lv(lv, lv1))
56356a34939Shaad 			return_0;
56456a34939Shaad 		lv->status &= ~MIRRORED;
56556a34939Shaad 		lv->status &= ~MIRROR_NOTSYNCED;
56656a34939Shaad 		if (collapse && !_merge_mirror_images(lv, &tmp_orphan_lvs)) {
56756a34939Shaad 			log_error("Failed to add mirror images");
56856a34939Shaad 			return 0;
56956a34939Shaad 		}
57056a34939Shaad 	} else if (new_area_count == 0) {
57156a34939Shaad 		log_very_verbose("All mimages of %s are gone", lv->name);
57256a34939Shaad 
57356a34939Shaad 		/* All mirror images are gone.
57456a34939Shaad 		 * It can happen for vgreduce --removemissing. */
57556a34939Shaad 		detached_log_lv = detach_mirror_log(mirrored_seg);
57656a34939Shaad 		lv->status &= ~MIRRORED;
57756a34939Shaad 		lv->status &= ~MIRROR_NOTSYNCED;
57856a34939Shaad 		if (!replace_lv_with_error_segment(lv))
57956a34939Shaad 			return_0;
58056a34939Shaad 	} else if (remove_log)
58156a34939Shaad 		detached_log_lv = detach_mirror_log(mirrored_seg);
58256a34939Shaad 
58356a34939Shaad 	/*
58456a34939Shaad 	 * To successfully remove these unwanted LVs we need to
58556a34939Shaad 	 * remove the LVs from the mirror set, commit that metadata
58656a34939Shaad 	 * then deactivate and remove them fully.
58756a34939Shaad 	 */
58856a34939Shaad 
58956a34939Shaad 	if (!vg_write(mirrored_seg->lv->vg)) {
59056a34939Shaad 		log_error("intermediate VG write failed.");
59156a34939Shaad 		return 0;
59256a34939Shaad 	}
59356a34939Shaad 
59456a34939Shaad 	if (!suspend_lv(mirrored_seg->lv->vg->cmd, mirrored_seg->lv)) {
59556a34939Shaad 		log_error("Failed to lock %s", mirrored_seg->lv->name);
59656a34939Shaad 		vg_revert(mirrored_seg->lv->vg);
59756a34939Shaad 		return 0;
59856a34939Shaad 	}
59956a34939Shaad 
60056a34939Shaad 	if (!vg_commit(mirrored_seg->lv->vg)) {
60156a34939Shaad 		resume_lv(mirrored_seg->lv->vg->cmd, mirrored_seg->lv);
60256a34939Shaad 		return 0;
60356a34939Shaad 	}
60456a34939Shaad 
60556a34939Shaad 	log_very_verbose("Updating \"%s\" in kernel", mirrored_seg->lv->name);
60656a34939Shaad 
60756a34939Shaad 	/*
60856a34939Shaad 	 * Avoid having same mirror target loaded twice simultaneously by first
60956a34939Shaad 	 * resuming the removed LV which now contains an error segment.
61056a34939Shaad 	 * As it's now detached from mirrored_seg->lv we must resume it
61156a34939Shaad 	 * explicitly.
61256a34939Shaad 	 */
613*7c604eeaShaad 	if (lv1) {
614*7c604eeaShaad 		if (!resume_lv(lv1->vg->cmd, lv1)) {
61556a34939Shaad 			log_error("Problem resuming temporary LV, %s", lv1->name);
61656a34939Shaad 			return 0;
61756a34939Shaad 		}
61856a34939Shaad 
619*7c604eeaShaad 		/*
620*7c604eeaShaad 		 * The code above calls a suspend_lv once, however we now need
621*7c604eeaShaad 		 * to resume 2 LVs, due to image removal: the mirror image
622*7c604eeaShaad 		 * itself here, and now the remaining mirror LV. Since
623*7c604eeaShaad 		 * suspend_lv/resume_lv call memlock_inc/memlock_dec and these
624*7c604eeaShaad 		 * need to be balanced, we need to call an extra memlock_inc()
625*7c604eeaShaad 		 * here to balance for the this extra resume -- the following
626*7c604eeaShaad 		 * one could otherwise either deadlock due to suspended
627*7c604eeaShaad 		 * devices, or alternatively drop memlock_count below 0.
628*7c604eeaShaad 		 */
629*7c604eeaShaad 		memlock_inc();
630*7c604eeaShaad 	}
631*7c604eeaShaad 
63256a34939Shaad 	if (!resume_lv(mirrored_seg->lv->vg->cmd, mirrored_seg->lv)) {
63356a34939Shaad 		log_error("Problem reactivating %s", mirrored_seg->lv->name);
63456a34939Shaad 		return 0;
63556a34939Shaad 	}
63656a34939Shaad 
63756a34939Shaad 	/* Save or delete the 'orphan' LVs */
63856a34939Shaad 	if (!collapse) {
63956a34939Shaad 		dm_list_iterate_items(lvl, &tmp_orphan_lvs)
64056a34939Shaad 			if (!_delete_lv(lv, lvl->lv))
64156a34939Shaad 				return_0;
64256a34939Shaad 	}
64356a34939Shaad 
64456a34939Shaad 	if (lv1 && !_delete_lv(lv, lv1))
64556a34939Shaad 		return_0;
64656a34939Shaad 
64756a34939Shaad 	if (detached_log_lv && !_delete_lv(lv, detached_log_lv))
64856a34939Shaad 		return_0;
64956a34939Shaad 
65056a34939Shaad 	/* Mirror with only 1 area is 'in sync'. */
65156a34939Shaad 	if (new_area_count == 1 && is_temporary_mirror_layer(lv)) {
65256a34939Shaad 		if (first_seg(lv)->log_lv &&
65356a34939Shaad 		    !_init_mirror_log(lv->vg->cmd, first_seg(lv)->log_lv,
65456a34939Shaad 				      1, &lv->tags, 0)) {
65556a34939Shaad 			/* As a result, unnecessary sync may run after
65656a34939Shaad 			 * collapsing. But safe.*/
65756a34939Shaad 			log_error("Failed to initialize log device");
65856a34939Shaad 			return_0;
65956a34939Shaad 		}
66056a34939Shaad 	}
66156a34939Shaad 
66256a34939Shaad 	if (removed)
66356a34939Shaad 		*removed = old_area_count - new_area_count;
66456a34939Shaad 
66556a34939Shaad 	log_very_verbose("%" PRIu32 " image(s) removed from %s",
66656a34939Shaad 			 old_area_count - num_removed, lv->name);
66756a34939Shaad 
66856a34939Shaad 	return 1;
66956a34939Shaad }
67056a34939Shaad 
67156a34939Shaad /*
67256a34939Shaad  * Remove the number of mirror images from the LV
67356a34939Shaad  */
remove_mirror_images(struct logical_volume * lv,uint32_t num_mirrors,struct dm_list * removable_pvs,unsigned remove_log)67456a34939Shaad int remove_mirror_images(struct logical_volume *lv, uint32_t num_mirrors,
67556a34939Shaad 			 struct dm_list *removable_pvs, unsigned remove_log)
67656a34939Shaad {
67756a34939Shaad 	uint32_t num_removed, removed_once, r;
67856a34939Shaad 	uint32_t existing_mirrors = lv_mirror_count(lv);
67956a34939Shaad 	struct logical_volume *next_lv = lv;
68056a34939Shaad 
68156a34939Shaad 	num_removed = existing_mirrors - num_mirrors;
68256a34939Shaad 
68356a34939Shaad 	/* num_removed can be 0 if the function is called just to remove log */
68456a34939Shaad 	do {
68556a34939Shaad 		if (num_removed < first_seg(next_lv)->area_count)
68656a34939Shaad 			removed_once = num_removed;
68756a34939Shaad 		else
68856a34939Shaad 			removed_once = first_seg(next_lv)->area_count - 1;
68956a34939Shaad 
69056a34939Shaad 		if (!_remove_mirror_images(next_lv, removed_once,
69156a34939Shaad 					   removable_pvs, remove_log, 0, &r))
69256a34939Shaad 			return_0;
69356a34939Shaad 
69456a34939Shaad 		if (r < removed_once) {
69556a34939Shaad 			/* Some mirrors are removed from the temporary mirror,
69656a34939Shaad 			 * but the temporary layer still exists.
69756a34939Shaad 			 * Down the stack and retry for remainder. */
69856a34939Shaad 			next_lv = find_temporary_mirror(next_lv);
69956a34939Shaad 		}
70056a34939Shaad 
70156a34939Shaad 		num_removed -= r;
70256a34939Shaad 	} while (next_lv && num_removed);
70356a34939Shaad 
70456a34939Shaad 	if (num_removed) {
70556a34939Shaad 		if (num_removed == existing_mirrors - num_mirrors)
70656a34939Shaad 			log_error("No mirror images found using specified PVs.");
70756a34939Shaad 		else {
70856a34939Shaad 			log_error("%u images are removed out of requested %u.",
70956a34939Shaad 				  existing_mirrors - lv_mirror_count(lv),
71056a34939Shaad 				  existing_mirrors - num_mirrors);
71156a34939Shaad 		}
71256a34939Shaad 		return 0;
71356a34939Shaad 	}
71456a34939Shaad 
71556a34939Shaad 	return 1;
71656a34939Shaad }
71756a34939Shaad 
_mirrored_lv_in_sync(struct logical_volume * lv)71856a34939Shaad static int _mirrored_lv_in_sync(struct logical_volume *lv)
71956a34939Shaad {
72056a34939Shaad 	float sync_percent;
721*7c604eeaShaad 	percent_range_t percent_range;
72256a34939Shaad 
723*7c604eeaShaad 	if (!lv_mirror_percent(lv->vg->cmd, lv, 0, &sync_percent,
724*7c604eeaShaad 			       &percent_range, NULL)) {
72556a34939Shaad 		log_error("Unable to determine mirror sync status of %s/%s.",
72656a34939Shaad 			  lv->vg->name, lv->name);
72756a34939Shaad 		return 0;
72856a34939Shaad 	}
72956a34939Shaad 
730*7c604eeaShaad 	return (percent_range == PERCENT_100) ? 1 : 0;
73156a34939Shaad }
73256a34939Shaad 
73356a34939Shaad /*
73456a34939Shaad  * Collapsing temporary mirror layers.
73556a34939Shaad  *
73656a34939Shaad  * When mirrors are added to already-mirrored LV, a temporary mirror layer
73756a34939Shaad  * is inserted at the top of the stack to reduce resync work.
73856a34939Shaad  * The function will remove the intermediate layer and collapse the stack
73956a34939Shaad  * as far as mirrors are in-sync.
74056a34939Shaad  *
74156a34939Shaad  * The function is destructive: to remove intermediate mirror layers,
74256a34939Shaad  * VG metadata commits and suspend/resume are necessary.
74356a34939Shaad  */
collapse_mirrored_lv(struct logical_volume * lv)74456a34939Shaad int collapse_mirrored_lv(struct logical_volume *lv)
74556a34939Shaad {
74656a34939Shaad 	struct logical_volume *tmp_lv;
74756a34939Shaad 	struct lv_segment *mirror_seg;
74856a34939Shaad 
74956a34939Shaad 	while ((tmp_lv = find_temporary_mirror(lv))) {
75056a34939Shaad 		mirror_seg = find_mirror_seg(first_seg(tmp_lv));
75156a34939Shaad 		if (!mirror_seg) {
75256a34939Shaad 			log_error("Failed to find mirrored LV for %s",
75356a34939Shaad 				  tmp_lv->name);
75456a34939Shaad 			return 0;
75556a34939Shaad 		}
75656a34939Shaad 
75756a34939Shaad 		if (!_mirrored_lv_in_sync(mirror_seg->lv)) {
75856a34939Shaad 			log_verbose("Not collapsing %s: out-of-sync",
75956a34939Shaad 				    mirror_seg->lv->name);
76056a34939Shaad 			return 1;
76156a34939Shaad 		}
76256a34939Shaad 
76356a34939Shaad 		if (!_remove_mirror_images(mirror_seg->lv,
76456a34939Shaad 					   mirror_seg->area_count - 1,
76556a34939Shaad 					   NULL, 1, 1, NULL)) {
76656a34939Shaad 			log_error("Failed to release mirror images");
76756a34939Shaad 			return 0;
76856a34939Shaad 		}
76956a34939Shaad 	}
77056a34939Shaad 
77156a34939Shaad 	return 1;
77256a34939Shaad }
77356a34939Shaad 
get_mirror_fault_policy(struct cmd_context * cmd __attribute ((unused)),int log_policy)77456a34939Shaad static int get_mirror_fault_policy(struct cmd_context *cmd __attribute((unused)),
77556a34939Shaad 				   int log_policy)
77656a34939Shaad {
77756a34939Shaad 	const char *policy;
77856a34939Shaad 
77956a34939Shaad 	if (log_policy)
78056a34939Shaad 		policy = find_config_str(NULL, "activation/mirror_log_fault_policy",
78156a34939Shaad 					 DEFAULT_MIRROR_LOG_FAULT_POLICY);
78256a34939Shaad 	else
78356a34939Shaad 		policy = find_config_str(NULL, "activation/mirror_device_fault_policy",
78456a34939Shaad 					 DEFAULT_MIRROR_DEV_FAULT_POLICY);
78556a34939Shaad 
78656a34939Shaad 	if (!strcmp(policy, "remove"))
78756a34939Shaad 		return MIRROR_REMOVE;
78856a34939Shaad 	else if (!strcmp(policy, "allocate"))
78956a34939Shaad 		return MIRROR_ALLOCATE;
79056a34939Shaad 	else if (!strcmp(policy, "allocate_anywhere"))
79156a34939Shaad 		return MIRROR_ALLOCATE_ANYWHERE;
79256a34939Shaad 
79356a34939Shaad 	if (log_policy)
79456a34939Shaad 		log_error("Bad activation/mirror_log_fault_policy");
79556a34939Shaad 	else
79656a34939Shaad 		log_error("Bad activation/mirror_device_fault_policy");
79756a34939Shaad 
79856a34939Shaad 	return MIRROR_REMOVE;
79956a34939Shaad }
80056a34939Shaad 
get_mirror_log_fault_policy(struct cmd_context * cmd)80156a34939Shaad static int get_mirror_log_fault_policy(struct cmd_context *cmd)
80256a34939Shaad {
80356a34939Shaad 	return get_mirror_fault_policy(cmd, 1);
80456a34939Shaad }
80556a34939Shaad 
get_mirror_device_fault_policy(struct cmd_context * cmd)80656a34939Shaad static int get_mirror_device_fault_policy(struct cmd_context *cmd)
80756a34939Shaad {
80856a34939Shaad 	return get_mirror_fault_policy(cmd, 0);
80956a34939Shaad }
81056a34939Shaad 
81156a34939Shaad /*
81256a34939Shaad  * replace_mirror_images
81356a34939Shaad  * @mirrored_seg: segment (which may be linear now) to restore
81456a34939Shaad  * @num_mirrors: number of copies we should end up with
81556a34939Shaad  * @replace_log: replace log if not present
81656a34939Shaad  * @in_sync: was the original mirror in-sync?
81756a34939Shaad  *
81856a34939Shaad  * in_sync will be set to 0 if new mirror devices are being added
81956a34939Shaad  * In other words, it is only useful if the log (and only the log)
82056a34939Shaad  * is being restored.
82156a34939Shaad  *
82256a34939Shaad  * Returns: 0 on failure, 1 on reconfig, -1 if no reconfig done
82356a34939Shaad  */
replace_mirror_images(struct lv_segment * mirrored_seg,uint32_t num_mirrors,int log_policy,int in_sync)82456a34939Shaad static int replace_mirror_images(struct lv_segment *mirrored_seg,
82556a34939Shaad 				 uint32_t num_mirrors,
82656a34939Shaad 				 int log_policy, int in_sync)
82756a34939Shaad {
82856a34939Shaad 	int r = -1;
82956a34939Shaad 	struct logical_volume *lv = mirrored_seg->lv;
83056a34939Shaad 
83156a34939Shaad 	/* FIXME: Use lvconvert rather than duplicating its code */
83256a34939Shaad 
83356a34939Shaad 	if (mirrored_seg->area_count < num_mirrors) {
83456a34939Shaad 		log_error("WARNING: Failed to replace mirror device in %s/%s",
83556a34939Shaad 			  mirrored_seg->lv->vg->name, mirrored_seg->lv->name);
83656a34939Shaad 
83756a34939Shaad 		if ((mirrored_seg->area_count > 1) && !mirrored_seg->log_lv)
83856a34939Shaad 			log_error("WARNING: Use 'lvconvert -m %d %s/%s --corelog' to replace failed devices",
83956a34939Shaad 				  num_mirrors - 1, lv->vg->name, lv->name);
84056a34939Shaad 		else
84156a34939Shaad 			log_error("WARNING: Use 'lvconvert -m %d %s/%s' to replace failed devices",
84256a34939Shaad 				  num_mirrors - 1, lv->vg->name, lv->name);
84356a34939Shaad 		r = 0;
84456a34939Shaad 
84556a34939Shaad 		/* REMEMBER/FIXME: set in_sync to 0 if a new mirror device was added */
84656a34939Shaad 		in_sync = 0;
84756a34939Shaad 	}
84856a34939Shaad 
84956a34939Shaad 	/*
85056a34939Shaad 	 * FIXME: right now, we ignore the allocation policy specified to
85156a34939Shaad 	 * allocate the new log.
85256a34939Shaad 	 */
85356a34939Shaad 	if ((mirrored_seg->area_count > 1) && !mirrored_seg->log_lv &&
85456a34939Shaad 	    (log_policy != MIRROR_REMOVE)) {
85556a34939Shaad 		log_error("WARNING: Failed to replace mirror log device in %s/%s",
85656a34939Shaad 			  lv->vg->name, lv->name);
85756a34939Shaad 
85856a34939Shaad 		log_error("WARNING: Use 'lvconvert -m %d %s/%s' to replace failed devices",
85956a34939Shaad 			  mirrored_seg->area_count - 1 , lv->vg->name, lv->name);
86056a34939Shaad 		r = 0;
86156a34939Shaad 	}
86256a34939Shaad 
86356a34939Shaad 	return r;
86456a34939Shaad }
86556a34939Shaad 
reconfigure_mirror_images(struct lv_segment * mirrored_seg,uint32_t num_mirrors,struct dm_list * removable_pvs,unsigned remove_log)86656a34939Shaad int reconfigure_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
86756a34939Shaad 			      struct dm_list *removable_pvs, unsigned remove_log)
86856a34939Shaad {
86956a34939Shaad 	int r;
87056a34939Shaad 	int in_sync;
87156a34939Shaad 	int log_policy, dev_policy;
87256a34939Shaad 	uint32_t old_num_mirrors = mirrored_seg->area_count;
87356a34939Shaad 	int had_log = (mirrored_seg->log_lv) ? 1 : 0;
87456a34939Shaad 
87556a34939Shaad 	/* was the mirror in-sync before problems? */
87656a34939Shaad 	in_sync = _mirrored_lv_in_sync(mirrored_seg->lv);
87756a34939Shaad 
87856a34939Shaad 	/*
87956a34939Shaad 	 * While we are only removing devices, we can have sync set.
88056a34939Shaad 	 * Setting this is only useful if we are moving to core log
88156a34939Shaad 	 * otherwise the disk log will contain the sync information
88256a34939Shaad 	 */
88356a34939Shaad 	init_mirror_in_sync(in_sync);
88456a34939Shaad 
88556a34939Shaad 	r = _remove_mirror_images(mirrored_seg->lv, old_num_mirrors - num_mirrors,
88656a34939Shaad 				  removable_pvs, remove_log, 0, NULL);
88756a34939Shaad 	if (!r)
88856a34939Shaad 		/* Unable to remove bad devices */
88956a34939Shaad 		return 0;
89056a34939Shaad 
89156a34939Shaad 	log_warn("WARNING: Bad device removed from mirror volume, %s/%s",
89256a34939Shaad 		  mirrored_seg->lv->vg->name, mirrored_seg->lv->name);
89356a34939Shaad 
89456a34939Shaad 	log_policy = get_mirror_log_fault_policy(mirrored_seg->lv->vg->cmd);
89556a34939Shaad 	dev_policy = get_mirror_device_fault_policy(mirrored_seg->lv->vg->cmd);
89656a34939Shaad 
89756a34939Shaad 	r = replace_mirror_images(mirrored_seg,
89856a34939Shaad 				  (dev_policy != MIRROR_REMOVE) ?
89956a34939Shaad 				  old_num_mirrors : num_mirrors,
90056a34939Shaad 				  log_policy, in_sync);
90156a34939Shaad 
90256a34939Shaad 	if (!r)
90356a34939Shaad 		/* Failed to replace device(s) */
90456a34939Shaad 		log_error("WARNING: Unable to find substitute device for mirror volume, %s/%s",
90556a34939Shaad 			  mirrored_seg->lv->vg->name, mirrored_seg->lv->name);
90656a34939Shaad 	else if (r > 0)
90756a34939Shaad 		/* Success in replacing device(s) */
90856a34939Shaad 		log_warn("WARNING: Mirror volume, %s/%s restored - substitute for failed device found.",
90956a34939Shaad 			  mirrored_seg->lv->vg->name, mirrored_seg->lv->name);
91056a34939Shaad 	else
91156a34939Shaad 		/* Bad device removed, but not replaced because of policy */
91256a34939Shaad 		if (mirrored_seg->area_count == 1) {
91356a34939Shaad 			log_warn("WARNING: Mirror volume, %s/%s converted to linear due to device failure.",
91456a34939Shaad 				  mirrored_seg->lv->vg->name, mirrored_seg->lv->name);
91556a34939Shaad 		} else if (had_log && !mirrored_seg->log_lv) {
91656a34939Shaad 			log_warn("WARNING: Mirror volume, %s/%s disk log removed due to device failure.",
91756a34939Shaad 				  mirrored_seg->lv->vg->name, mirrored_seg->lv->name);
91856a34939Shaad 		}
91956a34939Shaad 	/*
92056a34939Shaad 	 * If we made it here, we at least removed the bad device.
92156a34939Shaad 	 * Consider this success.
92256a34939Shaad 	 */
92356a34939Shaad 	return 1;
92456a34939Shaad }
92556a34939Shaad 
_create_mimage_lvs(struct alloc_handle * ah,uint32_t num_mirrors,struct logical_volume * lv,struct logical_volume ** img_lvs)92656a34939Shaad static int _create_mimage_lvs(struct alloc_handle *ah,
92756a34939Shaad 			      uint32_t num_mirrors,
92856a34939Shaad 			      struct logical_volume *lv,
92956a34939Shaad 			      struct logical_volume **img_lvs)
93056a34939Shaad {
93156a34939Shaad 	uint32_t m;
93256a34939Shaad 	char *img_name;
93356a34939Shaad 	size_t len;
93456a34939Shaad 
93556a34939Shaad 	len = strlen(lv->name) + 32;
93656a34939Shaad 	if (!(img_name = alloca(len))) {
93756a34939Shaad 		log_error("img_name allocation failed. "
93856a34939Shaad 			  "Remove new LV and retry.");
93956a34939Shaad 		return 0;
94056a34939Shaad 	}
94156a34939Shaad 
94256a34939Shaad 	if (dm_snprintf(img_name, len, "%s_mimage_%%d", lv->name) < 0) {
94356a34939Shaad 		log_error("img_name allocation failed. "
94456a34939Shaad 			  "Remove new LV and retry.");
94556a34939Shaad 		return 0;
94656a34939Shaad 	}
94756a34939Shaad 
94856a34939Shaad 	for (m = 0; m < num_mirrors; m++) {
94956a34939Shaad 		if (!(img_lvs[m] = lv_create_empty(img_name,
95056a34939Shaad 					     NULL, LVM_READ | LVM_WRITE,
951*7c604eeaShaad 					     ALLOC_INHERIT, lv->vg))) {
95256a34939Shaad 			log_error("Aborting. Failed to create mirror image LV. "
95356a34939Shaad 				  "Remove new LV and retry.");
95456a34939Shaad 			return 0;
95556a34939Shaad 		}
95656a34939Shaad 
95756a34939Shaad 		if (!lv_add_segment(ah, m, 1, img_lvs[m],
95856a34939Shaad 				    get_segtype_from_string(lv->vg->cmd,
95956a34939Shaad 							    "striped"),
96056a34939Shaad 				    0, 0, 0, NULL)) {
96156a34939Shaad 			log_error("Aborting. Failed to add mirror image segment "
96256a34939Shaad 				  "to %s. Remove new LV and retry.",
96356a34939Shaad 				  img_lvs[m]->name);
96456a34939Shaad 			return 0;
96556a34939Shaad 		}
96656a34939Shaad 	}
96756a34939Shaad 
96856a34939Shaad 	return 1;
96956a34939Shaad }
97056a34939Shaad 
97156a34939Shaad /*
97256a34939Shaad  * Remove mirrors from each segment.
97356a34939Shaad  * 'new_mirrors' is the number of mirrors after the removal. '0' for linear.
97456a34939Shaad  * If 'status_mask' is non-zero, the removal happens only when all segments
97556a34939Shaad  * has the status bits on.
97656a34939Shaad  */
remove_mirrors_from_segments(struct logical_volume * lv,uint32_t new_mirrors,uint32_t status_mask)97756a34939Shaad int remove_mirrors_from_segments(struct logical_volume *lv,
97856a34939Shaad 				 uint32_t new_mirrors, uint32_t status_mask)
97956a34939Shaad {
98056a34939Shaad 	struct lv_segment *seg;
98156a34939Shaad 	uint32_t s;
98256a34939Shaad 
98356a34939Shaad 	/* Check the segment params are compatible */
98456a34939Shaad 	dm_list_iterate_items(seg, &lv->segments) {
98556a34939Shaad 		if (!seg_is_mirrored(seg)) {
98656a34939Shaad 			log_error("Segment is not mirrored: %s:%" PRIu32,
98756a34939Shaad 				  lv->name, seg->le);
98856a34939Shaad 			return 0;
98956a34939Shaad 		} if ((seg->status & status_mask) != status_mask) {
99056a34939Shaad 			log_error("Segment status does not match: %s:%" PRIu32
99156a34939Shaad 				  " status:0x%x/0x%x", lv->name, seg->le,
99256a34939Shaad 				  seg->status, status_mask);
99356a34939Shaad 			return 0;
99456a34939Shaad 		}
99556a34939Shaad 	}
99656a34939Shaad 
99756a34939Shaad 	/* Convert the segments */
99856a34939Shaad 	dm_list_iterate_items(seg, &lv->segments) {
99956a34939Shaad 		if (!new_mirrors && seg->extents_copied == seg->area_len) {
100056a34939Shaad 			if (!move_lv_segment_area(seg, 0, seg, 1))
100156a34939Shaad 				return_0;
100256a34939Shaad 		}
100356a34939Shaad 
100456a34939Shaad 		for (s = new_mirrors + 1; s < seg->area_count; s++)
100556a34939Shaad 			release_lv_segment_area(seg, s, seg->area_len);
100656a34939Shaad 
100756a34939Shaad 		seg->area_count = new_mirrors + 1;
100856a34939Shaad 
100956a34939Shaad 		if (!new_mirrors)
101056a34939Shaad 			seg->segtype = get_segtype_from_string(lv->vg->cmd,
101156a34939Shaad 							       "striped");
101256a34939Shaad 	}
101356a34939Shaad 
101456a34939Shaad 	return 1;
101556a34939Shaad }
101656a34939Shaad 
get_pvmove_pvname_from_lv_mirr(struct logical_volume * lv_mirr)101756a34939Shaad const char *get_pvmove_pvname_from_lv_mirr(struct logical_volume *lv_mirr)
101856a34939Shaad {
101956a34939Shaad 	struct lv_segment *seg;
102056a34939Shaad 
102156a34939Shaad 	dm_list_iterate_items(seg, &lv_mirr->segments) {
102256a34939Shaad 		if (!seg_is_mirrored(seg))
102356a34939Shaad 			continue;
102456a34939Shaad 		if (seg_type(seg, 0) != AREA_PV)
102556a34939Shaad 			continue;
102656a34939Shaad 		return dev_name(seg_dev(seg, 0));
102756a34939Shaad 	}
102856a34939Shaad 
102956a34939Shaad 	return NULL;
103056a34939Shaad }
103156a34939Shaad 
get_pvmove_pvname_from_lv(struct logical_volume * lv)103256a34939Shaad const char *get_pvmove_pvname_from_lv(struct logical_volume *lv)
103356a34939Shaad {
103456a34939Shaad 	struct lv_segment *seg;
103556a34939Shaad 	uint32_t s;
103656a34939Shaad 
103756a34939Shaad 	dm_list_iterate_items(seg, &lv->segments) {
103856a34939Shaad 		for (s = 0; s < seg->area_count; s++) {
103956a34939Shaad 			if (seg_type(seg, s) != AREA_LV)
104056a34939Shaad 				continue;
104156a34939Shaad 			return get_pvmove_pvname_from_lv_mirr(seg_lv(seg, s));
104256a34939Shaad 		}
104356a34939Shaad 	}
104456a34939Shaad 
104556a34939Shaad 	return NULL;
104656a34939Shaad }
104756a34939Shaad 
find_pvmove_lv(struct volume_group * vg,struct device * dev,uint32_t lv_type)104856a34939Shaad struct logical_volume *find_pvmove_lv(struct volume_group *vg,
104956a34939Shaad 				      struct device *dev,
105056a34939Shaad 				      uint32_t lv_type)
105156a34939Shaad {
105256a34939Shaad 	struct lv_list *lvl;
105356a34939Shaad 	struct logical_volume *lv;
105456a34939Shaad 	struct lv_segment *seg;
105556a34939Shaad 
105656a34939Shaad 	/* Loop through all LVs */
105756a34939Shaad 	dm_list_iterate_items(lvl, &vg->lvs) {
105856a34939Shaad 		lv = lvl->lv;
105956a34939Shaad 
106056a34939Shaad 		if (!(lv->status & lv_type))
106156a34939Shaad 			continue;
106256a34939Shaad 
106356a34939Shaad 		/* Check segment origins point to pvname */
106456a34939Shaad 		dm_list_iterate_items(seg, &lv->segments) {
106556a34939Shaad 			if (seg_type(seg, 0) != AREA_PV)
106656a34939Shaad 				continue;
106756a34939Shaad 			if (seg_dev(seg, 0) != dev)
106856a34939Shaad 				continue;
106956a34939Shaad 			return lv;
107056a34939Shaad 		}
107156a34939Shaad 	}
107256a34939Shaad 
107356a34939Shaad 	return NULL;
107456a34939Shaad }
107556a34939Shaad 
find_pvmove_lv_from_pvname(struct cmd_context * cmd,struct volume_group * vg,const char * name,const char * uuid __attribute ((unused)),uint32_t lv_type)107656a34939Shaad struct logical_volume *find_pvmove_lv_from_pvname(struct cmd_context *cmd,
107756a34939Shaad 						  struct volume_group *vg,
107856a34939Shaad 						  const char *name,
1079*7c604eeaShaad 						  const char *uuid __attribute((unused)),
108056a34939Shaad 						  uint32_t lv_type)
108156a34939Shaad {
108256a34939Shaad 	struct physical_volume *pv;
108356a34939Shaad 
108456a34939Shaad 	if (!(pv = find_pv_by_name(cmd, name)))
108556a34939Shaad 		return_NULL;
108656a34939Shaad 
108756a34939Shaad 	return find_pvmove_lv(vg, pv->dev, lv_type);
108856a34939Shaad }
108956a34939Shaad 
lvs_using_lv(struct cmd_context * cmd,struct volume_group * vg,struct logical_volume * lv)109056a34939Shaad struct dm_list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
109156a34939Shaad 			  struct logical_volume *lv)
109256a34939Shaad {
109356a34939Shaad 	struct dm_list *lvs;
109456a34939Shaad 	struct logical_volume *lv1;
109556a34939Shaad 	struct lv_list *lvl, *lvl1;
109656a34939Shaad 	struct lv_segment *seg;
109756a34939Shaad 	uint32_t s;
109856a34939Shaad 
109956a34939Shaad 	if (!(lvs = dm_pool_alloc(cmd->mem, sizeof(*lvs)))) {
110056a34939Shaad 		log_error("lvs list alloc failed");
110156a34939Shaad 		return NULL;
110256a34939Shaad 	}
110356a34939Shaad 
110456a34939Shaad 	dm_list_init(lvs);
110556a34939Shaad 
110656a34939Shaad 	/* Loop through all LVs except the one supplied */
110756a34939Shaad 	dm_list_iterate_items(lvl1, &vg->lvs) {
110856a34939Shaad 		lv1 = lvl1->lv;
110956a34939Shaad 		if (lv1 == lv)
111056a34939Shaad 			continue;
111156a34939Shaad 
111256a34939Shaad 		/* Find whether any segment points at the supplied LV */
111356a34939Shaad 		dm_list_iterate_items(seg, &lv1->segments) {
111456a34939Shaad 			for (s = 0; s < seg->area_count; s++) {
111556a34939Shaad 				if (seg_type(seg, s) != AREA_LV ||
111656a34939Shaad 				    seg_lv(seg, s) != lv)
111756a34939Shaad 					continue;
111856a34939Shaad 				if (!(lvl = dm_pool_alloc(cmd->mem, sizeof(*lvl)))) {
111956a34939Shaad 					log_error("lv_list alloc failed");
112056a34939Shaad 					return NULL;
112156a34939Shaad 				}
112256a34939Shaad 				lvl->lv = lv1;
112356a34939Shaad 				dm_list_add(lvs, &lvl->list);
112456a34939Shaad 				goto next_lv;
112556a34939Shaad 			}
112656a34939Shaad 		}
112756a34939Shaad 	      next_lv:
112856a34939Shaad 		;
112956a34939Shaad 	}
113056a34939Shaad 
113156a34939Shaad 	return lvs;
113256a34939Shaad }
113356a34939Shaad 
copy_percent(struct logical_volume * lv_mirr,percent_range_t * percent_range)1134*7c604eeaShaad float copy_percent(struct logical_volume *lv_mirr,
1135*7c604eeaShaad 		   percent_range_t *percent_range)
113656a34939Shaad {
113756a34939Shaad 	uint32_t numerator = 0u, denominator = 0u;
113856a34939Shaad 	struct lv_segment *seg;
113956a34939Shaad 
114056a34939Shaad 	dm_list_iterate_items(seg, &lv_mirr->segments) {
114156a34939Shaad 		denominator += seg->area_len;
114256a34939Shaad 
114356a34939Shaad 		if (seg_is_mirrored(seg) && seg->area_count > 1)
114456a34939Shaad 			numerator += seg->extents_copied;
114556a34939Shaad 		else
114656a34939Shaad 			numerator += seg->area_len;
114756a34939Shaad 	}
114856a34939Shaad 
1149*7c604eeaShaad 	if (!denominator || (numerator == denominator))
1150*7c604eeaShaad 		*percent_range = PERCENT_100;
1151*7c604eeaShaad 	else if (numerator == 0)
1152*7c604eeaShaad 		*percent_range = PERCENT_0;
1153*7c604eeaShaad 	else
1154*7c604eeaShaad 		*percent_range = PERCENT_0_TO_100;
1155*7c604eeaShaad 
115656a34939Shaad 	return denominator ? (float) numerator *100 / denominator : 100.0;
115756a34939Shaad }
115856a34939Shaad 
115956a34939Shaad /*
116056a34939Shaad  * Fixup mirror pointers after single-pass segment import
116156a34939Shaad  */
fixup_imported_mirrors(struct volume_group * vg)116256a34939Shaad int fixup_imported_mirrors(struct volume_group *vg)
116356a34939Shaad {
116456a34939Shaad 	struct lv_list *lvl;
116556a34939Shaad 	struct lv_segment *seg;
116656a34939Shaad 
116756a34939Shaad 	dm_list_iterate_items(lvl, &vg->lvs) {
116856a34939Shaad 		dm_list_iterate_items(seg, &lvl->lv->segments) {
116956a34939Shaad 			if (seg->segtype !=
117056a34939Shaad 			    get_segtype_from_string(vg->cmd, "mirror"))
117156a34939Shaad 				continue;
117256a34939Shaad 
117356a34939Shaad 			if (seg->log_lv && !add_seg_to_segs_using_this_lv(seg->log_lv, seg))
117456a34939Shaad 				return_0;
117556a34939Shaad 		}
117656a34939Shaad 	}
117756a34939Shaad 
117856a34939Shaad 	return 1;
117956a34939Shaad }
118056a34939Shaad 
118156a34939Shaad /*
118256a34939Shaad  * Add mirrors to "linear" or "mirror" segments
118356a34939Shaad  */
add_mirrors_to_segments(struct cmd_context * cmd,struct logical_volume * lv,uint32_t mirrors,uint32_t region_size,struct dm_list * allocatable_pvs,alloc_policy_t alloc)118456a34939Shaad int add_mirrors_to_segments(struct cmd_context *cmd, struct logical_volume *lv,
118556a34939Shaad 			    uint32_t mirrors, uint32_t region_size,
118656a34939Shaad 			    struct dm_list *allocatable_pvs, alloc_policy_t alloc)
118756a34939Shaad {
118856a34939Shaad 	struct alloc_handle *ah;
118956a34939Shaad 	const struct segment_type *segtype;
119056a34939Shaad 	struct dm_list *parallel_areas;
119156a34939Shaad 	uint32_t adjusted_region_size;
1192*7c604eeaShaad 	int r = 1;
119356a34939Shaad 
119456a34939Shaad 	if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv)))
119556a34939Shaad 		return_0;
119656a34939Shaad 
119756a34939Shaad 	if (!(segtype = get_segtype_from_string(cmd, "mirror")))
119856a34939Shaad 		return_0;
119956a34939Shaad 
120056a34939Shaad 	adjusted_region_size = adjusted_mirror_region_size(lv->vg->extent_size,
120156a34939Shaad 							   lv->le_count,
120256a34939Shaad 							   region_size);
120356a34939Shaad 
1204bec4d750Shaad 	if (!(ah = allocate_extents(lv->vg, NULL, segtype, 1, mirrors, 0, 0,
120556a34939Shaad 				    lv->le_count, allocatable_pvs, alloc,
120656a34939Shaad 				    parallel_areas))) {
120756a34939Shaad 		log_error("Unable to allocate mirror extents for %s.", lv->name);
120856a34939Shaad 		return 0;
120956a34939Shaad 	}
121056a34939Shaad 
121156a34939Shaad 	if (!lv_add_mirror_areas(ah, lv, 0, adjusted_region_size)) {
121256a34939Shaad 		log_error("Failed to add mirror areas to %s", lv->name);
1213*7c604eeaShaad 		r = 0;
121456a34939Shaad 	}
121556a34939Shaad 
1216*7c604eeaShaad 	alloc_destroy(ah);
1217*7c604eeaShaad 	return r;
121856a34939Shaad }
121956a34939Shaad 
122056a34939Shaad /*
122156a34939Shaad  * Convert mirror log
122256a34939Shaad  *
122356a34939Shaad  * FIXME: Can't handle segment-by-segment mirror (like pvmove)
122456a34939Shaad  */
remove_mirror_log(struct cmd_context * cmd,struct logical_volume * lv,struct dm_list * removable_pvs)122556a34939Shaad int remove_mirror_log(struct cmd_context *cmd,
122656a34939Shaad 		      struct logical_volume *lv,
122756a34939Shaad 		      struct dm_list *removable_pvs)
122856a34939Shaad {
122956a34939Shaad 	float sync_percent;
1230*7c604eeaShaad 	percent_range_t percent_range = PERCENT_0;
123156a34939Shaad 	struct lvinfo info;
123256a34939Shaad 	struct volume_group *vg = lv->vg;
123356a34939Shaad 
123456a34939Shaad 	/* Unimplemented features */
123556a34939Shaad 	if (dm_list_size(&lv->segments) != 1) {
123656a34939Shaad 		log_error("Multiple-segment mirror is not supported");
123756a34939Shaad 		return 0;
123856a34939Shaad 	}
123956a34939Shaad 
124056a34939Shaad 	/* Had disk log, switch to core. */
124156a34939Shaad 	if (lv_info(cmd, lv, &info, 0, 0) && info.exists) {
1242*7c604eeaShaad 		if (!lv_mirror_percent(cmd, lv, 0, &sync_percent,
1243*7c604eeaShaad 				       &percent_range, NULL)) {
124456a34939Shaad 			log_error("Unable to determine mirror sync status.");
124556a34939Shaad 			return 0;
124656a34939Shaad 		}
124756a34939Shaad 	} else if (vg_is_clustered(vg)) {
1248*7c604eeaShaad 		log_error("Unable to convert the log of an inactive "
1249*7c604eeaShaad 			  "cluster mirror, %s", lv->name);
125056a34939Shaad 		return 0;
125156a34939Shaad 	} else if (yes_no_prompt("Full resync required to convert "
125256a34939Shaad 				 "inactive mirror %s to core log. "
1253*7c604eeaShaad 				 "Proceed? [y/n]: ") == 'y')
125456a34939Shaad 		sync_percent = 0;
125556a34939Shaad 	else
125656a34939Shaad 		return 0;
125756a34939Shaad 
1258*7c604eeaShaad 	if (percent_range == PERCENT_100)
125956a34939Shaad 		init_mirror_in_sync(1);
126056a34939Shaad 	else {
126156a34939Shaad 		/* A full resync will take place */
126256a34939Shaad 		lv->status &= ~MIRROR_NOTSYNCED;
126356a34939Shaad 		init_mirror_in_sync(0);
126456a34939Shaad 	}
126556a34939Shaad 
126656a34939Shaad 	if (!remove_mirror_images(lv, lv_mirror_count(lv),
126756a34939Shaad 				  removable_pvs, 1U))
126856a34939Shaad 		return_0;
126956a34939Shaad 
127056a34939Shaad 	return 1;
127156a34939Shaad }
127256a34939Shaad 
_create_mirror_log(struct logical_volume * lv,struct alloc_handle * ah,alloc_policy_t alloc,const char * lv_name,const char * suffix)127356a34939Shaad static struct logical_volume *_create_mirror_log(struct logical_volume *lv,
127456a34939Shaad 						 struct alloc_handle *ah,
127556a34939Shaad 						 alloc_policy_t alloc,
127656a34939Shaad 						 const char *lv_name,
127756a34939Shaad 						 const char *suffix)
127856a34939Shaad {
127956a34939Shaad 	struct logical_volume *log_lv;
128056a34939Shaad 	char *log_name;
128156a34939Shaad 	size_t len;
128256a34939Shaad 
128356a34939Shaad 	len = strlen(lv_name) + 32;
128456a34939Shaad 	if (!(log_name = alloca(len))) {
128556a34939Shaad 		log_error("log_name allocation failed.");
128656a34939Shaad 		return NULL;
128756a34939Shaad 	}
128856a34939Shaad 
128956a34939Shaad 	if (dm_snprintf(log_name, len, "%s%s", lv_name, suffix) < 0) {
129056a34939Shaad 		log_error("log_name allocation failed.");
129156a34939Shaad 		return NULL;
129256a34939Shaad 	}
129356a34939Shaad 
129456a34939Shaad 	if (!(log_lv = lv_create_empty(log_name, NULL,
129556a34939Shaad 				       VISIBLE_LV | LVM_READ | LVM_WRITE,
1296*7c604eeaShaad 				       alloc, lv->vg)))
129756a34939Shaad 		return_NULL;
129856a34939Shaad 
129956a34939Shaad 	if (!lv_add_log_segment(ah, log_lv))
130056a34939Shaad 		return_NULL;
130156a34939Shaad 
130256a34939Shaad 	return log_lv;
130356a34939Shaad }
130456a34939Shaad 
_set_up_mirror_log(struct cmd_context * cmd,struct alloc_handle * ah,struct logical_volume * lv,uint32_t log_count,uint32_t region_size __attribute ((unused)),alloc_policy_t alloc,int in_sync)130556a34939Shaad static struct logical_volume *_set_up_mirror_log(struct cmd_context *cmd,
130656a34939Shaad 						 struct alloc_handle *ah,
130756a34939Shaad 						 struct logical_volume *lv,
130856a34939Shaad 						 uint32_t log_count,
130956a34939Shaad 						 uint32_t region_size __attribute((unused)),
131056a34939Shaad 						 alloc_policy_t alloc,
131156a34939Shaad 						 int in_sync)
131256a34939Shaad {
131356a34939Shaad 	struct logical_volume *log_lv;
131456a34939Shaad 	const char *suffix, *c;
131556a34939Shaad 	char *lv_name;
131656a34939Shaad 	size_t len;
131756a34939Shaad 	struct lv_segment *seg;
131856a34939Shaad 
131956a34939Shaad 	init_mirror_in_sync(in_sync);
132056a34939Shaad 
132156a34939Shaad 	if (log_count != 1) {
132256a34939Shaad 		log_error("log_count != 1 is not supported.");
132356a34939Shaad 		return NULL;
132456a34939Shaad 	}
132556a34939Shaad 
132656a34939Shaad 	/* Mirror log name is lv_name + suffix, determined as the following:
132756a34939Shaad 	 *   1. suffix is:
132856a34939Shaad 	 *        o "_mlog" for the original mirror LV.
132956a34939Shaad 	 *        o "_mlogtmp_%d" for temporary mirror LV,
133056a34939Shaad 	 *   2. lv_name is:
133156a34939Shaad 	 *        o lv->name, if the log is temporary
133256a34939Shaad 	 *        o otherwise, the top-level LV name
133356a34939Shaad 	 */
133456a34939Shaad 	seg = first_seg(lv);
133556a34939Shaad 	if (seg_type(seg, 0) == AREA_LV &&
133656a34939Shaad 	    strstr(seg_lv(seg, 0)->name, MIRROR_SYNC_LAYER)) {
133756a34939Shaad 		lv_name = lv->name;
133856a34939Shaad 		suffix = "_mlogtmp_%d";
133956a34939Shaad 	} else if ((c = strstr(lv->name, MIRROR_SYNC_LAYER))) {
134056a34939Shaad 		len = c - lv->name + 1;
134156a34939Shaad 		if (!(lv_name = alloca(len)) ||
134256a34939Shaad 		    !dm_snprintf(lv_name, len, "%s", lv->name)) {
134356a34939Shaad 			log_error("mirror log name allocation failed");
134456a34939Shaad 			return 0;
134556a34939Shaad 		}
134656a34939Shaad 		suffix = "_mlog";
134756a34939Shaad 	} else {
134856a34939Shaad 		lv_name = lv->name;
134956a34939Shaad 		suffix = "_mlog";
135056a34939Shaad 	}
135156a34939Shaad 
135256a34939Shaad 	if (!(log_lv = _create_mirror_log(lv, ah, alloc,
135356a34939Shaad 					  (const char *) lv_name, suffix))) {
135456a34939Shaad 		log_error("Failed to create mirror log.");
135556a34939Shaad 		return NULL;
135656a34939Shaad 	}
135756a34939Shaad 
135856a34939Shaad 	if (!_init_mirror_log(cmd, log_lv, in_sync, &lv->tags, 1)) {
135956a34939Shaad 		log_error("Failed to create mirror log.");
136056a34939Shaad 		return NULL;
136156a34939Shaad 	}
136256a34939Shaad 
136356a34939Shaad 	return log_lv;
136456a34939Shaad }
136556a34939Shaad 
attach_mirror_log(struct lv_segment * seg,struct logical_volume * log_lv)136656a34939Shaad int attach_mirror_log(struct lv_segment *seg, struct logical_volume *log_lv)
136756a34939Shaad {
136856a34939Shaad 	seg->log_lv = log_lv;
136956a34939Shaad 	log_lv->status |= MIRROR_LOG;
1370*7c604eeaShaad 	lv_set_hidden(log_lv);
137156a34939Shaad 	return add_seg_to_segs_using_this_lv(log_lv, seg);
137256a34939Shaad }
137356a34939Shaad 
add_mirror_log(struct cmd_context * cmd,struct logical_volume * lv,uint32_t log_count,uint32_t region_size,struct dm_list * allocatable_pvs,alloc_policy_t alloc)137456a34939Shaad int add_mirror_log(struct cmd_context *cmd, struct logical_volume *lv,
137556a34939Shaad 		   uint32_t log_count, uint32_t region_size,
137656a34939Shaad 		   struct dm_list *allocatable_pvs, alloc_policy_t alloc)
137756a34939Shaad {
137856a34939Shaad 	struct alloc_handle *ah;
137956a34939Shaad 	const struct segment_type *segtype;
138056a34939Shaad 	struct dm_list *parallel_areas;
138156a34939Shaad 	float sync_percent;
1382*7c604eeaShaad 	percent_range_t percent_range;
138356a34939Shaad 	int in_sync;
138456a34939Shaad 	struct logical_volume *log_lv;
138556a34939Shaad 	struct lvinfo info;
1386*7c604eeaShaad 	int r = 0;
138756a34939Shaad 
138856a34939Shaad 	/* Unimplemented features */
138956a34939Shaad 	if (log_count > 1) {
139056a34939Shaad 		log_error("log_count > 1 is not supported");
139156a34939Shaad 		return 0;
139256a34939Shaad 	}
139356a34939Shaad 
139456a34939Shaad 	if (dm_list_size(&lv->segments) != 1) {
139556a34939Shaad 		log_error("Multiple-segment mirror is not supported");
139656a34939Shaad 		return 0;
139756a34939Shaad 	}
139856a34939Shaad 
139956a34939Shaad 	/*
140056a34939Shaad 	 * We are unable to convert the log of inactive cluster mirrors
140156a34939Shaad 	 * due to the inability to detect whether the mirror is active
140256a34939Shaad 	 * on remote nodes (even though it is inactive on this node)
140356a34939Shaad 	 */
140456a34939Shaad 	if (vg_is_clustered(lv->vg) &&
140556a34939Shaad 	    !(lv_info(cmd, lv, &info, 0, 0) && info.exists)) {
140656a34939Shaad 		log_error("Unable to convert the log of inactive "
140756a34939Shaad 			  "cluster mirror %s", lv->name);
140856a34939Shaad 		return 0;
140956a34939Shaad 	}
141056a34939Shaad 
141156a34939Shaad 	if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv)))
141256a34939Shaad 		return_0;
141356a34939Shaad 
141456a34939Shaad 	if (!(segtype = get_segtype_from_string(cmd, "mirror")))
141556a34939Shaad 		return_0;
141656a34939Shaad 
141756a34939Shaad 	if (activation() && segtype->ops->target_present &&
1418*7c604eeaShaad 	    !segtype->ops->target_present(cmd, NULL, NULL)) {
141956a34939Shaad 		log_error("%s: Required device-mapper target(s) not "
142056a34939Shaad 			  "detected in your kernel", segtype->name);
142156a34939Shaad 		return 0;
142256a34939Shaad 	}
142356a34939Shaad 
142456a34939Shaad 	/* allocate destination extents */
142556a34939Shaad 	ah = allocate_extents(lv->vg, NULL, segtype,
1426bec4d750Shaad 			      0, 0, log_count, region_size, 0,
142756a34939Shaad 			      allocatable_pvs, alloc, parallel_areas);
142856a34939Shaad 	if (!ah) {
142956a34939Shaad 		log_error("Unable to allocate extents for mirror log.");
143056a34939Shaad 		return 0;
143156a34939Shaad 	}
143256a34939Shaad 
143356a34939Shaad 	/* check sync status */
1434*7c604eeaShaad 	if (lv_mirror_percent(cmd, lv, 0, &sync_percent, &percent_range,
1435*7c604eeaShaad 			      NULL) &&
1436*7c604eeaShaad 	    (percent_range == PERCENT_100))
143756a34939Shaad 		in_sync = 1;
143856a34939Shaad 	else
143956a34939Shaad 		in_sync = 0;
144056a34939Shaad 
144156a34939Shaad 	if (!(log_lv = _set_up_mirror_log(cmd, ah, lv, log_count,
144256a34939Shaad 					  region_size, alloc, in_sync)))
1443*7c604eeaShaad 		goto_out;
144456a34939Shaad 
144556a34939Shaad 	if (!attach_mirror_log(first_seg(lv), log_lv))
1446*7c604eeaShaad 		goto_out;
144756a34939Shaad 
1448*7c604eeaShaad 	r = 1;
1449*7c604eeaShaad out:
145056a34939Shaad 	alloc_destroy(ah);
1451*7c604eeaShaad 	return r;
145256a34939Shaad }
145356a34939Shaad 
145456a34939Shaad /*
145556a34939Shaad  * Convert "linear" LV to "mirror".
145656a34939Shaad  */
add_mirror_images(struct cmd_context * cmd,struct logical_volume * lv,uint32_t mirrors,uint32_t stripes,uint32_t region_size,struct dm_list * allocatable_pvs,alloc_policy_t alloc,uint32_t log_count)145756a34939Shaad int add_mirror_images(struct cmd_context *cmd, struct logical_volume *lv,
145856a34939Shaad 		      uint32_t mirrors, uint32_t stripes, uint32_t region_size,
145956a34939Shaad 		      struct dm_list *allocatable_pvs, alloc_policy_t alloc,
146056a34939Shaad 		      uint32_t log_count)
146156a34939Shaad {
146256a34939Shaad 	struct alloc_handle *ah;
146356a34939Shaad 	const struct segment_type *segtype;
146456a34939Shaad 	struct dm_list *parallel_areas;
146556a34939Shaad 	struct logical_volume **img_lvs;
146656a34939Shaad 	struct logical_volume *log_lv = NULL;
146756a34939Shaad 
146856a34939Shaad 	if (stripes > 1) {
146956a34939Shaad 		log_error("stripes > 1 is not supported");
147056a34939Shaad 		return 0;
147156a34939Shaad 	}
147256a34939Shaad 
147356a34939Shaad 	/*
147456a34939Shaad 	 * allocate destination extents
147556a34939Shaad 	 */
147656a34939Shaad 
147756a34939Shaad 	if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv)))
147856a34939Shaad 		return_0;
147956a34939Shaad 
148056a34939Shaad 	if (!(segtype = get_segtype_from_string(cmd, "mirror")))
148156a34939Shaad 		return_0;
148256a34939Shaad 
148356a34939Shaad 	ah = allocate_extents(lv->vg, NULL, segtype,
1484bec4d750Shaad 			      stripes, mirrors, log_count, region_size, lv->le_count,
148556a34939Shaad 			      allocatable_pvs, alloc, parallel_areas);
148656a34939Shaad 	if (!ah) {
148756a34939Shaad 		log_error("Unable to allocate extents for mirror(s).");
148856a34939Shaad 		return 0;
148956a34939Shaad 	}
149056a34939Shaad 
149156a34939Shaad 	/*
149256a34939Shaad 	 * create and initialize mirror log
149356a34939Shaad 	 */
149456a34939Shaad 	if (log_count &&
149556a34939Shaad 	    !(log_lv = _set_up_mirror_log(cmd, ah, lv, log_count, region_size,
1496*7c604eeaShaad 					  alloc, mirror_in_sync()))) {
1497*7c604eeaShaad 		stack;
1498*7c604eeaShaad 		goto out_remove_images;
1499*7c604eeaShaad 	}
150056a34939Shaad 
150156a34939Shaad 	/* The log initialization involves vg metadata commit.
150256a34939Shaad 	   So from here on, if failure occurs, the log must be explicitly
150356a34939Shaad 	   removed and the updated vg metadata should be committed. */
150456a34939Shaad 
150556a34939Shaad 	/*
150656a34939Shaad 	 * insert a mirror layer
150756a34939Shaad 	 */
150856a34939Shaad 	if (dm_list_size(&lv->segments) != 1 ||
150956a34939Shaad 	    seg_type(first_seg(lv), 0) != AREA_LV)
151056a34939Shaad 		if (!insert_layer_for_lv(cmd, lv, 0, "_mimage_%d"))
151156a34939Shaad 			goto out_remove_log;
151256a34939Shaad 
151356a34939Shaad 	/*
151456a34939Shaad 	 * create mirror image LVs
151556a34939Shaad 	 */
151656a34939Shaad 	if (!(img_lvs = alloca(sizeof(*img_lvs) * mirrors))) {
151756a34939Shaad 		log_error("img_lvs allocation failed. "
151856a34939Shaad 			  "Remove new LV and retry.");
151956a34939Shaad 		goto out_remove_log;
152056a34939Shaad 	}
152156a34939Shaad 
152256a34939Shaad 	if (!_create_mimage_lvs(ah, mirrors, lv, img_lvs))
152356a34939Shaad 		goto out_remove_log;
152456a34939Shaad 
152556a34939Shaad 	if (!lv_add_mirror_lvs(lv, img_lvs, mirrors,
152656a34939Shaad 			       MIRROR_IMAGE | (lv->status & LOCKED),
152756a34939Shaad 			       region_size)) {
152856a34939Shaad 		log_error("Aborting. Failed to add mirror segment. "
152956a34939Shaad 			  "Remove new LV and retry.");
1530*7c604eeaShaad 		goto out_remove_images;
153156a34939Shaad 	}
153256a34939Shaad 
153356a34939Shaad 	if (log_count && !attach_mirror_log(first_seg(lv), log_lv))
153456a34939Shaad 		stack;
153556a34939Shaad 
153656a34939Shaad 	alloc_destroy(ah);
153756a34939Shaad 	return 1;
153856a34939Shaad 
153956a34939Shaad   out_remove_log:
1540*7c604eeaShaad 	if (log_lv) {
1541*7c604eeaShaad 		if (!lv_remove(log_lv) ||
1542*7c604eeaShaad 		    !vg_write(log_lv->vg) ||
1543*7c604eeaShaad 		    !vg_commit(log_lv->vg))
154456a34939Shaad 			log_error("Manual intervention may be required to remove "
154556a34939Shaad 				  "abandoned log LV before retrying.");
1546*7c604eeaShaad 		else
1547*7c604eeaShaad 			backup(log_lv->vg);
1548*7c604eeaShaad 	}
1549*7c604eeaShaad   out_remove_images:
1550*7c604eeaShaad 	alloc_destroy(ah);
155156a34939Shaad 	return 0;
155256a34939Shaad }
155356a34939Shaad 
155456a34939Shaad /*
155556a34939Shaad  * Generic interface for adding mirror and/or mirror log.
155656a34939Shaad  * 'mirror' is the number of mirrors to be added.
155756a34939Shaad  * 'pvs' is either allocatable pvs.
155856a34939Shaad  */
lv_add_mirrors(struct cmd_context * cmd,struct logical_volume * lv,uint32_t mirrors,uint32_t stripes,uint32_t region_size,uint32_t log_count,struct dm_list * pvs,alloc_policy_t alloc,uint32_t flags)155956a34939Shaad int lv_add_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
156056a34939Shaad 		   uint32_t mirrors, uint32_t stripes,
156156a34939Shaad 		   uint32_t region_size, uint32_t log_count,
156256a34939Shaad 		   struct dm_list *pvs, alloc_policy_t alloc, uint32_t flags)
156356a34939Shaad {
156456a34939Shaad 	if (!mirrors && !log_count) {
156556a34939Shaad 		log_error("No conversion is requested");
156656a34939Shaad 		return 0;
156756a34939Shaad 	}
156856a34939Shaad 
156956a34939Shaad 	/* For corelog mirror, activation code depends on
157056a34939Shaad 	 * the global mirror_in_sync status. As we are adding
157156a34939Shaad 	 * a new mirror, it should be set as 'out-of-sync'
157256a34939Shaad 	 * so that the sync starts. */
157356a34939Shaad 	/* However, MIRROR_SKIP_INIT_SYNC even overrides it. */
157456a34939Shaad 	if (flags & MIRROR_SKIP_INIT_SYNC)
157556a34939Shaad 		init_mirror_in_sync(1);
157656a34939Shaad 	else if (!log_count)
157756a34939Shaad 		init_mirror_in_sync(0);
157856a34939Shaad 
157956a34939Shaad 	if (flags & MIRROR_BY_SEG) {
158056a34939Shaad 		if (log_count) {
158156a34939Shaad 			log_error("Persistent log is not supported on "
158256a34939Shaad 				  "segment-by-segment mirroring");
158356a34939Shaad 			return 0;
158456a34939Shaad 		}
158556a34939Shaad 		if (stripes > 1) {
158656a34939Shaad 			log_error("Striped-mirroring is not supported on "
158756a34939Shaad 				  "segment-by-segment mirroring");
158856a34939Shaad 			return 0;
158956a34939Shaad 		}
159056a34939Shaad 
159156a34939Shaad 		return add_mirrors_to_segments(cmd, lv, mirrors,
159256a34939Shaad 					       region_size, pvs, alloc);
159356a34939Shaad 	} else if (flags & MIRROR_BY_LV) {
159456a34939Shaad 		if (!mirrors)
159556a34939Shaad 			return add_mirror_log(cmd, lv, log_count,
159656a34939Shaad 					      region_size, pvs, alloc);
159756a34939Shaad 		return add_mirror_images(cmd, lv, mirrors,
159856a34939Shaad 					 stripes, region_size,
159956a34939Shaad 					 pvs, alloc, log_count);
160056a34939Shaad 	}
160156a34939Shaad 
160256a34939Shaad 	log_error("Unsupported mirror conversion type");
160356a34939Shaad 	return 0;
160456a34939Shaad }
160556a34939Shaad 
160656a34939Shaad /*
160756a34939Shaad  * Generic interface for removing mirror and/or mirror log.
160856a34939Shaad  * 'mirror' is the number of mirrors to be removed.
160956a34939Shaad  * 'pvs' is removable pvs.
161056a34939Shaad  */
lv_remove_mirrors(struct cmd_context * cmd __attribute ((unused)),struct logical_volume * lv,uint32_t mirrors,uint32_t log_count,struct dm_list * pvs,uint32_t status_mask)161156a34939Shaad int lv_remove_mirrors(struct cmd_context *cmd __attribute((unused)),
161256a34939Shaad 		      struct logical_volume *lv,
161356a34939Shaad 		      uint32_t mirrors, uint32_t log_count, struct dm_list *pvs,
161456a34939Shaad 		      uint32_t status_mask)
161556a34939Shaad {
161656a34939Shaad 	uint32_t new_mirrors;
161756a34939Shaad 	struct lv_segment *seg;
161856a34939Shaad 
161956a34939Shaad 	if (!mirrors && !log_count) {
162056a34939Shaad 		log_error("No conversion is requested");
162156a34939Shaad 		return 0;
162256a34939Shaad 	}
162356a34939Shaad 
162456a34939Shaad 	seg = first_seg(lv);
162556a34939Shaad 	if (!seg_is_mirrored(seg)) {
162656a34939Shaad 		log_error("Not a mirror segment");
162756a34939Shaad 		return 0;
162856a34939Shaad 	}
162956a34939Shaad 
163056a34939Shaad 	if (lv_mirror_count(lv) <= mirrors) {
163156a34939Shaad 		log_error("Removing more than existing: %d <= %d",
163256a34939Shaad 			  seg->area_count, mirrors);
163356a34939Shaad 		return 0;
163456a34939Shaad 	}
163556a34939Shaad 	new_mirrors = lv_mirror_count(lv) - mirrors - 1;
163656a34939Shaad 
163756a34939Shaad 	/* MIRROR_BY_LV */
163856a34939Shaad 	if (seg_type(seg, 0) == AREA_LV &&
163956a34939Shaad 	    seg_lv(seg, 0)->status & MIRROR_IMAGE)
164056a34939Shaad 		return remove_mirror_images(lv, new_mirrors + 1,
164156a34939Shaad 					    pvs, log_count ? 1U : 0);
164256a34939Shaad 
164356a34939Shaad 	/* MIRROR_BY_SEG */
164456a34939Shaad 	if (log_count) {
164556a34939Shaad 		log_error("Persistent log is not supported on "
164656a34939Shaad 			  "segment-by-segment mirroring");
164756a34939Shaad 		return 0;
164856a34939Shaad 	}
164956a34939Shaad 	return remove_mirrors_from_segments(lv, new_mirrors, status_mask);
165056a34939Shaad }
165156a34939Shaad 
1652