In get_tree_bdev_flags(), sget_dev() calls sget_fc(), which transfers ownership of fc->s_fs_info to the new superblock (s->s_fs_info) and clears fc->s_fs_info. If setup_bdev_super() then fails, the superblock is torn down via deactivate_locked_super(). However, generic_shutdown_super() only calls the filesystem's ->put_super() when sb->s_root is non-NULL. Since setup_bdev_super() fails before fill_super() runs, sb->s_root is never set, so ->put_super() is never called and the allocated s_fs_info is leaked. Return ownership of s_fs_info to fc when setup_bdev_super() fails so put_fs_context() can free it via the filesystem's ->free() callback. Clear s->s_fs_info to avoid a stale reference. Do this only when setup_bdev_super() fails; when fill_super() fails, it already frees s_fs_info in its own error path. Reported-by: syzbot+99f6ed51479b86ac4c41@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=99f6ed51479b86ac4c41 Signed-off-by: Shardul Bankar --- fs/super.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/super.c b/fs/super.c index 3d85265d1400..1aa8dbd19bb6 100644 --- a/fs/super.c +++ b/fs/super.c @@ -1687,6 +1687,11 @@ int get_tree_bdev_flags(struct fs_context *fc, } } else { error = setup_bdev_super(s, fc->sb_flags, fc); + if (error) { + fc->s_fs_info = s->s_fs_info; + s->s_fs_info = NULL; + } + if (!error) error = fill_super(s, fc); if (error) { -- 2.34.1