diff --git a/.gitignore b/.gitignore index d9acf11..bf3cd56 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -SOURCES/LVM2.2.02.177.tgz -SOURCES/boom-0.8.5.tar.gz +SOURCES/LVM2.2.02.180.tgz +SOURCES/boom-0.9.tar.gz diff --git a/.lvm2.metadata b/.lvm2.metadata index b1e86fd..498c1a7 100644 --- a/.lvm2.metadata +++ b/.lvm2.metadata @@ -1,2 +1,2 @@ -b114b2ef40fca63c6df290a5f1aac54ff3e764aa SOURCES/LVM2.2.02.177.tgz -56a275b49755264565ed595098ea2bb8b0cfe75e SOURCES/boom-0.8.5.tar.gz +d85f7a9bdfd2de48f0bd7ce4d7698685eff6b68e SOURCES/LVM2.2.02.180.tgz +dd96613e238f342641b5be8977ee8598662e8ab9 SOURCES/boom-0.9.tar.gz diff --git a/SOURCES/lvm2-2_02_178-activation-guard-exclusive-activation.patch b/SOURCES/lvm2-2_02_178-activation-guard-exclusive-activation.patch deleted file mode 100644 index 4221e16..0000000 --- a/SOURCES/lvm2-2_02_178-activation-guard-exclusive-activation.patch +++ /dev/null @@ -1,53 +0,0 @@ -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 deleted file mode 100644 index 0b17a2e..0000000 --- a/SOURCES/lvm2-2_02_178-activation-move-check-later.patch +++ /dev/null @@ -1,45 +0,0 @@ -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 deleted file mode 100644 index c514685..0000000 --- a/SOURCES/lvm2-2_02_178-allocation-Avoid-exceeding-array-bounds-in-allocatio.patch +++ /dev/null @@ -1,47 +0,0 @@ -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 deleted file mode 100644 index f738e92..0000000 --- a/SOURCES/lvm2-2_02_178-cleanup-drop-unused-code.patch +++ /dev/null @@ -1,40 +0,0 @@ -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 deleted file mode 100644 index fe914e6..0000000 --- a/SOURCES/lvm2-2_02_178-cleanup-enhance-messages.patch +++ /dev/null @@ -1,90 +0,0 @@ -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 deleted file mode 100644 index 41060a6..0000000 --- a/SOURCES/lvm2-2_02_178-dmeventd-add-check-for-result-code.patch +++ /dev/null @@ -1,39 +0,0 @@ -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 deleted file mode 100644 index 6801604..0000000 --- a/SOURCES/lvm2-2_02_178-libdm-accept-mirror-status-with-userspace-word-in-th.patch +++ /dev/null @@ -1,32 +0,0 @@ - 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 deleted file mode 100644 index f0e1cc5..0000000 --- a/SOURCES/lvm2-2_02_178-locking-exclusive-can-be-either-remote-or-local.patch +++ /dev/null @@ -1,32 +0,0 @@ - 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 deleted file mode 100644 index 0ec0b2f..0000000 --- a/SOURCES/lvm2-2_02_178-lvconvert-use-excl-activation-for-conversion.patch +++ /dev/null @@ -1,156 +0,0 @@ -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 deleted file mode 100644 index 81d98a0..0000000 --- a/SOURCES/lvm2-2_02_178-lvmlockd-add-lockopt-values-for-skipping-selected-lo.patch +++ /dev/null @@ -1,82 +0,0 @@ -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 deleted file mode 100644 index 31fd92c..0000000 --- a/SOURCES/lvm2-2_02_178-lvmlockd-clear-coverity-complaint.patch +++ /dev/null @@ -1,28 +0,0 @@ -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 deleted file mode 100644 index aa2e689..0000000 --- a/SOURCES/lvm2-2_02_178-lvmlockd-print-warning-when-skipping-locking.patch +++ /dev/null @@ -1,39 +0,0 @@ -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 deleted file mode 100644 index e6b161c..0000000 --- a/SOURCES/lvm2-2_02_178-man-lvmlockd-remove-lv-resizing-comment.patch +++ /dev/null @@ -1,27 +0,0 @@ -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 deleted file mode 100644 index 90e78f3..0000000 --- a/SOURCES/lvm2-2_02_178-man-lvmlockd-update-wording.patch +++ /dev/null @@ -1,26 +0,0 @@ -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 deleted file mode 100644 index f1a0b7f..0000000 --- a/SOURCES/lvm2-2_02_178-mirror-Add-deprecation-warning-for-mirrored-log.patch +++ /dev/null @@ -1,74 +0,0 @@ - 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 deleted file mode 100644 index 9f1ae45..0000000 --- a/SOURCES/lvm2-2_02_178-pvmove-better-check-for-exclusive-LV.patch +++ /dev/null @@ -1,28 +0,0 @@ -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 deleted file mode 100644 index f6a6d6a..0000000 --- a/SOURCES/lvm2-2_02_178-pvmove-drop-misleading-pvmove-restriction-for-cluste.patch +++ /dev/null @@ -1,38 +0,0 @@ -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 deleted file mode 100644 index 8970948..0000000 --- a/SOURCES/lvm2-2_02_178-pvmove-enhance-accepted-states-of-active-LVs.patch +++ /dev/null @@ -1,156 +0,0 @@ - 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 deleted file mode 100644 index 411465a..0000000 --- a/SOURCES/lvm2-2_02_178-pvmove-fix-_remove_sibling_pvs_from_trim_list.patch +++ /dev/null @@ -1,70 +0,0 @@ -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 deleted file mode 100644 index 1c48301..0000000 --- a/SOURCES/lvm2-2_02_178-pvmove-reinstantiate-clustered-pvmove.patch +++ /dev/null @@ -1,280 +0,0 @@ - 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 deleted file mode 100644 index ac295c6..0000000 --- a/SOURCES/lvm2-2_02_178-tests-check-preserved-exclusivness-of-snapshot-merge.patch +++ /dev/null @@ -1,52 +0,0 @@ -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 deleted file mode 100644 index a1885f6..0000000 --- a/SOURCES/lvm2-2_02_178-tests-check-pvmove-is-merging-segments.patch +++ /dev/null @@ -1,48 +0,0 @@ -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 deleted file mode 100644 index d9235e5..0000000 --- a/SOURCES/lvm2-2_02_178-tests-longer-startup-timeout-for-daemons-with-valgri.patch +++ /dev/null @@ -1,63 +0,0 @@ -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 deleted file mode 100644 index 1029b8e..0000000 --- a/SOURCES/lvm2-2_02_178-tests-properly-test-with-clustered-VG.patch +++ /dev/null @@ -1,145 +0,0 @@ -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-2_02_180-make-generate.patch b/SOURCES/lvm2-2_02_180-make-generate.patch new file mode 100644 index 0000000..314425c --- /dev/null +++ b/SOURCES/lvm2-2_02_180-make-generate.patch @@ -0,0 +1,239 @@ + conf/example.conf.in | 20 ++++++++++++++++---- + man/pvcreate.8_pregen | 7 ++++--- + man/vgcfgrestore.8_pregen | 9 +++++---- + man/vgconvert.8_pregen | 14 +++++++++----- + man/vgcreate.8_pregen | 7 ++++--- + man/vgextend.8_pregen | 7 ++++--- + man/vgsplit.8_pregen | 7 ++++--- + 7 files changed, 46 insertions(+), 25 deletions(-) + +diff --git a/conf/example.conf.in b/conf/example.conf.in +index cd58615..742812c 100644 +--- a/conf/example.conf.in ++++ b/conf/example.conf.in +@@ -702,17 +702,29 @@ global { + activation = 1 + + # Configuration option global/fallback_to_lvm1. +- # This setting is no longer used. ++ # Try running LVM1 tools if LVM cannot communicate with DM. ++ # This option only applies to 2.4 kernels and is provided to help ++ # switch between device-mapper kernels and LVM1 kernels. The LVM1 ++ # tools need to be installed with .lvm1 suffices, e.g. vgscan.lvm1. ++ # They will stop working once the lvm2 on-disk metadata format is used. + # This configuration option has an automatic default value. +- # fallback_to_lvm1 = 0 ++ # fallback_to_lvm1 = @DEFAULT_FALLBACK_TO_LVM1@ + + # Configuration option global/format. +- # This setting is no longer used. ++ # The default metadata format that commands should use. ++ # The -M 1|2 option overrides this setting. ++ # ++ # Accepted values: ++ # lvm1 ++ # lvm2 ++ # + # This configuration option has an automatic default value. + # format = "lvm2" + + # Configuration option global/format_libraries. +- # This setting is no longer used. ++ # Shared libraries that process different metadata formats. ++ # If support for LVM1 metadata was compiled as a shared library use ++ # format_libraries = "liblvm2format1.so" + # This configuration option does not have a default value defined. + + # Configuration option global/segment_libraries. +diff --git a/man/pvcreate.8_pregen b/man/pvcreate.8_pregen +index c4b03da..abceb82 100644 +--- a/man/pvcreate.8_pregen ++++ b/man/pvcreate.8_pregen +@@ -38,7 +38,7 @@ normally prevent it, e.g. if the PV is already in a VG. + .ad b + .br + .ad l +-[ \fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP ] ++[ \fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP|\fBlvm1\fP ] + .ad b + .br + .ad l +@@ -266,11 +266,12 @@ The size may be rounded. + .ad b + .HP + .ad l +-\fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP ++\fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP|\fBlvm1\fP + .br + Specifies the type of on-disk metadata to use. + \fBlvm2\fP (or just \fB2\fP) is the current, standard format. +-\fBlvm1\fP (or just \fB1\fP) is no longer used. ++\fBlvm1\fP (or just \fB1\fP) is a historical format that ++can be used for accessing old data. + .ad b + .HP + .ad l +diff --git a/man/vgcfgrestore.8_pregen b/man/vgcfgrestore.8_pregen +index cffd44b..e028103 100644 +--- a/man/vgcfgrestore.8_pregen ++++ b/man/vgcfgrestore.8_pregen +@@ -51,7 +51,7 @@ vgcfgrestore - Restore volume group configuration + .ad b + .br + .ad l +- \fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP ++ \fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP|\fBlvm1\fP + .ad b + .br + .ad l +@@ -141,7 +141,7 @@ Common options for command: + . + .RS 4 + .ad l +-[ \fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP ] ++[ \fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP|\fBlvm1\fP ] + .ad b + .br + .ad l +@@ -280,11 +280,12 @@ Display long help text. + .ad b + .HP + .ad l +-\fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP ++\fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP|\fBlvm1\fP + .br + Specifies the type of on-disk metadata to use. + \fBlvm2\fP (or just \fB2\fP) is the current, standard format. +-\fBlvm1\fP (or just \fB1\fP) is no longer used. ++\fBlvm1\fP (or just \fB1\fP) is a historical format that ++can be used for accessing old data. + .ad b + .HP + .ad l +diff --git a/man/vgconvert.8_pregen b/man/vgconvert.8_pregen +index 5e7f8a9..6228087 100644 +--- a/man/vgconvert.8_pregen ++++ b/man/vgconvert.8_pregen +@@ -8,9 +8,12 @@ vgconvert - Change volume group metadata format + [ \fIoption_args\fP ] + .br + .SH DESCRIPTION +-vgconvert converts VG metadata from one format to another. This command +-is no longer used because this version of lvm no longer supports the LVM1 ++vgconvert converts VG metadata from one format to another. The new ++metadata format must be able to fit into the space provided by the old + format. ++ ++Because the LVM1 format should no longer be used, this command is no ++longer needed in general. + .SH USAGE + \fBvgconvert\fP \fIVG\fP ... + .br +@@ -20,7 +23,7 @@ format. + .ad b + .br + .ad l +-[ \fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP ] ++[ \fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP|\fBlvm1\fP ] + .ad b + .br + .ad l +@@ -191,11 +194,12 @@ The size may be rounded. + .ad b + .HP + .ad l +-\fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP ++\fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP|\fBlvm1\fP + .br + Specifies the type of on-disk metadata to use. + \fBlvm2\fP (or just \fB2\fP) is the current, standard format. +-\fBlvm1\fP (or just \fB1\fP) is no longer used. ++\fBlvm1\fP (or just \fB1\fP) is a historical format that ++can be used for accessing old data. + .ad b + .HP + .ad l +diff --git a/man/vgcreate.8_pregen b/man/vgcreate.8_pregen +index 09bf126..ddad391 100644 +--- a/man/vgcreate.8_pregen ++++ b/man/vgcreate.8_pregen +@@ -33,7 +33,7 @@ devices are also available with vgcreate. + .ad b + .br + .ad l +-[ \fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP ] ++[ \fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP|\fBlvm1\fP ] + .ad b + .br + .ad l +@@ -324,11 +324,12 @@ The size may be rounded. + .ad b + .HP + .ad l +-\fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP ++\fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP|\fBlvm1\fP + .br + Specifies the type of on-disk metadata to use. + \fBlvm2\fP (or just \fB2\fP) is the current, standard format. +-\fBlvm1\fP (or just \fB1\fP) is no longer used. ++\fBlvm1\fP (or just \fB1\fP) is a historical format that ++can be used for accessing old data. + .ad b + .HP + .ad l +diff --git a/man/vgextend.8_pregen b/man/vgextend.8_pregen +index a6a30e9..ee805a8 100644 +--- a/man/vgextend.8_pregen ++++ b/man/vgextend.8_pregen +@@ -36,7 +36,7 @@ will initialize them. In this case pvcreate options can be used, e.g. + .ad b + .br + .ad l +-[ \fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP ] ++[ \fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP|\fBlvm1\fP ] + .ad b + .br + .ad l +@@ -237,11 +237,12 @@ The size may be rounded. + .ad b + .HP + .ad l +-\fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP ++\fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP|\fBlvm1\fP + .br + Specifies the type of on-disk metadata to use. + \fBlvm2\fP (or just \fB2\fP) is the current, standard format. +-\fBlvm1\fP (or just \fB1\fP) is no longer used. ++\fBlvm1\fP (or just \fB1\fP) is a historical format that ++can be used for accessing old data. + .ad b + .HP + .ad l +diff --git a/man/vgsplit.8_pregen b/man/vgsplit.8_pregen +index 6c3e6ec..210c266 100644 +--- a/man/vgsplit.8_pregen ++++ b/man/vgsplit.8_pregen +@@ -62,7 +62,7 @@ Common options for command: + .ad b + .br + .ad l +-[ \fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP ] ++[ \fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP|\fBlvm1\fP ] + .ad b + .br + .ad l +@@ -230,11 +230,12 @@ and --vgmetadatacopies for improving performance. + .ad b + .HP + .ad l +-\fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP ++\fB-M\fP|\fB--metadatatype\fP \fBlvm2\fP|\fBlvm1\fP + .br + Specifies the type of on-disk metadata to use. + \fBlvm2\fP (or just \fB2\fP) is the current, standard format. +-\fBlvm1\fP (or just \fB1\fP) is no longer used. ++\fBlvm1\fP (or just \fB1\fP) is a historical format that ++can be used for accessing old data. + .ad b + .HP + .ad l diff --git a/SOURCES/lvm2-2_02_181-WHATS_NEW.patch b/SOURCES/lvm2-2_02_181-WHATS_NEW.patch new file mode 100644 index 0000000..ad5b2a0 --- /dev/null +++ b/SOURCES/lvm2-2_02_181-WHATS_NEW.patch @@ -0,0 +1,29 @@ +From b6608e0f8426ad334a9eb2f6e1c9a1cfced0536e Mon Sep 17 00:00:00 2001 +From: Marian Csontos +Date: Tue, 31 Jul 2018 17:02:47 +0200 +Subject: [PATCH 1/2] Update WHATS_NEW + +--- + WHATS_NEW | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/WHATS_NEW b/WHATS_NEW +index 3b15325..546d3e6 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,7 +1,10 @@ + Version 2.02.181 - + ================================= +- lvconvert: reject conversions on raid1 LVs with split tracked SubLVs +- lvconvert: reject conversions on raid1 split tracked SubLVs ++ Reject conversions on raid1 LVs with split tracked SubLVs. ++ Reject conversions on raid1 split tracked SubLVs. ++ Fix dmstats list failing when no regions exist. ++ Reject conversions of LVs under snapshot. ++ Limit suggested options on incorrect option for lvconvert subcommand. + + Version 2.02.180 - 19th July 2018 + ================================= +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_181-build-make-generate.patch b/SOURCES/lvm2-2_02_181-build-make-generate.patch new file mode 100644 index 0000000..ea9232e --- /dev/null +++ b/SOURCES/lvm2-2_02_181-build-make-generate.patch @@ -0,0 +1,52 @@ +From fc32d2b1b62eb9b75c246efd9c8e514b39f7bd3e Mon Sep 17 00:00:00 2001 +From: Marian Csontos +Date: Tue, 31 Jul 2018 17:36:04 +0200 +Subject: [PATCH] build: make generate + +(cherry picked from commit 12dfd0ed02e003e21072798d17dcec4a80fc466d) +--- + man/lvconvert.8_pregen | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/man/lvconvert.8_pregen b/man/lvconvert.8_pregen +index 91691a3..a47127b 100644 +--- a/man/lvconvert.8_pregen ++++ b/man/lvconvert.8_pregen +@@ -475,7 +475,7 @@ Split images from a raid1 or mirror LV and use them to create a new LV. + .RE + - + +-Split images from a raid1 LV and track changes to origin. ++Split images from a raid1 LV and track changes to origin for later merge. + .br + .P + \fBlvconvert\fP \fB--splitmirrors\fP \fINumber\fP \fB--trackchanges\fP \fILV\fP\fI_cache_raid1\fP +@@ -1281,6 +1281,8 @@ Before the separation, the cache is flushed. Also see --uncache. + Splits the specified number of images from a raid1 or mirror LV + and uses them to create a new LV. If --trackchanges is also specified, + changes to the raid1 LV are tracked while the split LV remains detached. ++If --name is specified, then the images are permanently split from the ++original LV and changes are not tracked. + .ad b + .HP + .ad l +@@ -1354,10 +1356,12 @@ The name of a thin pool LV. + .br + Can be used with --splitmirrors on a raid1 LV. This causes + changes to the original raid1 LV to be tracked while the split images +-remain detached. This allows the read-only detached image(s) to be +-merged efficiently back into the raid1 LV later. Only the regions with +-changed data are resynchronized during merge. (This option only applies +-when using the raid1 LV type.) ++remain detached. This is a temporary state that allows the read-only ++detached image to be merged efficiently back into the raid1 LV later. ++Only the regions with changed data are resynchronized during merge. ++While a raid1 LV is tracking changes, operations on it are limited to ++merging the split image (see --mergemirrors) or permanently splitting ++the image (see --splitmirrors with --name. + .ad b + .HP + .ad l +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_181-dmeventd-base-vdo-plugin.patch b/SOURCES/lvm2-2_02_181-dmeventd-base-vdo-plugin.patch new file mode 100644 index 0000000..938c669 --- /dev/null +++ b/SOURCES/lvm2-2_02_181-dmeventd-base-vdo-plugin.patch @@ -0,0 +1,562 @@ + WHATS_NEW_DM | 1 + + configure | 3 +- + configure.ac | 1 + + daemons/dmeventd/libdevmapper-event.c | 1 + + daemons/dmeventd/plugins/Makefile.in | 9 +- + daemons/dmeventd/plugins/vdo/.exported_symbols | 3 + + daemons/dmeventd/plugins/vdo/Makefile.in | 36 +++ + daemons/dmeventd/plugins/vdo/dmeventd_vdo.c | 406 +++++++++++++++++++++++++ + 8 files changed, 453 insertions(+), 7 deletions(-) + create mode 100644 daemons/dmeventd/plugins/vdo/.exported_symbols + create mode 100644 daemons/dmeventd/plugins/vdo/Makefile.in + create mode 100644 daemons/dmeventd/plugins/vdo/dmeventd_vdo.c + +diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM +index e77352a..c42ee17 100644 +--- a/WHATS_NEW_DM ++++ b/WHATS_NEW_DM +@@ -1,5 +1,6 @@ + Version 1.02.150 - + ================================= ++ Add vdo plugin for monitoring VDO devices. + + Version 1.02.149 - 19th July 2018 + ================================= +diff --git a/configure b/configure +index 10b49c6..eb7d70b 100755 +--- a/configure ++++ b/configure +@@ -15648,7 +15648,7 @@ _ACEOF + + + ################################################################################ +-ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/dmfilemapd/Makefile daemons/lvmdbusd/Makefile daemons/lvmdbusd/lvmdbusd daemons/lvmdbusd/lvmdb.py daemons/lvmdbusd/lvm_shell_proxy.py daemons/lvmdbusd/path.py daemons/lvmetad/Makefile daemons/lvmpolld/Makefile daemons/lvmlockd/Makefile device_mapper/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile include/lvm-version.h libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/com.redhat.lvmdbus1.service scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmdbusd_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_hat.socket scripts/lvm2_lvmlockd_systemd_red_hat.service scripts/lvm2_lvmlocking_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/lvmdump.sh scripts/Makefile test/Makefile test/api/Makefile test/api/python_lvm_unit.py test/unit/Makefile tools/Makefile udev/Makefile" ++ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/dmeventd/plugins/vdo/Makefile daemons/dmfilemapd/Makefile daemons/lvmdbusd/Makefile daemons/lvmdbusd/lvmdbusd daemons/lvmdbusd/lvmdb.py daemons/lvmdbusd/lvm_shell_proxy.py daemons/lvmdbusd/path.py daemons/lvmetad/Makefile daemons/lvmpolld/Makefile daemons/lvmlockd/Makefile device_mapper/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile include/lvm-version.h libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/com.redhat.lvmdbus1.service scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmdbusd_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_hat.socket scripts/lvm2_lvmlockd_systemd_red_hat.service scripts/lvm2_lvmlocking_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/lvmdump.sh scripts/Makefile test/Makefile test/api/Makefile test/api/python_lvm_unit.py test/unit/Makefile tools/Makefile udev/Makefile" + + cat >confcache <<\_ACEOF + # This file is a shell script that caches the results of configure +@@ -16356,6 +16356,7 @@ do + "daemons/dmeventd/plugins/mirror/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/mirror/Makefile" ;; + "daemons/dmeventd/plugins/snapshot/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/snapshot/Makefile" ;; + "daemons/dmeventd/plugins/thin/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/thin/Makefile" ;; ++ "daemons/dmeventd/plugins/vdo/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/vdo/Makefile" ;; + "daemons/dmfilemapd/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmfilemapd/Makefile" ;; + "daemons/lvmdbusd/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/lvmdbusd/Makefile" ;; + "daemons/lvmdbusd/lvmdbusd") CONFIG_FILES="$CONFIG_FILES daemons/lvmdbusd/lvmdbusd" ;; +diff --git a/configure.ac b/configure.ac +index 9fa0c76..24bae39 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -2155,6 +2155,7 @@ daemons/dmeventd/plugins/raid/Makefile + daemons/dmeventd/plugins/mirror/Makefile + daemons/dmeventd/plugins/snapshot/Makefile + daemons/dmeventd/plugins/thin/Makefile ++daemons/dmeventd/plugins/vdo/Makefile + daemons/dmfilemapd/Makefile + daemons/lvmdbusd/Makefile + daemons/lvmdbusd/lvmdbusd +diff --git a/daemons/dmeventd/libdevmapper-event.c b/daemons/dmeventd/libdevmapper-event.c +index 9aeb4c5..f9a8a2b 100644 +--- a/daemons/dmeventd/libdevmapper-event.c ++++ b/daemons/dmeventd/libdevmapper-event.c +@@ -645,6 +645,7 @@ int dm_event_register_handler(const struct dm_event_handler *dmevh) + uuid = dm_task_get_uuid(dmt); + + if (!strstr(dmevh->dso, "libdevmapper-event-lvm2thin.so") && ++ !strstr(dmevh->dso, "libdevmapper-event-lvm2vdo.so") && + !strstr(dmevh->dso, "libdevmapper-event-lvm2snapshot.so") && + !strstr(dmevh->dso, "libdevmapper-event-lvm2mirror.so") && + !strstr(dmevh->dso, "libdevmapper-event-lvm2raid.so")) +diff --git a/daemons/dmeventd/plugins/Makefile.in b/daemons/dmeventd/plugins/Makefile.in +index 27edf55..951dd2b 100644 +--- a/daemons/dmeventd/plugins/Makefile.in ++++ b/daemons/dmeventd/plugins/Makefile.in +@@ -1,6 +1,6 @@ + # + # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. +-# Copyright (C) 2004-2005, 2011 Red Hat, Inc. All rights reserved. ++# Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved. + # + # This file is part of LVM2. + # +@@ -16,11 +16,7 @@ srcdir = @srcdir@ + top_srcdir = @top_srcdir@ + top_builddir = @top_builddir@ + +-SUBDIRS += lvm2 snapshot raid thin mirror +- +-ifeq ($(MAKECMDGOALS),distclean) +- SUBDIRS = lvm2 mirror snapshot raid thin +-endif ++SUBDIRS += lvm2 snapshot raid thin mirror vdo + + include $(top_builddir)/make.tmpl + +@@ -28,3 +24,4 @@ snapshot: lvm2 + mirror: lvm2 + raid: lvm2 + thin: lvm2 ++vdo: lvm2 +diff --git a/daemons/dmeventd/plugins/vdo/.exported_symbols b/daemons/dmeventd/plugins/vdo/.exported_symbols +new file mode 100644 +index 0000000..b88c705 +--- /dev/null ++++ b/daemons/dmeventd/plugins/vdo/.exported_symbols +@@ -0,0 +1,3 @@ ++process_event ++register_device ++unregister_device +diff --git a/daemons/dmeventd/plugins/vdo/Makefile.in b/daemons/dmeventd/plugins/vdo/Makefile.in +new file mode 100644 +index 0000000..bda738a +--- /dev/null ++++ b/daemons/dmeventd/plugins/vdo/Makefile.in +@@ -0,0 +1,36 @@ ++# ++# Copyright (C) 2018 Red Hat, Inc. All rights reserved. ++# ++# This file is part of LVM2. ++# ++# 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 ++ ++srcdir = @srcdir@ ++top_srcdir = @top_srcdir@ ++top_builddir = @top_builddir@ ++ ++INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2 ++CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2 ++ ++SOURCES = dmeventd_vdo.c ++ ++LIB_NAME = libdevmapper-event-lvm2vdo ++LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX) ++LIB_VERSION = $(LIB_VERSION_LVM) ++ ++CFLOW_LIST = $(SOURCES) ++CFLOW_LIST_TARGET = $(LIB_NAME).cflow ++ ++include $(top_builddir)/make.tmpl ++ ++LIBS += -ldevmapper-event-lvm2 $(INTERNAL_LIBS) ++ ++install_lvm2: install_dm_plugin ++ ++install: install_lvm2 +diff --git a/daemons/dmeventd/plugins/vdo/dmeventd_vdo.c b/daemons/dmeventd/plugins/vdo/dmeventd_vdo.c +new file mode 100644 +index 0000000..d77ca79 +--- /dev/null ++++ b/daemons/dmeventd/plugins/vdo/dmeventd_vdo.c +@@ -0,0 +1,406 @@ ++/* ++ * Copyright (C) 2018 Red Hat, Inc. All rights reserved. ++ * ++ * This file is part of LVM2. ++ * ++ * 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 Lesser General Public License v.2.1. ++ * ++ * You should have received a copy of the GNU Lesser 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 ++ */ ++ ++#include "lib/misc/lib.h" ++#include "dmeventd_lvm.h" ++#include "daemons/dmeventd/libdevmapper-event.h" ++#include "device_mapper/vdo/target.h" ++ ++#include ++#include ++ ++/* First warning when VDO pool is 80% full. */ ++#define WARNING_THRESH (DM_PERCENT_1 * 80) ++/* Run a check every 5%. */ ++#define CHECK_STEP (DM_PERCENT_1 * 5) ++/* Do not bother checking VDO pool is less than 50% full. */ ++#define CHECK_MINIMUM (DM_PERCENT_1 * 50) ++ ++#define MAX_FAILS (256) /* ~42 mins between cmd call retry with 10s delay */ ++ ++#define VDO_DEBUG 0 ++ ++struct dso_state { ++ struct dm_pool *mem; ++ int percent_check; ++ int percent; ++ uint64_t known_data_size; ++ unsigned fails; ++ unsigned max_fails; ++ int restore_sigset; ++ sigset_t old_sigset; ++ pid_t pid; ++ char *argv[3]; ++ const char *cmd_str; ++ const char *name; ++}; ++ ++DM_EVENT_LOG_FN("vdo") ++ ++static int _run_command(struct dso_state *state) ++{ ++ char val[16]; ++ int i; ++ ++ /* Mark for possible lvm2 command we are running from dmeventd ++ * lvm2 will not try to talk back to dmeventd while processing it */ ++ (void) setenv("LVM_RUN_BY_DMEVENTD", "1", 1); ++ ++ if (state->percent) { ++ /* Prepare some known data to env vars for easy use */ ++ if (dm_snprintf(val, sizeof(val), "%d", ++ state->percent / DM_PERCENT_1) != -1) ++ (void) setenv("DMEVENTD_VDO_POOL", val, 1); ++ } else { ++ /* For an error event it's for a user to check status and decide */ ++ log_debug("Error event processing."); ++ } ++ ++ log_verbose("Executing command: %s", state->cmd_str); ++ ++ /* TODO: ++ * Support parallel run of 'task' and it's waitpid maintainence ++ * ATM we can't handle signaling of SIGALRM ++ * as signalling is not allowed while 'process_event()' is running ++ */ ++ if (!(state->pid = fork())) { ++ /* child */ ++ (void) close(0); ++ for (i = 3; i < 255; ++i) (void) close(i); ++ execvp(state->argv[0], state->argv); ++ _exit(errno); ++ } else if (state->pid == -1) { ++ log_error("Can't fork command %s.", state->cmd_str); ++ state->fails = 1; ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static int _use_policy(struct dm_task *dmt, struct dso_state *state) ++{ ++#if VDO_DEBUG ++ log_debug("dmeventd executes: %s.", state->cmd_str); ++#endif ++ if (state->argv[0]) ++ return _run_command(state); ++ ++ if (!dmeventd_lvm2_run_with_lock(state->cmd_str)) { ++ log_error("Failed command for %s.", dm_task_get_name(dmt)); ++ state->fails = 1; ++ return 0; ++ } ++ ++ state->fails = 0; ++ ++ return 1; ++} ++ ++/* Check if executed command has finished ++ * Only 1 command may run */ ++static int _wait_for_pid(struct dso_state *state) ++{ ++ int status = 0; ++ ++ if (state->pid == -1) ++ return 1; ++ ++ if (!waitpid(state->pid, &status, WNOHANG)) ++ return 0; ++ ++ /* Wait for finish */ ++ if (WIFEXITED(status)) { ++ log_verbose("Child %d exited with status %d.", ++ state->pid, WEXITSTATUS(status)); ++ state->fails = WEXITSTATUS(status) ? 1 : 0; ++ } else { ++ if (WIFSIGNALED(status)) ++ log_verbose("Child %d was terminated with status %d.", ++ state->pid, WTERMSIG(status)); ++ state->fails = 1; ++ } ++ ++ state->pid = -1; ++ ++ return 1; ++} ++ ++void process_event(struct dm_task *dmt, ++ enum dm_event_mask event __attribute__((unused)), ++ void **user) ++{ ++ const char *device = dm_task_get_name(dmt); ++ struct dso_state *state = *user; ++ void *next = NULL; ++ uint64_t start, length; ++ char *target_type = NULL; ++ char *params; ++ int needs_policy = 0; ++ struct dm_task *new_dmt = NULL; ++ struct dm_vdo_status_parse_result vdop = { .status = NULL }; ++ ++#if VDO_DEBUG ++ log_debug("Watch for VDO %s:%.2f%%.", state->name, ++ dm_percent_to_round_float(state->percent_check, 2)); ++#endif ++ if (!_wait_for_pid(state)) { ++ log_warn("WARNING: Skipping event, child %d is still running (%s).", ++ state->pid, state->cmd_str); ++ return; ++ } ++ ++ if (event & DM_EVENT_DEVICE_ERROR) { ++#if VDO_DEBUG ++ log_debug("VDO event error."); ++#endif ++ /* Error -> no need to check and do instant resize */ ++ state->percent = 0; ++ if (_use_policy(dmt, state)) ++ goto out; ++ ++ stack; ++ ++ if (!(new_dmt = dm_task_create(DM_DEVICE_STATUS))) ++ goto_out; ++ ++ if (!dm_task_set_uuid(new_dmt, dm_task_get_uuid(dmt))) ++ goto_out; ++ ++ /* Non-blocking status read */ ++ if (!dm_task_no_flush(new_dmt)) ++ log_warn("WARNING: Can't set no_flush for dm status."); ++ ++ if (!dm_task_run(new_dmt)) ++ goto_out; ++ ++ dmt = new_dmt; ++ } ++ ++ dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms); ++ ++ if (!target_type || (strcmp(target_type, "vdo") != 0)) { ++ log_error("Invalid target type."); ++ goto out; ++ } ++ ++ if (!dm_vdo_status_parse(state->mem, params, &vdop)) { ++ log_error("Failed to parse status."); ++ goto out; ++ } ++ ++ state->percent = dm_make_percent(vdop.status->used_blocks, ++ vdop.status->total_blocks); ++ ++#if VDO_DEBUG ++ log_debug("VDO %s status %.2f%% " FMTu64 "/" FMTu64 ".", ++ state->name, dm_percent_to_round_float(state->percent, 2), ++ vdop.status->used_blocks, vdop.status->total_blocks); ++#endif ++ ++ /* VDO pool size had changed. Clear the threshold. */ ++ if (state->known_data_size != vdop.status->total_blocks) { ++ state->percent_check = CHECK_MINIMUM; ++ state->known_data_size = vdop.status->total_blocks; ++ state->fails = 0; ++ } ++ ++ /* ++ * Trigger action when threshold boundary is exceeded. ++ * Report 80% threshold warning when it's used above 80%. ++ * Only 100% is exception as it cannot be surpased so policy ++ * action is called for: >50%, >55% ... >95%, 100% ++ */ ++ if ((state->percent > WARNING_THRESH) && ++ (state->percent > state->percent_check)) ++ log_warn("WARNING: VDO %s %s is now %.2f%% full.", ++ state->name, device, ++ dm_percent_to_round_float(state->percent, 2)); ++ if (state->percent > CHECK_MINIMUM) { ++ /* Run action when usage raised more than CHECK_STEP since the last time */ ++ if (state->percent > state->percent_check) ++ needs_policy = 1; ++ state->percent_check = (state->percent / CHECK_STEP + 1) * CHECK_STEP; ++ if (state->percent_check == DM_PERCENT_100) ++ state->percent_check--; /* Can't get bigger then 100% */ ++ } else ++ state->percent_check = CHECK_MINIMUM; ++ ++ /* Reduce number of _use_policy() calls by power-of-2 factor till frequency of MAX_FAILS is reached. ++ * Avoids too high number of error retries, yet shows some status messages in log regularly. ++ * i.e. PV could have been pvmoved and VG/LV was locked for a while... ++ */ ++ if (state->fails) { ++ if (state->fails++ <= state->max_fails) { ++ log_debug("Postponing frequently failing policy (%u <= %u).", ++ state->fails - 1, state->max_fails); ++ return; ++ } ++ if (state->max_fails < MAX_FAILS) ++ state->max_fails <<= 1; ++ state->fails = needs_policy = 1; /* Retry failing command */ ++ } else ++ state->max_fails = 1; /* Reset on success */ ++ ++ /* FIXME: ATM nothing can be done, drop 0, once it becomes useful */ ++ if (0 && needs_policy) ++ _use_policy(dmt, state); ++out: ++ if (vdop.status) ++ dm_pool_free(state->mem, vdop.status); ++ ++ if (new_dmt) ++ dm_task_destroy(new_dmt); ++} ++ ++/* Handle SIGCHLD for a thread */ ++static void _sig_child(int signum __attribute__((unused))) ++{ ++ /* empty SIG_IGN */; ++} ++ ++/* Setup handler for SIGCHLD when executing external command ++ * to get quick 'waitpid()' reaction ++ * It will interrupt syscall just like SIGALRM and ++ * invoke process_event(). ++ */ ++static void _init_thread_signals(struct dso_state *state) ++{ ++ struct sigaction act = { .sa_handler = _sig_child }; ++ sigset_t my_sigset; ++ ++ sigemptyset(&my_sigset); ++ ++ if (sigaction(SIGCHLD, &act, NULL)) ++ log_warn("WARNING: Failed to set SIGCHLD action."); ++ else if (sigaddset(&my_sigset, SIGCHLD)) ++ log_warn("WARNING: Failed to add SIGCHLD to set."); ++ else if (pthread_sigmask(SIG_UNBLOCK, &my_sigset, &state->old_sigset)) ++ log_warn("WARNING: Failed to unblock SIGCHLD."); ++ else ++ state->restore_sigset = 1; ++} ++ ++static void _restore_thread_signals(struct dso_state *state) ++{ ++ if (state->restore_sigset && ++ pthread_sigmask(SIG_SETMASK, &state->old_sigset, NULL)) ++ log_warn("WARNING: Failed to block SIGCHLD."); ++} ++ ++int register_device(const char *device, ++ const char *uuid, ++ int major __attribute__((unused)), ++ int minor __attribute__((unused)), ++ void **user) ++{ ++ struct dso_state *state; ++ const char *cmd; ++ char *str; ++ char cmd_str[PATH_MAX + 128 + 2]; /* cmd ' ' vg/lv \0 */ ++ const char *name = "pool"; ++ ++ if (!dmeventd_lvm2_init_with_pool("vdo_pool_state", state)) ++ goto_bad; ++ ++ state->cmd_str = ""; ++ ++ /* Search for command for LVM- prefixed devices only */ ++ cmd = (strncmp(uuid, "LVM-", 4) == 0) ? "_dmeventd_vdo_command" : ""; ++ ++ if (!dmeventd_lvm2_command(state->mem, cmd_str, sizeof(cmd_str), cmd, device)) ++ goto_bad; ++ ++ if (strncmp(cmd_str, "lvm ", 4) == 0) { ++ if (!(state->cmd_str = dm_pool_strdup(state->mem, cmd_str + 4))) { ++ log_error("Failed to copy lvm VDO command."); ++ goto bad; ++ } ++ } else if (cmd_str[0] == '/') { ++ if (!(state->cmd_str = dm_pool_strdup(state->mem, cmd_str))) { ++ log_error("Failed to copy VDO command."); ++ goto bad; ++ } ++ ++ /* Find last space before 'vg/lv' */ ++ if (!(str = strrchr(state->cmd_str, ' '))) ++ goto inval; ++ ++ if (!(state->argv[0] = dm_pool_strndup(state->mem, state->cmd_str, ++ str - state->cmd_str))) { ++ log_error("Failed to copy command."); ++ goto bad; ++ } ++ ++ state->argv[1] = str + 1; /* 1 argument - vg/lv */ ++ _init_thread_signals(state); ++ } else if (cmd[0] == 0) { ++ state->name = "volume"; /* What to use with 'others?' */ ++ } else/* Unuspported command format */ ++ goto inval; ++ ++ state->pid = -1; ++ state->name = name; ++ *user = state; ++ ++ log_info("Monitoring VDO %s %s.", name, device); ++ ++ return 1; ++inval: ++ log_error("Invalid command for monitoring: %s.", cmd_str); ++bad: ++ log_error("Failed to monitor VDO %s %s.", name, device); ++ ++ if (state) ++ dmeventd_lvm2_exit_with_pool(state); ++ ++ return 0; ++} ++ ++int unregister_device(const char *device, ++ const char *uuid __attribute__((unused)), ++ int major __attribute__((unused)), ++ int minor __attribute__((unused)), ++ void **user) ++{ ++ struct dso_state *state = *user; ++ const char *name = state->name; ++ int i; ++ ++ for (i = 0; !_wait_for_pid(state) && (i < 6); ++i) { ++ if (i == 0) ++ /* Give it 2 seconds, then try to terminate & kill it */ ++ log_verbose("Child %d still not finished (%s) waiting.", ++ state->pid, state->cmd_str); ++ else if (i == 3) { ++ log_warn("WARNING: Terminating child %d.", state->pid); ++ kill(state->pid, SIGINT); ++ kill(state->pid, SIGTERM); ++ } else if (i == 5) { ++ log_warn("WARNING: Killing child %d.", state->pid); ++ kill(state->pid, SIGKILL); ++ } ++ sleep(1); ++ } ++ ++ if (state->pid != -1) ++ log_warn("WARNING: Cannot kill child %d!", state->pid); ++ ++ _restore_thread_signals(state); ++ ++ dmeventd_lvm2_exit_with_pool(state); ++ log_info("No longer monitoring VDO %s %s.", name, device); ++ ++ return 1; ++} diff --git a/SOURCES/lvm2-2_02_181-dmeventd-rebase-to-stable-branch.patch b/SOURCES/lvm2-2_02_181-dmeventd-rebase-to-stable-branch.patch new file mode 100644 index 0000000..05cdc33 --- /dev/null +++ b/SOURCES/lvm2-2_02_181-dmeventd-rebase-to-stable-branch.patch @@ -0,0 +1,94 @@ + daemons/dmeventd/plugins/vdo/dmeventd_vdo.c | 39 +++++++++++++++++++---------- + 1 file changed, 26 insertions(+), 13 deletions(-) + +diff --git a/daemons/dmeventd/plugins/vdo/dmeventd_vdo.c b/daemons/dmeventd/plugins/vdo/dmeventd_vdo.c +index d77ca79..389632c 100644 +--- a/daemons/dmeventd/plugins/vdo/dmeventd_vdo.c ++++ b/daemons/dmeventd/plugins/vdo/dmeventd_vdo.c +@@ -12,10 +12,9 @@ + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +-#include "lib/misc/lib.h" ++#include "lib.h" + #include "dmeventd_lvm.h" +-#include "daemons/dmeventd/libdevmapper-event.h" +-#include "device_mapper/vdo/target.h" ++#include "libdevmapper-event.h" + + #include + #include +@@ -46,6 +45,23 @@ struct dso_state { + const char *name; + }; + ++struct vdo_status { ++ uint64_t used_blocks; ++ uint64_t total_blocks; ++}; ++ ++static int _vdo_status_parse(const char *params, struct vdo_status *status) ++{ ++ if (sscanf(params, "%*s %*s %*s %*s %*s %" PRIu64 " %" PRIu64, ++ &status->used_blocks, ++ &status->total_blocks) < 2) { ++ log_error("Failed to parse vdo params: %s.", params); ++ return 0; ++ } ++ ++ return 1; ++} ++ + DM_EVENT_LOG_FN("vdo") + + static int _run_command(struct dso_state *state) +@@ -149,7 +165,7 @@ void process_event(struct dm_task *dmt, + char *params; + int needs_policy = 0; + struct dm_task *new_dmt = NULL; +- struct dm_vdo_status_parse_result vdop = { .status = NULL }; ++ struct vdo_status status; + + #if VDO_DEBUG + log_debug("Watch for VDO %s:%.2f%%.", state->name, +@@ -195,24 +211,24 @@ void process_event(struct dm_task *dmt, + goto out; + } + +- if (!dm_vdo_status_parse(state->mem, params, &vdop)) { ++ if (!_vdo_status_parse(params, &status)) { + log_error("Failed to parse status."); + goto out; + } + +- state->percent = dm_make_percent(vdop.status->used_blocks, +- vdop.status->total_blocks); ++ state->percent = dm_make_percent(status.used_blocks, ++ status.total_blocks); + + #if VDO_DEBUG + log_debug("VDO %s status %.2f%% " FMTu64 "/" FMTu64 ".", + state->name, dm_percent_to_round_float(state->percent, 2), +- vdop.status->used_blocks, vdop.status->total_blocks); ++ status.used_blocks, status.total_blocks); + #endif + + /* VDO pool size had changed. Clear the threshold. */ +- if (state->known_data_size != vdop.status->total_blocks) { ++ if (state->known_data_size != status.total_blocks) { + state->percent_check = CHECK_MINIMUM; +- state->known_data_size = vdop.status->total_blocks; ++ state->known_data_size = status.total_blocks; + state->fails = 0; + } + +@@ -257,9 +273,6 @@ void process_event(struct dm_task *dmt, + if (0 && needs_policy) + _use_policy(dmt, state); + out: +- if (vdop.status) +- dm_pool_free(state->mem, vdop.status); +- + if (new_dmt) + dm_task_destroy(new_dmt); + } diff --git a/SOURCES/lvm2-2_02_181-dmsetup-fix-error-propagation-in-_display_info_cols.patch b/SOURCES/lvm2-2_02_181-dmsetup-fix-error-propagation-in-_display_info_cols.patch new file mode 100644 index 0000000..8a1a079 --- /dev/null +++ b/SOURCES/lvm2-2_02_181-dmsetup-fix-error-propagation-in-_display_info_cols.patch @@ -0,0 +1,19 @@ + tools/dmsetup.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/tools/dmsetup.c b/tools/dmsetup.c +index 95a15dd..3cdf862 100644 +--- a/tools/dmsetup.c ++++ b/tools/dmsetup.c +@@ -939,8 +939,10 @@ static int _display_info_cols(struct dm_task *dmt, struct dm_info *info) + goto_out; + + /* No regions to report is not an error */ +- if (!dm_stats_get_nr_regions(obj.stats)) ++ if (!dm_stats_get_nr_regions(obj.stats)) { ++ r = 1; + goto out; ++ } + } + + /* group report with no groups? */ diff --git a/SOURCES/lvm2-2_02_181-lvconvert-improve-text-about-splitmirrors.patch b/SOURCES/lvm2-2_02_181-lvconvert-improve-text-about-splitmirrors.patch new file mode 100644 index 0000000..32fd96d --- /dev/null +++ b/SOURCES/lvm2-2_02_181-lvconvert-improve-text-about-splitmirrors.patch @@ -0,0 +1,72 @@ + lib/metadata/raid_manip.c | 4 ++-- + tools/args.h | 14 +++++++++----- + tools/command-lines.in | 2 +- + 3 files changed, 12 insertions(+), 8 deletions(-) + +diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c +index 8f78e1a..705a7f9 100644 +--- a/lib/metadata/raid_manip.c ++++ b/lib/metadata/raid_manip.c +@@ -3563,7 +3563,7 @@ int lv_raid_merge(struct logical_volume *image_lv) + struct volume_group *vg = image_lv->vg; + + if (image_lv->status & LVM_WRITE) { +- log_error("%s is not read-only - refusing to merge.", ++ log_error("%s cannot be merged because --trackchanges was not used.", + display_lvname(image_lv)); + return 0; + } +@@ -3572,7 +3572,7 @@ int lv_raid_merge(struct logical_volume *image_lv) + return_0; + + if (!(p = strstr(lv_name, "_rimage_"))) { +- log_error("Unable to merge non-mirror image %s.", ++ log_error("Unable to merge non-raid image %s.", + display_lvname(image_lv)); + return 0; + } +diff --git a/tools/args.h b/tools/args.h +index b80b8da..abe193c 100644 +--- a/tools/args.h ++++ b/tools/args.h +@@ -611,7 +611,9 @@ arg(splitcache_ARG, '\0', "splitcache", 0, 0, 0, + arg(splitmirrors_ARG, '\0', "splitmirrors", number_VAL, 0, 0, + "Splits the specified number of images from a raid1 or mirror LV\n" + "and uses them to create a new LV. If --trackchanges is also specified,\n" +- "changes to the raid1 LV are tracked while the split LV remains detached.\n") ++ "changes to the raid1 LV are tracked while the split LV remains detached.\n" ++ "If --name is specified, then the images are permanently split from the\n" ++ "original LV and changes are not tracked.\n") + + arg(splitsnapshot_ARG, '\0', "splitsnapshot", 0, 0, 0, + "Separates a COW snapshot from its origin LV. The LV that is split off\n" +@@ -691,10 +693,12 @@ arg(thinpool_ARG, '\0', "thinpool", lv_VAL, 0, 0, + arg(trackchanges_ARG, '\0', "trackchanges", 0, 0, 0, + "Can be used with --splitmirrors on a raid1 LV. This causes\n" + "changes to the original raid1 LV to be tracked while the split images\n" +- "remain detached. This allows the read-only detached image(s) to be\n" +- "merged efficiently back into the raid1 LV later. Only the regions with\n" +- "changed data are resynchronized during merge. (This option only applies\n" +- "when using the raid1 LV type.)\n") ++ "remain detached. This is a temporary state that allows the read-only\n" ++ "detached image to be merged efficiently back into the raid1 LV later.\n" ++ "Only the regions with changed data are resynchronized during merge.\n" ++ "While a raid1 LV is tracking changes, operations on it are limited to\n" ++ "merging the split image (see --mergemirrors) or permanently splitting\n" ++ "the image (see --splitmirrors with --name.\n") + + /* TODO: hide this? */ + arg(trustcache_ARG, '\0', "trustcache", 0, 0, 0, +diff --git a/tools/command-lines.in b/tools/command-lines.in +index b7aefa3..a8c06ba 100644 +--- a/tools/command-lines.in ++++ b/tools/command-lines.in +@@ -399,7 +399,7 @@ lvconvert --splitmirrors Number --trackchanges LV_raid1_cache + OO: OO_LVCONVERT + OP: PV ... + ID: lvconvert_split_mirror_images +-DESC: Split images from a raid1 LV and track changes to origin. ++DESC: Split images from a raid1 LV and track changes to origin for later merge. + RULE: all not lv_is_locked lv_is_pvmove + + lvconvert --mergemirrors LV_linear_raid|VG|Tag ... diff --git a/SOURCES/lvm2-2_02_181-lvconvert-reject-conversions-of-LVs-under-snapshot.patch b/SOURCES/lvm2-2_02_181-lvconvert-reject-conversions-of-LVs-under-snapshot.patch new file mode 100644 index 0000000..78dfd4e --- /dev/null +++ b/SOURCES/lvm2-2_02_181-lvconvert-reject-conversions-of-LVs-under-snapshot.patch @@ -0,0 +1,20 @@ + tools/lvconvert.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/tools/lvconvert.c b/tools/lvconvert.c +index 3ce228f..3fad02c 100644 +--- a/tools/lvconvert.c ++++ b/tools/lvconvert.c +@@ -4256,6 +4256,12 @@ static int _lvconvert_to_pool_or_swap_metadata_single(struct cmd_context *cmd, + return 0; + }; + ++ if (lv_is_origin(lv)) { ++ log_error("Cannot convert logical volume %s under snapshot.", ++ display_lvname(lv)); ++ return 0; ++ }; ++ + if (cmd->position_argc > 1) { + /* First pos arg is required LV, remaining are optional PVs. */ + if (!(use_pvh = create_pv_list(cmd->mem, lv->vg, cmd->position_argc - 1, cmd->position_argv + 1, 0))) diff --git a/SOURCES/lvm2-2_02_181-lvconvert-restrict-command-matching-for-no-option-va.patch b/SOURCES/lvm2-2_02_181-lvconvert-restrict-command-matching-for-no-option-va.patch new file mode 100644 index 0000000..61608ed --- /dev/null +++ b/SOURCES/lvm2-2_02_181-lvconvert-restrict-command-matching-for-no-option-va.patch @@ -0,0 +1,69 @@ + lib/commands/toolcontext.h | 1 + + tools/command-lines.in | 2 +- + tools/lvmcmdline.c | 14 ++++++++++++++ + 3 files changed, 16 insertions(+), 1 deletion(-) + +diff --git a/lib/commands/toolcontext.h b/lib/commands/toolcontext.h +index bc05736..da5d582 100644 +--- a/lib/commands/toolcontext.h ++++ b/lib/commands/toolcontext.h +@@ -95,6 +95,7 @@ struct cmd_context { + char **argv; + struct arg_values *opt_arg_values; + struct dm_list arg_value_groups; ++ int opt_count; /* total number of options (beginning with - or --) */ + + /* + * Position args remaining after command name +diff --git a/tools/command-lines.in b/tools/command-lines.in +index 9d407d0..b7aefa3 100644 +--- a/tools/command-lines.in ++++ b/tools/command-lines.in +@@ -700,7 +700,7 @@ RULE: all and lv_is_converting + # for compat since this was how it used to be done. + lvconvert LV_mirror_raid + OO: OO_LVCONVERT +-ID: lvconvert_start_poll ++ID: lvconvert_plain + DESC: Poll LV to continue conversion (also see --startpoll) + DESC: or waits till conversion/mirror syncing is finished + FLAGS: SECONDARY_SYNTAX +diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c +index 0600b1c..c62a66e 100644 +--- a/tools/lvmcmdline.c ++++ b/tools/lvmcmdline.c +@@ -119,6 +119,7 @@ static const struct command_function _command_functions[CMD_COUNT] = { + + /* lvconvert utility to trigger polling on an LV. */ + { lvconvert_start_poll_CMD, lvconvert_start_poll_cmd }, ++ { lvconvert_plain_CMD, lvconvert_start_poll_cmd }, + + /* lvconvert utilities for creating/maintaining thin and cache objects. */ + { lvconvert_to_thinpool_CMD, lvconvert_to_pool_cmd }, +@@ -1579,6 +1580,17 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path, + if (arg_is_set(cmd, help_ARG) || arg_is_set(cmd, help2_ARG) || arg_is_set(cmd, longhelp_ARG) || arg_is_set(cmd, version_ARG)) + return &commands[i]; + ++ /* ++ * The 'lvconvert LV' cmd def matches any lvconvert cmd which throws off ++ * nearest-command partial-match suggestions. Make it a special case so ++ * that it won't be used as a close match. If the command has any option ++ * set (other than -v), don't attempt to match it to 'lvconvert LV'. ++ */ ++ if (commands[i].command_enum == lvconvert_plain_CMD) { ++ if (cmd->opt_count - cmd->opt_arg_values[verbose_ARG].count) ++ continue; ++ } ++ + match_required = 0; /* required parameters that match */ + match_ro = 0; /* required opt_args that match */ + match_rp = 0; /* required pos_args that match */ +@@ -2097,6 +2109,8 @@ static int _process_command_line(struct cmd_context *cmd, int *argc, char ***arg + if (goval == '?') + return 0; + ++ cmd->opt_count++; ++ + /* + * translate the option value used by getopt into the enum + * value (e.g. foo_ARG) from the args array. diff --git a/SOURCES/lvm2-2_02_181-post-release.patch b/SOURCES/lvm2-2_02_181-post-release.patch new file mode 100644 index 0000000..126d1bd --- /dev/null +++ b/SOURCES/lvm2-2_02_181-post-release.patch @@ -0,0 +1,26 @@ + WHATS_NEW | 3 +++ + WHATS_NEW_DM | 3 +++ + 2 files changed, 6 insertions(+) + +diff --git a/WHATS_NEW b/WHATS_NEW +index 62a5045..bdd2fa6 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,3 +1,6 @@ ++Version 2.02.181 - ++================================= ++ + Version 2.02.180 - 19th July 2018 + ================================= + Never send any discard ioctl with test mode. +diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM +index 93e4b14..e77352a 100644 +--- a/WHATS_NEW_DM ++++ b/WHATS_NEW_DM +@@ -1,3 +1,6 @@ ++Version 1.02.150 - ++================================= ++ + Version 1.02.149 - 19th July 2018 + ================================= + diff --git a/SOURCES/lvm2-2_02_181-reject-conversions-trackchanges-LVs.patch b/SOURCES/lvm2-2_02_181-reject-conversions-trackchanges-LVs.patch new file mode 100644 index 0000000..68c7b5d --- /dev/null +++ b/SOURCES/lvm2-2_02_181-reject-conversions-trackchanges-LVs.patch @@ -0,0 +1,51 @@ + WHATS_NEW | 1 + + test/shell/lvconvert-raid1-split-trackchanges.sh | 7 +++++++ + tools/lvconvert.c | 6 ++++++ + 3 files changed, 14 insertions(+) + +diff --git a/WHATS_NEW b/WHATS_NEW +index 7c74c50..3b15325 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,5 +1,6 @@ + Version 2.02.181 - + ================================= ++ lvconvert: reject conversions on raid1 LVs with split tracked SubLVs + lvconvert: reject conversions on raid1 split tracked SubLVs + + Version 2.02.180 - 19th July 2018 +diff --git a/test/shell/lvconvert-raid1-split-trackchanges.sh b/test/shell/lvconvert-raid1-split-trackchanges.sh +index e25a632..718c254 100644 +--- a/test/shell/lvconvert-raid1-split-trackchanges.sh ++++ b/test/shell/lvconvert-raid1-split-trackchanges.sh +@@ -27,6 +27,13 @@ vgcreate $SHARED -s 512k "$vg" "${DEVICES[@]}" + lvcreate -y --ty raid1 -m 2 -n $lv1 -l 1 $vg + lvconvert -y --splitmirrors 1 --trackchanges $vg/$lv1 + ++not lvconvert -y --ty linear $vg/$lv1 ++not lvconvert -y --ty striped -i 3 $vg/$lv1 ++not lvconvert -y --ty mirror $vg/$lv1 ++not lvconvert -y --ty raid4 $vg/$lv1 ++not lvconvert -y --ty raid5 $vg/$lv1 ++not lvconvert -y --ty raid6 $vg/$lv1 ++not lvconvert -y --ty raid10 $vg/$lv1 + not lvconvert -y --ty striped -m 1 $vg/${lv1}_rimage_2 + not lvconvert -y --ty raid1 -m 1 $vg/${lv1}_rimage_2 + not lvconvert -y --ty mirror -m 1 $vg/${lv1}_rimage_2 +diff --git a/tools/lvconvert.c b/tools/lvconvert.c +index 079c3cd..731a210 100644 +--- a/tools/lvconvert.c ++++ b/tools/lvconvert.c +@@ -1170,6 +1170,12 @@ static int _raid_split_image_conversion(struct logical_volume *lv) + { + const char *s; + ++ if (lv_is_raid_with_tracking(lv)) { ++ log_error("Conversion of tracking raid1 LV %s is not supported.", ++ display_lvname(lv)); ++ return 1; ++ } ++ + if (lv_is_raid_image(lv) && + (s = strstr(lv->name, "_rimage_"))) { + size_t len = s - lv->name; diff --git a/SOURCES/lvm2-2_02_181-reject-conversions-trackchanges-SubLVs.patch b/SOURCES/lvm2-2_02_181-reject-conversions-trackchanges-SubLVs.patch new file mode 100644 index 0000000..f822a79 --- /dev/null +++ b/SOURCES/lvm2-2_02_181-reject-conversions-trackchanges-SubLVs.patch @@ -0,0 +1,150 @@ + WHATS_NEW | 1 + + test/shell/lvconvert-raid1-split-trackchanges.sh | 36 +++++++++++++++++++ + tools/lvconvert.c | 45 ++++++++++++++++++++++++ + 3 files changed, 82 insertions(+) + create mode 100644 test/shell/lvconvert-raid1-split-trackchanges.sh + +diff --git a/WHATS_NEW b/WHATS_NEW +index bdd2fa6..7c74c50 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,5 +1,6 @@ + Version 2.02.181 - + ================================= ++ lvconvert: reject conversions on raid1 split tracked SubLVs + + Version 2.02.180 - 19th July 2018 + ================================= +diff --git a/test/shell/lvconvert-raid1-split-trackchanges.sh b/test/shell/lvconvert-raid1-split-trackchanges.sh +new file mode 100644 +index 0000000..e25a632 +--- /dev/null ++++ b/test/shell/lvconvert-raid1-split-trackchanges.sh +@@ -0,0 +1,36 @@ ++#!/usr/bin/env bash ++ ++# Copyright (C) 2018 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 ++ ++ ++SKIP_WITH_LVMPOLLD=1 ++ ++. lib/inittest ++ ++# rhbz1579072/rhbz1579438 ++ ++aux have_raid 1 3 0 || skip ++ ++# 8 PVs needed for RAID10 testing (4-stripes/2-mirror) ++aux prepare_pvs 4 2 ++get_devs ++vgcreate $SHARED -s 512k "$vg" "${DEVICES[@]}" ++ ++lvcreate -y --ty raid1 -m 2 -n $lv1 -l 1 $vg ++lvconvert -y --splitmirrors 1 --trackchanges $vg/$lv1 ++ ++not lvconvert -y --ty striped -m 1 $vg/${lv1}_rimage_2 ++not lvconvert -y --ty raid1 -m 1 $vg/${lv1}_rimage_2 ++not lvconvert -y --ty mirror -m 1 $vg/${lv1}_rimage_2 ++not lvconvert -y --ty cache-pool $vg/${lv1}_rimage_2 ++not lvconvert -y --ty thin-pool $vg/${lv1}_rimage_2 ++ ++vgremove -ff $vg +diff --git a/tools/lvconvert.c b/tools/lvconvert.c +index 3fad02c..079c3cd 100644 +--- a/tools/lvconvert.c ++++ b/tools/lvconvert.c +@@ -1165,6 +1165,36 @@ static int _lvconvert_validate_thin(struct logical_volume *lv, + return 0; + } + ++/* Check for raid1 split trackchanges image to reject conversions on it. */ ++static int _raid_split_image_conversion(struct logical_volume *lv) ++{ ++ const char *s; ++ ++ if (lv_is_raid_image(lv) && ++ (s = strstr(lv->name, "_rimage_"))) { ++ size_t len = s - lv->name; ++ char raidlv_name[len + 1]; ++ const struct logical_volume *tmp_lv; ++ ++ strncpy(raidlv_name, lv->name, len); ++ raidlv_name[len] = '\0'; ++ ++ if (!(tmp_lv = find_lv(lv->vg, raidlv_name))) { ++ log_error(INTERNAL_ERROR "Failed to find RaidLV of RAID subvolume %s.", ++ display_lvname(lv)); ++ return 1; ++ } ++ ++ if (lv_is_raid_with_tracking(tmp_lv)) { ++ log_error("Conversion of tracked raid1 subvolume %s is not supported.", ++ display_lvname(lv)); ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ + /* + * _lvconvert_mirrors + * +@@ -1180,6 +1210,9 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, + uint32_t new_mimage_count = 0; + uint32_t new_log_count = 0; + ++ if (_raid_split_image_conversion(lv)) ++ return 0; ++ + if ((lp->corelog || lp->mirrorlog) && *lp->type_str && strcmp(lp->type_str, SEG_TYPE_NAME_MIRROR)) { + log_error("--corelog and --mirrorlog are only compatible with mirror devices."); + return 0; +@@ -1296,6 +1329,9 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l + struct cmd_context *cmd = lv->vg->cmd; + struct lv_segment *seg = first_seg(lv); + ++ if (_raid_split_image_conversion(lv)) ++ return 0; ++ + if (_linear_type_requested(lp->type_str)) { + if (arg_is_set(cmd, mirrors_ARG) && (arg_uint_value(cmd, mirrors_ARG, 0) != 0)) { + log_error("Cannot specify mirrors with linear type."); +@@ -2579,6 +2615,9 @@ static int _lvconvert_to_thin_with_external(struct cmd_context *cmd, + .virtual_extents = lv->le_count, + }; + ++ if (_raid_split_image_conversion(lv)) ++ return 0; ++ + if (lv == thinpool_lv) { + log_error("Can't use same LV %s for thin pool and thin volume.", + display_lvname(thinpool_lv)); +@@ -2888,6 +2927,9 @@ static int _lvconvert_to_pool(struct cmd_context *cmd, + struct id lockd_meta_id; + const char *str_seg_type = to_cachepool ? SEG_TYPE_NAME_CACHE_POOL : SEG_TYPE_NAME_THIN_POOL; + ++ if (_raid_split_image_conversion(lv)) ++ return 0; ++ + if (lv_is_thin_pool(lv) || lv_is_cache_pool(lv)) { + log_error(INTERNAL_ERROR "LV %s is already a pool.", display_lvname(lv)); + return 0; +@@ -3339,6 +3381,9 @@ static int _lvconvert_to_cache_vol(struct cmd_context *cmd, + struct dm_config_tree *policy_settings = NULL; + int r = 0; + ++ if (_raid_split_image_conversion(lv)) ++ return 0; ++ + /* If LV is inactive here, ensure it's not active elsewhere. */ + if (!lockd_lv(cmd, lv, "ex", 0)) + return_0; diff --git a/SOURCES/lvm2-2_02_182-cache-drop-metadata_format-validation.patch b/SOURCES/lvm2-2_02_182-cache-drop-metadata_format-validation.patch new file mode 100644 index 0000000..6c92fad --- /dev/null +++ b/SOURCES/lvm2-2_02_182-cache-drop-metadata_format-validation.patch @@ -0,0 +1,36 @@ + WHATS_NEW | 4 ++++ + lib/metadata/cache_manip.c | 5 ----- + 2 files changed, 4 insertions(+), 5 deletions(-) + +diff --git a/WHATS_NEW b/WHATS_NEW +index 546d3e6..17aff08 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,3 +1,7 @@ ++Version 2.02.182 - ++============================== ++ Do not pair cache policy and cache metadata format. ++ + Version 2.02.181 - + ================================= + Reject conversions on raid1 LVs with split tracked SubLVs. +diff --git a/lib/metadata/cache_manip.c b/lib/metadata/cache_manip.c +index c15f117..8376bfb 100644 +--- a/lib/metadata/cache_manip.c ++++ b/lib/metadata/cache_manip.c +@@ -843,15 +843,10 @@ int cache_set_metadata_format(struct lv_segment *seg, cache_metadata_format_t fo + + /* + * If policy is unselected, but format 2 is selected, policy smq is enforced. +- * ATM no other then smq & cleaner policy is allowed to select format 2. + */ + if (!seg->policy_name) { + if (format == CACHE_METADATA_FORMAT_2) + seg->policy_name = "smq"; +- } else if (strcmp(seg->policy_name, "smq") && +- strcmp(seg->policy_name, "cleaner")) { +- seg->cache_metadata_format = CACHE_METADATA_FORMAT_1; +- return 1; + } + + /* Check if we need to search for configured cache metadata format */ diff --git a/SOURCES/lvm2-2_02_182-dmeventd-lvm2-plugin-uses-envvar-registry.patch b/SOURCES/lvm2-2_02_182-dmeventd-lvm2-plugin-uses-envvar-registry.patch new file mode 100644 index 0000000..3d79e13 --- /dev/null +++ b/SOURCES/lvm2-2_02_182-dmeventd-lvm2-plugin-uses-envvar-registry.patch @@ -0,0 +1,131 @@ +From 41d8039e12ebad0727f8c7455ad9392bc61e6414 Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Mon, 27 Aug 2018 10:18:26 +0200 +Subject: [PATCH 1/2] dmeventd: lvm2 plugin uses envvar registry + +Thin plugin started to use configuble setting to allow to configure +usage of external scripts - however to read this value it needed to +execute internal command as dmeventd itself has no access to lvm.conf +and the API for dmeventd plugin has been kept stable. + +The call of command itself was not normally 'a big issue' until users +started to use higher number of monitored LVs and execution of command +got stuck because other monitored resource already started to execute +some other lvm2 command and become blocked waiting on VG lock. + +This scenario revealed necesity to somehow avoid calling lvm2 command +during resource registration - but this requires bigger changes - so +meanwhile this patch tries to minimize the possibility to hit this race +by obtaining any configurable setting just once - such patch is small +and covers majority of problem - yet better solution needs to be +introduced likely with bigger rework of dmeventd. + +TODO: Avoid blocking registration of resource with execution of lvm2 +commands since those can get stuck waiting on mutexes. + +(cherry picked from commit a8d59404f7713ae4f9a3b172dd560ed1364d8bee) + +Conflicts: + WHATS_NEW_DM +--- + WHATS_NEW_DM | 4 +++ + daemons/dmeventd/plugins/lvm2/dmeventd_lvm.c | 49 +++++++++++++++++++++------- + 2 files changed, 42 insertions(+), 11 deletions(-) + +diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM +index c42ee17..42cf2a8 100644 +--- a/WHATS_NEW_DM ++++ b/WHATS_NEW_DM +@@ -1,3 +1,7 @@ ++Version 1.02.151 - ++============================== ++ Add hot fix to avoiding locking collision when monitoring thin-pools. ++ + Version 1.02.150 - + ================================= + Add vdo plugin for monitoring VDO devices. +diff --git a/daemons/dmeventd/plugins/lvm2/dmeventd_lvm.c b/daemons/dmeventd/plugins/lvm2/dmeventd_lvm.c +index 930f9fc..5be11f1 100644 +--- a/daemons/dmeventd/plugins/lvm2/dmeventd_lvm.c ++++ b/daemons/dmeventd/plugins/lvm2/dmeventd_lvm.c +@@ -31,6 +31,13 @@ static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER; + static int _register_count = 0; + static struct dm_pool *_mem_pool = NULL; + static void *_lvm_handle = NULL; ++static DM_LIST_INIT(_env_registry); ++ ++struct env_data { ++ struct dm_list list; ++ const char *cmd; ++ const char *data; ++}; + + DM_EVENT_LOG_FN("#lvm") + +@@ -100,6 +107,7 @@ void dmeventd_lvm2_exit(void) + lvm2_run(_lvm_handle, "_memlock_dec"); + dm_pool_destroy(_mem_pool); + _mem_pool = NULL; ++ dm_list_init(&_env_registry); + lvm2_exit(_lvm_handle); + _lvm_handle = NULL; + log_debug("lvm plugin exited."); +@@ -124,6 +132,8 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size, + static char _internal_prefix[] = "_dmeventd_"; + char *vg = NULL, *lv = NULL, *layer; + int r; ++ struct env_data *env_data; ++ const char *env = NULL; + + if (!dm_split_lvm_name(mem, device, &vg, &lv, &layer)) { + log_error("Unable to determine VG name from %s.", +@@ -137,18 +147,35 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size, + *layer = '\0'; + + if (!strncmp(cmd, _internal_prefix, sizeof(_internal_prefix) - 1)) { +- dmeventd_lvm2_lock(); +- /* output of internal command passed via env var */ +- if (!dmeventd_lvm2_run(cmd)) +- cmd = NULL; +- else if ((cmd = getenv(cmd))) +- cmd = dm_pool_strdup(mem, cmd); /* copy with lock */ +- dmeventd_lvm2_unlock(); +- +- if (!cmd) { +- log_error("Unable to find configured command."); +- return 0; ++ /* check if ENVVAR wasn't already resolved */ ++ dm_list_iterate_items(env_data, &_env_registry) ++ if (!strcmp(cmd, env_data->cmd)) { ++ env = env_data->data; ++ break; ++ } ++ ++ if (!env) { ++ /* run lvm2 command to find out setting value */ ++ dmeventd_lvm2_lock(); ++ if (!dmeventd_lvm2_run(cmd) || ++ !(env = getenv(cmd))) { ++ log_error("Unable to find configured command."); ++ return 0; ++ } ++ /* output of internal command passed via env var */ ++ env = dm_pool_strdup(_mem_pool, env); /* copy with lock */ ++ dmeventd_lvm2_unlock(); ++ if (!env || ++ !(env_data = dm_pool_zalloc(_mem_pool, sizeof(*env_data))) || ++ !(env_data->cmd = dm_pool_strdup(_mem_pool, cmd))) { ++ log_error("Unable to allocate env memory."); ++ return 0; ++ } ++ env_data->data = env; ++ /* add to ENVVAR registry */ ++ dm_list_add(&_env_registry, &env_data->list); + } ++ cmd = env; + } + + r = dm_snprintf(buffer, size, "%s %s/%s", cmd, vg, lv); +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_182-lvconvert-avoid-superfluous-interim-raid-type.patch b/SOURCES/lvm2-2_02_182-lvconvert-avoid-superfluous-interim-raid-type.patch new file mode 100644 index 0000000..7da9388 --- /dev/null +++ b/SOURCES/lvm2-2_02_182-lvconvert-avoid-superfluous-interim-raid-type.patch @@ -0,0 +1,45 @@ +From c43515c7ba1d13d54c92d43b76ca0a661c097292 Mon Sep 17 00:00:00 2001 +From: Heinz Mauelshagen +Date: Fri, 31 Aug 2018 19:03:52 +0200 +Subject: [PATCH] lvconvert: avoid superfluous interim raid type + +When converting striped/raid0*/raid6_n_6 <-> raid4, +avoid superfluous interim raid5_n layout. + +Related: rhbz1447809 +(cherry picked from commit 22a13043683a5647e8cc4e3aead911e5269ffd2f) +(cherry picked from commit 0e03c686191b036a7cd6e570888793ddbdd5f958) +--- + lib/metadata/raid_manip.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c +index d3e3a20..3eee77a 100644 +--- a/lib/metadata/raid_manip.c ++++ b/lib/metadata/raid_manip.c +@@ -6140,7 +6140,7 @@ static int _set_convenient_raid145610_segtype_to(const struct lv_segment *seg_fr + seg_flag = SEG_RAID6_N_6; + + if (segtype_is_linear(*segtype) || +- (!segtype_is_raid10(*segtype) && !segtype_is_striped(*segtype))) ++ (!segtype_is_raid4(*segtype) && !segtype_is_raid10(*segtype) && !segtype_is_striped(*segtype))) + seg_flag = SEG_RAID5_N; + + /* raid1 -> */ +@@ -6209,10 +6209,9 @@ static int _set_convenient_raid145610_segtype_to(const struct lv_segment *seg_fr + lvseg_name(seg_from), display_lvname(seg_from->lv), *new_image_count); + } + +- /* raid4 -> !raid4/raid5* */ +- } else if (seg_is_raid4(seg_from) && +- !segtype_is_raid4(*segtype) && !segtype_is_any_raid5(*segtype)) { +- seg_flag = SEG_RAID5_N; ++ /* raid4 -> * */ ++ } else if (seg_is_raid4(seg_from) && !segtype_is_raid4(*segtype) && !segtype_is_striped(*segtype)) { ++ seg_flag = segtype_is_any_raid6(*segtype) ? SEG_RAID6_N_6 : SEG_RAID5_N; + + /* raid6 -> striped/raid0/raid5/raid10 */ + } else if (seg_is_any_raid6(seg_from)) { +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_182-lvconvert-fix-conversion-attempts-to-linear.patch b/SOURCES/lvm2-2_02_182-lvconvert-fix-conversion-attempts-to-linear.patch new file mode 100644 index 0000000..9c1b7d1 --- /dev/null +++ b/SOURCES/lvm2-2_02_182-lvconvert-fix-conversion-attempts-to-linear.patch @@ -0,0 +1,268 @@ +From 83b93f9f5a72ac67f63e6be2c25ce4b3919c4c84 Mon Sep 17 00:00:00 2001 +From: Heinz Mauelshagen +Date: Wed, 22 Aug 2018 16:39:36 +0200 +Subject: [PATCH] lvconvert: fix conversion attempts to linear + +"lvconvert --type linear RaidLV" on striped and raid4/5/6/10 +have to provide the convenient interim layouts. Fix involves +a cleanup to the convenience type function. + +As a result of testing, add missing sync waits to +lvconvert-raid-reshape-linear_to_raid6-single-type.sh. + +Resolves: rhbz1447809 +(cherry picked from commit e83c4f07ca4a84808178d5d22cba655e5e370cd8) + +Conflicts: + WHATS_NEW + +(cherry picked from commit d910f75d89e02e46cd16f9ddbc8e8358c3c2efd3) +--- + WHATS_NEW | 1 + + lib/metadata/raid_manip.c | 145 +++++++++------------ + ...ert-raid-reshape-linear_to_raid6-single-type.sh | 2 + + 3 files changed, 68 insertions(+), 80 deletions(-) + +diff --git a/WHATS_NEW b/WHATS_NEW +index e3eee56..92e5c04 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,5 +1,6 @@ + Version 2.02.182 - + ============================== ++ Fix lvconvert conversion attempts to linear. + Fix lvconvert raid0/raid0_meta -> striped regression. + Fix lvconvert --splitmirror for mirror type (2.02.178). + Do not pair cache policy and cache metadata format. +diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c +index 804f78b..d3e3a20 100644 +--- a/lib/metadata/raid_manip.c ++++ b/lib/metadata/raid_manip.c +@@ -6120,8 +6120,7 @@ static int _set_convenient_raid145610_segtype_to(const struct lv_segment *seg_fr + const struct segment_type *segtype_sav = *segtype; + + /* Linear -> striped request */ +- if (seg_is_striped(seg_from) && +- seg_from->area_count == 1 && ++ if (seg_is_linear(seg_from) && + segtype_is_striped(*segtype)) + ; + /* Bail out if same RAID level is requested. */ +@@ -6130,24 +6129,20 @@ static int _set_convenient_raid145610_segtype_to(const struct lv_segment *seg_fr + + 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)) { +- /* linear -> raid*, interim/first conversion is to raid1 */ +- if (seg_from->area_count == 1) +- seg_flag = SEG_RAID1; +- +- else if (seg_is_any_raid0(seg_from) && segtype_is_striped(*segtype)) +- ; +- +- /* If this is any raid5 conversion request -> enforce raid5_n, because we convert from striped */ +- else if (((segtype_is_striped(*segtype) && !segtype_is_any_raid0(*segtype)) || segtype_is_any_raid5(*segtype)) && +- !segtype_is_raid5_n(*segtype)) +- seg_flag = SEG_RAID5_N; + +- /* 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)) ++ /* linear -> */ ++ if (seg_is_linear(seg_from)) { ++ seg_flag = SEG_RAID1; ++ ++ /* striped/raid0 -> */ ++ } else if (seg_is_striped(seg_from) || seg_is_any_raid0(seg_from)) { ++ if (segtype_is_any_raid6(*segtype)) + seg_flag = SEG_RAID6_N_6; + ++ if (segtype_is_linear(*segtype) || ++ (!segtype_is_raid10(*segtype) && !segtype_is_striped(*segtype))) ++ seg_flag = SEG_RAID5_N; ++ + /* raid1 -> */ + } else if (seg_is_raid1(seg_from) && !segtype_is_mirror(*segtype)) { + if (seg_from->area_count != 2) { +@@ -6157,85 +6152,68 @@ static int _set_convenient_raid145610_segtype_to(const struct lv_segment *seg_fr + } + + if (segtype_is_striped(*segtype) || +- segtype_is_any_raid0(*segtype) || +- segtype_is_raid10(*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) || segtype_is_linear(*segtype)) && seg_is_raid5_n(seg_from)) { ++ /* raid5* -> */ ++ } else if (seg_is_any_raid5(seg_from)) { ++ if (segtype_is_raid1(*segtype) || segtype_is_linear(*segtype)) { + if (seg_from->area_count != 2) { + log_error("Converting %s LV %s to 2 stripes first.", + lvseg_name(seg_from), display_lvname(seg_from->lv)); + *new_image_count = 2; +- seg_flag = SEG_RAID5_N; ++ *segtype = seg_from->segtype; ++ seg_flag = 0; + } else + seg_flag = SEG_RAID1; + +- } else if (segtype_is_raid1(*segtype) && seg_from->area_count != 2) { +- 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) && +- (segtype_is_linear(*segtype) || segtype_is_any_raid5(*segtype)) && +- !segtype_is_raid5_n(*segtype)) +- seg_flag = SEG_RAID5_N; ++ } else if (segtype_is_any_raid6(*segtype)) { ++ if (seg_from->area_count < 4) { ++ if (*stripes > 3) ++ *new_image_count = *stripes + seg_from->segtype->parity_devs; ++ else ++ *new_image_count = 4; + +- else if (seg_is_raid5_n(seg_from) && seg_from->area_count == 2) { +- if (*stripes >= 2) { ++ *segtype = seg_from->segtype; + log_error("Converting %s LV %s to %u stripes first.", +- lvseg_name(seg_from), display_lvname(seg_from->lv), *stripes); ++ lvseg_name(seg_from), display_lvname(seg_from->lv), *new_image_count); ++ ++ } else ++ seg_flag = _raid_seg_flag_5_to_6(seg_from); ++ ++ } else if (segtype_is_striped(*segtype) || segtype_is_raid10(*segtype)) { ++ int change = 0; ++ ++ if (!seg_is_raid5_n(seg_from)) { ++ seg_flag = SEG_RAID5_N; ++ ++ } else if (*stripes > 2 && *stripes != seg_from->area_count - seg_from->segtype->parity_devs) { ++ change = 1; + *new_image_count = *stripes + seg_from->segtype->parity_devs; + seg_flag = SEG_RAID5_N; +- } else { +- 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; +- } +- } else if (seg_is_any_raid5(seg_from) && +- (segtype_is_linear(*segtype) || 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) { +- if (*stripes >= 2) { +- log_error("Converting %s LV %s to %u stripes first.", +- lvseg_name(seg_from), display_lvname(seg_from->lv), *stripes); +- *new_image_count = *stripes + seg_from->segtype->parity_devs; +- seg_flag = SEG_RAID5_N; +- } else { +- 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; +- } +- } else +- seg_flag = seg_is_raid5_n(seg_from) ? SEG_RAID0_META : SEG_RAID5_N; ++ } else if (seg_from->area_count < 3) { ++ change = 1; ++ *new_image_count = 3; ++ seg_flag = SEG_RAID5_N; + +- } else if (segtype_is_any_raid6(*segtype)) { +- if (seg_from->area_count < 4 && +- seg_is_any_raid5(seg_from)) { +- if (*stripes >= 3) { +- log_error("Converting %s LV %s to %u stripes first.", +- lvseg_name(seg_from), display_lvname(seg_from->lv), *stripes); +- *new_image_count = *stripes + seg_from->segtype->parity_devs; +- seg_flag = SEG_RAID5_LS; +- } else { +- 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 (!segtype_is_striped(*segtype)) ++ seg_flag = SEG_RAID0_META; + +- } 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); ++ if (change) ++ log_error("Converting %s LV %s to %u stripes first.", ++ lvseg_name(seg_from), display_lvname(seg_from->lv), *new_image_count); + } + ++ /* raid4 -> !raid4/raid5* */ ++ } else if (seg_is_raid4(seg_from) && ++ !segtype_is_raid4(*segtype) && !segtype_is_any_raid5(*segtype)) { ++ seg_flag = SEG_RAID5_N; ++ + /* raid6 -> striped/raid0/raid5/raid10 */ + } else if (seg_is_any_raid6(seg_from)) { + if (segtype_is_raid1(*segtype)) { +@@ -6247,6 +6225,9 @@ static int _set_convenient_raid145610_segtype_to(const struct lv_segment *seg_fr + } 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_linear(*segtype)) { ++ seg_flag = seg_is_raid6_n_6(seg_from) ? SEG_RAID5_N : SEG_RAID6_N_6; ++ + } else if (segtype_is_striped(*segtype) || segtype_is_any_raid0(*segtype)) { + if (!seg_is_raid6_n_6(seg_from)) + seg_flag = SEG_RAID6_N_6; +@@ -6277,12 +6258,16 @@ static int _set_convenient_raid145610_segtype_to(const struct lv_segment *seg_fr + return 0; + } + +- /* raid10 -> ... */ +- } else if (seg_is_raid10(seg_from) && +- !segtype_is_striped(*segtype) && +- !segtype_is_any_raid0(*segtype)) +- seg_flag = SEG_RAID0_META; ++ } else if (seg_is_raid10(seg_from)) { ++ if (segtype_is_linear(*segtype) || ++ (!segtype_is_striped(*segtype) && ++ !segtype_is_any_raid0(*segtype))) { ++ seg_flag = SEG_RAID0_META; ++ } ++ } + ++ ++ /* raid10 -> ... */ + if (seg_flag) { + if (!(*segtype = get_segtype_from_flag(cmd, seg_flag))) + return_0; +diff --git a/test/shell/lvconvert-raid-reshape-linear_to_raid6-single-type.sh b/test/shell/lvconvert-raid-reshape-linear_to_raid6-single-type.sh +index f01e7ef..05cb616 100644 +--- a/test/shell/lvconvert-raid-reshape-linear_to_raid6-single-type.sh ++++ b/test/shell/lvconvert-raid-reshape-linear_to_raid6-single-type.sh +@@ -78,6 +78,7 @@ check lv_first_seg_field $vg/$lv data_stripes 3 + check lv_first_seg_field $vg/$lv stripesize "64.00k" + check lv_first_seg_field $vg/$lv regionsize "128.00k" + check lv_first_seg_field $vg/$lv reshape_len_le 0 ++aux wait_for_sync $vg $lv + + # Convert raid6_ls_6 -> raid6(_zr) (reshape) + lvconvert -y --type raid6 --stripes 3 --stripesize 64K --regionsize 128K $vg/$lv +@@ -88,6 +89,7 @@ check lv_first_seg_field $vg/$lv data_stripes 3 + check lv_first_seg_field $vg/$lv stripesize "64.00k" + check lv_first_seg_field $vg/$lv regionsize "128.00k" + check lv_first_seg_field $vg/$lv reshape_len_le 10 ++aux wait_for_sync $vg $lv + + # Remove reshape space + lvconvert -y --type raid6 --stripes 3 --stripesize 64K --regionsize 128K $vg/$lv +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_182-lvconvert-fix-direct-raid0-to-striped-conversion.patch b/SOURCES/lvm2-2_02_182-lvconvert-fix-direct-raid0-to-striped-conversion.patch new file mode 100644 index 0000000..c07dcaa --- /dev/null +++ b/SOURCES/lvm2-2_02_182-lvconvert-fix-direct-raid0-to-striped-conversion.patch @@ -0,0 +1,62 @@ + WHATS_NEW | 1 + + lib/metadata/raid_manip.c | 3 +++ + test/shell/lvconvert-raid0-striped.sh | 25 +++++++++++++++++++++++++ + 3 files changed, 29 insertions(+) + create mode 100644 test/shell/lvconvert-raid0-striped.sh + +diff --git a/WHATS_NEW b/WHATS_NEW +index 6560357..e3eee56 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,5 +1,6 @@ + Version 2.02.182 - + ============================== ++ Fix lvconvert raid0/raid0_meta -> striped regression. + Fix lvconvert --splitmirror for mirror type (2.02.178). + Do not pair cache policy and cache metadata format. + +diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c +index 705a7f9..804f78b 100644 +--- a/lib/metadata/raid_manip.c ++++ b/lib/metadata/raid_manip.c +@@ -6136,6 +6136,9 @@ static int _set_convenient_raid145610_segtype_to(const struct lv_segment *seg_fr + if (seg_from->area_count == 1) + seg_flag = SEG_RAID1; + ++ else if (seg_is_any_raid0(seg_from) && segtype_is_striped(*segtype)) ++ ; ++ + /* If this is any raid5 conversion request -> enforce raid5_n, because we convert from striped */ + else if (((segtype_is_striped(*segtype) && !segtype_is_any_raid0(*segtype)) || segtype_is_any_raid5(*segtype)) && + !segtype_is_raid5_n(*segtype)) +diff --git a/test/shell/lvconvert-raid0-striped.sh b/test/shell/lvconvert-raid0-striped.sh +new file mode 100644 +index 0000000..4521b34 +--- /dev/null ++++ b/test/shell/lvconvert-raid0-striped.sh +@@ -0,0 +1,25 @@ ++#!/usr/bin/env bash ++ ++# Copyright (C) 2018 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 ++ ++ ++SKIP_WITH_LVMPOLLD=1 ++ ++. lib/inittest ++ ++aux have_raid 1 7 0 || skip ++ ++aux prepare_vg 3 16 ++ ++lvcreate -aey --type raid0 -i 3 -l3 -n $lv $vg ++lvconvert -y --type striped $vg/$lv ++check lv_field $vg/$lv segtype "striped" ++vgremove -ff $vg diff --git a/SOURCES/lvm2-2_02_182-lvconvert-fix-interim-segtype-regression-on-raid6-co.patch b/SOURCES/lvm2-2_02_182-lvconvert-fix-interim-segtype-regression-on-raid6-co.patch new file mode 100644 index 0000000..32ad471 --- /dev/null +++ b/SOURCES/lvm2-2_02_182-lvconvert-fix-interim-segtype-regression-on-raid6-co.patch @@ -0,0 +1,93 @@ +From 2ee0f6d4ddd6c602def295e3b1dfccbd8a50a4c8 Mon Sep 17 00:00:00 2001 +From: Heinz Mauelshagen +Date: Fri, 7 Sep 2018 13:48:13 +0200 +Subject: [PATCH] lvconvert: fix interim segtype regression on raid6 + conversions + +When converting from striped/raid0/raid0_meta +to raid6 with > 2 stripes, allow possible +direct conversion (to raid6_n_6). + +In case of 2 stripes, first convert to raid5_n to restripe +to at least 3 data stripes (the raid6 minimum in lvm2) in +a second conversion before finally converting to raid6_n_6. + +As before, raid6_n_6 then can be converted +to any other raid6 layout. + +Enhance lvconvert-raid-takeover.sh to test the +2 stripes conversions to raid6. + +Resolves: rhbz1624038 +(cherry picked from commit e2e30a64ab10602951443dfbd3481bd6b32f5459) + +Conflicts: + WHATS_NEW + +(cherry picked from commit c26bde42af0930bef2cee95c76951285d801ba70) +--- + WHATS_NEW | 1 + + lib/metadata/raid_manip.c | 6 +++--- + test/shell/lvconvert-raid-takeover.sh | 16 ++++++++++++---- + 3 files changed, 16 insertions(+), 7 deletions(-) + +diff --git a/WHATS_NEW b/WHATS_NEW +index 9da40b6..d8a24b0 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,5 +1,6 @@ + Version 2.02.182 - + ============================== ++ Fix lvconvert striped/raid0/raid0_meta -> raid6 regression. + Add After=rbdmap.service to {lvm2-activation-net,blk-availability}.service. + Fix lvconvert conversion attempts to linear. + Fix lvconvert raid0/raid0_meta -> striped regression. +diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c +index 3eee77a..cb7202a 100644 +--- a/lib/metadata/raid_manip.c ++++ b/lib/metadata/raid_manip.c +@@ -6137,10 +6137,10 @@ static int _set_convenient_raid145610_segtype_to(const struct lv_segment *seg_fr + /* striped/raid0 -> */ + } else if (seg_is_striped(seg_from) || seg_is_any_raid0(seg_from)) { + if (segtype_is_any_raid6(*segtype)) +- seg_flag = SEG_RAID6_N_6; ++ seg_flag = seg_from->area_count < 3 ? SEG_RAID5_N : SEG_RAID6_N_6; + +- if (segtype_is_linear(*segtype) || +- (!segtype_is_raid4(*segtype) && !segtype_is_raid10(*segtype) && !segtype_is_striped(*segtype))) ++ else if (segtype_is_linear(*segtype) || ++ (!segtype_is_raid4(*segtype) && !segtype_is_raid10(*segtype) && !segtype_is_striped(*segtype))) + seg_flag = SEG_RAID5_N; + + /* raid1 -> */ +diff --git a/test/shell/lvconvert-raid-takeover.sh b/test/shell/lvconvert-raid-takeover.sh +index d1c5d30..d22c11b 100644 +--- a/test/shell/lvconvert-raid-takeover.sh ++++ b/test/shell/lvconvert-raid-takeover.sh +@@ -108,11 +108,19 @@ function _invalid_raid5_conversions + not _lvconvert raid6 raid6_n_6 4 6 $vg $lv1 + } + +-# Check raid6 conversion constrainst of minimum 3 stripes +-_lvcreate striped 2 2 4m $vg $lv1 +-not _lvconvert raid6 raid6_n_6 2 4 $vg $lv1 +-lvremove -y $vg ++# Check raid6 conversion constrainst for 2 stripes ++for type in striped raid0 raid0_meta ++do ++ _lvcreate $type 2 2 4m $vg $lv1 ++ not _lvconvert raid6 raid6_n_6 2 4 $vg $lv1 ++ _lvconvert raid6 raid5_n 2 3 $vg $lv1 ++ _lvconvert raid6 raid5_n 3 4 $vg $lv1 ++ _lvconvert raid6 raid6_n_6 3 5 $vg $lv1 ++ lvremove -y $vg ++done + ++ ++# Check raid6 conversion constrainst of minimum 3 stripes + _lvcreate raid0 3 3 4m $vg $lv1 + _lvconvert raid6 raid6_n_6 3 5 $vg $lv1 + lvremove -y $vg +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_182-mirror-fix-splitmirrors-for-mirror-type.patch b/SOURCES/lvm2-2_02_182-mirror-fix-splitmirrors-for-mirror-type.patch new file mode 100644 index 0000000..9c2e3ea --- /dev/null +++ b/SOURCES/lvm2-2_02_182-mirror-fix-splitmirrors-for-mirror-type.patch @@ -0,0 +1,45 @@ + WHATS_NEW | 1 + + lib/activate/activate.c | 5 +++++ + lib/metadata/mirror.c | 2 +- + 3 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/WHATS_NEW b/WHATS_NEW +index 17aff08..6560357 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,5 +1,6 @@ + Version 2.02.182 - + ============================== ++ Fix lvconvert --splitmirror for mirror type (2.02.178). + Do not pair cache policy and cache metadata format. + + Version 2.02.181 - +diff --git a/lib/activate/activate.c b/lib/activate/activate.c +index e38ab03..16704f6 100644 +--- a/lib/activate/activate.c ++++ b/lib/activate/activate.c +@@ -2125,6 +2125,11 @@ static int _preload_detached_lv(struct logical_volume *lv, void *data) + !lv_is_raid_metadata(lv_pre) && lv_is_active(lv) && + !_lv_preload(lv_pre, detached->laopts, detached->flush_required)) + return_0; ++ } else if (lv_is_mirror_image(lv)) { ++ if ((lv_pre = find_lv_in_vg_by_lvid(detached->lv_pre->vg, &lv->lvid)) && ++ !lv_is_mirror_image(lv_pre) && lv_is_active(lv) && ++ !_lv_preload(lv_pre, detached->laopts, detached->flush_required)) ++ return_0; + } + + if (!lv_is_visible(lv) && (lv_pre = find_lv(detached->lv_pre->vg, lv->name)) && +diff --git a/lib/metadata/mirror.c b/lib/metadata/mirror.c +index 7f38d4f..c7d8a9e 100644 +--- a/lib/metadata/mirror.c ++++ b/lib/metadata/mirror.c +@@ -786,7 +786,7 @@ static int _split_mirror_images(struct logical_volume *lv, + + act = lv_is_active(lv_lock_holder(lv)); + +- if (act && !_activate_lv_like_model(lv, new_lv)) { ++ if (act && (!deactivate_lv(cmd, new_lv) || !_activate_lv_like_model(lv, new_lv))) { + log_error("Failed to rename newly split LV in the kernel"); + return 0; + } diff --git a/SOURCES/lvm2-2_02_182-mirrors-fix-read_only_volume_list.patch b/SOURCES/lvm2-2_02_182-mirrors-fix-read_only_volume_list.patch new file mode 100644 index 0000000..885d995 --- /dev/null +++ b/SOURCES/lvm2-2_02_182-mirrors-fix-read_only_volume_list.patch @@ -0,0 +1,16 @@ + lib/activate/activate.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/lib/activate/activate.c b/lib/activate/activate.c +index 18f4b84..e38ab03 100644 +--- a/lib/activate/activate.c ++++ b/lib/activate/activate.c +@@ -1864,6 +1864,8 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume + + if (!laopts) + laopts = &zlaopts; ++ else ++ mirr_laopts.read_only = laopts->read_only; + + /* skip dmeventd code altogether */ + if (dmeventd_monitor_mode() == DMEVENTD_MONITOR_IGNORE) diff --git a/SOURCES/lvm2-2_02_182-scripts-add-After-rbdmap.service-to-lvm2-activation.patch b/SOURCES/lvm2-2_02_182-scripts-add-After-rbdmap.service-to-lvm2-activation.patch new file mode 100644 index 0000000..cc2f209 --- /dev/null +++ b/SOURCES/lvm2-2_02_182-scripts-add-After-rbdmap.service-to-lvm2-activation.patch @@ -0,0 +1,73 @@ +From 4484518f67dd41151571e0841ef13134abe39408 Mon Sep 17 00:00:00 2001 +From: Peter Rajnoha +Date: Thu, 30 Aug 2018 12:35:58 +0200 +Subject: [PATCH 2/2] scripts: add After=rbdmap.service to + {lvm2-activation-net,blk-availability}.service + +We need to have Ceph RBD devices mapped first before use in a stack +where LVM is on top so make sure rbdmap.service is called before +generated lvm2-activation-net.service. + +On shutdown, we need to stop blk-availability first before we stop the +rbdmap.service. + +Resolves: rhbz1623479 +(cherry picked from commit cb17ef221bdefea3625a22c19c6d8f5504441771) + +Conflicts: + WHATS_NEW + +(cherry picked from commit 3374a592502ef099d38491b0c2020a6945d825b1) + +Conflicts: + WHATS_NEW +--- + WHATS_NEW | 2 ++ + scripts/blk_availability_systemd_red_hat.service.in | 2 +- + scripts/lvm2_activation_generator_systemd_red_hat.c | 2 +- + 3 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/WHATS_NEW b/WHATS_NEW +index 92e5c04..9da40b6 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,9 +1,11 @@ + Version 2.02.182 - + ============================== ++ Add After=rbdmap.service to {lvm2-activation-net,blk-availability}.service. + Fix lvconvert conversion attempts to linear. + Fix lvconvert raid0/raid0_meta -> striped regression. + Fix lvconvert --splitmirror for mirror type (2.02.178). + Do not pair cache policy and cache metadata format. ++ Fix mirrors honoring read_only_volume_list. + + Version 2.02.181 - + ================================= +diff --git a/scripts/blk_availability_systemd_red_hat.service.in b/scripts/blk_availability_systemd_red_hat.service.in +index 1198baa..9462072 100644 +--- a/scripts/blk_availability_systemd_red_hat.service.in ++++ b/scripts/blk_availability_systemd_red_hat.service.in +@@ -1,6 +1,6 @@ + [Unit] + Description=Availability of block devices +-After=lvm2-activation.service lvm2-lvmetad.service iscsi-shutdown.service iscsi.service iscsid.service fcoe.service ++After=lvm2-activation.service lvm2-lvmetad.service iscsi-shutdown.service iscsi.service iscsid.service fcoe.service rbdmap.service + DefaultDependencies=no + Conflicts=shutdown.target + +diff --git a/scripts/lvm2_activation_generator_systemd_red_hat.c b/scripts/lvm2_activation_generator_systemd_red_hat.c +index 0f7f89c..487582f 100644 +--- a/scripts/lvm2_activation_generator_systemd_red_hat.c ++++ b/scripts/lvm2_activation_generator_systemd_red_hat.c +@@ -128,7 +128,7 @@ static int generate_unit(const char *dir, int unit, int sysinit_needed) + "DefaultDependencies=no\n", f); + + if (unit == UNIT_NET) { +- fprintf(f, "After=%s iscsi.service fcoe.service\n" ++ fprintf(f, "After=%s iscsi.service fcoe.service rbdmap.service\n" + "Before=remote-fs-pre.target shutdown.target\n\n" + "[Service]\n" + "ExecStartPre=/usr/bin/udevadm settle\n", unit_names[UNIT_MAIN]); +-- +1.8.3.1 + diff --git a/SOURCES/lvm2-2_02_182-vgcreate-close-exclusive-fd-after-pvcreate.patch b/SOURCES/lvm2-2_02_182-vgcreate-close-exclusive-fd-after-pvcreate.patch new file mode 100644 index 0000000..7a7e060 --- /dev/null +++ b/SOURCES/lvm2-2_02_182-vgcreate-close-exclusive-fd-after-pvcreate.patch @@ -0,0 +1,53 @@ + lib/label/label.c | 6 +++--- + tools/toollib.c | 7 +++++++ + 2 files changed, 10 insertions(+), 3 deletions(-) + +diff --git a/lib/label/label.c b/lib/label/label.c +index ac37713..bafa543 100644 +--- a/lib/label/label.c ++++ b/lib/label/label.c +@@ -1190,7 +1190,7 @@ bool dev_write_bytes(struct device *dev, uint64_t start, size_t len, void *data) + return false; + } + +- if (!(dev->flags & DEV_BCACHE_WRITE)) { ++ if (_in_bcache(dev) && !(dev->flags & DEV_BCACHE_WRITE)) { + /* FIXME: avoid tossing out bcache blocks just to replace fd. */ + log_debug("Close and reopen to write %s", dev_name(dev)); + bcache_invalidate_fd(scan_bcache, dev->bcache_fd); +@@ -1236,7 +1236,7 @@ bool dev_write_zeros(struct device *dev, uint64_t start, size_t len) + return false; + } + +- if (!(dev->flags & DEV_BCACHE_WRITE)) { ++ if (_in_bcache(dev) && !(dev->flags & DEV_BCACHE_WRITE)) { + /* FIXME: avoid tossing out bcache blocks just to replace fd. */ + log_debug("Close and reopen to write %s", dev_name(dev)); + bcache_invalidate_fd(scan_bcache, dev->bcache_fd); +@@ -1282,7 +1282,7 @@ bool dev_set_bytes(struct device *dev, uint64_t start, size_t len, uint8_t val) + return false; + } + +- if (!(dev->flags & DEV_BCACHE_WRITE)) { ++ if (_in_bcache(dev) && !(dev->flags & DEV_BCACHE_WRITE)) { + /* FIXME: avoid tossing out bcache blocks just to replace fd. */ + log_debug("Close and reopen to write %s", dev_name(dev)); + bcache_invalidate_fd(scan_bcache, dev->bcache_fd); +diff --git a/tools/toollib.c b/tools/toollib.c +index b60ff06..e1c86f9 100644 +--- a/tools/toollib.c ++++ b/tools/toollib.c +@@ -5897,6 +5897,13 @@ do_command: + pd->name); + } + ++ /* ++ * Don't keep devs open excl in bcache because the excl will prevent ++ * using that dev elsewhere. ++ */ ++ dm_list_iterate_items(devl, &rescan_devs) ++ label_scan_invalidate(devl->dev); ++ + dm_list_iterate_items(pd, &pp->arg_fail) + log_debug("%s: command failed for %s.", + cmd->command->name, pd->name); 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 29677e4..0c7a0b0 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 @@ -1,13 +1,13 @@ configure | 20 ++++++++++---------- - configure.in | 4 ++-- + configure.ac | 4 ++-- lib/device/dev-type.c | 3 +-- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/configure b/configure -index d04b9d3..4f6e7d7 100755 +index 7d945df..ef24b31 100755 --- a/configure +++ b/configure -@@ -12322,12 +12322,12 @@ if test -n "$BLKID_CFLAGS"; then +@@ -12111,12 +12111,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 d04b9d3..4f6e7d7 100755 test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes -@@ -12339,12 +12339,12 @@ if test -n "$BLKID_LIBS"; then +@@ -12128,12 +12128,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 d04b9d3..4f6e7d7 100755 test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes -@@ -12365,9 +12365,9 @@ else +@@ -12154,9 +12154,9 @@ else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then @@ -51,7 +51,7 @@ index d04b9d3..4f6e7d7 100755 fi # Put the nasty error message in config.log where it belongs echo "$BLKID_PKG_ERRORS" >&5 -@@ -12375,7 +12375,7 @@ fi +@@ -12164,7 +12164,7 @@ fi if test "$BLKID_WIPING" = maybe; then BLKID_WIPING=no else @@ -60,7 +60,7 @@ index d04b9d3..4f6e7d7 100755 fi elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -@@ -12383,7 +12383,7 @@ $as_echo "no" >&6; } +@@ -12172,7 +12172,7 @@ $as_echo "no" >&6; } if test "$BLKID_WIPING" = maybe; then BLKID_WIPING=no else @@ -69,11 +69,11 @@ index d04b9d3..4f6e7d7 100755 fi else BLKID_CFLAGS=$pkg_cv_BLKID_CFLAGS -diff --git a/configure.in b/configure.in -index d879408..ab8b585 100644 ---- a/configure.in -+++ b/configure.in -@@ -1312,7 +1312,7 @@ AC_ARG_ENABLE(blkid_wiping, +diff --git a/configure.ac b/configure.ac +index e427708..935ea08 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1235,7 +1235,7 @@ AC_ARG_ENABLE(blkid_wiping, DEFAULT_USE_BLKID_WIPING=0 if test "$BLKID_WIPING" != no; then pkg_config_init @@ -82,7 +82,7 @@ index d879408..ab8b585 100644 [ BLKID_WIPING=yes BLKID_PC="blkid" DEFAULT_USE_BLKID_WIPING=1 -@@ -1320,7 +1320,7 @@ if test "$BLKID_WIPING" != no; then +@@ -1243,7 +1243,7 @@ if test "$BLKID_WIPING" != no; then ], [if test "$BLKID_WIPING" = maybe; then BLKID_WIPING=no else @@ -92,10 +92,10 @@ index d879408..ab8b585 100644 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 9608146..1e45f9d 100644 +index af4b407..eda7982 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 +@@ -712,8 +712,7 @@ static int _wipe_known_signatures_with_blkid(struct device *dev, const char *nam BLKID_SUBLKS_TYPE | BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION | diff --git a/SOURCES/lvm2-rhel7-add-lvm1-and-pool-back.patch b/SOURCES/lvm2-rhel7-add-lvm1-and-pool-back.patch new file mode 100644 index 0000000..675ed3d --- /dev/null +++ b/SOURCES/lvm2-rhel7-add-lvm1-and-pool-back.patch @@ -0,0 +1,6364 @@ + configure | 93 ++++- + configure.ac | 58 +++ + daemons/clvmd/clvmd-command.c | 1 + + daemons/clvmd/lvm-functions.c | 10 + + daemons/clvmd/lvm-functions.h | 1 + + daemons/lvmetad/lvmetad-client.h | 1 + + daemons/lvmetad/lvmetad-core.c | 9 +- + include/configure.h.in | 14 + + lib/Makefile.in | 29 ++ + lib/activate/activate.c | 13 + + lib/activate/activate.h | 1 + + lib/cache/lvmcache.c | 4 + + lib/cache/lvmetad.c | 23 +- + lib/commands/toolcontext.c | 24 ++ + lib/config/config_settings.h | 22 +- + lib/display/display.c | 9 +- + lib/format1/.exported_symbols | 1 + + lib/format1/Makefile.in | 33 ++ + lib/format1/disk-rep.c | 761 ++++++++++++++++++++++++++++++++++++++ + lib/format1/disk-rep.h | 250 +++++++++++++ + lib/format1/format1.c | 630 +++++++++++++++++++++++++++++++ + lib/format1/format1.h | 29 ++ + lib/format1/import-export.c | 680 ++++++++++++++++++++++++++++++++++ + lib/format1/import-extents.c | 377 +++++++++++++++++++ + lib/format1/layout.c | 172 +++++++++ + lib/format1/lvm1-label.c | 129 +++++++ + lib/format1/lvm1-label.h | 23 ++ + lib/format1/vg_number.c | 60 +++ + lib/format_pool/.exported_symbols | 1 + + lib/format_pool/Makefile.in | 30 ++ + lib/format_pool/disk_rep.c | 409 ++++++++++++++++++++ + lib/format_pool/disk_rep.h | 156 ++++++++ + lib/format_pool/format_pool.c | 337 +++++++++++++++++ + lib/format_pool/format_pool.h | 28 ++ + lib/format_pool/import_export.c | 285 ++++++++++++++ + lib/format_pool/pool_label.c | 104 ++++++ + lib/format_pool/pool_label.h | 23 ++ + lib/format_pool/sptype_names.h | 42 +++ + lib/format_text/export.c | 2 + + lib/format_text/format-text.c | 4 +- + lib/format_text/import_vsn1.c | 9 +- + lib/locking/locking.c | 40 ++ + lib/metadata/lv_manip.c | 26 ++ + lib/metadata/metadata-exported.h | 10 +- + lib/metadata/metadata.c | 18 +- + lib/metadata/segtype.h | 2 +- + lib/metadata/snapshot_manip.c | 11 + + lib/metadata/vg.c | 17 +- + lib/metadata/vg.h | 1 + + lib/report/report.c | 4 +- + lib/striped/striped.c | 3 +- + man/vgconvert.8_des | 7 +- + test/shell/format-lvm1.sh | 38 ++ + test/shell/lvm1-basic.sh | 36 ++ + test/shell/snapshot-lvm1.sh | 35 ++ + tools/args.h | 3 +- + tools/lvconvert.c | 5 + + tools/lvmcmdline.c | 58 ++- + tools/pvscan.c | 5 +- + tools/stub.h | 1 + + tools/toollib.c | 29 +- + tools/vals.h | 4 +- + tools/vgchange.c | 10 + + tools/vgconvert.c | 53 ++- + tools/vgscan.c | 4 +- + 65 files changed, 5254 insertions(+), 53 deletions(-) + create mode 100644 lib/format1/.exported_symbols + create mode 100644 lib/format1/Makefile.in + create mode 100644 lib/format1/disk-rep.c + create mode 100644 lib/format1/disk-rep.h + create mode 100644 lib/format1/format1.c + create mode 100644 lib/format1/format1.h + create mode 100644 lib/format1/import-export.c + create mode 100644 lib/format1/import-extents.c + create mode 100644 lib/format1/layout.c + create mode 100644 lib/format1/lvm1-label.c + create mode 100644 lib/format1/lvm1-label.h + create mode 100644 lib/format1/vg_number.c + create mode 100644 lib/format_pool/.exported_symbols + create mode 100644 lib/format_pool/Makefile.in + create mode 100644 lib/format_pool/disk_rep.c + create mode 100644 lib/format_pool/disk_rep.h + create mode 100644 lib/format_pool/format_pool.c + create mode 100644 lib/format_pool/format_pool.h + create mode 100644 lib/format_pool/import_export.c + create mode 100644 lib/format_pool/pool_label.c + create mode 100644 lib/format_pool/pool_label.h + create mode 100644 lib/format_pool/sptype_names.h + create mode 100644 test/shell/format-lvm1.sh + create mode 100644 test/shell/lvm1-basic.sh + create mode 100644 test/shell/snapshot-lvm1.sh + +diff --git a/configure b/configure +index ef24b31..10b49c6 100755 +--- a/configure ++++ b/configure +@@ -675,6 +675,7 @@ PYTHON_BINDINGS + PYTHON3 + PTHREAD_LIBS + M_LIBS ++POOL + PKGCONFIG + ODIRECT + OCFDIR +@@ -689,6 +690,8 @@ LVM_MINOR + LVM_MAJOR + LVM_LIBAPI + LVM_VERSION ++LVM1_FALLBACK ++LVM1 + LIB_SUFFIX + LDDEPS + JOBS +@@ -716,6 +719,7 @@ DEFAULT_RAID10_SEGTYPE + DEFAULT_PROFILE_SUBDIR + DEFAULT_PID_DIR + DEFAULT_MIRROR_SEGTYPE ++DEFAULT_FALLBACK_TO_LVM1 + DEFAULT_LOCK_DIR + DEFAULT_DM_RUN_DIR + DEFAULT_DATA_ALIGNMENT +@@ -908,6 +912,9 @@ with_device_gid + with_device_mode + with_device_nodes_on + with_default_name_mangling ++enable_lvm1_fallback ++with_lvm1 ++with_pool + with_cluster + with_snapshots + with_mirrors +@@ -1673,6 +1680,8 @@ Optional Features: + speeds up one-time build. + --enable-static_link use this to link the tools to their libraries + statically (default is dynamic linking ++ --enable-lvm1_fallback use this to fall back and use LVM1 binaries if ++ device-mapper is missing from the kernel + --disable-thin_check_needs_check + required if thin_check version is < 0.3.0 + --disable-cache_check_needs_check +@@ -1739,6 +1748,10 @@ Optional Packages: + create nodes on resume or create [ON=resume] + --with-default-name-mangling=MANGLING + default name mangling: auto/none/hex [auto] ++ --with-lvm1=TYPE LVM1 metadata support: internal/shared/none ++ [internal] ++ --with-pool=TYPE GFS pool read-only support: internal/shared/none ++ [internal] + --with-cluster=TYPE cluster LVM locking support: internal/shared/none + [internal] + --with-snapshots=TYPE snapshot support: internal/shared/none [internal] +@@ -8372,6 +8385,78 @@ _ACEOF + + + ################################################################################ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable lvm1 fallback" >&5 ++$as_echo_n "checking whether to enable lvm1 fallback... " >&6; } ++# Check whether --enable-lvm1_fallback was given. ++if test "${enable_lvm1_fallback+set}" = set; then : ++ enableval=$enable_lvm1_fallback; LVM1_FALLBACK=$enableval ++else ++ LVM1_FALLBACK=no ++fi ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LVM1_FALLBACK" >&5 ++$as_echo "$LVM1_FALLBACK" >&6; } ++ ++if test "$LVM1_FALLBACK" = yes; then ++ DEFAULT_FALLBACK_TO_LVM1=1 ++ ++$as_echo "#define LVM1_FALLBACK 1" >>confdefs.h ++ ++else ++ DEFAULT_FALLBACK_TO_LVM1=0 ++fi ++ ++cat >>confdefs.h <<_ACEOF ++#define DEFAULT_FALLBACK_TO_LVM1 $DEFAULT_FALLBACK_TO_LVM1 ++_ACEOF ++ ++ ++################################################################################ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include support for lvm1 metadata" >&5 ++$as_echo_n "checking whether to include support for lvm1 metadata... " >&6; } ++ ++# Check whether --with-lvm1 was given. ++if test "${with_lvm1+set}" = set; then : ++ withval=$with_lvm1; LVM1=$withval ++else ++ LVM1=internal ++fi ++ ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LVM1" >&5 ++$as_echo "$LVM1" >&6; } ++ ++case "$LVM1" in ++ none|shared) ;; ++ internal) ++$as_echo "#define LVM1_INTERNAL 1" >>confdefs.h ++ ;; ++ *) as_fn_error $? "--with-lvm1 parameter invalid" "$LINENO" 5 ;; ++esac ++ ++################################################################################ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include support for GFS pool metadata" >&5 ++$as_echo_n "checking whether to include support for GFS pool metadata... " >&6; } ++ ++# Check whether --with-pool was given. ++if test "${with_pool+set}" = set; then : ++ withval=$with_pool; POOL=$withval ++else ++ POOL=internal ++fi ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $POOL" >&5 ++$as_echo "$POOL" >&6; } ++ ++case "$POOL" in ++ none|shared) ;; ++ internal) ++$as_echo "#define POOL_INTERNAL 1" >>confdefs.h ++ ;; ++ *) as_fn_error $? "--with-pool parameter invalid" "$LINENO" 5 ++esac ++ ++################################################################################ + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include support for cluster locking" >&5 + $as_echo_n "checking whether to include support for cluster locking... " >&6; } + +@@ -15558,8 +15643,12 @@ _ACEOF + + + ++ ++ ++ ++ + ################################################################################ +-ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/dmfilemapd/Makefile daemons/lvmdbusd/Makefile daemons/lvmdbusd/lvmdbusd daemons/lvmdbusd/lvmdb.py daemons/lvmdbusd/lvm_shell_proxy.py daemons/lvmdbusd/path.py daemons/lvmetad/Makefile daemons/lvmpolld/Makefile daemons/lvmlockd/Makefile device_mapper/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/locking/Makefile include/lvm-version.h libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/com.redhat.lvmdbus1.service scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmdbusd_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_hat.socket scripts/lvm2_lvmlockd_systemd_red_hat.service scripts/lvm2_lvmlocking_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/lvmdump.sh scripts/Makefile test/Makefile test/api/Makefile test/api/python_lvm_unit.py test/unit/Makefile tools/Makefile udev/Makefile" ++ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/dmfilemapd/Makefile daemons/lvmdbusd/Makefile daemons/lvmdbusd/lvmdbusd daemons/lvmdbusd/lvmdb.py daemons/lvmdbusd/lvm_shell_proxy.py daemons/lvmdbusd/path.py daemons/lvmetad/Makefile daemons/lvmpolld/Makefile daemons/lvmlockd/Makefile device_mapper/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile include/lvm-version.h libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/com.redhat.lvmdbus1.service scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmdbusd_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_hat.socket scripts/lvm2_lvmlockd_systemd_red_hat.service scripts/lvm2_lvmlocking_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/lvmdump.sh scripts/Makefile test/Makefile test/api/Makefile test/api/python_lvm_unit.py test/unit/Makefile tools/Makefile udev/Makefile" + + cat >confcache <<\_ACEOF + # This file is a shell script that caches the results of configure +@@ -16285,6 +16374,8 @@ do + "include/.symlinks") CONFIG_FILES="$CONFIG_FILES include/.symlinks" ;; + "include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;; + "lib/Makefile") CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;; ++ "lib/format1/Makefile") CONFIG_FILES="$CONFIG_FILES lib/format1/Makefile" ;; ++ "lib/format_pool/Makefile") CONFIG_FILES="$CONFIG_FILES lib/format_pool/Makefile" ;; + "lib/locking/Makefile") CONFIG_FILES="$CONFIG_FILES lib/locking/Makefile" ;; + "include/lvm-version.h") CONFIG_FILES="$CONFIG_FILES include/lvm-version.h" ;; + "libdaemon/Makefile") CONFIG_FILES="$CONFIG_FILES libdaemon/Makefile" ;; +diff --git a/configure.ac b/configure.ac +index 935ea08..9fa0c76 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -283,6 +283,58 @@ AC_MSG_RESULT($MANGLING) + AC_DEFINE_UNQUOTED([DEFAULT_DM_NAME_MANGLING], $mangling, [Define default name mangling behaviour]) + + ################################################################################ ++dnl -- LVM1 tool fallback option ++AC_MSG_CHECKING(whether to enable lvm1 fallback) ++AC_ARG_ENABLE(lvm1_fallback, ++ AC_HELP_STRING([--enable-lvm1_fallback], ++ [use this to fall back and use LVM1 binaries if ++ device-mapper is missing from the kernel]), ++ LVM1_FALLBACK=$enableval, LVM1_FALLBACK=no) ++AC_MSG_RESULT($LVM1_FALLBACK) ++ ++if test "$LVM1_FALLBACK" = yes; then ++ DEFAULT_FALLBACK_TO_LVM1=1 ++ AC_DEFINE([LVM1_FALLBACK], 1, [Define to 1 if 'lvm' should fall back to using LVM1 binaries if device-mapper is missing from the kernel]) ++else ++ DEFAULT_FALLBACK_TO_LVM1=0 ++fi ++AC_DEFINE_UNQUOTED(DEFAULT_FALLBACK_TO_LVM1, [$DEFAULT_FALLBACK_TO_LVM1], ++ [Fall back to LVM1 by default if device-mapper is missing from the kernel.]) ++ ++################################################################################ ++dnl -- format1 inclusion type ++AC_MSG_CHECKING(whether to include support for lvm1 metadata) ++AC_ARG_WITH(lvm1, ++ AC_HELP_STRING([--with-lvm1=TYPE], ++ [LVM1 metadata support: internal/shared/none [internal]]), ++ LVM1=$withval, LVM1=internal) ++ ++AC_MSG_RESULT($LVM1) ++ ++case "$LVM1" in ++ none|shared) ;; ++ internal) AC_DEFINE([LVM1_INTERNAL], 1, ++ [Define to 1 to include built-in support for LVM1 metadata.]) ;; ++ *) AC_MSG_ERROR([--with-lvm1 parameter invalid]) ;; ++esac ++ ++################################################################################ ++dnl -- format_pool inclusion type ++AC_MSG_CHECKING(whether to include support for GFS pool metadata) ++AC_ARG_WITH(pool, ++ AC_HELP_STRING([--with-pool=TYPE], ++ [GFS pool read-only support: internal/shared/none [internal]]), ++ POOL=$withval, POOL=internal) ++AC_MSG_RESULT($POOL) ++ ++case "$POOL" in ++ none|shared) ;; ++ internal) AC_DEFINE([POOL_INTERNAL], 1, ++ [Define to 1 to include built-in support for GFS pool metadata.]) ;; ++ *) AC_MSG_ERROR([--with-pool parameter invalid]) ++esac ++ ++################################################################################ + dnl -- cluster_locking inclusion type + AC_MSG_CHECKING(whether to include support for cluster locking) + AC_ARG_WITH(cluster, +@@ -1967,6 +2019,7 @@ AC_SUBST(DEFAULT_CACHE_SUBDIR) + AC_SUBST(DEFAULT_DATA_ALIGNMENT) + AC_SUBST(DEFAULT_DM_RUN_DIR) + AC_SUBST(DEFAULT_LOCK_DIR) ++AC_SUBST(DEFAULT_FALLBACK_TO_LVM1) + AC_SUBST(DEFAULT_MIRROR_SEGTYPE) + AC_SUBST(DEFAULT_PID_DIR) + AC_SUBST(DEFAULT_PROFILE_SUBDIR) +@@ -1997,6 +2050,8 @@ AC_SUBST(JOBS) + AC_SUBST(LDDEPS) + AC_SUBST(LIBS) + AC_SUBST(LIB_SUFFIX) ++AC_SUBST(LVM1) ++AC_SUBST(LVM1_FALLBACK) + AC_SUBST(LVM_VERSION) + AC_SUBST(LVM_LIBAPI) + AC_SUBST(LVM_MAJOR) +@@ -2013,6 +2068,7 @@ AC_SUBST(OCF) + AC_SUBST(OCFDIR) + AC_SUBST(ODIRECT) + AC_SUBST(PKGCONFIG) ++AC_SUBST(POOL) + AC_SUBST(M_LIBS) + AC_SUBST(PTHREAD_LIBS) + AC_SUBST(PYTHON2) +@@ -2117,6 +2173,8 @@ conf/metadata_profile_template.profile + include/.symlinks + include/Makefile + lib/Makefile ++lib/format1/Makefile ++lib/format_pool/Makefile + lib/locking/Makefile + include/lvm-version.h + libdaemon/Makefile +diff --git a/daemons/clvmd/clvmd-command.c b/daemons/clvmd/clvmd-command.c +index ce7f500..2971ecb 100644 +--- a/daemons/clvmd/clvmd-command.c ++++ b/daemons/clvmd/clvmd-command.c +@@ -108,6 +108,7 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen, + lock_flags = args[1]; + lockname = &args[2]; + /* Check to see if the VG is in use by LVM1 */ ++ status = do_check_lvm1(lockname); + do_lock_vg(lock_cmd, lock_flags, lockname); + break; + +diff --git a/daemons/clvmd/lvm-functions.c b/daemons/clvmd/lvm-functions.c +index d6d395f..477c252 100644 +--- a/daemons/clvmd/lvm-functions.c ++++ b/daemons/clvmd/lvm-functions.c +@@ -639,6 +639,16 @@ int post_lock_lv(unsigned char command, unsigned char lock_flags, + return 0; + } + ++/* Check if a VG is in use by LVM1 so we don't stomp on it */ ++int do_check_lvm1(const char *vgname) ++{ ++ int status; ++ ++ status = check_lvm1_vg_inactive(cmd, vgname); ++ ++ return status == 1 ? 0 : EBUSY; ++} ++ + int do_refresh_cache(void) + { + DEBUGLOG("Refreshing context\n"); +diff --git a/daemons/clvmd/lvm-functions.h b/daemons/clvmd/lvm-functions.h +index 6785997..eac966f 100644 +--- a/daemons/clvmd/lvm-functions.h ++++ b/daemons/clvmd/lvm-functions.h +@@ -25,6 +25,7 @@ extern int do_lock_lv(unsigned char lock_cmd, unsigned char lock_flags, + extern const char *do_lock_query(char *resource); + extern int post_lock_lv(unsigned char lock_cmd, unsigned char lock_flags, + char *resource); ++extern int do_check_lvm1(const char *vgname); + extern int do_refresh_cache(void); + extern int init_clvm(struct dm_hash_table *excl_uuid); + extern void destroy_lvm(void); +diff --git a/daemons/lvmetad/lvmetad-client.h b/daemons/lvmetad/lvmetad-client.h +index be2623a..a2adfe6 100644 +--- a/daemons/lvmetad/lvmetad-client.h ++++ b/daemons/lvmetad/lvmetad-client.h +@@ -22,6 +22,7 @@ + #define LVMETAD_TOKEN_UPDATE_IN_PROGRESS "update in progress" + + #define LVMETAD_DISABLE_REASON_DIRECT "DIRECT" ++#define LVMETAD_DISABLE_REASON_LVM1 "LVM1" + #define LVMETAD_DISABLE_REASON_DUPLICATES "DUPLICATES" + #define LVMETAD_DISABLE_REASON_VGRESTORE "VGRESTORE" + #define LVMETAD_DISABLE_REASON_REPAIR "REPAIR" +diff --git a/daemons/lvmetad/lvmetad-core.c b/daemons/lvmetad/lvmetad-core.c +index 72473d7..f4f5f42 100644 +--- a/daemons/lvmetad/lvmetad-core.c ++++ b/daemons/lvmetad/lvmetad-core.c +@@ -200,12 +200,12 @@ struct vg_info { + #define GLFL_INVALID 0x00000001 + #define GLFL_DISABLE 0x00000002 + #define GLFL_DISABLE_REASON_DIRECT 0x00000004 +- /* 0x00000008 */ ++#define GLFL_DISABLE_REASON_LVM1 0x00000008 + #define GLFL_DISABLE_REASON_DUPLICATES 0x00000010 + #define GLFL_DISABLE_REASON_VGRESTORE 0x00000020 + #define GLFL_DISABLE_REASON_REPAIR 0x00000040 + +-#define GLFL_DISABLE_REASON_ALL (GLFL_DISABLE_REASON_DIRECT | GLFL_DISABLE_REASON_REPAIR | GLFL_DISABLE_REASON_DUPLICATES | GLFL_DISABLE_REASON_VGRESTORE) ++#define GLFL_DISABLE_REASON_ALL (GLFL_DISABLE_REASON_DIRECT | GLFL_DISABLE_REASON_REPAIR | GLFL_DISABLE_REASON_LVM1 | GLFL_DISABLE_REASON_DUPLICATES | GLFL_DISABLE_REASON_VGRESTORE) + + #define VGFL_INVALID 0x00000001 + +@@ -2369,6 +2369,8 @@ static response set_global_info(lvmetad_state *s, request r) + reason_flags |= GLFL_DISABLE_REASON_DIRECT; + if (strstr(reason, LVMETAD_DISABLE_REASON_REPAIR)) + reason_flags |= GLFL_DISABLE_REASON_REPAIR; ++ if (strstr(reason, LVMETAD_DISABLE_REASON_LVM1)) ++ reason_flags |= GLFL_DISABLE_REASON_LVM1; + if (strstr(reason, LVMETAD_DISABLE_REASON_DUPLICATES)) + reason_flags |= GLFL_DISABLE_REASON_DUPLICATES; + if (strstr(reason, LVMETAD_DISABLE_REASON_VGRESTORE)) +@@ -2427,9 +2429,10 @@ static response get_global_info(lvmetad_state *s, request r) + pid = (int)daemon_request_int(r, "pid", 0); + + if (s->flags & GLFL_DISABLE) { +- snprintf(reason, REASON_BUF_SIZE, "%s%s%s%s", ++ snprintf(reason, REASON_BUF_SIZE, "%s%s%s%s%s", + (s->flags & GLFL_DISABLE_REASON_DIRECT) ? LVMETAD_DISABLE_REASON_DIRECT "," : "", + (s->flags & GLFL_DISABLE_REASON_REPAIR) ? LVMETAD_DISABLE_REASON_REPAIR "," : "", ++ (s->flags & GLFL_DISABLE_REASON_LVM1) ? LVMETAD_DISABLE_REASON_LVM1 "," : "", + (s->flags & GLFL_DISABLE_REASON_DUPLICATES) ? LVMETAD_DISABLE_REASON_DUPLICATES "," : "", + (s->flags & GLFL_DISABLE_REASON_VGRESTORE) ? LVMETAD_DISABLE_REASON_VGRESTORE "," : ""); + } +diff --git a/include/configure.h.in b/include/configure.h.in +index 15fd150..605f1e1 100644 +--- a/include/configure.h.in ++++ b/include/configure.h.in +@@ -72,6 +72,10 @@ + /* Default system configuration directory. */ + #undef DEFAULT_ETC_DIR + ++/* Fall back to LVM1 by default if device-mapper is missing from the kernel. ++ */ ++#undef DEFAULT_FALLBACK_TO_LVM1 ++ + /* Name of default locking directory. */ + #undef DEFAULT_LOCK_DIR + +@@ -616,6 +620,13 @@ + slash. */ + #undef LSTAT_FOLLOWS_SLASHED_SYMLINK + ++/* Define to 1 if 'lvm' should fall back to using LVM1 binaries if ++ device-mapper is missing from the kernel */ ++#undef LVM1_FALLBACK ++ ++/* Define to 1 to include built-in support for LVM1 metadata. */ ++#undef LVM1_INTERNAL ++ + /* Path to lvmetad pidfile. */ + #undef LVMETAD_PIDFILE + +@@ -678,6 +689,9 @@ + /* Define to the version of this package. */ + #undef PACKAGE_VERSION + ++/* Define to 1 to include built-in support for GFS pool metadata. */ ++#undef POOL_INTERNAL ++ + /* Define to 1 to include built-in support for raid. */ + #undef RAID_INTERNAL + +diff --git a/lib/Makefile.in b/lib/Makefile.in +index 1d42235..241cf09 100644 +--- a/lib/Makefile.in ++++ b/lib/Makefile.in +@@ -16,6 +16,14 @@ srcdir = @srcdir@ + top_srcdir = @top_srcdir@ + top_builddir = @top_builddir@ + ++ifeq ("@LVM1@", "shared") ++ SUBDIRS = format1 ++endif ++ ++ifeq ("@POOL@", "shared") ++ SUBDIRS += format_pool ++endif ++ + ifeq ("@CLUSTER@", "shared") + SUBDIRS += locking + endif +@@ -107,6 +115,25 @@ SOURCES =\ + uuid/uuid.c \ + zero/zero.c + ++ifeq ("@LVM1@", "internal") ++ SOURCES +=\ ++ format1/disk-rep.c \ ++ format1/format1.c \ ++ format1/import-export.c \ ++ format1/import-extents.c \ ++ format1/layout.c \ ++ format1/lvm1-label.c \ ++ format1/vg_number.c ++endif ++ ++ifeq ("@POOL@", "internal") ++ SOURCES +=\ ++ format_pool/disk_rep.c \ ++ format_pool/format_pool.c \ ++ format_pool/import_export.c \ ++ format_pool/pool_label.c ++endif ++ + ifeq ("@CLUSTER@", "internal") + SOURCES += locking/cluster_locking.c + endif +@@ -143,6 +170,8 @@ LIB_STATIC = $(LIB_NAME).a + + ifeq ($(MAKECMDGOALS),distclean) + SUBDIRS =\ ++ format1 \ ++ format_pool \ + notify \ + locking + endif +diff --git a/lib/activate/activate.c b/lib/activate/activate.c +index 56ec732..18f4b84 100644 +--- a/lib/activate/activate.c ++++ b/lib/activate/activate.c +@@ -37,6 +37,19 @@ + + #define _skip(fmt, args...) log_very_verbose("Skipping: " fmt , ## args) + ++int lvm1_present(struct cmd_context *cmd) ++{ ++ static char path[PATH_MAX]; ++ ++ if (dm_snprintf(path, sizeof(path), "%s/lvm/global", cmd->proc_dir) ++ < 0) { ++ log_error("LVM1 proc global snprintf failed"); ++ return 0; ++ } ++ ++ return (path_exists(path)) ? 1 : 0; ++} ++ + int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg, + struct dm_list *modules) + { +diff --git a/lib/activate/activate.h b/lib/activate/activate.h +index d2c6db7..2fc74ce 100644 +--- a/lib/activate/activate.h ++++ b/lib/activate/activate.h +@@ -91,6 +91,7 @@ int activation(void); + + int driver_version(char *version, size_t size); + int library_version(char *version, size_t size); ++int lvm1_present(struct cmd_context *cmd); + + int module_present(struct cmd_context *cmd, const char *target_name); + int target_present_version(struct cmd_context *cmd, const char *target_name, +diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c +index 3e681a2..2fba3ff 100644 +--- a/lib/cache/lvmcache.c ++++ b/lib/cache/lvmcache.c +@@ -22,6 +22,8 @@ + #include "memlock.h" + #include "str_list.h" + #include "format-text.h" ++#include "format_pool.h" ++#include "format1.h" + #include "config.h" + + #include "lvmetad.h" +@@ -543,6 +545,8 @@ void lvmcache_drop_metadata(const char *vgname, int drop_precommitted) + /* For VG_ORPHANS, we need to invalidate all labels on orphan PVs. */ + if (!strcmp(vgname, VG_ORPHANS)) { + _drop_metadata(FMT_TEXT_ORPHAN_VG_NAME, 0); ++ _drop_metadata(FMT_LVM1_ORPHAN_VG_NAME, 0); ++ _drop_metadata(FMT_POOL_ORPHAN_VG_NAME, 0); + } else + _drop_metadata(vgname, drop_precommitted); + } +diff --git a/lib/cache/lvmetad.c b/lib/cache/lvmetad.c +index a1ab41a..2a2d7ea 100644 +--- a/lib/cache/lvmetad.c ++++ b/lib/cache/lvmetad.c +@@ -37,6 +37,8 @@ static const char *_lvmetad_socket = NULL; + static struct cmd_context *_lvmetad_cmd = NULL; + static int64_t _lvmetad_update_timeout; + ++static int _found_lvm1_metadata = 0; ++ + static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg, const char *vgid, struct format_type *fmt); + + static uint64_t _monotonic_seconds(void) +@@ -2277,6 +2279,18 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev, + if (!baton.fid) + goto_bad; + ++ if (fmt->features & FMT_OBSOLETE) { ++ fmt->ops->destroy_instance(baton.fid); ++ log_warn("WARNING: Disabling lvmetad cache which does not support obsolete (lvm1) metadata."); ++ lvmetad_set_disabled(cmd, LVMETAD_DISABLE_REASON_LVM1); ++ _found_lvm1_metadata = 1; ++ /* ++ * return 1 (success) so that we'll continue to populate lvmetad ++ * instead of leaving the update incomplete. ++ */ ++ return 1; ++ } ++ + lvmcache_foreach_mda(info, _lvmetad_pvscan_single, &baton); + + if (!baton.vg) +@@ -2440,9 +2454,11 @@ int lvmetad_pvscan_all_devs(struct cmd_context *cmd, int do_wait) + } + + /* +- * If lvmetad is disabled, and no duplicate PVs were seen, then re-enable lvmetad. ++ * If lvmetad is disabled, and no lvm1 metadata was seen and no ++ * duplicate PVs were seen, then re-enable lvmetad. + */ +- if (lvmetad_is_disabled(cmd, &reason) && !lvmcache_found_duplicate_pvs()) { ++ if (lvmetad_is_disabled(cmd, &reason) && ++ !lvmcache_found_duplicate_pvs() && !_found_lvm1_metadata) { + log_debug_lvmetad("Enabling lvmetad which was previously disabled."); + lvmetad_clear_disabled(cmd); + } +@@ -3058,6 +3074,9 @@ int lvmetad_is_disabled(struct cmd_context *cmd, const char **reason) + } else if (strstr(reply_reason, LVMETAD_DISABLE_REASON_REPAIR)) { + *reason = "a repair command was run"; + ++ } else if (strstr(reply_reason, LVMETAD_DISABLE_REASON_LVM1)) { ++ *reason = "LVM1 metadata was found"; ++ + } else if (strstr(reply_reason, LVMETAD_DISABLE_REASON_DUPLICATES)) { + *reason = "duplicate PVs were found"; + +diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c +index c9596e2..2b72645 100644 +--- a/lib/commands/toolcontext.c ++++ b/lib/commands/toolcontext.c +@@ -36,6 +36,14 @@ + #include "sharedlib.h" + #endif + ++#ifdef LVM1_INTERNAL ++#include "format1.h" ++#endif ++ ++#ifdef POOL_INTERNAL ++#include "format_pool.h" ++#endif ++ + #include + #include + #include +@@ -1134,12 +1142,14 @@ static struct dev_filter *_init_lvmetad_filter_chain(struct cmd_context *cmd) + } + nr_filt++; + ++#if 0 + /* signature filter. Required. */ + if (!(filters[nr_filt] = signature_filter_create(cmd->dev_types))) { + log_error("Failed to create signature device filter"); + goto bad; + } + nr_filt++; ++#endif + + /* md component filter. Optional, non-critical. */ + if (find_config_tree_bool(cmd, devices_md_component_detection_CFG, NULL)) { +@@ -1340,6 +1350,20 @@ static int _init_formats(struct cmd_context *cmd) + const struct dm_config_node *cn; + #endif + ++#ifdef LVM1_INTERNAL ++ if (!(fmt = init_lvm1_format(cmd))) ++ return 0; ++ fmt->library = NULL; ++ dm_list_add(&cmd->formats, &fmt->list); ++#endif ++ ++#ifdef POOL_INTERNAL ++ if (!(fmt = init_pool_format(cmd))) ++ return 0; ++ fmt->library = NULL; ++ dm_list_add(&cmd->formats, &fmt->list); ++#endif ++ + #ifdef HAVE_LIBDL + /* Load any formats in shared libs if not static */ + if (!is_static() && +diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h +index e98ca6d..6d79087 100644 +--- a/lib/config/config_settings.h ++++ b/lib/config/config_settings.h +@@ -767,14 +767,26 @@ cfg(global_activation_CFG, "activation", global_CFG_SECTION, 0, CFG_TYPE_BOOL, D + "is not present in the kernel, disabling this should suppress\n" + "the error messages.\n") + +-cfg(global_fallback_to_lvm1_CFG, "fallback_to_lvm1", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 0, vsn(1, 0, 18), NULL, 0, NULL, +- "This setting is no longer used.\n") ++cfg(global_fallback_to_lvm1_CFG, "fallback_to_lvm1", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_FALLBACK_TO_LVM1, vsn(1, 0, 18), "@DEFAULT_FALLBACK_TO_LVM1@", 0, NULL, ++ "Try running LVM1 tools if LVM cannot communicate with DM.\n" ++ "This option only applies to 2.4 kernels and is provided to help\n" ++ "switch between device-mapper kernels and LVM1 kernels. The LVM1\n" ++ "tools need to be installed with .lvm1 suffices, e.g. vgscan.lvm1.\n" ++ "They will stop working once the lvm2 on-disk metadata format is used.\n") + + cfg(global_format_CFG, "format", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_FORMAT, vsn(1, 0, 0), NULL, 0, NULL, +- "This setting is no longer used.\n") +- ++ "The default metadata format that commands should use.\n" ++ "The -M 1|2 option overrides this setting.\n" ++ "#\n" ++ "Accepted values:\n" ++ " lvm1\n" ++ " lvm2\n" ++ "#\n") ++ + cfg_array(global_format_libraries_CFG, "format_libraries", global_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL, +- "This setting is no longer used.") ++ "Shared libraries that process different metadata formats.\n" ++ "If support for LVM1 metadata was compiled as a shared library use\n" ++ "format_libraries = \"liblvm2format1.so\"\n") + + cfg_array(global_segment_libraries_CFG, "segment_libraries", global_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 18), NULL, 0, NULL, NULL) + +diff --git a/lib/display/display.c b/lib/display/display.c +index 9b4be88..9a928d9 100644 +--- a/lib/display/display.c ++++ b/lib/display/display.c +@@ -705,10 +705,13 @@ void vgdisplay_full(const struct volume_group *vg) + + log_print("--- Volume group ---"); + log_print("VG Name %s", vg->name); +- log_print("System ID %s", (vg->system_id && *vg->system_id) ? vg->system_id : ""); ++ log_print("System ID %s", (vg->system_id && *vg->system_id) ? vg->system_id : vg->lvm1_system_id ? : ""); + log_print("Format %s", vg->fid->fmt->name); +- log_print("Metadata Areas %d", vg_mda_count(vg)); +- log_print("Metadata Sequence No %d", vg->seqno); ++ if (vg->fid->fmt->features & FMT_MDAS) { ++ log_print("Metadata Areas %d", ++ vg_mda_count(vg)); ++ log_print("Metadata Sequence No %d", vg->seqno); ++ } + access_str = vg->status & (LVM_READ | LVM_WRITE); + log_print("VG Access %s%s%s%s", + access_str == (LVM_READ | LVM_WRITE) ? "read/write" : "", +diff --git a/lib/format1/.exported_symbols b/lib/format1/.exported_symbols +new file mode 100644 +index 0000000..e9fac2e +--- /dev/null ++++ b/lib/format1/.exported_symbols +@@ -0,0 +1 @@ ++init_format +diff --git a/lib/format1/Makefile.in b/lib/format1/Makefile.in +new file mode 100644 +index 0000000..4a905c0 +--- /dev/null ++++ b/lib/format1/Makefile.in +@@ -0,0 +1,33 @@ ++# ++# Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. ++# Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved. ++# ++# This file is part of LVM2. ++# ++# 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 ++ ++srcdir = @srcdir@ ++top_srcdir = @top_srcdir@ ++top_builddir = @top_builddir@ ++ ++SOURCES =\ ++ disk-rep.c \ ++ format1.c \ ++ import-export.c \ ++ import-extents.c \ ++ layout.c \ ++ lvm1-label.c \ ++ vg_number.c ++ ++LIB_SHARED = liblvm2format1.$(LIB_SUFFIX) ++LIB_VERSION = $(LIB_VERSION_LVM) ++ ++include $(top_builddir)/make.tmpl ++ ++install: install_lvm2_plugin +diff --git a/lib/format1/disk-rep.c b/lib/format1/disk-rep.c +new file mode 100644 +index 0000000..9169d82 +--- /dev/null ++++ b/lib/format1/disk-rep.c +@@ -0,0 +1,761 @@ ++/* ++ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. ++ * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. ++ * ++ * This file is part of LVM2. ++ * ++ * 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 Lesser General Public License v.2.1. ++ * ++ * You should have received a copy of the GNU Lesser 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 ++ */ ++ ++#include "lib.h" ++#include "disk-rep.h" ++#include "xlate.h" ++#include "lvmcache.h" ++#include "metadata-exported.h" ++ ++#include ++ ++#define xx16(v) disk->v = xlate16(disk->v) ++#define xx32(v) disk->v = xlate32(disk->v) ++#define xx64(v) disk->v = xlate64(disk->v) ++ ++/* ++ * Functions to perform the endian conversion ++ * between disk and core. The same code works ++ * both ways of course. ++ */ ++static void _xlate_pvd(struct pv_disk *disk) ++{ ++ xx16(version); ++ ++ xx32(pv_on_disk.base); ++ xx32(pv_on_disk.size); ++ xx32(vg_on_disk.base); ++ xx32(vg_on_disk.size); ++ xx32(pv_uuidlist_on_disk.base); ++ xx32(pv_uuidlist_on_disk.size); ++ xx32(lv_on_disk.base); ++ xx32(lv_on_disk.size); ++ xx32(pe_on_disk.base); ++ xx32(pe_on_disk.size); ++ ++ xx32(pv_major); ++ xx32(pv_number); ++ xx32(pv_status); ++ xx32(pv_allocatable); ++ xx32(pv_size); ++ xx32(lv_cur); ++ xx32(pe_size); ++ xx32(pe_total); ++ xx32(pe_allocated); ++ xx32(pe_start); ++} ++ ++static void _xlate_lvd(struct lv_disk *disk) ++{ ++ xx32(lv_access); ++ xx32(lv_status); ++ xx32(lv_open); ++ xx32(lv_dev); ++ xx32(lv_number); ++ xx32(lv_mirror_copies); ++ xx32(lv_recovery); ++ xx32(lv_schedule); ++ xx32(lv_size); ++ xx32(lv_snapshot_minor); ++ xx16(lv_chunk_size); ++ xx16(dummy); ++ xx32(lv_allocated_le); ++ xx32(lv_stripes); ++ xx32(lv_stripesize); ++ xx32(lv_badblock); ++ xx32(lv_allocation); ++ xx32(lv_io_timeout); ++ xx32(lv_read_ahead); ++} ++ ++static void _xlate_vgd(struct vg_disk *disk) ++{ ++ xx32(vg_number); ++ xx32(vg_access); ++ xx32(vg_status); ++ xx32(lv_max); ++ xx32(lv_cur); ++ xx32(lv_open); ++ xx32(pv_max); ++ xx32(pv_cur); ++ xx32(pv_act); ++ xx32(dummy); ++ xx32(vgda); ++ xx32(pe_size); ++ xx32(pe_total); ++ xx32(pe_allocated); ++ xx32(pvg_total); ++} ++ ++static void _xlate_extents(struct pe_disk *extents, uint32_t count) ++{ ++ unsigned i; ++ ++ for (i = 0; i < count; i++) { ++ extents[i].lv_num = xlate16(extents[i].lv_num); ++ extents[i].le_num = xlate16(extents[i].le_num); ++ } ++} ++ ++/* ++ * Handle both minor metadata formats. ++ */ ++static int _munge_formats(struct pv_disk *pvd) ++{ ++ uint32_t pe_start; ++ unsigned b, e; ++ ++ switch (pvd->version) { ++ case 1: ++ pvd->pe_start = ((pvd->pe_on_disk.base + ++ pvd->pe_on_disk.size) >> SECTOR_SHIFT); ++ break; ++ ++ case 2: ++ pvd->version = 1; ++ pe_start = pvd->pe_start << SECTOR_SHIFT; ++ pvd->pe_on_disk.size = pe_start - pvd->pe_on_disk.base; ++ break; ++ ++ default: ++ return 0; ++ } ++ ++ /* UUID too long? */ ++ if (pvd->pv_uuid[ID_LEN]) { ++ /* Retain ID_LEN chars from end */ ++ for (e = ID_LEN; e < sizeof(pvd->pv_uuid); e++) { ++ if (!pvd->pv_uuid[e]) { ++ e--; ++ break; ++ } ++ } ++ for (b = 0; b < ID_LEN; b++) { ++ pvd->pv_uuid[b] = pvd->pv_uuid[++e - ID_LEN]; ++ /* FIXME Remove all invalid chars */ ++ if (pvd->pv_uuid[b] == '/') ++ pvd->pv_uuid[b] = '#'; ++ } ++ memset(&pvd->pv_uuid[ID_LEN], 0, sizeof(pvd->pv_uuid) - ID_LEN); ++ } ++ ++ /* If UUID is missing, create one */ ++ if (pvd->pv_uuid[0] == '\0') { ++ uuid_from_num((char *)pvd->pv_uuid, pvd->pv_number); ++ pvd->pv_uuid[ID_LEN] = '\0'; ++ } ++ ++ return 1; ++} ++ ++/* ++ * If exported, remove "PV_EXP" from end of VG name ++ */ ++static void _munge_exported_vg(struct pv_disk *pvd) ++{ ++ int l; ++ size_t s; ++ ++ /* Return if PV not in a VG */ ++ if ((!*pvd->vg_name)) ++ return; ++ /* FIXME also check vgd->status & VG_EXPORTED? */ ++ ++ l = strlen((char *)pvd->vg_name); ++ s = sizeof(EXPORTED_TAG); ++ if (!strncmp((char *)pvd->vg_name + l - s + 1, EXPORTED_TAG, s)) { ++ pvd->vg_name[l - s + 1] = '\0'; ++ pvd->pv_status |= VG_EXPORTED; ++ } ++} ++ ++int munge_pvd(struct device *dev, struct pv_disk *pvd) ++{ ++ _xlate_pvd(pvd); ++ ++ if (pvd->id[0] != 'H' || pvd->id[1] != 'M') { ++ log_very_verbose("%s does not have a valid LVM1 PV identifier", ++ dev_name(dev)); ++ return 0; ++ } ++ ++ if (!_munge_formats(pvd)) { ++ log_very_verbose("format1: Unknown metadata version %d " ++ "found on %s", pvd->version, dev_name(dev)); ++ return 0; ++ } ++ ++ /* If VG is exported, set VG name back to the real name */ ++ _munge_exported_vg(pvd); ++ ++ return 1; ++} ++ ++static int _read_pvd(struct device *dev, struct pv_disk *pvd) ++{ ++ if (!dev_read_bytes(dev, UINT64_C(0), sizeof(*pvd), pvd)) { ++ log_very_verbose("Failed to read PV data from %s", ++ dev_name(dev)); ++ return 0; ++ } ++ ++ return munge_pvd(dev, pvd); ++} ++ ++static int _read_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk) ++{ ++ if (!dev_read_bytes(dev, pos, sizeof(*disk), disk)) ++ return_0; ++ ++ _xlate_lvd(disk); ++ ++ return 1; ++} ++ ++int read_vgd(struct device *dev, struct vg_disk *vgd, struct pv_disk *pvd) ++{ ++ uint64_t pos = pvd->vg_on_disk.base; ++ ++ if (!dev_read_bytes(dev, pos, sizeof(*vgd), vgd)) ++ return_0; ++ ++ _xlate_vgd(vgd); ++ ++ if ((vgd->lv_max > MAX_LV) || (vgd->pv_max > MAX_PV)) ++ return_0; ++ ++ /* If UUID is missing, create one */ ++ if (vgd->vg_uuid[0] == '\0') ++ uuid_from_num((char *)vgd->vg_uuid, vgd->vg_number); ++ ++ return 1; ++} ++ ++static int _read_uuids(struct disk_list *data) ++{ ++ unsigned num_read = 0; ++ struct uuid_list *ul; ++ char buffer[NAME_LEN] __attribute__((aligned(8))); ++ uint64_t pos = data->pvd.pv_uuidlist_on_disk.base; ++ uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size; ++ ++ while (pos < end && num_read < data->vgd.pv_cur) { ++ if (!dev_read_bytes(data->dev, pos, sizeof(buffer), buffer)) ++ return_0; ++ ++ if (!(ul = dm_pool_alloc(data->mem, sizeof(*ul)))) ++ return_0; ++ ++ memcpy(ul->uuid, buffer, NAME_LEN); ++ ul->uuid[NAME_LEN - 1] = '\0'; ++ ++ dm_list_add(&data->uuids, &ul->list); ++ ++ pos += NAME_LEN; ++ num_read++; ++ } ++ ++ return 1; ++} ++ ++static int _check_lvd(struct lv_disk *lvd) ++{ ++ return !(lvd->lv_name[0] == '\0'); ++} ++ ++static int _read_lvs(struct disk_list *data) ++{ ++ unsigned int i, lvs_read = 0; ++ uint64_t pos; ++ struct lvd_list *ll; ++ struct vg_disk *vgd = &data->vgd; ++ ++ for (i = 0; (i < vgd->lv_max) && (lvs_read < vgd->lv_cur); i++) { ++ pos = data->pvd.lv_on_disk.base + (i * sizeof(struct lv_disk)); ++ ll = dm_pool_alloc(data->mem, sizeof(*ll)); ++ ++ if (!ll) ++ return_0; ++ ++ if (!_read_lvd(data->dev, pos, &ll->lvd)) ++ return_0; ++ ++ if (!_check_lvd(&ll->lvd)) ++ continue; ++ ++ lvs_read++; ++ dm_list_add(&data->lvds, &ll->list); ++ } ++ ++ return 1; ++} ++ ++static int _read_extents(struct disk_list *data) ++{ ++ size_t len = sizeof(struct pe_disk) * data->pvd.pe_total; ++ struct pe_disk *extents = dm_pool_alloc(data->mem, len); ++ uint64_t pos = data->pvd.pe_on_disk.base; ++ ++ if (!extents) ++ return_0; ++ ++ if (!dev_read_bytes(data->dev, pos, len, extents)) ++ return_0; ++ ++ _xlate_extents(extents, data->pvd.pe_total); ++ data->extents = extents; ++ ++ return 1; ++} ++ ++static void __update_lvmcache(const struct format_type *fmt, ++ struct disk_list *dl, ++ struct device *dev, const char *vgid, ++ unsigned exported) ++{ ++ struct lvmcache_info *info; ++ const char *vgname = *((char *)dl->pvd.vg_name) ? ++ (char *)dl->pvd.vg_name : fmt->orphan_vg_name; ++ ++ if (!(info = lvmcache_add(fmt->labeller, (char *)dl->pvd.pv_uuid, dev, ++ vgname, vgid, exported ? EXPORTED_VG : 0))) { ++ stack; ++ return; ++ } ++ ++ lvmcache_set_device_size(info, ((uint64_t)xlate32(dl->pvd.pv_size)) << SECTOR_SHIFT); ++ lvmcache_del_mdas(info); ++} ++ ++static struct disk_list *__read_disk(const struct format_type *fmt, ++ struct device *dev, struct dm_pool *mem, ++ const char *vg_name) ++{ ++ struct disk_list *dl = dm_pool_zalloc(mem, sizeof(*dl)); ++ const char *name = dev_name(dev); ++ ++ if (!dl) ++ return_NULL; ++ ++ dl->dev = dev; ++ dl->mem = mem; ++ dm_list_init(&dl->uuids); ++ dm_list_init(&dl->lvds); ++ ++ if (!_read_pvd(dev, &dl->pvd)) ++ goto_bad; ++ ++ /* ++ * is it an orphan ? ++ */ ++ if (!*dl->pvd.vg_name) { ++ log_very_verbose("%s is not a member of any format1 VG", name); ++ ++ __update_lvmcache(fmt, dl, dev, fmt->orphan_vg_name, 0); ++ return (vg_name) ? NULL : dl; ++ } ++ ++ if (!read_vgd(dl->dev, &dl->vgd, &dl->pvd)) { ++ log_error("Failed to read VG data from PV (%s)", name); ++ __update_lvmcache(fmt, dl, dev, fmt->orphan_vg_name, 0); ++ goto bad; ++ } ++ ++ if (vg_name && strcmp(vg_name, (char *)dl->pvd.vg_name)) { ++ log_very_verbose("%s is not a member of the VG %s", ++ name, vg_name); ++ __update_lvmcache(fmt, dl, dev, fmt->orphan_vg_name, 0); ++ goto bad; ++ } ++ ++ __update_lvmcache(fmt, dl, dev, (char *)dl->vgd.vg_uuid, ++ dl->vgd.vg_status & VG_EXPORTED); ++ ++ if (!_read_uuids(dl)) { ++ log_error("Failed to read PV uuid list from %s", name); ++ goto bad; ++ } ++ ++ if (!_read_lvs(dl)) { ++ log_error("Failed to read LV's from %s", name); ++ goto bad; ++ } ++ ++ if (!_read_extents(dl)) { ++ log_error("Failed to read extents from %s", name); ++ goto bad; ++ } ++ ++ log_very_verbose("Found %s in %sVG %s", name, ++ (dl->vgd.vg_status & VG_EXPORTED) ? "exported " : "", ++ dl->pvd.vg_name); ++ ++ return dl; ++ ++ bad: ++ dm_pool_free(dl->mem, dl); ++ return NULL; ++} ++ ++struct disk_list *read_disk(const struct format_type *fmt, struct device *dev, ++ struct dm_pool *mem, const char *vg_name) ++{ ++ struct disk_list *dl; ++ ++ if (!dev_open_readonly(dev)) ++ return_NULL; ++ ++ dl = __read_disk(fmt, dev, mem, vg_name); ++ ++ if (!dev_close(dev)) ++ stack; ++ ++ return dl; ++} ++ ++static void _add_pv_to_list(struct cmd_context *cmd, struct dm_list *head, struct disk_list *data) ++{ ++ struct pv_disk *pvd; ++ struct disk_list *diskl; ++ ++ dm_list_iterate_items(diskl, head) { ++ pvd = &diskl->pvd; ++ if (!strncmp((char *)data->pvd.pv_uuid, (char *)pvd->pv_uuid, ++ sizeof(pvd->pv_uuid))) { ++ if (!dev_subsystem_part_major(cmd->dev_types, data->dev)) { ++ log_very_verbose("Ignoring duplicate PV %s on " ++ "%s", pvd->pv_uuid, ++ dev_name(data->dev)); ++ return; ++ } ++ log_very_verbose("Duplicate PV %s - using %s %s", ++ pvd->pv_uuid, dev_subsystem_name(cmd->dev_types, data->dev), ++ dev_name(data->dev)); ++ dm_list_del(&diskl->list); ++ break; ++ } ++ } ++ dm_list_add(head, &data->list); ++} ++ ++struct _read_pvs_in_vg_baton { ++ const char *vg_name; ++ struct dm_list *head; ++ struct disk_list *data; ++ struct dm_pool *mem; ++ int empty; ++}; ++ ++static int _read_pv_in_vg(struct lvmcache_info *info, void *baton) ++{ ++ struct _read_pvs_in_vg_baton *b = baton; ++ ++ b->empty = 0; ++ ++ if (!lvmcache_device(info) || ++ !(b->data = read_disk(lvmcache_fmt(info), lvmcache_device(info), b->mem, b->vg_name))) ++ return 0; /* stop here */ ++ ++ _add_pv_to_list(lvmcache_fmt(info)->cmd, b->head, b->data); ++ return 1; ++} ++ ++/* ++ * Build a list of pv_d's structures, allocated from mem. ++ * We keep track of the first object allocated from the pool ++ * so we can free off all the memory if something goes wrong. ++ */ ++int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name, ++ struct dev_filter *filter, struct dm_pool *mem, ++ struct dm_list *head) ++{ ++ struct dev_iter *iter; ++ struct device *dev; ++ struct lvmcache_vginfo *vginfo; ++ struct _read_pvs_in_vg_baton baton; ++ ++ baton.head = head; ++ baton.empty = 1; ++ baton.data = NULL; ++ baton.mem = mem; ++ baton.vg_name = vg_name; ++ ++ /* Fast path if we already saw this VG and cached the list of PVs */ ++ if (vg_name && (vginfo = lvmcache_vginfo_from_vgname(vg_name, NULL))) { ++ ++ lvmcache_foreach_pv(vginfo, _read_pv_in_vg, &baton); ++ ++ if (!baton.empty) { ++ /* Did we find the whole VG? */ ++ if (!vg_name || is_orphan_vg(vg_name) || ++ (baton.data && *baton.data->pvd.vg_name && ++ dm_list_size(head) == baton.data->vgd.pv_cur)) ++ return 1; ++ ++ /* Failed */ ++ dm_list_init(head); ++ /* vgcache_del(vg_name); */ ++ } ++ } ++ ++ if (!(iter = dev_iter_create(filter, 1))) { ++ log_error("read_pvs_in_vg: dev_iter_create failed"); ++ return 0; ++ } ++ ++ /* Otherwise do a complete scan */ ++ for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) { ++ if ((baton.data = read_disk(fmt, dev, mem, vg_name))) { ++ _add_pv_to_list(fmt->cmd, head, baton.data); ++ } ++ } ++ dev_iter_destroy(iter); ++ ++ if (dm_list_empty(head)) ++ return 0; ++ ++ return 1; ++} ++ ++static int _write_vgd(struct disk_list *data) ++{ ++ struct vg_disk *vgd = &data->vgd; ++ uint64_t pos = data->pvd.vg_on_disk.base; ++ ++ log_debug_metadata("Writing %s VG metadata to %s at %" PRIu64 " len %" PRIsize_t, ++ data->pvd.vg_name, dev_name(data->dev), pos, sizeof(*vgd)); ++ ++ _xlate_vgd(vgd); ++ if (!dev_write(data->dev, pos, sizeof(*vgd), DEV_IO_FMT1, vgd)) ++ return_0; ++ ++ _xlate_vgd(vgd); ++ ++ return 1; ++} ++ ++static int _write_uuids(struct disk_list *data) ++{ ++ struct uuid_list *ul; ++ uint64_t pos = data->pvd.pv_uuidlist_on_disk.base; ++ uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size; ++ ++ dm_list_iterate_items(ul, &data->uuids) { ++ if (pos >= end) { ++ log_error("Too many uuids to fit on %s", ++ dev_name(data->dev)); ++ return 0; ++ } ++ ++ log_debug_metadata("Writing %s uuidlist to %s at %" PRIu64 " len %d", ++ data->pvd.vg_name, dev_name(data->dev), ++ pos, NAME_LEN); ++ ++ if (!dev_write(data->dev, pos, NAME_LEN, DEV_IO_FMT1, ul->uuid)) ++ return_0; ++ ++ pos += NAME_LEN; ++ } ++ ++ return 1; ++} ++ ++static int _write_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk) ++{ ++ log_debug_metadata("Writing %s LV %s metadata to %s at %" PRIu64 " len %" ++ PRIsize_t, disk->vg_name, disk->lv_name, dev_name(dev), ++ pos, sizeof(*disk)); ++ ++ _xlate_lvd(disk); ++ if (!dev_write(dev, pos, sizeof(*disk), DEV_IO_FMT1, disk)) ++ return_0; ++ ++ _xlate_lvd(disk); ++ ++ return 1; ++} ++ ++static int _write_lvs(struct disk_list *data) ++{ ++ struct lvd_list *ll; ++ uint64_t pos, offset; ++ ++ pos = data->pvd.lv_on_disk.base; ++ ++ if (!dev_set(data->dev, pos, data->pvd.lv_on_disk.size, DEV_IO_FMT1, 0)) { ++ log_error("Couldn't zero lv area on device '%s'", ++ dev_name(data->dev)); ++ return 0; ++ } ++ ++ dm_list_iterate_items(ll, &data->lvds) { ++ offset = sizeof(struct lv_disk) * ll->lvd.lv_number; ++ if (offset + sizeof(struct lv_disk) > data->pvd.lv_on_disk.size) { ++ log_error("lv_number %d too large", ll->lvd.lv_number); ++ return 0; ++ } ++ ++ if (!_write_lvd(data->dev, pos + offset, &ll->lvd)) ++ return_0; ++ } ++ ++ return 1; ++} ++ ++static int _write_extents(struct disk_list *data) ++{ ++ size_t len = sizeof(struct pe_disk) * data->pvd.pe_total; ++ struct pe_disk *extents = data->extents; ++ uint64_t pos = data->pvd.pe_on_disk.base; ++ ++ log_debug_metadata("Writing %s extents metadata to %s at %" PRIu64 " len %" ++ PRIsize_t, data->pvd.vg_name, dev_name(data->dev), ++ pos, len); ++ ++ _xlate_extents(extents, data->pvd.pe_total); ++ if (!dev_write(data->dev, pos, len, DEV_IO_FMT1, extents)) ++ return_0; ++ ++ _xlate_extents(extents, data->pvd.pe_total); ++ ++ return 1; ++} ++ ++static int _write_pvd(struct disk_list *data) ++{ ++ char *buf; ++ uint64_t pos = data->pvd.pv_on_disk.base; ++ size_t size = data->pvd.pv_on_disk.size; ++ ++ if (size < sizeof(struct pv_disk)) { ++ log_error("Invalid PV structure size."); ++ return 0; ++ } ++ ++ /* Make sure that the gap between the PV structure and ++ the next one is zeroed in order to make non LVM tools ++ happy (idea from AED) */ ++ buf = dm_zalloc(size); ++ if (!buf) { ++ log_error("Couldn't allocate temporary PV buffer."); ++ return 0; ++ } ++ ++ memcpy(buf, &data->pvd, sizeof(struct pv_disk)); ++ ++ log_debug_metadata("Writing %s PV metadata to %s at %" PRIu64 " len %" ++ PRIsize_t, data->pvd.vg_name, dev_name(data->dev), ++ pos, size); ++ ++ _xlate_pvd((struct pv_disk *) buf); ++ if (!dev_write(data->dev, pos, size, DEV_IO_FMT1, buf)) { ++ dm_free(buf); ++ return_0; ++ } ++ ++ dm_free(buf); ++ return 1; ++} ++ ++/* ++ * assumes the device has been opened. ++ */ ++static int __write_all_pvd(const struct format_type *fmt __attribute__((unused)), ++ struct disk_list *data, int write_vg_metadata) ++{ ++ const char *pv_name = dev_name(data->dev); ++ ++ if (!_write_pvd(data)) { ++ log_error("Failed to write PV structure onto %s", pv_name); ++ return 0; ++ } ++ ++ /* vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, fmt); */ ++ /* ++ * Stop here for orphan PVs or if VG metadata write not requested. ++ */ ++ if ((data->pvd.vg_name[0] == '\0') || !write_vg_metadata) { ++ /* if (!test_mode()) ++ vgcache_add(data->pvd.vg_name, NULL, data->dev, fmt); */ ++ return 1; ++ } ++ ++ /* if (!test_mode()) ++ vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, ++ fmt); */ ++ ++ if (!_write_vgd(data)) { ++ log_error("Failed to write VG data to %s", pv_name); ++ return 0; ++ } ++ ++ if (!_write_uuids(data)) { ++ log_error("Failed to write PV uuid list to %s", pv_name); ++ return 0; ++ } ++ ++ if (!_write_lvs(data)) { ++ log_error("Failed to write LV's to %s", pv_name); ++ return 0; ++ } ++ ++ if (!_write_extents(data)) { ++ log_error("Failed to write extents to %s", pv_name); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++/* ++ * opens the device and hands to the above fn. ++ */ ++static int _write_all_pvd(const struct format_type *fmt, struct disk_list *data, int write_vg_metadata) ++{ ++ int r; ++ ++ if (!data->dev) ++ return_0; ++ ++ if (!dev_open(data->dev)) ++ return_0; ++ ++ r = __write_all_pvd(fmt, data, write_vg_metadata); ++ ++ if (!dev_close(data->dev)) ++ stack; ++ ++ return r; ++} ++ ++/* ++ * Writes all the given pv's to disk. Does very ++ * little sanity checking, so make sure correct ++ * data is passed to here. ++ */ ++int write_disks(const struct format_type *fmt, struct dm_list *pvs, int write_vg_metadata) ++{ ++ struct disk_list *dl; ++ ++ dm_list_iterate_items(dl, pvs) { ++ if (!(_write_all_pvd(fmt, dl, write_vg_metadata))) ++ return_0; ++ ++ log_very_verbose("Successfully wrote data to %s", ++ dev_name(dl->dev)); ++ } ++ ++ return 1; ++} +diff --git a/lib/format1/disk-rep.h b/lib/format1/disk-rep.h +new file mode 100644 +index 0000000..221ae8e +--- /dev/null ++++ b/lib/format1/disk-rep.h +@@ -0,0 +1,250 @@ ++/* ++ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. ++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. ++ * ++ * This file is part of LVM2. ++ * ++ * 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 Lesser General Public License v.2.1. ++ * ++ * You should have received a copy of the GNU Lesser 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 ++ */ ++ ++#ifndef DISK_REP_FORMAT1_H ++#define DISK_REP_FORMAT1_H ++ ++#include "metadata.h" ++#include "toolcontext.h" ++ ++#define MAX_PV 256 ++#define MAX_LV 256 ++#define MAX_VG 99 ++ ++#define LVM_BLK_MAJOR 58 ++ ++#define MAX_PV_SIZE ((uint32_t) -1) /* 2TB in sectors - 1 */ ++#define PE_SIZE_PV_SIZE_REL 5 /* PV size must be at least 5 times PE size */ ++#define MAX_LE_TOTAL 65534 /* 2^16 - 2 */ ++#define MAX_PE_TOTAL ((uint32_t) -2) ++ ++#define UNMAPPED_EXTENT 0 ++ ++/* volume group */ ++#define VG_ACTIVE 0x01 /* vg_status */ ++#define VG_EXPORTED 0x02 /* " */ ++#define VG_EXTENDABLE 0x04 /* " */ ++ ++#define VG_READ 0x01 /* vg_access */ ++#define VG_WRITE 0x02 /* " */ ++#define VG_CLUSTERED 0x04 /* " */ ++#define VG_SHARED 0x08 /* " */ ++ ++/* logical volume */ ++#define LV_ACTIVE 0x01 /* lv_status */ ++#define LV_SPINDOWN 0x02 /* " */ ++#define LV_PERSISTENT_MINOR 0x04 /* " */ ++ ++#define LV_READ 0x01 /* lv_access */ ++#define LV_WRITE 0x02 /* " */ ++#define LV_SNAPSHOT 0x04 /* " */ ++#define LV_SNAPSHOT_ORG 0x08 /* " */ ++ ++#define LV_BADBLOCK_ON 0x01 /* lv_badblock */ ++ ++#define LV_STRICT 0x01 /* lv_allocation */ ++#define LV_CONTIGUOUS 0x02 /* " */ ++ ++/* physical volume */ ++#define PV_ACTIVE 0x01 /* pv_status */ ++#define PV_ALLOCATABLE 0x02 /* pv_allocatable */ ++ ++#define EXPORTED_TAG "PV_EXP" /* Identifier for exported PV */ ++#define IMPORTED_TAG "PV_IMP" /* Identifier for imported PV */ ++ ++struct data_area { ++ uint32_t base; ++ uint32_t size; ++} __attribute__ ((packed)); ++ ++struct pv_disk { ++ int8_t id[2]; ++ uint16_t version; /* lvm version */ ++ struct data_area pv_on_disk; ++ struct data_area vg_on_disk; ++ struct data_area pv_uuidlist_on_disk; ++ struct data_area lv_on_disk; ++ struct data_area pe_on_disk; ++ int8_t pv_uuid[NAME_LEN]; ++ int8_t vg_name[NAME_LEN]; ++ int8_t system_id[NAME_LEN]; /* for vgexport/vgimport */ ++ uint32_t pv_major; ++ uint32_t pv_number; ++ uint32_t pv_status; ++ uint32_t pv_allocatable; ++ uint32_t pv_size; ++ uint32_t lv_cur; ++ uint32_t pe_size; ++ uint32_t pe_total; ++ uint32_t pe_allocated; ++ ++ /* only present on version == 2 pv's */ ++ uint32_t pe_start; ++} __attribute__ ((packed)); ++ ++struct lv_disk { ++ int8_t lv_name[NAME_LEN]; ++ int8_t vg_name[NAME_LEN]; ++ uint32_t lv_access; ++ uint32_t lv_status; ++ uint32_t lv_open; ++ uint32_t lv_dev; ++ uint32_t lv_number; ++ uint32_t lv_mirror_copies; /* for future use */ ++ uint32_t lv_recovery; /* " */ ++ uint32_t lv_schedule; /* " */ ++ uint32_t lv_size; ++ uint32_t lv_snapshot_minor; /* minor number of original */ ++ uint16_t lv_chunk_size; /* chunk size of snapshot */ ++ uint16_t dummy; ++ uint32_t lv_allocated_le; ++ uint32_t lv_stripes; ++ uint32_t lv_stripesize; ++ uint32_t lv_badblock; /* for future use */ ++ uint32_t lv_allocation; ++ uint32_t lv_io_timeout; /* for future use */ ++ uint32_t lv_read_ahead; ++} __attribute__ ((packed)); ++ ++struct vg_disk { ++ int8_t vg_uuid[ID_LEN]; /* volume group UUID */ ++ int8_t vg_name_dummy[NAME_LEN - ID_LEN]; /* rest of v1 VG name */ ++ uint32_t vg_number; /* volume group number */ ++ uint32_t vg_access; /* read/write */ ++ uint32_t vg_status; /* active or not */ ++ uint32_t lv_max; /* maximum logical volumes */ ++ uint32_t lv_cur; /* current logical volumes */ ++ uint32_t lv_open; /* open logical volumes */ ++ uint32_t pv_max; /* maximum physical volumes */ ++ uint32_t pv_cur; /* current physical volumes FU */ ++ uint32_t pv_act; /* active physical volumes */ ++ uint32_t dummy; ++ uint32_t vgda; /* volume group descriptor arrays FU */ ++ uint32_t pe_size; /* physical extent size in sectors */ ++ uint32_t pe_total; /* total of physical extents */ ++ uint32_t pe_allocated; /* allocated physical extents */ ++ uint32_t pvg_total; /* physical volume groups FU */ ++} __attribute__ ((packed)); ++ ++struct pe_disk { ++ uint16_t lv_num; ++ uint16_t le_num; ++} __attribute__ ((packed)); ++ ++struct uuid_list { ++ struct dm_list list; ++ char uuid[NAME_LEN] __attribute__((aligned(8))); ++}; ++ ++struct lvd_list { ++ struct dm_list list; ++ struct lv_disk lvd; ++}; ++ ++struct disk_list { ++ struct dm_list list; ++ struct dm_pool *mem; ++ struct device *dev; ++ ++ struct pv_disk pvd __attribute__((aligned(8))); ++ struct vg_disk vgd __attribute__((aligned(8))); ++ struct dm_list uuids __attribute__((aligned(8))); ++ struct dm_list lvds __attribute__((aligned(8))); ++ struct pe_disk *extents __attribute__((aligned(8))); ++}; ++ ++/* ++ * Layout constants. ++ */ ++#define METADATA_ALIGN 4096UL ++#define LVM1_PE_ALIGN (65536UL >> SECTOR_SHIFT) /* PE alignment */ ++ ++#define METADATA_BASE 0UL ++#define PV_SIZE 1024UL ++#define VG_SIZE 4096UL ++ ++/* ++ * Functions to calculate layout info. ++ */ ++int calculate_layout(struct disk_list *dl); ++int calculate_extent_count(struct physical_volume *pv, uint32_t extent_size, ++ uint32_t max_extent_count, uint64_t pe_start); ++ ++/* ++ * Low level io routines which read/write ++ * disk_lists. ++ */ ++ ++struct disk_list *read_disk(const struct format_type *fmt, struct device *dev, ++ struct dm_pool *mem, const char *vg_name); ++ ++int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name, ++ struct dev_filter *filter, ++ struct dm_pool *mem, struct dm_list *results); ++ ++int write_disks(const struct format_type *fmt, struct dm_list *pvds, ++ int write_vg_metadata); ++ ++/* ++ * Functions to translate to between disk and in ++ * core structures. ++ */ ++int import_pv(const struct format_type *fmt, struct dm_pool *mem, ++ struct device *dev, struct volume_group *vg, ++ struct physical_volume *pv, struct pv_disk *pvd, ++ struct vg_disk *vgd); ++int export_pv(struct cmd_context *cmd, struct dm_pool *mem, ++ struct volume_group *vg, ++ struct pv_disk *pvd, struct physical_volume *pv); ++ ++int import_vg(struct dm_pool *mem, ++ struct volume_group *vg, struct disk_list *dl); ++int export_vg(struct vg_disk *vgd, struct volume_group *vg); ++ ++int import_lv(struct cmd_context *cmd, struct dm_pool *mem, ++ struct logical_volume *lv, struct lv_disk *lvd); ++ ++int import_extents(struct cmd_context *cmd, struct volume_group *vg, ++ struct dm_list *pvds); ++int export_extents(struct disk_list *dl, uint32_t lv_num, ++ struct logical_volume *lv, struct physical_volume *pv); ++ ++int import_pvs(const struct format_type *fmt, struct dm_pool *mem, ++ struct volume_group *vg, struct dm_list *pvds); ++ ++int import_lvs(struct dm_pool *mem, struct volume_group *vg, struct dm_list *pvds); ++int export_lvs(struct disk_list *dl, struct volume_group *vg, ++ struct physical_volume *pv, const char *dev_dir); ++ ++int import_snapshots(struct dm_pool *mem, struct volume_group *vg, ++ struct dm_list *pvds); ++ ++int export_uuids(struct disk_list *dl, struct volume_group *vg); ++ ++void export_numbers(struct dm_list *pvds, struct volume_group *vg); ++ ++void export_pv_act(struct dm_list *pvds); ++int munge_pvd(struct device *dev, struct pv_disk *pvd); ++int read_vgd(struct device *dev, struct vg_disk *vgd, struct pv_disk *pvd); ++ ++/* blech */ ++int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter, ++ const char *candidate_vg, int *result); ++int export_vg_number(struct format_instance *fid, struct dm_list *pvds, ++ const char *vg_name, struct dev_filter *filter); ++ ++int generate_lvm1_system_id(struct cmd_context *cmd, char *s, const char *prefix); ++ ++#endif +diff --git a/lib/format1/format1.c b/lib/format1/format1.c +new file mode 100644 +index 0000000..6e7e888 +--- /dev/null ++++ b/lib/format1/format1.c +@@ -0,0 +1,630 @@ ++/* ++ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. ++ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. ++ * ++ * This file is part of LVM2. ++ * ++ * 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 Lesser General Public License v.2.1. ++ * ++ * You should have received a copy of the GNU Lesser 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 ++ */ ++ ++#include "lib.h" ++#include "disk-rep.h" ++#include "limits.h" ++#include "display.h" ++#include "toolcontext.h" ++#include "lvm1-label.h" ++#include "format1.h" ++#include "segtype.h" ++#include "pv_alloc.h" ++ ++/* VG consistency checks */ ++static int _check_vgs(struct dm_list *pvs, struct volume_group *vg) ++{ ++ struct dm_list *pvh, *t; ++ struct disk_list *dl = NULL; ++ struct disk_list *first = NULL; ++ ++ uint32_t pv_count = 0; ++ uint32_t exported = 0; ++ int first_time = 1; ++ ++ /* ++ * If there are exported and unexported PVs, ignore exported ones. ++ * This means an active VG won't be affected if disks are inserted ++ * bearing an exported VG with the same name. ++ */ ++ dm_list_iterate_items(dl, pvs) { ++ if (first_time) { ++ exported = dl->pvd.pv_status & VG_EXPORTED; ++ first_time = 0; ++ continue; ++ } ++ ++ if (exported != (dl->pvd.pv_status & VG_EXPORTED)) { ++ /* Remove exported PVs */ ++ dm_list_iterate_safe(pvh, t, pvs) { ++ dl = dm_list_item(pvh, struct disk_list); ++ if (dl->pvd.pv_status & VG_EXPORTED) ++ dm_list_del(pvh); ++ } ++ break; ++ } ++ } ++ ++ /* Remove any PVs with VG structs that differ from the first */ ++ dm_list_iterate_safe(pvh, t, pvs) { ++ dl = dm_list_item(pvh, struct disk_list); ++ ++ if (!first) ++ first = dl; ++ ++ else if (memcmp(&first->vgd, &dl->vgd, sizeof(first->vgd))) { ++ log_error("VG data differs between PVs %s and %s", ++ dev_name(first->dev), dev_name(dl->dev)); ++ log_debug_metadata("VG data on %s: %s %s %" PRIu32 " %" PRIu32 ++ " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" ++ PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 ++ " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" ++ PRIu32 " %" PRIu32 " %" PRIu32, ++ dev_name(first->dev), first->vgd.vg_uuid, ++ first->vgd.vg_name_dummy, ++ first->vgd.vg_number, first->vgd.vg_access, ++ first->vgd.vg_status, first->vgd.lv_max, ++ first->vgd.lv_cur, first->vgd.lv_open, ++ first->vgd.pv_max, first->vgd.pv_cur, ++ first->vgd.pv_act, first->vgd.dummy, ++ first->vgd.vgda, first->vgd.pe_size, ++ first->vgd.pe_total, first->vgd.pe_allocated, ++ first->vgd.pvg_total); ++ log_debug_metadata("VG data on %s: %s %s %" PRIu32 " %" PRIu32 ++ " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" ++ PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 ++ " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" ++ PRIu32 " %" PRIu32 " %" PRIu32, ++ dev_name(dl->dev), dl->vgd.vg_uuid, ++ dl->vgd.vg_name_dummy, dl->vgd.vg_number, ++ dl->vgd.vg_access, dl->vgd.vg_status, ++ dl->vgd.lv_max, dl->vgd.lv_cur, ++ dl->vgd.lv_open, dl->vgd.pv_max, ++ dl->vgd.pv_cur, dl->vgd.pv_act, dl->vgd.dummy, ++ dl->vgd.vgda, dl->vgd.pe_size, ++ dl->vgd.pe_total, dl->vgd.pe_allocated, ++ dl->vgd.pvg_total); ++ dm_list_del(pvh); ++ return 0; ++ } ++ pv_count++; ++ } ++ ++ /* On entry to fn, list known to be non-empty */ ++ if (pv_count != first->vgd.pv_cur) { ++ log_error("%d PV(s) found for VG %s: expected %d", ++ pv_count, first->pvd.vg_name, first->vgd.pv_cur); ++ vg->status |= PARTIAL_VG; ++ } ++ ++ return 1; ++} ++ ++static int _fix_partial_vg(struct volume_group *vg, struct dm_list *pvs) ++{ ++ uint32_t extent_count = 0; ++ struct disk_list *dl; ++ struct dm_list *pvh; ++ struct pv_list *pvl; ++ struct lv_list *ll; ++ struct lv_segment *seg; ++ ++ /* ++ * FIXME: code should remap missing segments to error segment. ++ * Also current mapping code allocates 1 segment per missing extent. ++ * For now bail out completely - allocated structures are not complete ++ */ ++ dm_list_iterate_items(ll, &vg->lvs) ++ dm_list_iterate_items(seg, &ll->lv->segments) { ++ ++ /* area_count is always 1 here, s == 0 */ ++ if (seg_type(seg, 0) != AREA_PV) ++ continue; ++ ++ if (seg_pv(seg, 0)) ++ continue; ++ ++ log_error("Partial mode support for missing lvm1 PVs and " ++ "partially available LVs is currently not implemented."); ++ return 0; ++ } ++ ++ dm_list_iterate(pvh, pvs) { ++ dl = dm_list_item(pvh, struct disk_list); ++ extent_count += dl->pvd.pe_total; ++ } ++ ++ /* FIXME: move this to one place to pv_manip */ ++ if (!(pvl = dm_pool_zalloc(vg->vgmem, sizeof(*pvl))) || ++ !(pvl->pv = dm_pool_zalloc(vg->vgmem, sizeof(*pvl->pv)))) ++ return_0; ++ ++ /* Use vg uuid with replaced first chars to "missing" as missing PV UUID */ ++ memcpy(&pvl->pv->id.uuid, vg->id.uuid, sizeof(pvl->pv->id.uuid)); ++ memcpy(&pvl->pv->id.uuid, "missing", 7); ++ ++ if (!(pvl->pv->vg_name = dm_pool_strdup(vg->vgmem, vg->name))) ++ goto_out; ++ memcpy(&pvl->pv->vgid, &vg->id, sizeof(vg->id)); ++ pvl->pv->status |= MISSING_PV; ++ dm_list_init(&pvl->pv->tags); ++ dm_list_init(&pvl->pv->segments); ++ ++ pvl->pv->pe_size = vg->extent_size; ++ pvl->pv->pe_count = vg->extent_count - extent_count; ++ if (!alloc_pv_segment_whole_pv(vg->vgmem, pvl->pv)) ++ goto_out; ++ ++ add_pvl_to_vgs(vg, pvl); ++ log_debug_metadata("%s: partial VG, allocated missing PV using %d extents.", ++ vg->name, pvl->pv->pe_count); ++ ++ return 1; ++out: ++ dm_pool_free(vg->vgmem, pvl); ++ return 0; ++} ++ ++static struct volume_group *_format1_vg_read(struct format_instance *fid, ++ const char *vg_name, ++ struct metadata_area *mda __attribute__((unused)), ++ struct cached_vg_fmtdata **vg_fmtdata __attribute__((unused)), ++ unsigned *use_previous_vg __attribute__((unused))) ++{ ++ struct volume_group *vg; ++ struct disk_list *dl; ++ DM_LIST_INIT(pvs); ++ ++ /* Strip dev_dir if present */ ++ if (vg_name) ++ vg_name = strip_dir(vg_name, fid->fmt->cmd->dev_dir); ++ ++ if (!(vg = alloc_vg("format1_vg_read", fid->fmt->cmd, NULL))) ++ return_NULL; ++ ++ if (!read_pvs_in_vg(fid->fmt, vg_name, fid->fmt->cmd->filter, ++ vg->vgmem, &pvs)) ++ goto_bad; ++ ++ if (dm_list_empty(&pvs)) ++ goto_bad; ++ ++ if (!_check_vgs(&pvs, vg)) ++ goto_bad; ++ ++ dl = dm_list_item(pvs.n, struct disk_list); ++ ++ if (!import_vg(vg->vgmem, vg, dl)) ++ goto_bad; ++ ++ if (!import_pvs(fid->fmt, vg->vgmem, vg, &pvs)) ++ goto_bad; ++ ++ if (!import_lvs(vg->vgmem, vg, &pvs)) ++ goto_bad; ++ ++ if (!import_extents(fid->fmt->cmd, vg, &pvs)) ++ goto_bad; ++ ++ /* FIXME: workaround - temporary assignment of fid */ ++ vg->fid = fid; ++ if (!import_snapshots(vg->vgmem, vg, &pvs)) { ++ vg->fid = NULL; ++ goto_bad; ++ } ++ vg->fid = NULL; ++ ++ /* Fix extents counts by adding missing PV if partial VG */ ++ if ((vg->status & PARTIAL_VG) && !_fix_partial_vg(vg, &pvs)) ++ goto_bad; ++ ++ vg_set_fid(vg, fid); ++ ++ return vg; ++ ++bad: ++ release_vg(vg); ++ ++ return NULL; ++} ++ ++static struct disk_list *_flatten_pv(struct format_instance *fid, ++ struct dm_pool *mem, struct volume_group *vg, ++ struct physical_volume *pv, ++ const char *dev_dir) ++{ ++ struct disk_list *dl = dm_pool_alloc(mem, sizeof(*dl)); ++ ++ if (!dl) ++ return_NULL; ++ ++ dl->mem = mem; ++ dl->dev = pv->dev; ++ ++ dm_list_init(&dl->uuids); ++ dm_list_init(&dl->lvds); ++ ++ if (!export_pv(fid->fmt->cmd, mem, vg, &dl->pvd, pv) || ++ !export_vg(&dl->vgd, vg) || ++ !export_uuids(dl, vg) || ++ !export_lvs(dl, vg, pv, dev_dir) || !calculate_layout(dl)) { ++ dm_pool_free(mem, dl); ++ return_NULL; ++ } ++ ++ return dl; ++} ++ ++static int _flatten_vg(struct format_instance *fid, struct dm_pool *mem, ++ struct volume_group *vg, ++ struct dm_list *pvds, const char *dev_dir, ++ struct dev_filter *filter) ++{ ++ struct pv_list *pvl; ++ struct disk_list *data; ++ ++ dm_list_iterate_items(pvl, &vg->pvs) { ++ if (!(data = _flatten_pv(fid, mem, vg, pvl->pv, dev_dir))) ++ return_0; ++ ++ dm_list_add(pvds, &data->list); ++ } ++ ++ export_numbers(pvds, vg); ++ export_pv_act(pvds); ++ ++ if (!export_vg_number(fid, pvds, vg->name, filter)) ++ return_0; ++ ++ return 1; ++} ++ ++static int _format1_vg_write(struct format_instance *fid, struct volume_group *vg, ++ struct metadata_area *mda __attribute__((unused))) ++{ ++ struct dm_pool *mem = dm_pool_create("lvm1 vg_write", VG_MEMPOOL_CHUNK); ++ struct dm_list pvds; ++ int r = 0; ++ ++ if (!mem) ++ return_0; ++ ++ dm_list_init(&pvds); ++ ++ r = (_flatten_vg(fid, mem, vg, &pvds, fid->fmt->cmd->dev_dir, ++ fid->fmt->cmd->filter) && ++ write_disks(fid->fmt, &pvds, 1)); ++ ++ lvmcache_update_vg(vg, 0); ++ dm_pool_destroy(mem); ++ return r; ++} ++ ++static int _format1_pv_read(const struct format_type *fmt, const char *pv_name, ++ struct physical_volume *pv, int scan_label_only __attribute__((unused))) ++{ ++ struct dm_pool *mem = dm_pool_create("lvm1 pv_read", 1024); ++ struct disk_list *dl; ++ struct device *dev; ++ int r = 0; ++ ++ log_very_verbose("Reading physical volume data %s from disk", pv_name); ++ ++ if (!mem) ++ return_0; ++ ++ if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter))) ++ goto_out; ++ ++ if (!(dl = read_disk(fmt, dev, mem, NULL))) ++ goto_out; ++ ++ if (!import_pv(fmt, fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd, &dl->vgd)) ++ goto_out; ++ ++ pv->fmt = fmt; ++ ++ r = 1; ++ ++ out: ++ dm_pool_destroy(mem); ++ return r; ++} ++ ++static int _format1_pv_initialise(const struct format_type * fmt, ++ struct pv_create_args *pva, ++ struct physical_volume * pv) ++{ ++ if (pv->size > MAX_PV_SIZE) ++ pv->size--; ++ if (pv->size > MAX_PV_SIZE) { ++ log_error("Physical volumes cannot be bigger than %s", ++ display_size(fmt->cmd, (uint64_t) MAX_PV_SIZE)); ++ return 0; ++ } ++ ++ /* Nothing more to do if extent size isn't provided */ ++ if (!pva->extent_size) ++ return 1; ++ ++ /* ++ * This works out pe_start and pe_count. ++ */ ++ if (!calculate_extent_count(pv, pva->extent_size, pva->extent_count, pva->pe_start)) ++ return_0; ++ ++ /* Retain existing extent locations exactly */ ++ if (((pva->pe_start || pva->extent_count) && (pva->pe_start != pv->pe_start)) || ++ (pva->extent_count && (pva->extent_count != pv->pe_count))) { ++ log_error("Metadata would overwrite physical extents"); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static int _format1_pv_setup(const struct format_type *fmt, ++ struct physical_volume *pv, ++ struct volume_group *vg) ++{ ++ struct pv_create_args pva = { .id = {{0}}, ++ .idp = NULL, ++ .ba_start = 0, ++ .ba_size = 0, ++ .pe_start = 0, ++ .extent_count = 0, ++ .extent_size = vg->extent_size}; ++ ++ return _format1_pv_initialise(fmt, &pva, pv); ++} ++ ++static int _format1_lv_setup(struct format_instance *fid, struct logical_volume *lv) ++{ ++ uint64_t max_size = UINT_MAX; ++ ++ if (!*lv->lvid.s) ++ lvid_from_lvnum(&lv->lvid, &lv->vg->id, find_free_lvnum(lv)); ++ ++ if (lv->le_count > MAX_LE_TOTAL) { ++ log_error("logical volumes cannot contain more than " ++ "%d extents.", MAX_LE_TOTAL); ++ return 0; ++ } ++ if (lv->size > max_size) { ++ log_error("logical volumes cannot be larger than %s", ++ display_size(fid->fmt->cmd, max_size)); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static int _format1_pv_write(const struct format_type *fmt, struct physical_volume *pv) ++{ ++ struct dm_pool *mem; ++ struct disk_list *dl; ++ struct dm_list pvs; ++ struct lvmcache_info *info; ++ int pe_count, pe_size, pe_start; ++ int r = 1; ++ ++ if (!(info = lvmcache_add(fmt->labeller, (char *) &pv->id, pv->dev, ++ pv->vg_name, NULL, 0))) ++ return_0; ++ ++ lvmcache_update_pv(info, pv, fmt); ++ lvmcache_del_mdas(info); ++ lvmcache_del_das(info); ++ lvmcache_del_bas(info); ++ ++ dm_list_init(&pvs); ++ ++ pe_count = pv->pe_count; ++ pe_size = pv->pe_size; ++ pe_start = pv->pe_start; ++ ++ /* Ensure any residual PE structure is gone */ ++ pv->pe_size = pv->pe_count = 0; ++ pv->pe_start = LVM1_PE_ALIGN; ++ ++ if (!(mem = dm_pool_create("lvm1 pv_write", 1024))) ++ return_0; ++ ++ if (!(dl = dm_pool_alloc(mem, sizeof(*dl)))) ++ goto_bad; ++ ++ dl->mem = mem; ++ dl->dev = pv->dev; ++ dm_list_init(&dl->uuids); ++ dm_list_init(&dl->lvds); ++ ++ if (!export_pv(fmt->cmd, mem, NULL, &dl->pvd, pv)) ++ goto_bad; ++ ++ /* must be set to be able to zero gap after PV structure in ++ dev_write in order to make other disk tools happy */ ++ dl->pvd.pv_on_disk.base = METADATA_BASE; ++ dl->pvd.pv_on_disk.size = PV_SIZE; ++ dl->pvd.pe_on_disk.base = LVM1_PE_ALIGN << SECTOR_SHIFT; ++ ++ dm_list_add(&pvs, &dl->list); ++ if (!write_disks(fmt, &pvs, 0)) ++ goto_bad; ++ ++ goto out; ++ ++ bad: ++ r = 0; ++ ++ out: ++ pv->pe_size = pe_size; ++ pv->pe_count = pe_count; ++ pv->pe_start = pe_start; ++ ++ dm_pool_destroy(mem); ++ return r; ++} ++ ++static int _format1_vg_setup(struct format_instance *fid, struct volume_group *vg) ++{ ++ /* just check max_pv and max_lv */ ++ if (!vg->max_lv || vg->max_lv >= MAX_LV) ++ vg->max_lv = MAX_LV - 1; ++ ++ if (!vg->max_pv || vg->max_pv >= MAX_PV) ++ vg->max_pv = MAX_PV - 1; ++ ++ if (!vg_check_new_extent_size(vg->fid->fmt, vg->extent_size)) ++ return_0; ++ ++ /* Generate lvm1_system_id if not yet set */ ++ if (!*vg->lvm1_system_id && ++ !generate_lvm1_system_id(vg->cmd, vg->lvm1_system_id, "")) ++ return_0; ++ ++ return 1; ++} ++ ++static int _format1_segtype_supported(struct format_instance *fid __attribute__((unused)), ++ const struct segment_type *segtype) ++{ ++ if (!(segtype->flags & SEG_FORMAT1_SUPPORT)) ++ return_0; ++ ++ return 1; ++} ++ ++static struct metadata_area_ops _metadata_format1_ops = { ++ .vg_read = _format1_vg_read, ++ .vg_write = _format1_vg_write, ++}; ++ ++static struct format_instance *_format1_create_instance(const struct format_type *fmt, ++ const struct format_instance_ctx *fic) ++{ ++ struct format_instance *fid; ++ struct metadata_area *mda; ++ ++ if (!(fid = alloc_fid(fmt, fic))) ++ return_NULL; ++ ++ /* Define a NULL metadata area */ ++ if (!(mda = dm_pool_zalloc(fid->mem, sizeof(*mda)))) { ++ log_error("Unable to allocate metadata area structure " ++ "for lvm1 format"); ++ goto bad; ++ } ++ ++ mda->ops = &_metadata_format1_ops; ++ mda->metadata_locn = NULL; ++ mda->status = 0; ++ dm_list_add(&fid->metadata_areas_in_use, &mda->list); ++ ++ return fid; ++ ++bad: ++ dm_pool_destroy(fid->mem); ++ return NULL; ++} ++ ++static void _format1_destroy_instance(struct format_instance *fid) ++{ ++ if (--fid->ref_count <= 1) ++ dm_pool_destroy(fid->mem); ++} ++ ++static void _format1_destroy(struct format_type *fmt) ++{ ++ if (fmt->orphan_vg) ++ free_orphan_vg(fmt->orphan_vg); ++ ++ dm_free(fmt); ++} ++ ++static struct format_handler _format1_ops = { ++ .pv_read = _format1_pv_read, ++ .pv_initialise = _format1_pv_initialise, ++ .pv_setup = _format1_pv_setup, ++ .pv_write = _format1_pv_write, ++ .lv_setup = _format1_lv_setup, ++ .vg_setup = _format1_vg_setup, ++ .segtype_supported = _format1_segtype_supported, ++ .create_instance = _format1_create_instance, ++ .destroy_instance = _format1_destroy_instance, ++ .destroy = _format1_destroy, ++}; ++ ++#ifdef LVM1_INTERNAL ++struct format_type *init_lvm1_format(struct cmd_context *cmd) ++#else /* Shared */ ++struct format_type *init_format(struct cmd_context *cmd); ++struct format_type *init_format(struct cmd_context *cmd) ++#endif ++{ ++ struct format_type *fmt = dm_malloc(sizeof(*fmt)); ++ struct format_instance_ctx fic; ++ struct format_instance *fid; ++ ++ if (!fmt) { ++ log_error("Failed to allocate format1 format type structure."); ++ return NULL; ++ } ++ ++ fmt->cmd = cmd; ++ fmt->ops = &_format1_ops; ++ fmt->name = FMT_LVM1_NAME; ++ fmt->alias = NULL; ++ fmt->orphan_vg_name = FMT_LVM1_ORPHAN_VG_NAME; ++ fmt->features = FMT_RESTRICTED_LVIDS | FMT_ORPHAN_ALLOCATABLE | ++ FMT_RESTRICTED_READAHEAD | FMT_OBSOLETE | ++ FMT_SYSTEMID_ON_PVS; ++ fmt->private = NULL; ++ ++ dm_list_init(&fmt->mda_ops); ++ ++ if (!(fmt->labeller = lvm1_labeller_create(fmt))) { ++ log_error("Couldn't create lvm1 label handler."); ++ dm_free(fmt); ++ return NULL; ++ } ++ ++ if (!(label_register_handler(fmt->labeller))) { ++ log_error("Couldn't register lvm1 label handler."); ++ fmt->labeller->ops->destroy(fmt->labeller); ++ dm_free(fmt); ++ return NULL; ++ } ++ ++ if (!(fmt->orphan_vg = alloc_vg("format1_orphan", cmd, fmt->orphan_vg_name))) { ++ log_error("Couldn't create lvm1 orphan VG."); ++ dm_free(fmt); ++ return NULL; ++ } ++ ++ fic.type = FMT_INSTANCE_AUX_MDAS; ++ fic.context.vg_ref.vg_name = fmt->orphan_vg_name; ++ fic.context.vg_ref.vg_id = NULL; ++ ++ if (!(fid = _format1_create_instance(fmt, &fic))) { ++ _format1_destroy(fmt); ++ return_NULL; ++ } ++ ++ vg_set_fid(fmt->orphan_vg, fid); ++ ++ log_very_verbose("Initialised format: %s", fmt->name); ++ ++ return fmt; ++} +diff --git a/lib/format1/format1.h b/lib/format1/format1.h +new file mode 100644 +index 0000000..42ddc66 +--- /dev/null ++++ b/lib/format1/format1.h +@@ -0,0 +1,29 @@ ++/* ++ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. ++ * Copyright (C) 2004 Red Hat, Inc. All rights reserved. ++ * ++ * This file is part of LVM2. ++ * ++ * 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 Lesser General Public License v.2.1. ++ * ++ * You should have received a copy of the GNU Lesser 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 ++ */ ++ ++#ifndef _LVM_FORMAT1_H ++#define _LVM_FORMAT1_H ++ ++#include "metadata.h" ++#include "lvmcache.h" ++ ++#define FMT_LVM1_NAME "lvm1" ++#define FMT_LVM1_ORPHAN_VG_NAME ORPHAN_VG_NAME(FMT_LVM1_NAME) ++ ++#ifdef LVM1_INTERNAL ++struct format_type *init_lvm1_format(struct cmd_context *cmd); ++#endif ++ ++#endif +diff --git a/lib/format1/import-export.c b/lib/format1/import-export.c +new file mode 100644 +index 0000000..c29527b +--- /dev/null ++++ b/lib/format1/import-export.c +@@ -0,0 +1,680 @@ ++/* ++ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. ++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. ++ * ++ * This file is part of LVM2. ++ * ++ * 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 Lesser General Public License v.2.1. ++ * ++ * You should have received a copy of the GNU Lesser 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 ++ */ ++ ++/* ++ * Translates between disk and in-core formats. ++ */ ++ ++#include "lib.h" ++#include "disk-rep.h" ++#include "lvm-string.h" ++#include "toolcontext.h" ++#include "segtype.h" ++#include "pv_alloc.h" ++#include "display.h" ++#include "metadata.h" ++ ++#include ++ ++static int _check_vg_name(const char *name) ++{ ++ return strlen(name) < NAME_LEN; ++} ++ ++/* ++ * Extracts the last part of a path. ++ */ ++static char *_create_lv_name(struct dm_pool *mem, const char *full_name) ++{ ++ const char *ptr = strrchr(full_name, '/'); ++ ++ if (!ptr) ++ ptr = full_name; ++ else ++ ptr++; ++ ++ return dm_pool_strdup(mem, ptr); ++} ++ ++int import_pv(const struct format_type *fmt, struct dm_pool *mem, ++ struct device *dev, struct volume_group *vg, ++ struct physical_volume *pv, struct pv_disk *pvd, ++ struct vg_disk *vgd) ++{ ++ uint64_t size; ++ ++ memset(pv, 0, sizeof(*pv)); ++ memcpy(&pv->id, pvd->pv_uuid, ID_LEN); ++ ++ pv->dev = dev; ++ if (!*pvd->vg_name) ++ pv->vg_name = fmt->orphan_vg_name; ++ else if (!(pv->vg_name = dm_pool_strdup(mem, (char *)pvd->vg_name))) { ++ log_error("Volume Group name allocation failed."); ++ return 0; ++ } ++ ++ memcpy(&pv->vgid, vgd->vg_uuid, sizeof(vg->id)); ++ ++ /* Store system_id from first PV if PV belongs to a VG */ ++ if (vg && !*vg->lvm1_system_id) ++ strncpy(vg->lvm1_system_id, (char *)pvd->system_id, NAME_LEN); ++ ++ if (vg && ++ strncmp(vg->lvm1_system_id, (char *)pvd->system_id, sizeof(pvd->system_id))) ++ log_very_verbose("System ID %s on %s differs from %s for " ++ "volume group", pvd->system_id, ++ pv_dev_name(pv), vg->lvm1_system_id); ++ ++ /* ++ * If exported, we still need to flag in pv->status too because ++ * we don't always have a struct volume_group when we need this. ++ */ ++ if (pvd->pv_status & VG_EXPORTED) ++ pv->status |= EXPORTED_VG; ++ ++ if (pvd->pv_allocatable) ++ pv->status |= ALLOCATABLE_PV; ++ ++ pv->size = pvd->pv_size; ++ pv->pe_size = pvd->pe_size; ++ pv->pe_start = pvd->pe_start; ++ pv->pe_count = pvd->pe_total; ++ pv->pe_alloc_count = 0; ++ pv->pe_align = 0; ++ pv->is_labelled = 0; /* format1 PVs have no label */ ++ pv->label_sector = 0; ++ ++ /* Fix up pv size if missing or impossibly large */ ++ if (!pv->size || pv->size > (1ULL << 62)) { ++ if (!dev_get_size(dev, &pv->size)) { ++ log_error("%s: Couldn't get size.", pv_dev_name(pv)); ++ return 0; ++ } ++ log_verbose("Fixing up missing format1 size (%s) " ++ "for PV %s", display_size(fmt->cmd, pv->size), ++ pv_dev_name(pv)); ++ if (vg) { ++ size = pv->pe_count * (uint64_t) vg->extent_size + ++ pv->pe_start; ++ if (size > pv->size) ++ log_warn("WARNING: Physical Volume %s is too " ++ "large for underlying device", ++ pv_dev_name(pv)); ++ } ++ } ++ ++ dm_list_init(&pv->tags); ++ dm_list_init(&pv->segments); ++ ++ if (!alloc_pv_segment_whole_pv(mem, pv)) ++ return_0; ++ ++ return 1; ++} ++ ++int generate_lvm1_system_id(struct cmd_context *cmd, char *s, const char *prefix) ++{ ++ ++ if (dm_snprintf(s, NAME_LEN, "%s%s" FMTu64, ++ prefix, cmd->hostname, (uint64_t)time(NULL)) < 0) { ++ log_error("Generated LVM1 format system_id too long"); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++int export_pv(struct cmd_context *cmd, struct dm_pool *mem __attribute__((unused)), ++ struct volume_group *vg, ++ struct pv_disk *pvd, struct physical_volume *pv) ++{ ++ memset(pvd, 0, sizeof(*pvd)); ++ ++ pvd->id[0] = 'H'; ++ pvd->id[1] = 'M'; ++ pvd->version = 1; ++ ++ memcpy(pvd->pv_uuid, pv->id.uuid, ID_LEN); ++ ++ if (pv->vg_name && !is_orphan(pv) && !(pv->status & UNLABELLED_PV)) { ++ if (!_check_vg_name(pv->vg_name)) ++ return_0; ++ strncpy((char *)pvd->vg_name, pv->vg_name, sizeof(pvd->vg_name)); ++ } ++ ++ /* Preserve existing system_id if it exists */ ++ if (vg && vg->lvm1_system_id && *vg->lvm1_system_id) ++ strncpy((char *)pvd->system_id, vg->lvm1_system_id, sizeof(pvd->system_id)); ++ else if (vg && vg->system_id && *vg->system_id) ++ strncpy((char *)pvd->system_id, vg->system_id, sizeof(pvd->system_id)); ++ ++ /* Is VG already exported or being exported? */ ++ if (vg && vg_is_exported(vg)) { ++ /* Does system_id need setting? */ ++ if (!vg->lvm1_system_id || !*vg->lvm1_system_id || ++ strncmp(vg->lvm1_system_id, EXPORTED_TAG, ++ sizeof(EXPORTED_TAG) - 1)) { ++ if (!generate_lvm1_system_id(cmd, (char *)pvd->system_id, EXPORTED_TAG)) ++ return_0; ++ } ++ if (strlen((char *)pvd->vg_name) + sizeof(EXPORTED_TAG) > ++ sizeof(pvd->vg_name)) { ++ log_error("Volume group name %s too long to export", ++ pvd->vg_name); ++ return 0; ++ } ++ strcat((char *)pvd->vg_name, EXPORTED_TAG); ++ } ++ ++ /* Is VG being imported? */ ++ if (vg && !vg_is_exported(vg) && vg->lvm1_system_id && *vg->lvm1_system_id && ++ !strncmp(vg->lvm1_system_id, EXPORTED_TAG, sizeof(EXPORTED_TAG) - 1)) { ++ if (!generate_lvm1_system_id(cmd, (char *)pvd->system_id, IMPORTED_TAG)) ++ return_0; ++ } ++ ++ /* Generate system_id if PV is in VG */ ++ if (!pvd->system_id[0]) ++ if (!generate_lvm1_system_id(cmd, (char *)pvd->system_id, "")) ++ return_0; ++ ++ /* Update internal system_id if we changed it */ ++ if (vg && vg->lvm1_system_id && ++ (!*vg->lvm1_system_id || ++ strncmp(vg->lvm1_system_id, (char *)pvd->system_id, sizeof(pvd->system_id)))) ++ strncpy(vg->lvm1_system_id, (char *)pvd->system_id, NAME_LEN); ++ ++ //pvd->pv_major = MAJOR(pv->dev); ++ ++ if (pv->status & ALLOCATABLE_PV) ++ pvd->pv_allocatable = PV_ALLOCATABLE; ++ ++ pvd->pv_size = pv->size; ++ pvd->lv_cur = 0; /* this is set when exporting the lv list */ ++ if (vg) ++ pvd->pe_size = vg->extent_size; ++ else ++ pvd->pe_size = pv->pe_size; ++ pvd->pe_total = pv->pe_count; ++ pvd->pe_allocated = pv->pe_alloc_count; ++ pvd->pe_start = pv->pe_start; ++ ++ return 1; ++} ++ ++int import_vg(struct dm_pool *mem, ++ struct volume_group *vg, struct disk_list *dl) ++{ ++ struct vg_disk *vgd = &dl->vgd; ++ memcpy(vg->id.uuid, vgd->vg_uuid, ID_LEN); ++ ++ if (!_check_vg_name((char *)dl->pvd.vg_name)) ++ return_0; ++ ++ if (!(vg->name = dm_pool_strdup(mem, (char *)dl->pvd.vg_name))) ++ return_0; ++ ++ if (!(vg->lvm1_system_id = dm_pool_zalloc(mem, NAME_LEN + 1))) ++ return_0; ++ ++ if (vgd->vg_status & VG_EXPORTED) ++ vg->status |= EXPORTED_VG; ++ ++ if (vgd->vg_status & VG_EXTENDABLE) ++ vg->status |= RESIZEABLE_VG; ++ ++ if (vgd->vg_access & VG_READ) ++ vg->status |= LVM_READ; ++ ++ if (vgd->vg_access & VG_WRITE) ++ vg->status |= LVM_WRITE; ++ ++ if (vgd->vg_access & VG_CLUSTERED) ++ vg->status |= CLUSTERED; ++ ++ if (vgd->vg_access & VG_SHARED) ++ vg->status |= SHARED; ++ ++ vg->extent_size = vgd->pe_size; ++ vg->extent_count = vgd->pe_total; ++ vg->free_count = vgd->pe_total; ++ vg->max_lv = vgd->lv_max; ++ vg->max_pv = vgd->pv_max; ++ vg->alloc = ALLOC_NORMAL; ++ ++ return 1; ++} ++ ++int export_vg(struct vg_disk *vgd, struct volume_group *vg) ++{ ++ memset(vgd, 0, sizeof(*vgd)); ++ memcpy(vgd->vg_uuid, vg->id.uuid, ID_LEN); ++ ++ if (vg->status & LVM_READ) ++ vgd->vg_access |= VG_READ; ++ ++ if (vg->status & LVM_WRITE) ++ vgd->vg_access |= VG_WRITE; ++ ++ if (vg_is_clustered(vg)) ++ vgd->vg_access |= VG_CLUSTERED; ++ ++ if (vg->status & SHARED) ++ vgd->vg_access |= VG_SHARED; ++ ++ if (vg_is_exported(vg)) ++ vgd->vg_status |= VG_EXPORTED; ++ ++ if (vg_is_resizeable(vg)) ++ vgd->vg_status |= VG_EXTENDABLE; ++ ++ vgd->lv_max = vg->max_lv; ++ vgd->lv_cur = vg_visible_lvs(vg) + snapshot_count(vg); ++ ++ vgd->pv_max = vg->max_pv; ++ vgd->pv_cur = vg->pv_count; ++ ++ vgd->pe_size = vg->extent_size; ++ vgd->pe_total = vg->extent_count; ++ vgd->pe_allocated = vg->extent_count - vg->free_count; ++ ++ return 1; ++} ++ ++int import_lv(struct cmd_context *cmd, struct dm_pool *mem, ++ struct logical_volume *lv, struct lv_disk *lvd) ++{ ++ if (!(lv->name = _create_lv_name(mem, (char *)lvd->lv_name))) ++ return_0; ++ ++ lv->status |= VISIBLE_LV; ++ ++ if (lvd->lv_status & LV_SPINDOWN) ++ lv->status |= SPINDOWN_LV; ++ ++ if (lvd->lv_status & LV_PERSISTENT_MINOR) { ++ lv->status |= FIXED_MINOR; ++ lv->minor = MINOR(lvd->lv_dev); ++ lv->major = MAJOR(lvd->lv_dev); ++ } else { ++ lv->major = -1; ++ lv->minor = -1; ++ } ++ ++ if (lvd->lv_access & LV_READ) ++ lv->status |= LVM_READ; ++ ++ if (lvd->lv_access & LV_WRITE) ++ lv->status |= LVM_WRITE; ++ ++ if (lvd->lv_badblock) ++ lv->status |= BADBLOCK_ON; ++ ++ /* Drop the unused LV_STRICT here */ ++ if (lvd->lv_allocation & LV_CONTIGUOUS) ++ lv->alloc = ALLOC_CONTIGUOUS; ++ else ++ lv->alloc = ALLOC_NORMAL; ++ ++ if (!lvd->lv_read_ahead) ++ lv->read_ahead = cmd->default_settings.read_ahead; ++ else ++ lv->read_ahead = lvd->lv_read_ahead; ++ ++ lv->size = lvd->lv_size; ++ lv->le_count = lvd->lv_allocated_le; ++ ++ return 1; ++} ++ ++static void _export_lv(struct lv_disk *lvd, struct volume_group *vg, ++ struct logical_volume *lv, const char *dev_dir) ++{ ++ memset(lvd, 0, sizeof(*lvd)); ++ snprintf((char *)lvd->lv_name, sizeof(lvd->lv_name), "%s%s/%s", ++ dev_dir, vg->name, lv->name); ++ ++ (void) dm_strncpy((char *)lvd->vg_name, vg->name, sizeof(lvd->vg_name)); ++ ++ if (lv->status & LVM_READ) ++ lvd->lv_access |= LV_READ; ++ ++ if (lv->status & LVM_WRITE) ++ lvd->lv_access |= LV_WRITE; ++ ++ if (lv->status & SPINDOWN_LV) ++ lvd->lv_status |= LV_SPINDOWN; ++ ++ if (lv->status & FIXED_MINOR) { ++ lvd->lv_status |= LV_PERSISTENT_MINOR; ++ lvd->lv_dev = MKDEV(lv->major, lv->minor); ++ } else { ++ lvd->lv_dev = MKDEV(LVM_BLK_MAJOR, lvnum_from_lvid(&lv->lvid)); ++ } ++ ++ if (lv->read_ahead == DM_READ_AHEAD_AUTO || ++ lv->read_ahead == DM_READ_AHEAD_NONE) ++ lvd->lv_read_ahead = 0; ++ else ++ lvd->lv_read_ahead = lv->read_ahead; ++ ++ lvd->lv_stripes = ++ dm_list_item(lv->segments.n, struct lv_segment)->area_count; ++ lvd->lv_stripesize = ++ dm_list_item(lv->segments.n, struct lv_segment)->stripe_size; ++ ++ lvd->lv_size = lv->size; ++ lvd->lv_allocated_le = lv->le_count; ++ ++ if (lv->status & BADBLOCK_ON) ++ lvd->lv_badblock = LV_BADBLOCK_ON; ++ ++ if (lv->alloc == ALLOC_CONTIGUOUS) ++ lvd->lv_allocation |= LV_CONTIGUOUS; ++} ++ ++int export_extents(struct disk_list *dl, uint32_t lv_num, ++ struct logical_volume *lv, struct physical_volume *pv) ++{ ++ struct pe_disk *ped; ++ struct lv_segment *seg; ++ uint32_t pe, s; ++ ++ dm_list_iterate_items(seg, &lv->segments) { ++ for (s = 0; s < seg->area_count; s++) { ++ if (!(seg->segtype->flags & SEG_FORMAT1_SUPPORT)) { ++ log_error("Segment type %s in LV %s: " ++ "unsupported by format1", ++ lvseg_name(seg), lv->name); ++ return 0; ++ } ++ if (seg_type(seg, s) != AREA_PV) { ++ log_error("Non-PV stripe found in LV %s: " ++ "unsupported by format1", lv->name); ++ return 0; ++ } ++ if (seg_pv(seg, s) != pv) ++ continue; /* not our pv */ ++ ++ for (pe = 0; pe < (seg->len / seg->area_count); pe++) { ++ ped = &dl->extents[pe + seg_pe(seg, s)]; ++ ped->lv_num = lv_num; ++ ped->le_num = (seg->le / seg->area_count) + pe + ++ s * (lv->le_count / seg->area_count); ++ } ++ } ++ } ++ ++ return 1; ++} ++ ++int import_pvs(const struct format_type *fmt, struct dm_pool *mem, ++ struct volume_group *vg, struct dm_list *pvds) ++{ ++ struct disk_list *dl; ++ struct pv_list *pvl; ++ ++ vg->pv_count = 0; ++ dm_list_iterate_items(dl, pvds) { ++ if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl))) || ++ !(pvl->pv = dm_pool_alloc(mem, sizeof(*pvl->pv)))) ++ return_0; ++ ++ if (!import_pv(fmt, mem, dl->dev, vg, pvl->pv, &dl->pvd, &dl->vgd)) ++ return_0; ++ ++ pvl->pv->fmt = fmt; ++ add_pvl_to_vgs(vg, pvl); ++ } ++ ++ return 1; ++} ++ ++static struct logical_volume *_add_lv(struct dm_pool *mem, ++ struct volume_group *vg, ++ struct lv_disk *lvd) ++{ ++ struct logical_volume *lv; ++ ++ if (!(lv = alloc_lv(mem))) ++ return_NULL; ++ ++ lvid_from_lvnum(&lv->lvid, &vg->id, lvd->lv_number); ++ ++ if (!import_lv(vg->cmd, mem, lv, lvd)) ++ goto_bad; ++ ++ if (!link_lv_to_vg(vg, lv)) ++ goto_bad; ++ ++ return lv; ++bad: ++ dm_pool_free(mem, lv); ++ return NULL; ++} ++ ++int import_lvs(struct dm_pool *mem, struct volume_group *vg, struct dm_list *pvds) ++{ ++ struct disk_list *dl; ++ struct lvd_list *ll; ++ struct lv_disk *lvd; ++ ++ dm_list_iterate_items(dl, pvds) { ++ dm_list_iterate_items(ll, &dl->lvds) { ++ lvd = &ll->lvd; ++ ++ if (!find_lv(vg, (char *)lvd->lv_name) && ++ !_add_lv(mem, vg, lvd)) ++ return_0; ++ } ++ } ++ ++ return 1; ++} ++ ++/* FIXME: tidy */ ++int export_lvs(struct disk_list *dl, struct volume_group *vg, ++ struct physical_volume *pv, const char *dev_dir) ++{ ++ int r = 0; ++ struct lv_list *ll; ++ struct lvd_list *lvdl; ++ size_t len; ++ uint32_t lv_num; ++ struct dm_hash_table *lvd_hash; ++ ++ if (!_check_vg_name(vg->name)) ++ return_0; ++ ++ if (!(lvd_hash = dm_hash_create(32))) ++ return_0; ++ ++ /* ++ * setup the pv's extents array ++ */ ++ len = sizeof(struct pe_disk) * dl->pvd.pe_total; ++ if (!(dl->extents = dm_pool_zalloc(dl->mem, len))) ++ goto_out; ++ ++ dm_list_iterate_items(ll, &vg->lvs) { ++ if (lv_is_snapshot(ll->lv)) ++ continue; ++ ++ if (!(lvdl = dm_pool_alloc(dl->mem, sizeof(*lvdl)))) ++ goto_out; ++ ++ _export_lv(&lvdl->lvd, vg, ll->lv, dev_dir); ++ ++ lv_num = lvnum_from_lvid(&ll->lv->lvid); ++ lvdl->lvd.lv_number = lv_num; ++ ++ if (!dm_hash_insert(lvd_hash, ll->lv->name, &lvdl->lvd)) ++ goto_out; ++ ++ if (!export_extents(dl, lv_num + 1, ll->lv, pv)) ++ goto_out; ++ ++ if (lv_is_origin(ll->lv)) ++ lvdl->lvd.lv_access |= LV_SNAPSHOT_ORG; ++ ++ if (lv_is_cow(ll->lv)) { ++ lvdl->lvd.lv_access |= LV_SNAPSHOT; ++ lvdl->lvd.lv_chunk_size = ll->lv->snapshot->chunk_size; ++ lvdl->lvd.lv_snapshot_minor = ++ lvnum_from_lvid(&ll->lv->snapshot->origin->lvid); ++ } ++ ++ dm_list_add(&dl->lvds, &lvdl->list); ++ dl->pvd.lv_cur++; ++ } ++ ++ r = 1; ++ ++ out: ++ dm_hash_destroy(lvd_hash); ++ return r; ++} ++ ++/* ++ * FIXME: More inefficient code. ++ */ ++int import_snapshots(struct dm_pool *mem __attribute__((unused)), struct volume_group *vg, ++ struct dm_list *pvds) ++{ ++ struct logical_volume *lvs[MAX_LV] = { 0 }; ++ struct disk_list *dl; ++ struct lvd_list *ll; ++ struct lv_disk *lvd; ++ int lvnum; ++ struct logical_volume *org, *cow; ++ ++ /* build an index of lv numbers */ ++ dm_list_iterate_items(dl, pvds) { ++ dm_list_iterate_items(ll, &dl->lvds) { ++ lvd = &ll->lvd; ++ ++ lvnum = lvd->lv_number; ++ ++ if (lvnum >= MAX_LV) { ++ log_error("Logical volume number " ++ "out of bounds."); ++ return 0; ++ } ++ ++ if (!lvs[lvnum] && ++ !(lvs[lvnum] = find_lv(vg, (char *)lvd->lv_name))) { ++ log_error("Couldn't find logical volume '%s'.", ++ lvd->lv_name); ++ return 0; ++ } ++ } ++ } ++ ++ /* ++ * Now iterate through yet again adding the snapshots. ++ */ ++ dm_list_iterate_items(dl, pvds) { ++ dm_list_iterate_items(ll, &dl->lvds) { ++ lvd = &ll->lvd; ++ ++ if (!(lvd->lv_access & LV_SNAPSHOT)) ++ continue; ++ ++ lvnum = lvd->lv_number; ++ cow = lvs[lvnum]; ++ if (!(org = lvs[lvd->lv_snapshot_minor])) { ++ log_error("Couldn't find origin logical volume " ++ "for snapshot '%s'.", lvd->lv_name); ++ return 0; ++ } ++ ++ /* we may have already added this snapshot */ ++ if (lv_is_cow(cow)) ++ continue; ++ ++ /* insert the snapshot */ ++ if (!vg_add_snapshot(org, cow, NULL, ++ org->le_count, ++ lvd->lv_chunk_size)) { ++ log_error("Couldn't add snapshot."); ++ return 0; ++ } ++ } ++ } ++ ++ return 1; ++} ++ ++int export_uuids(struct disk_list *dl, struct volume_group *vg) ++{ ++ struct uuid_list *ul; ++ struct pv_list *pvl; ++ ++ dm_list_iterate_items(pvl, &vg->pvs) { ++ if (!(ul = dm_pool_alloc(dl->mem, sizeof(*ul)))) ++ return_0; ++ ++ memset(ul->uuid, 0, sizeof(ul->uuid)); ++ memcpy(ul->uuid, pvl->pv->id.uuid, ID_LEN); ++ ++ dm_list_add(&dl->uuids, &ul->list); ++ } ++ return 1; ++} ++ ++/* ++ * This calculates the nasty pv_number field ++ * used by LVM1. ++ */ ++void export_numbers(struct dm_list *pvds, struct volume_group *vg __attribute__((unused))) ++{ ++ struct disk_list *dl; ++ int pv_num = 1; ++ ++ dm_list_iterate_items(dl, pvds) ++ dl->pvd.pv_number = pv_num++; ++} ++ ++/* ++ * Calculate vg_disk->pv_act. ++ */ ++void export_pv_act(struct dm_list *pvds) ++{ ++ struct disk_list *dl; ++ int act = 0; ++ ++ dm_list_iterate_items(dl, pvds) ++ if (dl->pvd.pv_status & PV_ACTIVE) ++ act++; ++ ++ dm_list_iterate_items(dl, pvds) ++ dl->vgd.pv_act = act; ++} ++ ++int export_vg_number(struct format_instance *fid, struct dm_list *pvds, ++ const char *vg_name, struct dev_filter *filter) ++{ ++ struct disk_list *dl; ++ int vg_num; ++ ++ if (!get_free_vg_number(fid, filter, vg_name, &vg_num)) ++ return_0; ++ ++ dm_list_iterate_items(dl, pvds) ++ dl->vgd.vg_number = vg_num; ++ ++ return 1; ++} +diff --git a/lib/format1/import-extents.c b/lib/format1/import-extents.c +new file mode 100644 +index 0000000..c583741 +--- /dev/null ++++ b/lib/format1/import-extents.c +@@ -0,0 +1,377 @@ ++/* ++ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. ++ * Copyright (C) 2004-2017 Red Hat, Inc. All rights reserved. ++ * ++ * This file is part of LVM2. ++ * ++ * 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 Lesser General Public License v.2.1. ++ * ++ * You should have received a copy of the GNU Lesser 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 ++ */ ++ ++#include "lib.h" ++#include "metadata.h" ++#include "disk-rep.h" ++#include "lv_alloc.h" ++#include "display.h" ++#include "segtype.h" ++ ++/* ++ * After much thought I have decided it is easier, ++ * and probably no less efficient, to convert the ++ * pe->le map to a full le->pe map, and then ++ * process this to get the segments form that ++ * we're after. Any code which goes directly from ++ * the pe->le map to segments would be gladly ++ * accepted, if it is less complicated than this ++ * file. ++ */ ++struct pe_specifier { ++ struct physical_volume *pv; ++ uint32_t pe; ++}; ++ ++struct lv_map { ++ struct logical_volume *lv; ++ uint32_t stripes; ++ uint32_t stripe_size; ++ struct pe_specifier *map; ++}; ++ ++static struct dm_hash_table *_create_lv_maps(struct dm_pool *mem, ++ struct volume_group *vg) ++{ ++ struct dm_hash_table *maps = dm_hash_create(32); ++ struct lv_list *ll; ++ struct lv_map *lvm; ++ ++ if (!maps) { ++ log_error("Unable to create hash table for holding " ++ "extent maps."); ++ return NULL; ++ } ++ ++ dm_list_iterate_items(ll, &vg->lvs) { ++ if (lv_is_snapshot(ll->lv)) ++ continue; ++ ++ if (!(lvm = dm_pool_alloc(mem, sizeof(*lvm)))) ++ goto_bad; ++ ++ lvm->lv = ll->lv; ++ /* ++ * Alloc 1 extra element, so the loop in _area_length() and ++ * _check_stripe() finds the last map member as noncontinuous. ++ */ ++ if (!(lvm->map = dm_pool_zalloc(mem, sizeof(*lvm->map) ++ * (ll->lv->le_count + 1)))) ++ goto_bad; ++ ++ if (!dm_hash_insert(maps, ll->lv->name, lvm)) ++ goto_bad; ++ } ++ ++ return maps; ++ ++ bad: ++ dm_hash_destroy(maps); ++ return NULL; ++} ++ ++static int _fill_lv_array(struct lv_map **lvs, ++ struct dm_hash_table *maps, struct disk_list *dl) ++{ ++ struct lvd_list *ll; ++ struct lv_map *lvm; ++ ++ memset(lvs, 0, sizeof(*lvs) * MAX_LV); ++ ++ dm_list_iterate_items(ll, &dl->lvds) { ++ if (!(lvm = dm_hash_lookup(maps, strrchr((char *)ll->lvd.lv_name, '/') ++ + 1))) { ++ log_error("Physical volume (%s) contains an " ++ "unknown logical volume (%s).", ++ dev_name(dl->dev), ll->lvd.lv_name); ++ return 0; ++ } ++ ++ lvm->stripes = ll->lvd.lv_stripes; ++ lvm->stripe_size = ll->lvd.lv_stripesize; ++ ++ lvs[ll->lvd.lv_number] = lvm; ++ } ++ ++ return 1; ++} ++ ++static int _fill_maps(struct dm_hash_table *maps, struct volume_group *vg, ++ struct dm_list *pvds) ++{ ++ struct disk_list *dl; ++ struct physical_volume *pv; ++ struct lv_map *lvms[MAX_LV], *lvm; ++ struct pe_disk *e; ++ uint32_t i, lv_num, le; ++ ++ dm_list_iterate_items(dl, pvds) { ++ if (!(pv = find_pv(vg, dl->dev))) { ++ log_error("PV %s not found.", dl->dev->pvid); ++ return 0; ++ } ++ e = dl->extents; ++ ++ /* build an array of lv's for this pv */ ++ if (!_fill_lv_array(lvms, maps, dl)) ++ return_0; ++ ++ for (i = 0; i < dl->pvd.pe_total; i++) { ++ lv_num = e[i].lv_num; ++ ++ if (lv_num == UNMAPPED_EXTENT) ++ continue; ++ ++ lv_num--; ++ lvm = lvms[lv_num]; ++ ++ if (!lvm) { ++ log_error("Invalid LV in extent map " ++ "(PV %s, PE %" PRIu32 ++ ", LV %" PRIu32 ++ ", LE %" PRIu32 ")", ++ dev_name(pv->dev), i, ++ lv_num, e[i].le_num); ++ return 0; ++ } ++ ++ le = e[i].le_num; ++ ++ if (le >= lvm->lv->le_count) { ++ log_error("logical extent number " ++ "out of bounds"); ++ return 0; ++ } ++ ++ if (lvm->map[le].pv) { ++ log_error("logical extent (%u) " ++ "already mapped.", le); ++ return 0; ++ } ++ ++ lvm->map[le].pv = pv; ++ lvm->map[le].pe = i; ++ } ++ } ++ ++ return 1; ++} ++ ++static int _check_single_map(struct lv_map *lvm) ++{ ++ uint32_t i; ++ ++ for (i = 0; i < lvm->lv->le_count; i++) { ++ if (!lvm->map[i].pv) { ++ log_error("Logical volume (%s) contains an incomplete " ++ "mapping table.", lvm->lv->name); ++ return 0; ++ } ++ } ++ ++ return 1; ++} ++ ++static int _check_maps_are_complete(struct dm_hash_table *maps) ++{ ++ struct dm_hash_node *n; ++ struct lv_map *lvm; ++ ++ for (n = dm_hash_get_first(maps); n; n = dm_hash_get_next(maps, n)) { ++ lvm = (struct lv_map *) dm_hash_get_data(maps, n); ++ ++ if (!_check_single_map(lvm)) ++ return_0; ++ } ++ return 1; ++} ++ ++static uint32_t _area_length(struct lv_map *lvm, uint32_t le) ++{ ++ uint32_t len = 0; ++ ++ do ++ len++; ++ while ((lvm->map[le + len].pv == lvm->map[le].pv) && ++ (lvm->map[le].pv && ++ lvm->map[le + len].pe == lvm->map[le].pe + len)); ++ ++ return len; ++} ++ ++static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm) ++{ ++ uint32_t le = 0, len; ++ struct lv_segment *seg; ++ struct segment_type *segtype; ++ ++ if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED))) ++ return_0; ++ ++ while (le < lvm->lv->le_count) { ++ len = _area_length(lvm, le); ++ ++ if (!(seg = alloc_lv_segment(segtype, lvm->lv, le, len, 0, 0, 0, ++ NULL, 1, len, 0, 0, 0, 0, NULL))) { ++ log_error("Failed to allocate linear segment."); ++ return 0; ++ } ++ ++ if (!set_lv_segment_area_pv(seg, 0, lvm->map[le].pv, ++ lvm->map[le].pe)) ++ return_0; ++ ++ dm_list_add(&lvm->lv->segments, &seg->list); ++ ++ le += seg->len; ++ } ++ ++ return 1; ++} ++ ++static int _check_stripe(struct lv_map *lvm, uint32_t area_count, ++ uint32_t area_len, uint32_t base_le, ++ uint32_t total_area_len) ++{ ++ uint32_t st; ++ ++ /* ++ * Is the next physical extent in every stripe adjacent to the last? ++ */ ++ for (st = 0; st < area_count; st++) ++ if ((lvm->map[base_le + st * total_area_len + area_len].pv != ++ lvm->map[base_le + st * total_area_len].pv) || ++ (lvm->map[base_le + st * total_area_len].pv && ++ lvm->map[base_le + st * total_area_len + area_len].pe != ++ lvm->map[base_le + st * total_area_len].pe + area_len)) ++ return 0; ++ ++ return 1; ++} ++ ++static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm) ++{ ++ uint32_t st, first_area_le = 0, total_area_len; ++ uint32_t area_len; ++ struct lv_segment *seg; ++ struct segment_type *segtype; ++ ++ /* ++ * Work out overall striped length ++ */ ++ if (lvm->lv->le_count % lvm->stripes) { ++ log_error("Number of stripes (%u) incompatible " ++ "with logical extent count (%u) for %s", ++ lvm->stripes, lvm->lv->le_count, lvm->lv->name); ++ } ++ ++ total_area_len = lvm->lv->le_count / lvm->stripes; ++ ++ if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED))) ++ return_0; ++ ++ while (first_area_le < total_area_len) { ++ area_len = 1; ++ ++ /* ++ * Find how many extents are contiguous in all stripes ++ * and so can form part of this segment ++ */ ++ while (_check_stripe(lvm, lvm->stripes, ++ area_len, first_area_le, total_area_len)) ++ area_len++; ++ ++ if (!(seg = alloc_lv_segment(segtype, lvm->lv, ++ lvm->stripes * first_area_le, ++ lvm->stripes * area_len, 0, ++ 0, lvm->stripe_size, NULL, ++ lvm->stripes, ++ area_len, 0, 0, 0, 0, NULL))) { ++ log_error("Failed to allocate striped segment."); ++ return 0; ++ } ++ ++ /* ++ * Set up start positions of each stripe in this segment ++ */ ++ for (st = 0; st < seg->area_count; st++) ++ if (!set_lv_segment_area_pv(seg, st, ++ lvm->map[first_area_le + st * total_area_len].pv, ++ lvm->map[first_area_le + st * total_area_len].pe)) ++ return_0; ++ ++ dm_list_add(&lvm->lv->segments, &seg->list); ++ ++ first_area_le += area_len; ++ } ++ ++ return 1; ++} ++ ++static int _build_segments(struct cmd_context *cmd, struct lv_map *lvm) ++{ ++ return (lvm->stripes > 1 ? _read_stripes(cmd, lvm) : ++ _read_linear(cmd, lvm)); ++} ++ ++static int _build_all_segments(struct cmd_context *cmd, struct dm_hash_table *maps) ++{ ++ struct dm_hash_node *n; ++ struct lv_map *lvm; ++ ++ for (n = dm_hash_get_first(maps); n; n = dm_hash_get_next(maps, n)) { ++ lvm = (struct lv_map *) dm_hash_get_data(maps, n); ++ if (!_build_segments(cmd, lvm)) ++ return_0; ++ } ++ ++ return 1; ++} ++ ++int import_extents(struct cmd_context *cmd, struct volume_group *vg, ++ struct dm_list *pvds) ++{ ++ int r = 0; ++ struct dm_pool *scratch = dm_pool_create("lvm1 import_extents", 10 * 1024); ++ struct dm_hash_table *maps; ++ ++ if (!scratch) ++ return_0; ++ ++ if (!(maps = _create_lv_maps(scratch, vg))) { ++ log_error("Couldn't allocate logical volume maps."); ++ goto out; ++ } ++ ++ if (!_fill_maps(maps, vg, pvds)) { ++ log_error("Couldn't fill logical volume maps."); ++ goto out; ++ } ++ ++ if (!_check_maps_are_complete(maps) && !(vg->status & PARTIAL_VG)) ++ goto_out; ++ ++ if (!_build_all_segments(cmd, maps)) { ++ log_error("Couldn't build extent segments."); ++ goto out; ++ } ++ r = 1; ++ ++ out: ++ if (maps) ++ dm_hash_destroy(maps); ++ dm_pool_destroy(scratch); ++ return r; ++} +diff --git a/lib/format1/layout.c b/lib/format1/layout.c +new file mode 100644 +index 0000000..380a983 +--- /dev/null ++++ b/lib/format1/layout.c +@@ -0,0 +1,172 @@ ++/* ++ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. ++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. ++ * ++ * This file is part of LVM2. ++ * ++ * 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 Lesser General Public License v.2.1. ++ * ++ * You should have received a copy of the GNU Lesser 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 ++ */ ++ ++#include "lib.h" ++#include "disk-rep.h" ++ ++/* ++ * Only works with powers of 2. ++ */ ++static uint32_t _round_up(uint32_t n, uint32_t size) ++{ ++ size--; ++ return (n + size) & ~size; ++} ++ ++/* Unused. ++static uint32_t _div_up(uint32_t n, uint32_t size) ++{ ++ return _round_up(n, size) / size; ++} ++*/ ++ ++/* ++ * Each chunk of metadata should be aligned to ++ * METADATA_ALIGN. ++ */ ++static uint32_t _next_base(struct data_area *area) ++{ ++ return _round_up(area->base + area->size, METADATA_ALIGN); ++} ++ ++/* ++ * Quick calculation based on pe_start. ++ */ ++static int _adjust_pe_on_disk(struct pv_disk *pvd) ++{ ++ uint32_t pe_start = pvd->pe_start << SECTOR_SHIFT; ++ ++ if (pe_start < pvd->pe_on_disk.base + pvd->pe_on_disk.size) ++ return 0; ++ ++ pvd->pe_on_disk.size = pe_start - pvd->pe_on_disk.base; ++ return 1; ++} ++ ++static void _calc_simple_layout(struct pv_disk *pvd) ++{ ++ pvd->pv_on_disk.base = METADATA_BASE; ++ pvd->pv_on_disk.size = PV_SIZE; ++ ++ pvd->vg_on_disk.base = _next_base(&pvd->pv_on_disk); ++ pvd->vg_on_disk.size = VG_SIZE; ++ ++ pvd->pv_uuidlist_on_disk.base = _next_base(&pvd->vg_on_disk); ++ pvd->pv_uuidlist_on_disk.size = MAX_PV * NAME_LEN; ++ ++ pvd->lv_on_disk.base = _next_base(&pvd->pv_uuidlist_on_disk); ++ pvd->lv_on_disk.size = MAX_LV * sizeof(struct lv_disk); ++ ++ pvd->pe_on_disk.base = _next_base(&pvd->lv_on_disk); ++ pvd->pe_on_disk.size = pvd->pe_total * sizeof(struct pe_disk); ++} ++ ++static int _check_vg_limits(struct disk_list *dl) ++{ ++ if (dl->vgd.lv_max > MAX_LV) { ++ log_error("MaxLogicalVolumes of %d exceeds format limit of %d " ++ "for VG '%s'", dl->vgd.lv_max, MAX_LV - 1, ++ dl->pvd.vg_name); ++ return 0; ++ } ++ ++ if (dl->vgd.pv_max > MAX_PV) { ++ log_error("MaxPhysicalVolumes of %d exceeds format limit of %d " ++ "for VG '%s'", dl->vgd.pv_max, MAX_PV - 1, ++ dl->pvd.vg_name); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++/* ++ * This assumes pe_count and pe_start have already ++ * been calculated correctly. ++ */ ++int calculate_layout(struct disk_list *dl) ++{ ++ struct pv_disk *pvd = &dl->pvd; ++ ++ _calc_simple_layout(pvd); ++ if (!_adjust_pe_on_disk(pvd)) { ++ log_error("Insufficient space for metadata and PE's."); ++ return 0; ++ } ++ ++ if (!_check_vg_limits(dl)) ++ return 0; ++ ++ return 1; ++} ++ ++/* ++ * The number of extents that can fit on a disk is metadata format dependant. ++ * pe_start is any existing value for pe_start ++ */ ++int calculate_extent_count(struct physical_volume *pv, uint32_t extent_size, ++ uint32_t max_extent_count, uint64_t pe_start) ++{ ++ struct pv_disk *pvd = dm_malloc(sizeof(*pvd)); ++ uint32_t end; ++ ++ if (!pvd) ++ return_0; ++ ++ /* ++ * Guess how many extents will fit, bearing in mind that ++ * one is going to be knocked off at the start of the ++ * next loop. ++ */ ++ if (max_extent_count) ++ pvd->pe_total = max_extent_count + 1; ++ else ++ pvd->pe_total = (pv->size / extent_size); ++ ++ if (pvd->pe_total < PE_SIZE_PV_SIZE_REL) { ++ log_error("Too few extents on %s. Try smaller extent size.", ++ pv_dev_name(pv)); ++ dm_free(pvd); ++ return 0; ++ } ++ ++ do { ++ pvd->pe_total--; ++ _calc_simple_layout(pvd); ++ end = ((pvd->pe_on_disk.base + pvd->pe_on_disk.size + ++ SECTOR_SIZE - 1) >> SECTOR_SHIFT); ++ ++ if (pe_start && end < pe_start) ++ end = pe_start; ++ ++ pvd->pe_start = _round_up(end, LVM1_PE_ALIGN); ++ ++ } while ((pvd->pe_start + ((uint64_t)pvd->pe_total * extent_size)) ++ > pv->size); ++ ++ if (pvd->pe_total > MAX_PE_TOTAL) { ++ log_error("Metadata extent limit (%u) exceeded for %s - " ++ "%u required", MAX_PE_TOTAL, pv_dev_name(pv), ++ pvd->pe_total); ++ dm_free(pvd); ++ return 0; ++ } ++ ++ pv->pe_count = pvd->pe_total; ++ pv->pe_start = pvd->pe_start; ++ /* We can't set pe_size here without breaking LVM1 compatibility */ ++ dm_free(pvd); ++ return 1; ++} +diff --git a/lib/format1/lvm1-label.c b/lib/format1/lvm1-label.c +new file mode 100644 +index 0000000..691a05a +--- /dev/null ++++ b/lib/format1/lvm1-label.c +@@ -0,0 +1,129 @@ ++/* ++ * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. ++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. ++ * ++ * This file is part of LVM2. ++ * ++ * 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 Lesser General Public License v.2.1. ++ * ++ * You should have received a copy of the GNU Lesser 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 ++ */ ++ ++#include "lib.h" ++#include "lvm1-label.h" ++#include "disk-rep.h" ++#include "label.h" ++#include "metadata.h" ++#include "xlate.h" ++#include "format1.h" ++ ++#include ++#include ++ ++static void _not_supported(const char *op) ++{ ++ log_error("The '%s' operation is not supported for the lvm1 labeller.", ++ op); ++} ++ ++static int _lvm1_can_handle(struct labeller *l __attribute__((unused)), void *buf, uint64_t sector) ++{ ++ struct pv_disk *pvd = (struct pv_disk *) buf; ++ uint32_t version; ++ ++ /* LVM1 label must always be in first sector */ ++ if (sector) ++ return 0; ++ ++ version = xlate16(pvd->version); ++ ++ if (pvd->id[0] == 'H' && pvd->id[1] == 'M' && ++ (version == 1 || version == 2)) ++ return 1; ++ ++ return 0; ++} ++ ++static int _lvm1_write(struct label *label __attribute__((unused)), void *buf __attribute__((unused))) ++{ ++ _not_supported("write"); ++ return 0; ++} ++ ++static int _lvm1_read(struct labeller *l, struct device *dev, void *buf, ++ struct label **label) ++{ ++ struct pv_disk *pvd = (struct pv_disk *) buf; ++ struct vg_disk vgd; ++ struct lvmcache_info *info; ++ const char *vgid = FMT_LVM1_ORPHAN_VG_NAME; ++ const char *vgname = FMT_LVM1_ORPHAN_VG_NAME; ++ unsigned exported = 0; ++ ++ munge_pvd(dev, pvd); ++ ++ if (*pvd->vg_name) { ++ if (!read_vgd(dev, &vgd, pvd)) ++ return_0; ++ vgid = (char *) vgd.vg_uuid; ++ vgname = (char *) pvd->vg_name; ++ exported = pvd->pv_status & VG_EXPORTED; ++ } ++ ++ if (!(info = lvmcache_add(l, (char *)pvd->pv_uuid, dev, vgname, vgid, ++ exported))) ++ return_0; ++ *label = lvmcache_get_label(info); ++ ++ lvmcache_set_device_size(info, ((uint64_t)xlate32(pvd->pv_size)) << SECTOR_SHIFT); ++ lvmcache_set_ext_version(info, 0); ++ lvmcache_set_ext_flags(info, 0); ++ lvmcache_del_mdas(info); ++ lvmcache_del_bas(info); ++ ++ return 1; ++} ++ ++static int _lvm1_initialise_label(struct labeller *l __attribute__((unused)), struct label *label) ++{ ++ strcpy(label->type, "LVM1"); ++ ++ return 1; ++} ++ ++static void _lvm1_destroy_label(struct labeller *l __attribute__((unused)), struct label *label __attribute__((unused))) ++{ ++} ++ ++static void _lvm1_destroy(struct labeller *l) ++{ ++ dm_free(l); ++} ++ ++struct label_ops _lvm1_ops = { ++ .can_handle = _lvm1_can_handle, ++ .write = _lvm1_write, ++ .read = _lvm1_read, ++ .initialise_label = _lvm1_initialise_label, ++ .destroy_label = _lvm1_destroy_label, ++ .destroy = _lvm1_destroy, ++}; ++ ++struct labeller *lvm1_labeller_create(struct format_type *fmt) ++{ ++ struct labeller *l; ++ ++ if (!(l = dm_malloc(sizeof(*l)))) { ++ log_error("Couldn't allocate labeller object."); ++ return NULL; ++ } ++ ++ l->ops = &_lvm1_ops; ++ l->fmt = fmt; ++ ++ return l; ++} +diff --git a/lib/format1/lvm1-label.h b/lib/format1/lvm1-label.h +new file mode 100644 +index 0000000..27f2f51 +--- /dev/null ++++ b/lib/format1/lvm1-label.h +@@ -0,0 +1,23 @@ ++/* ++ * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. ++ * Copyright (C) 2004 Red Hat, Inc. All rights reserved. ++ * ++ * This file is part of LVM2. ++ * ++ * 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 Lesser General Public License v.2.1. ++ * ++ * You should have received a copy of the GNU Lesser 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 ++ */ ++ ++#ifndef _LVM_LVM1_LABEL_H ++#define _LVM_LVM1_LABEL_H ++ ++#include "metadata.h" ++ ++struct labeller *lvm1_labeller_create(struct format_type *fmt); ++ ++#endif +diff --git a/lib/format1/vg_number.c b/lib/format1/vg_number.c +new file mode 100644 +index 0000000..8b1a803 +--- /dev/null ++++ b/lib/format1/vg_number.c +@@ -0,0 +1,60 @@ ++/* ++ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. ++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. ++ * ++ * This file is part of LVM2. ++ * ++ * 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 Lesser General Public License v.2.1. ++ * ++ * You should have received a copy of the GNU Lesser 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 ++ */ ++ ++#include "lib.h" ++#include "disk-rep.h" ++ ++/* ++ * FIXME: Quick hack. We can use caching to ++ * prevent a total re-read, even so vg_number ++ * causes the tools to check *every* pv. Yuck. ++ * Put in separate file so it wouldn't contaminate ++ * other code. ++ */ ++int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter, ++ const char *candidate_vg, int *result) ++{ ++ struct dm_list all_pvs; ++ struct disk_list *dl; ++ struct dm_pool *mem = dm_pool_create("lvm1 vg_number", 10 * 1024); ++ int i, r = 0, numbers[MAX_VG] = { 0 }; ++ ++ dm_list_init(&all_pvs); ++ ++ if (!mem) ++ return_0; ++ ++ if (!read_pvs_in_vg(fid->fmt, NULL, filter, mem, &all_pvs)) ++ goto_out; ++ ++ dm_list_iterate_items(dl, &all_pvs) { ++ if (!*dl->pvd.vg_name || !strcmp((char *)dl->pvd.vg_name, candidate_vg)) ++ continue; ++ ++ numbers[dl->vgd.vg_number] = 1; ++ } ++ ++ for (i = 0; i < MAX_VG; i++) { ++ if (!numbers[i]) { ++ r = 1; ++ *result = i; ++ break; ++ } ++ } ++ ++ out: ++ dm_pool_destroy(mem); ++ return r; ++} +diff --git a/lib/format_pool/.exported_symbols b/lib/format_pool/.exported_symbols +new file mode 100644 +index 0000000..e9fac2e +--- /dev/null ++++ b/lib/format_pool/.exported_symbols +@@ -0,0 +1 @@ ++init_format +diff --git a/lib/format_pool/Makefile.in b/lib/format_pool/Makefile.in +new file mode 100644 +index 0000000..05d1b0c +--- /dev/null ++++ b/lib/format_pool/Makefile.in +@@ -0,0 +1,30 @@ ++# ++# Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved. ++# Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved. ++# ++# This file is part of LVM2. ++# ++# 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 ++ ++srcdir = @srcdir@ ++top_srcdir = @top_srcdir@ ++top_builddir = @top_builddir@ ++ ++SOURCES =\ ++ disk_rep.c \ ++ format_pool.c \ ++ import_export.c \ ++ pool_label.c ++ ++LIB_SHARED = liblvm2formatpool.$(LIB_SUFFIX) ++LIB_VERSION = $(LIB_VERSION_LVM) ++ ++include $(top_builddir)/make.tmpl ++ ++install: install_lvm2_plugin +diff --git a/lib/format_pool/disk_rep.c b/lib/format_pool/disk_rep.c +new file mode 100644 +index 0000000..fe9b03e +--- /dev/null ++++ b/lib/format_pool/disk_rep.c +@@ -0,0 +1,409 @@ ++/* ++ * Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved. ++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. ++ * ++ * This file is part of LVM2. ++ * ++ * 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 Lesser General Public License v.2.1. ++ * ++ * You should have received a copy of the GNU Lesser 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 ++ */ ++ ++#include "lib.h" ++#include "label.h" ++#include "metadata.h" ++#include "lvmcache.h" ++#include "xlate.h" ++#include "disk_rep.h" ++#include "toolcontext.h" ++ ++#include ++ ++/* FIXME: memcpy might not be portable */ ++#define CPIN_8(x, y, z) {memcpy((x), (y), (z));} ++#define CPOUT_8(x, y, z) {memcpy((y), (x), (z));} ++#define CPIN_16(x, y) {(x) = xlate16_be((y));} ++#define CPOUT_16(x, y) {(y) = xlate16_be((x));} ++#define CPIN_32(x, y) {(x) = xlate32_be((y));} ++#define CPOUT_32(x, y) {(y) = xlate32_be((x));} ++#define CPIN_64(x, y) {(x) = xlate64_be((y));} ++#define CPOUT_64(x, y) {(y) = xlate64_be((x));} ++ ++static int __read_pool_disk(const struct format_type *fmt, struct device *dev, ++ struct dm_pool *mem __attribute__((unused)), struct pool_list *pl, ++ const char *vg_name __attribute__((unused))) ++{ ++ char buf[512] __attribute__((aligned(8))); ++ ++ /* FIXME: Need to check the cache here first */ ++ if (!dev_read(dev, UINT64_C(0), 512, DEV_IO_POOL, buf)) { ++ log_very_verbose("Failed to read PV data from %s", ++ dev_name(dev)); ++ return 0; ++ } ++ ++ if (!read_pool_label(pl, fmt->labeller, dev, buf, NULL)) ++ return_0; ++ ++ return 1; ++} ++ ++static void _add_pl_to_list(struct cmd_context *cmd, struct dm_list *head, struct pool_list *data) ++{ ++ struct pool_list *pl; ++ ++ dm_list_iterate_items(pl, head) { ++ if (id_equal(&data->pv_uuid, &pl->pv_uuid)) { ++ char uuid[ID_LEN + 7] __attribute__((aligned(8))); ++ ++ if (!id_write_format(&pl->pv_uuid, uuid, ID_LEN + 7)) ++ stack; ++ ++ if (!dev_subsystem_part_major(cmd->dev_types, data->dev)) { ++ log_very_verbose("Ignoring duplicate PV %s on " ++ "%s", uuid, ++ dev_name(data->dev)); ++ return; ++ } ++ log_very_verbose("Duplicate PV %s - using %s %s", ++ uuid, dev_subsystem_name(cmd->dev_types, data->dev), ++ dev_name(data->dev)); ++ dm_list_del(&pl->list); ++ break; ++ } ++ } ++ dm_list_add(head, &data->list); ++} ++ ++int read_pool_label(struct pool_list *pl, struct labeller *l, ++ struct device *dev, char *buf, struct label **label) ++{ ++ struct lvmcache_info *info; ++ struct id pvid; ++ struct id vgid; ++ char uuid[ID_LEN + 7] __attribute__((aligned(8))); ++ struct pool_disk *pd = &pl->pd; ++ ++ pool_label_in(pd, buf); ++ ++ get_pool_pv_uuid(&pvid, pd); ++ if (!id_write_format(&pvid, uuid, ID_LEN + 7)) ++ stack; ++ log_debug_metadata("Calculated uuid %s for %s", uuid, dev_name(dev)); ++ ++ get_pool_vg_uuid(&vgid, pd); ++ if (!id_write_format(&vgid, uuid, ID_LEN + 7)) ++ stack; ++ log_debug_metadata("Calculated uuid %s for %s", uuid, pd->pl_pool_name); ++ ++ if (!(info = lvmcache_add(l, (char *) &pvid, dev, pd->pl_pool_name, ++ (char *) &vgid, 0))) ++ return_0; ++ if (label) ++ *label = lvmcache_get_label(info); ++ ++ lvmcache_set_device_size(info, ((uint64_t)xlate32_be(pd->pl_blocks)) << SECTOR_SHIFT); ++ lvmcache_set_ext_version(info, 0); ++ lvmcache_set_ext_flags(info, 0); ++ lvmcache_del_mdas(info); ++ lvmcache_del_bas(info); ++ ++ pl->dev = dev; ++ pl->pv = NULL; ++ memcpy(&pl->pv_uuid, &pvid, sizeof(pvid)); ++ ++ return 1; ++} ++ ++/** ++ * pool_label_out - copies a pool_label_t into a char buffer ++ * @pl: ptr to a pool_label_t struct ++ * @buf: ptr to raw space where label info will be copied ++ * ++ * This function is important because it takes care of all of ++ * the endian issues when copying to disk. This way, when ++ * machines of different architectures are used, they will ++ * be able to interpret ondisk labels correctly. Always use ++ * this function before writing to disk. ++ */ ++void pool_label_out(struct pool_disk *pl, void *buf) ++{ ++ struct pool_disk *bufpl = (struct pool_disk *) buf; ++ ++ CPOUT_64(pl->pl_magic, bufpl->pl_magic); ++ CPOUT_64(pl->pl_pool_id, bufpl->pl_pool_id); ++ CPOUT_8(pl->pl_pool_name, bufpl->pl_pool_name, POOL_NAME_SIZE); ++ CPOUT_32(pl->pl_version, bufpl->pl_version); ++ CPOUT_32(pl->pl_subpools, bufpl->pl_subpools); ++ CPOUT_32(pl->pl_sp_id, bufpl->pl_sp_id); ++ CPOUT_32(pl->pl_sp_devs, bufpl->pl_sp_devs); ++ CPOUT_32(pl->pl_sp_devid, bufpl->pl_sp_devid); ++ CPOUT_32(pl->pl_sp_type, bufpl->pl_sp_type); ++ CPOUT_64(pl->pl_blocks, bufpl->pl_blocks); ++ CPOUT_32(pl->pl_striping, bufpl->pl_striping); ++ CPOUT_32(pl->pl_sp_dmepdevs, bufpl->pl_sp_dmepdevs); ++ CPOUT_32(pl->pl_sp_dmepid, bufpl->pl_sp_dmepid); ++ CPOUT_32(pl->pl_sp_weight, bufpl->pl_sp_weight); ++ CPOUT_32(pl->pl_minor, bufpl->pl_minor); ++ CPOUT_32(pl->pl_padding, bufpl->pl_padding); ++ CPOUT_8(pl->pl_reserve, bufpl->pl_reserve, 184); ++} ++ ++/** ++ * pool_label_in - copies a char buffer into a pool_label_t ++ * @pl: ptr to a pool_label_t struct ++ * @buf: ptr to raw space where label info is copied from ++ * ++ * This function is important because it takes care of all of ++ * the endian issues when information from disk is about to be ++ * used. This way, when machines of different architectures ++ * are used, they will be able to interpret ondisk labels ++ * correctly. Always use this function before using labels that ++ * were read from disk. ++ */ ++void pool_label_in(struct pool_disk *pl, void *buf) ++{ ++ struct pool_disk *bufpl = (struct pool_disk *) buf; ++ ++ CPIN_64(pl->pl_magic, bufpl->pl_magic); ++ CPIN_64(pl->pl_pool_id, bufpl->pl_pool_id); ++ CPIN_8(pl->pl_pool_name, bufpl->pl_pool_name, POOL_NAME_SIZE); ++ CPIN_32(pl->pl_version, bufpl->pl_version); ++ CPIN_32(pl->pl_subpools, bufpl->pl_subpools); ++ CPIN_32(pl->pl_sp_id, bufpl->pl_sp_id); ++ CPIN_32(pl->pl_sp_devs, bufpl->pl_sp_devs); ++ CPIN_32(pl->pl_sp_devid, bufpl->pl_sp_devid); ++ CPIN_32(pl->pl_sp_type, bufpl->pl_sp_type); ++ CPIN_64(pl->pl_blocks, bufpl->pl_blocks); ++ CPIN_32(pl->pl_striping, bufpl->pl_striping); ++ CPIN_32(pl->pl_sp_dmepdevs, bufpl->pl_sp_dmepdevs); ++ CPIN_32(pl->pl_sp_dmepid, bufpl->pl_sp_dmepid); ++ CPIN_32(pl->pl_sp_weight, bufpl->pl_sp_weight); ++ CPIN_32(pl->pl_minor, bufpl->pl_minor); ++ CPIN_32(pl->pl_padding, bufpl->pl_padding); ++ CPIN_8(pl->pl_reserve, bufpl->pl_reserve, 184); ++} ++ ++static char _calc_char(unsigned int id) ++{ ++ /* ++ * [0-9A-Za-z!#] - 64 printable chars (6-bits) ++ */ ++ ++ if (id < 10) ++ return id + 48; ++ if (id < 36) ++ return (id - 10) + 65; ++ if (id < 62) ++ return (id - 36) + 97; ++ if (id == 62) ++ return '!'; ++ if (id == 63) ++ return '#'; ++ ++ return '%'; ++} ++ ++void get_pool_uuid(char *uuid, uint64_t poolid, uint32_t spid, uint32_t devid) ++{ ++ int i; ++ unsigned shifter = 0x003F; ++ ++ assert(ID_LEN == 32); ++ memset(uuid, 0, ID_LEN); ++ strcat(uuid, "POOL0000000000"); ++ ++ /* We grab the entire 64 bits (+2 that get shifted in) */ ++ for (i = 13; i < 24; i++) { ++ uuid[i] = _calc_char(((unsigned) poolid) & shifter); ++ poolid = poolid >> 6; ++ } ++ ++ /* We grab the entire 32 bits (+4 that get shifted in) */ ++ for (i = 24; i < 30; i++) { ++ uuid[i] = _calc_char((unsigned) (spid & shifter)); ++ spid = spid >> 6; ++ } ++ ++ /* ++ * Since we can only have 128 devices, we only worry about the ++ * last 12 bits ++ */ ++ for (i = 30; i < 32; i++) { ++ uuid[i] = _calc_char((unsigned) (devid & shifter)); ++ devid = devid >> 6; ++ } ++ ++} ++ ++struct _read_pool_pv_baton { ++ const struct format_type *fmt; ++ struct dm_pool *mem, *tmpmem; ++ struct pool_list *pl; ++ struct dm_list *head; ++ const char *vgname; ++ uint32_t *sp_devs; ++ uint32_t sp_count; ++ int failed; ++ int empty; ++}; ++ ++static int _read_pool_pv(struct lvmcache_info *info, void *baton) ++{ ++ struct _read_pool_pv_baton *b = baton; ++ ++ b->empty = 0; ++ ++ if (lvmcache_device(info) && ++ !(b->pl = read_pool_disk(b->fmt, lvmcache_device(info), b->mem, b->vgname))) ++ return 0; ++ ++ /* ++ * We need to keep track of the total expected number ++ * of devices per subpool ++ */ ++ if (!b->sp_count) { ++ /* FIXME pl left uninitialised if !info->dev */ ++ if (!b->pl) { ++ log_error(INTERNAL_ERROR "device is missing"); ++ dm_pool_destroy(b->tmpmem); ++ b->failed = 1; ++ return 0; ++ } ++ b->sp_count = b->pl->pd.pl_subpools; ++ if (!(b->sp_devs = ++ dm_pool_zalloc(b->tmpmem, ++ sizeof(uint32_t) * b->sp_count))) { ++ log_error("Unable to allocate %d 32-bit uints", ++ b->sp_count); ++ dm_pool_destroy(b->tmpmem); ++ b->failed = 1; ++ return 0; ++ } ++ } ++ ++ /* ++ * watch out for a pool label with a different subpool ++ * count than the original - give up if it does ++ */ ++ if (b->sp_count != b->pl->pd.pl_subpools) ++ return 0; ++ ++ _add_pl_to_list(lvmcache_fmt(info)->cmd, b->head, b->pl); ++ ++ if (b->sp_count > b->pl->pd.pl_sp_id && b->sp_devs[b->pl->pd.pl_sp_id] == 0) ++ b->sp_devs[b->pl->pd.pl_sp_id] = b->pl->pd.pl_sp_devs; ++ ++ return 1; ++} ++ ++static int _read_vg_pds(struct _read_pool_pv_baton *b, ++ struct lvmcache_vginfo *vginfo, ++ uint32_t *devcount) ++{ ++ uint32_t i; ++ ++ b->sp_count = 0; ++ b->sp_devs = NULL; ++ b->failed = 0; ++ b->pl = NULL; ++ ++ /* FIXME: maybe should return a different error in memory ++ * allocation failure */ ++ if (!(b->tmpmem = dm_pool_create("pool read_vg", 512))) ++ return_0; ++ ++ lvmcache_foreach_pv(vginfo, _read_pool_pv, b); ++ ++ *devcount = 0; ++ for (i = 0; i < b->sp_count; i++) ++ *devcount += b->sp_devs[i]; ++ ++ dm_pool_destroy(b->tmpmem); ++ ++ if (b->pl && *b->pl->pd.pl_pool_name) ++ return 1; ++ ++ return 0; ++ ++} ++ ++int read_pool_pds(const struct format_type *fmt, const char *vg_name, ++ struct dm_pool *mem, struct dm_list *pdhead) ++{ ++ struct lvmcache_vginfo *vginfo; ++ uint32_t totaldevs; ++ int full_scan = -1; ++ ++ struct _read_pool_pv_baton baton; ++ ++ baton.vgname = vg_name; ++ baton.mem = mem; ++ baton.fmt = fmt; ++ baton.head = pdhead; ++ baton.empty = 1; ++ ++ do { ++ /* ++ * If the cache scanning doesn't work, this will never work ++ */ ++ if (vg_name && (vginfo = lvmcache_vginfo_from_vgname(vg_name, NULL)) && ++ _read_vg_pds(&baton, vginfo, &totaldevs) && !baton.empty) ++ { ++ /* ++ * If we found all the devices we were expecting, return ++ * success ++ */ ++ if (dm_list_size(pdhead) == totaldevs) ++ return 1; ++ ++ /* ++ * accept partial pool if we've done a full rescan of ++ * the cache ++ */ ++ if (full_scan > 0) ++ return 1; ++ } ++ ++ /* Failed */ ++ dm_list_init(pdhead); ++ ++ full_scan++; ++ if (full_scan > 1) { ++ log_debug_metadata("No devices for vg %s found in cache", ++ vg_name); ++ return 0; ++ } ++ lvmcache_label_scan(fmt->cmd); ++ ++ } while (1); ++ ++} ++ ++struct pool_list *read_pool_disk(const struct format_type *fmt, ++ struct device *dev, struct dm_pool *mem, ++ const char *vg_name) ++{ ++ struct pool_list *pl; ++ ++ if (!dev_open_readonly(dev)) ++ return_NULL; ++ ++ if (!(pl = dm_pool_zalloc(mem, sizeof(*pl)))) { ++ log_error("Unable to allocate pool list structure"); ++ return 0; ++ } ++ ++ if (!__read_pool_disk(fmt, dev, mem, pl, vg_name)) ++ return_NULL; ++ ++ if (!dev_close(dev)) ++ stack; ++ ++ return pl; ++ ++} +diff --git a/lib/format_pool/disk_rep.h b/lib/format_pool/disk_rep.h +new file mode 100644 +index 0000000..37e942e +--- /dev/null ++++ b/lib/format_pool/disk_rep.h +@@ -0,0 +1,156 @@ ++/* ++ * Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved. ++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. ++ * ++ * This file is part of LVM2. ++ * ++ * 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 Lesser General Public License v.2.1. ++ * ++ * You should have received a copy of the GNU Lesser 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 ++ */ ++ ++#ifndef DISK_REP_FORMAT_POOL_H ++#define DISK_REP_FORMAT_POOL_H ++ ++#include "label.h" ++#include "metadata.h" ++ ++#define MINOR_OFFSET 65536 ++ ++/* From NSP.cf */ ++#define NSPMajorVersion 4 ++#define NSPMinorVersion 1 ++#define NSPUpdateLevel 3 ++ ++/* From pool_std.h */ ++#define POOL_NAME_SIZE (256) ++#define POOL_MAGIC 0x011670 ++#define POOL_MAJOR (121) ++#define POOL_MAX_DEVICES 128 ++ ++/* When checking for version matching, the first two numbers ** ++** are important for metadata formats, a.k.a pool labels. ** ++** All the numbers are important when checking if the user ** ++** space tools match up with the kernel module............. */ ++#define POOL_VERSION (NSPMajorVersion << 16 | \ ++ NSPMinorVersion << 8 | \ ++ NSPUpdateLevel) ++ ++/* Pool label is at the head of every pool disk partition */ ++#define SIZEOF_POOL_LABEL (8192) ++ ++/* in sectors */ ++#define POOL_PE_SIZE (SIZEOF_POOL_LABEL >> SECTOR_SHIFT) ++#define POOL_PE_START (SIZEOF_POOL_LABEL >> SECTOR_SHIFT) ++ ++/* Helper fxns */ ++#define get_pool_vg_uuid(id, pd) do { get_pool_uuid((char *)(id), \ ++ (pd)->pl_pool_id, 0, 0); \ ++ } while(0) ++#define get_pool_pv_uuid(id, pd) do { get_pool_uuid((char *)(id), \ ++ (pd)->pl_pool_id, \ ++ (pd)->pl_sp_id, \ ++ (pd)->pl_sp_devid); \ ++ } while(0) ++#define get_pool_lv_uuid(id, pd) do { get_pool_uuid((char *)&(id)[0], \ ++ (pd)->pl_pool_id, 0, 0); \ ++ get_pool_uuid((char*)&(id)[1], \ ++ (pd)->pl_pool_id, 0, 0); \ ++ } while(0) ++ ++struct pool_disk; ++struct pool_list; ++struct user_subpool; ++struct user_device; ++ ++struct pool_disk { ++ uint64_t pl_magic; /* Pool magic number */ ++ uint64_t pl_pool_id; /* Unique pool identifier */ ++ char pl_pool_name[POOL_NAME_SIZE]; /* Name of pool */ ++ uint32_t pl_version; /* Pool version */ ++ uint32_t pl_subpools; /* Number of subpools in this pool */ ++ uint32_t pl_sp_id; /* Subpool number within pool */ ++ uint32_t pl_sp_devs; /* Number of data partitions in this subpool */ ++ uint32_t pl_sp_devid; /* Partition number within subpool */ ++ uint32_t pl_sp_type; /* Partition type */ ++ uint64_t pl_blocks; /* Number of blocks in this partition */ ++ uint32_t pl_striping; /* Striping size within subpool */ ++ /* ++ * If the number of DMEP devices is zero, then the next field ** ++ * ** (pl_sp_dmepid) becomes the subpool ID for redirection. In ** ++ * ** other words, if this subpool does not have the capability ** ++ * ** to do DMEP, then it must specify which subpool will do it ** ++ * ** in it's place ++ */ ++ ++ /* ++ * While the next 3 field are no longer used, they must stay to keep ** ++ * ** backward compatibility........................................... ++ */ ++ uint32_t pl_sp_dmepdevs;/* Number of dmep devices in this subpool */ ++ uint32_t pl_sp_dmepid; /* Dmep device number within subpool */ ++ uint32_t pl_sp_weight; /* if dmep dev, pref to using it */ ++ ++ uint32_t pl_minor; /* the pool minor number */ ++ uint32_t pl_padding; /* reminder - think about alignment */ ++ ++ /* ++ * Even though we're zeroing out 8k at the front of the disk before ++ * writing the label, putting this in ++ */ ++ char pl_reserve[184]; /* bump the structure size out to 512 bytes */ ++}; ++ ++struct pool_list { ++ struct dm_list list; ++ struct pool_disk pd; ++ struct physical_volume *pv; ++ struct id pv_uuid; ++ struct device *dev; ++}; ++ ++struct user_subpool { ++ uint32_t initialized; ++ uint32_t id; ++ uint32_t striping; ++ uint32_t num_devs; ++ uint32_t type; ++ uint32_t dummy; ++ struct user_device *devs; ++}; ++ ++struct user_device { ++ uint32_t initialized; ++ uint32_t sp_id; ++ uint32_t devid; ++ uint32_t dummy; ++ uint64_t blocks; ++ struct physical_volume *pv; ++}; ++ ++int read_pool_label(struct pool_list *pl, struct labeller *l, ++ struct device *dev, char *buf, struct label **label); ++void pool_label_out(struct pool_disk *pl, void *buf); ++void pool_label_in(struct pool_disk *pl, void *buf); ++void get_pool_uuid(char *uuid, uint64_t poolid, uint32_t spid, uint32_t devid); ++int import_pool_vg(struct volume_group *vg, struct dm_pool *mem, struct dm_list *pls); ++int import_pool_lvs(struct volume_group *vg, struct dm_pool *mem, ++ struct dm_list *pls); ++int import_pool_pvs(const struct format_type *fmt, struct volume_group *vg, ++ struct dm_pool *mem, struct dm_list *pls); ++int import_pool_pv(const struct format_type *fmt, struct dm_pool *mem, ++ struct volume_group *vg, struct physical_volume *pv, ++ struct pool_list *pl); ++int import_pool_segments(struct dm_list *lvs, struct dm_pool *mem, ++ struct user_subpool *usp, int sp_count); ++int read_pool_pds(const struct format_type *fmt, const char *vgname, ++ struct dm_pool *mem, struct dm_list *head); ++struct pool_list *read_pool_disk(const struct format_type *fmt, ++ struct device *dev, struct dm_pool *mem, ++ const char *vg_name); ++ ++#endif /* DISK_REP_POOL_FORMAT_H */ +diff --git a/lib/format_pool/format_pool.c b/lib/format_pool/format_pool.c +new file mode 100644 +index 0000000..f8223a3 +--- /dev/null ++++ b/lib/format_pool/format_pool.c +@@ -0,0 +1,337 @@ ++/* ++ * Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved. ++ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. ++ * ++ * This file is part of LVM2. ++ * ++ * 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 Lesser General Public License v.2.1. ++ * ++ * You should have received a copy of the GNU Lesser 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 ++ */ ++ ++#include "lib.h" ++#include "label.h" ++#include "metadata.h" ++#include "limits.h" ++#include "display.h" ++#include "toolcontext.h" ++#include "lvmcache.h" ++#include "disk_rep.h" ++#include "format_pool.h" ++#include "pool_label.h" ++ ++/* Must be called after pvs are imported */ ++static struct user_subpool *_build_usp(struct dm_list *pls, struct dm_pool *mem, ++ int *sps) ++{ ++ struct pool_list *pl; ++ struct user_subpool *usp = NULL, *cur_sp = NULL; ++ struct user_device *cur_dev = NULL; ++ ++ /* ++ * FIXME: Need to do some checks here - I'm tempted to add a ++ * user_pool structure and build the entire thing to check against. ++ */ ++ dm_list_iterate_items(pl, pls) { ++ *sps = pl->pd.pl_subpools; ++ if (!usp && (!(usp = dm_pool_zalloc(mem, sizeof(*usp) * (*sps))))) { ++ log_error("Unable to allocate %d subpool structures", ++ *sps); ++ return 0; ++ } ++ ++ if (cur_sp != &usp[pl->pd.pl_sp_id]) { ++ cur_sp = &usp[pl->pd.pl_sp_id]; ++ ++ cur_sp->id = pl->pd.pl_sp_id; ++ cur_sp->striping = pl->pd.pl_striping; ++ cur_sp->num_devs = pl->pd.pl_sp_devs; ++ cur_sp->type = pl->pd.pl_sp_type; ++ cur_sp->initialized = 1; ++ } ++ ++ if (!cur_sp->devs && ++ (!(cur_sp->devs = ++ dm_pool_zalloc(mem, ++ sizeof(*usp->devs) * pl->pd.pl_sp_devs)))) { ++ ++ log_error("Unable to allocate %d pool_device " ++ "structures", pl->pd.pl_sp_devs); ++ return 0; ++ } ++ ++ cur_dev = &cur_sp->devs[pl->pd.pl_sp_devid]; ++ cur_dev->sp_id = cur_sp->id; ++ cur_dev->devid = pl->pd.pl_sp_id; ++ cur_dev->blocks = pl->pd.pl_blocks; ++ cur_dev->pv = pl->pv; ++ cur_dev->initialized = 1; ++ } ++ ++ return usp; ++} ++ ++static int _check_usp(const char *vgname, struct user_subpool *usp, int sp_count) ++{ ++ int i; ++ unsigned j; ++ ++ for (i = 0; i < sp_count; i++) { ++ if (!usp[i].initialized) { ++ log_error("Missing subpool %d in pool %s", i, vgname); ++ return 0; ++ } ++ for (j = 0; j < usp[i].num_devs; j++) { ++ if (!usp[i].devs[j].initialized) { ++ log_error("Missing device %u for subpool %d" ++ " in pool %s", j, i, vgname); ++ return 0; ++ } ++ ++ } ++ } ++ ++ return 1; ++} ++ ++static struct volume_group *_pool_vg_read(struct format_instance *fid, ++ const char *vg_name, ++ struct metadata_area *mda __attribute__((unused)), ++ struct cached_vg_fmtdata **vg_fmtdata __attribute__((unused)), ++ unsigned *use_previous_vg __attribute__((unused))) ++{ ++ struct volume_group *vg; ++ struct user_subpool *usp; ++ int sp_count; ++ DM_LIST_INIT(pds); ++ ++ /* We can safely ignore the mda passed in */ ++ ++ /* Strip dev_dir if present */ ++ if (vg_name) ++ vg_name = strip_dir(vg_name, fid->fmt->cmd->dev_dir); ++ ++ /* Set vg_name through read_pool_pds() */ ++ if (!(vg = alloc_vg("pool_vg_read", fid->fmt->cmd, NULL))) ++ return_NULL; ++ ++ /* Read all the pvs in the vg */ ++ if (!read_pool_pds(fid->fmt, vg_name, vg->vgmem, &pds)) ++ goto_bad; ++ ++ /* Setting pool seqno to 1 because the code always did this, ++ * although we don't think it's needed. */ ++ vg->seqno = 1; ++ ++ if (!import_pool_vg(vg, vg->vgmem, &pds)) ++ goto_bad; ++ ++ if (!import_pool_pvs(fid->fmt, vg, vg->vgmem, &pds)) ++ goto_bad; ++ ++ if (!import_pool_lvs(vg, vg->vgmem, &pds)) ++ goto_bad; ++ ++ /* ++ * I need an intermediate subpool structure that contains all the ++ * relevant info for this. Then i can iterate through the subpool ++ * structures for checking, and create the segments ++ */ ++ if (!(usp = _build_usp(&pds, vg->vgmem, &sp_count))) ++ goto_bad; ++ ++ /* ++ * check the subpool structures - we can't handle partial VGs in ++ * the pool format, so this will error out if we're missing PVs ++ */ ++ if (!_check_usp(vg->name, usp, sp_count)) ++ goto_bad; ++ ++ if (!import_pool_segments(&vg->lvs, vg->vgmem, usp, sp_count)) ++ goto_bad; ++ ++ vg_set_fid(vg, fid); ++ ++ return vg; ++ ++bad: ++ release_vg(vg); ++ ++ return NULL; ++} ++ ++static int _pool_pv_initialise(const struct format_type *fmt __attribute__((unused)), ++ struct pv_create_args *pva __attribute__((unused)), ++ struct physical_volume *pv __attribute__((unused))) ++{ ++ return 1; ++} ++ ++static int _pool_pv_setup(const struct format_type *fmt __attribute__((unused)), ++ struct physical_volume *pv __attribute__((unused)), ++ struct volume_group *vg __attribute__((unused))) ++{ ++ return 1; ++} ++ ++static int _pool_pv_read(const struct format_type *fmt, const char *pv_name, ++ struct physical_volume *pv, ++ int scan_label_only __attribute__((unused))) ++{ ++ struct dm_pool *mem = dm_pool_create("pool pv_read", 1024); ++ struct pool_list *pl; ++ struct device *dev; ++ int r = 0; ++ ++ log_very_verbose("Reading physical volume data %s from disk", pv_name); ++ ++ if (!mem) ++ return_0; ++ ++ if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter))) ++ goto_out; ++ ++ /* ++ * I need to read the disk and populate a pv structure here ++ * I'll probably need to abstract some of this later for the ++ * vg_read code ++ */ ++ if (!(pl = read_pool_disk(fmt, dev, mem, NULL))) ++ goto_out; ++ ++ if (!import_pool_pv(fmt, fmt->cmd->mem, NULL, pv, pl)) ++ goto_out; ++ ++ pv->fmt = fmt; ++ ++ r = 1; ++ ++ out: ++ dm_pool_destroy(mem); ++ return r; ++} ++ ++/* *INDENT-OFF* */ ++static struct metadata_area_ops _metadata_format_pool_ops = { ++ .vg_read = _pool_vg_read, ++}; ++/* *INDENT-ON* */ ++ ++static struct format_instance *_pool_create_instance(const struct format_type *fmt, ++ const struct format_instance_ctx *fic) ++{ ++ struct format_instance *fid; ++ struct metadata_area *mda; ++ ++ if (!(fid = alloc_fid(fmt, fic))) ++ return_NULL; ++ ++ /* Define a NULL metadata area */ ++ if (!(mda = dm_pool_zalloc(fid->mem, sizeof(*mda)))) { ++ log_error("Unable to allocate metadata area structure " ++ "for pool format"); ++ goto bad; ++ } ++ ++ mda->ops = &_metadata_format_pool_ops; ++ mda->metadata_locn = NULL; ++ mda->status = 0; ++ dm_list_add(&fid->metadata_areas_in_use, &mda->list); ++ ++ return fid; ++ ++bad: ++ dm_pool_destroy(fid->mem); ++ return NULL; ++} ++ ++static void _pool_destroy_instance(struct format_instance *fid) ++{ ++ if (--fid->ref_count <= 1) ++ dm_pool_destroy(fid->mem); ++} ++ ++static void _pool_destroy(struct format_type *fmt) ++{ ++ if (fmt->orphan_vg) ++ free_orphan_vg(fmt->orphan_vg); ++ ++ dm_free(fmt); ++} ++ ++/* *INDENT-OFF* */ ++static struct format_handler _format_pool_ops = { ++ .pv_read = _pool_pv_read, ++ .pv_initialise = _pool_pv_initialise, ++ .pv_setup = _pool_pv_setup, ++ .create_instance = _pool_create_instance, ++ .destroy_instance = _pool_destroy_instance, ++ .destroy = _pool_destroy, ++}; ++/* *INDENT-ON */ ++ ++#ifdef POOL_INTERNAL ++struct format_type *init_pool_format(struct cmd_context *cmd) ++#else /* Shared */ ++struct format_type *init_format(struct cmd_context *cmd); ++struct format_type *init_format(struct cmd_context *cmd) ++#endif ++{ ++ struct format_type *fmt = dm_malloc(sizeof(*fmt)); ++ struct format_instance_ctx fic; ++ struct format_instance *fid; ++ ++ if (!fmt) { ++ log_error("Unable to allocate format type structure for pool " ++ "format"); ++ return NULL; ++ } ++ ++ fmt->cmd = cmd; ++ fmt->ops = &_format_pool_ops; ++ fmt->name = FMT_POOL_NAME; ++ fmt->alias = NULL; ++ fmt->orphan_vg_name = FMT_POOL_ORPHAN_VG_NAME; ++ fmt->features = FMT_OBSOLETE; ++ fmt->private = NULL; ++ ++ dm_list_init(&fmt->mda_ops); ++ ++ if (!(fmt->labeller = pool_labeller_create(fmt))) { ++ log_error("Couldn't create pool label handler."); ++ dm_free(fmt); ++ return NULL; ++ } ++ ++ if (!(label_register_handler(fmt->labeller))) { ++ log_error("Couldn't register pool label handler."); ++ fmt->labeller->ops->destroy(fmt->labeller); ++ dm_free(fmt); ++ return NULL; ++ } ++ ++ if (!(fmt->orphan_vg = alloc_vg("pool_orphan", cmd, fmt->orphan_vg_name))) { ++ log_error("Couldn't create pool orphan VG."); ++ dm_free(fmt); ++ return NULL; ++ } ++ ++ fic.type = FMT_INSTANCE_AUX_MDAS; ++ fic.context.vg_ref.vg_name = fmt->orphan_vg_name; ++ fic.context.vg_ref.vg_id = NULL; ++ ++ if (!(fid = _pool_create_instance(fmt, &fic))) { ++ _pool_destroy(fmt); ++ return NULL; ++ } ++ ++ vg_set_fid(fmt->orphan_vg, fid); ++ ++ log_very_verbose("Initialised format: %s", fmt->name); ++ ++ return fmt; ++} +diff --git a/lib/format_pool/format_pool.h b/lib/format_pool/format_pool.h +new file mode 100644 +index 0000000..8ad7eb5 +--- /dev/null ++++ b/lib/format_pool/format_pool.h +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved. ++ * Copyright (C) 2004 Red Hat, Inc. All rights reserved. ++ * ++ * This file is part of LVM2. ++ * ++ * 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 Lesser General Public License v.2.1. ++ * ++ * You should have received a copy of the GNU Lesser 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 ++ */ ++ ++#ifndef _LVM_FORMAT_POOL_H ++#define _LVM_FORMAT_POOL_H ++ ++#include "metadata.h" ++ ++#define FMT_POOL_NAME "pool" ++#define FMT_POOL_ORPHAN_VG_NAME ORPHAN_VG_NAME(FMT_POOL_NAME) ++ ++#ifdef POOL_INTERNAL ++struct format_type *init_pool_format(struct cmd_context *cmd); ++#endif ++ ++#endif +diff --git a/lib/format_pool/import_export.c b/lib/format_pool/import_export.c +new file mode 100644 +index 0000000..f4097a7 +--- /dev/null ++++ b/lib/format_pool/import_export.c +@@ -0,0 +1,285 @@ ++/* ++ * Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved. ++ * Copyright (C) 2004-2017 Red Hat, Inc. All rights reserved. ++ * ++ * This file is part of LVM2. ++ * ++ * 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 Lesser General Public License v.2.1. ++ * ++ * You should have received a copy of the GNU Lesser 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 ++ */ ++ ++#include "lib.h" ++#include "label.h" ++#include "metadata.h" ++#include "disk_rep.h" ++#include "sptype_names.h" ++#include "lv_alloc.h" ++#include "pv_alloc.h" ++#include "str_list.h" ++#include "display.h" ++#include "segtype.h" ++#include "toolcontext.h" ++ ++/* This file contains only imports at the moment... */ ++ ++int import_pool_vg(struct volume_group *vg, struct dm_pool *mem, struct dm_list *pls) ++{ ++ struct pool_list *pl; ++ ++ dm_list_iterate_items(pl, pls) { ++ vg->extent_count += ++ ((pl->pd.pl_blocks) / POOL_PE_SIZE); ++ ++ vg->free_count = vg->extent_count; ++ ++ if (vg->name) ++ continue; ++ ++ vg->name = dm_pool_strdup(mem, pl->pd.pl_pool_name); ++ get_pool_vg_uuid(&vg->id, &pl->pd); ++ vg->extent_size = POOL_PE_SIZE; ++ vg->status |= LVM_READ | LVM_WRITE | CLUSTERED | SHARED; ++ vg->max_lv = 1; ++ vg->max_pv = POOL_MAX_DEVICES; ++ vg->alloc = ALLOC_NORMAL; ++ } ++ ++ return 1; ++} ++ ++int import_pool_lvs(struct volume_group *vg, struct dm_pool *mem, struct dm_list *pls) ++{ ++ struct pool_list *pl; ++ struct logical_volume *lv; ++ ++ if (!(lv = alloc_lv(mem))) ++ return_0; ++ ++ lv->status = 0; ++ lv->alloc = ALLOC_NORMAL; ++ lv->size = 0; ++ lv->name = NULL; ++ lv->le_count = 0; ++ lv->read_ahead = vg->cmd->default_settings.read_ahead; ++ ++ dm_list_iterate_items(pl, pls) { ++ lv->size += pl->pd.pl_blocks; ++ ++ if (lv->name) ++ continue; ++ ++ if (!(lv->name = dm_pool_strdup(mem, pl->pd.pl_pool_name))) ++ return_0; ++ ++ get_pool_lv_uuid(lv->lvid.id, &pl->pd); ++ log_debug_metadata("Calculated lv uuid for lv %s: %s", lv->name, ++ lv->lvid.s); ++ ++ lv->status |= VISIBLE_LV | LVM_READ | LVM_WRITE; ++ lv->major = POOL_MAJOR; ++ ++ /* for pool a minor of 0 is dynamic */ ++ if (pl->pd.pl_minor) { ++ lv->status |= FIXED_MINOR; ++ lv->minor = pl->pd.pl_minor + MINOR_OFFSET; ++ } else { ++ lv->minor = -1; ++ } ++ } ++ ++ lv->le_count = lv->size / POOL_PE_SIZE; ++ ++ return link_lv_to_vg(vg, lv); ++} ++ ++int import_pool_pvs(const struct format_type *fmt, struct volume_group *vg, ++ struct dm_pool *mem, struct dm_list *pls) ++{ ++ struct pv_list *pvl; ++ struct pool_list *pl; ++ ++ dm_list_iterate_items(pl, pls) { ++ if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl)))) { ++ log_error("Unable to allocate pv list structure"); ++ return 0; ++ } ++ if (!(pvl->pv = dm_pool_zalloc(mem, sizeof(*pvl->pv)))) { ++ log_error("Unable to allocate pv structure"); ++ return 0; ++ } ++ if (!import_pool_pv(fmt, mem, vg, pvl->pv, pl)) { ++ return 0; ++ } ++ pl->pv = pvl->pv; ++ pvl->mdas = NULL; ++ pvl->pe_ranges = NULL; ++ add_pvl_to_vgs(vg, pvl); ++ } ++ ++ return 1; ++} ++ ++int import_pool_pv(const struct format_type *fmt, struct dm_pool *mem, ++ struct volume_group *vg, struct physical_volume *pv, ++ struct pool_list *pl) ++{ ++ struct pool_disk *pd = &pl->pd; ++ ++ memset(pv, 0, sizeof(*pv)); ++ ++ get_pool_pv_uuid(&pv->id, pd); ++ pv->fmt = fmt; ++ ++ pv->dev = pl->dev; ++ if (!(pv->vg_name = dm_pool_strdup(mem, pd->pl_pool_name))) { ++ log_error("Unable to duplicate vg_name string"); ++ return 0; ++ } ++ if (vg != NULL) ++ memcpy(&pv->vgid, &vg->id, sizeof(vg->id)); ++ pv->status = 0; ++ pv->size = pd->pl_blocks; ++ pv->pe_size = POOL_PE_SIZE; ++ pv->pe_start = POOL_PE_START; ++ pv->pe_count = pv->size / POOL_PE_SIZE; ++ pv->pe_alloc_count = 0; ++ pv->pe_align = 0; ++ ++ dm_list_init(&pv->tags); ++ dm_list_init(&pv->segments); ++ ++ if (!alloc_pv_segment_whole_pv(mem, pv)) ++ return_0; ++ ++ return 1; ++} ++ ++static const char *_cvt_sptype(uint32_t sptype) ++{ ++ int i; ++ for (i = 0; sptype_names[i].name[0]; i++) { ++ if (sptype == sptype_names[i].label) { ++ break; ++ } ++ } ++ log_debug_metadata("Found sptype %X and converted it to %s", ++ sptype, sptype_names[i].name); ++ return sptype_names[i].name; ++} ++ ++static int _add_stripe_seg(struct dm_pool *mem, ++ struct user_subpool *usp, struct logical_volume *lv, ++ uint32_t *le_cur) ++{ ++ struct lv_segment *seg; ++ struct segment_type *segtype; ++ unsigned j; ++ uint32_t area_len; ++ ++ if (!is_power_of_2(usp->striping)) { ++ log_error("Stripe size must be a power of 2"); ++ return 0; ++ } ++ ++ area_len = (usp->devs[0].blocks) / POOL_PE_SIZE; ++ ++ if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED))) ++ return_0; ++ ++ if (!(seg = alloc_lv_segment(segtype, lv, *le_cur, ++ area_len * usp->num_devs, 0, 0, ++ usp->striping, NULL, usp->num_devs, ++ area_len, 0, 0, 0, 0, NULL))) { ++ log_error("Unable to allocate striped lv_segment structure"); ++ return 0; ++ } ++ ++ for (j = 0; j < usp->num_devs; j++) ++ if (!set_lv_segment_area_pv(seg, j, usp->devs[j].pv, 0)) ++ return_0; ++ ++ /* add the subpool type to the segment tag list */ ++ if (!str_list_add(mem, &seg->tags, _cvt_sptype(usp->type))) { ++ log_error("Allocation failed for str_list."); ++ return 0; ++ } ++ ++ dm_list_add(&lv->segments, &seg->list); ++ ++ *le_cur += seg->len; ++ ++ return 1; ++} ++ ++static int _add_linear_seg(struct dm_pool *mem, ++ struct user_subpool *usp, struct logical_volume *lv, ++ uint32_t *le_cur) ++{ ++ struct lv_segment *seg; ++ struct segment_type *segtype; ++ unsigned j; ++ uint32_t area_len; ++ ++ if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED))) ++ return_0; ++ ++ for (j = 0; j < usp->num_devs; j++) { ++ area_len = (usp->devs[j].blocks) / POOL_PE_SIZE; ++ ++ if (!(seg = alloc_lv_segment(segtype, lv, *le_cur, ++ area_len, 0, 0, usp->striping, ++ NULL, 1, area_len, 0, ++ POOL_PE_SIZE, 0, 0, NULL))) { ++ log_error("Unable to allocate linear lv_segment " ++ "structure"); ++ return 0; ++ } ++ ++ /* add the subpool type to the segment tag list */ ++ if (!str_list_add(mem, &seg->tags, _cvt_sptype(usp->type))) { ++ log_error("Allocation failed for str_list."); ++ return 0; ++ } ++ ++ if (!set_lv_segment_area_pv(seg, 0, usp->devs[j].pv, 0)) ++ return_0; ++ dm_list_add(&lv->segments, &seg->list); ++ ++ *le_cur += seg->len; ++ } ++ ++ return 1; ++} ++ ++int import_pool_segments(struct dm_list *lvs, struct dm_pool *mem, ++ struct user_subpool *usp, int subpools) ++{ ++ struct lv_list *lvl; ++ struct logical_volume *lv; ++ uint32_t le_cur = 0; ++ int i; ++ ++ dm_list_iterate_items(lvl, lvs) { ++ lv = lvl->lv; ++ ++ if (lv_is_snapshot(lv)) ++ continue; ++ ++ for (i = 0; i < subpools; i++) { ++ if (usp[i].striping) { ++ if (!_add_stripe_seg(mem, &usp[i], lv, &le_cur)) ++ return_0; ++ } else { ++ if (!_add_linear_seg(mem, &usp[i], lv, &le_cur)) ++ return_0; ++ } ++ } ++ } ++ ++ return 1; ++} +diff --git a/lib/format_pool/pool_label.c b/lib/format_pool/pool_label.c +new file mode 100644 +index 0000000..2e30a7b +--- /dev/null ++++ b/lib/format_pool/pool_label.c +@@ -0,0 +1,104 @@ ++/* ++ * Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved. ++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. ++ * ++ * This file is part of LVM2. ++ * ++ * 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 Lesser General Public License v.2.1. ++ * ++ * You should have received a copy of the GNU Lesser 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 ++ */ ++ ++#include "lib.h" ++#include "label.h" ++#include "metadata.h" ++#include "disk_rep.h" ++#include "pool_label.h" ++ ++#include ++#include ++ ++static void _pool_not_supported(const char *op) ++{ ++ log_error("The '%s' operation is not supported for the pool labeller.", ++ op); ++} ++ ++static int _pool_can_handle(struct labeller *l __attribute__((unused)), void *buf, uint64_t sector) ++{ ++ ++ struct pool_disk pd; ++ ++ /* ++ * POOL label must always be in first sector ++ */ ++ if (sector) ++ return 0; ++ ++ pool_label_in(&pd, buf); ++ ++ /* can ignore 8 rightmost bits for ondisk format check */ ++ if ((pd.pl_magic == POOL_MAGIC) && ++ (pd.pl_version >> 8 == POOL_VERSION >> 8)) ++ return 1; ++ ++ return 0; ++} ++ ++static int _pool_write(struct label *label __attribute__((unused)), void *buf __attribute__((unused))) ++{ ++ _pool_not_supported("write"); ++ return 0; ++} ++ ++static int _pool_read(struct labeller *l, struct device *dev, void *buf, ++ struct label **label) ++{ ++ struct pool_list pl; ++ ++ return read_pool_label(&pl, l, dev, buf, label); ++} ++ ++static int _pool_initialise_label(struct labeller *l __attribute__((unused)), struct label *label) ++{ ++ strcpy(label->type, "POOL"); ++ ++ return 1; ++} ++ ++static void _pool_destroy_label(struct labeller *l __attribute__((unused)), struct label *label __attribute__((unused))) ++{ ++} ++ ++static void _label_pool_destroy(struct labeller *l) ++{ ++ dm_free(l); ++} ++ ++struct label_ops _pool_ops = { ++ .can_handle = _pool_can_handle, ++ .write = _pool_write, ++ .read = _pool_read, ++ .initialise_label = _pool_initialise_label, ++ .destroy_label = _pool_destroy_label, ++ .destroy = _label_pool_destroy, ++}; ++ ++struct labeller *pool_labeller_create(struct format_type *fmt) ++{ ++ struct labeller *l; ++ ++ if (!(l = dm_malloc(sizeof(*l)))) { ++ log_error("Couldn't allocate labeller object."); ++ return NULL; ++ } ++ ++ l->ops = &_pool_ops; ++ l->fmt = fmt; ++ ++ return l; ++} +diff --git a/lib/format_pool/pool_label.h b/lib/format_pool/pool_label.h +new file mode 100644 +index 0000000..1a529a4 +--- /dev/null ++++ b/lib/format_pool/pool_label.h +@@ -0,0 +1,23 @@ ++/* ++ * Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved. ++ * Copyright (C) 2004 Red Hat, Inc. All rights reserved. ++ * ++ * This file is part of LVM2. ++ * ++ * 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 Lesser General Public License v.2.1. ++ * ++ * You should have received a copy of the GNU Lesser 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 ++ */ ++ ++#ifndef _LVM_POOL_LABEL_H ++#define _LVM_POOL_LABEL_H ++ ++#include "metadata.h" ++ ++struct labeller *pool_labeller_create(struct format_type *fmt); ++ ++#endif +diff --git a/lib/format_pool/sptype_names.h b/lib/format_pool/sptype_names.h +new file mode 100644 +index 0000000..5812adb +--- /dev/null ++++ b/lib/format_pool/sptype_names.h +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved. ++ * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. ++ * ++ * This file is part of LVM2. ++ * ++ * 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 Lesser General Public License v.2.1. ++ * ++ * You should have received a copy of the GNU Lesser 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 ++ */ ++ ++#ifndef SPTYPE_NAMES_H ++#define SPTYPE_NAMES_H ++ ++/* This must be kept up to date with sistina/pool/module/pool_sptypes.h */ ++ ++/* Generic Labels */ ++#define SPTYPE_DATA (0x00000000) ++ ++/* GFS specific labels */ ++#define SPTYPE_GFS_DATA (0x68011670) ++#define SPTYPE_GFS_JOURNAL (0x69011670) ++ ++struct sptype_name { ++ const char *name; ++ uint32_t label; ++}; ++ ++static const struct sptype_name sptype_names[] = { ++ {"data", SPTYPE_DATA}, ++ ++ {"gfs_data", SPTYPE_GFS_DATA}, ++ {"gfs_journal", SPTYPE_GFS_JOURNAL}, ++ ++ {"", 0x0} /* This must be the last flag. */ ++}; ++ ++#endif +diff --git a/lib/format_text/export.c b/lib/format_text/export.c +index 7866d56..e535237 100644 +--- a/lib/format_text/export.c ++++ b/lib/format_text/export.c +@@ -467,6 +467,8 @@ static int _print_vg(struct formatter *f, struct volume_group *vg) + + if (vg->system_id && *vg->system_id) + outf(f, "system_id = \"%s\"", vg->system_id); ++ else if (vg->lvm1_system_id && *vg->lvm1_system_id) ++ outf(f, "system_id = \"%s\"", vg->lvm1_system_id); + + if (vg->lock_type) { + outf(f, "lock_type = \"%s\"", vg->lock_type); +diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c +index 5c7b72f..792d75a 100644 +--- a/lib/format_text/format-text.c ++++ b/lib/format_text/format-text.c +@@ -2545,9 +2545,9 @@ struct format_type *create_text_format(struct cmd_context *cmd) + fmt->name = FMT_TEXT_NAME; + fmt->alias = FMT_TEXT_ALIAS; + fmt->orphan_vg_name = ORPHAN_VG_NAME(FMT_TEXT_NAME); +- fmt->features = FMT_SEGMENTS | FMT_TAGS | FMT_PRECOMMIT | ++ fmt->features = FMT_SEGMENTS | FMT_MDAS | FMT_TAGS | FMT_PRECOMMIT | + FMT_UNLIMITED_VOLS | FMT_RESIZE_PV | +- FMT_UNLIMITED_STRIPESIZE | FMT_CONFIG_PROFILE | ++ FMT_UNLIMITED_STRIPESIZE | FMT_BAS | FMT_CONFIG_PROFILE | + FMT_NON_POWER2_EXTENTS | FMT_PV_FLAGS; + + if (!(mda_lists = dm_malloc(sizeof(struct mda_lists)))) { +diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c +index 58f517e..e038a27 100644 +--- a/lib/format_text/import_vsn1.c ++++ b/lib/format_text/import_vsn1.c +@@ -1084,8 +1084,15 @@ static struct volume_group *_read_vg(struct format_instance *fid, + goto bad; + } + ++ /* ++ * A system id without WRITE_LOCKED is an old lvm1 system id. ++ */ + if (dm_config_get_str(vgn, "system_id", &system_id)) { +- if (!(vg->system_id = dm_pool_strdup(vg->vgmem, system_id))) { ++ if (!(vgstatus & LVM_WRITE_LOCKED)) { ++ if (!(vg->lvm1_system_id = dm_pool_zalloc(vg->vgmem, NAME_LEN + 1))) ++ goto_bad; ++ strncpy(vg->lvm1_system_id, system_id, NAME_LEN); ++ } else if (!(vg->system_id = dm_pool_strdup(vg->vgmem, system_id))) { + log_error("Failed to allocate memory for system_id in _read_vg."); + goto bad; + } +diff --git a/lib/locking/locking.c b/lib/locking/locking.c +index 2584227..2b53553 100644 +--- a/lib/locking/locking.c ++++ b/lib/locking/locking.c +@@ -221,6 +221,42 @@ void fin_locking(void) + } + + /* ++ * Does the LVM1 driver know of this VG name? ++ */ ++int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname) ++{ ++ struct stat info; ++ char path[PATH_MAX]; ++ ++ /* We'll allow operations on orphans */ ++ if (!is_real_vg(vgname)) ++ return 1; ++ ++ /* LVM1 is only present in 2.4 kernels. */ ++ if (strncmp(cmd->kernel_vsn, "2.4.", 4)) ++ return 1; ++ ++ if (dm_snprintf(path, sizeof(path), "%s/lvm/VGs/%s", cmd->proc_dir, ++ vgname) < 0) { ++ log_error("LVM1 proc VG pathname too long for %s", vgname); ++ return 0; ++ } ++ ++ if (stat(path, &info) == 0) { ++ log_error("%s exists: Is the original LVM driver using " ++ "this volume group?", path); ++ return 0; ++ } ++ ++ if (errno != ENOENT && errno != ENOTDIR) { ++ log_sys_error("stat", path); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++/* + * VG locking is by VG name. + * FIXME This should become VG uuid. + */ +@@ -332,6 +368,10 @@ int lock_vol(struct cmd_context *cmd, const char *vol, uint32_t flags, const str + lvmcache_drop_metadata(vol, 0); + } + ++ /* Lock VG to change on-disk metadata. */ ++ /* If LVM1 driver knows about the VG, it can't be accessed. */ ++ if (!check_lvm1_vg_inactive(cmd, vol)) ++ return_0; + break; + case LCK_LV: + /* All LV locks are non-blocking. */ +diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c +index e4293cc..1c6dc62 100644 +--- a/lib/metadata/lv_manip.c ++++ b/lib/metadata/lv_manip.c +@@ -5981,6 +5981,8 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv, + force_t force, int suppress_remove_message) + { + struct volume_group *vg; ++ struct logical_volume *format1_origin = NULL; ++ int format1_reload_required = 0; + int visible, historical; + struct logical_volume *pool_lv = NULL; + struct logical_volume *lock_lv = lv; +@@ -6133,6 +6135,10 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv, + } + + if (lv_is_cow(lv)) { ++ /* Old format1 code */ ++ if (!(lv->vg->fid->fmt->features & FMT_MDAS)) ++ format1_origin = origin_from_cow(lv); ++ + log_verbose("Removing snapshot volume %s.", display_lvname(lv)); + /* vg_remove_snapshot() will preload origin/former snapshots */ + if (!vg_remove_snapshot(lv)) +@@ -6188,10 +6194,30 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv, + } + } + ++ /* ++ * Old format1 code: If no snapshots left reload without -real. ++ */ ++ if (format1_origin && !lv_is_origin(format1_origin)) { ++ log_warn("WARNING: Support for snapshots with old LVM1-style metadata is deprecated."); ++ log_warn("WARNING: Please use lvconvert to update to lvm2 metadata at your convenience."); ++ format1_reload_required = 1; ++ } ++ + /* store it on disks */ + if (!vg_write(vg) || !vg_commit(vg)) + return_0; + ++ /* format1 */ ++ if (format1_reload_required) { ++ if (!suspend_lv(cmd, format1_origin)) ++ log_error("Failed to refresh %s without snapshot.", format1_origin->name); ++ ++ if (!resume_lv(cmd, format1_origin)) { ++ log_error("Failed to resume %s.", format1_origin->name); ++ return 0; ++ } ++ } ++ + /* Release unneeded blocks in thin pool */ + /* TODO: defer when multiple LVs relased at once */ + if (pool_lv && !update_pool_lv(pool_lv, 1)) { +diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h +index f4fb112..377644b 100644 +--- a/lib/metadata/metadata-exported.h ++++ b/lib/metadata/metadata-exported.h +@@ -149,7 +149,7 @@ + + /* Format features flags */ + #define FMT_SEGMENTS 0x00000001U /* Arbitrary segment params? */ +-// #define FMT_MDAS 0x00000002U /* Proper metadata areas? */ ++#define FMT_MDAS 0x00000002U /* Proper metadata areas? */ + #define FMT_TAGS 0x00000004U /* Tagging? */ + #define FMT_UNLIMITED_VOLS 0x00000008U /* Unlimited PVs/LVs? */ + #define FMT_RESTRICTED_LVIDS 0x00000010U /* LVID <= 255 */ +@@ -158,13 +158,15 @@ + #define FMT_RESIZE_PV 0x00000080U /* Supports pvresize? */ + #define FMT_UNLIMITED_STRIPESIZE 0x00000100U /* Unlimited stripe size? */ + #define FMT_RESTRICTED_READAHEAD 0x00000200U /* Readahead restricted to 2-120? */ +-// #define FMT_BAS 0x000000400U /* Supports bootloader areas? */ ++#define FMT_BAS 0x000000400U /* Supports bootloader areas? */ + #define FMT_CONFIG_PROFILE 0x000000800U /* Supports configuration profiles? */ +-// #define FMT_OBSOLETE 0x000001000U /* Obsolete format? */ ++#define FMT_OBSOLETE 0x000001000U /* Obsolete format? */ + #define FMT_NON_POWER2_EXTENTS 0x000002000U /* Non-power-of-2 extent sizes? */ +-// #define FMT_SYSTEMID_ON_PVS 0x000004000U /* System ID is stored on PVs not VG */ ++#define FMT_SYSTEMID_ON_PVS 0x000004000U /* System ID is stored on PVs not VG */ + #define FMT_PV_FLAGS 0x000008000U /* Supports PV flags */ + ++#define systemid_on_pvs(vg) ((vg)->fid->fmt->features & FMT_SYSTEMID_ON_PVS) ++ + /* Mirror conversion type flags */ + #define MIRROR_BY_SEG 0x00000001U /* segment-by-segment mirror */ + #define MIRROR_BY_LV 0x00000002U /* mirror using whole mimage LVs */ +diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c +index 2292568..e33a779 100644 +--- a/lib/metadata/metadata.c ++++ b/lib/metadata/metadata.c +@@ -1011,6 +1011,8 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name) + + vg->status = (RESIZEABLE_VG | LVM_READ | LVM_WRITE); + vg->system_id = NULL; ++ if (!(vg->lvm1_system_id = dm_pool_zalloc(vg->vgmem, NAME_LEN + 1))) ++ goto_bad; + + vg->extent_size = DEFAULT_EXTENT_SIZE * 2; + vg->max_lv = DEFAULT_MAX_LV; +@@ -2971,7 +2973,7 @@ int vg_write(struct volume_group *vg) + return 0; + } + +- if (!_vg_adjust_ignored_mdas(vg)) ++ if ((vg->fid->fmt->features & FMT_MDAS) && !_vg_adjust_ignored_mdas(vg)) + return_0; + + if (!vg_mda_used_count(vg)) { +@@ -5375,6 +5377,15 @@ int is_system_id_allowed(struct cmd_context *cmd, const char *system_id) + static int _access_vg_systemid(struct cmd_context *cmd, struct volume_group *vg) + { + /* ++ * LVM1 VGs must not be accessed if a new-style LVM2 system ID is set. ++ */ ++ if (cmd->system_id && systemid_on_pvs(vg)) { ++ log_error("Cannot access VG %s with LVM1 system ID %s when host system ID is set.", ++ vg->name, vg->lvm1_system_id); ++ return 0; ++ } ++ ++ /* + * A few commands allow read-only access to foreign VGs. + */ + if (cmd->include_foreign_vgs) +@@ -5426,6 +5437,11 @@ static int _vg_access_permitted(struct cmd_context *cmd, struct volume_group *vg + uint32_t lockd_state, uint32_t *failure) + { + if (!is_real_vg(vg->name)) { ++ /* Disallow use of LVM1 orphans when a host system ID is set. */ ++ if (cmd->system_id && *cmd->system_id && systemid_on_pvs(vg)) { ++ *failure |= FAILED_SYSTEMID; ++ return_0; ++ } + return 1; + } + +diff --git a/lib/metadata/segtype.h b/lib/metadata/segtype.h +index 9c05836..309a246 100644 +--- a/lib/metadata/segtype.h ++++ b/lib/metadata/segtype.h +@@ -32,7 +32,7 @@ struct dev_manager; + #define SEG_AREAS_STRIPED (1ULL << 1) + #define SEG_AREAS_MIRRORED (1ULL << 2) + #define SEG_SNAPSHOT (1ULL << 3) +-/* #define SEG_FORMAT1_SUPPORT (1ULL << 4) */ ++#define SEG_FORMAT1_SUPPORT (1ULL << 4) + #define SEG_VIRTUAL (1ULL << 5) + #define SEG_CANNOT_BE_ZEROED (1ULL << 6) + #define SEG_MONITORED (1ULL << 7) +diff --git a/lib/metadata/snapshot_manip.c b/lib/metadata/snapshot_manip.c +index 76d78f3..8357ea0 100644 +--- a/lib/metadata/snapshot_manip.c ++++ b/lib/metadata/snapshot_manip.c +@@ -332,6 +332,17 @@ int vg_remove_snapshot(struct logical_volume *cow) + cow->snapshot = NULL; + lv_set_visible(cow); + ++ /* format1 must do the change in one step, with the commit last. */ ++ if (!(origin->vg->fid->fmt->features & FMT_MDAS)) { ++ /* Get the lock for COW volume */ ++ if (is_origin_active && !activate_lv(cow->vg->cmd, cow)) { ++ log_error("Unable to activate logical volume \"%s\"", ++ cow->name); ++ return 0; ++ } ++ return 1; ++ } ++ + if (!vg_write(origin->vg)) + return_0; + +diff --git a/lib/metadata/vg.c b/lib/metadata/vg.c +index b8b1501..1020a67 100644 +--- a/lib/metadata/vg.c ++++ b/lib/metadata/vg.c +@@ -42,6 +42,12 @@ struct volume_group *alloc_vg(const char *pool_name, struct cmd_context *cmd, + return NULL; + } + ++ if (!(vg->lvm1_system_id = dm_pool_zalloc(vgmem, NAME_LEN + 1))) { ++ log_error("Failed to allocate VG systemd id."); ++ dm_pool_destroy(vgmem); ++ return NULL; ++ } ++ + vg->system_id = ""; + + vg->cmd = cmd; +@@ -172,7 +178,7 @@ char *vg_name_dup(const struct volume_group *vg) + + char *vg_system_id_dup(const struct volume_group *vg) + { +- return dm_pool_strdup(vg->vgmem, vg->system_id ? : ""); ++ return dm_pool_strdup(vg->vgmem, vg->system_id ? : vg->lvm1_system_id ? : ""); + } + + char *vg_lock_type_dup(const struct volume_group *vg) +@@ -671,11 +677,20 @@ int vg_set_system_id(struct volume_group *vg, const char *system_id) + return 1; + } + ++ if (systemid_on_pvs(vg)) { ++ log_error("Metadata format %s does not support this type of system ID.", ++ vg->fid->fmt->name); ++ return 0; ++ } ++ + if (!(vg->system_id = dm_pool_strdup(vg->vgmem, system_id))) { + log_error("Failed to allocate memory for system_id in vg_set_system_id."); + return 0; + } + ++ if (vg->lvm1_system_id) ++ *vg->lvm1_system_id = '\0'; ++ + return 1; + } + +diff --git a/lib/metadata/vg.h b/lib/metadata/vg.h +index 7ecfafe..29d88f8 100644 +--- a/lib/metadata/vg.h ++++ b/lib/metadata/vg.h +@@ -70,6 +70,7 @@ struct volume_group { + const char *name; + const char *old_name; /* Set during vgrename and vgcfgrestore */ + const char *system_id; ++ char *lvm1_system_id; + const char *lock_type; + const char *lock_args; + +diff --git a/lib/report/report.c b/lib/report/report.c +index 19f0f5c..8905d26 100644 +--- a/lib/report/report.c ++++ b/lib/report/report.c +@@ -2845,7 +2845,7 @@ static int _vgsystemid_disp(struct dm_report *rh, struct dm_pool *mem, + const void *data, void *private) + { + const struct volume_group *vg = (const struct volume_group *) data; +- const char *repstr = (vg->system_id && *vg->system_id) ? vg->system_id : ""; ++ const char *repstr = (vg->system_id && *vg->system_id) ? vg->system_id : vg->lvm1_system_id ? : ""; + + return _field_string(rh, field, repstr); + } +@@ -3830,6 +3830,7 @@ static struct volume_group _dummy_vg = { + .fid = &_dummy_fid, + .name = "", + .system_id = (char *) "", ++ .lvm1_system_id = (char *) "", + .pvs = DM_LIST_HEAD_INIT(_dummy_vg.pvs), + .lvs = DM_LIST_HEAD_INIT(_dummy_vg.lvs), + .historical_lvs = DM_LIST_HEAD_INIT(_dummy_vg.historical_lvs), +@@ -3840,6 +3841,7 @@ static struct volume_group _unknown_vg = { + .fid = &_dummy_fid, + .name = "[unknown]", + .system_id = (char *) "", ++ .lvm1_system_id = (char *) "", + .pvs = DM_LIST_HEAD_INIT(_unknown_vg.pvs), + .lvs = DM_LIST_HEAD_INIT(_unknown_vg.lvs), + .historical_lvs = DM_LIST_HEAD_INIT(_unknown_vg.historical_lvs), +diff --git a/lib/striped/striped.c b/lib/striped/striped.c +index 498b202..a2eaf80 100644 +--- a/lib/striped/striped.c ++++ b/lib/striped/striped.c +@@ -239,7 +239,8 @@ static struct segment_type *_init_segtype(struct cmd_context *cmd, const char *n + + segtype->ops = &_striped_ops; + segtype->name = name; +- segtype->flags = target | SEG_CAN_SPLIT | SEG_AREAS_STRIPED; ++ segtype->flags = target | SEG_CAN_SPLIT | SEG_AREAS_STRIPED | ++ SEG_FORMAT1_SUPPORT; + + log_very_verbose("Initialised segtype: %s", segtype->name); + return segtype; +diff --git a/man/vgconvert.8_des b/man/vgconvert.8_des +index 8519063..a0d34fd 100644 +--- a/man/vgconvert.8_des ++++ b/man/vgconvert.8_des +@@ -1,3 +1,6 @@ +-vgconvert converts VG metadata from one format to another. This command +-is no longer used because this version of lvm no longer supports the LVM1 ++vgconvert converts VG metadata from one format to another. The new ++metadata format must be able to fit into the space provided by the old + format. ++ ++Because the LVM1 format should no longer be used, this command is no ++longer needed in general. +diff --git a/test/shell/format-lvm1.sh b/test/shell/format-lvm1.sh +new file mode 100644 +index 0000000..b88579f +--- /dev/null ++++ b/test/shell/format-lvm1.sh +@@ -0,0 +1,38 @@ ++#!/usr/bin/env bash ++ ++# Copyright (C) 2008 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_description='Test lvm1 format' ++ ++SKIP_WITH_LVMPOLLD=1 ++ ++. lib/inittest ++ ++aux prepare_devs 1 ++ ++if test -n "$LVM_TEST_LVM1" ; then ++pvcreate -M1 "$dev1" ++vgcreate -M1 $vg "$dev1" ++check vg_field $vg fmt "lvm1" ++fi ++ ++# TODO: if we decide to make using lvm1 with lvmetad an error, ++# then if lvmetad is being used, then verify: ++# not pvcreate -M1 "$dev1" ++# not vgcreate -M1 $vg "$dev1" ++# ++# TODO: if we decide to allow using lvm1 with lvmetad, but disable lvmetad ++# when it happens, then verify: ++# pvcreate -M1 "$dev1" | tee err ++# grep "disabled" err ++# vgcreate -M1 $vg "$dev1" | tee err ++# grep "disabled" err ++ +diff --git a/test/shell/lvm1-basic.sh b/test/shell/lvm1-basic.sh +new file mode 100644 +index 0000000..93509c4 +--- /dev/null ++++ b/test/shell/lvm1-basic.sh +@@ -0,0 +1,36 @@ ++#!/usr/bin/env bash ++ ++# Copyright (C) 2012 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 ++ ++SKIP_WITH_LVMLOCKD=1 ++SKIP_WITHOUT_LVMETAD=1 ++SKIP_WITH_LVMPOLLD=1 ++ ++. lib/inittest ++ ++aux prepare_devs 2 ++pvcreate --metadatatype 1 "$dev1" ++pvs | tee out ++grep "$dev1" out ++vgcreate --metadatatype 1 $vg1 "$dev1" ++vgs | tee out ++grep $vg1 out ++pvs | tee out ++grep "$dev1" out ++ ++# check for RHBZ 1080189 -- SEGV in lvremove/vgremove ++pvcreate -ff -y --metadatatype 1 "$dev1" "$dev2" ++vgcreate --metadatatype 1 $vg1 "$dev1" "$dev2" ++lvcreate -l1 $vg1 "$dev1" ++pvremove -ff -y "$dev2" ++vgchange -an $vg1 ++not lvremove $vg1 ++not vgremove -ff -y $vg1 +diff --git a/test/shell/snapshot-lvm1.sh b/test/shell/snapshot-lvm1.sh +new file mode 100644 +index 0000000..75c97cb +--- /dev/null ++++ b/test/shell/snapshot-lvm1.sh +@@ -0,0 +1,35 @@ ++#!/usr/bin/env bash ++ ++# Copyright (C) 2013 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 ++ ++# regression test for lvmetad reporting error: ++# Internal error: LV snap_with_lvm1_meta (00000000000000000000000000000001) missing from preload metadata ++ ++SKIP_WITH_LVMLOCKD=1 ++SKIP_WITH_LVMPOLLD=1 ++ ++. lib/inittest ++ ++aux prepare_devs 2 ++get_devs ++ ++vgcreate --metadatatype 1 "$vg" "${DEVICES[@]}" ++ ++# Make origin volume ++lvcreate -ae -l5 $vg -n origin ++ ++# Create a snap of origin ++lvcreate -s $vg/origin -n snap_with_lvm1_meta -l4 ++ ++# Remove volume snapper/snap_with_lvm1_meta ++lvremove -f $vg/snap_with_lvm1_meta ++ ++vgremove -ff $vg +diff --git a/tools/args.h b/tools/args.h +index 603a0cf..b80b8da 100644 +--- a/tools/args.h ++++ b/tools/args.h +@@ -1207,7 +1207,8 @@ arg(mirrors_ARG, 'm', "mirrors", number_VAL, 0, 0, + arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_VAL, 0, 0, + "Specifies the type of on-disk metadata to use.\n" + "\\fBlvm2\\fP (or just \\fB2\\fP) is the current, standard format.\n" +- "\\fBlvm1\\fP (or just \\fB1\\fP) is no longer used.\n") ++ "\\fBlvm1\\fP (or just \\fB1\\fP) is a historical format that\n" ++ "can be used for accessing old data.\n") + + arg(name_ARG, 'n', "name", string_VAL, 0, 0, + "#lvcreate\n" +diff --git a/tools/lvconvert.c b/tools/lvconvert.c +index b149201..3ce228f 100644 +--- a/tools/lvconvert.c ++++ b/tools/lvconvert.c +@@ -1770,6 +1770,11 @@ static int _lvconvert_splitsnapshot(struct cmd_context *cmd, struct logical_volu + return 0; + } + ++ if (!(vg->fid->fmt->features & FMT_MDAS)) { ++ log_error("Unable to split off snapshot %s using old LVM1-style metadata.", cow_name); ++ return 0; ++ } ++ + if (is_lockd_type(vg->lock_type)) { + /* FIXME: we need to create a lock for the new LV. */ + log_error("Unable to split snapshots in VG with lock_type %s.", vg->lock_type); +diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c +index 0dd24ec..0600b1c 100644 +--- a/tools/lvmcmdline.c ++++ b/tools/lvmcmdline.c +@@ -23,6 +23,7 @@ + + #include "stub.h" + #include "last-path-component.h" ++#include "format1.h" + + #include + #include +@@ -2899,6 +2900,13 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv) + goto out; + } + ++ if (!strcmp(cmd->fmt->name, FMT_LVM1_NAME) && lvmetad_used()) { ++ log_warn("WARNING: Disabling lvmetad cache which does not support obsolete metadata."); ++ lvmetad_set_disabled(cmd, LVMETAD_DISABLE_REASON_LVM1); ++ log_warn("WARNING: Not using lvmetad because lvm1 format is used."); ++ lvmetad_make_unused(cmd); ++ } ++ + if (cmd->command->command_enum == lvconvert_repair_CMD) { + log_warn("WARNING: Disabling lvmetad cache for repair command."); + lvmetad_set_disabled(cmd, LVMETAD_DISABLE_REASON_REPAIR); +@@ -2963,7 +2971,7 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv) + * by different token values.) + * + * lvmetad may have been previously disabled (or disabled during the +- * rescan done here) because duplicate devices were seen. ++ * rescan done here) because duplicate devices or lvm1 metadata were seen. + * In this case, disable the *use* of lvmetad by this command, reverting to + * disk scanning. + */ +@@ -3388,6 +3396,41 @@ static int _run_script(struct cmd_context *cmd, int argc, char **argv) + return ret; + } + ++/* ++ * Determine whether we should fall back and exec the equivalent LVM1 tool ++ */ ++static int _lvm1_fallback(struct cmd_context *cmd) ++{ ++ char vsn[80]; ++ int dm_present; ++ ++ if (!find_config_tree_bool(cmd, global_fallback_to_lvm1_CFG, NULL) || ++ strncmp(cmd->kernel_vsn, "2.4.", 4)) ++ return 0; ++ ++ log_suppress(1); ++ dm_present = driver_version(vsn, sizeof(vsn)); ++ log_suppress(0); ++ ++ if (dm_present || !lvm1_present(cmd)) ++ return 0; ++ ++ return 1; ++} ++ ++static void _exec_lvm1_command(char **argv) ++{ ++ char path[PATH_MAX]; ++ ++ if (dm_snprintf(path, sizeof(path), "%s.lvm1", argv[0]) < 0) { ++ log_error("Failed to create LVM1 tool pathname"); ++ return; ++ } ++ ++ execvp(path, argv); ++ log_sys_error("execvp", path); ++} ++ + static void _nonroot_warning(void) + { + if (getuid() || geteuid()) +@@ -3477,6 +3520,19 @@ int lvm2_main(int argc, char **argv) + } else + run_name = dm_basename(argv[0]); + ++ if (_lvm1_fallback(cmd)) { ++ /* Attempt to run equivalent LVM1 tool instead */ ++ if (!argc) { ++ log_error("Falling back to LVM1 tools, but no " ++ "command specified."); ++ ret = ECMD_FAILED; ++ goto out; ++ } ++ _exec_lvm1_command(argv); ++ ret = ECMD_FAILED; ++ goto_out; ++ } ++ + /* + * Decide if we are running a shell or a command or a script. When + * there is no run_name, it's a shell, when run_name is a recognized +diff --git a/tools/pvscan.c b/tools/pvscan.c +index 2915db5..d9ad097 100644 +--- a/tools/pvscan.c ++++ b/tools/pvscan.c +@@ -631,7 +631,7 @@ out: + * display the PV info. + * + * iii. If lvmetad is being used, but has been disabled (because of +- * duplicate devs), or has a non-matching token ++ * duplicate devs or lvm1 metadata), or has a non-matching token + * (because the device filter is different from the device filter last + * used to populate lvmetad), then 'pvscan' will begin by rescanning + * devices to repopulate lvmetad. If lvmetad is enabled after the +@@ -644,7 +644,8 @@ out: + * attempt to repopulate the lvmetad cache by rescanning all devs + * (regardless of whether lvmetad was previously disabled or had an + * unmatching token.) lvmetad may be enabled or disabled after the +- * rescan (depending on whether duplicate devs). ++ * rescan (depending on whether duplicate devs or lvm1 metadata was ++ * found). + * + * 3. The 'pvscan --cache ' command will attempt to repopulate the + * lvmetad cache by rescanning all devs if lvmetad has a non-matching +diff --git a/tools/stub.h b/tools/stub.h +index 1d58387..f03e5d3 100644 +--- a/tools/stub.h ++++ b/tools/stub.h +@@ -37,6 +37,7 @@ int pvdata(struct cmd_context *cmd __attribute__((unused)), + { + log_error("There's no 'pvdata' command in LVM2."); + log_error("Use lvs, pvs, vgs instead; or use vgcfgbackup and read the text file backup."); ++ log_error("Metadata in LVM1 format can still be displayed using LVM1's pvdata command."); + return ECMD_FAILED; + } + +diff --git a/tools/toollib.c b/tools/toollib.c +index 413937f..b60ff06 100644 +--- a/tools/toollib.c ++++ b/tools/toollib.c +@@ -14,6 +14,7 @@ + */ + + #include "tools.h" ++#include "format1.h" + #include "format-text.h" + + #include +@@ -4110,6 +4111,7 @@ static int _process_duplicate_pvs(struct cmd_context *cmd, + .fid = &dummy_fid, + .name = "", + .system_id = (char *) "", ++ .lvm1_system_id = (char *) "", + .pvs = DM_LIST_HEAD_INIT(dummy_vg.pvs), + .lvs = DM_LIST_HEAD_INIT(dummy_vg.lvs), + .historical_lvs = DM_LIST_HEAD_INIT(dummy_vg.historical_lvs), +@@ -4747,6 +4749,23 @@ int pvcreate_params_from_args(struct cmd_context *cmd, struct pvcreate_params *p + pp->pva.label_sector = arg_int64_value(cmd, labelsector_ARG, + DEFAULT_LABELSECTOR); + ++ if (!(cmd->fmt->features & FMT_MDAS) && ++ (arg_is_set(cmd, pvmetadatacopies_ARG) || ++ arg_is_set(cmd, metadatasize_ARG) || ++ arg_is_set(cmd, dataalignment_ARG) || ++ arg_is_set(cmd, dataalignmentoffset_ARG))) { ++ log_error("Metadata and data alignment parameters only " ++ "apply to text format."); ++ return 0; ++ } ++ ++ if (!(cmd->fmt->features & FMT_BAS) && ++ arg_is_set(cmd, bootloaderareasize_ARG)) { ++ log_error("Bootloader area parameters only " ++ "apply to text format."); ++ return 0; ++ } ++ + if (arg_is_set(cmd, metadataignore_ARG)) + pp->pva.metadataignore = arg_int_value(cmd, metadataignore_ARG, + DEFAULT_PVMETADATAIGNORE); +@@ -5106,7 +5125,10 @@ static int _pvcreate_check_single(struct cmd_context *cmd, + pd->is_orphan_pv = 1; + } + +- pp->orphan_vg_name = FMT_TEXT_ORPHAN_VG_NAME; ++ if (!strcmp(vg->name, FMT_LVM1_ORPHAN_VG_NAME)) ++ pp->orphan_vg_name = FMT_LVM1_ORPHAN_VG_NAME; ++ else ++ pp->orphan_vg_name = FMT_TEXT_ORPHAN_VG_NAME; + } else { + log_debug("Found pvcreate arg %s: device is not a PV.", pd->name); + /* Device is not a PV. */ +@@ -5335,7 +5357,10 @@ static int _pvremove_check_single(struct cmd_context *cmd, + pd->is_orphan_pv = 1; + } + +- pp->orphan_vg_name = FMT_TEXT_ORPHAN_VG_NAME; ++ if (!strcmp(vg->name, FMT_LVM1_ORPHAN_VG_NAME)) ++ pp->orphan_vg_name = FMT_LVM1_ORPHAN_VG_NAME; ++ else ++ pp->orphan_vg_name = FMT_TEXT_ORPHAN_VG_NAME; + } else { + /* FIXME: is it possible to reach here? */ + log_debug("Found pvremove arg %s: device is not a PV.", pd->name); +diff --git a/tools/vals.h b/tools/vals.h +index 79c48b5..95dc8b2 100644 +--- a/tools/vals.h ++++ b/tools/vals.h +@@ -77,7 +77,7 @@ + * + * FIXME: are there some specialized or irrelevant + * options included in the usage text below that should +- * be removed? ++ * be removed? Should "lvm1" be removed? + * + * Size is a Number that takes an optional unit. + * A full usage could be "Size[b|B|s|S|k|K|m|M|g|G|t|T|p|P|e|E]" +@@ -126,7 +126,7 @@ val(sextents_VAL, sextents_arg, "SExtents", "[+|-]Number[PERCENT]") + val(pextents_VAL, pextents_arg, "PExtents", "[+]Number[PERCENT]") + val(nextents_VAL, nextents_arg, "NExtents", "[-]Number[PERCENT]") + val(permission_VAL, permission_arg, "Permission", "rw|r") +-val(metadatatype_VAL, metadatatype_arg, "MetadataType", "lvm2") ++val(metadatatype_VAL, metadatatype_arg, "MetadataType", "lvm2|lvm1") + val(units_VAL, string_arg, "Units", "r|R|h|H|b|B|s|S|k|K|m|M|g|G|t|T|p|P|e|E") + val(segtype_VAL, segtype_arg, "SegType", "linear|striped|snapshot|mirror|raid|thin|cache|thin-pool|cache-pool") + val(alloc_VAL, alloc_arg, "Alloc", "contiguous|cling|cling_by_tags|normal|anywhere|inherit") +diff --git a/tools/vgchange.c b/tools/vgchange.c +index 623517b..67be3ec 100644 +--- a/tools/vgchange.c ++++ b/tools/vgchange.c +@@ -534,6 +534,13 @@ static int _vgchange_system_id(struct cmd_context *cmd, struct volume_group *vg) + const char *system_id; + const char *system_id_arg_str = arg_str_value(cmd, systemid_ARG, NULL); + ++ /* FIXME Merge with vg_set_system_id() */ ++ if (systemid_on_pvs(vg)) { ++ log_error("Metadata format %s does not support this type of system ID.", ++ vg->fid->fmt->name); ++ return 0; ++ } ++ + if (!(system_id = system_id_from_string(cmd, system_id_arg_str))) { + log_error("Unable to set system ID."); + return 0; +@@ -583,6 +590,9 @@ static int _vgchange_system_id(struct cmd_context *cmd, struct volume_group *vg) + + vg->system_id = system_id; + ++ if (vg->lvm1_system_id) ++ *vg->lvm1_system_id = '\0'; ++ + return 1; + } + +diff --git a/tools/vgconvert.c b/tools/vgconvert.c +index ca9615c..8bdf8be 100644 +--- a/tools/vgconvert.c ++++ b/tools/vgconvert.c +@@ -34,25 +34,29 @@ static int _vgconvert_single(struct cmd_context *cmd, const char *vg_name, + return ECMD_FAILED; + } + +- if (arg_sign_value(cmd, metadatasize_ARG, SIGN_NONE) == SIGN_MINUS) { +- log_error("Metadata size may not be negative"); +- return EINVALID_CMD_LINE; +- } +- +- pva.pvmetadatasize = arg_uint64_value(cmd, metadatasize_ARG, UINT64_C(0)); +- if (!pva.pvmetadatasize) +- pva.pvmetadatasize = find_config_tree_int(cmd, metadata_pvmetadatasize_CFG, NULL); ++ if (cmd->fmt->features & FMT_MDAS) { ++ if (arg_sign_value(cmd, metadatasize_ARG, SIGN_NONE) == SIGN_MINUS) { ++ log_error("Metadata size may not be negative"); ++ return EINVALID_CMD_LINE; ++ } + +- pva.pvmetadatacopies = arg_int_value(cmd, pvmetadatacopies_ARG, -1); +- if (pva.pvmetadatacopies < 0) +- pva.pvmetadatacopies = find_config_tree_int(cmd, metadata_pvmetadatacopies_CFG, NULL); ++ pva.pvmetadatasize = arg_uint64_value(cmd, metadatasize_ARG, UINT64_C(0)); ++ if (!pva.pvmetadatasize) ++ pva.pvmetadatasize = find_config_tree_int(cmd, metadata_pvmetadatasize_CFG, NULL); + +- if (arg_sign_value(cmd, bootloaderareasize_ARG, SIGN_NONE) == SIGN_MINUS) { +- log_error("Bootloader area size may not be negative"); +- return EINVALID_CMD_LINE; ++ pva.pvmetadatacopies = arg_int_value(cmd, pvmetadatacopies_ARG, -1); ++ if (pva.pvmetadatacopies < 0) ++ pva.pvmetadatacopies = find_config_tree_int(cmd, metadata_pvmetadatacopies_CFG, NULL); + } + +- pva.ba_size = arg_uint64_value(cmd, bootloaderareasize_ARG, UINT64_C(0)); ++ if (cmd->fmt->features & FMT_BAS) { ++ if (arg_sign_value(cmd, bootloaderareasize_ARG, SIGN_NONE) == SIGN_MINUS) { ++ log_error("Bootloader area size may not be negative"); ++ return EINVALID_CMD_LINE; ++ } ++ ++ pva.ba_size = arg_uint64_value(cmd, bootloaderareasize_ARG, UINT64_C(0)); ++ } + + if (!vg_check_new_extent_size(cmd->fmt, vg->extent_size)) + return_ECMD_FAILED; +@@ -82,6 +86,13 @@ static int _vgconvert_single(struct cmd_context *cmd, const char *vg_name, + return ECMD_FAILED; + } + ++ /* New-style system ID supported? */ ++ if (vg->system_id && *vg->system_id && (cmd->fmt->features & FMT_SYSTEMID_ON_PVS)) { ++ log_error("Unable to convert VG %s while it has a system ID set (%s).", vg->name, ++ vg->system_id); ++ return ECMD_FAILED; ++ } ++ + /* Attempt to change any LVIDs that are too big */ + if (cmd->fmt->features & FMT_RESTRICTED_LVIDS) { + dm_list_iterate_items(lvl, &vg->lvs) { +@@ -146,6 +157,18 @@ int vgconvert(struct cmd_context *cmd, int argc, char **argv) + return EINVALID_CMD_LINE; + } + ++ if (!(cmd->fmt->features & FMT_MDAS) && ++ arg_is_set(cmd, pvmetadatacopies_ARG)) { ++ log_error("Metadata parameters only apply to text format"); ++ return EINVALID_CMD_LINE; ++ } ++ ++ if (!(cmd->fmt->features & FMT_BAS) && ++ arg_is_set(cmd, bootloaderareasize_ARG)) { ++ log_error("Bootloader area parameters only apply to text format"); ++ return EINVALID_CMD_LINE; ++ } ++ + return process_each_vg(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, 0, NULL, + &_vgconvert_single); + } +diff --git a/tools/vgscan.c b/tools/vgscan.c +index f9fa382..1ec9083 100644 +--- a/tools/vgscan.c ++++ b/tools/vgscan.c +@@ -44,7 +44,7 @@ static int _vgscan_single(struct cmd_context *cmd, const char *vg_name, + * display the VG info. + * + * iii. If lvmetad is being used, but has been disabled (because of +- * duplicate devs), or has a non-matching token ++ * duplicate devs or lvm1 metadata), or has a non-matching token + * (because the device filter is different from the device filter last + * used to populate lvmetad), then 'vgscan' will begin by rescanning + * devices to repopulate lvmetad. If lvmetad is enabled after the +@@ -57,7 +57,7 @@ static int _vgscan_single(struct cmd_context *cmd, const char *vg_name, + * the lvmetad cache by rescanning all devs (regardless of whether + * lvmetad was previously disabled or had an unmatching token.) + * lvmetad may be enabled or disabled after the rescan (depending +- * on whether duplicate devs were found). ++ * on whether duplicate devs or lvm1 metadata was found). + * If enabled, then it will simply read and display VG info from the + * lvmetad cache (like case 1.i.). If disabled, then it will + * read all devices to display VG info (like case 1.ii.) diff --git a/SOURCES/lvm2-rhel7-fix-StartLimitInterval.patch b/SOURCES/lvm2-rhel7-fix-StartLimitInterval.patch index 6245bdb..5e6616b 100644 --- a/SOURCES/lvm2-rhel7-fix-StartLimitInterval.patch +++ b/SOURCES/lvm2-rhel7-fix-StartLimitInterval.patch @@ -18,6 +18,3 @@ index 839bfd1..f0bbd46 100644 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 5efa755..e14a8e9 100644 --- a/SOURCES/lvm2-rhel7.patch +++ b/SOURCES/lvm2-rhel7.patch @@ -3,17 +3,16 @@ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION -index 849efb0..996ced9 100644 +index 9e5739e..98731d0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ --2.02.177(2) (2017-12-18) -+2.02.177(2)-RHEL7 (2018-01-22) +-2.02.180(2) (2018-07-19) ++2.02.180(2)-RHEL7 (2018-07-20) diff --git a/VERSION_DM b/VERSION_DM -index a37f632..1853e94 100644 +index 88fc33b..1da204c 100644 --- a/VERSION_DM +++ b/VERSION_DM @@ -1 +1 @@ --1.02.146 (2017-12-18) -+1.02.146-RHEL7 (2018-01-22) - +-1.02.149 (2018-07-19) ++1.02.149-RHEL7 (2018-07-20) diff --git a/SPECS/lvm2.spec b/SPECS/lvm2.spec index f68e8e7..4b87fd3 100644 --- a/SPECS/lvm2.spec +++ b/SPECS/lvm2.spec @@ -1,4 +1,4 @@ -%global device_mapper_version 1.02.146 +%global device_mapper_version 1.02.149 %global enable_cache 1 %global enable_cluster 1 @@ -20,16 +20,19 @@ %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 boom_version 0.9 %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_version 0.9 +%global boom_release 11 %global boom_summary A set of libraries and tools for managing boot loader entries %global boom_dir boom-%{boom_version} +#%%global scratch .bz1610455 + %if 0%{?rhel} %ifnarch i686 x86_64 ppc64le s390x %global enable_cluster 0 @@ -63,8 +66,8 @@ Summary: Userland logical volume management tools Name: lvm2 Epoch: 7 -Version: 2.02.177 -Release: 4%{?dist} +Version: 2.02.180 +Release: 8%{?dist}%{?scratch} License: GPLv2 Group: System Environment/Base URL: http://sources.redhat.com/lvm2 @@ -76,35 +79,35 @@ 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 -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 +Patch6: lvm2-rhel7-add-lvm1-and-pool-back.patch +Patch7: lvm2-2_02_180-make-generate.patch +Patch8: lvm2-2_02_181-post-release.patch +Patch9: lvm2-2_02_181-lvconvert-restrict-command-matching-for-no-option-va.patch +Patch10: lvm2-2_02_181-lvconvert-improve-text-about-splitmirrors.patch +Patch11: lvm2-2_02_181-lvconvert-reject-conversions-of-LVs-under-snapshot.patch +Patch12: lvm2-2_02_181-dmsetup-fix-error-propagation-in-_display_info_cols.patch +Patch13: lvm2-2_02_181-reject-conversions-trackchanges-SubLVs.patch +Patch14: lvm2-2_02_181-reject-conversions-trackchanges-LVs.patch +Patch15: lvm2-2_02_181-dmeventd-base-vdo-plugin.patch +Patch16: lvm2-2_02_181-dmeventd-rebase-to-stable-branch.patch +Patch17: lvm2-2_02_181-WHATS_NEW.patch +Patch18: lvm2-2_02_181-build-make-generate.patch +Patch19: lvm2-2_02_182-vgcreate-close-exclusive-fd-after-pvcreate.patch +Patch20: lvm2-2_02_182-mirrors-fix-read_only_volume_list.patch +Patch21: lvm2-2_02_182-cache-drop-metadata_format-validation.patch +Patch22: lvm2-2_02_182-mirror-fix-splitmirrors-for-mirror-type.patch +Patch23: lvm2-2_02_182-lvconvert-fix-direct-raid0-to-striped-conversion.patch +Patch24: lvm2-2_02_182-lvconvert-fix-conversion-attempts-to-linear.patch +Patch25: lvm2-2_02_182-dmeventd-lvm2-plugin-uses-envvar-registry.patch +Patch26: lvm2-2_02_182-scripts-add-After-rbdmap.service-to-lvm2-activation.patch +Patch27: lvm2-2_02_182-lvconvert-avoid-superfluous-interim-raid-type.patch +Patch28: lvm2-2_02_182-lvconvert-fix-interim-segtype-regression-on-raid6-co.patch BuildRequires: libselinux-devel >= %{libselinux_version}, libsepol-devel BuildRequires: libblkid-devel >= %{util_linux_version} BuildRequires: ncurses-devel BuildRequires: readline-devel +BuildRequires: libaio-devel %if %{enable_cluster} BuildRequires: corosynclib-devel >= %{corosync_version} %endif @@ -157,30 +160,29 @@ 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 .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 +%patch6 -p1 -b .add_lvm1_and_pool +%patch7 -p1 -b .make_generate +%patch8 -p1 -b .post_release +%patch9 -p1 -b .lvconvert_matching_no_option +%patch10 -p1 -b .lvconvert_text_splitmirrors +%patch11 -p1 -b .reject_conversions_under_snapshot +%patch12 -p1 -b .dmsetup_fix_error_display_info_cols +%patch13 -p1 -b .reject_conversions_trackchage_LVs +%patch14 -p1 -b .reject_conversions_trackchang_subLVs +%patch15 -p1 -b .dmeventd_base_vdo_plugin +%patch16 -p1 -b .dmeventd_rebase_to_stable_branch +%patch17 -p1 -b .WHATS_NEW +%patch18 -p1 -b .build_make_generate +%patch19 -p1 -b .close_excl_fd_after_pvcreate +%patch20 -p1 -b .mirrors_fix_RO_volume_list +%patch21 -p1 -b .cache_drop_metadata_format_validation +%patch22 -p1 -b .mirror_fix_splitmirrors +%patch23 -p1 -b .direct_raid0_to_striped_conversion +%patch24 -p1 -b .fix_conversion_to_linear +%patch25 -p1 -b .dmeventd_lvm2_plugin_uses_envvar_registry +%patch26 -p1 -b .lvm2_activation_after_rdbmap +%patch27 -p1 -b .avoid_superfluous_raid_conversion +%patch28 -p1 -b .fix_interim_segtype_on_raid6 %build %global _default_pid_dir /run @@ -539,6 +541,10 @@ This package contains shared lvm2 libraries for applications. %{_libdir}/device-mapper/libdevmapper-event-lvm2thin.so %endif +%{_libdir}/device-mapper/libdevmapper-event-lvm2vdo.so +%{_libdir}/libdevmapper-event-lvm2vdo.so + + %if %{enable_python} %package python-libs @@ -924,10 +930,12 @@ the device-mapper event library. %package -n %{boom_pkgname} Summary: %{boom_summary} Version: %{boom_version} +Release: %{boom_release}%{?dist}%{?scratch} License: GPLv2 Group: System Environment/Base BuildArch: noarch %{?python_provide:%python_provide python2-boom} +Requires: grub2 %description -n %{boom_pkgname} Boom is a boot manager for Linux systems using boot loaders that support @@ -953,6 +961,70 @@ This package provides the python2 version of boom. %endif %changelog +* Mon Sep 10 2018 Marian Csontos - 7:2.02.180-8 +- Fix lvconvert striped/raid0/raid0_meta to raid6 regression. + +* Wed Sep 05 2018 Marian Csontos - 7:2.02.180-7 +- Fix ordering of lvm2 activation and rbdmap services. +- Fix to avoid locking collisions when monitoring thin-pools. + +* Fri Aug 24 2018 Marian Csontos - 7:2.02.180-6 +- Fix direct RAID0 to striped conversion. + +* Tue Aug 21 2018 Marian Csontos - 7:2.02.180-5 +- Fix direct RAID0 to striped conversion. + +* Tue Aug 21 2018 Marian Csontos - 7:2.02.180-3 +- Fix lvconvert --splitmirror for mirror type (2.02.178). +- Do not pair cache policy and cache metadata format. +- Fix mirrors honoring read_only_volume_list. +- Fix vgcreate with sanlock when PVs are created automatically. + +* Tue Jul 31 2018 Marian Csontos - 7:2.02.180-2 +- Add vdo plugin for monitoring VDO devices. +- Reject conversions on raid1 LVs with split tracked SubLVs. +- Reject conversions on raid1 split tracked SubLVs. +- Fix dmstats list failing when no regions exist. +- Reject conversions of LVs under snapshot. +- Limit suggested options on incorrect option for lvconvert subcommand. + +* Fri Jul 20 2018 Marian Csontos - 7:2.02.180-1 +- Never send any discard ioctl with test mode. +- Fix thin-pool alloc which needs same PV for data and metadata. +- Enhance vgcfgrestore to check for active LVs in restored VG. +- Cache can use metadata format 2 with cleaner policy. +- Fix lvmetad hanging on shutdown. +- Fix check if resized PV can also fit metadata area. + +* Tue Jun 26 2018 Marian Csontos - 7:2.02.179-4 +- Rebuild man pages and config file (make generate.) + +* Tue Jun 26 2018 Marian Csontos - 7:2.02.179-3 +- Add convenient conversions between stripe and linear. +- Fix snapshot hanging on shutdown. +- Fix internal error in lvs while pvmove in progress. +- Fix more coverity issues. +- Improve message for pvresize. + +* Thu Jun 21 2018 Marian Csontos - 7:2.02.179-2 +- Fix issue caused by udev considering device open in RW mode a change. +- Fix leaks and buffer overflow. +- boom: Update to new minor release. + +* Mon Jun 18 2018 Marian Csontos - 7:2.02.179-1 +- Fixing known problems with cache and lvmlockd. + +* Thu Jun 14 2018 Marian Csontos - 7:2.02.178-1 +- Rework disk scanning and when it is used. +- Add new io layer using libaio for faster scanning. +- Support activation of component LVs in read-only mode. +- Avoid non-exclusive activation of exclusive segment types. +- Restore pvmove support for clusterwide active volumes (2.02.177). +- Add prioritized_section() to restore cookie boundaries (2.02.177). +- Again accept striped LV as COW LV with lvconvert -s (2.02.169). +- Restore usability of thin LV to be again external origin for another thin (2.02.169). +- See WHATS_NEW and WHATS_NEW_DM in the documentation directory for more. + * Fri Feb 16 2018 Marian Csontos - 7:2.02.177-4 - pvmove enhance accepted states of active LVs. - boom: Remove debug output.