mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
Rename the kld_unload event handler to kld_unload_try, and add a new
kld_unload event handler which gets invoked after a linker file has been successfully unloaded. The kld_unload and kld_load event handlers are now invoked with the shared linker lock held, while kld_unload_try is invoked with the lock exclusively held. Convert hwpmc(4) to use these event handlers instead of having kern_kldload() and kern_kldunload() invoke hwpmc(4) hooks whenever files are loaded or unloaded. This has no functional effect, but simplifes the linker code somewhat. Reviewed by: jhb
This commit is contained in:
parent
ce6169e715
commit
29f4e216f2
9 changed files with 84 additions and 98 deletions
|
|
@ -202,6 +202,8 @@ Callbacks invoked when a BPF listener attaches to/detaches from network interfac
|
|||
.It Vt kld_load
|
||||
Callbacks invoked after a linker file has been loaded.
|
||||
.It Vt kld_unload
|
||||
Callbacks invoked after a linker file has been successfully unloaded.
|
||||
.It Vt kld_unload_try
|
||||
Callbacks invoked before a linker file is about to be unloaded.
|
||||
These callbacks may be used to return an error and prevent the unload from
|
||||
proceeding.
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ int dtrace_in_probe; /* non-zero if executing a probe */
|
|||
uintptr_t dtrace_in_probe_addr; /* Address of invop when already in probe */
|
||||
#endif
|
||||
static eventhandler_tag dtrace_kld_load_tag;
|
||||
static eventhandler_tag dtrace_kld_unload_tag;
|
||||
static eventhandler_tag dtrace_kld_unload_try_tag;
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
@ -15351,7 +15351,7 @@ dtrace_kld_load(void *arg __unused, linker_file_t lf)
|
|||
}
|
||||
|
||||
static void
|
||||
dtrace_kld_unload(void *arg __unused, linker_file_t lf, int *error)
|
||||
dtrace_kld_unload_try(void *arg __unused, linker_file_t lf, int *error)
|
||||
{
|
||||
|
||||
if (*error != 0)
|
||||
|
|
|
|||
|
|
@ -59,8 +59,8 @@ dtrace_load(void *dummy)
|
|||
/* Register callbacks for linker file load and unload events. */
|
||||
dtrace_kld_load_tag = EVENTHANDLER_REGISTER(kld_load,
|
||||
dtrace_kld_load, NULL, EVENTHANDLER_PRI_ANY);
|
||||
dtrace_kld_unload_tag = EVENTHANDLER_REGISTER(kld_unload,
|
||||
dtrace_kld_unload, NULL, EVENTHANDLER_PRI_ANY);
|
||||
dtrace_kld_unload_try_tag = EVENTHANDLER_REGISTER(kld_unload_try,
|
||||
dtrace_kld_unload_try, NULL, EVENTHANDLER_PRI_ANY);
|
||||
|
||||
/*
|
||||
* Initialise the mutexes without 'witness' because the dtrace
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ dtrace_unload()
|
|||
|
||||
dtrace_provider = NULL;
|
||||
EVENTHANDLER_DEREGISTER(kld_load, dtrace_kld_load_tag);
|
||||
EVENTHANDLER_DEREGISTER(kld_unload, dtrace_kld_unload_tag);
|
||||
EVENTHANDLER_DEREGISTER(kld_unload_try, dtrace_kld_unload_try_tag);
|
||||
|
||||
if ((state = dtrace_anon_grab()) != NULL) {
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ static int sdt_unload(void *);
|
|||
static void sdt_create_provider(struct sdt_provider *);
|
||||
static void sdt_create_probe(struct sdt_probe *);
|
||||
static void sdt_kld_load(void *, struct linker_file *);
|
||||
static void sdt_kld_unload(void *, struct linker_file *, int *);
|
||||
static void sdt_kld_unload_try(void *, struct linker_file *, int *);
|
||||
|
||||
static MALLOC_DEFINE(M_SDT, "SDT", "DTrace SDT providers");
|
||||
|
||||
|
|
@ -95,7 +95,7 @@ static struct cdev *sdt_cdev;
|
|||
static TAILQ_HEAD(, sdt_provider) sdt_prov_list;
|
||||
|
||||
eventhandler_tag sdt_kld_load_tag;
|
||||
eventhandler_tag sdt_kld_unload_tag;
|
||||
eventhandler_tag sdt_kld_unload_try_tag;
|
||||
|
||||
static void
|
||||
sdt_create_provider(struct sdt_provider *prov)
|
||||
|
|
@ -264,7 +264,7 @@ sdt_kld_load(void *arg __unused, struct linker_file *lf)
|
|||
}
|
||||
|
||||
static void
|
||||
sdt_kld_unload(void *arg __unused, struct linker_file *lf, int *error __unused)
|
||||
sdt_kld_unload_try(void *arg __unused, struct linker_file *lf, int *error __unused)
|
||||
{
|
||||
struct sdt_provider *prov, **curr, **begin, **end, *tmp;
|
||||
|
||||
|
|
@ -319,8 +319,8 @@ sdt_load(void *arg __unused)
|
|||
|
||||
sdt_kld_load_tag = EVENTHANDLER_REGISTER(kld_load, sdt_kld_load, NULL,
|
||||
EVENTHANDLER_PRI_ANY);
|
||||
sdt_kld_unload_tag = EVENTHANDLER_REGISTER(kld_unload, sdt_kld_unload,
|
||||
NULL, EVENTHANDLER_PRI_ANY);
|
||||
sdt_kld_unload_try_tag = EVENTHANDLER_REGISTER(kld_unload_try,
|
||||
sdt_kld_unload_try, NULL, EVENTHANDLER_PRI_ANY);
|
||||
|
||||
/* Pick up probes from the kernel and already-loaded linker files. */
|
||||
linker_file_foreach(sdt_linker_file_cb, NULL);
|
||||
|
|
@ -332,7 +332,7 @@ sdt_unload(void *arg __unused)
|
|||
struct sdt_provider *prov, *tmp;
|
||||
|
||||
EVENTHANDLER_DEREGISTER(kld_load, sdt_kld_load_tag);
|
||||
EVENTHANDLER_DEREGISTER(kld_unload, sdt_kld_unload_tag);
|
||||
EVENTHANDLER_DEREGISTER(kld_unload_try, sdt_kld_unload_try_tag);
|
||||
|
||||
sdt_probe_func = sdt_probe_stub;
|
||||
|
||||
|
|
|
|||
|
|
@ -132,7 +132,8 @@ static int *pmc_pmcdisp; /* PMC row dispositions */
|
|||
|
||||
|
||||
/* various event handlers */
|
||||
static eventhandler_tag pmc_exit_tag, pmc_fork_tag;
|
||||
static eventhandler_tag pmc_exit_tag, pmc_fork_tag, pmc_kld_load_tag,
|
||||
pmc_kld_unload_tag;
|
||||
|
||||
/* Module statistics */
|
||||
struct pmc_op_getdriverstats pmc_stats;
|
||||
|
|
@ -1475,50 +1476,6 @@ pmc_process_csw_out(struct thread *td)
|
|||
critical_exit();
|
||||
}
|
||||
|
||||
/*
|
||||
* Log a KLD operation.
|
||||
*/
|
||||
|
||||
static void
|
||||
pmc_process_kld_load(struct pmckern_map_in *pkm)
|
||||
{
|
||||
struct pmc_owner *po;
|
||||
|
||||
sx_assert(&pmc_sx, SX_LOCKED);
|
||||
|
||||
/*
|
||||
* Notify owners of system sampling PMCs about KLD operations.
|
||||
*/
|
||||
|
||||
LIST_FOREACH(po, &pmc_ss_owners, po_ssnext)
|
||||
if (po->po_flags & PMC_PO_OWNS_LOGFILE)
|
||||
pmclog_process_map_in(po, (pid_t) -1, pkm->pm_address,
|
||||
(char *) pkm->pm_file);
|
||||
|
||||
/*
|
||||
* TODO: Notify owners of (all) process-sampling PMCs too.
|
||||
*/
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
pmc_process_kld_unload(struct pmckern_map_out *pkm)
|
||||
{
|
||||
struct pmc_owner *po;
|
||||
|
||||
sx_assert(&pmc_sx, SX_LOCKED);
|
||||
|
||||
LIST_FOREACH(po, &pmc_ss_owners, po_ssnext)
|
||||
if (po->po_flags & PMC_PO_OWNS_LOGFILE)
|
||||
pmclog_process_map_out(po, (pid_t) -1,
|
||||
pkm->pm_address, pkm->pm_address + pkm->pm_size);
|
||||
|
||||
/*
|
||||
* TODO: Notify owners of process-sampling PMCs.
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* A mapping change for a process.
|
||||
*/
|
||||
|
|
@ -1833,8 +1790,8 @@ const char *pmc_hooknames[] = {
|
|||
"CSW-IN",
|
||||
"CSW-OUT",
|
||||
"SAMPLE",
|
||||
"KLDLOAD",
|
||||
"KLDUNLOAD",
|
||||
"UNUSED1",
|
||||
"UNUSED2",
|
||||
"MMAP",
|
||||
"MUNMAP",
|
||||
"CALLCHAIN-NMI",
|
||||
|
|
@ -2002,17 +1959,6 @@ pmc_hook_handler(struct thread *td, int function, void *arg)
|
|||
pmc_process_samples(PCPU_GET(cpuid), PMC_SR);
|
||||
break;
|
||||
|
||||
|
||||
case PMC_FN_KLD_LOAD:
|
||||
sx_assert(&pmc_sx, SX_LOCKED);
|
||||
pmc_process_kld_load((struct pmckern_map_in *) arg);
|
||||
break;
|
||||
|
||||
case PMC_FN_KLD_UNLOAD:
|
||||
sx_assert(&pmc_sx, SX_LOCKED);
|
||||
pmc_process_kld_unload((struct pmckern_map_out *) arg);
|
||||
break;
|
||||
|
||||
case PMC_FN_MMAP:
|
||||
sx_assert(&pmc_sx, SX_LOCKED);
|
||||
pmc_process_mmap(td, (struct pmckern_map_in *) arg);
|
||||
|
|
@ -4644,6 +4590,47 @@ pmc_process_fork(void *arg __unused, struct proc *p1, struct proc *newproc,
|
|||
sx_xunlock(&pmc_sx);
|
||||
}
|
||||
|
||||
static void
|
||||
pmc_kld_load(void *arg __unused, linker_file_t lf)
|
||||
{
|
||||
struct pmc_owner *po;
|
||||
|
||||
sx_slock(&pmc_sx);
|
||||
|
||||
/*
|
||||
* Notify owners of system sampling PMCs about KLD operations.
|
||||
*/
|
||||
LIST_FOREACH(po, &pmc_ss_owners, po_ssnext)
|
||||
if (po->po_flags & PMC_PO_OWNS_LOGFILE)
|
||||
pmclog_process_map_in(po, (pid_t) -1,
|
||||
(uintfptr_t) lf->address, lf->filename);
|
||||
|
||||
/*
|
||||
* TODO: Notify owners of (all) process-sampling PMCs too.
|
||||
*/
|
||||
|
||||
sx_sunlock(&pmc_sx);
|
||||
}
|
||||
|
||||
static void
|
||||
pmc_kld_unload(void *arg __unused, const char *filename __unused,
|
||||
caddr_t address, size_t size)
|
||||
{
|
||||
struct pmc_owner *po;
|
||||
|
||||
sx_slock(&pmc_sx);
|
||||
|
||||
LIST_FOREACH(po, &pmc_ss_owners, po_ssnext)
|
||||
if (po->po_flags & PMC_PO_OWNS_LOGFILE)
|
||||
pmclog_process_map_out(po, (pid_t) -1,
|
||||
(uintfptr_t) address, (uintfptr_t) address + size);
|
||||
|
||||
/*
|
||||
* TODO: Notify owners of process-sampling PMCs.
|
||||
*/
|
||||
|
||||
sx_sunlock(&pmc_sx);
|
||||
}
|
||||
|
||||
/*
|
||||
* initialization
|
||||
|
|
@ -4913,6 +4900,12 @@ pmc_initialize(void)
|
|||
pmc_fork_tag = EVENTHANDLER_REGISTER(process_fork,
|
||||
pmc_process_fork, NULL, EVENTHANDLER_PRI_ANY);
|
||||
|
||||
/* register kld event handlers */
|
||||
pmc_kld_load_tag = EVENTHANDLER_REGISTER(kld_load, pmc_kld_load,
|
||||
NULL, EVENTHANDLER_PRI_ANY);
|
||||
pmc_kld_unload_tag = EVENTHANDLER_REGISTER(kld_unload, pmc_kld_unload,
|
||||
NULL, EVENTHANDLER_PRI_ANY);
|
||||
|
||||
/* initialize logging */
|
||||
pmclog_initialize();
|
||||
|
||||
|
|
@ -4970,6 +4963,8 @@ pmc_cleanup(void)
|
|||
/* deregister event handlers */
|
||||
EVENTHANDLER_DEREGISTER(process_fork, pmc_fork_tag);
|
||||
EVENTHANDLER_DEREGISTER(process_exit, pmc_exit_tag);
|
||||
EVENTHANDLER_DEREGISTER(kld_load, pmc_kld_load_tag);
|
||||
EVENTHANDLER_DEREGISTER(kld_unload, pmc_kld_unload_tag);
|
||||
|
||||
/* send SIGBUS to all owner threads, free up allocations */
|
||||
if (pmc_ownerhash)
|
||||
|
|
|
|||
|
|
@ -995,9 +995,6 @@ linker_search_symbol_name(caddr_t value, char *buf, u_int buflen,
|
|||
int
|
||||
kern_kldload(struct thread *td, const char *file, int *fileid)
|
||||
{
|
||||
#ifdef HWPMC_HOOKS
|
||||
struct pmckern_map_in pkm;
|
||||
#endif
|
||||
const char *kldname, *modname;
|
||||
linker_file_t lf;
|
||||
int error;
|
||||
|
|
@ -1037,17 +1034,9 @@ kern_kldload(struct thread *td, const char *file, int *fileid)
|
|||
if (fileid != NULL)
|
||||
*fileid = lf->id;
|
||||
|
||||
EVENTHANDLER_INVOKE(kld_load, lf);
|
||||
|
||||
#ifdef HWPMC_HOOKS
|
||||
sx_downgrade(&kld_sx);
|
||||
pkm.pm_file = lf->filename;
|
||||
pkm.pm_address = (uintptr_t) lf->address;
|
||||
PMC_CALL_HOOK(td, PMC_FN_KLD_LOAD, (void *) &pkm);
|
||||
EVENTHANDLER_INVOKE(kld_load, lf);
|
||||
sx_sunlock(&kld_sx);
|
||||
#else
|
||||
sx_xunlock(&kld_sx);
|
||||
#endif
|
||||
|
||||
done:
|
||||
CURVNET_RESTORE();
|
||||
|
|
@ -1076,10 +1065,10 @@ sys_kldload(struct thread *td, struct kldload_args *uap)
|
|||
int
|
||||
kern_kldunload(struct thread *td, int fileid, int flags)
|
||||
{
|
||||
#ifdef HWPMC_HOOKS
|
||||
struct pmckern_map_out pkm;
|
||||
#endif
|
||||
linker_file_t lf;
|
||||
char *filename = NULL;
|
||||
caddr_t address;
|
||||
size_t size;
|
||||
int error = 0;
|
||||
|
||||
if ((error = securelevel_gt(td->td_ucred, 0)) != 0)
|
||||
|
|
@ -1094,7 +1083,7 @@ kern_kldunload(struct thread *td, int fileid, int flags)
|
|||
if (lf) {
|
||||
KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
|
||||
|
||||
EVENTHANDLER_INVOKE(kld_unload, lf, &error);
|
||||
EVENTHANDLER_INVOKE(kld_unload_try, lf, &error);
|
||||
if (error != 0)
|
||||
error = EBUSY;
|
||||
else if (lf->userrefs == 0) {
|
||||
|
|
@ -1105,11 +1094,11 @@ kern_kldunload(struct thread *td, int fileid, int flags)
|
|||
" loaded by the kernel\n");
|
||||
error = EBUSY;
|
||||
} else {
|
||||
#ifdef HWPMC_HOOKS
|
||||
/* Save data needed by hwpmc(4) before unloading. */
|
||||
pkm.pm_address = (uintptr_t) lf->address;
|
||||
pkm.pm_size = lf->size;
|
||||
#endif
|
||||
/* Save data needed for the kld_unload callbacks. */
|
||||
filename = strdup(lf->filename, M_TEMP);
|
||||
address = lf->address;
|
||||
size = lf->size;
|
||||
|
||||
lf->userrefs--;
|
||||
error = linker_file_unload(lf, flags);
|
||||
if (error)
|
||||
|
|
@ -1118,16 +1107,14 @@ kern_kldunload(struct thread *td, int fileid, int flags)
|
|||
} else
|
||||
error = ENOENT;
|
||||
|
||||
#ifdef HWPMC_HOOKS
|
||||
if (error == 0) {
|
||||
sx_downgrade(&kld_sx);
|
||||
PMC_CALL_HOOK(td, PMC_FN_KLD_UNLOAD, (void *) &pkm);
|
||||
EVENTHANDLER_INVOKE(kld_unload, filename, address, size);
|
||||
sx_sunlock(&kld_sx);
|
||||
} else
|
||||
sx_xunlock(&kld_sx);
|
||||
#else
|
||||
sx_xunlock(&kld_sx);
|
||||
#endif
|
||||
free(filename, M_TEMP);
|
||||
|
||||
CURVNET_RESTORE();
|
||||
return (error);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -269,8 +269,10 @@ EVENTHANDLER_DECLARE(maxsockets_change, uma_zone_chfn);
|
|||
/* Kernel linker file load and unload events */
|
||||
struct linker_file;
|
||||
typedef void (*kld_load_fn)(void *, struct linker_file *);
|
||||
typedef void (*kld_unload_fn)(void *, struct linker_file *, int *);
|
||||
typedef void (*kld_unload_fn)(void *, const char *, caddr_t, size_t);
|
||||
typedef void (*kld_unload_try_fn)(void *, struct linker_file *, int *);
|
||||
EVENTHANDLER_DECLARE(kld_load, kld_load_fn);
|
||||
EVENTHANDLER_DECLARE(kld_unload, kld_unload_fn);
|
||||
EVENTHANDLER_DECLARE(kld_unload_try, kld_unload_try_fn);
|
||||
|
||||
#endif /* SYS_EVENTHANDLER_H */
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@
|
|||
#define PMC_FN_CSW_IN 2
|
||||
#define PMC_FN_CSW_OUT 3
|
||||
#define PMC_FN_DO_SAMPLES 4
|
||||
#define PMC_FN_KLD_LOAD 5
|
||||
#define PMC_FN_KLD_UNLOAD 6
|
||||
#define PMC_FN_UNUSED1 5
|
||||
#define PMC_FN_UNUSED2 6
|
||||
#define PMC_FN_MMAP 7
|
||||
#define PMC_FN_MUNMAP 8
|
||||
#define PMC_FN_USER_CALLCHAIN 9
|
||||
|
|
|
|||
Loading…
Reference in a new issue