Skip to content

Commit ec251f3

Browse files
committed
Merge tag 'exfat-for-5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat
Pull exfat updates from Namjae Jeon: - Add keep_last_dots mount option to allow access to paths with trailing dots - Avoid repetitive volume dirty bit set/clear to improve storage life time * tag 'exfat-for-5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat: exfat: do not clear VolumeDirty in writeback exfat: allow access to paths with trailing dots
2 parents cda4351 + a4a3d8c commit ec251f3

4 files changed

Lines changed: 47 additions & 30 deletions

File tree

fs/exfat/exfat_fs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,8 @@ struct exfat_mount_options {
203203
/* on error: continue, panic, remount-ro */
204204
enum exfat_error_mode errors;
205205
unsigned utf8:1, /* Use of UTF-8 character set */
206-
discard:1; /* Issue discard requests on deletions */
206+
discard:1, /* Issue discard requests on deletions */
207+
keep_last_dots:1; /* Keep trailing periods in paths */
207208
int time_offset; /* Offset of timestamps from UTC (in minutes) */
208209
};
209210

fs/exfat/file.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,6 @@ int __exfat_truncate(struct inode *inode, loff_t new_size)
218218
if (exfat_free_cluster(inode, &clu))
219219
return -EIO;
220220

221-
exfat_clear_volume_dirty(sb);
222-
223221
return 0;
224222
}
225223

fs/exfat/namei.c

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,14 @@ static int exfat_d_revalidate(struct dentry *dentry, unsigned int flags)
6565
return ret;
6666
}
6767

68-
/* returns the length of a struct qstr, ignoring trailing dots */
69-
static unsigned int exfat_striptail_len(unsigned int len, const char *name)
68+
/* returns the length of a struct qstr, ignoring trailing dots if necessary */
69+
static unsigned int exfat_striptail_len(unsigned int len, const char *name,
70+
bool keep_last_dots)
7071
{
71-
while (len && name[len - 1] == '.')
72-
len--;
72+
if (!keep_last_dots) {
73+
while (len && name[len - 1] == '.')
74+
len--;
75+
}
7376
return len;
7477
}
7578

