Update to latest upstream

Resolves: RHEL-36424

Signed-off-by: Xiao Ni <xni@redhat.com>
This commit is contained in:
Xiao Ni 2024-05-16 11:02:51 -04:00
parent c9d414952b
commit f102102bb4
27 changed files with 5826 additions and 1 deletions

View File

@ -0,0 +1,44 @@
From cc75b0faaa016e54d569486c9a7abe6c39cb883a Mon Sep 17 00:00:00 2001
From: Blazej Kucman <blazej.kucman@intel.com>
Date: Fri, 22 Mar 2024 12:51:15 +0100
Subject: [PATCH 42/69] mdadm: Move pr_vrb define to mdadm.h
Move pr_vrb define from super-intel.c to mdadm.h to make it widely
available. This change will be used in the next patches.
Signed-off-by: Blazej Kucman <blazej.kucman@intel.com>
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
mdadm.h | 2 ++
super-intel.c | 2 --
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/mdadm.h b/mdadm.h
index ae2106a2..fbb161ba 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -1911,6 +1911,8 @@ static inline int xasprintf(char **strp, const char *fmt, ...) {
#define pr_info(fmt, args...) printf("%s: "fmt, Name, ##args)
+#define pr_vrb(fmt, arg...) ((void)(verbose && pr_err(fmt, ##arg)))
+
void *xmalloc(size_t len);
void *xrealloc(void *ptr, size_t len);
void *xcalloc(size_t num, size_t size);
diff --git a/super-intel.c b/super-intel.c
index 70f3c4ef..212387ec 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -393,8 +393,6 @@ struct md_list {
struct md_list *next;
};
-#define pr_vrb(fmt, arg...) (void) (verbose && pr_err(fmt, ##arg))
-
static __u8 migr_type(struct imsm_dev *dev)
{
if (dev->vol.migr_type == MIGR_VERIFY &&
--
2.41.0

View File

@ -0,0 +1,463 @@
From cc48406887b3bc439e3462e8e4d20f992e81b87e Mon Sep 17 00:00:00 2001
From: Blazej Kucman <blazej.kucman@intel.com>
Date: Fri, 22 Mar 2024 12:51:16 +0100
Subject: [PATCH 43/69] Add reading Opal NVMe encryption information
For NVMe devices with Opal support, encryption information, status and
ability are determined based on Opal Level 0 discovery response. Technical
documentation used is given in the implementation.
Ability in general describes what type of encryption is supported, Status
describes in what state the disk with encryption support is. The current
patch includes only the implementation of reading encryption information,
functions will be used in one of the next patches.
Motivation for adding this functionality is to block mixing of disks in
IMSM arrays with encryption enabled and disabled. The main goal is to not
allow stealing data by rebuilding array to not encrypted drive which can be
read elsewhere.
Value ENA_OTHER from enum encryption_ability will be used in the next
patch.
Signed-off-by: Blazej Kucman <blazej.kucman@intel.com>
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
Makefile | 4 +-
drive_encryption.c | 362 +++++++++++++++++++++++++++++++++++++++++++++
drive_encryption.h | 32 ++++
3 files changed, 396 insertions(+), 2 deletions(-)
create mode 100644 drive_encryption.c
create mode 100644 drive_encryption.h
diff --git a/Makefile b/Makefile
index cbdba49a..7c221a89 100644
--- a/Makefile
+++ b/Makefile
@@ -170,7 +170,7 @@ OBJS = mdadm.o config.o policy.o mdstat.o ReadMe.o uuid.o util.o maps.o lib.o u
mdopen.o super0.o super1.o super-ddf.o super-intel.o bitmap.o \
super-mbr.o super-gpt.o \
restripe.o sysfs.o sha1.o mapfile.o crc32.o sg_io.o msg.o xmalloc.o \
- platform-intel.o probe_roms.o crc32c.o
+ platform-intel.o probe_roms.o crc32c.o drive_encryption.o
CHECK_OBJS = restripe.o uuid.o sysfs.o maps.o lib.o xmalloc.o dlink.o
@@ -183,7 +183,7 @@ MON_OBJS = mdmon.o monitor.o managemon.o uuid.o util.o maps.o mdstat.o sysfs.o c
Kill.o sg_io.o dlink.o ReadMe.o super-intel.o \
super-mbr.o super-gpt.o \
super-ddf.o sha1.o crc32.o msg.o bitmap.o xmalloc.o \
- platform-intel.o probe_roms.o crc32c.o
+ platform-intel.o probe_roms.o crc32c.o drive_encryption.o
MON_SRCS = $(patsubst %.o,%.c,$(MON_OBJS))
diff --git a/drive_encryption.c b/drive_encryption.c
new file mode 100644
index 00000000..b44585a7
--- /dev/null
+++ b/drive_encryption.c
@@ -0,0 +1,362 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Read encryption information for Opal and ATA devices.
+ *
+ * Copyright (C) 2024 Intel Corporation
+ * Author: Blazej Kucman <blazej.kucman@intel.com>
+ */
+
+#include "mdadm.h"
+
+#include <asm/types.h>
+#include <linux/nvme_ioctl.h>
+#include "drive_encryption.h"
+
+/*
+ * Opal defines
+ * TCG Storage Opal SSC 2.01 chapter 3.3.3
+ * NVM ExpressTM Revision 1.4c, chapter 5
+ */
+#define TCG_SECP_01 (0x01)
+#define TCG_SECP_00 (0x00)
+#define OPAL_DISCOVERY_COMID (0x0001)
+#define OPAL_LOCKING_FEATURE (0x0002)
+#define OPAL_IO_BUFFER_LEN 2048
+#define OPAL_DISCOVERY_FEATURE_HEADER_LEN (4)
+
+/*
+ * NVMe defines
+ * NVM ExpressTM Revision 1.4c, chapter 5
+ */
+#define NVME_SECURITY_RECV (0x82)
+#define NVME_IDENTIFY (0x06)
+#define NVME_IDENTIFY_RESPONSE_LEN 4096
+#define NVME_OACS_BYTE_POSITION (256)
+#define NVME_IDENTIFY_CONTROLLER_DATA (1)
+
+typedef enum drive_feature_support_status {
+ /* Drive feature is supported. */
+ DRIVE_FEAT_SUP_ST = 0,
+ /* Drive feature is not supported. */
+ DRIVE_FEAT_NOT_SUP_ST,
+ /* Drive feature support check failed. */
+ DRIVE_FEAT_CHECK_FAILED_ST
+} drive_feat_sup_st;
+
+/* TCG Storage Opal SSC 2.01 chapter 3.1.1.3 */
+typedef struct opal_locking_feature {
+ /* feature header */
+ __u16 feature_code;
+ __u8 reserved : 4;
+ __u8 version : 4;
+ __u8 description_length;
+ /* feature description */
+ __u8 locking_supported : 1;
+ __u8 locking_enabled : 1;
+ __u8 locked : 1;
+ __u8 media_encryption : 1;
+ __u8 mbr_enabled : 1;
+ __u8 mbr_done : 1;
+ __u8 mbr_shadowing_not_supported : 1;
+ __u8 hw_reset_for_dor_supported : 1;
+ __u8 reserved1[11];
+} __attribute__((__packed__)) opal_locking_feature_t;
+
+/* TCG Storage Opal SSC 2.01 chapter 3.1.1.1 */
+typedef struct opal_level0_header {
+ __u32 length;
+ __u32 version;
+ __u64 reserved;
+ __u8 vendor_specific[32];
+} opal_level0_header_t;
+
+/**
+ * NVM ExpressTM Revision 1.4c, Figure 249
+ * Structure specifies only OACS filed, which is needed in the current use case.
+ */
+typedef struct nvme_identify_ctrl {
+ __u8 reserved[255];
+ __u16 oacs;
+ __u8 reserved2[3839];
+} nvme_identify_ctrl_t;
+
+/* SCSI Primary Commands - 4 (SPC-4), Table 512 */
+typedef struct supported_security_protocols {
+ __u8 reserved[6];
+ __u16 list_length;
+ __u8 list[504];
+} supported_security_protocols_t;
+
+/**
+ * get_opal_locking_feature_description() - get opal locking feature description.
+ * @response: response from Opal Discovery Level 0.
+ *
+ * Based on the documentation TCG Storage Opal SSC 2.01 chapter 3.1.1,
+ * a Locking feature is searched for in Opal Level 0 Discovery response.
+ *
+ * Return: if locking feature is found, pointer to struct %opal_locking_feature_t, NULL otherwise.
+ */
+static opal_locking_feature_t *get_opal_locking_feature_description(__u8 *response)
+{
+ opal_level0_header_t *response_header = (opal_level0_header_t *)response;
+ int features_length = __be32_to_cpu(response_header->length);
+ int current_position = sizeof(*response_header);
+
+ while (current_position < features_length) {
+ opal_locking_feature_t *feature;
+
+ feature = (opal_locking_feature_t *)(response + current_position);
+
+ if (__be16_to_cpu(feature->feature_code) == OPAL_LOCKING_FEATURE)
+ return feature;
+
+ current_position += feature->description_length + OPAL_DISCOVERY_FEATURE_HEADER_LEN;
+ }
+
+ return NULL;
+}
+
+/**
+ * nvme_security_recv_ioctl() - nvme security receive ioctl.
+ * @disk_fd: a disk file descriptor.
+ * @sec_protocol: security protocol.
+ * @comm_id: command id.
+ * @response_buffer: response buffer to fill out.
+ * @buf_size: response buffer size.
+ * @verbose: verbose flag.
+ *
+ * Based on the documentations TCG Storage Opal SSC 2.01 chapter 3.3.3 and
+ * NVM ExpressTM Revision 1.4c, chapter 5.25,
+ * read security receive command via ioctl().
+ * On success, @response_buffer is completed.
+ *
+ * Return: %MDADM_STATUS_SUCCESS on success, %MDADM_STATUS_ERROR otherwise.
+ */
+static mdadm_status_t
+nvme_security_recv_ioctl(int disk_fd, __u8 sec_protocol, __u16 comm_id, void *response_buffer,
+ size_t buf_size, const int verbose)
+{
+ struct nvme_admin_cmd nvme_cmd = {0};
+ int status;
+
+ nvme_cmd.opcode = NVME_SECURITY_RECV;
+ nvme_cmd.cdw10 = sec_protocol << 24 | comm_id << 8;
+ nvme_cmd.cdw11 = buf_size;
+ nvme_cmd.data_len = buf_size;
+ nvme_cmd.addr = (__u64)response_buffer;
+
+ status = ioctl(disk_fd, NVME_IOCTL_ADMIN_CMD, &nvme_cmd);
+ if (status != 0) {
+ pr_vrb("Failed to read NVMe security receive ioctl() for device /dev/%s, status: %d\n",
+ fd2kname(disk_fd), status);
+ return MDADM_STATUS_ERROR;
+ }
+
+ return MDADM_STATUS_SUCCESS;
+}
+
+/**
+ * nvme_identify_ioctl() - NVMe identify ioctl.
+ * @disk_fd: a disk file descriptor.
+ * @response_buffer: response buffer to fill out.
+ * @buf_size: response buffer size.
+ * @verbose: verbose flag.
+ *
+ * Based on the documentations TCG Storage Opal SSC 2.01 chapter 3.3.3 and
+ * NVM ExpressTM Revision 1.4c, chapter 5.25,
+ * read NVMe identify via ioctl().
+ * On success, @response_buffer will be completed.
+ *
+ * Return: %MDADM_STATUS_SUCCESS on success, %MDADM_STATUS_ERROR otherwise.
+ */
+static mdadm_status_t
+nvme_identify_ioctl(int disk_fd, void *response_buffer, size_t buf_size, const int verbose)
+{
+ struct nvme_admin_cmd nvme_cmd = {0};
+ int status;
+
+ nvme_cmd.opcode = NVME_IDENTIFY;
+ nvme_cmd.cdw10 = NVME_IDENTIFY_CONTROLLER_DATA;
+ nvme_cmd.data_len = buf_size;
+ nvme_cmd.addr = (__u64)response_buffer;
+
+ status = ioctl(disk_fd, NVME_IOCTL_ADMIN_CMD, &nvme_cmd);
+ if (status != 0) {
+ pr_vrb("Failed to read NVMe identify ioctl() for device /dev/%s, status: %d\n",
+ fd2kname(disk_fd), status);
+ return MDADM_STATUS_ERROR;
+ }
+
+ return MDADM_STATUS_SUCCESS;
+}
+
+/**
+ * is_sec_prot_01h_supported() - check if security protocol 01h supported.
+ * @security_protocols: struct with response from disk (NVMe, SATA) describing supported
+ * security protocols.
+ *
+ * Return: true if TCG_SECP_01 found, false otherwise.
+ */
+static bool is_sec_prot_01h_supported(supported_security_protocols_t *security_protocols)
+{
+ int list_length = be16toh(security_protocols->list_length);
+ int index;
+
+ for (index = 0 ; index < list_length; index++) {
+ if (security_protocols->list[index] == TCG_SECP_01)
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * is_sec_prot_01h_supported_nvme() - check if security protocol 01h supported for given NVMe disk.
+ * @disk_fd: a disk file descriptor.
+ * @verbose: verbose flag.
+ *
+ * Return: %DRIVE_FEAT_SUP_ST if TCG_SECP_01 supported, %DRIVE_FEAT_NOT_SUP_ST if not supported,
+ * %DRIVE_FEAT_CHECK_FAILED_ST if failed to check.
+ */
+static drive_feat_sup_st is_sec_prot_01h_supported_nvme(int disk_fd, const int verbose)
+{
+ supported_security_protocols_t security_protocols = {0};
+
+ /* security_protocol: TCG_SECP_00, comm_id: not applicable */
+ if (nvme_security_recv_ioctl(disk_fd, TCG_SECP_00, 0x0, &security_protocols,
+ sizeof(security_protocols), verbose))
+ return DRIVE_FEAT_CHECK_FAILED_ST;
+
+ if (is_sec_prot_01h_supported(&security_protocols))
+ return DRIVE_FEAT_SUP_ST;
+
+ return DRIVE_FEAT_NOT_SUP_ST;
+}
+
+/**
+ * is_nvme_sec_send_recv_supported() - check if Security Send and Security Receive is supported.
+ * @disk_fd: a disk file descriptor.
+ * @verbose: verbose flag.
+ *
+ * Check if "Optional Admin Command Support" bit 0 is set in NVMe identify.
+ * Bit 0 set to 1 means controller supports the Security Send and Security Receive commands.
+ *
+ * Return: %DRIVE_FEAT_SUP_ST if security send/receive supported,
+ * %DRIVE_FEAT_NOT_SUP_ST if not supported, %DRIVE_FEAT_CHECK_FAILED_ST if check failed.
+ */
+static drive_feat_sup_st is_nvme_sec_send_recv_supported(int disk_fd, const int verbose)
+{
+ nvme_identify_ctrl_t nvme_identify = {0};
+ int status = 0;
+
+ status = nvme_identify_ioctl(disk_fd, &nvme_identify, sizeof(nvme_identify), verbose);
+ if (status)
+ return DRIVE_FEAT_CHECK_FAILED_ST;
+
+ if ((__le16_to_cpu(nvme_identify.oacs) & 0x1) == 0x1)
+ return DRIVE_FEAT_SUP_ST;
+
+ return DRIVE_FEAT_NOT_SUP_ST;
+}
+
+/**
+ * get_opal_encryption_information() - get Opal encryption information.
+ * @buffer: buffer with Opal Level 0 Discovery response.
+ * @information: struct to fill out, describing encryption status of disk.
+ *
+ * If Locking feature frame is in response from Opal Level 0 discovery, &encryption_information_t
+ * structure is completed with status and ability otherwise the status is set to &None.
+ * For possible encryption statuses and abilities,
+ * please refer to enums &encryption_status and &encryption_ability.
+ *
+ * Return: %MDADM_STATUS_SUCCESS on success, %MDADM_STATUS_ERROR otherwise.
+ */
+static mdadm_status_t get_opal_encryption_information(__u8 *buffer,
+ encryption_information_t *information)
+{
+ opal_locking_feature_t *opal_locking_feature =
+ get_opal_locking_feature_description(buffer);
+
+ if (!opal_locking_feature)
+ return MDADM_STATUS_ERROR;
+
+ if (opal_locking_feature->locking_supported == 1) {
+ information->ability = ENC_ABILITY_SED;
+
+ if (opal_locking_feature->locking_enabled == 0)
+ information->status = ENC_STATUS_UNENCRYPTED;
+ else if (opal_locking_feature->locked == 1)
+ information->status = ENC_STATUS_LOCKED;
+ else
+ information->status = ENC_STATUS_UNLOCKED;
+ } else {
+ information->ability = ENC_ABILITY_NONE;
+ information->status = ENC_STATUS_UNENCRYPTED;
+ }
+
+ return MDADM_STATUS_SUCCESS;
+}
+
+/**
+ * get_nvme_opal_encryption_information() - get NVMe Opal encryption information.
+ * @disk_fd: a disk file descriptor.
+ * @information: struct to fill out, describing encryption status of disk.
+ * @verbose: verbose flag.
+ *
+ * In case the disk supports Opal Level 0 discovery, &encryption_information_t structure
+ * is completed with status and ability based on ioctl response,
+ * otherwise the ability is set to %ENC_ABILITY_NONE and &status to %ENC_STATUS_UNENCRYPTED.
+ * As the current use case does not need the knowledge of Opal support, if there is no support,
+ * %MDADM_STATUS_SUCCESS will be returned, with the values described above.
+ * For possible encryption statuses and abilities,
+ * please refer to enums &encryption_status and &encryption_ability.
+ *
+ * %MDADM_STATUS_SUCCESS on success, %MDADM_STATUS_ERROR otherwise.
+ */
+mdadm_status_t
+get_nvme_opal_encryption_information(int disk_fd, encryption_information_t *information,
+ const int verbose)
+{
+ __u8 buffer[OPAL_IO_BUFFER_LEN];
+ int sec_send_recv_supported = 0;
+ int protocol_01h_supported = 0;
+ mdadm_status_t status;
+
+ information->ability = ENC_ABILITY_NONE;
+ information->status = ENC_STATUS_UNENCRYPTED;
+
+ sec_send_recv_supported = is_nvme_sec_send_recv_supported(disk_fd, verbose);
+ if (sec_send_recv_supported == DRIVE_FEAT_CHECK_FAILED_ST)
+ return MDADM_STATUS_ERROR;
+
+ /* Opal not supported */
+ if (sec_send_recv_supported == DRIVE_FEAT_NOT_SUP_ST)
+ return MDADM_STATUS_SUCCESS;
+
+ /**
+ * sec_send_recv_supported determine that it should be possible to read
+ * supported sec protocols
+ */
+ protocol_01h_supported = is_sec_prot_01h_supported_nvme(disk_fd, verbose);
+ if (protocol_01h_supported == DRIVE_FEAT_CHECK_FAILED_ST)
+ return MDADM_STATUS_ERROR;
+
+ /* Opal not supported */
+ if (sec_send_recv_supported == DRIVE_FEAT_SUP_ST &&
+ protocol_01h_supported == DRIVE_FEAT_NOT_SUP_ST)
+ return MDADM_STATUS_SUCCESS;
+
+ if (nvme_security_recv_ioctl(disk_fd, TCG_SECP_01, OPAL_DISCOVERY_COMID, (void *)&buffer,
+ OPAL_IO_BUFFER_LEN, verbose))
+ return MDADM_STATUS_ERROR;
+
+ status = get_opal_encryption_information((__u8 *)&buffer, information);
+ if (status)
+ pr_vrb("Locking feature description not found in Level 0 discovery response. Device /dev/%s.\n",
+ fd2kname(disk_fd));
+
+ if (information->ability == ENC_ABILITY_NONE)
+ assert(information->status == ENC_STATUS_UNENCRYPTED);
+
+ return status;
+}
diff --git a/drive_encryption.h b/drive_encryption.h
new file mode 100644
index 00000000..82c2c624
--- /dev/null
+++ b/drive_encryption.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Read encryption information for Opal and ATA devices.
+ *
+ * Copyright (C) 2024 Intel Corporation
+ * Author: Blazej Kucman <blazej.kucman@intel.com>
+ */
+
+typedef enum encryption_status {
+ /* The drive is not currently encrypted. */
+ ENC_STATUS_UNENCRYPTED = 0,
+ /* The drive is encrypted and the data is not accessible. */
+ ENC_STATUS_LOCKED,
+ /* The drive is encrypted but the data is accessible in unencrypted form. */
+ ENC_STATUS_UNLOCKED
+} encryption_status_t;
+
+typedef enum encryption_ability {
+ ENC_ABILITY_NONE = 0,
+ ENC_ABILITY_OTHER,
+ /* Self encrypted drive */
+ ENC_ABILITY_SED
+} encryption_ability_t;
+
+typedef struct encryption_information {
+ encryption_ability_t ability;
+ encryption_status_t status;
+} encryption_information_t;
+
+mdadm_status_t
+get_nvme_opal_encryption_information(int disk_fd, struct encryption_information *information,
+ const int verbose);
--
2.41.0

View File

@ -0,0 +1,459 @@
From df38df3052c3386c0fd076e0d534b4f688b5c8a4 Mon Sep 17 00:00:00 2001
From: Blazej Kucman <blazej.kucman@intel.com>
Date: Fri, 22 Mar 2024 12:51:17 +0100
Subject: [PATCH 44/69] Add reading SATA encryption information
Functionality reads information about SATA disk encryption. Technical
documentation used is given in the implementation.
The implementation is able to recognized two encryption standards for SATA
drives, OPAL and ATA security.
If the SATA drive supports OPAL, encryption status and ability are
determined based on Opal Level 0 discovery response, for ATA security,
based on ATA identify response. If SATA supports OPAL, ability is set to
"SED", for ATA security to "Other".
SED(Self-Encrypting Drive) is commonly used to describe drive which using
OPAL or Enterprise standards developed by Trusted Computing Group. Ability
"Other" is used for ATA security because we rely only on information from
ATA identify which describe the overall state of encryption.
It is allowed to mix disks with different encryption ability such as "SED"
and "Other" and it is not security gap.
Motivation for adding this functionality is to block mixing of disks in
IMSM arrays with encryption enabled and disabled. The main goal is to not
allow stealing data by rebuilding array to not encrypted drive which can be
read elsewhere.
For SATA Opal drives, libata allow_tmp parameter enabled is required, which
is necessary for Opal Security commands to work, therefore, if the
parameter is not enabled, SATA Opal disk cannot be used in case the
encryption will be checked by metadata.
Implemented functions will be used in one of the next patches. In one of
the next patches, a flag will be added to enable disabling SATA Opal
encryption checking due to allow_tpm kernel setting dependency.
Signed-off-by: Blazej Kucman <blazej.kucman@intel.com>
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
drive_encryption.c | 318 +++++++++++++++++++++++++++++++++++++++++++++
drive_encryption.h | 3 +
mdadm.h | 1 +
sysfs.c | 29 +++++
4 files changed, 351 insertions(+)
diff --git a/drive_encryption.c b/drive_encryption.c
index b44585a7..d520f0c7 100644
--- a/drive_encryption.c
+++ b/drive_encryption.c
@@ -10,8 +10,12 @@
#include <asm/types.h>
#include <linux/nvme_ioctl.h>
+#include <scsi/sg.h>
+#include <scsi/scsi.h>
#include "drive_encryption.h"
+#define DEFAULT_SECTOR_SIZE (512)
+
/*
* Opal defines
* TCG Storage Opal SSC 2.01 chapter 3.3.3
@@ -34,6 +38,35 @@
#define NVME_OACS_BYTE_POSITION (256)
#define NVME_IDENTIFY_CONTROLLER_DATA (1)
+/*
+ * ATA defines
+ * ATA/ATAPI Command Set ATA8-ACS
+ * SCSI / ATA Translation - 3 (SAT-3)
+ * SCSI Primary Commands - 4 (SPC-4)
+ * AT Attachment-8 - ATA Serial Transport (ATA8-AST)
+ * ATA Command Pass-Through
+ */
+#define ATA_IDENTIFY (0xec)
+#define ATA_TRUSTED_RECEIVE (0x5c)
+#define ATA_SECURITY_WORD_POSITION (128)
+#define HDIO_DRIVE_CMD (0x031f)
+#define ATA_TRUSTED_COMPUTING_POS (48)
+#define ATA_PASS_THROUGH_12 (0xa1)
+#define ATA_IDENTIFY_RESPONSE_LEN (512)
+#define ATA_PIO_DATA_IN (4)
+#define SG_CHECK_CONDITION (0x02)
+#define ATA_STATUS_RETURN_DESCRIPTOR (0x09)
+#define ATA_PT_INFORMATION_AVAILABLE_ASCQ (0x1d)
+#define ATA_PT_INFORMATION_AVAILABLE_ASC (0x00)
+#define ATA_INQUIRY_LENGTH (0x0c)
+#define SG_INTERFACE_ID 'S'
+#define SG_IO_TIMEOUT (60000)
+#define SG_SENSE_SIZE (32)
+#define SENSE_DATA_CURRENT_FIXED (0x70)
+#define SENSE_DATA_CURRENT_DESC (0x72)
+#define SENSE_CURRENT_RES_DESC_POS (8)
+#define SG_DRIVER_SENSE (0x08)
+
typedef enum drive_feature_support_status {
/* Drive feature is supported. */
DRIVE_FEAT_SUP_ST = 0,
@@ -87,6 +120,27 @@ typedef struct supported_security_protocols {
__u8 list[504];
} supported_security_protocols_t;
+/* ATA/ATAPI Command Set - 3 (ACS-3), Table 45 */
+typedef struct ata_security_status {
+ __u16 security_supported : 1;
+ __u16 security_enabled : 1;
+ __u16 security_locked : 1;
+ __u16 security_frozen : 1;
+ __u16 security_count_expired : 1;
+ __u16 enhanced_security_erase_supported : 1;
+ __u16 reserved1 : 2;
+ __u16 security_level : 1;
+ __u16 reserved2 : 7;
+} __attribute__((__packed__)) ata_security_status_t;
+
+/* ATA/ATAPI Command Set - 3 (ACS-3), Table 45 */
+typedef struct ata_trusted_computing {
+ __u16 tc_feature :1;
+ __u16 reserved : 13;
+ __u16 var1 : 1;
+ __u16 var2 : 1;
+} __attribute__((__packed__)) ata_trusted_computing_t;
+
/**
* get_opal_locking_feature_description() - get opal locking feature description.
* @response: response from Opal Discovery Level 0.
@@ -360,3 +414,267 @@ get_nvme_opal_encryption_information(int disk_fd, encryption_information_t *info
return status;
}
+
+/**
+ * ata_pass_through12_ioctl() - ata pass through12 ioctl.
+ * @disk_fd: a disk file descriptor.
+ * @ata_command: ata command.
+ * @sec_protocol: security protocol.
+ * @comm_id: additional command id.
+ * @response_buffer: response buffer to fill out.
+ * @buf_size: response buffer size.
+ * @verbose: verbose flag.
+ *
+ * Based on the documentations ATA Command Pass-Through, chapter 13.2.2 and
+ * ATA Translation - 3 (SAT-3), send read ata pass through 12 command via ioctl().
+ * On success, @response_buffer will be completed.
+ *
+ * Return: %MDADM_STATUS_SUCCESS on success, %MDADM_STATUS_ERROR on fail.
+ */
+static mdadm_status_t
+ata_pass_through12_ioctl(int disk_fd, __u8 ata_command, __u8 sec_protocol, __u16 comm_id,
+ void *response_buffer, size_t buf_size, const int verbose)
+{
+ __u8 cdb[ATA_INQUIRY_LENGTH] = {0};
+ __u8 sense[SG_SENSE_SIZE] = {0};
+ __u8 *sense_desc = NULL;
+ sg_io_hdr_t sg = {0};
+
+ /*
+ * ATA Command Pass-Through, chapter 13.2.2
+ * SCSI Primary Commands - 4 (SPC-4)
+ * ATA Translation - 3 (SAT-3)
+ */
+ cdb[0] = ATA_PASS_THROUGH_12;
+ /* protocol, bits 1-4 */
+ cdb[1] = ATA_PIO_DATA_IN << 1;
+ /* Bytes: CK_COND=1, T_DIR = 1, BYTE_BLOCK = 1, Length in Sector Count = 2 */
+ cdb[2] = 0x2E;
+ cdb[3] = sec_protocol;
+ /* Sector count */
+ cdb[4] = buf_size / DEFAULT_SECTOR_SIZE;
+ cdb[6] = (comm_id) & 0xFF;
+ cdb[7] = (comm_id >> 8) & 0xFF;
+ cdb[9] = ata_command;
+
+ sg.interface_id = SG_INTERFACE_ID;
+ sg.cmd_len = sizeof(cdb);
+ sg.mx_sb_len = sizeof(sense);
+ sg.dxfer_direction = SG_DXFER_FROM_DEV;
+ sg.dxfer_len = buf_size;
+ sg.dxferp = response_buffer;
+ sg.cmdp = cdb;
+ sg.sbp = sense;
+ sg.timeout = SG_IO_TIMEOUT;
+ sg.usr_ptr = NULL;
+
+ if (ioctl(disk_fd, SG_IO, &sg) < 0) {
+ pr_vrb("Failed ata passthrough12 ioctl. Device: /dev/%s.\n", fd2kname(disk_fd));
+ return MDADM_STATUS_ERROR;
+ }
+
+ if ((sg.status && sg.status != SG_CHECK_CONDITION) || sg.host_status ||
+ (sg.driver_status && sg.driver_status != SG_DRIVER_SENSE)) {
+ pr_vrb("Failed ata passthrough12 ioctl. Device: /dev/%s.\n", fd2kname(disk_fd));
+ pr_vrb("SG_IO error: ATA_12 Status: %d Host Status: %d, Driver Status: %d\n",
+ sg.status, sg.host_status, sg.driver_status);
+ return MDADM_STATUS_ERROR;
+ }
+
+ /* verify expected sense response code */
+ if (!(sense[0] == SENSE_DATA_CURRENT_DESC || sense[0] == SENSE_DATA_CURRENT_FIXED)) {
+ pr_vrb("Failed ata passthrough12 ioctl. Device: /dev/%s.\n", fd2kname(disk_fd));
+ return MDADM_STATUS_ERROR;
+ }
+
+ sense_desc = sense + SENSE_CURRENT_RES_DESC_POS;
+ /* verify sense data current response with descriptor format */
+ if (sense[0] == SENSE_DATA_CURRENT_DESC &&
+ !(sense_desc[0] == ATA_STATUS_RETURN_DESCRIPTOR &&
+ sense_desc[1] == ATA_INQUIRY_LENGTH)) {
+ pr_vrb("Failed ata passthrough12 ioctl. Device: /dev/%s. Sense data ASC: %d, ASCQ: %d.\n",
+ fd2kname(disk_fd), sense[2], sense[3]);
+ return MDADM_STATUS_ERROR;
+ }
+
+ /* verify sense data current response with fixed format */
+ if (sense[0] == SENSE_DATA_CURRENT_FIXED &&
+ !(sense[12] == ATA_PT_INFORMATION_AVAILABLE_ASC &&
+ sense[13] == ATA_PT_INFORMATION_AVAILABLE_ASCQ)) {
+ pr_vrb("Failed ata passthrough12 ioctl. Device: /dev/%s. Sense data ASC: %d, ASCQ: %d.\n",
+ fd2kname(disk_fd), sense[12], sense[13]);
+ return MDADM_STATUS_ERROR;
+ }
+
+ return MDADM_STATUS_SUCCESS;
+}
+
+/**
+ * is_sec_prot_01h_supported_ata() - check if security protocol 01h supported for given SATA disk.
+ * @disk_fd: a disk file descriptor.
+ * @verbose: verbose flag.
+ *
+ * Return: %DRIVE_FEAT_SUP_ST if TCG_SECP_01 supported, %DRIVE_FEAT_NOT_SUP_ST if not supported,
+ * %DRIVE_FEAT_CHECK_FAILED_ST if failed.
+ */
+static drive_feat_sup_st is_sec_prot_01h_supported_ata(int disk_fd, const int verbose)
+{
+ supported_security_protocols_t security_protocols;
+
+ mdadm_status_t result = ata_pass_through12_ioctl(disk_fd, ATA_TRUSTED_RECEIVE, TCG_SECP_00,
+ 0x0, &security_protocols,
+ sizeof(security_protocols), verbose);
+ if (result)
+ return DRIVE_FEAT_CHECK_FAILED_ST;
+
+ if (is_sec_prot_01h_supported(&security_protocols))
+ return DRIVE_FEAT_SUP_ST;
+
+ return DRIVE_FEAT_NOT_SUP_ST;
+}
+
+/**
+ * is_ata_trusted_computing_supported() - check if ata trusted computing supported.
+ * @buffer: buffer with ATA identify response, not NULL.
+ *
+ * Return: true if trusted computing bit set, false otherwise.
+ */
+bool is_ata_trusted_computing_supported(__u16 *buffer)
+{
+ /* Added due to warnings from the compiler about a possible uninitialized variable below. */
+ assert(buffer);
+
+ __u16 security_tc_frame = __le16_to_cpu(buffer[ATA_TRUSTED_COMPUTING_POS]);
+ ata_trusted_computing_t *security_tc = (ata_trusted_computing_t *)&security_tc_frame;
+
+ if (security_tc->tc_feature == 1)
+ return true;
+
+ return false;
+}
+
+/**
+ * get_ata_standard_security_status() - get ATA disk encryption information from ATA identify.
+ * @buffer: buffer with response from ATA identify, not NULL.
+ * @information: struct to fill out, describing encryption status of disk.
+ *
+ * The function based on the Security status frame from ATA identify,
+ * completed encryption information.
+ * For possible encryption statuses and abilities,
+ * please refer to enums &encryption_status and &encryption_ability.
+ *
+ * Return: %MDADM_STATUS_SUCCESS on success, %MDADM_STATUS_ERROR on fail.
+ */
+static mdadm_status_t get_ata_standard_security_status(__u16 *buffer,
+ struct encryption_information *information)
+{
+ /* Added due to warnings from the compiler about a possible uninitialized variable below. */
+ assert(buffer);
+
+ __u16 security_status_frame = __le16_to_cpu(buffer[ATA_SECURITY_WORD_POSITION]);
+ ata_security_status_t *security_status = (ata_security_status_t *)&security_status_frame;
+
+ if (!security_status->security_supported) {
+ information->ability = ENC_ABILITY_NONE;
+ information->status = ENC_STATUS_UNENCRYPTED;
+
+ return MDADM_STATUS_SUCCESS;
+ }
+
+ information->ability = ENC_ABILITY_OTHER;
+
+ if (security_status->security_enabled == 0)
+ information->status = ENC_STATUS_UNENCRYPTED;
+ else if (security_status->security_locked == 1)
+ information->status = ENC_STATUS_LOCKED;
+ else
+ information->status = ENC_STATUS_UNLOCKED;
+
+ return MDADM_STATUS_SUCCESS;
+}
+
+/**
+ * is_ata_opal() - check if SATA disk support Opal.
+ * @disk_fd: a disk file descriptor.
+ * @buffer: buffer with ATA identify response.
+ * @verbose: verbose flag.
+ *
+ * Return: %DRIVE_FEAT_SUP_ST if TCG_SECP_01 supported, %DRIVE_FEAT_NOT_SUP_ST if not supported,
+ * %DRIVE_FEAT_CHECK_FAILED_ST if failed to check.
+ */
+static drive_feat_sup_st is_ata_opal(int disk_fd, __u16 *buffer_identify, const int verbose)
+{
+ bool tc_status = is_ata_trusted_computing_supported(buffer_identify);
+ drive_feat_sup_st tcg_sec_prot_status;
+
+ if (!tc_status)
+ return DRIVE_FEAT_NOT_SUP_ST;
+
+ tcg_sec_prot_status = is_sec_prot_01h_supported_ata(disk_fd, verbose);
+
+ if (tcg_sec_prot_status == DRIVE_FEAT_CHECK_FAILED_ST) {
+ pr_vrb("Failed to verify if security protocol 01h supported. Device /dev/%s.\n",
+ fd2kname(disk_fd));
+ return DRIVE_FEAT_CHECK_FAILED_ST;
+ }
+
+ if (tc_status && tcg_sec_prot_status == DRIVE_FEAT_SUP_ST)
+ return DRIVE_FEAT_SUP_ST;
+
+ return DRIVE_FEAT_NOT_SUP_ST;
+}
+
+/**
+ * get_ata_encryption_information() - get ATA disk encryption information.
+ * @disk_fd: a disk file descriptor.
+ * @information: struct to fill out, describing encryption status of disk.
+ * @verbose: verbose flag.
+ *
+ * The function reads information about encryption, if the disk supports Opal,
+ * the information is completed based on Opal Level 0 discovery, otherwise,
+ * based on ATA security status frame from ATA identification response.
+ * For possible encryption statuses and abilities,
+ * please refer to enums &encryption_status and &encryption_ability.
+ *
+ * Based on the documentations ATA/ATAPI Command Set ATA8-ACS and
+ * AT Attachment-8 - ATA Serial Transport (ATA8-AST).
+ *
+ * Return: %MDADM_STATUS_SUCCESS on success, %MDADM_STATUS_ERROR on fail.
+ */
+mdadm_status_t
+get_ata_encryption_information(int disk_fd, struct encryption_information *information,
+ const int verbose)
+{
+ __u8 buffer_opal_level0_discovery[OPAL_IO_BUFFER_LEN] = {0};
+ __u16 buffer_identify[ATA_IDENTIFY_RESPONSE_LEN] = {0};
+ drive_feat_sup_st ata_opal_status;
+ mdadm_status_t status;
+
+ /* Get disk ATA identification */
+ status = ata_pass_through12_ioctl(disk_fd, ATA_IDENTIFY, 0x0, 0x0, buffer_identify,
+ sizeof(buffer_identify), verbose);
+ if (status == MDADM_STATUS_ERROR)
+ return MDADM_STATUS_ERROR;
+
+ if (is_ata_trusted_computing_supported(buffer_identify) &&
+ !sysfs_is_libata_allow_tpm_enabled(verbose)) {
+ pr_vrb("For SATA with Trusted Computing support, required libata.tpm_enabled=1.\n");
+ return MDADM_STATUS_ERROR;
+ }
+
+ ata_opal_status = is_ata_opal(disk_fd, buffer_identify, verbose);
+ if (ata_opal_status == DRIVE_FEAT_CHECK_FAILED_ST)
+ return MDADM_STATUS_ERROR;
+
+ if (ata_opal_status == DRIVE_FEAT_NOT_SUP_ST)
+ return get_ata_standard_security_status(buffer_identify, information);
+
+ /* SATA Opal */
+ status = ata_pass_through12_ioctl(disk_fd, ATA_TRUSTED_RECEIVE, TCG_SECP_01,
+ OPAL_DISCOVERY_COMID, buffer_opal_level0_discovery,
+ OPAL_IO_BUFFER_LEN, verbose);
+ if (status != MDADM_STATUS_SUCCESS)
+ return MDADM_STATUS_ERROR;
+
+ return get_opal_encryption_information(buffer_opal_level0_discovery, information);
+}
diff --git a/drive_encryption.h b/drive_encryption.h
index 82c2c624..77c7f10f 100644
--- a/drive_encryption.h
+++ b/drive_encryption.h
@@ -30,3 +30,6 @@ typedef struct encryption_information {
mdadm_status_t
get_nvme_opal_encryption_information(int disk_fd, struct encryption_information *information,
const int verbose);
+mdadm_status_t
+get_ata_encryption_information(int disk_fd, struct encryption_information *information,
+ const int verbose);
diff --git a/mdadm.h b/mdadm.h
index fbb161ba..52a66b9a 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -853,6 +853,7 @@ extern int restore_stripes(int *dest, unsigned long long *offsets,
int source, unsigned long long read_offset,
unsigned long long start, unsigned long long length,
char *src_buf);
+extern bool sysfs_is_libata_allow_tpm_enabled(const int verbose);
#ifndef Sendmail
#define Sendmail "/usr/lib/sendmail -t"
diff --git a/sysfs.c b/sysfs.c
index 4ded1672..20fe1e9e 100644
--- a/sysfs.c
+++ b/sysfs.c
@@ -1121,3 +1121,32 @@ void sysfsline(char *line)
sr->next = sysfs_rules;
sysfs_rules = sr;
}
+
+/**
+ * sysfs_is_libata_allow_tpm_enabled() - check if libata allow_tmp is enabled.
+ * @verbose: verbose flag.
+ *
+ * Check if libata allow_tmp flag is set, this is required for SATA Opal Security commands to work.
+ *
+ * Return: true if allow_tpm enable, false otherwise.
+ */
+bool sysfs_is_libata_allow_tpm_enabled(const int verbose)
+{
+ const char *path = "/sys/module/libata/parameters/allow_tpm";
+ const char *expected_value = "1";
+ int fd = open(path, O_RDONLY);
+ char buf[3];
+
+ if (!is_fd_valid(fd)) {
+ pr_vrb("Failed open file descriptor to %s. Cannot check libata allow_tpm param.\n",
+ path);
+ return false;
+ }
+
+ sysfs_fd_get_str(fd, buf, sizeof(buf));
+ close(fd);
+
+ if (strncmp(buf, expected_value, 1) == 0)
+ return true;
+ return false;
+}
--
2.41.0

View File

@ -0,0 +1,163 @@
From 336e13fc5ef43bc5b4633a9dadac5f7208e6c241 Mon Sep 17 00:00:00 2001
From: Blazej Kucman <blazej.kucman@intel.com>
Date: Fri, 22 Mar 2024 12:51:18 +0100
Subject: [PATCH 45/69] Add key ENCRYPTION_NO_VERIFY to conf
Add ENCRYPTION_NO_VERIFY config key and allow to disable checking
encryption status for given type of drives.
The key is introduced because of SATA Opal disks for which TPM commands
must be enabled in libata kernel module, (libata.allow_tpm=1), otherwise
it is impossible to verify encryption status. TPM commands are disabled by
default.
Currently the key only supports the "sata_opal" value, if necessary,
the functionality is ready to support more types of disks. This
functionality will be used in the next patches.
Signed-off-by: Blazej Kucman <blazej.kucman@intel.com>
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
config.c | 25 ++++++++++++++++++++++++-
drive_encryption.c | 16 ++++++++++++----
mdadm.conf.5.in | 13 +++++++++++++
mdadm.h | 1 +
4 files changed, 50 insertions(+), 5 deletions(-)
diff --git a/config.c b/config.c
index 44f7dd2f..b46d71cb 100644
--- a/config.c
+++ b/config.c
@@ -81,7 +81,7 @@ char DefaultAltConfDir[] = CONFFILE2 ".d";
enum linetype { Devices, Array, Mailaddr, Mailfrom, Program, CreateDev,
Homehost, HomeCluster, AutoMode, Policy, PartPolicy, Sysfs,
- MonitorDelay, LTEnd };
+ MonitorDelay, EncryptionNoVerify, LTEnd };
char *keywords[] = {
[Devices] = "devices",
[Array] = "array",
@@ -96,6 +96,7 @@ char *keywords[] = {
[PartPolicy]="part-policy",
[Sysfs] = "sysfs",
[MonitorDelay] = "monitordelay",
+ [EncryptionNoVerify] = "ENCRYPTION_NO_VERIFY",
[LTEnd] = NULL
};
@@ -729,6 +730,19 @@ void monitordelayline(char *line)
}
}
+static bool sata_opal_encryption_no_verify;
+void encryption_no_verify_line(char *line)
+{
+ char *word;
+
+ for (word = dl_next(line); word != line; word = dl_next(word)) {
+ if (strcasecmp(word, "sata_opal") == 0)
+ sata_opal_encryption_no_verify = true;
+ else
+ pr_err("unrecognised word on ENCRYPTION_NO_VERIFY line: %s\n", word);
+ }
+}
+
char auto_yes[] = "yes";
char auto_no[] = "no";
char auto_homehost[] = "homehost";
@@ -913,6 +927,9 @@ void conf_file(FILE *f)
case MonitorDelay:
monitordelayline(line);
break;
+ case EncryptionNoVerify:
+ encryption_no_verify_line(line);
+ break;
default:
pr_err("Unknown keyword %s\n", line);
}
@@ -1075,6 +1092,12 @@ int conf_get_monitor_delay(void)
return monitor_delay;
}
+bool conf_get_sata_opal_encryption_no_verify(void)
+{
+ load_conffile();
+ return sata_opal_encryption_no_verify;
+}
+
struct createinfo *conf_get_create_info(void)
{
load_conffile();
diff --git a/drive_encryption.c b/drive_encryption.c
index d520f0c7..6b2bd358 100644
--- a/drive_encryption.c
+++ b/drive_encryption.c
@@ -656,10 +656,18 @@ get_ata_encryption_information(int disk_fd, struct encryption_information *infor
if (status == MDADM_STATUS_ERROR)
return MDADM_STATUS_ERROR;
- if (is_ata_trusted_computing_supported(buffer_identify) &&
- !sysfs_is_libata_allow_tpm_enabled(verbose)) {
- pr_vrb("For SATA with Trusted Computing support, required libata.tpm_enabled=1.\n");
- return MDADM_STATUS_ERROR;
+ /* Possible OPAL support, further checks require tpm_enabled.*/
+ if (is_ata_trusted_computing_supported(buffer_identify)) {
+ /* OPAL SATA encryption checking disabled. */
+ if (conf_get_sata_opal_encryption_no_verify())
+ return MDADM_STATUS_SUCCESS;
+
+ if (!sysfs_is_libata_allow_tpm_enabled(verbose)) {
+ pr_vrb("Detected SATA drive /dev/%s with Trusted Computing support.\n",
+ fd2kname(disk_fd));
+ pr_vrb("Cannot verify encryption state. Requires libata.tpm_enabled=1.\n");
+ return MDADM_STATUS_ERROR;
+ }
}
ata_opal_status = is_ata_opal(disk_fd, buffer_identify, verbose);
diff --git a/mdadm.conf.5.in b/mdadm.conf.5.in
index 787e51e9..afb0a296 100644
--- a/mdadm.conf.5.in
+++ b/mdadm.conf.5.in
@@ -636,6 +636,17 @@ If multiple
.B MINITORDELAY
lines are provided, only first non-zero value is considered.
+.TP
+.B ENCRYPTION_NO_VERIFY
+The
+.B ENCRYPTION_NO_VERIFY
+disables encryption verification for devices with particular encryption support detected.
+Currently, only verification of SATA OPAL encryption can be disabled.
+It does not disable ATA security encryption verification.
+Available parameter
+.I "sata_opal".
+
+
.SH FILES
.SS {CONFFILE}
@@ -744,6 +755,8 @@ SYSFS uuid=bead5eb6:31c17a27:da120ba2:7dfda40d group_thread_cnt=4
sync_speed_max=1000000
.br
MONITORDELAY 60
+.br
+ENCRYPTION_NO_VERIFY sata_opal
.SH SEE ALSO
.BR mdadm (8),
diff --git a/mdadm.h b/mdadm.h
index 52a66b9a..2640b396 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -1673,6 +1673,7 @@ extern char *conf_get_program(void);
extern char *conf_get_homehost(int *require_homehostp);
extern char *conf_get_homecluster(void);
extern int conf_get_monitor_delay(void);
+extern bool conf_get_sata_opal_encryption_no_verify(void);
extern char *conf_line(FILE *file);
extern char *conf_word(FILE *file, int allow_key);
extern void print_quoted(char *str);
--
2.41.0

View File

@ -0,0 +1,217 @@
From bf62ed5d9642aa60abf4ac2d1d89f173bd66ae48 Mon Sep 17 00:00:00 2001
From: Blazej Kucman <blazej.kucman@intel.com>
Date: Fri, 22 Mar 2024 12:51:19 +0100
Subject: [PATCH 46/69] imsm: print disk encryption information
Print SATA/NVMe disk encryption information in --detail-platform.
Encryption Ability and Status will be printed for each disk.
There is one exception, Opal SATA drives encryption is not checked when
ENCRYPTION_NO_VERIFY key with "sata_opal" value is set in conf, for this
reason such drives are treated as without encryption support.
To test this feature, drives SATA/NVMe with Opal support or SATA drives
with encryption support have to be used.
Example outputs of --detail-platform:
Non Opal, encryption enabled, SATA drive:
Port0 : /dev/sdc (CVPR050600G3120LGN)
Encryption(Ability|Status): Other|Unlocked
NVMe drive without Opal support:
NVMe under VMD : /dev/nvme2n1 (PHLF737302GB1P0GGN)
Encryption(Ability|Status): None|Unencrypted
Unencrypted SATA drive with OPAL support:
- default allow_tpm, we will get an error from mdadm:
Port6 : /dev/sdi (CVTS4246015V180IGN)
mdadm: Detected SATA drive /dev/sdi with Trusted Computing support.
mdadm: Cannot verify encryption state. Requires libata.tpm_enabled=1.
mdadm: Failed to get drive encrytpion information.
- default "allow_tpm" and config entry "ENCRYPTION_NO_VERIFY sata_opal":
Port6 : /dev/sdi (CVTS4246015V180IGN)
Encryption(Ability|Status): None|Unencrypted
- added "libata.allow_tpm=1" to boot parameters(requires reboot),
the status will be read correctly:
Port6 : /dev/sdi (CVTS4246015V180IGN)
Encryption(Ability|Status): SED|Unencrypted
Signed-off-by: Blazej Kucman <blazej.kucman@intel.com>
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
drive_encryption.c | 36 ++++++++++++++++++++++++++++++++++++
drive_encryption.h | 2 ++
mdadm.conf.5.in | 3 +++
super-intel.c | 42 ++++++++++++++++++++++++++++++++++++++----
4 files changed, 79 insertions(+), 4 deletions(-)
diff --git a/drive_encryption.c b/drive_encryption.c
index 6b2bd358..27da9621 100644
--- a/drive_encryption.c
+++ b/drive_encryption.c
@@ -141,6 +141,42 @@ typedef struct ata_trusted_computing {
__u16 var2 : 1;
} __attribute__((__packed__)) ata_trusted_computing_t;
+mapping_t encryption_ability_map[] = {
+ { "None", ENC_ABILITY_NONE },
+ { "Other", ENC_ABILITY_OTHER },
+ { "SED", ENC_ABILITY_SED },
+ { NULL, UnSet }
+};
+
+mapping_t encryption_status_map[] = {
+ { "Unencrypted", ENC_STATUS_UNENCRYPTED },
+ { "Locked", ENC_STATUS_LOCKED },
+ { "Unlocked", ENC_STATUS_UNLOCKED },
+ { NULL, UnSet }
+};
+
+/**
+ * get_encryption_ability_string() - get encryption ability name string.
+ * @ability: encryption ability enum.
+ *
+ * Return: encryption ability string.
+ */
+const char *get_encryption_ability_string(enum encryption_ability ability)
+{
+ return map_num_s(encryption_ability_map, ability);
+}
+
+/**
+ * get_encryption_status_string() - get encryption status name string.
+ * @ability: encryption status enum.
+ *
+ * Return: encryption status string.
+ */
+const char *get_encryption_status_string(enum encryption_status status)
+{
+ return map_num_s(encryption_status_map, status);
+}
+
/**
* get_opal_locking_feature_description() - get opal locking feature description.
* @response: response from Opal Discovery Level 0.
diff --git a/drive_encryption.h b/drive_encryption.h
index 77c7f10f..0cb8ff1b 100644
--- a/drive_encryption.h
+++ b/drive_encryption.h
@@ -33,3 +33,5 @@ get_nvme_opal_encryption_information(int disk_fd, struct encryption_information
mdadm_status_t
get_ata_encryption_information(int disk_fd, struct encryption_information *information,
const int verbose);
+const char *get_encryption_ability_string(enum encryption_ability ability);
+const char *get_encryption_status_string(enum encryption_status status);
diff --git a/mdadm.conf.5.in b/mdadm.conf.5.in
index afb0a296..14302a91 100644
--- a/mdadm.conf.5.in
+++ b/mdadm.conf.5.in
@@ -643,6 +643,9 @@ The
disables encryption verification for devices with particular encryption support detected.
Currently, only verification of SATA OPAL encryption can be disabled.
It does not disable ATA security encryption verification.
+Currently effective only for
+.I IMSM
+metadata.
Available parameter
.I "sata_opal".
diff --git a/super-intel.c b/super-intel.c
index 212387ec..fbd1c11f 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -27,6 +27,7 @@
#include <scsi/sg.h>
#include <ctype.h>
#include <dirent.h>
+#include "drive_encryption.h"
/* MPB == Metadata Parameter Block */
#define MPB_SIGNATURE "Intel Raid ISM Cfg Sig. "
@@ -2349,12 +2350,41 @@ static int imsm_read_serial(int fd, char *devname, __u8 *serial,
size_t serial_buf_len);
static void fd2devname(int fd, char *name);
-static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_base, int verbose)
+void print_encryption_information(int disk_fd, enum sys_dev_type hba_type)
+{
+ struct encryption_information information = {0};
+ mdadm_status_t status = MDADM_STATUS_SUCCESS;
+ const char *indent = " ";
+
+ switch (hba_type) {
+ case SYS_DEV_VMD:
+ case SYS_DEV_NVME:
+ status = get_nvme_opal_encryption_information(disk_fd, &information, 1);
+ break;
+ case SYS_DEV_SATA:
+ case SYS_DEV_SATA_VMD:
+ status = get_ata_encryption_information(disk_fd, &information, 1);
+ break;
+ default:
+ return;
+ }
+
+ if (status) {
+ pr_err("Failed to get drive encryption information.\n");
+ return;
+ }
+
+ printf("%sEncryption(Ability|Status): %s|%s\n", indent,
+ get_encryption_ability_string(information.ability),
+ get_encryption_status_string(information.status));
+}
+
+static int ahci_enumerate_ports(struct sys_dev *hba, int port_count, int host_base, int verbose)
{
/* dump an unsorted list of devices attached to AHCI Intel storage
* controller, as well as non-connected ports
*/
- int hba_len = strlen(hba_path) + 1;
+ int hba_len = strlen(hba->path) + 1;
struct dirent *ent;
DIR *dir;
char *path = NULL;
@@ -2390,7 +2420,7 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
path = devt_to_devpath(makedev(major, minor), 1, NULL);
if (!path)
continue;
- if (!path_attached_to_hba(path, hba_path)) {
+ if (!path_attached_to_hba(path, hba->path)) {
free(path);
path = NULL;
continue;
@@ -2493,6 +2523,8 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
printf(" (%s)\n", buf);
else
printf(" ()\n");
+
+ print_encryption_information(fd, hba->type);
close(fd);
}
free(path);
@@ -2557,6 +2589,8 @@ static int print_nvme_info(struct sys_dev *hba)
else
printf("()\n");
+ print_encryption_information(fd, hba->type);
+
skip:
close_fd(&fd);
}
@@ -2812,7 +2846,7 @@ static int detail_platform_imsm(int verbose, int enumerate_only, char *controlle
hba->path, get_sys_dev_type(hba->type));
if (hba->type == SYS_DEV_SATA || hba->type == SYS_DEV_SATA_VMD) {
host_base = ahci_get_port_count(hba->path, &port_count);
- if (ahci_enumerate_ports(hba->path, port_count, host_base, verbose)) {
+ if (ahci_enumerate_ports(hba, port_count, host_base, verbose)) {
if (verbose > 0)
pr_err("failed to enumerate ports on %s controller at %s.\n",
get_sys_dev_type(hba->type), hba->pci_id);
--
2.41.0

View File

@ -0,0 +1,114 @@
From acb8f13be88c224eb1e01f72c1e1fda955bc80ba Mon Sep 17 00:00:00 2001
From: Blazej Kucman <blazej.kucman@intel.com>
Date: Fri, 22 Mar 2024 12:51:20 +0100
Subject: [PATCH 47/69] imsm: drive encryption policy implementation
IMSM cares about drive encryption state. It is not allowed to mix disks
with different encryption state within one md device. This policy will
verify that attempt to use disks with different encryption states will
fail. Verification is performed for devices NVMe/SATA Opal and SATA.
There is one exception, Opal SATA drives encryption is not checked when
ENCRYPTION_NO_VERIFY key with "sata_opal" value is set in conf, for this
reason such drives are treated as without encryption support.
Signed-off-by: Blazej Kucman <blazej.kucman@intel.com>
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
super-intel.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 73 insertions(+)
diff --git a/super-intel.c b/super-intel.c
index fbd1c11f..1faab607 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -11291,6 +11291,78 @@ test_and_add_drive_controller_policy_imsm(const char * const type, dev_policy_t
return MDADM_STATUS_ERROR;
}
+/**
+ * test_and_add_drive_encryption_policy_imsm() - add disk encryption to policies list.
+ * @type: policy type to search in the list.
+ * @pols: list of currently recorded policies.
+ * @disk_fd: file descriptor of the device to check.
+ * @hba: The hba to which the drive is attached, could be NULL if verification is disabled.
+ * @verbose: verbose flag.
+ *
+ * IMSM cares about drive encryption state. It is not allowed to mix disks with different
+ * encryption state within one md device.
+ * If there is no encryption policy on pols we are free to add first one.
+ * If there is a policy then, new must be the same.
+ */
+static mdadm_status_t
+test_and_add_drive_encryption_policy_imsm(const char * const type, dev_policy_t **pols, int disk_fd,
+ struct sys_dev *hba, const int verbose)
+{
+ struct dev_policy *expected_policy = pol_find(*pols, (char *)type);
+ struct encryption_information information = {0};
+ char *encryption_state = "Unknown";
+ int status = MDADM_STATUS_SUCCESS;
+ bool encryption_checked = true;
+ char devname[PATH_MAX];
+
+ if (!hba)
+ goto check_policy;
+
+ switch (hba->type) {
+ case SYS_DEV_NVME:
+ case SYS_DEV_VMD:
+ status = get_nvme_opal_encryption_information(disk_fd, &information, verbose);
+ break;
+ case SYS_DEV_SATA:
+ case SYS_DEV_SATA_VMD:
+ status = get_ata_encryption_information(disk_fd, &information, verbose);
+ break;
+ default:
+ encryption_checked = false;
+ }
+
+ if (status) {
+ fd2devname(disk_fd, devname);
+ pr_vrb("Failed to read encryption information of device %s\n", devname);
+ return MDADM_STATUS_ERROR;
+ }
+
+ if (encryption_checked) {
+ if (information.status == ENC_STATUS_LOCKED) {
+ fd2devname(disk_fd, devname);
+ pr_vrb("Device %s is in Locked state, cannot use. Aborting.\n", devname);
+ return MDADM_STATUS_ERROR;
+ }
+ encryption_state = (char *)get_encryption_status_string(information.status);
+ }
+
+check_policy:
+ if (expected_policy) {
+ if (strcmp(expected_policy->value, encryption_state) == 0)
+ return MDADM_STATUS_SUCCESS;
+
+ fd2devname(disk_fd, devname);
+ pr_vrb("Encryption status \"%s\" detected for disk %s, but \"%s\" status was detected eariler.\n",
+ encryption_state, devname, expected_policy->value);
+ pr_vrb("Disks with different encryption status cannot be used.\n");
+ return MDADM_STATUS_ERROR;
+ }
+
+ pol_add(pols, (char *)type, encryption_state, "imsm");
+
+ return MDADM_STATUS_SUCCESS;
+}
+
struct imsm_drive_policy {
char *type;
mdadm_status_t (*test_and_add_drive_policy)(const char * const type,
@@ -11300,6 +11372,7 @@ struct imsm_drive_policy {
struct imsm_drive_policy imsm_policies[] = {
{"controller", test_and_add_drive_controller_policy_imsm},
+ {"encryption", test_and_add_drive_encryption_policy_imsm}
};
mdadm_status_t test_and_add_drive_policies_imsm(struct dev_policy **pols, int disk_fd,
--
2.41.0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,66 @@
From 21d6c5d96a5a467b5877ba1d38106b3746005bcc Mon Sep 17 00:00:00 2001
From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Date: Tue, 26 Mar 2024 13:21:11 +0100
Subject: [PATCH 49/69] mdadm: Add MAINTAINERS.md
Describe rules maintainer should follow.
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
MAINTAINERS.md | 44 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
create mode 100644 MAINTAINERS.md
diff --git a/MAINTAINERS.md b/MAINTAINERS.md
new file mode 100644
index 00000000..9c79ba87
--- /dev/null
+++ b/MAINTAINERS.md
@@ -0,0 +1,44 @@
+# Maintainer tools
+
+Useful tools used in daily routines:
+- [checkpatch](https://docs.kernel.org/dev-tools/checkpatch.html)
+- [kup](https://korg.docs.kernel.org/kup.html)
+- [Auto-publishing](https://korg.docs.kernel.org/kup.html#auto-publishing-with-git-archive-signer)
+- [b4](https://b4.docs.kernel.org/en/latest/)
+
+# Checklist before applying patch
+
+We don't have CI testing yet, so all those steps must be performed manually:
+- Style check with [checkpatch](https://docs.kernel.org/dev-tools/checkpatch.html):
+
+ This is the current code style follows. We are not strict to all rules. It must be run
+ by **checkpatch --no-tree**, see README.md.
+
+- [Commit style](https://www.kernel.org/doc/html/v4.10/process/submitting-patches.html):
+
+ It doesn't need to be followed as strictly as is in kernel but changes should be logically
+ separated. Submitter should care at least to mention "It is used in next patches" if unused
+ externs/files are added in patch. We love: *Reported-by:*, *Suggested-by:*, *Fixes:* tags.
+
+- Compilation, ideally on various gcc versions.
+- Mdadm test suite execution.
+- Consider requesting new tests from submitter, especially for new functionalities.
+- Ensure that maintainer *sign-off* is added, before pushing.
+
+# Making a release
+
+Assuming that maintainer is certain that release is safe, following steps must be done:
+
+- Update versions strings in release commit, please refer to previous releases for examples.
+
+- Create GPG signed tag and push it to repo. Use same format as was used previously, prefixed by
+ **mdadm-**, e.g. **mdadm-3.1.2**, **mdadm-4.1**.
+
+- [Auto-publishing](https://korg.docs.kernel.org/kup.html#auto-publishing-with-git-archive-signer):
+
+ Adopt script to our release tag model. When ready, push signed note to repository. If it is done
+ correctly, then *(sig)* is added to the package automatically generated by kernel.org automation.
+ There is no need to upload archive manually.
+
+- Update CHANGELOG.md.
+- Write "ANNOUNCE" mail to linux-raid@kernel.org to notify community.
--
2.41.0

View File

@ -0,0 +1,106 @@
From 256edaef3d43a112356762aaea4a48f021f45aec Mon Sep 17 00:00:00 2001
From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Date: Tue, 26 Mar 2024 13:21:12 +0100
Subject: [PATCH 50/69] mdadm: Add README.md
Describe supported metadata types, add step-by-step patch sending
instruction, mention minimally supported kernel version and licensing.
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
README.md | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 83 insertions(+)
create mode 100644 README.md
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..64f2ecec
--- /dev/null
+++ b/README.md
@@ -0,0 +1,83 @@
+**mdadm** is a utility used to create and manage **software RAID** devices implemented through
+**Multiple devices driver (MD)** in kernel. It supports following RAID metadata formats:
+
+* [Linux native RAID](https://raid.wiki.kernel.org/index.php/RAID_superblock_formats):
+
+ Known as **native** or **native RAID**. First and default metadata format. Metadata management
+ is implemented in **MD driver**.
+
+* Matrix Storage Manager Support (no reference, metadata format documentation is proprietary).
+
+ Known as **IMSM**. Metadata format developed and maintained by **Intel®** as a part of **VROC**
+ solution. There are some functional differences between **native** and **imsm**. The most
+ important difference is that the metadata is managed from userspace.
+
+ **CAUTION:** **imsm** is compatible with **Intel RST**, however it is not officially supported.
+ You are using it on your own risk.
+
+* [Common RAID DDF Specification Revision](https://www.snia.org/sites/default/files/SNIA_DDF_Technical_Position_v2.0.pdf)
+
+ **IMPORTANT:** DDF is in **maintenance only** mode. There is no active development around it.
+ Please do not use it in new solutions.
+
+# How to Contribute
+
+ **mdadm** is hosted on [kernel.org](https://kernel.org/). You can access repository
+[here](https://git.kernel.org/pub/scm/utils/mdadm/mdadm.git).
+
+It is maintained similarly to kernel, using *mailing list*. Patches must be send through email.
+Please familiarize with general kernel
+[submitting patches](https://www.kernel.org/doc/html/v4.17/process/submitting-patches.html)
+documentation. Formatting, tags and commit message guidelines applies to **mdadm**.
+
+## Sending patches step-by-step
+
+To maximize change of patches being taken, follow this instruction when submitting:
+
+1. Create possibly logically separated commits and generate patches:
+
+ Use ``git format-patch --cover-letter --signoff -v <nr>`` to create patches:
+ * ``--cover-letter`` can be skipped if it is only one patch;
+ * ``--signoff`` adds sign-off tag;
+ * ``-v <nr>`` indicates review revision number, sender should increment it before resending.
+
+2. Check style of every patch with kernel
+ [checkpatch](https://docs.kernel.org/dev-tools/checkpatch.html) script:
+
+ It is important to keep same coding style that is why in **mdadm**
+ [kernel coding style](https://www.kernel.org/doc/html/v4.10/process/coding-style.html)
+ is preferred. ``checkpath --no-tree <patch_file>`` can be used to verify patches.
+ Following checkpatch issues can be ignored:
+ - New typedefs.
+ - comparing with *True/False*.
+ - kernel *MAINTAINERS* file warning.
+ - *extern* keyword in headers.
+
+3. Send patches using ``git send-mail --to=linux-raid@vger.kernel.org <cover-letter> <patch1> <patch2> (...)``
+
+# Maintainers
+
+It is good practice to add **mdadm maintainers** to recipients for patches:
+
+- Jes Sorensen <jes@trained-monkey.org>;
+- Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>;
+
+Adding **MD maintainers** could be reasonable, especially if patches may affect MD driver:
+
+- Song Liu <song@kernel.org>;
+- Yu Kuai <yukuai3@huawei.com>;
+
+# Reviewers
+
+**mdadm** utility is not part of kernel tree, so there is no certificated *Reviewers* list. Everyone
+can comment on mailing list, last decision (and merging) belongs to maintainers.
+
+# Minimal supported kernel version
+
+We do not support kernel versions below **v3.10**. Please be aware that maintainers may remove
+workarounds and fixes for legacy issues.
+
+# License
+
+It is released under the terms of the **GNU General Public License version 2** as published
+by the **Free Software Foundation**.
--
2.41.0

View File

@ -0,0 +1,41 @@
From 52bead95d2957437c691891fcdc49bd6afccdd49 Mon Sep 17 00:00:00 2001
From: Fabrice Fontaine <fontaine.fabrice@gmail.com>
Date: Fri, 12 Apr 2024 18:45:13 +0200
Subject: [PATCH 51/69] Create.c: fix uclibc build
Define FALLOC_FL_ZERO_RANGE if needed as FALLOC_FL_ZERO_RANGE is only
defined for aarch64 on uclibc-ng resulting in the following or1k build
failure since commit 577fd10486d8d1472a6b559066f344ac30a3a391:
Create.c: In function 'write_zeroes_fork':
Create.c:155:35: error: 'FALLOC_FL_ZERO_RANGE' undeclared (first use in this function)
155 | if (fallocate(fd, FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE,
| ^~~~~~~~~~~~~~~~~~~~
Fixes:
- http://autobuild.buildroot.org/results/0e04bcdb591ca5642053e1f7e31384f06581e989
Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
Create.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Create.c b/Create.c
index 4397ff49..d94253b1 100644
--- a/Create.c
+++ b/Create.c
@@ -32,6 +32,10 @@
#include <sys/signalfd.h>
#include <sys/wait.h>
+#ifndef FALLOC_FL_ZERO_RANGE
+#define FALLOC_FL_ZERO_RANGE 16
+#endif
+
static int round_size_and_verify(unsigned long long *size, int chunk)
{
if (*size == 0)
--
2.41.0

View File

@ -0,0 +1,309 @@
From bdc2c56998abf76141294b04facf20217cfd1911 Mon Sep 17 00:00:00 2001
From: Mateusz Kusiak <mateusz.kusiak@intel.com>
Date: Mon, 29 Apr 2024 15:07:13 +0200
Subject: [PATCH 52/69] mdadm: pass struct context for external reshapes
This patch alters mutiple functions calls so the context is passed to
external reshape functions.
There are two main reasons behind it:
- reduces number of arguments passed and unifies them,
- imsm code will make use of context in incoming patches.
Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
Assemble.c | 7 ++----
Grow.c | 68 +++++++++++++++++++++------------------------------
mdadm.c | 2 +-
mdadm.h | 11 +++------
super-intel.c | 6 ++---
5 files changed, 37 insertions(+), 57 deletions(-)
diff --git a/Assemble.c b/Assemble.c
index f6c5b99e..f5e9ab1f 100644
--- a/Assemble.c
+++ b/Assemble.c
@@ -1197,9 +1197,7 @@ static int start_array(int mdfd,
rv = sysfs_set_str(content, NULL,
"array_state", "readonly");
if (rv == 0)
- rv = Grow_continue(mdfd, st, content,
- c->backup_file, 0,
- c->freeze_reshape);
+ rv = Grow_continue(mdfd, st, content, 0, c);
} else if (c->readonly &&
sysfs_attribute_available(content, NULL,
"array_state")) {
@@ -2180,8 +2178,7 @@ int assemble_container_content(struct supertype *st, int mdfd,
st->update_tail = &st->updates;
}
- err = Grow_continue(mdfd, st, content, c->backup_file,
- 0, c->freeze_reshape);
+ err = Grow_continue(mdfd, st, content, 0, c);
} else switch(content->array.level) {
case LEVEL_LINEAR:
case LEVEL_MULTIPATH:
diff --git a/Grow.c b/Grow.c
index 074f1995..f477b438 100644
--- a/Grow.c
+++ b/Grow.c
@@ -864,8 +864,7 @@ static void wait_reshape(struct mdinfo *sra)
static int reshape_super(struct supertype *st, unsigned long long size,
int level, int layout, int chunksize, int raid_disks,
- int delta_disks, char *backup_file, char *dev,
- int direction, int verbose)
+ int delta_disks, char *dev, int direction, struct context *c)
{
/* nothing extra to check in the native case */
if (!st->ss->external)
@@ -876,9 +875,8 @@ static int reshape_super(struct supertype *st, unsigned long long size,
return 1;
}
- return st->ss->reshape_super(st, size, level, layout, chunksize,
- raid_disks, delta_disks, backup_file, dev,
- direction, verbose);
+ return st->ss->reshape_super(st, size, level, layout, chunksize, raid_disks,
+ delta_disks, dev, direction, c);
}
static void sync_metadata(struct supertype *st)
@@ -1764,9 +1762,8 @@ static int reshape_container(char *container, char *devname,
int mdfd,
struct supertype *st,
struct mdinfo *info,
- int force,
- char *backup_file, int verbose,
- int forked, int restart, int freeze_reshape);
+ struct context *c,
+ int forked, int restart);
/**
* prepare_external_reshape() - prepares update on external metadata if supported.
@@ -2004,9 +2001,8 @@ int Grow_reshape(char *devname, int fd,
goto release;
}
- if (reshape_super(st, s->size, UnSet, UnSet, 0, 0, UnSet, NULL,
- devname, APPLY_METADATA_CHANGES,
- c->verbose > 0)) {
+ if (reshape_super(st, s->size, UnSet, UnSet, 0, 0, UnSet,
+ devname, APPLY_METADATA_CHANGES, c)) {
rv = 1;
goto release;
}
@@ -2124,10 +2120,8 @@ size_change_error:
int err = errno;
/* restore metadata */
- if (reshape_super(st, orig_size, UnSet, UnSet, 0, 0,
- UnSet, NULL, devname,
- ROLLBACK_METADATA_CHANGES,
- c->verbose) == 0)
+ if (reshape_super(st, orig_size, UnSet, UnSet, 0, 0, UnSet,
+ devname, ROLLBACK_METADATA_CHANGES, c) == 0)
sync_metadata(st);
pr_err("Cannot set device size for %s: %s\n",
devname, strerror(err));
@@ -2338,8 +2332,7 @@ size_change_error:
*/
close_fd(&fd);
rv = reshape_container(container, devname, -1, st, &info,
- c->force, c->backup_file, c->verbose,
- 0, 0, 0);
+ c, 0, 0);
frozen = 0;
} else {
/* get spare devices from external metadata
@@ -2356,13 +2349,13 @@ size_change_error:
}
/* Impose these changes on a single array. First
- * check that the metadata is OK with the change. */
+ * check that the metadata is OK with the change.
+ */
if (reshape_super(st, 0, info.new_level,
info.new_layout, info.new_chunk,
info.array.raid_disks, info.delta_disks,
- c->backup_file, devname,
- APPLY_METADATA_CHANGES, c->verbose)) {
+ devname, APPLY_METADATA_CHANGES, c)) {
rv = 1;
goto release;
}
@@ -3668,9 +3661,8 @@ int reshape_container(char *container, char *devname,
int mdfd,
struct supertype *st,
struct mdinfo *info,
- int force,
- char *backup_file, int verbose,
- int forked, int restart, int freeze_reshape)
+ struct context *c,
+ int forked, int restart)
{
struct mdinfo *cc = NULL;
int rv = restart;
@@ -3683,8 +3675,7 @@ int reshape_container(char *container, char *devname,
reshape_super(st, 0, info->new_level,
info->new_layout, info->new_chunk,
info->array.raid_disks, info->delta_disks,
- backup_file, devname, APPLY_METADATA_CHANGES,
- verbose)) {
+ devname, APPLY_METADATA_CHANGES, c)) {
unfreeze(st);
return 1;
}
@@ -3695,7 +3686,7 @@ int reshape_container(char *container, char *devname,
*/
ping_monitor(container);
- if (!forked && !freeze_reshape)
+ if (!forked && !c->freeze_reshape)
if (continue_via_systemd(container, GROW_SERVICE, NULL))
return 0;
@@ -3705,7 +3696,7 @@ int reshape_container(char *container, char *devname,
unfreeze(st);
return 1;
default: /* parent */
- if (!freeze_reshape)
+ if (!c->freeze_reshape)
printf("%s: multi-array reshape continues in background\n", Name);
return 0;
case 0: /* child */
@@ -3802,12 +3793,12 @@ int reshape_container(char *container, char *devname,
flush_mdmon(container);
rv = reshape_array(container, fd, adev, st,
- content, force, NULL, INVALID_SECTORS,
- backup_file, verbose, 1, restart,
- freeze_reshape);
+ content, c->force, NULL, INVALID_SECTORS,
+ c->backup_file, c->verbose, 1, restart,
+ c->freeze_reshape);
close(fd);
- if (freeze_reshape) {
+ if (c->freeze_reshape) {
sysfs_free(cc);
exit(0);
}
@@ -4970,8 +4961,7 @@ int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist,
return 1;
}
-int Grow_continue_command(char *devname, int fd,
- char *backup_file, int verbose)
+int Grow_continue_command(char *devname, int fd, struct context *c)
{
int ret_val = 0;
struct supertype *st = NULL;
@@ -5157,7 +5147,7 @@ int Grow_continue_command(char *devname, int fd,
/* continue reshape
*/
- ret_val = Grow_continue(fd, st, content, backup_file, 1, 0);
+ ret_val = Grow_continue(fd, st, content, 1, c);
Grow_continue_command_exit:
if (cfd > -1)
@@ -5171,7 +5161,7 @@ Grow_continue_command_exit:
}
int Grow_continue(int mdfd, struct supertype *st, struct mdinfo *info,
- char *backup_file, int forked, int freeze_reshape)
+ int forked, struct context *c)
{
int ret_val = 2;
@@ -5187,14 +5177,12 @@ int Grow_continue(int mdfd, struct supertype *st, struct mdinfo *info,
st->ss->load_container(st, cfd, st->container_devnm);
close(cfd);
ret_val = reshape_container(st->container_devnm, NULL, mdfd,
- st, info, 0, backup_file, 0,
- forked, 1 | info->reshape_active,
- freeze_reshape);
+ st, info, c, forked, 1 | info->reshape_active);
} else
ret_val = reshape_array(NULL, mdfd, "array", st, info, 1,
- NULL, INVALID_SECTORS, backup_file,
+ NULL, INVALID_SECTORS, c->backup_file,
0, forked, 1 | info->reshape_active,
- freeze_reshape);
+ c->freeze_reshape);
return ret_val;
}
diff --git a/mdadm.c b/mdadm.c
index 3f191288..d18619db 100644
--- a/mdadm.c
+++ b/mdadm.c
@@ -1636,7 +1636,7 @@ int main(int argc, char *argv[])
c.delay = DEFAULT_BITMAP_DELAY;
rv = Grow_addbitmap(ident.devname, mdfd, &c, &s);
} else if (grow_continue)
- rv = Grow_continue_command(ident.devname, mdfd, c.backup_file, c.verbose);
+ rv = Grow_continue_command(ident.devname, mdfd, &c);
else if (s.size > 0 || s.raiddisks || s.layout_str ||
s.chunk != 0 || s.level != UnSet ||
s.data_offset != INVALID_SECTORS) {
diff --git a/mdadm.h b/mdadm.h
index 2640b396..0ade4beb 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -1235,9 +1235,8 @@ extern struct superswitch {
int (*reshape_super)(struct supertype *st,
unsigned long long size, int level,
int layout, int chunksize, int raid_disks,
- int delta_disks, char *backup, char *dev,
- int direction,
- int verbose); /* optional */
+ int delta_disks, char *dev, int direction,
+ struct context *c);
int (*manage_reshape)( /* optional */
int afd, struct mdinfo *sra, struct reshape *reshape,
struct supertype *st, unsigned long blocks,
@@ -1541,8 +1540,7 @@ extern int Grow_reshape(char *devname, int fd,
extern int Grow_restart(struct supertype *st, struct mdinfo *info,
int *fdlist, int cnt, char *backup_file, int verbose);
extern int Grow_continue(int mdfd, struct supertype *st,
- struct mdinfo *info, char *backup_file,
- int forked, int freeze_reshape);
+ struct mdinfo *info, int forked, struct context *c);
extern int Grow_consistency_policy(char *devname, int fd,
struct context *c, struct shape *s);
@@ -1552,8 +1550,7 @@ extern int restore_backup(struct supertype *st,
int spares,
char **backup_filep,
int verbose);
-extern int Grow_continue_command(char *devname, int fd,
- char *backup_file, int verbose);
+extern int Grow_continue_command(char *devname, int fd, struct context *c);
extern int Assemble(struct supertype *st, char *mddev,
struct mddev_ident *ident,
diff --git a/super-intel.c b/super-intel.c
index 1faab607..417da267 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -12153,10 +12153,8 @@ exit:
}
static int imsm_reshape_super(struct supertype *st, unsigned long long size,
- int level,
- int layout, int chunksize, int raid_disks,
- int delta_disks, char *backup, char *dev,
- int direction, int verbose)
+ int level, int layout, int chunksize, int raid_disks,
+ int delta_disks, char *dev, int direction, struct context *c)
{
int ret_val = 1;
struct geo_params geo;
--
2.41.0

View File

@ -0,0 +1,296 @@
From 0acda7053df653022e46fa3b7caf1f4d4ba31a66 Mon Sep 17 00:00:00 2001
From: Mateusz Kusiak <mateusz.kusiak@intel.com>
Date: Mon, 29 Apr 2024 15:07:14 +0200
Subject: [PATCH 53/69] mdadm: use struct context in reshape_super()
reshape_super() takes too many arguments. Change passing params in
favor of single struct.
Add devname pointer and change direction members to struct shape
and use it for reshape_super().
Create reshape_array_size() and reshape_array_non_size() to handle
reshape_super() calls.
Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
Grow.c | 93 +++++++++++++++++++++++++++++++++++++--------------
mdadm.h | 18 +++++-----
super-intel.c | 43 +++++++++++++++---------
3 files changed, 105 insertions(+), 49 deletions(-)
diff --git a/Grow.c b/Grow.c
index f477b438..87ed9214 100644
--- a/Grow.c
+++ b/Grow.c
@@ -862,9 +862,7 @@ static void wait_reshape(struct mdinfo *sra)
close(fd);
}
-static int reshape_super(struct supertype *st, unsigned long long size,
- int level, int layout, int chunksize, int raid_disks,
- int delta_disks, char *dev, int direction, struct context *c)
+static int reshape_super(struct supertype *st, struct shape *shape, struct context *c)
{
/* nothing extra to check in the native case */
if (!st->ss->external)
@@ -875,8 +873,65 @@ static int reshape_super(struct supertype *st, unsigned long long size,
return 1;
}
- return st->ss->reshape_super(st, size, level, layout, chunksize, raid_disks,
- delta_disks, dev, direction, c);
+ return st->ss->reshape_super(st, shape, c);
+}
+
+/**
+ * reshape_super_size() - Reshape array, size only.
+ *
+ * @st: supertype.
+ * @devname: device name.
+ * @size: component size.
+ * @dir metadata changes direction
+ * Returns: 0 on success, 1 otherwise.
+ *
+ * This function is solely used to change size of the volume.
+ * Setting size is not valid for container.
+ * Size is only change that can be rolled back, thus the @dir param.
+ */
+static int reshape_super_size(struct supertype *st, char *devname,
+ unsigned long long size, change_dir_t direction,
+ struct context *c)
+{
+ struct shape shape = {0};
+
+ shape.level = UnSet;
+ shape.layout = UnSet;
+ shape.delta_disks = UnSet;
+ shape.dev = devname;
+ shape.size = size;
+ shape.direction = direction;
+
+ return reshape_super(st, &shape, c);
+}
+
+/**
+ * reshape_super_non_size() - Reshape array, non size changes.
+ *
+ * @st: supertype.
+ * @devname: device name.
+ * @info: superblock info.
+ * Returns: 0 on success, 1 otherwise.
+ *
+ * This function is used for any external array changes but size.
+ * It handles both volumes and containers.
+ * For changes other than size, rollback is not possible.
+ */
+static int reshape_super_non_size(struct supertype *st, char *devname,
+ struct mdinfo *info, struct context *c)
+{
+ struct shape shape = {0};
+ /* Size already set to zero, not updating size */
+ shape.level = info->new_level;
+ shape.layout = info->new_layout;
+ shape.chunk = info->new_chunk;
+ shape.raiddisks = info->array.raid_disks;
+ shape.delta_disks = info->delta_disks;
+ shape.dev = devname;
+ /* Rollback not possible for non size changes */
+ shape.direction = APPLY_METADATA_CHANGES;
+
+ return reshape_super(st, &shape, c);
}
static void sync_metadata(struct supertype *st)
@@ -1979,9 +2034,8 @@ int Grow_reshape(char *devname, int fd,
}
/* ========= set size =============== */
- if (s->size > 0 &&
- (s->size == MAX_SIZE || s->size != (unsigned)array.size)) {
- unsigned long long orig_size = get_component_size(fd)/2;
+ if (s->size > 0 && (s->size == MAX_SIZE || s->size != (unsigned)array.size)) {
+ unsigned long long orig_size = get_component_size(fd) / 2;
unsigned long long min_csize;
struct mdinfo *mdi;
int raid0_takeover = 0;
@@ -2001,8 +2055,7 @@ int Grow_reshape(char *devname, int fd,
goto release;
}
- if (reshape_super(st, s->size, UnSet, UnSet, 0, 0, UnSet,
- devname, APPLY_METADATA_CHANGES, c)) {
+ if (reshape_super_size(st, devname, s->size, APPLY_METADATA_CHANGES, c)) {
rv = 1;
goto release;
}
@@ -2120,8 +2173,8 @@ size_change_error:
int err = errno;
/* restore metadata */
- if (reshape_super(st, orig_size, UnSet, UnSet, 0, 0, UnSet,
- devname, ROLLBACK_METADATA_CHANGES, c) == 0)
+ if (reshape_super_size(st, devname, orig_size,
+ ROLLBACK_METADATA_CHANGES, c) == 0)
sync_metadata(st);
pr_err("Cannot set device size for %s: %s\n",
devname, strerror(err));
@@ -2351,11 +2404,7 @@ size_change_error:
/* Impose these changes on a single array. First
* check that the metadata is OK with the change.
*/
-
- if (reshape_super(st, 0, info.new_level,
- info.new_layout, info.new_chunk,
- info.array.raid_disks, info.delta_disks,
- devname, APPLY_METADATA_CHANGES, c)) {
+ if (reshape_super_non_size(st, devname, &info, c)) {
rv = 1;
goto release;
}
@@ -3668,14 +3717,8 @@ int reshape_container(char *container, char *devname,
int rv = restart;
char last_devnm[32] = "";
- /* component_size is not meaningful for a container,
- * so pass '0' meaning 'no change'
- */
- if (!restart &&
- reshape_super(st, 0, info->new_level,
- info->new_layout, info->new_chunk,
- info->array.raid_disks, info->delta_disks,
- devname, APPLY_METADATA_CHANGES, c)) {
+ /* component_size is not meaningful for a container */
+ if (!restart && reshape_super_non_size(st, devname, info, c)) {
unfreeze(st);
return 1;
}
diff --git a/mdadm.h b/mdadm.h
index 0ade4beb..2ff3e463 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -594,6 +594,11 @@ enum flag_mode {
FlagDefault, FlagSet, FlagClear,
};
+typedef enum {
+ ROLLBACK_METADATA_CHANGES,
+ APPLY_METADATA_CHANGES
+} change_dir_t;
+
/* structures read from config file */
/* List of mddevice names and identifiers
* Identifiers can be:
@@ -667,7 +672,9 @@ struct context {
};
struct shape {
+ char *dev;
int raiddisks;
+ int delta_disks;
int sparedisks;
int journaldisks;
int level;
@@ -682,6 +689,7 @@ struct shape {
unsigned long long size;
unsigned long long data_offset;
int consistency_policy;
+ change_dir_t direction;
};
/* List of device names - wildcards expanded */
@@ -1229,14 +1237,8 @@ extern struct superswitch {
* initialized to indicate if reshape is being performed at the
* container or subarray level
*/
-#define APPLY_METADATA_CHANGES 1
-#define ROLLBACK_METADATA_CHANGES 0
-
- int (*reshape_super)(struct supertype *st,
- unsigned long long size, int level,
- int layout, int chunksize, int raid_disks,
- int delta_disks, char *dev, int direction,
- struct context *c);
+
+ int (*reshape_super)(struct supertype *st, struct shape *shape, struct context *c);
int (*manage_reshape)( /* optional */
int afd, struct mdinfo *sra, struct reshape *reshape,
struct supertype *st, unsigned long blocks,
diff --git a/super-intel.c b/super-intel.c
index 417da267..1a8a7b12 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -12152,26 +12152,37 @@ exit:
return ret_val;
}
-static int imsm_reshape_super(struct supertype *st, unsigned long long size,
- int level, int layout, int chunksize, int raid_disks,
- int delta_disks, char *dev, int direction, struct context *c)
+/**
+ * shape_to_geo() - fill geo_params from shape.
+ *
+ * @shape: array details.
+ * @geo: new geometry params.
+ * Returns: 0 on success, 1 otherwise.
+ */
+static void shape_to_geo(struct shape *shape, struct geo_params *geo)
+{
+ assert(shape);
+ assert(geo);
+
+ geo->dev_name = shape->dev;
+ geo->size = shape->size;
+ geo->level = shape->level;
+ geo->layout = shape->layout;
+ geo->chunksize = shape->chunk;
+ geo->raid_disks = shape->raiddisks;
+}
+
+static int imsm_reshape_super(struct supertype *st, struct shape *shape, struct context *c)
{
int ret_val = 1;
- struct geo_params geo;
+ struct geo_params geo = {0};
dprintf("(enter)\n");
- memset(&geo, 0, sizeof(struct geo_params));
-
- geo.dev_name = dev;
+ shape_to_geo(shape, &geo);
strcpy(geo.devnm, st->devnm);
- geo.size = size;
- geo.level = level;
- geo.layout = layout;
- geo.chunksize = chunksize;
- geo.raid_disks = raid_disks;
- if (delta_disks != UnSet)
- geo.raid_disks += delta_disks;
+ if (shape->delta_disks != UnSet)
+ geo.raid_disks += shape->delta_disks;
dprintf("for level : %i\n", geo.level);
dprintf("for raid_disks : %i\n", geo.raid_disks);
@@ -12182,7 +12193,7 @@ static int imsm_reshape_super(struct supertype *st, unsigned long long size,
int old_raid_disks = 0;
if (imsm_reshape_is_allowed_on_container(
- st, &geo, &old_raid_disks, direction)) {
+ st, &geo, &old_raid_disks, shape->direction)) {
struct imsm_update_reshape *u = NULL;
int len;
@@ -12236,7 +12247,7 @@ static int imsm_reshape_super(struct supertype *st, unsigned long long size,
goto exit_imsm_reshape_super;
}
super->current_vol = dev->index;
- change = imsm_analyze_change(st, &geo, direction);
+ change = imsm_analyze_change(st, &geo, shape->direction);
switch (change) {
case CH_TAKEOVER:
ret_val = imsm_takeover(st, &geo);
--
2.41.0

View File

@ -0,0 +1,184 @@
From 27550b13297adbdefe42fe4eb785b7fde1c0ed91 Mon Sep 17 00:00:00 2001
From: Mateusz Kusiak <mateusz.kusiak@intel.com>
Date: Mon, 29 Apr 2024 15:07:15 +0200
Subject: [PATCH 54/69] imsm: add support for literal RAID 10
As for now, IMSM supports only 4 drive RAID 1+0. This patch is first in
series to add support for literal RAID 10 (with more than 4 drives) to
imsm.
Allow setting RAID 10 as raid level for imsm arrays.
Add update_imsm_raid_level() to handle raid level updates. Set RAID10 as
default level for imsm R0 to R10 migrations. Replace magic numbers with
defined values for RAID level checks/assigns.
Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
super-intel.c | 67 ++++++++++++++++++++++++++++++++++++---------------
1 file changed, 48 insertions(+), 19 deletions(-)
diff --git a/super-intel.c b/super-intel.c
index 1a8a7b12..a7efc8df 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -166,7 +166,8 @@ struct imsm_map {
__u8 raid_level;
#define IMSM_T_RAID0 0
#define IMSM_T_RAID1 1
-#define IMSM_T_RAID5 5 /* since metadata version 1.2.02 ? */
+#define IMSM_T_RAID5 5
+#define IMSM_T_RAID10 10
__u8 num_members; /* number of member disks */
__u8 num_domains; /* number of parity domains */
__u8 failed_disk_num; /* valid only when state is degraded */
@@ -1259,14 +1260,42 @@ static int get_imsm_disk_slot(struct imsm_map *map, const unsigned int idx)
return IMSM_STATUS_ERROR;
}
+/**
+ * update_imsm_raid_level() - update raid level appropriately in &imsm_map.
+ * @map: &imsm_map pointer.
+ * @new_level: MD style level.
+ *
+ * For backward compatibility reasons we need to differentiate RAID10.
+ * In the past IMSM RAID10 was presented as RAID1.
+ * Keep compatibility unless it is not explicitly updated by UEFI driver.
+ *
+ * Routine needs num_members to be set and (optionally) raid_level.
+ */
+static void update_imsm_raid_level(struct imsm_map *map, int new_level)
+{
+ if (new_level != IMSM_T_RAID10) {
+ map->raid_level = new_level;
+ return;
+ }
+
+ if (map->num_members == 4) {
+ if (map->raid_level == IMSM_T_RAID10 || map->raid_level == IMSM_T_RAID1)
+ return;
+
+ map->raid_level = IMSM_T_RAID1;
+ return;
+ }
+
+ map->raid_level = IMSM_T_RAID10;
+}
static int get_imsm_raid_level(struct imsm_map *map)
{
- if (map->raid_level == 1) {
+ if (map->raid_level == IMSM_T_RAID1) {
if (map->num_members == 2)
- return 1;
+ return IMSM_T_RAID1;
else
- return 10;
+ return IMSM_T_RAID10;
}
return map->raid_level;
@@ -5678,7 +5707,7 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
set_pba_of_lba0(map, super->create_offset);
map->blocks_per_strip = __cpu_to_le16(info_to_blocks_per_strip(info));
map->failed_disk_num = ~0;
- if (info->level > 0)
+ if (info->level > IMSM_T_RAID0)
map->map_state = (info->state ? IMSM_T_STATE_NORMAL
: IMSM_T_STATE_UNINITIALIZED);
else
@@ -5686,16 +5715,15 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
IMSM_T_STATE_NORMAL;
map->ddf = 1;
- if (info->level == 1 && info->raid_disks > 2) {
+ if (info->level == IMSM_T_RAID1 && info->raid_disks > 2) {
free(dev);
free(dv);
- pr_err("imsm does not support more than 2 disksin a raid1 volume\n");
+ pr_err("imsm does not support more than 2 disks in a raid1 volume\n");
return 0;
}
+ map->num_members = info->raid_disks;
- map->raid_level = info->level;
- if (info->level == 10)
- map->raid_level = 1;
+ update_imsm_raid_level(map, info->level);
set_num_domains(map);
size_per_member += NUM_BLOCKS_DIRTY_STRIPE_REGION;
@@ -5703,7 +5731,6 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
size_per_member /
BLOCKS_PER_KB));
- map->num_members = info->raid_disks;
update_num_data_stripes(map, array_blocks);
for (i = 0; i < map->num_members; i++) {
/* initialized in add_to_super */
@@ -8275,7 +8302,7 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
info_d->data_offset = pba_of_lba0(map);
info_d->component_size = calc_component_size(map, dev);
- if (map->raid_level == 5) {
+ if (map->raid_level == IMSM_T_RAID5) {
info_d->ppl_sector = this->ppl_sector;
info_d->ppl_size = this->ppl_size;
if (this->consistency_policy == CONSISTENCY_POLICY_PPL &&
@@ -9533,7 +9560,7 @@ static int apply_reshape_migration_update(struct imsm_update_reshape_migration *
}
to_state = map->map_state;
- if ((u->new_level == 5) && (map->raid_level == 0)) {
+ if ((u->new_level == IMSM_T_RAID5) && (map->raid_level == IMSM_T_RAID0)) {
map->num_members++;
/* this should not happen */
if (u->new_disks[0] < 0) {
@@ -9544,11 +9571,13 @@ static int apply_reshape_migration_update(struct imsm_update_reshape_migration *
to_state = IMSM_T_STATE_NORMAL;
}
migrate(new_dev, super, to_state, MIGR_GEN_MIGR);
+
if (u->new_level > -1)
- map->raid_level = u->new_level;
+ update_imsm_raid_level(map, u->new_level);
+
migr_map = get_imsm_map(new_dev, MAP_1);
- if ((u->new_level == 5) &&
- (migr_map->raid_level == 0)) {
+ if ((u->new_level == IMSM_T_RAID5) &&
+ (migr_map->raid_level == IMSM_T_RAID0)) {
int ord = map->num_members - 1;
migr_map->num_members--;
if (u->new_disks[0] < 0)
@@ -9584,7 +9613,7 @@ static int apply_reshape_migration_update(struct imsm_update_reshape_migration *
/* add disk
*/
- if (u->new_level != 5 || migr_map->raid_level != 0 ||
+ if (u->new_level != IMSM_T_RAID5 || migr_map->raid_level != IMSM_T_RAID0 ||
migr_map->raid_level == map->raid_level)
goto skip_disk_add;
@@ -9963,7 +9992,7 @@ static int apply_takeover_update(struct imsm_update_takeover *u,
/* update map */
map->num_members /= map->num_domains;
map->map_state = IMSM_T_STATE_NORMAL;
- map->raid_level = 0;
+ update_imsm_raid_level(map, IMSM_T_RAID0);
set_num_domains(map);
update_num_data_stripes(map, imsm_dev_size(dev));
map->failed_disk_num = -1;
@@ -10007,7 +10036,7 @@ static int apply_takeover_update(struct imsm_update_takeover *u,
map = get_imsm_map(dev_new, MAP_0);
map->map_state = IMSM_T_STATE_DEGRADED;
- map->raid_level = 1;
+ update_imsm_raid_level(map, IMSM_T_RAID10);
set_num_domains(map);
map->num_members = map->num_members * map->num_domains;
update_num_data_stripes(map, imsm_dev_size(dev));
--
2.41.0

View File

@ -0,0 +1,345 @@
From 191e6ddb1388236c5c54baf5020a87c996be941f Mon Sep 17 00:00:00 2001
From: Mateusz Kusiak <mateusz.kusiak@intel.com>
Date: Mon, 29 Apr 2024 15:07:16 +0200
Subject: [PATCH 55/69] imsm: refactor RAID level handling
Add imsm_level_ops struct for better handling and unifying raid level
support. Add helper methods and move "orom_has_raid[...]" methods from
header to source file.
RAID 1e is not supported under Linux, remove RAID 1e associated code.
Refactor imsm_analyze_change() and is_raid_level_supported().
Remove hardcoded check for 4 drives and make devNumChange a multiplier
for RAID 10.
Refactor printing supported raid levels.
Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
platform-intel.c | 57 ++++++++++++++++++++++++
platform-intel.h | 32 ++++++--------
super-intel.c | 111 ++++++++++++++++++++++++++++-------------------
3 files changed, 138 insertions(+), 62 deletions(-)
diff --git a/platform-intel.c b/platform-intel.c
index ac282bc5..40e8fb82 100644
--- a/platform-intel.c
+++ b/platform-intel.c
@@ -32,6 +32,63 @@
#define NVME_SUBSYS_PATH "/sys/devices/virtual/nvme-subsystem/"
+static bool imsm_orom_has_raid0(const struct imsm_orom *orom)
+{
+ return imsm_rlc_has_bit(orom, IMSM_OROM_RLC_RAID0);
+}
+
+static bool imsm_orom_has_raid1(const struct imsm_orom *orom)
+{
+ return imsm_rlc_has_bit(orom, IMSM_OROM_RLC_RAID1);
+}
+
+static bool imsm_orom_has_raid10(const struct imsm_orom *orom)
+{
+ return imsm_rlc_has_bit(orom, IMSM_OROM_RLC_RAID10);
+}
+
+static bool imsm_orom_has_raid5(const struct imsm_orom *orom)
+{
+ return imsm_rlc_has_bit(orom, IMSM_OROM_RLC_RAID5);
+}
+
+/* IMSM platforms do not define how many disks are allowed for each level,
+ * but there are some global limitations we need to follow.
+ */
+static bool imsm_orom_support_raid_disks_count_raid0(const int raid_disks)
+{
+ return true;
+}
+
+static bool imsm_orom_support_raid_disks_count_raid1(const int raid_disks)
+{
+ if (raid_disks == 2)
+ return true;
+ return false;
+}
+
+static bool imsm_orom_support_raid_disks_count_raid5(const int raid_disks)
+{
+ if (raid_disks > 2)
+ return true;
+ return false;
+}
+
+static bool imsm_orom_support_raid_disks_count_raid10(const int raid_disks)
+{
+ if (raid_disks == 4)
+ return true;
+ return false;
+}
+
+struct imsm_level_ops imsm_level_ops[] = {
+ {0, imsm_orom_has_raid0, imsm_orom_support_raid_disks_count_raid0, "raid0"},
+ {1, imsm_orom_has_raid1, imsm_orom_support_raid_disks_count_raid1, "raid1"},
+ {5, imsm_orom_has_raid5, imsm_orom_support_raid_disks_count_raid5, "raid5"},
+ {10, imsm_orom_has_raid10, imsm_orom_support_raid_disks_count_raid10, "raid10"},
+ {-1, NULL, NULL, NULL}
+};
+
static int devpath_to_ll(const char *dev_path, const char *entry,
unsigned long long *val);
diff --git a/platform-intel.h b/platform-intel.h
index 3c2bc595..dcc5aaa7 100644
--- a/platform-intel.h
+++ b/platform-intel.h
@@ -109,25 +109,21 @@ struct imsm_orom {
#define IMSM_OROM_CAPABILITIES_TPV (1 << 10)
} __attribute__((packed));
-static inline int imsm_orom_has_raid0(const struct imsm_orom *orom)
-{
- return !!(orom->rlc & IMSM_OROM_RLC_RAID0);
-}
-static inline int imsm_orom_has_raid1(const struct imsm_orom *orom)
-{
- return !!(orom->rlc & IMSM_OROM_RLC_RAID1);
-}
-static inline int imsm_orom_has_raid1e(const struct imsm_orom *orom)
-{
- return !!(orom->rlc & IMSM_OROM_RLC_RAID1E);
-}
-static inline int imsm_orom_has_raid10(const struct imsm_orom *orom)
-{
- return !!(orom->rlc & IMSM_OROM_RLC_RAID10);
-}
-static inline int imsm_orom_has_raid5(const struct imsm_orom *orom)
+/* IMSM metadata requirements for each level */
+struct imsm_level_ops {
+ int level;
+ bool (*is_level_supported)(const struct imsm_orom *);
+ bool (*is_raiddisks_count_supported)(const int);
+ char *name;
+};
+
+extern struct imsm_level_ops imsm_level_ops[];
+
+static inline bool imsm_rlc_has_bit(const struct imsm_orom *orom, const unsigned short bit)
{
- return !!(orom->rlc & IMSM_OROM_RLC_RAID5);
+ if (orom->rlc & bit)
+ return true;
+ return false;
}
/**
diff --git a/super-intel.c b/super-intel.c
index a7efc8df..da17265d 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -2681,6 +2681,15 @@ static int ahci_get_port_count(const char *hba_path, int *port_count)
return host_base;
}
+static void print_imsm_level_capability(const struct imsm_orom *orom)
+{
+ int idx;
+
+ for (idx = 0; imsm_level_ops[idx].name; idx++)
+ if (imsm_level_ops[idx].is_level_supported(orom))
+ printf("%s ", imsm_level_ops[idx].name);
+}
+
static void print_imsm_capability(const struct imsm_orom *orom)
{
printf(" Platform : Intel(R) ");
@@ -2699,12 +2708,11 @@ static void print_imsm_capability(const struct imsm_orom *orom)
printf(" Version : %d.%d.%d.%d\n", orom->major_ver,
orom->minor_ver, orom->hotfix_ver, orom->build);
}
- printf(" RAID Levels :%s%s%s%s%s\n",
- imsm_orom_has_raid0(orom) ? " raid0" : "",
- imsm_orom_has_raid1(orom) ? " raid1" : "",
- imsm_orom_has_raid1e(orom) ? " raid1e" : "",
- imsm_orom_has_raid10(orom) ? " raid10" : "",
- imsm_orom_has_raid5(orom) ? " raid5" : "");
+
+ printf(" RAID Levels : ");
+ print_imsm_level_capability(orom);
+ printf("\n");
+
printf(" Chunk Sizes :%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
imsm_orom_has_chunk(orom, 2) ? " 2k" : "",
imsm_orom_has_chunk(orom, 4) ? " 4k" : "",
@@ -2739,12 +2747,11 @@ static void print_imsm_capability_export(const struct imsm_orom *orom)
if (orom->major_ver || orom->minor_ver || orom->hotfix_ver || orom->build)
printf("IMSM_VERSION=%d.%d.%d.%d\n", orom->major_ver, orom->minor_ver,
orom->hotfix_ver, orom->build);
- printf("IMSM_SUPPORTED_RAID_LEVELS=%s%s%s%s%s\n",
- imsm_orom_has_raid0(orom) ? "raid0 " : "",
- imsm_orom_has_raid1(orom) ? "raid1 " : "",
- imsm_orom_has_raid1e(orom) ? "raid1e " : "",
- imsm_orom_has_raid5(orom) ? "raid10 " : "",
- imsm_orom_has_raid10(orom) ? "raid5 " : "");
+
+ printf("IMSM_SUPPORTED_RAID_LEVELS=");
+ print_imsm_level_capability(orom);
+ printf("\n");
+
printf("IMSM_SUPPORTED_CHUNK_SIZES=%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
imsm_orom_has_chunk(orom, 2) ? "2k " : "",
imsm_orom_has_chunk(orom, 4) ? "4k " : "",
@@ -6992,26 +6999,41 @@ static unsigned long long merge_extents(struct intel_super *super, const bool ex
return free_size - reservation_size;
}
-static int is_raid_level_supported(const struct imsm_orom *orom, int level, int raiddisks)
+/**
+ * is_raid_level_supported() - check if this count of drives and level is supported by platform.
+ * @orom: hardware properties, could be NULL.
+ * @level: requested raid level.
+ * @raiddisks: requested disk count.
+ *
+ * IMSM UEFI/OROM does not provide information about supported count of raid disks
+ * for particular level. That is why it is hardcoded.
+ * It is recommended to not allow of usage other levels than supported,
+ * IMSM code is not tested against different level implementations.
+ *
+ * Return: true if supported, false otherwise.
+ */
+static bool is_raid_level_supported(const struct imsm_orom *orom, int level, int raiddisks)
{
- if (level < 0 || level == 6 || level == 4)
- return 0;
+ int idx;
- /* if we have an orom prevent invalid raid levels */
- if (orom)
- switch (level) {
- case 0: return imsm_orom_has_raid0(orom);
- case 1:
- if (raiddisks > 2)
- return imsm_orom_has_raid1e(orom);
- return imsm_orom_has_raid1(orom) && raiddisks == 2;
- case 10: return imsm_orom_has_raid10(orom) && raiddisks == 4;
- case 5: return imsm_orom_has_raid5(orom) && raiddisks > 2;
- }
- else
- return 1; /* not on an Intel RAID platform so anything goes */
+ for (idx = 0; imsm_level_ops[idx].name; idx++) {
+ if (imsm_level_ops[idx].level == level)
+ break;
+ }
- return 0;
+ if (!imsm_level_ops[idx].name)
+ return false;
+
+ if (!imsm_level_ops[idx].is_raiddisks_count_supported(raiddisks))
+ return false;
+
+ if (!orom)
+ return true;
+
+ if (imsm_level_ops[idx].is_level_supported(orom))
+ return true;
+
+ return false;
}
static int
@@ -11962,18 +11984,17 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
int change = -1;
int check_devs = 0;
int chunk;
- /* number of added/removed disks in operation result */
- int devNumChange = 0;
/* imsm compatible layout value for array geometry verification */
int imsm_layout = -1;
+ int raid_disks = geo->raid_disks;
imsm_status_t rv;
getinfo_super_imsm_volume(st, &info, NULL);
- if (geo->level != info.array.level && geo->level >= 0 &&
+ if (geo->level != info.array.level && geo->level >= IMSM_T_RAID0 &&
geo->level != UnSet) {
switch (info.array.level) {
- case 0:
- if (geo->level == 5) {
+ case IMSM_T_RAID0:
+ if (geo->level == IMSM_T_RAID5) {
change = CH_MIGRATION;
if (geo->layout != ALGORITHM_LEFT_ASYMMETRIC) {
pr_err("Error. Requested Layout not supported (left-asymmetric layout is supported only)!\n");
@@ -11982,20 +12003,20 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
}
imsm_layout = geo->layout;
check_devs = 1;
- devNumChange = 1; /* parity disk added */
- } else if (geo->level == 10) {
+ raid_disks += 1; /* parity disk added */
+ } else if (geo->level == IMSM_T_RAID10) {
change = CH_TAKEOVER;
check_devs = 1;
- devNumChange = 2; /* two mirrors added */
+ raid_disks *= 2; /* mirrors added */
imsm_layout = 0x102; /* imsm supported layout */
}
break;
- case 1:
- case 10:
+ case IMSM_T_RAID1:
+ case IMSM_T_RAID10:
if (geo->level == 0) {
change = CH_TAKEOVER;
check_devs = 1;
- devNumChange = -(geo->raid_disks/2);
+ raid_disks /= 2;
imsm_layout = 0; /* imsm raid0 layout */
}
break;
@@ -12011,10 +12032,10 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
if (geo->layout != info.array.layout &&
(geo->layout != UnSet && geo->layout != -1)) {
change = CH_MIGRATION;
- if (info.array.layout == 0 && info.array.level == 5 &&
+ if (info.array.layout == 0 && info.array.level == IMSM_T_RAID5 &&
geo->layout == 5) {
/* reshape 5 -> 4 */
- } else if (info.array.layout == 5 && info.array.level == 5 &&
+ } else if (info.array.layout == 5 && info.array.level == IMSM_T_RAID5 &&
geo->layout == 0) {
/* reshape 4 -> 5 */
geo->layout = 0;
@@ -12033,7 +12054,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
if (geo->chunksize > 0 && geo->chunksize != UnSet &&
geo->chunksize != info.array.chunk_size) {
- if (info.array.level == 10) {
+ if (info.array.level == IMSM_T_RAID10) {
pr_err("Error. Chunk size change for RAID 10 is not supported.\n");
change = -1;
goto analyse_change_exit;
@@ -12058,14 +12079,16 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
rv = imsm_analyze_expand(st, geo, &info, direction);
if (rv != IMSM_STATUS_OK)
goto analyse_change_exit;
+ raid_disks = geo->raid_disks;
change = CH_ARRAY_SIZE;
}
chunk = geo->chunksize / 1024;
+
if (!validate_geometry_imsm(st,
geo->level,
imsm_layout,
- geo->raid_disks + devNumChange,
+ raid_disks,
&chunk,
geo->size, INVALID_SECTORS,
0, 0, info.consistency_policy, 1))
--
2.41.0

View File

@ -0,0 +1,180 @@
From ec7e873ba6643a9e5e74311b00ede66a3d2e36c9 Mon Sep 17 00:00:00 2001
From: Mateusz Kusiak <mateusz.kusiak@intel.com>
Date: Mon, 29 Apr 2024 15:07:17 +0200
Subject: [PATCH 56/69] imsm: bump minimal version
IMSM version 1.3 (called ATTRIBS) brought attributes used to define array
properties which require support in driver. The goal of this change was
to avoid changing version when adding new features.
For some reasons migration has never been completed and currently (after
10 years of implementing) IMSM can use older versions.
It is right time to finally switch it. There is no point in using old
versions, use 1.3.00 as minimal one.
Define JD_VERSION used by Windows driver.
Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
super-intel.c | 87 ++++++++++++++++++++++-----------------------------
1 file changed, 38 insertions(+), 49 deletions(-)
diff --git a/super-intel.c b/super-intel.c
index da17265d..4b168add 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -32,14 +32,19 @@
/* MPB == Metadata Parameter Block */
#define MPB_SIGNATURE "Intel Raid ISM Cfg Sig. "
#define MPB_SIG_LEN (strlen(MPB_SIGNATURE))
-#define MPB_VERSION_RAID0 "1.0.00"
-#define MPB_VERSION_RAID1 "1.1.00"
-#define MPB_VERSION_MANY_VOLUMES_PER_ARRAY "1.2.00"
-#define MPB_VERSION_3OR4_DISK_ARRAY "1.2.01"
-#define MPB_VERSION_RAID5 "1.2.02"
-#define MPB_VERSION_5OR6_DISK_ARRAY "1.2.04"
-#define MPB_VERSION_CNG "1.2.06"
+
+/* Legacy IMSM versions:
+ * MPB_VERSION_RAID0 1.0.00
+ * MPB_VERSION_RAID1 1.1.00
+ * MPB_VERSION_MANY_VOLUMES_PER_ARRAY 1.2.00
+ * MPB_VERSION_3OR4_DISK_ARRAY 1.2.01
+ * MPB_VERSION_RAID5 1.2.02
+ * MPB_VERSION_5OR6_DISK_ARRAY 1.2.04
+ * MPB_VERSION_CNG 1.2.06
+ */
+
#define MPB_VERSION_ATTRIBS "1.3.00"
+#define MPB_VERSION_ATTRIBS_JD "2.0.00"
#define MAX_SIGNATURE_LENGTH 32
#define MAX_RAID_SERIAL_LEN 16
@@ -5512,51 +5517,46 @@ static unsigned long long info_to_blocks_per_member(mdu_array_info_t *info,
return (size * 2) & ~(info_to_blocks_per_strip(info) - 1);
}
+static void imsm_write_signature(struct imsm_super *mpb)
+{
+ /* It is safer to eventually truncate version rather than left it not NULL ended */
+ snprintf((char *) mpb->sig, MAX_SIGNATURE_LENGTH, MPB_SIGNATURE MPB_VERSION_ATTRIBS);
+}
+
static void imsm_update_version_info(struct intel_super *super)
{
/* update the version and attributes */
struct imsm_super *mpb = super->anchor;
- char *version;
struct imsm_dev *dev;
struct imsm_map *map;
int i;
+ mpb->attributes |= MPB_ATTRIB_CHECKSUM_VERIFY;
+
for (i = 0; i < mpb->num_raid_devs; i++) {
dev = get_imsm_dev(super, i);
map = get_imsm_map(dev, MAP_0);
+
if (__le32_to_cpu(dev->size_high) > 0)
mpb->attributes |= MPB_ATTRIB_2TB;
- /* FIXME detect when an array spans a port multiplier */
- #if 0
- mpb->attributes |= MPB_ATTRIB_PM;
- #endif
-
- if (mpb->num_raid_devs > 1 ||
- mpb->attributes != MPB_ATTRIB_CHECKSUM_VERIFY) {
- version = MPB_VERSION_ATTRIBS;
- switch (get_imsm_raid_level(map)) {
- case 0: mpb->attributes |= MPB_ATTRIB_RAID0; break;
- case 1: mpb->attributes |= MPB_ATTRIB_RAID1; break;
- case 10: mpb->attributes |= MPB_ATTRIB_RAID10; break;
- case 5: mpb->attributes |= MPB_ATTRIB_RAID5; break;
- }
- } else {
- if (map->num_members >= 5)
- version = MPB_VERSION_5OR6_DISK_ARRAY;
- else if (dev->status == DEV_CLONE_N_GO)
- version = MPB_VERSION_CNG;
- else if (get_imsm_raid_level(map) == 5)
- version = MPB_VERSION_RAID5;
- else if (map->num_members >= 3)
- version = MPB_VERSION_3OR4_DISK_ARRAY;
- else if (get_imsm_raid_level(map) == 1)
- version = MPB_VERSION_RAID1;
- else
- version = MPB_VERSION_RAID0;
+ switch (get_imsm_raid_level(map)) {
+ case IMSM_T_RAID0:
+ mpb->attributes |= MPB_ATTRIB_RAID0;
+ break;
+ case IMSM_T_RAID1:
+ mpb->attributes |= MPB_ATTRIB_RAID1;
+ break;
+ case IMSM_T_RAID5:
+ mpb->attributes |= MPB_ATTRIB_RAID5;
+ break;
+ case IMSM_T_RAID10:
+ mpb->attributes |= MPB_ATTRIB_RAID10;
+ break;
}
- strcpy(((char *) mpb->sig) + strlen(MPB_SIGNATURE), version);
}
+
+ imsm_write_signature(mpb);
}
/**
@@ -5785,7 +5785,6 @@ static int init_super_imsm(struct supertype *st, mdu_array_info_t *info,
struct intel_super *super;
struct imsm_super *mpb;
size_t mpb_size;
- char *version;
if (data_offset != INVALID_SECTORS) {
pr_err("data-offset not supported by imsm\n");
@@ -5828,13 +5827,7 @@ static int init_super_imsm(struct supertype *st, mdu_array_info_t *info,
return 0;
}
- mpb->attributes = MPB_ATTRIB_CHECKSUM_VERIFY;
-
- version = (char *) mpb->sig;
- strcpy(version, MPB_SIGNATURE);
- version += strlen(MPB_SIGNATURE);
- strcpy(version, MPB_VERSION_RAID0);
-
+ imsm_update_version_info(super);
return 1;
}
@@ -6208,7 +6201,6 @@ static union {
static int write_super_imsm_spare(struct intel_super *super, struct dl *d)
{
- struct imsm_super *mpb = super->anchor;
struct imsm_super *spare = &spare_record.anchor;
__u32 sum;
@@ -6217,14 +6209,11 @@ static int write_super_imsm_spare(struct intel_super *super, struct dl *d)
spare->mpb_size = __cpu_to_le32(sizeof(struct imsm_super));
spare->generation_num = __cpu_to_le32(1UL);
- spare->attributes = MPB_ATTRIB_CHECKSUM_VERIFY;
spare->num_disks = 1;
spare->num_raid_devs = 0;
- spare->cache_size = mpb->cache_size;
spare->pwr_cycle_count = __cpu_to_le32(1);
- snprintf((char *) spare->sig, MAX_SIGNATURE_LENGTH,
- MPB_SIGNATURE MPB_VERSION_RAID0);
+ imsm_write_signature(spare);
spare->disk[0] = d->disk;
if (__le32_to_cpu(d->disk.total_blocks_hi) > 0)
--
2.41.0

View File

@ -0,0 +1,67 @@
From 610fc2ee6fc09e828b14e8fa221b3f4f70fc7b2b Mon Sep 17 00:00:00 2001
From: Mateusz Kusiak <mateusz.kusiak@intel.com>
Date: Mon, 29 Apr 2024 15:07:18 +0200
Subject: [PATCH 57/69] imsm: define RAID_10 attribute
Add MPB_ATTRIB_RAID10_EXT attribute to support RAID 10
with more than 4 drives.
Allow more than 4 drives in imsm_orom_support_raid_disks_raid10().
This is one of last patches for introducing R10D4+ to imsm.
Only small adjustments in reshape behaviours are needed.
Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
platform-intel.c | 3 ++-
super-intel.c | 5 +++++
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/platform-intel.c b/platform-intel.c
index 40e8fb82..15a9fa5a 100644
--- a/platform-intel.c
+++ b/platform-intel.c
@@ -76,7 +76,8 @@ static bool imsm_orom_support_raid_disks_count_raid5(const int raid_disks)
static bool imsm_orom_support_raid_disks_count_raid10(const int raid_disks)
{
- if (raid_disks == 4)
+ /* raid_disks count must be higher than 4 and even */
+ if (raid_disks >= 4 && (raid_disks & 1) == 0)
return true;
return false;
}
diff --git a/super-intel.c b/super-intel.c
index 4b168add..2d309316 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -62,6 +62,8 @@
#define MPB_ATTRIB_RAIDCNG __cpu_to_le32(0x00000020)
/* supports expanded stripe sizes of 256K, 512K and 1MB */
#define MPB_ATTRIB_EXP_STRIPE_SIZE __cpu_to_le32(0x00000040)
+/* supports RAID10 with more than 4 drives */
+#define MPB_ATTRIB_RAID10_EXT __cpu_to_le32(0x00000080)
/* The OROM Support RST Caching of Volumes */
#define MPB_ATTRIB_NVM __cpu_to_le32(0x02000000)
@@ -89,6 +91,7 @@
MPB_ATTRIB_RAID10 | \
MPB_ATTRIB_RAID5 | \
MPB_ATTRIB_EXP_STRIPE_SIZE | \
+ MPB_ATTRIB_RAID10_EXT | \
MPB_ATTRIB_BBM)
/* Define attributes that are unused but not harmful */
@@ -5552,6 +5555,8 @@ static void imsm_update_version_info(struct intel_super *super)
break;
case IMSM_T_RAID10:
mpb->attributes |= MPB_ATTRIB_RAID10;
+ if (map->num_members > 4)
+ mpb->attributes |= MPB_ATTRIB_RAID10_EXT;
break;
}
}
--
2.41.0

View File

@ -0,0 +1,153 @@
From e0e56f4b2ed514f5049eb96b4ff8f7fdf30a4c49 Mon Sep 17 00:00:00 2001
From: Mateusz Kusiak <mateusz.kusiak@intel.com>
Date: Mon, 29 Apr 2024 15:07:19 +0200
Subject: [PATCH 58/69] imsm: simplify imsm_check_attributes()
imsm_check_attributes() is too complex for that it really does.
Remove repeating code and simplify the function.
Fix function calls.
Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
super-intel.c | 106 ++++++++------------------------------------------
1 file changed, 16 insertions(+), 90 deletions(-)
diff --git a/super-intel.c b/super-intel.c
index 2d309316..d60915e8 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -2135,91 +2135,18 @@ void convert_from_4k(struct intel_super *super)
mpb->check_sum = __gen_imsm_checksum(mpb);
}
-/*******************************************************************************
- * function: imsm_check_attributes
- * Description: Function checks if features represented by attributes flags
- * are supported by mdadm.
- * Parameters:
- * attributes - Attributes read from metadata
- * Returns:
- * 0 - passed attributes contains unsupported features flags
- * 1 - all features are supported
- ******************************************************************************/
-static int imsm_check_attributes(__u32 attributes)
+/**
+ * imsm_check_attributes() - Check if features represented by attributes flags are supported.
+ *
+ * @attributes: attributes read from metadata.
+ * Returns: true if all features are supported, false otherwise.
+ */
+static bool imsm_check_attributes(__u32 attributes)
{
- int ret_val = 1;
- __u32 not_supported = MPB_ATTRIB_SUPPORTED^0xffffffff;
-
- not_supported &= ~MPB_ATTRIB_IGNORED;
-
- not_supported &= attributes;
- if (not_supported) {
- pr_err("(IMSM): Unsupported attributes : %x\n",
- (unsigned)__le32_to_cpu(not_supported));
- if (not_supported & MPB_ATTRIB_CHECKSUM_VERIFY) {
- dprintf("\t\tMPB_ATTRIB_CHECKSUM_VERIFY \n");
- not_supported ^= MPB_ATTRIB_CHECKSUM_VERIFY;
- }
- if (not_supported & MPB_ATTRIB_2TB) {
- dprintf("\t\tMPB_ATTRIB_2TB\n");
- not_supported ^= MPB_ATTRIB_2TB;
- }
- if (not_supported & MPB_ATTRIB_RAID0) {
- dprintf("\t\tMPB_ATTRIB_RAID0\n");
- not_supported ^= MPB_ATTRIB_RAID0;
- }
- if (not_supported & MPB_ATTRIB_RAID1) {
- dprintf("\t\tMPB_ATTRIB_RAID1\n");
- not_supported ^= MPB_ATTRIB_RAID1;
- }
- if (not_supported & MPB_ATTRIB_RAID10) {
- dprintf("\t\tMPB_ATTRIB_RAID10\n");
- not_supported ^= MPB_ATTRIB_RAID10;
- }
- if (not_supported & MPB_ATTRIB_RAID1E) {
- dprintf("\t\tMPB_ATTRIB_RAID1E\n");
- not_supported ^= MPB_ATTRIB_RAID1E;
- }
- if (not_supported & MPB_ATTRIB_RAID5) {
- dprintf("\t\tMPB_ATTRIB_RAID5\n");
- not_supported ^= MPB_ATTRIB_RAID5;
- }
- if (not_supported & MPB_ATTRIB_RAIDCNG) {
- dprintf("\t\tMPB_ATTRIB_RAIDCNG\n");
- not_supported ^= MPB_ATTRIB_RAIDCNG;
- }
- if (not_supported & MPB_ATTRIB_BBM) {
- dprintf("\t\tMPB_ATTRIB_BBM\n");
- not_supported ^= MPB_ATTRIB_BBM;
- }
- if (not_supported & MPB_ATTRIB_CHECKSUM_VERIFY) {
- dprintf("\t\tMPB_ATTRIB_CHECKSUM_VERIFY (== MPB_ATTRIB_LEGACY)\n");
- not_supported ^= MPB_ATTRIB_CHECKSUM_VERIFY;
- }
- if (not_supported & MPB_ATTRIB_EXP_STRIPE_SIZE) {
- dprintf("\t\tMPB_ATTRIB_EXP_STRIP_SIZE\n");
- not_supported ^= MPB_ATTRIB_EXP_STRIPE_SIZE;
- }
- if (not_supported & MPB_ATTRIB_2TB_DISK) {
- dprintf("\t\tMPB_ATTRIB_2TB_DISK\n");
- not_supported ^= MPB_ATTRIB_2TB_DISK;
- }
- if (not_supported & MPB_ATTRIB_NEVER_USE2) {
- dprintf("\t\tMPB_ATTRIB_NEVER_USE2\n");
- not_supported ^= MPB_ATTRIB_NEVER_USE2;
- }
- if (not_supported & MPB_ATTRIB_NEVER_USE) {
- dprintf("\t\tMPB_ATTRIB_NEVER_USE\n");
- not_supported ^= MPB_ATTRIB_NEVER_USE;
- }
-
- if (not_supported)
- dprintf("(IMSM): Unknown attributes : %x\n", not_supported);
-
- ret_val = 0;
- }
+ if ((attributes & (MPB_ATTRIB_SUPPORTED | MPB_ATTRIB_IGNORED)) == attributes)
+ return true;
- return ret_val;
+ return false;
}
static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *map);
@@ -2247,11 +2174,10 @@ static void examine_super_imsm(struct supertype *st, char *homehost)
creation_time = __le64_to_cpu(mpb->creation_time);
printf(" Creation Time : %.24s\n",
creation_time ? ctime(&creation_time) : "Unknown");
- printf(" Attributes : ");
- if (imsm_check_attributes(mpb->attributes))
- printf("All supported\n");
- else
- printf("not supported\n");
+
+ printf(" Attributes : %08x (%s)\n", mpb->attributes,
+ imsm_check_attributes(mpb->attributes) ? "supported" : "not supported");
+
getinfo_super_imsm(st, &info, NULL);
fname_from_uuid(&info, nbuf);
printf(" UUID : %s\n", nbuf + 5);
@@ -8182,9 +8108,9 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
int current_vol = super->current_vol;
/* do not assemble arrays when not all attributes are supported */
- if (imsm_check_attributes(mpb->attributes) == 0) {
+ if (imsm_check_attributes(mpb->attributes) == false) {
sb_errors = 1;
- pr_err("Unsupported attributes in IMSM metadata.Arrays activation is blocked.\n");
+ pr_err("Unsupported attributes in IMSM metadata. Arrays activation is blocked.\n");
}
/* count spare devices, not used in maps
--
2.41.0

View File

@ -0,0 +1,168 @@
From 44463edeb303a464c4a44fcea184b267aeb53302 Mon Sep 17 00:00:00 2001
From: Mateusz Kusiak <mateusz.kusiak@intel.com>
Date: Mon, 29 Apr 2024 15:07:20 +0200
Subject: [PATCH 59/69] imsm: support RAID 10 with more than 4 drives
VROC UEFI driver does not support RAID 10 with more than 4 drives.
Add user prompts if such layout is being created and for R0->R10
reshapes.
Refactor ask() function:
- simplify the code,
- remove dialog reattempts,
- do no pass '?' sign on function calls,
- highlight default option on output.
This patch completes adding support for R10D4+ to IMSM.
Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
Create.c | 9 ++++++++-
super-intel.c | 14 ++++++++++++--
util.c | 39 +++++++++++++++++++++++++--------------
3 files changed, 45 insertions(+), 17 deletions(-)
diff --git a/Create.c b/Create.c
index d94253b1..d033eb68 100644
--- a/Create.c
+++ b/Create.c
@@ -965,6 +965,13 @@ int Create(struct supertype *st, struct mddev_ident *ident, int subdevs,
return 1;
}
+ if (st->ss == &super_imsm && s->level == 10 && s->raiddisks > 4) {
+ /* Print no matter runstop was specifed */
+ pr_err("Warning! VROC UEFI driver does not support RAID10 in requested layout.\n");
+ pr_err("Array won't be suitable as boot device.\n");
+ warn = 1;
+ }
+
if (!have_container && s->level > 0 && ((maxsize-s->size)*100 > maxsize)) {
if (c->runstop != 1 || c->verbose >= 0)
pr_err("largest drive (%s) exceeds size (%lluK) by more than 1%%\n",
@@ -984,7 +991,7 @@ int Create(struct supertype *st, struct mddev_ident *ident, int subdevs,
if (warn) {
if (c->runstop!= 1) {
- if (!ask("Continue creating array? ")) {
+ if (!ask("Continue creating array")) {
pr_err("create aborted.\n");
return 1;
}
diff --git a/super-intel.c b/super-intel.c
index d60915e8..2b8b6fda 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -523,6 +523,7 @@ enum imsm_reshape_type {
CH_TAKEOVER,
CH_MIGRATION,
CH_ARRAY_SIZE,
+ CH_ABORT
};
/* definition of messages passed to imsm_process_update */
@@ -11898,7 +11899,7 @@ success:
****************************************************************************/
enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
struct geo_params *geo,
- int direction)
+ int direction, struct context *c)
{
struct mdinfo info;
int change = -1;
@@ -11925,6 +11926,14 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
check_devs = 1;
raid_disks += 1; /* parity disk added */
} else if (geo->level == IMSM_T_RAID10) {
+ if (geo->level == IMSM_T_RAID10 && geo->raid_disks > 2 &&
+ !c->force) {
+ pr_err("Warning! VROC UEFI driver does not support RAID10 in requested layout.\n");
+ pr_err("Array won't be suitable as boot device.\n");
+ pr_err("Note: You can omit this check with \"--force\"\n");
+ if (ask("Do you want to continue") < 1)
+ return CH_ABORT;
+ }
change = CH_TAKEOVER;
check_devs = 1;
raid_disks *= 2; /* mirrors added */
@@ -12219,7 +12228,7 @@ static int imsm_reshape_super(struct supertype *st, struct shape *shape, struct
goto exit_imsm_reshape_super;
}
super->current_vol = dev->index;
- change = imsm_analyze_change(st, &geo, shape->direction);
+ change = imsm_analyze_change(st, &geo, shape->direction, c);
switch (change) {
case CH_TAKEOVER:
ret_val = imsm_takeover(st, &geo);
@@ -12262,6 +12271,7 @@ static int imsm_reshape_super(struct supertype *st, struct shape *shape, struct
free(u);
}
break;
+ case CH_ABORT:
default:
ret_val = 1;
}
diff --git a/util.c b/util.c
index 9e837045..4fbf11c4 100644
--- a/util.c
+++ b/util.c
@@ -725,23 +725,33 @@ int stat_is_blkdev(char *devname, dev_t *rdev)
return 1;
}
+/**
+ * ask() - prompt user for "yes/no" dialog.
+ * @mesg: message to be printed, without '?' sign.
+ * Returns: 1 if 'Y/y', 0 otherwise.
+ *
+ * The default value is 'N/n', thus the caps on "N" on prompt.
+ */
int ask(char *mesg)
{
- char *add = "";
- int i;
- for (i = 0; i < 5; i++) {
- char buf[100];
- fprintf(stderr, "%s%s", mesg, add);
- fflush(stderr);
- if (fgets(buf, 100, stdin)==NULL)
- return 0;
- if (buf[0]=='y' || buf[0]=='Y')
- return 1;
- if (buf[0]=='n' || buf[0]=='N')
- return 0;
- add = "(y/n) ";
+ char buf[3] = {0};
+
+ fprintf(stderr, "%s [y/N]? ", mesg);
+ fflush(stderr);
+ if (fgets(buf, 3, stdin) == NULL)
+ return 0;
+ if (strlen(buf) == 1) {
+ pr_err("assuming no.\n");
+ return 0;
}
- pr_err("assuming 'no'\n");
+ if (buf[1] != '\n')
+ goto bad_option;
+ if (toupper(buf[0]) == 'Y')
+ return 1;
+ if (toupper(buf[0]) == 'N')
+ return 0;
+bad_option:
+ pr_err("bad option.\n");
return 0;
}
@@ -1868,6 +1878,7 @@ int set_array_info(int mdfd, struct supertype *st, struct mdinfo *info)
if (st->ss->external)
return sysfs_set_array(info);
+
memset(&inf, 0, sizeof(inf));
inf.major_version = info->array.major_version;
inf.minor_version = info->array.minor_version;
--
2.41.0

View File

@ -0,0 +1,41 @@
From d399c494c6364a6b6d0f965c08443fdc79d1e248 Mon Sep 17 00:00:00 2001
From: Xiao Ni <xni@redhat.com>
Date: Thu, 18 Apr 2024 18:23:19 +0800
Subject: [PATCH 60/69] tests/01r5fail enhance
After removing dev0, the recovery starts because it already has a spare
disk. It's good to check recovery. But it's not right to check recovery
after adding dev3. Because the recovery may finish. It depends on the
recovery performance of the testing machine. If the recovery finishes,
it will fail. But dev3 is only added as a spare disk, we can't expect
there is a recovery happens.
So remove the codes about adding dev3.
Signed-off-by: Xiao Ni <xni@redhat.com>
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
tests/01r5fail | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/tests/01r5fail b/tests/01r5fail
index 873dba58..c210d6e7 100644
--- a/tests/01r5fail
+++ b/tests/01r5fail
@@ -17,11 +17,7 @@ check wait
mdadm $md0 --fail $dev0
mdadm $md0 --remove $dev3 $dev0
check recovery
-check state _UUU
-
-mdadm $md0 -a $dev3
-check recovery
check wait
check state UUUU
-mdadm -S $md0
\ No newline at end of file
+mdadm -S $md0
--
2.41.0

View File

@ -0,0 +1,32 @@
From a20cb3872c02241e4f0f7cc26933a43bac7d1cbb Mon Sep 17 00:00:00 2001
From: Xiao Ni <xni@redhat.com>
Date: Thu, 18 Apr 2024 18:23:20 +0800
Subject: [PATCH 61/69] tests/01r5integ.broken
01r5integ can be run successfully 152 times without error with
kernel 6.9.0-rc4 and mdadm - v4.3-51-g52bead95. So remove this
one broken case.
Signed-off-by: Xiao Ni <xni@redhat.com>
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
tests/01r5integ.broken | 7 -------
1 file changed, 7 deletions(-)
delete mode 100644 tests/01r5integ.broken
diff --git a/tests/01r5integ.broken b/tests/01r5integ.broken
deleted file mode 100644
index 20737637..00000000
--- a/tests/01r5integ.broken
+++ /dev/null
@@ -1,7 +0,0 @@
-fails rarely
-
-Fails about 1 in every 30 runs with a sha mismatch error:
-
- c49ab26e1b01def7874af9b8a6d6d0c29fdfafe6 /dev/md0 does not match
- 15dc2f73262f811ada53c65e505ceec9cf025cb9 /dev/md0 with /dev/loop3
- missing
--
2.41.0

View File

@ -0,0 +1,31 @@
From 896948b14ad26f15590269dce50ac4896284dc29 Mon Sep 17 00:00:00 2001
From: Xiao Ni <xni@redhat.com>
Date: Thu, 18 Apr 2024 18:23:21 +0800
Subject: [PATCH 62/69] tests/01raid6integ.broken can be removed
01raid6integ can be run successfully with kernel 6.9.0-rc3.
So remove 01raid6integ.broken.
Signed-off-by: Xiao Ni <xni@redhat.com>
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
tests/01raid6integ.broken | 7 -------
1 file changed, 7 deletions(-)
delete mode 100644 tests/01raid6integ.broken
diff --git a/tests/01raid6integ.broken b/tests/01raid6integ.broken
deleted file mode 100644
index 1df735f0..00000000
--- a/tests/01raid6integ.broken
+++ /dev/null
@@ -1,7 +0,0 @@
-fails infrequently
-
-Fails about 1 in 5 with a sha mismatch:
-
- 8286c2bc045ae2cfe9f8b7ae3a898fa25db6926f /dev/md0 does not match
- a083a0738b58caab37fd568b91b177035ded37df /dev/md0 with /dev/loop2 and
- /dev/loop3 missing
--
2.41.0

View File

@ -0,0 +1,38 @@
From 893a55831e5abbcd15b171db66fa1f389fb61506 Mon Sep 17 00:00:00 2001
From: Fabrice Fontaine <fontaine.fabrice@gmail.com>
Date: Tue, 7 May 2024 19:32:16 +0200
Subject: [PATCH 63/69] Makefile: Move -pie to LDFLAGS
Move -pie from LDLIBS to LDFLAGS and make LDFLAGS configurable to allow
the user to drop it by setting their own LDFLAGS (e.g. PIE could be
enabled or disabled by the buildsystem such as buildroot).
Suggested-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
Makefile | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile
index 7c221a89..adac7905 100644
--- a/Makefile
+++ b/Makefile
@@ -132,12 +132,12 @@ CFLAGS += -DUSE_PTHREADS
MON_LDFLAGS += -pthread
endif
-LDFLAGS = -Wl,-z,now,-z,noexecstack
+LDFLAGS ?= -pie -Wl,-z,now,-z,noexecstack
# If you want a static binary, you might uncomment these
# LDFLAGS += -static
# STRIP = -s
-LDLIBS = -ldl -pie
+LDLIBS = -ldl
# To explicitly disable libudev, set -DNO_LIBUDEV in CXFLAGS
ifeq (, $(findstring -DNO_LIBUDEV, $(CXFLAGS)))
--
2.41.0

View File

@ -0,0 +1,30 @@
From a0174749426f49a04f11ae0e728cb0a681bfa465 Mon Sep 17 00:00:00 2001
From: Yu Kuai <yukuai3@huawei.com>
Date: Thu, 9 May 2024 09:10:59 +0800
Subject: [PATCH 64/69] tests/23rdev-lifetime: fix a typo
"pill" was wrong, while it should be "kill", test will still pass while
test thread will not be cleaned up.
Signed-off-by: Yu Kuai <yukuai3@huawei.com>
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
tests/23rdev-lifetime | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/23rdev-lifetime b/tests/23rdev-lifetime
index 1750b0db..03b61de4 100644
--- a/tests/23rdev-lifetime
+++ b/tests/23rdev-lifetime
@@ -4,7 +4,7 @@ pid=""
runtime=2
clean_up_test() {
- pill -9 $pid
+ kill -9 $pid
echo clear > /sys/block/md0/md/array_state
}
--
2.41.0

View File

@ -0,0 +1,55 @@
From b0f4e8e30f38d83f7e3f53d01d72d4cb3b4d42d7 Mon Sep 17 00:00:00 2001
From: Kinga Stefaniuk <kinga.stefaniuk@intel.com>
Date: Tue, 7 May 2024 05:38:55 +0200
Subject: [PATCH 65/69] util.c: change devnm to const in mdmon functions
Devnm shall not be changed inside mdmon_running()
and mdmon_pid() functions, change this parameter to const.
Signed-off-by: Kinga Stefaniuk <kinga.stefaniuk@intel.com>
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
mdadm.h | 4 ++--
util.c | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/mdadm.h b/mdadm.h
index 2ff3e463..1ba541fc 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -1768,8 +1768,8 @@ extern int is_subarray_active(char *subarray, char *devname);
extern int open_subarray(char *dev, char *subarray, struct supertype *st, int quiet);
extern struct superswitch *version_to_superswitch(char *vers);
-extern int mdmon_running(char *devnm);
-extern int mdmon_pid(char *devnm);
+extern int mdmon_running(const char *devnm);
+extern int mdmon_pid(const char *devnm);
extern int check_env(char *name);
extern __u32 random32(void);
extern void random_uuid(__u8 *buf);
diff --git a/util.c b/util.c
index 4fbf11c4..e2b490e1 100644
--- a/util.c
+++ b/util.c
@@ -1902,7 +1902,7 @@ unsigned long long min_recovery_start(struct mdinfo *array)
return recovery_start;
}
-int mdmon_pid(char *devnm)
+int mdmon_pid(const char *devnm)
{
char path[100];
char pid[10];
@@ -1922,7 +1922,7 @@ int mdmon_pid(char *devnm)
return atoi(pid);
}
-int mdmon_running(char *devnm)
+int mdmon_running(const char *devnm)
{
int pid = mdmon_pid(devnm);
if (pid <= 0)
--
2.41.0

View File

@ -0,0 +1,121 @@
From aa1cc5815d2b14a8b47add18cfaa8264e19c10ce Mon Sep 17 00:00:00 2001
From: Kinga Stefaniuk <kinga.stefaniuk@intel.com>
Date: Tue, 7 May 2024 05:38:56 +0200
Subject: [PATCH 66/69] Wait for mdmon when it is stared via systemd
When mdmon is being started it may need few seconds to start.
For now, we didn't wait for it. Introduce wait_for_mdmon()
function, which waits up to 5 seconds for mdmon to start completely.
Signed-off-by: Kinga Stefaniuk <kinga.stefaniuk@intel.com>
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
Assemble.c | 4 ++--
Grow.c | 7 ++++---
mdadm.h | 2 ++
util.c | 29 +++++++++++++++++++++++++++++
4 files changed, 37 insertions(+), 5 deletions(-)
diff --git a/Assemble.c b/Assemble.c
index f5e9ab1f..83dced19 100644
--- a/Assemble.c
+++ b/Assemble.c
@@ -2173,8 +2173,8 @@ int assemble_container_content(struct supertype *st, int mdfd,
if (!mdmon_running(st->container_devnm))
start_mdmon(st->container_devnm);
ping_monitor(st->container_devnm);
- if (mdmon_running(st->container_devnm) &&
- st->update_tail == NULL)
+ if (wait_for_mdmon(st->container_devnm) == MDADM_STATUS_SUCCESS &&
+ !st->update_tail)
st->update_tail = &st->updates;
}
diff --git a/Grow.c b/Grow.c
index 87ed9214..1923c27c 100644
--- a/Grow.c
+++ b/Grow.c
@@ -2134,7 +2134,7 @@ int Grow_reshape(char *devname, int fd,
if (!mdmon_running(st->container_devnm))
start_mdmon(st->container_devnm);
ping_monitor(container);
- if (mdmon_running(st->container_devnm) == false) {
+ if (wait_for_mdmon(st->container_devnm) != MDADM_STATUS_SUCCESS) {
pr_err("No mdmon found. Grow cannot continue.\n");
goto release;
}
@@ -3218,7 +3218,8 @@ static int reshape_array(char *container, int fd, char *devname,
if (!mdmon_running(container))
start_mdmon(container);
ping_monitor(container);
- if (mdmon_running(container) && st->update_tail == NULL)
+ if (wait_for_mdmon(container) == MDADM_STATUS_SUCCESS &&
+ !st->update_tail)
st->update_tail = &st->updates;
}
}
@@ -5173,7 +5174,7 @@ int Grow_continue_command(char *devname, int fd, struct context *c)
start_mdmon(container);
ping_monitor(container);
- if (mdmon_running(container) == false) {
+ if (wait_for_mdmon(container) != MDADM_STATUS_SUCCESS) {
pr_err("No mdmon found. Grow cannot continue.\n");
ret_val = 1;
goto Grow_continue_command_exit;
diff --git a/mdadm.h b/mdadm.h
index 1ba541fc..b71d7b32 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -1770,6 +1770,8 @@ extern struct superswitch *version_to_superswitch(char *vers);
extern int mdmon_running(const char *devnm);
extern int mdmon_pid(const char *devnm);
+extern mdadm_status_t wait_for_mdmon(const char *devnm);
+
extern int check_env(char *name);
extern __u32 random32(void);
extern void random_uuid(__u8 *buf);
diff --git a/util.c b/util.c
index e2b490e1..bf79742f 100644
--- a/util.c
+++ b/util.c
@@ -1932,6 +1932,35 @@ int mdmon_running(const char *devnm)
return 0;
}
+/*
+ * wait_for_mdmon() - Waits for mdmon within specified time.
+ * @devnm: Device for which mdmon should start.
+ *
+ * Function waits for mdmon to start. It may need few seconds
+ * to start, we set timeout to 5, it should be sufficient.
+ * Do not wait if mdmon has been started.
+ *
+ * Return: MDADM_STATUS_SUCCESS if mdmon is running, error code otherwise.
+ */
+mdadm_status_t wait_for_mdmon(const char *devnm)
+{
+ const time_t mdmon_timeout = 5;
+ time_t start_time = time(0);
+
+ if (mdmon_running(devnm))
+ return MDADM_STATUS_SUCCESS;
+
+ pr_info("Waiting for mdmon to start\n");
+ while (time(0) - start_time < mdmon_timeout) {
+ sleep_for(0, MSEC_TO_NSEC(200), true);
+ if (mdmon_running(devnm))
+ return MDADM_STATUS_SUCCESS;
+ };
+
+ pr_err("Timeout waiting for mdmon\n");
+ return MDADM_STATUS_ERROR;
+}
+
int start_mdmon(char *devnm)
{
int i;
--
2.41.0

View File

@ -0,0 +1,62 @@
From c5879860eac64ddd7bec4ba50c9adbfebcbf1d2e Mon Sep 17 00:00:00 2001
From: Blazej Kucman <blazej.kucman@intel.com>
Date: Wed, 15 May 2024 13:26:28 +0200
Subject: [PATCH 69/69] mdadm: Fix compilation for 32-bit arch
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Casting void pointer to __u64 works for 64-bit arch but fails to compile
on 32-bit arch like i686.
Fail on i686 platform:
drive_encryption.c: In function nvme_security_recv_ioctl:
drive_encryption.c:236:25: error: cast from pointer to integer of
different size [-Werror=pointer-to-int-cast]
236 | nvme_cmd.addr = (__u64)response_buffer;
| ^
drive_encryption.c: In function nvme_identify_ioctl:
drive_encryption.c:271:25: error: cast from pointer to integer of
different size [-Werror=pointer-to-int-cast]
271 | nvme_cmd.addr = (__u64)response_buffer;
| ^
cc1: all warnings being treated as errors
make: *** [Makefile:211: drive_encryption.o] Error 1
This change adds cast void pointer to uintptr_t first to ensure that
proper pointer size is used for casting from pointer type. Then is safe to
cast it to __u64 because it is tracked as u_int, regardless it is 32-bit
or 64-bit arch.
Reported-by: Xiao Ni <xni@redhat.com>
Fixes: cc48406887b3 ("Add reading Opal NVMe encryption information")
Signed-off-by: Blazej Kucman <blazej.kucman@intel.com>
---
drive_encryption.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drive_encryption.c b/drive_encryption.c
index 27da9621..a4ad799f 100644
--- a/drive_encryption.c
+++ b/drive_encryption.c
@@ -233,7 +233,7 @@ nvme_security_recv_ioctl(int disk_fd, __u8 sec_protocol, __u16 comm_id, void *re
nvme_cmd.cdw10 = sec_protocol << 24 | comm_id << 8;
nvme_cmd.cdw11 = buf_size;
nvme_cmd.data_len = buf_size;
- nvme_cmd.addr = (__u64)response_buffer;
+ nvme_cmd.addr = (__u64)(uintptr_t)response_buffer;
status = ioctl(disk_fd, NVME_IOCTL_ADMIN_CMD, &nvme_cmd);
if (status != 0) {
@@ -268,7 +268,7 @@ nvme_identify_ioctl(int disk_fd, void *response_buffer, size_t buf_size, const i
nvme_cmd.opcode = NVME_IDENTIFY;
nvme_cmd.cdw10 = NVME_IDENTIFY_CONTROLLER_DATA;
nvme_cmd.data_len = buf_size;
- nvme_cmd.addr = (__u64)response_buffer;
+ nvme_cmd.addr = (__u64)(uintptr_t)response_buffer;
status = ioctl(disk_fd, NVME_IOCTL_ADMIN_CMD, &nvme_cmd);
if (status != 0) {
--
2.41.0

View File

@ -1,7 +1,7 @@
Name: mdadm
Version: 4.3
# extraversion is used to define rhel internal version
%define extraversion 1
%define extraversion 2
Release: %{extraversion}%{?dist}
Summary: The mdadm program controls Linux md devices (software RAID arrays)
URL: http://www.kernel.org/pub/linux/utils/raid/mdadm/
@ -60,6 +60,32 @@ Patch037: 0038-mdadm-Fix-native-detail-export.patch
Patch038: 0039-sysfs-remove-vers-parameter-from-sysfs_set_array.patch
Patch039: 0040-mdadm-fix-grow-segfault-for-IMSM.patch
Patch040: 0041-Remove-all-if-zeros-pt.2.patch
Patch041: 0042-mdadm-Move-pr_vrb-define-to-mdadm.h.patch
Patch042: 0043-Add-reading-Opal-NVMe-encryption-information.patch
Patch043: 0044-Add-reading-SATA-encryption-information.patch
Patch044: 0045-Add-key-ENCRYPTION_NO_VERIFY-to-conf.patch
Patch045: 0046-imsm-print-disk-encryption-information.patch
Patch046: 0047-imsm-drive-encryption-policy-implementation.patch
Patch047: 0048-mdadm-add-CHANGELOG.md.patch
Patch048: 0049-mdadm-Add-MAINTAINERS.md.patch
Patch049: 0050-mdadm-Add-README.md.patch
Patch050: 0051-Create.c-fix-uclibc-build.patch
Patch051: 0052-mdadm-pass-struct-context-for-external-reshapes.patch
Patch052: 0053-mdadm-use-struct-context-in-reshape_super.patch
Patch053: 0054-imsm-add-support-for-literal-RAID-10.patch
Patch054: 0055-imsm-refactor-RAID-level-handling.patch
Patch055: 0056-imsm-bump-minimal-version.patch
Patch056: 0057-imsm-define-RAID_10-attribute.patch
Patch057: 0058-imsm-simplify-imsm_check_attributes.patch
Patch058: 0059-imsm-support-RAID-10-with-more-than-4-drives.patch
Patch059: 0060-tests-01r5fail-enhance.patch
Patch060: 0061-tests-01r5integ.broken.patch
Patch061: 0062-tests-01raid6integ.broken-can-be-removed.patch
Patch062: 0063-Makefile-Move-pie-to-LDFLAGS.patch
Patch063: 0064-tests-23rdev-lifetime-fix-a-typo.patch
Patch064: 0065-util.c-change-devnm-to-const-in-mdmon-functions.patch
Patch065: 0066-Wait-for-mdmon-when-it-is-stared-via-systemd.patch
Patch066: 0069-mdadm-Fix-compilation-for-32-bit-arch.patch
# Fedora customization patches
@ -138,6 +164,10 @@ install -m644 %{SOURCE5} %{buildroot}/etc/libreport/events.d
/usr/share/mdadm/mdcheck
%changelog
* Thu May 16 2024 Xiao Ni <xni@redhat.com> 4.3-2
- Update to latest upstream
- Resolves RHEL-36424
* Fri Mar 29 2024 Xiao Ni <xni@redhat.com> 4.3-1
- Update to 4.3 and to latest upstream
- Resolves RHEL-30529