Re: [syzbot] [exfat?] [ocfs2?] kernel BUG in link_path_walk

Jan Kara
2025-12-11T09:00:50Z

On Wed 10-12-25 21:47:30, Al Viro wrote:
> #syz test
>
> commit 9c7d3d572d0a67484e9cbe178184cfd9a89aa430
> Author: Al Viro <viro@zeniv.linux.org.uk>
> Date: Wed Dec 10 16:44:53 2025 -0500
>
> Revert "ocfs2: mark inode bad upon validation failure during read"
>
> This reverts commit 58b6fcd2ab34399258dc509f701d0986a8e0bcaa.
>
> You can't use make_bad_inode() on live inodes.

At first I was confused because ocfs2_read_inode_block_full() gets called
when loading new inode into memory and that's a place for which
make_bad_inode() is safe. But then I've noticed ocfs2 does reread the inode
in many places through ocfs2_read_inode_block() and that could be marking
fully alive inode as bad. So this commit is indeed buggy. Adding relevant
people to CC.

Guys, maybe I'm misunderstanding the changelog of 58b6fcd2ab34 but the
justification:

The VFS open(O_DIRECT) operation appears to incorrectly clear the inode's
I_DIRTY flag without ensuring the dirty metadata (reflecting the earlier
buffered write, e.g., an updated i_size) is flushed to disk.

looks bogus. Combinations of direct and buffered IO work perfectly fine for
other filesystems (definitely not corrupting them). VFS definitely does not
clear dirty flags without writing back the inode.

The particular syzbot reproducers mentioned in 58b6fcd2ab34 are likely
confusing ocfs2 by calling LOOP_SET_STATUS(64) on the loopback device with
mounted ocfs2 filesystem which may effectively corrupt the filesystem
underneath. So I suspect proper fix for your issues is actually
https://lore.kernel.org/all/20251114144204.2402336-2-rpthibeault@gmail.com/.

Perhaps we should ping Jens to pick it up.

Honza

>
> diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
> index 8340525e5589..53d649436017 100644
> --- a/fs/ocfs2/inode.c
> +++ b/fs/ocfs2/inode.c
> @@ -1708,8 +1708,6 @@ int ocfs2_read_inode_block_full(struct inode *inode, struct buffer_head **bh,
> rc = ocfs2_read_blocks(INODE_CACHE(inode), OCFS2_I(inode)->ip_blkno,
> 1, &tmp, flags, ocfs2_validate_inode_block);
>
> - if (rc < 0)
> - make_bad_inode(inode);
> /* If ocfs2_read_blocks() got us a new bh, pass it up. */
> if (!rc && !*bh)
> *bh = tmp;
--
Jan Kara <jack@suse.com>
SUSE Labs, CR