1*86d7f5d3SJohn Marino /*	$NetBSD: mirrored.c,v 1.1.1.2 2009/12/02 00:26:26 haad Exp $	*/
2*86d7f5d3SJohn Marino 
3*86d7f5d3SJohn Marino /*
4*86d7f5d3SJohn Marino  * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
5*86d7f5d3SJohn Marino  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
6*86d7f5d3SJohn Marino  *
7*86d7f5d3SJohn Marino  * This file is part of LVM2.
8*86d7f5d3SJohn Marino  *
9*86d7f5d3SJohn Marino  * This copyrighted material is made available to anyone wishing to use,
10*86d7f5d3SJohn Marino  * modify, copy, or redistribute it subject to the terms and conditions
11*86d7f5d3SJohn Marino  * of the GNU Lesser General Public License v.2.1.
12*86d7f5d3SJohn Marino  *
13*86d7f5d3SJohn Marino  * You should have received a copy of the GNU Lesser General Public License
14*86d7f5d3SJohn Marino  * along with this program; if not, write to the Free Software Foundation,
15*86d7f5d3SJohn Marino  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16*86d7f5d3SJohn Marino  */
17*86d7f5d3SJohn Marino 
18*86d7f5d3SJohn Marino #include "lib.h"
19*86d7f5d3SJohn Marino #include "toolcontext.h"
20*86d7f5d3SJohn Marino #include "metadata.h"
21*86d7f5d3SJohn Marino #include "segtype.h"
22*86d7f5d3SJohn Marino #include "display.h"
23*86d7f5d3SJohn Marino #include "text_export.h"
24*86d7f5d3SJohn Marino #include "text_import.h"
25*86d7f5d3SJohn Marino #include "config.h"
26*86d7f5d3SJohn Marino #include "defaults.h"
27*86d7f5d3SJohn Marino #include "lvm-string.h"
28*86d7f5d3SJohn Marino #include "targets.h"
29*86d7f5d3SJohn Marino #include "activate.h"
30*86d7f5d3SJohn Marino #include "sharedlib.h"
31*86d7f5d3SJohn Marino #include "str_list.h"
32*86d7f5d3SJohn Marino 
33*86d7f5d3SJohn Marino #ifdef DMEVENTD
34*86d7f5d3SJohn Marino #  include "libdevmapper-event.h"
35*86d7f5d3SJohn Marino #endif
36*86d7f5d3SJohn Marino 
37*86d7f5d3SJohn Marino static int _block_on_error_available = 0;
38*86d7f5d3SJohn Marino static unsigned _mirror_attributes = 0;
39*86d7f5d3SJohn Marino 
40*86d7f5d3SJohn Marino enum {
41*86d7f5d3SJohn Marino 	MIRR_DISABLED,
42*86d7f5d3SJohn Marino 	MIRR_RUNNING,
43*86d7f5d3SJohn Marino 	MIRR_COMPLETED
44*86d7f5d3SJohn Marino };
45*86d7f5d3SJohn Marino 
46*86d7f5d3SJohn Marino struct mirror_state {
47*86d7f5d3SJohn Marino 	uint32_t default_region_size;
48*86d7f5d3SJohn Marino };
49*86d7f5d3SJohn Marino 
_mirrored_name(const struct lv_segment * seg)50*86d7f5d3SJohn Marino static const char *_mirrored_name(const struct lv_segment *seg)
51*86d7f5d3SJohn Marino {
52*86d7f5d3SJohn Marino 	return seg->segtype->name;
53*86d7f5d3SJohn Marino }
54*86d7f5d3SJohn Marino 
_mirrored_display(const struct lv_segment * seg)55*86d7f5d3SJohn Marino static void _mirrored_display(const struct lv_segment *seg)
56*86d7f5d3SJohn Marino {
57*86d7f5d3SJohn Marino 	const char *size;
58*86d7f5d3SJohn Marino 	uint32_t s;
59*86d7f5d3SJohn Marino 
60*86d7f5d3SJohn Marino 	log_print("  Mirrors\t\t%u", seg->area_count);
61*86d7f5d3SJohn Marino 	log_print("  Mirror size\t\t%u", seg->area_len);
62*86d7f5d3SJohn Marino 	if (seg->log_lv)
63*86d7f5d3SJohn Marino 		log_print("  Mirror log volume\t%s", seg->log_lv->name);
64*86d7f5d3SJohn Marino 
65*86d7f5d3SJohn Marino 	if (seg->region_size) {
66*86d7f5d3SJohn Marino 		size = display_size(seg->lv->vg->cmd,
67*86d7f5d3SJohn Marino 				    (uint64_t) seg->region_size);
68*86d7f5d3SJohn Marino 		log_print("  Mirror region size\t%s", size);
69*86d7f5d3SJohn Marino 	}
70*86d7f5d3SJohn Marino 
71*86d7f5d3SJohn Marino 	log_print("  Mirror original:");
72*86d7f5d3SJohn Marino 	display_stripe(seg, 0, "    ");
73*86d7f5d3SJohn Marino 	log_print("  Mirror destinations:");
74*86d7f5d3SJohn Marino 	for (s = 1; s < seg->area_count; s++)
75*86d7f5d3SJohn Marino 		display_stripe(seg, s, "    ");
76*86d7f5d3SJohn Marino 	log_print(" ");
77*86d7f5d3SJohn Marino }
78*86d7f5d3SJohn Marino 
_mirrored_text_import_area_count(struct config_node * sn,uint32_t * area_count)79*86d7f5d3SJohn Marino static int _mirrored_text_import_area_count(struct config_node *sn, uint32_t *area_count)
80*86d7f5d3SJohn Marino {
81*86d7f5d3SJohn Marino 	if (!get_config_uint32(sn, "mirror_count", area_count)) {
82*86d7f5d3SJohn Marino 		log_error("Couldn't read 'mirror_count' for "
83*86d7f5d3SJohn Marino 			  "segment '%s'.", config_parent_name(sn));
84*86d7f5d3SJohn Marino 		return 0;
85*86d7f5d3SJohn Marino 	}
86*86d7f5d3SJohn Marino 
87*86d7f5d3SJohn Marino 	return 1;
88*86d7f5d3SJohn Marino }
89*86d7f5d3SJohn Marino 
_mirrored_text_import(struct lv_segment * seg,const struct config_node * sn,struct dm_hash_table * pv_hash)90*86d7f5d3SJohn Marino static int _mirrored_text_import(struct lv_segment *seg, const struct config_node *sn,
91*86d7f5d3SJohn Marino 			struct dm_hash_table *pv_hash)
92*86d7f5d3SJohn Marino {
93*86d7f5d3SJohn Marino 	const struct config_node *cn;
94*86d7f5d3SJohn Marino 	char *logname = NULL;
95*86d7f5d3SJohn Marino 
96*86d7f5d3SJohn Marino 	if (find_config_node(sn, "extents_moved")) {
97*86d7f5d3SJohn Marino 		if (get_config_uint32(sn, "extents_moved",
98*86d7f5d3SJohn Marino 				      &seg->extents_copied))
99*86d7f5d3SJohn Marino 			seg->status |= PVMOVE;
100*86d7f5d3SJohn Marino 		else {
101*86d7f5d3SJohn Marino 			log_error("Couldn't read 'extents_moved' for "
102*86d7f5d3SJohn Marino 				  "segment %s of logical volume %s.",
103*86d7f5d3SJohn Marino 				  config_parent_name(sn), seg->lv->name);
104*86d7f5d3SJohn Marino 			return 0;
105*86d7f5d3SJohn Marino 		}
106*86d7f5d3SJohn Marino 	}
107*86d7f5d3SJohn Marino 
108*86d7f5d3SJohn Marino 	if (find_config_node(sn, "region_size")) {
109*86d7f5d3SJohn Marino 		if (!get_config_uint32(sn, "region_size",
110*86d7f5d3SJohn Marino 				      &seg->region_size)) {
111*86d7f5d3SJohn Marino 			log_error("Couldn't read 'region_size' for "
112*86d7f5d3SJohn Marino 				  "segment %s of logical volume %s.",
113*86d7f5d3SJohn Marino 				  config_parent_name(sn), seg->lv->name);
114*86d7f5d3SJohn Marino 			return 0;
115*86d7f5d3SJohn Marino 		}
116*86d7f5d3SJohn Marino 	}
117*86d7f5d3SJohn Marino 
118*86d7f5d3SJohn Marino 	if ((cn = find_config_node(sn, "mirror_log"))) {
119*86d7f5d3SJohn Marino 		if (!cn->v || !cn->v->v.str) {
120*86d7f5d3SJohn Marino 			log_error("Mirror log type must be a string.");
121*86d7f5d3SJohn Marino 			return 0;
122*86d7f5d3SJohn Marino 		}
123*86d7f5d3SJohn Marino 		logname = cn->v->v.str;
124*86d7f5d3SJohn Marino 		if (!(seg->log_lv = find_lv(seg->lv->vg, logname))) {
125*86d7f5d3SJohn Marino 			log_error("Unrecognised mirror log in "
126*86d7f5d3SJohn Marino 				  "segment %s of logical volume %s.",
127*86d7f5d3SJohn Marino 				  config_parent_name(sn), seg->lv->name);
128*86d7f5d3SJohn Marino 			return 0;
129*86d7f5d3SJohn Marino 		}
130*86d7f5d3SJohn Marino 		seg->log_lv->status |= MIRROR_LOG;
131*86d7f5d3SJohn Marino 	}
132*86d7f5d3SJohn Marino 
133*86d7f5d3SJohn Marino 	if (logname && !seg->region_size) {
134*86d7f5d3SJohn Marino 		log_error("Missing region size for mirror log for "
135*86d7f5d3SJohn Marino 			  "segment %s of logical volume %s.",
136*86d7f5d3SJohn Marino 			  config_parent_name(sn), seg->lv->name);
137*86d7f5d3SJohn Marino 		return 0;
138*86d7f5d3SJohn Marino 	}
139*86d7f5d3SJohn Marino 
140*86d7f5d3SJohn Marino 	if (!(cn = find_config_node(sn, "mirrors"))) {
141*86d7f5d3SJohn Marino 		log_error("Couldn't find mirrors array for "
142*86d7f5d3SJohn Marino 			  "segment %s of logical volume %s.",
143*86d7f5d3SJohn Marino 			  config_parent_name(sn), seg->lv->name);
144*86d7f5d3SJohn Marino 		return 0;
145*86d7f5d3SJohn Marino 	}
146*86d7f5d3SJohn Marino 
147*86d7f5d3SJohn Marino 	return text_import_areas(seg, sn, cn, pv_hash, MIRROR_IMAGE);
148*86d7f5d3SJohn Marino }
149*86d7f5d3SJohn Marino 
_mirrored_text_export(const struct lv_segment * seg,struct formatter * f)150*86d7f5d3SJohn Marino static int _mirrored_text_export(const struct lv_segment *seg, struct formatter *f)
151*86d7f5d3SJohn Marino {
152*86d7f5d3SJohn Marino 	outf(f, "mirror_count = %u", seg->area_count);
153*86d7f5d3SJohn Marino 	if (seg->status & PVMOVE)
154*86d7f5d3SJohn Marino 		out_size(f, (uint64_t) seg->extents_copied * seg->lv->vg->extent_size,
155*86d7f5d3SJohn Marino 			 "extents_moved = %" PRIu32, seg->extents_copied);
156*86d7f5d3SJohn Marino 	if (seg->log_lv)
157*86d7f5d3SJohn Marino 		outf(f, "mirror_log = \"%s\"", seg->log_lv->name);
158*86d7f5d3SJohn Marino 	if (seg->region_size)
159*86d7f5d3SJohn Marino 		outf(f, "region_size = %" PRIu32, seg->region_size);
160*86d7f5d3SJohn Marino 
161*86d7f5d3SJohn Marino 	return out_areas(f, seg, "mirror");
162*86d7f5d3SJohn Marino }
163*86d7f5d3SJohn Marino 
164*86d7f5d3SJohn Marino #ifdef DEVMAPPER_SUPPORT
_mirrored_init_target(struct dm_pool * mem,struct cmd_context * cmd)165*86d7f5d3SJohn Marino static struct mirror_state *_mirrored_init_target(struct dm_pool *mem,
166*86d7f5d3SJohn Marino 					 struct cmd_context *cmd)
167*86d7f5d3SJohn Marino {
168*86d7f5d3SJohn Marino 	struct mirror_state *mirr_state;
169*86d7f5d3SJohn Marino 
170*86d7f5d3SJohn Marino 	if (!(mirr_state = dm_pool_alloc(mem, sizeof(*mirr_state)))) {
171*86d7f5d3SJohn Marino 		log_error("struct mirr_state allocation failed");
172*86d7f5d3SJohn Marino 		return NULL;
173*86d7f5d3SJohn Marino 	}
174*86d7f5d3SJohn Marino 
175*86d7f5d3SJohn Marino 	mirr_state->default_region_size = 2 *
176*86d7f5d3SJohn Marino 	    find_config_tree_int(cmd,
177*86d7f5d3SJohn Marino 			    "activation/mirror_region_size",
178*86d7f5d3SJohn Marino 			    DEFAULT_MIRROR_REGION_SIZE);
179*86d7f5d3SJohn Marino 
180*86d7f5d3SJohn Marino 	return mirr_state;
181*86d7f5d3SJohn Marino }
182*86d7f5d3SJohn Marino 
_mirrored_target_percent(void ** target_state,percent_range_t * percent_range,struct dm_pool * mem,struct cmd_context * cmd,struct lv_segment * seg,char * params,uint64_t * total_numerator,uint64_t * total_denominator)183*86d7f5d3SJohn Marino static int _mirrored_target_percent(void **target_state,
184*86d7f5d3SJohn Marino 				    percent_range_t *percent_range,
185*86d7f5d3SJohn Marino 				    struct dm_pool *mem,
186*86d7f5d3SJohn Marino 				    struct cmd_context *cmd,
187*86d7f5d3SJohn Marino 				    struct lv_segment *seg, char *params,
188*86d7f5d3SJohn Marino 				    uint64_t *total_numerator,
189*86d7f5d3SJohn Marino 				    uint64_t *total_denominator)
190*86d7f5d3SJohn Marino {
191*86d7f5d3SJohn Marino 	struct mirror_state *mirr_state;
192*86d7f5d3SJohn Marino 	uint64_t numerator, denominator;
193*86d7f5d3SJohn Marino 	unsigned mirror_count, m;
194*86d7f5d3SJohn Marino 	int used;
195*86d7f5d3SJohn Marino 	char *pos = params;
196*86d7f5d3SJohn Marino 
197*86d7f5d3SJohn Marino 	if (!*target_state)
198*86d7f5d3SJohn Marino 		*target_state = _mirrored_init_target(mem, cmd);
199*86d7f5d3SJohn Marino 
200*86d7f5d3SJohn Marino 	mirr_state = *target_state;
201*86d7f5d3SJohn Marino 
202*86d7f5d3SJohn Marino 	/* Status line: <#mirrors> (maj:min)+ <synced>/<total_regions> */
203*86d7f5d3SJohn Marino 	log_debug("Mirror status: %s", params);
204*86d7f5d3SJohn Marino 
205*86d7f5d3SJohn Marino 	if (sscanf(pos, "%u %n", &mirror_count, &used) != 1) {
206*86d7f5d3SJohn Marino 		log_error("Failure parsing mirror status mirror count: %s",
207*86d7f5d3SJohn Marino 			  params);
208*86d7f5d3SJohn Marino 		return 0;
209*86d7f5d3SJohn Marino 	}
210*86d7f5d3SJohn Marino 	pos += used;
211*86d7f5d3SJohn Marino 
212*86d7f5d3SJohn Marino 	for (m = 0; m < mirror_count; m++) {
213*86d7f5d3SJohn Marino 		if (sscanf(pos, "%*x:%*x %n", &used) != 0) {
214*86d7f5d3SJohn Marino 			log_error("Failure parsing mirror status devices: %s",
215*86d7f5d3SJohn Marino 				  params);
216*86d7f5d3SJohn Marino 			return 0;
217*86d7f5d3SJohn Marino 		}
218*86d7f5d3SJohn Marino 		pos += used;
219*86d7f5d3SJohn Marino 	}
220*86d7f5d3SJohn Marino 
221*86d7f5d3SJohn Marino 	if (sscanf(pos, "%" PRIu64 "/%" PRIu64 "%n", &numerator, &denominator,
222*86d7f5d3SJohn Marino 		   &used) != 2) {
223*86d7f5d3SJohn Marino 		log_error("Failure parsing mirror status fraction: %s", params);
224*86d7f5d3SJohn Marino 		return 0;
225*86d7f5d3SJohn Marino 	}
226*86d7f5d3SJohn Marino 	pos += used;
227*86d7f5d3SJohn Marino 
228*86d7f5d3SJohn Marino 	*total_numerator += numerator;
229*86d7f5d3SJohn Marino 	*total_denominator += denominator;
230*86d7f5d3SJohn Marino 
231*86d7f5d3SJohn Marino 	if (seg)
232*86d7f5d3SJohn Marino 		seg->extents_copied = seg->area_len * numerator / denominator;
233*86d7f5d3SJohn Marino 
234*86d7f5d3SJohn Marino 	if (numerator == denominator)
235*86d7f5d3SJohn Marino 		*percent_range = PERCENT_100;
236*86d7f5d3SJohn Marino 	else if (numerator == 0)
237*86d7f5d3SJohn Marino 		*percent_range = PERCENT_0;
238*86d7f5d3SJohn Marino 	else
239*86d7f5d3SJohn Marino 		*percent_range = PERCENT_0_TO_100;
240*86d7f5d3SJohn Marino 
241*86d7f5d3SJohn Marino 	return 1;
242*86d7f5d3SJohn Marino }
243*86d7f5d3SJohn Marino 
_add_log(struct dev_manager * dm,struct lv_segment * seg,struct dm_tree_node * node,uint32_t area_count,uint32_t region_size)244*86d7f5d3SJohn Marino static int _add_log(struct dev_manager *dm, struct lv_segment *seg,
245*86d7f5d3SJohn Marino 		    struct dm_tree_node *node, uint32_t area_count, uint32_t region_size)
246*86d7f5d3SJohn Marino {
247*86d7f5d3SJohn Marino 	unsigned clustered = 0;
248*86d7f5d3SJohn Marino 	char *log_dlid = NULL;
249*86d7f5d3SJohn Marino 	uint32_t log_flags = 0;
250*86d7f5d3SJohn Marino 
251*86d7f5d3SJohn Marino 	/*
252*86d7f5d3SJohn Marino 	 * Use clustered mirror log for non-exclusive activation
253*86d7f5d3SJohn Marino 	 * in clustered VG.
254*86d7f5d3SJohn Marino 	 */
255*86d7f5d3SJohn Marino 	if ((!(seg->lv->status & ACTIVATE_EXCL) &&
256*86d7f5d3SJohn Marino 	      (vg_is_clustered(seg->lv->vg))))
257*86d7f5d3SJohn Marino 		clustered = 1;
258*86d7f5d3SJohn Marino 
259*86d7f5d3SJohn Marino 	if (seg->log_lv) {
260*86d7f5d3SJohn Marino 		/* If disk log, use its UUID */
261*86d7f5d3SJohn Marino 		if (!(log_dlid = build_dlid(dm, seg->log_lv->lvid.s, NULL))) {
262*86d7f5d3SJohn Marino 			log_error("Failed to build uuid for log LV %s.",
263*86d7f5d3SJohn Marino 				  seg->log_lv->name);
264*86d7f5d3SJohn Marino 			return 0;
265*86d7f5d3SJohn Marino 		}
266*86d7f5d3SJohn Marino 	} else {
267*86d7f5d3SJohn Marino 		/* If core log, use mirror's UUID and set DM_CORELOG flag */
268*86d7f5d3SJohn Marino 		if (!(log_dlid = build_dlid(dm, seg->lv->lvid.s, NULL))) {
269*86d7f5d3SJohn Marino 			log_error("Failed to build uuid for mirror LV %s.",
270*86d7f5d3SJohn Marino 				  seg->lv->name);
271*86d7f5d3SJohn Marino 			return 0;
272*86d7f5d3SJohn Marino 		}
273*86d7f5d3SJohn Marino 		log_flags |= DM_CORELOG;
274*86d7f5d3SJohn Marino 	}
275*86d7f5d3SJohn Marino 
276*86d7f5d3SJohn Marino 	if (mirror_in_sync() && !(seg->status & PVMOVE))
277*86d7f5d3SJohn Marino 		log_flags |= DM_NOSYNC;
278*86d7f5d3SJohn Marino 
279*86d7f5d3SJohn Marino 	if (_block_on_error_available && !(seg->status & PVMOVE))
280*86d7f5d3SJohn Marino 		log_flags |= DM_BLOCK_ON_ERROR;
281*86d7f5d3SJohn Marino 
282*86d7f5d3SJohn Marino 	return dm_tree_node_add_mirror_target_log(node, region_size, clustered, log_dlid, area_count, log_flags);
283*86d7f5d3SJohn Marino }
284*86d7f5d3SJohn Marino 
_mirrored_add_target_line(struct dev_manager * dm,struct dm_pool * mem,struct cmd_context * cmd,void ** target_state,struct lv_segment * seg,struct dm_tree_node * node,uint64_t len,uint32_t * pvmove_mirror_count)285*86d7f5d3SJohn Marino static int _mirrored_add_target_line(struct dev_manager *dm, struct dm_pool *mem,
286*86d7f5d3SJohn Marino 				struct cmd_context *cmd, void **target_state,
287*86d7f5d3SJohn Marino 				struct lv_segment *seg,
288*86d7f5d3SJohn Marino 				struct dm_tree_node *node, uint64_t len,
289*86d7f5d3SJohn Marino 				uint32_t *pvmove_mirror_count)
290*86d7f5d3SJohn Marino {
291*86d7f5d3SJohn Marino 	struct mirror_state *mirr_state;
292*86d7f5d3SJohn Marino 	uint32_t area_count = seg->area_count;
293*86d7f5d3SJohn Marino 	unsigned start_area = 0u;
294*86d7f5d3SJohn Marino 	int mirror_status = MIRR_RUNNING;
295*86d7f5d3SJohn Marino 	uint32_t region_size;
296*86d7f5d3SJohn Marino 	int r;
297*86d7f5d3SJohn Marino 
298*86d7f5d3SJohn Marino 	if (!*target_state)
299*86d7f5d3SJohn Marino 		*target_state = _mirrored_init_target(mem, cmd);
300*86d7f5d3SJohn Marino 
301*86d7f5d3SJohn Marino 	mirr_state = *target_state;
302*86d7f5d3SJohn Marino 
303*86d7f5d3SJohn Marino 	/*
304*86d7f5d3SJohn Marino 	 * Mirror segment could have only 1 area temporarily
305*86d7f5d3SJohn Marino 	 * if the segment is under conversion.
306*86d7f5d3SJohn Marino 	 */
307*86d7f5d3SJohn Marino  	if (seg->area_count == 1)
308*86d7f5d3SJohn Marino 		mirror_status = MIRR_DISABLED;
309*86d7f5d3SJohn Marino 
310*86d7f5d3SJohn Marino 	/*
311*86d7f5d3SJohn Marino 	 * For pvmove, only have one mirror segment RUNNING at once.
312*86d7f5d3SJohn Marino 	 * Segments before this are COMPLETED and use 2nd area.
313*86d7f5d3SJohn Marino 	 * Segments after this are DISABLED and use 1st area.
314*86d7f5d3SJohn Marino 	 */
315*86d7f5d3SJohn Marino 	if (seg->status & PVMOVE) {
316*86d7f5d3SJohn Marino 		if (seg->extents_copied == seg->area_len) {
317*86d7f5d3SJohn Marino 			mirror_status = MIRR_COMPLETED;
318*86d7f5d3SJohn Marino 			start_area = 1;
319*86d7f5d3SJohn Marino 		} else if ((*pvmove_mirror_count)++) {
320*86d7f5d3SJohn Marino 			mirror_status = MIRR_DISABLED;
321*86d7f5d3SJohn Marino 			area_count = 1;
322*86d7f5d3SJohn Marino 		}
323*86d7f5d3SJohn Marino 		/* else MIRR_RUNNING */
324*86d7f5d3SJohn Marino 	}
325*86d7f5d3SJohn Marino 
326*86d7f5d3SJohn Marino 	if (mirror_status != MIRR_RUNNING) {
327*86d7f5d3SJohn Marino 		if (!dm_tree_node_add_linear_target(node, len))
328*86d7f5d3SJohn Marino 			return_0;
329*86d7f5d3SJohn Marino 		goto done;
330*86d7f5d3SJohn Marino 	}
331*86d7f5d3SJohn Marino 
332*86d7f5d3SJohn Marino 	if (!(seg->status & PVMOVE)) {
333*86d7f5d3SJohn Marino 		if (!seg->region_size) {
334*86d7f5d3SJohn Marino 			log_error("Missing region size for mirror segment.");
335*86d7f5d3SJohn Marino 			return 0;
336*86d7f5d3SJohn Marino 		}
337*86d7f5d3SJohn Marino 		region_size = seg->region_size;
338*86d7f5d3SJohn Marino 
339*86d7f5d3SJohn Marino 	} else
340*86d7f5d3SJohn Marino 		region_size = adjusted_mirror_region_size(seg->lv->vg->extent_size,
341*86d7f5d3SJohn Marino 							  seg->area_len,
342*86d7f5d3SJohn Marino 							  mirr_state->default_region_size);
343*86d7f5d3SJohn Marino 
344*86d7f5d3SJohn Marino 	if (!dm_tree_node_add_mirror_target(node, len))
345*86d7f5d3SJohn Marino 		return_0;
346*86d7f5d3SJohn Marino 
347*86d7f5d3SJohn Marino 	if ((r = _add_log(dm, seg, node, area_count, region_size)) <= 0) {
348*86d7f5d3SJohn Marino 		stack;
349*86d7f5d3SJohn Marino 		return r;
350*86d7f5d3SJohn Marino 	}
351*86d7f5d3SJohn Marino 
352*86d7f5d3SJohn Marino       done:
353*86d7f5d3SJohn Marino 	return add_areas_line(dm, seg, node, start_area, area_count);
354*86d7f5d3SJohn Marino }
355*86d7f5d3SJohn Marino 
_mirrored_target_present(struct cmd_context * cmd,const struct lv_segment * seg,unsigned * attributes)356*86d7f5d3SJohn Marino static int _mirrored_target_present(struct cmd_context *cmd,
357*86d7f5d3SJohn Marino 				    const struct lv_segment *seg,
358*86d7f5d3SJohn Marino 				    unsigned *attributes)
359*86d7f5d3SJohn Marino {
360*86d7f5d3SJohn Marino 	static int _mirrored_checked = 0;
361*86d7f5d3SJohn Marino 	static int _mirrored_present = 0;
362*86d7f5d3SJohn Marino 	uint32_t maj, min, patchlevel;
363*86d7f5d3SJohn Marino 	unsigned maj2, min2, patchlevel2;
364*86d7f5d3SJohn Marino 	char vsn[80];
365*86d7f5d3SJohn Marino 
366*86d7f5d3SJohn Marino 	if (!_mirrored_checked) {
367*86d7f5d3SJohn Marino 		_mirrored_present = target_present(cmd, "mirror", 1);
368*86d7f5d3SJohn Marino 
369*86d7f5d3SJohn Marino 		/*
370*86d7f5d3SJohn Marino 		 * block_on_error available as "block_on_error" log
371*86d7f5d3SJohn Marino 		 * argument with mirror target >= 1.1 and <= 1.11
372*86d7f5d3SJohn Marino 		 * or with 1.0 in RHEL4U3 driver >= 4.5
373*86d7f5d3SJohn Marino 		 *
374*86d7f5d3SJohn Marino 		 * block_on_error available as "handle_errors" mirror
375*86d7f5d3SJohn Marino 		 * argument with mirror target >= 1.12.
376*86d7f5d3SJohn Marino 		 *
377*86d7f5d3SJohn Marino 		 * libdm-deptree.c is smart enough to handle the differences
378*86d7f5d3SJohn Marino 		 * between block_on_error and handle_errors for all
379*86d7f5d3SJohn Marino 		 * mirror target versions >= 1.1
380*86d7f5d3SJohn Marino 		 */
381*86d7f5d3SJohn Marino 		/* FIXME Move this into libdevmapper */
382*86d7f5d3SJohn Marino 
383*86d7f5d3SJohn Marino 		if (target_version("mirror", &maj, &min, &patchlevel) &&
384*86d7f5d3SJohn Marino 		    maj == 1 &&
385*86d7f5d3SJohn Marino 		    ((min >= 1) ||
386*86d7f5d3SJohn Marino 		     (min == 0 && driver_version(vsn, sizeof(vsn)) &&
387*86d7f5d3SJohn Marino 		      sscanf(vsn, "%u.%u.%u", &maj2, &min2, &patchlevel2) == 3 &&
388*86d7f5d3SJohn Marino 		      maj2 == 4 && min2 == 5 && patchlevel2 == 0)))	/* RHEL4U3 */
389*86d7f5d3SJohn Marino 			_block_on_error_available = 1;
390*86d7f5d3SJohn Marino 	}
391*86d7f5d3SJohn Marino 
392*86d7f5d3SJohn Marino 	/*
393*86d7f5d3SJohn Marino 	 * Check only for modules if atttributes requested and no previous check.
394*86d7f5d3SJohn Marino 	 * FIXME: Fails incorrectly if cmirror was built into kernel.
395*86d7f5d3SJohn Marino 	 */
396*86d7f5d3SJohn Marino 	if (attributes) {
397*86d7f5d3SJohn Marino 		if (!_mirror_attributes && module_present(cmd, "log-clustered"))
398*86d7f5d3SJohn Marino 			_mirror_attributes |= MIRROR_LOG_CLUSTERED;
399*86d7f5d3SJohn Marino 		*attributes = _mirror_attributes;
400*86d7f5d3SJohn Marino 	}
401*86d7f5d3SJohn Marino 	_mirrored_checked = 1;
402*86d7f5d3SJohn Marino 
403*86d7f5d3SJohn Marino 	return _mirrored_present;
404*86d7f5d3SJohn Marino }
405*86d7f5d3SJohn Marino 
406*86d7f5d3SJohn Marino #ifdef DMEVENTD
_get_mirror_dso_path(struct cmd_context * cmd,char ** dso)407*86d7f5d3SJohn Marino static int _get_mirror_dso_path(struct cmd_context *cmd, char **dso)
408*86d7f5d3SJohn Marino {
409*86d7f5d3SJohn Marino 	char *path;
410*86d7f5d3SJohn Marino 	const char *libpath;
411*86d7f5d3SJohn Marino 
412*86d7f5d3SJohn Marino 	if (!(path = dm_pool_alloc(cmd->mem, PATH_MAX))) {
413*86d7f5d3SJohn Marino 		log_error("Failed to allocate dmeventd library path.");
414*86d7f5d3SJohn Marino 		return 0;
415*86d7f5d3SJohn Marino 	}
416*86d7f5d3SJohn Marino 
417*86d7f5d3SJohn Marino 	libpath = find_config_tree_str(cmd, "dmeventd/mirror_library",
418*86d7f5d3SJohn Marino 				       DEFAULT_DMEVENTD_MIRROR_LIB);
419*86d7f5d3SJohn Marino 
420*86d7f5d3SJohn Marino 	get_shared_library_path(cmd, libpath, path, PATH_MAX);
421*86d7f5d3SJohn Marino 
422*86d7f5d3SJohn Marino 	*dso = path;
423*86d7f5d3SJohn Marino 
424*86d7f5d3SJohn Marino 	return 1;
425*86d7f5d3SJohn Marino }
426*86d7f5d3SJohn Marino 
_create_dm_event_handler(const char * dmname,const char * dso,enum dm_event_mask mask)427*86d7f5d3SJohn Marino static struct dm_event_handler *_create_dm_event_handler(const char *dmname,
428*86d7f5d3SJohn Marino 							 const char *dso,
429*86d7f5d3SJohn Marino 							 enum dm_event_mask mask)
430*86d7f5d3SJohn Marino {
431*86d7f5d3SJohn Marino 	struct dm_event_handler *dmevh;
432*86d7f5d3SJohn Marino 
433*86d7f5d3SJohn Marino 	if (!(dmevh = dm_event_handler_create()))
434*86d7f5d3SJohn Marino 		return_0;
435*86d7f5d3SJohn Marino 
436*86d7f5d3SJohn Marino        if (dm_event_handler_set_dso(dmevh, dso))
437*86d7f5d3SJohn Marino 		goto fail;
438*86d7f5d3SJohn Marino 
439*86d7f5d3SJohn Marino 	if (dm_event_handler_set_dev_name(dmevh, dmname))
440*86d7f5d3SJohn Marino 		goto fail;
441*86d7f5d3SJohn Marino 
442*86d7f5d3SJohn Marino 	dm_event_handler_set_event_mask(dmevh, mask);
443*86d7f5d3SJohn Marino 	return dmevh;
444*86d7f5d3SJohn Marino 
445*86d7f5d3SJohn Marino fail:
446*86d7f5d3SJohn Marino 	dm_event_handler_destroy(dmevh);
447*86d7f5d3SJohn Marino 	return NULL;
448*86d7f5d3SJohn Marino }
449*86d7f5d3SJohn Marino 
_target_monitored(struct lv_segment * seg,int * pending)450*86d7f5d3SJohn Marino static int _target_monitored(struct lv_segment *seg, int *pending)
451*86d7f5d3SJohn Marino {
452*86d7f5d3SJohn Marino 	char *dso, *name;
453*86d7f5d3SJohn Marino 	struct logical_volume *lv;
454*86d7f5d3SJohn Marino 	struct volume_group *vg;
455*86d7f5d3SJohn Marino 	enum dm_event_mask evmask = 0;
456*86d7f5d3SJohn Marino 	struct dm_event_handler *dmevh;
457*86d7f5d3SJohn Marino 
458*86d7f5d3SJohn Marino 	lv = seg->lv;
459*86d7f5d3SJohn Marino 	vg = lv->vg;
460*86d7f5d3SJohn Marino 
461*86d7f5d3SJohn Marino 	*pending = 0;
462*86d7f5d3SJohn Marino 	if (!_get_mirror_dso_path(vg->cmd, &dso))
463*86d7f5d3SJohn Marino 		return_0;
464*86d7f5d3SJohn Marino 
465*86d7f5d3SJohn Marino 	if (!(name = build_dm_name(vg->cmd->mem, vg->name, lv->name, NULL)))
466*86d7f5d3SJohn Marino 		return_0;
467*86d7f5d3SJohn Marino 
468*86d7f5d3SJohn Marino 	if (!(dmevh = _create_dm_event_handler(name, dso, DM_EVENT_ALL_ERRORS)))
469*86d7f5d3SJohn Marino 		return_0;
470*86d7f5d3SJohn Marino 
471*86d7f5d3SJohn Marino 	if (dm_event_get_registered_device(dmevh, 0)) {
472*86d7f5d3SJohn Marino 		dm_event_handler_destroy(dmevh);
473*86d7f5d3SJohn Marino 		return 0;
474*86d7f5d3SJohn Marino 	}
475*86d7f5d3SJohn Marino 
476*86d7f5d3SJohn Marino 	evmask = dm_event_handler_get_event_mask(dmevh);
477*86d7f5d3SJohn Marino 	if (evmask & DM_EVENT_REGISTRATION_PENDING) {
478*86d7f5d3SJohn Marino 		*pending = 1;
479*86d7f5d3SJohn Marino 		evmask &= ~DM_EVENT_REGISTRATION_PENDING;
480*86d7f5d3SJohn Marino 	}
481*86d7f5d3SJohn Marino 
482*86d7f5d3SJohn Marino 	dm_event_handler_destroy(dmevh);
483*86d7f5d3SJohn Marino 
484*86d7f5d3SJohn Marino 	return evmask;
485*86d7f5d3SJohn Marino }
486*86d7f5d3SJohn Marino 
487*86d7f5d3SJohn Marino /* FIXME This gets run while suspended and performs banned operations. */
_target_set_events(struct lv_segment * seg,int evmask __attribute ((unused)),int set)488*86d7f5d3SJohn Marino static int _target_set_events(struct lv_segment *seg,
489*86d7f5d3SJohn Marino 			      int evmask __attribute((unused)), int set)
490*86d7f5d3SJohn Marino {
491*86d7f5d3SJohn Marino 	char *dso, *name;
492*86d7f5d3SJohn Marino 	struct logical_volume *lv;
493*86d7f5d3SJohn Marino 	struct volume_group *vg;
494*86d7f5d3SJohn Marino 	struct dm_event_handler *dmevh;
495*86d7f5d3SJohn Marino 	int r;
496*86d7f5d3SJohn Marino 
497*86d7f5d3SJohn Marino 	lv = seg->lv;
498*86d7f5d3SJohn Marino 	vg = lv->vg;
499*86d7f5d3SJohn Marino 
500*86d7f5d3SJohn Marino 	if (!_get_mirror_dso_path(vg->cmd, &dso))
501*86d7f5d3SJohn Marino 		return_0;
502*86d7f5d3SJohn Marino 
503*86d7f5d3SJohn Marino 	if (!(name = build_dm_name(vg->cmd->mem, vg->name, lv->name, NULL)))
504*86d7f5d3SJohn Marino 		return_0;
505*86d7f5d3SJohn Marino 
506*86d7f5d3SJohn Marino 	if (!(dmevh = _create_dm_event_handler(name, dso, DM_EVENT_ALL_ERRORS)))
507*86d7f5d3SJohn Marino 		return_0;
508*86d7f5d3SJohn Marino 
509*86d7f5d3SJohn Marino 	r = set ? dm_event_register_handler(dmevh) : dm_event_unregister_handler(dmevh);
510*86d7f5d3SJohn Marino 	dm_event_handler_destroy(dmevh);
511*86d7f5d3SJohn Marino 	if (!r)
512*86d7f5d3SJohn Marino 		return_0;
513*86d7f5d3SJohn Marino 
514*86d7f5d3SJohn Marino 	log_info("%s %s for events", set ? "Monitored" : "Unmonitored", name);
515*86d7f5d3SJohn Marino 
516*86d7f5d3SJohn Marino 	return 1;
517*86d7f5d3SJohn Marino }
518*86d7f5d3SJohn Marino 
_target_monitor_events(struct lv_segment * seg,int events)519*86d7f5d3SJohn Marino static int _target_monitor_events(struct lv_segment *seg, int events)
520*86d7f5d3SJohn Marino {
521*86d7f5d3SJohn Marino 	return _target_set_events(seg, events, 1);
522*86d7f5d3SJohn Marino }
523*86d7f5d3SJohn Marino 
_target_unmonitor_events(struct lv_segment * seg,int events)524*86d7f5d3SJohn Marino static int _target_unmonitor_events(struct lv_segment *seg, int events)
525*86d7f5d3SJohn Marino {
526*86d7f5d3SJohn Marino 	return _target_set_events(seg, events, 0);
527*86d7f5d3SJohn Marino }
528*86d7f5d3SJohn Marino 
529*86d7f5d3SJohn Marino #endif /* DMEVENTD */
530*86d7f5d3SJohn Marino #endif /* DEVMAPPER_SUPPORT */
531*86d7f5d3SJohn Marino 
_mirrored_modules_needed(struct dm_pool * mem,const struct lv_segment * seg,struct dm_list * modules)532*86d7f5d3SJohn Marino static int _mirrored_modules_needed(struct dm_pool *mem,
533*86d7f5d3SJohn Marino 				    const struct lv_segment *seg,
534*86d7f5d3SJohn Marino 				    struct dm_list *modules)
535*86d7f5d3SJohn Marino {
536*86d7f5d3SJohn Marino 	if (seg->log_lv &&
537*86d7f5d3SJohn Marino 	    !list_segment_modules(mem, first_seg(seg->log_lv), modules))
538*86d7f5d3SJohn Marino 		return_0;
539*86d7f5d3SJohn Marino 
540*86d7f5d3SJohn Marino 	if (vg_is_clustered(seg->lv->vg) &&
541*86d7f5d3SJohn Marino 	    !str_list_add(mem, modules, "clog")) {
542*86d7f5d3SJohn Marino 		log_error("cluster log string list allocation failed");
543*86d7f5d3SJohn Marino 		return 0;
544*86d7f5d3SJohn Marino 	}
545*86d7f5d3SJohn Marino 
546*86d7f5d3SJohn Marino 	if (!str_list_add(mem, modules, "mirror")) {
547*86d7f5d3SJohn Marino 		log_error("mirror string list allocation failed");
548*86d7f5d3SJohn Marino 		return 0;
549*86d7f5d3SJohn Marino 	}
550*86d7f5d3SJohn Marino 
551*86d7f5d3SJohn Marino 	return 1;
552*86d7f5d3SJohn Marino }
553*86d7f5d3SJohn Marino 
_mirrored_destroy(const struct segment_type * segtype)554*86d7f5d3SJohn Marino static void _mirrored_destroy(const struct segment_type *segtype)
555*86d7f5d3SJohn Marino {
556*86d7f5d3SJohn Marino 	dm_free((void *) segtype);
557*86d7f5d3SJohn Marino }
558*86d7f5d3SJohn Marino 
559*86d7f5d3SJohn Marino static struct segtype_handler _mirrored_ops = {
560*86d7f5d3SJohn Marino 	.name = _mirrored_name,
561*86d7f5d3SJohn Marino 	.display = _mirrored_display,
562*86d7f5d3SJohn Marino 	.text_import_area_count = _mirrored_text_import_area_count,
563*86d7f5d3SJohn Marino 	.text_import = _mirrored_text_import,
564*86d7f5d3SJohn Marino 	.text_export = _mirrored_text_export,
565*86d7f5d3SJohn Marino #ifdef DEVMAPPER_SUPPORT
566*86d7f5d3SJohn Marino 	.add_target_line = _mirrored_add_target_line,
567*86d7f5d3SJohn Marino 	.target_percent = _mirrored_target_percent,
568*86d7f5d3SJohn Marino 	.target_present = _mirrored_target_present,
569*86d7f5d3SJohn Marino #ifdef DMEVENTD
570*86d7f5d3SJohn Marino 	.target_monitored = _target_monitored,
571*86d7f5d3SJohn Marino 	.target_monitor_events = _target_monitor_events,
572*86d7f5d3SJohn Marino 	.target_unmonitor_events = _target_unmonitor_events,
573*86d7f5d3SJohn Marino #endif
574*86d7f5d3SJohn Marino #endif
575*86d7f5d3SJohn Marino 	.modules_needed = _mirrored_modules_needed,
576*86d7f5d3SJohn Marino 	.destroy = _mirrored_destroy,
577*86d7f5d3SJohn Marino };
578*86d7f5d3SJohn Marino 
579*86d7f5d3SJohn Marino #ifdef MIRRORED_INTERNAL
init_mirrored_segtype(struct cmd_context * cmd)580*86d7f5d3SJohn Marino struct segment_type *init_mirrored_segtype(struct cmd_context *cmd)
581*86d7f5d3SJohn Marino #else				/* Shared */
582*86d7f5d3SJohn Marino struct segment_type *init_segtype(struct cmd_context *cmd);
583*86d7f5d3SJohn Marino struct segment_type *init_segtype(struct cmd_context *cmd)
584*86d7f5d3SJohn Marino #endif
585*86d7f5d3SJohn Marino {
586*86d7f5d3SJohn Marino 	struct segment_type *segtype = dm_malloc(sizeof(*segtype));
587*86d7f5d3SJohn Marino 
588*86d7f5d3SJohn Marino 	if (!segtype)
589*86d7f5d3SJohn Marino 		return_NULL;
590*86d7f5d3SJohn Marino 
591*86d7f5d3SJohn Marino 	segtype->cmd = cmd;
592*86d7f5d3SJohn Marino 	segtype->ops = &_mirrored_ops;
593*86d7f5d3SJohn Marino 	segtype->name = "mirror";
594*86d7f5d3SJohn Marino 	segtype->private = NULL;
595*86d7f5d3SJohn Marino 	segtype->flags = SEG_AREAS_MIRRORED | SEG_MONITORED;
596*86d7f5d3SJohn Marino 
597*86d7f5d3SJohn Marino 	log_very_verbose("Initialised segtype: %s", segtype->name);
598*86d7f5d3SJohn Marino 
599*86d7f5d3SJohn Marino 	return segtype;
600*86d7f5d3SJohn Marino }
601