Re: Files with non-ASCII names inaccessible after xfs_repair

Dave Chinner
2014-01-15T06:37:34Z

On Tue, Jan 14, 2014 at 09:30:57PM -0800, Zachary Kotlarek wrote:
>
> On Jan 14, 2014, at 7:48 PM, Dave Chinner <david@fromorbit.com> wrote:
>
> > It's called *ASCII* Case Insensitivity for a reason: it doesn't
> > support anything other than ASCII. So your usage is not actually
> > supported at all, hence it's no surprise that it has caused
> > breakage.
>
> Okay. Thanks for the explanation.
>
> FWIW, I read “ASCII-only case-insensitive” to mean “only case-insensitive for ASCII” as in ñ and Ñ would not match each other. If it actually means “anything other than ASCII is subject to complete breakage” a more nuanced explanation in the man page might be desirable.

Sure. Can you write a patch to add explanation that explain the
problem you've had?

> I don’t suppose there’s any way to disable that setting short of creating a new file system?

Not officially. Changing it means you have to change every single
hash for every directory entry. I *think* that you could probably do
it with a bit of xfs_db magic and and xfs_repair pass.

First, A warning, some advice and a disclaimer: back up anything you
don't want to lose, because if this screws up it'll trash the
directory structure and you may *LOSE* *ALL* *YOUR* *DATA*. This is
dangerous, not recommended and I take no responsibility for what
happens if you try it and it fails.

After taking a backup, use xfs_metadump to set up for a
non-destructive trial run. take a copy of the filesystem metadata
using xfs_metadump:

# xfs_metadump <dev> scratch.metadump

Restore the metadump to a file - this is a sparse image file we can
operate on safely.

# xfs_mdrestore scratch.metadump scratch_xfs_filesystem.img

Then point xfs_db at the image file:

# xfs_db -x -f scratch_xfs_filesystem.img

Remove the case insensitive feature bit using the version command.
First dump the current values using version:

xfs_db> version
versionnum [0xf4a4+0x8a] = V4,NLINK,ALIGN,DIRV2,LOGV2,EXTFLG,ASCII_CI,MOREBITS,ATTR2,LAZYSBCOUNT,PROJID32BIT

And you'll see the ASCII_CI bit in there. That's what we want to
remove. It's value is:

#define XFS_SB_VERSION_BORGBIT 0x4000

so we need to clear that from the version field.

0xf4a4 - 0x4000 = 0xb4a4

And we want to write that back into the version field:

xfs_db> sb 0
xfs_db> p versionnum
versionnum = 0xf4a4
xfs_db> write versionnum 0xb4a4
versionnum = 0xb4a4
xfs_db> p versionnum
versionnum = 0xb4a4
xfs_db> quit

And now run xfs_repair on the image file:

# xfs_repair -f scratch_xfs_filesystem.img

That should through lots of "bad hash table.... repairing" errors.
Once it completes, mount the filesystem image on the loopback
device:

# mount -o loop,ro,norecovery scratch_xfs_filesystem.img /mnt/scratch

And walk around the filesystem to determine if the directory
structure is correct and intact. If you have any doubts, or anything
was left in lost+found, then it hasn't worked properly and you
should not do this to your filesystem.

Only if you are convinced that everything is OK and you can do the
conversion without stuffing up, run the same xfs_db/repair process
on the real filesystem. If you have any doubts or not confident that
it has worked, then go the long way of mkfs and restoring the backup
you've already made.

> > I suspect that the way to fix your filesystem is to run xfs_repair
> > under a "C" locale so that the glibc tolower() function behaves the
> > same way the kernel behaves and so the hashes calculated by
> > xfs_repair match the what the kernel thinks is correct.
>
> Neither this:
> LC_ALL=C
> nor this:
> LC_ALL=POSIX
> or for that matter:
> LC_ALL=en_US.utf8
> made any difference. And my default was already POSIX.
>
> Any other thoughts?

$ LC_ALL=C locale
LANG=en_AU.UTF-8
LANGUAGE=en_AU:en
LC_CTYPE="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_COLLATE="C"
LC_MONETARY="C"
LC_MESSAGES="C"
LC_PAPER="C"
LC_NAME="C"
LC_ADDRESS="C"
LC_TELEPHONE="C"
LC_MEASUREMENT="C"
LC_IDENTIFICATION="C"
LC_ALL=C
$

Perhaps you also need to override LANG and LANGUAGE?

> Theoretically I could find the expected hashvals and overwrite
> them with xfs_db, right?

In theory, but hashvals need to be ordered correctly and that
potentially means having to update btree node pointers and all sorts
of other complexities. xfs_db is really not designed to rewrite
directory structures manually.

> Or at least unlink the files so I can
> reclaim the disk space?

You need to be able to stat the file to be able to unlink it....

Cheers,

Dave.
--
Dave Chinner
david@fromorbit.com