Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 17 Jul 2011 21:53:42 +0000 (UTC)
From:      Ryan Stone <rstone@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r224156 - head/sys/kern
Message-ID:  <201107172153.p6HLrgOM091978@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rstone
Date: Sun Jul 17 21:53:42 2011
New Revision: 224156
URL: http://svn.freebsd.org/changeset/base/224156

Log:
  Fix a LOR between hwpmc and the kernel linker.  When a system-wide
  sampling mode PMC is allocated, hwpmc calls linker_hwpmc_list_objects()
  while already holding an exclusive lock on pmc-sx lock.  list_objects()
  tries to acquire an exclusive lock on the kld_sx lock.  When a KLD module
  is loaded or unloaded successfully, kern_kld(un)load calls into the pmc
  hook while already holding an exclusive lock on the kld_sx lock.  Calling
  the pmc hook requires acquiring a shared lock on the pmc-sx lock.
  
  Fix this by only acquiring a shared lock on the kld_sx lock in
  linker_hwpmc_list_objects(), and also downgrading to a shared lock on the
  kld_sx lock in kern_kld(un)load before calling into the pmc hook.  In
  kern_kldload this required moving some modifications of the linker_file_t
  to happen before calling into the pmc hook.
  
  This fixes the deadlock by ensuring that the hwpmc -> list_objects() case
  is always able to proceed.  Without this patch, I was able to deadlock a
  multicore system within minutes by constantly loading and unloading an KLD
  module while I simultaneously started a sampling mode PMC in a loop.
  
  MFC after:	1 month

Modified:
  head/sys/kern/kern_linker.c

Modified: head/sys/kern/kern_linker.c
==============================================================================
--- head/sys/kern/kern_linker.c	Sun Jul 17 21:52:55 2011	(r224155)
+++ head/sys/kern/kern_linker.c	Sun Jul 17 21:53:42 2011	(r224156)
@@ -70,6 +70,9 @@ SYSCTL_INT(_debug, OID_AUTO, kld_debug, 
 
 #define	KLD_LOCK()		sx_xlock(&kld_sx)
 #define	KLD_UNLOCK()		sx_xunlock(&kld_sx)
+#define	KLD_DOWNGRADE()		sx_downgrade(&kld_sx)
+#define	KLD_LOCK_READ()		sx_slock(&kld_sx)
+#define	KLD_UNLOCK_READ()	sx_sunlock(&kld_sx)
 #define	KLD_LOCKED()		sx_xlocked(&kld_sx)
 #define	KLD_LOCK_ASSERT() do {						\
 	if (!cold)							\
@@ -1019,18 +1022,24 @@ kern_kldload(struct thread *td, const ch
 
 	KLD_LOCK();
 	error = linker_load_module(kldname, modname, NULL, NULL, &lf);
-	if (error)
-		goto unlock;
+	if (error) {
+		KLD_UNLOCK();
+		goto done;
+	}
+	lf->userrefs++;
+	if (fileid != NULL)
+		*fileid = lf->id;
 #ifdef HWPMC_HOOKS
+	KLD_DOWNGRADE();
 	pkm.pm_file = lf->filename;
 	pkm.pm_address = (uintptr_t) lf->address;
 	PMC_CALL_HOOK(td, PMC_FN_KLD_LOAD, (void *) &pkm);
-#endif
-	lf->userrefs++;
-	if (fileid != NULL)
-		*fileid = lf->id;
-unlock:
+	KLD_UNLOCK_READ();
+#else
 	KLD_UNLOCK();
+#endif
+
+done:
 	CURVNET_RESTORE();
 	return (error);
 }
@@ -1102,10 +1111,14 @@ kern_kldunload(struct thread *td, int fi
 		error = ENOENT;
 
 #ifdef HWPMC_HOOKS
-	if (error == 0)
+	if (error == 0) {
+		KLD_DOWNGRADE();
 		PMC_CALL_HOOK(td, PMC_FN_KLD_UNLOAD, (void *) &pkm);
+		KLD_UNLOCK_READ();
+	} else
+#else
+		KLD_UNLOCK();
 #endif
-	KLD_UNLOCK();
 	CURVNET_RESTORE();
 	return (error);
 }
@@ -1932,7 +1945,7 @@ linker_hwpmc_list_objects(void)
 	int i, nmappings;
 
 	nmappings = 0;
-	KLD_LOCK();
+	KLD_LOCK_READ();
 	TAILQ_FOREACH(lf, &linker_files, link)
 		nmappings++;
 
@@ -1947,7 +1960,7 @@ linker_hwpmc_list_objects(void)
 		kobase[i].pm_address = (uintptr_t)lf->address;
 		i++;
 	}
-	KLD_UNLOCK();
+	KLD_UNLOCK_READ();
 
 	KASSERT(i > 0, ("linker_hpwmc_list_objects: no kernel objects?"));
 



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