public inbox for stable@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 2/2] ext4: Fix fsync(2) for nojournal mode
       [not found] <20260211140209.30337-1-jack@suse.cz>
@ 2026-02-16 16:48 ` Jan Kara
  2026-02-26 11:56   ` Zhang Yi
  0 siblings, 1 reply; 3+ messages in thread
From: Jan Kara @ 2026-02-16 16:48 UTC (permalink / raw)
  To: Ted Tso; +Cc: linux-ext4, Free Ekanayaka, Jan Kara, stable

When inode metadata is changed, we sometimes just call
ext4_mark_inode_dirty() to track modified metadata. This copies inode
metadata into block buffer which is enough when we are journalling
metadata. However when we are running in nojournal mode we currently
fail to write the dirtied inode buffer during fsync(2) because the inode
is not marked as dirty. Use explicit ext4_write_inode() call to make
sure the inode table buffer is written to the disk. This is a band aid
solution but proper solution requires a much larger rewrite including
changes in metadata bh tracking infrastructure.

Reported-by: Free Ekanayaka <free.ekanayaka@gmail.com>
Link: https://lore.kernel.org/all/87il8nhxdm.fsf@x1.mail-host-address-is-not-set/
CC: stable@vger.kernel.org
Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/ext4/fsync.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c
index e476c6de3074..bd8f230fa507 100644
--- a/fs/ext4/fsync.c
+++ b/fs/ext4/fsync.c
@@ -83,11 +83,23 @@ static int ext4_fsync_nojournal(struct file *file, loff_t start, loff_t end,
 				int datasync, bool *needs_barrier)
 {
 	struct inode *inode = file->f_inode;
+	struct writeback_control wbc = {
+		.sync_mode = WB_SYNC_ALL,
+		.nr_to_write = 0,
+	};
 	int ret;
 
 	ret = generic_buffers_fsync_noflush(file, start, end, datasync);
-	if (!ret)
-		ret = ext4_sync_parent(inode);
+	if (ret)
+		return ret;
+
+	/* Force writeout of inode table buffer to disk */
+	ret = ext4_write_inode(inode, &wbc);
+	if (ret)
+		return ret;
+
+	ret = ext4_sync_parent(inode);
+
 	if (test_opt(inode->i_sb, BARRIER))
 		*needs_barrier = true;
 
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH 2/2] ext4: Fix fsync(2) for nojournal mode
  2026-02-16 16:48 ` [PATCH 2/2] ext4: Fix fsync(2) for nojournal mode Jan Kara
@ 2026-02-26 11:56   ` Zhang Yi
  2026-02-26 13:39     ` Jan Kara
  0 siblings, 1 reply; 3+ messages in thread
From: Zhang Yi @ 2026-02-26 11:56 UTC (permalink / raw)
  To: Jan Kara, Ted Tso; +Cc: linux-ext4, Free Ekanayaka, stable

On 2/17/2026 12:48 AM, Jan Kara wrote:
> When inode metadata is changed, we sometimes just call
> ext4_mark_inode_dirty() to track modified metadata. This copies inode
> metadata into block buffer which is enough when we are journalling
> metadata. However when we are running in nojournal mode we currently
> fail to write the dirtied inode buffer during fsync(2) because the inode
> is not marked as dirty.

Please let me understand this. You mean that because some places we
directly call ext4_mark_inode_dirty() to mark the inode as dirty, instead
of using the generic mark_inode_dirty(), this results in the inode missing
the I_DIRTY_INODE flag. Consequently, generic_buffers_fsync_noflush()->
sync_inode_metadata() does not write the inode, leading to the metadata
not being updated on disk after fsync(2), right?

Reviewed-by: Zhang Yi <yi.zhang@huawei.com>

> Use explicit ext4_write_inode() call to make
> sure the inode table buffer is written to the disk. This is a band aid
> solution but proper solution requires a much larger rewrite including
> changes in metadata bh tracking infrastructure.
> 
> Reported-by: Free Ekanayaka <free.ekanayaka@gmail.com>
> Link: https://lore.kernel.org/all/87il8nhxdm.fsf@x1.mail-host-address-is-not-set/
> CC: stable@vger.kernel.org
> Signed-off-by: Jan Kara <jack@suse.cz>
> ---
>  fs/ext4/fsync.c | 16 ++++++++++++++--
>  1 file changed, 14 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c
> index e476c6de3074..bd8f230fa507 100644
> --- a/fs/ext4/fsync.c
> +++ b/fs/ext4/fsync.c
> @@ -83,11 +83,23 @@ static int ext4_fsync_nojournal(struct file *file, loff_t start, loff_t end,
>  				int datasync, bool *needs_barrier)
>  {
>  	struct inode *inode = file->f_inode;
> +	struct writeback_control wbc = {
> +		.sync_mode = WB_SYNC_ALL,
> +		.nr_to_write = 0,
> +	};
>  	int ret;
>  
>  	ret = generic_buffers_fsync_noflush(file, start, end, datasync);
> -	if (!ret)
> -		ret = ext4_sync_parent(inode);
> +	if (ret)
> +		return ret;
> +
> +	/* Force writeout of inode table buffer to disk */
> +	ret = ext4_write_inode(inode, &wbc);
> +	if (ret)
> +		return ret;
> +
> +	ret = ext4_sync_parent(inode);
> +
>  	if (test_opt(inode->i_sb, BARRIER))
>  		*needs_barrier = true;
>  


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH 2/2] ext4: Fix fsync(2) for nojournal mode
  2026-02-26 11:56   ` Zhang Yi
