Tizen 2.1 base
[external/device-mapper.git] / lib / replicator / replicator.c
1 /*
2  * Copyright (C) 2009-2010 Red Hat, Inc. All rights reserved.
3  *
4  * This file is part of LVM2.
5  *
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.
9  *
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
13  */
14
15 #include "lib.h"
16 #include "toolcontext.h"
17 #include "metadata.h"
18 #include "segtype.h"
19 #include "text_export.h"
20 #include "text_import.h"
21 #include "config.h"
22 #include "activate.h"
23 #include "str_list.h"
24 #ifdef DMEVENTD
25 #  include "sharedlib.h"
26 #  include "libdevmapper-event.h"
27 #endif
28
29 /* Dm kernel module name for replicator */
30 #define REPLICATOR_MODULE "replicator"
31 #define REPLICATOR_DEV_MODULE "replicator-dev"
32
33 /*
34  * Macro used as return argument - returns 0.
35  * return is left to be written in the function for better readability.
36  */
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;
40
41
42 /*
43  *  Replicator target
44  */
45 static const char *_replicator_name(const struct lv_segment *seg)
46 {
47         return seg->segtype->name;
48 }
49
50 /* FIXME: missing implementation */
51 static void _replicator_display(const struct lv_segment *seg)
52 {
53         //const char *size;
54         //uint32_t s;
55
56         log_print("  Replicator");
57         if (seg->rlog_lv)
58                 log_print("  Replicator volume\t%s", seg->rlog_lv->name);
59 }
60
61 /* Wrapper for get_config_uint32() with default value */
62 static uint32_t _get_config_uint32(const struct config_node *cn,
63                                    const char *path,
64                                    uint32_t def)
65 {
66         uint32_t t;
67
68         return get_config_uint32(cn, path, &t) ? t : def;
69 }
70
71 /* Wrapper for get_config_uint64() with default value */
72 static uint64_t _get_config_uint64(const struct config_node *cn,
73                                    const char *path,
74                                    uint64_t def)
75 {
76         uint64_t t;
77
78         return get_config_uint64(cn, path, &t) ? t : def;
79 }
80
81
82 /* Strings replicator_state_t enum */
83 static const char _state_txt[NUM_REPLICATOR_STATE][8] = {
84         "passive",
85         "active"
86 };
87
88 /* Parse state string */
89 static replicator_state_t _get_state(const struct config_node *sn,
90                                      const char *path, replicator_state_t def)
91 {
92         const char *str;
93         unsigned i;
94
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;
99
100                 log_warn("%s: unknown value '%s', using default '%s' state",
101                          path, str, _state_txt[def]);
102         }
103
104         return def;
105 }
106
107 /* Strings for replicator_action_t enum */
108 static const char _op_mode_txt[NUM_DM_REPLICATOR_MODES][8] = {
109         "sync",
110         "warn",
111         "stall",
112         "drop",
113         "fail"
114 };
115
116
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)
120 {
121         const char *str;
122         unsigned i;
123
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;
130                         }
131                 log_warn("%s: unknown value '%s', using default '%s' operation mode",
132                          path, str, _op_mode_txt[def]);
133         }
134
135         return def;
136 }
137
138 static struct replicator_site *_get_site(struct logical_volume *replicator,
139                                          const char *key)
140 {
141         struct dm_pool *mem = replicator->vg->vgmem;
142         struct replicator_site *rsite;
143
144         dm_list_iterate_items(rsite, &replicator->rsites)
145                 if (strcasecmp(rsite->name, key) == 0)
146                         return rsite;
147
148         if (!(rsite = dm_pool_zalloc(mem, sizeof(*rsite))))
149                 return_NULL;
150
151         if (!(rsite->name = dm_pool_strdup(mem, key)))
152                 return_NULL;
153
154         rsite->replicator = replicator;
155         dm_list_init(&rsite->rdevices);
156         dm_list_add(&replicator->rsites, &rsite->list);
157
158         return rsite;
159 }
160
161
162 /* Parse replicator site element */
163 static int _add_site(struct lv_segment *seg,
164                      const char *key,
165                      const struct config_node *sn)
166 {
167         struct dm_pool *mem = seg->lv->vg->vgmem;
168         const struct config_node *cn;
169         struct replicator_site *rsite;
170
171         if (!(rsite = _get_site(seg->lv, key)))
172                 return_0;
173
174         if (!find_config_node(sn, "site_index"))
175                 return SEG_LOG_ERROR("Mandatory site_index is missing for");
176
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);
182
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;
187
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");
194
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");
198
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");
202
203                 rsite->op_mode = _get_op_mode(sn, "operation_mode",
204                                               rsite->op_mode);
205         }
206
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");
210
211                 if (!(rsite->vg_name = dm_pool_strdup(mem, cn->v->v.str)))
212                         return_0;
213
214         } else if (rsite->site_index != 0)
215                 return SEG_LOG_ERROR("volume_group is mandatory for remote site in");
216
217         return 1;
218 }
219
220
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)))
225 {
226         const struct config_node *cn;
227         struct logical_volume *rlog_lv;
228
229         if (!replicator_add_replicator_dev(seg->lv, NULL))
230                 return_0;
231
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");
235
236         if (!(rlog_lv = find_lv(seg->lv->vg, cn->v->v.str)))
237                 return SEG_LOG_ERROR("Unknown replicator log %s in",
238                                      cn->v->v.str);
239
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");
245
246         if (!(seg->rlog_type = dm_pool_strdup(seg->lv->vg->vgmem, cn->v->v.str)))
247                 return_0;
248
249
250         log_very_verbose("replicator_log = %s", rlog_lv->name);
251         log_very_verbose("replicator_log_type = %s", seg->rlog_type);
252
253         if (!replicator_add_rlog(seg, rlog_lv))
254                 return_0;
255
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);
258
259         seg->region_size = _get_config_uint32(sn, "sync_log_size", 0);
260
261         for (; sn; sn = sn->sib)
262                 if (!sn->v) {
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))
268                                 return_0;
269                 }
270         return 1;
271 }
272
273 /* Export replicator segment */
274 static int _replicator_text_export(const struct lv_segment *seg,
275                                    struct formatter *f)
276 {
277         struct replicator_site *rsite;
278
279         if (!seg->rlog_lv)
280                 return_0;
281
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);
286
287         if (seg->region_size)
288                 outsize(f, (uint64_t)seg->region_size,
289                         "sync_log_size = %" PRIu32, seg->region_size);
290
291         if (!dm_list_empty(&seg->lv->rsites))
292                 outnl(f);
293
294         dm_list_iterate_items(rsite, &seg->lv->rsites) {
295                 outf(f, "%s {", rsite->name);
296                 out_inc_indent(f);
297
298                 outf(f, "state = \"%s\"", _state_txt[rsite->state]);
299                 outf(f, "site_index = %d", rsite->site_index);
300
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);
316
317                 out_dec_indent(f);
318                 outf(f, "}");
319         }
320
321         return 1;
322 }
323
324 #ifdef DEVMAPPER_SUPPORT
325 static int _replicator_add_target_line(struct dev_manager *dm,
326                                        struct dm_pool *mem,
327                                        struct cmd_context *cmd,
328                                        void **target_state,
329                                        struct lv_segment *seg,
330                                        struct dm_tree_node *node,
331                                        uint64_t len,
332                                        uint32_t *pvmove_mirror_count)
333 {
334         const char *rlog_dlid;
335         struct replicator_site *rsite;
336
337         if (!seg->rlog_lv)
338                 return_0;
339
340         if (!(rlog_dlid = build_dm_uuid(mem, seg->rlog_lv->lvid.s, NULL)))
341                 return_0;
342
343         dm_list_iterate_items(rsite, &seg->lv->rsites) {
344                 if (!dm_tree_node_add_replicator_target(node,
345                                                         seg->rlog_lv->size,
346                                                         rlog_dlid,
347                                                         seg->rlog_type,
348                                                         rsite->site_index,
349                                                         rsite->op_mode,
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);
357                                 return 0;
358                         }
359                         // FIXME:
360                 }
361         }
362
363         return 1;
364 }
365
366 /* FIXME: write something useful for replicator here */
367 static int _replicator_target_percent(void **target_state,
368                                       percent_t *percent,
369                                       struct dm_pool *mem,
370                                       struct cmd_context *cmd,
371                                       struct lv_segment *seg,
372                                       char *params, uint64_t *total_numerator,
373                                       uint64_t *total_denominator)
374 {
375         return 1;
376 }
377
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)))
382 {
383         static int _checked = 0;
384         static int _present = 0;
385
386         if (!_checked) {
387                 _present = target_present(cmd, REPLICATOR_MODULE, 1);
388                 _checked = 1;
389         }
390
391         return _present;
392 }
393
394 #endif
395
396 static int _replicator_modules_needed(struct dm_pool *mem,
397                                       const struct lv_segment *seg __attribute__((unused)),
398                                       struct dm_list *modules)
399 {
400         if (!str_list_add(mem, modules, REPLICATOR_MODULE))
401                 return_0;
402
403         if (!str_list_add(mem, modules, REPLICATOR_DEV_MODULE))
404                 return_0;
405
406         return 1;
407 }
408
409 static void _replicator_destroy(struct segment_type *segtype)
410 {
411         dm_free(segtype);
412 }
413
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,
423 #endif
424         .modules_needed = _replicator_modules_needed,
425         .destroy = _replicator_destroy,
426 };
427
428 /*
429  *  Replicator-dev  target
430  */
431 static void _replicator_dev_display(const struct lv_segment *seg)
432 {
433         //const char *size;
434         //uint32_t s;
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);
438         if (seg->log_lv)
439                 log_print("  Replicator log volume\t%s", seg->rlog_lv->name);
440
441 }
442
443 static int _add_device(struct lv_segment *seg,
444                        const char *site_name,
445                        const struct config_node *sn,
446                        uint64_t devidx)
447 {
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;
456
457         dm_list_iterate_items(rdev, &rsite->rdevices)
458                 if (rdev->replicator_dev == seg)
459                         return SEG_LOG_ERROR("Duplicate site found in");
460
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;
465         }
466
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");
470
471         dev_str = cn->v->v.str;
472
473         if (!seg->lv->rdevice) {
474                 if (slog_str)
475                         return SEG_LOG_ERROR("Sync log %s defined for local "
476                                              "device in", slog_str);
477
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",
481                                              dev_str);
482         } else {
483                 if (!slog_str)
484                         return SEG_LOG_ERROR("Sync log is missing for remote "
485                                              "device in");
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",
489                                              slog_str);
490         }
491
492         if (!(rdev = dm_pool_zalloc(mem, sizeof(*rdev))))
493                 return_0;
494
495         if (!(rdev->name = dm_pool_strdup(mem, dev_str)))
496                 return_0;
497
498         rdev->replicator_dev = seg;
499         rdev->rsite = rsite;
500         rdev->device_index = devidx;
501
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;
506         } else {
507                 if (!slog_str ||
508                     !(rdev->slog_name = dm_pool_strdup(mem, slog_str)))
509                         return_0;
510
511                 if (!replicator_dev_add_slog(rdev, slog_lv))
512                         return SEG_LOG_ERROR("Sync log inconsistency found in");
513         }
514
515         dm_list_add(&rsite->rdevices, &rdev->list);// linked site list
516
517         return 1;
518 }
519
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)))
524 {
525         const struct config_node *cn;
526         struct logical_volume *replicator;
527         uint64_t devidx;
528
529         if (!(cn = find_config_node(sn, "replicator")))
530                 return SEG_LOG_ERROR("Replicator is missing for");
531
532         if (!cn->v || !cn->v->v.str)
533                 return SEG_LOG_ERROR("Replicator must be a string for");
534
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);
537
538         if (!replicator_add_replicator_dev(replicator, seg))
539                 return_0;
540
541         log_very_verbose("replicator=%s", replicator->name);
542
543         /* Mandatory */
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");
547
548         /* Read devices from sites */
549         for (; sn; sn = sn->sib)
550                 if (!(sn->v) && !_add_device(seg, sn->key, sn->child, devidx))
551                         return_0;
552
553         if (!seg->lv->rdevice)
554                 return SEG_LOG_ERROR("Replicator device without site in");
555
556         seg->rlog_lv = NULL;
557         seg->lv->status |= REPLICATOR;
558
559         return 1;
560 }
561
562 /* Export replicator-dev segment */
563 static int _replicator_dev_text_export(const struct lv_segment *seg,
564                                        struct formatter *f)
565 {
566         struct replicator_site *rsite;
567         struct replicator_device *rdev;
568
569         if (!seg->replicator || !seg->lv->rdevice)
570                 return_0;
571
572         outf(f, "replicator = \"%s\"", seg->replicator->name);
573         outf(f, "device_index = %" PRId64, seg->lv->rdevice->device_index);
574
575         outnl(f);
576
577         dm_list_iterate_items(rsite, &seg->replicator->rsites) {
578                 dm_list_iterate_items(rdev, &rsite->rdevices) {
579                         if (rdev->replicator_dev != seg)
580                                 continue;
581
582                         outf(f, "%s {", rdev->rsite->name);
583
584                         out_inc_indent(f);
585
586                         outf(f, "logical_volume = \"%s\"",
587                              rdev->name ? rdev->name : rdev->lv->name);
588
589                         if (rdev->slog)
590                                 outf(f, "sync_log = \"%s\"", rdev->slog->name);
591                         else if (rdev->slog_name)
592                                 outf(f, "sync_log = \"%s\"", rdev->slog_name);
593
594                         out_dec_indent(f);
595
596                         outf(f, "}");
597                 }
598         }
599
600         return 1;
601 }
602
603 #ifdef DEVMAPPER_SUPPORT
604 /*
605  * Add target for passive site matching the device index
606  */
607 static int _replicator_dev_add_target_line(struct dev_manager *dm,
608                                            struct dm_pool *mem,
609                                            struct cmd_context *cmd,
610                                            void **target_state,
611                                            struct lv_segment *seg,
612                                            struct dm_tree_node *node,
613                                            uint64_t len,
614                                            uint32_t *pvmove_mirror_count)
615 {
616         const char *replicator_dlid, *rdev_dlid, *slog_dlid;
617         struct replicator_device *rdev, *rdev_search;
618         struct replicator_site *rsite;
619         uint32_t slog_size;
620         uint32_t slog_flags;
621
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))
627                         return_0;
628                 if (!(rdev_dlid = build_dm_uuid(mem, seg->lv->rdevice->lv->lvid.s, NULL)))
629                         return_0;
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 */
636         }
637
638         /*
639          * At this point all devices that have some connection with replicator
640          * must be present in dm_tree
641          */
642         if (!seg_is_replicator_dev(seg) ||
643             !(replicator_dlid = build_dm_uuid(mem, seg->replicator->lvid.s, NULL)))
644                 return_0;
645
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;
651                 } else {
652                         rdev = NULL;
653                         dm_list_iterate_items(rdev_search, &rsite->rdevices) {
654                                 if (rdev_search->replicator_dev == seg) {
655                                         rdev = rdev_search;
656                                         break;
657                                 }
658                         }
659
660                         if (!rdev) {
661                                 log_error(INTERNAL_ERROR "rdev list not found.");
662                                 return 0;
663                         }
664                 }
665
666                 if (!rdev->lv ||
667                     !(rdev_dlid = build_dm_uuid(mem, rdev->lv->lvid.s, NULL)))
668                         return_0;
669
670                 slog_dlid = NULL;
671
672                 /* Using either disk or core (in memory) log */
673                 if (rdev->slog) {
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)))
677                                 return_0;
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);
685                                 return 0;
686                         }
687                 } else  {
688                         slog_flags = DM_CORELOG | DM_FORCESYNC;
689                         slog_size = 0; /* NOLOG */
690                 }
691
692                 if (!dm_tree_node_add_replicator_dev_target(node,
693                                                             seg->lv->size,
694                                                             replicator_dlid,
695                                                             seg->lv->rdevice->device_index,
696                                                             rdev_dlid,
697                                                             rsite->site_index,
698                                                             slog_dlid,
699                                                             slog_flags,
700                                                             slog_size)) {
701                         return_0;
702                         /* FIXME: handle 'state = dropped' in future */
703                 }
704         }
705
706         return 1;
707 }
708
709 /* FIXME: write something useful for replicator-dev here */
710 static int _replicator_dev_target_percent(void **target_state,
711                                           percent_t *percent,
712                                           struct dm_pool *mem,
713                                           struct cmd_context *cmd,
714                                           struct lv_segment *seg,
715                                           char *params,
716                                           uint64_t *total_numerator,
717                                           uint64_t *total_denominator)
718 {
719         return 1;
720 }
721
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)))
726 {
727         static int _checked = 0;
728         static int _present = 0;
729
730         if (!_checked) {
731                 _present = target_present(cmd, REPLICATOR_DEV_MODULE, 1);
732                 _checked = 1;
733         }
734
735         return _present;
736 }
737
738 #endif
739
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,
749 #endif
750         .modules_needed = _replicator_modules_needed,
751         .destroy = _replicator_destroy,
752 };
753
754 #ifdef REPLICATOR_INTERNAL
755 int init_replicator_segtype(struct segtype_library *seglib)
756 #else /* Shared */
757 int init_multiple_segtype(struct segtype_library *seglib);
758 int init_multiple_segtype(struct segtype_library *seglib)
759 #endif
760 {
761         struct segment_type *segtype;
762
763         if (!(segtype = dm_malloc(sizeof(*segtype))))
764                 return_0;
765
766         segtype->ops = &_replicator_ops;
767         segtype->name = REPLICATOR_MODULE;
768         segtype->private = NULL;
769         segtype->flags = SEG_REPLICATOR;
770
771         if (!lvm_register_segtype(seglib, segtype))
772                 return_0;
773
774         log_very_verbose("Initialised segtype: " REPLICATOR_MODULE);
775
776         if (!(segtype = dm_malloc(sizeof(*segtype))))
777                 return_0;
778
779         segtype->ops = &_replicator_dev_ops;
780         segtype->name = REPLICATOR_DEV_MODULE;
781         segtype->private = NULL;
782         segtype->flags = SEG_REPLICATOR_DEV;
783
784         if (!lvm_register_segtype(seglib, segtype))
785                 return_0;
786
787         log_very_verbose("Initialised segtype: " REPLICATOR_DEV_MODULE);
788
789         return 1;
790 }