svn commit: r227440 - stable/8/sys/kern
Ryan Stone
rstone at FreeBSD.org
Fri Nov 11 02:15:44 UTC 2011
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?"));
More information about the svn-src-stable-8
mailing list