Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 3 Jul 2019 18:14:01 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r349660 - stable/12/sys/fs/cuse
Message-ID:  <201907031814.x63IE1Ys023960@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Wed Jul  3 18:14:00 2019
New Revision: 349660
URL: https://svnweb.freebsd.org/changeset/base/349660

Log:
  MFC r349367:
  Fix for deadlock situation in cuse(3)
  
  The final server unref should be done by the server thread to prevent
  deadlock in the client cdevpriv destructor, which cannot destroy
  itself.
  
  Sponsored by:	Mellanox Technologies

Modified:
  stable/12/sys/fs/cuse/cuse.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/fs/cuse/cuse.c
==============================================================================
--- stable/12/sys/fs/cuse/cuse.c	Wed Jul  3 18:11:22 2019	(r349659)
+++ stable/12/sys/fs/cuse/cuse.c	Wed Jul  3 18:14:00 2019	(r349660)
@@ -699,12 +699,38 @@ cuse_server_unref(struct cuse_server *pcs)
 	free(pcs, M_CUSE);
 }
 
+static int
+cuse_server_do_close(struct cuse_server *pcs)
+{
+	int retval;
+
+	cuse_lock();
+	cuse_server_is_closing(pcs);
+	/* final client wakeup, if any */
+	cuse_server_wakeup_all_client_locked(pcs);
+
+	knlist_clear(&pcs->selinfo.si_note, 1);
+
+	retval = pcs->refs;
+	cuse_unlock();
+
+	return (retval);
+}
+
 static void
 cuse_server_free(void *arg)
 {
 	struct cuse_server *pcs = arg;
 
-	/* drop refcount */
+	/*
+	 * The final server unref should be done by the server thread
+	 * to prevent deadlock in the client cdevpriv destructor,
+	 * which cannot destroy itself.
+	 */
+	while (cuse_server_do_close(pcs) != 1)
+		pause("W", hz);
+
+	/* drop final refcount */
 	cuse_server_unref(pcs);
 }
 
@@ -746,21 +772,10 @@ static int
 cuse_server_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
 {
 	struct cuse_server *pcs;
-	int error;
 
-	error = cuse_server_get(&pcs);
-	if (error != 0)
-		goto done;
+	if (cuse_server_get(&pcs) == 0)
+		cuse_server_do_close(pcs);
 
-	cuse_lock();
-	cuse_server_is_closing(pcs);
-	/* final client wakeup, if any */
-	cuse_server_wakeup_all_client_locked(pcs);
-
-	knlist_clear(&pcs->selinfo.si_note, 1);
-	cuse_unlock();
-
-done:
 	return (0);
 }
 



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