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