summaryrefslogtreecommitdiffstats
path: root/sys/cddl
diff options
context:
space:
mode:
authoravg <avg@FreeBSD.org>2016-06-23 07:01:54 +0000
committeravg <avg@FreeBSD.org>2016-06-23 07:01:54 +0000
commit6efa34305bb5e56714c708e0ea703023b0c8cfd1 (patch)
treea0d8dd9bd34c8447871bf78044c098510f444a5c /sys/cddl
parentdb5b889e7a94fff893bfa972be9e32514b42f2a2 (diff)
downloadFreeBSD-src-6efa34305bb5e56714c708e0ea703023b0c8cfd1.zip
FreeBSD-src-6efa34305bb5e56714c708e0ea703023b0c8cfd1.tar.gz
fix deadlock-prone code in getzfsvfs()
getzfsvfs() called vfs_busy() in the waiting mode while having a hold on a pool (via a call to dmu_objset_hold). In other words, dp_config_rwlock was held in the shared mode while a thread could be sleeping in vfs_busy(). The pool's txg sync thread needs to take dp_config_rwlock in the exclusive mode for some actions, e.g., for executing sync tasks. If the sync thread gets blocked, then any thread waiting for its sync task to get executed is also blocked. Which, in turn, could mean that vfs_busy() will keep waiting indefinitely. The solution is to use vfs_ref() in the locked section and to call vfs_busy() only after dropping other locks. Note that a reference on a struct mount object does not prevent an associated zfsvfs_t object from being destroyed. So, we have to be careful to operate only on the struct mount object until we successfully vfs_busy it. Approved by: re (gjb) MFC after: 2 weeks
Diffstat (limited to 'sys/cddl')
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c19
1 files changed, 11 insertions, 8 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
index 740eacd..aa5ab2e 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
@@ -1430,6 +1430,7 @@ static int
getzfsvfs(const char *dsname, zfsvfs_t **zfvp)
{
objset_t *os;
+ vfs_t *vfsp;
int error;
error = dmu_objset_hold(dsname, FTAG, &os);
@@ -1443,19 +1444,21 @@ getzfsvfs(const char *dsname, zfsvfs_t **zfvp)
mutex_enter(&os->os_user_ptr_lock);
*zfvp = dmu_objset_get_user(os);
if (*zfvp) {
-#ifdef illumos
- VFS_HOLD((*zfvp)->z_vfs);
-#else
- if (vfs_busy((*zfvp)->z_vfs, 0) != 0) {
- *zfvp = NULL;
- error = SET_ERROR(ESRCH);
- }
-#endif
+ vfsp = (*zfvp)->z_vfs;
+ vfs_ref(vfsp);
} else {
error = SET_ERROR(ESRCH);
}
mutex_exit(&os->os_user_ptr_lock);
dmu_objset_rele(os, FTAG);
+ if (error == 0) {
+ error = vfs_busy(vfsp, 0);
+ vfs_rel(vfsp);
+ if (error != 0) {
+ *zfvp = NULL;
+ error = SET_ERROR(ESRCH);
+ }
+ }
return (error);
}
OpenPOWER on IntegriCloud