]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Fix NULL pointer in zfs_preumount from 1d9b3bd
authorChunwei Chen <david.chen@osnexus.com>
Tue, 19 Jul 2016 19:02:33 +0000 (12:02 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Wed, 20 Jul 2016 16:05:43 +0000 (09:05 -0700)
When zfs_domount fails zsb will be freed, and its caller
mount_nodev/get_sb_nodev will do deactivate_locked_super and calls into
zfs_preumount.

In order to make sure we don't touch any nonexistent stuff, we must make sure
s_fs_info is NULL in the fail path so zfs_preumount can easily check that.

Signed-off-by: Chunwei Chen <david.chen@osnexus.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #4867
Issue #4854

module/zfs/zfs_vfsops.c

index 2f1f44207b69ee944cb1822905f3a17dda028ee8..8486510912b60ca3ff141f0c743bc536485680ed 100644 (file)
@@ -1369,7 +1369,8 @@ zfs_domount(struct super_block *sb, zfs_mntopts_t *zmo, int silent)
                dmu_objset_set_user(zsb->z_os, zsb);
                mutex_exit(&zsb->z_os->os_user_ptr_lock);
        } else {
                dmu_objset_set_user(zsb->z_os, zsb);
                mutex_exit(&zsb->z_os->os_user_ptr_lock);
        } else {
-               error = zfs_sb_setup(zsb, B_TRUE);
+               if ((error = zfs_sb_setup(zsb, B_TRUE)))
+                       goto out;
        }
 
        /* Allocate a root inode for the filesystem. */
        }
 
        /* Allocate a root inode for the filesystem. */
@@ -1395,6 +1396,11 @@ out:
        if (error) {
                dmu_objset_disown(zsb->z_os, zsb);
                zfs_sb_free(zsb);
        if (error) {
                dmu_objset_disown(zsb->z_os, zsb);
                zfs_sb_free(zsb);
+               /*
+                * make sure we don't have dangling sb->s_fs_info which
+                * zfs_preumount will use.
+                */
+               sb->s_fs_info = NULL;
        }
 
        return (error);
        }
 
        return (error);
@@ -1413,26 +1419,29 @@ zfs_preumount(struct super_block *sb)
 {
        zfs_sb_t *zsb = sb->s_fs_info;
 
 {
        zfs_sb_t *zsb = sb->s_fs_info;
 
-       if (zsb)
+       /* zsb is NULL when zfs_domount fails during mount */
+       if (zsb) {
                zfsctl_destroy(sb->s_fs_info);
                zfsctl_destroy(sb->s_fs_info);
-       /*
-        * Wait for iput_async before entering evict_inodes in
-        * generic_shutdown_super. The reason we must finish before
-        * evict_inodes is when lazytime is on, or when zfs_purgedir calls
-        * zfs_zget, iput would bump i_count from 0 to 1. This would race
-        * with the i_count check in evict_inodes.  This means it could
-        * destroy the inode while we are still using it.
-        *
-        * We wait for two passes.  xattr directories in the first pass may
-        * add xattr entries in zfs_purgedir, so in the second pass we wait
-        * for them.  We don't use taskq_wait here because it is a pool wide
-        * taskq.  Other mounted filesystems can constantly do iput_async
-        * and there's no guarantee when taskq will be empty.
-        */
-       taskq_wait_outstanding(dsl_pool_iput_taskq(
-           dmu_objset_pool(zsb->z_os)), 0);
-       taskq_wait_outstanding(dsl_pool_iput_taskq(
-           dmu_objset_pool(zsb->z_os)), 0);
+               /*
+                * Wait for iput_async before entering evict_inodes in
+                * generic_shutdown_super. The reason we must finish before
+                * evict_inodes is when lazytime is on, or when zfs_purgedir
+                * calls zfs_zget, iput would bump i_count from 0 to 1. This
+                * would race with the i_count check in evict_inodes. This means
+                * it could destroy the inode while we are still using it.
+                *
+                * We wait for two passes. xattr directories in the first pass
+                * may add xattr entries in zfs_purgedir, so in the second pass
+                * we wait for them. We don't use taskq_wait here because it is
+                * a pool wide taskq. Other mounted filesystems can constantly
+                * do iput_async and there's no guarantee when taskq will be
+                * empty.
+                */
+               taskq_wait_outstanding(dsl_pool_iput_taskq(
+                   dmu_objset_pool(zsb->z_os)), 0);
+               taskq_wait_outstanding(dsl_pool_iput_taskq(
+                   dmu_objset_pool(zsb->z_os)), 0);
+       }
 }
 EXPORT_SYMBOL(zfs_preumount);
 
 }
 EXPORT_SYMBOL(zfs_preumount);