Re: [PATCH] exfat: intorduce skip_stream_check mount opt

From: Namjae Jeon
Date: Thu Jun 09 2022 - 21:04:26 EST


2022-06-07 11:49 GMT+09:00, Yangtao Li <frank.li@xxxxxxxx>:
> There are some files in my USB flash drive that can be recognized by
> the Windows computer, but on Linux, only the existence of the file name
> can be seen.
>
> When executing ls command to view the file attributes or access, the file
> does not exist. Therefore, when the current windows and linux drivers
> access a file, there is a difference in the checking of the file metadata,
> which leads to this situation.
> (There is also a difference between traversing all children of the parent
> directory and finding a child in the parent directory on linux.)
Still having problem on linux-exfat after recovering it using windows chkdsk?

Thanks.
>
> So, we introduce a new mount option that skips the check of the file stream
> entry in exfat_find_dir_entry().
>
> Signed-off-by: Yangtao Li <frank.li@xxxxxxxx>
> ---
> fs/exfat/dir.c | 6 ++++--
> fs/exfat/exfat_fs.h | 3 ++-
> fs/exfat/super.c | 7 +++++++
> 3 files changed, 13 insertions(+), 3 deletions(-)
>
> diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c
> index cb1c0d8c1714..4ea0077f2955 100644
> --- a/fs/exfat/dir.c
> +++ b/fs/exfat/dir.c
> @@ -1013,6 +1013,7 @@ int exfat_find_dir_entry(struct super_block *sb,
> struct exfat_inode_info *ei,
> }
>
> if (entry_type == TYPE_STREAM) {
> + struct exfat_mount_options *opts = &sbi->options;
> u16 name_hash;
>
> if (step != DIRENT_STEP_STRM) {
> @@ -1023,9 +1024,10 @@ int exfat_find_dir_entry(struct super_block *sb,
> struct exfat_inode_info *ei,
> step = DIRENT_STEP_FILE;
> name_hash = le16_to_cpu(
> ep->dentry.stream.name_hash);
> - if (p_uniname->name_hash == name_hash &&
> + if ((p_uniname->name_hash == name_hash &&
> p_uniname->name_len ==
> - ep->dentry.stream.name_len) {
> + ep->dentry.stream.name_len) ||
> + opts->skip_stream_check == 1) {
> step = DIRENT_STEP_NAME;
> order = 1;
> name_len = 0;
> diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
> index 1d6da61157c9..5cd00ac112d9 100644
> --- a/fs/exfat/exfat_fs.h
> +++ b/fs/exfat/exfat_fs.h
> @@ -204,7 +204,8 @@ struct exfat_mount_options {
> /* on error: continue, panic, remount-ro */
> enum exfat_error_mode errors;
> unsigned utf8:1, /* Use of UTF-8 character set */
> - discard:1; /* Issue discard requests on deletions */
> + discard:1, /* Issue discard requests on deletions */
> + skip_stream_check:1; /* Skip stream entry check in
> exfat_find_dir_entry() */
> int time_offset; /* Offset of timestamps from UTC (in minutes) */
> };
>
> diff --git a/fs/exfat/super.c b/fs/exfat/super.c
> index 5539ffc20d16..e9c7df25f2b5 100644
> --- a/fs/exfat/super.c
> +++ b/fs/exfat/super.c
> @@ -173,6 +173,8 @@ static int exfat_show_options(struct seq_file *m, struct
> dentry *root)
> seq_puts(m, ",errors=remount-ro");
> if (opts->discard)
> seq_puts(m, ",discard");
> + if (opts->skip_stream_check)
> + seq_puts(m, ",skip_stream_check");
> if (opts->time_offset)
> seq_printf(m, ",time_offset=%d", opts->time_offset);
> return 0;
> @@ -216,6 +218,7 @@ enum {
> Opt_charset,
> Opt_errors,
> Opt_discard,
> + Opt_skip_stream_check,
> Opt_time_offset,
>
> /* Deprecated options */
> @@ -242,6 +245,7 @@ static const struct fs_parameter_spec exfat_parameters[]
> = {
> fsparam_string("iocharset", Opt_charset),
> fsparam_enum("errors", Opt_errors, exfat_param_enums),
> fsparam_flag("discard", Opt_discard),
> + fsparam_flag("skip_stream_check", Opt_skip_stream_check),
> fsparam_s32("time_offset", Opt_time_offset),
> __fsparam(NULL, "utf8", Opt_utf8, fs_param_deprecated,
> NULL),
> @@ -296,6 +300,9 @@ static int exfat_parse_param(struct fs_context *fc,
> struct fs_parameter *param)
> case Opt_discard:
> opts->discard = 1;
> break;
> + case Opt_skip_stream_check:
> + opts->skip_stream_check = 1;
> + break;
> case Opt_time_offset:
> /*
> * Make the limit 24 just in case someone invents something
> --
> 2.35.1
>
>