4 * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
7 * This file is part of LVM2.
9 * This copyrighted material is made available to anyone wishing to use,
10 * modify, copy, or redistribute it subject to the terms and conditions
11 * of the GNU Lesser General Public License v.2.1.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "toolcontext.h"
23 #include "text_export.h"
24 #include "text_import.h"
27 #include "lvm-string.h"
30 #include "sharedlib.h"
34 # include "libdevmapper-event.h"
37 static int _block_on_error_available
= 0;
38 static unsigned _mirror_attributes
= 0;
47 uint32_t default_region_size
;
50 static const char *_mirrored_name(const struct lv_segment
*seg
)
52 return seg
->segtype
->name
;
55 static void _mirrored_display(const struct lv_segment
*seg
)
60 log_print(" Mirrors\t\t%u", seg
->area_count
);
61 log_print(" Mirror size\t\t%u", seg
->area_len
);
63 log_print(" Mirror log volume\t%s", seg
->log_lv
->name
);
65 if (seg
->region_size
) {
66 size
= display_size(seg
->lv
->vg
->cmd
,
67 (uint64_t) seg
->region_size
);
68 log_print(" Mirror region size\t%s", size
);
71 log_print(" Mirror original:");
72 display_stripe(seg
, 0, " ");
73 log_print(" Mirror destinations:");
74 for (s
= 1; s
< seg
->area_count
; s
++)
75 display_stripe(seg
, s
, " ");
79 static int _mirrored_text_import_area_count(struct config_node
*sn
, uint32_t *area_count
)
81 if (!get_config_uint32(sn
, "mirror_count", area_count
)) {
82 log_error("Couldn't read 'mirror_count' for "
83 "segment '%s'.", config_parent_name(sn
));
90 static int _mirrored_text_import(struct lv_segment
*seg
, const struct config_node
*sn
,
91 struct dm_hash_table
*pv_hash
)
93 const struct config_node
*cn
;
96 if (find_config_node(sn
, "extents_moved")) {
97 if (get_config_uint32(sn
, "extents_moved",
98 &seg
->extents_copied
))
99 seg
->status
|= PVMOVE
;
101 log_error("Couldn't read 'extents_moved' for "
102 "segment %s of logical volume %s.",
103 config_parent_name(sn
), seg
->lv
->name
);
108 if (find_config_node(sn
, "region_size")) {
109 if (!get_config_uint32(sn
, "region_size",
110 &seg
->region_size
)) {
111 log_error("Couldn't read 'region_size' for "
112 "segment %s of logical volume %s.",
113 config_parent_name(sn
), seg
->lv
->name
);
118 if ((cn
= find_config_node(sn
, "mirror_log"))) {
119 if (!cn
->v
|| !cn
->v
->v
.str
) {
120 log_error("Mirror log type must be a string.");
123 logname
= cn
->v
->v
.str
;
124 if (!(seg
->log_lv
= find_lv(seg
->lv
->vg
, logname
))) {
125 log_error("Unrecognised mirror log in "
126 "segment %s of logical volume %s.",
127 config_parent_name(sn
), seg
->lv
->name
);
130 seg
->log_lv
->status
|= MIRROR_LOG
;
133 if (logname
&& !seg
->region_size
) {
134 log_error("Missing region size for mirror log for "
135 "segment %s of logical volume %s.",
136 config_parent_name(sn
), seg
->lv
->name
);
140 if (!(cn
= find_config_node(sn
, "mirrors"))) {
141 log_error("Couldn't find mirrors array for "
142 "segment %s of logical volume %s.",
143 config_parent_name(sn
), seg
->lv
->name
);
147 return text_import_areas(seg
, sn
, cn
, pv_hash
, MIRROR_IMAGE
);
150 static int _mirrored_text_export(const struct lv_segment
*seg
, struct formatter
*f
)
152 outf(f
, "mirror_count = %u", seg
->area_count
);
153 if (seg
->status
& PVMOVE
)
154 out_size(f
, (uint64_t) seg
->extents_copied
* seg
->lv
->vg
->extent_size
,
155 "extents_moved = %" PRIu32
, seg
->extents_copied
);
157 outf(f
, "mirror_log = \"%s\"", seg
->log_lv
->name
);
158 if (seg
->region_size
)
159 outf(f
, "region_size = %" PRIu32
, seg
->region_size
);
161 return out_areas(f
, seg
, "mirror");
164 #ifdef DEVMAPPER_SUPPORT
165 static struct mirror_state
*_mirrored_init_target(struct dm_pool
*mem
,
166 struct cmd_context
*cmd
)
168 struct mirror_state
*mirr_state
;
170 if (!(mirr_state
= dm_pool_alloc(mem
, sizeof(*mirr_state
)))) {
171 log_error("struct mirr_state allocation failed");
175 mirr_state
->default_region_size
= 2 *
176 find_config_tree_int(cmd
,
177 "activation/mirror_region_size",
178 DEFAULT_MIRROR_REGION_SIZE
);
183 static int _mirrored_target_percent(void **target_state
,
184 percent_range_t
*percent_range
,
186 struct cmd_context
*cmd
,
187 struct lv_segment
*seg
, char *params
,
188 uint64_t *total_numerator
,
189 uint64_t *total_denominator
)
191 struct mirror_state
*mirr_state
;
192 uint64_t numerator
, denominator
;
193 unsigned mirror_count
, m
;
198 *target_state
= _mirrored_init_target(mem
, cmd
);
200 mirr_state
= *target_state
;
202 /* Status line: <#mirrors> (maj:min)+ <synced>/<total_regions> */
203 log_debug("Mirror status: %s", params
);
205 if (sscanf(pos
, "%u %n", &mirror_count
, &used
) != 1) {
206 log_error("Failure parsing mirror status mirror count: %s",
212 for (m
= 0; m
< mirror_count
; m
++) {
213 if (sscanf(pos
, "%*x:%*x %n", &used
) != 0) {
214 log_error("Failure parsing mirror status devices: %s",
221 if (sscanf(pos
, "%" PRIu64
"/%" PRIu64
"%n", &numerator
, &denominator
,
223 log_error("Failure parsing mirror status fraction: %s", params
);
228 *total_numerator
+= numerator
;
229 *total_denominator
+= denominator
;
232 seg
->extents_copied
= seg
->area_len
* numerator
/ denominator
;
234 if (numerator
== denominator
)
235 *percent_range
= PERCENT_100
;
236 else if (numerator
== 0)
237 *percent_range
= PERCENT_0
;
239 *percent_range
= PERCENT_0_TO_100
;
244 static int _add_log(struct dev_manager
*dm
, struct lv_segment
*seg
,
245 struct dm_tree_node
*node
, uint32_t area_count
, uint32_t region_size
)
247 unsigned clustered
= 0;
248 char *log_dlid
= NULL
;
249 uint32_t log_flags
= 0;
252 * Use clustered mirror log for non-exclusive activation
255 if ((!(seg
->lv
->status
& ACTIVATE_EXCL
) &&
256 (vg_is_clustered(seg
->lv
->vg
))))
260 /* If disk log, use its UUID */
261 if (!(log_dlid
= build_dlid(dm
, seg
->log_lv
->lvid
.s
, NULL
))) {
262 log_error("Failed to build uuid for log LV %s.",
267 /* If core log, use mirror's UUID and set DM_CORELOG flag */
268 if (!(log_dlid
= build_dlid(dm
, seg
->lv
->lvid
.s
, NULL
))) {
269 log_error("Failed to build uuid for mirror LV %s.",
273 log_flags
|= DM_CORELOG
;
276 if (mirror_in_sync() && !(seg
->status
& PVMOVE
))
277 log_flags
|= DM_NOSYNC
;
279 if (_block_on_error_available
&& !(seg
->status
& PVMOVE
))
280 log_flags
|= DM_BLOCK_ON_ERROR
;
282 return dm_tree_node_add_mirror_target_log(node
, region_size
, clustered
, log_dlid
, area_count
, log_flags
);
285 static int _mirrored_add_target_line(struct dev_manager
*dm
, struct dm_pool
*mem
,
286 struct cmd_context
*cmd
, void **target_state
,
287 struct lv_segment
*seg
,
288 struct dm_tree_node
*node
, uint64_t len
,
289 uint32_t *pvmove_mirror_count
)
291 struct mirror_state
*mirr_state
;
292 uint32_t area_count
= seg
->area_count
;
293 unsigned start_area
= 0u;
294 int mirror_status
= MIRR_RUNNING
;
295 uint32_t region_size
;
299 *target_state
= _mirrored_init_target(mem
, cmd
);
301 mirr_state
= *target_state
;
304 * Mirror segment could have only 1 area temporarily
305 * if the segment is under conversion.
307 if (seg
->area_count
== 1)
308 mirror_status
= MIRR_DISABLED
;
311 * For pvmove, only have one mirror segment RUNNING at once.
312 * Segments before this are COMPLETED and use 2nd area.
313 * Segments after this are DISABLED and use 1st area.
315 if (seg
->status
& PVMOVE
) {
316 if (seg
->extents_copied
== seg
->area_len
) {
317 mirror_status
= MIRR_COMPLETED
;
319 } else if ((*pvmove_mirror_count
)++) {
320 mirror_status
= MIRR_DISABLED
;
323 /* else MIRR_RUNNING */
326 if (mirror_status
!= MIRR_RUNNING
) {
327 if (!dm_tree_node_add_linear_target(node
, len
))
332 if (!(seg
->status
& PVMOVE
)) {
333 if (!seg
->region_size
) {
334 log_error("Missing region size for mirror segment.");
337 region_size
= seg
->region_size
;
340 region_size
= adjusted_mirror_region_size(seg
->lv
->vg
->extent_size
,
342 mirr_state
->default_region_size
);
344 if (!dm_tree_node_add_mirror_target(node
, len
))
347 if ((r
= _add_log(dm
, seg
, node
, area_count
, region_size
)) <= 0) {
353 return add_areas_line(dm
, seg
, node
, start_area
, area_count
);
356 static int _mirrored_target_present(struct cmd_context
*cmd
,
357 const struct lv_segment
*seg
,
358 unsigned *attributes
)
360 static int _mirrored_checked
= 0;
361 static int _mirrored_present
= 0;
362 uint32_t maj
, min
, patchlevel
;
363 unsigned maj2
, min2
, patchlevel2
;
366 if (!_mirrored_checked
) {
367 _mirrored_present
= target_present(cmd
, "mirror", 1);
370 * block_on_error available as "block_on_error" log
371 * argument with mirror target >= 1.1 and <= 1.11
372 * or with 1.0 in RHEL4U3 driver >= 4.5
374 * block_on_error available as "handle_errors" mirror
375 * argument with mirror target >= 1.12.
377 * libdm-deptree.c is smart enough to handle the differences
378 * between block_on_error and handle_errors for all
379 * mirror target versions >= 1.1
381 /* FIXME Move this into libdevmapper */
383 if (target_version("mirror", &maj
, &min
, &patchlevel
) &&
386 (min
== 0 && driver_version(vsn
, sizeof(vsn
)) &&
387 sscanf(vsn
, "%u.%u.%u", &maj2
, &min2
, &patchlevel2
) == 3 &&
388 maj2
== 4 && min2
== 5 && patchlevel2
== 0))) /* RHEL4U3 */
389 _block_on_error_available
= 1;
393 * Check only for modules if atttributes requested and no previous check.
394 * FIXME: Fails incorrectly if cmirror was built into kernel.
397 if (!_mirror_attributes
&& module_present(cmd
, "log-clustered"))
398 _mirror_attributes
|= MIRROR_LOG_CLUSTERED
;
399 *attributes
= _mirror_attributes
;
401 _mirrored_checked
= 1;
403 return _mirrored_present
;
407 static int _get_mirror_dso_path(struct cmd_context
*cmd
, char **dso
)
412 if (!(path
= dm_pool_alloc(cmd
->mem
, PATH_MAX
))) {
413 log_error("Failed to allocate dmeventd library path.");
417 libpath
= find_config_tree_str(cmd
, "dmeventd/mirror_library",
418 DEFAULT_DMEVENTD_MIRROR_LIB
);
420 get_shared_library_path(cmd
, libpath
, path
, PATH_MAX
);
427 static struct dm_event_handler
*_create_dm_event_handler(const char *dmname
,
429 enum dm_event_mask mask
)
431 struct dm_event_handler
*dmevh
;
433 if (!(dmevh
= dm_event_handler_create()))
436 if (dm_event_handler_set_dso(dmevh
, dso
))
439 if (dm_event_handler_set_dev_name(dmevh
, dmname
))
442 dm_event_handler_set_event_mask(dmevh
, mask
);
446 dm_event_handler_destroy(dmevh
);
450 static int _target_monitored(struct lv_segment
*seg
, int *pending
)
453 struct logical_volume
*lv
;
454 struct volume_group
*vg
;
455 enum dm_event_mask evmask
= 0;
456 struct dm_event_handler
*dmevh
;
462 if (!_get_mirror_dso_path(vg
->cmd
, &dso
))
465 if (!(name
= build_dm_name(vg
->cmd
->mem
, vg
->name
, lv
->name
, NULL
)))
468 if (!(dmevh
= _create_dm_event_handler(name
, dso
, DM_EVENT_ALL_ERRORS
)))
471 if (dm_event_get_registered_device(dmevh
, 0)) {
472 dm_event_handler_destroy(dmevh
);
476 evmask
= dm_event_handler_get_event_mask(dmevh
);
477 if (evmask
& DM_EVENT_REGISTRATION_PENDING
) {
479 evmask
&= ~DM_EVENT_REGISTRATION_PENDING
;
482 dm_event_handler_destroy(dmevh
);
487 /* FIXME This gets run while suspended and performs banned operations. */
488 static int _target_set_events(struct lv_segment
*seg
,
489 int evmask
__attribute((unused
)), int set
)
492 struct logical_volume
*lv
;
493 struct volume_group
*vg
;
494 struct dm_event_handler
*dmevh
;
500 if (!_get_mirror_dso_path(vg
->cmd
, &dso
))
503 if (!(name
= build_dm_name(vg
->cmd
->mem
, vg
->name
, lv
->name
, NULL
)))
506 if (!(dmevh
= _create_dm_event_handler(name
, dso
, DM_EVENT_ALL_ERRORS
)))
509 r
= set
? dm_event_register_handler(dmevh
) : dm_event_unregister_handler(dmevh
);
510 dm_event_handler_destroy(dmevh
);
514 log_info("%s %s for events", set
? "Monitored" : "Unmonitored", name
);
519 static int _target_monitor_events(struct lv_segment
*seg
, int events
)
521 return _target_set_events(seg
, events
, 1);
524 static int _target_unmonitor_events(struct lv_segment
*seg
, int events
)
526 return _target_set_events(seg
, events
, 0);
529 #endif /* DMEVENTD */
530 #endif /* DEVMAPPER_SUPPORT */
532 static int _mirrored_modules_needed(struct dm_pool
*mem
,
533 const struct lv_segment
*seg
,
534 struct dm_list
*modules
)
537 !list_segment_modules(mem
, first_seg(seg
->log_lv
), modules
))
540 if (vg_is_clustered(seg
->lv
->vg
) &&
541 !str_list_add(mem
, modules
, "clog")) {
542 log_error("cluster log string list allocation failed");
546 if (!str_list_add(mem
, modules
, "mirror")) {
547 log_error("mirror string list allocation failed");
554 static void _mirrored_destroy(const struct segment_type
*segtype
)
556 dm_free((void *) segtype
);
559 static struct segtype_handler _mirrored_ops
= {
560 .name
= _mirrored_name
,
561 .display
= _mirrored_display
,
562 .text_import_area_count
= _mirrored_text_import_area_count
,
563 .text_import
= _mirrored_text_import
,
564 .text_export
= _mirrored_text_export
,
565 #ifdef DEVMAPPER_SUPPORT
566 .add_target_line
= _mirrored_add_target_line
,
567 .target_percent
= _mirrored_target_percent
,
568 .target_present
= _mirrored_target_present
,
570 .target_monitored
= _target_monitored
,
571 .target_monitor_events
= _target_monitor_events
,
572 .target_unmonitor_events
= _target_unmonitor_events
,
575 .modules_needed
= _mirrored_modules_needed
,
576 .destroy
= _mirrored_destroy
,
579 #ifdef MIRRORED_INTERNAL
580 struct segment_type
*init_mirrored_segtype(struct cmd_context
*cmd
)
582 struct segment_type
*init_segtype(struct cmd_context
*cmd
);
583 struct segment_type
*init_segtype(struct cmd_context
*cmd
)
586 struct segment_type
*segtype
= dm_malloc(sizeof(*segtype
));
592 segtype
->ops
= &_mirrored_ops
;
593 segtype
->name
= "mirror";
594 segtype
->private = NULL
;
595 segtype
->flags
= SEG_AREAS_MIRRORED
| SEG_MONITORED
;
597 log_very_verbose("Initialised segtype: %s", segtype
->name
);