2 * Copyright (C) 2009-2010 Red Hat, Inc. All rights reserved.
4 * This file is part of LVM2.
6 * This copyrighted material is made available to anyone wishing to use,
7 * modify, copy, or redistribute it subject to the terms and conditions
8 * of the GNU Lesser General Public License v.2.1.
10 * You should have received a copy of the GNU Lesser General Public License
11 * along with this program; if not, write to the Free Software Foundation,
12 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 #include "toolcontext.h"
19 #include "text_export.h"
20 #include "text_import.h"
25 # include "sharedlib.h"
26 # include "libdevmapper-event.h"
29 /* Dm kernel module name for replicator */
30 #define REPLICATOR_MODULE "replicator"
31 #define REPLICATOR_DEV_MODULE "replicator-dev"
34 * Macro used as return argument - returns 0.
35 * return is left to be written in the function for better readability.
37 #define SEG_LOG_ERROR(t, p...) \
38 log_error(t " segment %s of logical volume %s.", ## p, \
39 config_parent_name(sn), seg->lv->name), 0;
45 static const char *_replicator_name(const struct lv_segment *seg)
47 return seg->segtype->name;
50 /* FIXME: missing implementation */
51 static void _replicator_display(const struct lv_segment *seg)
56 log_print(" Replicator");
58 log_print(" Replicator volume\t%s", seg->rlog_lv->name);
61 /* Wrapper for get_config_uint32() with default value */
62 static uint32_t _get_config_uint32(const struct config_node *cn,
68 return get_config_uint32(cn, path, &t) ? t : def;
71 /* Wrapper for get_config_uint64() with default value */
72 static uint64_t _get_config_uint64(const struct config_node *cn,
78 return get_config_uint64(cn, path, &t) ? t : def;
82 /* Strings replicator_state_t enum */
83 static const char _state_txt[NUM_REPLICATOR_STATE][8] = {
88 /* Parse state string */
89 static replicator_state_t _get_state(const struct config_node *sn,
90 const char *path, replicator_state_t def)
95 if (get_config_str(sn, path, &str)) {
96 for (i = 0; i < sizeof(_state_txt)/sizeof(_state_txt[0]); ++i)
97 if (strcasecmp(str, _state_txt[i]) == 0)
98 return (replicator_state_t) i;
100 log_warn("%s: unknown value '%s', using default '%s' state",
101 path, str, _state_txt[def]);
107 /* Strings for replicator_action_t enum */
108 static const char _op_mode_txt[NUM_DM_REPLICATOR_MODES][8] = {
117 /* Parse action string */
118 static dm_replicator_mode_t _get_op_mode(const struct config_node *sn,
119 const char *path, dm_replicator_mode_t def)
124 if (get_config_str(sn, path, &str)) {
125 for (i = 0; i < sizeof(_op_mode_txt)/sizeof(_op_mode_txt[0]); ++i)
126 if (strcasecmp(str, _op_mode_txt[i]) == 0) {
127 log_very_verbose("Setting %s to %s",
128 path, _op_mode_txt[i]);
129 return (dm_replicator_mode_t) i;
131 log_warn("%s: unknown value '%s', using default '%s' operation mode",
132 path, str, _op_mode_txt[def]);
138 static struct replicator_site *_get_site(struct logical_volume *replicator,
141 struct dm_pool *mem = replicator->vg->vgmem;
142 struct replicator_site *rsite;
144 dm_list_iterate_items(rsite, &replicator->rsites)
145 if (strcasecmp(rsite->name, key) == 0)
148 if (!(rsite = dm_pool_zalloc(mem, sizeof(*rsite))))
151 if (!(rsite->name = dm_pool_strdup(mem, key)))
154 rsite->replicator = replicator;
155 dm_list_init(&rsite->rdevices);
156 dm_list_add(&replicator->rsites, &rsite->list);
162 /* Parse replicator site element */
163 static int _add_site(struct lv_segment *seg,
165 const struct config_node *sn)
167 struct dm_pool *mem = seg->lv->vg->vgmem;
168 const struct config_node *cn;
169 struct replicator_site *rsite;
171 if (!(rsite = _get_site(seg->lv, key)))
174 if (!find_config_node(sn, "site_index"))
175 return SEG_LOG_ERROR("Mandatory site_index is missing for");
177 rsite->state = _get_state(sn, "state", REPLICATOR_STATE_PASSIVE);
178 rsite->site_index = _get_config_uint32(sn, "site_index", 0);
179 if (rsite->site_index > seg->rsite_index_highest)
180 return SEG_LOG_ERROR("site_index=%d > highest_site_index=%d for",
181 rsite->site_index, seg->rsite_index_highest);
183 rsite->fall_behind_data = _get_config_uint64(sn, "fall_behind_data", 0);
184 rsite->fall_behind_ios = _get_config_uint32(sn, "fall_behind_ios", 0);
185 rsite->fall_behind_timeout = _get_config_uint32(sn, "fall_behind_timeout", 0);
186 rsite->op_mode = DM_REPLICATOR_SYNC;
188 if (rsite->fall_behind_data ||
189 rsite->fall_behind_ios ||
190 rsite->fall_behind_timeout) {
191 if (rsite->fall_behind_data && rsite->fall_behind_ios)
192 return SEG_LOG_ERROR("Defined both fall_behind_data "
193 "and fall_behind_ios in");
195 if (rsite->fall_behind_data && rsite->fall_behind_timeout)
196 return SEG_LOG_ERROR("Defined both fall_behind_data "
197 "and fall_behind_timeout in");
199 if (rsite->fall_behind_ios && rsite->fall_behind_timeout)
200 return SEG_LOG_ERROR("Defined both fall_behind_ios "
201 "and fall_behind_timeout in");
203 rsite->op_mode = _get_op_mode(sn, "operation_mode",
207 if ((cn = find_config_node(sn, "volume_group"))) {
208 if (!cn->v || cn->v->type != CFG_STRING)
209 return SEG_LOG_ERROR("volume_group must be a string in");
211 if (!(rsite->vg_name = dm_pool_strdup(mem, cn->v->v.str)))
214 } else if (rsite->site_index != 0)
215 return SEG_LOG_ERROR("volume_group is mandatory for remote site in");
221 /* Import replicator segment */
222 static int _replicator_text_import(struct lv_segment *seg,
223 const struct config_node *sn,
224 struct dm_hash_table *pv_hash __attribute__((unused)))
226 const struct config_node *cn;
227 struct logical_volume *rlog_lv;
229 if (!replicator_add_replicator_dev(seg->lv, NULL))
232 if (!(cn = find_config_node(sn, "replicator_log")) ||
233 !cn->v || cn->v->type != CFG_STRING)
234 return SEG_LOG_ERROR("Replicator log type must be a string in");
236 if (!(rlog_lv = find_lv(seg->lv->vg, cn->v->v.str)))
237 return SEG_LOG_ERROR("Unknown replicator log %s in",
240 if (!(cn = find_config_node(sn, "replicator_log_type")) ||
241 !cn->v || cn->v->type != CFG_STRING)
242 return SEG_LOG_ERROR("Replicator log's type must be a string in");
243 if (strcasecmp(cn->v->v.str, "ringbuffer"))
244 return SEG_LOG_ERROR("Only ringbuffer replicator log type is supported in");
246 if (!(seg->rlog_type = dm_pool_strdup(seg->lv->vg->vgmem, cn->v->v.str)))
250 log_very_verbose("replicator_log = %s", rlog_lv->name);
251 log_very_verbose("replicator_log_type = %s", seg->rlog_type);
253 if (!replicator_add_rlog(seg, rlog_lv))
256 seg->rdevice_index_highest = _get_config_uint64(sn, "highest_device_index", 0);
257 seg->rsite_index_highest = _get_config_uint32(sn, "highest_site_index", 0);
259 seg->region_size = _get_config_uint32(sn, "sync_log_size", 0);
261 for (; sn; sn = sn->sib)
263 for (cn = sn->sib; cn; cn = cn->sib)
264 if (!cn->v && (strcasecmp(cn->key ,sn->key) == 0))
265 return SEG_LOG_ERROR("Detected duplicate site "
266 "name %s in", sn->key);
267 if (!_add_site(seg, sn->key, sn->child))
273 /* Export replicator segment */
274 static int _replicator_text_export(const struct lv_segment *seg,
277 struct replicator_site *rsite;
282 outf(f, "replicator_log = \"%s\"", seg->rlog_lv->name);
283 outf(f, "replicator_log_type = \"%s\"", seg->rlog_type);
284 outf(f, "highest_device_index = %" PRIu64, seg->rdevice_index_highest);
285 outf(f, "highest_site_index = %d", seg->rsite_index_highest);
287 if (seg->region_size)
288 outsize(f, (uint64_t)seg->region_size,
289 "sync_log_size = %" PRIu32, seg->region_size);
291 if (!dm_list_empty(&seg->lv->rsites))
294 dm_list_iterate_items(rsite, &seg->lv->rsites) {
295 outf(f, "%s {", rsite->name);
298 outf(f, "state = \"%s\"", _state_txt[rsite->state]);
299 outf(f, "site_index = %d", rsite->site_index);
301 /* Only non-default parameters are written */
302 if (rsite->op_mode != DM_REPLICATOR_SYNC)
303 outf(f, "operation_mode = \"%s\"",
304 _op_mode_txt[rsite->op_mode]);
305 if (rsite->fall_behind_timeout)
306 outfc(f, "# seconds", "fall_behind_timeout = %u",
307 rsite->fall_behind_timeout);
308 if (rsite->fall_behind_ios)
309 outfc(f, "# io operations", "fall_behind_ios = %u",
310 rsite->fall_behind_ios);
311 if (rsite->fall_behind_data)
312 outsize(f, rsite->fall_behind_data, "fall_behind_data = %" PRIu64,
313 rsite->fall_behind_data);
314 if (rsite->state != REPLICATOR_STATE_ACTIVE && rsite->vg_name)
315 outf(f, "volume_group = \"%s\"", rsite->vg_name);
324 #ifdef DEVMAPPER_SUPPORT
325 static int _replicator_add_target_line(struct dev_manager *dm,
327 struct cmd_context *cmd,
329 struct lv_segment *seg,
330 struct dm_tree_node *node,
332 uint32_t *pvmove_mirror_count)
334 const char *rlog_dlid;
335 struct replicator_site *rsite;
340 if (!(rlog_dlid = build_dm_uuid(mem, seg->rlog_lv->lvid.s, NULL)))
343 dm_list_iterate_items(rsite, &seg->lv->rsites) {
344 if (!dm_tree_node_add_replicator_target(node,
350 rsite->fall_behind_timeout,
351 rsite->fall_behind_data,
352 rsite->fall_behind_ios)) {
353 if (rsite->site_index == 0) {
354 log_error("Failed to add replicator log '%s' "
355 "to replicator '%s'.",
356 rlog_dlid, seg->lv->name);
366 /* FIXME: write something useful for replicator here */
367 static int _replicator_target_percent(void **target_state,
370 struct cmd_context *cmd,
371 struct lv_segment *seg,
372 char *params, uint64_t *total_numerator,
373 uint64_t *total_denominator)
378 /* Check for module presence */
379 static int _replicator_target_present(struct cmd_context *cmd,
380 const struct lv_segment *seg __attribute__((unused)),
381 unsigned *attributes __attribute__((unused)))
383 static int _checked = 0;
384 static int _present = 0;
387 _present = target_present(cmd, REPLICATOR_MODULE, 1);
396 static int _replicator_modules_needed(struct dm_pool *mem,
397 const struct lv_segment *seg __attribute__((unused)),
398 struct dm_list *modules)
400 if (!str_list_add(mem, modules, REPLICATOR_MODULE))
403 if (!str_list_add(mem, modules, REPLICATOR_DEV_MODULE))
409 static void _replicator_destroy(struct segment_type *segtype)
414 static struct segtype_handler _replicator_ops = {
415 .name = _replicator_name,
416 .display = _replicator_display,
417 .text_import = _replicator_text_import,
418 .text_export = _replicator_text_export,
419 #ifdef DEVMAPPER_SUPPORT
420 .add_target_line = _replicator_add_target_line,
421 .target_percent = _replicator_target_percent,
422 .target_present = _replicator_target_present,
424 .modules_needed = _replicator_modules_needed,
425 .destroy = _replicator_destroy,
429 * Replicator-dev target
431 static void _replicator_dev_display(const struct lv_segment *seg)
435 // FIXME: debug test code for now
436 log_print(" Replicator\t\t%u", seg->area_count);
437 log_print(" Mirror size\t\t%u", seg->area_len);
439 log_print(" Replicator log volume\t%s", seg->rlog_lv->name);
443 static int _add_device(struct lv_segment *seg,
444 const char *site_name,
445 const struct config_node *sn,
448 struct dm_pool *mem = seg->lv->vg->vgmem;
449 struct logical_volume *lv = NULL;
450 struct logical_volume *slog_lv = NULL;
451 struct replicator_site *rsite = _get_site(seg->replicator, site_name);
452 struct replicator_device *rdev;
453 const char *dev_str = NULL;
454 const char *slog_str = NULL;
455 const struct config_node *cn;
457 dm_list_iterate_items(rdev, &rsite->rdevices)
458 if (rdev->replicator_dev == seg)
459 return SEG_LOG_ERROR("Duplicate site found in");
461 if ((cn = find_config_node(sn, "sync_log"))) {
462 if (!cn->v || !cn->v->v.str)
463 return SEG_LOG_ERROR("Sync log must be a string in");
464 slog_str = cn->v->v.str;
467 if (!(cn = find_config_node(sn, "logical_volume")) ||
468 !cn->v || !cn->v->v.str)
469 return SEG_LOG_ERROR("Logical volume must be a string in");
471 dev_str = cn->v->v.str;
473 if (!seg->lv->rdevice) {
475 return SEG_LOG_ERROR("Sync log %s defined for local "
476 "device in", slog_str);
478 /* Check for device in current VG */
479 if (!(lv = find_lv(seg->lv->vg, dev_str)))
480 return SEG_LOG_ERROR("Logical volume %s not found in",
484 return SEG_LOG_ERROR("Sync log is missing for remote "
486 /* Check for slog device in current VG */
487 if (!(slog_lv = find_lv(seg->lv->vg, slog_str)))
488 return SEG_LOG_ERROR("Sync log %s not found in",
492 if (!(rdev = dm_pool_zalloc(mem, sizeof(*rdev))))
495 if (!(rdev->name = dm_pool_strdup(mem, dev_str)))
498 rdev->replicator_dev = seg;
500 rdev->device_index = devidx;
502 if (!seg->lv->rdevice) {
503 if (!replicator_dev_add_rimage(rdev, lv))
504 return SEG_LOG_ERROR("LV inconsistency found in");
505 seg->lv->rdevice = rdev;
508 !(rdev->slog_name = dm_pool_strdup(mem, slog_str)))
511 if (!replicator_dev_add_slog(rdev, slog_lv))
512 return SEG_LOG_ERROR("Sync log inconsistency found in");
515 dm_list_add(&rsite->rdevices, &rdev->list);// linked site list
520 /* Import replicator segment */
521 static int _replicator_dev_text_import(struct lv_segment *seg,
522 const struct config_node *sn,
523 struct dm_hash_table *pv_hash __attribute__((unused)))
525 const struct config_node *cn;
526 struct logical_volume *replicator;
529 if (!(cn = find_config_node(sn, "replicator")))
530 return SEG_LOG_ERROR("Replicator is missing for");
532 if (!cn->v || !cn->v->v.str)
533 return SEG_LOG_ERROR("Replicator must be a string for");
535 if (!(replicator = find_lv(seg->lv->vg, cn->v->v.str)))
536 return SEG_LOG_ERROR("Unknown replicator %s for", cn->v->v.str);
538 if (!replicator_add_replicator_dev(replicator, seg))
541 log_very_verbose("replicator=%s", replicator->name);
544 if (!find_config_node(sn, "device_index") ||
545 !get_config_uint64(sn, "device_index", &devidx))
546 return SEG_LOG_ERROR("Could not read 'device_index' for");
548 /* Read devices from sites */
549 for (; sn; sn = sn->sib)
550 if (!(sn->v) && !_add_device(seg, sn->key, sn->child, devidx))
553 if (!seg->lv->rdevice)
554 return SEG_LOG_ERROR("Replicator device without site in");
557 seg->lv->status |= REPLICATOR;
562 /* Export replicator-dev segment */
563 static int _replicator_dev_text_export(const struct lv_segment *seg,
566 struct replicator_site *rsite;
567 struct replicator_device *rdev;
569 if (!seg->replicator || !seg->lv->rdevice)
572 outf(f, "replicator = \"%s\"", seg->replicator->name);
573 outf(f, "device_index = %" PRId64, seg->lv->rdevice->device_index);
577 dm_list_iterate_items(rsite, &seg->replicator->rsites) {
578 dm_list_iterate_items(rdev, &rsite->rdevices) {
579 if (rdev->replicator_dev != seg)
582 outf(f, "%s {", rdev->rsite->name);
586 outf(f, "logical_volume = \"%s\"",
587 rdev->name ? rdev->name : rdev->lv->name);
590 outf(f, "sync_log = \"%s\"", rdev->slog->name);
591 else if (rdev->slog_name)
592 outf(f, "sync_log = \"%s\"", rdev->slog_name);
603 #ifdef DEVMAPPER_SUPPORT
605 * Add target for passive site matching the device index
607 static int _replicator_dev_add_target_line(struct dev_manager *dm,
609 struct cmd_context *cmd,
611 struct lv_segment *seg,
612 struct dm_tree_node *node,
614 uint32_t *pvmove_mirror_count)
616 const char *replicator_dlid, *rdev_dlid, *slog_dlid;
617 struct replicator_device *rdev, *rdev_search;
618 struct replicator_site *rsite;
622 if (!lv_is_active_replicator_dev(seg->lv)) {
623 /* Create passive linear mapping */
624 log_very_verbose("Inactive replicator %s using %s.",
625 seg->lv->name, seg->lv->rdevice->lv->name);
626 if (!dm_tree_node_add_linear_target(node, seg->lv->size))
628 if (!(rdev_dlid = build_dm_uuid(mem, seg->lv->rdevice->lv->lvid.s, NULL)))
630 return dm_tree_node_add_target_area(node, NULL, rdev_dlid, 0);
631 } else if (seg->lv->rdevice->rsite->site_index) {
632 log_error("Active site with site_index != 0 (%s, %d)",
633 seg->lv->rdevice->rsite->name,
634 seg->lv->rdevice->rsite->site_index);
635 return 0; /* Replicator without any active site */
639 * At this point all devices that have some connection with replicator
640 * must be present in dm_tree
642 if (!seg_is_replicator_dev(seg) ||
643 !(replicator_dlid = build_dm_uuid(mem, seg->replicator->lvid.s, NULL)))
646 /* Select remote devices with the same device index */
647 dm_list_iterate_items(rsite, &seg->replicator->rsites) {
648 if (rsite->site_index == 0) {
649 /* Local slink0 device */
650 rdev = seg->lv->rdevice;
653 dm_list_iterate_items(rdev_search, &rsite->rdevices) {
654 if (rdev_search->replicator_dev == seg) {
661 log_error(INTERNAL_ERROR "rdev list not found.");
667 !(rdev_dlid = build_dm_uuid(mem, rdev->lv->lvid.s, NULL)))
672 /* Using either disk or core (in memory) log */
674 slog_flags = DM_NOSYNC;
675 slog_size = (uint32_t) rdev->slog->size;
676 if (!(slog_dlid = build_dm_uuid(mem, rdev->slog->lvid.s, NULL)))
678 } else if (rdev->slog_name &&
679 sscanf(rdev->slog_name, "%" PRIu32, &slog_size) == 1) {
680 slog_flags = DM_CORELOG | DM_FORCESYNC;
681 if (slog_size == 0) {
682 log_error("Failed to use empty corelog size "
683 "in replicator '%s'.",
684 rsite->replicator->name);
688 slog_flags = DM_CORELOG | DM_FORCESYNC;
689 slog_size = 0; /* NOLOG */
692 if (!dm_tree_node_add_replicator_dev_target(node,
695 seg->lv->rdevice->device_index,
702 /* FIXME: handle 'state = dropped' in future */
709 /* FIXME: write something useful for replicator-dev here */
710 static int _replicator_dev_target_percent(void **target_state,
713 struct cmd_context *cmd,
714 struct lv_segment *seg,
716 uint64_t *total_numerator,
717 uint64_t *total_denominator)
722 /* Check for module presence */
723 static int _replicator_dev_target_present(struct cmd_context *cmd,
724 const struct lv_segment *seg __attribute__((unused)),
725 unsigned *attributes __attribute__((unused)))
727 static int _checked = 0;
728 static int _present = 0;
731 _present = target_present(cmd, REPLICATOR_DEV_MODULE, 1);
740 static struct segtype_handler _replicator_dev_ops = {
741 .name = _replicator_name,
742 .display = _replicator_dev_display,
743 .text_import = _replicator_dev_text_import,
744 .text_export = _replicator_dev_text_export,
745 #ifdef DEVMAPPER_SUPPORT
746 .add_target_line = _replicator_dev_add_target_line,
747 .target_percent = _replicator_dev_target_percent,
748 .target_present = _replicator_dev_target_present,
750 .modules_needed = _replicator_modules_needed,
751 .destroy = _replicator_destroy,
754 #ifdef REPLICATOR_INTERNAL
755 int init_replicator_segtype(struct segtype_library *seglib)
757 int init_multiple_segtype(struct segtype_library *seglib);
758 int init_multiple_segtype(struct segtype_library *seglib)
761 struct segment_type *segtype;
763 if (!(segtype = dm_malloc(sizeof(*segtype))))
766 segtype->ops = &_replicator_ops;
767 segtype->name = REPLICATOR_MODULE;
768 segtype->private = NULL;
769 segtype->flags = SEG_REPLICATOR;
771 if (!lvm_register_segtype(seglib, segtype))
774 log_very_verbose("Initialised segtype: " REPLICATOR_MODULE);
776 if (!(segtype = dm_malloc(sizeof(*segtype))))
779 segtype->ops = &_replicator_dev_ops;
780 segtype->name = REPLICATOR_DEV_MODULE;
781 segtype->private = NULL;
782 segtype->flags = SEG_REPLICATOR_DEV;
784 if (!lvm_register_segtype(seglib, segtype))
787 log_very_verbose("Initialised segtype: " REPLICATOR_DEV_MODULE);