From 06cafbbbbff0aae3634eb2908d25d0dc46c2048b Mon Sep 17 00:00:00 2001
From: Vojtech Trefny <vtrefny@redhat.com>
Date: Tue, 9 Nov 2021 15:52:48 +0100
Subject: [PATCH] Use bigger chunk size for thinpools bigger than ~15.88 TiB
With our default chunk size of 64 KiB we cannot create bigger
thin pools than 15.88 TiB. Unfortunately we need to specify chunk
size to be able to calculate thin metadata properly so we can't
simply leave this to LVM to determine the correct chunk size.
---
blivet/devicelibs/lvm.py | 11 +++++++++++
blivet/devices/lvm.py | 6 +++---
tests/devices_test/lvm_test.py | 11 +++++++++++
3 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/blivet/devicelibs/lvm.py b/blivet/devicelibs/lvm.py
index d56a76ed..cb6f655e 100644
--- a/blivet/devicelibs/lvm.py
+++ b/blivet/devicelibs/lvm.py
@@ -20,6 +20,7 @@
# Author(s): Dave Lehman <dlehman@redhat.com>
#
+import math
import os
import re
@@ -51,6 +52,7 @@ LVM_THINP_MIN_METADATA_SIZE = Size("2 MiB")
LVM_THINP_MAX_METADATA_SIZE = Size("16 GiB")
LVM_THINP_MIN_CHUNK_SIZE = Size("64 KiB")
LVM_THINP_MAX_CHUNK_SIZE = Size("1 GiB")
+LVM_THINP_ADDRESSABLE_CHUNK_SIZE = Size("17455015526400 B") # 15.88 TiB
raid_levels = raid.RAIDLevels(["linear", "striped", "raid1", "raid4", "raid5", "raid6", "raid10"])
raid_seg_types = list(itertools.chain.from_iterable([level.names for level in raid_levels if level.name != "linear"]))
@@ -225,3 +227,12 @@ def is_lvm_name_valid(name):
return False
return True
+
+
+def recommend_thpool_chunk_size(thpool_size):
+ # calculation of the recommended chunk size by LVM is so complicated that we
+ # can't really replicate it, but we know that 64 KiB chunk size gives us
+ # upper limit of ~15.88 TiB so we will just add 64 KiB to the chunk size
+ # for every ~15.88 TiB of thinpool data size
+ return min(math.ceil(thpool_size / LVM_THINP_ADDRESSABLE_CHUNK_SIZE) * LVM_THINP_MIN_CHUNK_SIZE,
+ LVM_THINP_MAX_CHUNK_SIZE)
diff --git a/blivet/devices/lvm.py b/blivet/devices/lvm.py
index 51d785d9..c61eeb4b 100644
--- a/blivet/devices/lvm.py
+++ b/blivet/devices/lvm.py
@@ -1634,9 +1634,9 @@ class LVMThinPoolMixin(object):
return
# we need to know chunk size to calculate recommended metadata size
- if self._chunk_size == 0:
- self._chunk_size = Size(blockdev.LVM_DEFAULT_CHUNK_SIZE)
- log.debug("Using default chunk size: %s", self._chunk_size)
+ if self._chunk_size == 0 or enforced:
+ self._chunk_size = lvm.recommend_thpool_chunk_size(self._size)
+ log.debug("Using recommended chunk size: %s", self._chunk_size)
old_md_size = self._metadata_size
old_pmspare_size = self.vg.pmspare_size
diff --git a/tests/devices_test/lvm_test.py b/tests/devices_test/lvm_test.py
index 4156d0bf..336c5b99 100644
--- a/tests/devices_test/lvm_test.py
+++ b/tests/devices_test/lvm_test.py
@@ -442,6 +442,17 @@ class LVMDeviceTest(unittest.TestCase):
self.assertFalse(pool.exists)
self.assertTrue(lvm.lvremove.called)
+ def test_lvmthinpool_chunk_size(self):
+ pv = StorageDevice("pv1", fmt=blivet.formats.get_format("lvmpv"),
+ size=Size("100 TiB"))
+ vg = LVMVolumeGroupDevice("testvg", parents=[pv])
+ pool = LVMLogicalVolumeDevice("pool1", parents=[vg], size=Size("500 MiB"), seg_type="thin-pool")
+ self.assertEqual(pool.chunk_size, Size("64 KiB"))
+
+ pool.size = Size("16 TiB")
+ pool.autoset_md_size(enforced=True)
+ self.assertEqual(pool.chunk_size, Size("128 KiB"))
+
class TypeSpecificCallsTest(unittest.TestCase):
def test_type_specific_calls(self):
--
2.31.1