Vojtech Trefny 11326d
From dc1e2fe7783748528cac2f7aa516c89d1959b052 Mon Sep 17 00:00:00 2001
Vojtech Trefny 11326d
From: Vojtech Trefny <vtrefny@redhat.com>
Vojtech Trefny 11326d
Date: Thu, 29 Jul 2021 14:44:22 +0200
Vojtech Trefny 11326d
Subject: [PATCH] Do not set chunk size for RAID 1
Vojtech Trefny 11326d
Vojtech Trefny 11326d
Setting chunk size for RAID 1 doesn't make sense and latest
Vojtech Trefny 11326d
mdadm started returning error instead of ignoring the --chunk
Vojtech Trefny 11326d
option when creating an array.
Vojtech Trefny 11326d
Vojtech Trefny 11326d
Resolves: rhbz#1987170
Vojtech Trefny 11326d
---
Vojtech Trefny 11326d
 blivet/devicelibs/raid.py     | 12 ++++++++++
Vojtech Trefny 11326d
 blivet/devices/md.py          | 15 ++++++++++---
Vojtech Trefny 11326d
 tests/devices_test/md_test.py | 41 +++++++++++++++++++++++++++++++++--
Vojtech Trefny 11326d
 3 files changed, 63 insertions(+), 5 deletions(-)
Vojtech Trefny 11326d
Vojtech Trefny 11326d
diff --git a/blivet/devicelibs/raid.py b/blivet/devicelibs/raid.py
Vojtech Trefny 11326d
index 19c3fae98..a9e241c7a 100644
Vojtech Trefny 11326d
--- a/blivet/devicelibs/raid.py
Vojtech Trefny 11326d
+++ b/blivet/devicelibs/raid.py
Vojtech Trefny 11326d
@@ -462,6 +462,18 @@ def _pad(self, size, chunk_size):
Vojtech Trefny 11326d
     def _get_recommended_stride(self, member_count):
Vojtech Trefny 11326d
         return None
Vojtech Trefny 11326d
 
Vojtech Trefny 11326d
+    def get_size(self, member_sizes, num_members=None, chunk_size=None, superblock_size_func=None):
Vojtech Trefny 11326d
+        if not member_sizes:
Vojtech Trefny 11326d
+            return Size(0)
Vojtech Trefny 11326d
+
Vojtech Trefny 11326d
+        if num_members is None:
Vojtech Trefny 11326d
+            num_members = len(member_sizes)
Vojtech Trefny 11326d
+
Vojtech Trefny 11326d
+        min_size = min(member_sizes)
Vojtech Trefny 11326d
+        superblock_size = superblock_size_func(min_size)
Vojtech Trefny 11326d
+        min_data_size = self._trim(min_size - superblock_size, chunk_size)
Vojtech Trefny 11326d
+        return self.get_net_array_size(num_members, min_data_size)
Vojtech Trefny 11326d
+
Vojtech Trefny 11326d
 
Vojtech Trefny 11326d
 RAID1 = RAID1()
Vojtech Trefny 11326d
 ALL_LEVELS.add_raid_level(RAID1)
