[PATCH v1 2/3] exfat: remove duplicate write inode for truncating file

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This commit moves updating file attributes and timestamps before
calling __exfat_write_inode(), so that all updates of the inode
had been written by __exfat_write_inode(), mark_inode_dirty() is
unneeded.

Signed-off-by: Yuezhang Mo <Yuezhang.Mo@xxxxxxxx>
Reviewed-by: Andy Wu <Andy.Wu@xxxxxxxx>
Reviewed-by: Aoyama Wataru <wataru.aoyama@xxxxxxxx>
Reviewed-by: Daniel Palmer <daniel.palmer@xxxxxxxx>
---
 fs/exfat/file.c  | 37 ++++++++++++++++++++++++-------------
 fs/exfat/inode.c |  1 +
 2 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/fs/exfat/file.c b/fs/exfat/file.c
index 08e5ffd78b10..4e0793f35e8f 100644
--- a/fs/exfat/file.c
+++ b/fs/exfat/file.c
@@ -148,8 +148,17 @@ int __exfat_truncate(struct inode *inode, loff_t new_size)
 	if (ei->type == TYPE_FILE)
 		ei->attr |= ATTR_ARCHIVE;
 
-	/* update the directory entry */
-	inode->i_mtime = current_time(inode);
+	/*
+	 * update the directory entry
+	 *
+	 * If the directory entry is updated by mark_inode_dirty(), the
+	 * directory entry will be written after a writeback cycle of
+	 * updating the bitmap/FAT, which may result in clusters being
+	 * freed but referenced by the directory entry in the event of a
+	 * sudden power failure.
+	 * __exfat_write_inode() is called for directory entry, bitmap
+	 * and FAT to be written in a same writeback.
+	 */
 	if (__exfat_write_inode(inode, inode_needs_sync(inode)))
 		return -EIO;
 
@@ -202,12 +211,6 @@ void exfat_truncate(struct inode *inode, loff_t size)
 	if (err)
 		goto write_size;
 
-	inode->i_ctime = inode->i_mtime = current_time(inode);
-	if (IS_DIRSYNC(inode))
-		exfat_sync_inode(inode);
-	else
-		mark_inode_dirty(inode);
-
 	inode->i_blocks = round_up(i_size_read(inode), sbi->cluster_size) >>
 				inode->i_blkbits;
 write_size:
@@ -289,6 +292,12 @@ int exfat_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
 			attr->ia_valid &= ~ATTR_MODE;
 	}
 
+	if (attr->ia_valid & ATTR_SIZE)
+		inode->i_mtime = inode->i_ctime = current_time(inode);
+
+	setattr_copy(&init_user_ns, inode, attr);
+	exfat_truncate_atime(&inode->i_atime);
+
 	if (attr->ia_valid & ATTR_SIZE) {
 		error = exfat_block_truncate_page(inode, attr->ia_size);
 		if (error)
@@ -296,13 +305,15 @@ int exfat_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
 
 		down_write(&EXFAT_I(inode)->truncate_lock);
 		truncate_setsize(inode, attr->ia_size);
+
+		/*
+		 * __exfat_write_inode() is called from exfat_truncate(), inode
+		 * is already written by it, so mark_inode_dirty() is unneeded.
+		 */
 		exfat_truncate(inode, attr->ia_size);
 		up_write(&EXFAT_I(inode)->truncate_lock);
-	}
-
-	setattr_copy(&init_user_ns, inode, attr);
-	exfat_truncate_atime(&inode->i_atime);
-	mark_inode_dirty(inode);
+	} else
+		mark_inode_dirty(inode);
 
 out:
 	return error;
diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c
index ebc64fa5c2de..3acfbec1a0d4 100644
--- a/fs/exfat/inode.c
+++ b/fs/exfat/inode.c
@@ -369,6 +369,7 @@ static void exfat_write_failed(struct address_space *mapping, loff_t to)
 
 	if (to > i_size_read(inode)) {
 		truncate_pagecache(inode, i_size_read(inode));
+		inode->i_mtime = inode->i_ctime = current_time(inode);
 		exfat_truncate(inode, EXFAT_I(inode)->i_size_aligned);
 	}
 }
-- 
2.25.1

Attachment: v1-0002-exfat-remove-duplicate-write-inode-for-truncating.patch
Description: v1-0002-exfat-remove-duplicate-write-inode-for-truncating.patch


[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux