diff --git a/WHATS_NEW b/WHATS_NEW index 8844c6435..f6e04f227 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,7 @@ Version 2.02.48 - =============================== + Use lvconvert --repair instead of vgreduce in mirror dmeventd DSO. + Introduce lvconvert --use_policies (repair policy according to lvm.conf). Fix clvmd-corosync to match new corosync API. Fix makefile to build also shared libraries when running plain make. Fix rename of active snapshot with virtual origin. diff --git a/daemons/dmeventd/plugins/mirror/dmeventd_mirror.c b/daemons/dmeventd/plugins/mirror/dmeventd_mirror.c index fc610aea8..4c9fcf5c4 100644 --- a/daemons/dmeventd/plugins/mirror/dmeventd_mirror.c +++ b/daemons/dmeventd/plugins/mirror/dmeventd_mirror.c @@ -152,7 +152,7 @@ static int _remove_failed_devices(const char *device) } /* FIXME Is any sanity-checking required on %s? */ - if (CMD_SIZE <= snprintf(cmd_str, CMD_SIZE, "vgreduce --config devices{ignore_suspended_devices=1} --removemissing --force %s", vg)) { + if (CMD_SIZE <= snprintf(cmd_str, CMD_SIZE, "lvconvert --config devices{ignore_suspended_devices=1} --repair --use-policies %s/%s", vg, lv)) { /* this error should be caught above, but doesn't hurt to check again */ syslog(LOG_ERR, "Unable to form LVM command: Device name too long"); dm_pool_empty(_mem_pool); /* FIXME: not safe with multiple threads */ diff --git a/doc/example.conf b/doc/example.conf index e06a32906..73f17c279 100644 --- a/doc/example.conf +++ b/doc/example.conf @@ -317,8 +317,10 @@ activation { # A disk log ensures that a mirror does not need to be re-synced # (all copies made the same) every time a machine reboots or crashes. # - # In the event of a failure, the specified policy will be used to - # determine what happens: + # In the event of a failure, the specified policy will be used to determine + # what happens. This applies to automatic repairs (when the mirror is being + # monitored by dmeventd) and to manual lvconvert --repair when + # --use-policies is given. # # "remove" - Simply remove the faulty device and run without it. If # the log device fails, the mirror would convert to using @@ -338,20 +340,13 @@ activation { # will preserve the mirror characteristic of the device. # This policy acts like "remove" if no suitable device and # space can be allocated for the replacement. - # Currently this is not implemented properly and behaves - # similarly to: # - # "allocate_anywhere" - Operates like "allocate", but it does not - # require that the new space being allocated be on a - # device is not part of the mirror. For a log device - # failure, this could mean that the log is allocated on - # the same device as a mirror device. For a mirror - # device, this could mean that the mirror device is - # allocated on the same device as another mirror device. - # This policy would not be wise for mirror devices - # because it would break the redundant nature of the - # mirror. This policy acts like "remove" if no suitable - # device and space can be allocated for the replacement. + # "allocate_anywhere" - Not yet implemented. Useful to place the log device + # temporarily on same physical volume as one of the mirror + # images. This policy is not recommended for mirror devices + # since it would break the redundant nature of the mirror. This + # policy acts like "remove" if no suitable device and space can + # be allocated for the replacement. mirror_log_fault_policy = "allocate" mirror_device_fault_policy = "remove" diff --git a/lib/config/defaults.h b/lib/config/defaults.h index 605bc4975..98c023acf 100644 --- a/lib/config/defaults.h +++ b/lib/config/defaults.h @@ -126,4 +126,7 @@ #define DEFAULT_SEGS_SORT "vg_name,lv_name,seg_start" #define DEFAULT_PVSEGS_SORT "pv_name,pvseg_start" +#define DEFAULT_MIRROR_DEVICE_FAULT_POLICY "remove" +#define DEFAULT_MIRROR_LOG_FAULT_POLICY "allocate" + #endif /* _LVM_DEFAULTS_H */ diff --git a/man/lvconvert.8.in b/man/lvconvert.8.in index 6c9a2ce88..1375729e1 100644 --- a/man/lvconvert.8.in +++ b/man/lvconvert.8.in @@ -63,8 +63,14 @@ Report progress as a percentage at regular intervals. .TP .I \-\-repair Repair a mirror that has suffered a disk failure. The mirror will be brought -back into a consistent state, and if possible, the original number of -mirrors will be restored. +back into a consistent state, and if possible, the original number of mirrors +will be restored, if so desired. By default, lvconvert will prompt you whether +to perform the replacement. If you instead wish to unconditionally replace +missing devices, you may specify \-y on the commandline and if you instead want +no replacement to happen at all, you may provide \-f. Additionally, you may use +"--use-policies" - this option will use the device replacement policy specified +in lvm.conf, specifically "activation/mirror_log_fault_policy" and +"activation/mirror_device_fault_policy". .br .TP .I \-s, \-\-snapshot diff --git a/test/t-lvconvert-repair.sh b/test/t-lvconvert-repair.sh index 1ec927e93..a40cd2767 100644 --- a/test/t-lvconvert-repair.sh +++ b/test/t-lvconvert-repair.sh @@ -22,19 +22,19 @@ disable_dev $dev1 lvchange --partial -a y $vg/mirror not vgreduce -v --removemissing $vg -lvconvert -i 1 --repair $vg/mirror +lvconvert -y -i 1 --repair $vg/mirror vgreduce --removemissing $vg enable_dev $dev1 vgextend $vg $dev1 disable_dev $dev2 -lvconvert -i 1 --repair $vg/mirror +lvconvert -y -i 1 --repair $vg/mirror vgreduce --removemissing $vg enable_dev $dev2 vgextend $vg $dev2 disable_dev $dev3 -lvconvert -i 1 --repair $vg/mirror +lvconvert -y -i 1 --repair $vg/mirror vgreduce --removemissing $vg enable_dev $dev3 @@ -42,5 +42,5 @@ vgextend $vg $dev3 lvcreate -m 2 -l 1 -n mirror2 $vg $dev1 $dev2 $dev3 $dev4 vgchange -a n $vg pvremove -ff -y $dev4 -echo 'y' | not lvconvert -i 1 --repair $vg/mirror2 +echo 'y' | not lvconvert -y -i 1 --repair $vg/mirror2 vgs diff --git a/tools/args.h b/tools/args.h index f8dc02c60..846b6c2ef 100644 --- a/tools/args.h +++ b/tools/args.h @@ -50,6 +50,7 @@ arg(resync_ARG, '\0', "resync", NULL, 0) arg(corelog_ARG, '\0', "corelog", NULL, 0) arg(mirrorlog_ARG, '\0', "mirrorlog", string_arg, 0) arg(repair_ARG, '\0', "repair", NULL, 0) +arg(use_policies_ARG, '\0', "use-policies", NULL, 0) arg(monitor_ARG, '\0', "monitor", yes_no_arg, 0) arg(config_ARG, '\0', "config", string_arg, 0) arg(trustcache_ARG, '\0', "trustcache", NULL, 0) diff --git a/tools/commands.h b/tools/commands.h index eec62e3bb..ee39bf917 100644 --- a/tools/commands.h +++ b/tools/commands.h @@ -94,7 +94,7 @@ xx(lvconvert, 0, "lvconvert " "[-m|--mirrors Mirrors [{--mirrorlog {disk|core}|--corelog}]]\n" - "\t[--repair]\n" + "\t[--repair [--use-policies]]\n" "\t[-R|--regionsize MirrorLogRegionSize]\n" "\t[--alloc AllocationPolicy]\n" "\t[-b|--background]\n" @@ -117,7 +117,7 @@ xx(lvconvert, alloc_ARG, background_ARG, chunksize_ARG, corelog_ARG, interval_ARG, mirrorlog_ARG, mirrors_ARG, regionsize_ARG, repair_ARG, snapshot_ARG, - test_ARG, zero_ARG) + test_ARG, use_policies_ARG, yes_ARG, force_ARG, zero_ARG) xx(lvcreate, "Create a logical volume", diff --git a/tools/lvconvert.c b/tools/lvconvert.c index c5e63a390..47f5de751 100644 --- a/tools/lvconvert.c +++ b/tools/lvconvert.c @@ -457,6 +457,49 @@ static struct logical_volume *_original_lv(struct logical_volume *lv) return next_lv; } +static void _lvconvert_mirrors_repair_ask(struct cmd_context *cmd, + int failed_log, int failed_mirrors, + int *replace_log, int *replace_mirrors) +{ + const char *leg_policy = NULL, *log_policy = NULL; + + int force = arg_count(cmd, force_ARG); + int yes = arg_count(cmd, yes_ARG); + + *replace_log = *replace_mirrors = 1; + + if (arg_count(cmd, use_policies_ARG)) { + leg_policy = find_config_tree_str(cmd, + "activation/mirror_device_fault_policy", + DEFAULT_MIRROR_DEVICE_FAULT_POLICY); + log_policy = find_config_tree_str(cmd, + "activation/mirror_log_fault_policy", + DEFAULT_MIRROR_LOG_FAULT_POLICY); + *replace_mirrors = strcmp(leg_policy, "remove"); + *replace_log = strcmp(log_policy, "remove"); + return; + } + + if (yes) + return; + + if (force != PROMPT) { + *replace_log = *replace_mirrors = 0; + return; + } + + if (failed_log && + yes_no_prompt("Attempt to replace failed mirror log? [y/n]: ") == 'n') { + *replace_log = 0; + } + + if (failed_mirrors && + yes_no_prompt("Attempt to replace failed mirror images " + "(requires full device resync)? [y/n]: ") == 'n') { + *replace_mirrors = 0; + } +} + static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv, struct lvconvert_params *lp) { @@ -470,18 +513,21 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv int failed_mirrors = 0, failed_log = 0; struct dm_list *old_pvh = NULL, *remove_pvs = NULL; + int repair = arg_count(cmd, repair_ARG); + int replace_log = 1, replace_mirrors = 1; + seg = first_seg(lv); existing_mirrors = lv_mirror_count(lv); /* If called with no argument, try collapsing the resync layers */ if (!arg_count(cmd, mirrors_ARG) && !arg_count(cmd, mirrorlog_ARG) && !arg_count(cmd, corelog_ARG) && !arg_count(cmd, regionsize_ARG) && - !arg_count(cmd, repair_ARG)) { + !repair) { lp->need_polling = 1; return 1; } - if (arg_count(cmd, mirrors_ARG) && arg_count(cmd, repair_ARG)) { + if (arg_count(cmd, mirrors_ARG) && repair) { log_error("You can only use one of -m, --repair."); return 0; } @@ -503,7 +549,7 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv else lp->mirrors += 1; - if (arg_count(cmd,repair_ARG)) { + if (repair) { cmd->handles_missing_pvs = 1; cmd->partial_activation = 1; lp->need_polling = 0; @@ -514,7 +560,7 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv if ((failed_mirrors = _failed_mirrors_count(lv)) < 0) return_0; lp->mirrors -= failed_mirrors; - log_error("Mirror status: %d/%d legs failed.", + log_error("Mirror status: %d/%d images failed.", failed_mirrors, existing_mirrors); old_pvh = lp->pvh; if (!(lp->pvh = _failed_pv_list(lv->vg))) @@ -577,6 +623,10 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv return 0; } + if (repair) + _lvconvert_mirrors_repair_ask(cmd, failed_log, failed_mirrors, + &replace_log, &replace_mirrors); + restart: /* * Converting from mirror to linear @@ -594,7 +644,7 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv */ if (lp->mirrors < existing_mirrors) { /* Reduce number of mirrors */ - if (arg_count(cmd, repair_ARG) || lp->pv_count) + if (repair || lp->pv_count) remove_pvs = lp->pvh; if (!lv_remove_mirrors(cmd, lv, existing_mirrors - lp->mirrors, (corelog || lp->mirrors == 1) ? 1U : 0U, @@ -727,13 +777,15 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv if (failed_log || failed_mirrors) { lp->pvh = old_pvh; - if (failed_log) + if (failed_log && replace_log) failed_log = corelog = 0; - lp->mirrors += failed_mirrors; + if (replace_mirrors) + lp->mirrors += failed_mirrors; failed_mirrors = 0; existing_mirrors = lv_mirror_count(lv); /* Now replace missing devices. */ - goto restart; + if (replace_log || replace_mirrors) + goto restart; } if (!lp->need_polling)