Re: [PATCH] nilfs2: fix infinite loop in nilfs_clean_segments()

From: Ryusuke Konishi

Date: Fri Jul 17 2026 - 06:35:25 EST


On Fri, Jul 17, 2026 at 4:49 PM Joshua Crofts wrote:
>
> syzbot reported a hung task in nilfs_transaction_begin(). This occurs
> because the cleaner ioctl falls into an infinite loop if
> nilfs_segctor_construct() repeatedly returns -EROFS (e.g. the device
> is remounted as read-only after an I/O error).
>
> Currently in nilfs_clean_segments(), if err is non-zero, it logs the
> error and sleeps but doesn't abort when it encounters a terminal error
> like -EROFS. This causes the thread to loop forever.
>
> Fix this by breaking out of the loop if nilfs_segctor_construct()
> returns -EROFS. This matches the behaviour in
> nilfs_segctor_write_out(), which also handles -EROFS.
>
> Reported-by: syzbot+cae54346a70bbceeff2c@xxxxxxxxxxxxxxxxxxxxxxxxx
> Closes: https://syzkaller.appspot.com/bug?extid=cae54346a70bbceeff2c
> Fixes: 9ff05123e3bf ("nilfs2: segment constructor")
> Assisted-by: gemini:gemini-3.1-pro
> Signed-off-by: Joshua Crofts <joshua.crofts1@xxxxxxxxx>
> ---
> As much as I've tried, syzbot is unable to test this and always fails
> with "FATAL: Kernel too old". Nevertheless, I've tested the patch with
> the same reproducer in QEMU and the system didn't hang.

Thanks for the patch, Joshua!
This fix correctly addresses the issue reported by syzbot.

I have one request regarding the loop exit:
Could you modify the patch to jump to the out_unlock label instead of
using break?
This is to prevent discard commands from being sent to the underlying
block device when the operation has failed and the filesystem state
has degraded to read-only.

Thanks,
Ryusuke Konishi

> ---
> fs/nilfs2/segment.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c
> index 9332f5ac6..91d3bb314 100644
> --- a/fs/nilfs2/segment.c
> +++ b/fs/nilfs2/segment.c
> @@ -2561,6 +2561,9 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv,
> break;
>
> nilfs_warn(sb, "error %d cleaning segments", err);
> + if (unlikely(err == -EROFS))
> + break;
> +
> set_current_state(TASK_INTERRUPTIBLE);
> schedule_timeout(sci->sc_interval);
> }
> --
> 2.47.3
>