Vojtech Trefny 11326d
diff --git a/blivet/devices/md.py b/blivet/devices/md.py
Vojtech Trefny 11326d
index 69eee93a5..d1a2faf1f 100644
Vojtech Trefny 11326d
--- a/blivet/devices/md.py
Vojtech Trefny 11326d
+++ b/blivet/devices/md.py
Vojtech Trefny 11326d
@@ -138,7 +138,7 @@ def __init__(self, name, level=None, major=None, minor=None, size=None,
Vojtech Trefny 11326d
         if self.exists:
Vojtech Trefny 11326d
             self._chunk_size = self.read_chunk_size()
Vojtech Trefny 11326d
         else:
Vojtech Trefny 11326d
-            self._chunk_size = chunk_size or mdraid.MD_CHUNK_SIZE
Vojtech Trefny 11326d
+            self.chunk_size = chunk_size or Size(0)
Vojtech Trefny 11326d
 
Vojtech Trefny 11326d
         if not self.exists and not isinstance(metadata_version, str):
Vojtech Trefny 11326d
             self.metadata_version = "default"
Vojtech Trefny 11326d
@@ -208,8 +208,14 @@ def sector_size(self):
Vojtech Trefny 11326d
 
Vojtech Trefny 11326d
     @property
Vojtech Trefny 11326d
     def chunk_size(self):
Vojtech Trefny 11326d
-        if self.exists and self._chunk_size == Size(0):
Vojtech Trefny 11326d
-            self._chunk_size = self.read_chunk_size()
Vojtech Trefny 11326d
+        if self._chunk_size == Size(0):
Vojtech Trefny 11326d
+            if self.exists:
Vojtech Trefny 11326d
+                return self.read_chunk_size()
Vojtech Trefny 11326d
+            else:
Vojtech Trefny 11326d
+                if self.level == raid.RAID1:
Vojtech Trefny 11326d
+                    return self._chunk_size
Vojtech Trefny 11326d
+                else:
Vojtech Trefny 11326d
+                    return mdraid.MD_CHUNK_SIZE
Vojtech Trefny 11326d
         return self._chunk_size
Vojtech Trefny 11326d
 
Vojtech Trefny 11326d
     @chunk_size.setter
Vojtech Trefny 11326d
@@ -223,6 +229,9 @@ def chunk_size(self, newsize):
Vojtech Trefny 11326d
         if self.exists:
Vojtech Trefny 11326d
             raise ValueError("cannot set chunk size for an existing device")
Vojtech Trefny 11326d
 
Vojtech Trefny 11326d
+        if self.level == raid.RAID1 and newsize != Size(0):
Vojtech Trefny 11326d
+            raise ValueError("specifying chunk size is not allowed for raid1")
Vojtech Trefny 11326d
+
Vojtech Trefny 11326d
         self._chunk_size = newsize
Vojtech Trefny 11326d
 
Vojtech Trefny 11326d
     def read_chunk_size(self):
Vojtech Trefny 11326d
diff --git a/tests/devices_test/md_test.py b/tests/devices_test/md_test.py
Vojtech Trefny 11326d
index 46df76d3d..47a0fa0cc 100644
Vojtech Trefny 11326d
--- a/tests/devices_test/md_test.py
Vojtech Trefny 11326d
+++ b/tests/devices_test/md_test.py
Vojtech Trefny 11326d
@@ -1,6 +1,11 @@
Vojtech Trefny 11326d
 import six
Vojtech Trefny 11326d
 import unittest
Vojtech Trefny 11326d
 
Vojtech Trefny 11326d
+try:
Vojtech Trefny 11326d
+    from unittest.mock import patch
Vojtech Trefny 11326d
+except ImportError:
Vojtech Trefny 11326d
+    from mock import patch
Vojtech Trefny 11326d
+
Vojtech Trefny 11326d
 import blivet
Vojtech Trefny 11326d
 
Vojtech Trefny 11326d
 from blivet.devices import StorageDevice
Vojtech Trefny 11326d
@@ -27,9 +32,27 @@ def test_chunk_size1(self):
Vojtech Trefny 11326d
         raid_array = MDRaidArrayDevice(name="raid", level="raid0", member_devices=2,
Vojtech Trefny 11326d
                                        total_devices=2, parents=[member1, member2])
Vojtech Trefny 11326d
 
Vojtech Trefny 11326d
-        # no chunk_size specified -- default value
Vojtech Trefny 11326d
+        # no chunk_size specified and RAID0 -- default value
Vojtech Trefny 11326d
         self.assertEqual(raid_array.chunk_size, mdraid.MD_CHUNK_SIZE)
Vojtech Trefny 11326d
 
Vojtech Trefny 11326d
+        with patch("blivet.devices.md.blockdev.md.create") as md_create:
Vojtech Trefny 11326d
+            raid_array._create()
Vojtech Trefny 11326d
+            md_create.assert_called_with("/dev/md/raid", "raid0", ["/dev/member1", "/dev/member2"],
Vojtech Trefny 11326d
+                                         0, version="default", bitmap=False,
Vojtech Trefny 11326d
+                                         chunk_size=mdraid.MD_CHUNK_SIZE)
Vojtech Trefny 11326d
+
Vojtech Trefny 11326d
+        raid_array = MDRaidArrayDevice(name="raid", level="raid1", member_devices=2,
Vojtech Trefny 11326d
+                                       total_devices=2, parents=[member1, member2])
Vojtech Trefny 11326d
+
Vojtech Trefny 11326d
+        # no chunk_size specified and RAID1 -- no chunk size set (0)
Vojtech Trefny 11326d
+        self.assertEqual(raid_array.chunk_size, Size(0))
Vojtech Trefny 11326d
+
Vojtech Trefny 11326d
+        with patch("blivet.devices.md.blockdev.md.create") as md_create:
Vojtech Trefny 11326d
+            raid_array._create()
Vojtech Trefny 11326d
+            md_create.assert_called_with("/dev/md/raid", "raid1", ["/dev/member1", "/dev/member2"],
Vojtech Trefny 11326d
+                                         0, version="default", bitmap=True,
Vojtech Trefny 11326d
+                                         chunk_size=0)
Vojtech Trefny 11326d
+
Vojtech Trefny 11326d
     def test_chunk_size2(self):
Vojtech Trefny 11326d
 
Vojtech Trefny 11326d
         member1 = StorageDevice("member1", fmt=blivet.formats.get_format("mdmember"),
Vojtech Trefny 11326d
@@ -40,11 +63,25 @@ def test_chunk_size2(self):
Vojtech Trefny 11326d
         raid_array = MDRaidArrayDevice(name="raid", level="raid0", member_devices=2,
Vojtech Trefny 11326d
                                        total_devices=2, parents=[member1, member2],
Vojtech Trefny 11326d
                                        chunk_size=Size("1024 KiB"))
Vojtech Trefny 11326d
-
Vojtech Trefny 11326d
         self.assertEqual(raid_array.chunk_size, Size("1024 KiB"))
Vojtech Trefny 11326d
 
Vojtech Trefny 11326d
+        # for raid0 setting chunk_size = 0 means "default"
Vojtech Trefny 11326d
+        raid_array.chunk_size = Size(0)
Vojtech Trefny 11326d
+        self.assertEqual(raid_array.chunk_size, mdraid.MD_CHUNK_SIZE)
Vojtech Trefny 11326d
+
Vojtech Trefny 11326d
         with six.assertRaisesRegex(self, ValueError, "new chunk size must be of type Size"):
Vojtech Trefny 11326d
             raid_array.chunk_size = 1
Vojtech Trefny 11326d
 
Vojtech Trefny 11326d
         with six.assertRaisesRegex(self, ValueError, "new chunk size must be multiple of 4 KiB"):
Vojtech Trefny 11326d
             raid_array.chunk_size = Size("5 KiB")
Vojtech Trefny 11326d
+
Vojtech Trefny 11326d
+        with six.assertRaisesRegex(self, ValueError, "specifying chunk size is not allowed for raid1"):
Vojtech Trefny 11326d
+            MDRaidArrayDevice(name="raid", level="raid1", member_devices=2,
Vojtech Trefny 11326d
+                              total_devices=2, parents=[member1, member2],
Vojtech Trefny 11326d
+                              chunk_size=Size("1024 KiB"))
Vojtech Trefny 11326d
+
Vojtech Trefny 11326d
+        raid_array = MDRaidArrayDevice(name="raid", level="raid1", member_devices=2,
Vojtech Trefny 11326d
+                                       total_devices=2, parents=[member1, member2])
Vojtech Trefny 11326d
+
Vojtech Trefny 11326d
+        with six.assertRaisesRegex(self, ValueError, "specifying chunk size is not allowed for raid1"):
Vojtech Trefny 11326d
+            raid_array.chunk_size = Size("512 KiB")