Additional patches for 10.0.0 lvm2

Resolves: RHEL-75625 RHEL-75626 RHEL-75628 RHEL-75629
This commit is contained in:
Marian Csontos 2025-01-21 15:31:46 +01:00
parent a03c1494be
commit a534c95540
12 changed files with 1680 additions and 0 deletions

View File

@ -0,0 +1,805 @@
From ed334e35e9e951f5524b39a8483ac7f802bfea0b Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
Date: Fri, 6 Dec 2024 15:02:20 -0600
Subject: [PATCH 11/21] device_id: nvme devices may use alternate wwids
Device quirks may cause sysfs wwid file to change what it
displays, from a bogus eui... string to an nvme... string.
The old wwid may be saved in system.devices, so recognizing
the device requires finding the old value from libnvme.
After matching the old bogus value using libnvme, system.devices
is updated with the current sysfs wwid value.
(cherry picked from commit d952358636887348c390784a8ca5efb87b26784f)
---
lib/Makefile.in | 1 +
lib/device/dev-mpath.c | 6 +-
lib/device/dev-type.c | 6 +-
lib/device/dev-type.h | 2 +-
lib/device/device.h | 16 ++-
lib/device/device_id.c | 174 +++++++++++++++++++++++---
lib/device/device_id.h | 11 +-
lib/device/nvme.c | 273 +++++++++++++++++++++++++++++++++++++++++
lib/device/parse_vpd.c | 8 +-
9 files changed, 464 insertions(+), 33 deletions(-)
create mode 100644 lib/device/nvme.c
diff --git a/lib/Makefile.in b/lib/Makefile.in
index 50c7a1fd2..8eab625aa 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -43,6 +43,7 @@ SOURCES =\
device/filesystem.c \
device/online.c \
device/parse_vpd.c \
+ device/nvme.c \
device/dev_util.c \
display/display.c \
error/errseg.c \
diff --git a/lib/device/dev-mpath.c b/lib/device/dev-mpath.c
index 72501e345..7450244b0 100644
--- a/lib/device/dev-mpath.c
+++ b/lib/device/dev-mpath.c
@@ -595,7 +595,7 @@ static int _dev_in_wwid_file(struct cmd_context *cmd, struct device *dev,
*/
lookup:
dm_list_iterate_items(dw, &dev->wwids) {
- if (dw->type == 1 || dw->type == 2 || dw->type == 3)
+ if (dw->scsi_type == 1 || dw->scsi_type == 2 || dw->scsi_type == 3)
wwid = &dw->id[4];
else
wwid = dw->id;
@@ -615,7 +615,7 @@ lookup:
goto lookup;
if (!(dev->flags & DEV_ADDED_SYS_WWID) && dev_read_sys_wwid(cmd, dev, idbuf, sizeof(idbuf), &dw)) {
- if (dw->type == 1 || dw->type == 2 || dw->type == 3)
+ if (dw->scsi_type == 1 || dw->scsi_type == 2 || dw->scsi_type == 3)
wwid = &dw->id[4];
else
wwid = dw->id;
@@ -642,7 +642,7 @@ int dev_is_mpath_component(struct cmd_context *cmd, struct device *dev, dev_t *h
/*
* multipath only uses SCSI or NVME devices
*/
- if (!major_is_scsi_device(dt, MAJOR(dev->dev)) && !dev_is_nvme(dt, dev))
+ if (!major_is_scsi_device(dt, MAJOR(dev->dev)) && !dev_is_nvme(dev))
return 0;
/*
diff --git a/lib/device/dev-type.c b/lib/device/dev-type.c
index c29fb21a8..7c6c10e01 100644
--- a/lib/device/dev-type.c
+++ b/lib/device/dev-type.c
@@ -46,7 +46,7 @@
* is excessive and unnecessary compared to just comparing /dev/name*.
*/
-int dev_is_nvme(struct dev_types *dt, struct device *dev)
+int dev_is_nvme(struct device *dev)
{
return (dev->flags & DEV_IS_NVME) ? 1 : 0;
}
@@ -562,7 +562,7 @@ static int _is_partitionable(struct dev_types *dt, struct device *dev)
_loop_is_with_partscan(dev))
return 1;
- if (dev_is_nvme(dt, dev)) {
+ if (dev_is_nvme(dev)) {
/* If this dev is already a partition then it's not partitionable. */
if (_has_sys_partition(dev))
return 0;
@@ -790,7 +790,7 @@ int dev_get_primary_dev(struct dev_types *dt, struct device *dev, dev_t *result)
* block dev types that have their own major number, so
* the calculation based on minor number doesn't work.
*/
- if (dev_is_nvme(dt, dev))
+ if (dev_is_nvme(dev))
goto sys_partition;
/*
diff --git a/lib/device/dev-type.h b/lib/device/dev-type.h
index 60e5789f7..4708dd3e2 100644
--- a/lib/device/dev-type.h
+++ b/lib/device/dev-type.h
@@ -98,7 +98,7 @@ int dev_is_rotational(struct dev_types *dt, struct device *dev);
int dev_is_pmem(struct dev_types *dt, struct device *dev);
-int dev_is_nvme(struct dev_types *dt, struct device *dev);
+int dev_is_nvme(struct device *dev);
int dev_is_lv(struct cmd_context *cmd, struct device *dev);
diff --git a/lib/device/device.h b/lib/device/device.h
index af5e8a934..d5979e90b 100644
--- a/lib/device/device.h
+++ b/lib/device/device.h
@@ -41,6 +41,8 @@
#define DEV_MATCHED_USE_ID 0x00080000 /* matched an entry from cmd->use_devices */
#define DEV_SCAN_FOUND_NOLABEL 0x00100000 /* label_scan read, passed filters, but no lvm label */
#define DEV_SCAN_NOT_READ 0x00200000 /* label_scan not able to read dev */
+#define DEV_ADDED_NVME_WWIDS 0x00400000 /* wwids have been ready from libnvme */
+#define DEV_UPDATE_USE_ID 0x00800000 /* update system.devices entry to use preferred wwid */
/*
* Support for external device info.
@@ -70,8 +72,12 @@ struct dev_ext {
#define DEV_ID_TYPE_WWID_NAA 9
#define DEV_ID_TYPE_WWID_EUI 10
#define DEV_ID_TYPE_WWID_T10 11
+/* reserve 12 for "scsi name string" if we decide to add that */
+#define DEV_ID_TYPE_NVME_EUI64 13
+#define DEV_ID_TYPE_NVME_NGUID 14
+#define DEV_ID_TYPE_NVME_UUID 15
-/* Max length of WWID_NAA, WWID_EUI, WWID_T10 */
+/* Max length of SCSI or NVME WWID */
#define DEV_WWID_SIZE 128
/*
@@ -79,12 +85,14 @@ struct dev_ext {
* /sys/dev/block/%d:%d/device/wwid
* /sys/dev/block/%d:%d/wwid
* /sys/dev/block/%d:%d/device/vpd_pg83
+ * or libnvme
*/
struct dev_wwid {
- struct dm_list list; /* dev->wwids */
- int type; /* 1,2,3 for NAA,EUI,T10 */
- char id[DEV_WWID_SIZE]; /* includes prefix naa.,eui.,t10. */
+ struct dm_list list; /* dev->wwids */
+ uint16_t scsi_type; /* 1,2,3 for SCSI NAA,EUI,T10 */
+ uint16_t nvme_type; /* 1,2,3 for NVME EUI64,NGUID,UUID */
+ char id[DEV_WWID_SIZE]; /* includes prefix e.g. naa.,eui.,t10. */
};
/*
diff --git a/lib/device/device_id.c b/lib/device/device_id.c
index 06788db32..34524f718 100644
--- a/lib/device/device_id.c
+++ b/lib/device/device_id.c
@@ -568,7 +568,7 @@ static int _dev_has_lvmlv_uuid(struct cmd_context *cmd, struct device *dev, char
* The numbers 1,2,3 for NAA,EUI,T10 are part of the standard
* and are used in the vpd data.
*/
-static int _wwid_type_num(char *id)
+static int _scsi_wwid_type_num(char *id)
{
if (!strncmp(id, "naa.", 4))
return 3;
@@ -580,9 +580,9 @@ static int _wwid_type_num(char *id)
return 0; /* any unrecognized, non-standard prefix */
}
-int wwid_type_to_idtype(int wwid_type)
+int scsi_type_to_idtype(int scsi_type)
{
- switch (wwid_type) {
+ switch (scsi_type) {
case 3: return DEV_ID_TYPE_WWID_NAA;
case 2: return DEV_ID_TYPE_WWID_EUI;
case 1: return DEV_ID_TYPE_WWID_T10;
@@ -591,7 +591,7 @@ int wwid_type_to_idtype(int wwid_type)
}
}
-int idtype_to_wwid_type(int idtype)
+int idtype_to_scsi_type(int idtype)
{
switch (idtype) {
case DEV_ID_TYPE_WWID_NAA: return 3;
@@ -602,6 +602,45 @@ int idtype_to_wwid_type(int idtype)
}
}
+/*
+ * libnvme only returns the standard identifiers UUID/NGUID/EUI64
+ * sysfs wwid file will return "nvme." identifier when one of the
+ * others is not available.
+ */
+static int _nvme_wwid_type_num(char *id)
+{
+ if (!strncmp(id, "uuid.", 5))
+ return 3; /* UUID is 16 bytes */
+ else if (!strncmp(id, "eui.", 4)) {
+ if (strlen(id) > 15)
+ return 2; /* NGUID is 16 bytes */
+ return 1; /* EUI64 is 8 bytes */
+ }
+ return 0; /* any other prefix, including "nvme.", which must come from sysfs wwid file */
+}
+
+int nvme_type_to_idtype(int nvme_type)
+{
+ switch (nvme_type) {
+ case 3: return DEV_ID_TYPE_NVME_UUID;
+ case 2: return DEV_ID_TYPE_NVME_NGUID;
+ case 1: return DEV_ID_TYPE_NVME_EUI64;
+ case 0: return DEV_ID_TYPE_SYS_WWID;
+ default: return -1;
+ }
+}
+
+int idtype_to_nvme_type(int idtype)
+{
+ switch (idtype) {
+ case DEV_ID_TYPE_NVME_UUID: return 3;
+ case DEV_ID_TYPE_NVME_NGUID: return 2;
+ case DEV_ID_TYPE_NVME_EUI64: return 1;
+ case DEV_ID_TYPE_SYS_WWID: return 0;
+ default: return -1;
+ }
+}
+
void free_wwids(struct dm_list *ids)
{
struct dev_wwid *dw, *safe;
@@ -620,22 +659,41 @@ void free_wwids(struct dm_list *ids)
* in /etc/multipath/wwids.
*/
-struct dev_wwid *dev_add_wwid(char *id, int id_type, struct dm_list *ids)
+struct dev_wwid *dev_add_wwid(char *id, int dw_type, int is_nvme, struct dm_list *ids)
{
struct dev_wwid *dw;
+ uint16_t scsi_type = 0;
+ uint16_t nvme_type = 0;
+
+ if (is_nvme)
+ nvme_type = dw_type ?: _nvme_wwid_type_num(id);
+ else
+ scsi_type = dw_type ?: _scsi_wwid_type_num(id);
- if (!id_type)
- id_type = _wwid_type_num(id);
+ /* nvme_type/scsi_type will be 0 for any sysfs wwid string that
+ doesn't begin with a prefix recognized by lvm, e.g. that
+ comes from sysfs wwid. */
if (!(dw = zalloc(sizeof(*dw))))
return_NULL;
/* Copy id string with upto DEV_WWID_SIZE characters */
dm_strncpy(dw->id, id, sizeof(dw->id));
- dw->type = id_type;
+ dw->scsi_type = scsi_type;
+ dw->nvme_type = nvme_type;
dm_list_add(ids, &dw->list);
return dw;
}
+struct dev_wwid *dev_add_scsi_wwid(char *id, int dw_type, struct dm_list *ids)
+{
+ return dev_add_wwid(id, dw_type, 0, ids);
+}
+
+struct dev_wwid *dev_add_nvme_wwid(char *id, int dw_type, struct dm_list *ids)
+{
+ return dev_add_wwid(id, dw_type, 1, ids);
+}
+
#define VPD_SIZE 4096
int dev_read_vpd_wwids(struct cmd_context *cmd, struct device *dev)
@@ -693,9 +751,13 @@ int dev_read_sys_wwid(struct cmd_context *cmd, struct device *dev,
else
format_general_id((const char *)buf, sizeof(buf), (unsigned char *)outbuf, outbufsize);
+ /* We don't currently add the sysfs wwid to dev->wwids for nvme, it's not needed. */
+ if (dev_is_nvme(dev))
+ return 1;
+
/* Note, if wwids are also read from vpd, this same wwid will be added again. */
- if (!(dw = dev_add_wwid(buf, 0, &dev->wwids)))
+ if (!(dw = dev_add_wwid(buf, 0, dev_is_nvme(dev), &dev->wwids)))
return_0;
if (dw_out)
*dw_out = dw;
@@ -809,7 +871,17 @@ char *device_id_system_read(struct cmd_context *cmd, struct device *dev, uint16_
if (!(dev->flags & DEV_ADDED_VPD_WWIDS))
dev_read_vpd_wwids(cmd, dev);
dm_list_iterate_items(dw, &dev->wwids) {
- if (idtype_to_wwid_type(idtype) == dw->type)
+ if (idtype_to_scsi_type(idtype) == dw->scsi_type)
+ return strdup(dw->id);
+ }
+ return NULL;
+ case DEV_ID_TYPE_NVME_EUI64:
+ case DEV_ID_TYPE_NVME_NGUID:
+ case DEV_ID_TYPE_NVME_UUID:
+ if (!(dev->flags & DEV_ADDED_NVME_WWIDS))
+ dev_read_nvme_wwids(dev);
+ dm_list_iterate_items(dw, &dev->wwids) {
+ if (idtype_to_nvme_type(idtype) == dw->nvme_type)
return strdup(dw->id);
}
return NULL;
@@ -823,6 +895,9 @@ char *device_id_system_read(struct cmd_context *cmd, struct device *dev, uint16_
*/
if ((idtype != DEV_ID_TYPE_SYS_WWID) &&
(idtype != DEV_ID_TYPE_SYS_SERIAL) &&
+ (idtype != DEV_ID_TYPE_NVME_EUI64) &&
+ (idtype != DEV_ID_TYPE_NVME_NGUID) &&
+ (idtype != DEV_ID_TYPE_NVME_UUID) &&
(idtype != DEV_ID_TYPE_WWID_NAA) &&
(idtype != DEV_ID_TYPE_WWID_EUI) &&
(idtype != DEV_ID_TYPE_WWID_T10)) {
@@ -1043,6 +1118,9 @@ static const char _dev_id_types[][16] = {
[DEV_ID_TYPE_WWID_NAA] = "wwid_naa",
[DEV_ID_TYPE_WWID_EUI] = "wwid_eui",
[DEV_ID_TYPE_WWID_T10] = "wwid_t10",
+ [DEV_ID_TYPE_NVME_EUI64] = "nvme_eui64",
+ [DEV_ID_TYPE_NVME_NGUID] = "nvme_nguid",
+ [DEV_ID_TYPE_NVME_UUID] = "nvme_uuid",
};
static int _is_idtype(uint16_t idtype) {
@@ -1107,6 +1185,17 @@ static const char *_dev_idname(struct device *dev, uint16_t idtype)
return NULL;
}
+static struct dev_id *get_dev_id(struct device *dev, uint16_t idtype)
+{
+ struct dev_id *id;
+
+ dm_list_iterate_items(id, &dev->ids) {
+ if (id->idtype == idtype)
+ return id;
+ }
+ return NULL;
+}
+
static int _dev_has_id(struct device *dev, uint16_t idtype, const char *idname)
{
struct dev_id *id;
@@ -2564,33 +2653,63 @@ static int _match_du_to_dev(struct cmd_context *cmd, struct dev_use *du, struct
*/
/*
+ * SCSI:
* Make the du match this device if the dev has a vpd_pg83 wwid
* that matches du->idname, even if the sysfs wwid for dev did
* not match the du->idname. This could happen if sysfs changes
* which wwid it reports (there are often multiple), or if lvm in
* the future selects a sys_wwid value from vpd_pg83 data rather
* than from the sysfs wwid.
- *
* TODO: update the df entry IDTYPE somewhere?
+ *
+ * NVME:
+ * For some nvme drives (faulty hw, flagged with quirk), the sysfs wwid
+ * file changed to reporting a new/correct wwid. The du->idname may
+ * still have the wwid from the old sysfs wwid, so we need to look
+ * at the old wwids that can be found from libnvme.
+ *
+ * device_ids_validate updates system.devices to use the latest value
+ * from sysfs wwid.
+ *
+ * In future, we could limit dev_read_nvme_wwids() to only devices
+ * that have the quirk flag (indicating a bad wwid had been used.)
+ * dev_has_nvme_quirk() checks a flag in a newly exposed sysfs file.
+ * If that sysfs file doesn't exist because of an older kernel, then
+ * the function returns -1. When the quirk file exists and says 0,
+ * then the device hasn't changed its reported sys_wwid value, and
+ * we don't need to check libnvme for other wwids that the dev
+ * might have displayed in the past.
*/
if (du->idtype == DEV_ID_TYPE_SYS_WWID) {
struct dev_wwid *dw;
- if (!(dev->flags & DEV_ADDED_VPD_WWIDS))
+ if (!(dev->flags & DEV_ADDED_VPD_WWIDS) && !dev_is_nvme(dev))
dev_read_vpd_wwids(cmd, dev);
+ if (!(dev->flags & DEV_ADDED_NVME_WWIDS) && dev_is_nvme(dev))
+ dev_read_nvme_wwids(dev);
+
dm_list_iterate_items(dw, &dev->wwids) {
if (!strcmp(dw->id, du_idname)) {
if (!(id = zalloc(sizeof(struct dev_id))))
return_0;
- /* wwid types are 1,2,3 and idtypes are DEV_ID_TYPE_ */
- id->idtype = wwid_type_to_idtype(dw->type);
+ /* scsi/nvme types are 1,2,3 and idtypes are DEV_ID_TYPE_ */
+ if (dev_is_nvme(dev))
+ id->idtype = nvme_type_to_idtype(dw->nvme_type);
+ else
+ id->idtype = scsi_type_to_idtype(dw->scsi_type);
id->idname = strdup(dw->id);
dm_list_add(&dev->ids, &id->list);
du->dev = dev;
dev->id = id;
dev->flags |= DEV_MATCHED_USE_ID;
- log_debug("Match %s %s to %s: using vpd_pg83 %s %s",
+
+ /* update system.devices with sysfs wwid value since IDTYPE=sys_wwid */
+ /* FIXME: also do this for scsi */
+ if (dev_is_nvme(dev))
+ dev->flags |= DEV_UPDATE_USE_ID;
+
+ log_debug("Match %s %s to %s: using extra %s %s",
idtype_to_str(du->idtype), du_idname, dev_name(dev),
idtype_to_str(id->idtype), id->idname ?: ".");
du->idtype = id->idtype;
@@ -2939,6 +3058,31 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
du->dev ? dev_name(du->dev) : "not set");
}
+ /*
+ * Replace old wwid with new value displayed by sysfs wwid.
+ */
+ dm_list_iterate_items(du, &cmd->use_devices) {
+ if (!du->dev)
+ continue;
+ if (!(du->dev->flags & DEV_UPDATE_USE_ID))
+ continue;
+ if ((id = get_dev_id(du->dev, DEV_ID_TYPE_SYS_WWID)) && id->idname) {
+ log_debug("Validate %s %s PVID %s on %s: replace old wwid with %s",
+ idtype_to_str(du->idtype), du->idname ?: ".", du->pvid ?: ".",
+ dev_name(du->dev), id->idname);
+ if (!(tmpdup = strdup(id->idname)))
+ continue;
+ free(du->idname);
+ du->idtype = DEV_ID_TYPE_SYS_WWID;
+ du->idname = tmpdup;
+ du->dev->id = id;
+ update_file = 1;
+ } else {
+ log_warn("Device %s PVID %s is using only old wwid %s.",
+ dev_name(du->dev), du->pvid ?: ".", du->idname ?: ".");
+ }
+ }
+
/*
* Validate entries with proper device id types.
* idname is the authority for pairing du and dev.
diff --git a/lib/device/device_id.h b/lib/device/device_id.h
index a67774f1b..b10df9bf4 100644
--- a/lib/device/device_id.h
+++ b/lib/device/device_id.h
@@ -69,11 +69,16 @@ int read_sys_block_binary(struct cmd_context *cmd, struct device *dev,
int dev_has_mpath_uuid(struct cmd_context *cmd, struct device *dev, char **idname_out);
-int wwid_type_to_idtype(int wwid_type);
-int idtype_to_wwid_type(int idtype);
+int scsi_type_to_idtype(int wwid_type);
+int nvme_type_to_idtype(int wwid_type);
+int idtype_to_scsi_type(int idtype);
+int idtype_to_nvme_type(int idtype);
void free_wwids(struct dm_list *ids);
-struct dev_wwid *dev_add_wwid(char *id, int id_type, struct dm_list *ids);
+struct dev_wwid *dev_add_wwid(char *id, int dw_type, int is_nvme, struct dm_list *ids);
+struct dev_wwid *dev_add_scsi_wwid(char *id, int dw_type, struct dm_list *ids);
+struct dev_wwid *dev_add_nvme_wwid(char *id, int dw_type, struct dm_list *ids);
int dev_read_vpd_wwids(struct cmd_context *cmd, struct device *dev);
+void dev_read_nvme_wwids(struct device *dev);
int dev_read_sys_wwid(struct cmd_context *cmd, struct device *dev,
char *buf, int bufsize, struct dev_wwid **dw_out);
diff --git a/lib/device/nvme.c b/lib/device/nvme.c
new file mode 100644
index 000000000..aa4a7a947
--- /dev/null
+++ b/lib/device/nvme.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2024 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "base/memory/zalloc.h"
+#include "lib/misc/lib.h"
+#include "lib/commands/toolcontext.h"
+#include "lib/device/device.h"
+#include "lib/device/device_id.h"
+#include "lib/mm/xlate.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <limits.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#ifdef NVME_SUPPORT
+#include <libnvme.h>
+
+static int iszero(unsigned char *d, size_t n)
+{
+ size_t i;
+
+ for (i = 0; i < n; ++i) {
+ if (d[i])
+ return 0;
+ }
+ return 1;
+}
+
+static void _save_uuid(struct device *dev, unsigned char *uuid)
+{
+ char idname[DEV_WWID_SIZE] = {0};
+ int max, pos, num, i;
+
+ max = sizeof(idname);
+ pos = 0;
+
+ num = snprintf(idname + pos, max - pos, "uuid.");
+ if (num >= max - pos)
+ goto bad;
+ pos += num;
+
+ for (i = 0; i < NVME_UUID_LEN; ++i) {
+ num = snprintf(idname + pos, max - pos, "%02x", uuid[i]);
+ if (num >= max - pos)
+ goto bad;
+ pos += num;
+
+ if (i == 3 || i == 5 || i == 7 || i == 9) {
+ num = snprintf(idname + pos, max - pos, "-");
+ if (num >= max - pos)
+ goto bad;
+ pos += num;
+ }
+ }
+
+ idname[DEV_WWID_SIZE-1] = '\0';
+
+ dev_add_nvme_wwid(idname, 3, &dev->wwids);
+
+ return;
+bad:
+ log_debug("dev_read_nvme_wwids ignore invalid uuid %s for %s", uuid, dev_name(dev));
+}
+
+static void _save_nguid(struct device *dev, unsigned char *nguid)
+{
+ char idname[DEV_WWID_SIZE] = {0};
+ int max, pos, num, i;
+
+ max = sizeof(idname);
+ pos = 0;
+
+ num = snprintf(idname + pos, max - pos, "eui.");
+ if (num >= max - pos)
+ goto bad;
+ pos += num;
+
+ for (i = 0; i < 16; ++i) {
+ num = snprintf(idname + pos, max - pos, "%02x", nguid[i]);
+ if (num >= max - pos)
+ goto bad;
+ pos += num;
+ }
+
+ idname[DEV_WWID_SIZE-1] = '\0';
+
+ dev_add_nvme_wwid(idname, 2, &dev->wwids);
+
+ return;
+bad:
+ log_debug("dev_read_nvme_wwids ignore invalid nguid %s for %s", nguid, dev_name(dev));
+}
+
+static void _save_eui64(struct device *dev, unsigned char *eui64)
+{
+ char idname[DEV_WWID_SIZE] = {0};
+ int max, pos, num, i;
+
+ max = sizeof(idname);
+ pos = 0;
+
+ num = snprintf(idname + pos, max - pos, "eui.");
+ if (num >= max - pos)
+ goto bad;
+ pos += num;
+
+ for (i = 0; i < 8; ++i) {
+ num = snprintf(idname + pos, max - pos, "%02x", eui64[i]);
+ if (num >= max - pos)
+ goto bad;
+ pos += num;
+ }
+
+ idname[DEV_WWID_SIZE-1] = '\0';
+
+ dev_add_nvme_wwid(idname, 1, &dev->wwids);
+
+ return;
+bad:
+ log_debug("dev_read_nvme_wwids ignore invalid eui64 %s for %s", eui64, dev_name(dev));
+}
+
+#define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
+static void *_nvme_alloc(size_t len)
+{
+ size_t _len = ROUND_UP(len, 0x1000);
+ void *p;
+
+ if (posix_memalign((void *)&p, getpagesize(), _len))
+ return NULL;
+
+ memset(p, 0, _len);
+ return p;
+}
+
+void dev_read_nvme_wwids(struct device *dev)
+{
+ const char *devpath;
+ unsigned char *data = NULL;
+ struct nvme_id_ns *ns = NULL;
+ struct nvme_id_ctrl *ctrl_id = NULL;
+ unsigned char nguid[16] = {0};
+ unsigned char eui64[8] = {0};
+ unsigned char uuid[NVME_UUID_LEN] = {0};
+ uint32_t nsid;
+ int fd, i, len;
+
+ dev->flags |= DEV_ADDED_NVME_WWIDS;
+
+ /* shouldn't happen */
+ if (dm_list_empty(&dev->aliases))
+ return;
+
+ devpath = dev_name(dev);
+
+ if ((fd = open(devpath, O_RDONLY)) < 0) {
+ log_debug("dev_read_nvme_wwids cannot open %s", devpath);
+ return;
+ }
+
+ if (nvme_get_nsid(fd, &nsid)) {
+ log_print("dev_read_nvme_wwids nvme_get_nsid error %d %s", errno, devpath);
+ goto out;
+ }
+
+ if (!(ns = _nvme_alloc(sizeof(*ns))))
+ goto_out;
+
+ if (nvme_identify_ns(fd, nsid, ns)) {
+ log_debug("dev_read_nvme_wwids nvme_identify_ns error %d %s", errno, devpath);
+ goto out;
+ }
+
+ memcpy(nguid, ns->nguid, 16);
+ memcpy(eui64, ns->eui64, 8);
+
+ if (!iszero(nguid, 16))
+ _save_nguid(dev, nguid);
+ if (!iszero(eui64, 8))
+ _save_eui64(dev, eui64);
+
+ if (!(ctrl_id = _nvme_alloc(sizeof(struct nvme_id_ctrl))))
+ goto_out;
+
+ /* Avoid using nvme_identify_ns_descs before ver 1.3. */
+ if (!nvme_identify_ctrl(fd, ctrl_id)) {
+ if (le32_to_cpu(ctrl_id->ver) < 0x10300)
+ goto_out;
+ }
+
+ if (!(data = _nvme_alloc(NVME_IDENTIFY_DATA_SIZE)))
+ goto_out;
+
+ if (nvme_identify_ns_descs(fd, nsid, (struct nvme_ns_id_desc *)data)) {
+ log_debug("dev_read_nvme_wwids nvme_identify_ns_descs error %d %s", errno, devpath);
+ goto out;
+ }
+
+ for (i = 0; i < NVME_IDENTIFY_DATA_SIZE; i += len) {
+ struct nvme_ns_id_desc *cur = (struct nvme_ns_id_desc *)(data + i);
+
+ if (cur->nidl == 0)
+ break;
+
+ memset(eui64, 0, sizeof(eui64));
+ memset(nguid, 0, sizeof(nguid));
+ memset(uuid, 0, sizeof(uuid));
+
+ switch (cur->nidt) {
+ case NVME_NIDT_EUI64:
+ memcpy(eui64, data + i + sizeof(*cur), sizeof(eui64));
+ len = sizeof(eui64);
+ break;
+ case NVME_NIDT_NGUID:
+ memcpy(nguid, data + i + sizeof(*cur), sizeof(nguid));
+ len = sizeof(nguid);
+ break;
+ case NVME_NIDT_UUID:
+ memcpy(uuid, data + i + sizeof(*cur), NVME_UUID_LEN);
+ len = sizeof(uuid);
+ break;
+ case NVME_NIDT_CSI:
+ len = 1;
+ break;
+ default:
+ len = cur->nidl;
+ break;
+ }
+
+ len += sizeof(*cur);
+
+ if (!iszero(uuid, NVME_UUID_LEN))
+ _save_uuid(dev, uuid);
+ else if (!iszero(nguid, 16))
+ _save_nguid(dev, nguid);
+ else if (!iszero(eui64, 8))
+ _save_eui64(dev, eui64);
+ }
+out:
+ free(ctrl_id);
+ free(ns);
+ free(data);
+ close(fd);
+}
+#else
+void dev_read_nvme_wwids(struct device *dev)
+{
+}
+#endif
diff --git a/lib/device/parse_vpd.c b/lib/device/parse_vpd.c
index 968fd1f9c..16a653a14 100644
--- a/lib/device/parse_vpd.c
+++ b/lib/device/parse_vpd.c
@@ -177,7 +177,7 @@ int parse_vpd_ids(const unsigned char *vpd_data, int vpd_datalen, struct dm_list
break;
if (id_size >= ID_BUFSIZE)
id_size = ID_BUFSIZE - 1;
- dev_add_wwid(id, 1, ids);
+ dev_add_scsi_wwid(id, 1, ids);
break;
case 0x2:
/* EUI-64 */
@@ -203,7 +203,7 @@ int parse_vpd_ids(const unsigned char *vpd_data, int vpd_datalen, struct dm_list
break;
if (id_size >= ID_BUFSIZE)
id_size = ID_BUFSIZE - 1;
- dev_add_wwid(id, 2, ids);
+ dev_add_scsi_wwid(id, 2, ids);
break;
case 0x3:
/* NAA */
@@ -225,7 +225,7 @@ int parse_vpd_ids(const unsigned char *vpd_data, int vpd_datalen, struct dm_list
break;
if (id_size >= ID_BUFSIZE)
id_size = ID_BUFSIZE - 1;
- dev_add_wwid(id, 3, ids);
+ dev_add_scsi_wwid(id, 3, ids);
break;
case 0x8:
/* SCSI name string */
@@ -257,7 +257,7 @@ int parse_vpd_ids(const unsigned char *vpd_data, int vpd_datalen, struct dm_list
for (i = 0; i < strlen(id); i++)
id[i] = tolower(id[i]);
}
- dev_add_wwid(id, type, ids);
+ dev_add_scsi_wwid(id, type, ids);
break;
default:
break;
--
2.47.1

View File

@ -0,0 +1,121 @@
From c5552b43d33ca090439b6dce90dd78cdc6286ac4 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
Date: Mon, 9 Dec 2024 14:33:39 +0100
Subject: [PATCH 12/21] configure.ac: add support for libnvme
Add 2 new options for linking libnvme with lvm2.
Option --without-libnvme, --disable-nvme-wwid
(cherry picked from commit cb87e184bcbade1ac2da8fb611177f520169decd)
---
configure.ac | 34 ++++++++++++++++++++++++++++++++++
include/configure.h.in | 3 +++
lib/Makefile.in | 2 +-
make.tmpl.in | 5 ++++-
4 files changed, 42 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac
index cbea6adc6..5d4999b2d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -217,6 +217,8 @@ test "$exec_prefix" = "NONE" && exec_prefix='${prefix}'
AC_ARG_WITH(blkid, [AS_HELP_STRING([--without-blkid], [do not build with blkid library])],
[], with_blkid="yes")
+AC_ARG_WITH(libnvme, [AS_HELP_STRING([--without-libnvme], [do not build with libnvme library])],
+ [], with_libnvme="yes")
AC_ARG_WITH(systemd, [AS_HELP_STRING([--without-systemd], [do not build with systemd library])],
[], with_systemd="yes")
AC_ARG_WITH(udev, [AS_HELP_STRING([--without-udev], [do not build with udev library])],
@@ -1139,6 +1141,38 @@ AC_MSG_RESULT([$BLKID_WIPING])
AC_DEFINE_UNQUOTED(DEFAULT_USE_BLKID_WIPING, [$DEFAULT_USE_BLKID_WIPING],
[Use blkid wiping by default.])
+################################################################################
+dnl -- Enable nvme alternate WWID via libnvme
+AC_ARG_ENABLE(nvme-wwid,
+ AS_HELP_STRING([--disable-nvme-wwid],
+ [do not use libnvme to detect alternate WWIDs]),
+ NVME_WWID=$enableval,
+ [AS_IF([test "$with_libnvme" = "yes"], [NVME_WWID="maybe"], [NVME_WWID="no"])])
+
+# ATM NVME_WWID is the only user of libnvme, so skip checking for libnvme when disabled
+AS_IF([test "$NVME_WWID" = "no"], [with_libnvme="no"])
+
+AS_IF([test "$with_libnvme" = "yes"], [
+ PKG_CHECK_MODULES([LIBNVME], [libnvme >= 1.4], [
+ AC_CACHE_CHECK([for NVME_NIDT_CSI in libnvme.h],
+ [ac_cv_have_libnvme_csi],
+ [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <libnvme.h>
+const int a = NVME_NIDT_CSI;
+ ])], [ac_cv_have_libnvme_csi="yes"], [ac_cv_have_libnvme_csi="no"])])
+
+ AS_IF([test "$NVME_WWID" != "no"], [
+ AC_IF_YES(ac_cv_have_libnvme_csi, [NVME_WWID="yes"
+ AC_DEFINE(NVME_SUPPORT, 1, [Use libnvme for WWID.])],
+ [NVME_WWID="error"])])
+ ], [AS_IF([test "$NVME_WWID" = "yes"], [NVME_WWID="error"])])
+], [AS_IF([test "$NVME_WWID" = "yes"], [NVME_WWID="error"])])
+
+AS_IF([test "$NVME_WWID" = "error"],
+ [AC_MSG_ERROR([--enable-nvme-wwid requires libnvme library >= 1.1. (--with-libnvme=$with_libnvme)])])
+
+AC_MSG_CHECKING([whether to use libnvme for alternate WWIDs])
+AC_MSG_RESULT([$NVME_WWID])
+
################################################################################
dnl -- Enable udev synchronization
AC_MSG_CHECKING([whether to enable synchronization with udev processing])
diff --git a/include/configure.h.in b/include/configure.h.in
index 1dabd23c6..5a09f1d11 100644
--- a/include/configure.h.in
+++ b/include/configure.h.in
@@ -633,6 +633,9 @@
/* Define to 1 to include code that uses dbus notification. */
#undef NOTIFYDBUS_SUPPORT
+/* Use libnvme for WWID. */
+#undef NVME_SUPPORT
+
/* Define to 1 to enable O_DIRECT support. */
#undef O_DIRECT_SUPPORT
diff --git a/lib/Makefile.in b/lib/Makefile.in
index 8eab625aa..8424ac952 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -143,7 +143,7 @@ LIB_STATIC = $(LIB_NAME).a
CFLOW_LIST = $(SOURCES)
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
-PROGS_CFLAGS = $(BLKID_CFLAGS) $(UDEV_CFLAGS)
+PROGS_CFLAGS = $(BLKID_CFLAGS) $(LIBNVME_CFLAGS) $(UDEV_CFLAGS)
include $(top_builddir)/make.tmpl
diff --git a/make.tmpl.in b/make.tmpl.in
index c8a870a8e..878288938 100644
--- a/make.tmpl.in
+++ b/make.tmpl.in
@@ -57,7 +57,8 @@ PYTHON3 = @PYTHON3@
PYCOMPILE = $(top_srcdir)/autoconf/py-compile
LIBS += @LIBS@ $(SELINUX_LIBS) $(UDEV_LIBS) $(RT_LIBS) $(M_LIBS)
-LVMLIBS = $(DMEVENT_LIBS) $(READLINE_LIBS) $(EDITLINE_LIBS) $(LIBSYSTEMD_LIBS) $(BLKID_LIBS) $(AIO_LIBS) $(LIBS)
+LVMLIBS = $(DMEVENT_LIBS) $(READLINE_LIBS) $(EDITLINE_LIBS) $(LIBSYSTEMD_LIBS)\
+ $(BLKID_LIBS) $(LIBNVME_LIBS) $(AIO_LIBS) $(LIBS)
# Extra libraries always linked with static binaries
STATIC_LIBS = $(PTHREAD_LIBS) $(SELINUX_STATIC_LIBS) $(UDEV_STATIC_LIBS) $(BLKID_STATIC_LIBS) $(M_LIBS)
DEFS += @DEFS@
@@ -88,6 +89,8 @@ LIBDLM_CFLAGS = @LIBDLM_CFLAGS@
LIBDLM_LIBS = @LIBDLM_LIBS@
LIBDLMCONTROL_CFLAGS = @LIBDLMCONTROL_CFLAGS@
LIBDLMCONTROL_LIBS = @LIBDLMCONTROL_LIBS@
+LIBNVME_CFLAGS = @LIBNVME_CFLAGS@
+LIBNVME_LIBS = @LIBNVME_LIBS@
LIBSANLOCKCLIENT_CFLAGS = @LIBSANLOCKCLIENT_CFLAGS@
LIBSANLOCKCLIENT_LIBS = @LIBSANLOCKCLIENT_LIBS@
LIBSEAGATEILM_CFLAGS = @LIBSEAGATEILM_CFLAGS@
--
2.47.1

View File

@ -0,0 +1,271 @@
From ba3a0e852df240922401a47436248a124938ce42 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
Date: Mon, 9 Dec 2024 14:35:16 +0100
Subject: [PATCH 13/21] configure: autoreconf
(cherry picked from commit 928b8e9c6eaf871b3405b91c64eac5ea854f2572)
---
configure | 191 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 191 insertions(+)
diff --git a/configure b/configure
index 5147c7910..e98f7c1f3 100755
--- a/configure
+++ b/configure
@@ -787,6 +787,8 @@ LIBSYSTEMD_LIBS
LIBSYSTEMD_CFLAGS
UDEV_LIBS
UDEV_CFLAGS
+LIBNVME_LIBS
+LIBNVME_CFLAGS
BLKID_LIBS
BLKID_CFLAGS
SYSTEMD_RUN_CMD
@@ -912,6 +914,7 @@ enable_silent_rules
enable_static_link
enable_shared
with_blkid
+with_libnvme
with_systemd
with_udev
with_user
@@ -973,6 +976,7 @@ enable_systemd_journal
enable_app_machineid
with_systemd_run
enable_blkid_wiping
+enable_nvme_wwid
enable_udev_sync
enable_udev_rules
enable_udev_rule_exec_detection
@@ -1045,6 +1049,8 @@ LIBSEAGATEILM_CFLAGS
LIBSEAGATEILM_LIBS
BLKID_CFLAGS
BLKID_LIBS
+LIBNVME_CFLAGS
+LIBNVME_LIBS
UDEV_CFLAGS
UDEV_LIBS
LIBSYSTEMD_CFLAGS
@@ -1715,6 +1721,7 @@ Optional Features:
--disable-app-machineid disable LVM system ID using app-specific machine-id
--disable-blkid_wiping disable libblkid detection of signatures when wiping
and use native code instead
+ --disable-nvme-wwid do not use libnvme to detect alternate WWIDs
--enable-udev_sync enable synchronization with udev processing
--enable-udev_rules install rule files needed for udev synchronization
--enable-udev-rule-exec-detection
@@ -1741,6 +1748,7 @@ Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--without-blkid do not build with blkid library
+ --without-libnvme do not build with libnvme library
--without-systemd do not build with systemd library
--without-udev do not build with udev library
--with-user=USER set the owner of installed files [USER=]
@@ -1880,6 +1888,10 @@ Some influential environment variables:
BLKID_CFLAGS
C compiler flags for BLKID, overriding pkg-config
BLKID_LIBS linker flags for BLKID, overriding pkg-config
+ LIBNVME_CFLAGS
+ C compiler flags for LIBNVME, overriding pkg-config
+ LIBNVME_LIBS
+ linker flags for LIBNVME, overriding pkg-config
UDEV_CFLAGS C compiler flags for UDEV, overriding pkg-config
UDEV_LIBS linker flags for UDEV, overriding pkg-config
LIBSYSTEMD_CFLAGS
@@ -9128,6 +9140,16 @@ esac
fi
+# Check whether --with-libnvme was given.
+if test ${with_libnvme+y}
+then :
+ withval=$with_libnvme;
+else case e in #(
+ e) with_libnvme="yes" ;;
+esac
+fi
+
+
# Check whether --with-systemd was given.
if test ${with_systemd+y}
then :
@@ -13129,6 +13151,175 @@ printf "%s\n" "$BLKID_WIPING" >&6; }
printf "%s\n" "#define DEFAULT_USE_BLKID_WIPING $DEFAULT_USE_BLKID_WIPING" >>confdefs.h
+################################################################################
+# Check whether --enable-nvme-wwid was given.
+if test ${enable_nvme_wwid+y}
+then :
+ enableval=$enable_nvme_wwid; NVME_WWID=$enableval
+else case e in #(
+ e) if test "$with_libnvme" = "yes"
+then :
+ NVME_WWID="maybe"
+else case e in #(
+ e) NVME_WWID="no" ;;
+esac
+fi ;;
+esac
+fi
+
+
+# ATM NVME_WWID is the only user of libnvme, so skip checking for libnvme when disabled
+if test "$NVME_WWID" = "no"
+then :
+ with_libnvme="no"
+fi
+
+if test "$with_libnvme" = "yes"
+then :
+
+
+pkg_failed=no
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libnvme >= 1.4" >&5
+printf %s "checking for libnvme >= 1.4... " >&6; }
+
+if test -n "$LIBNVME_CFLAGS"; then
+ pkg_cv_LIBNVME_CFLAGS="$LIBNVME_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnvme >= 1.4\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libnvme >= 1.4") 2>&5
+ ac_status=$?
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_LIBNVME_CFLAGS=`$PKG_CONFIG --cflags "libnvme >= 1.4" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$LIBNVME_LIBS"; then
+ pkg_cv_LIBNVME_LIBS="$LIBNVME_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnvme >= 1.4\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libnvme >= 1.4") 2>&5
+ ac_status=$?
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_LIBNVME_LIBS=`$PKG_CONFIG --libs "libnvme >= 1.4" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ LIBNVME_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libnvme >= 1.4" 2>&1`
+ else
+ LIBNVME_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libnvme >= 1.4" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$LIBNVME_PKG_ERRORS" >&5
+
+ if test "$NVME_WWID" = "yes"
+then :
+ NVME_WWID="error"
+fi
+elif test $pkg_failed = untried; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ if test "$NVME_WWID" = "yes"
+then :
+ NVME_WWID="error"
+fi
+else
+ LIBNVME_CFLAGS=$pkg_cv_LIBNVME_CFLAGS
+ LIBNVME_LIBS=$pkg_cv_LIBNVME_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for NVME_NIDT_CSI in libnvme.h" >&5
+printf %s "checking for NVME_NIDT_CSI in libnvme.h... " >&6; }
+if test ${ac_cv_have_libnvme_csi+y}
+then :
+ printf %s "(cached) " >&6
+else case e in #(
+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <libnvme.h>
+const int a = NVME_NIDT_CSI;
+
+int
+main (void)
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_have_libnvme_csi="yes"
+else case e in #(
+ e) ac_cv_have_libnvme_csi="no" ;;
+esac
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;;
+esac
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_libnvme_csi" >&5
+printf "%s\n" "$ac_cv_have_libnvme_csi" >&6; }
+
+ if test "$NVME_WWID" != "no"
+then :
+
+ if test $ac_cv_have_libnvme_csi = yes
+then :
+ NVME_WWID="yes"
+
+printf "%s\n" "#define NVME_SUPPORT 1" >>confdefs.h
+
+else case e in #(
+ e) NVME_WWID="error" ;;
+esac
+fi
+fi
+
+fi
+
+else case e in #(
+ e) if test "$NVME_WWID" = "yes"
+then :
+ NVME_WWID="error"
+fi ;;
+esac
+fi
+
+if test "$NVME_WWID" = "error"
+then :
+ as_fn_error $? "--enable-nvme-wwid requires libnvme library >= 1.1. (--with-libnvme=$with_libnvme)" "$LINENO" 5
+fi
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to use libnvme for alternate WWIDs" >&5
+printf %s "checking whether to use libnvme for alternate WWIDs... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $NVME_WWID" >&5
+printf "%s\n" "$NVME_WWID" >&6; }
+
################################################################################
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable synchronization with udev processing" >&5
printf %s "checking whether to enable synchronization with udev processing... " >&6; }
--
2.47.1

View File

@ -0,0 +1,52 @@
From 878633052b22219fc1224184091531dba5b19252 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
Date: Thu, 19 Dec 2024 14:47:16 +0100
Subject: [PATCH 14/21] thin: deactivate converted volume early
Deactivate converted volume to pool early, so the conversion
exits early and does not leave some already created metadata
volumes that needed manual cleanup by user after command
aborted its conversion operation when the converted volume
was actually in-use (i.e. when user tried to convert
a mounted LV into a thin-pool, 2 extra volumes needed removal).
(cherry picked from commit 6326d0093730fe945eeb4748738ddda55bf8a3c9)
---
tools/lvconvert.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 8dd8eea1b..d15e01fd7 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -3154,6 +3154,13 @@ static int _lvconvert_to_pool(struct cmd_context *cmd,
activate_pool = to_thinpool && is_active;
+ /* Before the conversion starts, make sure the volume is unused and can be deactivated
+ * (as it needs to change target type) */
+ if (is_active && !to_thin && !deactivate_lv(cmd, lv)) {
+ log_error("Cannot convert logical volume %s.", display_lvname(lv));
+ return 0;
+ }
+
/* Wipe metadata_lv by default, but allow skipping this for cache pools. */
zero_metadata = (to_cachepool) ? arg_int_value(cmd, zero_ARG, 1) : 1;
@@ -3405,13 +3412,6 @@ static int _lvconvert_to_pool(struct cmd_context *cmd,
if (!(pool_lv = _lvconvert_insert_thin_layer(lv)))
goto_bad;
} else {
- /* Deactivate the data LV (changing target type) */
- if (!deactivate_lv(cmd, lv)) {
- log_error("Aborting. Failed to deactivate logical volume %s.",
- display_lvname(lv));
- goto bad;
- }
-
if (data_vdo) {
if (lv_is_vdo(lv)) {
if ((seg = first_seg(lv)))
--
2.47.1

View File

@ -0,0 +1,51 @@
From 6eb8a0bdb62c1089f414f94c77197bacb1a79bee Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
Date: Thu, 19 Dec 2024 14:50:32 +0100
Subject: [PATCH 15/21] tests: check conversion of in-use volume
Thin-pool conversion fails early when trying to convert
volume which is in use (simulated by sleep <)
(cherry picked from commit 3e641578d80bc7a28bcb451115b06da87d232b3a)
---
test/shell/lvconvert-thin-vdo.sh | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/test/shell/lvconvert-thin-vdo.sh b/test/shell/lvconvert-thin-vdo.sh
index d61126276..5b4fe9d97 100644
--- a/test/shell/lvconvert-thin-vdo.sh
+++ b/test/shell/lvconvert-thin-vdo.sh
@@ -34,11 +34,29 @@ which mkfs.ext4 || skip
aux prepare_vg 4 6400
-# convert to thin-pool with VDO backend from existing VG/LV
+# Convert to thin-pool with VDO backend from existing VG/LV
lvcreate -L5G --name $lv1 $vg
+
+# Keep volume in use for 6 seconds
+# - lvm retries for ~5sec to deactivate
+sleep 6 < "$DM_DEV_DIR/$vg/$lv1" &
+
+# Volume in use cannot be converted
+fail lvconvert -y --type thin-pool $vg/$lv1 --pooldatavdo y
+
+# Wait for sleep to not use LV anymore
+wait
+
+# No extra volume should appear in VG after failure
+test "$(get vg_field $vg lv_count)" -eq "1"
+
mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
# Conversion caught present filesystem and should fail
fail lvconvert -Wy --type thin-pool -c 256K --deduplication n --pooldatavdo y $vg/$lv1
+
+# No extra volume should appear in VG after failure
+test "$(get vg_field $vg lv_count)" -eq "1"
+
# With --yes it should work over prompt
lvconvert --yes -Wy --type thin-pool -c 256K --deduplication n --pooldatavdo y $vg/$lv1
--
2.47.1

View File

@ -0,0 +1,25 @@
From ba5ec30c20fa9c422282595871a0caca6f882c8b Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
Date: Thu, 19 Dec 2024 14:57:43 +0100
Subject: [PATCH 16/21] WHATS_NEW: update
(cherry picked from commit 5ef958704c82c45a6bd8215d920e4366c0c5e1bd)
---
WHATS_NEW | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/WHATS_NEW b/WHATS_NEW
index bea47f154..e63dfc393 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,3 +1,7 @@
+Version 2.03.30 -
+==================
+ lvconvert detects early volume in use when converting it to a pool.
+
Version 2.03.29 -
==================
Fix renaming of raid sub LVs when converting a volume to raid (2.03.28).
--
2.47.1

View File

@ -0,0 +1,176 @@
From 6bd6916728fe467770294c5e8b9c1e3aa8390a55 Mon Sep 17 00:00:00 2001
From: Peter Rajnoha <prajnoha@redhat.com>
Date: Fri, 3 Jan 2025 10:52:47 +0100
Subject: [PATCH 17/21] lv_manip: check fs resize is supported before LV
extension
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This avoids a situation where we would extend an LV and then we would
not do anything to the FS on it because the FS info check failed for some
reason, like the type was not supported (e.g. swap) or we could not resize
the FS unless being in some supported state (e.g. XFS to be mounted for
the xfs_growfs to work).
Before this patch (LV resized, FS not resized):
lvextend --fs resize -L+4M vg/swap
Size of logical volume vg/swap changed from 32.00 MiB (8 extents) to 36.00 MiB (9 extents).
File system extend is not supported (swap).
File system extend error.
Logical volume vg/swap successfully resized.
With this patch (LV not resized, FS not resized):
lvextend --fs resize -L+4M vg/swap
File system extend is not supported (swap).
(cherry picked from commit 5f53ecda3600834e920eef14065d35cd0fb6c59b)
---
lib/metadata/lv_manip.c | 71 +++++++++++++++++++++--------------------
1 file changed, 36 insertions(+), 35 deletions(-)
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 15a7f3c9a..dab160234 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -6550,23 +6550,18 @@ static int _fs_reduce(struct cmd_context *cmd, struct logical_volume *lv,
return ret;
}
-static int _fs_extend(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvresize_params *lp)
+static int _fs_extend_check_fsinfo(struct cmd_context *cmd, struct logical_volume *lv, struct lvresize_params *lp,
+ struct fs_info *fsinfo, uint64_t *newsize_bytes_fs)
{
- struct fs_info fsinfo;
uint64_t newsize_bytes_lv;
- uint64_t newsize_bytes_fs;
- int ret = 0;
- memset(&fsinfo, 0, sizeof(fsinfo));
+ memset(fsinfo, 0, sizeof(*fsinfo));
- if (!fs_get_info(cmd, lv, &fsinfo, 1))
- goto_out;
+ if (!fs_get_info(cmd, lv, fsinfo, 1))
+ return 0;
- if (fsinfo.nofs) {
- ret = 1;
- goto_out;
- }
+ if (fsinfo->nofs)
+ return 1;
/*
* Note: here in the case of extend, newsize_bytes_lv/newsize_bytes_fs
@@ -6577,40 +6572,43 @@ static int _fs_extend(struct cmd_context *cmd, struct logical_volume *lv,
/* extent_size units is SECTOR_SIZE (512) */
newsize_bytes_lv = (uint64_t) lp->extents * lv->vg->extent_size * SECTOR_SIZE;
- newsize_bytes_fs = newsize_bytes_lv;
- if (fsinfo.needs_crypt) {
- newsize_bytes_fs -= fsinfo.crypt_offset_bytes;
+ *newsize_bytes_fs = newsize_bytes_lv;
+ if (fsinfo->needs_crypt) {
+ *newsize_bytes_fs -= fsinfo->crypt_offset_bytes;
log_print_unless_silent("File system size %llub is adjusted for crypt data offset %ub.",
- (unsigned long long)newsize_bytes_fs, fsinfo.crypt_offset_bytes);
+ (unsigned long long)*newsize_bytes_fs, fsinfo->crypt_offset_bytes);
}
/*
* Decide if fs should be extended based on the --fs option,
* the fs type and the mount state.
*/
- if (!_fs_extend_allow(cmd, lv, lp, &fsinfo))
- goto_out;
+ if (!_fs_extend_allow(cmd, lv, lp, fsinfo))
+ return 0;
+
+ return 1;
+}
+static int _fs_extend(struct cmd_context *cmd, struct logical_volume *lv,
+ struct lvresize_params *lp, struct fs_info *fsinfo, uint64_t newsize_bytes_fs)
+{
/*
* fs extend is not needed
*/
- if (!fsinfo.needs_extend) {
- ret = 1;
- goto_out;
- }
+ if (!fsinfo->needs_extend)
+ return 1;
if (test_mode()) {
- if (fsinfo.needs_unmount)
+ if (fsinfo->needs_unmount)
log_print_unless_silent("Skip unmount in test mode.");
- if (fsinfo.needs_fsck)
+ if (fsinfo->needs_fsck)
log_print_unless_silent("Skip fsck in test mode.");
- if (fsinfo.needs_mount)
+ if (fsinfo->needs_mount)
log_print_unless_silent("Skip mount in test mode.");
- if (fsinfo.needs_crypt)
+ if (fsinfo->needs_crypt)
log_print_unless_silent("Skip cryptsetup in test mode.");
log_print_unless_silent("Skip fs extend in test mode.");
- ret = 1;
- goto out;
+ return 1;
}
/*
@@ -6621,12 +6619,7 @@ static int _fs_extend(struct cmd_context *cmd, struct logical_volume *lv,
*/
unlock_vg(cmd, lv->vg, lv->vg->name);
- if (!fs_extend_script(cmd, lv, &fsinfo, newsize_bytes_fs, lp->fsmode))
- goto_out;
-
- ret = 1;
- out:
- return ret;
+ return fs_extend_script(cmd, lv, fsinfo, newsize_bytes_fs, lp->fsmode);
}
int lv_resize(struct cmd_context *cmd, struct logical_volume *lv,
@@ -6640,6 +6633,8 @@ int lv_resize(struct cmd_context *cmd, struct logical_volume *lv,
struct logical_volume *lv_meta = NULL;
struct logical_volume *lv_main_layer = NULL;
struct logical_volume *lv_meta_layer = NULL;
+ struct fs_info fsinfo;
+ uint64_t newsize_bytes_fs;
int main_size_matches = 0;
int meta_size_matches = 0;
int is_extend = (lp->resize == LV_EXTEND);
@@ -7100,6 +7095,12 @@ int lv_resize(struct cmd_context *cmd, struct logical_volume *lv,
if (!lv_main)
goto end_main;
+
+ if (is_extend && lp->fsopt[0] && strcmp(lp->fsopt, "resize_fsadm")) {
+ if (!_fs_extend_check_fsinfo(cmd, lv_top, lp, &fsinfo, &newsize_bytes_fs))
+ goto_out;
+ }
+
if (!_lv_resize_volume(lv_main, lp, lp->pvh))
goto_out;
if (!lp->size_changed) {
@@ -7145,7 +7146,7 @@ int lv_resize(struct cmd_context *cmd, struct logical_volume *lv,
}
} else {
/* New approach to fs handling using fs info. */
- if (!_fs_extend(cmd, lv_top, lp)) {
+ if (!_fs_extend(cmd, lv_top, lp, &fsinfo, newsize_bytes_fs)) {
log_error("File system extend error.");
lp->extend_fs_error = 1;
goto out;
--
2.47.1

View File

@ -0,0 +1,65 @@
From 4f9bf0cb0910eea457137102ec460c994068af45 Mon Sep 17 00:00:00 2001
From: Peter Rajnoha <prajnoha@redhat.com>
Date: Fri, 3 Jan 2025 15:26:27 +0100
Subject: [PATCH 18/21] tests: adjust lvresize-xfs tests for recent lvextend
changes
Because now, we are doing the fsinfo check before extending an LV and if
that check fails, we do not proceed to the LV extension itself and the
lvextend command bails out immediatelly.
(cherry picked from commit e86a75b4fe5873f563c930a575f54143ddca7c7c)
---
test/shell/lvresize-xfs.sh | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/test/shell/lvresize-xfs.sh b/test/shell/lvresize-xfs.sh
index 87fbf6f9d..17bc6fba3 100644
--- a/test/shell/lvresize-xfs.sh
+++ b/test/shell/lvresize-xfs.sh
@@ -104,13 +104,12 @@ lvremove -f $vg/$lv
####################
# lvextend, xfs, active, mounted, --fs resize --fsmode offline
-lvcreate -n $lv -L 300M $vg
+lvcreate -n $lv -L 320M $vg
mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir_space"
df --output=size "$mount_dir_space" |tee df1
dd if=/dev/zero of="$mount_dir_space/zeros1" bs=1M count=20 oflag=direct
-# xfs_growfs requires the fs to be mounted, so extending the lv is
-# succeeds, then the xfs extend fails because it cannot be done unmounted
+# xfs_growfs requires the fs to be mounted, so the lvextend fails here
not lvextend --fs resize --fsmode offline -L+20M $vg/$lv
check lv_field $vg/$lv lv_size "320.00m"
df | tee dfa
@@ -136,7 +135,7 @@ umount "$mount_dir_space"
# xfs_growfs requires the fs to be mounted to grow, so --fsmode nochange
# with an unmounted fs fails
not lvextend --fs resize --fsmode nochange -L+20M $vg/$lv
-check lv_field $vg/$lv lv_size "380.00m"
+check lv_field $vg/$lv lv_size "360.00m"
mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir_space"
df --output=size "$mount_dir_space" |tee df4
# fs not extended so fs size not changed
@@ -147,7 +146,7 @@ umount "$mount_dir_space"
# --yes needed because mount changes are required and plain "resize"
# fsopt did not specify if the user wants to change mount state
lvextend --yes --fs resize -L+10M $vg/$lv
-check lv_field $vg/$lv lv_size "390.00m"
+check lv_field $vg/$lv lv_size "370.00m"
mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir_space"
df --output=size "$mount_dir_space" |tee df5
not diff df4 df5
@@ -155,7 +154,7 @@ umount "$mount_dir_space"
# lvextend, xfs, active, unmounted, --fs resize_fsadm
lvextend --fs resize_fsadm -L+10M $vg/$lv
-check lv_field $vg/$lv lv_size "400.00m"
+check lv_field $vg/$lv lv_size "380.00m"
mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir_space"
df --output=size "$mount_dir_space" |tee df6
not diff df5 df6
--
2.47.1

View File

@ -0,0 +1,24 @@
From 170d6658c5ba33c01e07de3e1fe60b8e66a01712 Mon Sep 17 00:00:00 2001
From: Peter Rajnoha <prajnoha@redhat.com>
Date: Mon, 6 Jan 2025 15:35:44 +0100
Subject: [PATCH 19/21] WHATS_NEW: update
(cherry picked from commit 1576273273b84bc8d3d330f113ffb1ac67f2c0a2)
---
WHATS_NEW | 1 +
1 file changed, 1 insertion(+)
diff --git a/WHATS_NEW b/WHATS_NEW
index e63dfc393..40c6c2cd0 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.03.30 -
==================
+ Do not extend an LV if FS resize unsupported and '--fs resize' used.
lvconvert detects early volume in use when converting it to a pool.
Version 2.03.29 -
--
2.47.1

View File

@ -0,0 +1,42 @@
From 2b0945ac5c65fdbaca0fffb257c1574803071af5 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
Date: Wed, 8 Jan 2025 17:48:53 +0100
Subject: [PATCH 20/21] memlock: check for proper reserved size
Fix regression introduced with commit:
964012fdb924076e9ab97fabe00e759ddbf7c3bd
that effectively disabled memory locking before suspending volumes.
From merging/testing there remained wrong condition
as we really want to check for 0 memory reservation value
for both checked settings.
(cherry picked from commit 4ef211a187dac348fa1857d577f5c17c9dace190)
---
lib/mm/memlock.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/mm/memlock.c b/lib/mm/memlock.c
index e28044df6..e7b0b4f7a 100644
--- a/lib/mm/memlock.c
+++ b/lib/mm/memlock.c
@@ -517,7 +517,7 @@ static void _restore_priority_if_possible(struct cmd_context *cmd)
/* Stop memory getting swapped out */
static void _lock_mem(struct cmd_context *cmd)
{
- if (!_size_stack || _size_malloc_tmp) {
+ if (!_size_stack || !_size_malloc_tmp) {
log_debug_mem("Skipping memory locking (reserved memory: "
FMTsize_t " stack: " FMTsize_t ").",
_size_malloc_tmp, _size_stack);
@@ -564,7 +564,7 @@ static void _unlock_mem(struct cmd_context *cmd)
{
size_t unlock_mstats = 0;
- if (!_size_stack || _size_malloc_tmp) {
+ if (!_size_stack || !_size_malloc_tmp) {
log_debug_mem("Skipping memory unlocking (reserved memory: "
FMTsize_t " stack: " FMTsize_t ").",
_size_malloc_tmp, _size_stack);
--
2.47.1

View File

@ -0,0 +1,27 @@
From caf9a0dc9139a676f8afa09206511b955b67a76b Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
Date: Wed, 8 Jan 2025 23:05:12 +0100
Subject: [PATCH 21/21] WHATS_NEW: update
---
WHATS_NEW | 3 +++
1 file changed, 3 insertions(+)
diff --git a/WHATS_NEW b/WHATS_NEW
index 40c6c2cd0..0296720d3 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,7 +1,10 @@
Version 2.03.30 -
==================
+ Fix support for disabling memory locking (2.03.27).
Do not extend an LV if FS resize unsupported and '--fs resize' used.
+ Prevent leftover temporary device when converting in use volume to a pool.
lvconvert detects early volume in use when converting it to a pool.
+ Handle NVMe with quirk changed WWID not matching WWID in devices file.
Version 2.03.29 -
==================
--
2.47.1

View File

@ -56,6 +56,21 @@ Patch7: 0007-tests-check-vdo-minimum_io_size.patch
Patch8: 0008-raid-fix-name-rotation.patch
Patch9: 0009-tests-check-_tdata-conversion-to-raid1.patch
Patch10: 0010-WHATS_NEW-update.patch
# RHEL-75625:
Patch11: 0011-device_id-nvme-devices-may-use-alternate-wwids.patch
Patch12: 0012-configure.ac-add-support-for-libnvme.patch
Patch13: 0013-configure-autoreconf.patch
# RHEL-75626:
Patch14: 0014-thin-deactivate-converted-volume-early.patch
Patch15: 0015-tests-check-conversion-of-in-use-volume.patch
Patch16: 0016-WHATS_NEW-update.patch
# RHEL-75628:
Patch17: 0017-lv_manip-check-fs-resize-is-supported-before-LV-exte.patch
Patch18: 0018-tests-adjust-lvresize-xfs-tests-for-recent-lvextend-.patch
Patch19: 0019-WHATS_NEW-update.patch
# RHEL-75629:
Patch20: 0020-memlock-check-for-proper-reserved-size.patch
Patch21: 0021-WHATS_NEW-update.patch
BuildRequires: make
BuildRequires: gcc
@ -656,6 +671,12 @@ An extensive functional testsuite for LVM2.
%endif
%changelog
* Tue Jan 21 2025 Marian Csontos <mcsontos@redhat.com> - 2.03.28-4
- Fix temporary LVs not cleaned when converting in use LV to a thin pool.
- Check FS resize is supported before extending LV.
- Fix issue affecting memory locking before suspend (2.03.27).
- Workaround for NVMe WWID changing after kernel update.
* Thu Nov 14 2024 Marian Csontos <mcsontos@redhat.com> - 2.03.28-3
- Fix duplicate LV names when converting pools to RAID1 with more than 2 legs.