@ 2026-02-26 13:39     ` Jan Kara
  0 siblings, 0 replies; 3+ messages in thread
From: Jan Kara @ 2026-02-26 13:39 UTC (permalink / raw)
  To: Zhang Yi; +Cc: Jan Kara, Ted Tso, linux-ext4, Free Ekanayaka, stable

On Thu 26-02-26 19:56:34, Zhang Yi wrote:
> On 2/17/2026 12:48 AM, Jan Kara wrote:
> > When inode metadata is changed, we sometimes just call
> > ext4_mark_inode_dirty() to track modified metadata. This copies inode
> > metadata into block buffer which is enough when we are journalling
> > metadata. However when we are running in nojournal mode we currently
> > fail to write the dirtied inode buffer during fsync(2) because the inode
> > is not marked as dirty.
> 
> Please let me understand this. You mean that because some places we
> directly call ext4_mark_inode_dirty() to mark the inode as dirty, instead
> of using the generic mark_inode_dirty(), this results in the inode missing
> the I_DIRTY_INODE flag. Consequently, generic_buffers_fsync_noflush()->
> sync_inode_metadata() does not write the inode, leading to the metadata
> not being updated on disk after fsync(2), right?

Correct.

> Reviewed-by: Zhang Yi <yi.zhang@huawei.com>

Thanks for review!

								Honza

> > Use explicit ext4_write_inode() call to make
> > sure the inode table buffer is written to the disk. This is a band aid
> > solution but proper solution requires a much larger rewrite including
> > changes in metadata bh tracking infrastructure.
> > 
> > Reported-by: Free Ekanayaka <free.ekanayaka@gmail.com>
> > Link: https://lore.kernel.org/all/87il8nhxdm.fsf@x1.mail-host-address-is-not-set/
> > CC: stable@vger.kernel.org
> > Signed-off-by: Jan Kara <jack@suse.cz>
> > ---
> >  fs/ext4/fsync.c | 16 ++++++++++++++--
> >  1 file changed, 14 insertions(+), 2 deletions(-)
> > 
> > diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c
> > index e476c6de3074..bd8f230fa507 100644
> > --- a/fs/ext4/fsync.c
> > +++ b/fs/ext4/fsync.c
> > @@ -83,11 +83,23 @@ static int ext4_fsync_nojournal(struct file *file, loff_t start, loff_t end,
> >  				int datasync, bool *needs_barrier)
> >  {
> >  	struct inode *inode = file->f_inode;
> > +	struct writeback_control wbc = {
> > +		.sync_mode = WB_SYNC_ALL,
> > +		.nr_to_write = 0,
> > +	};
> >  	int ret;
> >  
> >  	ret = generic_buffers_fsync_noflush(file, start, end, datasync);
> > -	if (!ret)
> > -		ret = ext4_sync_parent(inode);
> > +	if (ret)
> > +		return ret;
> > +
> > +	/* Force writeout of inode table buffer to disk */
> > +	ret = ext4_write_inode(inode, &wbc);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = ext4_sync_parent(inode);
> > +
> >  	if (test_opt(inode->i_sb, BARRIER))
> >  		*needs_barrier = true;
> >  
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-02-26 13:39 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20260211140209.30337-1-jack@suse.cz>
2026-02-16 16:48 ` [PATCH 2/2] ext4: Fix fsync(2) for nojournal mode Jan Kara
2026-02-26 11:56   ` Zhang Yi
2026-02-26 13:39     ` Jan Kara

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox