62e56e
From 83a42f3e232c7c4a02deb3539972c82b6dca284b Mon Sep 17 00:00:00 2001
62e56e
From: Vojtech Trefny <vtrefny@redhat.com>
62e56e
Date: Fri, 4 Oct 2019 12:30:03 +0200
62e56e
Subject: [PATCH 1/2] Add a new "sector_size" property to storage devices.
62e56e
62e56e
This represents the logical sector size of the device.
62e56e
62e56e
Related: rhbz#1754446
62e56e
---
62e56e
 blivet/devices/disk.py      |  6 +++++-
62e56e
 blivet/devices/md.py        | 11 +++++++++++
62e56e
 blivet/devices/partition.py |  7 +++++++
62e56e
 blivet/devices/storage.py   | 15 +++++++++++++++
62e56e
 4 files changed, 38 insertions(+), 1 deletion(-)
62e56e
62e56e
diff --git a/blivet/devices/disk.py b/blivet/devices/disk.py
62e56e
index bf2f7a4f..7dfeabf0 100644
62e56e
--- a/blivet/devices/disk.py
62e56e
+++ b/blivet/devices/disk.py
62e56e
@@ -687,7 +687,7 @@ def __init__(self, device, **kwargs):
62e56e
         """
62e56e
         self.mode = kwargs.pop("mode")
62e56e
         self.devname = kwargs.pop("devname")
62e56e
-        self.sector_size = kwargs.pop("sector_size")
62e56e
+        self._sector_size = kwargs.pop("sector_size")
62e56e
 
62e56e
         DiskDevice.__init__(self, device, **kwargs)
62e56e
 
62e56e
@@ -710,3 +710,7 @@ def description(self):
62e56e
                % {'devname': self.devname,
62e56e
                   'mode': self.mode,
62e56e
                   'path': self.path}
62e56e
+
62e56e
+    @property
62e56e
+    def sector_size(self):
62e56e
+        return self._sector_size
62e56e
diff --git a/blivet/devices/md.py b/blivet/devices/md.py
62e56e
index 6a837df0..0b6da980 100644
62e56e
--- a/blivet/devices/md.py
62e56e
+++ b/blivet/devices/md.py
62e56e
@@ -19,10 +19,13 @@
62e56e
 # Red Hat Author(s): David Lehman <dlehman@redhat.com>
62e56e
 #
62e56e
 
62e56e
+import math
62e56e
 import os
62e56e
 import six
62e56e
 import time
62e56e
 
62e56e
+from six.moves import reduce
62e56e
+
62e56e
 import gi
62e56e
 gi.require_version("BlockDev", "2.0")
62e56e
 
62e56e
@@ -195,6 +198,14 @@ def level(self, value):
62e56e
 
62e56e
         self._level = level
62e56e
 
62e56e
+    @property
62e56e
+    def sector_size(self):
62e56e
+        if not self.exists:
62e56e
+            # Least common multiple of parents' sector sizes
62e56e
+            return reduce(lambda a, b: a * b // math.gcd(a, b), (int(p.sector_size) for p in self.parents))
62e56e
+
62e56e
+        return super(MDRaidArrayDevice, self).sector_size
62e56e
+
62e56e
     @property
62e56e
     def chunk_size(self):
62e56e
         if self.exists and self._chunk_size == Size(0):
62e56e
diff --git a/blivet/devices/partition.py b/blivet/devices/partition.py
62e56e
index 623e1c9d..73daa76f 100644
62e56e
--- a/blivet/devices/partition.py
62e56e
+++ b/blivet/devices/partition.py
62e56e
@@ -729,6 +729,13 @@ def protected(self):
62e56e
     def protected(self, value):
62e56e
         self._protected = value
62e56e
 
62e56e
+    @property
62e56e
+    def sector_size(self):
62e56e
+        if self.disk:
62e56e
+            return self.disk.sector_size
62e56e
+
62e56e
+        return super(PartitionDevice, self).sector_size
62e56e
+
62e56e
     def _pre_resize(self):
62e56e
         if not self.exists:
62e56e
             raise errors.DeviceError("device has not been created", self.name)
62e56e
diff --git a/blivet/devices/storage.py b/blivet/devices/storage.py
62e56e
index e087fa64..91c5e60e 100644
62e56e
--- a/blivet/devices/storage.py
62e56e
+++ b/blivet/devices/storage.py
62e56e
@@ -190,6 +190,21 @@ def raw_device(self):
62e56e
         """ The device itself, or when encrypted, the backing device. """
62e56e
         return self
62e56e
 
62e56e
+    @property
62e56e
+    def sector_size(self):
62e56e
+        """ Logical sector (block) size of this device """
62e56e
+        if not self.exists:
62e56e
+            if self.parents:
62e56e
+                return self.parents[0].sector_size
62e56e
+            else:
62e56e
+                return LINUX_SECTOR_SIZE
62e56e
+
62e56e
+        block_size = util.get_sysfs_attr(self.sysfs_path, "queue/logical_block_size")
62e56e
+        if block_size:
62e56e
+            return int(block_size)
62e56e
+        else:
62e56e
+            return LINUX_SECTOR_SIZE
62e56e
+
62e56e
     @property
62e56e
     def controllable(self):
62e56e
         return self._controllable and not flags.testing and not self.unavailable_type_dependencies()
62e56e
62e56e
From 9f81bd1ffb877862760223ba88f2086deebd2d06 Mon Sep 17 00:00:00 2001
62e56e
From: Vojtech Trefny <vtrefny@redhat.com>
62e56e
Date: Fri, 4 Oct 2019 12:37:01 +0200
62e56e
Subject: [PATCH 2/2] Do not allow creating VGs with PVs with different sector
62e56e
 size
62e56e
62e56e
New versions of LVM don't allow mixing PVs with different sector
62e56e
sizes in one VG.
62e56e
62e56e
Resolves: rhbz#1754446
62e56e
---
62e56e
 blivet/devices/lvm.py          | 12 ++++++++++++
62e56e
 tests/devices_test/lvm_test.py | 13 ++++++++++++-
62e56e
 2 files changed, 24 insertions(+), 1 deletion(-)
62e56e
62e56e
diff --git a/blivet/devices/lvm.py b/blivet/devices/lvm.py
62e56e
index 4347f483..b9da286a 100644
62e56e
--- a/blivet/devices/lvm.py
62e56e
+++ b/blivet/devices/lvm.py
62e56e
@@ -356,6 +356,18 @@ def _remove_log_vol(self, lv):
62e56e
     def _add_parent(self, parent):
62e56e
         super(LVMVolumeGroupDevice, self)._add_parent(parent)
62e56e
 
62e56e
+        # we are creating new VG or adding a new PV to an existing (complete) one
62e56e
+        if not self.exists or (self.exists and self._complete):
62e56e
+            parent_sectors = set([p.sector_size for p in self.pvs] + [parent.sector_size])
62e56e
+            if len(parent_sectors) != 1:
62e56e
+                if not self.exists:
62e56e
+                    msg = "The volume group %s cannot be created. Selected disks have " \
62e56e
+                          "inconsistent sector sizes (%s)." % (self.name, parent_sectors)
62e56e
+                else:
62e56e
+                    msg = "Disk %s cannot be added to this volume group. LVM doesn't " \
62e56e
+                          "allow using physical volumes with inconsistent (logical) sector sizes." % parent.name
62e56e
+                raise ValueError(msg)
62e56e
+
62e56e
         if (self.exists and parent.format.exists and
62e56e
                 len(self.parents) + 1 == self.pv_count):
62e56e
             self._complete = True
62e56e
diff --git a/tests/devices_test/lvm_test.py b/tests/devices_test/lvm_test.py
62e56e
index 8ed577f4..a32c1d83 100644
62e56e
--- a/tests/devices_test/lvm_test.py
62e56e
+++ b/tests/devices_test/lvm_test.py
62e56e
@@ -2,7 +2,7 @@
62e56e
 import test_compat  # pylint: disable=unused-import
62e56e
 
62e56e
 import six
62e56e
-from six.moves.mock import patch  # pylint: disable=no-name-in-module,import-error
62e56e
+from six.moves.mock import patch, PropertyMock  # pylint: disable=no-name-in-module,import-error
62e56e
 import unittest
62e56e
 
62e56e
 import blivet
62e56e
@@ -352,6 +352,17 @@ def test_target_size(self):
62e56e
         self.assertEqual(lv.target_size, orig_size)
62e56e
         self.assertEqual(lv.size, orig_size)
62e56e
 
62e56e
+    def test_lvm_inconsistent_sector_size(self):
62e56e
+        pv = StorageDevice("pv1", fmt=blivet.formats.get_format("lvmpv"),
62e56e
+                           size=Size("1024 MiB"))
62e56e
+        pv2 = StorageDevice("pv2", fmt=blivet.formats.get_format("lvmpv"),
62e56e
+                            size=Size("1024 MiB"))
62e56e
+
62e56e
+        with patch("blivet.devices.StorageDevice.sector_size", new_callable=PropertyMock) as mock_property:
62e56e
+            mock_property.__get__ = lambda _mock, pv, _class: 512 if pv.name == "pv1" else 4096
62e56e
+            with six.assertRaisesRegex(self, ValueError, "The volume group testvg cannot be created."):
62e56e
+                LVMVolumeGroupDevice("testvg", parents=[pv, pv2])
62e56e
+
62e56e
 
62e56e
 class TypeSpecificCallsTest(unittest.TestCase):
62e56e
     def test_type_specific_calls(self):