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