@@ -83,7 +86,8 @@ static int exfat_d_hash(const struct dentry *dentry, struct qstr *qstr)
8386
struct super_block *sb = dentry->d_sb;
8487
struct nls_table *t = EXFAT_SB(sb)->nls_io;
8588
const unsigned char *name = qstr->name;
86-
unsigned int len = exfat_striptail_len(qstr->len, qstr->name);
89+
unsigned int len = exfat_striptail_len(qstr->len, qstr->name,
90+
EXFAT_SB(sb)->options.keep_last_dots);
8791
unsigned long hash = init_name_hash(dentry);
8892
int i, charlen;
8993
wchar_t c;
@@ -104,8 +108,10 @@ static int exfat_d_cmp(const struct dentry *dentry, unsigned int len,
104108
{
105109
struct super_block *sb = dentry->d_sb;
106110
struct nls_table *t = EXFAT_SB(sb)->nls_io;
107-
unsigned int alen = exfat_striptail_len(name->len, name->name);
108-
unsigned int blen = exfat_striptail_len(len, str);
111+
unsigned int alen = exfat_striptail_len(name->len, name->name,
112+
EXFAT_SB(sb)->options.keep_last_dots);
113+
unsigned int blen = exfat_striptail_len(len, str,
114+
EXFAT_SB(sb)->options.keep_last_dots);
109115
wchar_t c1, c2;
110116
int charlen, i;
111117

@@ -136,7 +142,8 @@ static int exfat_utf8_d_hash(const struct dentry *dentry, struct qstr *qstr)
136142
{
137143
struct super_block *sb = dentry->d_sb;
138144
const unsigned char *name = qstr->name;
139-
unsigned int len = exfat_striptail_len(qstr->len, qstr->name);
145+
unsigned int len = exfat_striptail_len(qstr->len, qstr->name,
146+
EXFAT_SB(sb)->options.keep_last_dots);
140147
unsigned long hash = init_name_hash(dentry);
141148
int i, charlen;
142149
unicode_t u;
@@ -161,8 +168,11 @@ static int exfat_utf8_d_cmp(const struct dentry *dentry, unsigned int len,
161168
const char *str, const struct qstr *name)
162169
{
163170
struct super_block *sb = dentry->d_sb;
164-
unsigned int alen = exfat_striptail_len(name->len, name->name);
165-
unsigned int blen = exfat_striptail_len(len, str);
171+
unsigned int alen = exfat_striptail_len(name->len, name->name,
172+
EXFAT_SB(sb)->options.keep_last_dots);
173+
unsigned int blen = exfat_striptail_len(len, str,
174+
EXFAT_SB(sb)->options.keep_last_dots);
175+
166176
unicode_t u_a, u_b;
167177
int charlen, i;
168178

@@ -416,13 +426,25 @@ static int __exfat_resolve_path(struct inode *inode, const unsigned char *path,
416426
struct super_block *sb = inode->i_sb;
417427
struct exfat_sb_info *sbi = EXFAT_SB(sb);
418428
struct exfat_inode_info *ei = EXFAT_I(inode);
429+
int pathlen = strlen(path);
419430

420-
/* strip all trailing periods */
421-
namelen = exfat_striptail_len(strlen(path), path);
431+
/*
432+
* get the length of the pathname excluding
433+
* trailing periods, if any.
434+
*/
435+
namelen = exfat_striptail_len(pathlen, path, false);
436+
if (EXFAT_SB(sb)->options.keep_last_dots) {
437+
/*
438+
* Do not allow the creation of files with names
439+
* ending with period(s).
440+
*/
441+
if (!lookup && (namelen < pathlen))
442+
return -EINVAL;
443+
namelen = pathlen;
444+
}
422445
if (!namelen)
423446
return -ENOENT;
424-
425-
if (strlen(path) > (MAX_NAME_LENGTH * MAX_CHARSET_SIZE))
447+
if (pathlen > (MAX_NAME_LENGTH * MAX_CHARSET_SIZE))
426448
return -ENAMETOOLONG;
427449

428450
/*
@@ -554,7 +576,6 @@ static int exfat_create(struct user_namespace *mnt_userns, struct inode *dir,
554576
exfat_set_volume_dirty(sb);
555577
err = exfat_add_entry(dir, dentry->d_name.name, &cdir, TYPE_FILE,
556578
&info);
557-
exfat_clear_volume_dirty(sb);
558579
if (err)
559580
goto unlock;
560581

@@ -812,7 +833,6 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry)
812833

813834
/* This doesn't modify ei */
814835
ei->dir.dir = DIR_DELETED;
815-
exfat_clear_volume_dirty(sb);
816836

817837
inode_inc_iversion(dir);
818838
dir->i_mtime = dir->i_atime = current_time(dir);
@@ -846,7 +866,6 @@ static int exfat_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
846866
exfat_set_volume_dirty(sb);
847867
err = exfat_add_entry(dir, dentry->d_name.name, &cdir, TYPE_DIR,
848868
&info);
849-
exfat_clear_volume_dirty(sb);
850869
if (err)
851870
goto unlock;
852871

@@ -976,7 +995,6 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
976995
goto unlock;
977996
}
978997
ei->dir.dir = DIR_DELETED;
979-
exfat_clear_volume_dirty(sb);
980998

981999
inode_inc_iversion(dir);
9821000
dir->i_mtime = dir->i_atime = current_time(dir);
@@ -1311,7 +1329,6 @@ static int __exfat_rename(struct inode *old_parent_inode,
13111329
*/
13121330
new_ei->dir.dir = DIR_DELETED;
13131331
}
1314-
exfat_clear_volume_dirty(sb);
13151332
out:
13161333
return ret;
13171334
}

fs/exfat/super.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ static int exfat_set_vol_flags(struct super_block *sb, unsigned short new_flags)
100100
{
101101
struct exfat_sb_info *sbi = EXFAT_SB(sb);
102102
struct boot_sector *p_boot = (struct boot_sector *)sbi->boot_bh->b_data;
103-
bool sync;
104103

105104
/* retain persistent-flags */
106105
new_flags |= sbi->vol_flags_persistent;
@@ -119,16 +118,11 @@ static int exfat_set_vol_flags(struct super_block *sb, unsigned short new_flags)
119118

120119
p_boot->vol_flags = cpu_to_le16(new_flags);
121120

122-
if ((new_flags & VOLUME_DIRTY) && !buffer_dirty(sbi->boot_bh))
123-
sync = true;
124-
else
125-
sync = false;
126-
127121
set_buffer_uptodate(sbi->boot_bh);
128122
mark_buffer_dirty(sbi->boot_bh);
129123

130-
if (sync)
131-
sync_dirty_buffer(sbi->boot_bh);
124+
__sync_dirty_buffer(sbi->boot_bh, REQ_SYNC | REQ_FUA | REQ_PREFLUSH);
125+
132126
return 0;
133127
}
134128

@@ -174,6 +168,8 @@ static int exfat_show_options(struct seq_file *m, struct dentry *root)
174168
seq_puts(m, ",errors=remount-ro");
175169
if (opts->discard)
176170
seq_puts(m, ",discard");
171+
if (opts->keep_last_dots)
172+
seq_puts(m, ",keep_last_dots");
177173
if (opts->time_offset)
178174
seq_printf(m, ",time_offset=%d", opts->time_offset);
179175
return 0;
@@ -217,6 +213,7 @@ enum {
217213
Opt_charset,
218214
Opt_errors,
219215
Opt_discard,
216+
Opt_keep_last_dots,
220217
Opt_time_offset,
221218

222219
/* Deprecated options */
@@ -243,6 +240,7 @@ static const struct fs_parameter_spec exfat_parameters[] = {
243240
fsparam_string("iocharset", Opt_charset),
244241
fsparam_enum("errors", Opt_errors, exfat_param_enums),
245242
fsparam_flag("discard", Opt_discard),
243+
fsparam_flag("keep_last_dots", Opt_keep_last_dots),
246244
fsparam_s32("time_offset", Opt_time_offset),
247245
__fsparam(NULL, "utf8", Opt_utf8, fs_param_deprecated,
248246
NULL),
@@ -297,6 +295,9 @@ static int exfat_parse_param(struct fs_context *fc, struct fs_parameter *param)
297295
case Opt_discard:
298296
opts->discard = 1;
299297
break;
298+
case Opt_keep_last_dots:
299+
opts->keep_last_dots = 1;
300+
break;
300301
case Opt_time_offset:
301302
/*
302303
* Make the limit 24 just in case someone invents something

0 commit comments

Comments
 (0)