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
This commit is contained in:
parent
1d9b2fdb21
commit
05a4755ef6
@ -70,6 +70,9 @@ SYSCTL_INT(_debug, OID_AUTO, kld_debug, CTLFLAG_RW,
|
||||
|
||||
#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 char *file, int *fileid)
|
||||
|
||||
KLD_LOCK();
|
||||
error = linker_load_module(kldname, modname, NULL, NULL, &lf);
|
||||
if (error)
|
||||
goto unlock;
|
||||
#ifdef HWPMC_HOOKS
|
||||
pkm.pm_file = lf->filename;
|
||||
pkm.pm_address = (uintptr_t) lf->address;
|
||||
PMC_CALL_HOOK(td, PMC_FN_KLD_LOAD, (void *) &pkm);
|
||||
#endif
|
||||
if (error) {
|
||||
KLD_UNLOCK();
|
||||
goto done;
|
||||
}
|
||||
lf->userrefs++;
|
||||
if (fileid != NULL)
|
||||
*fileid = lf->id;
|
||||
unlock:
|
||||
#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);
|
||||
KLD_UNLOCK_READ();
|
||||
#else
|
||||
KLD_UNLOCK();
|
||||
#endif
|
||||
|
||||
done:
|
||||
CURVNET_RESTORE();
|
||||
return (error);
|
||||
}
|
||||
@ -1102,10 +1111,14 @@ kern_kldunload(struct thread *td, int fileid, int flags)
|
||||
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?"));
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user