mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] f2fs: fix livelock in f2fs_sync_inode_meta()
@ 2026-09-04 14:59 Daeho Jeong
  2026-09-07 10:23 ` [f2fs-dev] " Chao Yu
  0 siblings, 1 reply; 3+ messages in thread
From: Daeho Jeong @ 2026-09-04 14:59 UTC (permalink / raw)
  To: linux-kernel, linux-f2fs-devel, kernel-team; +Cc: Daeho Jeong

From: Daeho Jeong <daehojeong@google.com>

During checkpoint, f2fs_sync_inode_meta() iterates over dirty inodes in
the DIRTY_META list. If igrab() fails on an inode (e.g. because it is in
the freeing state), the loop continues without moving the current inode to
the tail of the list. As a result, subsequent iterations pick the same
inode repeatedly, preventing other ready dirty inodes in the list from
making forward progress and leading to a livelock.

Fix this by moving the current inode to the tail of the list
(list_move_tail(&fi->gdirty_list, head)) before attempting igrab().

Additionally, if igrab() fails, the freeing inode may be waiting for its
pending writeback data pages to complete during eviction.
Submit any pending merged data writes and yield the
CPU with cond_resched() to allow the eviction to make progress.

Signed-off-by: Daeho Jeong <daehojeong@google.com>
---
 fs/f2fs/checkpoint.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index ef22692cef0a..5597033533b0 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -1460,6 +1460,7 @@ static int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi)
 		}
 		fi = list_first_entry(head, struct f2fs_inode_info,
 							gdirty_list);
+		list_move_tail(&fi->gdirty_list, head);
 		inode = igrab(&fi->vfs_inode);
 		spin_unlock(&sbi->inode_lock[DIRTY_META]);
 		if (inode) {
@@ -1469,6 +1470,13 @@ static int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi)
 			if (is_inode_flag_set(inode, FI_DIRTY_INODE))
 				f2fs_update_inode_page(inode);
 			iput(inode);
+		} else {
+			/*
+			 * We should submit bio, since it exists several
+			 * writebacking pages in the freeing inode.
+			 */
+			f2fs_submit_merged_write(sbi, DATA);
+			cond_resched();
 		}
 	}
 	return 0;
-- 
2.55.0.979.g7e5102b832-goog


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

* Re: [f2fs-dev] [PATCH] f2fs: fix livelock in f2fs_sync_inode_meta()
  2026-09-04 14:59 [PATCH] f2fs: fix livelock in f2fs_sync_inode_meta() Daeho Jeong
@ 2026-09-07 10:23 ` Chao Yu
  2026-09-09 18:44   ` Daeho Jeong
  0 siblings, 1 reply; 3+ messages in thread
From: Chao Yu @ 2026-09-07 10:23 UTC (permalink / raw)
  To: Daeho Jeong, linux-kernel, linux-f2fs-devel, kernel-team
  Cc: chao, Daeho Jeong

On 9/4/26 22:59, Daeho Jeong wrote:
> From: Daeho Jeong <daehojeong@google.com>
> 
> During checkpoint, f2fs_sync_inode_meta() iterates over dirty inodes in
> the DIRTY_META list. If igrab() fails on an inode (e.g. because it is in
> the freeing state), the loop continues without moving the current inode to
> the tail of the list. As a result, subsequent iterations pick the same
> inode repeatedly, preventing other ready dirty inodes in the list from
> making forward progress and leading to a livelock.
> 
> Fix this by moving the current inode to the tail of the list
> (list_move_tail(&fi->gdirty_list, head)) before attempting igrab().
> 
> Additionally, if igrab() fails, the freeing inode may be waiting for its
> pending writeback data pages to complete during eviction.
> Submit any pending merged data writes and yield the
> CPU with cond_resched() to allow the eviction to make progress.
> 
> Signed-off-by: Daeho Jeong <daehojeong@google.com>
> ---
>   fs/f2fs/checkpoint.c | 8 ++++++++
>   1 file changed, 8 insertions(+)
> 
> diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
> index ef22692cef0a..5597033533b0 100644
> --- a/fs/f2fs/checkpoint.c
> +++ b/fs/f2fs/checkpoint.c
> @@ -1460,6 +1460,7 @@ static int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi)
>   		}
>   		fi = list_first_entry(head, struct f2fs_inode_info,
>   							gdirty_list);
> +		list_move_tail(&fi->gdirty_list, head);

Seems fine, if so, do we need to do this in f2fs_sync_dirty_inodes() as well?

>   		inode = igrab(&fi->vfs_inode);
>   		spin_unlock(&sbi->inode_lock[DIRTY_META]);
>   		if (inode) {
> @@ -1469,6 +1470,13 @@ static int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi)
>   			if (is_inode_flag_set(inode, FI_DIRTY_INODE))
>   				f2fs_update_inode_page(inode);
>   			iput(inode);
> +		} else {
> +			/*
> +			 * We should submit bio, since it exists several
> +			 * writebacking pages in the freeing inode.
> +			 */
> +			f2fs_submit_merged_write(sbi, DATA);
> +			cond_resched();

It uses the same implementation from f2fs_sync_dirty_inodes(), after git blame on
it, the implementation was introduce long time ago, I suspect we don't need this?
because in .writepages, we will submit cached bio anyway, right?

Thanks,

>   		}
>   	}
>   	return 0;


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

* Re: [f2fs-dev] [PATCH] f2fs: fix livelock in f2fs_sync_inode_meta()
  2026-09-07 10:23 ` [f2fs-dev] " Chao Yu
