summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormarkj <markj@FreeBSD.org>2013-08-24 21:13:38 +0000
committermarkj <markj@FreeBSD.org>2013-08-24 21:13:38 +0000
commit3541d8b1434b233c6420ff91d742fe8b8c53a2e1 (patch)
treeef10dca68a0c1d91a3cc018d4f95de74d267c03f
parent6ad648e223be6153dd1674649bfc08d9733aa04a (diff)
downloadFreeBSD-src-3541d8b1434b233c6420ff91d742fe8b8c53a2e1.zip
FreeBSD-src-3541d8b1434b233c6420ff91d742fe8b8c53a2e1.tar.gz
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
-rw-r--r--share/man/man9/EVENTHANDLER.92
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c4
-rw-r--r--sys/cddl/dev/dtrace/dtrace_load.c4
-rw-r--r--sys/cddl/dev/dtrace/dtrace_unload.c2
-rw-r--r--sys/cddl/dev/sdt/sdt.c12
-rw-r--r--sys/dev/hwpmc/hwpmc_mod.c111
-rw-r--r--sys/kern/kern_linker.c39
-rw-r--r--sys/sys/eventhandler.h4
-rw-r--r--sys/sys/pmckern.h4
9 files changed, 84 insertions, 98 deletions
diff --git a/share/man/man9/EVENTHANDLER.9 b/share/man/man9/EVENTHANDLER.9
index c3b646d..d6e7556 100644
--- a/share/man/man9/EVENTHANDLER.9
+++ b/share/man/man9/EVENTHANDLER.9
@@ -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.
diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
index 9c007e7..babc42c 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
@@ -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)
diff --git a/sys/cddl/dev/dtrace/dtrace_load.c b/sys/cddl/dev/dtrace/dtrace_load.c
index f37d593..05436fe 100644
--- a/sys/cddl/dev/dtrace/dtrace_load.c
+++ b/sys/cddl/dev/dtrace/dtrace_load.c
@@ -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
diff --git a/sys/cddl/dev/dtrace/dtrace_unload.c b/sys/cddl/dev/dtrace/dtrace_unload.c
index 9e37114..e9bd53c 100644
--- a/sys/cddl/dev/dtrace/dtrace_unload.c
+++ b/sys/cddl/dev/dtrace/dtrace_unload.c
@@ -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) {
/*
diff --git a/sys/cddl/dev/sdt/sdt.c b/sys/cddl/dev/sdt/sdt.c
index b65d1ad..41d3610 100644
--- a/sys/cddl/dev/sdt/sdt.c
+++ b/sys/cddl/dev/sdt/sdt.c
@@ -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;
diff --git a/sys/dev/hwpmc/hwpmc_mod.c b/sys/dev/hwpmc/hwpmc_mod.c
index 150c69a..86242d9 100644
--- a/sys/dev/hwpmc/hwpmc_mod.c
+++ b/sys/dev/hwpmc/hwpmc_mod.c
@@ -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;
@@ -1476,50 +1477,6 @@ pmc_process_csw_out(struct thread *td)
}
/*
- * 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)
diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c
index b5a2fbb..7d32260 100644
--- a/sys/kern/kern_linker.c
+++ b/sys/kern/kern_linker.c
@@ -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);
}
diff --git a/sys/sys/eventhandler.h b/sys/sys/eventhandler.h
index a1f9c55..f1d06b5 100644
--- a/sys/sys/eventhandler.h
+++ b/sys/sys/eventhandler.h
@@ -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 */
diff --git a/sys/sys/pmckern.h b/sys/sys/pmckern.h
index e3e18a6..70b9b3f 100644
--- a/sys/sys/pmckern.h
+++ b/sys/sys/pmckern.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
OpenPOWER on IntegriCloud