diff --git a/LVM2.2.03.10.tgz.asc b/LVM2.2.03.10.tgz.asc deleted file mode 100644 index 32afc43..0000000 --- a/LVM2.2.03.10.tgz.asc +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN PGP SIGNATURE----- -Version: GnuPG v2.0.22 (GNU/Linux) - -iQIcBAABAgAGBQJfMBQmAAoJELkRJDHlCQOfTCoP/RF9P2RY7NXhXVxfpKbTqqhW -Xag1M5HAMmxflbiYI8Lrh1S7NrSHicWWitiHeKkYTwZxiC8E/HVwZq4UJyl5EDcA -F7FoZuVKB/NPVCjrnvDTwm9pZGZcYErufqb1sT/8cSCtr+vOvRQB5wAWtiu0lQA6 -OgcqAzM6Vvx04DiufKYfGoii+VvvfmICtOcQtMBfXpMmp7MCtOlTVeMYCbyiKYr1 -4YutnoB41lIyfARA6vu0E+VfbpgJX0KwJS01cWV5XES4kDGBdqqFPJVgagMRCCGo -ssBETAFybQBWVs1OUipIhiZAn1JGXmoZ10UIBPs1GBfKisz+NOr4UQtQV+hMKLex -Wx6fqRzZsof1hOLn/XO8h6626fDcf2YGV5ayIFAyv2IGpMJN0iqBkw4PHOtcP1ft -RqkjwWTm56q97eZN5o8clvAnIN6Anyyx8t1BJUWmZ/QTzMYC98CMZTa0/foq7kw4 -qBrsqz1PmdKhWL8xtBdrEcwiuDyPaP/hfdfGEDNBiqVN9zVEVIfbJ2OK4xSUfIr5 -hdyjYC+gGRQ/CX0o0YC8PQifzxXthw17XDiH15MhlplCrLJk2CwLMQqKLThe9ksE -3OcQnynS59gI2AfQdALVgSIvzUSMBY7V3I2H9kkBGhywJ64Ow2qpNWXd1wF9DDb5 -6F0ElaB5hDrghbwMcFTg -=0jtu ------END PGP SIGNATURE----- diff --git a/LVM2.2.03.11.tgz.asc b/LVM2.2.03.11.tgz.asc new file mode 100644 index 0000000..ef62186 --- /dev/null +++ b/LVM2.2.03.11.tgz.asc @@ -0,0 +1,17 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v2.0.22 (GNU/Linux) + +iQIcBAABAgAGBQJf+CGBAAoJELkRJDHlCQOfbcAQAIky3+aEOxnpeT5T2XFRvsCJ +Uk71G70q24JupybEEYvhehf3RmeQkLP3c0TeNMFweqzUwpZBIhpbymglhaNG2AZc +3Bbnl1SAGZ5IzdqacrKfCIas1b/UZMbRAhjcCFQ3oD0SApl+dED2RUacJCnlZxkE +NX3+MG4S6po84uQdHwZGtAw2+HQ0G5GwIETjxJHcQ+q8SZdWJRhKU25Z7UC1LI5u +648SmSlsy2KoNIOSM/sWwgz1MXSWnN0y1mBxfBrR7bdnrPW+ExumzTqZrECIuiyl +bbD3Me/wEfyk4XZt2SoZF9k0Hf3QcSULeTeJlHOqUfLRGKm9E9ngkR/yfb2De/zP +tMzvFyu/tiCfFRXmQbS7K8dFzUzs6KQCHIPuJYnv+BjxOW9gjeyK5JPgBCsOLu// +mEf64ttDDKmCx1qOEnMhxTckvSH8YedmbQRov3g0ZXE3syG4OrhT1DHTyAnv69/f +fNVhOjd4POAoQx2UQzftgU7f4LiMPrQyRiUnQ0DRxHSEYXnIngpqokaVodfvpJp5 +8YEuce9Xvq9JCplzKc1OXNtZQUHMybeyVzeenPVYvRV11ZbHzMAzwB6Byhwc9xgt +iKIuWpxMiPveKih3l/THoGOj19OUAN2XvWcGbOa6hTy6m/wsnoJQ0Xx5b5Ysfc1s +U60q2IDLJUS0H2R2raoc +=NE9u +-----END PGP SIGNATURE----- diff --git a/lvm2-2_03_12-WHATS_NEW-update.patch b/lvm2-2_03_12-WHATS_NEW-update.patch new file mode 100644 index 0000000..ed16b64 --- /dev/null +++ b/lvm2-2_03_12-WHATS_NEW-update.patch @@ -0,0 +1,15 @@ + WHATS_NEW | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/WHATS_NEW b/WHATS_NEW +index ffefc9d..3953c7e 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,5 +1,7 @@ + Version 2.03.12 - + =================================== ++ Fix problem with wiping of converted LVs. ++ Fix memleak in scanning (2.03.11). + Fix corner case allocation for thin-pools. + + Version 2.03.11 - 08th January 2021 diff --git a/lvm2-2_03_12-alloc-enhance-estimation-of-sufficient_pes_free.patch b/lvm2-2_03_12-alloc-enhance-estimation-of-sufficient_pes_free.patch new file mode 100644 index 0000000..a60a2b8 --- /dev/null +++ b/lvm2-2_03_12-alloc-enhance-estimation-of-sufficient_pes_free.patch @@ -0,0 +1,47 @@ + WHATS_NEW | 10 ++++++++-- + lib/metadata/lv_manip.c | 10 +++++++--- + 2 files changed, 11 insertions(+), 3 deletions(-) + +diff --git a/WHATS_NEW b/WHATS_NEW +index 452a631..fe347f7 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,3 +1,7 @@ ++Version 2.03.12 - ++=================================== ++ Fix corner case allocation for thin-pools. ++ + Version 2.03.11 - 08th January 2021 + =================================== + Fix pvck handling MDA at offset different from 4096. +diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c +index 7046436..443d32c 100644 +--- a/lib/metadata/lv_manip.c ++++ b/lib/metadata/lv_manip.c +@@ -1850,11 +1850,13 @@ static uint32_t _mirror_log_extents(uint32_t region_size, uint32_t pe_size, uint + + /* Is there enough total space or should we give up immediately? */ + static int _sufficient_pes_free(struct alloc_handle *ah, struct dm_list *pvms, +- uint32_t allocated, uint32_t extents_still_needed) ++ uint32_t allocated, uint32_t log_still_needed, ++ uint32_t extents_still_needed) + { + uint32_t area_extents_needed = (extents_still_needed - allocated) * ah->area_count / ah->area_multiple; + uint32_t parity_extents_needed = (extents_still_needed - allocated) * ah->parity_count / ah->area_multiple; +- uint32_t metadata_extents_needed = ah->alloc_and_split_meta ? 0 : ah->metadata_area_count * RAID_METADATA_AREA_LEN + ah->log_len; /* One each */ ++ uint32_t metadata_extents_needed = (ah->alloc_and_split_meta ? 0 : ah->metadata_area_count * RAID_METADATA_AREA_LEN) + ++ (log_still_needed ? ah->log_len : 0); /* One each */ + uint64_t total_extents_needed = (uint64_t)area_extents_needed + parity_extents_needed + metadata_extents_needed; + uint32_t free_pes = pv_maps_size(pvms); + +@@ -3359,7 +3361,9 @@ static int _allocate(struct alloc_handle *ah, + old_allocated = alloc_state.allocated; + log_debug_alloc("Trying allocation using %s policy.", get_alloc_string(alloc)); + +- if (!ah->approx_alloc && !_sufficient_pes_free(ah, pvms, alloc_state.allocated, ah->new_extents)) ++ if (!ah->approx_alloc && !_sufficient_pes_free(ah, pvms, alloc_state.allocated, ++ alloc_state.log_area_count_still_needed, ++ ah->new_extents)) + goto_out; + + _init_alloc_parms(ah, &alloc_parms, alloc, prev_lvseg, diff --git a/lvm2-2_03_12-cache-reuse-code-for-metadata-min_max.patch b/lvm2-2_03_12-cache-reuse-code-for-metadata-min_max.patch new file mode 100644 index 0000000..ce35731 --- /dev/null +++ b/lvm2-2_03_12-cache-reuse-code-for-metadata-min_max.patch @@ -0,0 +1,107 @@ + lib/metadata/cache_manip.c | 40 ++++++++++++++-------------------------- + lib/metadata/metadata-exported.h | 1 + + tools/lvconvert.c | 1 + + tools/lvcreate.c | 1 + + 4 files changed, 17 insertions(+), 26 deletions(-) + +diff --git a/lib/metadata/cache_manip.c b/lib/metadata/cache_manip.c +index 2c4cc92..90ebd94 100644 +--- a/lib/metadata/cache_manip.c ++++ b/lib/metadata/cache_manip.c +@@ -204,6 +204,7 @@ int update_cache_pool_params(struct cmd_context *cmd, + unsigned attr, + uint32_t pool_data_extents, + uint32_t *pool_metadata_extents, ++ struct logical_volume *metadata_lv, + int *chunk_size_calc_method, uint32_t *chunk_size) + { + uint64_t min_meta_size; +@@ -252,39 +253,26 @@ int update_cache_pool_params(struct cmd_context *cmd, + if (!validate_cache_chunk_size(cmd, *chunk_size)) + return_0; + +- min_meta_size = _cache_min_metadata_size((uint64_t) pool_data_extents * extent_size, *chunk_size); ++ if ((uint64_t) *chunk_size > (uint64_t) pool_data_extents * extent_size) { ++ log_error("Size of %s data volume cannot be smaller than chunk size %s.", ++ segtype->name, display_size(cmd, *chunk_size)); ++ return 0; ++ } + +- /* Round up to extent size */ +- if (min_meta_size % extent_size) +- min_meta_size += extent_size - min_meta_size % extent_size; ++ min_meta_size = _cache_min_metadata_size((uint64_t) pool_data_extents * extent_size, *chunk_size); ++ min_meta_size = dm_round_up(min_meta_size, extent_size); + + if (!pool_metadata_size) + pool_metadata_size = min_meta_size; + +- if (pool_metadata_size > (2 * DEFAULT_CACHE_POOL_MAX_METADATA_SIZE)) { +- pool_metadata_size = 2 * DEFAULT_CACHE_POOL_MAX_METADATA_SIZE; +- if (*pool_metadata_extents) +- log_warn("WARNING: Maximum supported pool metadata size is %s.", +- display_size(cmd, pool_metadata_size)); +- } else if (pool_metadata_size < min_meta_size) { +- if (*pool_metadata_extents) +- log_warn("WARNING: Minimum required pool metadata size is %s " +- "(needs extra %s).", +- display_size(cmd, min_meta_size), +- display_size(cmd, min_meta_size - pool_metadata_size)); +- pool_metadata_size = min_meta_size; +- } +- +- if (!(*pool_metadata_extents = +- extents_from_size(cmd, pool_metadata_size, extent_size))) ++ if (!update_pool_metadata_min_max(cmd, extent_size, ++ min_meta_size, ++ (2 * DEFAULT_CACHE_POOL_MAX_METADATA_SIZE), ++ &pool_metadata_size, ++ metadata_lv, ++ pool_metadata_extents)) + return_0; + +- if ((uint64_t) *chunk_size > (uint64_t) pool_data_extents * extent_size) { +- log_error("Size of %s data volume cannot be smaller than chunk size %s.", +- segtype->name, display_size(cmd, *chunk_size)); +- return 0; +- } +- + log_verbose("Preferred pool metadata size %s.", + display_size(cmd, (uint64_t)*pool_metadata_extents * extent_size)); + +diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h +index 0e57722..c0fa564 100644 +--- a/lib/metadata/metadata-exported.h ++++ b/lib/metadata/metadata-exported.h +@@ -1319,6 +1319,7 @@ int update_cache_pool_params(struct cmd_context *cmd, + unsigned attr, + uint32_t pool_data_extents, + uint32_t *pool_metadata_extents, ++ struct logical_volume *metadata_lv, + int *chunk_size_calc_method, uint32_t *chunk_size); + int validate_lv_cache_chunk_size(struct logical_volume *pool_lv, uint32_t chunk_size); + int validate_lv_cache_create_pool(const struct logical_volume *pool_lv); +diff --git a/tools/lvconvert.c b/tools/lvconvert.c +index ce90279..416e8a7 100644 +--- a/tools/lvconvert.c ++++ b/tools/lvconvert.c +@@ -3189,6 +3189,7 @@ static int _lvconvert_to_pool(struct cmd_context *cmd, + pool_segtype, target_attr, + lv->le_count, + &meta_extents, ++ metadata_lv, + &chunk_calc, + &chunk_size)) + goto_bad; +diff --git a/tools/lvcreate.c b/tools/lvcreate.c +index 1ee9e14..1ce561f 100644 +--- a/tools/lvcreate.c ++++ b/tools/lvcreate.c +@@ -403,6 +403,7 @@ static int _update_extents_params(struct volume_group *vg, + lp->segtype, lp->target_attr, + lp->extents, + &lp->pool_metadata_extents, ++ NULL, + &lp->thin_chunk_size_calc_policy, + &lp->chunk_size)) + return_0; diff --git a/lvm2-2_03_12-config-avoid-printing-spaces-before-end-of-line.patch b/lvm2-2_03_12-config-avoid-printing-spaces-before-end-of-line.patch new file mode 100644 index 0000000..ffed82b --- /dev/null +++ b/lvm2-2_03_12-config-avoid-printing-spaces-before-end-of-line.patch @@ -0,0 +1,613 @@ + conf/example.conf.in | 146 +++++++++++++++++++++++++------------------------- + conf/lvmlocal.conf.in | 4 +- + lib/config/config.c | 2 +- + 3 files changed, 76 insertions(+), 76 deletions(-) + +diff --git a/conf/example.conf.in b/conf/example.conf.in +index d149ed9..cd53147 100644 +--- a/conf/example.conf.in ++++ b/conf/example.conf.in +@@ -78,14 +78,14 @@ devices { + # routines to acquire this information. For example, this information + # is used to drive LVM filtering like MD component detection, multipath + # component detection, partition detection and others. +- # ++ # + # Accepted values: + # none + # No external device information source is used. + # udev + # Reuse existing udev database records. Applicable only if LVM is + # compiled with udev support. +- # ++ # + external_device_info_source = "none" + + # Configuration option devices/hints. +@@ -94,13 +94,13 @@ devices { + # scanning, and will only scan the listed PVs. Removing the hint file + # will cause lvm to generate a new one. Disable hints if PVs will + # be copied onto devices using non-lvm commands, like dd. +- # ++ # + # Accepted values: + # all + # Use all hints. + # none + # Use no hints. +- # ++ # + # This configuration option has an automatic default value. + # hints = "all" + +@@ -118,11 +118,11 @@ devices { + # Prefer the name with the least number of slashes. + # Prefer a name that is a symlink. + # Prefer the path with least value in lexicographical order. +- # ++ # + # Example + # preferred_names = [ "^/dev/mpath/", "^/dev/mapper/mpath", "^/dev/[hs]d" ] +- # +- # This configuration option has an automatic default value. ++ # ++ # This configuration option does not have a default value defined. + # preferred_names = [ "^/dev/mpath/", "^/dev/mapper/mpath", "^/dev/[hs]d" ] + + # Configuration option devices/filter. +@@ -140,7 +140,7 @@ devices { + # then the device is accepted. Be careful mixing 'a' and 'r' patterns, + # as the combination might produce unexpected results (test changes.) + # Run vgscan after changing the filter to regenerate the cache. +- # ++ # + # Example + # Accept every block device: + # filter = [ "a|.*|" ] +@@ -152,7 +152,7 @@ devices { + # filter = [ "a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|" ] + # Use anchors to be very specific: + # filter = [ "a|^/dev/hda8$|", "r|.*|" ] +- # ++ # + # This configuration option has an automatic default value. + # filter = [ "a|.*|" ] + +@@ -170,10 +170,10 @@ devices { + # List of additional acceptable block device types. + # These are of device type names from /proc/devices, followed by the + # maximum number of partitions. +- # ++ # + # Example + # types = [ "fd", 16 ] +- # ++ # + # This configuration option is advanced. + # This configuration option does not have a default value defined. + +@@ -215,7 +215,7 @@ devices { + # Configuration option devices/md_component_checks. + # The checks LVM should use to detect MD component devices. + # MD component devices are block devices used by MD software RAID. +- # ++ # + # Accepted values: + # auto + # LVM will skip scanning the end of devices when it has other +@@ -226,7 +226,7 @@ devices { + # full + # LVM will scan the start and end of devices for MD superblocks. + # This requires an extra read at the end of devices. +- # ++ # + # This configuration option has an automatic default value. + # md_component_checks = "auto" + +@@ -368,7 +368,7 @@ allocation { + # defined here, it will check whether any of them are attached to the + # PVs concerned and then seek to match those PV tags between existing + # extents and new extents. +- # ++ # + # Example + # Use the special tag "@*" as a wildcard to match any PV tag: + # cling_tag_list = [ "@*" ] +@@ -376,7 +376,7 @@ allocation { + # PVs are tagged with either @site1 or @site2 to indicate where + # they are situated: + # cling_tag_list = [ "@site1", "@site2" ] +- # ++ # + # This configuration option does not have a default value defined. + + # Configuration option allocation/maximise_cling. +@@ -435,25 +435,25 @@ allocation { + + # Configuration option allocation/cache_metadata_format. + # Sets default metadata format for new cache. +- # ++ # + # Accepted values: + # 0 Automatically detected best available format + # 1 Original format + # 2 Improved 2nd. generation format +- # ++ # + # This configuration option has an automatic default value. + # cache_metadata_format = 0 + + # Configuration option allocation/cache_mode. + # The default cache mode used for new cache. +- # ++ # + # Accepted values: + # writethrough + # Data blocks are immediately written from the cache to disk. + # writeback + # Data blocks are written from the cache back to disk after some + # delay to improve performance. +- # ++ # + # This setting replaces allocation/cache_pool_cachemode. + # This configuration option has an automatic default value. + # cache_mode = "writethrough" +@@ -502,18 +502,18 @@ allocation { + + # Configuration option allocation/thin_pool_discards. + # The discards behaviour of thin pool volumes. +- # ++ # + # Accepted values: + # ignore + # nopassdown + # passdown +- # ++ # + # This configuration option has an automatic default value. + # thin_pool_discards = "passdown" + + # Configuration option allocation/thin_pool_chunk_size_policy. + # The chunk size calculation policy for thin pool volumes. +- # ++ # + # Accepted values: + # generic + # If thin_pool_chunk_size is defined, use it. Otherwise, calculate +@@ -525,7 +525,7 @@ allocation { + # the chunk size for performance based on device hints exposed in + # sysfs - the optimal_io_size. The chunk size is always at least + # 512KiB. +- # ++ # + # This configuration option has an automatic default value. + # thin_pool_chunk_size_policy = "generic" + +@@ -962,7 +962,7 @@ global { + # Configuration option global/mirror_segtype_default. + # The segment type used by the short mirroring option -m. + # The --type mirror|raid1 option overrides this setting. +- # ++ # + # Accepted values: + # mirror + # The original RAID1 implementation from LVM/DM. It is +@@ -982,16 +982,16 @@ global { + # handling a failure. This mirror implementation is not + # cluster-aware and cannot be used in a shared (active/active) + # fashion in a cluster. +- # ++ # + mirror_segtype_default = "@DEFAULT_MIRROR_SEGTYPE@" + + # Configuration option global/support_mirrored_mirror_log. + # Enable mirrored 'mirror' log type for testing. +- # ++ # + # This type is deprecated to create or convert to but can + # be enabled to test that activation of existing mirrored + # logs and conversion to disk/core works. +- # ++ # + # Not supported for regular operation! + # This configuration option has an automatic default value. + # support_mirrored_mirror_log = 0 +@@ -1002,7 +1002,7 @@ global { + # The --stripes/-i and --mirrors/-m options can both be specified + # during the creation of a logical volume to use both striping and + # mirroring for the LV. There are two different implementations. +- # ++ # + # Accepted values: + # raid10 + # LVM uses MD's RAID10 personality through DM. This is the +@@ -1012,7 +1012,7 @@ global { + # is done by creating a mirror LV on top of striped sub-LVs, + # effectively creating a RAID 0+1 array. The layering is suboptimal + # in terms of providing redundancy and performance. +- # ++ # + raid10_segtype_default = "@DEFAULT_RAID10_SEGTYPE@" + + # Configuration option global/sparse_segtype_default. +@@ -1020,7 +1020,7 @@ global { + # The --type snapshot|thin option overrides this setting. + # The combination of -V and -L options creates a sparse LV. There are + # two different implementations. +- # ++ # + # Accepted values: + # snapshot + # The original snapshot implementation from LVM/DM. It uses an old +@@ -1032,7 +1032,7 @@ global { + # bigger minimal chunk size (64KiB) and uses a separate volume for + # metadata. It has better performance, especially when more data + # is used. It also supports full snapshots. +- # ++ # + sparse_segtype_default = "@DEFAULT_SPARSE_SEGTYPE@" + + # Configuration option global/lvdisplay_shows_full_device_path. +@@ -1130,20 +1130,20 @@ global { + # causing problems. Features include: block_size, discards, + # discards_non_power_2, external_origin, metadata_resize, + # external_origin_extend, error_if_no_space. +- # ++ # + # Example + # thin_disabled_features = [ "discards", "block_size" ] +- # ++ # + # This configuration option does not have a default value defined. + + # Configuration option global/cache_disabled_features. + # Features to not use in the cache driver. + # This can be helpful for testing, or to avoid using a feature that is + # causing problems. Features include: policy_mq, policy_smq, metadata2. +- # ++ # + # Example + # cache_disabled_features = [ "policy_smq" ] +- # ++ # + # This configuration option does not have a default value defined. + + # Configuration option global/cache_check_executable. +@@ -1207,7 +1207,7 @@ global { + # or vgimport.) A VG on shared storage devices is accessible only to + # the host with a matching system ID. See 'man lvmsystemid' for + # information on limitations and correct usage. +- # ++ # + # Accepted values: + # none + # The host has no system ID. +@@ -1224,7 +1224,7 @@ global { + # file + # Use the contents of another file (system_id_file) to set the + # system ID. +- # ++ # + system_id_source = "none" + + # Configuration option global/system_id_file. +@@ -1350,7 +1350,7 @@ activation { + # If this list is defined, an LV is only activated if it matches an + # entry in this list. If this list is undefined, it imposes no limits + # on LV activation (all are allowed). +- # ++ # + # Accepted values: + # vgname + # The VG name is matched exactly and selects all LVs in the VG. +@@ -1364,10 +1364,10 @@ activation { + # or VG. See tags/hosttags. If any host tags exist but volume_list + # is not defined, a default single-entry list containing '@*' + # is assumed. +- # ++ # + # Example + # volume_list = [ "vg1", "vg2/lvol1", "@tag1", "@*" ] +- # ++ # + # This configuration option does not have a default value defined. + + # Configuration option activation/auto_activation_volume_list. +@@ -1387,7 +1387,7 @@ activation { + # commands run directly by a user. A user may also use the 'a' flag + # directly to perform auto-activation. Also see pvscan(8) for more + # information about auto-activation. +- # ++ # + # Accepted values: + # vgname + # The VG name is matched exactly and selects all LVs in the VG. +@@ -1401,10 +1401,10 @@ activation { + # or VG. See tags/hosttags. If any host tags exist but volume_list + # is not defined, a default single-entry list containing '@*' + # is assumed. +- # ++ # + # Example + # auto_activation_volume_list = [ "vg1", "vg2/lvol1", "@tag1", "@*" ] +- # ++ # + # This configuration option does not have a default value defined. + + # Configuration option activation/read_only_volume_list. +@@ -1413,7 +1413,7 @@ activation { + # against this list, and if it matches, it is activated in read-only + # mode. This overrides the permission setting stored in the metadata, + # e.g. from --permission rw. +- # ++ # + # Accepted values: + # vgname + # The VG name is matched exactly and selects all LVs in the VG. +@@ -1427,10 +1427,10 @@ activation { + # or VG. See tags/hosttags. If any host tags exist but volume_list + # is not defined, a default single-entry list containing '@*' + # is assumed. +- # ++ # + # Example + # read_only_volume_list = [ "vg1", "vg2/lvol1", "@tag1", "@*" ] +- # ++ # + # This configuration option does not have a default value defined. + + # Configuration option activation/raid_region_size. +@@ -1453,13 +1453,13 @@ activation { + + # Configuration option activation/readahead. + # Setting to use when there is no readahead setting in metadata. +- # ++ # + # Accepted values: + # none + # Disable readahead. + # auto + # Use default value chosen by kernel. +- # ++ # + # This configuration option has an automatic default value. + # readahead = "auto" + +@@ -1471,7 +1471,7 @@ activation { + # performed by dmeventd automatically, and the steps perfomed by the + # manual command lvconvert --repair --use-policies. + # Automatic handling requires dmeventd to be monitoring the LV. +- # ++ # + # Accepted values: + # warn + # Use the system log to warn the user that a device in the RAID LV +@@ -1482,7 +1482,7 @@ activation { + # allocate + # Attempt to use any extra physical volumes in the VG as spares and + # replace faulty devices. +- # ++ # + raid_fault_policy = "warn" + + # Configuration option activation/mirror_image_fault_policy. +@@ -1494,7 +1494,7 @@ activation { + # determines the steps perfomed by dmeventd automatically, and the steps + # performed by the manual command lvconvert --repair --use-policies. + # Automatic handling requires dmeventd to be monitoring the LV. +- # ++ # + # Accepted values: + # remove + # Simply remove the faulty device and run without it. If the log +@@ -1519,7 +1519,7 @@ activation { + # the redundant nature of the mirror. This policy acts like + # 'remove' if no suitable device and space can be allocated for the + # replacement. +- # ++ # + mirror_image_fault_policy = "remove" + + # Configuration option activation/mirror_log_fault_policy. +@@ -1534,26 +1534,26 @@ activation { + # The minimum value is 50 (a smaller value is treated as 50.) + # Also see snapshot_autoextend_percent. + # Automatic extension requires dmeventd to be monitoring the LV. +- # ++ # + # Example + # Using 70% autoextend threshold and 20% autoextend size, when a 1G + # snapshot exceeds 700M, it is extended to 1.2G, and when it exceeds + # 840M, it is extended to 1.44G: + # snapshot_autoextend_threshold = 70 +- # ++ # + snapshot_autoextend_threshold = 100 + + # Configuration option activation/snapshot_autoextend_percent. + # Auto-extending a snapshot adds this percent extra space. + # The amount of additional space added to a snapshot is this + # percent of its current size. +- # ++ # + # Example + # Using 70% autoextend threshold and 20% autoextend size, when a 1G + # snapshot exceeds 700M, it is extended to 1.2G, and when it exceeds + # 840M, it is extended to 1.44G: + # snapshot_autoextend_percent = 20 +- # ++ # + snapshot_autoextend_percent = 20 + + # Configuration option activation/thin_pool_autoextend_threshold. +@@ -1562,26 +1562,26 @@ activation { + # The minimum value is 50 (a smaller value is treated as 50.) + # Also see thin_pool_autoextend_percent. + # Automatic extension requires dmeventd to be monitoring the LV. +- # ++ # + # Example + # Using 70% autoextend threshold and 20% autoextend size, when a 1G + # thin pool exceeds 700M, it is extended to 1.2G, and when it exceeds + # 840M, it is extended to 1.44G: + # thin_pool_autoextend_threshold = 70 +- # ++ # + thin_pool_autoextend_threshold = 100 + + # Configuration option activation/thin_pool_autoextend_percent. + # Auto-extending a thin pool adds this percent extra space. + # The amount of additional space added to a thin pool is this + # percent of its current size. +- # ++ # + # Example + # Using 70% autoextend threshold and 20% autoextend size, when a 1G + # thin pool exceeds 700M, it is extended to 1.2G, and when it exceeds + # 840M, it is extended to 1.44G: + # thin_pool_autoextend_percent = 20 +- # ++ # + thin_pool_autoextend_percent = 20 + + # Configuration option activation/vdo_pool_autoextend_threshold. +@@ -1590,13 +1590,13 @@ activation { + # The minimum value is 50 (a smaller value is treated as 50.) + # Also see vdo_pool_autoextend_percent. + # Automatic extension requires dmeventd to be monitoring the LV. +- # ++ # + # Example + # Using 70% autoextend threshold and 20% autoextend size, when a 10G + # VDO pool exceeds 7G, it is extended to 12G, and when it exceeds + # 8.4G, it is extended to 14.4G: + # vdo_pool_autoextend_threshold = 70 +- # ++ # + # This configuration option has an automatic default value. + # vdo_pool_autoextend_threshold = 100 + +@@ -1604,7 +1604,7 @@ activation { + # Auto-extending a VDO pool adds this percent extra space. + # The amount of additional space added to a VDO pool is this + # percent of its current size. +- # ++ # + # Example + # Using 70% autoextend threshold and 20% autoextend size, when a 10G + # VDO pool exceeds 7G, it is extended to 12G, and when it exceeds +@@ -1623,10 +1623,10 @@ activation { + # pages corresponding to lines that match are not pinned. On some + # systems, locale-archive was found to make up over 80% of the memory + # used by the process. +- # ++ # + # Example + # mlock_filter = [ "locale/locale-archive", "gconv/gconv-modules.cache" ] +- # ++ # + # This configuration option is advanced. + # This configuration option does not have a default value defined. + +@@ -1667,7 +1667,7 @@ activation { + # Configuration option activation/activation_mode. + # How LVs with missing devices are activated. + # The --activationmode option overrides this setting. +- # ++ # + # Accepted values: + # complete + # Only allow activation of an LV if all of the Physical Volumes it +@@ -1682,7 +1682,7 @@ activation { + # could cause data loss with a portion of the LV inaccessible. + # This setting should not normally be used, but may sometimes + # assist with data recovery. +- # ++ # + activation_mode = "degraded" + + # Configuration option activation/lock_start_list. +@@ -1730,7 +1730,7 @@ activation { + # Configuration option metadata/pvmetadatacopies. + # Number of copies of metadata to store on each PV. + # The --pvmetadatacopies option overrides this setting. +- # ++ # + # Accepted values: + # 2 + # Two copies of the VG metadata are stored on the PV, one at the +@@ -1740,7 +1740,7 @@ activation { + # 0 + # No copies of VG metadata are stored on the PV. This may be + # useful for VGs containing large numbers of PVs. +- # ++ # + # This configuration option is advanced. + # This configuration option has an automatic default value. + # pvmetadatacopies = 1 +@@ -1890,7 +1890,7 @@ activation { + # sequences are copied verbatim. Each special character sequence is + # introduced by the '%' character and such sequence is then + # substituted with a value as described below. +- # ++ # + # Accepted values: + # %a + # The abbreviated name of the day of the week according to the +@@ -2013,7 +2013,7 @@ activation { + # The timezone name or abbreviation. + # %% + # A literal '%' character. +- # ++ # + # This configuration option has an automatic default value. + # time_format = "%Y-%m-%d %T %z" + +@@ -2282,12 +2282,12 @@ dmeventd { + # applied to the local machine as a 'host tag'. If this subsection is + # empty (has no host_list), then the subsection name is always applied + # as a 'host tag'. +- # ++ # + # Example + # The host tag foo is given to all hosts, and the host tag + # bar is given to the hosts named machine1 and machine2. + # tags { foo { } bar { host_list = [ "machine1", "machine2" ] } } +- # ++ # + # This configuration section has variable name. + # This configuration section has an automatic default value. + # tag { +diff --git a/conf/lvmlocal.conf.in b/conf/lvmlocal.conf.in +index 04414bf..12214ea 100644 +--- a/conf/lvmlocal.conf.in ++++ b/conf/lvmlocal.conf.in +@@ -28,13 +28,13 @@ local { + # main configuration file, e.g. lvm.conf. When used, it must be set to + # a unique value among all hosts sharing access to the storage, + # e.g. a host name. +- # ++ # + # Example + # Set no system ID: + # system_id = "" + # Set the system_id to a specific name: + # system_id = "host1" +- # ++ # + # This configuration option has an automatic default value. + # system_id = "" + +diff --git a/lib/config/config.c b/lib/config/config.c +index a25b7db..f9ca566 100644 +--- a/lib/config/config.c ++++ b/lib/config/config.c +@@ -1738,7 +1738,7 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi + continue; + commentline[0] = '\0'; + } +- fprintf(out->fp, "%s# %s\n", line, commentline); ++ fprintf(out->fp, "%s#%s%s\n", line, commentline[0] ? " " : "", commentline); + /* withsummary prints only the first comment line. */ + if (!out->tree_spec->withcomments) + break; diff --git a/lvm2-2_03_12-dev_get_primary_dev-fix-invalid-path-check.patch b/lvm2-2_03_12-dev_get_primary_dev-fix-invalid-path-check.patch new file mode 100644 index 0000000..add3525 --- /dev/null +++ b/lvm2-2_03_12-dev_get_primary_dev-fix-invalid-path-check.patch @@ -0,0 +1,48 @@ +From b3719266bd5e3a9e6737d6bda60e543121ddf343 Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Tue, 9 Feb 2021 09:47:08 -0600 +Subject: [PATCH] dev_get_primary_dev: fix invalid path check + +Fix commit bee9f4efdd81 "filter-mpath: work with nvme devices" +which removed setting the path for readlink. + +(cherry picked from commit f74f94c2ddb1d33d75d325c959344a566a621fd5) + +Conflicts: + lib/device/dev-type.c +--- + lib/device/dev-type.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/lib/device/dev-type.c b/lib/device/dev-type.c +index 379afa8..1342e97 100644 +--- a/lib/device/dev-type.c ++++ b/lib/device/dev-type.c +@@ -434,7 +434,7 @@ static int _has_sys_partition(struct device *dev) + int minor = (int) MINOR(dev->dev); + + /* check if dev is a partition */ +- if (dm_snprintf(path, sizeof(path), "%s/dev/block/%d:%d/partition", ++ if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d/partition", + dm_sysfs_dir(), major, minor) < 0) { + log_error("dm_snprintf partition failed"); + return 0; +@@ -660,8 +660,13 @@ int dev_get_primary_dev(struct dev_types *dt, struct device *dev, dev_t *result) + * - basename ../../block/md0/md0 = md0 + * Parent's 'dev' sysfs attribute = /sys/block/md0/dev + */ +- if ((size = readlink(dirname(path), temp_path, sizeof(temp_path) - 1)) < 0) { +- log_sys_error("readlink", path); ++ if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d", ++ dm_sysfs_dir(), major, minor) < 0) { ++ log_warn("WARNING: %s: major:minor sysfs path is too long.", dev_name(dev)); ++ return 0; ++ } ++ if ((size = readlink(path, temp_path, sizeof(temp_path) - 1)) < 0) { ++ log_warn("WARNING: Readlink of %s failed.", path); + goto out; + } + +-- +1.8.3.1 + diff --git a/lvm2-2_03_12-devs-remove-invalid-path-name-aliases.patch b/lvm2-2_03_12-devs-remove-invalid-path-name-aliases.patch new file mode 100644 index 0000000..0f00653 --- /dev/null +++ b/lvm2-2_03_12-devs-remove-invalid-path-name-aliases.patch @@ -0,0 +1,255 @@ + lib/device/dev-cache.c | 161 ++++++++++++++++++++++++++++++++++++---------- + test/shell/dev-aliases.sh | 53 +++++++++++++++ + 2 files changed, 179 insertions(+), 35 deletions(-) + create mode 100644 test/shell/dev-aliases.sh + +diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c +index d5f18ff..8082efa 100644 +--- a/lib/device/dev-cache.c ++++ b/lib/device/dev-cache.c +@@ -1428,60 +1428,151 @@ struct device *dev_hash_get(const char *name) + return (struct device *) dm_hash_lookup(_cache.names, name); + } + ++static void _remove_alias(struct device *dev, const char *name) ++{ ++ struct dm_str_list *strl; ++ ++ dm_list_iterate_items(strl, &dev->aliases) { ++ if (!strcmp(strl->str, name)) { ++ dm_list_del(&strl->list); ++ return; ++ } ++ } ++} ++ ++/* ++ * Check that paths for this dev still refer to the same dev_t. This is known ++ * to drop invalid paths in the case where lvm deactivates an LV, which causes ++ * that LV path to go away, but that LV path is not removed from dev-cache (it ++ * probably should be). Later a new path to a different LV is added to ++ * dev-cache, where the new LV has the same major:minor as the previously ++ * deactivated LV. The new LV will find the existing struct dev, and that ++ * struct dev will have dev->aliases entries that refer to the name of the old ++ * deactivated LV. Those old paths are all invalid and are dropped here. ++ */ ++ ++static void _verify_aliases(struct device *dev, const char *newname) ++{ ++ struct dm_str_list *strl, *strl2; ++ struct stat st; ++ ++ dm_list_iterate_items_safe(strl, strl2, &dev->aliases) { ++ /* newname was just stat'd and added by caller */ ++ if (newname && !strcmp(strl->str, newname)) ++ continue; ++ ++ if (stat(strl->str, &st) || (st.st_rdev != dev->dev)) { ++ log_debug("Drop invalid path %s for %d:%d (new path %s).", ++ strl->str, (int)MAJOR(dev->dev), (int)MINOR(dev->dev), newname ?: ""); ++ dm_hash_remove(_cache.names, strl->str); ++ dm_list_del(&strl->list); ++ } ++ } ++} ++ + struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct dev_filter *f) + { +- struct stat buf; +- struct device *d = (struct device *) dm_hash_lookup(_cache.names, name); +- int info_available = 0; +- int ret = 1; ++ struct device *dev = (struct device *) dm_hash_lookup(_cache.names, name); ++ struct stat st; ++ int ret; + +- if (d && (d->flags & DEV_REGULAR)) +- return d; ++ /* ++ * DEV_REGULAR means that is "dev" is actually a file, not a device. ++ * FIXME: I don't think dev-cache is used for files any more and this ++ * can be dropped? ++ */ ++ if (dev && (dev->flags & DEV_REGULAR)) ++ return dev; ++ ++ /* ++ * The requested path is invalid, remove any dev-cache ++ * info for it. ++ */ ++ if (stat(name, &st)) { ++ if (dev) { ++ log_print("Device path %s is invalid for %d:%d %s.", ++ name, (int)MAJOR(dev->dev), (int)MINOR(dev->dev), dev_name(dev)); + +- /* If the entry's wrong, remove it */ +- if (stat(name, &buf) < 0) { +- if (d) + dm_hash_remove(_cache.names, name); +- log_sys_very_verbose("stat", name); +- d = NULL; +- } else +- info_available = 1; + +- if (d && (buf.st_rdev != d->dev)) { +- dm_hash_remove(_cache.names, name); +- d = NULL; +- } ++ _remove_alias(dev, name); + +- if (!d) { +- _insert(name, info_available ? &buf : NULL, 0, obtain_device_list_from_udev()); +- d = (struct device *) dm_hash_lookup(_cache.names, name); +- if (!d) { +- log_debug_devs("Device name not found in dev_cache repeat dev_cache_scan for %s", name); +- dev_cache_scan(); +- d = (struct device *) dm_hash_lookup(_cache.names, name); ++ /* Remove any other names in dev->aliases that are incorrect. */ ++ _verify_aliases(dev, NULL); + } ++ return NULL; + } + +- if (!d) ++ if (!S_ISBLK(st.st_mode)) { ++ log_debug("Not a block device %s.", name); + return NULL; ++ } + +- if (d && (d->flags & DEV_REGULAR)) +- return d; ++ /* ++ * dev-cache has incorrect info for the requested path. ++ * Remove incorrect info and then add new dev-cache entry. ++ */ ++ if (dev && (st.st_rdev != dev->dev)) { ++ log_print("Device path %s does not match %d:%d %s.", ++ name, (int)MAJOR(dev->dev), (int)MINOR(dev->dev), dev_name(dev)); ++ ++ dm_hash_remove(_cache.names, name); ++ ++ _remove_alias(dev, name); ++ ++ /* Remove any other names in dev->aliases that are incorrect. */ ++ _verify_aliases(dev, NULL); ++ ++ /* Add new dev-cache entry next. */ ++ dev = NULL; ++ } ++ ++ /* ++ * Either add a new struct dev for st_rdev and name, ++ * or add name as a new alias for an existing struct dev ++ * for st_rdev. ++ */ ++ if (!dev) { ++ _insert_dev(name, st.st_rdev); + +- if (f && !(d->flags & DEV_REGULAR)) { +- ret = f->passes_filter(cmd, f, d, NULL); ++ /* Get the struct dev that was just added. */ ++ dev = (struct device *) dm_hash_lookup(_cache.names, name); + +- if (ret == -EAGAIN) { +- log_debug_devs("get device by name defer filter %s", dev_name(d)); +- d->flags |= DEV_FILTER_AFTER_SCAN; +- ret = 1; ++ if (!dev) { ++ log_error("Failed to get device %s", name); ++ return NULL; + } ++ ++ _verify_aliases(dev, name); + } + +- if (f && !(d->flags & DEV_REGULAR) && !ret) ++ /* ++ * The caller passed a filter if they only want the dev if it ++ * passes filters. ++ */ ++ ++ if (!f) ++ return dev; ++ ++ ret = f->passes_filter(cmd, f, dev, NULL); ++ ++ /* ++ * This might happen if this function is called before ++ * filters can do i/o. I don't think this will happen ++ * any longer and this EAGAIN case can be removed. ++ */ ++ if (ret == -EAGAIN) { ++ log_debug_devs("dev_cache_get filter deferred %s", dev_name(dev)); ++ dev->flags |= DEV_FILTER_AFTER_SCAN; ++ ret = 1; ++ } ++ ++ if (!ret) { ++ log_debug_devs("dev_cache_get filter excludes %s", dev_name(dev)); + return NULL; ++ } + +- return d; ++ return dev; + } + + static struct device *_dev_cache_seek_devt(dev_t dev) +diff --git a/test/shell/dev-aliases.sh b/test/shell/dev-aliases.sh +new file mode 100644 +index 0000000..c97cd5d +--- /dev/null ++++ b/test/shell/dev-aliases.sh +@@ -0,0 +1,53 @@ ++#!/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_LVMPOLLD=1 ++ ++. lib/inittest ++ ++aux prepare_devs 3 ++ ++vgcreate $vg $dev1 $dev2 $dev3 ++ ++# ++# This lvconvert command will deactivate LV1, then internally create a new ++# lv, lvol0, as a poolmetadataspare, then activate lvol0 to zero it. ++# lvol0 will get the same major:minor that LV1 had. When the code gets ++# the struct dev for lvol0, the new path to lvol0 is added to the ++# dev-cache with it's major:minor. That major:minor already exists in ++# dev-cache and has the stale LV1 as an alias. So the path to lvol0 is ++# added as an alias to the existing struct dev (with the correct ++# major:minor), but that struct dev has the stale LV1 path on its aliases ++# list. The code will now validate all the aliases before returning the ++# dev for lvol0, and will find that the LV1 path is stale and remove it ++# from the aliases. That will prevent the stale path from being used for ++# the dev in place of the new path. ++# ++# The preferred_name is set to /dev/mapper so that if the stale path still ++# exists, that stale path would be used as the name for the dev, and the ++# wiping code would fail to open that stale name. ++# ++ ++lvcreate -n $lv1 -L32M $vg $dev1 ++lvcreate -n $lv2 -L16M $vg $dev2 ++lvconvert -y --type cache-pool --poolmetadata $lv2 --cachemode writeback $vg/$lv1 --config='devices { preferred_names=["/dev/mapper/"] }' ++lvremove -y $vg/$lv1 ++ ++lvcreate -n $lv1 -L32M $vg $dev1 ++lvcreate -n $lv2 -L16M $vg $dev2 ++lvconvert -y --type cache-pool --poolmetadata $lv2 $vg/$lv1 ++lvremove -y $vg/$lv1 ++ ++# TODO: add more validation of dev aliases being specified as command ++# args in combination with various preferred_names settings. ++ ++vgremove -ff $vg diff --git a/lvm2-2_03_12-filter-mpath-work-with-nvme-devices.patch b/lvm2-2_03_12-filter-mpath-work-with-nvme-devices.patch new file mode 100644 index 0000000..3778134 --- /dev/null +++ b/lvm2-2_03_12-filter-mpath-work-with-nvme-devices.patch @@ -0,0 +1,494 @@ + lib/device/dev-type.c | 81 +++++++++++++++++++---- + lib/device/dev-type.h | 2 + + lib/device/device.h | 1 + + lib/filters/filter-mpath.c | 156 ++++++++++++++++++++++++++++++--------------- + 4 files changed, 177 insertions(+), 63 deletions(-) + +diff --git a/lib/device/dev-type.c b/lib/device/dev-type.c +index 896821d..379afa8 100644 +--- a/lib/device/dev-type.c ++++ b/lib/device/dev-type.c +@@ -21,6 +21,7 @@ + #include "lib/metadata/metadata.h" + #include "lib/device/bcache.h" + #include "lib/label/label.h" ++#include "lib/commands/toolcontext.h" + + #ifdef BLKID_WIPING_SUPPORT + #include +@@ -67,6 +68,31 @@ int dev_is_pmem(struct device *dev) + return is_pmem ? 1 : 0; + } + ++/* ++ * An nvme device has major number 259 (BLKEXT), minor number , ++ * and reading /sys/dev/block/259:/device/dev shows a character ++ * device cmajor:cminor where cmajor matches the major number of the ++ * nvme character device entry in /proc/devices. Checking all of that ++ * is excessive and unnecessary compared to just comparing /dev/name*. ++ */ ++ ++int dev_is_nvme(struct dev_types *dt, struct device *dev) ++{ ++ struct dm_str_list *strl; ++ ++ if (dev->flags & DEV_IS_NVME) ++ return 1; ++ ++ dm_list_iterate_items(strl, &dev->aliases) { ++ if (!strncmp(strl->str, "/dev/nvme", 9)) { ++ log_debug("Found nvme device %s", dev_name(dev)); ++ dev->flags |= DEV_IS_NVME; ++ return 1; ++ } ++ } ++ return 0; ++} ++ + int dev_is_lv(struct device *dev) + { + FILE *fp; +@@ -302,6 +328,9 @@ int dev_subsystem_part_major(struct dev_types *dt, struct device *dev) + + const char *dev_subsystem_name(struct dev_types *dt, struct device *dev) + { ++ if (dev->flags & DEV_IS_NVME) ++ return "NVME"; ++ + if (MAJOR(dev->dev) == dt->device_mapper_major) + return "DM"; + +@@ -348,7 +377,6 @@ int major_is_scsi_device(struct dev_types *dt, int major) + return (dt->dev_type_array[major].flags & PARTITION_SCSI_DEVICE) ? 1 : 0; + } + +- + static int _loop_is_with_partscan(struct device *dev) + { + FILE *fp; +@@ -398,6 +426,28 @@ struct partition { + uint32_t nr_sects; + } __attribute__((packed)); + ++static int _has_sys_partition(struct device *dev) ++{ ++ char path[PATH_MAX]; ++ struct stat info; ++ int major = (int) MAJOR(dev->dev); ++ int minor = (int) MINOR(dev->dev); ++ ++ /* check if dev is a partition */ ++ if (dm_snprintf(path, sizeof(path), "%s/dev/block/%d:%d/partition", ++ dm_sysfs_dir(), major, minor) < 0) { ++ log_error("dm_snprintf partition failed"); ++ return 0; ++ } ++ ++ if (stat(path, &info) == -1) { ++ if (errno != ENOENT) ++ log_sys_error("stat", path); ++ return 0; ++ } ++ return 1; ++} ++ + static int _is_partitionable(struct dev_types *dt, struct device *dev) + { + int parts = major_max_partitions(dt, MAJOR(dev->dev)); +@@ -414,6 +464,13 @@ static int _is_partitionable(struct dev_types *dt, struct device *dev) + _loop_is_with_partscan(dev)) + return 1; + ++ if (dev_is_nvme(dt, dev)) { ++ /* If this dev is already a partition then it's not partitionable. */ ++ if (_has_sys_partition(dev)) ++ return 0; ++ return 1; ++ } ++ + if ((parts <= 1) || (MINOR(dev->dev) % parts)) + return 0; + +@@ -557,11 +614,18 @@ int dev_get_primary_dev(struct dev_types *dt, struct device *dev, dev_t *result) + char path[PATH_MAX]; + char temp_path[PATH_MAX]; + char buffer[64]; +- struct stat info; + FILE *fp = NULL; + int parts, residue, size, ret = 0; + + /* ++ * /dev/nvme devs don't use the major:minor numbering like ++ * block dev types that have their own major number, so ++ * the calculation based on minor number doesn't work. ++ */ ++ if (dev_is_nvme(dt, dev)) ++ goto sys_partition; ++ ++ /* + * Try to get the primary dev out of the + * list of known device types first. + */ +@@ -576,23 +640,14 @@ int dev_get_primary_dev(struct dev_types *dt, struct device *dev, dev_t *result) + goto out; + } + ++ sys_partition: + /* + * If we can't get the primary dev out of the list of known device + * types, try to look at sysfs directly then. This is more complex + * way and it also requires certain sysfs layout to be present + * which might not be there in old kernels! + */ +- +- /* check if dev is a partition */ +- if (dm_snprintf(path, sizeof(path), "%s/dev/block/%d:%d/partition", +- sysfs_dir, major, minor) < 0) { +- log_error("dm_snprintf partition failed"); +- goto out; +- } +- +- if (stat(path, &info) == -1) { +- if (errno != ENOENT) +- log_sys_error("stat", path); ++ if (!_has_sys_partition(dev)) { + *result = dev->dev; + ret = 1; + goto out; /* dev is not a partition! */ +diff --git a/lib/device/dev-type.h b/lib/device/dev-type.h +index fdf7791..8b94b79 100644 +--- a/lib/device/dev-type.h ++++ b/lib/device/dev-type.h +@@ -95,6 +95,8 @@ int dev_is_rotational(struct dev_types *dt, struct device *dev); + + int dev_is_pmem(struct device *dev); + ++int dev_is_nvme(struct dev_types *dt, struct device *dev); ++ + int dev_is_lv(struct device *dev); + + int get_fs_block_size(struct device *dev, uint32_t *fs_block_size); +diff --git a/lib/device/device.h b/lib/device/device.h +index a58bff8..816db31 100644 +--- a/lib/device/device.h ++++ b/lib/device/device.h +@@ -38,6 +38,7 @@ + #define DEV_SCAN_FOUND_LABEL 0x00010000 /* label scan read dev and found label */ + #define DEV_IS_MD_COMPONENT 0x00020000 /* device is an md component */ + #define DEV_UDEV_INFO_MISSING 0x00040000 /* we have no udev info for this device */ ++#define DEV_IS_NVME 0x00080000 /* set if dev is nvme */ + + /* + * Support for external device info. +diff --git a/lib/filters/filter-mpath.c b/lib/filters/filter-mpath.c +index 85d1625..40e7df6 100644 +--- a/lib/filters/filter-mpath.c ++++ b/lib/filters/filter-mpath.c +@@ -16,6 +16,7 @@ + #include "lib/misc/lib.h" + #include "lib/filters/filter.h" + #include "lib/activate/activate.h" ++#include "lib/commands/toolcontext.h" + #ifdef UDEV_SYNC_SUPPORT + #include + #include "lib/device/dev-ext-udev-constants.h" +@@ -27,7 +28,6 @@ + + #define MPATH_PREFIX "mpath-" + +- + struct mpath_priv { + struct dm_pool *mem; + struct dev_filter f; +@@ -35,6 +35,9 @@ struct mpath_priv { + struct dm_hash_table *hash; + }; + ++/* ++ * given "/dev/foo" return "foo" ++ */ + static const char *_get_sysfs_name(struct device *dev) + { + const char *name; +@@ -53,6 +56,11 @@ static const char *_get_sysfs_name(struct device *dev) + return name; + } + ++/* ++ * given major:minor ++ * readlink translates /sys/dev/block/major:minor to /sys/.../foo ++ * from /sys/.../foo return "foo" ++ */ + static const char *_get_sysfs_name_by_devt(const char *sysfs_dir, dev_t devno, + char *buf, size_t buf_size) + { +@@ -102,27 +110,28 @@ static int _get_sysfs_string(const char *path, char *buffer, int max_size) + return r; + } + +-static int _get_sysfs_get_major_minor(const char *sysfs_dir, const char *kname, int *major, int *minor) ++static int _get_sysfs_dm_mpath(struct dev_types *dt, const char *sysfs_dir, const char *holder_name) + { +- char path[PATH_MAX], buffer[64]; ++ char path[PATH_MAX]; ++ char buffer[128]; + +- if (dm_snprintf(path, sizeof(path), "%s/block/%s/dev", sysfs_dir, kname) < 0) { ++ if (dm_snprintf(path, sizeof(path), "%sblock/%s/dm/uuid", sysfs_dir, holder_name) < 0) { + log_error("Sysfs path string is too long."); + return 0; + } + ++ buffer[0] = '\0'; ++ + if (!_get_sysfs_string(path, buffer, sizeof(buffer))) + return_0; + +- if (sscanf(buffer, "%d:%d", major, minor) != 2) { +- log_error("Failed to parse major minor from %s", buffer); +- return 0; +- } ++ if (!strncmp(buffer, MPATH_PREFIX, 6)) ++ return 1; + +- return 1; ++ return 0; + } + +-static int _get_parent_mpath(const char *dir, char *name, int max_size) ++static int _get_holder_name(const char *dir, char *name, int max_size) + { + struct dirent *d; + DIR *dr; +@@ -155,7 +164,7 @@ static int _get_parent_mpath(const char *dir, char *name, int max_size) + } + + #ifdef UDEV_SYNC_SUPPORT +-static int _udev_dev_is_mpath(struct device *dev) ++static int _udev_dev_is_mpath_component(struct device *dev) + { + const char *value; + struct dev_ext *ext; +@@ -174,95 +183,148 @@ static int _udev_dev_is_mpath(struct device *dev) + return 0; + } + #else +-static int _udev_dev_is_mpath(struct device *dev) ++static int _udev_dev_is_mpath_component(struct device *dev) + { + return 0; + } + #endif + +-static int _native_dev_is_mpath(struct dev_filter *f, struct device *dev) ++static int _native_dev_is_mpath_component(struct cmd_context *cmd, struct dev_filter *f, struct device *dev) + { + struct mpath_priv *mp = (struct mpath_priv *) f->private; + struct dev_types *dt = mp->dt; +- const char *part_name, *name; +- struct stat info; +- char path[PATH_MAX], parent_name[PATH_MAX]; ++ const char *part_name; ++ const char *name; /* e.g. "sda" for "/dev/sda" */ ++ char link_path[PATH_MAX]; /* some obscure, unpredictable sysfs path */ ++ char holders_path[PATH_MAX]; /* e.g. "/sys/block/sda/holders/" */ ++ char dm_dev_path[PATH_MAX]; /* e.g. "/dev/dm-1" */ ++ char holder_name[128] = { 0 }; /* e.g. "dm-1" */ + const char *sysfs_dir = dm_sysfs_dir(); +- int major = MAJOR(dev->dev); +- int minor = MINOR(dev->dev); ++ int dev_major = MAJOR(dev->dev); ++ int dev_minor = MINOR(dev->dev); ++ int dm_dev_major; ++ int dm_dev_minor; ++ struct stat info; + dev_t primary_dev; + long look; + +- /* Limit this filter only to SCSI devices */ +- if (!major_is_scsi_device(dt, MAJOR(dev->dev))) ++ /* Limit this filter to SCSI or NVME devices */ ++ if (!major_is_scsi_device(dt, dev_major) && !dev_is_nvme(dt, dev)) + return 0; + + switch (dev_get_primary_dev(dt, dev, &primary_dev)) { ++ + case 2: /* The dev is partition. */ + part_name = dev_name(dev); /* name of original dev for log_debug msg */ +- if (!(name = _get_sysfs_name_by_devt(sysfs_dir, primary_dev, parent_name, sizeof(parent_name)))) ++ ++ /* gets "foo" for "/dev/foo" where "/dev/foo" comes from major:minor */ ++ if (!(name = _get_sysfs_name_by_devt(sysfs_dir, primary_dev, link_path, sizeof(link_path)))) + return_0; ++ + log_debug_devs("%s: Device is a partition, using primary " + "device %s for mpath component detection", + part_name, name); + break; ++ + case 1: /* The dev is already a primary dev. Just continue with the dev. */ ++ ++ /* gets "foo" for "/dev/foo" */ + if (!(name = _get_sysfs_name(dev))) + return_0; + break; ++ + default: /* 0, error. */ +- log_warn("Failed to get primary device for %d:%d.", major, minor); ++ log_warn("Failed to get primary device for %d:%d.", dev_major, dev_minor); + return 0; + } + +- if (dm_snprintf(path, sizeof(path), "%s/block/%s/holders", sysfs_dir, name) < 0) { ++ if (dm_snprintf(holders_path, sizeof(holders_path), "%sblock/%s/holders", sysfs_dir, name) < 0) { + log_warn("Sysfs path to check mpath is too long."); + return 0; + } + + /* also will filter out partitions */ +- if (stat(path, &info)) ++ if (stat(holders_path, &info)) + return 0; + + if (!S_ISDIR(info.st_mode)) { +- log_warn("Path %s is not a directory.", path); ++ log_warn("Path %s is not a directory.", holders_path); + return 0; + } + +- if (!_get_parent_mpath(path, parent_name, sizeof(parent_name))) ++ /* ++ * If holders dir contains an entry such as "dm-1", then this sets ++ * holder_name to "dm-1". ++ * ++ * If holders dir is empty, return 0 (this is generally where ++ * devs that are not mpath components return.) ++ */ ++ if (!_get_holder_name(holders_path, holder_name, sizeof(holder_name))) + return 0; + +- if (!_get_sysfs_get_major_minor(sysfs_dir, parent_name, &major, &minor)) +- return_0; ++ if (dm_snprintf(dm_dev_path, sizeof(dm_dev_path), "%s/%s", cmd->dev_dir, holder_name) < 0) { ++ log_warn("dm device path to check mpath is too long."); ++ return 0; ++ } + +- if (major != dt->device_mapper_major) ++ /* ++ * stat "/dev/dm-1" which is the holder of the dev we're checking ++ * dm_dev_major:dm_dev_minor come from stat("/dev/dm-1") ++ */ ++ if (stat(dm_dev_path, &info)) { ++ log_debug("filter-mpath %s holder %s stat result %d", ++ dev_name(dev), dm_dev_path, errno); + return 0; ++ } ++ dm_dev_major = (int)MAJOR(info.st_rdev); ++ dm_dev_minor = (int)MINOR(info.st_rdev); ++ ++ if (dm_dev_major != dt->device_mapper_major) { ++ log_debug_devs("filter-mpath %s holder %s %d:%d does not have dm major", ++ dev_name(dev), dm_dev_path, dm_dev_major, dm_dev_minor); ++ return 0; ++ } + +- /* Avoid repeated detection of multipath device and use first checked result */ +- look = (long) dm_hash_lookup_binary(mp->hash, &minor, sizeof(minor)); ++ /* ++ * Save the result of checking that "/dev/dm-1" is an mpath device ++ * to avoid repeating it for each path component. ++ * The minor number of "/dev/dm-1" is added to the hash table with ++ * const value 2 meaning that dm minor 1 (for /dev/dm-1) is a multipath dev ++ * and const value 1 meaning that dm minor 1 is not a multipath dev. ++ */ ++ look = (long) dm_hash_lookup_binary(mp->hash, &dm_dev_minor, sizeof(dm_dev_minor)); + if (look > 0) { +- log_debug_devs("%s(%u:%u): already checked as %sbeing mpath.", +- parent_name, major, minor, (look > 1) ? "" : "not "); ++ log_debug_devs("filter-mpath %s holder %s %u:%u already checked as %sbeing mpath.", ++ dev_name(dev), holder_name, dm_dev_major, dm_dev_minor, (look > 1) ? "" : "not "); + return (look > 1) ? 1 : 0; + } + +- if (lvm_dm_prefix_check(major, minor, MPATH_PREFIX)) { +- (void) dm_hash_insert_binary(mp->hash, &minor, sizeof(minor), (void*)2); ++ /* ++ * Returns 1 if /sys/block//dm/uuid indicates that ++ * is a dm device with dm uuid prefix mpath-. ++ * When true, will be something like "dm-1". ++ * ++ * (Is a hash table worth it to avoid reading one sysfs file?) ++ */ ++ if (_get_sysfs_dm_mpath(dt, sysfs_dir, holder_name)) { ++ log_debug_devs("filter-mpath %s holder %s %u:%u ignore mpath component", ++ dev_name(dev), holder_name, dm_dev_major, dm_dev_minor); ++ (void) dm_hash_insert_binary(mp->hash, &dm_dev_minor, sizeof(dm_dev_minor), (void*)2); + return 1; + } + +- (void) dm_hash_insert_binary(mp->hash, &minor, sizeof(minor), (void*)1); ++ (void) dm_hash_insert_binary(mp->hash, &dm_dev_minor, sizeof(dm_dev_minor), (void*)1); + + return 0; + } + +-static int _dev_is_mpath(struct dev_filter *f, struct device *dev) ++static int _dev_is_mpath_component(struct cmd_context *cmd, struct dev_filter *f, struct device *dev) + { + if (dev->ext.src == DEV_EXT_NONE) +- return _native_dev_is_mpath(f, dev); ++ return _native_dev_is_mpath_component(cmd, f, dev); + + if (dev->ext.src == DEV_EXT_UDEV) +- return _udev_dev_is_mpath(dev); ++ return _udev_dev_is_mpath_component(dev); + + log_error(INTERNAL_ERROR "Missing hook for mpath recognition " + "using external device info source %s", dev_ext_name(dev)); +@@ -272,11 +334,11 @@ static int _dev_is_mpath(struct dev_filter *f, struct device *dev) + + #define MSG_SKIPPING "%s: Skipping mpath component device" + +-static int _ignore_mpath(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name) ++static int _ignore_mpath_component(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name) + { + dev->filtered_flags &= ~DEV_FILTERED_MPATH_COMPONENT; + +- if (_dev_is_mpath(f, dev) == 1) { ++ if (_dev_is_mpath_component(cmd, f, dev) == 1) { + if (dev->ext.src == DEV_EXT_NONE) + log_debug_devs(MSG_SKIPPING, dev_name(dev)); + else +@@ -303,8 +365,8 @@ static void _destroy(struct dev_filter *f) + struct dev_filter *mpath_filter_create(struct dev_types *dt) + { + const char *sysfs_dir = dm_sysfs_dir(); +- struct dm_pool *mem; + struct mpath_priv *mp; ++ struct dm_pool *mem; + struct dm_hash_table *hash; + + if (!*sysfs_dir) { +@@ -328,19 +390,13 @@ struct dev_filter *mpath_filter_create(struct dev_types *dt) + goto bad; + } + +- if (!(mp = dm_pool_zalloc(mem, sizeof(*mp)))) { +- log_error("mpath filter allocation failed."); +- goto bad; +- } +- +- mp->f.passes_filter = _ignore_mpath; ++ mp->f.passes_filter = _ignore_mpath_component; + mp->f.destroy = _destroy; + mp->f.use_count = 0; + mp->f.private = mp; + mp->f.name = "mpath"; +- +- mp->mem = mem; + mp->dt = dt; ++ mp->mem = mem; + mp->hash = hash; + + log_debug_devs("mpath filter initialised."); diff --git a/lvm2-2_03_12-integrity-fix-segfault-on-error-path-when-replacing-.patch b/lvm2-2_03_12-integrity-fix-segfault-on-error-path-when-replacing-.patch new file mode 100644 index 0000000..d4ece0d --- /dev/null +++ b/lvm2-2_03_12-integrity-fix-segfault-on-error-path-when-replacing-.patch @@ -0,0 +1,24 @@ + lib/metadata/integrity_manip.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/lib/metadata/integrity_manip.c b/lib/metadata/integrity_manip.c +index 53ab1b3..abf90d8 100644 +--- a/lib/metadata/integrity_manip.c ++++ b/lib/metadata/integrity_manip.c +@@ -773,9 +773,13 @@ int lv_add_integrity_to_raid(struct logical_volume *lv, struct integrity_setting + bad: + log_error("Failed to add integrity."); + +- for (s = 0; s < revert_meta_lvs; s++) { +- if (!lv_remove(imeta_lvs[s])) +- log_error("New integrity metadata LV may require manual removal."); ++ if (revert_meta_lvs) { ++ for (s = 0; s < DEFAULT_RAID_MAX_IMAGES; s++) { ++ if (!imeta_lvs[s]) ++ continue; ++ if (!lv_remove(imeta_lvs[s])) ++ log_error("New integrity metadata LV may require manual removal."); ++ } + } + + if (!vg_write(vg) || !vg_commit(vg)) diff --git a/lvm2-2_03_12-label_scan-fix-missing-free-of-filtered_devs.patch b/lvm2-2_03_12-label_scan-fix-missing-free-of-filtered_devs.patch new file mode 100644 index 0000000..b5bccfb --- /dev/null +++ b/lvm2-2_03_12-label_scan-fix-missing-free-of-filtered_devs.patch @@ -0,0 +1,19 @@ + lib/label/label.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/lib/label/label.c b/lib/label/label.c +index e067a6b..e6dd4a1 100644 +--- a/lib/label/label.c ++++ b/lib/label/label.c +@@ -1243,6 +1243,11 @@ int label_scan(struct cmd_context *cmd) + free(devl); + } + ++ dm_list_iterate_items_safe(devl, devl2, &filtered_devs) { ++ dm_list_del(&devl->list); ++ free(devl); ++ } ++ + /* + * If hints were not available/usable, then we scanned all devs, + * and we now know which are PVs. Save this list of PVs we've diff --git a/lvm2-2_03_12-lvcreate-use-lv_passes_readonly_filter.patch b/lvm2-2_03_12-lvcreate-use-lv_passes_readonly_filter.patch new file mode 100644 index 0000000..bb28cd7 --- /dev/null +++ b/lvm2-2_03_12-lvcreate-use-lv_passes_readonly_filter.patch @@ -0,0 +1,66 @@ + WHATS_NEW | 4 ++++ + lib/activate/activate.c | 5 +++++ + lib/activate/activate.h | 2 ++ + lib/metadata/lv_manip.c | 6 ++++++ + 4 files changed, 17 insertions(+) + +diff --git a/WHATS_NEW b/WHATS_NEW +index 3953c7e..c8f869c 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,5 +1,9 @@ + Version 2.03.12 - + =================================== ++ Check if lvcreate passes read_only_volume_list with tags and skips zeroing. ++ Limit pool metadata spare to 16GiB. ++ Improves conversion and allocation of pool metadata. ++ Support thin pool metadata 15.88GiB, adds 64MiB, thin_pool_crop_metadata=0. + Fix problem with wiping of converted LVs. + Fix memleak in scanning (2.03.11). + Fix corner case allocation for thin-pools. +diff --git a/lib/activate/activate.c b/lib/activate/activate.c +index 7ed6441..de866fb 100644 +--- a/lib/activate/activate.c ++++ b/lib/activate/activate.c +@@ -466,6 +466,11 @@ static int _passes_readonly_filter(struct cmd_context *cmd, + return _lv_passes_volumes_filter(cmd, lv, cn, activation_read_only_volume_list_CFG); + } + ++int lv_passes_readonly_filter(const struct logical_volume *lv) ++{ ++ return _passes_readonly_filter(lv->vg->cmd, lv); ++} ++ + int library_version(char *version, size_t size) + { + if (!activation()) +diff --git a/lib/activate/activate.h b/lib/activate/activate.h +index 3f4d128..53c8631 100644 +--- a/lib/activate/activate.h ++++ b/lib/activate/activate.h +@@ -208,6 +208,8 @@ int lvs_in_vg_opened(const struct volume_group *vg); + + int lv_is_active(const struct logical_volume *lv); + ++int lv_passes_readonly_filter(const struct logical_volume *lv); ++ + /* Check is any component LV is active */ + const struct logical_volume *lv_component_is_active(const struct logical_volume *lv); + const struct logical_volume *lv_holder_is_active(const struct logical_volume *lv); +diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c +index 445c4ad..5ff64a3 100644 +--- a/lib/metadata/lv_manip.c ++++ b/lib/metadata/lv_manip.c +@@ -7976,6 +7976,12 @@ static int _should_wipe_lv(struct lvcreate_params *lp, + first_seg(first_seg(lv)->pool_lv)->zero_new_blocks)) + return 0; + ++ if (warn && (lv_passes_readonly_filter(lv))) { ++ log_warn("WARNING: Read-only activated logical volume %s not zeroed.", ++ display_lvname(lv)); ++ return 0; ++ } ++ + /* Cannot zero read-only volume */ + if ((lv->status & LVM_WRITE) && + (lp->zero || lp->wipe_signatures)) diff --git a/lvm2-2_03_12-lvmlockd-sscanf-buffer-size-warnings.patch b/lvm2-2_03_12-lvmlockd-sscanf-buffer-size-warnings.patch new file mode 100644 index 0000000..9bc2f48 --- /dev/null +++ b/lvm2-2_03_12-lvmlockd-sscanf-buffer-size-warnings.patch @@ -0,0 +1,29 @@ + daemons/lvmlockd/lvmlockd-core.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/daemons/lvmlockd/lvmlockd-core.c b/daemons/lvmlockd/lvmlockd-core.c +index fea8ee6..c4abf66 100644 +--- a/daemons/lvmlockd/lvmlockd-core.c ++++ b/daemons/lvmlockd/lvmlockd-core.c +@@ -896,8 +896,9 @@ static int read_adopt_file(struct list_head *vg_lockd) + goto fail; + + memset(vg_uuid, 0, sizeof(vg_uuid)); ++ memset(lm_type_str, 0, sizeof(lm_type_str)); + +- if (sscanf(adopt_line, "VG: %63s %64s %16s %64s", ++ if (sscanf(adopt_line, "VG: %63s %64s %15s %64s", + vg_uuid, ls->vg_name, lm_type_str, ls->vg_args) != 4) { + goto fail; + } +@@ -916,8 +917,9 @@ static int read_adopt_file(struct list_head *vg_lockd) + r->type = LD_RT_LV; + + memset(vg_uuid, 0, sizeof(vg_uuid)); ++ memset(mode, 0, sizeof(mode)); + +- if (sscanf(adopt_line, "LV: %64s %64s %s %8s %u", ++ if (sscanf(adopt_line, "LV: %64s %64s %s %7s %u", + vg_uuid, r->name, r->lv_args, mode, &r->version) != 5) { + goto fail; + } diff --git a/lvm2-2_03_12-make-generate.patch b/lvm2-2_03_12-make-generate.patch new file mode 100644 index 0000000..2f4f682 --- /dev/null +++ b/lvm2-2_03_12-make-generate.patch @@ -0,0 +1,18 @@ + man/lvconvert.8_pregen | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/man/lvconvert.8_pregen b/man/lvconvert.8_pregen +index a47ccac..170eec8 100644 +--- a/man/lvconvert.8_pregen ++++ b/man/lvconvert.8_pregen +@@ -772,6 +772,10 @@ Add a cache to an LV, using a specified cache device. + .br + .RS 4 + .ad l ++[ \fB-c\fP|\fB--chunksize\fP \fISize\fP[k|UNIT] ] ++.ad b ++.br ++.ad l + [ \fB--cachesize\fP \fISize\fP[m|UNIT] ] + .ad b + .br diff --git a/lvm2-2_03_12-man-update-lvmthin.patch b/lvm2-2_03_12-man-update-lvmthin.patch new file mode 100644 index 0000000..f61660f --- /dev/null +++ b/lvm2-2_03_12-man-update-lvmthin.patch @@ -0,0 +1,86 @@ + man/lvmthin.7_main | 37 +++++++++++++++++++++++++------------ + 1 file changed, 25 insertions(+), 12 deletions(-) + +diff --git a/man/lvmthin.7_main b/man/lvmthin.7_main +index ce23431..e6f1d63 100644 +--- a/man/lvmthin.7_main ++++ b/man/lvmthin.7_main +@@ -394,7 +394,7 @@ the pmspare LV. + \& + + If thin pool metadata is damaged, it may be repairable. +-Checking and repairing thin pool metadata is analagous to ++Checking and repairing thin pool metadata is analogous to + running fsck/repair on a file system. + + When a thin pool LV is activated, lvm runs the thin_check command +@@ -437,14 +437,24 @@ copy to the VG's pmspare LV. + If step 1 is successful, the thin pool metadata LV is replaced + with the pmspare LV containing the corrected metadata. + The previous thin pool metadata LV, containing the damaged metadata, +-becomes visible with the new name ThinPoolLV_tmetaN (where N is 0,1,...). +- +-If the repair works, the thin pool LV and its thin LVs can be activated, +-and the LV containing the damaged thin pool metadata can be removed. +-It may be useful to move the new metadata LV (previously pmspare) to a +-better PV. +- +-If the repair does not work, the thin pool LV and its thin LVs are lost. ++becomes visible with the new name ThinPoolLV_metaN (where N is 0,1,...). ++ ++If the repair works, the thin pool LV and its thin LVs can be activated. ++User should manually check if repaired thin pool kernel metadata ++has all data for all lvm2 known LVs by individual activation of ++every thin LV. When all works, user should continue with fsck of ++all filesystems present these such volumes. ++Once the thin pool is considered fully functional user may remove ThinPoolLV_metaN ++(the LV containing the damaged thin pool metadata) for possible ++space reuse. ++For a better performance it may be useful to pvmove the new repaired metadata LV ++(written to previous pmspare volume) to a better PV (i.e. SSD) ++ ++If the repair operation fails, the thin pool LV and its thin LVs ++are not accessible and it may be necessary to restore their content ++from a backup. In such case the content of unmodified original damaged ++ThinPoolLV_metaN volume can be used by your support for more ++advanced recovery methods. + + If metadata is manually restored with thin_repair directly, + the pool metadata LV can be manually swapped with another LV +@@ -452,6 +462,9 @@ containing new metadata: + + .B lvconvert --thinpool VG/ThinPoolLV --poolmetadata VG/NewThinMetaLV + ++Note: Thin pool metadata is compact so even small corruptions ++in them may result in significant portions of mappings to be lost. ++It is recommended to use fast resilient storage for them. + + .SS Activation of thin snapshots + +@@ -549,7 +562,7 @@ Command to extend thin pool data space: + .fi + + Other methods of increasing free data space in a thin pool LV +-include removing a thin LV and its related snapsots, or running ++include removing a thin LV and its related snapshots, or running + fstrim on the file system using a thin LV. + + +@@ -689,7 +702,7 @@ with two configuration settings: + .B thin_pool_autoextend_threshold + .br + is a percentage full value that defines when the thin pool LV should be +-extended. Setting this to 100 disables automatic extention. The minimum ++extended. Setting this to 100 disables automatic extension. The minimum + value is 50. + + .BR lvm.conf (5) +@@ -716,7 +729,7 @@ the --ignoremonitoring option can be used. With this option, the command + will not ask dmeventd to monitor the thin pool LV. + + .IP \[bu] +-Setting thin_pool_autoextend_threshould to 100 disables automatic ++Setting thin_pool_autoextend_threshold to 100 disables automatic + extension of thin pool LVs, even if they are being monitored by dmeventd. + + .P diff --git a/lvm2-2_03_12-pool-limit-pmspare-to-16GiB.patch b/lvm2-2_03_12-pool-limit-pmspare-to-16GiB.patch new file mode 100644 index 0000000..b41b370 --- /dev/null +++ b/lvm2-2_03_12-pool-limit-pmspare-to-16GiB.patch @@ -0,0 +1,39 @@ + lib/metadata/pool_manip.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/lib/metadata/pool_manip.c b/lib/metadata/pool_manip.c +index b67882e..1975cb4 100644 +--- a/lib/metadata/pool_manip.c ++++ b/lib/metadata/pool_manip.c +@@ -697,6 +697,8 @@ static struct logical_volume *_alloc_pool_metadata_spare(struct volume_group *vg + int handle_pool_metadata_spare(struct volume_group *vg, uint32_t extents, + struct dm_list *pvh, int poolmetadataspare) + { ++ /* Max usable size of any spare volume is currently 16GiB rouned to extent size */ ++ const uint64_t MAX_SIZE = (UINT64_C(2 * 16) * 1024 * 1024 + vg->extent_size - 1) / vg->extent_size; + struct logical_volume *lv = vg->pool_metadata_spare_lv; + uint32_t seg_mirrors; + struct lv_segment *seg; +@@ -706,8 +708,11 @@ int handle_pool_metadata_spare(struct volume_group *vg, uint32_t extents, + /* Find maximal size of metadata LV */ + dm_list_iterate_items(lvl, &vg->lvs) + if (lv_is_pool_metadata(lvl->lv) && +- (lvl->lv->le_count > extents)) ++ (lvl->lv->le_count > extents)) { + extents = lvl->lv->le_count; ++ if (extents >= MAX_SIZE) ++ break; ++ } + + if (!poolmetadataspare) { + /* TODO: Not showing when lvm.conf would define 'n' ? */ +@@ -718,6 +723,9 @@ int handle_pool_metadata_spare(struct volume_group *vg, uint32_t extents, + return 1; + } + ++ if (extents > MAX_SIZE) ++ extents = MAX_SIZE; ++ + if (!lv) { + if (!_alloc_pool_metadata_spare(vg, extents, pvh)) + return_0; diff --git a/lvm2-2_03_12-pools-fix-removal-of-spare-volume.patch b/lvm2-2_03_12-pools-fix-removal-of-spare-volume.patch new file mode 100644 index 0000000..bec2210 --- /dev/null +++ b/lvm2-2_03_12-pools-fix-removal-of-spare-volume.patch @@ -0,0 +1,92 @@ + lib/metadata/lv_manip.c | 48 ++++++++++++++++++++++++------------------------ + 1 file changed, 24 insertions(+), 24 deletions(-) + +diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c +index 443d32c..c740ba2 100644 +--- a/lib/metadata/lv_manip.c ++++ b/lib/metadata/lv_manip.c +@@ -1470,6 +1470,8 @@ static int _lv_reduce(struct logical_volume *lv, uint32_t extents, int delete) + struct logical_volume *external_lv = NULL; + int is_raid10 = 0; + uint32_t data_copies = 0; ++ struct lv_list *lvl; ++ int is_last_pool = lv_is_pool(lv); + + if (!dm_list_empty(&lv->segments)) { + seg = first_seg(lv); +@@ -1581,6 +1583,28 @@ static int _lv_reduce(struct logical_volume *lv, uint32_t extents, int delete) + !lv_update_and_reload(external_lv)) + return_0; + ++ /* When removing last pool, automatically drop the spare volume */ ++ if (is_last_pool && lv->vg->pool_metadata_spare_lv) { ++ /* TODO: maybe use a list of pools or a counter to avoid linear search through VG */ ++ dm_list_iterate_items(lvl, &lv->vg->lvs) ++ if (lv_is_thin_type(lvl->lv) || ++ lv_is_cache_type(lvl->lv)) { ++ is_last_pool = 0; ++ break; ++ } ++ ++ if (is_last_pool) { ++ /* This is purely internal LV volume, no question */ ++ if (!deactivate_lv(lv->vg->cmd, lv->vg->pool_metadata_spare_lv)) { ++ log_error("Unable to deactivate spare logical volume %s.", ++ display_lvname(lv->vg->pool_metadata_spare_lv)); ++ return 0; ++ } ++ if (!lv_remove(lv->vg->pool_metadata_spare_lv)) ++ return_0; ++ } ++ } ++ + return 1; + } + +@@ -6433,10 +6457,8 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv, + struct logical_volume *lock_lv = lv; + struct lv_segment *cache_seg = NULL; + int ask_discard; +- struct lv_list *lvl; + struct seg_list *sl; + struct lv_segment *seg = first_seg(lv); +- int is_last_pool = lv_is_pool(lv); + + vg = lv->vg; + +@@ -6558,9 +6580,6 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv, + */ + struct logical_volume *cachevol_lv = first_seg(lv)->pool_lv; + +- if (lv_is_cache_pool(cachevol_lv)) +- is_last_pool = 1; +- + if (!archive(vg)) + return_0; + +@@ -6667,25 +6686,6 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv, + return 0; + } + +- if (is_last_pool && vg->pool_metadata_spare_lv) { +- /* When removed last pool, also remove the spare */ +- dm_list_iterate_items(lvl, &vg->lvs) +- if (lv_is_pool_metadata(lvl->lv)) { +- is_last_pool = 0; +- break; +- } +- if (is_last_pool) { +- /* This is purely internal LV volume, no question */ +- if (!deactivate_lv(cmd, vg->pool_metadata_spare_lv)) { +- log_error("Unable to deactivate spare logical volume %s.", +- display_lvname(vg->pool_metadata_spare_lv)); +- return 0; +- } +- if (!lv_remove(vg->pool_metadata_spare_lv)) +- return_0; +- } +- } +- + /* store it on disks */ + if (!vg_write(vg) || !vg_commit(vg)) + return_0; diff --git a/lvm2-2_03_12-pvck-fix-warning-and-exit-code-for-non-4k-mda1-offse.patch b/lvm2-2_03_12-pvck-fix-warning-and-exit-code-for-non-4k-mda1-offse.patch new file mode 100644 index 0000000..63020bd --- /dev/null +++ b/lvm2-2_03_12-pvck-fix-warning-and-exit-code-for-non-4k-mda1-offse.patch @@ -0,0 +1,24 @@ + tools/pvck.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/tools/pvck.c b/tools/pvck.c +index c36e182..88350de 100644 +--- a/tools/pvck.c ++++ b/tools/pvck.c +@@ -1140,9 +1140,13 @@ static int _dump_label_and_pv_header(struct cmd_context *cmd, uint64_t labelsect + *mda1_offset = xlate64(dlocn->offset); + *mda1_size = xlate64(dlocn->size); + +- if (*mda1_offset != 4096) { +- log_print("CHECK: pv_header.disk_locn[%d].offset expected 4096 # for first mda", di); +- bad++; ++ /* ++ * mda1 offset is page size from machine that created it, ++ * warn if it's not one of the expected page sizes. ++ */ ++ if ((*mda1_offset != 4096) && (*mda1_offset != 8192) && (*mda1_offset != 65536)) { ++ log_print("WARNING: pv_header.disk_locn[%d].offset %llu is unexpected # for first mda", ++ di, (unsigned long long)*mda1_offset); + } + } else { + *mda2_offset = xlate64(dlocn->offset); diff --git a/lvm2-2_03_12-test-check-read_only_volume_list-tagging-works.patch b/lvm2-2_03_12-test-check-read_only_volume_list-tagging-works.patch new file mode 100644 index 0000000..bdcc15b --- /dev/null +++ b/lvm2-2_03_12-test-check-read_only_volume_list-tagging-works.patch @@ -0,0 +1,19 @@ + test/shell/tags.sh | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/test/shell/tags.sh b/test/shell/tags.sh +index fd1b332..5b636a8 100644 +--- a/test/shell/tags.sh ++++ b/test/shell/tags.sh +@@ -52,6 +52,11 @@ check lv_field @firstlvtag1 tags "firstlvtag1" + not check lv_field @secondlvtag1 tags "firstlvtag1" + check lv_field $vg1/$lv2 tags "secondlvtag1" + not check lv_field $vg1/$lv1 tags "secondlvtag1" ++ ++# LV is not zeroed when tag matches read only volume list ++lvcreate -l1 $vg1 --addtag "RO" --config "activation/read_only_volume_list = [ \"@RO\" ]" 2>&1 | tee out ++grep "not zeroed" out ++ + vgremove -f $vg1 + + # lvchange with --addtag and --deltag diff --git a/lvm2-2_03_12-tests-check-16G-thin-pool-metadata-size.patch b/lvm2-2_03_12-tests-check-16G-thin-pool-metadata-size.patch new file mode 100644 index 0000000..ae05b76 --- /dev/null +++ b/lvm2-2_03_12-tests-check-16G-thin-pool-metadata-size.patch @@ -0,0 +1,98 @@ + test/shell/thin-16g.sh | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 88 insertions(+) + create mode 100644 test/shell/thin-16g.sh + +diff --git a/test/shell/thin-16g.sh b/test/shell/thin-16g.sh +new file mode 100644 +index 0000000..ee7e22e +--- /dev/null ++++ b/test/shell/thin-16g.sh +@@ -0,0 +1,88 @@ ++#!/usr/bin/env bash ++ ++# Copyright (C) 2021 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 usability of 16g thin pool metadata LV ++ ++ ++SKIP_WITH_LVMPOLLD=1 ++ ++. lib/inittest ++ ++aux have_thin 1 0 0 || skip ++ ++aux prepare_vg 1 50000 ++ ++lvcreate -T -L10 --poolmetadatasize 16g $vg/pool ++check lv_field $vg/pool_tmeta size "<15.88g" ++lvremove -f $vg ++ ++# Cropped way ++lvcreate -T -L10 --poolmetadatasize 16g --config 'allocation/thin_pool_crop_metadata=1' $vg/pool ++check lv_field $vg/pool_tmeta size "15.81g" ++lvremove -f $vg ++ ++lvcreate -L16G -n meta $vg ++lvcreate -L10 -n pool $vg ++lvconvert --yes --thinpool $vg/pool --poolmetadata meta ++# Uncropped size 33554432 sectors - 16GiB ++dmsetup table ${vg}-pool_tmeta | grep 33554432 ++lvremove -f $vg ++ ++# Uses 20G metadata volume, but crops the size in DM table ++lvcreate -L20G -n meta $vg ++lvcreate -L10 -n pool $vg ++lvconvert --yes --thinpool $vg/pool --poolmetadata meta --config 'allocation/thin_pool_crop_metadata=1' ++check lv_field $vg/lvol0_pmspare size "16.00g" ++# Size should be cropped to 33161216 sectors ~15.81GiB ++dmsetup table ${vg}-pool_tmeta | grep 33161216 ++ ++# Also size remains unchanged with activation has no cropping, ++# but metadata have no CROP_METADATA flag set ++lvchange -an $vg ++lvchange -ay $vg ++# Size still stays cropped to 33161216 sectors ~15.81GiB ++dmsetup table ${vg}-pool_tmeta | grep 33161216 ++lvremove -f $vg ++ ++# Minimal size is 2M ++lvcreate -L1M -n meta $vg ++lvcreate -L10 -n pool $vg ++not lvconvert --yes --thinpool $vg/pool --poolmetadata meta ++lvremove -f $vg ++ ++# Uses 20G metadata volume, but crops the size in DM table ++lvcreate -L1 --poolmetadatasize 10G -T $vg/pool ++lvresize -L+10G $vg/pool_tmeta --config 'allocation/thin_pool_crop_metadata=1' ++check lv_field $vg/lvol0_pmspare size "15.81g" ++# Size should be cropped to 33161216 sectors ~15.81GiB ++dmsetup table ${vg}-pool_tmeta | grep 33161216 ++ ++# Without cropping we can grop to ~15.88GiB ++lvresize -L+10G $vg/pool_tmeta ++check lv_field $vg/lvol0_pmspare size "<15.88g" ++lvremove -f $vg ++ ++# User has already 'bigger' metadata and wants them uncropped ++lvcreate -L16G -n meta $vg ++lvcreate -L10 -n pool $vg ++lvconvert --yes --thinpool $vg/pool --poolmetadata meta --config 'allocation/thin_pool_crop_metadata=1' ++ ++# No change with cropping ++lvresize -l+1 $vg/pool_tmeta --config 'allocation/thin_pool_crop_metadata=1' ++dmsetup table ${vg}-pool_tmeta | grep 33161216 ++ ++# Resizes to 'uncropped' size 16GiB with ANY size ++lvresize -l+1 $vg/pool_tmeta ++dmsetup table ${vg}-pool_tmeta | grep 33554432 ++check lv_field $vg/pool_tmeta size "16.00g" ++ ++vgremove -ff $vg diff --git a/lvm2-2_03_12-tests-check-full-zeroing-of-thin-pool-metadata.patch b/lvm2-2_03_12-tests-check-full-zeroing-of-thin-pool-metadata.patch new file mode 100644 index 0000000..d7edcc7 --- /dev/null +++ b/lvm2-2_03_12-tests-check-full-zeroing-of-thin-pool-metadata.patch @@ -0,0 +1,78 @@ + test/shell/thin-zero-meta.sh | 68 ++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 68 insertions(+) + create mode 100644 test/shell/thin-zero-meta.sh + +diff --git a/test/shell/thin-zero-meta.sh b/test/shell/thin-zero-meta.sh +new file mode 100644 +index 0000000..6a15a73 +--- /dev/null ++++ b/test/shell/thin-zero-meta.sh +@@ -0,0 +1,68 @@ ++#!/usr/bin/env bash ++ ++# Copyright (C) 2021 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 how zeroing of thin-pool metadata works ++ ++SKIP_WITH_LVMLOCKD=1 ++SKIP_WITH_LVMPOLLD=1 ++ ++export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false} ++ ++. lib/inittest ++ ++# ++# Main ++# ++aux have_thin 1 3 0 || skip ++aux have_cache 1 3 0 || skip ++ ++aux prepare_vg 3 40000 ++ ++# Create mostly-zero devs only front of it has some 'real' back-end ++aux zero_dev "$dev1" "$(( $(get first_extent_sector "$dev1") + 8192 )):" ++aux zero_dev "$dev2" "$(( $(get first_extent_sector "$dev2") + 8192 )):" ++aux zero_dev "$dev3" "$(( $(get first_extent_sector "$dev3") + 8192 )):" ++ ++# Prepare randomly filled 4M LV on dev2 ++lvcreate -L16G -n $lv1 $vg "$dev2" ++dd if=/dev/urandom of="$DM_DEV_DIR/$vg/$lv1" bs=1M count=4 oflag=direct || true ++lvremove -f $vg ++ ++for i in 0 1 ++do ++ aux lvmconf "allocation/zero_metadata = $i" ++ ++ # Lvm2 should allocate metadata on dev2 ++ lvcreate -T -L10G --poolmetadatasize 16G $vg/pool "$dev1" "$dev2" ++ lvchange -an $vg ++ ++ lvs -ao+seg_pe_ranges $vg ++ lvchange -ay $vg/pool_tmeta --yes ++ ++ # Skip past 1.2M which is 'created' by thin-pool initialization ++ hexdump -C -n 200 -s 2000000 "$DM_DEV_DIR/$vg/pool_tmeta" | tee out ++ ++ # When fully zeroed, it should be zero - so almost no output from hexdump ++ case "$i" in ++ 0) test $(wc -l < out) -ge 10 ;; # should not be zeroed ++ 1) test $(wc -l < out) -le 10 ;; # should be zeroed ++ esac ++ ++ lvremove -f $vg/pool ++done ++ ++# Check lvm2 spots error during full zeroing of metadata device ++aux error_dev "$dev2" "$(( $(get first_extent_sector "$dev2") + 32 )):" ++not lvcreate -T -L10G --poolmetadatasize 16G $vg/pool "$dev1" "$dev2" |& tee err ++grep "Failed to initialize logical volume" err ++ ++vgremove -ff $vg diff --git a/lvm2-2_03_12-tests-check-support-for-online-vdo-rename.patch b/lvm2-2_03_12-tests-check-support-for-online-vdo-rename.patch new file mode 100644 index 0000000..6c5ad63 --- /dev/null +++ b/lvm2-2_03_12-tests-check-support-for-online-vdo-rename.patch @@ -0,0 +1,128 @@ + test/shell/lvcreate-vdo-cache.sh | 17 +------- + test/shell/lvrename-vdo.sh | 88 ++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 90 insertions(+), 15 deletions(-) + create mode 100644 test/shell/lvrename-vdo.sh + +diff --git a/test/shell/lvcreate-vdo-cache.sh b/test/shell/lvcreate-vdo-cache.sh +index c31cccc..6cf8437 100644 +--- a/test/shell/lvcreate-vdo-cache.sh ++++ b/test/shell/lvcreate-vdo-cache.sh +@@ -32,22 +32,9 @@ export MKE2FS_CONFIG="$TESTDIR/lib/mke2fs.conf" + + aux prepare_vg 1 9000 + +-lvcreate --vdo -L4G -V2G --name $lv1 $vg/vpool1 +- ++lvcreate --vdo -L4G -V2G --name $lv1 $vg/vpool + # Test caching VDOPoolLV +-lvcreate -H -L10 $vg/vpool1 +- +-# Current VDO target driver cannot handle online rename +-# once this will be supported - update this test +-not lvrename $vg/vpool1 $vg/vpool 2>&1 | tee out +-grep "Cannot rename" out +- +-lvchange -an $vg +- +-# Ofline should work +-lvrename $vg/vpool1 $vg/vpool +- +-lvchange -ay $vg ++lvcreate -H -L10 $vg/vpool + + mkfs.ext4 -E nodiscard "$DM_DEV_DIR/$vg/$lv1" + +diff --git a/test/shell/lvrename-vdo.sh b/test/shell/lvrename-vdo.sh +new file mode 100644 +index 0000000..1417d9f +--- /dev/null ++++ b/test/shell/lvrename-vdo.sh +@@ -0,0 +1,88 @@ ++#!/usr/bin/env bash ++ ++# Copyright (C) 2021 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 ++ ++# Check online renaming of VDO devices works ++ ++ ++SKIP_WITH_LVMPOLLD=1 ++ ++. lib/inittest ++ ++# ++# Main ++# ++ ++aux have_vdo 6 2 1 || skip ++aux have_cache 1 3 0 || skip ++aux have_raid 1 3 0 || skip ++ ++aux prepare_vg 2 5000 ++ ++lvcreate --vdo -L4G -V2G --name $lv1 $vg/vpool1 ++lvrename $vg/vpool1 vpool2 ++check lv_exists $vg $lv1 vpool2 vpool2_vdata ++ ++lvremove -ff $vg ++ ++# With version >= 6.2.3 online rename should work ++if aux have_vdo 6 2 3 ; then ++ ++### CACHE #### ++lvcreate --vdo -L4G -V2G --name $lv1 $vg/vpool1 ++lvcreate -H -L10 $vg/vpool1 ++lvrename $vg/vpool1 $vg/vpool2 ++check lv_exists $vg vpool2 vpool2_vdata ++lvremove -ff $vg ++ ++### RAID #### ++lvcreate --type raid1 -L4G --nosync --name vpool1 $vg ++lvconvert --yes --type vdo-pool $vg/vpool1 ++lvrename $vg/vpool1 $vg/vpool2 ++check lv_exists $vg vpool2 vpool2_vdata vpool2_vdata_rimage_0 ++lvremove -ff $vg ++ ++fi # >= 6.2.3 ++ ++# Check when VDO target does not support online resize ++aux lvmconf "global/vdo_disabled_features = [ \"online_rename\" ]" ++ ++ ++### CACHE #### ++lvcreate --vdo -L4G -V2G --name $lv1 $vg/vpool1 ++lvcreate -H -L10 $vg/vpool1 ++ ++# VDO target driver cannot handle online rename ++not lvrename $vg/vpool1 $vg/vpool2 2>&1 | tee out ++grep "Cannot rename" out ++ ++# Ofline should work ++lvchange -an $vg ++lvrename $vg/vpool1 $vg/vpool2 ++lvchange -ay $vg ++check lv_exists $vg $lv1 vpool2 vpool2_vdata ++lvremove -ff $vg ++ ++ ++### RAID #### ++lvcreate --type raid1 -L4G --nosync --name vpool1 $vg ++lvconvert --yes --type vdo-pool $vg/vpool1 ++not lvrename $vg/vpool1 $vg/vpool2 2>&1 | tee out ++grep "Cannot rename" out ++ ++# Ofline should work ++lvchange -an $vg ++lvrename $vg/vpool1 $vg/vpool2 ++lvchange -ay $vg ++check lv_exists $vg vpool2 vpool2_vdata vpool2_vdata_rimage_0 ++lvremove -ff $vg ++ ++vgremove -ff $vg diff --git a/lvm2-2_03_12-tests-check-thin-pool-corner-case-allocs.patch b/lvm2-2_03_12-tests-check-thin-pool-corner-case-allocs.patch new file mode 100644 index 0000000..04962b8 --- /dev/null +++ b/lvm2-2_03_12-tests-check-thin-pool-corner-case-allocs.patch @@ -0,0 +1,47 @@ + test/shell/lvcreate-thin-limits.sh | 30 ++++++++++++++++++++++++++---- + 1 file changed, 26 insertions(+), 4 deletions(-) + +diff --git a/test/shell/lvcreate-thin-limits.sh b/test/shell/lvcreate-thin-limits.sh +index 6a9c33d..5dcc160 100644 +--- a/test/shell/lvcreate-thin-limits.sh ++++ b/test/shell/lvcreate-thin-limits.sh +@@ -27,13 +27,35 @@ aux can_use_16T || skip + aux have_thin 1 0 0 || skip + which mkfs.ext4 || skip + +-aux prepare_pvs 1 16777216 ++# 16T device ++aux prepare_pvs 2 8388608 + get_devs + +-vgcreate $SHARED -s 4K "$vg" "${DEVICES[@]}" ++# gives 16777215M device ++vgcreate $SHARED -s 4M "$vg" "${DEVICES[@]}" + +-not lvcreate -T -L15.995T --poolmetadatasize 5G $vg/pool ++# For 1st. pass only single PV ++lvcreate -l100%PV --name $lv1 $vg "$dev2" + +-lvs -ao+seg_pe_ranges $vg ++for i in 1 0 ++do ++ SIZE=$(get vg_field "$vg" vg_free --units m) ++ SIZE=${SIZE%%\.*} ++ ++ # ~16T - 2 * 5G + something -> should not fit ++ not lvcreate -Zn -T -L$(( SIZE - 2 * 5 * 1024 + 1 )) --poolmetadatasize 5G $vg/pool ++ ++ check vg_field "$vg" lv_count "$i" ++ ++ # Should fit data + metadata + pmspare ++ lvcreate -Zn -T -L$(( SIZE - 2 * 5 * 1024 )) --poolmetadatasize 5G $vg/pool ++ ++ check vg_field "$vg" vg_free "0" ++ ++ lvs -ao+seg_pe_ranges $vg ++ ++ # Remove everything for 2nd. pass ++ lvremove -ff $vg ++done + + vgremove -ff $vg diff --git a/lvm2-2_03_12-tests-update-thin-and-cache-checked-messages.patch b/lvm2-2_03_12-tests-update-thin-and-cache-checked-messages.patch new file mode 100644 index 0000000..f4ccd37 --- /dev/null +++ b/lvm2-2_03_12-tests-update-thin-and-cache-checked-messages.patch @@ -0,0 +1,77 @@ + test/shell/lvconvert-thin.sh | 2 +- + test/shell/lvcreate-cache.sh | 12 +++++------- + test/shell/lvcreate-thin-big.sh | 10 +++++----- + 3 files changed, 11 insertions(+), 13 deletions(-) + +diff --git a/test/shell/lvconvert-thin.sh b/test/shell/lvconvert-thin.sh +index 1319655..ee85691 100644 +--- a/test/shell/lvconvert-thin.sh ++++ b/test/shell/lvconvert-thin.sh +@@ -128,7 +128,7 @@ lvcreate -L1T -n $lv1 $vg + lvcreate -L32G -n $lv2 $vg + # Warning about bigger then needed + lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 2>&1 | tee err +-grep "WARNING: Maximum" err ++grep -i "maximum" err + lvremove -f $vg + + +diff --git a/test/shell/lvcreate-cache.sh b/test/shell/lvcreate-cache.sh +index 2c46e21..4d9d75e 100644 +--- a/test/shell/lvcreate-cache.sh ++++ b/test/shell/lvcreate-cache.sh +@@ -27,7 +27,6 @@ aux prepare_vg 5 80000 + + aux lvmconf 'global/cache_disabled_features = [ "policy_smq" ]' + +- + ####################### + # Cache_Pool creation # + ####################### +@@ -173,17 +172,16 @@ dmsetup table ${vg}-$lv1 | grep cache # ensure it is loaded in kernel + + lvremove -f $vg + +- + # Check minimum cache pool metadata size +-lvcreate -l 1 --type cache-pool --poolmetadatasize 1 $vg 2>out +-grep "WARNING: Minimum" out ++lvcreate -l 1 --type cache-pool --poolmetadatasize 1 $vg 2>&1 | tee out ++grep -i "minimal" out ++ + + # FIXME: This test is failing in allocator with smaller VG sizes +-lvcreate -l 1 --type cache-pool --poolmetadatasize 17G $vg 2>out +-grep "WARNING: Maximum" out ++lvcreate -l 1 --type cache-pool --poolmetadatasize 17G $vg 2>&1 | tee out ++grep -i "maximum" out + + lvremove -f $vg +- + ######################################## + # Cache conversion and r/w permissions # + ######################################## +diff --git a/test/shell/lvcreate-thin-big.sh b/test/shell/lvcreate-thin-big.sh +index 0b622b7..2549035 100644 +--- a/test/shell/lvcreate-thin-big.sh ++++ b/test/shell/lvcreate-thin-big.sh +@@ -31,14 +31,14 @@ vgcreate $SHARED -s 64K "$vg" "${DEVICES[@]}" + + # Size 0 is not valid + invalid lvcreate -L4M --chunksize 128 --poolmetadatasize 0 -T $vg/pool1 2>out +-lvcreate -Zn -L4M --chunksize 128 --poolmetadatasize 16k -T $vg/pool1 2>out +-grep "WARNING: Minimum" out ++lvcreate -Zn -L4M --chunksize 128 --poolmetadatasize 16k -T $vg/pool1 2>&1 >out ++grep -i "minimal" out + # FIXME: metadata allocation fails, if PV doesn't have at least 16GB + # i.e. pool metadata device cannot be multisegment +-lvcreate -Zn -L4M --chunksize 64k --poolmetadatasize 17G -T $vg/pool2 2>out +-grep "WARNING: Maximum" out ++lvcreate -Zn -L4M --chunksize 64k --poolmetadatasize 17G -T $vg/pool2 2>&1 >out ++grep "maximum" out + check lv_field $vg/pool1_tmeta size "2.00m" +-check lv_field $vg/pool2_tmeta size "15.81g" ++check lv_field $vg/pool2_tmeta size "<15.88g" + + # Check we do report correct percent values. + lvcreate --type zero -L3G $vg -n pool3 diff --git a/lvm2-2_03_12-thin-improve-16g-support-for-thin-pool-metadata.patch b/lvm2-2_03_12-thin-improve-16g-support-for-thin-pool-metadata.patch new file mode 100644 index 0000000..8347ad4 --- /dev/null +++ b/lvm2-2_03_12-thin-improve-16g-support-for-thin-pool-metadata.patch @@ -0,0 +1,694 @@ + conf/example.conf.in | 7 +++ + device_mapper/all.h | 16 +++++-- + device_mapper/libdm-deptree.c | 39 ++++++++++++----- + lib/activate/dev_manager.c | 8 ++-- + lib/config/config_settings.h | 5 +++ + lib/config/defaults.h | 2 + + lib/format_text/flags.c | 1 + + lib/metadata/lv_manip.c | 31 ++++++++++++++ + lib/metadata/merge.c | 2 + + lib/metadata/metadata-exported.h | 11 +++++ + lib/metadata/metadata.h | 13 ++++++ + lib/metadata/pool_manip.c | 46 ++++++++++++++++++++ + lib/metadata/thin_manip.c | 92 ++++++++++++++++++++++++++-------------- + lib/thin/thin.c | 22 +++++++--- + man/lvmthin.7_main | 10 ++++- + tools/lvconvert.c | 4 ++ + tools/lvcreate.c | 2 + + 17 files changed, 256 insertions(+), 55 deletions(-) + +diff --git a/conf/example.conf.in b/conf/example.conf.in +index d149ed9..107a071 100644 +--- a/conf/example.conf.in ++++ b/conf/example.conf.in +@@ -494,6 +494,13 @@ allocation { + # This configuration option has an automatic default value. + # thin_pool_metadata_require_separate_pvs = 0 + ++ # Configuration option allocation/thin_pool_crop_metadata. ++ # Older version of lvm2 cropped pool's metadata size to 15.81 GiB. ++ # This is slightly less then the actual maximum 15.88 GiB. ++ # For compatibility with older version and use of cropped size set to 1. ++ # This configuration option has an automatic default value. ++ # thin_pool_crop_metadata = 0 ++ + # Configuration option allocation/thin_pool_zero. + # Thin pool data chunks are zeroed before they are first used. + # Zeroing with a larger thin pool chunk size reduces performance. +diff --git a/device_mapper/all.h b/device_mapper/all.h +index 1080d25..489ca1c 100644 +--- a/device_mapper/all.h ++++ b/device_mapper/all.h +@@ -1072,10 +1072,10 @@ int dm_tree_node_add_replicator_dev_target(struct dm_tree_node *node, + #define DM_THIN_MIN_DATA_BLOCK_SIZE (UINT32_C(128)) + #define DM_THIN_MAX_DATA_BLOCK_SIZE (UINT32_C(2097152)) + /* +- * Max supported size for thin pool metadata device (17112760320 bytes) +- * Limitation is hardcoded into the kernel and bigger device size +- * is not accepted. ++ * Max supported size for thin pool metadata device (17045913600 bytes) + * drivers/md/dm-thin-metadata.h THIN_METADATA_MAX_SECTORS ++ * But here DM_THIN_MAX_METADATA_SIZE got defined incorrectly ++ * Correct size is (UINT64_C(255) * ((1 << 14) - 64) * (4096 / (1 << 9))) + */ + #define DM_THIN_MAX_METADATA_SIZE (UINT64_C(255) * (1 << 14) * (4096 / (1 << 9)) - 256 * 1024) + +@@ -1088,6 +1088,16 @@ int dm_tree_node_add_thin_pool_target(struct dm_tree_node *node, + uint64_t low_water_mark, + unsigned skip_block_zeroing); + ++int dm_tree_node_add_thin_pool_target_v1(struct dm_tree_node *node, ++ uint64_t size, ++ uint64_t transaction_id, ++ const char *metadata_uuid, ++ const char *pool_uuid, ++ uint32_t data_block_size, ++ uint64_t low_water_mark, ++ unsigned skip_block_zeroing, ++ unsigned crop_metadata); ++ + /* Supported messages for thin provision target */ + typedef enum { + DM_THIN_MESSAGE_CREATE_SNAP, /* device_id, origin_id */ +diff --git a/device_mapper/libdm-deptree.c b/device_mapper/libdm-deptree.c +index 6ce956f..5b60dc9 100644 +--- a/device_mapper/libdm-deptree.c ++++ b/device_mapper/libdm-deptree.c +@@ -3979,6 +3979,24 @@ int dm_tree_node_add_thin_pool_target(struct dm_tree_node *node, + uint64_t low_water_mark, + unsigned skip_block_zeroing) + { ++ return dm_tree_node_add_thin_pool_target_v1(node, size, transaction_id, ++ metadata_uuid, pool_uuid, ++ data_block_size, ++ low_water_mark, ++ skip_block_zeroing, ++ 1); ++} ++ ++int dm_tree_node_add_thin_pool_target_v1(struct dm_tree_node *node, ++ uint64_t size, ++ uint64_t transaction_id, ++ const char *metadata_uuid, ++ const char *pool_uuid, ++ uint32_t data_block_size, ++ uint64_t low_water_mark, ++ unsigned skip_block_zeroing, ++ unsigned crop_metadata) ++{ + struct load_segment *seg, *mseg; + uint64_t devsize = 0; + +@@ -4005,17 +4023,18 @@ int dm_tree_node_add_thin_pool_target(struct dm_tree_node *node, + if (!_link_tree_nodes(node, seg->metadata)) + return_0; + +- /* FIXME: more complex target may need more tweaks */ +- dm_list_iterate_items(mseg, &seg->metadata->props.segs) { +- devsize += mseg->size; +- if (devsize > DM_THIN_MAX_METADATA_SIZE) { +- log_debug_activation("Ignoring %" PRIu64 " of device.", +- devsize - DM_THIN_MAX_METADATA_SIZE); +- mseg->size -= (devsize - DM_THIN_MAX_METADATA_SIZE); +- devsize = DM_THIN_MAX_METADATA_SIZE; +- /* FIXME: drop remaining segs */ ++ if (crop_metadata) ++ /* FIXME: more complex target may need more tweaks */ ++ dm_list_iterate_items(mseg, &seg->metadata->props.segs) { ++ devsize += mseg->size; ++ if (devsize > DM_THIN_MAX_METADATA_SIZE) { ++ log_debug_activation("Ignoring %" PRIu64 " of device.", ++ devsize - DM_THIN_MAX_METADATA_SIZE); ++ mseg->size -= (devsize - DM_THIN_MAX_METADATA_SIZE); ++ devsize = DM_THIN_MAX_METADATA_SIZE; ++ /* FIXME: drop remaining segs */ ++ } + } +- } + + if (!(seg->pool = dm_tree_find_node_by_uuid(node->dtree, pool_uuid))) { + log_error("Missing pool uuid %s.", pool_uuid); +diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c +index 8d27bd3..9a25482 100644 +--- a/lib/activate/dev_manager.c ++++ b/lib/activate/dev_manager.c +@@ -261,7 +261,7 @@ static int _info_run(const char *dlid, struct dm_info *dminfo, + int dmtask; + int with_flush; /* TODO: arg for _info_run */ + void *target = NULL; +- uint64_t target_start, target_length, start, length; ++ uint64_t target_start, target_length, start, length, length_crop = 0; + char *target_name, *target_params; + const char *devname; + +@@ -297,7 +297,7 @@ static int _info_run(const char *dlid, struct dm_info *dminfo, + /* Uses max DM_THIN_MAX_METADATA_SIZE sectors for metadata device */ + if (lv_is_thin_pool_metadata(seg_status->seg->lv) && + (length > DM_THIN_MAX_METADATA_SIZE)) +- length = DM_THIN_MAX_METADATA_SIZE; ++ length_crop = DM_THIN_MAX_METADATA_SIZE; + + /* Uses virtual size with headers for VDO pool device */ + if (lv_is_vdo_pool(seg_status->seg->lv)) +@@ -310,7 +310,9 @@ static int _info_run(const char *dlid, struct dm_info *dminfo, + target = dm_get_next_target(dmt, target, &target_start, + &target_length, &target_name, &target_params); + +- if ((start == target_start) && (length == target_length)) ++ if ((start == target_start) && ++ ((length == target_length) || ++ (length_crop && (length_crop == target_length)))) + break; /* Keep target_params when matching segment is found */ + + target_params = NULL; /* Marking this target_params unusable */ +diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h +index 3c4032e..cb4e23a 100644 +--- a/lib/config/config_settings.h ++++ b/lib/config/config_settings.h +@@ -628,6 +628,11 @@ cfg(allocation_cache_pool_max_chunks_CFG, "cache_pool_max_chunks", allocation_CF + cfg(allocation_thin_pool_metadata_require_separate_pvs_CFG, "thin_pool_metadata_require_separate_pvs", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS, vsn(2, 2, 89), NULL, 0, NULL, + "Thin pool metadata and data will always use different PVs.\n") + ++cfg(allocation_thin_pool_crop_metadata_CFG, "thin_pool_crop_metadata", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_THIN_POOL_CROP_METADATA, vsn(2, 3, 12), NULL, 0, NULL, ++ "Older version of lvm2 cropped pool's metadata size to 15.81 GiB.\n" ++ "This is slightly less then the actual maximum 15.88 GiB.\n" ++ "For compatibility with older version and use of cropped size set to 1.\n") ++ + cfg(allocation_thin_pool_zero_CFG, "thin_pool_zero", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_THIN_POOL_ZERO, vsn(2, 2, 99), NULL, 0, NULL, + "Thin pool data chunks are zeroed before they are first used.\n" + "Zeroing with a larger thin pool chunk size reduces performance.\n") +diff --git a/lib/config/defaults.h b/lib/config/defaults.h +index 708a575..bcc20cc 100644 +--- a/lib/config/defaults.h ++++ b/lib/config/defaults.h +@@ -118,6 +118,8 @@ + #define DEFAULT_THIN_REPAIR_OPTION1 "" + #define DEFAULT_THIN_REPAIR_OPTIONS_CONFIG "#S" DEFAULT_THIN_REPAIR_OPTION1 + #define DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS 0 ++#define DEFAULT_THIN_POOL_CROP_METADATA 0 ++#define DEFAULT_THIN_POOL_MAX_METADATA_SIZE_V1_KB (UINT64_C(255) * ((1 << 14) - 64) * 4) /* KB */ /* 0x3f8040 blocks */ + #define DEFAULT_THIN_POOL_MAX_METADATA_SIZE (DM_THIN_MAX_METADATA_SIZE / 2) /* KB */ + #define DEFAULT_THIN_POOL_MIN_METADATA_SIZE 2048 /* KB */ + #define DEFAULT_THIN_POOL_OPTIMAL_METADATA_SIZE (128 * 1024) /* KB */ +diff --git a/lib/format_text/flags.c b/lib/format_text/flags.c +index bc93a5d..4cee14a 100644 +--- a/lib/format_text/flags.c ++++ b/lib/format_text/flags.c +@@ -72,6 +72,7 @@ static const struct flag _lv_flags[] = { + {LV_ACTIVATION_SKIP, "ACTIVATION_SKIP", COMPATIBLE_FLAG}, + {LV_ERROR_WHEN_FULL, "ERROR_WHEN_FULL", COMPATIBLE_FLAG}, + {LV_METADATA_FORMAT, "METADATA_FORMAT", SEGTYPE_FLAG}, ++ {LV_CROP_METADATA, "CROP_METADATA", SEGTYPE_FLAG}, + {LV_CACHE_VOL, "CACHE_VOL", COMPATIBLE_FLAG}, + {LV_CACHE_USES_CACHEVOL, "CACHE_USES_CACHEVOL", SEGTYPE_FLAG}, + {LV_NOSCAN, NULL, 0}, +diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c +index 443d32c..445c4ad 100644 +--- a/lib/metadata/lv_manip.c ++++ b/lib/metadata/lv_manip.c +@@ -5384,6 +5384,8 @@ static int _lvresize_adjust_extents(struct logical_volume *lv, + uint32_t existing_extents; + uint32_t seg_size = 0; + uint32_t new_extents; ++ uint64_t max_metadata_size; ++ thin_crop_metadata_t crop; + int reducing = 0; + + seg_last = last_seg(lv); +@@ -5544,6 +5546,33 @@ static int _lvresize_adjust_extents(struct logical_volume *lv, + return 1; + } + } ++ } else if (lv_is_thin_pool_metadata(lv)) { ++ if (!(seg = get_only_segment_using_this_lv(lv))) ++ return_0; ++ ++ max_metadata_size = get_thin_pool_max_metadata_size(cmd, vg->profile, &crop); ++ ++ if (((uint64_t)lp->extents * vg->extent_size) > max_metadata_size) { ++ lp->extents = (max_metadata_size + vg->extent_size - 1) / vg->extent_size; ++ log_print_unless_silent("Reached maximum pool metadata size %s (%" PRIu32 " extents).", ++ display_size(vg->cmd, max_metadata_size), lp->extents); ++ } ++ ++ if (existing_logical_extents >= lp->extents) ++ lp->extents = existing_logical_extents; ++ ++ crop = get_thin_pool_crop_metadata(cmd, crop, (uint64_t)lp->extents * vg->extent_size); ++ ++ if (seg->crop_metadata != crop) { ++ seg->crop_metadata = crop; ++ seg->lv->status |= LV_CROP_METADATA; ++ /* Crop change require reload even if there no size change */ ++ lp->size_changed = 1; ++ log_print_unless_silent("Thin pool will use metadata without cropping."); ++ } ++ ++ if (!(seg_size = lp->extents - existing_logical_extents)) ++ return 1; /* No change in metadata size */ + } + } else { /* If reducing, find stripes, stripesize & size of last segment */ + if (lp->stripes || lp->stripe_size || lp->mirrors) +@@ -8388,6 +8417,8 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, + first_seg(lv)->chunk_size = lp->chunk_size; + first_seg(lv)->zero_new_blocks = lp->zero_new_blocks; + first_seg(lv)->discards = lp->discards; ++ if ((first_seg(lv)->crop_metadata = lp->crop_metadata) == THIN_CROP_METADATA_NO) ++ lv->status |= LV_CROP_METADATA; + if (!recalculate_pool_chunk_size_with_dev_hints(lv, lp->thin_chunk_size_calc_policy)) { + stack; + goto revert_new_lv; +diff --git a/lib/metadata/merge.c b/lib/metadata/merge.c +index 0aa2293..eff59ae 100644 +--- a/lib/metadata/merge.c ++++ b/lib/metadata/merge.c +@@ -495,6 +495,8 @@ static void _check_lv_segment(struct logical_volume *lv, struct lv_segment *seg, + seg_error("sets discards"); + if (!dm_list_empty(&seg->thin_messages)) + seg_error("sets thin_messages list"); ++ if (seg->lv->status & LV_CROP_METADATA) ++ seg_error("sets CROP_METADATA flag"); + } + + if (seg_is_thin_volume(seg)) { +diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h +index 54dc29f..0e57722 100644 +--- a/lib/metadata/metadata-exported.h ++++ b/lib/metadata/metadata-exported.h +@@ -143,6 +143,7 @@ + + #define LV_REMOVE_AFTER_RESHAPE UINT64_C(0x0400000000000000) /* LV needs to be removed after a shrinking reshape */ + #define LV_METADATA_FORMAT UINT64_C(0x0800000000000000) /* LV has segments with metadata format */ ++#define LV_CROP_METADATA UINT64_C(0x0000000000000400) /* LV - also VG CLUSTERED */ + + #define LV_RESHAPE UINT64_C(0x1000000000000000) /* Ongoing reshape (number of stripes, stripesize or raid algorithm change): + used as SEGTYPE_FLAG to prevent activation on old runtime */ +@@ -326,6 +327,12 @@ typedef enum { + } thin_discards_t; + + typedef enum { ++ THIN_CROP_METADATA_UNSELECTED = 0, /* 'auto' selects */ ++ THIN_CROP_METADATA_NO, ++ THIN_CROP_METADATA_YES, ++} thin_crop_metadata_t; ++ ++typedef enum { + CACHE_MODE_UNSELECTED = 0, + CACHE_MODE_WRITETHROUGH, + CACHE_MODE_WRITEBACK, +@@ -502,6 +509,7 @@ struct lv_segment { + uint64_t transaction_id; /* For thin_pool, thin */ + thin_zero_t zero_new_blocks; /* For thin_pool */ + thin_discards_t discards; /* For thin_pool */ ++ thin_crop_metadata_t crop_metadata; /* For thin_pool */ + struct dm_list thin_messages; /* For thin_pool */ + struct logical_volume *external_lv; /* For thin */ + struct logical_volume *pool_lv; /* For thin, cache */ +@@ -885,6 +893,8 @@ int update_thin_pool_params(struct cmd_context *cmd, + unsigned attr, + uint32_t pool_data_extents, + uint32_t *pool_metadata_extents, ++ struct logical_volume *metadata_lv, ++ unsigned *crop_metadata, + int *chunk_size_calc_method, uint32_t *chunk_size, + thin_discards_t *discards, thin_zero_t *zero_new_blocks); + +@@ -1011,6 +1021,7 @@ struct lvcreate_params { + + uint64_t permission; /* all */ + unsigned error_when_full; /* when segment supports it */ ++ thin_crop_metadata_t crop_metadata; + uint32_t read_ahead; /* all */ + int approx_alloc; /* all */ + alloc_policy_t alloc; /* all */ +diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h +index 2c22450..0f230e4 100644 +--- a/lib/metadata/metadata.h ++++ b/lib/metadata/metadata.h +@@ -512,8 +512,21 @@ int pool_below_threshold(const struct lv_segment *pool_seg); + int pool_check_overprovisioning(const struct logical_volume *lv); + int create_pool(struct logical_volume *pool_lv, const struct segment_type *segtype, + struct alloc_handle *ah, uint32_t stripes, uint32_t stripe_size); ++uint64_t get_thin_pool_max_metadata_size(struct cmd_context *cmd, struct profile *profile, ++ thin_crop_metadata_t *crop); ++thin_crop_metadata_t get_thin_pool_crop_metadata(struct cmd_context *cmd, ++ thin_crop_metadata_t crop, ++ uint64_t metadata_size); + uint64_t estimate_thin_pool_metadata_size(uint32_t data_extents, uint32_t extent_size, uint32_t chunk_size); + ++int update_pool_metadata_min_max(struct cmd_context *cmd, ++ uint32_t extent_size, ++ uint64_t min_metadata_size, /* required min */ ++ uint64_t max_metadata_size, /* writable max */ ++ uint64_t *metadata_size, /* current calculated */ ++ struct logical_volume *metadata_lv, /* name of converted LV or NULL */ ++ uint32_t *metadata_extents); /* resulting extent count */ ++ + /* + * Begin skeleton for external LVM library + */ +diff --git a/lib/metadata/pool_manip.c b/lib/metadata/pool_manip.c +index a9dc611..b67882e 100644 +--- a/lib/metadata/pool_manip.c ++++ b/lib/metadata/pool_manip.c +@@ -742,6 +742,52 @@ int handle_pool_metadata_spare(struct volume_group *vg, uint32_t extents, + return 1; + } + ++int update_pool_metadata_min_max(struct cmd_context *cmd, ++ uint32_t extent_size, ++ uint64_t min_metadata_size, /* required min */ ++ uint64_t max_metadata_size, /* writable max */ ++ uint64_t *metadata_size, /* current calculated */ ++ struct logical_volume *metadata_lv, /* name of converted LV or NULL */ ++ uint32_t *metadata_extents) /* resulting extent count */ ++{ ++ max_metadata_size = dm_round_up(max_metadata_size, extent_size); ++ min_metadata_size = dm_round_up(min_metadata_size, extent_size); ++ ++ if (*metadata_size > max_metadata_size) { ++ if (metadata_lv) { ++ log_print_unless_silent("Size %s of pool metadata volume %s is bigger then maximum usable size %s.", ++ display_size(cmd, *metadata_size), ++ display_lvname(metadata_lv), ++ display_size(cmd, max_metadata_size)); ++ } else { ++ if (*metadata_extents) ++ log_print_unless_silent("Reducing pool metadata size %s to maximum usable size %s.", ++ display_size(cmd, *metadata_size), ++ display_size(cmd, max_metadata_size)); ++ *metadata_size = max_metadata_size; ++ } ++ } else if (*metadata_size < min_metadata_size) { ++ if (metadata_lv) { ++ log_error("Can't use volume %s with size %s as pool metadata. Minimal required size is %s.", ++ display_lvname(metadata_lv), ++ display_size(cmd, *metadata_size), ++ display_size(cmd, min_metadata_size)); ++ return 0; ++ } else { ++ if (*metadata_extents) ++ log_print_unless_silent("Extending pool metadata size %s to required minimal size %s.", ++ display_size(cmd, *metadata_size), ++ display_size(cmd, min_metadata_size)); ++ *metadata_size = min_metadata_size; ++ } ++ } ++ ++ if (!(*metadata_extents = extents_from_size(cmd, *metadata_size, extent_size))) ++ return_0; ++ ++ return 1; ++} ++ + int vg_set_pool_metadata_spare(struct logical_volume *lv) + { + char new_name[NAME_LEN]; +diff --git a/lib/metadata/thin_manip.c b/lib/metadata/thin_manip.c +index 4591dd7..451c382 100644 +--- a/lib/metadata/thin_manip.c ++++ b/lib/metadata/thin_manip.c +@@ -610,9 +610,9 @@ static uint64_t _estimate_metadata_size(uint32_t data_extents, uint32_t extent_s + } + + /* Estimate maximal supportable thin pool data size for given chunk_size */ +-static uint64_t _estimate_max_data_size(uint32_t chunk_size) ++static uint64_t _estimate_max_data_size(uint64_t max_metadata_size, uint32_t chunk_size) + { +- return chunk_size * (DEFAULT_THIN_POOL_MAX_METADATA_SIZE * 2) * SECTOR_SIZE / UINT64_C(64); ++ return max_metadata_size * chunk_size * SECTOR_SIZE / UINT64_C(64); + } + + /* Estimate thin pool chunk size from data and metadata size (in sector units) */ +@@ -662,6 +662,38 @@ int get_default_allocation_thin_pool_chunk_size(struct cmd_context *cmd, struct + return 1; + } + ++/* Return max supported metadata size with selected cropping */ ++uint64_t get_thin_pool_max_metadata_size(struct cmd_context *cmd, struct profile *profile, ++ thin_crop_metadata_t *crop) ++{ ++ *crop = find_config_tree_bool(cmd, allocation_thin_pool_crop_metadata_CFG, profile) ? ++ THIN_CROP_METADATA_YES : THIN_CROP_METADATA_NO; ++ ++ return (*crop == THIN_CROP_METADATA_NO) ? ++ (2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE_V1_KB) : (2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE); ++} ++ ++/* ++ * With existing crop method, check if the metadata_size would need cropping. ++ * If not, set UNSELECTED, otherwise print some verbose info about selected cropping ++ */ ++thin_crop_metadata_t get_thin_pool_crop_metadata(struct cmd_context *cmd, ++ thin_crop_metadata_t crop, ++ uint64_t metadata_size) ++{ ++ const uint64_t crop_size = (2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE); ++ ++ if (metadata_size > crop_size) { ++ if (crop == THIN_CROP_METADATA_NO) ++ log_verbose("Using metadata size without cropping."); ++ else ++ log_verbose("Cropping metadata size to %s.", display_size(cmd, crop_size)); ++ } else ++ crop = THIN_CROP_METADATA_UNSELECTED; ++ ++ return crop; ++} ++ + int update_thin_pool_params(struct cmd_context *cmd, + struct profile *profile, + uint32_t extent_size, +@@ -669,10 +701,13 @@ int update_thin_pool_params(struct cmd_context *cmd, + unsigned attr, + uint32_t pool_data_extents, + uint32_t *pool_metadata_extents, ++ struct logical_volume *metadata_lv, ++ thin_crop_metadata_t *crop_metadata, + int *chunk_size_calc_method, uint32_t *chunk_size, + thin_discards_t *discards, thin_zero_t *zero_new_blocks) + { +- uint64_t pool_metadata_size = (uint64_t) *pool_metadata_extents * extent_size; ++ uint64_t pool_metadata_size; ++ uint64_t max_metadata_size; + uint32_t estimate_chunk_size; + uint64_t max_pool_data_size; + const char *str; +@@ -702,7 +737,9 @@ int update_thin_pool_params(struct cmd_context *cmd, + *zero_new_blocks = find_config_tree_bool(cmd, allocation_thin_pool_zero_CFG, profile) + ? THIN_ZERO_YES : THIN_ZERO_NO; + +- if (!pool_metadata_size) { ++ max_metadata_size = get_thin_pool_max_metadata_size(cmd, profile, crop_metadata); ++ ++ if (!*pool_metadata_extents) { + if (!*chunk_size) { + if (!get_default_allocation_thin_pool_chunk_size(cmd, profile, + chunk_size, +@@ -723,20 +760,20 @@ int update_thin_pool_params(struct cmd_context *cmd, + } else { + pool_metadata_size = _estimate_metadata_size(pool_data_extents, extent_size, *chunk_size); + +- if (pool_metadata_size > (DEFAULT_THIN_POOL_MAX_METADATA_SIZE * 2)) { ++ if (pool_metadata_size > max_metadata_size) { + /* Suggest bigger chunk size */ + estimate_chunk_size = + _estimate_chunk_size(pool_data_extents, extent_size, +- (DEFAULT_THIN_POOL_MAX_METADATA_SIZE * 2), attr); ++ max_metadata_size, attr); + log_warn("WARNING: Chunk size is too small for pool, suggested minimum is %s.", + display_size(cmd, estimate_chunk_size)); + } + } + + /* Round up to extent size silently */ +- if (pool_metadata_size % extent_size) +- pool_metadata_size += extent_size - pool_metadata_size % extent_size; ++ pool_metadata_size = dm_round_up(pool_metadata_size, extent_size); + } else { ++ pool_metadata_size = (uint64_t) *pool_metadata_extents * extent_size; + estimate_chunk_size = _estimate_chunk_size(pool_data_extents, extent_size, + pool_metadata_size, attr); + +@@ -751,7 +788,19 @@ int update_thin_pool_params(struct cmd_context *cmd, + } + } + +- max_pool_data_size = _estimate_max_data_size(*chunk_size); ++ /* Use not rounded max for data size */ ++ max_pool_data_size = _estimate_max_data_size(max_metadata_size, *chunk_size); ++ ++ if (!update_pool_metadata_min_max(cmd, extent_size, ++ 2 * DEFAULT_THIN_POOL_MIN_METADATA_SIZE, ++ max_metadata_size, ++ &pool_metadata_size, ++ metadata_lv, ++ pool_metadata_extents)) ++ return_0; ++ ++ *crop_metadata = get_thin_pool_crop_metadata(cmd, *crop_metadata, pool_metadata_size); ++ + if ((max_pool_data_size / extent_size) < pool_data_extents) { + log_error("Selected chunk size %s cannot address more then %s of thin pool data space.", + display_size(cmd, *chunk_size), display_size(cmd, max_pool_data_size)); +@@ -764,22 +813,6 @@ int update_thin_pool_params(struct cmd_context *cmd, + if (!validate_thin_pool_chunk_size(cmd, *chunk_size)) + return_0; + +- if (pool_metadata_size > (2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE)) { +- pool_metadata_size = 2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE; +- if (*pool_metadata_extents) +- log_warn("WARNING: Maximum supported pool metadata size is %s.", +- display_size(cmd, pool_metadata_size)); +- } else if (pool_metadata_size < (2 * DEFAULT_THIN_POOL_MIN_METADATA_SIZE)) { +- pool_metadata_size = 2 * DEFAULT_THIN_POOL_MIN_METADATA_SIZE; +- if (*pool_metadata_extents) +- log_warn("WARNING: Minimum supported pool metadata size is %s.", +- display_size(cmd, pool_metadata_size)); +- } +- +- if (!(*pool_metadata_extents = +- extents_from_size(cmd, pool_metadata_size, extent_size))) +- return_0; +- + if ((uint64_t) *chunk_size > (uint64_t) pool_data_extents * extent_size) { + log_error("Size of %s data volume cannot be smaller than chunk size %s.", + segtype->name, display_size(cmd, *chunk_size)); +@@ -958,12 +991,5 @@ int validate_thin_pool_chunk_size(struct cmd_context *cmd, uint32_t chunk_size) + + uint64_t estimate_thin_pool_metadata_size(uint32_t data_extents, uint32_t extent_size, uint32_t chunk_size) + { +- uint64_t sz = _estimate_metadata_size(data_extents, extent_size, chunk_size); +- +- if (sz > (2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE)) +- sz = 2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE; +- else if (sz < (2 * DEFAULT_THIN_POOL_MIN_METADATA_SIZE)) +- sz = 2 * DEFAULT_THIN_POOL_MIN_METADATA_SIZE; +- +- return sz; ++ return _estimate_metadata_size(data_extents, extent_size, chunk_size); + } +diff --git a/lib/thin/thin.c b/lib/thin/thin.c +index ba0da71..51bc269 100644 +--- a/lib/thin/thin.c ++++ b/lib/thin/thin.c +@@ -86,6 +86,7 @@ static int _thin_pool_text_import(struct lv_segment *seg, + struct logical_volume *pool_data_lv, *pool_metadata_lv; + const char *discards_str = NULL; + uint32_t zero = 0; ++ uint32_t crop = 0; + + if (!dm_config_get_str(sn, "metadata", &lv_name)) + return SEG_LOG_ERROR("Metadata must be a string in"); +@@ -131,6 +132,13 @@ static int _thin_pool_text_import(struct lv_segment *seg, + + seg->zero_new_blocks = (zero) ? THIN_ZERO_YES : THIN_ZERO_NO; + ++ if (dm_config_has_node(sn, "crop_metadata")) { ++ if (!dm_config_get_uint32(sn, "crop_metadata", &crop)) ++ return SEG_LOG_ERROR("Could not read crop_metadata for"); ++ seg->crop_metadata = (crop) ? THIN_CROP_METADATA_YES : THIN_CROP_METADATA_NO; ++ seg->lv->status |= LV_CROP_METADATA; ++ } ++ + /* Read messages */ + for (; sn; sn = sn->sib) + if (!(sn->v) && !_thin_pool_add_message(seg, sn->key, sn->child)) +@@ -177,6 +185,9 @@ static int _thin_pool_text_export(const struct lv_segment *seg, struct formatter + return 0; + } + ++ if (seg->crop_metadata != THIN_CROP_METADATA_UNSELECTED) ++ outf(f, "crop_metadata = %u", (seg->crop_metadata == THIN_CROP_METADATA_YES) ? 1 : 0); ++ + dm_list_iterate_items(tmsg, &seg->thin_messages) { + /* Extra validation */ + switch (tmsg->type) { +@@ -307,11 +318,12 @@ static int _thin_pool_add_target_line(struct dev_manager *dm, + else + low_water_mark = 0; + +- if (!dm_tree_node_add_thin_pool_target(node, len, +- seg->transaction_id, +- metadata_dlid, pool_dlid, +- seg->chunk_size, low_water_mark, +- (seg->zero_new_blocks == THIN_ZERO_YES) ? 0 : 1)) ++ if (!dm_tree_node_add_thin_pool_target_v1(node, len, ++ seg->transaction_id, ++ metadata_dlid, pool_dlid, ++ seg->chunk_size, low_water_mark, ++ (seg->zero_new_blocks == THIN_ZERO_YES) ? 0 : 1, ++ (seg->crop_metadata == THIN_CROP_METADATA_YES) ? 1 : 0)) + return_0; + + if (attr & THIN_FEATURE_DISCARDS) { +diff --git a/man/lvmthin.7_main b/man/lvmthin.7_main +index e6f1d63..3ce34a5 100644 +--- a/man/lvmthin.7_main ++++ b/man/lvmthin.7_main +@@ -1104,7 +1104,7 @@ The default value is shown by: + The amount of thin metadata depends on how many blocks are shared between + thin LVs (i.e. through snapshots). A thin pool with many snapshots may + need a larger metadata LV. Thin pool metadata LV sizes can be from 2MiB +-to 16GiB. ++to approximately 16GiB. + + When using lvcreate to create what will become a thin metadata LV, the + size is specified with the -L|--size option. +@@ -1119,6 +1119,14 @@ needed, so it is recommended to start with a size of 1GiB which should be + enough for all practical purposes. A thin pool metadata LV can later be + manually or automatically extended if needed. + ++Configurable setting ++.BR lvm.conf (5) ++.BR allocation / thin_pool_crop_metadata ++gives control over cropping to 15.81GiB to stay backward compatible with older ++versions of lvm2. With enabled cropping there can be observed some problems when ++using volumes above this size with thin tools (i.e. thin_repair). ++Cropping should be enabled only when compatibility is required. ++ + + .SS Create a thin snapshot of an external, read only LV + +diff --git a/tools/lvconvert.c b/tools/lvconvert.c +index 7b74afb..ce90279 100644 +--- a/tools/lvconvert.c ++++ b/tools/lvconvert.c +@@ -3032,6 +3032,7 @@ static int _lvconvert_to_pool(struct cmd_context *cmd, + const char *policy_name; + struct dm_config_tree *policy_settings = NULL; + int pool_metadata_spare; ++ thin_crop_metadata_t crop_metadata; + thin_discards_t discards; + thin_zero_t zero_new_blocks; + int r = 0; +@@ -3196,6 +3197,8 @@ static int _lvconvert_to_pool(struct cmd_context *cmd, + pool_segtype, target_attr, + lv->le_count, + &meta_extents, ++ metadata_lv, ++ &crop_metadata, + &chunk_calc, + &chunk_size, + &discards, &zero_new_blocks)) +@@ -3401,6 +3404,7 @@ static int _lvconvert_to_pool(struct cmd_context *cmd, + goto_bad; + } else { + seg->transaction_id = 0; ++ seg->crop_metadata = crop_metadata; + seg->chunk_size = chunk_size; + seg->discards = discards; + seg->zero_new_blocks = zero_new_blocks; +diff --git a/tools/lvcreate.c b/tools/lvcreate.c +index e384291..1ee9e14 100644 +--- a/tools/lvcreate.c ++++ b/tools/lvcreate.c +@@ -391,6 +391,8 @@ static int _update_extents_params(struct volume_group *vg, + lp->segtype, lp->target_attr, + lp->extents, + &lp->pool_metadata_extents, ++ NULL, ++ &lp->crop_metadata, + &lp->thin_chunk_size_calc_policy, + &lp->chunk_size, + &lp->discards, diff --git a/lvm2-2_03_12-vdo-support-online-rename.patch b/lvm2-2_03_12-vdo-support-online-rename.patch new file mode 100644 index 0000000..ab2bc0e --- /dev/null +++ b/lvm2-2_03_12-vdo-support-online-rename.patch @@ -0,0 +1,194 @@ + conf/example.conf.in | 10 ++++++++++ + lib/config/config_settings.h | 9 +++++++++ + lib/metadata/lv_manip.c | 14 +++++++++++--- + lib/metadata/segtype.h | 2 ++ + lib/vdo/vdo.c | 46 ++++++++++++++++++++++++++++++++++++-------- + 5 files changed, 70 insertions(+), 11 deletions(-) + +diff --git a/conf/example.conf.in b/conf/example.conf.in +index cd53147..d02965e 100644 +--- a/conf/example.conf.in ++++ b/conf/example.conf.in +@@ -1195,6 +1195,16 @@ global { + # This configuration option has an automatic default value. + # vdo_format_options = [ "" ] + ++ # Configuration option global/vdo_disabled_features. ++ # Features to not use in the vdo driver. ++ # This can be helpful for testing, or to avoid using a feature that is ++ # causing problems. Features include: online_rename ++ # ++ # Example ++ # vdo_disabled_features = [ "online_rename" ] ++ # ++ # This configuration option does not have a default value defined. ++ + # Configuration option global/fsadm_executable. + # The full path to the fsadm command. + # LVM uses this command to help with lvresize -r operations. +diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h +index 3c4032e..f844594 100644 +--- a/lib/config/config_settings.h ++++ b/lib/config/config_settings.h +@@ -1206,6 +1206,15 @@ cfg(global_vdo_format_executable_CFG, "vdo_format_executable", global_CFG_SECTIO + cfg_array(global_vdo_format_options_CFG, "vdo_format_options", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_VDO_FORMAT_OPTIONS_CONFIG, VDO_1ST_VSN, NULL, 0, NULL, + "List of options passed added to standard vdoformat command.\n") + ++cfg_array(global_vdo_disabled_features_CFG, "vdo_disabled_features", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 3, 11), NULL, 0, NULL, ++ "Features to not use in the vdo driver.\n" ++ "This can be helpful for testing, or to avoid using a feature that is\n" ++ "causing problems. Features include: online_rename\n" ++ "#\n" ++ "Example\n" ++ "vdo_disabled_features = [ \"online_rename\" ]\n" ++ "#\n") ++ + cfg(global_fsadm_executable_CFG, "fsadm_executable", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_FSADM_PATH, vsn(2, 2, 170), "@FSADM_PATH@", 0, NULL, + "The full path to the fsadm command.\n" + "LVM uses this command to help with lvresize -r operations.\n") +diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c +index c740ba2..6c71263 100644 +--- a/lib/metadata/lv_manip.c ++++ b/lib/metadata/lv_manip.c +@@ -4738,6 +4738,8 @@ int lv_rename_update(struct cmd_context *cmd, struct logical_volume *lv, + struct lv_names lv_names = { .old = lv->name }; + int old_lv_is_historical = lv_is_historical(lv); + int historical; ++ unsigned attrs; ++ const struct segment_type *segtype; + + /* + * rename is not allowed on sub LVs except for pools +@@ -4763,9 +4765,15 @@ int lv_rename_update(struct cmd_context *cmd, struct logical_volume *lv, + } + + if (lv_is_vdo_pool(lv) && lv_is_active(lv_lock_holder(lv))) { +- log_error("Cannot rename active VDOPOOL volume %s.", +- display_lvname(lv)); +- return 0; ++ segtype = first_seg(lv)->segtype; ++ if (!segtype->ops->target_present || ++ !segtype->ops->target_present(lv->vg->cmd, NULL, &attrs) || ++ !(attrs & VDO_FEATURE_ONLINE_RENAME)) { ++ log_error("Cannot rename active VDOPOOL volume %s, " ++ "VDO target feature support is missing.", ++ display_lvname(lv)); ++ return 0; ++ } + } + + if (update_mda && !archive(vg)) +diff --git a/lib/metadata/segtype.h b/lib/metadata/segtype.h +index 08ddc35..2714a6b 100644 +--- a/lib/metadata/segtype.h ++++ b/lib/metadata/segtype.h +@@ -349,6 +349,8 @@ int init_cache_segtypes(struct cmd_context *cmd, struct segtype_library *seglib) + int init_vdo_segtypes(struct cmd_context *cmd, struct segtype_library *seglib); + #endif + ++#define VDO_FEATURE_ONLINE_RENAME (1U << 0) /* version 6.2.3 */ ++ + int init_writecache_segtypes(struct cmd_context *cmd, struct segtype_library *seglib); + + int init_integrity_segtypes(struct cmd_context *cmd, struct segtype_library *seglib); +diff --git a/lib/vdo/vdo.c b/lib/vdo/vdo.c +index c43a5dc..bb7c784 100644 +--- a/lib/vdo/vdo.c ++++ b/lib/vdo/vdo.c +@@ -25,6 +25,7 @@ + #include "lib/metadata/segtype.h" + #include "base/memory/zalloc.h" + ++static const char _vdo_module[] = MODULE_NAME_VDO; + static unsigned _feature_mask; + + static int _bad_field(const char *field) +@@ -391,18 +392,21 @@ static int _vdo_target_present(struct cmd_context *cmd, + static const struct feature { + uint32_t maj; + uint32_t min; ++ uint32_t patchlevel; + unsigned vdo_feature; + const char *feature; + } _features[] = { +- { 1, 1, 0, "" }, +- //{ 9, 9, VDO_FEATURE_RESIZE, "resize" }, ++ { 6, 2, 3, VDO_FEATURE_ONLINE_RENAME, "online_rename" }, + }; +- //static const char _lvmconf[] = "global/vdo_disabled_features"; ++ static const char _lvmconf[] = "global/vdo_disabled_features"; + static int _vdo_checked = 0; + static int _vdo_present = 0; + static unsigned _vdo_attrs = 0; + uint32_t i, maj, min, patchlevel; + const struct segment_type *segtype; ++ const struct dm_config_node *cn; ++ const struct dm_config_value *cv; ++ const char *str; + + if (!activation()) + return 0; +@@ -419,8 +423,8 @@ static int _vdo_target_present(struct cmd_context *cmd, + } + + if (maj < 6 || (maj == 6 && min < 2)) { +- log_warn("WARNING: VDO target version %u.%u.%u is too old.", +- maj, min, patchlevel); ++ log_warn("WARNING: Target %s version %u.%u.%u is too old.", ++ _vdo_module, maj, min, patchlevel); + return 0; + } + +@@ -437,15 +441,41 @@ static int _vdo_target_present(struct cmd_context *cmd, + /* Prepare for adding supported features */ + for (i = 0; i < DM_ARRAY_SIZE(_features); ++i) + if ((maj > _features[i].maj) || +- (maj == _features[i].maj && min >= _features[i].min)) ++ ((maj == _features[i].maj) && (min > _features[i].min)) || ++ ((maj == _features[i].maj) && (min == _features[i].min) && (patchlevel >= _features[i].patchlevel))) + _vdo_attrs |= _features[i].vdo_feature; + else + log_very_verbose("Target %s does not support %s.", +- TARGET_NAME_VDO, ++ _vdo_module, + _features[i].feature); + } + + if (attributes) { ++ if (!_feature_mask) { ++ /* Support runtime lvm.conf changes, N.B. avoid 32 feature */ ++ if ((cn = find_config_tree_array(cmd, global_vdo_disabled_features_CFG, NULL))) { ++ for (cv = cn->v; cv; cv = cv->next) { ++ if (cv->type != DM_CFG_STRING) { ++ log_warn("WARNING: Ignoring invalid string in config file %s.", ++ _lvmconf); ++ continue; ++ } ++ str = cv->v.str; ++ if (!*str) ++ continue; ++ for (i = 0; i < DM_ARRAY_SIZE(_features); ++i) ++ if (strcasecmp(str, _features[i].feature) == 0) ++ _feature_mask |= _features[i].vdo_feature; ++ } ++ } ++ _feature_mask = ~_feature_mask; ++ for (i = 0; i < DM_ARRAY_SIZE(_features); ++i) ++ if ((_vdo_attrs & _features[i].vdo_feature) && ++ !(_feature_mask & _features[i].vdo_feature)) ++ log_very_verbose("Target %s %s support disabled by %s.", ++ _vdo_module, ++ _features[i].feature, _lvmconf); ++ } + *attributes = _vdo_attrs & _feature_mask; + } + +@@ -456,7 +486,7 @@ static int _vdo_modules_needed(struct dm_pool *mem, + const struct lv_segment *seg __attribute__((unused)), + struct dm_list *modules) + { +- if (!str_list_add(mem, modules, MODULE_NAME_VDO)) { ++ if (!str_list_add(mem, modules, _vdo_module)) { + log_error("String list allocation failed for VDO module."); + return 0; + } diff --git a/lvm2-2_03_12-writecache-use-cleaner-message-instead-of-table-relo.patch b/lvm2-2_03_12-writecache-use-cleaner-message-instead-of-table-relo.patch new file mode 100644 index 0000000..9f08576 --- /dev/null +++ b/lvm2-2_03_12-writecache-use-cleaner-message-instead-of-table-relo.patch @@ -0,0 +1,45 @@ + lib/metadata/writecache_manip.c | 10 +++++++--- + tools/lvconvert.c | 2 ++ + 2 files changed, 9 insertions(+), 3 deletions(-) + +diff --git a/lib/metadata/writecache_manip.c b/lib/metadata/writecache_manip.c +index 5004aa9..8150d07 100644 +--- a/lib/metadata/writecache_manip.c ++++ b/lib/metadata/writecache_manip.c +@@ -75,7 +75,7 @@ static int _get_writecache_kernel_status(struct cmd_context *cmd, + return 0; + } + +- if (!lv_info_with_seg_status(cmd, first_seg(lv), &status, 1, 1)) { ++ if (!lv_info_with_seg_status(cmd, first_seg(lv), &status, 0, 0)) { + log_error("Failed to get device mapper status for %s", display_lvname(lv)); + goto fail; + } +@@ -434,8 +434,12 @@ int lv_writecache_set_cleaner(struct logical_volume *lv) + seg->writecache_settings.cleaner_set = 1; + + if (lv_is_active(lv)) { +- if (!lv_update_and_reload(lv)) { +- log_error("Failed to update VG and reload LV."); ++ if (!vg_write(lv->vg) || !vg_commit(lv->vg)) { ++ log_error("Failed to update VG."); ++ return 0; ++ } ++ if (!lv_writecache_message(lv, "cleaner")) { ++ log_error("Failed to set writecache cleaner for %s.", display_lvname(lv)); + return 0; + } + } else { +diff --git a/tools/lvconvert.c b/tools/lvconvert.c +index 4323965..7b74afb 100644 +--- a/tools/lvconvert.c ++++ b/tools/lvconvert.c +@@ -5720,6 +5720,8 @@ static int _lvconvert_detach_writecache_when_clean(struct cmd_context *cmd, + return 0; + } + ++ log_debug("detach writecache check clean reading vg %s", id->vg_name); ++ + vg = vg_read(cmd, id->vg_name, NULL, READ_FOR_UPDATE, lockd_state, &error_flags, NULL); + + if (!vg) { diff --git a/lvm2.spec b/lvm2.spec index 370ca81..1703edd 100644 --- a/lvm2.spec +++ b/lvm2.spec @@ -1,4 +1,4 @@ -%global device_mapper_version 1.02.173 +%global device_mapper_version 1.02.175 %global enable_cache 1 %global enable_cluster 1 @@ -11,6 +11,7 @@ %global enable_testsuite 1 %global enable_vdo 1 %global enable_writecache 1 +%global enable_integrity 1 %global system_release_version 23 %global systemd_version 189-3 @@ -56,12 +57,42 @@ Name: lvm2 %if 0%{?rhel} Epoch: %{rhel} %endif -Version: 2.03.10 -Release: 2%{?dist} +Version: 2.03.11 +Release: 1%{?dist} License: GPLv2 URL: http://sourceware.org/lvm2 Source0: ftp://sourceware.org/pub/lvm2/releases/LVM2.%{version}.tgz Patch0: lvm2-set-default-preferred_names.patch +Patch3: lvm2-2_03_12-lvmlockd-sscanf-buffer-size-warnings.patch +# BZ 1915497: +Patch4: lvm2-2_03_12-alloc-enhance-estimation-of-sufficient_pes_free.patch +Patch5: lvm2-2_03_12-tests-check-thin-pool-corner-case-allocs.patch +Patch6: lvm2-2_03_12-tests-check-full-zeroing-of-thin-pool-metadata.patch +# BZ 1915580: +Patch7: lvm2-2_03_12-integrity-fix-segfault-on-error-path-when-replacing-.patch +# BZ 1872695: +Patch8: lvm2-2_03_12-devs-remove-invalid-path-name-aliases.patch +Patch9: lvm2-2_03_12-make-generate.patch +Patch10: lvm2-2_03_12-label_scan-fix-missing-free-of-filtered_devs.patch +# BZ 1917920: +Patch11: lvm2-2_03_12-pvck-fix-warning-and-exit-code-for-non-4k-mda1-offse.patch +Patch12: lvm2-2_03_12-WHATS_NEW-update.patch +# BZ 1921214: +Patch13: lvm2-2_03_12-writecache-use-cleaner-message-instead-of-table-relo.patch +# BZ 1909699: +Patch14: lvm2-2_03_12-man-update-lvmthin.patch +Patch15: lvm2-2_03_12-thin-improve-16g-support-for-thin-pool-metadata.patch +Patch16: lvm2-2_03_12-pool-limit-pmspare-to-16GiB.patch +Patch17: lvm2-2_03_12-cache-reuse-code-for-metadata-min_max.patch +Patch18: lvm2-2_03_12-tests-check-16G-thin-pool-metadata-size.patch +Patch19: lvm2-2_03_12-tests-update-thin-and-cache-checked-messages.patch +# BZ 1914389: +Patch20: lvm2-2_03_12-lvcreate-use-lv_passes_readonly_filter.patch +Patch21: lvm2-2_03_12-test-check-read_only_volume_list-tagging-works.patch +# BZ 1859659: +Patch22: lvm2-2_03_12-filter-mpath-work-with-nvme-devices.patch +# BZ 1925871: +Patch23: lvm2-2_03_12-dev_get_primary_dev-fix-invalid-path-check.patch BuildRequires: make BuildRequires: gcc @@ -118,7 +149,28 @@ or more physical volumes and creating one or more logical volumes %prep %setup -q -n LVM2.%{version} -%patch0 -p1 -b .preferred_names +%patch0 -p1 -b .backup0 +%patch3 -p1 -b .backup3 +%patch4 -p1 -b .backup4 +%patch5 -p1 -b .backup5 +%patch6 -p1 -b .backup6 +%patch7 -p1 -b .backup7 +%patch8 -p1 -b .backup8 +%patch9 -p1 -b .backup9 +%patch10 -p1 -b .backup10 +%patch11 -p1 -b .backup11 +%patch12 -p1 -b .backup12 +%patch13 -p1 -b .backup13 +%patch14 -p1 -b .backup14 +%patch15 -p1 -b .backup15 +%patch16 -p1 -b .backup16 +%patch17 -p1 -b .backup17 +%patch18 -p1 -b .backup18 +%patch19 -p1 -b .backup19 +%patch20 -p1 -b .backup20 +%patch21 -p1 -b .backup21 +%patch22 -p1 -b .backup22 +%patch23 -p1 -b .backup23 %build %global _default_pid_dir /run @@ -165,12 +217,16 @@ or more physical volumes and creating one or more logical volumes %global configure_writecache --with-writecache=internal %endif +%if %{enable_integrity} +%global configure_integrity --with-integrity=internal +%endif + # NOTE: Using CFLAGS and LDFLAGS would override the fedora default flags, thus # using paths here... export CPATH="%{_includedir}/readline5" export LIBRARY_PATH="%{_libdir}/readline5" -%configure --with-default-dm-run-dir=%{_default_dm_run_dir} --with-default-run-dir=%{_default_run_dir} --with-default-pid-dir=%{_default_pid_dir} --with-default-locking-dir=%{_default_locking_dir} --with-usrlibdir=%{_libdir} --enable-fsadm --enable-write_install --with-user= --with-group= --with-device-uid=0 --with-device-gid=6 --with-device-mode=0660 --enable-pkgconfig --enable-cmdlib --enable-dmeventd --enable-blkid_wiping %{?configure_cluster} %{?configure_cmirror} %{?configure_udev} %{?configure_thin} %{?configure_cache} %{?configure_lvmpolld} %{?configure_lockd_dlm} %{?configure_lockd_sanlock} %{?configure_lvmdbusd} %{?configure_dmfilemapd} %{?configure_writecache} %{?configure_vdo} --disable-silent-rules +%configure --with-default-dm-run-dir=%{_default_dm_run_dir} --with-default-run-dir=%{_default_run_dir} --with-default-pid-dir=%{_default_pid_dir} --with-default-locking-dir=%{_default_locking_dir} --with-usrlibdir=%{_libdir} --enable-fsadm --enable-write_install --with-user= --with-group= --with-device-uid=0 --with-device-gid=6 --with-device-mode=0660 --enable-pkgconfig --enable-cmdlib --enable-dmeventd --enable-blkid_wiping %{?configure_cluster} %{?configure_cmirror} %{?configure_udev} %{?configure_thin} %{?configure_cache} %{?configure_lvmpolld} %{?configure_lockd_dlm} %{?configure_lockd_sanlock} %{?configure_lvmdbusd} %{?configure_dmfilemapd} %{?configure_writecache} %{?configure_vdo} %{?configure_integrity} --disable-silent-rules %make_build @@ -724,6 +780,36 @@ An extensive functional testsuite for LVM2. %endif %changelog +* Mon Feb 22 2021 Marian Csontos - 2.03.11-1 +- Fix mpath filtering of NVMe devices. +- Check if lvcreate passes read_only_volume_list with tags and skips zeroing. +- Limit pool metadata spare to 16GiB. +- Improves conversion and allocation of pool metadata. +- Fix different limits used for metadata by lvm2 and thin-tools. +- Fix interrupting lvconvert --splitcache command with striped origin volumes. +- Fix problem with wiping of converted LVs. +- Fix memleak in scanning. +- Fix corner case allocation for thin-pools. +- Fix pvck handling MDA at offset different from 4096. +- Partial or degraded activation of writecache is not allowed. +- Enhance error handling in fsadm and handle correct fsck result. +- Dmeventd lvm plugin ignores higher reserved_stack lvm.conf values. +- Support using BLKZEROOUT for clearing devices. +- Fixed interrup handling. +- Fix block cache when device has too many failing writes. +- Fix block cache waiting for IO completion with failing disks. +- Add configure --enable-editline support as an alternative to readline. +- Enhance reporting and error handling when creating thin volumes. +- Enable vgsplit for VDO volumes. +- Lvextend of vdo pool volumes ensure at least 1 new VDO slab is added. +- Restore lost signal blocking while VG lock is held. +- Improve estimation of needed extents when creating thin-pool. +- Use extra 1% when resizing thin-pool metadata LV with --use-policy. +- Enhance --use-policy percentage rounding. +- Allow pvmove of writecache origin. +- Report integrity fields. +- Integrity volumes defaults to journal mode. + * Tue Jan 26 2021 Fedora Release Engineering - 2.03.10-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild diff --git a/sources b/sources index 2bb734f..8642f65 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (LVM2.2.03.10.tgz) = 8678ae2f99739ccad0250f6f4b4b8e84520f2053835985a1ea9c80196a64df31a48858aebf983170c3dfcafecea83f2c6aa630ef73fd31dd84cf1627a1b421e4 +SHA512 (LVM2.2.03.11.tgz) = 50f21337e397fc5b4692bb08e5d48409b907b96b39168343bab2d40bb74fd84ff466e15f3d664305bc044f3f6be4369fa7378399d5a838793632e74706f17653 diff --git a/upstream b/upstream index 2e03728..42be455 100644 --- a/upstream +++ b/upstream @@ -1 +1 @@ -LVM2.2.03.10.tgz +LVM2.2.03.11.tgz