Additional patches for 9.9.0 lvm2
Patches from upstream up to 2.03.41. Resolves: RHEL-174324
This commit is contained in:
parent
a49ba1df62
commit
0d41e7e8af
@ -15,14 +15,14 @@ index 2d35b7660..4993d445a 100644
|
||||
+++ b/VERSION
|
||||
@@ -1 +1 @@
|
||||
-2.03.33(2) (2025-06-27)
|
||||
+2.03.33(2)-RHEL9 (2025-09-25)
|
||||
+2.03.33(2)-RHEL9 (2026-06-04)
|
||||
diff --git a/VERSION_DM b/VERSION_DM
|
||||
index 0e8dcd346..c0564e0ea 100644
|
||||
--- a/VERSION_DM
|
||||
+++ b/VERSION_DM
|
||||
@@ -1 +1 @@
|
||||
-1.02.207 (2025-06-27)
|
||||
+1.02.207-RHEL9 (2025-09-25)
|
||||
+1.02.207-RHEL9 (2026-06-04)
|
||||
--
|
||||
2.51.0
|
||||
|
||||
|
||||
61
0062-cov-pvck-fix-TOCTOU-race-in-get_devicefile.patch
Normal file
61
0062-cov-pvck-fix-TOCTOU-race-in-get_devicefile.patch
Normal file
@ -0,0 +1,61 @@
|
||||
From 442f1cff0766899544dbdb6a7ae88166ef7016e5 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 21:52:58 +0200
|
||||
Subject: [PATCH 062/211] cov: pvck: fix TOCTOU race in get_devicefile
|
||||
|
||||
Remove stat() check before open() to eliminate TOCTOU race.
|
||||
Instead, open the file first, then use fstat() on the fd to
|
||||
verify it's a regular file. Close fd on all error paths.
|
||||
|
||||
This ensures we're checking the actual file we opened, not
|
||||
a path that could have changed between stat() and open().
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 2079fc370d05b174f43a501617acba89e86240f4)
|
||||
---
|
||||
tools/pvck.c | 20 ++++++++++++++------
|
||||
1 file changed, 14 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/tools/pvck.c b/tools/pvck.c
|
||||
index 71171092c..8c7bbc92f 100644
|
||||
--- a/tools/pvck.c
|
||||
+++ b/tools/pvck.c
|
||||
@@ -352,21 +352,29 @@ static struct devicefile *get_devicefile(struct cmd_context *cmd, const char *pa
|
||||
struct stat sb;
|
||||
struct devicefile *def;
|
||||
size_t len;
|
||||
+ int fd;
|
||||
+
|
||||
+ if ((fd = open(path, O_RDONLY)) < 0)
|
||||
+ return_NULL;
|
||||
|
||||
- if (stat(path, &sb))
|
||||
+ if (fstat(fd, &sb) < 0) {
|
||||
+ (void) close(fd);
|
||||
return_NULL;
|
||||
+ }
|
||||
|
||||
- if ((sb.st_mode & S_IFMT) != S_IFREG)
|
||||
+ if ((sb.st_mode & S_IFMT) != S_IFREG) {
|
||||
+ (void) close(fd);
|
||||
return_NULL;
|
||||
+ }
|
||||
|
||||
len = strlen(path) + 1;
|
||||
- if (!(def = dm_pool_alloc(cmd->mem, sizeof(struct devicefile) + len)))
|
||||
+ if (!(def = dm_pool_alloc(cmd->mem, sizeof(struct devicefile) + len))) {
|
||||
+ (void) close(fd);
|
||||
return_NULL;
|
||||
+ }
|
||||
|
||||
memcpy(def->path, path, len);
|
||||
-
|
||||
- if ((def->fd = open(path, O_RDONLY)) < 0)
|
||||
- return_NULL;
|
||||
+ def->fd = fd;
|
||||
|
||||
return def;
|
||||
}
|
||||
--
|
||||
2.54.0
|
||||
|
||||
129
0063-cov-libdm-fix-TOCTOU-race-in-_sysfs_find_kernel_name.patch
Normal file
129
0063-cov-libdm-fix-TOCTOU-race-in-_sysfs_find_kernel_name.patch
Normal file
@ -0,0 +1,129 @@
|
||||
From 0c5fb9c14a75042620ddd43de513f1a1119e60be Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 21:37:54 +0200
|
||||
Subject: [PATCH 063/211] cov: libdm: fix TOCTOU race in
|
||||
_sysfs_find_kernel_name
|
||||
|
||||
Remove stat() check before opendir() to eliminate TOCTOU race.
|
||||
Instead, call opendir() directly and check errno:
|
||||
- ENOTDIR: silently skip (path is not a directory)
|
||||
- Other errors: log with log_sys_debug()
|
||||
|
||||
This simplifies the code and eliminates the race condition.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit f2f410e28db30a37e70fb7b2920ea1bd95d96d15)
|
||||
---
|
||||
libdm/libdm-common.c | 80 +++++++++++++++++++++-----------------------
|
||||
1 file changed, 38 insertions(+), 42 deletions(-)
|
||||
|
||||
diff --git a/libdm/libdm-common.c b/libdm/libdm-common.c
|
||||
index e4fdbbf05..21bdd826e 100644
|
||||
--- a/libdm/libdm-common.c
|
||||
+++ b/libdm/libdm-common.c
|
||||
@@ -1906,7 +1906,6 @@ static int _sysfs_find_kernel_name(uint32_t major, uint32_t minor, char *buf, si
|
||||
char path[PATH_MAX];
|
||||
struct dirent *dirent, *dirent_dev;
|
||||
DIR *d, *d_dev;
|
||||
- struct stat st;
|
||||
int r = 0, sz;
|
||||
|
||||
if (!*_sysfs_dir ||
|
||||
@@ -1938,56 +1937,53 @@ static int _sysfs_find_kernel_name(uint32_t major, uint32_t minor, char *buf, si
|
||||
}
|
||||
|
||||
path[sz - 4] = 0; /* strip /dev from end of path string */
|
||||
- if (stat(path, &st))
|
||||
+
|
||||
+ /* let's assume there is no tree-complex device in past systems */
|
||||
+ if (!(d_dev = opendir(path))) {
|
||||
+ /* Silently skip non-directories, log other errors */
|
||||
+ if (errno != ENOTDIR)
|
||||
+ log_sys_debug("opendir", path);
|
||||
continue;
|
||||
+ }
|
||||
|
||||
- if (S_ISDIR(st.st_mode)) {
|
||||
+ while ((dirent_dev = readdir(d_dev))) {
|
||||
+ name_dev = dirent_dev->d_name;
|
||||
+
|
||||
+ /* skip known ignorable paths */
|
||||
+ if (!strcmp(name_dev, ".") || !strcmp(name_dev, "..") ||
|
||||
+ !strcmp(name_dev, "bdi") ||
|
||||
+ !strcmp(name_dev, "dev") ||
|
||||
+ !strcmp(name_dev, "device") ||
|
||||
+ !strcmp(name_dev, "holders") ||
|
||||
+ !strcmp(name_dev, "integrity") ||
|
||||
+ !strcmp(name_dev, "loop") ||
|
||||
+ !strcmp(name_dev, "queue") ||
|
||||
+ !strcmp(name_dev, "md") ||
|
||||
+ !strcmp(name_dev, "mq") ||
|
||||
+ !strcmp(name_dev, "power") ||
|
||||
+ !strcmp(name_dev, "removable") ||
|
||||
+ !strcmp(name_dev, "slave") ||
|
||||
+ !strcmp(name_dev, "slaves") ||
|
||||
+ !strcmp(name_dev, "subsystem") ||
|
||||
+ !strcmp(name_dev, "trace") ||
|
||||
+ !strcmp(name_dev, "uevent"))
|
||||
+ continue;
|
||||
|
||||
- /* let's assume there is no tree-complex device in past systems */
|
||||
- if (!(d_dev = opendir(path))) {
|
||||
- log_sys_debug("opendir", path);
|
||||
+ if (dm_snprintf(path, sizeof(path), "%sblock/%s/%s/dev",
|
||||
+ _sysfs_dir, name, name_dev) == -1) {
|
||||
+ log_warn("Couldn't create path for %s/%s.", name, name_dev);
|
||||
continue;
|
||||
}
|
||||
|
||||
- while ((dirent_dev = readdir(d_dev))) {
|
||||
- name_dev = dirent_dev->d_name;
|
||||
-
|
||||
- /* skip known ignorable paths */
|
||||
- if (!strcmp(name_dev, ".") || !strcmp(name_dev, "..") ||
|
||||
- !strcmp(name_dev, "bdi") ||
|
||||
- !strcmp(name_dev, "dev") ||
|
||||
- !strcmp(name_dev, "device") ||
|
||||
- !strcmp(name_dev, "holders") ||
|
||||
- !strcmp(name_dev, "integrity") ||
|
||||
- !strcmp(name_dev, "loop") ||
|
||||
- !strcmp(name_dev, "queue") ||
|
||||
- !strcmp(name_dev, "md") ||
|
||||
- !strcmp(name_dev, "mq") ||
|
||||
- !strcmp(name_dev, "power") ||
|
||||
- !strcmp(name_dev, "removable") ||
|
||||
- !strcmp(name_dev, "slave") ||
|
||||
- !strcmp(name_dev, "slaves") ||
|
||||
- !strcmp(name_dev, "subsystem") ||
|
||||
- !strcmp(name_dev, "trace") ||
|
||||
- !strcmp(name_dev, "uevent"))
|
||||
- continue;
|
||||
-
|
||||
- if (dm_snprintf(path, sizeof(path), "%sblock/%s/%s/dev",
|
||||
- _sysfs_dir, name, name_dev) == -1) {
|
||||
- log_warn("Couldn't create path for %s/%s.", name, name_dev);
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- if (_sysfs_get_dev_major_minor(path, major, minor)) {
|
||||
- r = dm_strncpy(buf, name_dev, buf_size);
|
||||
- break; /* found */
|
||||
- }
|
||||
+ if (_sysfs_get_dev_major_minor(path, major, minor)) {
|
||||
+ r = dm_strncpy(buf, name_dev, buf_size);
|
||||
+ break; /* found */
|
||||
}
|
||||
+ }
|
||||
|
||||
- if (closedir(d_dev))
|
||||
- log_sys_debug("closedir", name);
|
||||
+ if (closedir(d_dev))
|
||||
+ log_sys_debug("closedir", name);
|
||||
}
|
||||
- }
|
||||
|
||||
if (closedir(d))
|
||||
log_sys_debug("closedir", path);
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
From 8483c7d96d831c06968ef585533ba06da8c36a05 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 22:01:14 +0200
|
||||
Subject: [PATCH 064/211] cov: dev-mpath: fix TOCTOU race in holders directory
|
||||
check
|
||||
|
||||
Remove stat() check before opendir() to eliminate TOCTOU race.
|
||||
Call opendir() directly and check errno:
|
||||
- ENOENT: silently skip (normal for partitions without holders)
|
||||
- ENOTDIR: warn (path exists but is not a directory)
|
||||
- Other errors: log debug message
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 44b9934d92c2e1ef723d58753ee1633b528582d1)
|
||||
---
|
||||
lib/device/dev-mpath.c | 20 +++++++++-----------
|
||||
1 file changed, 9 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/lib/device/dev-mpath.c b/lib/device/dev-mpath.c
|
||||
index 7e99e17d0..6e71ab080 100644
|
||||
--- a/lib/device/dev-mpath.c
|
||||
+++ b/lib/device/dev-mpath.c
|
||||
@@ -459,21 +459,19 @@ static int _dev_is_mpath_component_sysfs(struct cmd_context *cmd, struct device
|
||||
return 0;
|
||||
}
|
||||
|
||||
- /* also will filter out partitions */
|
||||
- if (stat(holders_path, &info))
|
||||
- return 0;
|
||||
-
|
||||
- if (!S_ISDIR(info.st_mode)) {
|
||||
- log_warn("Path %s is not a directory.", holders_path);
|
||||
- return 0;
|
||||
- }
|
||||
-
|
||||
/*
|
||||
* If any holder is a dm mpath device, then return 1;
|
||||
+ * This also filters out partitions (no holders directory).
|
||||
*/
|
||||
-
|
||||
if (!(dr = opendir(holders_path))) {
|
||||
- log_debug("Device %s has no holders dir", dev_name(dev));
|
||||
+ /* Distinguish between non-existent (partitions) and errors */
|
||||
+ if (errno == ENOENT)
|
||||
+ return 0; /* Normal for partitions */
|
||||
+ if (errno == ENOTDIR) {
|
||||
+ log_warn("Path %s is not a directory.", holders_path);
|
||||
+ return 0;
|
||||
+ }
|
||||
+ log_debug("Device %s has no holders dir.", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,52 @@
|
||||
From 7b9f2be292c3b6c6fd4985e5b56cd61bc44b1608 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 22:13:18 +0200
|
||||
Subject: [PATCH 065/211] cov: dev-cache: fix TOCTOU race in
|
||||
devices_file_rename_unused
|
||||
|
||||
Remove stat() check before rename() to eliminate TOCTOU race.
|
||||
Instead, call rename() directly and silently ignore ENOENT
|
||||
(file doesn't exist). Other errors still call stack.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 142aa7b6ceec37b72b6d39b3c1356909b4cf4bff)
|
||||
---
|
||||
lib/device/dev-cache.c | 8 +++-----
|
||||
1 file changed, 3 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c
|
||||
index 15cbc1d84..24a4d91c5 100644
|
||||
--- a/lib/device/dev-cache.c
|
||||
+++ b/lib/device/dev-cache.c
|
||||
@@ -2019,7 +2019,6 @@ static void devices_file_rename_unused(struct cmd_context *cmd)
|
||||
const char *filename;
|
||||
time_t t;
|
||||
struct tm *tm;
|
||||
- struct stat st;
|
||||
|
||||
filename = find_config_tree_str(cmd, devices_devicesfile_CFG, NULL);
|
||||
|
||||
@@ -2029,9 +2028,6 @@ static void devices_file_rename_unused(struct cmd_context *cmd)
|
||||
if (dm_snprintf(path, sizeof(path), "%s/devices/%s", cmd->system_dir, filename) < 0)
|
||||
return;
|
||||
|
||||
- if (stat(path, &st))
|
||||
- return;
|
||||
-
|
||||
t = time(NULL);
|
||||
if (!(tm = localtime(&t)))
|
||||
return;
|
||||
@@ -2043,7 +2039,9 @@ static void devices_file_rename_unused(struct cmd_context *cmd)
|
||||
return;
|
||||
|
||||
if (rename(path, path2) < 0) {
|
||||
- stack;
|
||||
+ /* Silently ignore if file doesn't exist */
|
||||
+ if (errno != ENOENT)
|
||||
+ stack;
|
||||
return;
|
||||
}
|
||||
log_debug("Devices file moved to %s", path2);
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
From 304e2acd7b40c9ebbebca1af474f5f7ba6b8a73e Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 12:01:35 +0200
|
||||
Subject: [PATCH 066/211] libdm: dbg_malloc: fix buffer overflow in
|
||||
dm_realloc_aux
|
||||
|
||||
memcpy used the old allocation size (mb->length) unconditionally.
|
||||
When shrinking (new size < old size), this overflows the new buffer.
|
||||
Copy the minimum of old and new sizes.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 767157754b694035d051093861cad5b9ac3494e7)
|
||||
---
|
||||
libdm/mm/dbg_malloc.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libdm/mm/dbg_malloc.c b/libdm/mm/dbg_malloc.c
|
||||
index 96d2311d5..c6a9ae3ed 100644
|
||||
--- a/libdm/mm/dbg_malloc.c
|
||||
+++ b/libdm/mm/dbg_malloc.c
|
||||
@@ -212,7 +212,7 @@ void *dm_realloc_aux(void *p, unsigned int s, const char *file, int line)
|
||||
r = dm_malloc_aux_debug(s, file, line);
|
||||
|
||||
if (r && p) {
|
||||
- memcpy(r, p, mb->length);
|
||||
+ memcpy(r, p, (s < mb->length) ? s : mb->length);
|
||||
dm_free_aux(p);
|
||||
}
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
From 724efc360fb2f54611bbb56adfed56e0699de880 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 12:38:57 +0200
|
||||
Subject: [PATCH 067/211] libdevmapper-event: fix read() buffer overflow in
|
||||
_daemon_read
|
||||
|
||||
read() was called with full 'size' instead of remaining 'size - bytes',
|
||||
so after a partial read, it could write past the end of the buffer.
|
||||
|
||||
The server-side counterpart in dmeventd.c correctly uses 'size - bytes'.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 17ae34da124c96922b266ab7accdbcfdc11791b4)
|
||||
---
|
||||
daemons/dmeventd/libdevmapper-event.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/daemons/dmeventd/libdevmapper-event.c b/daemons/dmeventd/libdevmapper-event.c
|
||||
index 485f04605..36f119261 100644
|
||||
--- a/daemons/dmeventd/libdevmapper-event.c
|
||||
+++ b/daemons/dmeventd/libdevmapper-event.c
|
||||
@@ -249,7 +249,7 @@ static int _daemon_read(struct dm_event_fifos *fifos,
|
||||
goto bad;
|
||||
}
|
||||
|
||||
- ret = read(fifos->server, buf + bytes, size);
|
||||
+ ret = read(fifos->server, buf + bytes, size - bytes);
|
||||
if (ret < 0) {
|
||||
if ((errno == EINTR) || (errno == EAGAIN))
|
||||
continue;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
From b897d04990f31f299aab883d5055f9ca351dfe6a Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 13 Mar 2026 16:00:40 +0100
|
||||
Subject: [PATCH 068/211] dmsetup: fix dangling pointer in _slurp_stdin after
|
||||
realloc
|
||||
|
||||
After realloc() the buffer may move to a new address, but pos
|
||||
was not updated, causing read() to write into freed memory.
|
||||
Triggers EFAULT when stdin input exceeds ~128KB.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 130ddc48ea2a084852e78c232990ed8d58aaeca9)
|
||||
---
|
||||
libdm/dm-tools/dmsetup.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/libdm/dm-tools/dmsetup.c b/libdm/dm-tools/dmsetup.c
|
||||
index 2d6ed0a71..eb77ebce4 100644
|
||||
--- a/libdm/dm-tools/dmsetup.c
|
||||
+++ b/libdm/dm-tools/dmsetup.c
|
||||
@@ -1263,6 +1263,7 @@ static char *_slurp_stdin(void)
|
||||
return NULL;
|
||||
}
|
||||
buf = newbuf;
|
||||
+ pos = buf + total;
|
||||
}
|
||||
} while (1);
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
From 81b04fb6706d19fe9cc85cf7c7fbbe1e4a714b82 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 10:05:12 +0200
|
||||
Subject: [PATCH 069/211] export: fix out-of-bounds access in _sectors_to_units
|
||||
|
||||
The loop could increment i to DM_ARRAY_SIZE(_units) before
|
||||
exiting, causing out-of-bounds access on _units[i].
|
||||
However issue cannot be hit, since lvm2 supports only 8EiB.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 4f1a29639abaa3ee7fd095116627b65c83e369ab)
|
||||
---
|
||||
lib/format_text/export.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/format_text/export.c b/lib/format_text/export.c
|
||||
index ccc3167ca..5c120f145 100644
|
||||
--- a/lib/format_text/export.c
|
||||
+++ b/lib/format_text/export.c
|
||||
@@ -240,7 +240,7 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
|
||||
/* to convert to K */
|
||||
d /= 2.0;
|
||||
|
||||
- for (i = 0; (d > 1024.0) && i < DM_ARRAY_SIZE(_units); ++i)
|
||||
+ for (i = 0; (d > 1024.0) && i < DM_ARRAY_SIZE(_units) - 1; ++i)
|
||||
d /= 1024.0;
|
||||
|
||||
return dm_snprintf(buffer, s, "# %g %s", d, _units[i]) > 0;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
From b55144da93ab7a0dc8ba750afade39f4144f3f12 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 13:40:49 +0200
|
||||
Subject: [PATCH 070/211] id: fix out-of-bounds read in _id_valid with corrupt
|
||||
metadata
|
||||
|
||||
id->uuid is int8_t[], so a corrupt on-disk byte >= 0x80 becomes
|
||||
negative and indexes before the _inverse_c[256] array.
|
||||
Cast to unsigned char to keep the index within bounds.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 7966fa3369dcd5671deb732615dfe0fe5633477c)
|
||||
---
|
||||
lib/id/id.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/id/id.c b/lib/id/id.c
|
||||
index b52121cd9..5c386ce0f 100644
|
||||
--- a/lib/id/id.c
|
||||
+++ b/lib/id/id.c
|
||||
@@ -96,7 +96,9 @@ static int _id_valid(struct id *id, int e)
|
||||
_build_inverse();
|
||||
|
||||
for (i = 0; i < ID_LEN; i++)
|
||||
- if (!_inverse_c[id->uuid[i]]) {
|
||||
+ /* Cast to unsigned char: int8_t uuid with corrupt byte >= 0x80
|
||||
+ * would be negative and index before _inverse_c[] array. */
|
||||
+ if (!_inverse_c[(unsigned char)id->uuid[i]]) {
|
||||
if (e)
|
||||
log_error("UUID contains invalid character '%c'", id->uuid[i]);
|
||||
return 0;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
From b95b1d3fb1a0eb132dbef466305bd33f78186a19 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Tue, 24 Mar 2026 21:31:58 +0100
|
||||
Subject: [PATCH 071/211] clang: lvmcache: fix use-after-free in
|
||||
lvmcache_update_vg_from_read
|
||||
|
||||
_drop_vginfo() detaches info from vginfo->infos and then frees
|
||||
vginfo if the infos list becomes empty. The next line accesses
|
||||
vginfo->outdated_infos which is use-after-free when the last PV
|
||||
info was just removed.
|
||||
|
||||
Use _vginfo_detach_info() directly since we only need to unlink
|
||||
info from vginfo->infos without the conditional vginfo cleanup.
|
||||
|
||||
Found by clang scan-build.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 374ec4c76ed7ad596cf22f70fc8f447854c17e82)
|
||||
---
|
||||
lib/cache/lvmcache.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
|
||||
index 86d252e45..da9a55d09 100644
|
||||
--- a/lib/cache/lvmcache.c
|
||||
+++ b/lib/cache/lvmcache.c
|
||||
@@ -2318,7 +2318,7 @@ void lvmcache_update_vg_from_read(struct volume_group *vg, int *incorrect_pv_cla
|
||||
if (!_outdated_warning++)
|
||||
log_warn("See vgck --updatemetadata to clear outdated metadata.");
|
||||
|
||||
- _drop_vginfo(info, vginfo); /* remove from vginfo->infos */
|
||||
+ _vginfo_detach_info(info); /* remove from vginfo->infos */
|
||||
dm_list_add(&vginfo->outdated_infos, &info->list);
|
||||
}
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
40
0072-clang-lvmlockd-fix-use-after-free-in-res_process.patch
Normal file
40
0072-clang-lvmlockd-fix-use-after-free-in-res_process.patch
Normal file
@ -0,0 +1,40 @@
|
||||
From fae11decdb12d9da660748bb181063dde5200d1f Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Tue, 24 Mar 2026 21:31:49 +0100
|
||||
Subject: [PATCH 072/211] clang: lvmlockd: fix use-after-free in res_process
|
||||
|
||||
add_client_result() may call free_action(act) when LD_AF_NO_CLIENT
|
||||
flag is set. The subsequent access of act->op to check for
|
||||
LD_OP_DISABLE is then a use-after-free. Save the op value before
|
||||
passing act to add_client_result().
|
||||
|
||||
Found by clang scan-build.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 3095302e97b9c48f2df4296a449e5ee76580f103)
|
||||
---
|
||||
daemons/lvmlockd/lvmlockd-core.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/daemons/lvmlockd/lvmlockd-core.c b/daemons/lvmlockd/lvmlockd-core.c
|
||||
index f7340ff3e..b3960feb7 100644
|
||||
--- a/daemons/lvmlockd/lvmlockd-core.c
|
||||
+++ b/daemons/lvmlockd/lvmlockd-core.c
|
||||
@@ -1989,12 +1989,13 @@ static void res_process(struct lockspace *ls, struct resource *r,
|
||||
|
||||
list_for_each_entry_safe(act, safe, &r->actions, list) {
|
||||
if (act->op == LD_OP_ENABLE || act->op == LD_OP_DISABLE) {
|
||||
+ int is_disable = (act->op == LD_OP_DISABLE);
|
||||
rv = res_able(ls, r, act);
|
||||
act->result = rv;
|
||||
list_del(&act->list);
|
||||
add_client_result(act);
|
||||
|
||||
- if (!rv && act->op == LD_OP_DISABLE) {
|
||||
+ if (!rv && is_disable) {
|
||||
log_debug("%s:%s free disabled", ls->name, r->name);
|
||||
goto r_free;
|
||||
}
|
||||
--
|
||||
2.54.0
|
||||
|
||||
32
0073-cov-device_id-fix-NULL-dereference-in-_dev_has_id.patch
Normal file
32
0073-cov-device_id-fix-NULL-dereference-in-_dev_has_id.patch
Normal file
@ -0,0 +1,32 @@
|
||||
From 58d413836eab837f113dfd741c999719d9e3ca16 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Wed, 1 Apr 2026 20:33:27 +0200
|
||||
Subject: [PATCH 073/211] cov: device_id: fix NULL dereference in _dev_has_id
|
||||
|
||||
Add NULL check for idname parameter before strcmp() call.
|
||||
The function could crash when called with NULL idname from
|
||||
device_ids_check_serial() if du->idname was unexpectedly NULL.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 035d0bf5b8e044198f4233e42f3f8f9de011c297)
|
||||
---
|
||||
lib/device/device_id.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/lib/device/device_id.c b/lib/device/device_id.c
|
||||
index 4bb92cb09..6ec8f43ba 100644
|
||||
--- a/lib/device/device_id.c
|
||||
+++ b/lib/device/device_id.c
|
||||
@@ -1199,6 +1199,9 @@ static int _dev_has_id(struct device *dev, uint16_t idtype, const char *idname)
|
||||
{
|
||||
struct dev_id *id;
|
||||
|
||||
+ if (!idname)
|
||||
+ return 0;
|
||||
+
|
||||
dm_list_iterate_items(id, &dev->ids) {
|
||||
if (id->idtype != idtype)
|
||||
continue;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
From ec768d527e2f33f919d7482ae722cf837433cfd6 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 12:47:30 +0200
|
||||
Subject: [PATCH 074/211] dmeventd: snapshot: fix NULL target_type passed to
|
||||
log_error %s
|
||||
|
||||
When target_type is NULL, passing it to %s format is undefined behavior.
|
||||
Use ??? as fallback to still report actual target_type when available.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 057434a6dc5def17379725b8b9c25453b286f250)
|
||||
---
|
||||
daemons/dmeventd/plugins/snapshot/dmeventd_snapshot.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/daemons/dmeventd/plugins/snapshot/dmeventd_snapshot.c b/daemons/dmeventd/plugins/snapshot/dmeventd_snapshot.c
|
||||
index e47747c1a..40d197297 100644
|
||||
--- a/daemons/dmeventd/plugins/snapshot/dmeventd_snapshot.c
|
||||
+++ b/daemons/dmeventd/plugins/snapshot/dmeventd_snapshot.c
|
||||
@@ -183,7 +183,7 @@ void process_event(struct dm_task *dmt,
|
||||
|
||||
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
||||
if (!target_type || strcmp(target_type, "snapshot")) {
|
||||
- log_error("Target %s is not snapshot.", target_type);
|
||||
+ log_error("Target %s is not snapshot.", target_type ?: "???");
|
||||
return;
|
||||
}
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
From 58160a59cafb671695d4c1149b504640d7953ed9 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 12:23:53 +0200
|
||||
Subject: [PATCH 075/211] libdaemon: config-util: fix NULL dereference in error
|
||||
message
|
||||
|
||||
When fmt (from strchr) is NULL, the error message was printing
|
||||
fmt instead of next, passing NULL to printf %s.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 7458d4755e724ec49dcf9f0e36566f1e80d49f48)
|
||||
---
|
||||
libdaemon/client/config-util.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libdaemon/client/config-util.c b/libdaemon/client/config-util.c
|
||||
index b0813f176..ceefc06a4 100644
|
||||
--- a/libdaemon/client/config-util.c
|
||||
+++ b/libdaemon/client/config-util.c
|
||||
@@ -246,7 +246,7 @@ struct dm_config_node *config_make_nodes_v(struct dm_config_tree *cft,
|
||||
fmt = strchr(next, '=');
|
||||
|
||||
if (!fmt) {
|
||||
- log_error(INTERNAL_ERROR "Bad format string '%s'", fmt);
|
||||
+ log_error(INTERNAL_ERROR "Bad format string '%s'.", next);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,37 @@
|
||||
From 18a1e4c8f486eacde276de49a75241578865c9e8 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Tue, 24 Mar 2026 21:38:48 +0100
|
||||
Subject: [PATCH 076/211] clang: metadata: add NULL check for pva in
|
||||
_alloc_parallel_area
|
||||
|
||||
The allocator's gap-filling logic can leave alloc_state areas
|
||||
with NULL pva in certain edge cases. Add a defensive NULL check
|
||||
before dereferencing pva->map->pv to avoid a potential NULL
|
||||
pointer dereference.
|
||||
|
||||
Found by clang scan-build.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 52319437d50614f782640eb43a29d56d5af98eda)
|
||||
---
|
||||
lib/metadata/lv_manip.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
|
||||
index 7296f5e66..201836d73 100644
|
||||
--- a/lib/metadata/lv_manip.c
|
||||
+++ b/lib/metadata/lv_manip.c
|
||||
@@ -2151,6 +2151,10 @@ static int _alloc_parallel_area(struct alloc_handle *ah, uint32_t max_to_allocat
|
||||
}
|
||||
|
||||
pva = alloc_state->areas[s + ix_log_skip].pva;
|
||||
+ if (!pva) {
|
||||
+ log_error("Missing PV area for parallel allocation.");
|
||||
+ return 0;
|
||||
+ }
|
||||
if (ah->alloc_and_split_meta && !ah->split_metadata_is_allocated) {
|
||||
/*
|
||||
* The metadata area goes at the front of the allocated
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,49 @@
|
||||
From f066ceec5967f7ac1000b707cee68adc4c7abb44 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Tue, 24 Mar 2026 21:32:21 +0100
|
||||
Subject: [PATCH 077/211] clang: libdm: fix dangling parent pointer to stack
|
||||
variable in config flatten
|
||||
|
||||
_override_path() uses a stack-local dummy node as the root anchor
|
||||
for _find_or_make_node(). When _make_node() creates a new top-level
|
||||
node, it sets node->parent = &dummy. After _override_path() returns,
|
||||
the dummy goes out of scope leaving a dangling parent pointer in
|
||||
the config tree returned by dm_config_flatten().
|
||||
|
||||
Clear the parent pointer for any top-level nodes that still
|
||||
reference the stack variable.
|
||||
|
||||
Found by clang scan-build.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 07572f306384bbc5604c0035f6297e7cd99e7b31)
|
||||
---
|
||||
libdm/libdm-config.c | 6 +++++-
|
||||
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libdm/libdm-config.c b/libdm/libdm-config.c
|
||||
index 0e8baea73..25cfa268c 100644
|
||||
--- a/libdm/libdm-config.c
|
||||
+++ b/libdm/libdm-config.c
|
||||
@@ -1510,13 +1510,17 @@ struct dm_pool *dm_config_memory(struct dm_config_tree *cft)
|
||||
static int _override_path(const char *path, struct dm_config_node *node, void *baton)
|
||||
{
|
||||
struct dm_config_tree *cft = baton;
|
||||
- struct dm_config_node dummy, *target;
|
||||
+ struct dm_config_node dummy, *target, *cn;
|
||||
dummy.child = cft->root;
|
||||
if (!(target = _find_or_make_node(cft->mem, &dummy, path, 0)))
|
||||
return_0;
|
||||
if (!(target->v = _clone_config_value(cft->mem, node->v)))
|
||||
return_0;
|
||||
cft->root = dummy.child;
|
||||
+ /* Clear dangling parent pointers to stack variable */
|
||||
+ for (cn = cft->root; cn; cn = cn->sib)
|
||||
+ if (cn->parent == &dummy)
|
||||
+ cn->parent = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
73
0078-parse_vpd-fix-VPD-descriptor-bounds-checking.patch
Normal file
73
0078-parse_vpd-fix-VPD-descriptor-bounds-checking.patch
Normal file
@ -0,0 +1,73 @@
|
||||
From ce1d80012d4237ea181747b78fe125164a889f3d Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Thu, 2 Apr 2026 00:03:37 +0200
|
||||
Subject: [PATCH 078/211] parse_vpd: fix VPD descriptor bounds checking
|
||||
|
||||
parse_vpd_ids had broken bounds checks in cases 0x1 (T10) and 0x8
|
||||
(SCSI name string) that compared cur_id_size against the output buffer
|
||||
size (id_len = 1024) instead of the VPD input buffer. Since cur_id_size
|
||||
is uint8_t (max 255 per VPD spec byte 3), those checks were always
|
||||
false (dead code), and the overflow assignments were flagged by Coverity.
|
||||
|
||||
The real risk is reading past vpd_datalen with malformed VPD data.
|
||||
|
||||
Fix by:
|
||||
- Tightening loop condition to d + 4 <= vpd_end so the 4-byte
|
||||
descriptor header is always readable
|
||||
- Clamping cur_id_size to available VPD bytes (vpd_end - d - 4)
|
||||
instead of output buffer size
|
||||
- Removing unused id_len variable
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 37ec8951e8881e906aa0b9dcd688bb71fe0d178a)
|
||||
---
|
||||
lib/device/parse_vpd.c | 12 ++++++------
|
||||
1 file changed, 6 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/lib/device/parse_vpd.c b/lib/device/parse_vpd.c
|
||||
index 16a653a14..b67e36763 100644
|
||||
--- a/lib/device/parse_vpd.c
|
||||
+++ b/lib/device/parse_vpd.c
|
||||
@@ -153,14 +153,14 @@ int parse_vpd_ids(const unsigned char *vpd_data, int vpd_datalen, struct dm_list
|
||||
char id[ID_BUFSIZE];
|
||||
unsigned char tmp_str[ID_BUFSIZE];
|
||||
const unsigned char *d, *cur_id_str;
|
||||
- size_t id_len = ID_BUFSIZE;
|
||||
+ const unsigned char *vpd_end = vpd_data + vpd_datalen;
|
||||
int id_size = -1;
|
||||
int type;
|
||||
uint8_t cur_id_size = 0;
|
||||
|
||||
memset(id, 0, ID_BUFSIZE);
|
||||
for (d = vpd_data + 4;
|
||||
- d < vpd_data + vpd_datalen;
|
||||
+ d + 4 <= vpd_end;
|
||||
d += d[3] + 4) {
|
||||
memset(tmp_str, 0, sizeof(tmp_str));
|
||||
|
||||
@@ -168,8 +168,8 @@ int parse_vpd_ids(const unsigned char *vpd_data, int vpd_datalen, struct dm_list
|
||||
case 0x1:
|
||||
/* T10 Vendor ID */
|
||||
cur_id_size = d[3];
|
||||
- if ((size_t)(cur_id_size + 4) > id_len)
|
||||
- cur_id_size = id_len - 4;
|
||||
+ if (d + 4 + cur_id_size > vpd_end)
|
||||
+ cur_id_size = vpd_end - d - 4;
|
||||
cur_id_str = d + 4;
|
||||
format_t10_id(cur_id_str, cur_id_size, tmp_str, sizeof(tmp_str));
|
||||
id_size = snprintf(id, ID_BUFSIZE, "t10.%s", tmp_str);
|
||||
@@ -230,9 +230,9 @@ int parse_vpd_ids(const unsigned char *vpd_data, int vpd_datalen, struct dm_list
|
||||
case 0x8:
|
||||
/* SCSI name string */
|
||||
cur_id_size = d[3];
|
||||
+ if (d + 4 + cur_id_size > vpd_end)
|
||||
+ cur_id_size = vpd_end - d - 4;
|
||||
cur_id_str = d + 4;
|
||||
- if (cur_id_size >= id_len)
|
||||
- cur_id_size = id_len - 1;
|
||||
memcpy(id, cur_id_str, cur_id_size);
|
||||
id_size = cur_id_size;
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
35
0079-cov-dev-ext-validate-src-bounds-in-dev_ext_enable.patch
Normal file
35
0079-cov-dev-ext-validate-src-bounds-in-dev_ext_enable.patch
Normal file
@ -0,0 +1,35 @@
|
||||
From 4341180f04be061e991fa40f215f000069c54243 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Wed, 1 Apr 2026 22:33:49 +0200
|
||||
Subject: [PATCH 079/211] cov: dev-ext: validate src bounds in dev_ext_enable
|
||||
|
||||
Check that src is within _ext_registry array bounds before
|
||||
using it as index. Prevents out of bounds access if src has
|
||||
an unexpected value.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 9cbc486bdc838612c7e3381bb8c198bede81ca77)
|
||||
---
|
||||
lib/device/dev-ext.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/lib/device/dev-ext.c b/lib/device/dev-ext.c
|
||||
index 8f0f519b5..8521b6e0b 100644
|
||||
--- a/lib/device/dev-ext.c
|
||||
+++ b/lib/device/dev-ext.c
|
||||
@@ -140,6 +140,12 @@ int dev_ext_release(struct device *dev)
|
||||
|
||||
int dev_ext_enable(struct device *dev, dev_ext_t src)
|
||||
{
|
||||
+ if (src >= DEV_EXT_NUM) {
|
||||
+ log_error(INTERNAL_ERROR "%s: Invalid external source [%d].",
|
||||
+ dev_name(dev), src);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
if (dev->ext.enabled && (dev->ext.src != src) && !dev_ext_release(dev)) {
|
||||
log_error("%s: Failed to enable external handle [%s].",
|
||||
dev_name(dev), _ext_registry[src].name);
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
From 5a9623ddea7094bb7fd3dc1124a495be9762bf67 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Wed, 1 Apr 2026 20:56:58 +0200
|
||||
Subject: [PATCH 080/211] cov: config: check for size overflow in
|
||||
config_file_read_fd
|
||||
|
||||
Add overflow check for size + size2 before buffer allocation.
|
||||
On 32-bit systems, the size_t addition could wrap, allocating
|
||||
a small buffer followed by a large read into it.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit f9dfc2223ccf94e3e9589d8249f48a658a214339)
|
||||
---
|
||||
lib/config/config.c | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/lib/config/config.c b/lib/config/config.c
|
||||
index 53d6fc9a0..9cc010e46 100644
|
||||
--- a/lib/config/config.c
|
||||
+++ b/lib/config/config.c
|
||||
@@ -513,6 +513,11 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
|
||||
|
||||
/* Ensure there is extra '\0' after end of buffer since we pass
|
||||
* buffer to functions like strtoll() */
|
||||
+ if (size + size2 < size) {
|
||||
+ log_error("Metadata buffer size overflow.");
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
if (!(buf = zalloc(size + size2 + 1))) {
|
||||
log_error("Failed to allocate circular buffer.");
|
||||
return 0;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,62 @@
|
||||
From 9eb047aa1742031f5999a8a1d22720dcd16dd432 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Wed, 1 Apr 2026 20:33:32 +0200
|
||||
Subject: [PATCH 081/211] cov: format_text: validate rlocn bounds before
|
||||
uint32_t cast
|
||||
|
||||
Validate rlocn offset and size fields against mda bounds before
|
||||
casting to uint32_t. The on-disk rlocn fields are uint64_t but
|
||||
wrap and size parameters are uint32_t, so crafted metadata with
|
||||
values exceeding UINT32_MAX would silently truncate, leading to
|
||||
incorrect buffer sizes.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit c42c285e1b7c062e9db736e8b8ad3646b477661a)
|
||||
---
|
||||
lib/format_text/format-text.c | 23 +++++++++++++++++++++++
|
||||
1 file changed, 23 insertions(+)
|
||||
|
||||
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
|
||||
index 615b92df9..3165312d7 100644
|
||||
--- a/lib/format_text/format-text.c
|
||||
+++ b/lib/format_text/format-text.c
|
||||
@@ -416,6 +416,17 @@ static struct volume_group *_vg_read_raw_area(struct cmd_context *cmd,
|
||||
goto out;
|
||||
}
|
||||
|
||||
+ /* Validate rlocn fields fit within mda bounds before uint32_t cast */
|
||||
+ if (rlocn->offset >= mdah->size ||
|
||||
+ rlocn->size > mdah->size - MDA_HEADER_SIZE) {
|
||||
+ log_error("Metadata location out of bounds (offset %llu size %llu mda %llu) on %s.",
|
||||
+ (unsigned long long)rlocn->offset,
|
||||
+ (unsigned long long)rlocn->size,
|
||||
+ (unsigned long long)mdah->size,
|
||||
+ dev_name(area->dev));
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
if (rlocn->offset + rlocn->size > mdah->size)
|
||||
wrap = (uint32_t) ((rlocn->offset + rlocn->size) - mdah->size);
|
||||
|
||||
@@ -1501,6 +1512,18 @@ int read_metadata_location_summary(const struct format_type *fmt,
|
||||
* at the beginning. The end of this wrapped metadata is located at an
|
||||
* offset of wrap+MDA_HEADER_SIZE from area.start.
|
||||
*/
|
||||
+
|
||||
+ /* Validate rlocn fields fit within mda bounds before uint32_t cast */
|
||||
+ if (rlocn->offset >= mdah->size ||
|
||||
+ rlocn->size > mdah->size - MDA_HEADER_SIZE) {
|
||||
+ log_warn("WARNING: Metadata location out of bounds (offset %llu size %llu mda %llu) on %s.",
|
||||
+ (unsigned long long)rlocn->offset,
|
||||
+ (unsigned long long)rlocn->size,
|
||||
+ (unsigned long long)mdah->size,
|
||||
+ dev_name(dev_area->dev));
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
if (rlocn->offset + rlocn->size > mdah->size)
|
||||
wrap = (uint32_t) ((rlocn->offset + rlocn->size) - mdah->size);
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
From aea719b00789152a2213f4791ac698836b2bd439 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 13:14:40 +0200
|
||||
Subject: [PATCH 082/211] label: clear DEV_IN_BCACHE on bcache_set_fd failure
|
||||
|
||||
When bcache_set_fd() fails, DEV_IN_BCACHE flag was left set while
|
||||
bcache_fd was reset to -1. This causes _in_bcache() to return true,
|
||||
making label_scan_open() skip the actual open.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit b69f9cc41a1f5b806cf1fc088876fa89cc14c0a2)
|
||||
---
|
||||
lib/label/label.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/lib/label/label.c b/lib/label/label.c
|
||||
index 91243494b..12a825c62 100644
|
||||
--- a/lib/label/label.c
|
||||
+++ b/lib/label/label.c
|
||||
@@ -563,6 +563,7 @@ static int _scan_dev_open(struct device *dev)
|
||||
if (close(fd))
|
||||
log_sys_debug("close", name);
|
||||
dev->bcache_fd = -1;
|
||||
+ dev->flags &= ~DEV_IN_BCACHE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
From c78d380024e6972dac5ea79aa2989cd2276c5c5a Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 21:28:49 +0200
|
||||
Subject: [PATCH 083/211] lv_manip: fix copy-paste error in thin pool metadata
|
||||
extend
|
||||
|
||||
Assigning poolmetadata_sign to lp_meta.size instead of lp_meta.sign,
|
||||
overwriting previously set size value.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit eea1ea49fb41352cf4f1fe59784dc08bc1669024)
|
||||
---
|
||||
lib/metadata/lv_manip.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
|
||||
index 201836d73..61816bd8c 100644
|
||||
--- a/lib/metadata/lv_manip.c
|
||||
+++ b/lib/metadata/lv_manip.c
|
||||
@@ -6803,7 +6803,7 @@ int lv_resize(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
_setup_params_for_extend_metadata(lv_meta, &lp_meta);
|
||||
if (lp->poolmetadata_size) {
|
||||
lp_meta.size = lp->poolmetadata_size;
|
||||
- lp_meta.size = lp->poolmetadata_sign;
|
||||
+ lp_meta.sign = lp->poolmetadata_sign;
|
||||
lp->poolmetadata_size = 0;
|
||||
lp->poolmetadata_sign = SIGN_NONE;
|
||||
}
|
||||
--
|
||||
2.54.0
|
||||
|
||||
36
0084-activate-fix-cachevol-cmeta-cdata-device-offsets.patch
Normal file
36
0084-activate-fix-cachevol-cmeta-cdata-device-offsets.patch
Normal file
@ -0,0 +1,36 @@
|
||||
From d84d1cb3056afa25792e332fa813012760958c62 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Wed, 4 Feb 2026 15:32:27 +0100
|
||||
Subject: [PATCH 084/211] activate: fix cachevol cmeta/cdata device offsets
|
||||
|
||||
Use actual metadata_start and data_start offsets when creating the
|
||||
cmeta and cdata linear devices for cachevol, instead of assuming
|
||||
metadata always starts at 0 and data at metadata_len.
|
||||
|
||||
This allows for flexible cachevol layouts as specified in metadata.
|
||||
|
||||
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
|
||||
(cherry picked from commit cd2f25ee0deb40161a17c7e5f427e237a0bda7bb)
|
||||
---
|
||||
lib/activate/dev_manager.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c
|
||||
index 8caa9f997..db3b24595 100644
|
||||
--- a/lib/activate/dev_manager.c
|
||||
+++ b/lib/activate/dev_manager.c
|
||||
@@ -3459,9 +3459,9 @@ static int _add_new_cvol_subdev_to_dtree(struct dev_manager *dm,
|
||||
if (!(dlid_pool = build_dm_uuid(dm->mem, pool_lv, NULL)))
|
||||
return_0;
|
||||
|
||||
- /* add seg_area to prev load_seg: offset 0 maps to cachevol lv offset 0 */
|
||||
+ /* add seg_area to prev load_seg: map to correct offset in cachevol */
|
||||
if (!dm_tree_node_add_target_area(dnode, NULL, dlid_pool,
|
||||
- meta_or_data ? 0 : lvseg->metadata_len))
|
||||
+ meta_or_data ? lvseg->metadata_start : lvseg->data_start))
|
||||
return_0;
|
||||
}
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
From 50740fb435f1cab88363bf3dc38a331a68dc8934 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 08:39:38 +0200
|
||||
Subject: [PATCH 085/211] merge: fix wrong variable in mirror size check
|
||||
log_error
|
||||
|
||||
The error message was printing area index 's' as the segment number.
|
||||
Use seg_count for the segment number and add 's' for the image index,
|
||||
matching the format used by the adjacent mirror pointer check message.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit fcae4db4074d6d9c7d059759a2a04596ba06801a)
|
||||
---
|
||||
lib/metadata/merge.c | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/lib/metadata/merge.c b/lib/metadata/merge.c
|
||||
index b2829f9d0..2cb9b4c08 100644
|
||||
--- a/lib/metadata/merge.c
|
||||
+++ b/lib/metadata/merge.c
|
||||
@@ -639,9 +639,10 @@ int check_lv_segments_complete_vg(struct logical_volume *lv)
|
||||
if (seg_is_mirrored(seg) && !seg_is_raid(seg) &&
|
||||
seg_type(seg, s) == AREA_LV && seg_lv(seg, s) &&
|
||||
seg_lv(seg, s)->le_count != seg->area_len) {
|
||||
- log_error("LV %s: mirrored LV segment %u has "
|
||||
+ log_error("LV %s: segment %u mirrored image %u has "
|
||||
"wrong size %u (should be %u).",
|
||||
- lv->name, s, seg_lv(seg, s)->le_count,
|
||||
+ lv->name, seg_count, s,
|
||||
+ seg_lv(seg, s)->le_count,
|
||||
seg->area_len);
|
||||
inc_error_count;
|
||||
}
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
From 7b4579ac06e2debcd889666723f39bd0de800766 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 10:24:46 +0200
|
||||
Subject: [PATCH 086/211] dev_manager: fix wrong sizeof in raid status
|
||||
allocation
|
||||
|
||||
Copy-paste error: sizeof(struct lv_status_cache) was used instead
|
||||
of sizeof(struct lv_status_raid) in dev_manager_raid_status.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 591d822bf496133a68bdd2ee98fdb4093199144a)
|
||||
---
|
||||
lib/activate/dev_manager.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c
|
||||
index db3b24595..46c626de5 100644
|
||||
--- a/lib/activate/dev_manager.c
|
||||
+++ b/lib/activate/dev_manager.c
|
||||
@@ -1664,7 +1664,7 @@ int dev_manager_raid_status(struct dev_manager *dm,
|
||||
struct dm_status_raid *sr;
|
||||
|
||||
*exists = -1;
|
||||
- if (!(*status = dm_pool_zalloc(dm->mem, sizeof(struct lv_status_cache))))
|
||||
+ if (!(*status = dm_pool_zalloc(dm->mem, sizeof(struct lv_status_raid))))
|
||||
return_0;
|
||||
|
||||
if (!(dlid = build_dm_uuid(dm->mem, lv, layer)))
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
From 3c3f8eac835e42ee6802e7e66bc059b91995ae50 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 14:34:04 +0200
|
||||
Subject: [PATCH 087/211] cov: thin: fix wrong variable in chunk_size error
|
||||
message
|
||||
|
||||
The error validates seg->chunk_size but printed seg->device_id.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 32d6cb664a38fb66fa361e385fc09812d9459b16)
|
||||
---
|
||||
lib/thin/thin.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/thin/thin.c b/lib/thin/thin.c
|
||||
index c9b40f635..85a90db38 100644
|
||||
--- a/lib/thin/thin.c
|
||||
+++ b/lib/thin/thin.c
|
||||
@@ -123,7 +123,7 @@ static int _thin_pool_text_import(struct lv_segment *seg,
|
||||
if ((seg->chunk_size < DM_THIN_MIN_DATA_BLOCK_SIZE) ||
|
||||
(seg->chunk_size > DM_THIN_MAX_DATA_BLOCK_SIZE))
|
||||
return SEG_LOG_ERROR("Unsupported value %u for chunk_size",
|
||||
- seg->device_id);
|
||||
+ seg->chunk_size);
|
||||
|
||||
if (dm_config_has_node(sn, "zero_new_blocks") &&
|
||||
!dm_config_get_uint32(sn, "zero_new_blocks", &zero))
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
From cc43f53099abafce472746deba9015a9f9db4373 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 08:40:26 +0200
|
||||
Subject: [PATCH 088/211] vdo_manip: fix missing si.mem_unit in total memory
|
||||
calculation
|
||||
|
||||
_get_sysinfo_memory() was computing total_mb without multiplying by
|
||||
si.mem_unit, unlike the available_mb calculation on the line above.
|
||||
When si.mem_unit != 1 (e.g. on 32-bit systems) this gave a wrong
|
||||
total memory value.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit ff30ca50aca84903c802a44db8e39aa13993aeaf)
|
||||
---
|
||||
lib/metadata/vdo_manip.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/metadata/vdo_manip.c b/lib/metadata/vdo_manip.c
|
||||
index 21084468f..f5d04918b 100644
|
||||
--- a/lib/metadata/vdo_manip.c
|
||||
+++ b/lib/metadata/vdo_manip.c
|
||||
@@ -651,7 +651,7 @@ static int _get_sysinfo_memory(uint64_t *total_mb, uint64_t *available_mb)
|
||||
(unsigned long long)si.freehigh >> 20, si.mem_unit);
|
||||
|
||||
*available_mb = ((uint64_t)(si.freeram + si.bufferram) * si.mem_unit) >> 30;
|
||||
- *total_mb = si.totalram >> 30;
|
||||
+ *total_mb = ((uint64_t) si.totalram * si.mem_unit) >> 30;
|
||||
|
||||
return 1;
|
||||
}
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
From 64029cb552f1b65bad1b2385bdbbfd7a63d6082c Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 12:45:03 +0200
|
||||
Subject: [PATCH 089/211] dmeventd: vdo: fix name overwrite and missing
|
||||
max_fails init
|
||||
|
||||
Fix two bugs in VDO plugin register_device():
|
||||
|
||||
1. 'state->name = "volume"' was unconditionally overwritten by
|
||||
'state->name = name' (where name="pool"). Fix by setting the
|
||||
local 'name' variable instead of state->name directly.
|
||||
|
||||
2. Missing 'state->max_fails = 1' initialization. Since state is
|
||||
zero-allocated, max_fails starts at 0 and the exponential backoff
|
||||
logic (which uses left-shift) never advances: 0 << 1 = 0.
|
||||
This causes failing policy commands to retry on every single event
|
||||
instead of backing off. Match the thin plugin which correctly
|
||||
initializes max_fails to 1.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 1d9edbfd6d3a1ad5da0a93765350407717436461)
|
||||
---
|
||||
daemons/dmeventd/plugins/vdo/dmeventd_vdo.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/daemons/dmeventd/plugins/vdo/dmeventd_vdo.c b/daemons/dmeventd/plugins/vdo/dmeventd_vdo.c
|
||||
index 093e71908..536870a16 100644
|
||||
--- a/daemons/dmeventd/plugins/vdo/dmeventd_vdo.c
|
||||
+++ b/daemons/dmeventd/plugins/vdo/dmeventd_vdo.c
|
||||
@@ -353,10 +353,11 @@ int register_device(const char *device,
|
||||
state->argv[1] = str + 1; /* 1 argument - vg/lv */
|
||||
_init_thread_signals(state);
|
||||
} else if (cmd[0] == 0) {
|
||||
- state->name = "volume"; /* What to use with 'others?' */
|
||||
+ name = "volume"; /* What to use with 'others?' */
|
||||
} else/* Unsupported command format */
|
||||
goto inval;
|
||||
|
||||
+ state->max_fails = 1;
|
||||
state->pid = -1;
|
||||
state->name = name;
|
||||
*user = state;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
From 4eb6ecf8f54b60f12c181a590e0eb32c19a4cd9b Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 12:54:24 +0200
|
||||
Subject: [PATCH 090/211] lvmlockd-dlm: fix wrong variable in fopen and error
|
||||
log
|
||||
|
||||
1. get_local_nodeid() constructed per-entry path in 'path' but opened
|
||||
'ls_comms_path' (the parent directory) instead, making local node ID
|
||||
detection non-functional.
|
||||
|
||||
2. read_cluster_name() logged fd (file descriptor) instead of rv
|
||||
(the read error) on read failure.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 4aa202dbe28fd2df9dc235a651cd7001b2904afb)
|
||||
---
|
||||
daemons/lvmlockd/lvmlockd-dlm.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/daemons/lvmlockd/lvmlockd-dlm.c b/daemons/lvmlockd/lvmlockd-dlm.c
|
||||
index 7529ad327..ec3a3b3c5 100644
|
||||
--- a/daemons/lvmlockd/lvmlockd-dlm.c
|
||||
+++ b/daemons/lvmlockd/lvmlockd-dlm.c
|
||||
@@ -113,7 +113,7 @@ static int read_cluster_name(char *clustername)
|
||||
|
||||
rv = read(fd, clustername, MAX_ARGS);
|
||||
if (rv < 0) {
|
||||
- log_error("read_cluster_name: cluster name read error %d, check dlm_controld", fd);
|
||||
+ log_error("read_cluster_name: cluster name read error %d, check dlm_controld", rv);
|
||||
goto out;
|
||||
}
|
||||
clustername[rv] = 0;
|
||||
@@ -247,7 +247,7 @@ static int get_local_nodeid(void)
|
||||
snprintf(path, sizeof(path), "%s/%s/local",
|
||||
DLM_COMMS_PATH, de->d_name);
|
||||
|
||||
- if (!(file = fopen(ls_comms_path, "r")))
|
||||
+ if (!(file = fopen(path, "r")))
|
||||
continue;
|
||||
str1 = fgets(line, sizeof(line), file);
|
||||
if (fclose(file))
|
||||
--
|
||||
2.54.0
|
||||
|
||||
30
0091-lvmlockd-sanlock-fix-wrong-variable-in-error-log.patch
Normal file
30
0091-lvmlockd-sanlock-fix-wrong-variable-in-error-log.patch
Normal file
@ -0,0 +1,30 @@
|
||||
From 22fd8e58f06adfdd212ec3c0d40ade2c274588a5 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 12:55:45 +0200
|
||||
Subject: [PATCH 091/211] lvmlockd-sanlock: fix wrong variable in error log
|
||||
|
||||
Error message printed rv (error code) twice instead of the offset value.
|
||||
The success path two lines above correctly uses offset.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 975b7886a17004fb5dcf0baf1c35848d1a57cbc8)
|
||||
---
|
||||
daemons/lvmlockd/lvmlockd-sanlock.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/daemons/lvmlockd/lvmlockd-sanlock.c b/daemons/lvmlockd/lvmlockd-sanlock.c
|
||||
index f06af6c60..2a5720b07 100644
|
||||
--- a/daemons/lvmlockd/lvmlockd-sanlock.c
|
||||
+++ b/daemons/lvmlockd/lvmlockd-sanlock.c
|
||||
@@ -1004,7 +1004,7 @@ int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char
|
||||
lock_args_version, (unsigned long long)offset);
|
||||
} else {
|
||||
log_error("S %s init_lv_san write error %d offset %llu",
|
||||
- ls_name, rv, (unsigned long long)rv);
|
||||
+ ls_name, rv, (unsigned long long)offset);
|
||||
}
|
||||
break;
|
||||
}
|
||||
--
|
||||
2.54.0
|
||||
|
||||
34
0092-daemon-client-fix-swapped-parameters-in-log_debug.patch
Normal file
34
0092-daemon-client-fix-swapped-parameters-in-log_debug.patch
Normal file
@ -0,0 +1,34 @@
|
||||
From d324d870e7409d2c3a84b26b37c13b60dd331869 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 20:32:03 +0200
|
||||
Subject: [PATCH 092/211] daemon-client: fix swapped parameters in log_debug
|
||||
|
||||
Line 31-32: Fixed swapped parameters in debug message. The format
|
||||
string suggests "%s: Opening daemon socket to %s" where the first %s
|
||||
is the daemon name and the second %s is the socket path. The arguments
|
||||
were swapped (i.socket, i.path) when they should be (i.path, i.socket)
|
||||
according to the daemon_info struct definition where path is the daemon
|
||||
binary and socket is the socket path.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit a47d90285a1172f37a713ab0969d4c8b87c314e6)
|
||||
---
|
||||
libdaemon/client/daemon-client.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libdaemon/client/daemon-client.c b/libdaemon/client/daemon-client.c
|
||||
index 9ee88fa69..14edee63e 100644
|
||||
--- a/libdaemon/client/daemon-client.c
|
||||
+++ b/libdaemon/client/daemon-client.c
|
||||
@@ -28,7 +28,7 @@ daemon_handle daemon_open(daemon_info i)
|
||||
struct sockaddr_un sockaddr = { .sun_family = AF_UNIX };
|
||||
|
||||
log_debug("%s: Opening daemon socket to %s for protocol %s version %d.",
|
||||
- i.socket, i.path, i.protocol, i.protocol_version);
|
||||
+ i.path, i.socket, i.protocol, i.protocol_version);
|
||||
|
||||
if ((h.socket_fd = socket(PF_UNIX, SOCK_STREAM /* | SOCK_NONBLOCK */, 0)) < 0) {
|
||||
h.error = errno;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,47 @@
|
||||
From 8e1bfa318078918b98dd16db253518c620df73e9 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 19:14:42 +0200
|
||||
Subject: [PATCH 093/211] raid_manip: fix swapped parameters in error message
|
||||
|
||||
Fix swapped parameters in error message after match_count decrement.
|
||||
|
||||
The execution flow is:
|
||||
1. Try to allocate match_count devices -> FAILS
|
||||
2. Decrement match_count--
|
||||
3. Log error message
|
||||
4. Retry with reduced count
|
||||
|
||||
Before the decrement, match_count had the value that just failed.
|
||||
After the decrement, match_count has the new reduced value we'll retry.
|
||||
|
||||
The message should say:
|
||||
"Failed to replace X (the old value). Attempting Y (the new value)."
|
||||
|
||||
Current code incorrectly prints:
|
||||
"Failed to replace 5 devices. Attempting to replace 6 instead."
|
||||
|
||||
Fixed code correctly prints:
|
||||
"Failed to replace 6 devices. Attempting to replace 5 instead."
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit cde1ea1ff15a5e1f80f55229f8b4b23f209157ea)
|
||||
---
|
||||
lib/metadata/raid_manip.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c
|
||||
index 2a78a0bec..99c71e967 100644
|
||||
--- a/lib/metadata/raid_manip.c
|
||||
+++ b/lib/metadata/raid_manip.c
|
||||
@@ -6995,7 +6995,7 @@ try_again:
|
||||
if (match_count > 0) {
|
||||
log_error("Failed to replace %u devices."
|
||||
" Attempting to replace %u instead.",
|
||||
- match_count, match_count+1);
|
||||
+ match_count+1, match_count);
|
||||
/*
|
||||
* Since we are replacing some but not all of the bad
|
||||
* devices, we must set partial_activation
|
||||
--
|
||||
2.54.0
|
||||
|
||||
30
0094-cov-memlock-fix-open-return-value-check.patch
Normal file
30
0094-cov-memlock-fix-open-return-value-check.patch
Normal file
@ -0,0 +1,30 @@
|
||||
From 1ada320659c8c1879cecae817853b643e31b071a Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 14:24:49 +0200
|
||||
Subject: [PATCH 094/211] cov: memlock: fix open() return value check
|
||||
|
||||
open() returns -1 on error and 0 is a valid file descriptor.
|
||||
Using !() would incorrectly treat fd 0 as failure.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 4c64e5b70ab9803f60ce2110c7f05367f98c3de9)
|
||||
---
|
||||
lib/mm/memlock.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/mm/memlock.c b/lib/mm/memlock.c
|
||||
index 8b45f10ee..0e43bf624 100644
|
||||
--- a/lib/mm/memlock.c
|
||||
+++ b/lib/mm/memlock.c
|
||||
@@ -551,7 +551,7 @@ static void _lock_mem(struct cmd_context *cmd)
|
||||
return;
|
||||
}
|
||||
|
||||
- if (!(_maps_fd = open(_procselfmaps, O_RDONLY))) {
|
||||
+ if ((_maps_fd = open(_procselfmaps, O_RDONLY)) < 0) {
|
||||
log_sys_debug("open", _procselfmaps);
|
||||
return;
|
||||
}
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
From 80326bcb7fa8638fd14ce8900a30e59b9c9dc2f4 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 13:32:46 +0200
|
||||
Subject: [PATCH 095/211] filesystem: fix nofs early-return checking wrong
|
||||
struct
|
||||
|
||||
fs_get_info() checked fsi->nofs (caller's zeroed output parameter)
|
||||
instead of info.nofs (the local struct populated by fs_get_blkid).
|
||||
The early-return for no-filesystem case never triggered, causing
|
||||
unnecessary crypto_LUKS, mount, and resize checks.
|
||||
|
||||
Result was still correct because *fsi = info copy at line 342
|
||||
propagated nofs to the caller, but the early exit was dead code.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 3606b9749042fb02117bebb0ba84f4e95ebeef57)
|
||||
---
|
||||
lib/device/filesystem.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/device/filesystem.c b/lib/device/filesystem.c
|
||||
index adb8f0174..87f97130d 100644
|
||||
--- a/lib/device/filesystem.c
|
||||
+++ b/lib/device/filesystem.c
|
||||
@@ -284,8 +284,10 @@ int fs_get_info(struct cmd_context *cmd, struct logical_volume *lv, struct fs_in
|
||||
return 0;
|
||||
}
|
||||
|
||||
- if (fsi->nofs)
|
||||
+ if (info.nofs) {
|
||||
+ fsi->nofs = 1;
|
||||
return 1;
|
||||
+ }
|
||||
|
||||
/*
|
||||
* If there's a LUKS dm-crypt layer over the LV, then
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,43 @@
|
||||
From cb232e39db78f5a11a8aefd6502ffd394c90eed9 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 11:08:44 +0200
|
||||
Subject: [PATCH 096/211] lvconvert: fix inverted proc_dir check and wrong
|
||||
sizeof
|
||||
|
||||
Fix two bugs:
|
||||
- The proc_dir emptiness check was inverted, skipping /proc/meminfo
|
||||
reading when proc_dir was available instead of when it was empty.
|
||||
- memset used sizeof(cvname) instead of sizeof(format) to clear the
|
||||
format buffer.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 54ec1fefa043522e4d04152998b3d66a059defe2)
|
||||
---
|
||||
tools/lvconvert.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
|
||||
index 270bae7d0..7a17028e5 100644
|
||||
--- a/tools/lvconvert.c
|
||||
+++ b/tools/lvconvert.c
|
||||
@@ -4538,7 +4538,7 @@ static int _lv_create_cachevol(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
if (find_lv(vg, cvname)) {
|
||||
- memset(format, 0, sizeof(cvname));
|
||||
+ memset(format, 0, sizeof(format));
|
||||
memset(cvname, 0, sizeof(cvname));
|
||||
if (dm_snprintf(format, sizeof(format), "%s_cache%%d", lv->name) < 0) {
|
||||
log_error("Failed to generate cachevol LV format.");
|
||||
@@ -6236,7 +6236,7 @@ static int _check_writecache_memory(struct cmd_context *cmd, struct logical_volu
|
||||
unsigned long long proc_mem_kb = 0;
|
||||
char proc_meminfo[PATH_MAX];
|
||||
|
||||
- if (*cmd->proc_dir)
|
||||
+ if (!*cmd->proc_dir)
|
||||
goto skip_proc;
|
||||
|
||||
if (dm_snprintf(proc_meminfo, sizeof(proc_meminfo),
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
From 437fa65fa0438d92c44e9ee647d1cee6cfdf416d Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 12:55:14 +0200
|
||||
Subject: [PATCH 097/211] lvmlockd-idm: fix stale rv check and missing & in
|
||||
convert
|
||||
|
||||
1. lm_lock_idm() checked stale 'rv' instead of 'rdi->op.mode' after
|
||||
to_idm_mode(), so invalid lock modes were never caught.
|
||||
|
||||
2. lm_convert_idm() passed vb_timestamp value as pointer (missing &),
|
||||
causing ilm_write_lvb() to read from an arbitrary address.
|
||||
The correct pattern with & is used in lm_unlock_idm().
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 0a04cb3d1f1cf377c1f49453d90381ca25857957)
|
||||
---
|
||||
daemons/lvmlockd/lvmlockd-idm.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/daemons/lvmlockd/lvmlockd-idm.c b/daemons/lvmlockd/lvmlockd-idm.c
|
||||
index bfba4f59b..92c7e56ab 100644
|
||||
--- a/daemons/lvmlockd/lvmlockd-idm.c
|
||||
+++ b/daemons/lvmlockd/lvmlockd-idm.c
|
||||
@@ -547,7 +547,7 @@ int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
}
|
||||
|
||||
rdi->op.mode = to_idm_mode(ld_mode);
|
||||
- if (rv < 0) {
|
||||
+ if (rdi->op.mode < 0) {
|
||||
log_error("lock_idm invalid mode %d", ld_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -725,7 +725,7 @@ int lm_convert_idm(struct lockspace *ls, struct resource *r,
|
||||
|
||||
if (rdi->vb && r_version && (r->mode == LD_LK_EX)) {
|
||||
rv = ilm_write_lvb(lmi->sock, &rdi->id,
|
||||
- (char *)rdi->vb_timestamp, sizeof(uint64_t));
|
||||
+ (char *)&rdi->vb_timestamp, sizeof(uint64_t));
|
||||
if (rv < 0) {
|
||||
log_error("S %s R %s convert_idm write lvb error %d",
|
||||
ls->name, r->name, rv);
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
From 6bbf2f55027d9a4db50572c514fb6a37cd988431 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 14:37:02 +0200
|
||||
Subject: [PATCH 098/211] cov: lv: fix off-by-one in
|
||||
_sublvs_remove_after_reshape
|
||||
|
||||
The backward loop 'for (s = area_count-1; s; s--)' never checked
|
||||
area index 0. While area 0 is unlikely to be marked for removal
|
||||
after reshape, use a standard forward loop for clarity.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit ba2fef12d6351347e0bd2ab6cef950d47617a727)
|
||||
---
|
||||
lib/metadata/lv.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c
|
||||
index 2ecc4cf4e..c7b213067 100644
|
||||
--- a/lib/metadata/lv.c
|
||||
+++ b/lib/metadata/lv.c
|
||||
@@ -1296,7 +1296,7 @@ static int _sublvs_remove_after_reshape(const struct logical_volume *lv)
|
||||
uint32_t s;
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
|
||||
- for (s = seg->area_count -1; s; s--)
|
||||
+ for (s = 0; s < seg->area_count; s++)
|
||||
if (seg_lv(seg, s)->status & LV_REMOVE_AFTER_RESHAPE)
|
||||
return 1;
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
38
0099-hints-fix-off-by-one-in-orphan-vgname-check.patch
Normal file
38
0099-hints-fix-off-by-one-in-orphan-vgname-check.patch
Normal file
@ -0,0 +1,38 @@
|
||||
From 7fd9d29a454797512bbd18b6d560813d34a1df25 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 13:17:30 +0200
|
||||
Subject: [PATCH 099/211] hints: fix off-by-one in orphan vgname check
|
||||
|
||||
Hint file lines have format: scan:/dev/sda pvid:xxx devn:8:0 vg:NAME
|
||||
For orphan PVs (no VG) it writes "vg:-".
|
||||
|
||||
The "vg:" prefix is 3 characters, so vgname[3] is the first char of
|
||||
the actual VG name. The orphan check used vgname[4] instead of
|
||||
vgname[3], so for "vg:-" it checked '\0' != '-' which is true,
|
||||
letting the orphan name "-" through into hint.vgname.
|
||||
|
||||
Currently masked by a downstream check (hint->vgname[0] == '-')
|
||||
that independently filters orphan hints.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 3201a6fa88595b2abbec00049ce6826cda7175b5)
|
||||
---
|
||||
lib/label/hints.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/label/hints.c b/lib/label/hints.c
|
||||
index de36da504..43103b440 100644
|
||||
--- a/lib/label/hints.c
|
||||
+++ b/lib/label/hints.c
|
||||
@@ -846,7 +846,7 @@ static int _read_hint_file(struct cmd_context *cmd, struct dm_list *hints, int *
|
||||
if (devn && sscanf(devn, "devn:%d:%d", &major, &minor) == 2)
|
||||
hint.devt = makedev(major, minor);
|
||||
|
||||
- if (vgname && (strlen(vgname) > 3) && (vgname[4] != '-'))
|
||||
+ if (vgname && (strlen(vgname) > 3) && (vgname[3] != '-'))
|
||||
if (!_dm_strncpy(hint.vgname, vgname + 3, sizeof(hint.vgname)))
|
||||
continue;
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,47 @@
|
||||
From d74e3b3f8b3b57cb1c12642fc4a317dd0e075a19 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 12:27:33 +0200
|
||||
Subject: [PATCH 100/211] lvmpolld: fix comma typo and off-by-one in timeout
|
||||
check
|
||||
|
||||
- lvmpolld-data-utils.c: comma instead of semicolon after
|
||||
_get_lvid assignment (worked by accident as comma expression)
|
||||
- lvmpolld-core.c: use > UINT_MAX instead of >= UINT_MAX
|
||||
in timeout argument parser
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 2869bd746d57929b099d67c1b17cbcaabc3da5f8)
|
||||
---
|
||||
daemons/lvmpolld/lvmpolld-core.c | 2 +-
|
||||
daemons/lvmpolld/lvmpolld-data-utils.c | 2 +-
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/daemons/lvmpolld/lvmpolld-core.c b/daemons/lvmpolld/lvmpolld-core.c
|
||||
index 7ab0db8b4..ff47e1fbc 100644
|
||||
--- a/daemons/lvmpolld/lvmpolld-core.c
|
||||
+++ b/daemons/lvmpolld/lvmpolld-core.c
|
||||
@@ -771,7 +771,7 @@ static int process_timeout_arg(const char *str, unsigned *max_timeouts)
|
||||
|
||||
errno = 0;
|
||||
l = strtoul(str, &endptr, 10);
|
||||
- if (errno || *endptr || l >= UINT_MAX)
|
||||
+ if (errno || *endptr || l > UINT_MAX)
|
||||
return 0;
|
||||
|
||||
*max_timeouts = (unsigned) l;
|
||||
diff --git a/daemons/lvmpolld/lvmpolld-data-utils.c b/daemons/lvmpolld/lvmpolld-data-utils.c
|
||||
index 2520becbe..8a4c6f8b0 100644
|
||||
--- a/daemons/lvmpolld/lvmpolld-data-utils.c
|
||||
+++ b/daemons/lvmpolld/lvmpolld-data-utils.c
|
||||
@@ -124,7 +124,7 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
|
||||
if (!pdlv || !tmp.lvmpolld_id || !tmp.lvname || !tmp.lvm_system_dir_env || !tmp.sinterval)
|
||||
goto err;
|
||||
|
||||
- tmp.lvid = _get_lvid(tmp.lvmpolld_id, sysdir),
|
||||
+ tmp.lvid = _get_lvid(tmp.lvmpolld_id, sysdir);
|
||||
|
||||
*pdlv = tmp;
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
From 8c0234432df5df88076b487a249ccc8c067171c1 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Sat, 21 Mar 2026 23:46:44 +0100
|
||||
Subject: [PATCH 101/211] pvmove_poll: fix off-by-one in mirror image bounds
|
||||
check
|
||||
|
||||
_is_pvmove_image_removable uses > instead of >= to validate
|
||||
mimage_to_remove against area_count. Since area indices are
|
||||
0-based, index == area_count is out of bounds and would cause
|
||||
seg_lv to access past the areas array.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 9dd36a05c11f9fec8f5896a77b626a4a19fac9d0)
|
||||
---
|
||||
tools/pvmove_poll.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tools/pvmove_poll.c b/tools/pvmove_poll.c
|
||||
index 58687ebdc..65e242ae9 100644
|
||||
--- a/tools/pvmove_poll.c
|
||||
+++ b/tools/pvmove_poll.c
|
||||
@@ -35,7 +35,7 @@ static int _is_pvmove_image_removable(struct logical_volume *mimage_lv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
- if (mimage_to_remove > mirror_seg->area_count) {
|
||||
+ if (mimage_to_remove >= mirror_seg->area_count) {
|
||||
log_error(INTERNAL_ERROR "Mirror image %" PRIu32 " not found in segment",
|
||||
mimage_to_remove);
|
||||
return 0;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
31
0102-pvck-fix-copy-paste-error-checking-mda2_size_set.patch
Normal file
31
0102-pvck-fix-copy-paste-error-checking-mda2_size_set.patch
Normal file
@ -0,0 +1,31 @@
|
||||
From 142ce4f7bb4e0d2d1f62aa24fdfb27c7d0153ecf Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 11:06:50 +0200
|
||||
Subject: [PATCH 102/211] pvck: fix copy-paste error checking mda2_size_set
|
||||
|
||||
The condition was checking set->mda_size_set instead of
|
||||
set->mda2_size_set in the mda2 settings block, making
|
||||
the mda2 size setting ignored.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit b3e913dcecfe9fe2d745546464efb1a88123a217)
|
||||
---
|
||||
tools/pvck.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tools/pvck.c b/tools/pvck.c
|
||||
index 8c7bbc92f..3be469562 100644
|
||||
--- a/tools/pvck.c
|
||||
+++ b/tools/pvck.c
|
||||
@@ -1631,7 +1631,7 @@ static int _dump_search(struct cmd_context *cmd, const char *dump, struct settin
|
||||
mda_offset = set->mda2_offset;
|
||||
set_vals++;
|
||||
}
|
||||
- if (set->mda_size_set) {
|
||||
+ if (set->mda2_size_set) {
|
||||
mda_size = set->mda2_size;
|
||||
set_vals++;
|
||||
}
|
||||
--
|
||||
2.54.0
|
||||
|
||||
49
0103-online-fix-buffer-pointer-in-write-loop.patch
Normal file
49
0103-online-fix-buffer-pointer-in-write-loop.patch
Normal file
@ -0,0 +1,49 @@
|
||||
From 8a05f2db20f70a91822dbbdc79169f39d6fc368c Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 13:27:24 +0200
|
||||
Subject: [PATCH 103/211] online: fix buffer pointer in write loop
|
||||
|
||||
The buffer is small enough that partial writes are unlikely, but
|
||||
use a separate char pointer to correctly advance the write position
|
||||
since buf is a stack array and cannot use pointer arithmetic.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit bb429948514e9cfd18791afbb934fa04020634c2)
|
||||
---
|
||||
lib/device/online.c | 5 ++++-
|
||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/device/online.c b/lib/device/online.c
|
||||
index 302b3d2d7..b5dfa29cb 100644
|
||||
--- a/lib/device/online.c
|
||||
+++ b/lib/device/online.c
|
||||
@@ -247,6 +247,7 @@ int online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const c
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
char buf[MAX_PVID_FILE_SIZE] = { 0 };
|
||||
+ char *bufp;
|
||||
char file_vgname[NAME_LEN];
|
||||
char file_devname[NAME_LEN];
|
||||
char devname[NAME_LEN];
|
||||
@@ -302,8 +303,9 @@ int online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const c
|
||||
return 0;
|
||||
}
|
||||
|
||||
+ bufp = buf;
|
||||
while (len > 0) {
|
||||
- rv = write(fd, buf, len);
|
||||
+ rv = write(fd, bufp, len);
|
||||
if (rv < 0) {
|
||||
/* file exists so it still works in part */
|
||||
log_warn("Cannot write online file for %s to %s error %d",
|
||||
@@ -312,6 +314,7 @@ int online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const c
|
||||
log_sys_debug("close", path);
|
||||
return 1;
|
||||
}
|
||||
+ bufp += rv;
|
||||
len -= rv;
|
||||
}
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
28
0104-libdm-fix-cut-and-past-bug.patch
Normal file
28
0104-libdm-fix-cut-and-past-bug.patch
Normal file
@ -0,0 +1,28 @@
|
||||
From e68693f02780259d8d15fa2aeb07c70260263068 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Sat, 21 Mar 2026 18:42:01 +0100
|
||||
Subject: [PATCH 104/211] libdm: fix cut and past bug
|
||||
|
||||
set_read_ahead is using BLKRASET ioctl.
|
||||
|
||||
(cherry picked from commit 2bb10cf33ee95f06fa4f10555fec433458c8b83f)
|
||||
---
|
||||
libdm/libdm-common.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libdm/libdm-common.c b/libdm/libdm-common.c
|
||||
index 21bdd826e..3ee5a1070 100644
|
||||
--- a/libdm/libdm-common.c
|
||||
+++ b/libdm/libdm-common.c
|
||||
@@ -1334,7 +1334,7 @@ static int _set_read_ahead(const char *dev_name, uint32_t major, uint32_t minor,
|
||||
}
|
||||
|
||||
if (!*dev_name) {
|
||||
- log_error("Empty device name passed to BLKRAGET");
|
||||
+ log_error("Empty device name passed to BLKRASET.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
From fc9e8b150de592d14cc6e9777e099a7d2f71b5c8 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 14:05:59 +0200
|
||||
Subject: [PATCH 105/211] lvmpolld: fix STDOUT/STDERR copy-paste error in poll
|
||||
warning
|
||||
|
||||
The fds[1] block handles STDERR but the error message said "STDOUT",
|
||||
copy-pasted from the fds[0] block above.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 56a6ff90b8701564170b79153be1870fc3f90670)
|
||||
---
|
||||
daemons/lvmpolld/lvmpolld-core.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/daemons/lvmpolld/lvmpolld-core.c b/daemons/lvmpolld/lvmpolld-core.c
|
||||
index ff47e1fbc..65ac18ab5 100644
|
||||
--- a/daemons/lvmpolld/lvmpolld-core.c
|
||||
+++ b/daemons/lvmpolld/lvmpolld-core.c
|
||||
@@ -294,7 +294,7 @@ static int poll_for_output(struct lvmpolld_lv *pdlv, struct lvmpolld_thread_data
|
||||
if (fds[1].revents & POLLHUP)
|
||||
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "caught err POLLHUP");
|
||||
else
|
||||
- WARN(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "poll for command's STDOUT failed");
|
||||
+ WARN(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "poll for command's STDERR failed");
|
||||
|
||||
fds[1].fd = -1;
|
||||
fds_count--;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
From cad7f79a1ec5523d36cc55332105e28d69903cd4 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 10:29:51 +0200
|
||||
Subject: [PATCH 106/211] lvmcache: use label_destroy instead of free for label
|
||||
cleanup
|
||||
|
||||
Use label_destroy to properly call the labeller's destroy_label
|
||||
callback, matching the pattern in _lvmcache_destroy_info.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 50a6700e44bc018cb925818e2d57eeec07937f23)
|
||||
---
|
||||
lib/cache/lvmcache.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
|
||||
index da9a55d09..1effc254c 100644
|
||||
--- a/lib/cache/lvmcache.c
|
||||
+++ b/lib/cache/lvmcache.c
|
||||
@@ -2596,7 +2596,7 @@ update_vginfo:
|
||||
if (created) {
|
||||
dm_hash_remove(_pvid_hash, pvid);
|
||||
info->dev->pvid[0] = 0;
|
||||
- free(info->label);
|
||||
+ label_destroy(info->label);
|
||||
free(info);
|
||||
}
|
||||
return NULL;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
30
0107-lvm-null-correct-field-after-freeing-log_rh.patch
Normal file
30
0107-lvm-null-correct-field-after-freeing-log_rh.patch
Normal file
@ -0,0 +1,30 @@
|
||||
From 9ed020b671833bc27368b5de220aaf992991dcb4 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 11:29:14 +0200
|
||||
Subject: [PATCH 107/211] lvm: null correct field after freeing log_rh
|
||||
|
||||
After dm_report_free(log_rh), the code was nulling report_group
|
||||
(already handled above) instead of log_rh.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 9e13c72a8d8273195b27fe9c54dc643e51a5a383)
|
||||
---
|
||||
tools/lvm.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tools/lvm.c b/tools/lvm.c
|
||||
index b0bbdd8f2..47c03170a 100644
|
||||
--- a/tools/lvm.c
|
||||
+++ b/tools/lvm.c
|
||||
@@ -363,7 +363,7 @@ report_log:
|
||||
|
||||
if (cmd->cmd_report.log_rh) {
|
||||
dm_report_free(cmd->cmd_report.log_rh);
|
||||
- cmd->cmd_report.report_group = NULL;
|
||||
+ cmd->cmd_report.log_rh = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
From 71cf345a9ece2419c8e9625f9bb99d41a11d3c50 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 12:43:38 +0200
|
||||
Subject: [PATCH 108/211] dmeventd: fix msg.data memory leak in
|
||||
_restart_dmeventd
|
||||
|
||||
msg.data from GET_STATUS was not freed before the second daemon_talk()
|
||||
for GET_PARAMETERS, which zeroes the struct via memset, leaking the
|
||||
previous allocation.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 9124508d1f692a7bd143e7b28a3ab89b4c8c270f)
|
||||
---
|
||||
daemons/dmeventd/dmeventd.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/daemons/dmeventd/dmeventd.c b/daemons/dmeventd/dmeventd.c
|
||||
index 22a713b9a..0c3880787 100644
|
||||
--- a/daemons/dmeventd/dmeventd.c
|
||||
+++ b/daemons/dmeventd/dmeventd.c
|
||||
@@ -2203,6 +2203,9 @@ static int _restart_dmeventd(struct dm_event_fifos *fifos)
|
||||
message += strlen(message) + 1;
|
||||
}
|
||||
|
||||
+ free(msg.data);
|
||||
+ msg.data = NULL;
|
||||
+
|
||||
if (version >= 2) {
|
||||
if (daemon_talk(fifos, &msg, DM_EVENT_CMD_GET_PARAMETERS, "-", "-", 0, 0)) {
|
||||
fprintf(stderr, "Failed to acquire parameters from old dmeventd.\n");
|
||||
--
|
||||
2.54.0
|
||||
|
||||
32
0109-polldaemon-check-finish_copy-result-on-abort-path.patch
Normal file
32
0109-polldaemon-check-finish_copy-result-on-abort-path.patch
Normal file
@ -0,0 +1,32 @@
|
||||
From ddb889f750e64b8f368493a373bf5fa7e7fe88a1 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Sat, 21 Mar 2026 23:33:53 +0100
|
||||
Subject: [PATCH 109/211] polldaemon: check finish_copy result on abort path
|
||||
|
||||
When update_metadata fails during segment progression, finish_copy
|
||||
is called for cleanup but its return value was silently ignored.
|
||||
Add stack trace on failure for diagnostics.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit f8c2e6054226f8ff8bfcfd25791640490b378b1b)
|
||||
---
|
||||
tools/polldaemon.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tools/polldaemon.c b/tools/polldaemon.c
|
||||
index 1a3c8fefc..605c90779 100644
|
||||
--- a/tools/polldaemon.c
|
||||
+++ b/tools/polldaemon.c
|
||||
@@ -104,7 +104,8 @@ static int _check_lv_status(struct cmd_context *cmd,
|
||||
if (parms->poll_fns->update_metadata &&
|
||||
!parms->poll_fns->update_metadata(cmd, vg, lv, lvs_changed, 0)) {
|
||||
log_error("ABORTING: Segment progression failed.");
|
||||
- parms->poll_fns->finish_copy(cmd, vg, lv, lvs_changed);
|
||||
+ if (!parms->poll_fns->finish_copy(cmd, vg, lv, lvs_changed))
|
||||
+ stack;
|
||||
return 0;
|
||||
}
|
||||
*finished = 0; /* Another segment */
|
||||
--
|
||||
2.54.0
|
||||
|
||||
214
0110-metadata-fix-lv_raid_healthy-to-detect-metadata-alra.patch
Normal file
214
0110-metadata-fix-lv_raid_healthy-to-detect-metadata-alra.patch
Normal file
@ -0,0 +1,214 @@
|
||||
From 6c03e5fd5c875aa29ad761aa1cd4aa764849b026 Mon Sep 17 00:00:00 2001
|
||||
From: Peter Rajnoha <prajnoha@redhat.com>
|
||||
Date: Thu, 5 Feb 2026 17:09:43 +0100
|
||||
Subject: [PATCH 110/211] metadata: fix lv_raid_healthy to detect metadata
|
||||
alrady updated to match device state
|
||||
|
||||
Consider a RAID LV where one of the legs goes missing.
|
||||
|
||||
There is a difference between these two:
|
||||
|
||||
A) transient device failure
|
||||
1) A RAID LV has underlying PV representing a leg missing.
|
||||
2) The missing leg is replaced by error target.
|
||||
3) LVM metadata are not updated yet, just transient error (vgreduce not called).
|
||||
4) The missing PV is present again.
|
||||
5) A message is reported when getting LV RAID health status (for e.g. lvs):
|
||||
"WARNING: RaidLV vg/lv needs to be refreshed!"
|
||||
6) After using lvchange --refresh vg/lv, the RAID LV is refreshed
|
||||
and the error targets for previously missing leg is mapped onto
|
||||
the actual PV again.
|
||||
|
||||
B) non-transient device failure
|
||||
1) A RAID LV has underlying PV representing a leg missing.
|
||||
2) The missing PV is reduced (vgreduce called).
|
||||
3) LVM metadata are updated.
|
||||
4) The missing leg is present again.
|
||||
5) Inconsistent metadata is detected, the VG is made consistent first,
|
||||
removes the actual leg from the old PV (vgck --updatemetadata vg).
|
||||
6) The message "WARNING: RaidLV vg/lv needs to be repaired!" is reported.
|
||||
7) After using lvconvert --repair vg/lv, the RAID LV is repaired and
|
||||
the error targets for previously missing leg is mapped onto the
|
||||
free PV.
|
||||
|
||||
Before, lv_raid_healthy could not differentiate between A) and B).
|
||||
|
||||
Now, lv_raid_healthy sets 'raid_need_t *need' output arguments where the value is one of:
|
||||
|
||||
- RAID_NEED_ERROR (an error occurred while trying to acquire the healthy status)
|
||||
- RAID_NEED_REFRESH (refresh is needed for transient failure)
|
||||
- RAID_NEED_REPAIR (repair is needed for non-transient failure)
|
||||
- RAID_NEED_REFRESH_OR_REPAIR (either refresh or repair, can't determine)
|
||||
|
||||
(cherry picked from commit 6104a78a87bbdc2d4a84791ea45c3df18422a28c)
|
||||
---
|
||||
lib/metadata/lv.c | 87 ++++++++++++++++++++++++++++++++++++++++-------
|
||||
lib/metadata/lv.h | 9 ++++-
|
||||
2 files changed, 83 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c
|
||||
index c7b213067..d201244a7 100644
|
||||
--- a/lib/metadata/lv.c
|
||||
+++ b/lib/metadata/lv.c
|
||||
@@ -1230,13 +1230,17 @@ static int lv_raid_integrity_image_in_sync(const struct logical_volume *lv_iorig
|
||||
* _lv_raid_healthy
|
||||
* @lv: A RAID_IMAGE, RAID_META, or RAID logical volume.
|
||||
*
|
||||
- * Returns: 1 if healthy, 0 if device is not health
|
||||
+ * Returns:
|
||||
+ * 1 if LV of RAID type healthy
|
||||
+ * 0 if LV of RAID type not healthy ('need' set appropriately if not NULL)
|
||||
*/
|
||||
-int lv_raid_healthy(const struct logical_volume *lv)
|
||||
+int lv_raid_healthy(const struct logical_volume *lv, raid_need_t *need)
|
||||
{
|
||||
unsigned s;
|
||||
char *raid_health;
|
||||
+ size_t raid_health_len;
|
||||
struct lv_segment *seg, *raid_seg = NULL;
|
||||
+ raid_need_t r_need = RAID_NEED_ERROR;
|
||||
|
||||
/*
|
||||
* If the LV is not active locally,
|
||||
@@ -1247,7 +1251,7 @@ int lv_raid_healthy(const struct logical_volume *lv)
|
||||
|
||||
if (!lv_is_raid_type(lv)) {
|
||||
log_error(INTERNAL_ERROR "%s is not of RAID type", lv->name);
|
||||
- return 0;
|
||||
+ goto out_need;
|
||||
}
|
||||
|
||||
if (lv_is_raid(lv))
|
||||
@@ -1257,20 +1261,55 @@ int lv_raid_healthy(const struct logical_volume *lv)
|
||||
|
||||
if (!raid_seg) {
|
||||
log_error("Failed to find RAID segment for %s", lv->name);
|
||||
- return 0;
|
||||
+ goto out_need;
|
||||
}
|
||||
|
||||
if (!seg_is_raid(raid_seg)) {
|
||||
log_error(INTERNAL_ERROR "%s on %s is not a RAID segment.",
|
||||
raid_seg->lv->name, lv->name);
|
||||
- return 0;
|
||||
+ goto out_need;
|
||||
}
|
||||
|
||||
- if (!lv_raid_dev_health(raid_seg->lv, &raid_health))
|
||||
- return_0;
|
||||
+ if (!lv_raid_dev_health(raid_seg->lv, &raid_health)) {
|
||||
+ stack;
|
||||
+ goto out_need;
|
||||
+ }
|
||||
|
||||
- if (lv_is_raid(lv))
|
||||
- return (strchr(raid_health, 'D')) ? 0 : 1;
|
||||
+ raid_health_len = strlen(raid_health);
|
||||
+
|
||||
+ if (lv_is_raid(lv)) {
|
||||
+ if (raid_seg->area_count == raid_health_len) {
|
||||
+ /*
|
||||
+ * Counts match - positions correspond.
|
||||
+ * Check each leg - only report unhealthy if a device is down
|
||||
+ * but the metadata expects it to be on a real device (not error segment).
|
||||
+ * If a device shows 'D' but the corresponding image LV is virtual
|
||||
+ * (error segment from vgreduce --removemissing), that's expected and
|
||||
+ * doesn't need a refresh.
|
||||
+ */
|
||||
+ for (s = 0; s < raid_seg->area_count; s++) {
|
||||
+ if (raid_health[s] == 'D') {
|
||||
+ if (lv_is_virtual(seg_lv(raid_seg, s)))
|
||||
+ r_need = RAID_NEED_REPAIR;
|
||||
+ else
|
||||
+ r_need = RAID_NEED_REFRESH;
|
||||
+ goto out_need;
|
||||
+ }
|
||||
+ }
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Counts don't match (reshape in progress) - can't reliably
|
||||
+ * correlate health positions with metadata, fall back to
|
||||
+ * behavior where any 'D' means unhealthy.
|
||||
+ */
|
||||
+ if (strchr(raid_health, 'D')) {
|
||||
+ r_need = RAID_NEED_REFRESH_OR_REPAIR;
|
||||
+ goto out_need;
|
||||
+ }
|
||||
+ return 1;
|
||||
+ }
|
||||
|
||||
/* Find out which sub-LV this is. */
|
||||
for (s = 0; s < raid_seg->area_count; s++)
|
||||
@@ -1281,13 +1320,37 @@ int lv_raid_healthy(const struct logical_volume *lv)
|
||||
log_error(INTERNAL_ERROR
|
||||
"sub-LV %s was not found in raid segment",
|
||||
lv->name);
|
||||
- return 0;
|
||||
+ goto out_need;
|
||||
}
|
||||
|
||||
- if (raid_health[s] == 'D')
|
||||
- return 0;
|
||||
+ if (raid_seg->area_count == raid_health_len) {
|
||||
+ /* Counts match - positions correspond */
|
||||
+ /* If sub-LV is virtual (error segment), 'D' is expected - not unhealthy */
|
||||
+ if (raid_health[s] == 'D') {
|
||||
+ if (lv_is_virtual(lv))
|
||||
+ r_need = RAID_NEED_REPAIR;
|
||||
+ else
|
||||
+ r_need = RAID_NEED_REFRESH;
|
||||
+ goto out_need;
|
||||
+ }
|
||||
+ return 1;
|
||||
+ }
|
||||
|
||||
+ /*
|
||||
+ * Counts don't match (reshape in progress) - can't reliably
|
||||
+ * correlate health position with sub-LV, fall back to
|
||||
+ * behavior where any 'D' means unhealthy.
|
||||
+ */
|
||||
+ if (strchr(raid_health, 'D')) {
|
||||
+ r_need = RAID_NEED_REFRESH_OR_REPAIR;
|
||||
+ goto out_need;
|
||||
+ }
|
||||
return 1;
|
||||
+
|
||||
+out_need:
|
||||
+ if (need)
|
||||
+ *need = r_need;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
/* Helper: check for any sub LVs after a disk removing reshape */
|
||||
diff --git a/lib/metadata/lv.h b/lib/metadata/lv.h
|
||||
index 0596ed86b..3bf9d4211 100644
|
||||
--- a/lib/metadata/lv.h
|
||||
+++ b/lib/metadata/lv.h
|
||||
@@ -139,7 +139,6 @@ const struct logical_volume *lv_lock_holder(const struct logical_volume *lv);
|
||||
const struct logical_volume *lv_committed(const struct logical_volume *lv);
|
||||
int lv_mirror_image_in_sync(const struct logical_volume *lv);
|
||||
int lv_raid_image_in_sync(const struct logical_volume *lv);
|
||||
-int lv_raid_healthy(const struct logical_volume *lv);
|
||||
const char *lvseg_name(const struct lv_segment *seg);
|
||||
uint64_t lvseg_start(const struct lv_segment *seg);
|
||||
struct dm_list *lvseg_devices(struct dm_pool *mem, const struct lv_segment *seg);
|
||||
@@ -153,6 +152,14 @@ char *lvseg_seg_le_ranges_str(struct dm_pool *mem, const struct lv_segment *seg)
|
||||
struct dm_list *lvseg_seg_metadata_le_ranges(struct dm_pool *mem, const struct lv_segment *seg);
|
||||
char *lvseg_seg_metadata_le_ranges_str(struct dm_pool *mem, const struct lv_segment *seg);
|
||||
|
||||
+typedef enum {
|
||||
+ RAID_NEED_ERROR,
|
||||
+ RAID_NEED_REFRESH,
|
||||
+ RAID_NEED_REPAIR,
|
||||
+ RAID_NEED_REFRESH_OR_REPAIR, /* can't determine */
|
||||
+} raid_need_t;
|
||||
+int lv_raid_healthy(const struct logical_volume *lv, raid_need_t *need);
|
||||
+
|
||||
/* LV kernel properties */
|
||||
int lv_kernel_major(const struct logical_volume *lv);
|
||||
int lv_kernel_minor(const struct logical_volume *lv);
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,61 @@
|
||||
From af3088f447aace9e6e87de388aa2da5dd6273c40 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Wed, 22 Oct 2025 16:44:09 +0200
|
||||
Subject: [PATCH 111/211] lv_manip: detect insufficient space for RAID with
|
||||
split metadata
|
||||
|
||||
When approx_alloc reduces allocation and we have RAID/mirror with
|
||||
split metadata (alloc_and_split_meta), verify that we allocated at
|
||||
least 1 extent per data area.
|
||||
|
||||
If total_area_len < area_count, the integer division during parallel
|
||||
area allocation (area_len = max_to_allocate / ah->area_multiple) results
|
||||
in area_len=0 for individual data areas. This causes those areas to be
|
||||
skipped (empty allocation), creating RAID image LVs with no segments.
|
||||
|
||||
This create invalid metadata with LVs without segments.
|
||||
|
||||
Example:
|
||||
- Need 52 extents total (4 data areas x 13 extents)
|
||||
- Metadata allocated: 4 extents (4 rmeta x 1 extent each)
|
||||
- Only 1 extent remains for data
|
||||
- Result: area_len = 1/4 = 0, all data areas get empty allocation
|
||||
|
||||
Fix by failing allocation early with clear error message instead of
|
||||
creating corrupted RAID LVs that trigger internal errors.
|
||||
|
||||
Resolves: https://issues.redhat.com/browse/RHEL-116884
|
||||
|
||||
Co-Authored-By: Claude <noreply@anthropic.com>
|
||||
(cherry picked from commit d2715e01f585c55f76215002db470c752ad208e3)
|
||||
---
|
||||
lib/metadata/lv_manip.c | 13 +++++++++++++
|
||||
1 file changed, 13 insertions(+)
|
||||
|
||||
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
|
||||
index 61816bd8c..42e3f2489 100644
|
||||
--- a/lib/metadata/lv_manip.c
|
||||
+++ b/lib/metadata/lv_manip.c
|
||||
@@ -3494,6 +3494,19 @@ static int _allocate(struct alloc_handle *ah,
|
||||
lv ? lv->name : "");
|
||||
goto out;
|
||||
}
|
||||
+ /*
|
||||
+ * For RAID/mirror with split metadata, verify we allocated
|
||||
+ * at least 1 extent per data area. If total_area_len is less
|
||||
+ * than area_count, integer division during allocation would
|
||||
+ * result in some areas getting 0 extents, creating LVs with
|
||||
+ * no segments which triggers internal errors during vg_write.
|
||||
+ */
|
||||
+ if (ah->alloc_and_split_meta && ah->total_area_len < ah->area_count) {
|
||||
+ log_error("Insufficient suitable allocatable extents for logical volume %s: "
|
||||
+ "%u extents found but at least %u required (1 extent per data image).",
|
||||
+ lv ? lv->name : "", ah->total_area_len, ah->area_count);
|
||||
+ goto out;
|
||||
+ }
|
||||
log_verbose("Found fewer %sallocatable extents "
|
||||
"for logical volume %s than requested: using %" PRIu32 " extents (reduced by %u).",
|
||||
can_split ? "" : "contiguous ",
|
||||
--
|
||||
2.54.0
|
||||
|
||||
103
0112-libdm-deptree-cancel-delay_resume-for-new-children-w.patch
Normal file
103
0112-libdm-deptree-cancel-delay_resume-for-new-children-w.patch
Normal file
@ -0,0 +1,103 @@
|
||||
From f64c7195de1d8a111b8f5a7054c5f4af2f5eb483 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Wed, 15 Oct 2025 18:07:00 +0200
|
||||
Subject: [PATCH 112/211] libdm: deptree: cancel delay_resume for new children
|
||||
when parent is inactive
|
||||
|
||||
When preloading children of an inactive parent node (other than root),
|
||||
cancel the delay_resume_if_new flag to allow immediate resume of new devices.
|
||||
|
||||
This fixes a specific issue with pvmove operations on RAID devices where:
|
||||
|
||||
1. The RAID logical volume has not been instantiated yet (inactive parent)
|
||||
2. A pvmove device needs to be created for one of the RAID legs
|
||||
3. The RAID table requires the leg LV to be active before loading
|
||||
4. Therefore, the pvmove device must be resumed immediately, not delayed
|
||||
|
||||
Background:
|
||||
When both RAID and pvmove devices are being created from scratch,
|
||||
the pvmove device can be started immediately without leaking direct
|
||||
access to the PV - all I/O goes through appropriate targets from the start.
|
||||
|
||||
However, if the RAID device is already active, we can only preload the
|
||||
new pvmove table. In that case, a full suspend must occur before resuming
|
||||
the new table, ensuring all I/O continues through the existing table
|
||||
until the resume point.
|
||||
|
||||
(cherry picked from commit 48015ecb3c674b0f7326f94a44af4d93c77f0fbe)
|
||||
---
|
||||
device_mapper/libdm-deptree.c | 23 ++++++++++++++++++++---
|
||||
libdm/libdm-deptree.c | 23 ++++++++++++++++++++---
|
||||
2 files changed, 40 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/device_mapper/libdm-deptree.c b/device_mapper/libdm-deptree.c
|
||||
index 2d5829c9c..98c0fa814 100644
|
||||
--- a/device_mapper/libdm-deptree.c
|
||||
+++ b/device_mapper/libdm-deptree.c
|
||||
@@ -3363,9 +3363,26 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
|
||||
|
||||
/* Preload children first */
|
||||
while ((child = dm_tree_next_child(&handle, dnode, 0))) {
|
||||
- /* Propagate delay of resume from parent node */
|
||||
- if (dnode->props.delay_resume_if_new > 1)
|
||||
- child->props.delay_resume_if_new = dnode->props.delay_resume_if_new;
|
||||
+ /* When a parent node (other than root) is inactive, we cannot delay
|
||||
+ * the resume of a new device.
|
||||
+ * For example, preloading a RAID table with a pvmoved leg requires the
|
||||
+ * leg LV to be active before loading the RAID LV, so the pvmove device must
|
||||
+ * be resumed immediately.
|
||||
+ * This scenario only occurs when neither the RAID nor pvmove device has
|
||||
+ * been instantiated yet. In this case, starting the pvmove device does
|
||||
+ * not leak access to the PV device without going through the mirror target.
|
||||
+ * However, if the RAID is already active and running, we can only preload
|
||||
+ * the new pvmove device, and a full suspend must occur before resuming
|
||||
+ * the new table with the running pvmove. So until the resume point
|
||||
+ * any IO is going through the existing table line and not via pvmove target.
|
||||
+ */
|
||||
+ if ((child->props.delay_resume_if_new > 1) &&
|
||||
+ !dnode->info.exists &&
|
||||
+ (dnode != &dnode->dtree->root)) { /* Ignore when parent is root node */
|
||||
+ log_debug("%s with inactive parent cancels delay_resume_if_new.",
|
||||
+ _node_name(child));
|
||||
+ child->props.delay_resume_if_new = 0;
|
||||
+ }
|
||||
|
||||
/* Skip existing non-device-mapper devices */
|
||||
if (!child->info.exists && child->info.major)
|
||||
diff --git a/libdm/libdm-deptree.c b/libdm/libdm-deptree.c
|
||||
index b0f476b3b..318b23ecc 100644
|
||||
--- a/libdm/libdm-deptree.c
|
||||
+++ b/libdm/libdm-deptree.c
|
||||
@@ -2906,9 +2906,26 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
|
||||
|
||||
/* Preload children first */
|
||||
while ((child = dm_tree_next_child(&handle, dnode, 0))) {
|
||||
- /* Propagate delay of resume from parent node */
|
||||
- if (dnode->props.delay_resume_if_new > 1)
|
||||
- child->props.delay_resume_if_new = dnode->props.delay_resume_if_new;
|
||||
+ /* When a parent node (other than root) is inactive, we cannot delay
|
||||
+ * the resume of a new device.
|
||||
+ * For example, preloading a RAID table with a pvmoved leg requires the
|
||||
+ * leg LV to be active before loading the RAID LV, so the pvmove device must
|
||||
+ * be resumed immediately.
|
||||
+ * This scenario only occurs when neither the RAID nor pvmove device has
|
||||
+ * been instantiated yet. In this case, starting the pvmove device does
|
||||
+ * not leak access to the PV device without going through the mirror target.
|
||||
+ * However, if the RAID is already active and running, we can only preload
|
||||
+ * the new pvmove device, and a full suspend must occur before resuming
|
||||
+ * the new table with the running pvmove. So until the resume point
|
||||
+ * any IO is going through the existing table line and not via pvmove target.
|
||||
+ */
|
||||
+ if ((child->props.delay_resume_if_new > 1) &&
|
||||
+ !dnode->info.exists &&
|
||||
+ (dnode != &dnode->dtree->root)) { /* Ignore when parent is root node */
|
||||
+ log_debug("%s with inactive parent cancels delay_resume_if_new.",
|
||||
+ _node_name(child));
|
||||
+ child->props.delay_resume_if_new = 0;
|
||||
+ }
|
||||
|
||||
/* Skip existing non-device-mapper devices */
|
||||
if (!child->info.exists && child->info.major)
|
||||
--
|
||||
2.54.0
|
||||
|
||||
139
0113-integrity-fix-adding-integrity-to-RAID.patch
Normal file
139
0113-integrity-fix-adding-integrity-to-RAID.patch
Normal file
@ -0,0 +1,139 @@
|
||||
From ec6b806b893bedda0356b825f9d775f546debbae Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Mon, 29 Sep 2025 14:03:42 +0200
|
||||
Subject: [PATCH 113/211] integrity: fix adding integrity to RAID
|
||||
|
||||
Fix several issues in integrity addition to RAID logical volumes and
|
||||
improve error handling and cleanup:
|
||||
|
||||
Synchronization and activation fixes:
|
||||
- Add sync_local_dev_names() before LV activation to handle potential
|
||||
udev deactivation in-flight from metadata device wiping
|
||||
- Consolidate deactivate_lv() calls to avoid code duplication in
|
||||
_set_integrity_block_size() error path
|
||||
|
||||
Missing segment relationship:
|
||||
- Add missing add_seg_to_segs_using_this_lv() call for imeta LV to
|
||||
properly establish segment relationships
|
||||
|
||||
Enhanced error recovery:
|
||||
- Improve error path cleanup in case integrity addition fails
|
||||
|
||||
(cherry picked from commit c33233cb88961a51e0effad02510f5f01bb930d4)
|
||||
---
|
||||
lib/metadata/integrity_manip.c | 59 ++++++++++++++++++++++++++--------
|
||||
1 file changed, 45 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/lib/metadata/integrity_manip.c b/lib/metadata/integrity_manip.c
|
||||
index be2d458b3..e03d422b2 100644
|
||||
--- a/lib/metadata/integrity_manip.c
|
||||
+++ b/lib/metadata/integrity_manip.c
|
||||
@@ -515,7 +515,7 @@ int lv_add_integrity_to_raid(struct logical_volume *lv, struct integrity_setting
|
||||
struct logical_volume *imeta_lvs[DEFAULT_RAID_MAX_IMAGES];
|
||||
struct cmd_context *cmd = lv->vg->cmd;
|
||||
struct volume_group *vg = lv->vg;
|
||||
- struct logical_volume *lv_image, *lv_imeta;
|
||||
+ struct logical_volume *lv_image, *lv_imeta, *lv_iorig;
|
||||
struct lv_segment *seg_top, *seg_image;
|
||||
struct pv_list *pvl;
|
||||
const struct segment_type *segtype;
|
||||
@@ -526,6 +526,7 @@ int lv_add_integrity_to_raid(struct logical_volume *lv, struct integrity_setting
|
||||
int lbs_4k = 0, lbs_512 = 0, lbs_unknown = 0;
|
||||
int pbs_4k = 0, pbs_512 = 0, pbs_unknown = 0;
|
||||
int is_active;
|
||||
+ int r;
|
||||
|
||||
memset(imeta_lvs, 0, sizeof(imeta_lvs));
|
||||
|
||||
@@ -659,6 +660,8 @@ int lv_add_integrity_to_raid(struct logical_volume *lv, struct integrity_setting
|
||||
}
|
||||
|
||||
if (!is_active) {
|
||||
+ if (!sync_local_dev_names(cmd))
|
||||
+ stack;
|
||||
/* checking block size of fs on the lv requires the lv to be active */
|
||||
if (!activate_lv(cmd, lv)) {
|
||||
log_error("Failed to activate LV to check block size %s", display_lvname(lv));
|
||||
@@ -673,19 +676,18 @@ int lv_add_integrity_to_raid(struct logical_volume *lv, struct integrity_setting
|
||||
* integrity block size chosen based on device logical block size and
|
||||
* file system block size.
|
||||
*/
|
||||
- if (!_set_integrity_block_size(cmd, lv, is_active, settings, lbs_4k, lbs_512, pbs_4k, pbs_512)) {
|
||||
- if (!is_active && !deactivate_lv(cmd, lv))
|
||||
- stack;
|
||||
- goto_bad;
|
||||
- }
|
||||
|
||||
- if (!is_active) {
|
||||
- if (!deactivate_lv(cmd, lv)) {
|
||||
- log_error("Failed to deactivate LV after checking block size %s", display_lvname(lv));
|
||||
- goto bad;
|
||||
- }
|
||||
+ if (!(r = _set_integrity_block_size(cmd, lv, is_active, settings, lbs_4k, lbs_512, pbs_4k, pbs_512)))
|
||||
+ stack;
|
||||
+
|
||||
+ if (!is_active && !deactivate_lv(cmd, lv)) {
|
||||
+ log_error("Failed to deactivate LV %s after checking block size.", display_lvname(lv));
|
||||
+ goto bad;
|
||||
}
|
||||
|
||||
+ if (!r)
|
||||
+ goto bad;
|
||||
+
|
||||
/*
|
||||
* For each rimage, move its segments to a new rimage_iorig and give
|
||||
* the rimage a new integrity segment.
|
||||
@@ -727,6 +729,8 @@ int lv_add_integrity_to_raid(struct logical_volume *lv, struct integrity_setting
|
||||
seg_image->integrity_data_sectors = lv_image->size;
|
||||
seg_image->integrity_meta_dev = lv_imeta;
|
||||
seg_image->integrity_recalculate = 1;
|
||||
+ if (!add_seg_to_segs_using_this_lv(lv_imeta, seg_image))
|
||||
+ goto_bad;
|
||||
|
||||
memcpy(&seg_image->integrity_settings, settings, sizeof(struct integrity_settings));
|
||||
set = &seg_image->integrity_settings;
|
||||
@@ -801,11 +805,38 @@ bad:
|
||||
for (s = 0; s < DEFAULT_RAID_MAX_IMAGES; s++) {
|
||||
if (!imeta_lvs[s])
|
||||
continue;
|
||||
- if (!lv_remove(imeta_lvs[s]))
|
||||
- log_error("New integrity metadata LV may require manual removal.");
|
||||
+
|
||||
+ lv_image = seg_lv(seg_top, s);
|
||||
+ seg_image = first_seg(lv_image);
|
||||
+ lv_iorig = seg_lv(seg_image, 0);
|
||||
+ if (lv_image->status & INTEGRITY) {
|
||||
+ if (!remove_layer_from_lv(lv_image, lv_iorig) ||
|
||||
+ !remove_seg_from_segs_using_this_lv(seg_image->integrity_meta_dev,
|
||||
+ seg_image)) {
|
||||
+ log_error("Aborting. Cannot remove integrity layer from LV %s.", display_lvname(lv_image));
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ lv_image->status &= ~INTEGRITY;
|
||||
+ imeta_lvs[s]->status &= ~INTEGRITY_METADATA;
|
||||
+
|
||||
+ lv_set_visible(imeta_lvs[s]);
|
||||
+ lv_set_visible(lv_iorig);
|
||||
+
|
||||
+ if (!lv_remove(lv_iorig)) {
|
||||
+ log_error("Aborting. Cannot remove new integrity origin LV %s.",
|
||||
+ display_lvname(lv_iorig));
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+ if (!lv_remove(imeta_lvs[s])) {
|
||||
+ log_error("Aborting. Cannot remove new integrity metadata LV %s.",
|
||||
+ display_lvname(imeta_lvs[s]));
|
||||
+ return 0;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
-
|
||||
+
|
||||
if (!vg_write(vg) || !vg_commit(vg))
|
||||
log_error("New integrity metadata LV may require manual removal.");
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
36
0114-integrity-fix-activation-race-during-setup.patch
Normal file
36
0114-integrity-fix-activation-race-during-setup.patch
Normal file
@ -0,0 +1,36 @@
|
||||
From a61fbb2bb54a29d03a00175c7e124c6ebe2e536a Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Thu, 2 Oct 2025 15:54:12 +0200
|
||||
Subject: [PATCH 114/211] integrity: fix activation race during setup
|
||||
|
||||
Add synchronization after deactivate_lv() to prevent races between
|
||||
deactivation and subsequent activation using the same udev cookie.
|
||||
|
||||
This ensures proper ordering when wiping prepared integrity metadata
|
||||
devices during RAID integrity setup, affecting both active and inactive
|
||||
code paths.
|
||||
|
||||
(cherry picked from commit 42e3a8705ec2911e256e14e541a2c97f5b404e15)
|
||||
---
|
||||
lib/metadata/integrity_manip.c | 5 ++++-
|
||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/metadata/integrity_manip.c b/lib/metadata/integrity_manip.c
|
||||
index e03d422b2..26b644266 100644
|
||||
--- a/lib/metadata/integrity_manip.c
|
||||
+++ b/lib/metadata/integrity_manip.c
|
||||
@@ -685,7 +685,10 @@ int lv_add_integrity_to_raid(struct logical_volume *lv, struct integrity_setting
|
||||
goto bad;
|
||||
}
|
||||
|
||||
- if (!r)
|
||||
+ if (!sync_local_dev_names(cmd))
|
||||
+ stack;
|
||||
+
|
||||
+ if (!r)
|
||||
goto bad;
|
||||
|
||||
/*
|
||||
--
|
||||
2.54.0
|
||||
|
||||
295
0115-snapshot-reject-lvreduce-that-would-truncate-COW-exc.patch
Normal file
295
0115-snapshot-reject-lvreduce-that-would-truncate-COW-exc.patch
Normal file
@ -0,0 +1,295 @@
|
||||
From abaf179f7ecb2945b6a5f5c795e60c80445c4f97 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Thu, 26 Feb 2026 20:24:46 +0100
|
||||
Subject: [PATCH 115/211] snapshot: reject lvreduce that would truncate COW
|
||||
exception data
|
||||
|
||||
Add a safety check in _lv_resize_check_type() that blocks lvreduce on
|
||||
an active CoW snapshot LV when the requested new size would truncate
|
||||
already-allocated exception blocks.
|
||||
|
||||
The check reads the exact used_sectors / total_sectors counts from the
|
||||
DM snapshot target (via new lv_snapshot_status() / dev_manager_snapshot_status())
|
||||
with a DM flush so that in-flight writes are accounted for before the
|
||||
comparison.
|
||||
|
||||
Fixes: https://github.com/lvmteam/lvm2/issues/164
|
||||
|
||||
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 21d5277eee3822c64b26f1a98b1d84764d612bd8)
|
||||
---
|
||||
lib/activate/activate.c | 34 ++++++++++++++
|
||||
lib/activate/activate.h | 3 ++
|
||||
lib/activate/dev_manager.c | 77 ++++++++++++++++++++++++++++++++
|
||||
lib/activate/dev_manager.h | 6 +++
|
||||
lib/metadata/lv_manip.c | 52 +++++++++++++++++++++
|
||||
lib/metadata/metadata-exported.h | 5 +++
|
||||
6 files changed, 177 insertions(+)
|
||||
|
||||
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
|
||||
index 50b8523ed..efeeaf26e 100644
|
||||
--- a/lib/activate/activate.c
|
||||
+++ b/lib/activate/activate.c
|
||||
@@ -258,6 +258,12 @@ int lv_snapshot_percent(const struct logical_volume *lv, dm_percent_t *percent)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
+int lv_snapshot_status(const struct logical_volume *lv,
|
||||
+ int flush,
|
||||
+ struct lv_status_snapshot **status)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
int lv_mirror_percent(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
int wait, dm_percent_t *percent, uint32_t *event_nr)
|
||||
{
|
||||
@@ -999,6 +1005,34 @@ int lv_snapshot_percent(const struct logical_volume *lv, dm_percent_t *percent)
|
||||
return r;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Get COW snapshot status for an active COW snapshot LV.
|
||||
+ * If flush is non-zero a DM flush is issued so in-flight writes are
|
||||
+ * reflected in the counts before the status is read.
|
||||
+ * On success returns 1 with *status populated.
|
||||
+ * Caller must call dm_pool_destroy((*status)->mem) when done.
|
||||
+ * Returns 0 if the LV is inactive or the query fails.
|
||||
+ */
|
||||
+int lv_snapshot_status(const struct logical_volume *lv,
|
||||
+ int flush,
|
||||
+ struct lv_status_snapshot **status)
|
||||
+{
|
||||
+ struct dev_manager *dm;
|
||||
+ int exists;
|
||||
+
|
||||
+ if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
|
||||
+ return_0;
|
||||
+
|
||||
+ if (!dev_manager_snapshot_status(dm, lv, flush, status, &exists)) {
|
||||
+ dev_manager_destroy(dm);
|
||||
+ if (exists)
|
||||
+ stack;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
/* FIXME Merge with snapshot_percent */
|
||||
int lv_mirror_percent(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
int wait, dm_percent_t *percent, uint32_t *event_nr)
|
||||
diff --git a/lib/activate/activate.h b/lib/activate/activate.h
|
||||
index 155936135..34ca7adb8 100644
|
||||
--- a/lib/activate/activate.h
|
||||
+++ b/lib/activate/activate.h
|
||||
@@ -187,6 +187,9 @@ int lv_check_transient(struct logical_volume *lv);
|
||||
* Returns 1 if percent has been set, else 0.
|
||||
*/
|
||||
int lv_snapshot_percent(const struct logical_volume *lv, dm_percent_t *percent);
|
||||
+int lv_snapshot_status(const struct logical_volume *lv,
|
||||
+ int flush,
|
||||
+ struct lv_status_snapshot **status);
|
||||
int lv_mirror_percent(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
int wait, dm_percent_t *percent, uint32_t *event_nr);
|
||||
int lv_raid_percent(const struct logical_volume *lv, dm_percent_t *percent);
|
||||
diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c
|
||||
index 46c626de5..7a7c6a475 100644
|
||||
--- a/lib/activate/dev_manager.c
|
||||
+++ b/lib/activate/dev_manager.c
|
||||
@@ -1620,6 +1620,83 @@ int dev_manager_snapshot_percent(struct dev_manager *dm,
|
||||
return 1;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Get COW snapshot status for an active COW snapshot LV.
|
||||
+ * If flush is non-zero a DM flush is issued so that in-flight writes are
|
||||
+ * accounted for before the status is read.
|
||||
+ * On success *status is populated and (*status)->mem must be destroyed by
|
||||
+ * the caller. Returns 1 on success, 0 on failure. *exists is set to 0 if
|
||||
+ * the DM device does not exist (inactive LV), 1 if it does.
|
||||
+ */
|
||||
+int dev_manager_snapshot_status(struct dev_manager *dm,
|
||||
+ const struct logical_volume *lv,
|
||||
+ int flush,
|
||||
+ struct lv_status_snapshot **status,
|
||||
+ int *exists)
|
||||
+{
|
||||
+ int r = 0;
|
||||
+ const struct logical_volume *snap_lv;
|
||||
+ const char *dlid;
|
||||
+ struct dm_task *dmt;
|
||||
+ struct dm_info info;
|
||||
+ uint64_t start, length;
|
||||
+ char *type = NULL;
|
||||
+ char *params = NULL;
|
||||
+
|
||||
+ *exists = -1;
|
||||
+ if (!(*status = dm_pool_zalloc(dm->mem, sizeof(struct lv_status_snapshot))))
|
||||
+ return_0;
|
||||
+
|
||||
+ if (lv_is_merging_cow(lv))
|
||||
+ /* must check status of origin for a merging snapshot */
|
||||
+ snap_lv = origin_from_cow(lv);
|
||||
+ else
|
||||
+ snap_lv = lv;
|
||||
+
|
||||
+ if (!(dlid = build_dm_uuid(dm->mem, snap_lv, NULL)))
|
||||
+ return_0;
|
||||
+
|
||||
+ if (!(dmt = _setup_task_run(DM_DEVICE_STATUS, &info, NULL, dlid, 0, 0, 0, 0, flush, 0)))
|
||||
+ return_0;
|
||||
+
|
||||
+ if (!(*exists = info.exists))
|
||||
+ goto out;
|
||||
+
|
||||
+ log_debug_activation("Checking snapshot status for LV %s.",
|
||||
+ display_lvname(snap_lv));
|
||||
+
|
||||
+ dm_get_next_target(dmt, NULL, &start, &length, &type, ¶ms);
|
||||
+
|
||||
+ if (!type || strcmp(type, TARGET_NAME_SNAPSHOT) || !params) {
|
||||
+ log_error("Expected snapshot segment type for %s but got %s.",
|
||||
+ display_lvname(snap_lv), type ? type : "NULL");
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (!dm_get_status_snapshot(dm->mem, params, &(*status)->snap))
|
||||
+ goto_out;
|
||||
+
|
||||
+ (*status)->mem = dm->mem;
|
||||
+
|
||||
+ if ((*status)->snap->invalid)
|
||||
+ (*status)->usage = DM_PERCENT_INVALID;
|
||||
+ else if ((*status)->snap->merge_failed)
|
||||
+ (*status)->usage = LVM_PERCENT_MERGE_FAILED;
|
||||
+ else if ((*status)->snap->has_metadata_sectors &&
|
||||
+ (*status)->snap->used_sectors == (*status)->snap->metadata_sectors)
|
||||
+ (*status)->usage = DM_PERCENT_0;
|
||||
+ else if ((*status)->snap->used_sectors == (*status)->snap->total_sectors)
|
||||
+ (*status)->usage = DM_PERCENT_100;
|
||||
+ else
|
||||
+ (*status)->usage = dm_make_percent((*status)->snap->used_sectors,
|
||||
+ (*status)->snap->total_sectors);
|
||||
+ r = 1;
|
||||
+out:
|
||||
+ dm_task_destroy(dmt);
|
||||
+
|
||||
+ return r;
|
||||
+}
|
||||
+
|
||||
/* FIXME Merge with snapshot_percent, auto-detecting target type */
|
||||
/* FIXME Cope with more than one target */
|
||||
int dev_manager_mirror_percent(struct dev_manager *dm,
|
||||
diff --git a/lib/activate/dev_manager.h b/lib/activate/dev_manager.h
|
||||
index 353c3c7d2..92c374a28 100644
|
||||
--- a/lib/activate/dev_manager.h
|
||||
+++ b/lib/activate/dev_manager.h
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
struct logical_volume;
|
||||
struct lv_activate_opts;
|
||||
+struct lv_status_snapshot;
|
||||
struct volume_group;
|
||||
struct cmd_context;
|
||||
struct dev_manager;
|
||||
@@ -56,6 +57,11 @@ int dev_manager_info(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
int dev_manager_snapshot_percent(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
dm_percent_t *percent);
|
||||
+int dev_manager_snapshot_status(struct dev_manager *dm,
|
||||
+ const struct logical_volume *lv,
|
||||
+ int flush,
|
||||
+ struct lv_status_snapshot **status,
|
||||
+ int *exists);
|
||||
int dev_manager_mirror_percent(struct dev_manager *dm,
|
||||
const struct logical_volume *lv, int wait,
|
||||
dm_percent_t *percent, uint32_t *event_nr);
|
||||
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
|
||||
index 42e3f2489..4397f0bc2 100644
|
||||
--- a/lib/metadata/lv_manip.c
|
||||
+++ b/lib/metadata/lv_manip.c
|
||||
@@ -5816,6 +5816,55 @@ static int _lv_reduce_vdo_discard(struct cmd_context *cmd,
|
||||
return 1;
|
||||
}
|
||||
|
||||
+static int _lv_resize_check_cow_reduce(struct logical_volume *lv,
|
||||
+ uint64_t new_size)
|
||||
+{
|
||||
+ struct cmd_context *cmd = lv->vg->cmd;
|
||||
+ struct lv_status_snapshot *snap_status;
|
||||
+ int r;
|
||||
+
|
||||
+ /*
|
||||
+ * COW snapshot must be active to check how many exception blocks are
|
||||
+ * in use. Reject when inactive to avoid silently truncating data.
|
||||
+ * If the snapshot content is not needed, remove it with lvremove.
|
||||
+ */
|
||||
+ if (!lv_is_active(lv_lock_holder(lv))) {
|
||||
+ log_error("Inactive snapshot %s cannot be reduced "
|
||||
+ "(activate or remove it).",
|
||||
+ display_lvname(lv));
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Reject reduce if it would truncate exception data already written
|
||||
+ * to the COW store. Flush so that in-flight writes are reflected
|
||||
+ * in the exception counts before we compare.
|
||||
+ */
|
||||
+ if ((r = lv_snapshot_status(lv, 1, &snap_status))) {
|
||||
+ /* merge_failed cannot occur here: merging snapshots are
|
||||
+ * rejected earlier in _lv_resize_check_type(); kept as
|
||||
+ * a defensive check.
|
||||
+ * overflow mode is currently not supported by lvm2
|
||||
+ * kept as a defensive check. */
|
||||
+ if (snap_status->snap->invalid ||
|
||||
+ snap_status->snap->merge_failed ||
|
||||
+ snap_status->snap->overflow) {
|
||||
+ log_error("Invalid snapshot %s cannot be reduced, only removed.",
|
||||
+ display_lvname(lv));
|
||||
+ r = 0;
|
||||
+ } else if (new_size < snap_status->snap->used_sectors) {
|
||||
+ log_error("Cannot reduce snapshot %s to below %s (%.2f%% full, would lose exception data).",
|
||||
+ display_lvname(lv),
|
||||
+ display_size(cmd, snap_status->snap->used_sectors),
|
||||
+ dm_percent_to_round_float(snap_status->usage, 2));
|
||||
+ r = 0;
|
||||
+ }
|
||||
+ dm_pool_destroy(snap_status->mem);
|
||||
+ }
|
||||
+
|
||||
+ return r;
|
||||
+}
|
||||
+
|
||||
static int _lv_resize_check_type(struct logical_volume *lv,
|
||||
struct lvresize_params *lp)
|
||||
{
|
||||
@@ -5888,6 +5937,9 @@ static int _lv_resize_check_type(struct logical_volume *lv,
|
||||
log_error("Cannot reduce LV with integrity.");
|
||||
return 0;
|
||||
}
|
||||
+ if (lv_is_cow(lv) &&
|
||||
+ !_lv_resize_check_cow_reduce(lv, (uint64_t)lp->extents * lv->vg->extent_size))
|
||||
+ return_0;
|
||||
} else if (lp->resize == LV_EXTEND) {
|
||||
if (lv_is_thin_pool_metadata(lv) &&
|
||||
(!(seg = find_pool_seg(first_seg(lv))) ||
|
||||
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
|
||||
index 7ec81f27d..a89d77284 100644
|
||||
--- a/lib/metadata/metadata-exported.h
|
||||
+++ b/lib/metadata/metadata-exported.h
|
||||
@@ -1201,6 +1201,11 @@ int vg_remove_snapshot(struct logical_volume *cow);
|
||||
|
||||
int validate_snapshot_origin(const struct logical_volume *origin_lv);
|
||||
|
||||
+struct lv_status_snapshot {
|
||||
+ struct dm_pool *mem;
|
||||
+ struct dm_status_snapshot *snap;
|
||||
+ dm_percent_t usage;
|
||||
+};
|
||||
|
||||
int vg_check_status(const struct volume_group *vg, uint64_t status);
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
36
0116-snapshot-reject-resize-of-merging-CoW-snapshot.patch
Normal file
36
0116-snapshot-reject-resize-of-merging-CoW-snapshot.patch
Normal file
@ -0,0 +1,36 @@
|
||||
From c0bd6195c00ef6d0e620c61ab05464424329a2e1 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Thu, 26 Feb 2026 21:57:52 +0100
|
||||
Subject: [PATCH 116/211] snapshot: reject resize of merging CoW snapshot
|
||||
|
||||
A snapshot that is in the process of merging back into its origin
|
||||
cannot be resized - the kernel runs a snapshot-merge target during
|
||||
the merge and resizing the COW store while the merge is in progress
|
||||
is not supported and could corrupt the operation.
|
||||
|
||||
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 152b0fe2ca6c5ac5482332b9352098a6f78d7d61)
|
||||
---
|
||||
lib/metadata/lv_manip.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
|
||||
index 4397f0bc2..783cd2c66 100644
|
||||
--- a/lib/metadata/lv_manip.c
|
||||
+++ b/lib/metadata/lv_manip.c
|
||||
@@ -5870,6 +5870,12 @@ static int _lv_resize_check_type(struct logical_volume *lv,
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
|
||||
+ if (lv_is_merging_cow(lv)) {
|
||||
+ log_error("Cannot resize merging snapshot %s.",
|
||||
+ display_lvname(lv));
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
if (lv_is_origin(lv)) {
|
||||
if (lp->resize == LV_REDUCE) {
|
||||
log_error("Snapshot origin volumes cannot be reduced in size yet.");
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,57 @@
|
||||
From 00b13dac560f293fa2a64b1e7e9dc0248bc88b45 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Thu, 26 Feb 2026 16:31:43 +0100
|
||||
Subject: [PATCH 117/211] lvresize: skip fs handling for CoW snapshot COW store
|
||||
LVs
|
||||
|
||||
The COW store LV has linear segments internally (it stores exception
|
||||
blocks), so lv_is_linear() returned true for it. This caused the
|
||||
fsopt disable check to be skipped, and LVM incorrectly ran fs_get_info()
|
||||
on the snapshot device which presents the origin filesystem data.
|
||||
|
||||
The result was a misleading error:
|
||||
File system xfs found on fedora/root-snap.
|
||||
File system size (9.00 GiB) is larger than the requested size (5.00 GiB).
|
||||
File system reduce is required and not supported (xfs).
|
||||
|
||||
Fix by explicitly excluding CoW snapshot LVs (lv_is_cow) from filesystem
|
||||
handling regardless of their underlying segment type.
|
||||
|
||||
Fixes: https://gitlab.com/lvmteam/lvm2/-/issues/27
|
||||
Fixes: https://github.com/lvmteam/lvm2/issues/163
|
||||
|
||||
TODO: might be worth to implemement -V options to allow resize
|
||||
of snapshot volume itself.
|
||||
|
||||
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 99639a37fb73b4a1e044ec822a562fb4608dda0e)
|
||||
---
|
||||
lib/metadata/lv_manip.c | 10 +++++++---
|
||||
1 file changed, 7 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
|
||||
index 783cd2c66..0fce14f21 100644
|
||||
--- a/lib/metadata/lv_manip.c
|
||||
+++ b/lib/metadata/lv_manip.c
|
||||
@@ -7050,11 +7050,15 @@ int lv_resize(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
|
||||
/*
|
||||
* Disable fsopt if LV type cannot hold a file system.
|
||||
+ * CoW snapshot LVs (the COW store) do not hold a filesystem even
|
||||
+ * though their segments are linear; the filesystem lives on the
|
||||
+ * origin LV and the COW store only holds exception blocks.
|
||||
*/
|
||||
if (lp->fsopt[0] &&
|
||||
- !(lv_is_linear(lv) || lv_is_striped(lv) || lv_is_raid(lv) ||
|
||||
- lv_is_mirror(lv) || lv_is_thin_volume(lv) || lv_is_vdo(lv) ||
|
||||
- lv_is_cache(lv) || lv_is_writecache(lv))) {
|
||||
+ (lv_is_cow(lv) ||
|
||||
+ !(lv_is_linear(lv) || lv_is_striped(lv) || lv_is_raid(lv) ||
|
||||
+ lv_is_mirror(lv) || lv_is_thin_volume(lv) || lv_is_vdo(lv) ||
|
||||
+ lv_is_cache(lv) || lv_is_writecache(lv)))) {
|
||||
log_print_unless_silent("Ignoring fs resizing options for LV type %s.",
|
||||
seg ? seg->segtype->name : "unknown");
|
||||
lp->fsopt[0] = '\0';
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
From 5c95e79a235f01c50f4d44a5a31b6afe6711958d Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 08:36:06 +0200
|
||||
Subject: [PATCH 118/211] metadata: fix vg_split_mdas losing first _move_mdas
|
||||
result
|
||||
|
||||
The second assignment to common_mda was overwriting the result from
|
||||
the first _move_mdas() call. If a common MDA was found in the in_use
|
||||
list but not in the ignored list, the information was lost. Use |=
|
||||
to accumulate results from both calls.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 14ba69b358c3c25be7fc3cc461677430ebd35d09)
|
||||
---
|
||||
lib/metadata/metadata.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
|
||||
index d15682fdb..ab037fd06 100644
|
||||
--- a/lib/metadata/metadata.c
|
||||
+++ b/lib/metadata/metadata.c
|
||||
@@ -1402,8 +1402,8 @@ int vg_split_mdas(struct cmd_context *cmd __attribute__((unused)),
|
||||
|
||||
common_mda = _move_mdas(vg_from, vg_to,
|
||||
mdas_from_in_use, mdas_to_in_use);
|
||||
- common_mda = _move_mdas(vg_from, vg_to,
|
||||
- mdas_from_ignored, mdas_to_ignored);
|
||||
+ common_mda |= _move_mdas(vg_from, vg_to,
|
||||
+ mdas_from_ignored, mdas_to_ignored);
|
||||
|
||||
if ((dm_list_empty(mdas_from_in_use) &&
|
||||
dm_list_empty(mdas_from_ignored)) ||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,43 @@
|
||||
From c51e71383068fc61ebfc8a241509454cda48c3fd Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 12:04:54 +0200
|
||||
Subject: [PATCH 119/211] libdm: stats: fix bitwise AND and use escaped
|
||||
aux_data
|
||||
|
||||
Fix two bugs:
|
||||
- Histogram parsing used bitwise & instead of logical && to check
|
||||
for unexpected characters, causing some chars to be missed.
|
||||
- stats_create message used unescaped aux_data instead of
|
||||
aux_data_escaped, defeating the escaping done just above.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 55f9f953c663a3f3545c6afe73e9d2d43ce7dcf1)
|
||||
---
|
||||
libdm/libdm-stats.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
|
||||
index 53c3c5480..6e6d63a8b 100644
|
||||
--- a/libdm/libdm-stats.c
|
||||
+++ b/libdm/libdm-stats.c
|
||||
@@ -1248,7 +1248,7 @@ static int _stats_parse_histogram(struct dm_pool *mem, char *hist_str,
|
||||
|
||||
if (*c == ':')
|
||||
c++;
|
||||
- else if (*c & (*c != '\n'))
|
||||
+ else if (*c && (*c != '\n'))
|
||||
/* Expected ':', '\n', or NULL. */
|
||||
goto badchar;
|
||||
|
||||
@@ -2060,7 +2060,7 @@ static int _stats_create_region(struct dm_stats *dms, uint64_t *region_id,
|
||||
" %s %s %s", (start || len) ? range : "-",
|
||||
(step < 0) ? "/" : "",
|
||||
(uint64_t)llabs(step),
|
||||
- opt_args, program_id, aux_data) < 0) {
|
||||
+ opt_args, program_id, aux_data_escaped) < 0) {
|
||||
err = "message";
|
||||
goto_bad;
|
||||
}
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
From 103e03c497d82b7338780b25549852c9345d0fb8 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 12:06:47 +0200
|
||||
Subject: [PATCH 120/211] libdm: report: fix missing negation in time range
|
||||
not-equal
|
||||
|
||||
The NOT-EQUAL case for time comparison was returning the same
|
||||
expression as EQUAL when a range was specified, missing the
|
||||
negation. The int and double comparison functions have it correct.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit f3ffd13dd1d91559812579b63779d91559467968)
|
||||
---
|
||||
libdm/libdm-report.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libdm/libdm-report.c b/libdm/libdm-report.c
|
||||
index 87c588c3c..f2f0774cd 100644
|
||||
--- a/libdm/libdm-report.c
|
||||
+++ b/libdm/libdm-report.c
|
||||
@@ -1731,7 +1731,7 @@ static int _cmp_field_time(struct dm_report *rh,
|
||||
case FLD_CMP_EQUAL:
|
||||
return range ? ((val >= sel1) && (val <= sel2)) : val == sel1;
|
||||
case FLD_CMP_NOT|FLD_CMP_EQUAL:
|
||||
- return range ? ((val >= sel1) && (val <= sel2)) : val != sel1;
|
||||
+ return range ? !((val >= sel1) && (val <= sel2)) : val != sel1;
|
||||
case FLD_CMP_TIME|FLD_CMP_GT:
|
||||
if (_check_value_is_strictly_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_TIME, &val, fs))
|
||||
return 0;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
62
0121-libdm-report-fix-row-sorting-of-percent-fields.patch
Normal file
62
0121-libdm-report-fix-row-sorting-of-percent-fields.patch
Normal file
@ -0,0 +1,62 @@
|
||||
From 9af697082ac096eb6eaff7acf7ebaef81a4a2940 Mon Sep 17 00:00:00 2001
|
||||
From: Peter Rajnoha <prajnoha@redhat.com>
|
||||
Date: Thu, 26 Mar 2026 16:34:04 +0100
|
||||
Subject: [PATCH 121/211] libdm: report: fix row sorting of percent fields
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
_row_compare was treating the sort_value of DM_REPORT_FIELD_TYPE_PERCENT
|
||||
fields as plain char pointer, but it is actually an integer. This
|
||||
caused incorrect sorting of these fields.
|
||||
|
||||
For example, before this patch:
|
||||
|
||||
❯ lvs -o lv_name,data_percent -O data_percent vg
|
||||
lv_name data_percent
|
||||
pool2 20.00
|
||||
pool 100.00
|
||||
lvol3 0.00
|
||||
lvol4 0.00
|
||||
lvol7 0.00
|
||||
lvol6 1.95
|
||||
lvol2 9.77
|
||||
|
||||
With this patch applied:
|
||||
|
||||
❯ lvs -o lv_name,data_percent -O data_percent vg
|
||||
lv_name data_percent
|
||||
lvol3 0.00
|
||||
lvol4 0.00
|
||||
lvol7 0.00
|
||||
lvol6 1.95
|
||||
lvol2 9.77
|
||||
pool2 20.00
|
||||
pool 100.00
|
||||
|
||||
(cherry picked from commit 1e80cdad1e7e20825040e9a80ffeff39719d5ca8)
|
||||
---
|
||||
libdm/libdm-report.c | 7 ++++---
|
||||
1 file changed, 4 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/libdm/libdm-report.c b/libdm/libdm-report.c
|
||||
index f2f0774cd..6022fef8f 100644
|
||||
--- a/libdm/libdm-report.c
|
||||
+++ b/libdm/libdm-report.c
|
||||
@@ -4623,9 +4623,10 @@ static int _row_compare(const void *a, const void *b)
|
||||
sfa = (*rowa->sort_fields)[cnt];
|
||||
sfb = (*rowb->sort_fields)[cnt];
|
||||
if (sfa->props->flags &
|
||||
- ((DM_REPORT_FIELD_TYPE_NUMBER) |
|
||||
- (DM_REPORT_FIELD_TYPE_SIZE) |
|
||||
- (DM_REPORT_FIELD_TYPE_TIME))) {
|
||||
+ (DM_REPORT_FIELD_TYPE_NUMBER |
|
||||
+ DM_REPORT_FIELD_TYPE_SIZE |
|
||||
+ DM_REPORT_FIELD_TYPE_PERCENT |
|
||||
+ DM_REPORT_FIELD_TYPE_TIME)) {
|
||||
const uint64_t numa =
|
||||
*(const uint64_t *) sfa->sort_value;
|
||||
const uint64_t numb =
|
||||
--
|
||||
2.54.0
|
||||
|
||||
80
0122-libdm-fix-row-sorting-for-string-list-fields.patch
Normal file
80
0122-libdm-fix-row-sorting-for-string-list-fields.patch
Normal file
@ -0,0 +1,80 @@
|
||||
From f62fa4b34736978650523e2ffed0d6d0acb249a1 Mon Sep 17 00:00:00 2001
|
||||
From: Peter Rajnoha <prajnoha@redhat.com>
|
||||
Date: Thu, 26 Mar 2026 12:42:32 +0100
|
||||
Subject: [PATCH 122/211] libdm: fix row sorting for string list fields
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
_row_compare was treating the sort_value of DM_REPORT_FIELD_TYPE_STRING_LIST
|
||||
fields as a plain char pointer, but it is actually a pointer to
|
||||
struct str_list_sort_value. This caused strcmp to compare the raw bytes
|
||||
of the struct (starting with a pointer) instead of the actual string
|
||||
content, producing effectively random sort order for string list fields.
|
||||
|
||||
Fix by extracting the display string (sortval->value) from
|
||||
str_list_sort_value before comparing with strcmp.
|
||||
|
||||
For example, before this patch:
|
||||
|
||||
❯ lvs -o lv_name,lv_layout -O lv_layout vg
|
||||
lv_name lv_layout
|
||||
lvol5 raid,raid1
|
||||
lvol4 thin,sparse
|
||||
lvol3 thin,sparse
|
||||
lvol2 thin,sparse
|
||||
lvol0 raid,raid1
|
||||
pool thin,pool
|
||||
|
||||
With this patch applied:
|
||||
|
||||
❯ lvs -o lv_name,lv_layout -O lv_layout vg
|
||||
lv_name lv_layout
|
||||
lvol0 raid,raid1
|
||||
lvol5 raid,raid1
|
||||
pool thin,pool
|
||||
lvol2 thin,sparse
|
||||
lvol3 thin,sparse
|
||||
lvol4 thin,sparse
|
||||
|
||||
Co-Authored-By: Claude <noreply@anthropic.com>
|
||||
(cherry picked from commit 424e995f6daeb56eeccec4b3d54d151d4e259040)
|
||||
---
|
||||
libdm/libdm-report.c | 20 +++++++++++++++-----
|
||||
1 file changed, 15 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/libdm/libdm-report.c b/libdm/libdm-report.c
|
||||
index 6022fef8f..13bc9a1e5 100644
|
||||
--- a/libdm/libdm-report.c
|
||||
+++ b/libdm/libdm-report.c
|
||||
@@ -4640,12 +4640,22 @@ static int _row_compare(const void *a, const void *b)
|
||||
} else { /* FLD_DESCENDING */
|
||||
return (numa < numb) ? 1 : -1;
|
||||
}
|
||||
+ } else if (sfa->props->flags & DM_REPORT_FIELD_TYPE_STRING_LIST) {
|
||||
+ int cmp = strcmp(((const struct str_list_sort_value *) sfa->sort_value)->value,
|
||||
+ ((const struct str_list_sort_value *) sfb->sort_value)->value);
|
||||
+
|
||||
+ if (!cmp)
|
||||
+ continue;
|
||||
+
|
||||
+ if (sfa->props->flags & FLD_ASCENDING) {
|
||||
+ return (cmp > 0) ? 1 : -1;
|
||||
+ } else { /* FLD_DESCENDING */
|
||||
+ return (cmp < 0) ? 1 : -1;
|
||||
+ }
|
||||
} else {
|
||||
- /* DM_REPORT_FIELD_TYPE_STRING
|
||||
- * DM_REPORT_FIELD_TYPE_STRING_LIST */
|
||||
- const char *stra = (const char *) sfa->sort_value;
|
||||
- const char *strb = (const char *) sfb->sort_value;
|
||||
- int cmp = strcmp(stra, strb);
|
||||
+ /* DM_REPORT_FIELD_TYPE_STRING and others */
|
||||
+ int cmp = strcmp((const char *) sfa->sort_value,
|
||||
+ (const char *) sfb->sort_value);
|
||||
|
||||
if (!cmp)
|
||||
continue;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
130
0123-libdm-report-fix-row-sorting-for-string-list-fields-.patch
Normal file
130
0123-libdm-report-fix-row-sorting-for-string-list-fields-.patch
Normal file
@ -0,0 +1,130 @@
|
||||
From 78dc9788be1a9296340f66b3168a6fd48dbf31b1 Mon Sep 17 00:00:00 2001
|
||||
From: Peter Rajnoha <prajnoha@redhat.com>
|
||||
Date: Thu, 26 Mar 2026 12:42:32 +0100
|
||||
Subject: [PATCH 123/211] libdm: report: fix row sorting for string list fields
|
||||
(continued)
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
(extending commit 424e995f6daeb56eeccec4b3d54d151d4e259040)
|
||||
|
||||
_row_compare was treating the sort_value of DM_REPORT_FIELD_TYPE_STRING_LIST
|
||||
fields as plain char pointer, but it was actually a pointer to
|
||||
struct str_list_sort_value. This caused incorrect sorting of these fields.
|
||||
|
||||
Also add an internal error report if a field type is not handled
|
||||
for sorting, so we notice if a new type is added without a sorting
|
||||
handler.
|
||||
|
||||
For example, before this patch:
|
||||
|
||||
❯ lvs -o lv_name,lv_layout -O lv_layout vg
|
||||
lv_name lv_layout
|
||||
lvol5 raid,raid1
|
||||
lvol4 thin,sparse
|
||||
lvol3 thin,sparse
|
||||
lvol2 thin,sparse
|
||||
lvol0 raid,raid1
|
||||
pool thin,pool
|
||||
|
||||
With this patch applied:
|
||||
|
||||
❯ lvs -o lv_name,lv_layout -O lv_layout vg
|
||||
lv_name lv_layout
|
||||
lvol0 raid,raid1
|
||||
lvol5 raid,raid1
|
||||
pool thin,pool
|
||||
lvol2 thin,sparse
|
||||
lvol3 thin,sparse
|
||||
lvol4 thin,sparse
|
||||
|
||||
Co-Authored-By: Claude <noreply@anthropic.com>
|
||||
(cherry picked from commit fabee343f79327bcfd9ca653bfcd4af4c03ad693)
|
||||
---
|
||||
libdm/libdm-report.c | 52 ++++++++++++++++++++------------------------
|
||||
1 file changed, 24 insertions(+), 28 deletions(-)
|
||||
|
||||
diff --git a/libdm/libdm-report.c b/libdm/libdm-report.c
|
||||
index 13bc9a1e5..a92f96720 100644
|
||||
--- a/libdm/libdm-report.c
|
||||
+++ b/libdm/libdm-report.c
|
||||
@@ -4618,10 +4618,12 @@ static int _row_compare(const void *a, const void *b)
|
||||
const struct row *rowb = *(const struct row * const *) b;
|
||||
const struct dm_report_field *sfa, *sfb;
|
||||
uint32_t cnt;
|
||||
+ int cmp;
|
||||
|
||||
for (cnt = 0; cnt < rowa->rh->keys_count; cnt++) {
|
||||
sfa = (*rowa->sort_fields)[cnt];
|
||||
sfb = (*rowb->sort_fields)[cnt];
|
||||
+
|
||||
if (sfa->props->flags &
|
||||
(DM_REPORT_FIELD_TYPE_NUMBER |
|
||||
DM_REPORT_FIELD_TYPE_SIZE |
|
||||
@@ -4632,40 +4634,34 @@ static int _row_compare(const void *a, const void *b)
|
||||
const uint64_t numb =
|
||||
*(const uint64_t *) sfb->sort_value;
|
||||
|
||||
- if (numa == numb)
|
||||
- continue;
|
||||
+ cmp = (numa == numb) ? 0 : (numa > numb) ? 1 : -1;
|
||||
+ } else if (sfa->props->flags &
|
||||
+ (DM_REPORT_FIELD_TYPE_STRING |
|
||||
+ DM_REPORT_FIELD_TYPE_STRING_LIST)) {
|
||||
+ const char *stra, *strb;
|
||||
|
||||
- if (sfa->props->flags & FLD_ASCENDING) {
|
||||
- return (numa > numb) ? 1 : -1;
|
||||
- } else { /* FLD_DESCENDING */
|
||||
- return (numa < numb) ? 1 : -1;
|
||||
+ if (sfa->props->flags & DM_REPORT_FIELD_TYPE_STRING_LIST) {
|
||||
+ stra = ((const struct str_list_sort_value *) sfa->sort_value)->value;
|
||||
+ strb = ((const struct str_list_sort_value *) sfb->sort_value)->value;
|
||||
+ } else {
|
||||
+ stra = (const char *) sfa->sort_value;
|
||||
+ strb = (const char *) sfb->sort_value;
|
||||
}
|
||||
- } else if (sfa->props->flags & DM_REPORT_FIELD_TYPE_STRING_LIST) {
|
||||
- int cmp = strcmp(((const struct str_list_sort_value *) sfa->sort_value)->value,
|
||||
- ((const struct str_list_sort_value *) sfb->sort_value)->value);
|
||||
|
||||
- if (!cmp)
|
||||
- continue;
|
||||
-
|
||||
- if (sfa->props->flags & FLD_ASCENDING) {
|
||||
- return (cmp > 0) ? 1 : -1;
|
||||
- } else { /* FLD_DESCENDING */
|
||||
- return (cmp < 0) ? 1 : -1;
|
||||
- }
|
||||
+ cmp = strcmp(stra, strb);
|
||||
} else {
|
||||
- /* DM_REPORT_FIELD_TYPE_STRING and others */
|
||||
- int cmp = strcmp((const char *) sfa->sort_value,
|
||||
- (const char *) sfb->sort_value);
|
||||
+ log_err_once(INTERNAL_ERROR "_row_compare: unhandled field type: %#x",
|
||||
+ sfa->props->flags & DM_REPORT_FIELD_TYPE_MASK);
|
||||
+ return 0;
|
||||
+ }
|
||||
|
||||
- if (!cmp)
|
||||
- continue;
|
||||
+ if (!cmp)
|
||||
+ continue;
|
||||
|
||||
- if (sfa->props->flags & FLD_ASCENDING) {
|
||||
- return (cmp > 0) ? 1 : -1;
|
||||
- } else { /* FLD_DESCENDING */
|
||||
- return (cmp < 0) ? 1 : -1;
|
||||
- }
|
||||
- }
|
||||
+ if (sfa->props->flags & FLD_ASCENDING)
|
||||
+ return (cmp > 0) ? 1 : -1;
|
||||
+ else /* FLD_DESCENDING */
|
||||
+ return (cmp < 0) ? 1 : -1;
|
||||
}
|
||||
|
||||
return 0; /* Identical */
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
From e106d5239e4687f27cefff9812b3028111df6838 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 08:59:00 +0200
|
||||
Subject: [PATCH 124/211] device_id: fix checking wrong buffer after
|
||||
format_general_id
|
||||
|
||||
Check outbuf (the output buffer) instead of buf (the input buffer)
|
||||
after format_general_id, matching the correct pattern at line 805.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 4116375f61cad895d0bce2f2ff0ee03ef5188e85)
|
||||
---
|
||||
lib/device/device_id.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/device/device_id.c b/lib/device/device_id.c
|
||||
index 6ec8f43ba..a55074c3c 100644
|
||||
--- a/lib/device/device_id.c
|
||||
+++ b/lib/device/device_id.c
|
||||
@@ -821,7 +821,7 @@ static int _dev_read_sys_serial(struct cmd_context *cmd, struct device *dev,
|
||||
ret = 0;
|
||||
if (ret) {
|
||||
format_general_id((const char *)buf, sizeof(buf), (unsigned char *)outbuf, outbufsize);
|
||||
- if (buf[0])
|
||||
+ if (outbuf[0])
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
--
|
||||
2.54.0
|
||||
|
||||
111
0125-device_id-prevent-incorrect-dm-uuid-idtype.patch
Normal file
111
0125-device_id-prevent-incorrect-dm-uuid-idtype.patch
Normal file
@ -0,0 +1,111 @@
|
||||
From 56b263eb9f539e7bc07b0666780048addbfcaede Mon Sep 17 00:00:00 2001
|
||||
From: David Teigland <teigland@redhat.com>
|
||||
Date: Thu, 6 Nov 2025 16:45:28 -0600
|
||||
Subject: [PATCH 125/211] device_id: prevent incorrect dm uuid idtype
|
||||
|
||||
If a dm-uuid-based device was added to system.devices, and
|
||||
the wrong dm-based type was specified, then the system.devices
|
||||
entry would have the correct idname but the wrong idtype. e.g.
|
||||
|
||||
lvmdevices --adddev /dev/mapper/mpatha --deviceidtype crypt_uuid
|
||||
would add an entry with: IDTYPE=crypt_uuid IDNAME=mpath-<uuid>
|
||||
rather than the correct: IDTYPE=mpath_uuid IDNAME=mpath-<uuid>
|
||||
|
||||
This mistaken type would not affect lvm, and the device would
|
||||
be entirely usable. The dm-based types (mpath, crypt, lvmlv)
|
||||
were interchangable because they all read the device id from
|
||||
the same dm/uuid sysfs file.
|
||||
|
||||
Fix this by adding a missing check that the dm uuid prefix is
|
||||
correct for the specified idtype. Also, accept an existing
|
||||
system.devices file which contains this mistake.
|
||||
|
||||
(cherry picked from commit f0b991a9ef9b0e232cf38df44693a1b935ed93d3)
|
||||
---
|
||||
lib/device/device_id.c | 54 +++++++++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 53 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/device/device_id.c b/lib/device/device_id.c
|
||||
index a55074c3c..91c998fe2 100644
|
||||
--- a/lib/device/device_id.c
|
||||
+++ b/lib/device/device_id.c
|
||||
@@ -845,9 +845,22 @@ char *device_id_system_read(struct cmd_context *cmd, struct device *dev, uint16_
|
||||
_dev_read_sys_serial(cmd, dev, sysbuf, sizeof(sysbuf));
|
||||
break;
|
||||
case DEV_ID_TYPE_MPATH_UUID:
|
||||
+ if (!dev_dm_uuid(cmd, dev, sysbuf, sizeof(sysbuf)))
|
||||
+ stack;
|
||||
+ if (sysbuf[0] && !dm_uuid_has_prefix(sysbuf, "mpath-"))
|
||||
+ sysbuf[0] = '\0';
|
||||
+ break;
|
||||
case DEV_ID_TYPE_CRYPT_UUID:
|
||||
+ if (!dev_dm_uuid(cmd, dev, sysbuf, sizeof(sysbuf)))
|
||||
+ stack;
|
||||
+ if (sysbuf[0] && !dm_uuid_has_prefix(sysbuf, "CRYPT-"))
|
||||
+ sysbuf[0] = '\0';
|
||||
+ break;
|
||||
case DEV_ID_TYPE_LVMLV_UUID:
|
||||
- (void)dev_dm_uuid(cmd, dev, sysbuf, sizeof(sysbuf));
|
||||
+ if (!dev_dm_uuid(cmd, dev, sysbuf, sizeof(sysbuf)))
|
||||
+ stack;
|
||||
+ if (sysbuf[0] && !dm_uuid_has_prefix(sysbuf, "LVM-"))
|
||||
+ sysbuf[0] = '\0';
|
||||
break;
|
||||
case DEV_ID_TYPE_MD_UUID:
|
||||
read_sys_block(cmd, dev, "md/uuid", sysbuf, sizeof(sysbuf));
|
||||
@@ -2524,6 +2537,33 @@ static int _match_dm_names(struct cmd_context *cmd, char *idname, struct device
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void _replace_incorrect_dm_idtype(struct dev_use *du)
|
||||
+{
|
||||
+ /* Previous bug let one of these types be swapped for another
|
||||
+ because they all read their value from sysfs file dm/uuid. */
|
||||
+ if (du->idtype != DEV_ID_TYPE_MPATH_UUID &&
|
||||
+ du->idtype != DEV_ID_TYPE_CRYPT_UUID &&
|
||||
+ du->idtype != DEV_ID_TYPE_LVMLV_UUID)
|
||||
+ return;
|
||||
+
|
||||
+ /* Use the IDNAME value to determine the correct IDTYPE. */
|
||||
+ if (dm_uuid_has_prefix(du->idname, "mpath-") && (du->idtype != DEV_ID_TYPE_MPATH_UUID)) {
|
||||
+ log_debug("replace incorrect mpath device id type for %u %s", du->idtype, du->idname);
|
||||
+ du->idtype = DEV_ID_TYPE_MPATH_UUID;
|
||||
+ return;
|
||||
+ }
|
||||
+ if (dm_uuid_has_prefix(du->idname, "CRYPT-") && (du->idtype != DEV_ID_TYPE_CRYPT_UUID)) {
|
||||
+ log_debug("replace incorrect crypt device id type for %u %s", du->idtype, du->idname);
|
||||
+ du->idtype = DEV_ID_TYPE_CRYPT_UUID;
|
||||
+ return;
|
||||
+ }
|
||||
+ if (dm_uuid_has_prefix(du->idname, "LVM-") && (du->idtype != DEV_ID_TYPE_LVMLV_UUID)) {
|
||||
+ log_debug("replace incorrect lvmlv device id type for %u %s", du->idtype, du->idname);
|
||||
+ du->idtype = DEV_ID_TYPE_LVMLV_UUID;
|
||||
+ return;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* du is a devices file entry. dev is any device on the system.
|
||||
* check if du is for dev by comparing the device's ids to du->idname.
|
||||
@@ -2634,6 +2674,18 @@ static int _match_du_to_dev(struct cmd_context *cmd, struct dev_use *du, struct
|
||||
_reduce_repeating_underscores(du_idname, sizeof(du_idname));
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * A past bug allowed mpath, crypt, or lvm devices to be added to
|
||||
+ * system.devices using any of the dm id types, and they could be
|
||||
+ * used normally. Accept an old system.devices with that mistake
|
||||
+ * by updating du->idtype to have the correct idtype based on the
|
||||
+ * idname dm prefix.
|
||||
+ */
|
||||
+ if (((du->idtype == DEV_ID_TYPE_MPATH_UUID) && !dm_uuid_has_prefix(du->idname, "mpath-")) ||
|
||||
+ ((du->idtype == DEV_ID_TYPE_CRYPT_UUID) && !dm_uuid_has_prefix(du->idname, "CRYPT-")) ||
|
||||
+ ((du->idtype == DEV_ID_TYPE_LVMLV_UUID) && !dm_uuid_has_prefix(du->idname, "LVM")))
|
||||
+ _replace_incorrect_dm_idtype(du);
|
||||
+
|
||||
/*
|
||||
* Try to match du with ids that have already been read for the dev
|
||||
* (and saved on dev->ids to avoid rereading.)
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
From 0ecb57749f1bb0971510bf4c1a1692d0a4a51525 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 11:12:02 +0200
|
||||
Subject: [PATCH 126/211] lvmcmdline: fix line-too-long check using wrong
|
||||
buffer index
|
||||
|
||||
The expression buffer[sizeof(buffer) - 1] - 2 performed arithmetic
|
||||
on the char value at the last position instead of indexing position
|
||||
sizeof(buffer) - 2 to check for newline.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 79eca4f6a5061c9ec4f544122edd341799d38ec6)
|
||||
---
|
||||
tools/lvmcmdline.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
|
||||
index 2ecdbd164..df11f57ab 100644
|
||||
--- a/tools/lvmcmdline.c
|
||||
+++ b/tools/lvmcmdline.c
|
||||
@@ -3526,7 +3526,7 @@ static int _run_script(struct cmd_context *cmd, int argc, char **argv)
|
||||
}
|
||||
}
|
||||
if ((strlen(buffer) == sizeof(buffer) - 1)
|
||||
- && (buffer[sizeof(buffer) - 1] - 2 != '\n')) {
|
||||
+ && (buffer[sizeof(buffer) - 2] != '\n')) {
|
||||
buffer[50] = '\0';
|
||||
log_error("Line too long (max 255) beginning: %s",
|
||||
buffer);
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
From 007326d4b11a22bc27e3e96ebd45d63f009ac82a Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 08:33:48 +0200
|
||||
Subject: [PATCH 127/211] report: fix lvseg_metadata_devices_str calling wrong
|
||||
function
|
||||
|
||||
lvseg_metadata_devices_str() was calling lvseg_devices() instead
|
||||
of lvseg_metadata_devices(), causing the metadata_devices report
|
||||
field to return data devices instead of metadata devices.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit aba1e6f1aed9cf2cf22ba53b54f06462107426b7)
|
||||
---
|
||||
lib/metadata/lv.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c
|
||||
index d201244a7..164ad7aba 100644
|
||||
--- a/lib/metadata/lv.c
|
||||
+++ b/lib/metadata/lv.c
|
||||
@@ -158,7 +158,7 @@ char *lvseg_metadata_devices_str(struct dm_pool *mem, const struct lv_segment *s
|
||||
{
|
||||
struct dm_list *list;
|
||||
|
||||
- if (!(list = lvseg_devices(mem, seg)))
|
||||
+ if (!(list = lvseg_metadata_devices(mem, seg)))
|
||||
return_NULL;
|
||||
|
||||
return str_list_to_str(mem, list, ",");
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
From 9e70f14abecee521f3036d0a8bca90646f8f83c2 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 08:34:15 +0200
|
||||
Subject: [PATCH 128/211] report: fix lvseg_seg_le_ranges_str calling wrong
|
||||
function
|
||||
|
||||
lvseg_seg_le_ranges_str() was calling lvseg_seg_pe_ranges() instead
|
||||
of lvseg_seg_le_ranges(), missing the report_mark_hidden_devices flag.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 826632ee8890fd9305f270f6c3ee09ad4fd8422c)
|
||||
---
|
||||
lib/metadata/lv.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c
|
||||
index 164ad7aba..7476cef8d 100644
|
||||
--- a/lib/metadata/lv.c
|
||||
+++ b/lib/metadata/lv.c
|
||||
@@ -188,7 +188,7 @@ char *lvseg_seg_le_ranges_str(struct dm_pool *mem, const struct lv_segment *seg)
|
||||
{
|
||||
struct dm_list *list;
|
||||
|
||||
- if (!(list = lvseg_seg_pe_ranges(mem, seg)))
|
||||
+ if (!(list = lvseg_seg_le_ranges(mem, seg)))
|
||||
return_NULL;
|
||||
|
||||
return str_list_to_str(mem, list, seg->lv->vg->cmd->report_list_item_separator);
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
From 84f108796ba80141465c035de75d36ac52a08b23 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 11:42:41 +0200
|
||||
Subject: [PATCH 129/211] vgchange: add NULL check for vg->system_id before
|
||||
strcmp
|
||||
|
||||
vg->system_id can be NULL (set in vg.c and metadata.c), so
|
||||
strcmp without a NULL check may cause undefined behavior.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 0e95d6933e2901e765a34d849f70ad718af66cf5)
|
||||
---
|
||||
tools/vgchange.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tools/vgchange.c b/tools/vgchange.c
|
||||
index deefbfe6d..2ffd73ca1 100644
|
||||
--- a/tools/vgchange.c
|
||||
+++ b/tools/vgchange.c
|
||||
@@ -559,7 +559,7 @@ static int _vgchange_system_id(struct cmd_context *cmd, struct volume_group *vg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
- if (!strcmp(vg->system_id, system_id)) {
|
||||
+ if (vg->system_id && !strcmp(vg->system_id, system_id)) {
|
||||
log_error("Volume Group system ID is already \"%s\".", vg->system_id);
|
||||
return 0;
|
||||
}
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
From 6adbfc16d1b8ba3d15bb7dc5d0e1998bb75349a5 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 11:59:23 +0200
|
||||
Subject: [PATCH 130/211] libdm: iface: use st_rdev instead of st_mode for
|
||||
MAJOR/MINOR
|
||||
|
||||
The log message was extracting major/minor from buf.st_mode
|
||||
(file type/permissions) instead of buf.st_rdev (device number).
|
||||
The comparison on line above correctly uses buf.st_rdev.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 42fb34bcf836c3356bf8f23d24bac2fe34d35346)
|
||||
---
|
||||
libdm/ioctl/libdm-iface.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libdm/ioctl/libdm-iface.c b/libdm/ioctl/libdm-iface.c
|
||||
index 3a3060475..4bbb40a7d 100644
|
||||
--- a/libdm/ioctl/libdm-iface.c
|
||||
+++ b/libdm/ioctl/libdm-iface.c
|
||||
@@ -278,8 +278,8 @@ static int _control_exists(const char *control, uint32_t major, uint32_t minor)
|
||||
|
||||
if (major && buf.st_rdev != MKDEV(major, minor)) {
|
||||
log_verbose("%s: Wrong device number: (%u, %u) instead of "
|
||||
- "(%u, %u)", control,
|
||||
- MAJOR(buf.st_mode), MINOR(buf.st_mode),
|
||||
+ "(%u, %u).", control,
|
||||
+ MAJOR(buf.st_rdev), MINOR(buf.st_rdev),
|
||||
major, minor);
|
||||
return _control_unlink(control);
|
||||
}
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
From c238b6ccc110030a272b1d07e229edc2e0db28e6 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 01:25:37 +0200
|
||||
Subject: [PATCH 131/211] lvmcache: fix unnecessary address-of on array in
|
||||
memcmp
|
||||
|
||||
Remove extra '&' before 'pvid' array in _get_pvsummary_device_id
|
||||
memcmp call, matching the style of the other two pvsummary functions.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 27afb397ff88c514cf21a4b02a1e04f5c04a8332)
|
||||
---
|
||||
lib/cache/lvmcache.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
|
||||
index 1effc254c..4c95db7db 100644
|
||||
--- a/lib/cache/lvmcache.c
|
||||
+++ b/lib/cache/lvmcache.c
|
||||
@@ -524,7 +524,7 @@ static const char *_get_pvsummary_device_id(const char *pvid_arg, const char **d
|
||||
|
||||
dm_list_iterate_items(vginfo, &_vginfos) {
|
||||
dm_list_iterate_items(pvl, &vginfo->pvsummaries) {
|
||||
- if (!memcmp(&pvid, &pvl->pv->id.uuid, ID_LEN)) {
|
||||
+ if (!memcmp(pvid, &pvl->pv->id.uuid, ID_LEN)) {
|
||||
*device_id_type = pvl->pv->device_id_type;
|
||||
return pvl->pv->device_id;
|
||||
}
|
||||
--
|
||||
2.54.0
|
||||
|
||||
115
0132-RHEL9-fix-compilation-issues.patch
Normal file
115
0132-RHEL9-fix-compilation-issues.patch
Normal file
@ -0,0 +1,115 @@
|
||||
From 444317ac2c2c6d40271c1e4ced0c95726c925de5 Mon Sep 17 00:00:00 2001
|
||||
From: Marian Csontos <mcsontos@redhat.com>
|
||||
Date: Fri, 15 May 2026 10:34:34 +0200
|
||||
Subject: [PATCH 132/211] RHEL9: fix compilation issues
|
||||
|
||||
---
|
||||
lib/device/device_id.c | 18 +++++++++---------
|
||||
lib/metadata/lv.c | 2 +-
|
||||
lib/report/report.c | 2 +-
|
||||
tools/reporter.c | 2 +-
|
||||
4 files changed, 12 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/lib/device/device_id.c b/lib/device/device_id.c
|
||||
index 91c998fe2..a83257e50 100644
|
||||
--- a/lib/device/device_id.c
|
||||
+++ b/lib/device/device_id.c
|
||||
@@ -847,19 +847,19 @@ char *device_id_system_read(struct cmd_context *cmd, struct device *dev, uint16_
|
||||
case DEV_ID_TYPE_MPATH_UUID:
|
||||
if (!dev_dm_uuid(cmd, dev, sysbuf, sizeof(sysbuf)))
|
||||
stack;
|
||||
- if (sysbuf[0] && !dm_uuid_has_prefix(sysbuf, "mpath-"))
|
||||
+ if (sysbuf[0] && !_dm_uuid_has_prefix(sysbuf, "mpath-"))
|
||||
sysbuf[0] = '\0';
|
||||
break;
|
||||
case DEV_ID_TYPE_CRYPT_UUID:
|
||||
if (!dev_dm_uuid(cmd, dev, sysbuf, sizeof(sysbuf)))
|
||||
stack;
|
||||
- if (sysbuf[0] && !dm_uuid_has_prefix(sysbuf, "CRYPT-"))
|
||||
+ if (sysbuf[0] && !_dm_uuid_has_prefix(sysbuf, "CRYPT-"))
|
||||
sysbuf[0] = '\0';
|
||||
break;
|
||||
case DEV_ID_TYPE_LVMLV_UUID:
|
||||
if (!dev_dm_uuid(cmd, dev, sysbuf, sizeof(sysbuf)))
|
||||
stack;
|
||||
- if (sysbuf[0] && !dm_uuid_has_prefix(sysbuf, "LVM-"))
|
||||
+ if (sysbuf[0] && !_dm_uuid_has_prefix(sysbuf, "LVM-"))
|
||||
sysbuf[0] = '\0';
|
||||
break;
|
||||
case DEV_ID_TYPE_MD_UUID:
|
||||
@@ -2547,17 +2547,17 @@ static void _replace_incorrect_dm_idtype(struct dev_use *du)
|
||||
return;
|
||||
|
||||
/* Use the IDNAME value to determine the correct IDTYPE. */
|
||||
- if (dm_uuid_has_prefix(du->idname, "mpath-") && (du->idtype != DEV_ID_TYPE_MPATH_UUID)) {
|
||||
+ if (_dm_uuid_has_prefix(du->idname, "mpath-") && (du->idtype != DEV_ID_TYPE_MPATH_UUID)) {
|
||||
log_debug("replace incorrect mpath device id type for %u %s", du->idtype, du->idname);
|
||||
du->idtype = DEV_ID_TYPE_MPATH_UUID;
|
||||
return;
|
||||
}
|
||||
- if (dm_uuid_has_prefix(du->idname, "CRYPT-") && (du->idtype != DEV_ID_TYPE_CRYPT_UUID)) {
|
||||
+ if (_dm_uuid_has_prefix(du->idname, "CRYPT-") && (du->idtype != DEV_ID_TYPE_CRYPT_UUID)) {
|
||||
log_debug("replace incorrect crypt device id type for %u %s", du->idtype, du->idname);
|
||||
du->idtype = DEV_ID_TYPE_CRYPT_UUID;
|
||||
return;
|
||||
}
|
||||
- if (dm_uuid_has_prefix(du->idname, "LVM-") && (du->idtype != DEV_ID_TYPE_LVMLV_UUID)) {
|
||||
+ if (_dm_uuid_has_prefix(du->idname, "LVM-") && (du->idtype != DEV_ID_TYPE_LVMLV_UUID)) {
|
||||
log_debug("replace incorrect lvmlv device id type for %u %s", du->idtype, du->idname);
|
||||
du->idtype = DEV_ID_TYPE_LVMLV_UUID;
|
||||
return;
|
||||
@@ -2681,9 +2681,9 @@ static int _match_du_to_dev(struct cmd_context *cmd, struct dev_use *du, struct
|
||||
* by updating du->idtype to have the correct idtype based on the
|
||||
* idname dm prefix.
|
||||
*/
|
||||
- if (((du->idtype == DEV_ID_TYPE_MPATH_UUID) && !dm_uuid_has_prefix(du->idname, "mpath-")) ||
|
||||
- ((du->idtype == DEV_ID_TYPE_CRYPT_UUID) && !dm_uuid_has_prefix(du->idname, "CRYPT-")) ||
|
||||
- ((du->idtype == DEV_ID_TYPE_LVMLV_UUID) && !dm_uuid_has_prefix(du->idname, "LVM")))
|
||||
+ if (((du->idtype == DEV_ID_TYPE_MPATH_UUID) && !_dm_uuid_has_prefix(du->idname, "mpath-")) ||
|
||||
+ ((du->idtype == DEV_ID_TYPE_CRYPT_UUID) && !_dm_uuid_has_prefix(du->idname, "CRYPT-")) ||
|
||||
+ ((du->idtype == DEV_ID_TYPE_LVMLV_UUID) && !_dm_uuid_has_prefix(du->idname, "LVM")))
|
||||
_replace_incorrect_dm_idtype(du);
|
||||
|
||||
/*
|
||||
diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c
|
||||
index 7476cef8d..0917cdd4e 100644
|
||||
--- a/lib/metadata/lv.c
|
||||
+++ b/lib/metadata/lv.c
|
||||
@@ -1552,7 +1552,7 @@ char *lv_attr_dup_with_info_and_seg_status(struct dm_pool *mem, const struct lv_
|
||||
|
||||
if (!activation())
|
||||
repstr[8] = 'X'; /* Unknown */
|
||||
- else if (!lv_raid_healthy(lv))
|
||||
+ else if (!lv_raid_healthy(lv, NULL))
|
||||
repstr[8] = 'r'; /* RAID needs 'r'efresh */
|
||||
else if (lv_is_raid(lv)) {
|
||||
if (lv_raid_mismatch_count(lv, &n) && n)
|
||||
diff --git a/lib/report/report.c b/lib/report/report.c
|
||||
index 049accf41..ab0675f69 100644
|
||||
--- a/lib/report/report.c
|
||||
+++ b/lib/report/report.c
|
||||
@@ -4005,7 +4005,7 @@ static int _lvhealthstatus_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
else if (lv_is_raid_type(lv)) {
|
||||
if (!activation())
|
||||
health = "unknown";
|
||||
- else if (!lv_raid_healthy(lv))
|
||||
+ else if (!lv_raid_healthy(lv, NULL))
|
||||
health = "refresh needed";
|
||||
else if (lv_is_raid(lv)) {
|
||||
if (lv_raid_mismatch_count(lv, &n) && n)
|
||||
diff --git a/tools/reporter.c b/tools/reporter.c
|
||||
index e88b8fa72..f4255680c 100644
|
||||
--- a/tools/reporter.c
|
||||
+++ b/tools/reporter.c
|
||||
@@ -155,7 +155,7 @@ static int _check_merging_origin(const struct logical_volume *lv,
|
||||
|
||||
static void _cond_warn_raid_volume_health(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
{
|
||||
- if (lv_is_raid(lv) && !lv_raid_healthy(lv) && !lv_is_partial(lv))
|
||||
+ if (lv_is_raid(lv) && !lv_raid_healthy(lv, NULL) && !lv_is_partial(lv))
|
||||
log_warn("WARNING: RaidLV %s needs to be refreshed! See character 'r' at position 9 in the RaidLV's attributes%s.", display_lvname(lv),
|
||||
arg_is_set(cmd, all_ARG) ? " and its SubLV(s)" : " and also its SubLV(s) with option '-a'");
|
||||
}
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,37 @@
|
||||
From 4cd7e5b0d9d00995153702a068a02c643b079b5f Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Wed, 1 Apr 2026 22:37:32 +0200
|
||||
Subject: [PATCH 133/211] cov: command: fix NULL dereference in
|
||||
_add_oo_definition_line
|
||||
|
||||
Check strchr return value before adding offset. If the line
|
||||
has no colon, strchr returns NULL and the +2 produces an
|
||||
invalid pointer passed to strdup.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit a794299bb03fbd88f35780ad9005060a2b558804)
|
||||
---
|
||||
tools/command.c | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tools/command.c b/tools/command.c
|
||||
index db1058bd7..519bb7eb3 100644
|
||||
--- a/tools/command.c
|
||||
+++ b/tools/command.c
|
||||
@@ -667,7 +667,12 @@ static void _add_oo_definition_line(const char *name, const char *line)
|
||||
return;
|
||||
}
|
||||
|
||||
- start = strchr(line, ':') + 2;
|
||||
+ if (!(start = strchr(line, ':'))) {
|
||||
+ log_error("Parsing command defs: invalid OO line.");
|
||||
+ return;
|
||||
+ }
|
||||
+ start += 2;
|
||||
+
|
||||
if (!(oo->line = strdup(start))) {
|
||||
log_error("Failed to duplicate line %s.", start);
|
||||
return;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
52
0134-bcache-fix-flush-orphaning-locked-dirty-blocks.patch
Normal file
52
0134-bcache-fix-flush-orphaning-locked-dirty-blocks.patch
Normal file
@ -0,0 +1,52 @@
|
||||
From 2742b532fbe93dc2d19725031ebc85cdbcac36f5 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 10:16:17 +0200
|
||||
Subject: [PATCH 134/211] bcache: fix flush orphaning locked dirty blocks
|
||||
|
||||
bcache_flush used _list_pop to remove blocks from the dirty list
|
||||
before checking ref_count. Blocks still locked (e.g. superblock)
|
||||
were popped but never re-added to any list, orphaning them.
|
||||
|
||||
Switch to dm_list_iterate_items_gen_safe matching the pattern
|
||||
used by _writeback(). _issue_write() internally moves written
|
||||
blocks from dirty to io_pending via dm_list_move(), while locked
|
||||
blocks are skipped and remain on the dirty list.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit b81b48881d4af2bc28dff257ccbf583b129b9204)
|
||||
---
|
||||
lib/device/bcache.c | 18 +++++++++---------
|
||||
1 file changed, 9 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/lib/device/bcache.c b/lib/device/bcache.c
|
||||
index c61f7a5d5..afa0315fd 100644
|
||||
--- a/lib/device/bcache.c
|
||||
+++ b/lib/device/bcache.c
|
||||
@@ -1294,15 +1294,15 @@ bool bcache_flush(struct bcache *cache)
|
||||
// try and rewrite everything.
|
||||
dm_list_splice(&cache->dirty, &cache->errored);
|
||||
|
||||
- while (!dm_list_empty(&cache->dirty)) {
|
||||
- struct block *b = dm_list_item(_list_pop(&cache->dirty), struct block);
|
||||
- if (b->ref_count || _test_flags(b, BF_IO_PENDING)) {
|
||||
- // The superblock may well be still locked.
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- _issue_write(b);
|
||||
- }
|
||||
+ /*
|
||||
+ * _writeback() uses safe iteration and skips locked blocks
|
||||
+ * (ref_count > 0). _issue_write() moves written blocks from
|
||||
+ * dirty to io_pending via dm_list_move() in _issue_low_level().
|
||||
+ * BF_IO_PENDING cannot occur here - _issue_low_level() moves
|
||||
+ * the block off dirty when setting that flag, and _complete_io()
|
||||
+ * clears it before moving to errored/clean.
|
||||
+ */
|
||||
+ _writeback(cache, cache->nr_cache_blocks);
|
||||
|
||||
_wait_all(cache);
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
From 12de2eed0e6bcf34f3f019b53fd7a412299ca429 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 12:41:41 +0200
|
||||
Subject: [PATCH 135/211] dmeventd: fix inverted systemd activation env var
|
||||
check
|
||||
|
||||
strcmp(e, "1") returns 0 (false) when strings match, so the condition
|
||||
was setting _systemd_activation when env var was NOT "1" and skipping
|
||||
it when it WAS "1" -- the exact opposite of the intended behavior.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 6c0aad9e0f8e844eeae4350d79ba2674c7c4342d)
|
||||
---
|
||||
daemons/dmeventd/dmeventd.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/daemons/dmeventd/dmeventd.c b/daemons/dmeventd/dmeventd.c
|
||||
index 0c3880787..1ae5ef629 100644
|
||||
--- a/daemons/dmeventd/dmeventd.c
|
||||
+++ b/daemons/dmeventd/dmeventd.c
|
||||
@@ -2233,7 +2233,7 @@ static int _restart_dmeventd(struct dm_event_fifos *fifos)
|
||||
}
|
||||
|
||||
if (!_systemd_activation &&
|
||||
- ((e = getenv(SD_ACTIVATION_ENV_VAR_NAME)) && strcmp(e, "1")))
|
||||
+ ((e = getenv(SD_ACTIVATION_ENV_VAR_NAME)) && !strcmp(e, "1")))
|
||||
_systemd_activation = 1;
|
||||
|
||||
fini_fifos(fifos);
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
From b0a6b406e5ca1eec0727192193f6d6c2566e15f3 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 11:27:21 +0200
|
||||
Subject: [PATCH 136/211] lvrename: fix historical LV prefix stripping using
|
||||
wrong variable
|
||||
|
||||
When both old and new names have the historical prefix, the prefix
|
||||
was stripped from lv_name_old instead of lv_name_new, leaving
|
||||
lv_name_new with the prefix still attached.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 067fa3eb938bbb808978dcf21ac62236a0dff45b)
|
||||
---
|
||||
tools/lvrename.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tools/lvrename.c b/tools/lvrename.c
|
||||
index 74248ee91..6fcf1db53 100644
|
||||
--- a/tools/lvrename.c
|
||||
+++ b/tools/lvrename.c
|
||||
@@ -165,7 +165,7 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv)
|
||||
|
||||
if (!strncmp(lv_name_new, HISTORICAL_LV_PREFIX, strlen(HISTORICAL_LV_PREFIX))) {
|
||||
if (historical)
|
||||
- lv_name_new = lv_name_old + strlen(HISTORICAL_LV_PREFIX);
|
||||
+ lv_name_new = lv_name_new + strlen(HISTORICAL_LV_PREFIX);
|
||||
else {
|
||||
log_error("Old name references live LV while "
|
||||
"new name is for historical LV.");
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
From 2a3765160281eda24e7a1aaa5089f86bc49fc688 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 11:35:25 +0200
|
||||
Subject: [PATCH 137/211] lvmdevices: fix resource leak on delpvid duplicate
|
||||
error path
|
||||
|
||||
When a duplicate PVID was found, du was already removed from the
|
||||
list but never freed before goto bad, leaking the structure.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit d0f9bf1c9f4438a369087edf6e51147b844ae336)
|
||||
---
|
||||
tools/lvmdevices.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/tools/lvmdevices.c b/tools/lvmdevices.c
|
||||
index 65399c96c..78ff70455 100644
|
||||
--- a/tools/lvmdevices.c
|
||||
+++ b/tools/lvmdevices.c
|
||||
@@ -1010,6 +1010,7 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
|
||||
if ((du2 = get_du_for_pvid(cmd, pvid))) {
|
||||
log_error("Multiple devices file entries for PVID %s (%s %s), remove by device name.",
|
||||
pvid, du->devname, du2->devname);
|
||||
+ free_du(du);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,37 @@
|
||||
From 8ae8f80d5234875e22a753b664f8ffa77754fb20 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 09:04:35 +0200
|
||||
Subject: [PATCH 138/211] dev-cache: fix missing dev_iter_destroy in
|
||||
iterate_devs_for_index
|
||||
|
||||
Add missing dev_iter_destroy() call before return in
|
||||
_dev_cache_iterate_devs_for_index().
|
||||
|
||||
The leak only occurs on the udev scanning path - the non-udev sysfs
|
||||
fallback (_dev_cache_iterate_sysfs_for_index) reads sysfs directly
|
||||
without using an iterator. Since the function is called once per
|
||||
command, the leak is small (iterator struct + values array), which
|
||||
explains why it was not caught in normal testing.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 9d98bf8a448a58d56417daa127b8cd5002184c00)
|
||||
---
|
||||
lib/device/dev-cache.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c
|
||||
index 24a4d91c5..8f9ef1bd7 100644
|
||||
--- a/lib/device/dev-cache.c
|
||||
+++ b/lib/device/dev-cache.c
|
||||
@@ -912,6 +912,8 @@ static int _dev_cache_iterate_devs_for_index(struct cmd_context *cmd)
|
||||
if (!_index_dev_by_vgid_and_lvid(cmd, dev))
|
||||
r = 0;
|
||||
|
||||
+ dev_iter_destroy(iter);
|
||||
+
|
||||
return r;
|
||||
}
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
From 1b21775c5b6d64ecc7e2acde34eac00abe4a5bb7 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 10:07:28 +0200
|
||||
Subject: [PATCH 139/211] import_vsn1: fix resource leak on historical LV id
|
||||
read failure
|
||||
|
||||
Use goto bad instead of return 0 to properly free allocations.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit dd4fd687ca3042d0c35b7a134cdb3eaaefaeec79)
|
||||
---
|
||||
lib/format_text/import_vsn1.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c
|
||||
index 4f76625a5..20b1739e9 100644
|
||||
--- a/lib/format_text/import_vsn1.c
|
||||
+++ b/lib/format_text/import_vsn1.c
|
||||
@@ -792,7 +792,7 @@ static int _read_historical_lvnames(struct cmd_context *cmd,
|
||||
if (!_read_id(&glv->historical->lvid.id[1], hlvn, "id")) {
|
||||
log_error("Couldn't read uuid for removed logical volume %s in vg %s.",
|
||||
glv->historical->name, vg->name);
|
||||
- return 0;
|
||||
+ goto bad;
|
||||
}
|
||||
memcpy(&glv->historical->lvid.id[0], &glv->historical->vg->id, sizeof(glv->historical->lvid.id[0]));
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
36
0140-lvm-exec-fix-close-error-msg-and-null_fd-fd-case.patch
Normal file
36
0140-lvm-exec-fix-close-error-msg-and-null_fd-fd-case.patch
Normal file
@ -0,0 +1,36 @@
|
||||
From 8dd9169a9128aca196b2b53bd7ede956bc24cd70 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 13:07:54 +0200
|
||||
Subject: [PATCH 140/211] lvm-exec: fix close error msg and null_fd == fd case
|
||||
|
||||
1. Fix copy-paste error in log_sys_error: reported "dup2" instead of
|
||||
"close" for the close(null_fd) call.
|
||||
|
||||
2. Guard close(null_fd) with null_fd != fd check. When the target fd
|
||||
was already closed, open("/dev/null") reuses the same fd number,
|
||||
dup2 is a no-op, and unconditional close would undo the setup.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 0139987d8d200ae2688fba2029af6c52f441f632)
|
||||
---
|
||||
lib/misc/lvm-exec.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/lib/misc/lvm-exec.c b/lib/misc/lvm-exec.c
|
||||
index 37b392545..5ae33516c 100644
|
||||
--- a/lib/misc/lvm-exec.c
|
||||
+++ b/lib/misc/lvm-exec.c
|
||||
@@ -136,8 +136,8 @@ static int _reopen_fd_to_null(int fd)
|
||||
|
||||
r = 1;
|
||||
out:
|
||||
- if (close(null_fd)) {
|
||||
- log_sys_error("dup2", "");
|
||||
+ if ((null_fd != fd) && close(null_fd)) {
|
||||
+ log_sys_error("close", "/dev/null");
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,43 @@
|
||||
From 159c89d0d33161e18dd75a53891528747313c62e Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Apr 2026 18:09:34 +0200
|
||||
Subject: [PATCH 141/211] lvmlockctl: fix close error msg and null_fd == fd
|
||||
case
|
||||
|
||||
Add missing null_fd != fd guards in _reopen_fd_to_null to match
|
||||
lib/misc/lvm-exec.c implementation. Without these guards, if
|
||||
open("/dev/null") returns the same fd number as the target fd
|
||||
(e.g., fd 0 is already closed so open returns 0), the function
|
||||
would incorrectly close the just-opened fd before dup2.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit f5ca64812df94d7816f06cfa383a0b06086105e1)
|
||||
---
|
||||
daemons/lvmlockd/lvmlockctl.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/daemons/lvmlockd/lvmlockctl.c b/daemons/lvmlockd/lvmlockctl.c
|
||||
index e36293260..63b7f77c6 100644
|
||||
--- a/daemons/lvmlockd/lvmlockctl.c
|
||||
+++ b/daemons/lvmlockd/lvmlockctl.c
|
||||
@@ -726,7 +726,7 @@ static int _reopen_fd_to_null(int fd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
- if (close(fd)) {
|
||||
+ if ((null_fd != fd) && close(fd)) {
|
||||
log_error("close error fd %d %d", fd, errno);
|
||||
goto out;
|
||||
}
|
||||
@@ -738,7 +738,7 @@ static int _reopen_fd_to_null(int fd)
|
||||
|
||||
r = 1;
|
||||
out:
|
||||
- if (close(null_fd)) {
|
||||
+ if ((null_fd != fd) && close(null_fd)) {
|
||||
log_error("close error fd %d %d", null_fd, errno);
|
||||
return 0;
|
||||
}
|
||||
--
|
||||
2.54.0
|
||||
|
||||
60
0142-bcache-do-not-call-io_destroy-in-forked-process.patch
Normal file
60
0142-bcache-do-not-call-io_destroy-in-forked-process.patch
Normal file
@ -0,0 +1,60 @@
|
||||
From 82ab9fbd220d8f1461397dafbbbbc59d6fc15ba5 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 3 Oct 2025 20:14:31 +0200
|
||||
Subject: [PATCH 142/211] bcache: do not call io_destroy in forked process
|
||||
|
||||
(cherry picked from commit 2b632d5f3a3fad50e3e39a89af58bd62d3a2d7e3)
|
||||
---
|
||||
lib/device/bcache.c | 18 +++++++++++++-----
|
||||
1 file changed, 13 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/lib/device/bcache.c b/lib/device/bcache.c
|
||||
index afa0315fd..b66c5fa7c 100644
|
||||
--- a/lib/device/bcache.c
|
||||
+++ b/lib/device/bcache.c
|
||||
@@ -131,6 +131,7 @@ struct async_engine {
|
||||
io_context_t aio_context;
|
||||
struct cb_set *cbs;
|
||||
unsigned page_mask;
|
||||
+ pid_t aio_context_pid; /* PID that created this AIO context */
|
||||
};
|
||||
|
||||
static struct async_engine *_to_async(struct io_engine *e)
|
||||
@@ -140,15 +141,21 @@ static struct async_engine *_to_async(struct io_engine *e)
|
||||
|
||||
static void _async_destroy(struct io_engine *ioe)
|
||||
{
|
||||
- int r;
|
||||
struct async_engine *e = _to_async(ioe);
|
||||
|
||||
_cb_set_destroy(e->cbs);
|
||||
|
||||
- // io_destroy is really slow
|
||||
- r = io_destroy(e->aio_context);
|
||||
- if (r)
|
||||
- log_sys_warn("io_destroy");
|
||||
+ /*
|
||||
+ * Only call io_destroy() if we're in the same process that created
|
||||
+ * the AIO context. After fork(), the child inherits the parent's
|
||||
+ * aio_context value but must not call io_destroy() on it.
|
||||
+ */
|
||||
+ if (e->aio_context) {
|
||||
+ if (e->aio_context_pid != getpid())
|
||||
+ log_debug("Skipping io_destroy() for different pid.");
|
||||
+ else if (io_destroy(e->aio_context)) // really slow
|
||||
+ log_sys_warn("io_destroy");
|
||||
+ }
|
||||
|
||||
free(e);
|
||||
}
|
||||
@@ -376,6 +383,7 @@ struct io_engine *create_async_io_engine(void)
|
||||
e->e.max_io = _async_max_io;
|
||||
|
||||
e->aio_context = 0;
|
||||
+ e->aio_context_pid = getpid();
|
||||
r = io_setup(MAX_IO, &e->aio_context);
|
||||
if (r < 0) {
|
||||
log_debug("io_setup failed %d", r);
|
||||
--
|
||||
2.54.0
|
||||
|
||||
36
0143-debug-add-tracing-for-context-destroy.patch
Normal file
36
0143-debug-add-tracing-for-context-destroy.patch
Normal file
@ -0,0 +1,36 @@
|
||||
From f4cbf26376cea75db8d1ed8cfeebc11a94693c9f Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Mon, 8 Dec 2025 14:44:49 +0100
|
||||
Subject: [PATCH 143/211] debug: add tracing for context destroy
|
||||
|
||||
Add trace note where the time is being lost.
|
||||
Context destroy may take ~40ms in kernel.
|
||||
|
||||
(cherry picked from commit f1374c5876783301b26812b144d2d016bb5f519f)
|
||||
---
|
||||
lib/device/bcache.c | 9 ++++++---
|
||||
1 file changed, 6 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/lib/device/bcache.c b/lib/device/bcache.c
|
||||
index b66c5fa7c..915db250c 100644
|
||||
--- a/lib/device/bcache.c
|
||||
+++ b/lib/device/bcache.c
|
||||
@@ -152,9 +152,12 @@ static void _async_destroy(struct io_engine *ioe)
|
||||
*/
|
||||
if (e->aio_context) {
|
||||
if (e->aio_context_pid != getpid())
|
||||
- log_debug("Skipping io_destroy() for different pid.");
|
||||
- else if (io_destroy(e->aio_context)) // really slow
|
||||
- log_sys_warn("io_destroy");
|
||||
+ log_debug_devs("Skipping AIO context destroy for different pid.");
|
||||
+ else {
|
||||
+ log_debug_devs("Destroy AIO context.");
|
||||
+ if (io_destroy(e->aio_context)) // really slow (~40ms)
|
||||
+ log_sys_warn("io_destroy");
|
||||
+ }
|
||||
}
|
||||
|
||||
free(e);
|
||||
--
|
||||
2.54.0
|
||||
|
||||
62
0144-bcache-report-libaio-errors-properly.patch
Normal file
62
0144-bcache-report-libaio-errors-properly.patch
Normal file
@ -0,0 +1,62 @@
|
||||
From 884d5e0dd0afca46d2f72b9448a6fa9e1cddf1c1 Mon Sep 17 00:00:00 2001
|
||||
From: Mike Gilbert <floppym@gentoo.org>
|
||||
Date: Fri, 13 Feb 2026 21:47:12 -0500
|
||||
Subject: [PATCH 144/211] bcache: report libaio errors properly
|
||||
|
||||
io_getevents and io_destroy return a negative error value instead of
|
||||
setting errno.
|
||||
|
||||
Bug: https://bugs.gentoo.org/970017
|
||||
(cherry picked from commit 512a3944893af8c1d4ce69c69d2ae587aebf2b08)
|
||||
---
|
||||
lib/device/bcache.c | 12 +++++++-----
|
||||
1 file changed, 7 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/lib/device/bcache.c b/lib/device/bcache.c
|
||||
index 915db250c..2ecad6376 100644
|
||||
--- a/lib/device/bcache.c
|
||||
+++ b/lib/device/bcache.c
|
||||
@@ -40,9 +40,9 @@ static int *_fd_table = NULL;
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
-static void log_sys_warn(const char *call)
|
||||
+static void log_sys_warn(const char *call, int err)
|
||||
{
|
||||
- log_warn("WARNING: %s failed: %s.", call, strerror(errno));
|
||||
+ log_warn("WARNING: %s failed: %s.", call, strerror(err));
|
||||
}
|
||||
|
||||
// Assumes the list is not empty.
|
||||
@@ -141,6 +141,7 @@ static struct async_engine *_to_async(struct io_engine *e)
|
||||
|
||||
static void _async_destroy(struct io_engine *ioe)
|
||||
{
|
||||
+ int r;
|
||||
struct async_engine *e = _to_async(ioe);
|
||||
|
||||
_cb_set_destroy(e->cbs);
|
||||
@@ -155,8 +156,9 @@ static void _async_destroy(struct io_engine *ioe)
|
||||
log_debug_devs("Skipping AIO context destroy for different pid.");
|
||||
else {
|
||||
log_debug_devs("Destroy AIO context.");
|
||||
- if (io_destroy(e->aio_context)) // really slow (~40ms)
|
||||
- log_sys_warn("io_destroy");
|
||||
+ r = io_destroy(e->aio_context); // really slow (~40ms)
|
||||
+ if (r < 0)
|
||||
+ log_sys_warn("io_destroy", -r);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,7 +333,7 @@ static bool _async_wait(struct io_engine *ioe, io_complete_fn fn)
|
||||
r = io_getevents(e->aio_context, 1, MAX_EVENT, event, NULL);
|
||||
|
||||
if (r < 0) {
|
||||
- log_sys_warn("io_getevents");
|
||||
+ log_sys_warn("io_getevents", -r);
|
||||
return false;
|
||||
}
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
30
0145-bcache-retry-io_getevents-on-EINTR.patch
Normal file
30
0145-bcache-retry-io_getevents-on-EINTR.patch
Normal file
@ -0,0 +1,30 @@
|
||||
From 895b49acb8fd5a10d0bb7ae243fe430386aee0a2 Mon Sep 17 00:00:00 2001
|
||||
From: Mike Gilbert <floppym@gentoo.org>
|
||||
Date: Fri, 13 Feb 2026 22:03:32 -0500
|
||||
Subject: [PATCH 145/211] bcache: retry io_getevents on EINTR
|
||||
|
||||
Bug: https://bugs.gentoo.org/970017
|
||||
(cherry picked from commit 791a842dea11808d647c1a605ca244d0fc1cdf5d)
|
||||
---
|
||||
lib/device/bcache.c | 5 ++++-
|
||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/device/bcache.c b/lib/device/bcache.c
|
||||
index 2ecad6376..4c91402c4 100644
|
||||
--- a/lib/device/bcache.c
|
||||
+++ b/lib/device/bcache.c
|
||||
@@ -330,7 +330,10 @@ static bool _async_wait(struct io_engine *ioe, io_complete_fn fn)
|
||||
struct async_engine *e = _to_async(ioe);
|
||||
|
||||
memset(&event, 0, sizeof(event));
|
||||
- r = io_getevents(e->aio_context, 1, MAX_EVENT, event, NULL);
|
||||
+
|
||||
+ do {
|
||||
+ r = io_getevents(e->aio_context, 1, MAX_EVENT, event, NULL);
|
||||
+ } while (r == -EINTR);
|
||||
|
||||
if (r < 0) {
|
||||
log_sys_warn("io_getevents", -r);
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
From 424b80266e954f6d612c23121325a891a2a8eec3 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Sat, 21 Feb 2026 10:31:45 +0100
|
||||
Subject: [PATCH 146/211] bcache: retry io_getevents() only if sigint not
|
||||
caught
|
||||
|
||||
Stray signals (SIGALRM, SIGCHLD, SIGWINCH, etc.) cause EINTR
|
||||
but should not abort I/O - the loop retries transparently.
|
||||
SIGINT/SIGTERM delivered inside a sigint_allow()/sigint_restore()
|
||||
window set sigint_caught(), which stops the loop and lets the
|
||||
caller detect and handle the cancellation.
|
||||
|
||||
LVM supports io_getevents() interruptible in commit b3c7a2b3f0bc.
|
||||
However when read-only command do not use signal handlers,
|
||||
this sigint_caught() check is effectively ignored. But in this case
|
||||
command will be interrupted with the default signal handler anyway.
|
||||
|
||||
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||||
|
||||
diff --git a/lib/device/bcache.c b/lib/device/bcache.c
|
||||
|
||||
(cherry picked from commit 0a55dd6dcdcad64a103f1d5ce29a0f1909548b7a)
|
||||
---
|
||||
lib/device/bcache.c | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/device/bcache.c b/lib/device/bcache.c
|
||||
index 4c91402c4..38da044b1 100644
|
||||
--- a/lib/device/bcache.c
|
||||
+++ b/lib/device/bcache.c
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "base/data-struct/radix-tree.h"
|
||||
#include "lib/log/lvm-logging.h"
|
||||
#include "lib/log/log.h"
|
||||
+#include "lib/misc/lvm-signal.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
@@ -331,9 +332,13 @@ static bool _async_wait(struct io_engine *ioe, io_complete_fn fn)
|
||||
|
||||
memset(&event, 0, sizeof(event));
|
||||
|
||||
+ /*
|
||||
+ * Retry on EINTR from stray signals, but stop if an LVM interrupt
|
||||
+ * signal (SIGINT/SIGTERM via sigint_allow()) has been caught.
|
||||
+ */
|
||||
do {
|
||||
r = io_getevents(e->aio_context, 1, MAX_EVENT, event, NULL);
|
||||
- } while (r == -EINTR);
|
||||
+ } while (r == -EINTR && !sigint_caught());
|
||||
|
||||
if (r < 0) {
|
||||
log_sys_warn("io_getevents", -r);
|
||||
--
|
||||
2.54.0
|
||||
|
||||
136
0147-bcache-fix-_wait_io-failure-ignored-by-_wait_all-and.patch
Normal file
136
0147-bcache-fix-_wait_io-failure-ignored-by-_wait_all-and.patch
Normal file
@ -0,0 +1,136 @@
|
||||
From 6e47af32fc2eb4d7d4a110c213b7eba308be0985 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Tue, 24 Feb 2026 00:47:20 +0100
|
||||
Subject: [PATCH 147/211] bcache: fix _wait_io failure ignored by _wait_all and
|
||||
_wait_specific
|
||||
|
||||
1. Use stack backtrace for EINTR - sigint_caught() already emits
|
||||
log_error("Interrupted..."), so only a backtrace marker is needed
|
||||
here; the previous log_sys_warn was incorrect since io_getevents
|
||||
returns -errno directly.
|
||||
|
||||
2. Break _wait_all/_wait_specific loops when _wait_io fails -
|
||||
previously the return value was discarded causing infinite
|
||||
busy-spin since BF_IO_PENDING is only cleared by _complete_io
|
||||
which is never called when io_getevents returns EINTR.
|
||||
|
||||
3. Propagate _wait_specific failure through _lookup_or_read_block
|
||||
returning NULL so bcache_get and callers can detect the
|
||||
interrupted I/O and abort the operation.
|
||||
|
||||
4. Make _wait_all() return bool and update all three callers to check
|
||||
the return value:
|
||||
|
||||
- _new_block: return NULL on failure (same path as I/O errors)
|
||||
- bcache_flush: return false immediately without checking errored list
|
||||
(writes never completed so the list state is unreliable)
|
||||
- bcache_invalidate_di: return false on failure
|
||||
|
||||
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||||
|
||||
diff --git a/lib/device/bcache.c b/lib/device/bcache.c
|
||||
index 770d7d8ff..4dc5f9a2f 100644
|
||||
--- a/lib/device/bcache.c
|
||||
+++ b/lib/device/bcache.c
|
||||
|
||||
(cherry picked from commit 4e82d987df02a0f2e71b56519196ab4b5ad7403b)
|
||||
---
|
||||
lib/device/bcache.c | 34 ++++++++++++++++++++++++----------
|
||||
1 file changed, 24 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/lib/device/bcache.c b/lib/device/bcache.c
|
||||
index 38da044b1..bf8d873f6 100644
|
||||
--- a/lib/device/bcache.c
|
||||
+++ b/lib/device/bcache.c
|
||||
@@ -341,7 +341,10 @@ static bool _async_wait(struct io_engine *ioe, io_complete_fn fn)
|
||||
} while (r == -EINTR && !sigint_caught());
|
||||
|
||||
if (r < 0) {
|
||||
- log_sys_warn("io_getevents", -r);
|
||||
+ if (r == -EINTR)
|
||||
+ stack;
|
||||
+ else
|
||||
+ log_sys_warn("io_getevents", -r);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -922,16 +925,20 @@ static bool _wait_io(struct bcache *cache)
|
||||
* High level IO handling
|
||||
*--------------------------------------------------------------*/
|
||||
|
||||
-static void _wait_all(struct bcache *cache)
|
||||
+static bool _wait_all(struct bcache *cache)
|
||||
{
|
||||
while (!dm_list_empty(&cache->io_pending))
|
||||
- _wait_io(cache);
|
||||
+ if (!_wait_io(cache))
|
||||
+ return false;
|
||||
+ return true;
|
||||
}
|
||||
|
||||
-static void _wait_specific(struct block *b)
|
||||
+static bool _wait_specific(struct block *b)
|
||||
{
|
||||
while (_test_flags(b, BF_IO_PENDING))
|
||||
- _wait_io(b->cache);
|
||||
+ if (!_wait_io(b->cache))
|
||||
+ return false;
|
||||
+ return true;
|
||||
}
|
||||
|
||||
static unsigned _writeback(struct bcache *cache, unsigned count)
|
||||
@@ -983,7 +990,8 @@ static struct block *_new_block(struct bcache *cache, int di, block_address i, b
|
||||
if (can_wait) {
|
||||
if (dm_list_empty(&cache->io_pending))
|
||||
_writeback(cache, 16); // FIXME: magic number
|
||||
- _wait_all(cache);
|
||||
+ if (!_wait_all(cache))
|
||||
+ return NULL;
|
||||
if (dm_list_size(&cache->errored) >= cache->max_io) {
|
||||
log_debug("bcache no new blocks for di %d index %u with >%d errors.",
|
||||
di, (uint32_t) i, cache->max_io);
|
||||
@@ -1061,7 +1069,8 @@ static struct block *_lookup_or_read_block(struct bcache *cache,
|
||||
|
||||
if (_test_flags(b, BF_IO_PENDING)) {
|
||||
_miss(cache, flags);
|
||||
- _wait_specific(b);
|
||||
+ if (!_wait_specific(b))
|
||||
+ return NULL;
|
||||
|
||||
} else
|
||||
_hit(b, flags);
|
||||
@@ -1081,7 +1090,10 @@ static struct block *_lookup_or_read_block(struct bcache *cache,
|
||||
|
||||
else {
|
||||
_issue_read(b);
|
||||
- _wait_specific(b);
|
||||
+ if (!_wait_specific(b)) {
|
||||
+ _unlink_block(b);
|
||||
+ return NULL;
|
||||
+ }
|
||||
|
||||
// we know the block is clean and unerrored.
|
||||
_unlink_block(b);
|
||||
@@ -1325,7 +1337,8 @@ bool bcache_flush(struct bcache *cache)
|
||||
*/
|
||||
_writeback(cache, cache->nr_cache_blocks);
|
||||
|
||||
- _wait_all(cache);
|
||||
+ if (!_wait_all(cache))
|
||||
+ return false;
|
||||
|
||||
return dm_list_empty(&cache->errored);
|
||||
}
|
||||
@@ -1422,7 +1435,8 @@ bool bcache_invalidate_di(struct bcache *cache, int di)
|
||||
it.it.visit = _writeback_v;
|
||||
radix_tree_iterate(cache->rtree, k.bytes, sizeof(k.parts.di), &it.it);
|
||||
|
||||
- _wait_all(cache);
|
||||
+ if (!_wait_all(cache))
|
||||
+ return false;
|
||||
|
||||
it.success = true;
|
||||
it.it.visit = _invalidate_v;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
From 8239bbf3cad6fba2db70bcf62ff24eb275ded214 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Tue, 10 Feb 2026 13:11:24 +0100
|
||||
Subject: [PATCH 148/211] libdm: fix cache feature_flags cleaner policy to
|
||||
preserve non-mode bits
|
||||
|
||||
When enforcing writethrough mode for cleaner policy, the code was
|
||||
assigning ~modemask to feature_flags instead of masking with &=.
|
||||
This discarded non-mode feature flags like DM_CACHE_FEATURE_METADATA2.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 8b955d13ea0d4eeb14427c68ff2939679766bbfa)
|
||||
---
|
||||
libdm/libdm-deptree.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libdm/libdm-deptree.c b/libdm/libdm-deptree.c
|
||||
index 318b23ecc..cfb57854d 100644
|
||||
--- a/libdm/libdm-deptree.c
|
||||
+++ b/libdm/libdm-deptree.c
|
||||
@@ -3442,7 +3442,7 @@ DM_EXPORT_NEW_SYMBOL(int, dm_tree_node_add_cache_target, 1_02_138)
|
||||
case DM_CACHE_FEATURE_WRITEBACK:
|
||||
if (strcmp(policy_name, "cleaner") == 0) {
|
||||
/* Enforce writethrough mode for cleaner policy */
|
||||
- feature_flags = ~_modemask;
|
||||
+ feature_flags &= ~_modemask;
|
||||
feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
|
||||
}
|
||||
/* Fall through */
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
From aff798f2816e323163da9878031ba8f3f0385a26 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Tue, 10 Feb 2026 13:11:43 +0100
|
||||
Subject: [PATCH 149/211] libdm: fix cache origin uuid error message printing
|
||||
wrong variable
|
||||
|
||||
The error message for missing cache origin was printing metadata_uuid
|
||||
instead of origin_uuid.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 045f941798f06f88121aac44a4e9a19f97de1a30)
|
||||
---
|
||||
libdm/libdm-deptree.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libdm/libdm-deptree.c b/libdm/libdm-deptree.c
|
||||
index cfb57854d..2fdd9fa07 100644
|
||||
--- a/libdm/libdm-deptree.c
|
||||
+++ b/libdm/libdm-deptree.c
|
||||
@@ -3490,7 +3490,7 @@ DM_EXPORT_NEW_SYMBOL(int, dm_tree_node_add_cache_target, 1_02_138)
|
||||
if (!(seg->origin = dm_tree_find_node_by_uuid(node->dtree,
|
||||
origin_uuid))) {
|
||||
log_error("Missing cache's origin uuid %s.",
|
||||
- metadata_uuid);
|
||||
+ origin_uuid);
|
||||
return 0;
|
||||
}
|
||||
if (!_link_tree_nodes(node, seg->origin))
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,40 @@
|
||||
From 338c45f3128680ca511c4c92402999bcbe8df6b1 Mon Sep 17 00:00:00 2001
|
||||
From: Peter Rajnoha <prajnoha@redhat.com>
|
||||
Date: Tue, 10 Feb 2026 11:21:51 +0100
|
||||
Subject: [PATCH 150/211] lvmlockd: check if sanlock lv is not partial before
|
||||
trying to activate
|
||||
|
||||
If the sanlock lv is partial, we can't execute lockd operations, like 'lock start'.
|
||||
The activate_lv would check if the lv is partial or not, but it would provide
|
||||
a misleading hint in this case:
|
||||
|
||||
"Refusing activation of partial LV <vg/lv>. Use '--activationmode partial' to override."
|
||||
|
||||
Instead, check for partial sanlock lv early and provide this message instead:
|
||||
|
||||
"Cannot use sanlock lv <vg>/<lv> with missing PVs."
|
||||
|
||||
(cherry picked from commit 365b9768dfc542689424a1840a208229cf43b25d)
|
||||
---
|
||||
lib/locking/lvmlockd.c | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/lib/locking/lvmlockd.c b/lib/locking/lvmlockd.c
|
||||
index 68dea52e0..af827e49e 100644
|
||||
--- a/lib/locking/lvmlockd.c
|
||||
+++ b/lib/locking/lvmlockd.c
|
||||
@@ -782,6 +782,11 @@ static int _handle_sanlock_lv(struct cmd_context *cmd, struct volume_group *vg)
|
||||
|
||||
static int _activate_sanlock_lv(struct cmd_context *cmd, struct volume_group *vg)
|
||||
{
|
||||
+ if (lv_is_partial(vg->sanlock_lv)) {
|
||||
+ log_error("Cannot use sanlock lv %s/%s with missing PVs.", vg->name, vg->sanlock_lv->name);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
if (!activate_lv(cmd, vg->sanlock_lv)) {
|
||||
log_error("Failed to activate sanlock lv %s/%s", vg->name, vg->sanlock_lv->name);
|
||||
return 0;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,57 @@
|
||||
From 83676b371fd99ca2c4ab9bc8932661539eec90b9 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Thu, 23 Oct 2025 19:18:16 +0200
|
||||
Subject: [PATCH 151/211] pool: initialize chunk_size_calc_method in update
|
||||
functions
|
||||
|
||||
Fix uninitialized variable bug causing valgrind warnings when
|
||||
converting LVs to pools with user-specified --chunksize.
|
||||
|
||||
The update_thin_pool_params() and update_cache_pool_params()
|
||||
functions only initialized chunk_size_calc_method in the code
|
||||
path that calculates default chunk size from profile settings.
|
||||
When users specified --chunksize, this output parameter remained
|
||||
uninitialized and was later used in a conditional check in
|
||||
recalculate_pool_chunk_size_with_dev_hints(), triggering valgrind:
|
||||
"Conditional jump or move depends on uninitialised value(s)"
|
||||
|
||||
Fix by initializing chunk_size_calc_method to 0 at the start of
|
||||
both functions. A value of 0 indicates chunk size was user-specified
|
||||
or should not be recalculated from device hints.
|
||||
|
||||
Co-Authored-By: Claude <noreply@anthropic.com>
|
||||
(cherry picked from commit 620cc808d1a47e007f40d0666f10048577eaa4d7)
|
||||
---
|
||||
lib/metadata/cache_manip.c | 2 ++
|
||||
lib/metadata/thin_manip.c | 2 ++
|
||||
2 files changed, 4 insertions(+)
|
||||
|
||||
diff --git a/lib/metadata/cache_manip.c b/lib/metadata/cache_manip.c
|
||||
index 3e7b34a66..fecf56919 100644
|
||||
--- a/lib/metadata/cache_manip.c
|
||||
+++ b/lib/metadata/cache_manip.c
|
||||
@@ -212,6 +212,8 @@ int update_cache_pool_params(struct cmd_context *cmd,
|
||||
DM_CACHE_MIN_DATA_BLOCK_SIZE - 1) /
|
||||
DM_CACHE_MIN_DATA_BLOCK_SIZE) * DM_CACHE_MIN_DATA_BLOCK_SIZE;
|
||||
|
||||
+ *chunk_size_calc_method = 0;
|
||||
+
|
||||
if (!*chunk_size) {
|
||||
if (!(*chunk_size = find_config_tree_int(cmd, allocation_cache_pool_chunk_size_CFG,
|
||||
profile) * 2)) {
|
||||
diff --git a/lib/metadata/thin_manip.c b/lib/metadata/thin_manip.c
|
||||
index b741ba0f5..b9db5d4b0 100644
|
||||
--- a/lib/metadata/thin_manip.c
|
||||
+++ b/lib/metadata/thin_manip.c
|
||||
@@ -832,6 +832,8 @@ int update_thin_pool_params(struct cmd_context *cmd,
|
||||
uint64_t max_pool_data_size;
|
||||
const char *str;
|
||||
|
||||
+ *chunk_size_calc_method = 0;
|
||||
+
|
||||
if (!*chunk_size &&
|
||||
find_config_tree_node(cmd, allocation_thin_pool_chunk_size_CFG, profile))
|
||||
*chunk_size = find_config_tree_int(cmd, allocation_thin_pool_chunk_size_CFG, profile) * 2;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
59
0152-pool-drop-LV_ACTIVATION_SKIP-from-converted-LVs.patch
Normal file
59
0152-pool-drop-LV_ACTIVATION_SKIP-from-converted-LVs.patch
Normal file
@ -0,0 +1,59 @@
|
||||
From 23e65201eee7460e6a40ddce520271924229d46c Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Sun, 14 Dec 2025 15:11:00 +0100
|
||||
Subject: [PATCH 152/211] pool: drop LV_ACTIVATION_SKIP from converted LVs
|
||||
|
||||
When converting LVs to use them as pool data & metadata LVs,
|
||||
drop LV_ACTIVATION_SKIP from their status.
|
||||
|
||||
This flag is not meaningful for internal LVs, and for thin-pools
|
||||
it has a side-effect selecting whether the thin-pool should be
|
||||
left active standalone.
|
||||
|
||||
(cherry picked from commit 0d0b42e418aac36c88aecb19aabc0b8d7b81cab3)
|
||||
---
|
||||
lib/metadata/pool_manip.c | 3 +++
|
||||
tools/lvconvert.c | 6 ++++++
|
||||
2 files changed, 9 insertions(+)
|
||||
|
||||
diff --git a/lib/metadata/pool_manip.c b/lib/metadata/pool_manip.c
|
||||
index cbe1b3ff0..eb081d978 100644
|
||||
--- a/lib/metadata/pool_manip.c
|
||||
+++ b/lib/metadata/pool_manip.c
|
||||
@@ -38,6 +38,7 @@ int attach_pool_metadata_lv(struct lv_segment *pool_seg,
|
||||
return 0;
|
||||
}
|
||||
pool_seg->metadata_lv = metadata_lv;
|
||||
+ metadata_lv->status &= ~LV_ACTIVATION_SKIP; /* Internal volume does not use skip */
|
||||
metadata_lv->status |= seg_is_thin_pool(pool_seg) ?
|
||||
THIN_POOL_METADATA : CACHE_POOL_METADATA;
|
||||
lv_set_hidden(metadata_lv);
|
||||
@@ -80,6 +81,8 @@ int attach_pool_data_lv(struct lv_segment *pool_seg,
|
||||
THIN_POOL_DATA : CACHE_POOL_DATA))
|
||||
return_0;
|
||||
|
||||
+ pool_data_lv->status &= ~LV_ACTIVATION_SKIP;
|
||||
+ pool_seg->lv->status &= ~LV_ACTIVATION_SKIP;
|
||||
pool_seg->lv->status |= seg_is_thin_pool(pool_seg) ?
|
||||
THIN_POOL : CACHE_POOL;
|
||||
lv_set_hidden(pool_data_lv);
|
||||
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
|
||||
index 7a17028e5..7dc8a3736 100644
|
||||
--- a/tools/lvconvert.c
|
||||
+++ b/tools/lvconvert.c
|
||||
@@ -3441,6 +3441,12 @@ static int _lvconvert_to_pool(struct cmd_context *cmd,
|
||||
pool_lv = lv;
|
||||
}
|
||||
|
||||
+ /* For pool skipping activation has slightly different meaning
|
||||
+ * so by default we create a regular pool with standard activation
|
||||
+ * User may use 'lvchange --setactivationskip' to use pool
|
||||
+ * with skipped activation */
|
||||
+ pool_lv->status &= ~LV_ACTIVATION_SKIP;
|
||||
+
|
||||
/*
|
||||
* starts with pool_lv foo (not a pool yet)
|
||||
* creates new data_lv foo_tdata
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,66 @@
|
||||
From 80d6b94863e6f49f38e16090ca2067c8f640c0cc Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Thu, 16 Apr 2026 11:56:00 +0200
|
||||
Subject: [PATCH 153/211] lib: fix buffer overflows in device_id and GPT
|
||||
parsing
|
||||
|
||||
device_id: use dm_snprintf in device_ids_write to handle
|
||||
truncation safely.
|
||||
|
||||
dev-type: validate GPT partition entry size before iterating.
|
||||
A crafted disk with sz_entry=0 causes ~4 billion loop iterations.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 8f39af43dd8d78ad99c1801cb0a2f0d1f5d2a19d)
|
||||
---
|
||||
lib/device/dev-type.c | 6 ++++++
|
||||
lib/device/device_id.c | 13 ++++++-------
|
||||
2 files changed, 12 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/lib/device/dev-type.c b/lib/device/dev-type.c
|
||||
index 4c1040c9f..5c6717f01 100644
|
||||
--- a/lib/device/dev-type.c
|
||||
+++ b/lib/device/dev-type.c
|
||||
@@ -612,6 +612,12 @@ static int _has_gpt_partition_table(struct device *dev)
|
||||
nr_entries = le32_to_cpu(gpt_header.nr_part_entries);
|
||||
sz_entry = le32_to_cpu(gpt_header.sz_part_entry);
|
||||
|
||||
+ if (sz_entry < sizeof(gpt_part_entry)) {
|
||||
+ log_debug("GPT partition entry size %u too small on %s.",
|
||||
+ sz_entry, dev_name(dev));
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
for (i = 0; i < nr_entries; i++) {
|
||||
if (!dev_read_bytes(dev, entries_start + (uint64_t)i * sz_entry,
|
||||
sizeof(gpt_part_entry), &gpt_part_entry))
|
||||
diff --git a/lib/device/device_id.c b/lib/device/device_id.c
|
||||
index a83257e50..73306558b 100644
|
||||
--- a/lib/device/device_id.c
|
||||
+++ b/lib/device/device_id.c
|
||||
@@ -1830,16 +1830,15 @@ int device_ids_write(struct cmd_context *cmd)
|
||||
|
||||
t = time(NULL);
|
||||
|
||||
- if ((fc_bytes = snprintf(fc, sizeof(fc),
|
||||
- "# LVM uses devices listed in this file.\n" \
|
||||
- "# Created by LVM command %s%s pid %d at %s" \
|
||||
- "# HASH=%u\n",
|
||||
- cmd->name, cmd->device_ids_auto_import ? " (auto)" : "",
|
||||
- getpid(), ctime(&t), hash)) < 0) {
|
||||
+ if ((fc_bytes = dm_snprintf(fc, sizeof(fc),
|
||||
+ "# LVM uses devices listed in this file.\n"
|
||||
+ "# Created by LVM command %s%s pid %d at %s"
|
||||
+ "# HASH=%u\n",
|
||||
+ cmd->name, cmd->device_ids_auto_import ? " (auto)" : "",
|
||||
+ getpid(), ctime(&t), hash)) < 0) {
|
||||
log_warn("Failed to write buffer for devices file content.");
|
||||
goto out;
|
||||
}
|
||||
- fc[fc_bytes] = '\0';
|
||||
|
||||
if (fputs(fc, fp) < 0) {
|
||||
log_warn("Failed to write devices file header.");
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,64 @@
|
||||
From 483caa0b663c8b1b180967856f495bae5fe978a2 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Thu, 16 Apr 2026 11:55:40 +0200
|
||||
Subject: [PATCH 154/211] lib: add missing NULL checks to prevent dereference
|
||||
crashes
|
||||
|
||||
cache_manip: check cn->v before dereferencing in cache_set_policy
|
||||
and cache_vol_set_params - a config section node has NULL value.
|
||||
|
||||
label: check scan_bcache in dev_invalidate_bytes and dev_invalidate,
|
||||
matching the guard already present in peer functions.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 36fe3bfb26dced3bd33018f4d820dd895f5a4074)
|
||||
---
|
||||
lib/label/label.c | 4 ++++
|
||||
lib/metadata/cache_manip.c | 4 ++--
|
||||
2 files changed, 6 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/lib/label/label.c b/lib/label/label.c
|
||||
index 12a825c62..d114c8e42 100644
|
||||
--- a/lib/label/label.c
|
||||
+++ b/lib/label/label.c
|
||||
@@ -1940,11 +1940,15 @@ bool dev_write_bytes(struct device *dev, uint64_t start, size_t len, void *data)
|
||||
|
||||
bool dev_invalidate_bytes(struct device *dev, uint64_t start, size_t len)
|
||||
{
|
||||
+ if (!scan_bcache)
|
||||
+ return true;
|
||||
return bcache_invalidate_bytes(scan_bcache, dev->bcache_di, start, len);
|
||||
}
|
||||
|
||||
void dev_invalidate(struct device *dev)
|
||||
{
|
||||
+ if (!scan_bcache)
|
||||
+ return;
|
||||
bcache_invalidate_di(scan_bcache, dev->bcache_di);
|
||||
}
|
||||
|
||||
diff --git a/lib/metadata/cache_manip.c b/lib/metadata/cache_manip.c
|
||||
index fecf56919..7bf0a2255 100644
|
||||
--- a/lib/metadata/cache_manip.c
|
||||
+++ b/lib/metadata/cache_manip.c
|
||||
@@ -858,7 +858,7 @@ int cache_set_policy(struct lv_segment *lvseg, const char *name,
|
||||
restart: /* remove any 'default" nodes */
|
||||
cn = seg->policy_settings ? seg->policy_settings->child : NULL;
|
||||
while (cn) {
|
||||
- if (cn->v->type == DM_CFG_STRING && !strcmp(cn->v->v.str, "default")) {
|
||||
+ if (cn->v && cn->v->type == DM_CFG_STRING && !strcmp(cn->v->v.str, "default")) {
|
||||
dm_config_remove_node(seg->policy_settings, cn);
|
||||
goto restart;
|
||||
}
|
||||
@@ -1157,7 +1157,7 @@ int cache_vol_set_params(struct cmd_context *cmd,
|
||||
restart: /* remove any 'default" nodes */
|
||||
cn = policy_settings ? policy_settings->child : NULL;
|
||||
while (cn) {
|
||||
- if (cn->v->type == DM_CFG_STRING && !strcmp(cn->v->v.str, "default")) {
|
||||
+ if (cn->v && cn->v->type == DM_CFG_STRING && !strcmp(cn->v->v.str, "default")) {
|
||||
dm_config_remove_node(policy_settings, cn);
|
||||
goto restart;
|
||||
}
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,85 @@
|
||||
From d075514407ffda578ac763491857f2abcab56667 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Thu, 16 Apr 2026 01:59:10 +0200
|
||||
Subject: [PATCH 155/211] pvck: fix buffer overflow, integer truncation, and
|
||||
type mismatches
|
||||
|
||||
- _chars_to_hexstr: memcpy used hardcoded 256 instead of max parameter
|
||||
- _backup_file_to_raw_metadata: back_size * 2 truncated uint64_t to uint32_t
|
||||
- _dump_backup_to_raw, _read_metadata_file: read() rv was int, compared
|
||||
via (int) cast against uint64_t sizes losing high bits
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 60fa392c72d7aa299a1488506608c619cac3a362)
|
||||
---
|
||||
tools/pvck.c | 19 +++++++++++++------
|
||||
1 file changed, 13 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/tools/pvck.c b/tools/pvck.c
|
||||
index 3be469562..325590f11 100644
|
||||
--- a/tools/pvck.c
|
||||
+++ b/tools/pvck.c
|
||||
@@ -123,7 +123,7 @@ static char *_chars_to_hexstr(const void *in, void *out, int num, int max, const
|
||||
i++;
|
||||
}
|
||||
|
||||
- memcpy(out, tmp, 256);
|
||||
+ memcpy(out, tmp, max);
|
||||
|
||||
free(tmp);
|
||||
|
||||
@@ -2696,7 +2696,12 @@ static int _backup_file_to_raw_metadata(char *back_buf, uint64_t back_size,
|
||||
uint32_t text_pos, pre_len = 0, back_pos, text_max;
|
||||
int len, len2, vgnamelen;
|
||||
|
||||
- text_max = back_size * 2;
|
||||
+ if (back_size > UINT32_MAX / 2) {
|
||||
+ log_error("Backup file too large.");
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ text_max = (uint32_t)(back_size * 2);
|
||||
|
||||
if (!(text_buf = zalloc(text_max)))
|
||||
return_0;
|
||||
@@ -2799,7 +2804,8 @@ static int _dump_backup_to_raw(struct cmd_context *cmd, struct settings *set)
|
||||
struct stat sb;
|
||||
char *back_buf, *text_buf;
|
||||
uint64_t back_size, text_size;
|
||||
- int fd, rv, ret;
|
||||
+ ssize_t rv;
|
||||
+ int fd, ret;
|
||||
|
||||
if (arg_is_set(cmd, file_ARG)) {
|
||||
if (!(tofile = arg_str_value(cmd, file_ARG, NULL)))
|
||||
@@ -2830,7 +2836,7 @@ static int _dump_backup_to_raw(struct cmd_context *cmd, struct settings *set)
|
||||
goto fail_close;
|
||||
|
||||
rv = read(fd, back_buf, back_size);
|
||||
- if (rv != (int)back_size) {
|
||||
+ if (rv != (ssize_t)back_size) {
|
||||
log_error("Cannot read file: %s", input);
|
||||
free(back_buf);
|
||||
goto fail_close;
|
||||
@@ -2946,7 +2952,8 @@ static int _read_metadata_file(struct cmd_context *cmd, struct metadata_file *mf
|
||||
char *text_buf;
|
||||
uint64_t text_size;
|
||||
uint32_t text_crc;
|
||||
- int fd, rv;
|
||||
+ ssize_t rv;
|
||||
+ int fd;
|
||||
|
||||
if ((fd = open(mf->filename, O_RDONLY)) < 0) {
|
||||
log_error("Cannot open file: %s", mf->filename);
|
||||
@@ -2967,7 +2974,7 @@ static int _read_metadata_file(struct cmd_context *cmd, struct metadata_file *mf
|
||||
goto_out;
|
||||
|
||||
rv = read(fd, text_buf, text_size);
|
||||
- if (rv != (int)text_size) {
|
||||
+ if (rv != (ssize_t)text_size) {
|
||||
log_error("Cannot read file: %s", mf->filename);
|
||||
free(text_buf);
|
||||
goto out;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,74 @@
|
||||
From 247ca0605f7d0602666abe0cb3d45fb02ebac4a7 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Thu, 16 Apr 2026 00:52:57 +0200
|
||||
Subject: [PATCH 156/211] lvmpolld: replace asserts with proper error handling
|
||||
|
||||
Replace assert(read_single_line()) with if-continue - assert with
|
||||
side effects compiles out with NDEBUG, silently skipping pipe reads
|
||||
and leaving data->line stale for subsequent log calls.
|
||||
|
||||
Replace assert(type < POLL_TYPE_MAX) with proper bounds check
|
||||
returning EINVAL - assert vanishes with NDEBUG allowing
|
||||
out-of-bounds array access.
|
||||
|
||||
Check devicesfile strdup failure in pdlv_create() - the allocation
|
||||
was not validated unlike all other fields in the struct.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit d0c1a22ce823e54eec42e6d2888b20dbcb8306a2)
|
||||
---
|
||||
daemons/lvmpolld/lvmpolld-core.c | 9 ++++++---
|
||||
daemons/lvmpolld/lvmpolld-data-utils.c | 3 ++-
|
||||
2 files changed, 8 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/daemons/lvmpolld/lvmpolld-core.c b/daemons/lvmpolld/lvmpolld-core.c
|
||||
index 65ac18ab5..8ede78597 100644
|
||||
--- a/daemons/lvmpolld/lvmpolld-core.c
|
||||
+++ b/daemons/lvmpolld/lvmpolld-core.c
|
||||
@@ -269,7 +269,8 @@ static int poll_for_output(struct lvmpolld_lv *pdlv, struct lvmpolld_thread_data
|
||||
if (fds[0].revents & POLLIN) {
|
||||
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "caught input data in STDOUT");
|
||||
|
||||
- assert(read_single_line(data, 0)); /* may block indef. anyway */
|
||||
+ if (!read_single_line(data, 0))
|
||||
+ continue; /* may block indef. anyway */
|
||||
INFO(pdlv->ls, "%s: PID %d: %s: '%s'", LVM2_LOG_PREFIX,
|
||||
pdlv->cmd_pid, "STDOUT", data->line);
|
||||
} else if (fds[0].revents) {
|
||||
@@ -287,7 +288,8 @@ static int poll_for_output(struct lvmpolld_lv *pdlv, struct lvmpolld_thread_data
|
||||
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX,
|
||||
"caught input data in STDERR");
|
||||
|
||||
- assert(read_single_line(data, 1)); /* may block indef. anyway */
|
||||
+ if (!read_single_line(data, 1))
|
||||
+ continue; /* may block indef. anyway */
|
||||
WARN(pdlv->ls, "%s: PID %d: %s: '%s'", LVM2_LOG_PREFIX,
|
||||
pdlv->cmd_pid, "STDERR", data->line);
|
||||
} else if (fds[1].revents) {
|
||||
@@ -628,7 +630,8 @@ static response poll_init(client_handle h, struct lvmpolld_state *ls, request re
|
||||
const char *devicesfile = daemon_request_str(req, LVMPD_PARM_DEVICESFILE, NULL);
|
||||
unsigned abort_polling = daemon_request_int(req, LVMPD_PARM_ABORT, 0);
|
||||
|
||||
- assert(type < POLL_TYPE_MAX);
|
||||
+ if (type >= POLL_TYPE_MAX)
|
||||
+ return reply(LVMPD_RESP_EINVAL, REASON_ILLEGAL_ABORT_REQUEST);
|
||||
|
||||
if (abort_polling && type != PVMOVE)
|
||||
return reply(LVMPD_RESP_EINVAL, REASON_ILLEGAL_ABORT_REQUEST);
|
||||
diff --git a/daemons/lvmpolld/lvmpolld-data-utils.c b/daemons/lvmpolld/lvmpolld-data-utils.c
|
||||
index 8a4c6f8b0..111a0f2b9 100644
|
||||
--- a/daemons/lvmpolld/lvmpolld-data-utils.c
|
||||
+++ b/daemons/lvmpolld/lvmpolld-data-utils.c
|
||||
@@ -121,7 +121,8 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
|
||||
.init_rq_count = 1
|
||||
}, *pdlv = (struct lvmpolld_lv *) malloc(sizeof(struct lvmpolld_lv));
|
||||
|
||||
- if (!pdlv || !tmp.lvmpolld_id || !tmp.lvname || !tmp.lvm_system_dir_env || !tmp.sinterval)
|
||||
+ if (!pdlv || !tmp.lvmpolld_id || !tmp.lvname || !tmp.lvm_system_dir_env || !tmp.sinterval ||
|
||||
+ (devicesfile && !tmp.devicesfile))
|
||||
goto err;
|
||||
|
||||
tmp.lvid = _get_lvid(tmp.lvmpolld_id, sysdir);
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,46 @@
|
||||
From 77967846b66b69eacca94a88c092d31515648410 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 10 Apr 2026 10:52:31 +0200
|
||||
Subject: [PATCH 157/211] import_vsn1: validate area_count before subtracting
|
||||
parity_devs
|
||||
|
||||
The RAID extent calculation subtracts parity_devs from area_count
|
||||
without checking that area_count is large enough:
|
||||
|
||||
area_count - segtype->parity_devs
|
||||
|
||||
Both are uint32_t. If an attacker crafts RAID6 metadata with
|
||||
device_count = 1, the subtraction underflows (1 - 2 = 0xFFFFFFFF),
|
||||
producing an invalid stripes value passed to raid_rimage_extents().
|
||||
|
||||
Add validation that area_count > parity_devs before the subtraction
|
||||
to reject semantically invalid metadata (fewer devices than parity
|
||||
requires).
|
||||
|
||||
Reported-by: Tony Asleson <tasleson@redhat.com>
|
||||
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
|
||||
(cherry picked from commit 73d24094985d7e27dc6e0f02f898747609b3635b)
|
||||
---
|
||||
lib/format_text/import_vsn1.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c
|
||||
index 20b1739e9..5b84d875f 100644
|
||||
--- a/lib/format_text/import_vsn1.c
|
||||
+++ b/lib/format_text/import_vsn1.c
|
||||
@@ -440,6 +440,12 @@ static int _read_segment(struct cmd_context *cmd,
|
||||
!segtype->ops->text_import_area_count(sn_child, &area_count))
|
||||
return_0;
|
||||
|
||||
+ if (segtype->parity_devs && area_count <= segtype->parity_devs) {
|
||||
+ log_error("area_count %u must exceed parity_devs %u for segment in %s.",
|
||||
+ area_count, segtype->parity_devs, display_lvname(lv));
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
area_extents = segtype->parity_devs ?
|
||||
raid_rimage_extents(segtype, extent_count, area_count - segtype->parity_devs, data_copies) : extent_count;
|
||||
if (!(seg = alloc_lv_segment(segtype, lv, start_extent,
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,75 @@
|
||||
From 8903bd4c1c5393a45dcf3273d947ce125bf1c672 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Fri, 10 Apr 2026 10:52:21 +0200
|
||||
Subject: [PATCH 158/211] format-text: validate mda size and rlocn size limits
|
||||
|
||||
Two related issues in metadata area validation:
|
||||
|
||||
1. Integer underflow in mdah->size validation: The rlocn bounds
|
||||
checks subtract MDA_HEADER_SIZE (512) from mdah->size without
|
||||
verifying mdah->size >= MDA_HEADER_SIZE. If mdah->size = 0,
|
||||
the subtraction underflows to 0xFFFFFFFFFFFFFE00, bypassing
|
||||
all bounds checks.
|
||||
|
||||
Fix: Add minimum size validation in _raw_read_mda_header() to
|
||||
reject mdah->size < MDA_HEADER_SIZE.
|
||||
|
||||
2. Unsafe uint64_t to uint32_t truncation: rlocn->size is a 64-bit
|
||||
value from disk but passed as uint32_t to text_read_metadata().
|
||||
If rlocn->size exceeds UINT32_MAX, the cast silently discards
|
||||
high bits.
|
||||
|
||||
Fix: Add rlocn->size > UINT32_MAX check in the existing bounds
|
||||
validation. Since wrap < rlocn->size (because rlocn->offset <
|
||||
mdah->size), this guarantees wrap also fits in uint32_t.
|
||||
|
||||
Both issues affect _vg_read_raw_area() and read_metadata_location_summary().
|
||||
|
||||
Reported-by: Tony Asleson <tasleson@redhat.com>
|
||||
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
|
||||
(cherry picked from commit d214bc8b158deab09c799c6e3a585332f633d983)
|
||||
---
|
||||
lib/format_text/format-text.c | 13 +++++++++++--
|
||||
1 file changed, 11 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
|
||||
index 3165312d7..39f1afcad 100644
|
||||
--- a/lib/format_text/format-text.c
|
||||
+++ b/lib/format_text/format-text.c
|
||||
@@ -234,6 +234,13 @@ static int _raw_read_mda_header(struct mda_header *mdah, struct device_area *dev
|
||||
*bad_fields |= BAD_MDA_START;
|
||||
}
|
||||
|
||||
+ if (mdah->size < MDA_HEADER_SIZE) {
|
||||
+ log_warn("WARNING: Metadata area size %llu too small in mda header on %s at %llu.",
|
||||
+ (unsigned long long)mdah->size,
|
||||
+ dev_name(dev_area->dev), (unsigned long long)dev_area->start);
|
||||
+ *bad_fields |= BAD_MDA_HEADER;
|
||||
+ }
|
||||
+
|
||||
*bad_fields &= ~ignore_bad_fields;
|
||||
|
||||
if (*bad_fields)
|
||||
@@ -418,7 +425,8 @@ static struct volume_group *_vg_read_raw_area(struct cmd_context *cmd,
|
||||
|
||||
/* Validate rlocn fields fit within mda bounds before uint32_t cast */
|
||||
if (rlocn->offset >= mdah->size ||
|
||||
- rlocn->size > mdah->size - MDA_HEADER_SIZE) {
|
||||
+ rlocn->size > mdah->size - MDA_HEADER_SIZE ||
|
||||
+ rlocn->size > UINT32_MAX) {
|
||||
log_error("Metadata location out of bounds (offset %llu size %llu mda %llu) on %s.",
|
||||
(unsigned long long)rlocn->offset,
|
||||
(unsigned long long)rlocn->size,
|
||||
@@ -1515,7 +1523,8 @@ int read_metadata_location_summary(const struct format_type *fmt,
|
||||
|
||||
/* Validate rlocn fields fit within mda bounds before uint32_t cast */
|
||||
if (rlocn->offset >= mdah->size ||
|
||||
- rlocn->size > mdah->size - MDA_HEADER_SIZE) {
|
||||
+ rlocn->size > mdah->size - MDA_HEADER_SIZE ||
|
||||
+ rlocn->size > UINT32_MAX) {
|
||||
log_warn("WARNING: Metadata location out of bounds (offset %llu size %llu mda %llu) on %s.",
|
||||
(unsigned long long)rlocn->offset,
|
||||
(unsigned long long)rlocn->size,
|
||||
--
|
||||
2.54.0
|
||||
|
||||
72
0159-lv_manip-validate-area_count-against-MAX_STRIPES.patch
Normal file
72
0159-lv_manip-validate-area_count-against-MAX_STRIPES.patch
Normal file
@ -0,0 +1,72 @@
|
||||
From 56e7c266bc2b6667481b589e230870c5086fb8cb Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Thu, 9 Apr 2026 21:34:07 +0200
|
||||
Subject: [PATCH 159/211] lv_manip: validate area_count against MAX_STRIPES
|
||||
|
||||
Add _validate_area_count helper to prevent integer overflow in
|
||||
multiplication before allocating segment areas.
|
||||
|
||||
Reported-by: Tony Asleson <tasleson@redhat.com>
|
||||
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
|
||||
(cherry picked from commit 30c19ac8d2b86895332bef2c1892403c7ceab0c4)
|
||||
---
|
||||
lib/metadata/lv_manip.c | 23 +++++++++++++++++++++--
|
||||
1 file changed, 21 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
|
||||
index 0fce14f21..72ab89211 100644
|
||||
--- a/lib/metadata/lv_manip.c
|
||||
+++ b/lib/metadata/lv_manip.c
|
||||
@@ -1024,6 +1024,15 @@ static uint32_t _round_to_stripe_boundary(struct volume_group *vg, uint32_t exte
|
||||
return new_extents;
|
||||
}
|
||||
|
||||
+static int _validate_area_count(uint32_t area_count)
|
||||
+{
|
||||
+ if (area_count > MAX_STRIPES) {
|
||||
+ log_error(INTERNAL_ERROR "area_count %u exceeds maximum %u.", area_count, MAX_STRIPES);
|
||||
+ return_0;
|
||||
+ }
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* All lv_segments get created here.
|
||||
*/
|
||||
@@ -1044,13 +1053,18 @@ struct lv_segment *alloc_lv_segment(const struct segment_type *segtype,
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
struct dm_pool *mem = lv->vg->vgmem;
|
||||
- uint32_t areas_sz = area_count * sizeof(*seg->areas);
|
||||
+ uint32_t areas_sz;
|
||||
|
||||
if (!segtype) {
|
||||
log_error(INTERNAL_ERROR "alloc_lv_segment: Missing segtype.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+ if (!_validate_area_count(area_count))
|
||||
+ return_NULL;
|
||||
+
|
||||
+ areas_sz = area_count * sizeof(*seg->areas);
|
||||
+
|
||||
if (!(seg = dm_pool_zalloc(mem, sizeof(*seg))))
|
||||
return_NULL;
|
||||
|
||||
@@ -1354,7 +1368,12 @@ int set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num,
|
||||
int add_lv_segment_areas(struct lv_segment *seg, uint32_t new_area_count)
|
||||
{
|
||||
struct lv_segment_area *newareas;
|
||||
- uint32_t areas_sz = new_area_count * sizeof(*newareas);
|
||||
+ uint32_t areas_sz;
|
||||
+
|
||||
+ if (!_validate_area_count(new_area_count))
|
||||
+ return_0;
|
||||
+
|
||||
+ areas_sz = new_area_count * sizeof(*newareas);
|
||||
|
||||
if (!(newareas = dm_pool_zalloc(seg->lv->vg->vgmem, areas_sz))) {
|
||||
log_error("Failed to allocate widened LV segment for %s.",
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
From af71204b76908cdc13ccfd36e8171a440f492df8 Mon Sep 17 00:00:00 2001
|
||||
From: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
Date: Thu, 16 Apr 2026 11:56:10 +0200
|
||||
Subject: [PATCH 160/211] lvmcache: fix use-after-free on vgid update failure
|
||||
|
||||
When _lvmcache_update_vgid fails after vginfo was already inserted
|
||||
into _vgname_hash, the error path frees vginfo without removing it
|
||||
from the hash, leaving a dangling pointer.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit 58ab3ef97891ab334137e271e9bc5f46acf7265a)
|
||||
---
|
||||
lib/cache/lvmcache.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
|
||||
index 4c95db7db..2da7c81ce 100644
|
||||
--- a/lib/cache/lvmcache.c
|
||||
+++ b/lib/cache/lvmcache.c
|
||||
@@ -1876,6 +1876,7 @@ static int _lvmcache_update_vgname(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
if (!_lvmcache_update_vgid(NULL, vginfo, vgid)) {
|
||||
+ dm_hash_remove(_vgname_hash, vgname);
|
||||
free(vginfo->vgname);
|
||||
free(vginfo);
|
||||
return_0;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user