* Tue Feb 03 2026 Andrew Price <anprice@redhat.com> - 3.5.1-3

- gfs2_edit: Use 0x notation when printing hexadecimal values
- libgfs2: Add a function to look up flags by symbol
- gfs2_edit: Allow setting flags fields using symbols
- gfs2_edit: Only call ioctl(BLKFLSBUF) on block devices
- libgfs2: Fall back to printing a numerical value in lgfs2_field_str()
- gfs2_edit: Set errno for invalid flag arguments in process_field()
- libgfs2: Use '|' as the flag separator in lgfs2_field_str()
- gfs2_edit: Print a better error message for missing path
  Resolves: RHEL-132202
- fsck.gfs2: Fix rebuilding bad 'system' inodes
  Resolves: RHEL-143418
This commit is contained in:
Andrew Price 2026-02-03 18:47:49 +00:00
parent 1d17e1fc2a
commit 77ca5b65dc
10 changed files with 619 additions and 1 deletions

View File

@ -0,0 +1,45 @@
commit 83ded388446e7422715196b2f470f1169d130311
Author: Andrew Price <anprice@redhat.com>
Date: Mon Dec 1 14:39:30 2025 +0000
gfs2_edit: Use 0x notation when printing hexadecimal values
Changes the output of gfs2_edit -x for struct fields and log header
flags.
Resolves: RHEL-132202
Signed-off-by: Andrew Price <anprice@redhat.com>
diff --git a/gfs2/libgfs2/meta.c b/gfs2/libgfs2/meta.c
index 5d8811a6..82f5d3a8 100644
--- a/gfs2/libgfs2/meta.c
+++ b/gfs2/libgfs2/meta.c
@@ -887,7 +887,7 @@ int lgfs2_field_str(char *str, const size_t size, const char *blk, const struct
}
if (hex) {
- snprintf(str, size, "%"PRIx64, value);
+ snprintf(str, size, "0x%"PRIx64, value);
goto out;
}
if (field->flags & LGFS2_MFF_MASK) {
diff --git a/tests/mkfs.at b/tests/mkfs.at
index 7064a9e2..9c93c80f 100644
--- a/tests/mkfs.at
+++ b/tests/mkfs.at
@@ -206,11 +206,11 @@ AT_CHECK([$GFS_MKFS -p lock_nolock -o root_inherit_jdata= $GFS_TGT], 255, [ignor
AT_CHECK([$GFS_MKFS -p lock_nolock -o root_inherit_jdata=42 $GFS_TGT], 255, [ignore], [ignore])
AT_CHECK([$GFS_MKFS -p lock_nolock -o root_inherit_jdata=X $GFS_TGT], 255, [ignore], [ignore])
AT_CHECK([$GFS_MKFS -p lock_nolock -o root_inherit_jdata $GFS_TGT], 0, [ignore], [ignore])
-AT_CHECK([gfs2_edit -x -p root field di_flags $GFS_TGT | tr -d '\n'], 0, [80000001], [ignore])
+AT_CHECK([gfs2_edit -x -p root field di_flags $GFS_TGT | tr -d '\n'], 0, [0x80000001], [ignore])
AT_CHECK([$GFS_MKFS -p lock_nolock -o root_inherit_jdata=1 $GFS_TGT], 0, [ignore], [ignore])
-AT_CHECK([gfs2_edit -x -p root field di_flags $GFS_TGT | tr -d '\n'], 0, [80000001], [ignore])
+AT_CHECK([gfs2_edit -x -p root field di_flags $GFS_TGT | tr -d '\n'], 0, [0x80000001], [ignore])
AT_CHECK([$GFS_MKFS -p lock_nolock -o root_inherit_jdata=0 $GFS_TGT], 0, [ignore], [ignore])
-AT_CHECK([gfs2_edit -x -p root field di_flags $GFS_TGT | tr -d '\n'], 0, [1], [ignore])
+AT_CHECK([gfs2_edit -x -p root field di_flags $GFS_TGT | tr -d '\n'], 0, [0x1], [ignore])
AT_CHECK([$GFS_MKFS -p lock_nolock $GFS_TGT], 0, [ignore], [ignore])
-AT_CHECK([gfs2_edit -x -p root field di_flags $GFS_TGT | tr -d '\n'], 0, [1], [ignore])
+AT_CHECK([gfs2_edit -x -p root field di_flags $GFS_TGT | tr -d '\n'], 0, [0x1], [ignore])
AT_CLEANUP

View File

@ -0,0 +1,98 @@
commit 9179cb0f0bec09add0b64281bcd917e1869e3569
Author: Andrew Price <anprice@redhat.com>
Date: Mon Dec 1 15:51:54 2025 +0000
libgfs2: Add a function to look up flags by symbol
Add lgfs2_flag_sym_value() to simplify parsing of flag values from
strings.
Resolves: RHEL-132202
Signed-off-by: Andrew Price <anprice@redhat.com>
diff --git a/gfs2/libgfs2/check_meta.c b/gfs2/libgfs2/check_meta.c
index 340d3c8d..8e448203 100644
--- a/gfs2/libgfs2/check_meta.c
+++ b/gfs2/libgfs2/check_meta.c
@@ -38,6 +38,30 @@ START_TEST(check_symtab)
}
END_TEST
+START_TEST(check_flag_sym_value)
+{
+ const struct lgfs2_metadata *di_meta = &lgfs2_metadata[LGFS2_MT_GFS2_DINODE];
+ const struct lgfs2_metafield *flags_field = lgfs2_find_mfield_name("di_flags", di_meta);
+
+ ck_assert(lgfs2_flag_sym_value(NULL, flags_field) == 0);
+ ck_assert(lgfs2_flag_sym_value("", flags_field) == 0);
+ ck_assert(lgfs2_flag_sym_value("invalid_flag", flags_field) == 0);
+ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_JDATA", flags_field) == GFS2_DIF_JDATA);
+ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_EXHASH", flags_field) == GFS2_DIF_EXHASH);
+ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_UNUSED", flags_field) == GFS2_DIF_UNUSED);
+ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_EA_INDIRECT", flags_field) == GFS2_DIF_EA_INDIRECT);
+ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_DIRECTIO", flags_field) == GFS2_DIF_DIRECTIO);
+ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_IMMUTABLE", flags_field) == GFS2_DIF_IMMUTABLE);
+ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_APPENDONLY", flags_field) == GFS2_DIF_APPENDONLY);
+ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_NOATIME", flags_field) == GFS2_DIF_NOATIME);
+ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_SYNC", flags_field) == GFS2_DIF_SYNC);
+ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_SYSTEM", flags_field) == GFS2_DIF_SYSTEM);
+ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_TRUNC_IN_PROG", flags_field) == GFS2_DIF_TRUNC_IN_PROG);
+ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_INHERIT_DIRECTIO", flags_field) == GFS2_DIF_INHERIT_DIRECTIO);
+ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_INHERIT_JDATA", flags_field) == GFS2_DIF_INHERIT_JDATA);
+}
+END_TEST
+
START_TEST(check_ptrs)
{
int i, j;
@@ -64,6 +88,7 @@ Suite *suite_meta(void)
tcase_add_test(tc_meta, check_metadata_sizes);
tcase_add_test(tc_meta, check_symtab);
tcase_add_test(tc_meta, check_ptrs);
+ tcase_add_test(tc_meta, check_flag_sym_value);
suite_add_tcase(s, tc_meta);
return s;
diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index 7531a2d6..abe9944e 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -452,6 +452,7 @@ extern const struct lgfs2_metadata *lgfs2_find_mtype(uint32_t mh_type, const uns
extern const struct lgfs2_metadata *lgfs2_find_mtype_name(const char *name, const unsigned versions);
extern const struct lgfs2_metafield *lgfs2_find_mfield_name(const char *name, const struct lgfs2_metadata *mtype);
extern int lgfs2_field_str(char *str, const size_t size, const char *blk, const struct lgfs2_metafield *field, int hex);
+extern uint32_t lgfs2_flag_sym_value(const char *sym, const struct lgfs2_metafield *field);
extern int lgfs2_field_assign(char *blk, const struct lgfs2_metafield *field, const void *val);
/* buf.c */
diff --git a/gfs2/libgfs2/meta.c b/gfs2/libgfs2/meta.c
index 82f5d3a8..3b313ad2 100644
--- a/gfs2/libgfs2/meta.c
+++ b/gfs2/libgfs2/meta.c
@@ -922,6 +922,26 @@ out:
return 0;
}
+/**
+ * Look up a flag value from a symbolic name. Matching is case-sensitive.
+ * Does not parse combined symbols like "X|Y".
+ * sym: the symbolic name
+ * field: the flags field the name relates to.
+ * Returns the flag value or 0 if not found.
+ */
+uint32_t lgfs2_flag_sym_value(const char *sym, const struct lgfs2_metafield *field)
+{
+ if (sym == NULL)
+ return 0;
+
+ for (unsigned i = 0; i < field->nsyms; i++)
+ {
+ if (strcmp(sym, field->symtab[i].value) == 0)
+ return field->symtab[i].key;
+ }
+ return 0;
+}
+
int lgfs2_field_assign(char *blk, const struct lgfs2_metafield *field, const void *val)
{
char *fieldp = blk + field->offset;

View File

@ -0,0 +1,95 @@
commit 67b9d9a2f1380a8db1bcb963b18cdd00550c76b9
Author: Andrew Price <anprice@redhat.com>
Date: Mon Dec 1 19:30:29 2025 +0000
gfs2_edit: Allow setting flags fields using symbols
Parse combinations of symbolic flags to set flags fields.
The separator is chosen to be '|' as it's consistent with C. It has the
drawback of needing to be escaped in command lines but unfortunately the
argument parsing code treats anything with '/' as a path so the
separator used in output cannot be used. Adding a third separator would
be even more confusing.
Resolves: RHEL-132202
Signed-off-by: Andrew Price <anprice@redhat.com>
diff --git a/gfs2/edit/hexedit.c b/gfs2/edit/hexedit.c
index ccce0fd0..821b9a02 100644
--- a/gfs2/edit/hexedit.c
+++ b/gfs2/edit/hexedit.c
@@ -1689,6 +1689,38 @@ static void find_change_block_alloc(int *newval)
exit(0);
}
+/**
+ * Parse a string like "GFS2_DIF_SYSTEM|GFS2_DIF_JDATA" into the corresponding
+ * value for a bitmask field.
+ * syms: The string.
+ * field: The field type.
+ * Returns the values for the specified flags ORed together or 0 on failure.
+ */
+static uint32_t flag_syms_value(const char *syms, const struct lgfs2_metafield *field)
+{
+ char *str, *iter, *tok;
+ uint32_t val = 0;
+
+ if (syms == NULL || *syms == '\0')
+ return 0;
+
+ str = iter = strdup(syms);
+ if (str == NULL)
+ return 0;
+
+ while ((tok = strsep(&iter, "|"))) {
+ uint32_t flag = lgfs2_flag_sym_value(tok, field);
+
+ if (flag == 0) {
+ free(str);
+ return 0;
+ }
+ val |= flag;
+ }
+ free(str);
+ return val;
+}
+
/**
* process request to print a certain field from a previously pushed block
*/
@@ -1720,7 +1752,13 @@ static void process_field(const char *field, const char *nstr)
err = lgfs2_field_assign(rbh->b_data, mfield, nstr);
} else {
uint64_t val = 0;
- err = sscanf(nstr, "%"SCNi64, &val);
+
+ if (mfield->flags & LGFS2_MFF_MASK) {
+ val = flag_syms_value(nstr, mfield);
+ err = 1;
+ }
+ if (val == 0)
+ err = sscanf(nstr, "%"SCNi64, &val);
if (err == 1)
/* coverity[overrun-buffer-val:SUPPRESS] False positive */
err = lgfs2_field_assign(rbh->b_data, mfield, &val);
diff --git a/tests/edit.at b/tests/edit.at
index 29835df0..bc3dc28b 100644
--- a/tests/edit.at
+++ b/tests/edit.at
@@ -71,3 +71,15 @@ AT_CHECK([truncate -s 10K test.file], 0, [ignore], [ignore])
AT_CHECK([gfs2_edit restoremeta test.meta test.file], 0, [ignore], [ignore])
AT_CHECK([fsck.gfs2 -n test.file], 0, [ignore], [ignore])
AT_CLEANUP
+
+AT_SETUP([Set flags by symbol])
+AT_KEYWORDS(gfs2_edit edit)
+GFS_TGT_REGEN
+AT_CHECK([$GFS_MKFS -p lock_nolock $GFS_TGT], 0, [ignore], [ignore])
+AT_CHECK([gfs2_edit -p journal0 field di_flags invalid_flag $GFS_TGT], 1, [ignore], [ignore])
+AT_CHECK([gfs2_edit -p journal0 field di_flags 'GFS2_DIF_SYSTEM' $GFS_TGT | tr -d '\n'], 0, [GFS2_DIF_SYSTEM], [ignore])
+AT_CHECK([gfs2_edit -p journal0 field di_flags 'GFS2_DIF_SYSTEM|GFS2_DIF_JDATA' $GFS_TGT | tr -d '\n'], 0, [GFS2_DIF_JDATA/GFS2_DIF_SYSTEM], [ignore])
+AT_CHECK([gfs2_edit -x -p journal0 field di_flags 'GFS2_DIF_SYSTEM|GFS2_DIF_JDATA' $GFS_TGT | tr -d '\n'], 0, [0x201], [ignore])
+AT_CHECK([gfs2_edit -p journal0 field di_flags $GFS_TGT | tr -d '\n'], 0, [GFS2_DIF_JDATA/GFS2_DIF_SYSTEM], [ignore])
+AT_CHECK([gfs2_edit -x -p journal0 field di_flags $GFS_TGT | tr -d '\n'], 0, [0x201], [ignore])
+AT_CLEANUP

View File

@ -0,0 +1,65 @@
commit 45628f23874fb8f596f5e8368f4247f08b30703b
Author: Andrew Price <anprice@redhat.com>
Date: Tue Dec 2 14:25:03 2025 +0000
gfs2_edit: Only call ioctl(BLKFLSBUF) on block devices
Prevents failures of these calls causing confusing error messages.
Resolves: RHEL-132202
Signed-off-by: Andrew Price <anprice@redhat.com>
diff --git a/gfs2/edit/hexedit.c b/gfs2/edit/hexedit.c
index 821b9a02..7e3a8a24 100644
--- a/gfs2/edit/hexedit.c
+++ b/gfs2/edit/hexedit.c
@@ -42,6 +42,7 @@ static struct lgfs2_inum gfs1_license_di;
int details = 0;
char *device = NULL;
+struct stat devstat;
/* ------------------------------------------------------------------------- */
/* erase - clear the screen */
@@ -872,7 +873,8 @@ static void read_superblock(int fd)
{
struct gfs2_meta_header *mh;
- ioctl(fd, BLKFLSBUF, 0);
+ if (S_ISBLK(devstat.st_mode))
+ ioctl(fd, BLKFLSBUF, 0);
memset(&sbd, 0, sizeof(struct lgfs2_sbd));
sbd.sd_bsize = LGFS2_DEFAULT_BSIZE;
sbd.device_fd = fd;
@@ -950,7 +952,8 @@ static int read_rindex(void)
static int read_master_dir(void)
{
- ioctl(sbd.device_fd, BLKFLSBUF, 0);
+ if (S_ISBLK(devstat.st_mode))
+ ioctl(sbd.device_fd, BLKFLSBUF, 0);
bh = lgfs2_bread(&sbd, sbd.sd_meta_dir.in_addr);
if (bh == NULL)
@@ -986,7 +989,8 @@ int display(int identify_only, int trunc_zeros, uint64_t flagref,
if (bh != NULL)
lgfs2_brelse(bh);
dev_offset = blk * sbd.sd_bsize;
- ioctl(sbd.device_fd, BLKFLSBUF, 0);
+ if (S_ISBLK(devstat.st_mode))
+ ioctl(sbd.device_fd, BLKFLSBUF, 0);
if (!(bh = lgfs2_bread(&sbd, blk))) {
fprintf(stderr, "read error: %s from %s:%d: "
"offset %"PRIu64" (0x%"PRIx64")\n",
@@ -2575,6 +2579,11 @@ int main(int argc, char *argv[])
fprintf(stderr, "Failed to open '%s': %s\n", device, strerror(errno));
exit(1);
}
+ if (fstat(fd, &devstat) != 0) {
+ fprintf(stderr, "Failed to fstat '%s': %s\n", device, strerror(errno));
+ close(fd);
+ exit(1);
+ }
max_block = lseek(fd, 0, SEEK_END) / sbd.sd_bsize;
read_superblock(fd);

View File

@ -0,0 +1,60 @@
commit 18fcae907955e5d24ddd63c9f98aa28c2e92ab5c
Author: Andrew Price <anprice@redhat.com>
Date: Tue Dec 2 17:06:31 2025 +0000
libgfs2: Fall back to printing a numerical value in lgfs2_field_str()
If the bitmask value isn't a valid combination of flags then
lgfs2_field_str() currently leaves the resulting string empty. Fall back
to setting the string to the numerical value instead.
Resolves: RHEL-132202
Signed-off-by: Andrew Price <anprice@redhat.com>
diff --git a/gfs2/libgfs2/meta.c b/gfs2/libgfs2/meta.c
index 3b313ad2..8b93c0a0 100644
--- a/gfs2/libgfs2/meta.c
+++ b/gfs2/libgfs2/meta.c
@@ -1,4 +1,5 @@
#include <stdint.h>
+#include <stdbool.h>
#include <string.h>
#include <uuid.h>
#include "libgfs2.h"
@@ -892,6 +893,7 @@ int lgfs2_field_str(char *str, const size_t size, const char *blk, const struct
}
if (field->flags & LGFS2_MFF_MASK) {
char *s = str, *end = str + size;
+ bool found = false;
unsigned n;
for (n = 0; n < field->nsyms; n++) {
@@ -899,6 +901,7 @@ int lgfs2_field_str(char *str, const size_t size, const char *blk, const struct
if (!(value & sym->key))
continue;
+ found = true;
if (s != str && s < end)
*s++ = '/';
if (s < end) {
@@ -913,7 +916,8 @@ int lgfs2_field_str(char *str, const size_t size, const char *blk, const struct
}
if (s < end)
*s = '\0';
- goto out;
+ if (found)
+ goto out;
}
snprintf(str, size, "%"PRIu64, value);
}
diff --git a/tests/edit.at b/tests/edit.at
index bc3dc28b..22a60f04 100644
--- a/tests/edit.at
+++ b/tests/edit.at
@@ -82,4 +82,6 @@ AT_CHECK([gfs2_edit -p journal0 field di_flags 'GFS2_DIF_SYSTEM|GFS2_DIF_JDATA'
AT_CHECK([gfs2_edit -x -p journal0 field di_flags 'GFS2_DIF_SYSTEM|GFS2_DIF_JDATA' $GFS_TGT | tr -d '\n'], 0, [0x201], [ignore])
AT_CHECK([gfs2_edit -p journal0 field di_flags $GFS_TGT | tr -d '\n'], 0, [GFS2_DIF_JDATA/GFS2_DIF_SYSTEM], [ignore])
AT_CHECK([gfs2_edit -x -p journal0 field di_flags $GFS_TGT | tr -d '\n'], 0, [0x201], [ignore])
+AT_CHECK([gfs2_edit -p journal0 field di_flags 0 $GFS_TGT | tr -d '\n'], 0, [0], [ignore])
+AT_CHECK([gfs2_edit -x -p journal0 field di_flags 0 $GFS_TGT | tr -d '\n'], 0, [0x0], [ignore])
AT_CLEANUP

View File

@ -0,0 +1,28 @@
commit aa645d8035dcfbfb00d7ab5496019e8a04e56b61
Author: Andrew Price <anprice@redhat.com>
Date: Tue Dec 2 17:52:46 2025 +0000
gfs2_edit: Set errno for invalid flag arguments in process_field()
sscanf() zeroes errno causing invalid flag arguments to be reported as
Could not set 'di_flags' to '': Success
Set errno to EINVAL to report validation failures in this section of
process_field() sensibly.
Resolves: RHEL-132202
Signed-off-by: Andrew Price <anprice@redhat.com>
diff --git a/gfs2/edit/hexedit.c b/gfs2/edit/hexedit.c
index 7e3a8a24..2dc7d0a7 100644
--- a/gfs2/edit/hexedit.c
+++ b/gfs2/edit/hexedit.c
@@ -1763,6 +1763,7 @@ static void process_field(const char *field, const char *nstr)
}
if (val == 0)
err = sscanf(nstr, "%"SCNi64, &val);
+ errno = EINVAL;
if (err == 1)
/* coverity[overrun-buffer-val:SUPPRESS] False positive */
err = lgfs2_field_assign(rbh->b_data, mfield, &val);

View File

@ -0,0 +1,40 @@
commit a83d4311da206711c3368c6be555c6ac16cb64e5
Author: Andrew Price <anprice@redhat.com>
Date: Wed Dec 3 15:44:56 2025 +0000
libgfs2: Use '|' as the flag separator in lgfs2_field_str()
To make gfs2_edit's output consistent with its expected input.
Resolves: RHEL-132202
Signed-off-by: Andrew Price <anprice@redhat.com>
diff --git a/gfs2/libgfs2/meta.c b/gfs2/libgfs2/meta.c
index 8b93c0a0..9fb43e05 100644
--- a/gfs2/libgfs2/meta.c
+++ b/gfs2/libgfs2/meta.c
@@ -903,7 +903,7 @@ int lgfs2_field_str(char *str, const size_t size, const char *blk, const struct
continue;
found = true;
if (s != str && s < end)
- *s++ = '/';
+ *s++ = '|';
if (s < end) {
const char *v = sym->value + sym->prefix;
size_t len = strlen(v);
diff --git a/tests/edit.at b/tests/edit.at
index 22a60f04..7aeaf70a 100644
--- a/tests/edit.at
+++ b/tests/edit.at
@@ -78,9 +78,9 @@ GFS_TGT_REGEN
AT_CHECK([$GFS_MKFS -p lock_nolock $GFS_TGT], 0, [ignore], [ignore])
AT_CHECK([gfs2_edit -p journal0 field di_flags invalid_flag $GFS_TGT], 1, [ignore], [ignore])
AT_CHECK([gfs2_edit -p journal0 field di_flags 'GFS2_DIF_SYSTEM' $GFS_TGT | tr -d '\n'], 0, [GFS2_DIF_SYSTEM], [ignore])
-AT_CHECK([gfs2_edit -p journal0 field di_flags 'GFS2_DIF_SYSTEM|GFS2_DIF_JDATA' $GFS_TGT | tr -d '\n'], 0, [GFS2_DIF_JDATA/GFS2_DIF_SYSTEM], [ignore])
+AT_CHECK([gfs2_edit -p journal0 field di_flags 'GFS2_DIF_SYSTEM|GFS2_DIF_JDATA' $GFS_TGT | tr -d '\n'], 0, [GFS2_DIF_JDATA|GFS2_DIF_SYSTEM], [ignore])
AT_CHECK([gfs2_edit -x -p journal0 field di_flags 'GFS2_DIF_SYSTEM|GFS2_DIF_JDATA' $GFS_TGT | tr -d '\n'], 0, [0x201], [ignore])
-AT_CHECK([gfs2_edit -p journal0 field di_flags $GFS_TGT | tr -d '\n'], 0, [GFS2_DIF_JDATA/GFS2_DIF_SYSTEM], [ignore])
+AT_CHECK([gfs2_edit -p journal0 field di_flags $GFS_TGT | tr -d '\n'], 0, [GFS2_DIF_JDATA|GFS2_DIF_SYSTEM], [ignore])
AT_CHECK([gfs2_edit -x -p journal0 field di_flags $GFS_TGT | tr -d '\n'], 0, [0x201], [ignore])
AT_CHECK([gfs2_edit -p journal0 field di_flags 0 $GFS_TGT | tr -d '\n'], 0, [0], [ignore])
AT_CHECK([gfs2_edit -x -p journal0 field di_flags 0 $GFS_TGT | tr -d '\n'], 0, [0x0], [ignore])

View File

@ -0,0 +1,28 @@
commit 3defe7201255961dc82720069a2b901ba3c6498a
Author: Andrew Price <anprice@redhat.com>
Date: Wed Dec 3 16:02:22 2025 +0000
gfs2_edit: Print a better error message for missing path
If gfs2_edit fails to parse the device path from argv it still passes
the device variable to open(2) which results in a "Bad address" error
message. Catch a NULL or empty path and report it as a missing path.
Resolves: RHEL-132202
Signed-off-by: Andrew Price <anprice@redhat.com>
diff --git a/gfs2/edit/hexedit.c b/gfs2/edit/hexedit.c
index 2dc7d0a7..19b58ff9 100644
--- a/gfs2/edit/hexedit.c
+++ b/gfs2/edit/hexedit.c
@@ -2575,6 +2575,10 @@ int main(int argc, char *argv[])
if (dmode == INIT_MODE)
dmode = HEX_MODE;
+ if (device == NULL || *device == '\0') {
+ fprintf(stderr, "No device path specified\n");
+ exit(1);
+ }
fd = open(device, O_RDWR);
if (fd < 0) {
fprintf(stderr, "Failed to open '%s': %s\n", device, strerror(errno));

View File

@ -0,0 +1,137 @@
commit d1392bb22bae2d82b589aefb267be93c22576bff
Author: Andrew Price <anprice@redhat.com>
Date: Thu Jan 15 17:30:12 2026 +0000
fsck.gfs2: Fix rebuilding bad 'system' inodes
When these inodes are scribbled over, the fsck.gfs2 builder functions
called by check_system_inode() don't rebuild them properly. Firstly,
they free the rebuilt inode causing a subsequent segfault; and secondly
they don't remove the directory entry before rebuilding, causing the
lgfs2_createi() call used by libgfs2 builder functions to just return
the existing broken inode. Fix these two issues in each of the system
inode builder functions.
Resolves: RHEL-143418
Signed-off-by: Andrew Price <anprice@redhat.com>
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 206929fc..49f51f53 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -1465,6 +1465,8 @@ static int check_system_inode(struct fsck_cx *cx,
if (query(cx, _("Create new %s system inode? (y/n) "), filename)) {
log_err( _("Rebuilding system file \"%s\"\n"),
filename);
+ lgfs2_inode_free(sysinode);
+ lgfs2_dirent_del(sysdir, filename, strlen(filename));
error = builder(cx->sdp);
if (error || *sysinode == NULL) {
log_err( _("Error rebuilding system "
@@ -1581,8 +1583,8 @@ static int build_inum(struct lgfs2_sbd *sdp)
struct lgfs2_inode *ip = lgfs2_build_inum(sdp);
if (ip == NULL)
return -1;
- lgfs2_inode_put(&ip);
- return 0;
+ sdp->md.inum = ip;
+ return lgfs2_init_inum(sdp);
}
static int build_statfs(struct lgfs2_sbd *sdp)
@@ -1590,8 +1592,8 @@ static int build_statfs(struct lgfs2_sbd *sdp)
struct lgfs2_inode *ip = lgfs2_build_statfs(sdp);
if (ip == NULL)
return -1;
- lgfs2_inode_put(&ip);
- return 0;
+ sdp->md.statfs = ip;
+ return lgfs2_init_statfs(sdp, NULL);
}
static int build_rindex(struct lgfs2_sbd *sdp)
@@ -1599,8 +1601,9 @@ static int build_rindex(struct lgfs2_sbd *sdp)
struct lgfs2_inode *ip = lgfs2_build_rindex(sdp);
if (ip == NULL)
return -1;
- lgfs2_inode_put(&ip);
- return 0;
+ sdp->md.riinode = ip;
+ lgfs2_dinode_out(ip, ip->i_bh->b_data);
+ return lgfs2_bwrite(ip->i_bh);
}
static int build_quota(struct lgfs2_sbd *sdp)
@@ -1608,8 +1611,9 @@ static int build_quota(struct lgfs2_sbd *sdp)
struct lgfs2_inode *ip = lgfs2_build_quota(sdp);
if (ip == NULL)
return -1;
- lgfs2_inode_put(&ip);
- return 0;
+ sdp->md.qinode = ip;
+ lgfs2_dinode_out(ip, ip->i_bh->b_data);
+ return lgfs2_bwrite(ip->i_bh);
}
static int check_system_inodes(struct fsck_cx *cx)
diff --git a/gfs2/libgfs2/fs_ops.c b/gfs2/libgfs2/fs_ops.c
index ba9434af..2f6b2828 100644
--- a/gfs2/libgfs2/fs_ops.c
+++ b/gfs2/libgfs2/fs_ops.c
@@ -115,7 +115,8 @@ void lgfs2_inode_free(struct lgfs2_inode **ipp)
{
struct lgfs2_inode *ip = *ipp;
- free(ip->i_bh);
+ if (ip)
+ free(ip->i_bh);
free(ip);
*ipp = NULL;
}
diff --git a/tests/fsck.at b/tests/fsck.at
index 538d41ad..c860d432 100644
--- a/tests/fsck.at
+++ b/tests/fsck.at
@@ -75,6 +75,42 @@ AT_CHECK([fsck.gfs2 -y $GFS_TGT], 1, [ignore], [ignore])
AT_CHECK([fsck.gfs2 -n $GFS_TGT], 0, [ignore], [ignore])
AT_CLEANUP
+AT_SETUP([Rebuild bad statfs])
+AT_KEYWORDS(fsck.gfs2 fsck)
+GFS_TGT_REGEN
+AT_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], 0, [ignore], [ignore])
+AT_CHECK([gfs2_edit -p statfs field di_header.mh_magic 0 $GFS_TGT], 0, [ignore], [ignore])
+AT_CHECK([fsck.gfs2 -y $GFS_TGT], 1, [ignore], [ignore])
+AT_CHECK([fsck.gfs2 -n $GFS_TGT], 0, [ignore], [ignore])
+AT_CLEANUP
+
+AT_SETUP([Rebuild bad inum])
+AT_KEYWORDS(fsck.gfs2 fsck)
+GFS_TGT_REGEN
+AT_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], 0, [ignore], [ignore])
+AT_CHECK([gfs2_edit -p inum field di_header.mh_magic 0 $GFS_TGT], 0, [ignore], [ignore])
+AT_CHECK([fsck.gfs2 -y $GFS_TGT], 1, [ignore], [ignore])
+AT_CHECK([fsck.gfs2 -n $GFS_TGT], 0, [ignore], [ignore])
+AT_CLEANUP
+
+AT_SETUP([Rebuild bad rindex])
+AT_KEYWORDS(fsck.gfs2 fsck)
+GFS_TGT_REGEN
+AT_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], 0, [ignore], [ignore])
+AT_CHECK([gfs2_edit -p rindex field di_header.mh_magic 0 $GFS_TGT], 0, [ignore], [ignore])
+AT_CHECK([fsck.gfs2 -y $GFS_TGT], 1, [ignore], [ignore])
+AT_CHECK([fsck.gfs2 -n $GFS_TGT], 0, [ignore], [ignore])
+AT_CLEANUP
+
+AT_SETUP([Rebuild bad quota])
+AT_KEYWORDS(fsck.gfs2 fsck)
+GFS_TGT_REGEN
+AT_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], 0, [ignore], [ignore])
+AT_CHECK([gfs2_edit -p quota field di_header.mh_magic 0 $GFS_TGT], 0, [ignore], [ignore])
+AT_CHECK([fsck.gfs2 -y $GFS_TGT], 1, [ignore], [ignore])
+AT_CHECK([fsck.gfs2 -n $GFS_TGT], 0, [ignore], [ignore])
+AT_CLEANUP
+
AT_SETUP([gfs2 format versions])
AT_KEYWORDS(fsck.gfs2 fsck)
GFS_TGT_REGEN

View File

@ -1,6 +1,6 @@
Name: gfs2-utils
Version: 3.5.1
Release: 2%{?dist}
Release: 3%{?dist}
License: GPLv2+ and LGPLv2+
Summary: Utilities for managing the global file system (GFS2)
%ifnarch %{arm}
@ -22,6 +22,15 @@ BuildRequires: make
Source: https://releases.pagure.org/gfs2-utils/gfs2-utils-%{version}.tar.gz
URL: https://pagure.io/gfs2-utils
Patch0: RHEL-26661-gfs2_edit_truncate_to_filesystem_size_at_end_of_restoremeta.patch
Patch1: RHEL-132202-1-gfs2_edit_Use_0x_notation_when_printing_hexadecimal_values.patch
Patch2: RHEL-132202-2-libgfs2_Add_a_function_to_look_up_flags_by_symbol.patch
Patch3: RHEL-132202-3-gfs2_edit_Allow_setting_flags_fields_using_symbols.patch
Patch4: RHEL-132202-4-gfs2_edit_Only_call_ioctl_BLKFLSBUF_on_block_devices.patch
Patch5: RHEL-132202-5-libgfs2_Fall_back_to_printing_a_numerical_value_in_lgfs2_field_str.patch
Patch6: RHEL-132202-6-gfs2_edit_Set_errno_for_invalid_flag_arguments_in_process_field.patch
Patch7: RHEL-132202-7-libgfs2_Use_as_the_flag_separator_in_lgfs2_field_str.patch
Patch8: RHEL-132202-8-gfs2_edit_Print_a_better_error_message_for_missing_path.patch
Patch9: RHEL-143418-fsck_gfs2_Fix_rebuilding_bad_system_inodes.patch
%prep
%autosetup -p1
@ -64,6 +73,19 @@ modifying, and correcting inconsistencies in GFS2 file systems.
%{_prefix}/lib/udev/rules.d/82-gfs2-withdraw.rules
%changelog
* Tue Feb 03 2026 Andrew Price <anprice@redhat.com> - 3.5.1-3
- gfs2_edit: Use 0x notation when printing hexadecimal values
- libgfs2: Add a function to look up flags by symbol
- gfs2_edit: Allow setting flags fields using symbols
- gfs2_edit: Only call ioctl(BLKFLSBUF) on block devices
- libgfs2: Fall back to printing a numerical value in lgfs2_field_str()
- gfs2_edit: Set errno for invalid flag arguments in process_field()
- libgfs2: Use '|' as the flag separator in lgfs2_field_str()
- gfs2_edit: Print a better error message for missing path
Resolves: RHEL-132202
- fsck.gfs2: Fix rebuilding bad 'system' inodes
Resolves: RHEL-143418
* Fri Jun 21 2024 Andrew Price <anprice@redhat.com> - 3.5.1-2
- gfs2_edit: truncate to filesystem size at end of restoremeta()
Resolves: RHEL-26661