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.
81 lines
2.9 KiB
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
|
|
|