Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 23 Jun 2016 07:01:54 +0000 (UTC)
From:      Andriy Gapon <avg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r302123 - head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs
Message-ID:  <201606230701.u5N71sLm016900@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: avg
Date: Thu Jun 23 07:01:54 2016
New Revision: 302123
URL: https://svnweb.freebsd.org/changeset/base/302123

Log:
  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

Modified:
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c	Thu Jun 23 06:27:41 2016	(r302122)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c	Thu Jun 23 07:01:54 2016	(r302123)
@@ -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 *
 	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);
 }
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201606230701.u5N71sLm016900>