changeset 12569:06d420824c4b

6532936 rare deadlock between multiple threads between fp_nexus_enum_tq and devfs
author Jakub Jermar <Jakub.Jermar@Sun.COM>
date Mon, 07 Jun 2010 13:16:48 +0200
parents 0f6ea478c2c7
children 4be1b7cb5db7
files usr/src/uts/common/fs/devfs/devfs_subr.c
diffstat 1 files changed, 14 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/fs/devfs/devfs_subr.c	Mon Jun 07 01:47:20 2010 -0600
+++ b/usr/src/uts/common/fs/devfs/devfs_subr.c	Mon Jun 07 13:16:48 2010 +0200
@@ -936,7 +936,11 @@
 
 	dcmn_err3(("dv_find %s\n", nm));
 
-	rw_enter(&ddv->dv_contents, RW_READER);
+	if (!rw_tryenter(&ddv->dv_contents, RW_READER)) {
+		if (tsd_get(devfs_clean_key))
+			return (EBUSY);
+		rw_enter(&ddv->dv_contents, RW_READER);
+	}
 start:
 	if (DV_STALE(ddv)) {
 		rw_exit(&ddv->dv_contents);
@@ -1241,10 +1245,16 @@
 		*vpp = vp;
 
 notfound:
-	rw_enter(&ddv->dv_contents, RW_WRITER);
-	if (was_busy)
+	if (was_busy) {
+		/*
+		 * Non-zero was_busy tells us that we are not in the
+		 * devfs_clean() path which in turn means that we can afford
+		 * to take the contents lock unconditionally.
+		 */
+		rw_enter(&ddv->dv_contents, RW_WRITER);
 		ddv->dv_busy--;
-	rw_exit(&ddv->dv_contents);
+		rw_exit(&ddv->dv_contents);
+	}
 	return (rv);
 }