Re: [PATCH] ext4: Properly sync file size update after O_SYNC direct IO

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

 



Hi Dave,

On 2023/10/12 08:26, Dave Chinner wrote:
On Wed, Oct 11, 2023 at 04:21:55PM +0200, Jan Kara wrote:
Gao Xiang has reported that on ext4 O_SYNC direct IO does not properly
sync file size update and thus if we crash at unfortunate moment, the
file can have smaller size although O_SYNC IO has reported successful
completion. The problem happens because update of on-disk inode size is
handled in ext4_dio_write_iter() *after* iomap_dio_rw() (and thus
dio_complete() in particular) has returned and generic_file_sync() gets
called by dio_complete(). Fix the problem by handling on-disk inode size
update directly in our ->end_io completion handler.

References: https://lore.kernel.org/all/02d18236-26ef-09b0-90ad-030c4fe3ee20@xxxxxxxxxxxxxxxxx
Reported-by: Gao Xiang <hsiangkao@xxxxxxxxxxxxxxxxx>
Signed-off-by: Jan Kara <jack@xxxxxxx>
---
  fs/ext4/file.c | 139 ++++++++++++++++++-------------------------------
  1 file changed, 52 insertions(+), 87 deletions(-)
.....
@@ -388,9 +342,28 @@ static ssize_t ext4_handle_inode_extension(struct inode *inode, loff_t offset,
  		 */
  		if (inode->i_nlink)
  			ext4_orphan_del(NULL, inode);
+		return;
  	}
+	/*
+	 * If i_disksize got extended due to writeback of delalloc blocks while
+	 * the DIO was running we could fail to cleanup the orphan list in
+	 * ext4_handle_inode_extension(). Do it now.
+	 */
+	if (!list_empty(&EXT4_I(inode)->i_orphan) && inode->i_nlink) {
+		handle_t *handle = ext4_journal_start(inode, EXT4_HT_INODE, 2);

So this has to be called after the DIO write completes and calls
ext4_handle_inode_extension()?

....

@@ -606,9 +570,8 @@ static ssize_t ext4_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)
  			   dio_flags, NULL, 0);
  	if (ret == -ENOTBLK)
  		ret = 0;
-
  	if (extend)
-		ret = ext4_handle_inode_extension(inode, offset, ret, count);
+		ext4_inode_extension_cleanup(inode, ret);

Because this doesn't wait for AIO DIO to complete and actually
extend the file before running the cleanup code...

As far as I know, for ext4 AIO DIO extension cases,
IOMAP_DIO_FORCE_WAIT will be set, thus no async DIO here.

So the timing for this case will be strictly:
  - ext4_handle_inode_extension()   --- record i_disksize in .end_io

  - generic_write_sync()            --- forcely do fsync()

  - ext4_inode_extension_cleanup()  --- drop orphan in another transaction
                                        as mentioned in [1]

Anyway, that is my current limited thoughts.

[1] https://lore.kernel.org/linux-ext4/20230920152005.7iowrlukd5zbvp43@quack3/

Thanks,
Gao Xiang


Cheers,

Dave.



[Index of Archives]     [Reiser Filesystem Development]     [Ceph FS]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite National Park]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Device Mapper]     [Linux Media]

  Powered by Linux