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?"));
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to