108 lines
4.7 KiB
Diff
108 lines
4.7 KiB
Diff
From d1e237d22deeb7dde724bdc5495b5cbbe8914404 Mon Sep 17 00:00:00 2001
|
|
From: Robert Schweikert <rjschwei@suse.com>
|
|
Date: Fri, 6 Jan 2023 18:16:28 -0500
|
|
Subject: [PATCH] Use btrfs enquque when available (#1926)
|
|
|
|
Reference:https://github.com/canonical/cloud-init/commit/d1e237d22deeb7dde724bdc5495b5cbbe8914404
|
|
Conflict:cc_resizefs:format diffs.
|
|
|
|
btrfs has operations that are blocking and when we try to resize a btrfs
|
|
filesystem we may be in a race condition with blocking operations. Use the
|
|
enqueue feature introduced in btrfs 5.10 to queue our resize request until
|
|
resize if possible.
|
|
|
|
Before this commit, hitting this race would cause the command to
|
|
immediately fail. With this change, the resize is queued and the command
|
|
blocks until resize has completed (event driven, with a poll loop of 1m).
|
|
---
|
|
cloudinit/config/cc_resizefs.py | 20 ++++++++++++----
|
|
.../test_handler/test_handler_resizefs.py | 23 +++++++++++++++++--
|
|
2 files changed, 37 insertions(+), 6 deletions(-)
|
|
|
|
diff --git a/cloudinit/config/cc_resizefs.py b/cloudinit/config/cc_resizefs.py
|
|
index abb812b..61e4fe2 100644
|
|
--- a/cloudinit/config/cc_resizefs.py
|
|
+++ b/cloudinit/config/cc_resizefs.py
|
|
@@ -63,11 +63,23 @@ def _resize_btrfs(mount_point, devpth):
|
|
# solution would be walk the subvolumes and find a rw mounted subvolume.
|
|
if (not util.mount_is_read_write(mount_point) and
|
|
os.path.isdir("%s/.snapshots" % mount_point)):
|
|
- return ('btrfs', 'filesystem', 'resize', 'max',
|
|
- '%s/.snapshots' % mount_point)
|
|
+ cmd = ['btrfs', 'filesystem', 'resize', 'max',
|
|
+ '%s/.snapshots' % mount_point]
|
|
else:
|
|
- return ('btrfs', 'filesystem', 'resize', 'max', mount_point)
|
|
-
|
|
+ cmd = ['btrfs', 'filesystem', 'resize', 'max', mount_point]
|
|
+
|
|
+ # btrfs has exclusive operations and resize may fail if btrfs is busy
|
|
+ # doing one of the operations that prevents resize. As of btrfs 5.10
|
|
+ # the resize operation can be queued
|
|
+ btrfs_with_queue = util.Version.from_str("5.10")
|
|
+ system_btrfs_ver = util.Version.from_str(
|
|
+ subp.subp(["btrfs", "--version"])[0].split("v")[-1].strip()
|
|
+ )
|
|
+ if system_btrfs_ver >= btrfs_with_queue:
|
|
+ idx = cmd.index("resize")
|
|
+ cmd.insert(idx + 1, "--enqueue")
|
|
+
|
|
+ return tuple(cmd)
|
|
|
|
def _resize_ext(mount_point, devpth):
|
|
return ('resize2fs', devpth)
|
|
diff --git a/tests/unittests/test_handler/test_handler_resizefs.py b/tests/unittests/test_handler/test_handler_resizefs.py
|
|
index 695c7f5..3e77322 100644
|
|
--- a/tests/unittests/test_handler/test_handler_resizefs.py
|
|
+++ b/tests/unittests/test_handler/test_handler_resizefs.py
|
|
@@ -367,24 +367,43 @@ class TestMaybeGetDevicePathAsWritableBlock(CiTestCase):
|
|
|
|
@mock.patch('cloudinit.util.mount_is_read_write')
|
|
@mock.patch('cloudinit.config.cc_resizefs.os.path.isdir')
|
|
- def test_resize_btrfs_mount_is_ro(self, m_is_dir, m_is_rw):
|
|
+ @mock.patch("cloudinit.subp.subp")
|
|
+ def test_resize_btrfs_mount_is_ro(self, m_subp, m_is_dir, m_is_rw):
|
|
"""Do not resize / directly if it is read-only. (LP: #1734787)."""
|
|
m_is_rw.return_value = False
|
|
m_is_dir.return_value = True
|
|
+ m_subp.return_value = ("btrfs-progs v4.19 \n", "")
|
|
self.assertEqual(
|
|
('btrfs', 'filesystem', 'resize', 'max', '//.snapshots'),
|
|
_resize_btrfs("/", "/dev/sda1"))
|
|
|
|
@mock.patch('cloudinit.util.mount_is_read_write')
|
|
@mock.patch('cloudinit.config.cc_resizefs.os.path.isdir')
|
|
- def test_resize_btrfs_mount_is_rw(self, m_is_dir, m_is_rw):
|
|
+ @mock.patch("cloudinit.subp.subp")
|
|
+ def test_resize_btrfs_mount_is_rw(self, m_subp, m_is_dir, m_is_rw):
|
|
"""Do not resize / directly if it is read-only. (LP: #1734787)."""
|
|
m_is_rw.return_value = True
|
|
m_is_dir.return_value = True
|
|
+ m_subp.return_value = ("btrfs-progs v4.19 \n", "")
|
|
self.assertEqual(
|
|
('btrfs', 'filesystem', 'resize', 'max', '/'),
|
|
_resize_btrfs("/", "/dev/sda1"))
|
|
|
|
+ @mock.patch("cloudinit.util.mount_is_read_write")
|
|
+ @mock.patch("cloudinit.config.cc_resizefs.os.path.isdir")
|
|
+ @mock.patch("cloudinit.subp.subp")
|
|
+ def test_resize_btrfs_mount_is_rw_has_queue(
|
|
+ self, m_subp, m_is_dir, m_is_rw
|
|
+ ):
|
|
+ """Queue the resize request if btrfs >= 5.10"""
|
|
+ m_is_rw.return_value = True
|
|
+ m_is_dir.return_value = True
|
|
+ m_subp.return_value = ("btrfs-progs v5.10 \n", "")
|
|
+ self.assertEqual(
|
|
+ ("btrfs", "filesystem", "resize", "--enqueue", "max", "/"),
|
|
+ _resize_btrfs("/", "/dev/sda1"),
|
|
+ )
|
|
+
|
|
@mock.patch('cloudinit.util.is_container', return_value=True)
|
|
@mock.patch('cloudinit.util.is_FreeBSD')
|
|
def test_maybe_get_writable_device_path_zfs_freebsd(self, freebsd,
|
|
--
|
|
2.33.0
|
|
|
|
|