[2/3] ext4: use ext4_write_inode() when fsyncing w/o a journal

Message ID 20181231194836.3761-2-tytso@mit.edu
State New
Headers show
Series
  • [1/3] ext4: avoid kernel warning when writing the superblock to a dead device
Related show

Commit Message

Theodore Ts'o Dec. 31, 2018, 7:48 p.m.
In no-journal mode, we previously used __generic_file_fsync() in
no-journal mode.  This triggers a lockdep warning, and in addition,
it's not safe to depend on the inode writeback mechanism in the case
ext4.  We can solve both problems by calling ext4_write_inode()
directly.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Cc: stable@kernel.org
---
 fs/ext4/fsync.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

Comments

Jan Kara Jan. 23, 2019, 11:34 a.m. | #1
On Mon 31-12-18 14:48:35, Theodore Ts'o wrote:
> In no-journal mode, we previously used __generic_file_fsync() in
> no-journal mode.  This triggers a lockdep warning, and in addition,
> it's not safe to depend on the inode writeback mechanism in the case
> ext4.  We can solve both problems by calling ext4_write_inode()
> directly.
> 
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> Cc: stable@kernel.org
> ---
>  fs/ext4/fsync.c | 13 +++++++++----
>  1 file changed, 9 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c
> index 26a7fe5c4fd3..87a7ff00ef62 100644
> --- a/fs/ext4/fsync.c
> +++ b/fs/ext4/fsync.c
> @@ -116,8 +116,16 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
>  		goto out;
>  	}
>  
> +	ret = file_write_and_wait_range(file, start, end);
> +	if (ret)
> +		return ret;
> +
>  	if (!journal) {
> -		ret = __generic_file_fsync(file, start, end, datasync);
> +		struct writeback_control wbc = {
> +			.sync_mode = WB_SYNC_ALL
> +		};
> +
> +		ret = ext4_write_inode(inode, &wbc);

Going through some older email... How come this is safe Ted?
ext4_write_inode() will not write out metadata buffers associated with the
inode (unlike __generic_file_fsync() which calls sync_mapping_buffers()).
So you probably need to call sync_mapping_buffers() before calling
ext4_write_inode() here?

								Honza

> @@ -125,9 +133,6 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
>  		goto out;
>  	}
>  
> -	ret = file_write_and_wait_range(file, start, end);
> -	if (ret)
> -		return ret;
>  	/*
>  	 * data=writeback,ordered:
>  	 *  The caller's filemap_fdatawrite()/wait will sync the data.
> -- 
> 2.19.1
>

Patch

diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c
index 26a7fe5c4fd3..87a7ff00ef62 100644
--- a/fs/ext4/fsync.c
+++ b/fs/ext4/fsync.c
@@ -116,8 +116,16 @@  int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 		goto out;
 	}
 
+	ret = file_write_and_wait_range(file, start, end);
+	if (ret)
+		return ret;
+
 	if (!journal) {
-		ret = __generic_file_fsync(file, start, end, datasync);
+		struct writeback_control wbc = {
+			.sync_mode = WB_SYNC_ALL
+		};
+
+		ret = ext4_write_inode(inode, &wbc);
 		if (!ret)
 			ret = ext4_sync_parent(inode);
 		if (test_opt(inode->i_sb, BARRIER))
@@ -125,9 +133,6 @@  int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 		goto out;
 	}
 
-	ret = file_write_and_wait_range(file, start, end);
-	if (ret)
-		return ret;
 	/*
 	 * data=writeback,ordered:
 	 *  The caller's filemap_fdatawrite()/wait will sync the data.