--- /dev/null
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Guillaume Abrioux <gabrioux@ibm.com>
+Date: Fri, 7 Jun 2024 10:46:16 +0200
+Subject: [PATCH] ceph-volume: fix set_dmcrypt_no_workqueue()
+
+`set_dmcrypt_no_workqueue()` from `ceph_volume.util.encryption`
+
+The function `set_dmcrypt_no_workqueue` in `encryption.py` now
+dynamically retrieves the installed cryptsetup version using `cryptsetup
+--version` command. It then parses the version string using a regular
+expression to accommodate varying digit counts. If the retrieved version
+is greater than or equal to the specified target version,
+`conf.dmcrypt_no_workqueue` is set to True, allowing for flexible version
+handling.
+
+Fixes: https://tracker.ceph.com/issues/66393
+
+Signed-off-by: Guillaume Abrioux <gabrioux@ibm.com>
+(cherry picked from commit dc28b77a6ea50b3390663ac02eeb80367650b7ed)
+(cherry picked from commit 05ea72c70e06cc70f74b459c399c43f0a8863986)
+Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
+---
+ .../ceph_volume/util/encryption.py | 44 +++++++++++++++++--
+ 1 file changed, 40 insertions(+), 4 deletions(-)
+
+diff --git a/src/ceph-volume/ceph_volume/util/encryption.py b/src/ceph-volume/ceph_volume/util/encryption.py
+index 844a81620d2..09f1cccf384 100644
+--- a/src/ceph-volume/ceph_volume/util/encryption.py
++++ b/src/ceph-volume/ceph_volume/util/encryption.py
+@@ -1,6 +1,7 @@
+ import base64
+ import os
+ import logging
++import re
+ from ceph_volume import process, conf, terminal
+ from ceph_volume.util import constants, system
+ from ceph_volume.util.device import Device
+@@ -12,14 +13,49 @@ logger = logging.getLogger(__name__)
+ mlogger = terminal.MultiLogger(__name__)
+
+ def set_dmcrypt_no_workqueue(target_version: str = '2.3.4') -> None:
+- """
+- set `conf.dmcrypt_no_workqueue` to `True` if the available
+- version of `cryptsetup` is greater or equal to `version`
++ """Set `conf.dmcrypt_no_workqueue` to `True` if the installed version
++ of `cryptsetup` is greater than or equal to the specified `target_version`.
++
++ Depending on the crypsetup version, `cryptsetup --version` output can be different.
++ Eg:
++
++ CentOS Stream9:
++ $ cryptsetup --version
++ cryptsetup 2.6.0 flags: UDEV BLKID KEYRING FIPS KERNEL_CAPI PWQUALITY
++
++ CentOS Stream8:
++ $ cryptsetup --version
++ cryptsetup 2.3.7
++
++ Args:
++ target_version (str, optional): The minimum version required for setting
++ `conf.dmcrypt_no_workqueue` to `True`. Defaults to '2.3.4'.
++
++ Raises:
++ RuntimeError: If failed to retrieve the cryptsetup version.
++ RuntimeError: If failed to parse the cryptsetup version.
++ RuntimeError: If failed to compare the cryptsetup version with the target version.
+ """
+ command = ["cryptsetup", "--version"]
+ out, err, rc = process.call(command)
++
++ # This regex extracts the version number from
++ # the `cryptsetup --version` output
++ pattern: str = r'\b\d+(\.\d+)*\b'
++
++ if rc:
++ raise RuntimeError(f"Can't retrieve cryptsetup version: {err}")
++
+ try:
+- if version.parse(out[0]) >= version.parse(f'cryptsetup {target_version}'):
++ cryptsetup_version = re.match(pattern, out[0])
++
++ if cryptsetup_version is None:
++ _output: str = "\n".join(out)
++ raise RuntimeError('Error while checking cryptsetup version.\n',
++ '`cryptsetup --version` output:\n',
++ f'{_output}')
++
++ if version.parse(cryptsetup_version.group(0)) >= version.parse(target_version):
+ conf.dmcrypt_no_workqueue = True
+ except IndexError:
+ mlogger.debug(f'cryptsetup version check: rc={rc} out={out} err={err}')
--- /dev/null
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Guillaume Abrioux <gabrioux@ibm.com>
+Date: Wed, 19 Jun 2024 15:06:52 +0200
+Subject: [PATCH] ceph-volume: fix regex usage in `set_dmcrypt_no_workqueue`
+
+- Updated the regex pattern to `r'(\d+\.?)+'` to more accurately
+ capture version numbers.
+
+- Replaced `re.match` with `re.search` to properly match the cryptsetup
+ version in the output.
+
+- `re.match` only checks for a match at the beginning of the string,
+ while `re.search` looks for a match anywhere in the string.
+
+This fix ensures that the function correctly retrieves the
+cryptsetup version from the output.
+
+Fixes: https://tracker.ceph.com/issues/66393
+
+Signed-off-by: Guillaume Abrioux <gabrioux@ibm.com>
+(cherry picked from commit 607eb34b2c278566c386efcbf3018629cf08ccfd)
+(cherry picked from commit d49b2888486623415a038630da54f5e1c99f1c63)
+Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
+---
+ .../ceph_volume/tests/util/test_encryption.py | 40 ++++++++++++++++++-
+ .../ceph_volume/util/encryption.py | 4 +-
+ 2 files changed, 41 insertions(+), 3 deletions(-)
+
+diff --git a/src/ceph-volume/ceph_volume/tests/util/test_encryption.py b/src/ceph-volume/ceph_volume/tests/util/test_encryption.py
+index cd2ea8f187f..200f1da84d8 100644
+--- a/src/ceph-volume/ceph_volume/tests/util/test_encryption.py
++++ b/src/ceph-volume/ceph_volume/tests/util/test_encryption.py
+@@ -1,6 +1,44 @@
+ from ceph_volume.util import encryption
+-from mock.mock import patch
++from mock.mock import patch, Mock
+ import base64
++import pytest
++
++
++class TestNoWorkqueue:
++ def setup_method(self):
++ encryption.conf.dmcrypt_no_workqueue = None
++
++ @patch('ceph_volume.util.encryption.process.call',
++ Mock(return_value=(['cryptsetup 2.7.2 flags: UDEV BLKID KEYRING' \
++ 'FIPS KERNEL_CAPI PWQUALITY '], [''], 0)))
++ def test_set_dmcrypt_no_workqueue_true(self):
++ encryption.set_dmcrypt_no_workqueue()
++ assert encryption.conf.dmcrypt_no_workqueue
++
++ @patch('ceph_volume.util.encryption.process.call',
++ Mock(return_value=(['cryptsetup 2.0.0'], [''], 0)))
++ def test_set_dmcrypt_no_workqueue_false(self):
++ encryption.set_dmcrypt_no_workqueue()
++ assert encryption.conf.dmcrypt_no_workqueue is None
++
++ @patch('ceph_volume.util.encryption.process.call',
++ Mock(return_value=([''], ['fake error'], 1)))
++ def test_set_dmcrypt_no_workqueue_cryptsetup_version_fails(self):
++ with pytest.raises(RuntimeError):
++ encryption.set_dmcrypt_no_workqueue()
++
++ @patch('ceph_volume.util.encryption.process.call',
++ Mock(return_value=(['unexpected output'], [''], 0)))
++ def test_set_dmcrypt_no_workqueue_pattern_not_found(self):
++ with pytest.raises(RuntimeError):
++ encryption.set_dmcrypt_no_workqueue()
++
++ @patch('ceph_volume.util.encryption.process.call',
++ Mock(return_value=([], [''], 0)))
++ def test_set_dmcrypt_no_workqueue_index_error(self):
++ with pytest.raises(RuntimeError):
++ encryption.set_dmcrypt_no_workqueue()
++
+
+ class TestGetKeySize(object):
+ def test_get_size_from_conf_default(self, conf_ceph_stub):
+diff --git a/src/ceph-volume/ceph_volume/util/encryption.py b/src/ceph-volume/ceph_volume/util/encryption.py
+index 09f1cccf384..15a31315645 100644
+--- a/src/ceph-volume/ceph_volume/util/encryption.py
++++ b/src/ceph-volume/ceph_volume/util/encryption.py
+@@ -41,13 +41,13 @@ def set_dmcrypt_no_workqueue(target_version: str = '2.3.4') -> None:
+
+ # This regex extracts the version number from
+ # the `cryptsetup --version` output
+- pattern: str = r'\b\d+(\.\d+)*\b'
++ pattern: str = r'(\d+\.?)+'
+
+ if rc:
+ raise RuntimeError(f"Can't retrieve cryptsetup version: {err}")
+
+ try:
+- cryptsetup_version = re.match(pattern, out[0])
++ cryptsetup_version = re.search(pattern, out[0])
+
+ if cryptsetup_version is None:
+ _output: str = "\n".join(out)