You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
xfsprogs/SOURCES/xfsprogs-for-next-xfs_repai...

81 lines
2.9 KiB

From 5a43a00432ebe9ab8b54155703a9eb9e1a1dd4ec Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <djwong@kernel.org>
Date: Mon, 29 Jul 2024 16:23:31 -0700
Subject: [PATCH] xfs_repair: allow symlinks with short remote targets
Symbolic links can have extended attributes. If the attr fork consumes
enough space in the inode record, a shortform symlink can become a
remote symlink. However, if we delete those extended attributes, the
target is not moved back into the inode core.
IOWs, we can end up with a symlink inode that looks like this:
core.magic = 0x494e
core.mode = 0120777
core.version = 3
core.format = 2 (extents)
core.nlinkv2 = 1
core.nextents = 1
core.size = 297
core.nblocks = 1
core.naextents = 0
core.forkoff = 0
core.aformat = 2 (extents)
u3.bmx[0] = [startoff,startblock,blockcount,extentflag]
0:[0,12,1,0]
This is a symbolic link with a 297-byte target stored in a disk block,
which is to say this is a symlink with a remote target. The forkoff is
0, which is to say that there's 512 - 176 == 336 bytes in the inode core
to store the data fork.
Prior to kernel commit 1eb70f54c445f, the kernel was ok with this
arrangement, but the change to symlink validation in that patch now
produces corruption errors on filesystems written by older kernels that
are not otherwise inconsistent. Those changes were inspired by reports
of illegal memory accesses, which I think were a result of making data
fork access decisions based on symlink di_size and not on di_format.
Unfortunately, for a very long time xfs_repair has flagged these inodes
as being corrupt, even though the kernel has historically been willing
to read and write symlinks with these properties. Resolve the conflict
by adjusting the xfs_repair corruption tests to allow extents format.
This change matches the kernel patch "xfs: allow symlinks with short
remote targets".
While we're at it, fix a lurking bad symlink fork access.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Pavel Reichl <preichl@redhat.com>
---
repair/dinode.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/repair/dinode.c b/repair/dinode.c
index 168cbf48..e36de9bf 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -1036,7 +1036,8 @@ process_symlink_extlist(
int max_blocks;
if (be64_to_cpu(dino->di_size) <= XFS_DFORK_DSIZE(dino, mp)) {
- if (dino->di_format == XFS_DINODE_FMT_LOCAL)
+ if (dino->di_format == XFS_DINODE_FMT_LOCAL ||
+ dino->di_format == XFS_DINODE_FMT_EXTENTS)
return 0;
do_warn(
_("mismatch between format (%d) and size (%" PRId64 ") in symlink ino %" PRIu64 "\n"),
@@ -1368,7 +1369,7 @@ process_symlink(
* get symlink contents into data area
*/
symlink = &data[0];
- if (be64_to_cpu(dino->di_size) <= XFS_DFORK_DSIZE(dino, mp)) {
+ if (dino->di_format == XFS_DINODE_FMT_LOCAL) {
/*
* local symlink, just copy the symlink out of the
* inode into the data area
--
2.46.0