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 > >