Fix zvol_open() lock inversion
commit8a02d01e85556bbe3a1c6947bc11b8ef028d4023
authorBrian Behlendorf <behlendorf1@llnl.gov>
Fri, 17 Dec 2021 17:52:13 +0000 (17 09:52 -0800)
committerGitHub <noreply@github.com>
Fri, 17 Dec 2021 17:52:13 +0000 (17 09:52 -0800)
treeb4ef2095a2ab60877b2447cf37a082642f2f7694
parentca1b2bb4b5bd7d3c481f2a7c5e35bb2cfe6b5871
Fix zvol_open() lock inversion

When restructuring the zvol_open() logic for the Linux 5.13 kernel
a lock inversion was accidentally introduced.  In the updated code
the spa_namespace_lock is now taken before the zv_suspend_lock
allowing the following scenario to occur:

    down_read <=== waiting for zv_suspend_lock
    zvol_open <=== holds spa_namespace_lock
    __blkdev_get
    blkdev_get_by_dev
    blkdev_open
    ...

     mutex_lock <== waiting for spa_namespace_lock
     spa_open_common
     spa_open
     dsl_pool_hold
     dmu_objset_hold_flags
     dmu_objset_hold
     dsl_prop_get
     dsl_prop_get_integer
     zvol_create_minor
     dmu_recv_end
     zfs_ioc_recv_impl <=== holds zv_suspend_lock via zvol_suspend()
     zfs_ioc_recv
     ...

This commit resolves the issue by moving the acquisition of the
spa_namespace_lock back to after the zv_suspend_lock which restores
the original ordering.

Additionally, as part of this change the error exit paths were
simplified where possible.

Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Rich Ercolani <rincebrain@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #12863
module/os/linux/zfs/zvol_os.c