diff --git a/.gitignore b/.gitignore index 6de202c..d9acf11 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -SOURCES/LVM2.2.02.171.tgz +SOURCES/LVM2.2.02.177.tgz +SOURCES/boom-0.8.5.tar.gz diff --git a/.lvm2.metadata b/.lvm2.metadata index 7d21c07..b1e86fd 100644 --- a/.lvm2.metadata +++ b/.lvm2.metadata @@ -1 +1,2 @@ -134498350084fe1371e48e1bdcf558913a112a78 SOURCES/LVM2.2.02.171.tgz +b114b2ef40fca63c6df290a5f1aac54ff3e764aa SOURCES/LVM2.2.02.177.tgz +56a275b49755264565ed595098ea2bb8b0cfe75e SOURCES/boom-0.8.5.tar.gz diff --git a/SOURCES/lvm2-2_02_172-fix-raid-segfault.patch b/SOURCES/lvm2-2_02_172-fix-raid-segfault.patch deleted file mode 100644 index 0a40151..0000000 --- a/SOURCES/lvm2-2_02_172-fix-raid-segfault.patch +++ /dev/null @@ -1,16 +0,0 @@ - lib/metadata/raid_manip.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c -index 9e4f3a3..66fc2bd 100644 ---- a/lib/metadata/raid_manip.c -+++ b/lib/metadata/raid_manip.c -@@ -2373,7 +2373,7 @@ static int _raid_reshape(struct logical_volume *lv, - if (seg->area_count != 2 || old_image_count != seg->area_count) { - if (!_lv_update_reload_fns_reset_eliminate_lvs(lv, 0, &removal_lvs, NULL)) - return_0; -- } if (!_vg_write_commit_backup(lv->vg)) -+ } else if (!_vg_write_commit_backup(lv->vg)) - return_0; - - return 1; diff --git a/SOURCES/lvm2-2_02_172-libdm-initialization-of-reused-struct.patch b/SOURCES/lvm2-2_02_172-libdm-initialization-of-reused-struct.patch deleted file mode 100644 index 05f5a61..0000000 --- a/SOURCES/lvm2-2_02_172-libdm-initialization-of-reused-struct.patch +++ /dev/null @@ -1,53 +0,0 @@ - WHATS_NEW_DM | 1 + - libdm/ioctl/libdm-iface.c | 10 +++++++++- - 2 files changed, 10 insertions(+), 1 deletion(-) - -diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM -index 581cd42..bf08130 100644 ---- a/WHATS_NEW_DM -+++ b/WHATS_NEW_DM -@@ -1,5 +1,6 @@ - Version 1.02.141 - - =============================== -+ Fix reusing of dm_task structure for status reading (used by dmeventd). - dm_get_status_raid() handle better some incosistent md statuses. - Accept truncated files in calls to dm_stats_update_regions_from_fd(). - Restore Warning by 5% increment when thin-pool is over 80% (1.02.138). -diff --git a/libdm/ioctl/libdm-iface.c b/libdm/ioctl/libdm-iface.c -index cb3e8dc..65e75f6 100644 ---- a/libdm/ioctl/libdm-iface.c -+++ b/libdm/ioctl/libdm-iface.c -@@ -467,7 +467,7 @@ static void _dm_zfree_dmi(struct dm_ioctl *dmi) - } - } - --void dm_task_destroy(struct dm_task *dmt) -+static void _dm_task_free_targets(struct dm_task *dmt) - { - struct target *t, *n; - -@@ -478,6 +478,12 @@ void dm_task_destroy(struct dm_task *dmt) - dm_free(t); - } - -+ dmt->head = dmt->tail = NULL; -+} -+ -+void dm_task_destroy(struct dm_task *dmt) -+{ -+ _dm_task_free_targets(dmt); - _dm_zfree_dmi(dmt->dmi.v4); - dm_free(dmt->dev_name); - dm_free(dmt->mangled_dev_name); -@@ -652,6 +658,8 @@ static int _unmarshal_status(struct dm_task *dmt, struct dm_ioctl *dmi) - uint32_t i; - struct dm_target_spec *spec; - -+ _dm_task_free_targets(dmt); -+ - for (i = 0; i < dmi->target_count; i++) { - spec = (struct dm_target_spec *) outptr; - if (!dm_task_add_target(dmt, spec->sector_start, --- -1.8.3.1 - diff --git a/SOURCES/lvm2-2_02_172-upstream-6.patch b/SOURCES/lvm2-2_02_172-upstream-6.patch deleted file mode 100644 index 36ae424..0000000 --- a/SOURCES/lvm2-2_02_172-upstream-6.patch +++ /dev/null @@ -1,1466 +0,0 @@ - WHATS_NEW | 2 + - WHATS_NEW_DM | 1 + - lib/metadata/lv.c | 11 +- - lib/metadata/lv_manip.c | 18 +- - lib/metadata/metadata-exported.h | 1 + - lib/metadata/raid_manip.c | 354 +++++++++++---------- - lib/raid/raid.c | 39 +-- - lib/report/report.c | 10 +- - libdm/libdm-targets.c | 18 ++ - scripts/fsadm.sh | 1 + - test/lib/check.sh | 2 +- - test/shell/fsadm.sh | 1 + - test/shell/lvconvert-raid-status-validation.sh | 127 ++++++++ - .../shell/lvconvert-raid-takeover-alloc-failure.sh | 9 +- - test/shell/lvconvert-raid-takeover-thin.sh | 72 +++++ - tools/lvresize.c | 1 + - 16 files changed, 465 insertions(+), 202 deletions(-) -diff --git a/WHATS_NEW b/WHATS_NEW -index b2796f6..e60380a 100644 ---- a/WHATS_NEW -+++ b/WHATS_NEW -@@ -1,5 +1,7 @@ - Version 2.02.172 - - =============================== -+ Reenable conversion of data and metadata thin-pool volumes to raid. -+ Improve raid status reporting with lvs. - No longer necessary to '--force' a repair for RAID1 - Linear to RAID1 upconverts now use "recover" sync action, not "resync". - Improve lvcreate --cachepool arg validation. -diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM -index 5718ab7..581cd42 100644 ---- a/WHATS_NEW_DM -+++ b/WHATS_NEW_DM -@@ -1,5 +1,6 @@ - Version 1.02.141 - - =============================== -+ dm_get_status_raid() handle better some incosistent md statuses. - Accept truncated files in calls to dm_stats_update_regions_from_fd(). - Restore Warning by 5% increment when thin-pool is over 80% (1.02.138). - -diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c -index b24c4aa..c87bb6b 100644 ---- a/lib/metadata/lv.c -+++ b/lib/metadata/lv.c -@@ -395,6 +395,15 @@ dm_percent_t lvseg_percent_with_info_and_seg_status(const struct lv_with_info_an - } - } - break; -+ case SEG_STATUS_RAID: -+ switch (type) { -+ case PERCENT_GET_DIRTY: -+ p = dm_make_percent(s->raid->insync_regions, s->raid->total_regions); -+ break; -+ default: -+ p = DM_PERCENT_INVALID; -+ } -+ break; - case SEG_STATUS_SNAPSHOT: - if (s->snapshot->merge_failed) - p = DM_PERCENT_INVALID; -@@ -1087,7 +1096,7 @@ int lv_raid_healthy(const struct logical_volume *lv) - } - - if (!seg_is_raid(raid_seg)) { -- log_error("%s on %s is not a RAID segment", -+ log_error(INTERNAL_ERROR "%s on %s is not a RAID segment.", - raid_seg->lv->name, lv->name); - return 0; - } -diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c -index 8f38839..c431868 100644 ---- a/lib/metadata/lv_manip.c -+++ b/lib/metadata/lv_manip.c -@@ -4578,6 +4578,7 @@ enum fsadm_cmd_e { FSADM_CMD_CHECK, FSADM_CMD_RESIZE }; - static int _fsadm_cmd(enum fsadm_cmd_e fcmd, - struct logical_volume *lv, - uint32_t extents, -+ int yes, - int force, - int *status) - { -@@ -4585,7 +4586,7 @@ static int _fsadm_cmd(enum fsadm_cmd_e fcmd, - struct cmd_context *cmd = vg->cmd; - char lv_path[PATH_MAX]; - char size_buf[SIZE_BUF]; -- const char *argv[FSADM_CMD_MAX_ARGS + 2]; -+ const char *argv[FSADM_CMD_MAX_ARGS + 4]; - unsigned i = 0; - - argv[i++] = find_config_tree_str(cmd, global_fsadm_executable_CFG, NULL); -@@ -4596,6 +4597,9 @@ static int _fsadm_cmd(enum fsadm_cmd_e fcmd, - if (verbose_level() >= _LOG_NOTICE) - argv[i++] = "--verbose"; - -+ if (yes) -+ argv[i++] = "--yes"; -+ - if (force) - argv[i++] = "--force"; - -@@ -5498,7 +5502,7 @@ int lv_resize(struct logical_volume *lv, - - if (lp->resizefs) { - if (!lp->nofsck && -- !_fsadm_cmd(FSADM_CMD_CHECK, lv, 0, lp->force, &status)) { -+ !_fsadm_cmd(FSADM_CMD_CHECK, lv, 0, lp->yes, lp->force, &status)) { - if (status != FSADM_CHECK_FAILS_FOR_MOUNTED) { - log_error("Filesystem check failed."); - return 0; -@@ -5508,7 +5512,7 @@ int lv_resize(struct logical_volume *lv, - - /* FIXME forks here */ - if ((lp->resize == LV_REDUCE) && -- !_fsadm_cmd(FSADM_CMD_RESIZE, lv, lp->extents, lp->force, NULL)) { -+ !_fsadm_cmd(FSADM_CMD_RESIZE, lv, lp->extents, lp->yes, lp->force, NULL)) { - log_error("Filesystem resize failed."); - return 0; - } -@@ -5589,7 +5593,7 @@ out: - display_lvname(lv)); - - if (lp->resizefs && (lp->resize == LV_EXTEND) && -- !_fsadm_cmd(FSADM_CMD_RESIZE, lv, lp->extents, lp->force, NULL)) -+ !_fsadm_cmd(FSADM_CMD_RESIZE, lv, lp->extents, lp->yes, lp->force, NULL)) - return_0; - - ret = 1; -@@ -6368,6 +6372,12 @@ static int _lv_update_and_reload(struct logical_volume *lv, int origin_only) - if (!vg_write(vg)) - return_0; - -+ if (lock_lv != lv) { -+ log_debug_activation("Dropping origin_only for %s as lock holds %s", -+ display_lvname(lv), display_lvname(lock_lv)); -+ origin_only = 0; -+ } -+ - if (!(origin_only ? suspend_lv_origin(vg->cmd, lock_lv) : suspend_lv(vg->cmd, lock_lv))) { - log_error("Failed to lock logical volume %s.", - display_lvname(lock_lv)); -diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h -index c4bebd0..6c3d8d7 100644 ---- a/lib/metadata/metadata-exported.h -+++ b/lib/metadata/metadata-exported.h -@@ -649,6 +649,7 @@ struct lvresize_params { - int use_policies; - - alloc_policy_t alloc; -+ int yes; - int force; - int nosync; - int nofsck; -diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c -index ade27e6..9e4f3a3 100644 ---- a/lib/metadata/raid_manip.c -+++ b/lib/metadata/raid_manip.c -@@ -75,6 +75,24 @@ static int _rebuild_with_emptymeta_is_supported(struct cmd_context *cmd, - return 1; - } - -+/* https://bugzilla.redhat.com/1447812 check open count of @lv vs. @open_count */ -+static int _check_lv_open_count(struct logical_volume *lv, int open_count) { -+ struct lvinfo info = { 0 }; -+ -+ if (!lv_info(lv->vg->cmd, lv, 0, &info, 1, 0)) { -+ log_error("lv_info failed: aborting."); -+ return 0; -+ } -+ if (info.open_count != open_count) { -+ log_error("Reshape is only supported when %s is not in use (e.g. unmount filesystem).", -+ display_lvname(lv)); -+ return 0; -+ } -+ -+ return 1; -+} -+ -+ - /* - * Ensure region size exceeds the minimum for @lv because - * MD's bitmap is limited to tracking 2^21 regions. -@@ -442,7 +460,7 @@ static int _raid_remove_top_layer(struct logical_volume *lv, - - if (!(lvl_array = dm_pool_alloc(lv->vg->vgmem, 2 * sizeof(*lvl)))) { - log_error("Memory allocation failed."); -- return_0; -+ return 0; - } - - /* Add last metadata area to removal_lvs */ -@@ -534,10 +552,20 @@ static int _lv_update_reload_fns_reset_eliminate_lvs(struct logical_volume *lv, - fn_on_lv_t fn_pre_on_lv = NULL, fn_post_on_lv; - void *fn_pre_data, *fn_post_data = NULL; - struct dm_list *removal_lvs; -+ const struct logical_volume *lock_lv = lv_lock_holder(lv); - - va_start(ap, origin_only); - removal_lvs = va_arg(ap, struct dm_list *); - -+ if (lock_lv != lv) { -+ log_debug_activation("Dropping origin_only for %s as lock holds %s", -+ display_lvname(lv), display_lvname(lock_lv)); -+ origin_only = 0; -+ } -+ -+ /* TODO/FIXME: this function should be simplified to just call -+ * lv_update_and_reload() and cleanup of remained LVs */ -+ - /* Retrieve post/pre functions and post/pre data reference from variable arguments, if any */ - if ((fn_post_on_lv = va_arg(ap, fn_on_lv_t))) { - fn_post_data = va_arg(ap, void *); -@@ -545,11 +573,13 @@ static int _lv_update_reload_fns_reset_eliminate_lvs(struct logical_volume *lv, - fn_pre_data = va_arg(ap, void *); - } - -+ va_end(ap); -+ - /* Call any fn_pre_on_lv before the first update and reload call (e.g. to rename LVs) */ - /* returns 1: ok+ask caller to update, 2: metadata commited+ask caller to resume */ - if (fn_pre_on_lv && !(r = fn_pre_on_lv(lv, fn_pre_data))) { - log_error(INTERNAL_ERROR "Pre callout function failed."); -- goto err; -+ return 0; - } - - if (r == 2) { -@@ -557,19 +587,19 @@ static int _lv_update_reload_fns_reset_eliminate_lvs(struct logical_volume *lv, - * Returning 2 from pre function -> lv is suspended and - * metadata got updated, don't need to do it again - */ -- if (!(r = (origin_only ? resume_lv_origin(lv->vg->cmd, lv_lock_holder(lv)) : -- resume_lv(lv->vg->cmd, lv_lock_holder(lv))))) { -+ if (!(r = (origin_only ? resume_lv_origin(lv->vg->cmd, lock_lv) : -+ resume_lv(lv->vg->cmd, lock_lv)))) { - log_error("Failed to resume %s.", display_lvname(lv)); -- goto err; -+ return 0; - } - - /* Update metadata and reload mappings including flags (e.g. LV_REBUILD, LV_RESHAPE_DELTA_DISKS_PLUS) */ - } else if (!(r = (origin_only ? lv_update_and_reload_origin(lv) : lv_update_and_reload(lv)))) -- goto err; -+ return_0; - - /* Eliminate any residual LV and don't commit the metadata */ - if (!(r = _eliminate_extracted_lvs_optional_write_vg(lv->vg, removal_lvs, 0))) -- goto err; -+ return_0; - - /* - * Now that any 'REBUILD' or 'RESHAPE_DELTA_DISKS' etc. -@@ -582,25 +612,22 @@ static int _lv_update_reload_fns_reset_eliminate_lvs(struct logical_volume *lv, - */ - log_debug_metadata("Clearing any flags for %s passed to the kernel.", display_lvname(lv)); - if (!(r = _reset_flags_passed_to_kernel(lv, &flags_reset))) -- goto err; -+ return_0; - - /* Call any @fn_post_on_lv before the second update call (e.g. to rename LVs back) */ - if (fn_post_on_lv && !(r = fn_post_on_lv(lv, fn_post_data))) { - log_error("Post callout function failed."); -- goto err; -+ return 0; - } - - /* Update and reload to clear out reset flags in the metadata and in the kernel */ - log_debug_metadata("Updating metadata mappings for %s.", display_lvname(lv)); - if ((r != 2 || flags_reset) && !(r = (origin_only ? lv_update_and_reload_origin(lv) : lv_update_and_reload(lv)))) { - log_error(INTERNAL_ERROR "Update of LV %s failed.", display_lvname(lv)); -- goto err; -+ return 0; - } - -- r = 1; --err: -- va_end(ap); -- return r; -+ return 1; - } - - /* -@@ -622,6 +649,12 @@ static int _lv_update_and_reload_list(struct logical_volume *lv, int origin_only - struct lv_list *lvl; - int r; - -+ if (lock_lv != lv) { -+ log_debug_activation("Dropping origin_only for %s as lock holds %s", -+ display_lvname(lv), display_lvname(lock_lv)); -+ origin_only = 0; -+ } -+ - log_very_verbose("Updating logical volume %s on disk(s)%s.", - display_lvname(lock_lv), origin_only ? " (origin only)": ""); - -@@ -879,7 +912,7 @@ static int _reorder_raid10_near_seg_areas(struct lv_segment *seg, enum raid0_rai - break; - - default: -- return 0; -+ return_0; - } - - /* Sort areas */ -@@ -1558,7 +1591,7 @@ static int _lv_alloc_reshape_space(struct logical_volume *lv, - lv->size = lv_size_cur; - /* pay attention to lv_extend maybe having allocated more because of layout specific rounding */ - if (!_lv_set_reshape_len(lv, _lv_total_rimage_len(lv) - prev_rimage_len)) -- return 0; -+ return_0; - } - - /* Preset data offset in case we fail relocating reshape space below */ -@@ -1635,7 +1668,7 @@ static int _lv_free_reshape_space_with_status(struct logical_volume *lv, enum al - seg->extents_copied = first_seg(lv)->area_len; - - if (!_lv_set_reshape_len(lv, 0)) -- return 0; -+ return_0; - - /* - * Only in case reshape space was freed at the beginning, -@@ -1689,7 +1722,7 @@ static int _reshaped_state(struct logical_volume *lv, const unsigned dev_count, - return_0; - - if (!_get_dev_health(lv, &kernel_devs, devs_health, devs_in_sync, NULL)) -- return 0; -+ return_0; - - if (kernel_devs == dev_count) - return 1; -@@ -1740,7 +1773,7 @@ static int _reshape_adjust_to_size(struct logical_volume *lv, - uint32_t new_le_count; - - if (!_lv_reshape_get_new_len(lv, old_image_count, new_image_count, &new_le_count)) -- return 0; -+ return_0; - - /* Externally visible LV size w/o reshape space */ - lv->le_count = seg->len = new_le_count; -@@ -1803,7 +1836,7 @@ static int _raid_reshape_add_images(struct logical_volume *lv, - } - - if (!_lv_reshape_get_new_len(lv, old_image_count, new_image_count, &grown_le_count)) -- return 0; -+ return_0; - - current_le_count = lv->le_count - _reshape_len_per_lv(lv); - grown_le_count -= _reshape_len_per_dev(seg) * _data_rimages_count(seg, new_image_count); -@@ -1828,7 +1861,7 @@ static int _raid_reshape_add_images(struct logical_volume *lv, - new_image_count - old_image_count, new_image_count - old_image_count > 1 ? "s" : "", - display_lvname(lv)); - if (!_lv_raid_change_image_count(lv, 1, new_image_count, allocate_pvs, NULL, 0, 0)) -- return 0; -+ return_0; - - /* Reshape adding image component pairs -> change sizes/counters accordingly */ - if (!_reshape_adjust_to_size(lv, old_image_count, new_image_count)) { -@@ -1839,7 +1872,7 @@ static int _raid_reshape_add_images(struct logical_volume *lv, - /* Allocate forward out of place reshape space at the beginning of all data image LVs */ - log_debug_metadata("(Re)allocating reshape space for %s.", display_lvname(lv)); - if (!_lv_alloc_reshape_space(lv, alloc_begin, NULL, allocate_pvs)) -- return 0; -+ return_0; - - /* - * Reshape adding image component pairs: -@@ -1914,7 +1947,7 @@ static int _raid_reshape_remove_images(struct logical_volume *lv, - } - - if (!_lv_reshape_get_new_len(lv, old_image_count, new_image_count, &reduced_le_count)) -- return 0; -+ return_0; - - reduced_le_count -= seg->reshape_len * _data_rimages_count(seg, new_image_count); - current_le_count = lv->le_count - seg->reshape_len * _data_rimages_count(seg, old_image_count); -@@ -1936,7 +1969,7 @@ static int _raid_reshape_remove_images(struct logical_volume *lv, - new_stripes, display_lvname(lv)); - - if (!force) { -- log_warn("WARNING: Can't remove stripes without --force option."); -+ log_error("Can't remove stripes without --force option."); - return 0; - } - -@@ -1952,7 +1985,7 @@ static int _raid_reshape_remove_images(struct logical_volume *lv, - * to remove disks from a raid set - */ - if (!_lv_alloc_reshape_space(lv, alloc_end, NULL, allocate_pvs)) -- return 0; -+ return_0; - - /* Flag all disks past new images as delta disks minus to kernel */ - for (s = new_image_count; s < old_image_count; s++) -@@ -1998,7 +2031,7 @@ static int _raid_reshape_remove_images(struct logical_volume *lv, - old_image_count - new_image_count, old_image_count - new_image_count > 1 ? "s" : "", - display_lvname(lv)); - if (!_lv_raid_change_image_count(lv, 1, new_image_count, allocate_pvs, removal_lvs, 0, 0)) -- return 0; -+ return_0; - - seg->area_count = new_image_count; - break; -@@ -2069,7 +2102,7 @@ static int _raid_reshape_keep_images(struct logical_volume *lv, - - if (alloc_reshape_space && - !_lv_alloc_reshape_space(lv, where, NULL, allocate_pvs)) -- return 0; -+ return_0; - - seg->segtype = new_segtype; - -@@ -2084,15 +2117,22 @@ static int _vg_write_lv_suspend_commit_backup(struct volume_group *vg, - struct logical_volume *lv, - int origin_only, int do_backup) - { -+ const struct logical_volume *lock_lv = lv_lock_holder(lv); - int r = 1; - -+ if (lock_lv != lv) { -+ log_debug_activation("Dropping origin_only for %s as lock holds %s", -+ display_lvname(lv), display_lvname(lock_lv)); -+ origin_only = 0; -+ } -+ - if (!vg_write(vg)) { - log_error("Write of VG %s failed.", vg->name); - return_0; - } - -- if (lv && !(r = (origin_only ? suspend_lv_origin(vg->cmd, lv_lock_holder(lv)) : -- suspend_lv(vg->cmd, lv_lock_holder(lv))))) { -+ if (lv && !(r = (origin_only ? suspend_lv_origin(vg->cmd, lock_lv) : -+ suspend_lv(vg->cmd, lock_lv)))) { - log_error("Failed to suspend %s before committing changes.", - display_lvname(lv)); - vg_revert(lv->vg); -@@ -2133,24 +2173,6 @@ static int _activate_sub_lv_excl_local(struct logical_volume *lv) - return 1; - } - --/* Helper: function to activate any sub LVs of @lv exclusively local starting with area indexed by @start_idx */ --static int _activate_sub_lvs_excl_local(struct logical_volume *lv, uint32_t start_idx) --{ -- uint32_t s; -- struct lv_segment *seg = first_seg(lv); -- -- /* seg->area_count may be 0 here! */ -- log_debug_metadata("Activating %u image component%s of LV %s.", -- seg->area_count - start_idx, seg->meta_areas ? " pairs" : "s", -- display_lvname(lv)); -- for (s = start_idx; s < seg->area_count; s++) -- if (!_activate_sub_lv_excl_local(seg_lv(seg, s)) || -- (seg->meta_areas && !_activate_sub_lv_excl_local(seg_metalv(seg, s)))) -- return_0; -- -- return 1; --} -- - /* Helper: function to activate any LVs on @lv_list */ - static int _activate_sub_lvs_excl_local_list(struct logical_volume *lv, struct dm_list *lv_list) - { -@@ -2169,20 +2191,6 @@ static int _activate_sub_lvs_excl_local_list(struct logical_volume *lv, struct d - return r; - } - --/* Helper: callback function to activate image component pairs of @lv to update size after reshape space allocation */ --static int _pre_raid_reactivate_legs(struct logical_volume *lv, void *data) --{ -- if (!_vg_write_lv_suspend_vg_commit(lv, 1)) -- return 0; -- -- /* Reload any changed image component pairs for out-of-place reshape space */ -- if (!_activate_sub_lvs_excl_local(lv, 0)) -- return 0; -- -- /* 1: ok+ask caller to update, 2: metadata commited+ask caller to resume */ -- return 2; --} -- - /* Helper: callback function to activate any rmetas on @data list */ - __attribute__ ((__unused__)) - static int _pre_raid0_remove_rmeta(struct logical_volume *lv, void *data) -@@ -2190,26 +2198,12 @@ static int _pre_raid0_remove_rmeta(struct logical_volume *lv, void *data) - struct dm_list *lv_list = data; - - if (!_vg_write_lv_suspend_vg_commit(lv, 1)) -- return 0; -+ return_0; - - /* 1: ok+ask caller to update, 2: metadata commited+ask caller to resume */ - return _activate_sub_lvs_excl_local_list(lv, lv_list) ? 2 : 0; - } - --/* Helper: callback dummy needed for takeover+reshape */ --static int _post_raid_reshape(struct logical_volume *lv, void *data) --{ -- /* 1: ask caller to update, 2: don't ask caller to update */ -- return 1; --} -- --/* Helper: callback dummy needed for takeover+reshape */ --static int _post_raid_takeover(struct logical_volume *lv, void *data) --{ -- /* 1: ask caller to update, 2: don't ask caller to update */ -- return 2; --} -- - /* - * Reshape logical volume @lv by adding/removing stripes - * (absolute new stripes given in @new_stripes), changing -@@ -2251,7 +2245,7 @@ static int _raid_reshape(struct logical_volume *lv, - return_0; - - if (!_check_region_size_constraints(lv, new_segtype, new_region_size, new_stripe_size)) -- return 0; -+ return_0; - - if (!_raid_in_sync(lv)) { - log_error("Unable to convert %s while it is not in-sync.", -@@ -2346,30 +2340,18 @@ static int _raid_reshape(struct logical_volume *lv, - - /* Handle disk addition reshaping */ - if (old_image_count < new_image_count) { -- /* FIXME: remove once MD kernel rhbz1443999 got fixed. */ -- if (sysconf(_SC_NPROCESSORS_ONLN) < 2) { -- log_error("Can't add stripes to LV %s on single core.", display_lvname(lv)); -- return 0; -- } -- - if (!_raid_reshape_add_images(lv, new_segtype, yes, - old_image_count, new_image_count, - new_stripes, new_stripe_size, allocate_pvs)) -- return 0; -+ return_0; - - /* Handle disk removal reshaping */ - } else if (old_image_count > new_image_count) { -- /* FIXME: remove once MD kernel rhbz1443999 got fixed. */ -- if (sysconf(_SC_NPROCESSORS_ONLN) < 2) { -- log_error("Can't remove stripes from LV %s on single core.", display_lvname(lv)); -- return 0; -- } -- - if (!_raid_reshape_remove_images(lv, new_segtype, yes, force, - old_image_count, new_image_count, - new_stripes, new_stripe_size, - allocate_pvs, &removal_lvs)) -- return 0; -+ return_0; - - /* - * Handle raid set layout reshaping w/o changing # of legs (allocation algorithm or stripe size change) -@@ -2377,20 +2359,22 @@ static int _raid_reshape(struct logical_volume *lv, - */ - } else if (!_raid_reshape_keep_images(lv, new_segtype, yes, force, &force_repair, - new_data_copies, new_stripe_size, allocate_pvs)) -- return 0; -+ return_0; - - /* HM FIXME: workaround for not resetting "nosync" flag */ - init_mirror_in_sync(0); - - seg->region_size = new_region_size; - -+ /* https://bugzilla.redhat.com/1447812 also check open count */ -+ if (!_check_lv_open_count(lv, 1)) -+ return_0; -+ - if (seg->area_count != 2 || old_image_count != seg->area_count) { -- if (!_lv_update_reload_fns_reset_eliminate_lvs(lv, 0, &removal_lvs, -- _post_raid_reshape, NULL, -- _pre_raid_reactivate_legs, NULL)) -- return 0; -+ if (!_lv_update_reload_fns_reset_eliminate_lvs(lv, 0, &removal_lvs, NULL)) -+ return_0; - } if (!_vg_write_commit_backup(lv->vg)) -- return 0; -+ return_0; - - return 1; - /* FIXME force_repair ? _lv_cond_repair(lv) : 1; */ -@@ -2565,14 +2549,6 @@ static int _raid_add_images_without_commit(struct logical_volume *lv, - return 0; - } - -- if (lv_is_active(lv_lock_holder(lv)) && -- (old_count == 1) && -- (lv_is_thin_pool_data(lv) || lv_is_thin_pool_metadata(lv))) { -- log_error("Can't add image to active thin pool LV %s yet. Deactivate first.", -- display_lvname(lv)); -- return 0; -- } -- - if (!archive(lv->vg)) - return_0; - -@@ -3233,11 +3209,13 @@ int lv_raid_split(struct logical_volume *lv, int yes, const char *split_name, - } - - /* Split on a 2-legged raid1 LV causes losing all resilience */ -- if (new_count == 1 && -- !yes && yes_no_prompt("Are you sure you want to split %s LV %s losing all resilience? [y/n]: ", -- lvseg_name(first_seg(lv)), display_lvname(lv)) == 'n') { -- log_error("Logical volume %s NOT split.", display_lvname(lv)); -- return 0; -+ if (new_count == 1) { -+ if (!yes && yes_no_prompt("Are you sure you want to split %s LV %s losing all resilience? [y/n]: ", -+ lvseg_name(first_seg(lv)), display_lvname(lv)) == 'n') { -+ log_error("Logical volume %s NOT split.", display_lvname(lv)); -+ return 0; -+ } -+ log_verbose("Losing all resilience for logical volume %s.", display_lvname(lv)); - } - - /* -@@ -3375,11 +3353,14 @@ int lv_raid_split_and_track(struct logical_volume *lv, - } - - /* Split and track changes on a 2-legged raid1 LV causes losing resilience for newly written data. */ -- if (seg->area_count == 2 && -- !yes && yes_no_prompt("Are you sure you want to split and track %s LV %s losing resilience for any newly written data? [y/n]: ", -- lvseg_name(seg), display_lvname(lv)) == 'n') { -- log_error("Logical volume %s NOT split.", display_lvname(lv)); -- return 0; -+ if (seg->area_count == 2) { -+ if (!yes && yes_no_prompt("Are you sure you want to split and track %s LV %s losing resilience for any newly written data? [y/n]: ", -+ lvseg_name(seg), display_lvname(lv)) == 'n') { -+ log_error("Logical volume %s NOT split.", display_lvname(lv)); -+ return 0; -+ } -+ log_verbose("Losing resilience for newly written data on logical volume %s.", -+ display_lvname(lv)); - } - - for (s = seg->area_count - 1; s >= 0; --s) { -@@ -3408,7 +3389,7 @@ int lv_raid_split_and_track(struct logical_volume *lv, - return_0; - - if (seg->area_count == 2) -- log_warn("Any newly written data will be non-resilient on LV %s during the split!", -+ log_warn("WARNING: Any newly written data will be non-resilient on LV %s during the split!", - display_lvname(lv)); - - log_print_unless_silent("Use 'lvconvert --merge %s' to merge back into %s.", -@@ -3568,7 +3549,7 @@ static int _add_image_component_list(struct lv_segment *seg, int delete_from_lis - if (delete_from_list) - dm_list_del(&lvl->list); - if (!_add_component_lv(seg, lvl->lv, lv_flags, s++)) -- return 0; -+ return_0; - } - - return 1; -@@ -3674,7 +3655,7 @@ static int _extract_image_component_sublist(struct lv_segment *seg, - - for (s = idx; s < end; s++) { - if (!_extract_image_component_error_seg(seg, type, s, &lvl->lv, error_seg)) -- return 0; -+ return_0; - - dm_list_add(removal_lvs, &lvl->list); - lvl++; -@@ -3831,7 +3812,7 @@ static int _raid0_add_or_remove_metadata_lvs(struct logical_volume *lv, - new_raid_type_flag = SEG_RAID0; - } else { - if (!_alloc_and_add_rmeta_devs_for_lv(lv, allocate_pvs)) -- return 0; -+ return_0; - - new_raid_type_flag = SEG_RAID0_META; - } -@@ -4002,7 +3983,6 @@ static int _convert_raid1_to_mirror(struct logical_volume *lv, - uint32_t new_image_count, - uint32_t new_region_size, - struct dm_list *allocate_pvs, -- int update_and_reload, - struct dm_list *removal_lvs) - { - struct logical_volume *log_lv; -@@ -4042,14 +4022,14 @@ static int _convert_raid1_to_mirror(struct logical_volume *lv, - /* Remove rmeta LVs */ - log_debug_metadata("Extracting and renaming metadata LVs."); - if (!_extract_image_component_list(seg, RAID_META, 0, removal_lvs)) -- return 0; -+ return_0; - - seg->meta_areas = NULL; - - /* Rename all data sub LVs from "*_rimage_*" to "*_mimage_*" and set their status */ - log_debug_metadata("Adjust data LVs of %s.", display_lvname(lv)); - if (!_adjust_data_lvs(lv, RAID1_TO_MIRROR)) -- return 0; -+ return_0; - - seg->segtype = new_segtype; - seg->region_size = new_region_size; -@@ -4059,7 +4039,10 @@ static int _convert_raid1_to_mirror(struct logical_volume *lv, - if (!attach_mirror_log(first_seg(lv), log_lv)) - return_0; - -- return update_and_reload ? _lv_update_reload_fns_reset_eliminate_lvs(lv, 0, removal_lvs, NULL) : 1; -+ if (!_lv_update_reload_fns_reset_eliminate_lvs(lv, 0, removal_lvs, NULL)) -+ return_0; -+ -+ return 1; - } - - /* -@@ -4543,7 +4526,7 @@ static int _process_type_flags(const struct logical_volume *lv, struct possible_ - !(t & seg->segtype->flags) && - ((segtype = get_segtype_from_flag(lv->vg->cmd, t)))) - if (!tfn(processed_segtypes, data ? : (void *) segtype)) -- return 0; -+ return_0; - } - - return 1; -@@ -4794,7 +4777,7 @@ static int _raid1_to_mirrored_wrapper(TAKEOVER_FN_ARGS) - return_0; - - return _convert_raid1_to_mirror(lv, new_segtype, new_image_count, new_region_size, -- allocate_pvs, 1, &removal_lvs); -+ allocate_pvs, &removal_lvs); - } - - /* -@@ -4874,7 +4857,7 @@ static int _clear_meta_lvs(struct logical_volume *lv) - dm_list_iterate_items(lvl, &meta_lvs) { - lv_set_hidden(lvl->lv); - if (!set_lv_segment_area_lv(seg, s++, lvl->lv, 0, RAID_META)) -- return 0; -+ return_0; - } - - return 1; -@@ -5028,7 +5011,7 @@ static int _raid45_to_raid54_wrapper(TAKEOVER_FN_ARGS) - - /* Shift parity SubLV pair "PDD..." <-> "DD...P" on raid4 <-> raid5_n conversion */ - if( !_shift_parity_dev(seg)) -- return 0; -+ return_0; - - /* Don't resync */ - init_mirror_in_sync(1); -@@ -5068,7 +5051,7 @@ static int _takeover_downconvert_wrapper(TAKEOVER_FN_ARGS) - } - - if (!_check_region_size_constraints(lv, new_segtype, new_region_size, new_stripe_size)) -- return 0; -+ return_0; - - if (seg_is_any_raid10(seg) && (seg->area_count % seg->data_copies)) { - log_error("Can't convert %s LV %s to %s with odd number of stripes.", -@@ -5113,12 +5096,12 @@ static int _takeover_downconvert_wrapper(TAKEOVER_FN_ARGS) - if (seg_is_raid4(seg)) { - /* Shift parity SubLV pair "PDD..." -> "DD...P" to be able to remove it off the end */ - if (!_shift_parity_dev(seg)) -- return 0; -+ return_0; - - } else if (seg_is_raid10_near(seg)) { - log_debug_metadata("Reordering areas for raid10 -> raid0 takeover."); - if (!_reorder_raid10_near_seg_areas(seg, reorder_from_raid10_near)) -- return 0; -+ return_0; - } - - if (segtype_is_any_raid0(new_segtype) && -@@ -5133,7 +5116,7 @@ static int _takeover_downconvert_wrapper(TAKEOVER_FN_ARGS) - lv_raid_image_count(lv) - new_image_count, - display_lvname(lv)); - if (!_lv_raid_change_image_count(lv, 1, new_image_count, allocate_pvs, &removal_lvs, 0, 0)) -- return 0; -+ return_0; - - seg->area_count = new_image_count; - } -@@ -5283,7 +5266,7 @@ static int _takeover_upconvert_wrapper(TAKEOVER_FN_ARGS) - } - - if (!_check_region_size_constraints(lv, new_segtype, new_region_size, new_stripe_size)) -- return 0; -+ return_0; - - /* Archive metadata */ - if (!archive(lv->vg)) -@@ -5304,7 +5287,7 @@ static int _takeover_upconvert_wrapper(TAKEOVER_FN_ARGS) - if (seg_is_raid0(seg)) { - log_debug_metadata("Adding metadata LVs to %s.", display_lvname(lv)); - if (!_raid0_add_or_remove_metadata_lvs(lv, 0 /* update_and_reload */, allocate_pvs, NULL)) -- return 0; -+ return_0; - } - - /* Have to be cleared in conversion from raid0_meta -> raid4 or kernel will reject due to reordering disks */ -@@ -5354,7 +5337,7 @@ static int _takeover_upconvert_wrapper(TAKEOVER_FN_ARGS) - if (!_eliminate_extracted_lvs(lv->vg, &removal_lvs)) /* Updates vg */ - return_0; - -- return 0; -+ return_0; - } - - seg = first_seg(lv); -@@ -5384,11 +5367,11 @@ static int _takeover_upconvert_wrapper(TAKEOVER_FN_ARGS) - - if (!_raid45_to_raid54_wrapper(lv, raid5_n_segtype, 1 /* yes */, force, seg->area_count, - 1 /* data_copies */, 0, 0, 0, allocate_pvs)) -- return 0; -+ return_0; - - if (!_drop_suffix(meta_lv->name, "_extracted") || - !_drop_suffix(data_lv->name, "_extracted")) -- return 0; -+ return_0; - - data_lv->status |= RAID_IMAGE; - meta_lv->status |= RAID_META; -@@ -5403,7 +5386,7 @@ static int _takeover_upconvert_wrapper(TAKEOVER_FN_ARGS) - } else if (segtype_is_raid5_n(new_segtype) && - !_raid45_to_raid54_wrapper(lv, raid5_n_segtype, yes, force, seg->area_count, - 1 /* data_copies */, 0, 0, 0, allocate_pvs)) -- return 0; -+ return_0; - } - - seg->data_copies = new_data_copies; -@@ -5419,7 +5402,7 @@ static int _takeover_upconvert_wrapper(TAKEOVER_FN_ARGS) - - log_debug_metadata("Reordering areas for raid0 -> raid10_near takeover."); - if (!_reorder_raid10_near_seg_areas(seg, reorder_to_raid10_near)) -- return 0; -+ return_0; - /* Set rebuild flags accordingly */ - for (s = 0; s < seg->area_count; s++) { - seg_lv(seg, s)->status &= ~LV_REBUILD; -@@ -5436,10 +5419,8 @@ static int _takeover_upconvert_wrapper(TAKEOVER_FN_ARGS) - - log_debug_metadata("Updating VG metadata and reloading %s LV %s.", - lvseg_name(seg), display_lvname(lv)); -- if (!_lv_update_reload_fns_reset_eliminate_lvs(lv, 0, &removal_lvs, -- _post_raid_takeover, NULL, -- _pre_raid_reactivate_legs, NULL)) -- return 0; -+ if (!_lv_update_reload_fns_reset_eliminate_lvs(lv, 0, &removal_lvs, NULL)) -+ return_0; - - if (segtype_is_raid4(new_segtype) && - seg->area_count != 2) { -@@ -5975,7 +5956,7 @@ static int _set_convenient_raid145610_segtype_to(const struct lv_segment *seg_fr - /* raid1 -> */ - } else if (seg_is_raid1(seg_from) && !segtype_is_mirror(*segtype)) { - if (seg_from->area_count != 2) { -- log_warn("Convert %s LV %s to 2 images first.", -+ log_error("Convert %s LV %s to 2 images first.", - lvseg_name(seg_from), display_lvname(seg_from->lv)); - return 0; - -@@ -5991,8 +5972,8 @@ static int _set_convenient_raid145610_segtype_to(const struct lv_segment *seg_fr - } else if (seg_is_raid4(seg_from) || seg_is_any_raid5(seg_from)) { - if (segtype_is_raid1(*segtype) && - seg_from->area_count != 2) { -- log_warn("Convert %s LV %s to 2 stripes first (i.e. --stripes 1).", -- lvseg_name(seg_from), display_lvname(seg_from->lv)); -+ log_error("Convert %s LV %s to 2 stripes first (i.e. --stripes 1).", -+ lvseg_name(seg_from), display_lvname(seg_from->lv)); - return 0; - - } else if (seg_is_raid4(seg_from) && -@@ -6007,8 +5988,8 @@ static int _set_convenient_raid145610_segtype_to(const struct lv_segment *seg_fr - - else if (segtype_is_raid10(*segtype)) { - if (seg_from->area_count < 3) { -- log_warn("Convert %s LV %s to minimum 3 stripes first (i.e. --stripes 2).", -- lvseg_name(seg_from), display_lvname(seg_from->lv)); -+ log_error("Convert %s LV %s to minimum 3 stripes first (i.e. --stripes 2).", -+ lvseg_name(seg_from), display_lvname(seg_from->lv)); - return 0; - } - -@@ -6016,8 +5997,8 @@ static int _set_convenient_raid145610_segtype_to(const struct lv_segment *seg_fr - - } else if (segtype_is_any_raid6(*segtype)) { - if (seg_from->area_count < 4) { -- log_warn("Convert %s LV %s to minimum 4 stripes first (i.e. --stripes 3).", -- lvseg_name(seg_from), display_lvname(seg_from->lv)); -+ log_error("Convert %s LV %s to minimum 4 stripes first (i.e. --stripes 3).", -+ lvseg_name(seg_from), display_lvname(seg_from->lv)); - return 0; - - } else if (seg_is_raid4(seg_from) && !segtype_is_raid6_n_6(*segtype)) -@@ -6053,12 +6034,12 @@ static int _set_convenient_raid145610_segtype_to(const struct lv_segment *seg_fr - /* -> raid1 */ - } else if (!seg_is_mirror(seg_from) && segtype_is_raid1(*segtype)) { - if (!seg_is_raid4(seg_from) && !seg_is_any_raid5(seg_from)) { -- log_warn("Convert %s LV %s to raid4/raid5 first.", -- lvseg_name(seg_from), display_lvname(seg_from->lv)); -+ log_error("Convert %s LV %s to raid4/raid5 first.", -+ lvseg_name(seg_from), display_lvname(seg_from->lv)); - return 0; - - } else if (seg_from->area_count != 2) { -- log_warn("Convert %s LV %s to 2 stripes first (i.e. --stripes 1).", -+ log_error("Convert %s LV %s to 2 stripes first (i.e. --stripes 1).", - lvseg_name(seg_from), display_lvname(seg_from->lv)); - return 0; - -@@ -6113,7 +6094,7 @@ static int _region_size_change_requested(struct logical_volume *lv, int yes, con - } - - if (!_check_region_size_constraints(lv, seg->segtype, region_size, seg->stripe_size)) -- return 0; -+ return_0; - - if (!_raid_in_sync(lv)) { - log_error("Unable to change region size on %s LV %s while it is not in-sync.", -@@ -6224,6 +6205,27 @@ static int _conversion_options_allowed(const struct lv_segment *seg_from, - return r; - } - -+/* https://bugzilla.redhat.com/1447812 try opening LV exclusively */ -+static int _lv_open_excl(struct logical_volume *lv, struct device **dev) { -+ char *dev_path; -+ size_t sz = strlen(lv->vg->cmd->dev_dir) + strlen(lv->vg->name) + strlen(lv->name) + 2; -+ -+ *dev = NULL; -+ if (!(dev_path = dm_pool_alloc(lv->vg->cmd->mem, sz))) -+ return_0; -+ if (dm_snprintf(dev_path, sz, "%s%s/%s", lv->vg->cmd->dev_dir, lv->vg->name, lv->name) < 0) -+ return_0; -+ if (!(*dev = dev_create_file(dev_path, NULL, NULL, 0))) -+ return_0; -+ if (!dev_open_flags(*dev, O_EXCL, 1, 1)) { -+ log_error("Reshape is only supported when %s is not in use (e.g. unmount filesystem).", -+ display_lvname(lv)); -+ return 0; -+ } -+ -+ return 1; -+} -+ - /* - * lv_raid_convert - * -@@ -6273,6 +6275,7 @@ int lv_raid_convert(struct logical_volume *lv, - uint32_t region_size; - uint32_t data_copies = seg->data_copies; - uint32_t available_slvs, removed_slvs; -+ struct device *dev; - takeover_fn_t takeover_fn; - - /* FIXME If not active, prompt and activate */ -@@ -6282,6 +6285,12 @@ int lv_raid_convert(struct logical_volume *lv, - log_error("%s must be active to perform this operation.", - display_lvname(lv)); - return 0; -+ } else if (vg_is_clustered(lv->vg) && -+ !lv_is_active_exclusive_locally(lv_lock_holder(lv))) { -+ /* In clustered VGs, the LV must be active on this node exclusively. */ -+ log_error("%s must be active exclusive locally to " -+ "perform this operation.", display_lvname(lv)); -+ return 0; - } - - new_segtype = new_segtype ? : seg->segtype; -@@ -6318,6 +6327,12 @@ int lv_raid_convert(struct logical_volume *lv, - new_stripes, new_stripe_size_supplied)) - return _log_possible_conversion_types(lv, new_segtype); - -+ /* https://bugzilla.redhat.com/1439399 */ -+ if (lv_is_origin(lv)) { -+ log_error("Can't convert snapshot origin %s.", display_lvname(lv)); -+ return 0; -+ } -+ - /* - * reshape of capable raid type requested - */ -@@ -6325,13 +6340,31 @@ int lv_raid_convert(struct logical_volume *lv, - case 0: - break; - case 1: -+ /* Conversion of reshapable raids is the cluster is not supported yet. */ -+ if (locking_is_clustered()) { -+ log_error("Conversion of %s not supported in the cluster.", display_lvname(lv)); -+ return 0; -+ } -+ -+ /* https://bugzilla.redhat.com/1447812 reject reshape on open LV */ -+ if (!_check_lv_open_count(lv, 0)) -+ return_0; -+ if (!_lv_open_excl(lv, &dev)) -+ return_0; -+ if (!_check_lv_open_count(lv, 1)) { -+ dev_close(dev); -+ return_0; -+ } -+ - if (!_raid_reshape(lv, new_segtype, yes, force, - data_copies, region_size, - stripes, stripe_size, allocate_pvs)) { -+ dev_close(dev); - log_error("Reshape request failed on LV %s.", display_lvname(lv)); - return 0; - } - -+ dev_close(dev); - return 1; - case 2: - log_error("Invalid conversion request on %s.", display_lvname(lv)); -@@ -6344,7 +6377,8 @@ int lv_raid_convert(struct logical_volume *lv, - - /* Prohibit any takeover in case sub LVs to be removed still exist after a previous reshape */ - if (!_get_available_removed_sublvs(lv, &available_slvs, &removed_slvs)) -- return 0; -+ return_0; -+ - if (removed_slvs) { - log_error("Can't convert %s LV %s to %s containing sub LVs to remove after a reshape.", - lvseg_name(seg), display_lvname(lv), new_segtype->name); -@@ -6387,13 +6421,6 @@ int lv_raid_convert(struct logical_volume *lv, - (segtype_is_striped_target(new_segtype) && - (new_stripes == 1)) ? SEG_TYPE_NAME_LINEAR : new_segtype->name); - -- /* In clustered VGs, the LV must be active on this node exclusively. */ -- if (vg_is_clustered(lv->vg) && !lv_is_active_exclusive_locally(lv)) { -- log_error("%s must be active exclusive locally to " -- "perform this operation.", display_lvname(lv)); -- return 0; -- } -- - /* LV must be in sync. */ - if (!_raid_in_sync(lv)) { - log_error("Unable to convert %s while it is not in-sync.", -@@ -6634,6 +6661,11 @@ static int _lv_raid_rebuild_or_replace(struct logical_volume *lv, - } - - if (!match_count) { -+ if (remove_pvs && !dm_list_empty(remove_pvs)) { -+ log_error("Logical volume %s does not contain devices specified to %s.", -+ display_lvname(lv), action_str); -+ return 0; -+ } - log_print_unless_silent("%s does not contain devices specified to %s.", - display_lvname(lv), action_str); - return 1; -diff --git a/lib/raid/raid.c b/lib/raid/raid.c -index 8a53d7e..c5cfb0f 100644 ---- a/lib/raid/raid.c -+++ b/lib/raid/raid.c -@@ -358,36 +358,21 @@ static int _raid_target_percent(void **target_state, - uint64_t *total_numerator, - uint64_t *total_denominator) - { -- int i; -- uint64_t numerator, denominator; -- char *pos = params; -- /* -- * Status line: -- * <#devs> / -- * Example: -- * raid1 2 AA 1024000/1024000 -- */ -- for (i = 0; i < 3; i++) { -- pos = strstr(pos, " "); -- if (pos) -- pos++; -- else -- break; -- } -- if (!pos || (sscanf(pos, FMTu64 "/" FMTu64 "%n", &numerator, &denominator, &i) != 2) || -- !denominator) { -- log_error("Failed to parse %s status fraction: %s", -- (seg) ? seg->segtype->name : "segment", params); -- return 0; -- } -+ struct dm_status_raid *sr; -+ -+ if (!dm_get_status_raid(mem, params, &sr)) -+ return_0; - -- *total_numerator += numerator; -- *total_denominator += denominator; -+ *total_numerator += sr->insync_regions; -+ *total_denominator += sr->total_regions; - - if (seg) -- seg->extents_copied = (uint64_t) seg->area_len * dm_make_percent(numerator, denominator) / DM_PERCENT_100; -+ seg->extents_copied = (uint64_t) seg->area_len -+ * dm_make_percent(sr->insync_regions , sr->total_regions) / DM_PERCENT_100; -+ -+ *percent = dm_make_percent(sr->insync_regions, sr->total_regions); - -- *percent = dm_make_percent(numerator, denominator); -+ dm_pool_free(mem, sr); - - return 1; - } -@@ -475,7 +460,7 @@ static int _raid_target_present(struct cmd_context *cmd, - { 1, 7, 0, RAID_FEATURE_RAID0, SEG_TYPE_NAME_RAID0 }, - { 1, 9, 0, RAID_FEATURE_SHRINK, "shrinking" }, - { 1, 9, 0, RAID_FEATURE_NEW_DEVICES_ACCEPT_REBUILD, "rebuild+emptymeta" }, -- { 1, 10, 1, RAID_FEATURE_RESHAPE, "reshaping" }, -+ { 1, 12, 0, RAID_FEATURE_RESHAPE, "reshaping" }, - }; - - static int _raid_checked = 0; -diff --git a/lib/report/report.c b/lib/report/report.c -index d9880b2..f61776e 100644 ---- a/lib/report/report.c -+++ b/lib/report/report.c -@@ -3079,11 +3079,13 @@ static int _copypercent_disp(struct dm_report *rh, - dm_percent_t percent = DM_PERCENT_INVALID; - - /* TODO: just cache passes through lvseg_percent... */ -- if (lv_is_cache(lv) || lv_is_used_cache_pool(lv)) -+ if (lv_is_cache(lv) || lv_is_used_cache_pool(lv) || -+ (!lv_is_merging_origin(lv) && lv_is_raid(lv) && !seg_is_any_raid0(first_seg(lv)))) - percent = lvseg_percent_with_info_and_seg_status(lvdm, PERCENT_GET_DIRTY); -- else if (((lv_is_raid(lv) && !seg_is_any_raid0(first_seg(lv)) && -- lv_raid_percent(lv, &percent)) || -- (lv_is_mirror(lv) && -+ else if (lv_is_raid(lv) && !seg_is_any_raid0(first_seg(lv))) -+ /* old way for percentage when merging snapshot into raid origin */ -+ (void) lv_raid_percent(lv, &percent); -+ else if (((lv_is_mirror(lv) && - lv_mirror_percent(lv->vg->cmd, lv, 0, &percent, NULL))) && - (percent != DM_PERCENT_INVALID)) - percent = copy_percent(lv); -diff --git a/libdm/libdm-targets.c b/libdm/libdm-targets.c -index 1709c2b..6577f07 100644 ---- a/libdm/libdm-targets.c -+++ b/libdm/libdm-targets.c -@@ -99,6 +99,7 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params, - unsigned num_fields; - const char *p, *pp, *msg_fields = ""; - struct dm_status_raid *s = NULL; -+ unsigned a = 0; - - if ((num_fields = _count_fields(params)) < 4) - goto_bad; -@@ -168,6 +169,23 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params, - out: - *status = s; - -+ if (s->insync_regions == s->total_regions) { -+ /* FIXME: kernel gives misleading info here -+ * Trying to recognize a true state */ -+ while (i-- > 0) -+ if (s->dev_health[i] == 'a') -+ a++; /* Count number of 'a' */ -+ -+ if (a && a < s->dev_count) { -+ /* SOME legs are in 'a' */ -+ if (!strcasecmp(s->sync_action, "recover") -+ || !strcasecmp(s->sync_action, "idle")) -+ /* Kernel may possibly start some action -+ * in near-by future, do not report 100% */ -+ s->insync_regions--; -+ } -+ } -+ - return 1; - - bad: -diff --git a/scripts/fsadm.sh b/scripts/fsadm.sh -index ea14efe..adf9b55 100755 ---- a/scripts/fsadm.sh -+++ b/scripts/fsadm.sh -@@ -402,6 +402,7 @@ yes_no() { - while read -r -s -n 1 ANS ; do - case "$ANS" in - "y" | "Y" ) echo y ; return 0 ;; -+ "n" | "N") break ;; - "" ) if [ -t 1 ] ; then - echo y ; return 0 - fi ;; -diff --git a/test/lib/check.sh b/test/lib/check.sh -index 64812fb..5eec936 100644 ---- a/test/lib/check.sh -+++ b/test/lib/check.sh -@@ -411,7 +411,7 @@ raid_leg_status() { - - grep_dmsetup() { - dmsetup $1 $2 | tee out -- grep "${@:3}" out || die "Expected output from dmsetup $1 not found!" -+ grep -q "${@:3}" out || die "Expected output \"${@:3}\" from dmsetup $1 not found!" - } - - #set -x -diff --git a/test/shell/fsadm.sh b/test/shell/fsadm.sh -index ac43900..6eff24a 100644 ---- a/test/shell/fsadm.sh -+++ b/test/shell/fsadm.sh -@@ -131,6 +131,7 @@ if check_missing ext3; then - not fsadm -y --lvresize resize $vg_lv 4M - echo n | not lvresize -L4M -r -n $vg_lv - lvresize -L+20M -r -n $vg_lv -+ lvresize -L-10M -r -y $vg_lv - umount "$mount_dir" - umount "$mount_space_dir" - fscheck_ext3 -diff --git a/test/shell/lvconvert-raid-status-validation.sh b/test/shell/lvconvert-raid-status-validation.sh -new file mode 100644 -index 0000000..d705cc2 ---- /dev/null -+++ b/test/shell/lvconvert-raid-status-validation.sh -@@ -0,0 +1,127 @@ -+####################################################################### -+# This series of tests is meant to validate the correctness of -+# 'dmsetup status' for RAID LVs - especially during various sync action -+# transitions, like: recover, resync, check, repair, idle, reshape, etc -+####################################################################### -+SKIP_WITH_LVMLOCKD=1 -+SKIP_WITH_LVMPOLLD=1 -+ -+export LVM_TEST_LVMETAD_DEBUG_OPTS=${LVM_TEST_LVMETAD_DEBUG_OPTS-} -+ -+. lib/inittest -+ -+# check for version 1.9.0 -+# - it is the point at which linear->raid1 uses "recover" -+aux have_raid 1 9 0 || skip -+ -+aux prepare_pvs 9 -+vgcreate -s 2m $vg $(cat DEVICES) -+ -+########################################### -+# Upconverted RAID1 should never have all 'a's in status output -+########################################### -+aux delay_dev $dev2 0 50 -+lvcreate -aey -l 2 -n $lv1 $vg $dev1 -+lvconvert --type raid1 -y -m 1 $vg/$lv1 $dev2 -+while ! check in_sync $vg $lv1; do -+ a=( $(dmsetup status $vg-$lv1) ) || die "Unable to get status of $vg/$lv1" -+ [ ${a[5]} != "aa" ] -+ sleep .1 -+done -+aux enable_dev $dev2 -+lvremove -ff $vg -+ -+########################################### -+# Upconverted RAID1 should not be at 100% right after upconvert -+########################################### -+aux delay_dev $dev2 0 50 -+lvcreate -aey -l 2 -n $lv1 $vg $dev1 -+lvconvert --type raid1 -y -m 1 $vg/$lv1 $dev2 -+a=( $(dmsetup status $vg-$lv1) ) || die "Unable to get status of $vg/$lv1" -+b=( $(echo ${a[6]} | sed s:/:' ':) ) -+[ ${b[0]} -ne ${b[1]} ] -+aux enable_dev $dev2 -+lvremove -ff $vg -+ -+########################################### -+# Catch anything suspicious with linear -> RAID1 upconvert -+########################################### -+aux delay_dev $dev2 0 50 -+lvcreate -aey -l 2 -n $lv1 $vg $dev1 -+lvconvert --type raid1 -y -m 1 $vg/$lv1 $dev2 -+while true; do -+ a=( $(dmsetup status $vg-$lv1) ) || die "Unable to get status of $vg/$lv1" -+ b=( $(echo ${a[6]} | sed s:/:' ':) ) -+ if [ ${b[0]} -ne ${b[1]} ]; then -+ # If the sync operation ("recover" in this case) is not -+ # finished, then it better be as follows: -+ [ ${a[5]} == "Aa" ] -+ [ ${a[7]} == "recover" ] -+ else -+ # Tough to tell the INVALID case, -+ # Before starting sync thread: "Aa X/X recover" -+ # from the valid case, -+ # Just finished sync thread: "Aa X/X recover" -+ # We'll just put "should" for now -+ should [ ${a[5]} == "AA" ] -+ should [ ${a[7]} == "idle" ] -+ break -+ fi -+ sleep .1 -+done -+aux enable_dev $dev2 -+lvremove -ff $vg -+ -+########################################### -+# Catch anything suspicious with RAID1 2-way -> 3-way upconvert -+########################################### -+aux delay_dev $dev3 0 50 -+lvcreate --type raid1 -m 1 -aey -l 2 -n $lv1 $vg $dev1 $dev2 -+lvconvert -y -m +1 $vg/$lv1 $dev3 -+while true; do -+ a=( $(dmsetup status $vg-$lv1) ) || die "Unable to get status of $vg/$lv1" -+ b=( $(echo ${a[6]} | sed s:/:' ':) ) -+ if [ ${b[0]} -ne ${b[1]} ]; then -+ # If the sync operation ("recover" in this case) is not -+ # finished, then it better be as follows: -+ [ ${a[5]} == "AAa" ] -+ [ ${a[7]} == "recover" ] -+ else -+ # Tough to tell the INVALID case, -+ # Before starting sync thread: "Aa X/X recover" -+ # from the valid case, -+ # Just finished sync thread: "Aa X/X recover" -+ # We'll just put "should" for now -+ should [ ${a[5]} == "AAA" ] -+ should [ ${a[7]} == "idle" ] -+ break -+ fi -+ sleep .1 -+done -+aux enable_dev $dev3 -+lvremove -ff $vg -+ -+########################################### -+# Catch anything suspicious with RAID1 initial resync -+########################################### -+aux delay_dev $dev2 0 50 -+lvcreate --type raid1 -m 1 -aey -l 2 -n $lv1 $vg $dev1 $dev2 -+while true; do -+ a=( $(dmsetup status $vg-$lv1) ) || die "Unable to get status of $vg/$lv1" -+ b=( $(echo ${a[6]} | sed s:/:' ':) ) -+ if [ ${b[0]} -ne ${b[1]} ]; then -+ # If the sync operation ("resync" in this case) is not -+ # finished, then it better be as follows: -+ [ ${a[5]} == "aa" ] -+ [ ${a[7]} == "resync" ] -+ else -+ should [ ${a[5]} == "AA" ] -+ should [ ${a[7]} == "idle" ] -+ break -+ fi -+ sleep .1 -+done -+aux enable_dev $dev2 -+lvremove -ff $vg -+ -+vgremove -ff $vg -diff --git a/test/shell/lvconvert-raid-takeover-alloc-failure.sh b/test/shell/lvconvert-raid-takeover-alloc-failure.sh -index 3870c35..cf926a1 100644 ---- a/test/shell/lvconvert-raid-takeover-alloc-failure.sh -+++ b/test/shell/lvconvert-raid-takeover-alloc-failure.sh -@@ -48,7 +48,7 @@ function check_no_sub_lvs - # Check takover upconversion fails allocation errors nicely without leaving image pair remnants behind - - # 6-way striped: neither conversion to raid5 nor raid6 possible --lvcreate --yes --stripes 6 --size 4M --name $lv1 $vg -+lvcreate -aey --yes --stripes 6 --size 4M --name $lv1 $vg - not lvconvert --yes --type raid4 $vg/$lv1 - check lv_field $vg/$lv1 segtype "striped" - check_no_sub_lvs $vg $lv1 0 5 -@@ -69,7 +69,7 @@ check_sub_lvs $vg $lv1 0 5 - lvremove -y $vg - - # 5-way striped: conversion to raid5 possible but not to raid6 --lvcreate --yes --stripes 5 --size 4M --name $lv1 $vg -+lvcreate -aey --stripes 5 --size 4M --name $lv1 $vg - not lvconvert --yes --type raid6 $vg/$lv1 - check lv_field $vg/$lv1 segtype "striped" - check_no_sub_lvs $vg $lv1 0 5 -@@ -83,7 +83,7 @@ check_sub_lvs $vg $lv1 0 5 - lvremove -y $vg - - # 4-way striped: conversion to raid5 and raid6 possible --lvcreate --yes --stripes 4 --size 4M --name $lv1 $vg -+lvcreate -aey --stripes 4 --size 4M --name $lv1 $vg - lvconvert --yes --type raid5 $vg/$lv1 - check lv_field $vg/$lv1 segtype "raid5_n" - check lv_field $vg/$lv1 stripes 5 -@@ -92,7 +92,8 @@ check_sub_lvs $vg $lv1 0 4 - check_no_sub_lvs $vg $lv1 5 5 - - lvremove -y $vg --lvcreate --yes --stripes 4 --size 4M --name $lv1 $vg -+ -+lvcreate -aey --stripes 4 --size 4M --name $lv1 $vg - lvconvert --yes --type raid6 $vg/$lv1 - check lv_field $vg/$lv1 segtype "raid6_n_6" - check lv_field $vg/$lv1 stripes 6 -diff --git a/test/shell/lvconvert-raid-takeover-thin.sh b/test/shell/lvconvert-raid-takeover-thin.sh -new file mode 100644 -index 0000000..647b133 ---- /dev/null -+++ b/test/shell/lvconvert-raid-takeover-thin.sh -@@ -0,0 +1,72 @@ -+#!/bin/sh -+# Copyright (C) 2017 Red Hat, Inc. All rights reserved. -+# -+# This copyrighted material is made available to anyone wishing to use, -+# modify, copy, or redistribute it subject to the terms and conditions -+# of the GNU General Public License v.2. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program; if not, write to the Free Software Foundation, -+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA2110-1301 USA -+ -+# check we may convert thin-pool to raid1/raid10 and back -+# RHBZ#1365286 -+ -+SKIP_WITH_LVMLOCKD=1 -+SKIP_WITH_LVMPOLLD=1 -+ -+. lib/inittest -+ -+aux have_thin 1 0 0 || skip -+aux have_raid 1 9 0 || skip -+ -+aux prepare_vg 6 -+ -+lvcreate -L4 -i3 -T $vg/pool -V10 -+ -+for i in 1 2 ; do -+lvconvert --type raid10 -y $vg/pool_tdata -+check grep_dmsetup table $vg-pool_tdata "raid10" -+aux wait_for_sync $vg pool_tdata -+ -+lvconvert --type striped -y $vg/pool_tdata -+check grep_dmsetup table $vg-pool_tdata "striped" -+done -+ -+lvremove -f $vg -+ -+lvcreate -L4 -T $vg/pool -V10 -n $lv1 -+ -+for j in data meta ; do -+ LV=pool_t${j} -+ for i in 1 2 ; do -+ lvconvert --type raid1 -m1 -y $vg/$LV -+ check grep_dmsetup table $vg-${LV} "raid1" -+ aux wait_for_sync $vg $LV -+ -+ lvconvert --type raid1 -m0 -y $vg/$LV -+ check grep_dmsetup table ${vg}-${LV} "linear" -+ done -+done -+ -+ -+# -+# Now same test again, when lock holding LV is not a thin-poll -+# but thinLV $lv1 -+# -+lvchange -an $vg -+lvchange -ay $vg/$lv1 -+ -+for j in data meta ; do -+ LV=pool_t${j} -+ for i in 1 2 ; do -+ lvconvert --type raid1 -m1 -y $vg/$LV -+ check grep_dmsetup table $vg-${LV} "raid1" -+ aux wait_for_sync $vg $LV -+ -+ lvconvert --type raid1 -m0 -y $vg/$LV -+ check grep_dmsetup table ${vg}-${LV} "linear" -+ done -+done -+ -+vgremove -ff $vg -diff --git a/tools/lvresize.c b/tools/lvresize.c -index 1d59239..9b061ac 100644 ---- a/tools/lvresize.c -+++ b/tools/lvresize.c -@@ -147,6 +147,7 @@ static int _lvresize_params(struct cmd_context *cmd, int argc, char **argv, - lp->argv = ++argv; - - lp->alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, 0); -+ lp->yes = arg_is_set(cmd, yes_ARG); - lp->force = arg_is_set(cmd, force_ARG); - lp->nofsck = arg_is_set(cmd, nofsck_ARG); - lp->nosync = arg_is_set(cmd, nosync_ARG); diff --git a/SOURCES/lvm2-2_02_172-upstream.patch b/SOURCES/lvm2-2_02_172-upstream.patch deleted file mode 100644 index ea903d7..0000000 --- a/SOURCES/lvm2-2_02_172-upstream.patch +++ /dev/null @@ -1,4536 +0,0 @@ - WHATS_NEW | 19 + - WHATS_NEW_DM | 5 + - daemons/dmeventd/plugins/raid/dmeventd_raid.c | 16 + - daemons/dmeventd/plugins/thin/dmeventd_thin.c | 12 +- - daemons/dmfilemapd/dmfilemapd.c | 49 +- - daemons/lvmdbusd/automatedproperties.py | 2 +- - daemons/lvmdbusd/background.py | 13 +- - daemons/lvmdbusd/cmdhandler.py | 18 +- - daemons/lvmdbusd/fetch.py | 10 +- - daemons/lvmdbusd/objectmanager.py | 10 +- - daemons/lvmdbusd/utils.py | 4 +- - lib/activate/activate.c | 1 - - lib/config/config_settings.h | 7 +- - lib/config/defaults.h | 4 +- - lib/format_text/export.c | 32 +- - lib/format_text/flags.c | 107 +++- - lib/format_text/import-export.h | 17 +- - lib/format_text/import_vsn1.c | 23 +- - lib/metadata/merge.c | 2 +- - lib/metadata/metadata-exported.h | 5 +- - lib/metadata/metadata.c | 129 ++++- - lib/metadata/raid_manip.c | 598 ++++++++++++++++----- - lib/metadata/segtype.h | 18 + - lib/metadata/thin_manip.c | 19 +- - lib/raid/raid.c | 1 + - libdm/libdm-stats.c | 24 +- - liblvm/lvm_lv.c | 2 +- - man/clvmd.8_main | 7 +- - man/lvm-fullreport.8_des | 1 - - man/lvm.8_main | 2 + - man/lvm.conf.5_main | 4 + - man/lvmcache.7_main | 18 + - man/lvmetad.8_main | 11 +- - man/lvmlockd.8_main | 97 ++-- - man/lvmraid.7_main | 132 +++-- - man/lvmreport.7_main | 2 +- - man/lvmsystemid.7_main | 19 +- - man/pvchange.8_des | 3 + - man/see_also.end | 2 + - man/vgexport.8_des | 2 +- - scripts/fsadm.sh | 203 +++++-- - test/dbus/lvmdbustest.py | 56 +- - test/shell/fsadm-renamed.sh | 116 ++++ - test/shell/lvchange-raid.sh | 1 + - test/shell/lvconvert-raid-regionsize.sh | 8 + - .../lvconvert-raid-reshape-striped_to_linear.sh | 2 +- - test/shell/lvconvert-raid.sh | 61 +++ - test/shell/lvconvert-thin.sh | 2 +- - test/shell/lvcreate-cache.sh | 6 + - test/shell/lvcreate-large-raid.sh | 10 +- - test/shell/lvcreate-raid-nosync.sh | 6 +- - test/shell/lvcreate-thin-big.sh | 2 +- - test/shell/lvresize-full.sh | 1 + - test/shell/thin-dmeventd-warns.sh | 85 +++ - test/shell/thin-large.sh | 54 ++ - test/shell/thin-resize-match.sh | 3 +- - test/shell/unknown-segment.sh | 9 +- - test/unit/Makefile.in | 14 +- - tools/args.h | 99 +++- - tools/command-lines.in | 2 +- - tools/command.c | 27 +- - tools/lvchange.c | 10 + - tools/lvcreate.c | 44 +- - tools/reporter.c | 6 +- - tools/toollib.c | 18 +- - 65 files changed, 1829 insertions(+), 453 deletions(-) - -diff --git a/WHATS_NEW b/WHATS_NEW -index 33a27e8..b2796f6 100644 ---- a/WHATS_NEW -+++ b/WHATS_NEW -@@ -1,3 +1,22 @@ -+Version 2.02.172 - -+=============================== -+ No longer necessary to '--force' a repair for RAID1 -+ Linear to RAID1 upconverts now use "recover" sync action, not "resync". -+ Improve lvcreate --cachepool arg validation. -+ Limit maximal size of thin-pool for specific chunk size. -+ Print a warning about in-use PVs with no VG using them. -+ Disable automatic clearing of PVs that look like in-use orphans. -+ Cache format2 flag is now using segment name type field. -+ Support storing status flags via segtype name field. -+ Stop using '--yes' mode when fsadm runs without terminal. -+ Extend validation of filesystems resized by fsadm. -+ Enhance lvconvert automatic settings of possible (raid) LV types. -+ Allow lvchange to change properties on a thin pool data sub LV. -+ Fix lvcreate extent percentage calculation for mirrors. -+ Don't reinstate still-missing devices when correcting inconsistent metadata. -+ Properly handle subshell return codes in fsadm. -+ Disallow cachepool creation with policy cleaner and mode writeback. -+ - Version 2.02.171 - 3rd May 2017 - =============================== - Fix memory warnings by using mempools for command definition processing. -diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM -index 20d6220..5718ab7 100644 ---- a/WHATS_NEW_DM -+++ b/WHATS_NEW_DM -@@ -1,3 +1,8 @@ -+Version 1.02.141 - -+=============================== -+ Accept truncated files in calls to dm_stats_update_regions_from_fd(). -+ Restore Warning by 5% increment when thin-pool is over 80% (1.02.138). -+ - Version 1.02.140 - 3rd May 2017 - =============================== - Add missing configure --enable-dmfilemapd status message and fix --disable. -diff --git a/daemons/dmeventd/plugins/raid/dmeventd_raid.c b/daemons/dmeventd/plugins/raid/dmeventd_raid.c -index 4f204bf..afeac28 100644 ---- a/daemons/dmeventd/plugins/raid/dmeventd_raid.c -+++ b/daemons/dmeventd/plugins/raid/dmeventd_raid.c -@@ -58,6 +58,22 @@ static int _process_raid_event(struct dso_state *state, char *params, const char - dead = 1; - } - -+ /* -+ * if we are converting from non-RAID to RAID (e.g. linear -> raid1) -+ * and too many original devices die, such that we cannot continue -+ * the "recover" operation, the sync action will go to "idle", the -+ * unsynced devs will remain at 'a', and the original devices will -+ * NOT SWITCH TO 'D', but will remain at 'A' - hoping to be revived. -+ * -+ * This is simply the way the kernel works... -+ */ -+ if (!strcmp(status->sync_action, "idle") && -+ strchr(status->dev_health, 'a')) { -+ log_error("Primary sources for new RAID, %s, have failed.", -+ device); -+ dead = 1; /* run it through LVM repair */ -+ } -+ - if (dead) { - if (status->insync_regions < status->total_regions) { - if (!state->warned) { -diff --git a/daemons/dmeventd/plugins/thin/dmeventd_thin.c b/daemons/dmeventd/plugins/thin/dmeventd_thin.c -index e7d24c5..7fd7b0e 100644 ---- a/daemons/dmeventd/plugins/thin/dmeventd_thin.c -+++ b/daemons/dmeventd/plugins/thin/dmeventd_thin.c -@@ -47,10 +47,8 @@ struct dso_state { - struct dm_pool *mem; - int metadata_percent_check; - int metadata_percent; -- int metadata_warn_once; - int data_percent_check; - int data_percent; -- int data_warn_once; - uint64_t known_metadata_size; - uint64_t known_data_size; - unsigned fails; -@@ -253,9 +251,8 @@ void process_event(struct dm_task *dmt, - * action is called for: >50%, >55% ... >95%, 100% - */ - state->metadata_percent = dm_make_percent(tps->used_metadata_blocks, tps->total_metadata_blocks); -- if (state->metadata_percent <= WARNING_THRESH) -- state->metadata_warn_once = 0; /* Dropped bellow threshold, reset warn once */ -- else if (!state->metadata_warn_once++) /* Warn once when raised above threshold */ -+ if ((state->metadata_percent > WARNING_THRESH) && -+ (state->metadata_percent > state->metadata_percent_check)) - log_warn("WARNING: Thin pool %s metadata is now %.2f%% full.", - device, dm_percent_to_float(state->metadata_percent)); - if (state->metadata_percent > CHECK_MINIMUM) { -@@ -269,9 +266,8 @@ void process_event(struct dm_task *dmt, - state->metadata_percent_check = CHECK_MINIMUM; - - state->data_percent = dm_make_percent(tps->used_data_blocks, tps->total_data_blocks); -- if (state->data_percent <= WARNING_THRESH) -- state->data_warn_once = 0; -- else if (!state->data_warn_once++) -+ if ((state->data_percent > WARNING_THRESH) && -+ (state->data_percent > state->data_percent_check)) - log_warn("WARNING: Thin pool %s data is now %.2f%% full.", - device, dm_percent_to_float(state->data_percent)); - if (state->data_percent > CHECK_MINIMUM) { -diff --git a/daemons/dmfilemapd/dmfilemapd.c b/daemons/dmfilemapd/dmfilemapd.c -index 2dd069a..43ae970 100644 ---- a/daemons/dmfilemapd/dmfilemapd.c -+++ b/daemons/dmfilemapd/dmfilemapd.c -@@ -266,8 +266,6 @@ static int _parse_args(int argc, char **argv, struct filemap_monitor *fm) - return 0; - } - -- memset(fm, 0, sizeof(*fm)); -- - /* - * We don't know the true nr_regions at daemon start time, - * and it is not worth a dm_stats_list()/group walk to count: -@@ -359,30 +357,33 @@ static int _parse_args(int argc, char **argv, struct filemap_monitor *fm) - return 1; - } - --static int _filemap_fd_check_changed(struct filemap_monitor *fm) -+static int _filemap_fd_update_blocks(struct filemap_monitor *fm) - { -- int64_t blocks, old_blocks; - struct stat buf; - - if (fm->fd < 0) { - log_error("Filemap fd is not open."); -- return -1; -+ return 0; - } - - if (fstat(fm->fd, &buf)) { - log_error("Failed to fstat filemap file descriptor."); -- return -1; -+ return 0; - } - -- blocks = buf.st_blocks; -+ fm->blocks = buf.st_blocks; - -- /* first check? */ -- if (fm->blocks < 0) -- old_blocks = buf.st_blocks; -- else -- old_blocks = fm->blocks; -+ return 1; -+} -+ -+static int _filemap_fd_check_changed(struct filemap_monitor *fm) -+{ -+ int64_t old_blocks; -+ -+ old_blocks = fm->blocks; - -- fm->blocks = blocks; -+ if (!_filemap_fd_update_blocks(fm)) -+ return -1; - - return (fm->blocks != old_blocks); - } -@@ -564,6 +565,7 @@ static int _filemap_monitor_check_file_unlinked(struct filemap_monitor *fm) - ssize_t len; - - fm->deleted = 0; -+ same = 0; - - if ((fd = open(fm->path, O_RDONLY)) < 0) - goto check_unlinked; -@@ -684,7 +686,10 @@ static int _update_regions(struct dm_stats *dms, struct filemap_monitor *fm) - for (region = regions; *region != DM_STATS_REGIONS_ALL; region++) - nr_regions++; - -- if (regions[0] != fm->group_id) { -+ if (!nr_regions) -+ log_warn("File contains no extents: exiting."); -+ -+ if (nr_regions && (regions[0] != fm->group_id)) { - log_warn("group_id changed from " FMTu64 " to " FMTu64, - fm->group_id, regions[0]); - fm->group_id = regions[0]; -@@ -715,6 +720,9 @@ static int _dmfilemapd(struct filemap_monitor *fm) - if (!_filemap_monitor_set_notify(fm)) - goto bad; - -+ if (!_filemap_fd_update_blocks(fm)) -+ goto bad; -+ - if (!dm_stats_list(dms, DM_STATS_ALL_PROGRAMS)) { - log_error("Failed to list stats handle."); - goto bad; -@@ -748,17 +756,16 @@ static int _dmfilemapd(struct filemap_monitor *fm) - if ((check = _filemap_fd_check_changed(fm)) < 0) - goto bad; - -- if (!check) -- goto wait; -- -- if (!_update_regions(dms, fm)) -+ if (check && !_update_regions(dms, fm)) - goto bad; - -+ running = !!fm->nr_regions; -+ if (!running) -+ continue; -+ - wait: - _filemap_monitor_wait(FILEMAPD_WAIT_USECS); - -- running = !!fm->nr_regions; -- - /* mode=inode termination condions */ - if (fm->mode == DM_FILEMAPD_FOLLOW_INODE) { - if (!_filemap_monitor_check_file_unlinked(fm)) -@@ -801,6 +808,8 @@ int main(int argc, char **argv) - { - struct filemap_monitor fm; - -+ memset(&fm, 0, sizeof(fm)); -+ - if (!_parse_args(argc, argv, &fm)) { - dm_free(fm.path); - return 1; -diff --git a/daemons/lvmdbusd/automatedproperties.py b/daemons/lvmdbusd/automatedproperties.py -index 68cea6e..e188fa4 100644 ---- a/daemons/lvmdbusd/automatedproperties.py -+++ b/daemons/lvmdbusd/automatedproperties.py -@@ -100,7 +100,7 @@ class AutomatedProperties(dbus.service.Object): - raise dbus.exceptions.DBusException( - obj._ap_interface, - 'The object %s does not implement the %s interface' -- % (self.__class__, interface_name)) -+ % (obj.__class__, interface_name)) - - @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, - in_signature='s', out_signature='a{sv}', -diff --git a/daemons/lvmdbusd/background.py b/daemons/lvmdbusd/background.py -index f7f77d5..90e8b68 100644 ---- a/daemons/lvmdbusd/background.py -+++ b/daemons/lvmdbusd/background.py -@@ -9,12 +9,13 @@ - - import subprocess - from . import cfg --from .cmdhandler import options_to_cli_args -+from .cmdhandler import options_to_cli_args, LvmExecutionMeta - import dbus - from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug,\ - add_no_notify - import os - import threading -+import time - - - def pv_move_lv_cmd(move_options, lv_full_name, -@@ -47,6 +48,11 @@ def _move_merge(interface_name, command, job_state): - # Instruct lvm to not register an event with us - command = add_no_notify(command) - -+ #(self, start, ended, cmd, ec, stdout_txt, stderr_txt) -+ meta = LvmExecutionMeta(time.time(), 0, command, -1000, None, None) -+ -+ cfg.blackbox.add(meta) -+ - process = subprocess.Popen(command, stdout=subprocess.PIPE, - env=os.environ, - stderr=subprocess.PIPE, close_fds=True) -@@ -74,6 +80,11 @@ def _move_merge(interface_name, command, job_state): - - out = process.communicate() - -+ with meta.lock: -+ meta.ended = time.time() -+ meta.ec = process.returncode -+ meta.stderr_txt = out[1] -+ - if process.returncode == 0: - job_state.Percent = 100 - else: -diff --git a/daemons/lvmdbusd/cmdhandler.py b/daemons/lvmdbusd/cmdhandler.py -index 8ed38cb..4fb1670 100644 ---- a/daemons/lvmdbusd/cmdhandler.py -+++ b/daemons/lvmdbusd/cmdhandler.py -@@ -37,6 +37,7 @@ cmd_lock = threading.RLock() - class LvmExecutionMeta(object): - - def __init__(self, start, ended, cmd, ec, stdout_txt, stderr_txt): -+ self.lock = threading.RLock() - self.start = start - self.ended = ended - self.cmd = cmd -@@ -45,12 +46,13 @@ class LvmExecutionMeta(object): - self.stderr_txt = stderr_txt - - def __str__(self): -- return "EC= %d for %s\n" \ -- "STARTED: %f, ENDED: %f\n" \ -- "STDOUT=%s\n" \ -- "STDERR=%s\n" % \ -- (self.ec, str(self.cmd), self.start, self.ended, self.stdout_txt, -- self.stderr_txt) -+ with self.lock: -+ return "EC= %d for %s\n" \ -+ "STARTED: %f, ENDED: %f\n" \ -+ "STDOUT=%s\n" \ -+ "STDERR=%s\n" % \ -+ (self.ec, str(self.cmd), self.start, self.ended, self.stdout_txt, -+ self.stderr_txt) - - - class LvmFlightRecorder(object): -@@ -618,10 +620,10 @@ def vg_reduce(vg_name, missing, pv_devices, reduce_options): - cmd = ['vgreduce'] - cmd.extend(options_to_cli_args(reduce_options)) - -- if len(pv_devices) == 0: -- cmd.append('--all') - if missing: - cmd.append('--removemissing') -+ elif len(pv_devices) == 0: -+ cmd.append('--all') - - cmd.append(vg_name) - cmd.extend(pv_devices) -diff --git a/daemons/lvmdbusd/fetch.py b/daemons/lvmdbusd/fetch.py -index 78c3a4b..c053685 100644 ---- a/daemons/lvmdbusd/fetch.py -+++ b/daemons/lvmdbusd/fetch.py -@@ -82,10 +82,10 @@ class StateUpdate(object): - - @staticmethod - def update_thread(obj): -+ queued_requests = [] - while cfg.run.value != 0: - # noinspection PyBroadException - try: -- queued_requests = [] - refresh = True - emit_signal = True - cache_refresh = True -@@ -96,7 +96,7 @@ class StateUpdate(object): - wait = not obj.deferred - obj.deferred = False - -- if wait: -+ if len(queued_requests) == 0 and wait: - queued_requests.append(obj.queue.get(True, 2)) - - # Ok we have one or the deferred queue has some, -@@ -131,11 +131,17 @@ class StateUpdate(object): - for i in queued_requests: - i.set_result(num_changes) - -+ # Only clear out the requests after we have given them a result -+ # otherwise we can orphan the waiting threads and they never -+ # wake up if we get an exception -+ queued_requests = [] -+ - except queue.Empty: - pass - except Exception: - st = traceback.format_exc() - log_error("update_thread exception: \n%s" % st) -+ cfg.blackbox.dump() - - def __init__(self): - self.lock = threading.RLock() -diff --git a/daemons/lvmdbusd/objectmanager.py b/daemons/lvmdbusd/objectmanager.py -index a9d13a7..563b9ec 100644 ---- a/daemons/lvmdbusd/objectmanager.py -+++ b/daemons/lvmdbusd/objectmanager.py -@@ -223,8 +223,9 @@ class ObjectManager(AutomatedProperties): - :param lvm_id: The lvm identifier - """ - with self.rlock: -- if lvm_id in self._id_to_object_path: -- return self.get_object_by_path(self._id_to_object_path[lvm_id]) -+ lookup_rc = self._id_lookup(lvm_id) -+ if lookup_rc: -+ return self.get_object_by_path(lookup_rc) - return None - - def get_object_path_by_lvm_id(self, lvm_id): -@@ -234,8 +235,9 @@ class ObjectManager(AutomatedProperties): - :return: Object path or '/' if not found - """ - with self.rlock: -- if lvm_id in self._id_to_object_path: -- return self._id_to_object_path[lvm_id] -+ lookup_rc = self._id_lookup(lvm_id) -+ if lookup_rc: -+ return lookup_rc - return '/' - - def _uuid_verify(self, path, uuid, lvm_id): -diff --git a/daemons/lvmdbusd/utils.py b/daemons/lvmdbusd/utils.py -index af9e10a..170824d 100644 ---- a/daemons/lvmdbusd/utils.py -+++ b/daemons/lvmdbusd/utils.py -@@ -519,7 +519,9 @@ def add_no_notify(cmdline): - if '--config' in cmdline: - for i, arg in enumerate(cmdline): - if arg == '--config': -- cmdline[i] += "global/notify_dbus=0" -+ if len(cmdline) <= i+1: -+ raise dbus.exceptions.DBusException("Missing value for --config option.") -+ cmdline[i+1] += " global/notify_dbus=0" - break - else: - cmdline.extend(['--config', 'global/notify_dbus=0']) -diff --git a/lib/activate/activate.c b/lib/activate/activate.c -index a3978ad..282dd4f 100644 ---- a/lib/activate/activate.c -+++ b/lib/activate/activate.c -@@ -835,7 +835,6 @@ int lv_info_with_seg_status(struct cmd_context *cmd, - * When merge is in progress, query merging origin LV instead. - * COW volume is already mapped as error target in this case. - */ -- status->lv = olv; - return 1; - } - -diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h -index 3b0eebb..40b64ab 100644 ---- a/lib/config/config_settings.h -+++ b/lib/config/config_settings.h -@@ -469,8 +469,9 @@ cfg(allocation_mirror_logs_require_separate_pvs_CFG, "mirror_logs_require_separa - - cfg(allocation_raid_stripe_all_devices_CFG, "raid_stripe_all_devices", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_ALLOCATION_STRIPE_ALL_DEVICES, vsn(2, 2, 162), NULL, 0, NULL, - "Stripe across all PVs when RAID stripes are not specified.\n" -- "If enabled, all PVs in the VG or on the command line are used for raid0/4/5/6/10\n" -- "when the command does not specify the number of stripes to use.\n" -+ "If enabled, all PVs in the VG or on the command line are used for\n" -+ "raid0/4/5/6/10 when the command does not specify the number of\n" -+ "stripes to use.\n" - "This was the default behaviour until release 2.02.162.\n") - - cfg(allocation_cache_pool_metadata_require_separate_pvs_CFG, "cache_pool_metadata_require_separate_pvs", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA, CFG_TYPE_BOOL, DEFAULT_CACHE_POOL_METADATA_REQUIRE_SEPARATE_PVS, vsn(2, 2, 106), NULL, 0, NULL, -@@ -934,7 +935,7 @@ cfg(global_use_lvmetad_CFG, "use_lvmetad", global_CFG_SECTION, 0, CFG_TYPE_BOOL, - "devices/global_filter.\n") - - cfg(global_lvmetad_update_wait_time_CFG, "lvmetad_update_wait_time", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_LVMETAD_UPDATE_WAIT_TIME, vsn(2, 2, 151), NULL, 0, NULL, -- "The number of seconds a command will wait for lvmetad update to finish.\n" -+ "Number of seconds a command will wait for lvmetad update to finish.\n" - "After waiting for this period, a command will not use lvmetad, and\n" - "will revert to disk scanning.\n") - -diff --git a/lib/config/defaults.h b/lib/config/defaults.h -index 65b81f1..d9e19d9 100644 ---- a/lib/config/defaults.h -+++ b/lib/config/defaults.h -@@ -104,9 +104,9 @@ - #define DEFAULT_THIN_REPAIR_OPTION1 "" - #define DEFAULT_THIN_REPAIR_OPTIONS_CONFIG "#S" DEFAULT_THIN_REPAIR_OPTION1 - #define DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS 0 --#define DEFAULT_THIN_POOL_MAX_METADATA_SIZE (16 * 1024 * 1024) /* KB */ -+#define DEFAULT_THIN_POOL_MAX_METADATA_SIZE (DM_THIN_MAX_METADATA_SIZE / 2) /* KB */ - #define DEFAULT_THIN_POOL_MIN_METADATA_SIZE 2048 /* KB */ --#define DEFAULT_THIN_POOL_OPTIMAL_SIZE (128 * 1024 * 1024) /* KB */ -+#define DEFAULT_THIN_POOL_OPTIMAL_METADATA_SIZE (128 * 1024) /* KB */ - #define DEFAULT_THIN_POOL_CHUNK_SIZE_POLICY "generic" - #define DEFAULT_THIN_POOL_CHUNK_SIZE 64 /* KB */ - #define DEFAULT_THIN_POOL_CHUNK_SIZE_PERFORMANCE 512 /* KB */ -diff --git a/lib/format_text/export.c b/lib/format_text/export.c -index 473275d..f369089 100644 ---- a/lib/format_text/export.c -+++ b/lib/format_text/export.c -@@ -358,11 +358,12 @@ static int _print_header(struct cmd_context *cmd, struct formatter *f, - static int _print_flag_config(struct formatter *f, uint64_t status, int type) - { - char buffer[4096]; -- if (!print_flags(status, type | STATUS_FLAG, buffer, sizeof(buffer))) -+ -+ if (!print_flags(buffer, sizeof(buffer), type, STATUS_FLAG, status)) - return_0; - outf(f, "status = %s", buffer); - -- if (!print_flags(status, type, buffer, sizeof(buffer))) -+ if (!print_flags(buffer, sizeof(buffer), type, COMPATIBLE_FLAG, status)) - return_0; - outf(f, "flags = %s", buffer); - -@@ -501,7 +502,13 @@ static int _print_vg(struct formatter *f, struct volume_group *vg) - */ - static const char *_get_pv_name_from_uuid(struct formatter *f, char *uuid) - { -- return dm_hash_lookup(f->pv_names, uuid); -+ const char *pv_name = dm_hash_lookup(f->pv_names, uuid); -+ -+ if (!pv_name) -+ log_error(INTERNAL_ERROR "PV name for uuid %s missing from text metadata export hash table.", -+ uuid); -+ -+ return pv_name; - } - - static const char *_get_pv_name(struct formatter *f, struct physical_volume *pv) -@@ -577,6 +584,11 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg) - static int _print_segment(struct formatter *f, struct volume_group *vg, - int count, struct lv_segment *seg) - { -+ char buffer[2048]; -+ -+ if (!print_segtype_lvflags(buffer, sizeof(buffer), seg->lv->status)) -+ return_0; -+ - outf(f, "segment%u {", count); - _inc_indent(f); - -@@ -587,7 +599,8 @@ static int _print_segment(struct formatter *f, struct volume_group *vg, - if (seg->reshape_len) - outsize(f, (uint64_t) seg->reshape_len * vg->extent_size, - "reshape_count = %u", seg->reshape_len); -- outf(f, "type = \"%s\"", seg->segtype->name); -+ -+ outf(f, "type = \"%s%s\"", seg->segtype->name, buffer); - - if (!_out_list(f, &seg->tags, "tags")) - return_0; -@@ -607,6 +620,7 @@ int out_areas(struct formatter *f, const struct lv_segment *seg, - { - const char *name; - unsigned int s; -+ struct physical_volume *pv; - - outnl(f); - -@@ -616,7 +630,13 @@ int out_areas(struct formatter *f, const struct lv_segment *seg, - for (s = 0; s < seg->area_count; s++) { - switch (seg_type(seg, s)) { - case AREA_PV: -- if (!(name = _get_pv_name(f, seg_pv(seg, s)))) -+ if (!(pv = seg_pv(seg, s))) { -+ log_error(INTERNAL_ERROR "Missing PV for area %" PRIu32 " of %s segment of LV %s.", -+ s, type, display_lvname(seg->lv)); -+ return 0; -+ } -+ -+ if (!(name = _get_pv_name(f, pv))) - return_0; - - outf(f, "\"%s\", %u%s", name, -@@ -650,6 +670,8 @@ int out_areas(struct formatter *f, const struct lv_segment *seg, - - break; - case AREA_UNASSIGNED: -+ log_error(INTERNAL_ERROR "Invalid type for area %" PRIu32 " of %s segment of LV %s.", -+ s, type, display_lvname(seg->lv)); - return 0; - } - } -diff --git a/lib/format_text/flags.c b/lib/format_text/flags.c -index a9f81f5..88fb091 100644 ---- a/lib/format_text/flags.c -+++ b/lib/format_text/flags.c -@@ -47,6 +47,7 @@ static const struct flag _pv_flags[] = { - {ALLOCATABLE_PV, "ALLOCATABLE", STATUS_FLAG}, - {EXPORTED_VG, "EXPORTED", STATUS_FLAG}, - {MISSING_PV, "MISSING", COMPATIBLE_FLAG}, -+ {MISSING_PV, "MISSING", STATUS_FLAG}, - {UNLABELLED_PV, NULL, 0}, - {0, NULL, 0} - }; -@@ -61,13 +62,14 @@ static const struct flag _lv_flags[] = { - {LOCKED, "LOCKED", STATUS_FLAG}, - {LV_NOTSYNCED, "NOTSYNCED", STATUS_FLAG}, - {LV_REBUILD, "REBUILD", STATUS_FLAG}, -- {LV_RESHAPE_DELTA_DISKS_PLUS, "RESHAPE_DELTA_DISKS_PLUS", STATUS_FLAG}, -- {LV_RESHAPE_DELTA_DISKS_MINUS, "RESHAPE_DELTA_DISKS_MINUS", STATUS_FLAG}, -- {LV_REMOVE_AFTER_RESHAPE, "REMOVE_AFTER_RESHAPE", STATUS_FLAG}, -+ {LV_RESHAPE, "RESHAPE", SEGTYPE_FLAG}, -+ {LV_RESHAPE_DELTA_DISKS_PLUS, "RESHAPE_DELTA_DISKS_PLUS", SEGTYPE_FLAG}, -+ {LV_RESHAPE_DELTA_DISKS_MINUS, "RESHAPE_DELTA_DISKS_MINUS", SEGTYPE_FLAG}, -+ {LV_REMOVE_AFTER_RESHAPE, "REMOVE_AFTER_RESHAPE", SEGTYPE_FLAG}, - {LV_WRITEMOSTLY, "WRITEMOSTLY", STATUS_FLAG}, - {LV_ACTIVATION_SKIP, "ACTIVATION_SKIP", COMPATIBLE_FLAG}, - {LV_ERROR_WHEN_FULL, "ERROR_WHEN_FULL", COMPATIBLE_FLAG}, -- {LV_METADATA_FORMAT, "METADATA_FORMAT", STATUS_FLAG}, -+ {LV_METADATA_FORMAT, "METADATA_FORMAT", SEGTYPE_FLAG}, - {LV_NOSCAN, NULL, 0}, - {LV_TEMPORARY, NULL, 0}, - {POOL_METADATA_SPARE, NULL, 0}, -@@ -101,9 +103,9 @@ static const struct flag _lv_flags[] = { - {0, NULL, 0} - }; - --static const struct flag *_get_flags(int type) -+static const struct flag *_get_flags(enum pv_vg_lv_e type) - { -- switch (type & ~STATUS_FLAG) { -+ switch (type) { - case VG_FLAGS: - return _vg_flags; - -@@ -114,7 +116,7 @@ static const struct flag *_get_flags(int type) - return _lv_flags; - } - -- log_error("Unknown flag set requested."); -+ log_error(INTERNAL_ERROR "Unknown flag set requested."); - return NULL; - } - -@@ -123,7 +125,7 @@ static const struct flag *_get_flags(int type) - * using one of the tables defined at the top of - * the file. - */ --int print_flags(uint64_t status, int type, char *buffer, size_t size) -+int print_flags(char *buffer, size_t size, enum pv_vg_lv_e type, int mask, uint64_t status) - { - int f, first = 1; - const struct flag *flags; -@@ -132,13 +134,13 @@ int print_flags(uint64_t status, int type, char *buffer, size_t size) - return_0; - - if (!emit_to_buffer(&buffer, &size, "[")) -- return 0; -+ return_0; - - for (f = 0; flags[f].mask; f++) { - if (status & flags[f].mask) { - status &= ~flags[f].mask; - -- if ((type & STATUS_FLAG) != flags[f].kind) -+ if (mask != flags[f].kind) - continue; - - /* Internal-only flag? */ -@@ -147,18 +149,18 @@ int print_flags(uint64_t status, int type, char *buffer, size_t size) - - if (!first) { - if (!emit_to_buffer(&buffer, &size, ", ")) -- return 0; -+ return_0; - } else - first = 0; - - if (!emit_to_buffer(&buffer, &size, "\"%s\"", -- flags[f].description)) -- return 0; -+ flags[f].description)) -+ return_0; - } - } - - if (!emit_to_buffer(&buffer, &size, "]")) -- return 0; -+ return_0; - - if (status) - log_warn(INTERNAL_ERROR "Metadata inconsistency: " -@@ -167,9 +169,9 @@ int print_flags(uint64_t status, int type, char *buffer, size_t size) - return 1; - } - --int read_flags(uint64_t *status, int type, const struct dm_config_value *cv) -+int read_flags(uint64_t *status, enum pv_vg_lv_e type, int mask, const struct dm_config_value *cv) - { -- int f; -+ unsigned f; - uint64_t s = UINT64_C(0); - const struct flag *flags; - -@@ -186,7 +188,8 @@ int read_flags(uint64_t *status, int type, const struct dm_config_value *cv) - } - - for (f = 0; flags[f].description; f++) -- if (!strcmp(flags[f].description, cv->v.str)) { -+ if ((flags[f].kind & mask) && -+ !strcmp(flags[f].description, cv->v.str)) { - s |= flags[f].mask; - break; - } -@@ -200,7 +203,7 @@ int read_flags(uint64_t *status, int type, const struct dm_config_value *cv) - * by this case. - */ - s |= PARTIAL_VG; -- } else if (!flags[f].description && (type & STATUS_FLAG)) { -+ } else if (!flags[f].description && (mask & STATUS_FLAG)) { - log_error("Unknown status flag '%s'.", cv->v.str); - return 0; - } -@@ -212,3 +215,71 @@ int read_flags(uint64_t *status, int type, const struct dm_config_value *cv) - *status |= s; - return 1; - } -+ -+/* -+ * Parse extra status flags from segment "type" string. -+ * These flags are seen as INCOMPATIBLE by any older lvm2 code. -+ * All flags separated by '+' are trimmed from passed string. -+ * All UNKNOWN flags will again cause the "UNKNOWN" segtype. -+ * -+ * Note: using these segtype status flags instead of actual -+ * status flags ensures wanted incompatiblity. -+ */ -+int read_segtype_lvflags(uint64_t *status, char *segtype_str) -+{ -+ unsigned i; -+ const struct flag *flags = _lv_flags; -+ char *delim; -+ char *flag, *buffer, *str; -+ -+ if (!(str = strchr(segtype_str, '+'))) -+ return 1; /* No flags */ -+ -+ if (!(buffer = dm_strdup(str + 1))) { -+ log_error("Cannot duplicate segment string."); -+ return 0; -+ } -+ -+ delim = buffer; -+ -+ do { -+ flag = delim; -+ if ((delim = strchr(delim, '+'))) -+ *delim++ = '\0'; -+ -+ for (i = 0; flags[i].description; i++) -+ if ((flags[i].kind & SEGTYPE_FLAG) && -+ !strcmp(flags[i].description, flag)) { -+ *status |= flags[i].mask; -+ break; -+ } -+ -+ } while (delim && flags[i].description); /* Till no more flags in type appear */ -+ -+ if (!flags[i].description) -+ /* Unknown flag is incompatible - returns unmodified segtype_str */ -+ log_warn("WARNING: Unrecognised flag %s in segment type %s.", -+ flag, segtype_str); -+ else -+ *str = '\0'; /* Cut away 1st. '+' */ -+ -+ dm_free(buffer); -+ -+ return 1; -+} -+ -+int print_segtype_lvflags(char *buffer, size_t size, uint64_t status) -+{ -+ unsigned i; -+ const struct flag *flags = _lv_flags; -+ -+ buffer[0] = 0; -+ for (i = 0; flags[i].mask; i++) -+ if ((flags[i].kind & SEGTYPE_FLAG) && -+ (status & flags[i].mask) && -+ !emit_to_buffer(&buffer, &size, "+%s", -+ flags[i].description)) -+ return 0; -+ -+ return 1; -+} -diff --git a/lib/format_text/import-export.h b/lib/format_text/import-export.h -index c081c51..4b47636 100644 ---- a/lib/format_text/import-export.h -+++ b/lib/format_text/import-export.h -@@ -35,14 +35,16 @@ - * VGs, PVs and LVs all have status bitsets, we gather together - * common code for reading and writing them. - */ --enum { -- COMPATIBLE_FLAG = 0x0, -+enum pv_vg_lv_e { -+ PV_FLAGS = 1, - VG_FLAGS, -- PV_FLAGS, - LV_FLAGS, -- STATUS_FLAG = 0x8, - }; - -+#define COMPATIBLE_FLAG 0x01 -+#define STATUS_FLAG 0x02 -+#define SEGTYPE_FLAG 0x04 -+ - struct text_vg_version_ops { - int (*check_version) (const struct dm_config_tree * cf); - struct volume_group *(*read_vg) (struct format_instance * fid, -@@ -58,8 +60,11 @@ struct text_vg_version_ops { - - struct text_vg_version_ops *text_vg_vsn1_init(void); - --int print_flags(uint64_t status, int type, char *buffer, size_t size); --int read_flags(uint64_t *status, int type, const struct dm_config_value *cv); -+int print_flags(char *buffer, size_t size, enum pv_vg_lv_e type, int mask, uint64_t status); -+int read_flags(uint64_t *status, enum pv_vg_lv_e type, int mask, const struct dm_config_value *cv); -+ -+int print_segtype_lvflags(char *buffer, size_t size, uint64_t status); -+int read_segtype_lvflags(uint64_t *status, char *segtype_scr); - - int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp); - size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf); -diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c -index e545008..7d9257e 100644 ---- a/lib/format_text/import_vsn1.c -+++ b/lib/format_text/import_vsn1.c -@@ -140,13 +140,14 @@ static int _read_flag_config(const struct dm_config_node *n, uint64_t *status, i - return 0; - } - -- if (!(read_flags(status, type | STATUS_FLAG, cv))) { -+ /* For backward compatible metadata accept both type of flags */ -+ if (!(read_flags(status, type, STATUS_FLAG | SEGTYPE_FLAG, cv))) { - log_error("Could not read status flags."); - return 0; - } - - if (dm_config_get_list(n, "flags", &cv)) { -- if (!(read_flags(status, type, cv))) { -+ if (!(read_flags(status, type, COMPATIBLE_FLAG, cv))) { - log_error("Could not read flags."); - return 0; - } -@@ -357,6 +358,7 @@ static int _read_segment(struct logical_volume *lv, const struct dm_config_node - uint32_t area_extents, start_extent, extent_count, reshape_count, data_copies; - struct segment_type *segtype; - const char *segtype_str; -+ char *segtype_with_flags; - - if (!sn_child) { - log_error("Empty segment section."); -@@ -388,9 +390,24 @@ static int _read_segment(struct logical_volume *lv, const struct dm_config_node - return 0; - } - -- if (!(segtype = get_segtype_from_string(lv->vg->cmd, segtype_str))) -+ /* Locally duplicate to parse out status flag bits */ -+ if (!(segtype_with_flags = dm_pool_strdup(mem, segtype_str))) { -+ log_error("Cannot duplicate segtype string."); -+ return 0; -+ } -+ -+ if (!read_segtype_lvflags(&lv->status, segtype_with_flags)) { -+ log_error("Couldn't read segtype for logical volume %s.", -+ display_lvname(lv)); -+ return 0; -+ } -+ -+ if (!(segtype = get_segtype_from_string(lv->vg->cmd, segtype_with_flags))) - return_0; - -+ /* Can drop temporary string here as nothing has allocated from VGMEM meanwhile */ -+ dm_pool_free(mem, segtype_with_flags); -+ - if (segtype->ops->text_import_area_count && - !segtype->ops->text_import_area_count(sn_child, &area_count)) - return_0; -diff --git a/lib/metadata/merge.c b/lib/metadata/merge.c -index 3d82a05..e642459 100644 ---- a/lib/metadata/merge.c -+++ b/lib/metadata/merge.c -@@ -222,7 +222,7 @@ static void _check_non_raid_seg_members(struct lv_segment *seg, int *error_count - } - - /* -- * Check RAID segment sruct members of @seg for acceptable -+ * Check RAID segment struct members of @seg for acceptable - * properties and increment @error_count for any bogus ones. - */ - static void _check_raid_seg(struct lv_segment *seg, int *error_count) -diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h -index 8b4310b..c4bebd0 100644 ---- a/lib/metadata/metadata-exported.h -+++ b/lib/metadata/metadata-exported.h -@@ -142,7 +142,10 @@ - - #define LV_REMOVE_AFTER_RESHAPE UINT64_C(0x0400000000000000) /* LV needs to be removed after a shrinking reshape */ - #define LV_METADATA_FORMAT UINT64_C(0x0800000000000000) /* LV has segments with metadata format */ --/* Next unused flag: UINT64_C(0x1000000000000000) */ -+ -+#define LV_RESHAPE UINT64_C(0x1000000000000000) /* Ongoing reshape (number of stripes, stripesize or raid algorithm change): -+ used as SEGTYPE_FLAG to prevent activation on old runtime */ -+/* Next unused flag: UINT64_C(0x2000000000000000) */ - - /* Format features flags */ - #define FMT_SEGMENTS 0x00000001U /* Arbitrary segment params? */ -diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c -index 1b500ed..4ba81c7 100644 ---- a/lib/metadata/metadata.c -+++ b/lib/metadata/metadata.c -@@ -1089,8 +1089,7 @@ static struct volume_group *_vg_make_handle(struct cmd_context *cmd, - if (!vg && !(vg = alloc_vg("vg_make_handle", cmd, NULL))) - return_NULL; - -- if (vg->read_status != failure) -- vg->read_status = failure; -+ vg->read_status = failure; - - if (vg->fid && !_vg_update_vg_committed(vg)) - vg->read_status |= FAILED_ALLOCATION; -@@ -1122,6 +1121,7 @@ int vg_has_unknown_segments(const struct volume_group *vg) - struct volume_group *vg_lock_and_create(struct cmd_context *cmd, const char *vg_name) - { - uint32_t rc; -+ struct volume_group *vg; - - if (!validate_name(vg_name)) { - log_error("Invalid vg name %s", vg_name); -@@ -1134,7 +1134,11 @@ struct volume_group *vg_lock_and_create(struct cmd_context *cmd, const char *vg_ - /* NOTE: let caller decide - this may be check for existence */ - return _vg_make_handle(cmd, NULL, rc); - -- return vg_create(cmd, vg_name); -+ vg = vg_create(cmd, vg_name); -+ if (!vg || vg_read_error(vg)) -+ unlock_vg(cmd, NULL, vg_name); -+ -+ return vg; - } - - /* -@@ -3707,6 +3711,37 @@ struct _vg_read_orphan_baton { - int repair; - }; - -+/* -+ * If we know that the PV is orphan, meaning there's at least one MDA on -+ * that PV which does not reference any VG and at the same time there's -+ * PV_EXT_USED flag set, we're certainly in an inconsistent state and we -+ * need to fix this. -+ * -+ * For example, such situation can happen during vgremove/vgreduce if we -+ * removed/reduced the VG, but we haven't written PV headers yet because -+ * vgremove stopped abruptly for whatever reason just before writing new -+ * PV headers with updated state, including PV extension flags (and so the -+ * PV_EXT_USED flag). -+ * -+ * However, in case the PV has no MDAs at all, we can't double-check -+ * whether the PV_EXT_USED is correct or not - if that PV is marked -+ * as used, it's either: -+ * - really used (but other disks with MDAs are missing) -+ * - or the error state as described above is hit -+ * -+ * User needs to overwrite the PV header directly if it's really clear -+ * the PV having no MDAs does not belong to any VG and at the same time -+ * it's still marked as being in use (pvcreate -ff will fix this). -+ * -+ * Note that the above doesn't account for the case where the PV has -+ * VG metadata that fails to be parsed. In that case, the PV looks -+ * like an in-use orphan, and is auto-repaired here. A PV with -+ * unparsable metadata should be kept on a special list of devices -+ * (like duplicate PVs) that are not auto-repaired, cannot be used -+ * by pvcreate, and are displayed with a special flag by 'pvs'. -+ */ -+ -+#if 0 - static int _check_or_repair_orphan_pv_ext(struct physical_volume *pv, - struct lvmcache_info *info, - struct _vg_read_orphan_baton *b) -@@ -3760,12 +3795,15 @@ static int _check_or_repair_orphan_pv_ext(struct physical_volume *pv, - - return 1; - } -+#endif - - static int _vg_read_orphan_pv(struct lvmcache_info *info, void *baton) - { - struct _vg_read_orphan_baton *b = baton; - struct physical_volume *pv = NULL; - struct pv_list *pvl; -+ uint32_t ext_version; -+ uint32_t ext_flags; - - if (!(pv = _pv_read(b->vg->cmd, b->vg->vgmem, dev_name(lvmcache_device(info)), - b->vg->fid, b->warn_flags, 0))) { -@@ -3781,10 +3819,59 @@ static int _vg_read_orphan_pv(struct lvmcache_info *info, void *baton) - pvl->pv = pv; - add_pvl_to_vgs(b->vg, pvl); - -+ /* -+ * FIXME: this bit of code that does the auto repair is disabled -+ * until we can distinguish cases where the repair should not -+ * happen, i.e. the VG metadata could not be read/parsed. -+ * -+ * A PV holding VG metadata that lvm can't understand -+ * (e.g. damaged, checksum error, unrecognized flag) -+ * will appear as an in-use orphan, and would be cleared -+ * by this repair code. Disable this repair until the -+ * code can keep track of these problematic PVs, and -+ * distinguish them from actual in-use orphans. -+ */ -+ -+ /* - if (!_check_or_repair_orphan_pv_ext(pv, info, baton)) { - stack; - return 0; - } -+ */ -+ -+ /* -+ * Nothing to do if PV header extension < 2: -+ * - version 0 is PV header without any extensions, -+ * - version 1 has bootloader area support only and -+ * we're not checking anything for that one here. -+ */ -+ ext_version = lvmcache_ext_version(info); -+ ext_flags = lvmcache_ext_flags(info); -+ -+ /* -+ * Warn about a PV that has the in-use flag set, but appears in -+ * the orphan VG (no VG was found referencing it.) -+ * There are a number of conditions that could lead to this: -+ * -+ * . The PV was created with no mdas and is used in a VG with -+ * other PVs (with metadata) that have not yet appeared on -+ * the system. So, no VG metadata is found by lvm which -+ * references the in-use PV with no mdas. -+ * -+ * . vgremove could have failed after clearing mdas but -+ * before clearing the in-use flag. In this case, the -+ * in-use flag needs to be manually cleared on the PV. -+ * -+ * . The PV may have damanged/unrecognized VG metadata -+ * that lvm could not read. -+ * -+ * . The PV may have no mdas, and the PVs with the metadata -+ * may have damaged/unrecognized metadata. -+ */ -+ if ((ext_version >= 2) && (ext_flags & PV_EXT_USED)) { -+ log_warn("WARNING: PV %s is marked in use but no VG was found using it.", pv_dev_name(pv)); -+ log_warn("WARNING: PV %s might need repairing.", pv_dev_name(pv)); -+ } - - return 1; - } -@@ -3910,7 +3997,13 @@ static int _check_reappeared_pv(struct volume_group *correct_vg, - * confusing. - */ - if (correct_vg->cmd->handles_missing_pvs) -- return rv; -+ return rv; -+ -+ /* -+ * Skip this if there is no underlying device present for this PV. -+ */ -+ if (!pv->dev) -+ return rv; - - dm_list_iterate_items(pvl, &correct_vg->pvs) - if (pv->dev == pvl->pv->dev && is_missing_pv(pvl->pv)) { -@@ -4039,6 +4132,7 @@ static int _check_or_repair_pv_ext(struct cmd_context *cmd, - struct volume_group *vg, - int repair, int *inconsistent_pvs) - { -+ char uuid[64] __attribute__((aligned(8))); - struct lvmcache_info *info; - uint32_t ext_version, ext_flags; - struct pv_list *pvl; -@@ -4052,6 +4146,14 @@ static int _check_or_repair_pv_ext(struct cmd_context *cmd, - if (is_missing_pv(pvl->pv)) - continue; - -+ if (!pvl->pv->dev) { -+ /* is_missing_pv doesn't catch NULL dev */ -+ memset(&uuid, 0, sizeof(uuid)); -+ id_write_format(&pvl->pv->id, uuid, sizeof(uuid)); -+ log_warn("WARNING: Not repairing PV %s with missing device.", uuid); -+ continue; -+ } -+ - if (!(info = lvmcache_info_from_pvid(pvl->pv->dev->pvid, pvl->pv->dev, 0))) { - log_error("Failed to find cached info for PV %s.", pv_dev_name(pvl->pv)); - goto out; -@@ -4165,8 +4267,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd, - if (lvmetad_used() && !use_precommitted) { - if ((correct_vg = lvmcache_get_vg(cmd, vgname, vgid, precommitted))) { - dm_list_iterate_items(pvl, &correct_vg->pvs) -- if (pvl->pv->dev) -- reappeared += _check_reappeared_pv(correct_vg, pvl->pv, *consistent); -+ reappeared += _check_reappeared_pv(correct_vg, pvl->pv, *consistent); - if (reappeared && *consistent) - *consistent = _repair_inconsistent_vg(correct_vg); - else -@@ -5863,7 +5964,11 @@ static struct volume_group *_vg_lock_and_read(struct cmd_context *cmd, const cha - if (failure) - goto_bad; - -- return _vg_make_handle(cmd, vg, failure); -+ if (!(vg = _vg_make_handle(cmd, vg, failure)) || vg_read_error(vg)) -+ if (!already_locked) -+ unlock_vg(cmd, vg, vg_name); -+ -+ return vg; - - bad: - if (!already_locked) -@@ -5924,7 +6029,12 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, - struct volume_group *vg_read_for_update(struct cmd_context *cmd, const char *vg_name, - const char *vgid, uint32_t read_flags, uint32_t lockd_state) - { -- return vg_read(cmd, vg_name, vgid, read_flags | READ_FOR_UPDATE, lockd_state); -+ struct volume_group *vg = vg_read(cmd, vg_name, vgid, read_flags | READ_FOR_UPDATE, lockd_state); -+ -+ if (!vg || vg_read_error(vg)) -+ stack; -+ -+ return vg; - } - - /* -@@ -5953,9 +6063,8 @@ uint32_t vg_read_error(struct volume_group *vg_handle) - */ - uint32_t vg_lock_newname(struct cmd_context *cmd, const char *vgname) - { -- if (!lock_vol(cmd, vgname, LCK_VG_WRITE, NULL)) { -+ if (!lock_vol(cmd, vgname, LCK_VG_WRITE, NULL)) - return FAILED_LOCKING; -- } - - /* Find the vgname in the cache */ - /* If it's not there we must do full scan to be completely sure */ -diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c -index b708442..52def78 100644 ---- a/lib/metadata/raid_manip.c -+++ b/lib/metadata/raid_manip.c -@@ -57,6 +57,25 @@ static int _reshape_is_supported(struct cmd_context *cmd, const struct segment_t - } - - /* -+ * Check if rebuild CTR args are allowed when other images exist in the array -+ * with empty metadata areas for this kernel. -+ */ -+static int _rebuild_with_emptymeta_is_supported(struct cmd_context *cmd, -+ const struct segment_type *segtype) -+{ -+ unsigned attrs; -+ -+ if (!segtype->ops->target_present || -+ !segtype->ops->target_present(cmd, NULL, &attrs) || -+ !(attrs & RAID_FEATURE_NEW_DEVICES_ACCEPT_REBUILD)) { -+ log_verbose("RAID module does not support rebuild+emptymeta."); -+ return 0; -+ } -+ -+ return 1; -+} -+ -+/* - * Ensure region size exceeds the minimum for @lv because - * MD's bitmap is limited to tracking 2^21 regions. - * -@@ -285,6 +304,17 @@ static int _deactivate_and_remove_lvs(struct volume_group *vg, struct dm_list *r - struct lv_list *lvl; - - dm_list_iterate_items(lvl, removal_lvs) { -+ if (!lv_is_visible(lvl->lv)) { -+ log_error(INTERNAL_ERROR -+ "LVs must be set visible before removing."); -+ return 0; -+ } -+ /* Got to get any cluster lock an SubLVs to be removed. */ -+ if (!activate_lv_excl_local(vg->cmd, lvl->lv)) -+ return_0; -+ } -+ -+ dm_list_iterate_items(lvl, removal_lvs) { - if (!deactivate_lv(vg->cmd, lvl->lv)) - return_0; - if (!lv_remove(lvl->lv)) -@@ -379,23 +409,6 @@ int lv_raid_in_sync(const struct logical_volume *lv) - return _raid_in_sync(lv); - } - --/* Check if RaidLV @lv is synced or any raid legs of @lv are not synced */ --static int _raid_devs_sync_healthy(struct logical_volume *lv) --{ -- char *raid_health; -- -- if (!_raid_in_sync(lv)) -- return 0; -- -- if (!seg_is_raid1(first_seg(lv))) -- return 1; -- -- if (!lv_raid_dev_health(lv, &raid_health)) -- return_0; -- -- return (strchr(raid_health, 'a') || strchr(raid_health, 'D')) ? 0 : 1; --} -- - /* - * _raid_remove_top_layer - * @lv -@@ -427,8 +440,10 @@ static int _raid_remove_top_layer(struct logical_volume *lv, - return 0; - } - -- if (!(lvl_array = dm_pool_alloc(lv->vg->vgmem, 2 * sizeof(*lvl)))) -+ if (!(lvl_array = dm_pool_alloc(lv->vg->vgmem, 2 * sizeof(*lvl)))) { -+ log_error("Memory allocation failed."); - return_0; -+ } - - /* Add last metadata area to removal_lvs */ - lvl_array[0].lv = seg_metalv(seg, 0); -@@ -786,8 +801,10 @@ static int _reorder_raid10_near_seg_areas(struct lv_segment *seg, enum raid0_rai - /* FIXME: once more data copies supported with raid10 */ - stripes /= data_copies; - -- if (!(idx = dm_pool_zalloc(seg_lv(seg, 0)->vg->vgmem, seg->area_count * sizeof(*idx)))) -- return 0; -+ if (!(idx = dm_pool_zalloc(seg_lv(seg, 0)->vg->vgmem, seg->area_count * sizeof(*idx)))) { -+ log_error("Memory allocation failed."); -+ return_0; -+ } - - /* Set up positional index array */ - switch (conv) { -@@ -1056,8 +1073,10 @@ static int _alloc_image_components(struct logical_volume *lv, - const char *raid_segtype; - - if (!(lvl_array = dm_pool_alloc(lv->vg->vgmem, -- sizeof(*lvl_array) * count * 2))) -+ sizeof(*lvl_array) * count * 2))) { -+ log_error("Memory allocation failed."); - return_0; -+ } - - if (!(parallel_areas = build_parallel_areas_from_lv(lv, 0, 1))) - return_0; -@@ -1250,6 +1269,10 @@ static int _cmp_level(const struct segment_type *t1, const struct segment_type * - (!segtype_is_any_raid10(t1) && segtype_is_any_raid10(t2))) - return 0; - -+ if ((segtype_is_raid4(t1) && segtype_is_raid5_n(t2)) || -+ (segtype_is_raid5_n(t1) && segtype_is_raid4(t2))) -+ return 1; -+ - return !strncmp(t1->name, t2->name, 5); - } - -@@ -1627,6 +1650,8 @@ static int _lv_free_reshape_space_with_status(struct logical_volume *lv, enum al - } else if (where_it_was) - *where_it_was = alloc_none; - -+ lv->status &= ~LV_RESHAPE; -+ - return 1; - } - -@@ -1834,6 +1859,9 @@ static int _raid_reshape_add_images(struct logical_volume *lv, - - seg->stripe_size = new_stripe_size; - -+ /* Define image adding reshape (used as SEGTYPE_FLAG to avoid incompatible activations on old runtime) */ -+ lv->status |= LV_RESHAPE; -+ - return 1; - } - -@@ -1933,6 +1961,8 @@ static int _raid_reshape_remove_images(struct logical_volume *lv, - if (seg_is_any_raid5(seg) && new_image_count == 2) - seg->data_copies = 2; - -+ /* Define image removing reshape (used as SEGTYPE_FLAG to avoid incompatible activations on old runtime) */ -+ lv ->status |= LV_RESHAPE; - break; - - case 1: -@@ -1971,7 +2001,6 @@ static int _raid_reshape_remove_images(struct logical_volume *lv, - return 0; - - seg->area_count = new_image_count; -- - break; - - default: -@@ -1986,10 +2015,11 @@ static int _raid_reshape_remove_images(struct logical_volume *lv, - /* - * HM Helper: - * -- * Reshape: keep images in RAID @lv but change stripe size or data copies -+ * Reshape: keep images in RAID @lv but change layout, stripe size or data copies - * - */ - static const char *_get_segtype_alias(const struct segment_type *segtype); -+static const char *_get_segtype_alias_str(const struct logical_volume *lv, const struct segment_type *segtype); - static int _raid_reshape_keep_images(struct logical_volume *lv, - const struct segment_type *new_segtype, - int yes, int force, int *force_repair, -@@ -2001,10 +2031,13 @@ static int _raid_reshape_keep_images(struct logical_volume *lv, - struct lv_segment *seg = first_seg(lv); - - if (seg->segtype != new_segtype) -- log_print_unless_silent("Converting %s LV %s to %s.", -- lvseg_name(seg), display_lvname(lv), new_segtype->name); -- if (!yes && yes_no_prompt("Are you sure you want to convert %s LV %s to %s? [y/n]: ", -- lvseg_name(seg), display_lvname(lv), new_segtype->name) == 'n') { -+ log_print_unless_silent("Converting %s%s LV %s to %s%s.", -+ lvseg_name(seg), _get_segtype_alias_str(lv, seg->segtype), -+ display_lvname(lv), new_segtype->name, -+ _get_segtype_alias_str(lv, new_segtype)); -+ -+ if (!yes && yes_no_prompt("Are you sure you want to convert %s LV %s? [y/n]: ", -+ lvseg_name(seg), display_lvname(lv)) == 'n') { - log_error("Logical volume %s NOT converted.", display_lvname(lv)); - return 0; - } -@@ -2022,12 +2055,9 @@ static int _raid_reshape_keep_images(struct logical_volume *lv, - * The dm-raid target is able to use the space whereever it - * is found by appropriately selecting forward or backward reshape. - */ -- if (seg->segtype != new_segtype) { -- const char *alias = _get_segtype_alias(seg->segtype); -- -- if (!strcmp(alias, new_segtype->name)) -- alloc_reshape_space = 0; -- } -+ if (seg->segtype != new_segtype && -+ !strcmp(_get_segtype_alias(seg->segtype), new_segtype->name)) -+ alloc_reshape_space = 0; - - if (seg->stripe_size != new_stripe_size) - alloc_reshape_space = 1; -@@ -2043,6 +2073,9 @@ static int _raid_reshape_keep_images(struct logical_volume *lv, - - seg->segtype = new_segtype; - -+ /* Define stripesize/raid algorithm reshape (used as SEGTYPE_FLAG to avoid incompatible activations on old runtime) */ -+ lv->status |= LV_RESHAPE; -+ - return 1; - } - -@@ -2226,6 +2259,8 @@ static int _raid_reshape(struct logical_volume *lv, - return 0; - } - -+ lv->status &= ~LV_RESHAPE; /* Reset any reshaping segtype flag */ -+ - dm_list_init(&removal_lvs); - - /* No change in layout requested ? */ -@@ -2311,6 +2346,12 @@ static int _raid_reshape(struct logical_volume *lv, - - /* Handle disk addition reshaping */ - if (old_image_count < new_image_count) { -+ /* FIXME: remove once MD kernel rhbz1443999 got fixed. */ -+ if (sysconf(_SC_NPROCESSORS_ONLN) < 2) { -+ log_error("Can't add stripes to LV %s on single core.", display_lvname(lv)); -+ return 0; -+ } -+ - if (!_raid_reshape_add_images(lv, new_segtype, yes, - old_image_count, new_image_count, - new_stripes, new_stripe_size, allocate_pvs)) -@@ -2318,6 +2359,12 @@ static int _raid_reshape(struct logical_volume *lv, - - /* Handle disk removal reshaping */ - } else if (old_image_count > new_image_count) { -+ /* FIXME: remove once MD kernel rhbz1443999 got fixed. */ -+ if (sysconf(_SC_NPROCESSORS_ONLN) < 2) { -+ log_error("Can't remove stripes from LV %s on single core.", display_lvname(lv)); -+ return 0; -+ } -+ - if (!_raid_reshape_remove_images(lv, new_segtype, yes, force, - old_image_count, new_image_count, - new_stripes, new_stripe_size, -@@ -2505,6 +2552,7 @@ static int _raid_add_images_without_commit(struct logical_volume *lv, - struct dm_list meta_lvs, data_lvs; - struct lv_list *lvl; - struct lv_segment_area *new_areas; -+ struct segment_type *segtype; - - if (lv_is_not_synced(lv)) { - log_error("Can't add image to out-of-sync RAID LV:" -@@ -2536,8 +2584,19 @@ static int _raid_add_images_without_commit(struct logical_volume *lv, - * LV to accompany it. - */ - if (seg_is_linear(seg)) { -- /* A complete resync will be done, no need to mark each sub-lv */ -- status_mask = ~(LV_REBUILD); -+ /* -+ * As of dm-raid version 1.9.0, it is possible to specify -+ * RAID table lines with the 'rebuild' parameters necessary -+ * to force a "recover" instead of a "resync" on upconvert. -+ * -+ * LVM's interaction with older kernels should be as before - -+ * performing a complete resync rather than a set of rebuilds. -+ */ -+ if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_RAID1))) -+ return_0; -+ -+ if (!_rebuild_with_emptymeta_is_supported(lv->vg->cmd, segtype)) -+ status_mask = ~(LV_REBUILD); - - /* FIXME: allow setting region size on upconvert from linear */ - seg->region_size = get_default_region_size(lv->vg->cmd); -@@ -2803,6 +2862,87 @@ static int _extract_image_components(struct lv_segment *seg, uint32_t idx, - } - - /* -+ * _raid_allow_extraction -+ * @lv -+ * @extract_count -+ * @target_pvs -+ * -+ * returns: 0 if no, 1 if yes -+ */ -+static int _raid_allow_extraction(struct logical_volume *lv, -+ int extract_count, -+ struct dm_list *target_pvs) -+{ -+ int s, redundancy = 0; -+ char *dev_health; -+ char *sync_action; -+ struct lv_segment *seg = first_seg(lv); -+ struct cmd_context *cmd = lv->vg->cmd; -+ -+ /* If in-sync or hanlding repairs, allow to proceed. */ -+ if (_raid_in_sync(lv) || lv->vg->cmd->handles_missing_pvs) -+ return 1; -+ -+ /* -+ * FIXME: -+ * Right now, we are primarily concerned with down-converting of -+ * RAID1 LVs, but parity RAIDs and RAID10 will also have to be -+ * considered. -+ * (e.g. It would not be good to allow extracting a dev from a -+ * stripe set while upconverting to RAID5/6.) -+ */ -+ if (!segtype_is_raid1(seg->segtype)) -+ return 1; -+ -+ /* -+ * We can allow extracting images if the array is performing a -+ * sync operation as long as it is "recover" and the image is not -+ * a primary image or if "resync". -+ */ -+ if (!lv_raid_sync_action(lv, &sync_action) || -+ !lv_raid_dev_health(lv, &dev_health)) -+ return_0; -+ -+ if (!strcmp("idle", sync_action)) { -+ log_error(INTERNAL_ERROR -+ "RAID LV should not be out-of-sync and \"idle\""); -+ return 0; -+ } -+ -+ if (!strcmp("resync", sync_action)) -+ return 1; -+ -+ /* If anything other than "recover" */ -+ if (strcmp("recover", sync_action)) { -+ log_error("Unable to remove RAID image while array" -+ " is performing \"%s\"", sync_action); -+ return 0; -+ } -+ -+ if (seg->area_count != strlen(dev_health)) { -+ log_error(INTERNAL_ERROR -+ "RAID LV area_count differs from number of health characters"); -+ return 0; -+ } -+ -+ for (s = 0; s < seg->area_count; s++) -+ if (dev_health[s] == 'A') -+ redundancy++; -+ -+ for (s = 0; (s < seg->area_count) && extract_count; s++) { -+ if (!lv_is_on_pvs(seg_lv(seg, s), target_pvs) && -+ !lv_is_on_pvs(seg_metalv(seg, s), target_pvs)) -+ continue; -+ if ((dev_health[s] == 'A') && !--redundancy) { -+ log_error("Unable to remove all primary source devices"); -+ return 0; -+ } -+ extract_count--; -+ } -+ return 1; -+} -+ -+/* - * _raid_extract_images - * @lv - * @force: force a replacement in case of primary mirror leg -@@ -2833,6 +2973,10 @@ static int _raid_extract_images(struct logical_volume *lv, - struct segment_type *error_segtype; - - extract = seg->area_count - new_count; -+ -+ if (!_raid_allow_extraction(lv, extract, target_pvs)) -+ return_0; -+ - log_verbose("Extracting %u %s from %s.", extract, - (extract > 1) ? "images" : "image", - display_lvname(lv)); -@@ -2888,20 +3032,8 @@ static int _raid_extract_images(struct logical_volume *lv, - if (!lv_is_on_pvs(seg_lv(seg, s), target_pvs) && - !lv_is_on_pvs(seg_metalv(seg, s), target_pvs)) - continue; -- -- /* -- * Kernel may report raid LV in-sync but still -- * image devices may not be in-sync or faulty. -- */ -- if (!_raid_devs_sync_healthy(lv) && -- (!seg_is_mirrored(seg) || (s == 0 && !force))) { -- log_error("Unable to extract %sRAID image" -- " while RAID array is not in-sync%s.", -- seg_is_mirrored(seg) ? "primary " : "", -- seg_is_mirrored(seg) ? " (use --force option to replace)" : ""); -- return 0; -- } - } -+ - if (!_extract_image_components(seg, s, &rmeta_lv, &rimage_lv)) { - log_error("Failed to extract %s from %s.", - display_lvname(seg_lv(seg, s)), -@@ -3035,6 +3167,13 @@ int lv_raid_change_image_count(struct logical_volume *lv, int yes, uint32_t new_ - const char *level = seg->area_count == 1 ? "raid1 with " : ""; - const char *resil = new_count < seg->area_count ? "reducing" : "enhancing"; - -+ /* LV must be active to perform raid conversion operations */ -+ if (!lv_is_active(lv)) { -+ log_error("%s must be active to perform this operation.", -+ display_lvname(lv)); -+ return 0; -+ } -+ - if (new_count != 1 && /* Already prompted for in _raid_remove_images() */ - !yes && yes_no_prompt("Are you sure you want to convert %s LV %s to %s%u images %s resilience? [y/n]: ", - lvseg_name(first_seg(lv)), display_lvname(lv), level, new_count, resil) == 'n') { -@@ -4437,6 +4576,7 @@ static int _log_possible_conversion(uint64_t *processed_segtypes, void *data) - return 1; - } - -+/* Return any segment type alias name for @segtype or empty string */ - static const char *_get_segtype_alias(const struct segment_type *segtype) - { - if (!strcmp(segtype->name, SEG_TYPE_NAME_RAID5)) -@@ -4460,12 +4600,28 @@ static const char *_get_segtype_alias(const struct segment_type *segtype) - return ""; - } - -+/* Return any segment type alias string (format " (same as raid*)") for @segtype or empty string */ -+static const char *_get_segtype_alias_str(const struct logical_volume *lv, const struct segment_type *segtype) -+{ -+ const char *alias = _get_segtype_alias(segtype); -+ -+ if (*alias) { -+ const char *msg = " (same as "; -+ size_t sz = strlen(msg) + strlen(alias) + 2; -+ char *buf = dm_pool_alloc(lv->vg->cmd->mem, sz); -+ -+ if (buf) -+ alias = (dm_snprintf(buf, sz, "%s%s)", msg, alias) < 0) ? "" : buf; -+ } -+ -+ return alias; -+} -+ - static int _log_possible_conversion_types(const struct logical_volume *lv, const struct segment_type *new_segtype) - { - unsigned possible_conversions = 0; - const struct lv_segment *seg = first_seg(lv); - struct possible_type *pt = NULL; -- const char *alias; - uint64_t processed_segtypes = UINT64_C(0); - - /* Count any possible segment types @seg an be directly converted to */ -@@ -4476,12 +4632,10 @@ static int _log_possible_conversion_types(const struct logical_volume *lv, const - if (!possible_conversions) - log_error("Direct conversion of %s LV %s is not possible.", lvseg_name(seg), display_lvname(lv)); - else { -- alias = _get_segtype_alias(seg->segtype); -- -- log_error("Converting %s from %s%s%s%s is " -+ log_error("Converting %s from %s%s is " - "directly possible to the following layout%s:", - display_lvname(lv), lvseg_name(seg), -- *alias ? " (same as " : "", alias, *alias ? ")" : "", -+ _get_segtype_alias_str(lv, seg->segtype), - possible_conversions > 1 ? "s" : ""); - - pt = NULL; -@@ -4526,10 +4680,16 @@ static int _takeover_noop(TAKEOVER_FN_ARGS) - - static int _takeover_unsupported(TAKEOVER_FN_ARGS) - { -- log_error("Converting the segment type for %s from %s to %s is not supported.", -- display_lvname(lv), lvseg_name(first_seg(lv)), -- (segtype_is_striped_target(new_segtype) && -- (new_stripes == 1)) ? SEG_TYPE_NAME_LINEAR : new_segtype->name); -+ struct lv_segment *seg = first_seg(lv); -+ -+ if (seg->segtype == new_segtype) -+ log_error("Logical volume %s already is type %s.", -+ display_lvname(lv), lvseg_name(seg)); -+ else -+ log_error("Converting the segment type for %s from %s to %s is not supported.", -+ display_lvname(lv), lvseg_name(seg), -+ (segtype_is_striped_target(new_segtype) && -+ (new_stripes == 1)) ? SEG_TYPE_NAME_LINEAR : new_segtype->name); - - if (!_log_possible_conversion_types(lv, new_segtype)) - stack; -@@ -4749,9 +4909,6 @@ static int _rename_area_lvs(struct logical_volume *lv, const char *suffix) - return_0; - } - -- for (s = 0; s < SLV_COUNT; s++) -- dm_pool_free(lv->vg->cmd->mem, sfx[s]); -- - return 1; - } - -@@ -4844,6 +5001,15 @@ static int _raid45_to_raid54_wrapper(TAKEOVER_FN_ARGS) - return 0; - } - -+ if (!yes && yes_no_prompt("Are you sure you want to convert %s%s LV %s to %s%s type? [y/n]: ", -+ lvseg_name(seg), _get_segtype_alias_str(lv, seg->segtype), -+ display_lvname(lv), new_segtype->name, -+ _get_segtype_alias_str(lv, new_segtype)) == 'n') { -+ log_error("Logical volume %s NOT converted to \"%s\".", -+ display_lvname(lv), new_segtype->name); -+ return 0; -+ } -+ - log_debug_metadata("Converting LV %s from %s to %s.", display_lvname(lv), - (seg_is_raid4(seg) ? SEG_TYPE_NAME_RAID4 : SEG_TYPE_NAME_RAID5_N), - (seg_is_raid4(seg) ? SEG_TYPE_NAME_RAID5_N : SEG_TYPE_NAME_RAID4)); -@@ -5018,7 +5184,7 @@ static int _takeover_downconvert_wrapper(TAKEOVER_FN_ARGS) - } - - if (segtype_is_raid4(new_segtype)) -- return _raid45_to_raid54_wrapper(lv, new_segtype, yes, force, first_seg(lv)->area_count, -+ return _raid45_to_raid54_wrapper(lv, new_segtype, 1 /* yes */, force, first_seg(lv)->area_count, - 1 /* data_copies */, 0, 0, 0, allocate_pvs); - - return 1; -@@ -5200,7 +5366,7 @@ static int _takeover_upconvert_wrapper(TAKEOVER_FN_ARGS) - if (!(raid5_n_segtype = get_segtype_from_flag(lv->vg->cmd, SEG_RAID5_N))) - return_0; - -- /* raid6 upconvert: vonvert to raid5_n preserving already allocated new image component pair */ -+ /* raid6 upconvert: convert to raid5_n preserving already allocated new image component pair */ - if (segtype_is_any_raid6(new_segtype)) { - struct logical_volume *meta_lv, *data_lv; - -@@ -5217,7 +5383,7 @@ static int _takeover_upconvert_wrapper(TAKEOVER_FN_ARGS) - extents_copied, seg_len); - seg->area_count--; - -- if (!_raid45_to_raid54_wrapper(lv, raid5_n_segtype, yes, force, seg->area_count, -+ if (!_raid45_to_raid54_wrapper(lv, raid5_n_segtype, 1 /* yes */, force, seg->area_count, - 1 /* data_copies */, 0, 0, 0, allocate_pvs)) - return 0; - -@@ -5751,94 +5917,172 @@ static uint64_t _r5_to_r6[][2] = { - - - /* Return segment type flag for raid5 -> raid6 conversions */ --static uint64_t _get_r56_flag(const struct lv_segment *seg, unsigned idx) -+static uint64_t _get_r56_flag(const struct segment_type *segtype, unsigned idx) - { - unsigned elems = ARRAY_SIZE(_r5_to_r6); - - while (elems--) -- if (seg->segtype->flags & _r5_to_r6[elems][idx]) -+ if (segtype->flags & _r5_to_r6[elems][idx]) - return _r5_to_r6[elems][!idx]; - - return 0; - } - --/* Return segment type flag for raid5 -> raid6 conversions */ -+/* Return segment type flag of @seg for raid5 -> raid6 conversions */ - static uint64_t _raid_seg_flag_5_to_6(const struct lv_segment *seg) - { -- return _get_r56_flag(seg, 0); -+ return _get_r56_flag(seg->segtype, 0); - } - --/* Return segment type flag for raid6 -> raid5 conversions */ -+/* Return segment type flag of @seg for raid6 -> raid5 conversions */ - static uint64_t _raid_seg_flag_6_to_5(const struct lv_segment *seg) - { -- return _get_r56_flag(seg, 1); -+ return _get_r56_flag(seg->segtype, 1); - } - --/* Change segtype for raid4 <-> raid5 <-> raid6 where necessary. */ --static int _set_convenient_raid1456_segtype_to(const struct lv_segment *seg_from, -- const struct segment_type **segtype, -- int yes) -+/* Return segment type flag of @segtype for raid5 -> raid6 conversions */ -+static uint64_t _raid_segtype_flag_5_to_6(const struct segment_type *segtype) - { -- size_t len = min(strlen((*segtype)->name), strlen(lvseg_name(seg_from))); -- uint64_t seg_flag; -+ return _get_r56_flag(segtype, 0); -+} -+ -+/* Change segtype for raid* for convenience where necessary. */ -+/* FIXME: do this like _conversion_options_allowed()? */ -+static int _set_convenient_raid145610_segtype_to(const struct lv_segment *seg_from, -+ const struct segment_type **segtype, -+ int yes) -+{ -+ uint64_t seg_flag = 0; - struct cmd_context *cmd = seg_from->lv->vg->cmd; - const struct segment_type *segtype_sav = *segtype; - - /* Bail out if same RAID level is requested. */ -- if (!strncmp((*segtype)->name, lvseg_name(seg_from), len)) -+ if (is_same_level(seg_from->segtype, *segtype)) - return 1; - -- /* Striped/raid0 -> raid5/6 */ -+ log_debug("Checking LV %s requested %s segment type for convenience", -+ display_lvname(seg_from->lv), (*segtype)->name); -+ -+ /* striped/raid0 -> raid5/6 */ - if (seg_is_striped(seg_from) || seg_is_any_raid0(seg_from)) { - /* If this is any raid5 conversion request -> enforce raid5_n, because we convert from striped */ -- if (segtype_is_any_raid5(*segtype) && !segtype_is_raid5_n(*segtype)) { -+ if (segtype_is_any_raid5(*segtype) && !segtype_is_raid5_n(*segtype)) - seg_flag = SEG_RAID5_N; -- goto replaced; - - /* If this is any raid6 conversion request -> enforce raid6_n_6, because we convert from striped */ -- } else if (segtype_is_any_raid6(*segtype) && !segtype_is_raid6_n_6(*segtype)) { -+ else if (segtype_is_any_raid6(*segtype) && !segtype_is_raid6_n_6(*segtype)) - seg_flag = SEG_RAID6_N_6; -- goto replaced; -+ -+ /* raid1 -> */ -+ } else if (seg_is_raid1(seg_from) && !segtype_is_mirror(*segtype)) { -+ if (seg_from->area_count != 2) { -+ log_warn("Convert %s LV %s to 2 images first.", -+ lvseg_name(seg_from), display_lvname(seg_from->lv)); -+ return 0; -+ -+ } else if (segtype_is_striped(*segtype) || -+ segtype_is_any_raid0(*segtype) || -+ segtype_is_raid10(*segtype)) -+ seg_flag = SEG_RAID5_N; -+ -+ else if (!segtype_is_raid4(*segtype) && !segtype_is_any_raid5(*segtype)) -+ seg_flag = SEG_RAID5_LS; -+ -+ /* raid4/raid5 -> striped/raid0/raid1/raid6/raid10 */ -+ } else if (seg_is_raid4(seg_from) || seg_is_any_raid5(seg_from)) { -+ if (segtype_is_raid1(*segtype) && -+ seg_from->area_count != 2) { -+ log_warn("Convert %s LV %s to 2 stripes first (i.e. --stripes 1).", -+ lvseg_name(seg_from), display_lvname(seg_from->lv)); -+ return 0; -+ -+ } else if (seg_is_raid4(seg_from) && -+ segtype_is_any_raid5(*segtype) && -+ !segtype_is_raid5_n(*segtype)) -+ seg_flag = SEG_RAID5_N; -+ -+ else if (seg_is_any_raid5(seg_from) && -+ segtype_is_raid4(*segtype) && -+ !segtype_is_raid5_n(*segtype)) -+ seg_flag = SEG_RAID5_N; -+ -+ else if (segtype_is_raid10(*segtype)) { -+ if (seg_from->area_count < 3) { -+ log_warn("Convert %s LV %s to minimum 3 stripes first (i.e. --stripes 2).", -+ lvseg_name(seg_from), display_lvname(seg_from->lv)); -+ return 0; -+ } -+ -+ seg_flag = SEG_RAID0_META; -+ -+ } else if (segtype_is_any_raid6(*segtype)) { -+ if (seg_from->area_count < 4) { -+ log_warn("Convert %s LV %s to minimum 4 stripes first (i.e. --stripes 3).", -+ lvseg_name(seg_from), display_lvname(seg_from->lv)); -+ return 0; -+ -+ } else if (seg_is_raid4(seg_from) && !segtype_is_raid6_n_6(*segtype)) -+ seg_flag = SEG_RAID6_N_6; -+ else -+ seg_flag = _raid_seg_flag_5_to_6(seg_from); - } - -- /* raid4 -> raid5_n */ -- } else if (seg_is_raid4(seg_from) && segtype_is_any_raid5(*segtype)) { -- seg_flag = SEG_RAID5_N; -- goto replaced; -+ /* raid6 -> striped/raid0/raid5/raid10 */ -+ } else if (seg_is_any_raid6(seg_from)) { -+ if (segtype_is_raid1(*segtype)) { -+ /* No result for raid6_{zr,nr,nc} */ -+ if (!(seg_flag = _raid_seg_flag_6_to_5(seg_from)) || -+ !(seg_flag & (*segtype)->flags)) -+ seg_flag = SEG_RAID6_LS_6; - -- /* raid4/raid5_n -> striped/raid0/raid6 */ -- } else if ((seg_is_raid4(seg_from) || seg_is_raid5_n(seg_from)) && -- !segtype_is_striped(*segtype) && -- !segtype_is_any_raid0(*segtype) && -- !segtype_is_raid1(*segtype) && -- !segtype_is_raid4(*segtype) && -- !segtype_is_raid5_n(*segtype) && -- !segtype_is_raid6_n_6(*segtype)) { -- seg_flag = SEG_RAID6_N_6; -- goto replaced; -- -- /* Got to do check for raid5 -> raid6 ... */ -- } else if (seg_is_any_raid5(seg_from) && segtype_is_any_raid6(*segtype)) { -- if (!(seg_flag = _raid_seg_flag_5_to_6(seg_from))) -- return_0; -- goto replaced; -+ } else if (segtype_is_any_raid10(*segtype)) { -+ seg_flag = seg_is_raid6_n_6(seg_from) ? SEG_RAID0_META : SEG_RAID6_N_6; -+ -+ } else if ((segtype_is_striped(*segtype) || segtype_is_any_raid0(*segtype)) && -+ !seg_is_raid6_n_6(seg_from)) { -+ seg_flag = SEG_RAID6_N_6; -+ -+ } else if (segtype_is_raid4(*segtype) && !seg_is_raid6_n_6(seg_from)) { -+ seg_flag = SEG_RAID6_N_6; - -- /* ... and raid6 -> raid5 */ -- } else if (seg_is_any_raid6(seg_from) && segtype_is_any_raid5(*segtype)) { -- /* No result for raid6_{zr,nr,nc} */ -- if (!(seg_flag = _raid_seg_flag_6_to_5(seg_from))) -+ } else if (segtype_is_any_raid5(*segtype)) -+ /* No result for raid6_{zr,nr,nc} */ -+ if (!(seg_flag = _raid_seg_flag_6_to_5(seg_from)) || -+ !(seg_flag & (*segtype)->flags)) -+ seg_flag = _raid_segtype_flag_5_to_6(*segtype); -+ -+ /* -> raid1 */ -+ } else if (!seg_is_mirror(seg_from) && segtype_is_raid1(*segtype)) { -+ if (!seg_is_raid4(seg_from) && !seg_is_any_raid5(seg_from)) { -+ log_warn("Convert %s LV %s to raid4/raid5 first.", -+ lvseg_name(seg_from), display_lvname(seg_from->lv)); - return 0; -- goto replaced; -- } - -- return 1; -+ } else if (seg_from->area_count != 2) { -+ log_warn("Convert %s LV %s to 2 stripes first (i.e. --stripes 1).", -+ lvseg_name(seg_from), display_lvname(seg_from->lv)); -+ return 0; -+ -+ } -+ -+ /* raid10 -> ... */ -+ } else if (seg_is_raid10(seg_from) && -+ !segtype_is_striped(*segtype) && -+ !segtype_is_any_raid0(*segtype)) -+ seg_flag = SEG_RAID0_META; -+ -+ if (seg_flag) { -+ if (!(*segtype = get_segtype_from_flag(cmd, seg_flag))) -+ return_0; -+ if (segtype_sav != *segtype) { -+ log_warn("Replaced LV type %s%s with possible type %s.", -+ segtype_sav->name, _get_segtype_alias_str(seg_from->lv, segtype_sav), -+ (*segtype)->name); -+ log_warn("Repeat this command to convert to %s after an interim conversion has finished.", -+ segtype_sav->name); -+ } -+ } - --replaced: -- if (!(*segtype = get_segtype_from_flag(cmd, seg_flag))) -- return_0; -- if (segtype_sav != *segtype) -- log_warn("Replaced LV type %s with possible type %s.", -- segtype_sav->name, (*segtype)->name); - return 1; - } - -@@ -5905,6 +6149,8 @@ static int _region_size_change_requested(struct logical_volume *lv, int yes, con - return 0; - } - -+ lv->status &= ~LV_RESHAPE; -+ - if (!lv_update_and_reload_origin(lv)) - return_0; - -@@ -5924,7 +6170,7 @@ static int _conversion_options_allowed(const struct lv_segment *seg_from, - int r = 1; - uint32_t opts; - -- if (!new_image_count && !_set_convenient_raid1456_segtype_to(seg_from, segtype_to, yes)) -+ if (!new_image_count && !_set_convenient_raid145610_segtype_to(seg_from, segtype_to, yes)) - return_0; - - if (!_get_allowed_conversion_options(seg_from, *segtype_to, new_image_count, &opts)) { -@@ -5952,12 +6198,28 @@ static int _conversion_options_allowed(const struct lv_segment *seg_from, - } - - if (r && -+ !yes && - strcmp((*segtype_to)->name, SEG_TYPE_NAME_MIRROR) && /* "mirror" is prompted for later */ -- !yes && yes_no_prompt("Are you sure you want to convert %s LV %s to %s type? [y/n]: ", -- lvseg_name(seg_from), display_lvname(seg_from->lv), -+ !is_same_level(seg_from->segtype, *segtype_to)) { /* Prompt here for takeover */ -+ const char *basic_fmt = "Are you sure you want to convert %s LV %s"; -+ const char *type_fmt = " to %s type"; -+ const char *question_fmt = "? [y/n]: "; -+ char *fmt; -+ size_t sz = strlen(basic_fmt) + ((seg_from->segtype == *segtype_to) ? 0 : strlen(type_fmt)) + strlen(question_fmt) + 1; -+ -+ if (!(fmt = dm_pool_alloc(seg_from->lv->vg->cmd->mem, sz))) -+ return_0; -+ -+ if (dm_snprintf(fmt, sz, "%s%s%s", basic_fmt, (seg_from->segtype == *segtype_to) ? "" : type_fmt, question_fmt) < 0) { -+ log_error(INTERNAL_ERROR "dm_snprintf failed."); -+ return_0; -+ } -+ -+ if (yes_no_prompt(fmt, lvseg_name(seg_from), display_lvname(seg_from->lv), - (*segtype_to)->name) == 'n') { -- log_error("Logical volume %s NOT converted.", display_lvname(seg_from->lv)); -- r = 0; -+ log_error("Logical volume %s NOT converted.", display_lvname(seg_from->lv)); -+ r = 0; -+ } - } - - return r; -@@ -6014,6 +6276,15 @@ int lv_raid_convert(struct logical_volume *lv, - uint32_t available_slvs, removed_slvs; - takeover_fn_t takeover_fn; - -+ /* FIXME If not active, prompt and activate */ -+ /* FIXME Some operations do not require the LV to be active */ -+ /* LV must be active to perform raid conversion operations */ -+ if (!lv_is_active(lv)) { -+ log_error("%s must be active to perform this operation.", -+ display_lvname(lv)); -+ return 0; -+ } -+ - new_segtype = new_segtype ? : seg->segtype; - if (!new_segtype) { - log_error(INTERNAL_ERROR "New segtype not specified."); -@@ -6040,6 +6311,15 @@ int lv_raid_convert(struct logical_volume *lv, - region_size = region_size ? : get_default_region_size(lv->vg->cmd); - - /* -+ * Check acceptible options mirrors, region_size, -+ * stripes and/or stripe_size have been provided. -+ */ -+ if (!_conversion_options_allowed(seg, &new_segtype, yes, -+ 0 /* Takeover */, 0 /*new_data_copies*/, new_region_size, -+ new_stripes, new_stripe_size_supplied)) -+ return _log_possible_conversion_types(lv, new_segtype); -+ -+ /* - * reshape of capable raid type requested - */ - switch (_reshape_requested(lv, new_segtype, data_copies, region_size, stripes, stripe_size)) { -@@ -6074,15 +6354,6 @@ int lv_raid_convert(struct logical_volume *lv, - return 0; - } - -- /* -- * Check acceptible options mirrors, region_size, -- * stripes and/or stripe_size have been provided. -- */ -- if (!_conversion_options_allowed(seg, &new_segtype, yes, -- 0 /* Takeover */, 0 /*new_data_copies*/, new_region_size, -- new_stripes, new_stripe_size_supplied)) -- return _log_possible_conversion_types(lv, new_segtype); -- - takeover_fn = _get_takeover_fn(first_seg(lv), new_segtype, new_image_count); - - /* Exit without doing activation checks if the combination isn't possible */ -@@ -6117,15 +6388,6 @@ int lv_raid_convert(struct logical_volume *lv, - (segtype_is_striped_target(new_segtype) && - (new_stripes == 1)) ? SEG_TYPE_NAME_LINEAR : new_segtype->name); - -- /* FIXME If not active, prompt and activate */ -- /* FIXME Some operations do not require the LV to be active */ -- /* LV must be active to perform raid conversion operations */ -- if (!lv_is_active(lv)) { -- log_error("%s must be active to perform this operation.", -- display_lvname(lv)); -- return 0; -- } -- - /* In clustered VGs, the LV must be active on this node exclusively. */ - if (vg_is_clustered(lv->vg) && !lv_is_active_exclusive_locally(lv)) { - log_error("%s must be active exclusive locally to " -@@ -6140,6 +6402,8 @@ int lv_raid_convert(struct logical_volume *lv, - return 0; - } - -+ lv->status &= ~LV_RESHAPE; -+ - return takeover_fn(lv, new_segtype, yes, force, new_image_count, 0, new_stripes, stripe_size, - region_size, allocate_pvs); - } -@@ -6229,6 +6493,39 @@ has_enough_space: - } - - /* -+ * _lv_raid_has_primary_failure_on_recover -+ * @lv -+ * -+ * The kernel behaves strangely in the presense of a primary failure -+ * during a "recover" sync operation. It's not technically a bug, I -+ * suppose, but the output of the status line can make it difficult -+ * to determine that we are in this state. The sync ratio will be -+ * 100% and the sync action will be "idle", but the health characters -+ * will be e.g. "Aaa" or "Aa", where the 'A' is the dead -+ * primary source that cannot be marked dead by the kernel b/c -+ * it is the only source for the remainder of data. -+ * -+ * This function helps to detect that condition. -+ * -+ * Returns: 1 if the state is detected, 0 otherwise. -+ * FIXME: would be better to return -1,0,1 to allow error report. -+ */ -+int _lv_raid_has_primary_failure_on_recover(struct logical_volume *lv) -+{ -+ char *tmp_dev_health; -+ char *tmp_sync_action; -+ -+ if (!lv_raid_sync_action(lv, &tmp_sync_action) || -+ !lv_raid_dev_health(lv, &tmp_dev_health)) -+ return_0; -+ -+ if (!strcmp(tmp_sync_action, "idle") && strchr(tmp_dev_health, 'a')) -+ return 1; -+ -+ return 0; -+} -+ -+/* - * Helper: - * - * _lv_raid_rebuild_or_replace -@@ -6279,11 +6576,38 @@ static int _lv_raid_rebuild_or_replace(struct logical_volume *lv, - } - - if (!_raid_in_sync(lv)) { -+ /* -+ * FIXME: There is a bug in the kernel that prevents 'rebuild' -+ * from being specified when the array is not in-sync. -+ * There are conditions where this should be allowed, -+ * but only when we are doing a repair - as indicated by -+ * 'lv->vg->cmd->handles_missing_pvs'. The above -+ * conditional should be: -+ (!lv->vg->cmd->handles_missing_pvs && !_raid_in_sync(lv)) -+ */ - log_error("Unable to replace devices in %s while it is " - "not in-sync.", display_lvname(lv)); - return 0; - } - -+ if (_lv_raid_has_primary_failure_on_recover(lv)) { -+ /* -+ * I hate having multiple error lines, but this -+ * seems to work best for syslog and CLI. -+ */ -+ log_error("Unable to repair %s/%s. Source devices failed" -+ " before the RAID could synchronize.", -+ lv->vg->name, lv->name); -+ log_error("You should choose one of the following:"); -+ log_error(" 1) deactivate %s/%s, revive failed " -+ "device, re-activate LV, and proceed.", -+ lv->vg->name, lv->name); -+ log_error(" 2) remove the LV (all data is lost)."); -+ log_error(" 3) Seek expert advice to attempt to salvage any" -+ " data from remaining devices."); -+ return 0; -+ } -+ - /* - * How many sub-LVs are being removed? - */ -diff --git a/lib/metadata/segtype.h b/lib/metadata/segtype.h -index 93132c3..2acb894 100644 ---- a/lib/metadata/segtype.h -+++ b/lib/metadata/segtype.h -@@ -290,6 +290,24 @@ struct segment_type *init_unknown_segtype(struct cmd_context *cmd, - #define RAID_FEATURE_RAID4 (1U << 3) /* ! version 1.8 or 1.9.0 */ - #define RAID_FEATURE_SHRINK (1U << 4) /* version 1.9.0 */ - #define RAID_FEATURE_RESHAPE (1U << 5) /* version 1.10.1 */ -+/* -+ * RAID_FEATURE_NEW_DEVICES_ACCEPT_REBUILD -+ * This signifies a behavioral change in dm-raid. Prior to upstream kernel -+ * commit 33e53f068, the kernel would refuse to allow 'rebuild' CTR args to -+ * be submitted when other devices in the array had uninitialized superblocks. -+ * After the commit, these parameters were allowed. -+ * -+ * The most obvious useful case of this new behavior is up-converting a -+ * linear device to RAID1. A new superblock is allocated for the linear dev -+ * and it will be uninitialized, while all the new images are specified for -+ * 'rebuild'. This valid scenario would not have been allowed prior to -+ * commit 33e53f068. -+ * -+ * Commit 33e53f068 did not bump the dm-raid version number. So it exists -+ * in some, but not all 1.8.1 versions of dm-raid. The only way to be -+ * certain the new behavior exists is to check for version 1.9.0. -+ */ -+#define RAID_FEATURE_NEW_DEVICES_ACCEPT_REBUILD (1U << 6) /* version 1.9.0 */ - - #ifdef RAID_INTERNAL - int init_raid_segtypes(struct cmd_context *cmd, struct segtype_library *seglib); -diff --git a/lib/metadata/thin_manip.c b/lib/metadata/thin_manip.c -index f9cd3d0..ad45ce9 100644 ---- a/lib/metadata/thin_manip.c -+++ b/lib/metadata/thin_manip.c -@@ -563,6 +563,12 @@ static uint64_t _estimate_metadata_size(uint32_t data_extents, uint32_t extent_s - return _estimate_size(data_extents, extent_size, chunk_size); - } - -+/* Estimate maximal supportable thin pool data size for given chunk_size */ -+static uint64_t _estimate_max_data_size(uint32_t chunk_size) -+{ -+ return chunk_size * (DEFAULT_THIN_POOL_MAX_METADATA_SIZE * 2) * SECTOR_SIZE / UINT64_C(64); -+} -+ - /* Estimate thin pool chunk size from data and metadata size (in sector units) */ - static uint32_t _estimate_chunk_size(uint32_t data_extents, uint32_t extent_size, - uint64_t metadata_size, int attr) -@@ -628,6 +634,7 @@ int update_thin_pool_params(struct cmd_context *cmd, - { - uint64_t pool_metadata_size = (uint64_t) *pool_metadata_extents * extent_size; - uint32_t estimate_chunk_size; -+ uint64_t max_pool_data_size; - const char *str; - - if (!*chunk_size && -@@ -666,7 +673,7 @@ int update_thin_pool_params(struct cmd_context *cmd, - - /* Check if we should eventually use bigger chunk size */ - while ((pool_metadata_size > -- (DEFAULT_THIN_POOL_OPTIMAL_SIZE / SECTOR_SIZE)) && -+ (DEFAULT_THIN_POOL_OPTIMAL_METADATA_SIZE * 2)) && - (*chunk_size < DM_THIN_MAX_DATA_BLOCK_SIZE)) { - *chunk_size <<= 1; - pool_metadata_size >>= 1; -@@ -704,6 +711,16 @@ int update_thin_pool_params(struct cmd_context *cmd, - } - } - -+ max_pool_data_size = _estimate_max_data_size(*chunk_size); -+ if ((max_pool_data_size / extent_size) < pool_data_extents) { -+ log_error("Selected chunk size %s cannot address more then %s of thin pool data space.", -+ display_size(cmd, *chunk_size), display_size(cmd, max_pool_data_size)); -+ return 0; -+ } -+ -+ log_print_unless_silent("Thin pool volume with chunk size %s can address at most %s of data.", -+ display_size(cmd, *chunk_size), display_size(cmd, max_pool_data_size)); -+ - if (!validate_thin_pool_chunk_size(cmd, *chunk_size)) - return_0; - -diff --git a/lib/raid/raid.c b/lib/raid/raid.c -index 25009f6..8a53d7e 100644 ---- a/lib/raid/raid.c -+++ b/lib/raid/raid.c -@@ -474,6 +474,7 @@ static int _raid_target_present(struct cmd_context *cmd, - { 1, 3, 0, RAID_FEATURE_RAID10, SEG_TYPE_NAME_RAID10 }, - { 1, 7, 0, RAID_FEATURE_RAID0, SEG_TYPE_NAME_RAID0 }, - { 1, 9, 0, RAID_FEATURE_SHRINK, "shrinking" }, -+ { 1, 9, 0, RAID_FEATURE_NEW_DEVICES_ACCEPT_REBUILD, "rebuild+emptymeta" }, - { 1, 10, 1, RAID_FEATURE_RESHAPE, "reshaping" }, - }; - -diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c -index 6ce6c57..b0c9e4b 100644 ---- a/libdm/libdm-stats.c -+++ b/libdm/libdm-stats.c -@@ -4466,6 +4466,7 @@ static struct _extent *_stats_get_extents_for_file(struct dm_pool *mem, int fd, - return extents; - - bad: -+ *count = 0; - dm_pool_abandon_object(mem); - dm_free(buf); - return NULL; -@@ -4536,7 +4537,7 @@ static int _stats_unmap_regions(struct dm_stats *dms, uint64_t group_id, - region = &dms->regions[i]; - nr_old++; - -- if (_find_extent(*count, extents, -+ if (extents && _find_extent(*count, extents, - region->start, region->len)) { - ext.start = region->start; - ext.len = region->len; -@@ -4653,11 +4654,12 @@ static uint64_t *_stats_map_file_regions(struct dm_stats *dms, int fd, - * causing complications in the error path. - */ - if (!(extent_mem = dm_pool_create("extents", sizeof(*extents)))) -- return_0; -+ return_NULL; - - if (!(extents = _stats_get_extents_for_file(extent_mem, fd, count))) { -- dm_pool_destroy(extent_mem); -- return_0; -+ log_very_verbose("No extents found in fd %d", fd); -+ if (!update) -+ goto out; - } - - if (update) { -@@ -4734,7 +4736,10 @@ static uint64_t *_stats_map_file_regions(struct dm_stats *dms, int fd, - if (bounds) - dm_free(hist_arg); - -- dm_pool_free(extent_mem, extents); -+ /* the extent table will be empty if the file has been truncated. */ -+ if (extents) -+ dm_pool_free(extent_mem, extents); -+ - dm_pool_destroy(extent_mem); - - return regions; -@@ -4755,12 +4760,6 @@ out_remove: - *count = 0; - - out: -- /* -- * The table of file extents in 'extents' is always built, so free -- * it explicitly: this will also free any 'old_extents' table that -- * was later allocated from the 'extent_mem' pool by this function. -- */ -- dm_pool_free(extent_mem, extents); - dm_pool_destroy(extent_mem); - dm_free(hist_arg); - dm_free(regions); -@@ -4872,7 +4871,8 @@ uint64_t *dm_stats_update_regions_from_fd(struct dm_stats *dms, int fd, - if (!dm_stats_list(dms, NULL)) - goto bad; - -- if (regroup) -+ /* regroup if there are regions to group */ -+ if (regroup && (*regions != DM_STATS_REGION_NOT_PRESENT)) - if (!_stats_group_file_regions(dms, regions, count, alias)) - goto bad; - -diff --git a/liblvm/lvm_lv.c b/liblvm/lvm_lv.c -index d5ca821..13d6cbf 100644 ---- a/liblvm/lvm_lv.c -+++ b/liblvm/lvm_lv.c -@@ -507,7 +507,7 @@ static int _lv_set_pool_params(struct lvcreate_params *lp, - pool_metadata_size = extents * vg->extent_size / - (lp->chunk_size * (SECTOR_SIZE / 64)); - while ((pool_metadata_size > -- (2 * DEFAULT_THIN_POOL_OPTIMAL_SIZE / SECTOR_SIZE)) && -+ (DEFAULT_THIN_POOL_OPTIMAL_METADATA_SIZE * 2)) && - lp->chunk_size < DM_THIN_MAX_DATA_BLOCK_SIZE) { - lp->chunk_size <<= 1; - pool_metadata_size >>= 1; -diff --git a/man/clvmd.8_main b/man/clvmd.8_main -index 8e9921d..de6ce25 100644 ---- a/man/clvmd.8_main -+++ b/man/clvmd.8_main -@@ -31,6 +31,9 @@ clvmd \(em cluster LVM daemon - clvmd is the daemon that distributes LVM metadata updates around a cluster. - It must be running on all nodes in the cluster and will give an error - if a node in the cluster does not have this daemon running. -+ -+Also see \fBlvmlockd\fP(8) for a newer method of using LVM on shared -+storage. - . - .SH OPTIONS - . -@@ -196,4 +199,6 @@ Defaults to \fI#LVM_PATH#\fP. - .SH SEE ALSO - .BR syslog (3), - .BR lvm.conf (5), --.BR lvm (8) -+.BR lvm (8), -+.BR lvmlockd (8), -+.BR lvmsystemid (7) -diff --git a/man/lvm-fullreport.8_des b/man/lvm-fullreport.8_des -index f350a0a..741cd12 100644 ---- a/man/lvm-fullreport.8_des -+++ b/man/lvm-fullreport.8_des -@@ -3,4 +3,3 @@ and LV segments. The information is all gathered together for each VG - (under a per-VG lock) so it is consistent. Information gathered from - separate calls to \fBvgs\fP, \fBpvs\fP, and \fBlvs\fP can be inconsistent - if information changes between commands. -- -diff --git a/man/lvm.8_main b/man/lvm.8_main -index 7506eaf..bd5d8a7 100644 ---- a/man/lvm.8_main -+++ b/man/lvm.8_main -@@ -537,6 +537,8 @@ directly. - .BR lvs (8) - .BR lvscan (8) - -+.BR lvm-fullreport (8) -+.BR lvm-lvpoll (8) - .BR lvm2-activation-generator (8) - .BR blkdeactivate (8) - .BR lvmdump (8) -diff --git a/man/lvm.conf.5_main b/man/lvm.conf.5_main -index 7b777af..3a45f1c 100644 ---- a/man/lvm.conf.5_main -+++ b/man/lvm.conf.5_main -@@ -10,6 +10,10 @@ being loaded - settings read in later override earlier - settings. File timestamps are checked between commands and if - any have changed, all the files are reloaded. - -+For a description of each lvm.conf setting, run: -+ -+.B lvmconfig --typeconfig default --withcomments --withspaces -+ - The settings defined in lvm.conf can be overridden by any - of these extended configuration methods: - .TP -diff --git a/man/lvmcache.7_main b/man/lvmcache.7_main -index e573b58..1f29185 100644 ---- a/man/lvmcache.7_main -+++ b/man/lvmcache.7_main -@@ -404,6 +404,24 @@ This is equivalent to: - .B lvconvert --type cache --cachepool VG/CachePoolLV VG/OriginLV - - -+.SS Cache metadata formats -+ -+\& -+ -+There are two disk formats for cache metadata. The metadata format can be -+specified when a cache pool is created, and cannot be changed. -+Format \fB2\fP has better performance; it is more compact, and stores -+dirty bits in a separate btree, which improves the speed of shutting down -+the cache. -+With \fBauto\fP, lvm selects the best option provided by the current -+dm-cache kernel target. -+ -+.B lvconvert --type cache-pool --cachemetadataformat auto|1|2 -+.RS -+.B VG/CacheDataLV -+.RE -+ -+ - .SH SEE ALSO - .BR lvm.conf (5), - .BR lvchange (8), -diff --git a/man/lvmetad.8_main b/man/lvmetad.8_main -index 31a89cc..ec55171 100644 ---- a/man/lvmetad.8_main -+++ b/man/lvmetad.8_main -@@ -53,10 +53,13 @@ metadata. - In some cases, lvmetad will be temporarily disabled while it continues - running. In this state, LVM commands will ignore the lvmetad cache and - revert to scanning disks. A warning will also be printed which includes --the reason why lvmetad is not being used. The most common reason is the --existence of duplicate PVs (lvmetad cannot cache data for duplicate PVs.) --Once duplicates have been resolved, the lvmetad cache is can be updated --with pvscan --cache and commands will return to using the cache. -+the reason why lvmetad is not being used. The most common reasons are the -+existence of duplicate PVs (lvmetad cannot cache data for duplicate PVs), -+or an 'lvconvert --repair' command has been run (the lvmetad cache may -+not be reliable while repairs are neeeded.) -+Once duplicates have been resolved, or repairs have been completed, -+the lvmetad cache is can be updated with pvscan --cache and commands -+will return to using the cache. - - Use of lvmetad is enabled/disabled by: - .br -diff --git a/man/lvmlockd.8_main b/man/lvmlockd.8_main -index 1a1c2fc..552eb94 100644 ---- a/man/lvmlockd.8_main -+++ b/man/lvmlockd.8_main -@@ -117,17 +117,22 @@ Assign each host a unique host_id in the range 1-2000 by setting - - .SS 3. start lvmlockd - --Use a service/init file if available, or just run "lvmlockd". -+Use a unit/init file, or run the lvmlockd daemon directly: -+.br -+systemctl start lvm2-lvmlockd - - .SS 4. start lock manager - - .I sanlock - .br -+Use unit/init files, or start wdmd and sanlock daemons directly: -+.br - systemctl start wdmd sanlock - - .I dlm - .br --Follow external clustering documentation when applicable, otherwise: -+Follow external clustering documentation when applicable, or use -+unit/init files: - .br - systemctl start corosync dlm - -@@ -146,8 +151,8 @@ vgchange --lock-start - lvmlockd requires shared VGs to be started before they are used. This is - a lock manager operation to start (join) the VG lockspace, and it may take - some time. Until the start completes, locks for the VG are not available. --LVM commands are allowed to read the VG while start is in progress. (An --init/unit file can also be used to start VGs.) -+LVM commands are allowed to read the VG while start is in progress. (A -+unit/init file can also be used to start VGs.) - - .SS 7. create and activate LVs - -@@ -247,9 +252,9 @@ clvmd for clustering. See below for converting a clvm VG to a lockd VG. - .SS lockd VGs from hosts not using lvmlockd - - Only hosts that use lockd VGs should be configured to run lvmlockd. --However, shared devices used by lockd VGs may be visible from hosts not --using lvmlockd. From a host not using lvmlockd, visible lockd VGs are --ignored in the same way as foreign VGs (see -+However, shared devices in lockd VGs may be visible from hosts not -+using lvmlockd. From a host not using lvmlockd, lockd VGs are ignored -+in the same way as foreign VGs (see - .BR lvmsystemid (7).) - - The --shared option for reporting and display commands causes lockd VGs -@@ -267,9 +272,9 @@ for all vgcreate options. - .B vgcreate - - .IP \[bu] 2 --Creates a local VG with the local system ID when neither lvmlockd nor clvm are configured. -+Creates a local VG with the local host's system ID when neither lvmlockd nor clvm are configured. - .IP \[bu] 2 --Creates a local VG with the local system ID when lvmlockd is configured. -+Creates a local VG with the local host's system ID when lvmlockd is configured. - .IP \[bu] 2 - Creates a clvm VG when clvm is configured. - -@@ -300,10 +305,11 @@ LVM commands request locks from clvmd to use the VG. - - .SS creating the first sanlock VG - --Creating the first sanlock VG is not protected by locking and requires --special attention. This is because sanlock locks exist within the VG, so --they are not available until the VG exists. The first sanlock VG will --contain the "global lock". -+Creating the first sanlock VG is not protected by locking, so it requires -+special attention. This is because sanlock locks exist on storage within -+the VG, so they are not available until the VG exists. The first sanlock -+VG created will automatically contain the "global lock". Be aware of the -+following special considerations: - - .IP \[bu] 2 - The first vgcreate command needs to be given the path to a device that has -@@ -313,6 +319,11 @@ global lock, which will not be available until after the first sanlock VG - is created. - - .IP \[bu] 2 -+Because the first sanlock VG will contain the global lock, this VG needs -+to be accessible to all hosts that will use sanlock shared VGs. All hosts -+will need to use the global lock from the first sanlock VG. -+ -+.IP \[bu] 2 - While running vgcreate for the first sanlock VG, ensure that the device - being used is not used by another LVM command. Allocation of shared - devices is usually protected by the global lock, but this cannot be done -@@ -323,11 +334,6 @@ While running vgcreate for the first sanlock VG, ensure that the VG name - being used is not used by another LVM command. Uniqueness of VG names is - usually ensured by the global lock. - --.IP \[bu] 2 --Because the first sanlock VG will contain the global lock, this VG needs --to be accessible to all hosts that will use sanlock shared VGs. All hosts --will need to use the global lock from the first sanlock VG. -- - See below for more information about managing the sanlock global lock. - - -@@ -383,7 +389,7 @@ lvmlockd is running - the lock manager is running - .br - \[bu] --the VG is visible to the system -+the VG's devices are visible on the system - .br - - A lockd VG can be stopped if all LVs are deactivated. -@@ -425,22 +431,23 @@ activation { - - .SS automatic starting and automatic activation - --Scripts or programs on a host that automatically start VGs will use the --"auto" option to indicate that the command is being run automatically by --the system: -+When system-level scripts/programs automatically start VGs, they should -+use the "auto" option. This option indicates that the command is being -+run automatically by the system: - - vgchange --lock-start --lock-opt auto [ ...] - --Without any additional configuration, including the "auto" option has no --effect; all VGs are started unless restricted by lock_start_list. -+The "auto" option causes the command to follow the lvm.conf -+activation/auto_lock_start_list. If auto_lock_start_list is undefined, -+all VGs are started, just as if the auto option was not used. - --However, when the lvm.conf activation/auto_lock_start_list is defined, the --auto start command performs an additional filtering phase to all VGs being --started, testing each VG name against the auto_lock_start_list. The --auto_lock_start_list defines lockd VGs that will be started by the auto --start command. Visible lockd VGs not included in the list are ignored by --the auto start command. If the list is undefined, all VG names pass this --filter. (The lock_start_list is also still used to filter all VGs.) -+When auto_lock_start_list is defined, it lists the lockd VGs that should -+be started by the auto command. VG names that do not match an item in the -+list will be ignored by the auto start command. -+ -+(The lock_start_list is also still used to filter VG names from all start -+commands, i.e. with or without the auto option. When the lock_start_list -+is defined, only VGs matching a list item can be started with vgchange.) - - The auto_lock_start_list allows a user to select certain lockd VGs that - should be automatically started by the system (or indirectly, those that -@@ -470,14 +477,12 @@ The set of orphan PVs and unused devices. - The properties of orphan PVs, e.g. PV size. - .br - --The global lock is used in shared mode by commands that read this --information, or in exclusive mode by commands that change it. -- --The command 'vgs' acquires the global lock in shared mode because it --reports the list of all VG names. -- --The vgcreate command acquires the global lock in exclusive mode because it --creates a new VG name, and it takes a PV from the list of unused PVs. -+The global lock is acquired in shared mode by commands that read this -+information, or in exclusive mode by commands that change it. For -+example, the command 'vgs' acquires the global lock in shared mode because -+it reports the list of all VG names, and the vgcreate command acquires the -+global lock in exclusive mode because it creates a new VG name, and it -+takes a PV from the list of unused PVs. - - When an LVM command is given a tag argument, or uses select, it must read - all VGs to match the tag or selection, which causes the global lock to be -@@ -485,10 +490,10 @@ acquired. - - .I VG lock - --A VG lock is associated with each VG. The VG lock is acquired in shared --mode to read the VG and in exclusive mode to change the VG (modify the VG --metadata or activate LVs). This lock serializes access to a VG with all --other LVM commands accessing the VG from all hosts. -+A VG lock is associated with each lockd VG. The VG lock is acquired in -+shared mode to read the VG and in exclusive mode to change the VG (modify -+the VG metadata or activating LVs). This lock serializes access to a VG -+with all other LVM commands accessing the VG from all hosts. - - The command 'vgs' will not only acquire the GL lock to read the list of - all VG names, but will acquire the VG lock for each VG prior to reading -@@ -502,7 +507,7 @@ argument. - - An LV lock is acquired before the LV is activated, and is released after - the LV is deactivated. If the LV lock cannot be acquired, the LV is not --activated. LV locks are persistent and remain in place after the -+activated. LV locks are persistent and remain in place when the - activation command is done. GL and VG locks are transient, and are held - only while an LVM command is running. - -@@ -822,8 +827,8 @@ While lvmlockd and clvmd are entirely different systems, LVM command usage - remains similar. Differences are more notable when using lvmlockd's - sanlock option. - --Visible usage differences between lockd VGs with lvmlockd and clvm VGs --with clvmd: -+Visible usage differences between lockd VGs (using lvmlockd) and clvm VGs -+(using clvmd): - - .IP \[bu] 2 - lvm.conf must be configured to use either lvmlockd (use_lvmlockd=1) or -diff --git a/man/lvmraid.7_main b/man/lvmraid.7_main -index f0d28f5..c27f1fa 100644 ---- a/man/lvmraid.7_main -+++ b/man/lvmraid.7_main -@@ -896,7 +896,7 @@ between linear and raid1. - .IP \(bu 3 - between mirror and raid1. - .IP \(bu 3 --between 2-legged raid1 and raid4/5. -+between raid1 with two images and raid4/5. - .IP \(bu 3 - between striped/raid0 and raid4. - .IP \(bu 3 -@@ -912,39 +912,90 @@ between striped/raid0 and raid10. - .IP \(bu 3 - between striped and raid4. - --.SS Examples -+.SS Indirect conversions - --1. Converting an LV from \fBlinear\fP to \fBraid1\fP. -+Converting from one raid level to another may require multiple steps, -+converting first to intermediate raid levels. - --.nf --# lvs -a -o name,segtype,size vg -- LV Type LSize -- lv linear 300.00g -+.B linear to raid6 - --# lvconvert --type raid1 --mirrors 1 vg/lv -+To convert an LV from linear to raid6: -+.br -+1. convert to raid1 with two images -+.br -+2. convert to raid5 (internally raid5_ls) with two images -+.br -+3. convert to raid5 with three or more stripes (reshape) -+.br -+4. convert to raid6 (internally raid6_ls_6) -+.br -+5. convert to raid6 (internally raid6_zr, reshape) - --# lvs -a -o name,segtype,size vg -- LV Type LSize -- lv raid1 300.00g -- [lv_rimage_0] linear 300.00g -- [lv_rimage_1] linear 300.00g -- [lv_rmeta_0] linear 3.00m -- [lv_rmeta_1] linear 3.00m --.fi -+The commands to perform the steps above are: -+.br -+1. lvconvert --type raid1 --mirrors 1 LV -+.br -+2. lvconvert --type raid5 LV -+.br -+3. lvconvert --stripes 3 LV -+.br -+4. lvconvert --type raid6 LV -+.br -+5. lvconvert --type raid6 LV - --2. Converting an LV from \fBmirror\fP to \fBraid1\fP. -+The final conversion from raid6_ls_6 to raid6_zr is done to avoid the -+potential write/recovery performance reduction in raid6_ls_6 because of -+the dedicated parity device. raid6_zr rotates data and parity blocks to -+avoid this. -+ -+.B linear to striped -+ -+To convert an LV from linear to striped: -+.br -+1. convert to raid1 with two images -+.br -+2. convert to raid5_n -+.br -+3. convert to raid5_n with five 128k stripes (reshape) -+.br -+4. convert raid5_n to striped -+ -+The commands to perform the steps above are: -+.br -+1. lvconvert --type raid1 --mirrors 1 LV -+.br -+2. lvconvert --type raid5_n LV -+.br -+3. lvconvert --stripes 5 --stripesize 128k LV -+.br -+4. lvconvert --type striped LV -+ -+The raid5_n type in step 2 is used because it has dedicated parity SubLVs -+at the end, and can be converted to striped directly. The stripe size is -+increased in step 3 to add extra space for the conversion process. This -+step grows the LV size by a factor of five. After conversion, this extra -+space can be reduced (or used to grow the file system using the LV). -+ -+Reversing these steps will convert a striped LV to linear. -+ -+.B raid6 to striped -+ -+To convert an LV from raid6_nr to striped: -+.br -+1. convert to raid6_n_6 -+.br -+2. convert to striped -+ -+The commands to perform the steps above are: -+.br -+1. lvconvert --type raid6_n_6 LV -+.br -+2. lvconvert --type striped LV - --.nf --# lvs -a -o name,segtype,size vg -- LV Type LSize -- lv mirror 100.00g -- [lv_mimage_0] linear 100.00g -- [lv_mimage_1] linear 100.00g -- [lv_mlog] linear 3.00m - - .SS Examples - --1. Converting an LV from \fBlinear\fP to \fBraid1\fP. -+Converting an LV from \fBlinear\fP to \fBraid1\fP. - - .nf - # lvs -a -o name,segtype,size vg -@@ -962,7 +1013,7 @@ between striped and raid4. - [lv_rmeta_1] linear 3.00m - .fi - --2. Converting an LV from \fBmirror\fP to \fBraid1\fP. -+Converting an LV from \fBmirror\fP to \fBraid1\fP. - - .nf - # lvs -a -o name,segtype,size vg -@@ -983,28 +1034,17 @@ between striped and raid4. - [lv_rmeta_1] linear 3.00m - .fi - --3. Converting an LV from \fBlinear\fP to \fBraid1\fP (with 3 images). -+Converting an LV from \fBlinear\fP to \fBraid1\fP (with 3 images). - - .nf --Start with a linear LV: -- --# lvcreate -L1G -n lv vg -- --Convert the linear LV to raid1 with three images --(original linear image plus 2 mirror images): -- - # lvconvert --type raid1 --mirrors 2 vg/lv - .fi - --4. Converting an LV from \fBstriped\fP (with 4 stripes) to \fBraid6_n_6\fP. -+Converting an LV from \fBstriped\fP (with 4 stripes) to \fBraid6_n_6\fP. - - .nf --Start with a striped LV: -- - # lvcreate --stripes 4 -L64M -n lv vg - --Convert the striped LV to raid6_n_6: -- - # lvconvert --type raid6 vg/lv - - # lvs -a -o lv_name,segtype,sync_percent,data_copies -@@ -1051,7 +1091,9 @@ that is done, the new stripe is unquiesced and used.) - - .SS Examples - --1. Converting raid6_n_6 to raid6_nr with rotating data/parity. -+(Command output shown in examples may change.) -+ -+Converting raid6_n_6 to raid6_nr with rotating data/parity. - - This conversion naturally follows a previous conversion from striped/raid0 - to raid6_n_6 (shown above). It completes the transition to a more -@@ -1318,7 +1360,8 @@ In case the RaidLV should be converted to striped: - .nf - # lvconvert --type striped vg/lv - Unable to convert LV vg/lv from raid6_nr to striped. -- Converting vg/lv from raid6_nr is directly possible to the following layouts: -+ Converting vg/lv from raid6_nr is directly possible to the \\ -+ following layouts: - raid6_nc - raid6_zr - raid6_la_6 -@@ -1621,7 +1664,9 @@ RAID6 last parity devices - .br - \[bu] - Fixed dedicated last devices (P-Syndrome N-1 and Q-Syndrome N) -+.RS 2 - with striped data used for striped/raid0 conversions -+.RE - .br - \[bu] - Used for RAID Takeover -@@ -1632,7 +1677,10 @@ raid6_{ls,rs,la,ra}_6 - RAID6 last parity device - .br - \[bu] --Dedicated last parity device used for conversions from/to raid5_{ls,rs,la,ra} -+Dedicated last parity device used for conversions from/to -+.RS 2 -+raid5_{ls,rs,la,ra} -+.RE - - raid6_ls_6 - .br -diff --git a/man/lvmreport.7_main b/man/lvmreport.7_main -index 7a26401..7167df0 100644 ---- a/man/lvmreport.7_main -+++ b/man/lvmreport.7_main -@@ -948,7 +948,7 @@ configuration directly on command line. - - You can obtain the same information with single command where all the - information about PVs, PV segments, LVs and LV segments are obtained --per VG under a single VG lock for consistency, see also \fBlvm fullreport\fP(8) -+per VG under a single VG lock for consistency, see also \fBlvm-fullreport\fP(8) - man page for more information. The fullreport has its own configuration - settings to define field sets to use, similar to individual reports as - displayed above, but configuration settings have "_full" suffix now. -diff --git a/man/lvmsystemid.7_main b/man/lvmsystemid.7_main -index 8c57042..9b36dc3 100644 ---- a/man/lvmsystemid.7_main -+++ b/man/lvmsystemid.7_main -@@ -94,19 +94,18 @@ corrupting the PVs. See the - section for more information. - - .IP \[bu] 2 --The system ID does not protect devices in VG from programs other than LVM. -+The system ID does not protect devices in a VG from programs other than LVM. - - .IP \[bu] 2 --A host using an old version of LVM without the system ID feature will not --recognize a system ID in VGs from other hosts. Even though the old --version of LVM is not blocked from reading a VG with a system ID, it is --blocked from writing to the VG (or its LVs). The system ID feature --changes the write mode of a VG, making it appear read-only to previous --versions of LVM. -- --This also means that if a host downgrades its version of LVM, it would -+A host using an old LVM version (without the system ID feature) will not -+recognize a system ID set in VGs. The old LVM can read a VG with a -+system ID, but is prevented from writing to the VG (or its LVs). -+The system ID feature changes the write mode of a VG, making it appear -+read-only to previous versions of LVM. -+ -+This also means that if a host downgrades to the old LVM version, it would - lose access to any VGs it had created with a system ID. To avoid this, --the system ID should be removed from VGs before downgrading to an LVM -+the system ID should be removed from local VGs before downgrading LVM to a - version without the system ID feature. - - -diff --git a/man/pvchange.8_des b/man/pvchange.8_des -index 802850f..e914e13 100644 ---- a/man/pvchange.8_des -+++ b/man/pvchange.8_des -@@ -1 +1,4 @@ - pvchange changes PV attributes in the VG. -+ -+For options listed in parentheses, any one is required, after which the -+others are optional. -diff --git a/man/see_also.end b/man/see_also.end -index 9e7d3b2..5b07719 100644 ---- a/man/see_also.end -+++ b/man/see_also.end -@@ -46,6 +46,8 @@ - .BR lvs (8) - .BR lvscan (8) - -+.BR lvm-fullreport (8) -+.BR lvm-lvpoll (8) - .BR lvm2-activation-generator (8) - .BR blkdeactivate (8) - .BR lvmdump (8) -diff --git a/man/vgexport.8_des b/man/vgexport.8_des -index f9fa49c..66d3af3 100644 ---- a/man/vgexport.8_des -+++ b/man/vgexport.8_des -@@ -1,6 +1,6 @@ - vgexport makes inactive VGs unknown to the system. In this state, all the - PVs in the VG can be moved to a different system, from which --\fBvgimport\fP can then be run. -+\fBvgimport\fP(8) can then be run. - - Most LVM tools ignore exported VGs. - -diff --git a/scripts/fsadm.sh b/scripts/fsadm.sh -index 26be102..ea14efe 100755 ---- a/scripts/fsadm.sh -+++ b/scripts/fsadm.sh -@@ -75,8 +75,9 @@ BLOCKCOUNT= - MOUNTPOINT= - MOUNTED= - REMOUNT= --PROCMOUNTS="/proc/mounts" --PROCSELFMOUNTINFO="/proc/self/mountinfo" -+PROCDIR="/proc" -+PROCMOUNTS="$PROCDIR/mounts" -+PROCSELFMOUNTINFO="$PROCDIR/self/mountinfo" - NULL="$DM_DEV_DIR/null" - - IFS_OLD=$IFS -@@ -113,8 +114,11 @@ verbose() { - test -n "$VERB" && echo "$TOOL: $@" || true - } - -+# Support multi-line error messages - error() { -- echo "$TOOL: $@" >&2 -+ for i in "$@" ; do -+ echo "$TOOL: $i" >&2 -+ done - cleanup 1 - } - -@@ -178,52 +182,135 @@ decode_size() { - fi - } - -+decode_major_minor() { -+ # 0x00000fff00 mask MAJOR -+ # 0xfffff000ff mask MINOR -+ -+ #MINOR=$(( $1 / 1048576 )) -+ #MAJOR=$(( ($1 - ${MINOR} * 1048576) / 256 )) -+ #MINOR=$(( $1 - ${MINOR} * 1048576 - ${MAJOR} * 256 + ${MINOR} * 256)) -+ -+ echo "$(( ( $1 >> 8 ) & 4095 )):$(( ( ( $1 >> 12 ) & 268435200 ) | ( $1 & 255 ) ))" -+} -+ - # detect filesystem on the given device - # dereference device name if it is symbolic link - detect_fs() { - VOLUME_ORIG=$1 - VOLUME=${1/#"${DM_DEV_DIR}/"/} -- VOLUME=$("$READLINK" $READLINK_E "$DM_DEV_DIR/$VOLUME") || error "Cannot get readlink \"$1\"" -+ VOLUME=$("$READLINK" $READLINK_E "$DM_DEV_DIR/$VOLUME") -+ test -n "$VOLUME" || error "Cannot get readlink \"$1\"." - RVOLUME=$VOLUME - case "$RVOLUME" in -- # hardcoded /dev since udev does not create these entries elsewhere -+ # hardcoded /dev since udev does not create these entries elsewhere - /dev/dm-[0-9]*) - read &1 && VOLUME="$DM_DEV_DIR/mapper/$SYSVOLUME" -- read &1 || error "Cannot get major:minor for \"$VOLUME\"" -+ read &1 || error "Cannot get major:minor for \"$VOLUME\"." -+ MAJOR=${MAJORMINOR%%:*} -+ MINOR=${MAJORMINOR##*:} - ;; - *) -- STAT=$(stat --format "MAJOR=%t MINOR=%T" ${RVOLUME}) || error "Cannot get major:minor for \"$VOLUME\"" -- eval $STAT -- MAJOR=$((0x${MAJOR})) -- MINOR=$((0x${MINOR})) -- MAJORMINOR=${MAJOR}:${MINOR} -+ STAT=$(stat --format "MAJOR=\$((0x%t)) MINOR=\$((0x%T))" ${RVOLUME}) -+ test -n "$STAT" || error "Cannot get major:minor for \"$VOLUME\"." -+ eval "$STAT" -+ MAJORMINOR="${MAJOR}:${MINOR}" - ;; - esac - # use null device as cache file to be sure about the result - # not using option '-o value' to be compatible with older version of blkid -- FSTYPE=$("$BLKID" -c "$NULL" -s TYPE "$VOLUME") || error "Cannot get FSTYPE of \"$VOLUME\"" -+ FSTYPE=$("$BLKID" -c "$NULL" -s TYPE "$VOLUME") -+ test -n "$FSTYPE" || error "Cannot get FSTYPE of \"$VOLUME\"." - FSTYPE=${FSTYPE##*TYPE=\"} # cut quotation marks - FSTYPE=${FSTYPE%%\"*} -- verbose "\"$FSTYPE\" filesystem found on \"$VOLUME\"" -+ verbose "\"$FSTYPE\" filesystem found on \"$VOLUME\"." -+} -+ -+ -+# Check that passed mounted MAJOR:MINOR is not matching $MAJOR:MINOR of resized $VOLUME -+validate_mounted_major_minor() { -+ test "$1" = "$MAJORMINOR" || { -+ local REFNAME=$(dmsetup info -c -j "${1%%:*}" -m "${1##*:}" -o name --noheadings 2>/dev/null) -+ local CURNAME=$(dmsetup info -c -j "$MAJOR" -m "$MINOR" -o name --noheadings 2>/dev/null) -+ error "Cannot ${CHECK+CHECK}${RESIZE+RESIZE} device \"$VOLUME\" without umounting filesystem $MOUNTED first." \ -+ "Mounted filesystem is using device $CURNAME, but referenced device is $REFNAME." \ -+ "Filesystem utilities currently do not support renamed devices." -+ } -+} -+ -+# ATM fsresize & fsck tools are not able to work properly -+# when mounted device has changed its name. -+# So whenever such device no longer exists with original name -+# abort further command processing -+check_valid_mounted_device() { -+ local MOUNTEDMAJORMINOR -+ local VOL=$("$READLINK" $READLINK_E "$1") -+ local CURNAME=$(dmsetup info -c -j "$MAJOR" -m "$MINOR" -o name --noheadings) -+ local SUGGEST="Possibly device \"$1\" has been renamed to \"$CURNAME\"?" -+ -+ # more confused, device is not DM.... -+ test -n "$CURNAME" || SUGGEST="Mounted volume is not a device mapper device???" -+ -+ test -n "$VOL" || -+ error "Cannot access device \"$1\" referenced by mounted filesystem \"$MOUNTED\"." \ -+ "$SUGGEST" \ -+ "Filesystem utilities currently do not support renamed devices." -+ -+ case "$VOL" in -+ # hardcoded /dev since udev does not create these entries elsewhere -+ /dev/dm-[0-9]*) -+ read &1 || error "Cannot get major:minor for \"$VOLUME\"." -+ ;; -+ *) -+ STAT=$(stat --format "MOUNTEDMAJORMINOR=\$((0x%t)):\$((0x%T))" "$VOL") -+ test -n "$STAT" || error "Cannot get major:minor for \"$VOLUME\"." -+ eval "$STAT" -+ ;; -+ esac -+ -+ validate_mounted_major_minor "$MOUNTEDMAJORMINOR" - } - --detect_mounted_with_proc_self_mountinfo() { -- MOUNTED=$("$GREP" "^[0-9]* [0-9]* $MAJORMINOR " "$PROCSELFMOUNTINFO") -+detect_mounted_with_proc_self_mountinfo() { -+ # Check self mountinfo -+ # grab major:minor mounted_device mount_point -+ MOUNTED=$("$GREP" "^[0-9]* [0-9]* $MAJORMINOR " "$PROCSELFMOUNTINFO" 2>/dev/null | head -1) -+ -+ # If device is opened and not yet found as self mounted -+ # check all other mountinfos (since it can be mounted in cgroups) -+ # Use 'find' to not fail on to long list of args with too many pids -+ # only 1st. line is needed -+ test -z "$MOUNTED" && -+ test $(dmsetup info -c --noheading -o open -j "$MAJOR" -m "$MINOR") -gt 0 && -+ MOUNTED=$(find "$PROCDIR" -maxdepth 2 -name mountinfo -print0 | xargs -0 "$GREP" "^[0-9]* [0-9]* $MAJORMINOR " 2>/dev/null | head -1 2>/dev/null) - -- # extract 5th field which is mount point -+ # TODO: for performance compare with sed and stop with 1st. match: -+ # sed -n "/$MAJORMINOR/ {;p;q;}" -+ -+ # extract 2nd field after ' - ' separator as mouted device -+ MOUNTDEV=$(echo ${MOUNTED##* - } | cut -d ' ' -f 2) -+ MOUNTDEV=$(echo -n -e ${MOUNTDEV}) -+ -+ # extract 5th field as mount point - # echo -e translates \040 to spaces -- MOUNTED=$(echo ${MOUNTED} | cut -d " " -f 5) -+ MOUNTED=$(echo ${MOUNTED} | cut -d ' ' -f 5) - MOUNTED=$(echo -n -e ${MOUNTED}) - -- test -n "$MOUNTED" -+ test -n "$MOUNTED" || return 1 # Not seen mounted anywhere -+ -+ check_valid_mounted_device "$MOUNTDEV" - } - --detect_mounted_with_proc_mounts() { -+# With older systems without /proc/*/mountinfo we may need to check -+# every mount point as cannot easily depend on the name of mounted -+# device (which could have been renamed). -+# We need to visit every mount point and check it's major minor -+detect_mounted_with_proc_mounts() { - MOUNTED=$("$GREP" "^$VOLUME[ \t]" "$PROCMOUNTS") - - # for empty string try again with real volume name - test -z "$MOUNTED" && MOUNTED=$("$GREP" "^$RVOLUME[ \t]" "$PROCMOUNTS") - -+ MOUNTDEV=$(echo -n -e ${MOUNTED%% *}) - # cut device name prefix and trim everything past mountpoint - # echo translates \040 to spaces - MOUNTED=${MOUNTED#* } -@@ -231,24 +318,43 @@ detect_mounted_with_proc_mounts() { - - # for systems with different device names - check also mount output - if test -z "$MOUNTED" ; then -+ # will not work with spaces in paths - MOUNTED=$(LC_ALL=C "$MOUNT" | "$GREP" "^$VOLUME[ \t]") - test -z "$MOUNTED" && MOUNTED=$(LC_ALL=C "$MOUNT" | "$GREP" "^$RVOLUME[ \t]") -+ MOUNTDEV=${MOUNTED%% on *} - MOUNTED=${MOUNTED##* on } - MOUNTED=${MOUNTED% type *} # allow type in the mount name - fi - -- test -n "$MOUNTED" -+ if test -n "$MOUNTED" ; then -+ check_valid_mounted_device "$MOUNTDEV" -+ return 0 # mounted -+ fi -+ -+ # If still nothing found and volume is in use -+ # check every known mount point against MAJOR:MINOR -+ if test $(dmsetup info -c --noheading -o open -j "$MAJOR" -m "$MINOR") -gt 0 ; then -+ while IFS=$'\n' read -r i ; do -+ MOUNTDEV=$(echo -n -e ${i%% *}) -+ MOUNTED=${i#* } -+ MOUNTED=$(echo -n -e ${MOUNTED%% *}) -+ STAT=$(stat --format "%d" $MOUNTED) -+ validate_mounted_major_minor $(decode_major_minor "$STAT") -+ done < "$PROCMOUNTS" -+ fi -+ -+ return 1 # nothing is mounted - } - - # check if the given device is already mounted and where - # FIXME: resolve swap usage and device stacking --detect_mounted() { -+detect_mounted() { - if test -e "$PROCSELFMOUNTINFO"; then - detect_mounted_with_proc_self_mountinfo - elif test -e "$PROCMOUNTS"; then - detect_mounted_with_proc_mounts - else -- error "Cannot detect mounted device \"$VOLUME\"" -+ error "Cannot detect mounted device \"$VOLUME\"." - fi - } - -@@ -257,10 +363,13 @@ detect_device_size() { - # check if blockdev supports getsize64 - "$BLOCKDEV" 2>&1 | "$GREP" getsize64 >"$NULL" - if test $? -eq 0; then -- DEVSIZE=$("$BLOCKDEV" --getsize64 "$VOLUME") || error "Cannot read size of device \"$VOLUME\"" -+ DEVSIZE=$("$BLOCKDEV" --getsize64 "$VOLUME") -+ test -n "$DEVSIZE" || error "Cannot read size of device \"$VOLUME\"." - else -- DEVSIZE=$("$BLOCKDEV" --getsize "$VOLUME") || error "Cannot read size of device \"$VOLUME\"" -- SSSIZE=$("$BLOCKDEV" --getss "$VOLUME") || error "Cannot block size read device \"$VOLUME\"" -+ DEVSIZE=$("$BLOCKDEV" --getsize "$VOLUME") -+ test -n "$DEVSIZE" || error "Cannot read size of device \"$VOLUME\"." -+ SSSIZE=$("$BLOCKDEV" --getss "$VOLUME") -+ test -n "$SSSIZE" || error "Cannot read sector size of device \"$VOLUME\"." - DEVSIZE=$(($DEVSIZE * $SSSIZE)) - fi - } -@@ -273,14 +382,14 @@ round_up_block_size() { - } - - temp_mount() { -- dry "$MKDIR" -p -m 0000 "$TEMPDIR" || error "Failed to create $TEMPDIR" -- dry "$MOUNT" "$VOLUME" "$TEMPDIR" || error "Failed to mount $TEMPDIR" -+ dry "$MKDIR" -p -m 0000 "$TEMPDIR" || error "Failed to create $TEMPDIR." -+ dry "$MOUNT" "$VOLUME" "$TEMPDIR" || error "Failed to mount $TEMPDIR." - } - - temp_umount() { -- dry "$UMOUNT" "$TEMPDIR" || error "Failed to umount \"$TEMPDIR\"" -- dry "$RMDIR" "${TEMPDIR}" || error "Failed to remove \"$TEMPDIR\"" -- dry "$RMDIR" "${TEMPDIR%%m}" || error "Failed to remove \"${TEMPDIR%%m}\"" -+ dry "$UMOUNT" "$TEMPDIR" || error "Failed to umount \"$TEMPDIR\"." -+ dry "$RMDIR" "${TEMPDIR}" || error "Failed to remove \"$TEMPDIR\"," -+ dry "$RMDIR" "${TEMPDIR%%m}" || error "Failed to remove \"${TEMPDIR%%m}\"." - } - - yes_no() { -@@ -292,19 +401,24 @@ yes_no() { - - while read -r -s -n 1 ANS ; do - case "$ANS" in -- "y" | "Y" | "") echo y ; return 0 ;; -- "n" | "N") echo n ; return 1 ;; -+ "y" | "Y" ) echo y ; return 0 ;; -+ "" ) if [ -t 1 ] ; then -+ echo y ; return 0 -+ fi ;; - esac - done -+ -+ echo n -+ return 1 - } - - try_umount() { - yes_no "Do you want to unmount \"$MOUNTED\"" && dry "$UMOUNT" "$MOUNTED" && return 0 -- error "Cannot proceed with mounted filesystem \"$MOUNTED\"" -+ error "Cannot proceed with mounted filesystem \"$MOUNTED\"." - } - - validate_parsing() { -- test -n "$BLOCKSIZE" && test -n "$BLOCKCOUNT" || error "Cannot parse $1 output" -+ test -n "$BLOCKSIZE" && test -n "$BLOCKCOUNT" || error "Cannot parse $1 output." - } - #################################### - # Resize ext2/ext3/ext4 filesystem -@@ -312,6 +426,9 @@ validate_parsing() { - # - unmounted for downsize - #################################### - resize_ext() { -+ local IS_MOUNTED=0 -+ detect_mounted && IS_MOUNTED=1 -+ - verbose "Parsing $TUNE_EXT -l \"$VOLUME\"" - for i in $(LC_ALL=C "$TUNE_EXT" -l "$VOLUME"); do - case "$i" in -@@ -324,7 +441,7 @@ resize_ext() { - FSFORCE=$FORCE - - if [ "$NEWBLOCKCOUNT" -lt "$BLOCKCOUNT" -o "$EXTOFF" -eq 1 ]; then -- detect_mounted && verbose "$RESIZE_EXT needs unmounted filesystem" && try_umount -+ test $IS_MOUNTED -eq 1 && verbose "$RESIZE_EXT needs unmounted filesystem" && try_umount - REMOUNT=$MOUNTED - if test -n "$MOUNTED" ; then - # Forced fsck -f for umounted extX filesystem. -@@ -374,7 +491,7 @@ resize_xfs() { - MOUNTPOINT=$MOUNTED - if [ -z "$MOUNTED" ]; then - MOUNTPOINT=$TEMPDIR -- temp_mount || error "Cannot mount Xfs filesystem" -+ temp_mount || error "Cannot mount Xfs filesystem." - fi - verbose "Parsing $TUNE_XFS \"$MOUNTPOINT\"" - for i in $(LC_ALL=C "$TUNE_XFS" "$MOUNTPOINT"); do -@@ -392,7 +509,7 @@ resize_xfs() { - elif [ $NEWBLOCKCOUNT -eq $BLOCKCOUNT ]; then - verbose "Xfs filesystem already has the right size" - else -- error "Xfs filesystem shrinking is unsupported" -+ error "Xfs filesystem shrinking is unsupported." - fi - } - -@@ -412,8 +529,8 @@ resize() { - "ext3"|"ext2"|"ext4") resize_ext $NEWSIZE ;; - "reiserfs") resize_reiser $NEWSIZE ;; - "xfs") resize_xfs $NEWSIZE ;; -- *) error "Filesystem \"$FSTYPE\" on device \"$VOLUME\" is not supported by this tool" ;; -- esac || error "Resize $FSTYPE failed" -+ *) error "Filesystem \"$FSTYPE\" on device \"$VOLUME\" is not supported by this tool." ;; -+ esac || error "Resize $FSTYPE failed." - cleanup 0 - } - -@@ -494,12 +611,12 @@ for i in "$TUNE_EXT" "$RESIZE_EXT" "$TUNE_REISER" "$RESIZE_REISER" \ - test -n "$i" || error "Required command definitions in the script are missing!" - done - --"$LVM" version >"$NULL" 2>&1 || error "Could not run lvm binary \"$LVM\"" -+"$LVM" version >"$NULL" 2>&1 || error "Could not run lvm binary \"$LVM\"." - $("$READLINK" -e / >"$NULL" 2>&1) || READLINK_E="-f" - TEST64BIT=$(( 1000 * 1000000000000 )) --test "$TEST64BIT" -eq 1000000000000000 || error "Shell does not handle 64bit arithmetic" --$(echo Y | "$GREP" Y >"$NULL") || error "Grep does not work properly" --test $("$DATE" -u -d"Jan 01 00:00:01 1970" +%s) -eq 1 || error "Date translation does not work" -+test "$TEST64BIT" -eq 1000000000000000 || error "Shell does not handle 64bit arithmetic." -+$(echo Y | "$GREP" Y >"$NULL") || error "Grep does not work properly." -+test $("$DATE" -u -d"Jan 01 00:00:01 1970" +%s) -eq 1 || error "Date translation does not work." - - - if [ "$#" -eq 0 ] ; then -diff --git a/test/dbus/lvmdbustest.py b/test/dbus/lvmdbustest.py -index 50f6ad4..3dca9d5 100755 ---- a/test/dbus/lvmdbustest.py -+++ b/test/dbus/lvmdbustest.py -@@ -18,6 +18,8 @@ import pyudev - from testlib import * - import testlib - from subprocess import Popen, PIPE -+from glob import glob -+import os - - g_tmo = 0 - -@@ -68,8 +70,12 @@ def lv_n(suffix=None): - return g_prefix + rs(8, s) - - -+def _is_testsuite_pv(pv_name): -+ return g_prefix != "" and pv_name[-1].isdigit() and pv_name[:-1].endswith(g_prefix + "pv") -+ -+ - def is_nested_pv(pv_name): -- return pv_name.count('/') == 3 -+ return pv_name.count('/') == 3 and not _is_testsuite_pv(pv_name) - - - def _root_pv_name(res, pv_name): -@@ -239,6 +245,7 @@ class TestDbusService(unittest.TestCase): - - # Check to make sure the PVs we had to start exist, else re-create - # them -+ self.objs, self.bus = get_objects() - if len(self.pvs) != len(self.objs[PV_INT]): - for p in self.pvs: - found = False -@@ -714,9 +721,9 @@ class TestDbusService(unittest.TestCase): - LV_BASE_INT) - self._validate_lookup("%s/%s" % (vg.Name, lv_name), lv.object_path) - -- def _create_lv(self, thinpool=False, size=None, vg=None): -+ def _create_lv(self, thinpool=False, size=None, vg=None, suffix=None): - -- lv_name = lv_n() -+ lv_name = lv_n(suffix=suffix) - interfaces = list(LV_BASE_INT) - - if thinpool: -@@ -1840,7 +1847,8 @@ class TestDbusService(unittest.TestCase): - self.assertIn(pv_object_path, vg.Vg.Pvs, - "Expecting PV object path in Vg.Pvs") - -- lv = self._create_lv(vg=vg.Vg, size=vg.Vg.FreeBytes) -+ lv = self._create_lv(vg=vg.Vg, size=vg.Vg.FreeBytes, -+ suffix="_pv") - device_path = '/dev/%s/%s' % (vg.Vg.Name, lv.LvCommon.Name) - new_pv_object_path = self._pv_create(device_path) - -@@ -1865,6 +1873,46 @@ class TestDbusService(unittest.TestCase): - for i in range(0, 5): - pv_object_path = self._create_nested(pv_object_path) - -+ def test_pv_symlinks(self): -+ # Lets take one of our test PVs, pvremove it, find a symlink to it -+ # and re-create using the symlink to ensure we return an object -+ # path to it. Additionally, we will take the symlink and do a lookup -+ # (Manager.LookUpByLvmId) using it and the original device path to -+ # ensure that we can find the PV. -+ symlink = None -+ -+ pv = self.objs[PV_INT][0] -+ pv_device_path = pv.Pv.Name -+ -+ self._pv_remove(pv) -+ -+ # Make sure we no longer find the pv -+ rc = self._lookup(pv_device_path) -+ self.assertEqual(rc, '/') -+ -+ # Lets locate a symlink for it -+ devices = glob('/dev/disk/*/*') -+ for d in devices: -+ if pv_device_path == os.path.realpath(d): -+ symlink = d -+ break -+ -+ self.assertIsNotNone(symlink, "We expected to find at least 1 symlink!") -+ -+ # Make sure symlink look up fails too -+ rc = self._lookup(symlink) -+ self.assertEqual(rc, '/') -+ -+ pv_object_path = self._pv_create(symlink) -+ self.assertNotEqual(pv_object_path, '/') -+ -+ pv_proxy = ClientProxy(self.bus, pv_object_path, interfaces=(PV_INT, )) -+ self.assertEqual(pv_proxy.Pv.Name, pv_device_path) -+ -+ # Lets check symlink lookup -+ self.assertEqual(pv_object_path, self._lookup(symlink)) -+ self.assertEqual(pv_object_path, self._lookup(pv_device_path)) -+ - - class AggregateResults(object): - -diff --git a/test/shell/fsadm-renamed.sh b/test/shell/fsadm-renamed.sh -new file mode 100644 -index 0000000..9f3cd3c ---- /dev/null -+++ b/test/shell/fsadm-renamed.sh -@@ -0,0 +1,116 @@ -+#!/bin/sh -+# Copyright (C) 2017 Red Hat, Inc. All rights reserved. -+# -+# This copyrighted material is made available to anyone wishing to use, -+# modify, copy, or redistribute it subject to the terms and conditions -+# of the GNU General Public License v.2. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program; if not, write to the Free Software Foundation, -+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+test_description='Exercise fsadm operation on renamed device' -+SKIP_WITH_LVMLOCKD=1 -+SKIP_WITH_LVMPOLLD=1 -+ -+. lib/inittest -+ -+aux prepare_vg 1 80 -+ -+vg_lv=$vg/$lv1 -+vg_lv_ren=${vg_lv}_renamed -+ -+dev_vg_lv="$DM_DEV_DIR/$vg_lv" -+dev_vg_lv_ren="$DM_DEV_DIR/$vg_lv_ren" -+ -+mount_dir="mnt" -+mount_space_dir="mnt space dir" -+mount_dolar_dir="mnt \$SPACE dir" -+# for recursive call -+export LVM_BINARY=$(which lvm) -+ -+test ! -d "$mount_dir" && mkdir "$mount_dir" -+test ! -d "$mount_space_dir" && mkdir "$mount_space_dir" -+test ! -d "$mount_dolar_dir" && mkdir "$mount_dolar_dir" -+ -+cleanup_mounted_and_teardown() -+{ -+ umount "$mount_dir" || true -+ umount "$mount_space_dir" || true -+ umount "$mount_dolar_dir" || true -+ aux teardown -+} -+ -+# Test for block sizes != 1024 (rhbz #480022) -+trap 'cleanup_mounted_and_teardown' EXIT -+ -+# Iterate over supported filesystems -+for i in mkfs.ext3 mkfs.xfs mkfs.reiserfs -+do -+ -+if not which "$i" ; then -+ echo "Skipping tests for missing $i" -+ continue -+fi -+ -+lvcreate -n $lv1 -L20M $vg -+ -+case "$i" in -+*ext3) MKFS_ARGS="-b1024 -j" ;; -+*xfs) MKFS_ARGS="-l internal,size=1000b -f" ;; -+*reiserfs) MKFS_ARGS="-s 513 -f" ;; -+esac -+ -+echo "$i" -+"$i" $MKFS_ARGS "$dev_vg_lv" -+ -+# Adding couple udev wait ops as some older systemd -+# might get confused and was 'randomly/racy' umounting -+# devices just mounted. -+# -+# See for explanation: -+# https://github.com/systemd/systemd/commit/628c89cc68ab96fce2de7ebba5933725d147aecc -+# https://github.com/systemd/systemd/pull/2017 -+aux udev_wait -+ -+mount "$dev_vg_lv" "$mount_dir" -+ -+aux udev_wait -+ -+lvrename $vg_lv $vg_lv_ren -+ -+mount | tee out -+grep $vg out -+ -+# fails on renamed LV -+fail lvresize -L+10M -r $vg_lv_ren -+ -+# fails on unknown mountpoint (FIXME: umount) -+not umount "$dev_vg_lv" -+ -+lvcreate -L20 -n $lv1 $vg -+"$i" $MKFS_ARGS "$dev_vg_lv" -+ -+aux udev_wait -+ -+mount "$dev_vg_lv" "$mount_dolar_dir" -+ -+mount | tee out -+grep $vg out -+ -+not lvresize -L+10M -r $vg_lv_ren -+ -+umount "$mount_dir" -+ -+# FIXME: lvresize CANNOT handle/propagage '--yes' to fsadm -+echo y | lvresize -L+10M -r $vg_lv -+ -+aux udev_wait -+ -+umount "$mount_dolar_dir" -+ -+lvremove -ff $vg -+ -+done -+ -+vgremove -ff $vg -diff --git a/test/shell/lvchange-raid.sh b/test/shell/lvchange-raid.sh -index 34a40dc..7418cd5 100644 ---- a/test/shell/lvchange-raid.sh -+++ b/test/shell/lvchange-raid.sh -@@ -42,6 +42,7 @@ run_writemostly_check() { - - printf "#\n#\n#\n# %s/%s (%s): run_writemostly_check\n#\n#\n#\n" \ - $vg $lv $segtype -+ aux wait_for_sync $vg $lv - - # No writemostly flag should be there yet. - check lv_attr_bit health $vg/${lv}_rimage_0 "-" -diff --git a/test/shell/lvconvert-raid-regionsize.sh b/test/shell/lvconvert-raid-regionsize.sh -index 9884c1b..d2c8a54 100644 ---- a/test/shell/lvconvert-raid-regionsize.sh -+++ b/test/shell/lvconvert-raid-regionsize.sh -@@ -64,6 +64,7 @@ _test_regionsizes raid1 - # Clean up - lvremove --yes $vg - -+if aux have_raid 1 10 1; then - # Create 5-way raid6 - lvcreate --yes -aey --type raid6 -i 3 --stripesize 128K -R 256K -L8M -n $lv1 $vg - check lv_field $vg/$lv1 segtype "raid6" -@@ -78,7 +79,11 @@ _test_regionsizes raid6 - - # Clean up - lvremove --yes $vg -+else -+ echo "Skipping RAID6 tests" -+fi - -+if aux have_raid 1 10 1; then - # Create 6-way raid01 - lvcreate --yes -aey --type raid10 -i 3 -m 1 --stripesize 128K -R 256K -L8M -n $lv1 $vg - check lv_field $vg/$lv1 segtype "raid10" -@@ -90,5 +95,8 @@ aux wait_for_sync $vg $lv1 - fsck -fn "$DM_DEV_DIR/$vg/$lv1" - - _test_regionsizes raid10 -+else -+ echo "Skipping RAID10 tests" -+fi - - vgremove -ff $vg -diff --git a/test/shell/lvconvert-raid-reshape-striped_to_linear.sh b/test/shell/lvconvert-raid-reshape-striped_to_linear.sh -index 4051862..d926827 100644 ---- a/test/shell/lvconvert-raid-reshape-striped_to_linear.sh -+++ b/test/shell/lvconvert-raid-reshape-striped_to_linear.sh -@@ -79,7 +79,7 @@ aux wait_for_sync $vg $lv1 1 - fsck -fn $DM_DEV_DIR/$vg/$lv1 - - # Remove the now freed legs --lvconvert --stripes 1 $vg/$lv1 -+lvconvert -y --stripes 1 $vg/$lv1 - check lv_first_seg_field $vg/$lv1 segtype "raid5_n" - check lv_first_seg_field $vg/$lv1 data_stripes 1 - check lv_first_seg_field $vg/$lv1 stripes 2 -diff --git a/test/shell/lvconvert-raid.sh b/test/shell/lvconvert-raid.sh -index e173d66..fba7864 100644 ---- a/test/shell/lvconvert-raid.sh -+++ b/test/shell/lvconvert-raid.sh -@@ -223,6 +223,67 @@ for i in 1 2 3 ; do - done - - ########################################### -+# Upconverted RAID1 should not allow loss of primary -+# - don't allow removal of primary while syncing -+# - DO allow removal of secondaries while syncing -+########################################### -+aux delay_dev $dev2 0 100 -+lvcreate -aey -l 2 -n $lv1 $vg $dev1 $dev2 -+lvconvert -y -m 1 $vg/$lv1 \ -+ --config 'global { mirror_segtype_default = "raid1" }' -+lvs --noheadings -o attr $vg/$lv1 | grep '^[[:space:]]*r' -+not lvconvert --yes -m 0 $vg/$lv1 $dev1 -+lvconvert --yes -m 0 $vg/$lv1 $dev2 -+aux enable_dev $dev2 -+lvremove -ff $vg -+ -+########################################### -+# lvcreated RAID1 should allow all down-conversion -+# - DO allow removal of primary while syncing -+# - DO allow removal of secondaries while syncing -+########################################### -+aux delay_dev $dev2 0 100 -+lvcreate --type raid1 -m 2 -aey -l 2 -n $lv1 $vg $dev1 $dev2 $dev3 -+lvconvert --yes -m 1 $vg/$lv1 $dev3 -+lvconvert --yes -m 0 $vg/$lv1 $dev1 -+aux enable_dev $dev2 -+lvremove -ff $vg -+ -+########################################### -+# Converting from 2-way RAID1 to 3-way -+# - DO allow removal of one of primary sources -+# - Do not allow removal of all primary sources -+########################################### -+lvcreate --type raid1 -m 1 -aey -l 2 -n $lv1 $vg $dev1 $dev2 -+aux wait_for_sync $vg $lv1 -+aux delay_dev $dev3 0 100 -+lvconvert --yes -m +1 $vg/$lv1 $dev3 -+# should allow 1st primary to be removed -+lvconvert --yes -m -1 $vg/$lv1 $dev1 -+# should NOT allow last primary to be removed -+not lvconvert --yes -m -1 $vg/$lv1 $dev2 -+# should allow non-primary to be removed -+lvconvert --yes -m 0 $vg/$lv1 $dev3 -+aux enable_dev $dev3 -+lvremove -ff $vg -+ -+########################################### -+# Converting from 2-way RAID1 to 3-way -+# - Should allow removal of two devices, -+# as long as they aren't both primary -+########################################### -+lvcreate --type raid1 -m 1 -aey -l 2 -n $lv1 $vg $dev1 $dev2 -+aux wait_for_sync $vg $lv1 -+aux delay_dev $dev3 0 100 -+lvconvert --yes -m +1 $vg/$lv1 $dev3 -+# should NOT allow both primaries to be removed -+not lvconvert -m 0 $vg/$lv1 $dev1 $dev2 -+# should allow primary + non-primary -+lvconvert --yes -m 0 $vg/$lv1 $dev1 $dev3 -+aux enable_dev $dev3 -+lvremove -ff $vg -+ -+########################################### - # Device Replacement Testing - ########################################### - # RAID1: Replace up to n-1 devices - trying different combinations -diff --git a/test/shell/lvconvert-thin.sh b/test/shell/lvconvert-thin.sh -index c08b95a..992a1f2 100644 ---- a/test/shell/lvconvert-thin.sh -+++ b/test/shell/lvconvert-thin.sh -@@ -135,7 +135,7 @@ lvremove -f $vg - if test "$TSIZE" = 64T; then - lvcreate -L24T -n $lv1 $vg - # Warning about bigger then needed (24T data and 16G -> 128K chunk) --lvconvert --yes -c 64 --thinpool $vg/$lv1 2>&1 | tee err -+fail lvconvert --yes -c 64 --thinpool $vg/$lv1 2>&1 | tee err - grep "WARNING: Chunk size is too small" err - lvremove -f $vg - fi -diff --git a/test/shell/lvcreate-cache.sh b/test/shell/lvcreate-cache.sh -index faa78b2..410e105 100644 ---- a/test/shell/lvcreate-cache.sh -+++ b/test/shell/lvcreate-cache.sh -@@ -26,6 +26,7 @@ aux prepare_vg 5 80000 - - aux lvmconf 'global/cache_disabled_features = [ "policy_smq" ]' - -+ - ####################### - # Cache_Pool creation # - ####################### -@@ -62,6 +63,11 @@ grep "No command with matching syntax recognised" err - # Check nothing has been created yet - check vg_field $vg lv_count 0 - -+# Checks that argument passed with --cachepool is really a cache-pool -+lvcreate -an -l 1 -n $lv1 $vg -+# Hint: nice way to 'tee' only stderr.log so we can check it's log_error() -+fail lvcreate -L10 --cachepool $vg/$lv1 2> >(tee -a stderr.log >&2) -+grep "not a cache pool" stderr.log - - # With --type cache-pool we are clear which segtype has to be created - lvcreate -l 1 --type cache-pool $vg/pool1 -diff --git a/test/shell/lvcreate-large-raid.sh b/test/shell/lvcreate-large-raid.sh -index ca3f715..7ec140b 100644 ---- a/test/shell/lvcreate-large-raid.sh -+++ b/test/shell/lvcreate-large-raid.sh -@@ -101,7 +101,15 @@ lvremove -ff $vg1 - lvcreate -aey -L 200T -n $lv1 $vg1 - lvconvert -y --type raid1 -m 1 $vg1/$lv1 - check lv_field $vg1/$lv1 size "200.00t" --check raid_leg_status $vg1 $lv1 "aa" -+if aux have_raid 1 9 0; then -+ # The 1.9.0 version of dm-raid is capable of performing -+ # linear -> RAID1 upconverts as "recover" not "resync" -+ # The LVM code now checks the dm-raid version when -+ # upconverting and if 1.9.0+ is found, it uses "recover" -+ check raid_leg_status $vg1 $lv1 "Aa" -+else -+ check raid_leg_status $vg1 $lv1 "aa" -+fi - lvremove -ff $vg1 - - # bz837927 END -diff --git a/test/shell/lvcreate-raid-nosync.sh b/test/shell/lvcreate-raid-nosync.sh -index 1f01f47..bd7ec81 100644 ---- a/test/shell/lvcreate-raid-nosync.sh -+++ b/test/shell/lvcreate-raid-nosync.sh -@@ -35,7 +35,7 @@ _sync() { - - # Delay 1st leg so that rebuilding status characters - # can be read before resync finished too quick. --aux delay_dev "$dev1" 0 90 $(get first_extent_sector "$dev1") -+aux delay_dev "$dev1" 0 100 $(get first_extent_sector "$dev1") - - # raid0/raid0_meta don't support resynchronization - for r in raid0 raid0_meta -@@ -58,7 +58,7 @@ lvremove --yes $vg/$lv1 - for r in $segtypes - do - # raid4/5 support resynchronization -- lvcreate --type $r -Zn -i 3 -l 4 -n $lv1 $vg -+ lvcreate --type $r -Zn -i 3 -L10 -n $lv1 $vg - check raid_leg_status $vg $lv1 "aaaa" - _sync "AAAA" - -@@ -77,7 +77,7 @@ _sync "AAAAA" - not lvcreate --type raid6 --nosync -Zn -i 3 -l 1 -n $lv1 $vg - - # raid10 supports resynchronization --lvcreate --type raid10 -m 1 -Zn -i 3 -l 4 -n $lv1 $vg -+lvcreate --type raid10 -m 1 -Zn -i 3 -L10 -n $lv1 $vg - check raid_leg_status $vg $lv1 "aaaaaa" - _sync "AAAAAA" - -diff --git a/test/shell/lvcreate-thin-big.sh b/test/shell/lvcreate-thin-big.sh -index da7812f..9c84288 100644 ---- a/test/shell/lvcreate-thin-big.sh -+++ b/test/shell/lvcreate-thin-big.sh -@@ -36,7 +36,7 @@ grep "WARNING: Minimum" out - lvcreate -L4M --chunksize 64k --poolmetadatasize 17G -T $vg/pool2 2>out - grep "WARNING: Maximum" out - check lv_field $vg/pool1_tmeta size "2.00m" --check lv_field $vg/pool2_tmeta size "16.00g" -+check lv_field $vg/pool2_tmeta size "15.81g" - - # Check can start and see thinpool with metadata size above kernel limit - lvcreate -L4M --poolmetadatasize 16G -T $vg/poolM -diff --git a/test/shell/lvresize-full.sh b/test/shell/lvresize-full.sh -index 17ee6aa..3eef11a 100644 ---- a/test/shell/lvresize-full.sh -+++ b/test/shell/lvresize-full.sh -@@ -20,6 +20,7 @@ SKIP_WITH_LVMPOLLD=1 - FSCK=${FSCK-fsck} - MKFS=${MKFS-mkfs.ext3} - RESIZEFS=${RESIZEFS-resize2fs} -+export LVM_BINARY=$(which lvm) - - which $FSCK || skip - which $MKFS || skip -diff --git a/test/shell/thin-dmeventd-warns.sh b/test/shell/thin-dmeventd-warns.sh -new file mode 100644 -index 0000000..d22863b ---- /dev/null -+++ b/test/shell/thin-dmeventd-warns.sh -@@ -0,0 +1,85 @@ -+#!/bin/sh -+ -+# Copyright (C) 2017 Red Hat, Inc. All rights reserved. -+# -+# This copyrighted material is made available to anyone wishing to use, -+# modify, copy, or redistribute it subject to the terms and conditions -+# of the GNU General Public License v.2. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program; if not, write to the Free Software Foundation, -+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ -+# test if dmeventd produces multiple warnings when pools runs above 80% -+ -+SKIP_WITH_LVMLOCKD=1 -+SKIP_WITH_LVMPOLLD=1 -+SKIP_WITH_CLVMD=1 -+SKIP_WITH_LVMETAD=1 -+ -+. lib/inittest -+ -+which blkdiscard || skip -+ -+percent_() { -+ get lv_field $vg/pool data_percent | cut -d. -f1 -+} -+ -+wait_warn_() { -+ -+ for i in $(seq 1 7) -+ do -+ test $(egrep "WARNING: Thin pool.*is now" debug.log_DMEVENTD_out | wc -l) -eq $1 && return 0 -+ sleep 2 -+ done -+ -+ die "Waiting too log for dmeventd log warning" -+} -+# -+# Main -+# -+aux have_thin 1 0 0 || skip -+ -+aux prepare_dmeventd -+aux prepare_vg -+ -+lvcreate -L8 -V8 -T $vg/pool -n $lv1 -+ -+ -+dd if=/dev/zero of="$DM_DEV_DIR/$vg/$lv1" bs=256K count=26 -+test $(percent_) -gt 80 -+ -+# Give it some time to dmeventd to log WARNING -+wait_warn_ 1 -+ -+dd if=/dev/zero of="$DM_DEV_DIR/$vg/$lv1" bs=256K count=30 -+test $(percent_) -gt 90 -+ -+# Give it some time to dmeventd to log WARNING -+wait_warn_ 2 -+ -+dd if=/dev/zero of="$DM_DEV_DIR/$vg/$lv1" bs=1M count=8 -+test $(percent_) -eq 100 -+ -+wait_warn_ 3 -+ -+blkdiscard "$DM_DEV_DIR/$vg/$lv1" -+ -+# FIXME: Enforce thin-pool metadata commit with flushing status -+dmsetup status ${vg}-pool-tpool -+# Wait for thin-pool monitoring to notice lower values -+sleep 11 -+# ATM dmeventd is not logging event for thin-pool getting -+# below 'WARNED' threshold. -+ -+ -+dd if=/dev/zero of="$DM_DEV_DIR/$vg/$lv1" bs=256K count=30 -+test $(percent_) -gt 90 -+ -+lvs -a $vg -+dmsetup status ${vg}-pool-tpool -+ -+# Check pool again Warns -+wait_warn_ 4 -+ -+vgremove -f $vg -diff --git a/test/shell/thin-large.sh b/test/shell/thin-large.sh -new file mode 100644 -index 0000000..da5a7ec ---- /dev/null -+++ b/test/shell/thin-large.sh -@@ -0,0 +1,54 @@ -+#!/bin/sh -+# Copyright (C) 2017 Red Hat, Inc. All rights reserved. -+# -+# This copyrighted material is made available to anyone wishing to use, -+# modify, copy, or redistribute it subject to the terms and conditions -+# of the GNU General Public License v.2. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program; if not, write to the Free Software Foundation, -+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ -+# 'Exercise logic around boundary sizes of thin-pool data and chunksize -+ -+SKIP_WITH_LVMLOCKD=1 -+SKIP_WITH_LVMPOLLD=1 -+ -+. lib/inittest -+ -+# FIXME update test to make something useful on <16T -+aux can_use_16T || skip -+ -+aux have_thin 1 0 0 || skip -+ -+# Prepare ~1P sized devices -+aux prepare_vg 1 1000000000 -+ -+lvcreate -an -T -L250T $vg/pool250 -+ -+lvcreate -an -T -L250T --poolmetadatasize 16G $vg/pool16 -+ -+fail lvcreate -an -T -L250T --chunksize 64K --poolmetadatasize 16G $vg/pool64 -+ -+# Creation of thin-pool with proper chunk-size but not enough metadata size -+# which can grow later needs to pass -+lvcreate -an -T -L250T --chunksize 1M --poolmetadatasize 4G $vg/pool1024 -+ -+# Creation of chunk should fit -+lvcreate -an -T -L12T --chunksize 64K --poolmetadatasize 16G $vg/pool64 -+ -+check lv_field $vg/pool64 chunksize "64.00k" -+ -+lvremove -ff $vg -+ -+ -+### Check also lvconvert ### -+ -+lvcreate -an -L250T -n pool $vg -+ -+fail lvconvert -y --chunksize 64 --thinpool $vg/pool -+lvconvert -y --chunksize 1M --thinpool $vg/pool -+ -+check lv_field $vg/pool chunksize "1.00m" -+ -+vgremove -ff $vg -diff --git a/test/shell/thin-resize-match.sh b/test/shell/thin-resize-match.sh -index c78842f..46b4531 100644 ---- a/test/shell/thin-resize-match.sh -+++ b/test/shell/thin-resize-match.sh -@@ -12,13 +12,12 @@ - # ensure there is no data loss during thin-pool resize - - SKIP_WITH_LVMLOCKD=1 -+SKIP_WITH_LVMPOLLD=1 - - export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false} - - . lib/inittest - --test -e LOCAL_LVMPOLLD && skip -- - which md5sum || skip - - aux have_thin 1 0 0 || skip -diff --git a/test/shell/unknown-segment.sh b/test/shell/unknown-segment.sh -index 27cea88..20fc920 100644 ---- a/test/shell/unknown-segment.sh -+++ b/test/shell/unknown-segment.sh -@@ -18,9 +18,10 @@ aux prepare_vg 4 - - lvcreate -an -Zn -l 1 -n $lv1 $vg - lvcreate -an -Zn -l 2 --type mirror -m 1 -n $lv2 $vg -+lvcreate -an -Zn --type zero -l 1 -n $lv3 $vg - - vgcfgbackup -f bak0 $vg --sed -e 's,striped,unstriped,;s,mirror,unmirror,' -i.orig bak0 -+sed -e 's,striped,unstriped,;s,mirror,unmirror,;s,zero,zero+NEWFLAG,' -i.orig bak0 - vgcfgrestore -f bak0 $vg - - # we have on-disk metadata with unknown segments now -@@ -28,11 +29,13 @@ not lvchange -aey $vg/$lv1 # check that activation is refused - - # try once more to catch invalid memory access with valgrind - # when clvmd flushes cmd mem pool --not lvchange -aey $vg/$lv1 # check that activation is refused -+not lvchange -aey $vg/$lv2 # check that activation is refused -+ -+not lvchange -aey $vg/$lv3 # check that activation is refused - - vgcfgbackup -f bak1 $vg - cat bak1 --sed -e 's,unstriped,striped,;s,unmirror,mirror,' -i.orig bak1 -+sed -e 's,unstriped,striped,;s,unmirror,mirror,;s,zero+NEWFLAG,zero,' -i.orig bak1 - vgcfgrestore -f bak1 $vg - vgcfgbackup -f bak2 $vg - -diff --git a/test/unit/Makefile.in b/test/unit/Makefile.in -index 70b7e79..7aa180f 100644 ---- a/test/unit/Makefile.in -+++ b/test/unit/Makefile.in -@@ -1,4 +1,4 @@ --# Copyright (C) 2011-2015 Red Hat, Inc. All rights reserved. -+# Copyright (C) 2011-2017 Red Hat, Inc. All rights reserved. - # - # This file is part of LVM2. - # -@@ -24,15 +24,15 @@ UNITS = \ - string_t.c\ - run.c - --include $(top_builddir)/make.tmpl -- --ifeq ($(MAKECMDGOALS),distclean) -+ifeq ("@TESTING@", "yes") - SOURCES = $(UNITS) -+TARGETS = run - endif - --ifeq ("$(TESTING)", "yes") -+include $(top_builddir)/make.tmpl -+ -+ifeq ($(MAKECMDGOALS),distclean) - SOURCES = $(UNITS) --TARGETS = run - endif - - ifeq ("$(TESTING)", "yes") -@@ -42,6 +42,8 @@ CFLAGS += @CUNIT_CFLAGS@ - check: unit - - $(TARGETS): $(OBJECTS) $(top_builddir)/libdm/libdevmapper.$(LIB_SUFFIX) -+ $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) -L$(top_builddir)/libdm \ -+ -o $@ $(OBJECTS) $(LDLIBS) - - unit: $(TARGETS) - @echo Running unit tests -diff --git a/tools/args.h b/tools/args.h -index 87b33e7..f5e864f 100644 ---- a/tools/args.h -+++ b/tools/args.h -@@ -42,7 +42,7 @@ arg(activationmode_ARG, '\0', "activationmode", activationmode_VAL, 0, 0, - - arg(addtag_ARG, '\0', "addtag", tag_VAL, ARG_GROUPABLE, 0, - "Adds a tag to a PV, VG or LV. This option can be repeated to add\n" -- "multiple tags at once. See lvm(8) for information about tags.\n") -+ "multiple tags at once. See \\fBlvm\\fP(8) for information about tags.\n") - - arg(aligned_ARG, '\0', "aligned", 0, 0, 0, - "Use with --separator to align the output columns\n") -@@ -132,10 +132,41 @@ arg(config_ARG, '\0', "config", string_VAL, 0, 0, - "See \\fBlvm.conf\\fP(5) for more information about config.\n") - - arg(configreport_ARG, '\0', "configreport", configreport_VAL, ARG_GROUPABLE, 1, -- "See lvmreport(7).\n") -+ "See \\fBlvmreport\\fP(7).\n") - - arg(configtype_ARG, '\0', "typeconfig", configtype_VAL, 0, 0, -- "See lvmreport(7).\n") -+ "\\fBcurrent\\fP prints the config settings that would be applied\n" -+ "to an lvm command (assuming the command does not override them\n" -+ "on the command line.) This includes:\n" -+ "settings that have been modified in lvm config files,\n" -+ "settings that get their default values from config files,\n" -+ "and default settings that have been uncommented in config files.\n" -+ "\\fBdefault\\fP prints all settings with their default values.\n" -+ "Changes made in lvm config files are not reflected in the output.\n" -+ "Some settings get their default values internally,\n" -+ "and these settings are printed as comments.\n" -+ "Other settings get their default values from config files,\n" -+ "and these settings are not printed as comments.\n" -+ "\\fBdiff\\fP prints only config settings that have been modified\n" -+ "from their default values in config files (the difference between\n" -+ "current and default.)\n" -+ "\\fBfull\\fP prints every setting uncommented and set to the\n" -+ "current value, i.e. how it would be used by an lvm command.\n" -+ "This includes settings modified in config files, settings that usually\n" -+ "get defaults internally, and settings that get defaults from config files.\n" -+ "\\fBlist\\fP prints all config names without values.\n" -+ "\\fBmissing\\fP prints settings that are missing from the\n" -+ "lvm config files. A missing setting that usually gets its default\n" -+ "from config files is printed uncommented and set to the internal default.\n" -+ "Settings that get their default internally and are not set in config files\n" -+ "are printed commented with the internal default.\n" -+ "\\fBnew\\fP prints config settings that have been added since\n" -+ "the lvm version specified by --sinceversion. They are printed\n" -+ "with their default values.\n" -+ "\\fBprofilable\\fP prints settings with their default values that can be set from a profile.\n" -+ "\\fBprofilable-command\\fP prints settings with their default values that can be set from a command profile.\n" -+ "\\fBprofilable-metadata\\fP prints settings with their default values that can be set from a metadata profile.\n" -+ "Also see \\fBlvm.conf\\fP(5).\n") - - arg(dataalignment_ARG, '\0', "dataalignment", sizekb_VAL, 0, 0, - "Align the start of the data to a multiple of this number.\n" -@@ -149,7 +180,7 @@ arg(dataalignmentoffset_ARG, '\0', "dataalignmentoffset", sizekb_VAL, 0, 0, - - arg(deltag_ARG, '\0', "deltag", tag_VAL, ARG_GROUPABLE, 0, - "Deletes a tag from a PV, VG or LV. This option can be repeated to delete\n" -- "multiple tags at once. See lvm(8) for information about tags.\n") -+ "multiple tags at once. See \\fBlvm\\fP(8) for information about tags.\n") - - arg(detachprofile_ARG, '\0', "detachprofile", 0, 0, 0, - "Detaches a metadata profile from a VG or LV.\n" -@@ -188,7 +219,7 @@ arg(force_long_ARG, '\0', "force", 0, ARG_COUNTABLE, 0, - - arg(foreign_ARG, '\0', "foreign", 0, 0, 0, - "Report/display foreign VGs that would otherwise be skipped.\n" -- "See lvmsystemid(7) for more information about foreign VGs.\n") -+ "See \\fBlvmsystemid\\fP(7) for more information about foreign VGs.\n") - - arg(handlemissingpvs_ARG, '\0', "handlemissingpvs", 0, 0, 0, - "Allows a polling operation to continue when PVs are missing,\n" -@@ -198,7 +229,10 @@ arg(ignoreadvanced_ARG, '\0', "ignoreadvanced", 0, 0, 0, - "Exclude advanced configuration settings from the output.\n") - - arg(ignorelocal_ARG, '\0', "ignorelocal", 0, 0, 0, -- "Ignore local section.\n") -+ "Ignore the local section. The local section should be defined in\n" -+ "the lvmlocal.conf file, and should contain config settings\n" -+ "specific to the local host which should not be copied to\n" -+ "other hosts.\n") - - arg(ignorelockingfailure_ARG, '\0', "ignorelockingfailure", 0, 0, 0, - "Allows a command to continue with read-only metadata\n" -@@ -227,25 +261,25 @@ arg(labelsector_ARG, '\0', "labelsector", number_VAL, 0, 0, - - arg(lockopt_ARG, '\0', "lockopt", string_VAL, 0, 0, - "Used to pass options for special cases to lvmlockd.\n" -- "See lvmlockd(8) for more information.\n") -+ "See \\fBlvmlockd\\fP(8) for more information.\n") - - arg(lockstart_ARG, '\0', "lockstart", 0, 0, 0, - "Start the lockspace of a shared VG in lvmlockd.\n" - "lvmlockd locks becomes available for the VG, allowing LVM to use the VG.\n" -- "See lvmlockd(8) for more information.\n") -+ "See \\fBlvmlockd\\fP(8) for more information.\n") - - arg(lockstop_ARG, '\0', "lockstop", 0, 0, 0, - "Stop the lockspace of a shared VG in lvmlockd.\n" - "lvmlockd locks become unavailable for the VG, preventing LVM from using the VG.\n" -- "See lvmlockd(8) for more information.\n") -+ "See \\fBlvmlockd\\fP(8) for more information.\n") - - arg(locktype_ARG, '\0', "locktype", locktype_VAL, 0, 0, - "#vgchange\n" - "Change the VG lock type to or from a shared lock type used with lvmlockd.\n" -- "See lvmlockd(8) for more information.\n" -+ "See \\fBlvmlockd\\fP(8) for more information.\n" - "#vgcreate\n" - "Specify the VG lock type directly in place of using --shared.\n" -- "See lvmlockd(8) for more information.\n") -+ "See \\fBlvmlockd\\fP(8) for more information.\n") - - arg(logonly_ARG, '\0', "logonly", 0, 0, 0, - "Suppress command report and display only log report.\n") -@@ -345,7 +379,7 @@ arg(monitor_ARG, '\0', "monitor", bool_VAL, 0, 0, - "Start (yes) or stop (no) monitoring an LV with dmeventd.\n" - "dmeventd monitors kernel events for an LV, and performs\n" - "automated maintenance for the LV in reponse to specific events.\n" -- "See dmeventd(8) for more information.\n") -+ "See \\fBdmeventd\\fP(8) for more information.\n") - - arg(nameprefixes_ARG, '\0', "nameprefixes", 0, 0, 0, - "Add an \"LVM2_\" prefix plus the field name to the output. Useful\n" -@@ -552,7 +586,7 @@ arg(shared_ARG, '\0', "shared", 0, 0, 0, - "manager is running. This allows multiple hosts to share a VG on shared\n" - "devices. lvmlockd and a lock manager must be configured and running.\n" - "(A shared VG using lvmlockd is different from a clustered VG using clvmd.)\n" -- "See lvmlockd(8) for more information about shared VGs.\n" -+ "See \\fBlvmlockd\\fP(8) for more information about shared VGs.\n" - "#vgs\n" - "#lvs\n" - "#pvs\n" -@@ -562,7 +596,7 @@ arg(shared_ARG, '\0', "shared", 0, 0, 0, - "#pvdisplay\n" - "Report/display shared VGs that would otherwise be skipped when\n" - "lvmlockd is not being used on the host.\n" -- "See lvmlockd(8) for more information about shared VGs.\n") -+ "See \\fBlvmlockd\\fP(8) for more information about shared VGs.\n") - - arg(sinceversion_ARG, '\0', "sinceversion", string_VAL, 0, 0, - "Specify an LVM version in x.y.z format where x is the major version,\n" -@@ -644,12 +678,12 @@ arg(systemid_ARG, '\0', "systemid", string_VAL, 0, 0, - "the host creating it. Using this option requires caution because the\n" - "system ID of the new VG may not match the system ID of the host running\n" - "the command, leaving the VG inaccessible to the host.\n" -- "See lvmsystemid(7) for more information.\n" -+ "See \\fBlvmsystemid\\fP(7) for more information.\n" - "#vgchange\n" - "Changes the system ID of the VG. Using this option requires caution\n" - "because the VG may become foreign to the host running the command,\n" - "leaving the host unable to access it.\n" -- "See lvmsystemid(7) for more information.\n") -+ "See \\fBlvmsystemid\\fP(7) for more information.\n") - - arg(thinpool_ARG, '\0', "thinpool", lv_VAL, 0, 0, - "The name of a thin pool LV.\n") -@@ -808,6 +842,9 @@ arg(metadatacopies_ARG, '\0', "metadatacopies", metadatacopies_VAL, 0, 0, NULL) - * ... and now the short args. - */ - arg(activate_ARG, 'a', "activate", activation_VAL, 0, 0, -+ "#pvscan\n" -+ "Auto-activate LVs in a VG when the PVs scanned have completed the VG.\n" -+ "(Only \\fBay\\fP is applicable.)\n" - "#lvchange\n" - "#vgchange\n" - "Change the active state of LVs.\n" -@@ -828,8 +865,8 @@ arg(activate_ARG, 'a', "activate", activation_VAL, 0, 0, - "if the list is set but empty, no LVs match.\n" - "Autoactivation should be used during system boot to make it possible\n" - "to select which LVs should be automatically activated by the system.\n" -- "See lvmlockd(8) for more information about activation options \\fBey\\fP and \\fBsy\\fP for shared VGs.\n" -- "See clvmd(8) for more information about activation options \\fBey\\fP, \\fBsy\\fP, \\fBly\\fP and \\fBln\\fP for clustered VGs.\n" -+ "See \\fBlvmlockd\\fP(8) for more information about activation options \\fBey\\fP and \\fBsy\\fP for shared VGs.\n" -+ "See \\fBclvmd\\fP(8) for more information about activation options \\fBey\\fP, \\fBsy\\fP, \\fBly\\fP and \\fBln\\fP for clustered VGs.\n" - "#lvcreate\n" - "Controls the active state of the new LV.\n" - "\\fBy\\fP makes the LV active, or available.\n" -@@ -842,12 +879,16 @@ arg(activate_ARG, 'a', "activate", activation_VAL, 0, 0, - "If autoactivation \\fBay\\fP is used, the LV is only activated\n" - "if it matches an item in lvm.conf activation/auto_activation_volume_list.\n" - "\\fBay\\fP implies --zero n and --wipesignatures n.\n" -- "See lvmlockd(8) for more information about activation options for shared VGs.\n" -- "See clvmd(8) for more information about activation options for clustered VGs.\n") -+ "See \\fBlvmlockd\\fP(8) for more information about activation options for shared VGs.\n" -+ "See \\fBclvmd\\fP(8) for more information about activation options for clustered VGs.\n") - - arg(all_ARG, 'a', "all", 0, 0, 0, - "#vgreduce\n" - "Removes all empty PVs if none are named on the command line.\n" -+ "#pvchange\n" -+ "Change all visible PVs.\n" -+ "#vgimport\n" -+ "Import all visible VGs.\n" - "#lvscan\n" - "#lvdisplay\n" - "#lvs\n" -@@ -863,7 +904,7 @@ arg(all_ARG, 'a', "all", 0, 0, 0, - - arg(autobackup_ARG, 'A', "autobackup", bool_VAL, 0, 0, - "Specifies if metadata should be backed up automatically after a change.\n" -- "Enabling this is strongly advised! See vgcfgbackup(8) for more information.\n") -+ "Enabling this is strongly advised! See \\fBvgcfgbackup\\fP(8) for more information.\n") - - arg(activevolumegroups_ARG, 'A', "activevolumegroups", 0, 0, 0, - "Only select active VGs. The VG is considered active\n" -@@ -907,20 +948,20 @@ arg(clustered_ARG, 'c', "clustered", bool_VAL, 0, 0, - "This allows multiple hosts to share a VG on shared devices.\n" - "clvmd and a lock manager must be configured and running.\n" - "(A clustered VG using clvmd is different from a shared VG using lvmlockd.)\n" -- "See clvmd(8) for more information about clustered VGs.\n" -+ "See \\fBclvmd\\fP(8) for more information about clustered VGs.\n" - "#vgchange\n" - "Change the clustered property of a VG using clvmd.\n" -- "See clvmd(8) for more information about clustered VGs.\n" -+ "See \\fBclvmd\\fP(8) for more information about clustered VGs.\n" - "#vgsplit\n" - "Specifies the clustered property of the new VG.\n") - - arg(colon_ARG, 'c', "colon", 0, 0, 0, - "Generate colon separated output for easier parsing in scripts or programs.\n" -- "Also see vgs(8) which provides considerably more control over the output.\n") -+ "Also see \\fBvgs\\fP(8) which provides considerably more control over the output.\n") - - arg(columns_ARG, 'C', "columns", 0, 0, 0, -- "Display output in columns, the equivalent of vgs(8).\n" -- "Options listed are the same as options given in vgs(8).\n") -+ "Display output in columns, the equivalent of \\fBvgs\\fP(8).\n" -+ "Options listed are the same as options given in \\fBvgs\\fP(8).\n") - - arg(contiguous_ARG, 'C', "contiguous", bool_VAL, 0, 0, - "Sets or resets the contiguous allocation policy for LVs.\n" -@@ -1208,7 +1249,7 @@ arg(options_ARG, 'o', "options", string_VAL, ARG_GROUPABLE, 0, - "\\fBseg_all\\fP all LV segment fields, and\n" - "\\fBpvseg_all\\fP all PV segment columns.\n" - "See the lvm.conf report section for more config options.\n" -- "See lvmreport(7) for more information about reporting.\n") -+ "See \\fBlvmreport\\fP(7) for more information about reporting.\n") - - arg(sort_ARG, 'O', "sort", string_VAL, ARG_GROUPABLE, 0, - "Comma-separated ordered list of columns to sort by. Replaces the default\n" -@@ -1348,11 +1389,11 @@ arg(uuidstr_ARG, 'u', "uuid", string_VAL, 0, 0, - "Specify a UUID for the device.\n" - "Without this option, a random UUID is generated.\n" - "This option is needed before restoring a backup of LVM metadata\n" -- "onto a replacement device; see vgcfgrestore(8). As such, use of\n" -+ "onto a replacement device; see \\fBvgcfgrestore\\fP(8). As such, use of\n" - "--restorefile is compulsory unless the --norestorefile is used.\n" - "All PVs must have unique UUIDs, and LVM will prevent certain operations\n" - "if multiple devices are seen with the same UUID.\n" -- "See vgimportclone(8) for more information.\n") -+ "See \\fBvgimportclone\\fP(8) for more information.\n") - - /* Not used */ - arg(uuidlist_ARG, 'U', "uuidlist", 0, 0, 0, NULL) -diff --git a/tools/command-lines.in b/tools/command-lines.in -index 2d9e48e..7f9c31f 100644 ---- a/tools/command-lines.in -+++ b/tools/command-lines.in -@@ -1417,7 +1417,7 @@ DESC: Display PV information. - - pvscan --cache_long - OO: --ignorelockingfailure, --reportformat ReportFmt, --background, ----activate Active, --major Number, --minor Number -+--activate ay, --major Number, --minor Number - OP: PV|String ... - ID: pvscan_cache - DESC: Populate the lvmetad cache by scanning PVs. -diff --git a/tools/command.c b/tools/command.c -index 0f69bbb..a08d068 100644 ---- a/tools/command.c -+++ b/tools/command.c -@@ -40,6 +40,8 @@ - */ - #ifdef MAN_PAGE_GENERATOR - -+#define stack -+ - struct cmd_context { - void *libmem; - }; -@@ -699,9 +701,16 @@ static void set_opt_def(struct cmd_context *cmdtool, struct command *cmd, char * - if (val_enum == constnum_VAL) - def->num = (uint64_t)atoi(name); - -- if (val_enum == conststr_VAL) -+ if (val_enum == conststr_VAL) { - def->str = dm_pool_strdup(cmdtool->libmem, name); - -+ if (!def->str) { -+ /* FIXME */ -+ stack; -+ return; -+ } -+ } -+ - if (val_enum == lv_VAL) { - if (strchr(name, '_')) - def->lvt_bits = lv_to_bits(cmd, name); -@@ -1416,6 +1425,12 @@ int define_commands(struct cmd_context *cmdtool, const char *run_name) - cmd_count++; - cmd->name = dm_pool_strdup(cmdtool->libmem, name); - -+ if (!cmd->name) { -+ /* FIXME */ -+ stack; -+ return 0; -+ } -+ - if (run_name && strcmp(run_name, name)) { - skip = 1; - prev_was_oo_def = 0; -@@ -1447,6 +1462,10 @@ int define_commands(struct cmd_context *cmdtool, const char *run_name) - memset(newdesc, 0, newlen); - snprintf(newdesc, newlen, "%s %s", cmd->desc, desc); - cmd->desc = newdesc; -+ } else { -+ /* FIXME */ -+ stack; -+ return 0; - } - } else - cmd->desc = desc; -@@ -1465,6 +1484,12 @@ int define_commands(struct cmd_context *cmdtool, const char *run_name) - - if (is_id_line(line_argv[0]) && cmd) { - cmd->command_id = dm_pool_strdup(cmdtool->libmem, line_argv[1]); -+ -+ if (!cmd->command_id) { -+ /* FIXME */ -+ stack; -+ return 0; -+ } - continue; - } - -diff --git a/tools/lvchange.c b/tools/lvchange.c -index 660570a..92161e2 100644 ---- a/tools/lvchange.c -+++ b/tools/lvchange.c -@@ -1238,6 +1238,16 @@ static int _lvchange_properties_check(struct cmd_context *cmd, - int lv_is_named_arg) - { - if (!lv_is_visible(lv)) { -+ /* -+ * Exceptions where we allow lvchange properties on -+ * a hidden sub lv. -+ * -+ * lv_is_thin_pool_data: e.g. needed when the data sublv -+ * is a cache lv and we need to change cache properties. -+ */ -+ if (lv_is_thin_pool_data(lv)) -+ return 1; -+ - if (lv_is_named_arg) - log_error("Operation not permitted on hidden LV %s.", display_lvname(lv)); - return 0; -diff --git a/tools/lvcreate.c b/tools/lvcreate.c -index f775290..f464896 100644 ---- a/tools/lvcreate.c -+++ b/tools/lvcreate.c -@@ -251,6 +251,7 @@ static int _update_extents_params(struct volume_group *vg, - uint32_t size_rest; - uint32_t stripesize_extents; - uint32_t extents; -+ uint32_t base_calc_extents; - - if (lcp->size && - !(lp->extents = extents_from_size(vg->cmd, lcp->size, -@@ -275,17 +276,17 @@ static int _update_extents_params(struct volume_group *vg, - - switch (lcp->percent) { - case PERCENT_VG: -- extents = percent_of_extents(lp->extents, vg->extent_count, 0); -+ extents = percent_of_extents(lp->extents, base_calc_extents = vg->extent_count, 0); - break; - case PERCENT_FREE: -- extents = percent_of_extents(lp->extents, vg->free_count, 0); -+ extents = percent_of_extents(lp->extents, base_calc_extents = vg->free_count, 0); - break; - case PERCENT_PVS: - if (lcp->pv_count) { - pv_extent_count = pv_list_extents_free(lp->pvh); -- extents = percent_of_extents(lp->extents, pv_extent_count, 0); -+ extents = percent_of_extents(lp->extents, base_calc_extents = pv_extent_count, 0); - } else -- extents = percent_of_extents(lp->extents, vg->extent_count, 0); -+ extents = percent_of_extents(lp->extents, base_calc_extents = vg->extent_count, 0); - break; - case PERCENT_LV: - log_error("Please express size as %%FREE%s, %%PVS or %%VG.", -@@ -304,7 +305,7 @@ static int _update_extents_params(struct volume_group *vg, - } - /* Add whole metadata size estimation */ - extents = cow_max_extents(origin_lv, lp->chunk_size) - origin_lv->le_count + -- percent_of_extents(lp->extents, origin_lv->le_count, 1); -+ percent_of_extents(lp->extents, base_calc_extents = origin_lv->le_count, 1); - break; - case PERCENT_NONE: - extents = lp->extents; -@@ -314,10 +315,27 @@ static int _update_extents_params(struct volume_group *vg, - return 0; - } - -- if (lcp->percent) { -+ if (lcp->percent != PERCENT_NONE) { - /* FIXME Don't do the adjustment for parallel allocation with PERCENT_ORIGIN! */ - lp->approx_alloc = 1; -- log_verbose("Converted %" PRIu32 "%%%s into %" PRIu32 " extents.", lp->extents, get_percent_string(lcp->percent), extents); -+ if (!extents) { -+ log_error("Calculated size of logical volume is 0 extents. Needs to be larger."); -+ return 0; -+ } -+ -+ /* For mirrors and raid with percentages based on physical extents, convert the total number of PEs -+ * into the number of logical extents per image (minimum 1) */ -+ /* FIXME Handle all the supported raid layouts here based on already-known segtype. */ -+ if ((lcp->percent != PERCENT_ORIGIN) && lp->mirrors) { -+ extents /= lp->mirrors; -+ if (!extents) -+ extents = 1; -+ } -+ -+ log_verbose("Converted %" PRIu32 "%% of %s (%" PRIu32 ") extents into %" PRIu32 " (with mimages %" PRIu32 " and stripes %" PRIu32 -+ " for segtype %s).", lp->extents, get_percent_string(lcp->percent), base_calc_extents, -+ extents, lp->mirrors, lp->stripes, lp->segtype->name); -+ - lp->extents = extents; - } - -@@ -389,6 +407,11 @@ static int _update_extents_params(struct volume_group *vg, - } - } - -+ if ((lcp->percent != PERCENT_NONE) && !lp->extents) { -+ log_error("Adjusted size of logical volume is 0 extents. Needs to be larger."); -+ return 0; -+ } -+ - return 1; - } - -@@ -1170,6 +1193,13 @@ static int _determine_cache_argument(struct volume_group *vg, - lp->create_pool = 0; - lp->origin_name = NULL; - } else if (lv) { -+ if (arg_is_set(cmd, cachepool_ARG)) { -+ /* Argument of --cachepool has to be a cache-pool */ -+ log_error("Logical volume %s is not a cache pool.", -+ display_lvname(lv)); -+ return 0; -+ } -+ - /* Origin exists, create cache pool volume */ - if (!validate_lv_cache_create_origin(lv)) - return_0; -diff --git a/tools/reporter.c b/tools/reporter.c -index 980f39c..b9c4153 100644 ---- a/tools/reporter.c -+++ b/tools/reporter.c -@@ -172,7 +172,7 @@ static int _do_lvs_with_info_and_status_single(struct cmd_context *cmd, - if (lv_is_merging_origin(lv)) { - if (!_check_merging_origin(lv, &status, &merged)) - goto_out; -- if (merged) -+ if (merged && lv_is_thin_volume(lv->snapshot->lv)) - lv = lv->snapshot->lv; - } - -@@ -234,13 +234,13 @@ static int _do_segs_with_info_and_status_single(struct cmd_context *cmd, - if (lv_is_merging_origin(seg->lv)) { - if (!_check_merging_origin(seg->lv, &status, &merged)) - goto_out; -- if (merged) -+ if (merged && lv_is_thin_volume(seg->lv->snapshot->lv)) - seg = seg->lv->snapshot; - } - - if (!report_object(sh ? : handle->custom_handle, sh != NULL, - seg->lv->vg, seg->lv, NULL, seg, NULL, &status, NULL)) -- goto_out; -+ goto_out; - - r = ECMD_PROCESSED; - out: -diff --git a/tools/toollib.c b/tools/toollib.c -index f3cf4ca..e5a854f 100644 ---- a/tools/toollib.c -+++ b/tools/toollib.c -@@ -1335,9 +1335,17 @@ int get_stripe_params(struct cmd_context *cmd, const struct segment_type *segtyp - return _validate_stripe_params(cmd, segtype, stripes, stripe_size); - } - --static int _validate_cachepool_params(const char *name, -- const struct dm_config_tree *settings) -+static int _validate_cachepool_params(const char *policy_name, cache_mode_t cache_mode) - { -+ /* -+ * FIXME: it might be nice if cmd def rules could check option values, -+ * then a rule could do this. -+ */ -+ if ((cache_mode == CACHE_MODE_WRITEBACK) && policy_name && !strcmp(policy_name, "cleaner")) { -+ log_error("Cache mode \"writeback\" is not compatible with cache policy \"cleaner\"."); -+ return 0; -+ } -+ - return 1; - } - -@@ -1371,6 +1379,9 @@ int get_cache_params(struct cmd_context *cmd, - - *name = arg_str_value(cmd, cachepolicy_ARG, NULL); - -+ if (!_validate_cachepool_params(*name, *cache_mode)) -+ goto_out; -+ - dm_list_iterate_items(group, &cmd->arg_value_groups) { - if (!grouped_arg_is_set(group->arg_values, cachesettings_ARG)) - continue; -@@ -1401,9 +1412,6 @@ int get_cache_params(struct cmd_context *cmd, - cn->child = result->root; - result->root = cn; - } -- -- if (!_validate_cachepool_params(*name, result)) -- goto_out; - } - - ok = 1; diff --git a/SOURCES/lvm2-2_02_178-activation-guard-exclusive-activation.patch b/SOURCES/lvm2-2_02_178-activation-guard-exclusive-activation.patch new file mode 100644 index 0000000..4221e16 --- /dev/null +++ b/SOURCES/lvm2-2_02_178-activation-guard-exclusive-activation.patch @@ -0,0 +1,53 @@ +From da05bd7f7207eeab5fbd70b7a7c5166a9885e3b4 Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Mon, 15 Jan 2018 16:26:00 +0100 +Subject: [PATCH 18/25] activation: guard exclusive activation + +Add protectional internall error whenever we spot activation +of 'exclusive' only segments in 'non-exclusive' mode. + +TODO: possibly the activation locking could be enhanced to handle +this fully behind the scene - as for now this works purely for +lvchange/vgchange activation. + +(cherry picked from commit a8bcdef4fd172b705572e3c0b277e6941be642f4) +--- + WHATS_NEW | 1 + + lib/activate/activate.c | 10 ++++++++++ + 2 files changed, 11 insertions(+) + +diff --git a/WHATS_NEW b/WHATS_NEW +index 4368543..c3117de 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,5 +1,6 @@ + Version 2.02.178 - + ===================================== ++ Avoid non-exclusive activation of exclusive segment types. + Fix trimming sibling PVs when doing a pvmove of raid subLVs. + Preserve exclusive activation during thin snaphost merge. + Avoid exceeding array bounds in allocation tag processing. +diff --git a/lib/activate/activate.c b/lib/activate/activate.c +index 4c69af7..b23400a 100644 +--- a/lib/activate/activate.c ++++ b/lib/activate/activate.c +@@ -2568,6 +2568,16 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s, + struct lvinfo info; + int r = 0; + ++ if (!laopts->exclusive && ++ (lv_is_origin(lv) || ++ lv_is_pvmove(lv) || ++ seg_only_exclusive(first_seg(lv)))) { ++ log_error(INTERNAL_ERROR "Trying non-exlusive activation of %s with " ++ "a volume type %s requiring exclusive activation.", ++ display_lvname(lv), lvseg_name(first_seg(lv))); ++ return 0; ++ } ++ + if (!activation()) + return 1; + +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_178-activation-move-check-later.patch b/SOURCES/lvm2-2_02_178-activation-move-check-later.patch new file mode 100644 index 0000000..0b17a2e --- /dev/null +++ b/SOURCES/lvm2-2_02_178-activation-move-check-later.patch @@ -0,0 +1,45 @@ +From e3e7ea0c384da84ccd38406482ec1877c6b19d8a Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Wed, 17 Jan 2018 15:15:43 +0100 +Subject: [PATCH 25/25] activation: move check later + +Check for lv when it's known in all cases. + +(cherry picked from commit f3c75bb2014e9ae7d212e0c016a94c529ac8a912) +--- + lib/activate/activate.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/lib/activate/activate.c b/lib/activate/activate.c +index b23400a..18cc7cf 100644 +--- a/lib/activate/activate.c ++++ b/lib/activate/activate.c +@@ -2568,6 +2568,12 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s, + struct lvinfo info; + int r = 0; + ++ if (!activation()) ++ return 1; ++ ++ if (!lv && !(lv_to_free = lv = lv_from_lvid(cmd, lvid_s, 0))) ++ goto out; ++ + if (!laopts->exclusive && + (lv_is_origin(lv) || + lv_is_pvmove(lv) || +@@ -2578,12 +2584,6 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s, + return 0; + } + +- if (!activation()) +- return 1; +- +- if (!lv && !(lv_to_free = lv = lv_from_lvid(cmd, lvid_s, 0))) +- goto out; +- + if (filter && !_passes_activation_filter(cmd, lv)) { + log_verbose("Not activating %s since it does not pass " + "activation filter.", display_lvname(lv)); +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_178-allocation-Avoid-exceeding-array-bounds-in-allocatio.patch b/SOURCES/lvm2-2_02_178-allocation-Avoid-exceeding-array-bounds-in-allocatio.patch new file mode 100644 index 0000000..c514685 --- /dev/null +++ b/SOURCES/lvm2-2_02_178-allocation-Avoid-exceeding-array-bounds-in-allocatio.patch @@ -0,0 +1,47 @@ +From ce8663ee13e68b8f21dce6e2cf612d3809519787 Mon Sep 17 00:00:00 2001 +From: Alasdair G Kergon +Date: Wed, 10 Jan 2018 02:03:32 +0000 +Subject: [PATCH 12/25] allocation: Avoid exceeding array bounds in allocation + tag code + +If _limit_to_one_area_per_tag() changes nothing it writes beyond +the array. + +(cherry picked from commit bacc94233368cf136b55e2574e969e7f53b31c6c) + +Conflicts: + WHATS_NEW +--- + WHATS_NEW | 4 ++++ + lib/metadata/lv_manip.c | 3 ++- + 2 files changed, 6 insertions(+), 1 deletion(-) + +diff --git a/WHATS_NEW b/WHATS_NEW +index 2163a5e..9375a86 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,3 +1,7 @@ ++Version 2.02.178 - ++===================================== ++ Avoid exceeding array bounds in allocation tag processing. ++ + Version 2.02.177 - 18th December 2017 + ===================================== + When writing text metadata content, use complete 4096 byte blocks. +diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c +index 70dc2d9..ac30dad 100644 +--- a/lib/metadata/lv_manip.c ++++ b/lib/metadata/lv_manip.c +@@ -2737,7 +2737,8 @@ static int _limit_to_one_area_per_tag(struct alloc_handle *ah, struct alloc_stat + s++; + } + +- alloc_state->areas[u].pva = NULL; ++ if (u < alloc_state->areas_size) ++ alloc_state->areas[u].pva = NULL; + + return 1; + } +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_178-cleanup-drop-unused-code.patch b/SOURCES/lvm2-2_02_178-cleanup-drop-unused-code.patch new file mode 100644 index 0000000..f738e92 --- /dev/null +++ b/SOURCES/lvm2-2_02_178-cleanup-drop-unused-code.patch @@ -0,0 +1,40 @@ +From be970a7e85cd3659119ca349303f3dd2ef40592b Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Thu, 11 Jan 2018 16:11:21 +0100 +Subject: [PATCH 20/25] cleanup: drop unused code + +(cherry picked from commit 3aedaa7f2aa3c8622538e2758bf905ceb156db4a) +--- + tools/pvmove.c | 9 --------- + 1 file changed, 9 deletions(-) + +diff --git a/tools/pvmove.c b/tools/pvmove.c +index af3fec4..b3d1d89 100644 +--- a/tools/pvmove.c ++++ b/tools/pvmove.c +@@ -329,8 +329,6 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, + uint32_t log_count = 0; + int lv_found = 0; + int lv_skipped = 0; +- int lv_active_count = 0; +- int lv_exclusive_count = 0; + + /* FIXME Cope with non-contiguous => splitting existing segments */ + if (!(lv_mirr = lv_create_empty("pvmove%d", NULL, +@@ -451,13 +449,6 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, + continue; + } + +- if (vg_is_clustered(vg)) { +- if (lv_is_active_exclusive_locally(lv)) +- lv_exclusive_count++; +- else if (lv_is_active(lv)) +- lv_active_count++; +- } +- + if (!_insert_pvmove_mirrors(cmd, lv_mirr, source_pvl, lv, + *lvs_changed)) + return_NULL; +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_178-cleanup-enhance-messages.patch b/SOURCES/lvm2-2_02_178-cleanup-enhance-messages.patch new file mode 100644 index 0000000..fe914e6 --- /dev/null +++ b/SOURCES/lvm2-2_02_178-cleanup-enhance-messages.patch @@ -0,0 +1,90 @@ +From f2365e3e82309056c2921016584a56210da6888b Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Thu, 11 Jan 2018 10:46:04 +0100 +Subject: [PATCH 19/25] cleanup: enhance messages + +Add extra info about failing local exlusive activation +(as in cluster the LV can be active on some other nodes). + +(cherry picked from commit 38b81e6537a8dc497a4bc616a1f51632b43137ca) +--- + lib/locking/locking.c | 3 ++- + tools/pvmove.c | 27 ++++++++++++++------------- + 2 files changed, 16 insertions(+), 14 deletions(-) + +diff --git a/lib/locking/locking.c b/lib/locking/locking.c +index c68d4c7..8daa61e 100644 +--- a/lib/locking/locking.c ++++ b/lib/locking/locking.c +@@ -406,7 +406,8 @@ int activate_lvs(struct cmd_context *cmd, struct dm_list *lvs) + + dm_list_iterate_items(lvl, lvs) { + if (!activate_lv_excl_local(cmd, lvl->lv)) { +- log_error("Failed to activate %s", display_lvname(lvl->lv)); ++ log_error("Failed to locally exclusively activate %s.", ++ display_lvname(lvl->lv)); + dm_list_uniterate(lvh, lvs, &lvl->list) { + lvl = dm_list_item(lvh, struct lv_list); + if (!deactivate_lv(cmd, lvl->lv)) +diff --git a/tools/pvmove.c b/tools/pvmove.c +index c5d7e52..af3fec4 100644 +--- a/tools/pvmove.c ++++ b/tools/pvmove.c +@@ -375,9 +375,9 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, + continue; + + if (lv_is_converting(lv) || lv_is_merging(lv)) { +- log_error("Unable to pvmove when %s volumes are present.", +- lv_is_converting(lv) ? +- "converting" : "merging"); ++ log_error("Unable to pvmove when %s volume %s is present.", ++ lv_is_converting(lv) ? "converting" : "merging", ++ display_lvname(lv)); + return NULL; + } + +@@ -389,13 +389,13 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, + return_NULL; + + /* +- * Remove any PVs holding SubLV siblings to allow +- * for collocation (e.g. *rmeta_0 -> *rimage_0). +- * +- * Callee checks for lv_name and valid raid segment type. +- * +- * FIXME: don't rely on namespace +- */ ++ * Remove any PVs holding SubLV siblings to allow ++ * for collocation (e.g. *rmeta_0 -> *rimage_0). ++ * ++ * Callee checks for lv_name and valid raid segment type. ++ * ++ * FIXME: don't rely on namespace ++ */ + if (!_remove_sibling_pvs_from_trim_list(lv, lv_name, &trim_list)) + return_NULL; + +@@ -436,7 +436,7 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, + + if (lv_is_locked(lv)) { + lv_skipped = 1; +- log_print_unless_silent("Skipping locked LV %s.", lv->name); ++ log_print_unless_silent("Skipping locked LV %s.", display_lvname(lv)); + continue; + } + +@@ -445,8 +445,9 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, + lv_is_active(lv) && + !lv_is_active_exclusive_locally(lv)) { + lv_skipped = 1; +- log_print_unless_silent("Skipping LV %s which is activated " +- "exclusively on remote node.", lv->name); ++ log_print_unless_silent("Skipping LV %s which is active, " ++ "but not locally exclusively.", ++ display_lvname(lv)); + continue; + } + +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_178-dmeventd-add-check-for-result-code.patch b/SOURCES/lvm2-2_02_178-dmeventd-add-check-for-result-code.patch new file mode 100644 index 0000000..41060a6 --- /dev/null +++ b/SOURCES/lvm2-2_02_178-dmeventd-add-check-for-result-code.patch @@ -0,0 +1,39 @@ +From 94a631461d2d17e1847d2e215bce297bb1a2b70d Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Fri, 5 Jan 2018 21:08:24 +0100 +Subject: [PATCH 17/25] dmeventd: add check for result code + +Check result from pthread_kill. + +(cherry picked from commit f41935909fec9eb8d64bc04530be2f38866f0b8e) +--- + daemons/dmeventd/dmeventd.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/daemons/dmeventd/dmeventd.c b/daemons/dmeventd/dmeventd.c +index 7ad7f81..8917422 100644 +--- a/daemons/dmeventd/dmeventd.c ++++ b/daemons/dmeventd/dmeventd.c +@@ -754,6 +754,7 @@ static void *_timeout_thread(void *unused __attribute__((unused))) + struct thread_status *thread; + struct timespec timeout; + time_t curr_time; ++ int ret; + + DEBUGLOG("Timeout thread starting."); + pthread_cleanup_push(_exit_timeout, NULL); +@@ -775,7 +776,10 @@ static void *_timeout_thread(void *unused __attribute__((unused))) + } else { + DEBUGLOG("Sending SIGALRM to Thr %x for timeout.", + (int) thread->thread); +- pthread_kill(thread->thread, SIGALRM); ++ ret = pthread_kill(thread->thread, SIGALRM); ++ if (ret && (ret != ESRCH)) ++ log_error("Unable to wakeup Thr %x for timeout: %s.", ++ (int) thread->thread, strerror(ret)); + } + _unlock_mutex(); + } +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_178-libdm-accept-mirror-status-with-userspace-word-in-th.patch b/SOURCES/lvm2-2_02_178-libdm-accept-mirror-status-with-userspace-word-in-th.patch new file mode 100644 index 0000000..6801604 --- /dev/null +++ b/SOURCES/lvm2-2_02_178-libdm-accept-mirror-status-with-userspace-word-in-th.patch @@ -0,0 +1,32 @@ + WHATS_NEW_DM | 4 ++++ + libdm/libdm-targets.c | 5 +++++ + 2 files changed, 9 insertions(+) + +diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM +index 8b304e6..fb92416 100644 +--- a/WHATS_NEW_DM ++++ b/WHATS_NEW_DM +@@ -1,3 +1,7 @@ ++Version 1.02.147 - ++===================================== ++ Parsing mirror status accepts 'userspace' keyword in status. ++ + Version 1.02.146 - 18th December 2017 + ===================================== + Activation tree of thin pool skips duplicated check of pool status. +diff --git a/libdm/libdm-targets.c b/libdm/libdm-targets.c +index 990d275..8766789 100644 +--- a/libdm/libdm-targets.c ++++ b/libdm/libdm-targets.c +@@ -508,6 +508,11 @@ int dm_get_status_mirror(struct dm_pool *mem, const char *params, + if (!(pos = _skip_fields(pos, argc))) + goto_out; + ++ if (strncmp(pos, "userspace", 9) == 0) { ++ pos += 9; ++ /* FIXME: support status of userspace mirror implementation */ ++ } ++ + if (sscanf(pos, "%u %n", &argc, &used) != 1) + goto_out; + pos += used; diff --git a/SOURCES/lvm2-2_02_178-locking-exclusive-can-be-either-remote-or-local.patch b/SOURCES/lvm2-2_02_178-locking-exclusive-can-be-either-remote-or-local.patch new file mode 100644 index 0000000..f0e1cc5 --- /dev/null +++ b/SOURCES/lvm2-2_02_178-locking-exclusive-can-be-either-remote-or-local.patch @@ -0,0 +1,32 @@ + WHATS_NEW | 1 + + lib/activate/activate.c | 5 ++++- + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/WHATS_NEW b/WHATS_NEW +index 762553f..776c739 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,5 +1,6 @@ + Version 2.02.178 - + ===================================== ++ Do not report LV as remotely active when it's locally exclusive in cluster. + Add deprecate messages for usage of mirrors with mirrorlog. + Restore pvmove support for wide-clustered active volumes (2.02.177). + Avoid non-exclusive activation of exclusive segment types. +diff --git a/lib/activate/activate.c b/lib/activate/activate.c +index 7a37130..b67e7b1 100644 +--- a/lib/activate/activate.c ++++ b/lib/activate/activate.c +@@ -1543,8 +1543,11 @@ static int _lv_is_active(const struct logical_volume *lv, + if (skip_cluster_query) + goto out; + +- if ((r = cluster_lock_held(lv->lvid.s, "", &e)) >= 0) ++ if ((r = cluster_lock_held(lv->lvid.s, "", &e)) >= 0) { ++ if (l && e) ++ r = 0; /* exclusive locally */ + goto out; ++ } + + /* + * If lock query is not supported (due to interfacing with old diff --git a/SOURCES/lvm2-2_02_178-lvconvert-use-excl-activation-for-conversion.patch b/SOURCES/lvm2-2_02_178-lvconvert-use-excl-activation-for-conversion.patch new file mode 100644 index 0000000..0ec0b2f --- /dev/null +++ b/SOURCES/lvm2-2_02_178-lvconvert-use-excl-activation-for-conversion.patch @@ -0,0 +1,156 @@ +From 8c34a9b06eab6c40a221730a1b72dcd5e43aabcc Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Fri, 12 Jan 2018 13:34:13 +0100 +Subject: [PATCH 13/25] lvconvert: use excl activation for conversion + +Use properly exclusive activation when reactivating origin after +snapshot merge (since origin must have been previously also exlusively +activated). + +Same applies when converting volumes to thin-pool or cache. + +Previously used 'only' local activation incorrectly allowed local +activation of some targets (i.e. raid) - thus 'leaking' chance to +activate same device on another node - which can be a problem +for device types like raid. + +(cherry picked from commit e86910b052ef50dfdaad104d17bda679f698e31f) + +Conflicts: + WHATS_NEW +--- + WHATS_NEW | 1 + + lib/metadata/cache_manip.c | 2 +- + lib/metadata/pool_manip.c | 6 +++--- + tools/lvconvert.c | 16 ++++++++-------- + 4 files changed, 13 insertions(+), 12 deletions(-) + +diff --git a/WHATS_NEW b/WHATS_NEW +index 9375a86..c997206 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,5 +1,6 @@ + Version 2.02.178 - + ===================================== ++ Preserve exclusive activation during thin snaphost merge. + Avoid exceeding array bounds in allocation tag processing. + + Version 2.02.177 - 18th December 2017 +diff --git a/lib/metadata/cache_manip.c b/lib/metadata/cache_manip.c +index 55ed724..97a3339 100644 +--- a/lib/metadata/cache_manip.c ++++ b/lib/metadata/cache_manip.c +@@ -960,7 +960,7 @@ int wipe_cache_pool(struct logical_volume *cache_pool_lv) + } + + cache_pool_lv->status |= LV_TEMPORARY; +- if (!activate_lv_local(cache_pool_lv->vg->cmd, cache_pool_lv)) { ++ if (!activate_lv_excl_local(cache_pool_lv->vg->cmd, cache_pool_lv)) { + log_error("Aborting. Failed to activate cache pool %s.", + display_lvname(cache_pool_lv)); + return 0; +diff --git a/lib/metadata/pool_manip.c b/lib/metadata/pool_manip.c +index 18e4e65..b832db7 100644 +--- a/lib/metadata/pool_manip.c ++++ b/lib/metadata/pool_manip.c +@@ -526,7 +526,7 @@ int create_pool(struct logical_volume *pool_lv, + * or directly converted to invisible device via suspend/resume + */ + pool_lv->status |= LV_TEMPORARY; +- if (!activate_lv_local(pool_lv->vg->cmd, pool_lv)) { ++ if (!activate_lv_excl_local(pool_lv->vg->cmd, pool_lv)) { + log_error("Aborting. Failed to activate pool metadata %s.", + display_lvname(pool_lv)); + goto bad; +@@ -538,7 +538,7 @@ int create_pool(struct logical_volume *pool_lv, + } + pool_lv->status &= ~LV_TEMPORARY; + /* Deactivates cleared metadata LV */ +- if (!deactivate_lv_local(pool_lv->vg->cmd, pool_lv)) { ++ if (!deactivate_lv(pool_lv->vg->cmd, pool_lv)) { + log_error("Aborting. Could not deactivate pool metadata %s.", + display_lvname(pool_lv)); + return 0; +@@ -660,7 +660,7 @@ static struct logical_volume *_alloc_pool_metadata_spare(struct volume_group *vg + return_0; + + /* Spare LV should not be active */ +- if (!deactivate_lv_local(vg->cmd, lv)) { ++ if (!deactivate_lv(vg->cmd, lv)) { + log_error("Unable to deactivate pool metadata spare LV. " + "Manual intervention required."); + return 0; +diff --git a/tools/lvconvert.c b/tools/lvconvert.c +index deb7cc9..fee0a4e 100644 +--- a/tools/lvconvert.c ++++ b/tools/lvconvert.c +@@ -1970,14 +1970,14 @@ static int _lvconvert_snapshot(struct cmd_context *cmd, + log_warn("WARNING: %s not zeroed.", snap_name); + else { + lv->status |= LV_TEMPORARY; +- if (!activate_lv_local(cmd, lv) || ++ if (!activate_lv_excl_local(cmd, lv) || + !wipe_lv(lv, (struct wipe_params) { .do_zero = 1 })) { + log_error("Aborting. Failed to wipe snapshot exception store."); + return 0; + } + lv->status &= ~LV_TEMPORARY; + /* Deactivates cleared metadata LV */ +- if (!deactivate_lv_local(lv->vg->cmd, lv)) { ++ if (!deactivate_lv(lv->vg->cmd, lv)) { + log_error("Failed to deactivate zeroed snapshot exception store."); + return 0; + } +@@ -2170,7 +2170,7 @@ static int _lvconvert_merge_thin_snapshot(struct cmd_context *cmd, + log_print_unless_silent("Volume %s replaced origin %s.", + display_lvname(origin), display_lvname(lv)); + +- if (origin_is_active && !activate_lv(cmd, lv)) { ++ if (origin_is_active && !activate_lv_excl_local(cmd, lv)) { + log_error("Failed to reactivate origin %s.", + display_lvname(lv)); + return 0; +@@ -2278,13 +2278,13 @@ static int _lvconvert_thin_pool_repair(struct cmd_context *cmd, + return 0; + } + +- if (!activate_lv_local(cmd, pmslv)) { ++ if (!activate_lv_excl_local(cmd, pmslv)) { + log_error("Cannot activate pool metadata spare volume %s.", + pmslv->name); + return 0; + } + +- if (!activate_lv_local(cmd, mlv)) { ++ if (!activate_lv_excl_local(cmd, mlv)) { + log_error("Cannot activate thin pool metadata volume %s.", + mlv->name); + goto deactivate_pmslv; +@@ -2476,13 +2476,13 @@ static int _lvconvert_cache_repair(struct cmd_context *cmd, + return 0; + } + +- if (!activate_lv_local(cmd, pmslv)) { ++ if (!activate_lv_excl_local(cmd, pmslv)) { + log_error("Cannot activate pool metadata spare volume %s.", + pmslv->name); + return 0; + } + +- if (!activate_lv_local(cmd, mlv)) { ++ if (!activate_lv_excl_local(cmd, mlv)) { + log_error("Cannot activate cache pool metadata volume %s.", + mlv->name); + goto deactivate_pmslv; +@@ -3130,7 +3130,7 @@ static int _lvconvert_to_pool(struct cmd_context *cmd, + + if (zero_metadata) { + metadata_lv->status |= LV_TEMPORARY; +- if (!activate_lv_local(cmd, metadata_lv)) { ++ if (!activate_lv_excl_local(cmd, metadata_lv)) { + log_error("Aborting. Failed to activate metadata lv."); + goto bad; + } +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_178-lvmlockd-add-lockopt-values-for-skipping-selected-lo.patch b/SOURCES/lvm2-2_02_178-lvmlockd-add-lockopt-values-for-skipping-selected-lo.patch new file mode 100644 index 0000000..81d98a0 --- /dev/null +++ b/SOURCES/lvm2-2_02_178-lvmlockd-add-lockopt-values-for-skipping-selected-lo.patch @@ -0,0 +1,82 @@ +From 8a5e0083200db4b8d1ee2d4e95079372e75fd750 Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Tue, 9 Jan 2018 11:18:57 -0600 +Subject: [PATCH 09/25] lvmlockd: add lockopt values for skipping selected + locks + +and add lockopt to common options. + +(cherry picked from commit 46cedb105bb7fdba0107794ca5801c2a0e8fd524) +--- + tools/command-lines.in | 9 ++++----- + tools/lvmcmdline.c | 10 ++++++++++ + 2 files changed, 14 insertions(+), 5 deletions(-) + +diff --git a/tools/command-lines.in b/tools/command-lines.in +index d0e5e06..a1776ce 100644 +--- a/tools/command-lines.in ++++ b/tools/command-lines.in +@@ -187,7 +187,7 @@ + # OO_ALL is included in every command automatically. + # + OO_ALL: --commandprofile String, --config String, --debug, +---driverloaded Bool, --help, --longhelp, --profile String, --quiet, ++--driverloaded Bool, --help, --lockopt String, --longhelp, --profile String, --quiet, + --verbose, --version, --yes, --test + + # +@@ -1524,19 +1524,18 @@ ID: vgchange_systemid + DESC: Change the system ID of a VG. + + vgchange --lockstart +-OO: --lockopt String, --select String ++OO: --select String + OP: VG|Tag|Select ... + ID: vgchange_lockstart + DESC: Start the lockspace of a shared VG in lvmlockd. + + vgchange --lockstop +-OO: --lockopt String, --select String ++OO: --select String + OP: VG|Tag|Select ... + ID: vgchange_lockstop + DESC: Stop the lockspace of a shared VG in lvmlockd. + + vgchange --locktype LockType VG +-OO: --lockopt String + ID: vgchange_locktype + DESC: Change the lock type for a shared VG. + +@@ -1563,7 +1562,7 @@ OO: --addtag Tag, --alloc Alloc, --autobackup Bool, --clustered Bool, --maxlogic + --physicalextentsize SizeMB, --force, --zero Bool, --labelsector Number, + --metadatasize SizeMB, --pvmetadatacopies MetadataCopiesPV, --vgmetadatacopies MetadataCopiesVG, + --reportformat ReportFmt, --dataalignment SizeKB, --dataalignmentoffset SizeKB, +---shared, --systemid String, --locktype LockType, --lockopt String ++--shared, --systemid String, --locktype LockType + ID: vgcreate_general + + --- +diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c +index b693722..791e272 100644 +--- a/tools/lvmcmdline.c ++++ b/tools/lvmcmdline.c +@@ -2682,6 +2682,16 @@ static int _init_lvmlockd(struct cmd_context *cmd) + return 1; + } + ++ if (use_lvmlockd && arg_is_set(cmd, lockopt_ARG)) { ++ const char *opts = arg_str_value(cmd, lockopt_ARG, ""); ++ if (strstr(opts, "skiplv")) ++ cmd->lockd_lv_disable = 1; ++ if (strstr(opts, "skipvg")) ++ cmd->lockd_vg_disable = 1; ++ if (strstr(opts, "skipgl")) ++ cmd->lockd_gl_disable = 1; ++ } ++ + if (use_lvmlockd && locking_is_clustered()) { + log_error("ERROR: configuration setting use_lvmlockd cannot be used with clustered locking_type 3."); + return 0; +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_178-lvmlockd-clear-coverity-complaint.patch b/SOURCES/lvm2-2_02_178-lvmlockd-clear-coverity-complaint.patch new file mode 100644 index 0000000..31fd92c --- /dev/null +++ b/SOURCES/lvm2-2_02_178-lvmlockd-clear-coverity-complaint.patch @@ -0,0 +1,28 @@ +From d70ba36fbb7851979265d7635740111a6aee5937 Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Mon, 18 Dec 2017 15:19:17 -0600 +Subject: [PATCH 07/25] lvmlockd: clear coverity complaint + +from previous coverity fix, it's never happy. + +(cherry picked from commit 3f9ae846b89a2963a4ca72cfa0281aab0bedcc02) +--- + lib/locking/lvmlockd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/locking/lvmlockd.c b/lib/locking/lvmlockd.c +index 0365797..a4684b4 100644 +--- a/lib/locking/lvmlockd.c ++++ b/lib/locking/lvmlockd.c +@@ -2148,7 +2148,7 @@ int lockd_lv_name(struct cmd_context *cmd, struct volume_group *vg, + static int _lockd_lv_thin(struct cmd_context *cmd, struct logical_volume *lv, + const char *def_mode, uint32_t flags) + { +- struct logical_volume *pool_lv; ++ struct logical_volume *pool_lv = NULL; + + if (lv_is_thin_volume(lv)) { + struct lv_segment *pool_seg = first_seg(lv); +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_178-lvmlockd-print-warning-when-skipping-locking.patch b/SOURCES/lvm2-2_02_178-lvmlockd-print-warning-when-skipping-locking.patch new file mode 100644 index 0000000..aa2e689 --- /dev/null +++ b/SOURCES/lvm2-2_02_178-lvmlockd-print-warning-when-skipping-locking.patch @@ -0,0 +1,39 @@ +From 599ec3dafea034dfafe0d897a8d591f0d07bd016 Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Tue, 9 Jan 2018 11:46:00 -0600 +Subject: [PATCH 10/25] lvmlockd: print warning when skipping locking + +(cherry picked from commit 51340888aab5e1b8630c7d8083e621ca0f4e4264) +--- + tools/lvmcmdline.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c +index 791e272..6be4bcd 100644 +--- a/tools/lvmcmdline.c ++++ b/tools/lvmcmdline.c +@@ -2684,12 +2684,18 @@ static int _init_lvmlockd(struct cmd_context *cmd) + + if (use_lvmlockd && arg_is_set(cmd, lockopt_ARG)) { + const char *opts = arg_str_value(cmd, lockopt_ARG, ""); +- if (strstr(opts, "skiplv")) ++ if (strstr(opts, "skiplv")) { ++ log_warn("WARNING: skipping LV lock in lvmlockd."); + cmd->lockd_lv_disable = 1; +- if (strstr(opts, "skipvg")) ++ } ++ if (strstr(opts, "skipvg")) { ++ log_warn("WARNING: skipping VG lock in lvmlockd."); + cmd->lockd_vg_disable = 1; +- if (strstr(opts, "skipgl")) ++ } ++ if (strstr(opts, "skipgl")) { ++ log_warn("WARNING: skipping global lock in lvmlockd."); + cmd->lockd_gl_disable = 1; ++ } + } + + if (use_lvmlockd && locking_is_clustered()) { +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_178-man-lvmlockd-remove-lv-resizing-comment.patch b/SOURCES/lvm2-2_02_178-man-lvmlockd-remove-lv-resizing-comment.patch new file mode 100644 index 0000000..e6b161c --- /dev/null +++ b/SOURCES/lvm2-2_02_178-man-lvmlockd-remove-lv-resizing-comment.patch @@ -0,0 +1,27 @@ +From 356e4eeb33d8f75cabb8f0c416cf9f09766d70b9 Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Wed, 10 Jan 2018 09:15:52 -0600 +Subject: [PATCH 11/25] man lvmlockd: remove lv resizing comment + +(cherry picked from commit 943b21779770f1cd93e73925e62f108e2efbd6cc) +--- + man/lvmlockd.8_main | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/man/lvmlockd.8_main b/man/lvmlockd.8_main +index bb45871..6f982bd 100644 +--- a/man/lvmlockd.8_main ++++ b/man/lvmlockd.8_main +@@ -862,9 +862,6 @@ vgsplit + .br + \[bu] + vgmerge +-.br +-\[bu] +-resizing an LV that is active in the shared mode on multiple hosts + + + .SS lvmlockd changes from clvmd +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_178-man-lvmlockd-update-wording.patch b/SOURCES/lvm2-2_02_178-man-lvmlockd-update-wording.patch new file mode 100644 index 0000000..90e78f3 --- /dev/null +++ b/SOURCES/lvm2-2_02_178-man-lvmlockd-update-wording.patch @@ -0,0 +1,26 @@ +From 52fd5414cb31c4c92344e8fe9a4f137cdaabea7a Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Tue, 2 Jan 2018 13:10:34 -0600 +Subject: [PATCH 08/25] man lvmlockd: update wording + +(cherry picked from commit 96801ac0859798c4e478d05e91aaa68b4ce10c91) +--- + man/lvmlockd.8_main | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/man/lvmlockd.8_main b/man/lvmlockd.8_main +index fbcdc87..bb45871 100644 +--- a/man/lvmlockd.8_main ++++ b/man/lvmlockd.8_main +@@ -15,7 +15,7 @@ coordinate reading and writing of LVM metadata + validate caching of LVM metadata + .br + \[bu] +-prevent concurrent activation of logical volumes ++prevent conflicting activation of logical volumes + .br + + lvmlockd uses an external lock manager to perform basic locking. +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_178-mirror-Add-deprecation-warning-for-mirrored-log.patch b/SOURCES/lvm2-2_02_178-mirror-Add-deprecation-warning-for-mirrored-log.patch new file mode 100644 index 0000000..f1a0b7f --- /dev/null +++ b/SOURCES/lvm2-2_02_178-mirror-Add-deprecation-warning-for-mirrored-log.patch @@ -0,0 +1,74 @@ + WHATS_NEW | 1 + + lib/metadata/mirror.c | 4 ++++ + tools/lvconvert.c | 11 ++++++++--- + 3 files changed, 13 insertions(+), 3 deletions(-) + +diff --git a/WHATS_NEW b/WHATS_NEW +index da10eed..762553f 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,5 +1,6 @@ + Version 2.02.178 - + ===================================== ++ Add deprecate messages for usage of mirrors with mirrorlog. + Restore pvmove support for wide-clustered active volumes (2.02.177). + Avoid non-exclusive activation of exclusive segment types. + Fix trimming sibling PVs when doing a pvmove of raid subLVs. +diff --git a/lib/metadata/mirror.c b/lib/metadata/mirror.c +index 38c3df6..4a0e99f 100644 +--- a/lib/metadata/mirror.c ++++ b/lib/metadata/mirror.c +@@ -1945,6 +1945,10 @@ int add_mirror_log(struct cmd_context *cmd, struct logical_volume *lv, + return 1; + } + ++ if (log_count > 1) { ++ log_warn("WARNING: Log type \"mirrored\" is DEPRECATED and will be removed in the future. Use RAID1 LV or disk log instead."); ++ } ++ + if (!(parallel_areas = build_parallel_areas_from_lv(lv, 0, 0))) + return_0; + +diff --git a/tools/lvconvert.c b/tools/lvconvert.c +index fee0a4e..8006699 100644 +--- a/tools/lvconvert.c ++++ b/tools/lvconvert.c +@@ -686,7 +686,7 @@ static void _remove_missing_empty_pv(struct volume_group *vg, struct dm_list *re + stack; + return; + } +- log_warn("%d missing and now unallocated Physical Volumes removed from VG.", removed); ++ log_warn("WARNING: %d missing and now unallocated Physical Volumes removed from VG.", removed); + } + } + +@@ -828,7 +828,7 @@ static int _lvconvert_mirrors_aux(struct cmd_context *cmd, + uint32_t old_log_count = _get_log_count(lv); + + if ((lp->mirrors == 1) && !lv_is_mirrored(lv)) { +- log_warn("Logical volume %s is already not mirrored.", ++ log_warn("WARNING: Logical volume %s is already not mirrored.", + display_lvname(lv)); + return 1; + } +@@ -1100,7 +1100,7 @@ static int _lvconvert_mirrors_repair(struct cmd_context *cmd, + log_count = replace_logs ? original_logs : (original_logs - failed_logs); + + while (replace_mimages || replace_logs) { +- log_warn("Trying to up-convert to %d images, %d logs.", lp->mirrors, log_count); ++ log_warn("WARNING: Trying to up-convert to %d images, %d logs.", lp->mirrors, log_count); + if (_lvconvert_mirrors_aux(cmd, lv, lp, NULL, + lp->mirrors, log_count, pvh)) + break; +@@ -1216,6 +1216,11 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, + (old_log_count == new_log_count)) + return 1; + ++ if ((old_log_count != new_log_count) && ++ (new_log_count == MIRROR_LOG_MIRRORED)) { ++ log_warn("WARNING: Log type \"mirrored\" is DEPRECATED and will be removed in the future. Use RAID1 LV or disk log instead."); ++ } ++ + if (!_lvconvert_mirrors_aux(cmd, lv, lp, NULL, + new_mimage_count, new_log_count, lp->pvh)) + return_0; diff --git a/SOURCES/lvm2-2_02_178-pvmove-better-check-for-exclusive-LV.patch b/SOURCES/lvm2-2_02_178-pvmove-better-check-for-exclusive-LV.patch new file mode 100644 index 0000000..9f1ae45 --- /dev/null +++ b/SOURCES/lvm2-2_02_178-pvmove-better-check-for-exclusive-LV.patch @@ -0,0 +1,28 @@ +From d21e2b6005f656c1600bb49942f585d001e94839 Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Fri, 12 Jan 2018 15:59:07 +0100 +Subject: [PATCH 15/25] pvmove: better check for exclusive LV + +(cherry picked from commit 5a961d3411c8c11312d2998378277efc8988fc7f) +--- + tools/pvmove.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/tools/pvmove.c b/tools/pvmove.c +index 39cf25f..9bbe12b 100644 +--- a/tools/pvmove.c ++++ b/tools/pvmove.c +@@ -451,7 +451,9 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, + } + + if (vg_is_clustered(vg) && +- lv_is_active_exclusive_remotely(lv)) { ++ lv_is_visible(lv) && ++ lv_is_active(lv) && ++ !lv_is_active_exclusive_locally(lv)) { + lv_skipped = 1; + log_print_unless_silent("Skipping LV %s which is activated " + "exclusively on remote node.", lv->name); +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_178-pvmove-drop-misleading-pvmove-restriction-for-cluste.patch b/SOURCES/lvm2-2_02_178-pvmove-drop-misleading-pvmove-restriction-for-cluste.patch new file mode 100644 index 0000000..f6a6d6a --- /dev/null +++ b/SOURCES/lvm2-2_02_178-pvmove-drop-misleading-pvmove-restriction-for-cluste.patch @@ -0,0 +1,38 @@ +From 00277d60e98409e493f6208f7f541f7b85ace91f Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Thu, 11 Jan 2018 16:15:16 +0100 +Subject: [PATCH 16/25] pvmove: drop misleading pvmove restriction for cluster + +pvmove handles properly locked LVs in cluster and this extra check +actually cause misbehavior as some LVs were silently skipped from +operation scope. + +(cherry picked from commit 02621cffb0d5ff72adb8770e26c1b4adb95bd0d9) +--- + tools/pvmove.c | 10 ---------- + 1 file changed, 10 deletions(-) + +diff --git a/tools/pvmove.c b/tools/pvmove.c +index 9bbe12b..c5d7e52 100644 +--- a/tools/pvmove.c ++++ b/tools/pvmove.c +@@ -371,16 +371,6 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, + if (lv_name && strcmp(lv->name, top_level_lv_name(vg, lv_name))) + continue; + +- /* +- * RAID, thin and snapshot-related LVs are not +- * processed in a cluster, so we don't have to +- * worry about avoiding certain PVs in that context. +- * +- * Allow clustered mirror, but not raid mirror. +- */ +- if (vg_is_clustered(vg) && !lv_is_mirror_type(lv)) +- continue; +- + if (!lv_is_on_pvs(lv, source_pvl)) + continue; + +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_178-pvmove-enhance-accepted-states-of-active-LVs.patch b/SOURCES/lvm2-2_02_178-pvmove-enhance-accepted-states-of-active-LVs.patch new file mode 100644 index 0000000..8970948 --- /dev/null +++ b/SOURCES/lvm2-2_02_178-pvmove-enhance-accepted-states-of-active-LVs.patch @@ -0,0 +1,156 @@ + tools/pvmove.c | 97 ++++++++++++++++++++++++++++++++-------------------------- + 1 file changed, 54 insertions(+), 43 deletions(-) + +diff --git a/tools/pvmove.c b/tools/pvmove.c +index cbd5cb8..2a26a10 100644 +--- a/tools/pvmove.c ++++ b/tools/pvmove.c +@@ -340,8 +340,8 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, + uint32_t log_count = 0; + int lv_found = 0; + int lv_skipped = 0; +- int lv_active_count = 0; +- int lv_exclusive_count = 0; ++ int needs_exclusive = *exclusive; ++ const struct logical_volume *holder; + + /* FIXME Cope with non-contiguous => splitting existing segments */ + if (!(lv_mirr = lv_create_empty("pvmove%d", NULL, +@@ -392,8 +392,13 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, + return NULL; + } + +- if (seg_is_raid(first_seg(lv)) || +- seg_is_mirrored(first_seg(lv))) { ++ seg = first_seg(lv); ++ ++ /* Presence of exclusive LV decides whether pvmove must be also exclusive */ ++ if ((seg_only_exclusive(seg) || lv_is_origin(lv) || lv_is_cow(lv))) ++ needs_exclusive = 1; ++ ++ if (seg_is_raid(seg) || seg_is_mirrored(seg)) { + dm_list_init(&trim_list); + + if (!get_pv_list_for_lv(vg->cmd->mem, lv, &trim_list)) +@@ -432,6 +437,14 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, + lv_found = 1; + } + ++ seg = first_seg(lv); ++ ++ if (seg_is_cache(seg) || seg_is_cache_pool(seg) || ++ seg_is_mirrored(seg) || seg_is_raid(seg) || ++ seg_is_snapshot(seg) || ++ seg_is_thin(seg) || seg_is_thin_pool(seg)) ++ continue; /* bottom-level LVs only... */ ++ + if (!lv_is_on_pvs(lv, source_pvl)) + continue; + +@@ -441,47 +454,36 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, + continue; + } + +- if (vg_is_clustered(vg) && lv_is_visible(lv)) { +- if (lv_is_active_exclusive_locally(lv)) { +- if (lv_active_count) { +- log_error("Cannot move in clustered VG %s " +- "if some LVs are activated " +- "exclusively while others don't.", +- vg->name); +- return NULL; +- } +- +- lv_exclusive_count++; +- } else if (lv_is_active(lv)) { +- if (seg_only_exclusive(first_seg(lv))) { +- lv_skipped = 1; +- log_print_unless_silent("Skipping LV %s which is active, " +- "but not locally exclusively.", +- display_lvname(lv)); +- continue; +- } +- +- if (*exclusive) { +- log_error("Cannot move in clustered VG %s, " +- "clustered mirror (cmirror) not detected " +- "and LVs are activated non-exclusively.", +- vg->name); +- return NULL; +- } +- +- lv_active_count++; +- } +- } ++ holder = lv_lock_holder(lv); + +- seg = first_seg(lv); +- if (seg_is_raid(seg) || seg_is_mirrored(seg) || +- seg_is_cache(seg) || seg_is_cache_pool(seg) || +- seg_is_thin(seg) || seg_is_thin_pool(seg)) +- /* +- * Pass over top-level LVs - they were handled. +- * Allow sub-LVs to proceed. ++ if (needs_exclusive) { ++ /* With exclusive pvmove skip LV when: ++ * - is active remotely ++ * - is not active locally and cannot be activated exclusively locally ++ * ++ * Note: lvm2 can proceed with exclusive pvmove for 'just' locally active LVs ++ * in the case it's NOT active anywhere else, since LOCKED LVs cannot be ++ * later activated by user. + */ ++ if (lv_is_active_remotely(holder) || ++ (!lv_is_active_locally(holder) && !activate_lv_excl_local(cmd, holder))) { ++ lv_skipped = 1; ++ log_print_unless_silent("Skipping LV %s which is not locally exclusive%s.", ++ display_lvname(lv), ++ /* Report missing cmirrord cases that matterd. ++ * With exclusive LV types cmirrord would not help. */ ++ (*exclusive && ++ !lv_is_origin(holder) && ++ !seg_only_exclusive(first_seg(holder))) ? ++ " and clustered mirror (cmirror) not detected" : ""); ++ continue; ++ } ++ } else if (!activate_lv(cmd, holder)) { ++ lv_skipped = 1; ++ log_print_unless_silent("Skipping LV %s which cannot be activated.", ++ display_lvname(lv)); + continue; ++ } + + if (!_insert_pvmove_mirrors(cmd, lv_mirr, source_pvl, lv, + *lvs_changed)) +@@ -517,7 +519,7 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, + return NULL; + } + +- if (lv_exclusive_count) ++ if (needs_exclusive) + *exclusive = 1; + + return lv_mirr; +@@ -600,6 +602,8 @@ static int _pvmove_setup_single(struct cmd_context *cmd, + struct dm_list *lvs_changed; + struct logical_volume *lv_mirr; + struct logical_volume *lv = NULL; ++ struct lv_list *lvl; ++ const struct logical_volume *lvh; + const char *pv_name = pv_dev_name(pv); + unsigned flags = PVMOVE_FIRST_TIME; + unsigned exclusive; +@@ -661,6 +665,13 @@ static int _pvmove_setup_single(struct cmd_context *cmd, + goto out; + } + ++ dm_list_iterate_items(lvl, lvs_changed) { ++ lvh = lv_lock_holder(lvl->lv); ++ /* Exclusive LV decides whether pvmove must be also exclusive */ ++ if (lv_is_origin(lvh) || seg_only_exclusive(first_seg(lvh))) ++ exclusive = 1; ++ } ++ + /* Ensure mirror LV is active */ + if (!_activate_lv(cmd, lv_mirr, exclusive)) { + log_error("ABORTING: Temporary mirror activation failed."); diff --git a/SOURCES/lvm2-2_02_178-pvmove-fix-_remove_sibling_pvs_from_trim_list.patch b/SOURCES/lvm2-2_02_178-pvmove-fix-_remove_sibling_pvs_from_trim_list.patch new file mode 100644 index 0000000..411465a --- /dev/null +++ b/SOURCES/lvm2-2_02_178-pvmove-fix-_remove_sibling_pvs_from_trim_list.patch @@ -0,0 +1,70 @@ +From 9c3e21e2483fa1818ff4ff4792aaec1d4ea437f8 Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Thu, 11 Jan 2018 13:21:08 +0100 +Subject: [PATCH 14/25] pvmove: fix _remove_sibling_pvs_from_trim_list + +Fix the function to really check it sibling raid image LV. +For LV_rmeta_0 check for LV_rimage_0 instead of +LV_rmeta_0rimage_0. + +(cherry picked from commit 7c6fb63041cd5c1fb899cc468d0a5cf23a01abbe) +--- + WHATS_NEW | 1 + + tools/pvmove.c | 16 +++++++++++++--- + 2 files changed, 14 insertions(+), 3 deletions(-) + +diff --git a/WHATS_NEW b/WHATS_NEW +index c997206..4368543 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,5 +1,6 @@ + Version 2.02.178 - + ===================================== ++ Fix trimming sibling PVs when doing a pvmove of raid subLVs. + Preserve exclusive activation during thin snaphost merge. + Avoid exceeding array bounds in allocation tag processing. + +diff --git a/tools/pvmove.c b/tools/pvmove.c +index 7bf1713..39cf25f 100644 +--- a/tools/pvmove.c ++++ b/tools/pvmove.c +@@ -145,6 +145,7 @@ static int _remove_sibling_pvs_from_trim_list(struct logical_volume *lv, + struct dm_list *trim_list) + { + char *idx, *suffix; ++ const char *sibling; + char sublv_name[NAME_LEN]; + struct logical_volume *sublv; + struct dm_list untrim_list, *pvh1, *pvh2; +@@ -159,7 +160,16 @@ static int _remove_sibling_pvs_from_trim_list(struct logical_volume *lv, + + dm_list_init(&untrim_list); + +- if (!(suffix = first_substring(lv_name, "_rimage_", "_rmeta_", NULL))) { ++ if (!dm_strncpy(sublv_name, lv_name, sizeof(sublv_name))) { ++ log_error(INTERNAL_ERROR "LV name %s is too long.", lv_name); ++ return 0; ++ } ++ ++ if ((suffix = strstr(sublv_name, "_rimage_"))) ++ sibling = "meta"; ++ else if ((suffix = strstr(sublv_name, "_rmeta_"))) ++ sibling = "image"; ++ else { + log_error("Can't find rimage or rmeta suffix."); + return 0; + } +@@ -171,8 +181,8 @@ static int _remove_sibling_pvs_from_trim_list(struct logical_volume *lv, + idx++; + + /* Create the siblings name (e.g. "raidlv_rmeta_N" -> "raidlv_rimage_N" */ +- if (dm_snprintf(sublv_name, sizeof(sublv_name), "%s_r%s_%s", lv_name, +- strstr(suffix, "_rimage_") ? "meta" : "image", idx) < 0) { ++ if (dm_snprintf(suffix + 2, sizeof(sublv_name) - 2 - (suffix - sublv_name), ++ "%s_%s", sibling, idx) < 0) { + log_error("Raid sublv for name %s too long.", lv_name); + return 0; + } +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_178-pvmove-reinstantiate-clustered-pvmove.patch b/SOURCES/lvm2-2_02_178-pvmove-reinstantiate-clustered-pvmove.patch new file mode 100644 index 0000000..1c48301 --- /dev/null +++ b/SOURCES/lvm2-2_02_178-pvmove-reinstantiate-clustered-pvmove.patch @@ -0,0 +1,280 @@ + WHATS_NEW | 1 + + lib/activate/activate.c | 1 - + lib/locking/locking.c | 12 ++++-- + lib/locking/locking.h | 2 +- + tools/pvmove.c | 109 ++++++++++++++++++++++++++++++++++++------------ + 5 files changed, 93 insertions(+), 32 deletions(-) + +diff --git a/WHATS_NEW b/WHATS_NEW +index c3117de..da10eed 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,5 +1,6 @@ + Version 2.02.178 - + ===================================== ++ Restore pvmove support for wide-clustered active volumes (2.02.177). + Avoid non-exclusive activation of exclusive segment types. + Fix trimming sibling PVs when doing a pvmove of raid subLVs. + Preserve exclusive activation during thin snaphost merge. +diff --git a/lib/activate/activate.c b/lib/activate/activate.c +index 18cc7cf..7a37130 100644 +--- a/lib/activate/activate.c ++++ b/lib/activate/activate.c +@@ -2576,7 +2576,6 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s, + + if (!laopts->exclusive && + (lv_is_origin(lv) || +- lv_is_pvmove(lv) || + seg_only_exclusive(first_seg(lv)))) { + log_error(INTERNAL_ERROR "Trying non-exlusive activation of %s with " + "a volume type %s requiring exclusive activation.", +diff --git a/lib/locking/locking.c b/lib/locking/locking.c +index 8daa61e..1a3ce9d 100644 +--- a/lib/locking/locking.c ++++ b/lib/locking/locking.c +@@ -399,15 +399,19 @@ int activate_lv_excl(struct cmd_context *cmd, const struct logical_volume *lv) + } + + /* Lock a list of LVs */ +-int activate_lvs(struct cmd_context *cmd, struct dm_list *lvs) ++int activate_lvs(struct cmd_context *cmd, struct dm_list *lvs, unsigned exclusive) + { + struct dm_list *lvh; + struct lv_list *lvl; + + dm_list_iterate_items(lvl, lvs) { +- if (!activate_lv_excl_local(cmd, lvl->lv)) { +- log_error("Failed to locally exclusively activate %s.", +- display_lvname(lvl->lv)); ++ if (!exclusive && !lv_is_active_exclusive(lvl->lv)) { ++ if (!activate_lv(cmd, lvl->lv)) { ++ log_error("Failed to activate %s", display_lvname(lvl->lv)); ++ return 0; ++ } ++ } else if (!activate_lv_excl(cmd, lvl->lv)) { ++ log_error("Failed to activate %s", display_lvname(lvl->lv)); + dm_list_uniterate(lvh, lvs, &lvl->list) { + lvl = dm_list_item(lvh, struct lv_list); + if (!deactivate_lv(cmd, lvl->lv)) +diff --git a/lib/locking/locking.h b/lib/locking/locking.h +index 47841ed..f2fbb00 100644 +--- a/lib/locking/locking.h ++++ b/lib/locking/locking.h +@@ -262,6 +262,6 @@ int sync_dev_names(struct cmd_context* cmd); + + /* Process list of LVs */ + struct volume_group; +-int activate_lvs(struct cmd_context *cmd, struct dm_list *lvs); ++int activate_lvs(struct cmd_context *cmd, struct dm_list *lvs, unsigned exclusive); + + #endif +diff --git a/tools/pvmove.c b/tools/pvmove.c +index b3d1d89..cbd5cb8 100644 +--- a/tools/pvmove.c ++++ b/tools/pvmove.c +@@ -64,6 +64,16 @@ static int _pvmove_target_present(struct cmd_context *cmd, int clustered) + return found; + } + ++static unsigned _pvmove_is_exclusive(struct cmd_context *cmd, ++ struct volume_group *vg) ++{ ++ if (vg_is_clustered(vg)) ++ if (!_pvmove_target_present(cmd, 1)) ++ return 1; ++ ++ return 0; ++} ++ + /* Allow /dev/vgname/lvname, vgname/lvname or lvname */ + static const char *_extract_lvname(struct cmd_context *cmd, const char *vgname, + const char *arg) +@@ -320,7 +330,8 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, + const char *lv_name, + struct dm_list *allocatable_pvs, + alloc_policy_t alloc, +- struct dm_list **lvs_changed) ++ struct dm_list **lvs_changed, ++ unsigned *exclusive) + { + struct logical_volume *lv_mirr, *lv; + struct lv_segment *seg; +@@ -329,6 +340,8 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, + uint32_t log_count = 0; + int lv_found = 0; + int lv_skipped = 0; ++ int lv_active_count = 0; ++ int lv_exclusive_count = 0; + + /* FIXME Cope with non-contiguous => splitting existing segments */ + if (!(lv_mirr = lv_create_empty("pvmove%d", NULL, +@@ -422,33 +435,54 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, + if (!lv_is_on_pvs(lv, source_pvl)) + continue; + +- seg = first_seg(lv); +- if (seg_is_raid(seg) || seg_is_mirrored(seg) || +- lv_is_thin_volume(lv) || lv_is_thin_pool(lv)) { +- /* +- * Pass over top-level LVs - they were handled. +- * Allow sub-LVs to proceed. +- */ +- continue; +- } +- + if (lv_is_locked(lv)) { + lv_skipped = 1; + log_print_unless_silent("Skipping locked LV %s.", display_lvname(lv)); + continue; + } + +- if (vg_is_clustered(vg) && +- lv_is_visible(lv) && +- lv_is_active(lv) && +- !lv_is_active_exclusive_locally(lv)) { +- lv_skipped = 1; +- log_print_unless_silent("Skipping LV %s which is active, " +- "but not locally exclusively.", +- display_lvname(lv)); +- continue; ++ if (vg_is_clustered(vg) && lv_is_visible(lv)) { ++ if (lv_is_active_exclusive_locally(lv)) { ++ if (lv_active_count) { ++ log_error("Cannot move in clustered VG %s " ++ "if some LVs are activated " ++ "exclusively while others don't.", ++ vg->name); ++ return NULL; ++ } ++ ++ lv_exclusive_count++; ++ } else if (lv_is_active(lv)) { ++ if (seg_only_exclusive(first_seg(lv))) { ++ lv_skipped = 1; ++ log_print_unless_silent("Skipping LV %s which is active, " ++ "but not locally exclusively.", ++ display_lvname(lv)); ++ continue; ++ } ++ ++ if (*exclusive) { ++ log_error("Cannot move in clustered VG %s, " ++ "clustered mirror (cmirror) not detected " ++ "and LVs are activated non-exclusively.", ++ vg->name); ++ return NULL; ++ } ++ ++ lv_active_count++; ++ } + } + ++ seg = first_seg(lv); ++ if (seg_is_raid(seg) || seg_is_mirrored(seg) || ++ seg_is_cache(seg) || seg_is_cache_pool(seg) || ++ seg_is_thin(seg) || seg_is_thin_pool(seg)) ++ /* ++ * Pass over top-level LVs - they were handled. ++ * Allow sub-LVs to proceed. ++ */ ++ continue; ++ + if (!_insert_pvmove_mirrors(cmd, lv_mirr, source_pvl, lv, + *lvs_changed)) + return_NULL; +@@ -483,15 +517,35 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, + return NULL; + } + ++ if (lv_exclusive_count) ++ *exclusive = 1; ++ + return lv_mirr; + } + ++static int _activate_lv(struct cmd_context *cmd, struct logical_volume *lv_mirr, ++ unsigned exclusive) ++{ ++ int r = 0; ++ ++ if (exclusive || lv_is_active_exclusive(lv_mirr)) ++ r = activate_lv_excl(cmd, lv_mirr); ++ else ++ r = activate_lv(cmd, lv_mirr); ++ ++ if (!r) ++ stack; ++ ++ return r; ++} ++ + /* + * Called to set up initial pvmove LV only. + * (Not called after first or any other section completes.) + */ + static int _update_metadata(struct logical_volume *lv_mirr, +- struct dm_list *lvs_changed) ++ struct dm_list *lvs_changed, ++ unsigned exclusive) + { + struct lv_list *lvl; + struct logical_volume *lv = lv_mirr; +@@ -505,7 +559,7 @@ static int _update_metadata(struct logical_volume *lv_mirr, + return_0; + + /* Ensure mirror LV is active */ +- if (!activate_lv_excl_local(lv_mirr->vg->cmd, lv_mirr)) { ++ if (!_activate_lv(lv_mirr->vg->cmd, lv_mirr, exclusive)) { + if (test_mode()) + return 1; + +@@ -548,6 +602,7 @@ static int _pvmove_setup_single(struct cmd_context *cmd, + struct logical_volume *lv = NULL; + const char *pv_name = pv_dev_name(pv); + unsigned flags = PVMOVE_FIRST_TIME; ++ unsigned exclusive; + int r = ECMD_FAILED; + + pp->found_pv = 1; +@@ -594,6 +649,8 @@ static int _pvmove_setup_single(struct cmd_context *cmd, + } + } + ++ exclusive = _pvmove_is_exclusive(cmd, vg); ++ + if ((lv_mirr = find_pvmove_lv(vg, pv_dev(pv), PVMOVE))) { + log_print_unless_silent("Detected pvmove in progress for %s.", pv_name); + if (pp->pv_count || lv_name) +@@ -605,7 +662,7 @@ static int _pvmove_setup_single(struct cmd_context *cmd, + } + + /* Ensure mirror LV is active */ +- if (!activate_lv_excl_local(cmd, lv_mirr)) { ++ if (!_activate_lv(cmd, lv_mirr, exclusive)) { + log_error("ABORTING: Temporary mirror activation failed."); + goto out; + } +@@ -630,12 +687,12 @@ static int _pvmove_setup_single(struct cmd_context *cmd, + + if (!(lv_mirr = _set_up_pvmove_lv(cmd, vg, source_pvl, lv_name, + allocatable_pvs, pp->alloc, +- &lvs_changed))) ++ &lvs_changed, &exclusive))) + goto_out; + } + + /* Lock lvs_changed and activate (with old metadata) */ +- if (!activate_lvs(cmd, lvs_changed)) ++ if (!activate_lvs(cmd, lvs_changed, exclusive)) + goto_out; + + /* FIXME Presence of a mirror once set PVMOVE - now remove associated logic */ +@@ -646,7 +703,7 @@ static int _pvmove_setup_single(struct cmd_context *cmd, + goto out; + + if (flags & PVMOVE_FIRST_TIME) +- if (!_update_metadata(lv_mirr, lvs_changed)) ++ if (!_update_metadata(lv_mirr, lvs_changed, exclusive)) + goto_out; + + /* LVs are all in status LOCKED */ diff --git a/SOURCES/lvm2-2_02_178-tests-check-preserved-exclusivness-of-snapshot-merge.patch b/SOURCES/lvm2-2_02_178-tests-check-preserved-exclusivness-of-snapshot-merge.patch new file mode 100644 index 0000000..ac295c6 --- /dev/null +++ b/SOURCES/lvm2-2_02_178-tests-check-preserved-exclusivness-of-snapshot-merge.patch @@ -0,0 +1,52 @@ +From 509497ae21a4c84f4714835c6f8017a66b666308 Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Mon, 15 Jan 2018 13:29:14 +0100 +Subject: [PATCH 22/25] tests: check preserved exclusivness of snapshot merge + +Detect if origin remains exclusively activated after merging. + +(cherry picked from commit 8ebd45fde759c438e854d6b4f02f0e9803094fea) +--- + test/shell/snapshot-merge.sh | 4 ++++ + test/shell/thin-merge.sh | 9 +++++++++ + 2 files changed, 13 insertions(+) + +diff --git a/test/shell/snapshot-merge.sh b/test/shell/snapshot-merge.sh +index 9d0a264..41e7b00 100644 +--- a/test/shell/snapshot-merge.sh ++++ b/test/shell/snapshot-merge.sh +@@ -54,7 +54,11 @@ setup_merge_ $vg $lv1 + + # make sure lvconvert --merge requires explicit LV listing + not lvconvert --merge ++ ++# check exclusive lock is preserved after merge ++check lv_field "$vg/$lv1" lv_active_exclusively "active exclusively" + lvconvert --merge "$vg/$(snap_lv_name_ "$lv1")" ++check lv_field "$vg/$lv1" lv_active_exclusively "active exclusively" + lvremove -f $vg/$lv1 + + setup_merge_ $vg $lv1 +diff --git a/test/shell/thin-merge.sh b/test/shell/thin-merge.sh +index 3abda40..24dec96 100644 +--- a/test/shell/thin-merge.sh ++++ b/test/shell/thin-merge.sh +@@ -30,6 +30,15 @@ aux have_thin 1 0 0 || skip + aux prepare_vg 2 + + lvcreate -T -L8M $vg/pool -V10M -n $lv1 ++lvcreate -s -K -n snap $vg/$lv1 ++# check exclusive lock is preserved after merge ++check lv_field "$vg/$lv1" lv_active_exclusively "active exclusively" ++lvconvert --merge $vg/snap ++check lv_field "$vg/$lv1" lv_active_exclusively "active exclusively" ++lvremove -ff $vg ++ ++ ++lvcreate -T -L8M $vg/pool -V10M -n $lv1 + lvchange --addtag tagL $vg/$lv1 + + mkdir mnt +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_178-tests-check-pvmove-is-merging-segments.patch b/SOURCES/lvm2-2_02_178-tests-check-pvmove-is-merging-segments.patch new file mode 100644 index 0000000..a1885f6 --- /dev/null +++ b/SOURCES/lvm2-2_02_178-tests-check-pvmove-is-merging-segments.patch @@ -0,0 +1,48 @@ +From c3a9e28b2dad569fc39f36e90408a8a8f6357d5a Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Fri, 1 Dec 2017 11:58:38 +0100 +Subject: [PATCH 24/25] tests: check pvmove is merging segments + +pvmove was imporoved to properly merge consqutive segments after pvmove +so check it's working. + +(cherry picked from commit e16d309d5651d1697f5246855ae816302cd8516f) +--- + test/shell/pvmove-all-segtypes.sh | 20 +++++++++++++++----- + 1 file changed, 15 insertions(+), 5 deletions(-) + +diff --git a/test/shell/pvmove-all-segtypes.sh b/test/shell/pvmove-all-segtypes.sh +index e10586e..f672290 100644 +--- a/test/shell/pvmove-all-segtypes.sh ++++ b/test/shell/pvmove-all-segtypes.sh +@@ -29,12 +29,22 @@ aux prepare_vg 5 20 + # Testing pvmove of linear LV + lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1" + lvcreate -aey -l 2 -n $lv1 $vg "$dev1" +-check lv_tree_on $vg ${lv1}_foo "$dev1" +-check lv_tree_on $vg $lv1 "$dev1" ++lvextend -l+2 $vg/${lv1}_foo "$dev1" ++lvextend -l+2 $vg/${lv1} "$dev1" ++lvextend -l+2 $vg/${lv1}_foo "$dev2" ++lvextend -l+2 $vg/${lv1} "$dev3" ++check lv_tree_on $vg ${lv1}_foo "$dev1" "$dev2" ++check lv_tree_on $vg $lv1 "$dev1" "$dev3" ++check lv_field $vg/${lv1}_foo seg_count 3 ++check lv_field $vg/$lv1 seg_count 3 + aux mkdev_md5sum $vg $lv1 +-pvmove "$dev1" "$dev5" +-check lv_tree_on $vg ${lv1}_foo "$dev5" +-check lv_tree_on $vg $lv1 "$dev5" ++dmsetup table ++pvmove --atomic "$dev1" "$dev5" ++check lv_tree_on $vg ${lv1}_foo "$dev2" "$dev5" ++check lv_tree_on $vg $lv1 "$dev3" "$dev5" ++# Also check 2 segments from $dev1 were merged on $dev5 ++check lv_field $vg/${lv1}_foo seg_count 2 ++check lv_field $vg/$lv1 seg_count 2 + check dev_md5sum $vg $lv1 + pvmove -n $lv1 "$dev5" "$dev4" + check lv_tree_on $vg $lv1 "$dev4" +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_178-tests-longer-startup-timeout-for-daemons-with-valgri.patch b/SOURCES/lvm2-2_02_178-tests-longer-startup-timeout-for-daemons-with-valgri.patch new file mode 100644 index 0000000..d9235e5 --- /dev/null +++ b/SOURCES/lvm2-2_02_178-tests-longer-startup-timeout-for-daemons-with-valgri.patch @@ -0,0 +1,63 @@ +From b32a169b079a67629304c146aad65c2d79acfe01 Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Mon, 15 Jan 2018 16:26:34 +0100 +Subject: [PATCH 23/25] tests: longer startup timeout for daemons with valgrind + +It's getting noticable somewhat slower... + +(cherry picked from commit 5baf2de8986ceeb353c39ccf0503f9fefcb6eb92) +--- + test/lib/aux.sh | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/test/lib/aux.sh b/test/lib/aux.sh +index 6bc7bd4..f30dfdd 100644 +--- a/test/lib/aux.sh ++++ b/test/lib/aux.sh +@@ -180,8 +180,8 @@ prepare_clvmd() { + LVM_LOG_FILE_EPOCH=CLVMD LVM_LOG_FILE_MAX_LINES=1000000 LVM_BINARY=$(which lvm) $run_valgrind clvmd -Isinglenode -d 1 -f & + echo $! > LOCAL_CLVMD + +- for i in {1..100} ; do +- test "$i" -eq 100 && die "Startup of clvmd is too slow." ++ for i in {200..0} ; do ++ test "$i" -eq 0 && die "Startup of clvmd is too slow." + test -e "$CLVMD_PIDFILE" && test -e "${CLVMD_PIDFILE%/*}/lvm/clvmd.sock" && break + echo -n . + sleep .1 +@@ -205,8 +205,8 @@ prepare_dmeventd() { + echo $! > LOCAL_DMEVENTD + + # FIXME wait for pipe in /var/run instead +- for i in {1..100} ; do +- test "$i" -eq 100 && die "Startup of dmeventd is too slow." ++ for i in {200..0} ; do ++ test "$i" -eq 0 && die "Startup of dmeventd is too slow." + test -e "${DMEVENTD_PIDFILE}" && break + echo -n . + sleep .1 +@@ -230,8 +230,8 @@ prepare_lvmetad() { + $run_valgrind lvmetad -f "$@" -s "$TESTDIR/lvmetad.socket" \ + ${LVM_TEST_LVMETAD_DEBUG_OPTS--l all} & + echo $! > LOCAL_LVMETAD +- for i in {1..100} ; do +- test "$i" -eq 100 && die "Startup of lvmetad is too slow." ++ for i in {200..0} ; do ++ test "$i" -eq 0 && die "Startup of lvmetad is too slow." + test -e "$TESTDIR/lvmetad.socket" && break + echo -n . + sleep .1; +@@ -280,8 +280,8 @@ prepare_lvmpolld() { + echo -n "## preparing lvmpolld..." + $run_valgrind lvmpolld -f "$@" -s "$TESTDIR/lvmpolld.socket" -B "$TESTDIR/lib/lvm" -l all & + echo $! > LOCAL_LVMPOLLD +- for i in {1..100} ; do +- test "$i" -eq 100 && die "Startup of lvmpolld is too slow." ++ for i in {200..0} ; do ++ test "$i" -eq 0 && die "Startup of lvmpolld is too slow." + test -e "$TESTDIR/lvmpolld.socket" && break + echo -n .; + sleep .1; +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_178-tests-properly-test-with-clustered-VG.patch b/SOURCES/lvm2-2_02_178-tests-properly-test-with-clustered-VG.patch new file mode 100644 index 0000000..1029b8e --- /dev/null +++ b/SOURCES/lvm2-2_02_178-tests-properly-test-with-clustered-VG.patch @@ -0,0 +1,145 @@ +From 42dd15665401075992d390ed034793c5c036e11f Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Thu, 11 Jan 2018 16:05:44 +0100 +Subject: [PATCH 21/25] tests: properly test with clustered VG + +Testing in cluster makes sense only with clustered VG. + +(cherry picked from commit 8c7ec44bf0fb23e2c5e426c5d07b02e3d25f5b59) +--- + test/shell/pvmove-basic.sh | 10 +++++----- + test/shell/pvmove-raid-segtypes.sh | 14 +++++++------- + test/shell/pvmove-thin-segtypes.sh | 14 +++++++------- + 3 files changed, 19 insertions(+), 19 deletions(-) + +diff --git a/test/shell/pvmove-basic.sh b/test/shell/pvmove-basic.sh +index 056274d..42f165b 100644 +--- a/test/shell/pvmove-basic.sh ++++ b/test/shell/pvmove-basic.sh +@@ -26,15 +26,15 @@ which md5sum || skip + # Utilities + + create_vg_() { +- vgcreate -c n -s 128k "$vg" "${DEVICES[@]}" ++ vgcreate -s 128k "$vg" "${DEVICES[@]}" + } + + # --------------------------------------------------------------------- + # Common environment setup/cleanup for each sub testcases + prepare_lvs_() { +- lvcreate -l2 -n $lv1 $vg "$dev1" ++ lvcreate -aey -l2 -n $lv1 $vg "$dev1" + check lv_on $vg $lv1 "$dev1" +- lvcreate -l9 -i3 -n $lv2 $vg "$dev2" "$dev3" "$dev4" ++ lvcreate -aey -l9 -i3 -n $lv2 $vg "$dev2" "$dev3" "$dev4" + check lv_on $vg $lv2 "$dev2" "$dev3" "$dev4" + lvextend -l+2 $vg/$lv1 "$dev2" + check lv_on $vg $lv1 "$dev1" "$dev2" +@@ -57,7 +57,7 @@ prepare_lvs_() { + # original content should be preserved + restore_lvs_() { + vgcfgrestore -f bak-$$ $vg +- vgchange -ay $vg ++ vgchange -aey $vg + } + + lvs_not_changed_() { +@@ -348,7 +348,7 @@ vgremove -ff $vg + pvcreate "${DEVICES[@]}" + pvcreate --metadatacopies 0 "$dev1" "$dev2" + create_vg_ +-lvcreate -l4 -n $lv1 $vg "$dev1" ++lvcreate -aey -l4 -n $lv1 $vg "$dev1" + pvmove $mode "$dev1" + + #COMM "pvmove fails activating mirror, properly restores state before pvmove" +diff --git a/test/shell/pvmove-raid-segtypes.sh b/test/shell/pvmove-raid-segtypes.sh +index be41547..6584b74 100644 +--- a/test/shell/pvmove-raid-segtypes.sh ++++ b/test/shell/pvmove-raid-segtypes.sh +@@ -22,7 +22,7 @@ aux have_raid 1 3 5 || skip + aux prepare_pvs 5 20 + get_devs + +-vgcreate -c n -s 128k "$vg" "${DEVICES[@]}" ++vgcreate -s 128k "$vg" "${DEVICES[@]}" + + for mode in "--atomic" "" + do +@@ -33,8 +33,8 @@ do + # 3) Move only the second LV by name + + # Testing pvmove of RAID1 LV +-lvcreate -l 2 -n ${lv1}_foo $vg "$dev1" +-lvcreate --regionsize 16K -l 2 --type raid1 -m 1 -n $lv1 $vg "$dev1" "$dev2" ++lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1" ++lvcreate -aey --regionsize 16K -l 2 --type raid1 -m 1 -n $lv1 $vg "$dev1" "$dev2" + check lv_tree_on $vg ${lv1}_foo "$dev1" + check lv_tree_on $vg $lv1 "$dev1" "$dev2" + aux mkdev_md5sum $vg $lv1 +@@ -49,8 +49,8 @@ check dev_md5sum $vg $lv1 + lvremove -ff $vg + + # Testing pvmove of RAID10 LV +-lvcreate -l 2 -n ${lv1}_foo $vg "$dev1" +-lvcreate -l 4 --type raid10 -i 2 -m 1 -n $lv1 $vg \ ++lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1" ++lvcreate -aey -l 4 --type raid10 -i 2 -m 1 -n $lv1 $vg \ + "$dev1" "$dev2" "$dev3" "$dev4" + check lv_tree_on $vg ${lv1}_foo "$dev1" + check lv_tree_on $vg $lv1 "$dev1" "$dev2" "$dev3" "$dev4" +@@ -75,8 +75,8 @@ check dev_md5sum $vg $lv1 + lvremove -ff $vg + + # Testing pvmove of RAID5 LV +-lvcreate -l 2 -n ${lv1}_foo $vg "$dev1" +-lvcreate -l 4 --type raid5 -i 2 -n $lv1 $vg \ ++lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1" ++lvcreate -aey -l 4 --type raid5 -i 2 -n $lv1 $vg \ + "$dev1" "$dev2" "$dev3" + check lv_tree_on $vg ${lv1}_foo "$dev1" + check lv_tree_on $vg $lv1 "$dev1" "$dev2" "$dev3" +diff --git a/test/shell/pvmove-thin-segtypes.sh b/test/shell/pvmove-thin-segtypes.sh +index 01d98b4..08685c8 100644 +--- a/test/shell/pvmove-thin-segtypes.sh ++++ b/test/shell/pvmove-thin-segtypes.sh +@@ -24,7 +24,7 @@ aux have_raid 1 3 5 || skip + aux prepare_pvs 5 20 + get_devs + +-vgcreate -c n -s 128k "$vg" "${DEVICES[@]}" ++vgcreate -s 128k "$vg" "${DEVICES[@]}" + + for mode in "--atomic" "" + do +@@ -37,8 +37,8 @@ do + + + # Testing pvmove of thin LV +-lvcreate -l 2 -n ${lv1}_foo $vg "$dev1" +-lvcreate -T $vg/${lv1}_pool -l 4 -V 8 -n $lv1 "$dev1" ++lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1" ++lvcreate -aey -T $vg/${lv1}_pool -l 4 -V 8 -n $lv1 "$dev1" + check lv_tree_on $vg ${lv1}_foo "$dev1" + check lv_tree_on $vg $lv1 "$dev1" + aux mkdev_md5sum $vg $lv1 +@@ -53,12 +53,12 @@ check dev_md5sum $vg $lv1 + lvremove -ff $vg + + # Testing pvmove of thin LV on RAID +-lvcreate -l 2 -n ${lv1}_foo $vg "$dev1" +-lvcreate --type raid1 -m 1 -l 4 -n ${lv1}_raid1_pool $vg "$dev1" "$dev2" +-lvcreate --type raid1 -m 1 -L 2 -n ${lv1}_raid1_meta $vg "$dev1" "$dev2" ++lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1" ++lvcreate -aey --type raid1 -m 1 -l 4 -n ${lv1}_raid1_pool $vg "$dev1" "$dev2" ++lvcreate -aey --type raid1 -m 1 -L 2 -n ${lv1}_raid1_meta $vg "$dev1" "$dev2" + lvconvert --yes --thinpool $vg/${lv1}_raid1_pool \ + --poolmetadata ${lv1}_raid1_meta +-lvcreate -T $vg/${lv1}_raid1_pool -V 8 -n $lv1 ++lvcreate -aey -T $vg/${lv1}_raid1_pool -V 8 -n $lv1 + check lv_tree_on $vg ${lv1}_foo "$dev1" + check lv_tree_on $vg $lv1 "$dev1" "$dev2" + aux mkdev_md5sum $vg $lv1 +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-default-allow-changes-with-duplicate-pvs.patch b/SOURCES/lvm2-default-allow-changes-with-duplicate-pvs.patch index aa05052..0bf0618 100644 --- a/SOURCES/lvm2-default-allow-changes-with-duplicate-pvs.patch +++ b/SOURCES/lvm2-default-allow-changes-with-duplicate-pvs.patch @@ -3,7 +3,7 @@ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/example.conf.in b/conf/example.conf.in -index b1a2a9c..8e68165 100644 +index 4894d04..48afbd1 100644 --- a/conf/example.conf.in +++ b/conf/example.conf.in @@ -311,7 +311,7 @@ devices { @@ -16,7 +16,7 @@ index b1a2a9c..8e68165 100644 # Configuration section allocation. diff --git a/lib/config/defaults.h b/lib/config/defaults.h -index d988779..985c832 100644 +index d9e19d9..894b979 100644 --- a/lib/config/defaults.h +++ b/lib/config/defaults.h @@ -45,7 +45,7 @@ diff --git a/SOURCES/lvm2-drop-unavailable-libblkid-2_24-BLKID_SUBLKS_BADCSUM-for-signature-detection.patch b/SOURCES/lvm2-drop-unavailable-libblkid-2_24-BLKID_SUBLKS_BADCSUM-for-signature-detection.patch index 028db8e..29677e4 100644 --- a/SOURCES/lvm2-drop-unavailable-libblkid-2_24-BLKID_SUBLKS_BADCSUM-for-signature-detection.patch +++ b/SOURCES/lvm2-drop-unavailable-libblkid-2_24-BLKID_SUBLKS_BADCSUM-for-signature-detection.patch @@ -4,10 +4,10 @@ 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/configure b/configure -index ffef9b9..1e4e744 100755 +index d04b9d3..4f6e7d7 100755 --- a/configure +++ b/configure -@@ -12246,12 +12246,12 @@ if test -n "$BLKID_CFLAGS"; then +@@ -12322,12 +12322,12 @@ if test -n "$BLKID_CFLAGS"; then pkg_cv_BLKID_CFLAGS="$BLKID_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ @@ -23,7 +23,7 @@ index ffef9b9..1e4e744 100755 test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes -@@ -12263,12 +12263,12 @@ if test -n "$BLKID_LIBS"; then +@@ -12339,12 +12339,12 @@ if test -n "$BLKID_LIBS"; then pkg_cv_BLKID_LIBS="$BLKID_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ @@ -39,7 +39,7 @@ index ffef9b9..1e4e744 100755 test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes -@@ -12289,9 +12289,9 @@ else +@@ -12365,9 +12365,9 @@ else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then @@ -51,7 +51,7 @@ index ffef9b9..1e4e744 100755 fi # Put the nasty error message in config.log where it belongs echo "$BLKID_PKG_ERRORS" >&5 -@@ -12299,7 +12299,7 @@ fi +@@ -12375,7 +12375,7 @@ fi if test "$BLKID_WIPING" = maybe; then BLKID_WIPING=no else @@ -60,7 +60,7 @@ index ffef9b9..1e4e744 100755 fi elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -@@ -12307,7 +12307,7 @@ $as_echo "no" >&6; } +@@ -12383,7 +12383,7 @@ $as_echo "no" >&6; } if test "$BLKID_WIPING" = maybe; then BLKID_WIPING=no else @@ -70,26 +70,29 @@ index ffef9b9..1e4e744 100755 else BLKID_CFLAGS=$pkg_cv_BLKID_CFLAGS diff --git a/configure.in b/configure.in -index 2ff4f99..7d2baa0 100644 +index d879408..ab8b585 100644 --- a/configure.in +++ b/configure.in -@@ -1319,12 +1319,12 @@ AC_MSG_RESULT($BLKID_WIPING) - +@@ -1312,7 +1312,7 @@ AC_ARG_ENABLE(blkid_wiping, + DEFAULT_USE_BLKID_WIPING=0 if test "$BLKID_WIPING" != no; then pkg_config_init - PKG_CHECK_MODULES(BLKID, blkid >= 2.24, + PKG_CHECK_MODULES(BLKID, blkid >= 2.23, - [test "$BLKID_WIPING" = maybe && BLKID_WIPING=yes], - [if test "$BLKID_WIPING" = maybe; then + [ BLKID_WIPING=yes + BLKID_PC="blkid" + DEFAULT_USE_BLKID_WIPING=1 +@@ -1320,7 +1320,7 @@ if test "$BLKID_WIPING" != no; then + ], [if test "$BLKID_WIPING" = maybe; then BLKID_WIPING=no else - AC_MSG_ERROR([bailing out... blkid library >= 2.24 is required]) + AC_MSG_ERROR([bailing out... blkid library >= 2.23 is required]) fi]) - if test "$BLKID_WIPING" = yes; then - BLKID_PC="blkid" + fi + AC_MSG_CHECKING([whether to enable libblkid detection of signatures when wiping]) diff --git a/lib/device/dev-type.c b/lib/device/dev-type.c -index 325b66b..cf7f992 100644 +index 9608146..1e45f9d 100644 --- a/lib/device/dev-type.c +++ b/lib/device/dev-type.c @@ -713,8 +713,7 @@ static int _wipe_known_signatures_with_blkid(struct device *dev, const char *nam diff --git a/SOURCES/lvm2-rhel7-fix-StartLimitInterval.patch b/SOURCES/lvm2-rhel7-fix-StartLimitInterval.patch index e5f79e2..6245bdb 100644 --- a/SOURCES/lvm2-rhel7-fix-StartLimitInterval.patch +++ b/SOURCES/lvm2-rhel7-fix-StartLimitInterval.patch @@ -2,7 +2,7 @@ 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/lvm2_pvscan_systemd_red_hat@.service.in b/scripts/lvm2_pvscan_systemd_red_hat@.service.in -index 0989590..9e3d19c 100644 +index 839bfd1..f0bbd46 100644 --- a/scripts/lvm2_pvscan_systemd_red_hat@.service.in +++ b/scripts/lvm2_pvscan_systemd_red_hat@.service.in @@ -2,7 +2,6 @@ @@ -15,8 +15,8 @@ index 0989590..9e3d19c 100644 After=lvm2-lvmetad.socket lvm2-lvmetad.service @@ -14,3 +13,4 @@ Type=oneshot RemainAfterExit=yes - ExecStart=@sbindir@/lvm pvscan --cache --activate ay %i - ExecStop=@sbindir@/lvm pvscan --cache %i + ExecStart=@SBINDIR@/lvm pvscan --cache --activate ay %i + ExecStop=@SBINDIR@/lvm pvscan --cache %i +StartLimitInterval=0 -- 1.8.3.1 diff --git a/SOURCES/lvm2-rhel7.patch b/SOURCES/lvm2-rhel7.patch index 7bceb41..5efa755 100644 --- a/SOURCES/lvm2-rhel7.patch +++ b/SOURCES/lvm2-rhel7.patch @@ -3,16 +3,17 @@ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION -index 1f63cd7..0b41bd1 100644 +index 849efb0..996ced9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ --2.02.171(2) (2017-05-03) -+2.02.171(2)-RHEL7 (2017-05-03) +-2.02.177(2) (2017-12-18) ++2.02.177(2)-RHEL7 (2018-01-22) diff --git a/VERSION_DM b/VERSION_DM -index 030d9c2..56b50a2 100644 +index a37f632..1853e94 100644 --- a/VERSION_DM +++ b/VERSION_DM @@ -1 +1 @@ --1.02.140 (2017-05-03) -+1.02.140-RHEL7 (2017-05-03) +-1.02.146 (2017-12-18) ++1.02.146-RHEL7 (2018-01-22) + diff --git a/SOURCES/lvm2-set-default-preferred_names.patch b/SOURCES/lvm2-set-default-preferred_names.patch index c545662..a1b3034 100644 --- a/SOURCES/lvm2-set-default-preferred_names.patch +++ b/SOURCES/lvm2-set-default-preferred_names.patch @@ -3,7 +3,7 @@ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/example.conf.in b/conf/example.conf.in -index ed34b91..b9fe1d9 100644 +index aab274d..4894d04 100644 --- a/conf/example.conf.in +++ b/conf/example.conf.in @@ -106,7 +106,7 @@ devices { @@ -16,10 +16,10 @@ index ed34b91..b9fe1d9 100644 # Configuration option devices/filter. # Limit the block devices that are used by LVM commands. diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h -index 3b0eebb..9a87e20 100644 +index 077fb15..65cda08 100644 --- a/lib/config/config_settings.h +++ b/lib/config/config_settings.h -@@ -211,7 +211,7 @@ cfg(devices_external_device_info_source_CFG, "external_device_info_source", devi +@@ -255,7 +255,7 @@ cfg(devices_external_device_info_source_CFG, "external_device_info_source", devi " compiled with udev support.\n" "#\n") diff --git a/SPECS/lvm2.spec b/SPECS/lvm2.spec index 279c607..f68e8e7 100644 --- a/SPECS/lvm2.spec +++ b/SPECS/lvm2.spec @@ -1,4 +1,4 @@ -%global device_mapper_version 1.02.140 +%global device_mapper_version 1.02.146 %global enable_cache 1 %global enable_cluster 1 @@ -20,10 +20,16 @@ %global libselinux_version 1.30.19-4 %global persistent_data_version 0.7.0-0.1.rc6 %global sanlock_version 3.3.0-1 +%global boom_version 0.8.5 %global enable_lockd_sanlock %{enable_lvmlockd} %global enable_lockd_dlm %{enable_lvmlockd} +%global boom_pkgname lvm2-python-boom +%global boom_version 0.8.5 +%global boom_summary A set of libraries and tools for managing boot loader entries +%global boom_dir boom-%{boom_version} + %if 0%{?rhel} %ifnarch i686 x86_64 ppc64le s390x %global enable_cluster 0 @@ -36,6 +42,12 @@ %endif %endif +%ifnarch s390x s390 + %global enable_boom 1 +%else + %global enable_boom 0 +%endif + %if %{enable_cluster} %global configure_cluster --with-cluster=internal --with-clvmd=corosync %if %{enable_cmirror} @@ -51,26 +63,43 @@ Summary: Userland logical volume management tools Name: lvm2 Epoch: 7 -Version: 2.02.171 -Release: 8%{?dist} +Version: 2.02.177 +Release: 4%{?dist} License: GPLv2 Group: System Environment/Base URL: http://sources.redhat.com/lvm2 Source0: ftp://sources.redhat.com/pub/lvm2/releases/LVM2.%{version}.tgz +Source1: https://github.com/bmr-cymru/boom/archive/%{boom_version}/boom-%{boom_version}.tar.gz Patch0: lvm2-rhel7.patch Patch1: lvm2-set-default-preferred_names.patch Patch2: lvm2-fix-libdm-versioning-for-dm_tree_node_size_changed-symbol.patch Patch3: lvm2-drop-unavailable-libblkid-2_24-BLKID_SUBLKS_BADCSUM-for-signature-detection.patch Patch4: lvm2-default-allow-changes-with-duplicate-pvs.patch Patch5: lvm2-rhel7-fix-StartLimitInterval.patch -# up to commit: 6c4b2a6aa16cdb4aff2bd80909dcf43032348a3a: -Patch6: lvm2-2_02_172-upstream.patch -# up to commit: 93fbfa2ed397d7b87d4088e19303748c242f24d1 -Patch7: lvm2-2_02_172-upstream-6.patch -# upstream patch: 64fac77e8a551f4dfe8f4cfaaf1ca984c9b5146c -Patch8: lvm2-2_02_172-fix-raid-segfault.patch -# upstream patch: 4e4067dd94f52f90f0aaae30c522102ccbaa2826 -Patch9: lvm2-2_02_172-libdm-initialization-of-reused-struct.patch +Patch6: lvm2-2_02_178-lvmlockd-clear-coverity-complaint.patch +Patch7: lvm2-2_02_178-man-lvmlockd-update-wording.patch +Patch8: lvm2-2_02_178-lvmlockd-add-lockopt-values-for-skipping-selected-lo.patch +Patch9: lvm2-2_02_178-lvmlockd-print-warning-when-skipping-locking.patch +Patch10: lvm2-2_02_178-man-lvmlockd-remove-lv-resizing-comment.patch +Patch11: lvm2-2_02_178-allocation-Avoid-exceeding-array-bounds-in-allocatio.patch +Patch12: lvm2-2_02_178-lvconvert-use-excl-activation-for-conversion.patch +Patch13: lvm2-2_02_178-pvmove-fix-_remove_sibling_pvs_from_trim_list.patch +Patch14: lvm2-2_02_178-pvmove-better-check-for-exclusive-LV.patch +Patch15: lvm2-2_02_178-pvmove-drop-misleading-pvmove-restriction-for-cluste.patch +Patch16: lvm2-2_02_178-dmeventd-add-check-for-result-code.patch +Patch17: lvm2-2_02_178-activation-guard-exclusive-activation.patch +Patch18: lvm2-2_02_178-cleanup-enhance-messages.patch +Patch19: lvm2-2_02_178-cleanup-drop-unused-code.patch +Patch20: lvm2-2_02_178-tests-properly-test-with-clustered-VG.patch +Patch21: lvm2-2_02_178-tests-check-preserved-exclusivness-of-snapshot-merge.patch +Patch22: lvm2-2_02_178-tests-longer-startup-timeout-for-daemons-with-valgri.patch +Patch23: lvm2-2_02_178-tests-check-pvmove-is-merging-segments.patch +Patch24: lvm2-2_02_178-activation-move-check-later.patch +Patch25: lvm2-2_02_178-libdm-accept-mirror-status-with-userspace-word-in-th.patch +Patch26: lvm2-2_02_178-pvmove-reinstantiate-clustered-pvmove.patch +Patch27: lvm2-2_02_178-mirror-Add-deprecation-warning-for-mirrored-log.patch +Patch28: lvm2-2_02_178-locking-exclusive-can-be-either-remote-or-local.patch +Patch29: lvm2-2_02_178-pvmove-enhance-accepted-states-of-active-LVs.patch BuildRequires: libselinux-devel >= %{libselinux_version}, libsepol-devel BuildRequires: libblkid-devel >= %{util_linux_version} @@ -86,7 +115,7 @@ BuildRequires: module-init-tools BuildRequires: pkgconfig BuildRequires: systemd-devel BuildRequires: systemd-units -%if %{enable_python} +%if %{enable_python} || %{enable_boom} BuildRequires: python2-devel BuildRequires: python-setuptools %endif @@ -96,6 +125,7 @@ BuildRequires: device-mapper-persistent-data >= %{persistent_data_version} %if %{enable_lockd_sanlock} BuildRequires: sanlock-devel >= %{sanlock_version} %endif + Requires: %{name}-libs = %{epoch}:%{version}-%{release} Requires: bash >= %{bash_version} Requires(post): systemd-units >= %{systemd_version} @@ -105,16 +135,21 @@ Requires: module-init-tools %if %{enable_thin} || %{enable_cache} Requires: device-mapper-persistent-data >= %{persistent_data_version} %endif +# BZ https://bugzilla.redhat.com/show_bug.cgi?id=1523288 %description LVM2 includes all of the support for handling read/write operations on physical volumes (hard disks, RAID-Systems, magneto optical, etc., -multiple devices (MD), see mdadd(8) or even loop devices, see +multiple devices (MD), see mdadm(8) or even loop devices, see losetup(8)), creating volume groups (kind of virtual disks) from one or more physical volumes and creating one or more logical volumes (kind of logical partitions) in volume groups. %prep +%if %{enable_boom} +%setup -q -b 1 -n %{boom_dir} +%endif + %setup -q -n LVM2.%{version} %patch0 -p1 -b .rhel7 %patch1 -p1 -b .preferred_names @@ -122,10 +157,30 @@ or more physical volumes and creating one or more logical volumes %patch3 -p1 -b .blkid_sublks_badcsum %patch4 -p1 -b .default_allow_dup %patch5 -p1 -b .startlimitinterval -%patch6 -p1 -b .v172 -%patch7 -p1 -b .v172_6 -%patch8 -p1 -b .raid_segfault -%patch9 -p1 -b .libdm_init +%patch6 -p1 -b .6lvmlockd_clear_coverity_complaint +%patch7 -p1 -b .7man_lvmlockd_update_wording +%patch8 -p1 -b .8lvmlockd_add_lockopt_values_for_skipping_selected_lo +%patch9 -p1 -b .9lvmlockd_print_warning_when_skipping_locking +%patch10 -p1 -b .10man_lvmlockd_remove_lv_resizing_comment +%patch11 -p1 -b .11allocation_Avoid_exceeding_array_bounds_in_allocatio +%patch12 -p1 -b .12lvconvert_use_excl_activation_for_conversion +%patch13 -p1 -b .13pvmove_fix__remove_sibling_pvs_from_trim_list +%patch14 -p1 -b .14pvmove_better_check_for_exclusive_LV +%patch15 -p1 -b .15pvmove_drop_misleading_pvmove_restriction_for_cluste +%patch16 -p1 -b .16dmeventd_add_check_for_result_code +%patch17 -p1 -b .17activation_guard_exclusive_activation +%patch18 -p1 -b .18cleanup_enhance_messages +%patch19 -p1 -b .19cleanup_drop_unused_code +%patch20 -p1 -b .20tests_properly_test_with_clustered_VG +%patch21 -p1 -b .21tests_check_preserved_exclusivness_of_snapshot_merge +%patch22 -p1 -b .22tests_longer_startup_timeout_for_daemons_with_valgri +%patch23 -p1 -b .23tests_check_pvmove_is_merging_segments +%patch24 -p1 -b .24activation_move_check_later +%patch25 -p1 -b .25libdm_mirror_status_userspace +%patch26 -p1 -b .26clustered_pvmove +%patch27 -p1 -b .27deprecation_warning_for_mirrored_log +%patch28 -p1 -b .28locking_ex_either_remote_or_local +%patch29 -p1 -b .29pvmove_enhance_accepted_states_of_active_LVs %build %global _default_pid_dir /run @@ -174,6 +229,13 @@ or more physical volumes and creating one or more logical volumes make %{?_smp_mflags} +%if %{enable_boom} +( +cd ../%{boom_dir} +%py2_build +) +%endif + %install make install DESTDIR=$RPM_BUILD_ROOT make install_system_dirs DESTDIR=$RPM_BUILD_ROOT @@ -182,6 +244,27 @@ make install_systemd_units DESTDIR=$RPM_BUILD_ROOT make install_systemd_generators DESTDIR=$RPM_BUILD_ROOT make install_tmpfiles_configuration DESTDIR=$RPM_BUILD_ROOT +%if %{enable_boom} +( +cd ../%{boom_dir} +%py2_install + +# Install Grub2 integration scripts +install -d -m 700 ${RPM_BUILD_ROOT}/etc/grub.d +install -d -m 755 ${RPM_BUILD_ROOT}/etc/default +install -m 755 etc/grub.d/42_boom ${RPM_BUILD_ROOT}/etc/grub.d +install -m 644 etc/default/boom ${RPM_BUILD_ROOT}/etc/default + +# Make configuration directories +install -d -m 700 ${RPM_BUILD_ROOT}/boot/boom/profiles +install -d -m 700 ${RPM_BUILD_ROOT}/boot/loader/entries +install -m 644 examples/profiles/*.profile ${RPM_BUILD_ROOT}/boot/boom/profiles + +install -d -m 755 ${RPM_BUILD_ROOT}/%{_mandir}/man8 +install -m 644 man/man8/boom.8 ${RPM_BUILD_ROOT}/%{_mandir}/man8 +) +%endif + %clean rm -rf $RPM_BUILD_ROOT @@ -238,7 +321,7 @@ systemctl start lvm2-lvmpolld.socket /bin/systemctl try-restart lvm2-monitor.service > /dev/null 2>&1 || : %files -%defattr(-,root,root,-) +%defattr(-,root,root,755) %{!?_licensedir:%global license %%doc} %license COPYING COPYING.LIB %doc README VERSION WHATS_NEW @@ -383,8 +466,8 @@ systemctl start lvm2-lvmpolld.socket %attr(700, -, -) %dir %{_sysconfdir}/lvm/backup %attr(700, -, -) %dir %{_sysconfdir}/lvm/cache %attr(700, -, -) %dir %{_sysconfdir}/lvm/archive -%ghost %dir %{_default_locking_dir} -%ghost %dir %{_default_run_dir} +%ghost %attr(700, -, -) %dir %{_default_locking_dir} +%ghost %attr(700, -, -) %dir %{_default_run_dir} %{_tmpfilesdir}/%{name}.conf %{_unitdir}/lvm2-monitor.service %attr(555, -, -) %{_prefix}/lib/systemd/system-generators/lvm2-activation-generator @@ -437,7 +520,7 @@ This package contains shared lvm2 libraries for applications. %postun libs -p /sbin/ldconfig %files libs -%defattr(555,root,root,-) +%defattr(555,root,root,555) %{!?_licensedir:%global license %%doc} %license COPYING.LIB %{_libdir}/liblvm2app.so.* @@ -471,7 +554,7 @@ Python module to allow the creation and use of LVM logical volumes, physical volumes, and volume groups. %files python-libs -%{python_sitearch}/* +%{python_sitearch}/lvm* %endif @@ -702,7 +785,8 @@ for the kernel device-mapper. %defattr(444,root,root,-) %attr(555, -, -) %{_sbindir}/dmsetup %attr(555, -, -) %{_sbindir}/blkdeactivate -%attr(555, -, -) %{_sbindir}/dmstats +# dmstats is a symlink +%{_sbindir}/dmstats %{_mandir}/man8/dmsetup.8.gz %{_mandir}/man8/dmstats.8.gz %{_mandir}/man8/blkdeactivate.8.gz @@ -748,7 +832,7 @@ This package contains the device-mapper shared library, libdevmapper. %postun -n device-mapper-libs -p /sbin/ldconfig %files -n device-mapper-libs -%defattr(555,root,root,-) +%defattr(555,root,root,555) %{!?_licensedir:%global license %%doc} %license COPYING COPYING.LIB %{_libdir}/libdevmapper.so.* @@ -810,7 +894,7 @@ libdevmapper-event. %postun -n device-mapper-event-libs -p /sbin/ldconfig %files -n device-mapper-event-libs -%defattr(555,root,root,-) +%defattr(555,root,root,555) %{!?_licensedir:%global license %%doc} %license COPYING.LIB %{_libdir}/libdevmapper-event.so.* @@ -833,7 +917,146 @@ the device-mapper event library. %{_includedir}/libdevmapper-event.h %{_libdir}/pkgconfig/devmapper-event.pc +%if %{enable_boom} +############################################################################## +# boom subpackages +############################################################################## +%package -n %{boom_pkgname} +Summary: %{boom_summary} +Version: %{boom_version} +License: GPLv2 +Group: System Environment/Base +BuildArch: noarch +%{?python_provide:%python_provide python2-boom} + +%description -n %{boom_pkgname} +Boom is a boot manager for Linux systems using boot loaders that support +the BootLoader Specification for boot entry configuration. + +Boom requires a BLS compatible boot loader to function: either the +systemd-boot project, or Grub2 with the bls patch (Red Hat Grub2 builds +include this support in both Red Hat Enterprise Linux 7 and Fedora). + +This package provides the python2 version of boom. + +%files -n %{boom_pkgname} +%license COPYING +%{_mandir}/man8/boom.* +%{python2_sitelib}/boom* +%{_bindir}/boom +/etc/grub.d/42_boom +%config(noreplace) /etc/default/boom +/boot/* +%doc ../%{boom_dir}/README.md +%doc ../%{boom_dir}/examples/ +%doc ../%{boom_dir}/tests/ +%endif + %changelog +* Fri Feb 16 2018 Marian Csontos - 7:2.02.177-4 +- pvmove enhance accepted states of active LVs. +- boom: Remove debug output. + +* Wed Feb 14 2018 Marian Csontos - 7:2.02.177-3 +- boom: Handle LVs passed in --root-device. +- boom: Allow /dev/VG/LV notation for --root-lv. +- boom: Detection of invalid root devices. +- boom: Support long options without dash separator. +- Add deprecation warning for mirrored mirror log. + +* Wed Feb 07 2018 Marian Csontos - 7:2.02.177-2 +- boom: Better error handling. +- boom: Warn user when grub2 integration is missing. +- Reenable clustered pvmove. + +* Tue Jan 23 2018 Marian Csontos - 7:2.02.177-1 +- boom: Add missing profiles +- Avoid non-exclusive activation of exclusive segment types. +- Fix trimming sibling PVs when doing a pvmove of raid subLVs. +- Preserve exclusive activation during thin snaphost merge. +- Check array boundaries in allocation tag processing. +- When writing metadata, consistently skip mdas marked as failed. +- Reduce checks for active LVs in vgchange before background polling. +- Ensure _node_send_message always uses clean status of thin pool. +- Activation tree of thin pool skips duplicated check of pool status. + +* Wed Dec 06 2017 Marian Csontos - 7:2.02.176-5 +- boom: Update man page. +- boom: Allow users to disable grub2 configuration. +- boom: Do not add snapshots submenu unless entries exist. +- boom: Use fdatasync() for profile and entry files. +- Fix lvmlockd to use pool lock when accessing _tmeta volume. +- Report expected sanlock_convert errors only when retries fail. +- Avoid blocking in sanlock_convert on SH to EX lock conversion. +- Deactivate missing raid LV legs (_rimage_X-missing_Y_Z) on decativation. +- Allow extending of raid LVs created with --nosync after a failed repair. +- Merge adjacent segments when pvmove is finished. +- Ensure very large numbers used as arguments are not casted to lower values. +- Enhance reading and validation of options stripes and stripes_size. +- Fix printing of default stripe size when user is not using stripes. +- Activation code for pvmove automatically discovers holding LVs for resume. +- Make a pvmove LV locking holder. +- Enhance activation code to automatically suspend pvmove participants. +- Prevent conversion of thin volumes to snapshot origin when lvmlockd is used. +- Correct the steps to change lock type in lvmlockd man page. +- Retry lock acquisition on recognized sanlock errors. +- Fix lock manager error codes in lvmlockd. +- Check raid reshape flags in vg_validate(). +- Add support for pvmove of cache and snapshot origins. +- Ehnance pvmove locking. +- Deactivate activated LVs on error path when pvmove activation fails. + +* Wed Nov 15 2017 Marian Csontos - 7:2.02.176-4 +- Avoid importing persistent filter in vgscan/pvscan/vgrename. +- Fix memleak of string buffer when vgcfgbackup runs in secure mode. +- Do not print error when clvmd cannot find running clvmd. +- Prevent start of new merge of snapshot if origin is already being merged. +- Suppress integrity encryption keys in 'table' output unless --showkeys supplied. +- Fix offered type for raid6_n_6 to raid5 conversion (raid5_n). +- Deactivate sub LVs when removing unused cache-pool. +- Do not take backup with suspended devices. +- Avoid RAID4 activation on incompatible kernels under all circumstances. +- Reject conversion request to striped/raid0 on 2-legged raid4/5. + +* Thu Nov 09 2017 Bryn M. Reeves - 7:2.02.176-3 +- Disable boom package build on s390x. + +* Fri Nov 03 2017 Marian Csontos - 7:2.02.176-2 +- Add "boom" boot manager. + +* Fri Nov 03 2017 Marian Csontos - 7:2.02.176-1 +- Fix segfault in lvm_pv_remove in liblvm. (2.02.173) +- Do not allow storing VG metadata with LV without any segment. +- Fix printed message when thin snapshot was already merged. +- Remove created spare LV when creation of thin-pool failed. +- Avoid reading ignored metadata when MDA gets used again. +- Fix detection of moved PVs in vgsplit. (2.02.175) +- Ignore --stripes/--stripesize on RAID takeover +- Disallow creation of snapshot of mirror/raid subLV (was never supported). +- Keep Install section only in *.socket systemd units. +- Improve used paths for generated systemd units and init shells. + +* Wed Oct 25 2017 Marian Csontos - 7:2.02.175-3 +- Fix regression in more advanced vgname extraction in lvconvert (2.02.169). +- Allow lvcreate to be used for caching of _tdata LV. +- Avoid internal error when resizing cache type _tdata LV (not yet supported). +- Show original converted names when lvconverting LV to pool volume. +- Distinguish between device not found and excluded by filter. +- Monitor external origin LVs. +- Remove unused replicator code, including configure --with-replicators. + +* Fri Oct 13 2017 Marian Csontos - 7:2.02.175-2 +- Allow lvcreate --type mirror to work with 100%%FREE. +- Improve selection of resource name for complex volume activation lock. +- Avoid cutting first character of resource name for activation lock. +- Support for encrypted devices in fsadm. +- Improve thin pool overprovisioning and repair warning messages. +- Fix incorrect adjustment of region size on striped RaidLVs. + +* Mon Oct 09 2017 Marian Csontos - 7:2.02.175-1 +- Update to latest upstream release with various fixes and + enhancements documented in WHATS_NEW and WHATS_NEW_DM file. + * Wed Jun 28 2017 Marian Csontos - 7:2.02.171-8 - Fix reusing of dm_task structure for status reading (used by dmeventd).