aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2024-05-10 08:54:45 -0700
committerDarrick J. Wong <djwong@kernel.org>2024-05-10 17:22:30 -0700
commit7559dcd626a9ff5530205009e083d594818c6ed2 (patch)
treea2563f6080595a7d5bc8172f876c27ff697f71ee
parent577b346c570806506c00eb05e4d687c1b3b17295 (diff)
downloadxfsprogs-dev-djwong-wtf.tar.gz
xfs_repair: allow symlinks with short remote targetsdjwong-wtf_2024-05-10djwong-wtf
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>
-rw-r--r--repair/dinode.c5
1 files changed, 3 insertions, 2 deletions
diff --git a/repair/dinode.c b/repair/dinode.c
index fefa5008b2..005ef1677c 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -1473,7 +1473,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"),
@@ -1805,7 +1806,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