@ 2026-09-09 18:44   ` Daeho Jeong
  0 siblings, 0 replies; 3+ messages in thread
From: Daeho Jeong @ 2026-09-09 18:44 UTC (permalink / raw)
  To: Chao Yu; +Cc: linux-kernel, linux-f2fs-devel, kernel-team, Daeho Jeong

On Mon, Sep 7, 2026 at 3:23 AM Chao Yu <chao@kernel.org> wrote:
>
> On 9/4/26 22:59, Daeho Jeong wrote:
> > From: Daeho Jeong <daehojeong@google.com>
> >
> > During checkpoint, f2fs_sync_inode_meta() iterates over dirty inodes in
> > the DIRTY_META list. If igrab() fails on an inode (e.g. because it is in
> > the freeing state), the loop continues without moving the current inode to
> > the tail of the list. As a result, subsequent iterations pick the same
> > inode repeatedly, preventing other ready dirty inodes in the list from
> > making forward progress and leading to a livelock.
> >
> > Fix this by moving the current inode to the tail of the list
> > (list_move_tail(&fi->gdirty_list, head)) before attempting igrab().
> >
> > Additionally, if igrab() fails, the freeing inode may be waiting for its
> > pending writeback data pages to complete during eviction.
> > Submit any pending merged data writes and yield the
> > CPU with cond_resched() to allow the eviction to make progress.
> >
> > Signed-off-by: Daeho Jeong <daehojeong@google.com>
> > ---
> >   fs/f2fs/checkpoint.c | 8 ++++++++
> >   1 file changed, 8 insertions(+)
> >
> > diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
> > index ef22692cef0a..5597033533b0 100644
> > --- a/fs/f2fs/checkpoint.c
> > +++ b/fs/f2fs/checkpoint.c
> > @@ -1460,6 +1460,7 @@ static int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi)
> >               }
> >               fi = list_first_entry(head, struct f2fs_inode_info,
> >                                                       gdirty_list);
> > +             list_move_tail(&fi->gdirty_list, head);
>
> Seems fine, if so, do we need to do this in f2fs_sync_dirty_inodes() as well?
>
> >               inode = igrab(&fi->vfs_inode);
> >               spin_unlock(&sbi->inode_lock[DIRTY_META]);
> >               if (inode) {
> > @@ -1469,6 +1470,13 @@ static int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi)
> >                       if (is_inode_flag_set(inode, FI_DIRTY_INODE))
> >                               f2fs_update_inode_page(inode);
> >                       iput(inode);
> > +             } else {
> > +                     /*
> > +                      * We should submit bio, since it exists several
> > +                      * writebacking pages in the freeing inode.
> > +                      */
> > +                     f2fs_submit_merged_write(sbi, DATA);
> > +                     cond_resched();
>
> It uses the same implementation from f2fs_sync_dirty_inodes(), after git blame on
> it, the implementation was introduce long time ago, I suspect we don't need this?
> because in .writepages, we will submit cached bio anyway, right?
>
> Thanks,


Thanks for the review.

1. Regarding list_move_tail in f2fs_sync_dirty_inodes():
I will apply list_move_tail() to f2fs_sync_dirty_inodes() as well in v2.

2. Regarding f2fs_submit_merged_write(sbi, DATA):
The original intention was just a defensive measure in case the freeing inode
was waiting in f2fs_evict_inode() -> filemap_fdatawait() for writeback
completion.
I will remove f2fs_submit_merged_write(sbi, DATA) and keep only cond_resched()
in the else block, and update both f2fs_sync_inode_meta() and
f2fs_sync_dirty_inodes() in v2.

Thanks,
Daeho

>
> >               }
> >       }
> >       return 0;
>

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

end of thread, other threads:[~2026-09-09 18:44 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-04 14:59 [PATCH] f2fs: fix livelock in f2fs_sync_inode_meta() Daeho Jeong
2026-09-07 10:23 ` [f2fs-dev] " Chao Yu
2026-09-09 18:44   ` Daeho Jeong

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

all inboxes | Powered by JetHome®