From 4ba6ccd695f5ed3ae851e59b443b757bbe4557fe Mon Sep 17 00:00:00 2001 From: "Hyeongseok.Kim" Date: Tue, 9 Jun 2020 14:30:44 +0900 Subject: exfat: Set the unused characters of FileName field to the value 0000h Some fsck tool complain that padding part of the FileName field is not set to the value 0000h. So let's maintain filesystem cleaner, as exfat's spec. recommendation. Signed-off-by: Hyeongseok.Kim Reviewed-by: Sungjong Seo Signed-off-by: Namjae Jeon --- fs/exfat/dir.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c index de43534aa299..8e775bd5d523 100644 --- a/fs/exfat/dir.c +++ b/fs/exfat/dir.c @@ -425,10 +425,12 @@ static void exfat_init_name_entry(struct exfat_dentry *ep, ep->dentry.name.flags = 0x0; for (i = 0; i < EXFAT_FILE_NAME_LEN; i++) { - ep->dentry.name.unicode_0_14[i] = cpu_to_le16(*uniname); - if (*uniname == 0x0) - break; - uniname++; + if (*uniname != 0x0) { + ep->dentry.name.unicode_0_14[i] = cpu_to_le16(*uniname); + uniname++; + } else { + ep->dentry.name.unicode_0_14[i] = 0x0; + } } } -- cgit From e8dd3cda8667118b70d9fe527f61fe22623de04d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 10 Jun 2020 20:22:13 +0300 Subject: exfat: add missing brelse() calls on error paths If the second exfat_get_dentry() call fails then we need to release "old_bh" before returning. There is a similar bug in exfat_move_file(). Fixes: 5f2aa075070c ("exfat: add inode operations") Reported-by: Markus Elfring Signed-off-by: Dan Carpenter Signed-off-by: Namjae Jeon --- fs/exfat/namei.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/exfat/namei.c b/fs/exfat/namei.c index 5b0f35329d63..edd8023865a0 100644 --- a/fs/exfat/namei.c +++ b/fs/exfat/namei.c @@ -1077,10 +1077,14 @@ static int exfat_rename_file(struct inode *inode, struct exfat_chain *p_dir, epold = exfat_get_dentry(sb, p_dir, oldentry + 1, &old_bh, §or_old); + if (!epold) + return -EIO; epnew = exfat_get_dentry(sb, p_dir, newentry + 1, &new_bh, §or_new); - if (!epold || !epnew) + if (!epnew) { + brelse(old_bh); return -EIO; + } memcpy(epnew, epold, DENTRY_SIZE); exfat_update_bh(sb, new_bh, sync); @@ -1161,10 +1165,14 @@ static int exfat_move_file(struct inode *inode, struct exfat_chain *p_olddir, epmov = exfat_get_dentry(sb, p_olddir, oldentry + 1, &mov_bh, §or_mov); + if (!epmov) + return -EIO; epnew = exfat_get_dentry(sb, p_newdir, newentry + 1, &new_bh, §or_new); - if (!epmov || !epnew) + if (!epnew) { + brelse(mov_bh); return -EIO; + } memcpy(epnew, epmov, DENTRY_SIZE); exfat_update_bh(sb, new_bh, IS_DIRSYNC(inode)); -- cgit From a0271a15cf2cf907ea5b0f2ba611123f1b7935ec Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 16 Jun 2020 14:34:45 +0900 Subject: exfat: call sync_filesystem for read-only remount We need to commit dirty metadata and pages to disk before remounting exfat as read-only. This fixes a failure in xfstests generic/452 generic/452 does the following: cp something / mount -o remount,ro the /something is corrupted. because while exfat is remounted as read-only, exfat doesn't have a chance to commit metadata and vfs invalidates page caches in a block device. Signed-off-by: Hyunchul Lee Acked-by: Sungjong Seo Signed-off-by: Namjae Jeon --- fs/exfat/super.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'fs') diff --git a/fs/exfat/super.c b/fs/exfat/super.c index e650e65536f8..253a92460d52 100644 --- a/fs/exfat/super.c +++ b/fs/exfat/super.c @@ -693,10 +693,20 @@ static void exfat_free(struct fs_context *fc) } } +static int exfat_reconfigure(struct fs_context *fc) +{ + fc->sb_flags |= SB_NODIRATIME; + + /* volume flag will be updated in exfat_sync_fs */ + sync_filesystem(fc->root->d_sb); + return 0; +} + static const struct fs_context_operations exfat_context_ops = { .parse_param = exfat_parse_param, .get_tree = exfat_get_tree, .free = exfat_free, + .reconfigure = exfat_reconfigure, }; static int exfat_init_fs_context(struct fs_context *fc) -- cgit From 3bcfb701099acf96b0e883bf5544f96af473aa1d Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 17 Jun 2020 12:17:18 +0900 Subject: exfat: move setting VOL_DIRTY over exfat_remove_entries() Move setting VOL_DIRTY over exfat_remove_entries() to avoid unneeded leaving VOL_DIRTY on -ENOTEMPTY. Fixes: 5f2aa075070c ("exfat: add inode operations") Cc: stable@vger.kernel.org # v5.7 Reported-by: Tetsuhiro Kohada Reviewed-by: Sungjong Seo Signed-off-by: Namjae Jeon --- fs/exfat/namei.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/exfat/namei.c b/fs/exfat/namei.c index edd8023865a0..2b9e21094a96 100644 --- a/fs/exfat/namei.c +++ b/fs/exfat/namei.c @@ -975,7 +975,6 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry) goto unlock; } - exfat_set_vol_flags(sb, VOL_DIRTY); exfat_chain_set(&clu_to_free, ei->start_clu, EXFAT_B_TO_CLU_ROUND_UP(i_size_read(inode), sbi), ei->flags); @@ -1002,6 +1001,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry) num_entries++; brelse(bh); + exfat_set_vol_flags(sb, VOL_DIRTY); err = exfat_remove_entries(dir, &cdir, entry, 0, num_entries); if (err) { exfat_err(sb, "failed to exfat_remove_entries : err(%d)", err); -- cgit From 5267456e953fd8c5abd8e278b1cc6a9f9027ac0a Mon Sep 17 00:00:00 2001 From: Sungjong Seo Date: Thu, 18 Jun 2020 20:43:26 +0900 Subject: exfat: flush dirty metadata in fsync generic_file_fsync() exfat used could not guarantee the consistency of a file because it has flushed not dirty metadata but only dirty data pages for a file. Instead of that, use exfat_file_fsync() for files and directories so that it guarantees to commit both the metadata and data pages for a file. Signed-off-by: Sungjong Seo Signed-off-by: Namjae Jeon --- fs/exfat/dir.c | 2 +- fs/exfat/exfat_fs.h | 1 + fs/exfat/file.c | 19 ++++++++++++++++++- 3 files changed, 20 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c index 8e775bd5d523..91ece649285d 100644 --- a/fs/exfat/dir.c +++ b/fs/exfat/dir.c @@ -309,7 +309,7 @@ const struct file_operations exfat_dir_operations = { .llseek = generic_file_llseek, .read = generic_read_dir, .iterate = exfat_iterate, - .fsync = generic_file_fsync, + .fsync = exfat_file_fsync, }; int exfat_alloc_new_dir(struct inode *inode, struct exfat_chain *clu) diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h index 595f3117f492..7579cd3bbadb 100644 --- a/fs/exfat/exfat_fs.h +++ b/fs/exfat/exfat_fs.h @@ -420,6 +420,7 @@ void exfat_truncate(struct inode *inode, loff_t size); int exfat_setattr(struct dentry *dentry, struct iattr *attr); int exfat_getattr(const struct path *path, struct kstat *stat, unsigned int request_mask, unsigned int query_flags); +int exfat_file_fsync(struct file *file, loff_t start, loff_t end, int datasync); /* namei.c */ extern const struct dentry_operations exfat_dentry_ops; diff --git a/fs/exfat/file.c b/fs/exfat/file.c index fce03f318787..3b7fea465fd4 100644 --- a/fs/exfat/file.c +++ b/fs/exfat/file.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "exfat_raw.h" #include "exfat_fs.h" @@ -346,12 +347,28 @@ out: return error; } +int exfat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync) +{ + struct inode *inode = filp->f_mapping->host; + int err; + + err = __generic_file_fsync(filp, start, end, datasync); + if (err) + return err; + + err = sync_blockdev(inode->i_sb->s_bdev); + if (err) + return err; + + return blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL); +} + const struct file_operations exfat_file_operations = { .llseek = generic_file_llseek, .read_iter = generic_file_read_iter, .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, - .fsync = generic_file_fsync, + .fsync = exfat_file_fsync, .splice_read = generic_file_splice_read, .splice_write = iter_file_splice_write, }; -- cgit