zfs_domount: fix vfs_t double-free on root setup failure

When zfs_root() or d_make_root() fails, zfs_domount() calls
zfs_umount(), which frees zfsvfs->z_vfs via zfsvfs_free(). After
the vfs_t lifetime was matched to fs_context, that vfs_t is still
owned by the caller in fc->fs_private. zpl_get_tree() then returns
without clearing fs_private, and put_fs_context() frees it again.

Detach z_vfs before zfs_umount() so the caller retains ownership,
matching the other zfs_domount() error paths.

This is a follow-up to the vfs_t lifetime change in #18377.

Reviewed-by: Rob Norris <[email protected]>
Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Wale Zhang <[email protected]>
Closes #19167
This commit is contained in:
wale authored and GitHub committed 2026-09-24 09:40:42 -07:00
1 parent db57b84c9c
commit 638abd22a9
1 file changed
+4
+4
View File
@@ -1491,6 +1491,8 @@ zfs_domount(struct super_block *sb, const char *osname,
/* Allocate a root inode for the filesystem. */
error = zfs_root(zfsvfs, &root_inode);
if (error) {
/* Caller still owns vfs_t; detach before zfs_umount(). */
zfsvfs->z_vfs = NULL;
(void) zfs_umount(sb);
zfsvfs = NULL; /* avoid double-free; first in zfs_umount */
goto out;
@@ -1499,6 +1501,8 @@ zfs_domount(struct super_block *sb, const char *osname,
/* Allocate a root dentry for the filesystem */
sb->s_root = d_make_root(root_inode);
if (sb->s_root == NULL) {
/* Caller still owns vfs_t; detach before zfs_umount(). */
zfsvfs->z_vfs = NULL;
(void) zfs_umount(sb);
zfsvfs = NULL; /* avoid double-free; first in zfs_umount */
error = SET_ERROR(ENOMEM);