Author: rstone
Date: Fri Nov 11 02:15:44 2011
New Revision: 227440
URL: http://svn.freebsd.org/changeset/base/227440

Log:
  MFC 224156:
  
   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.

Modified:
  stable/8/sys/kern/kern_linker.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/sys/kern/kern_linker.c
==============================================================================
--- stable/8/sys/kern/kern_linker.c     Fri Nov 11 02:13:35 2011        
(r227439)
+++ stable/8/sys/kern/kern_linker.c     Fri Nov 11 02:15:44 2011        
(r227440)
@@ -68,6 +68,9 @@ int kld_debug = 0;
 
 #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)                                                      \
@@ -1014,18 +1017,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);
 }
@@ -1097,10 +1106,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);
 }
@@ -1919,7 +1932,7 @@ linker_hwpmc_list_objects(void)
        int i, nmappings;
 
        nmappings = 0;
-       KLD_LOCK();
+       KLD_LOCK_READ();
        TAILQ_FOREACH(lf, &linker_files, link)
                nmappings++;
 
@@ -1934,7 +1947,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