summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorjb <jb@FreeBSD.org>2007-10-22 04:12:57 +0000
committerjb <jb@FreeBSD.org>2007-10-22 04:12:57 +0000
commit9dec415fef268455335c088626d24f3cd5dd26fc (patch)
treeca90169fbd250bbc580b712e8482c755895ffc8f /sys/kern
parent9392728ba026a7e54d585f8efec5f232146d34a2 (diff)
downloadFreeBSD-src-9dec415fef268455335c088626d24f3cd5dd26fc.zip
FreeBSD-src-9dec415fef268455335c088626d24f3cd5dd26fc.tar.gz
Add the full module path name to the kld_file_stat structure
for kldstat(2). This allows libdtrace to determine the exact file from which a kernel module was loaded without having to guess. The kldstat(2) API is versioned with the size of the kld_file_stat structure, so this change creates version 2. Add the pathname to the verbose output of kldstat(8) too. MFC: 3 days
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_linker.c45
1 files changed, 38 insertions, 7 deletions
diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c
index 7640334..324d349 100644
--- a/sys/kern/kern_linker.c
+++ b/sys/kern/kern_linker.c
@@ -97,6 +97,12 @@ linker_file_t linker_kernel_file;
static struct sx kld_sx; /* kernel linker lock */
+/*
+ * Load counter used by clients to determine if a linker file has been
+ * re-loaded. This counter is incremented for each file load.
+ */
+static int loadcnt;
+
static linker_class_list_t classes;
static linker_file_list_t linker_files;
static int next_file_id = 1;
@@ -534,7 +540,7 @@ linker_make_file(const char *pathname, linker_class_t lc)
KLD_LOCK_ASSERT();
filename = linker_basename(pathname);
- KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename));
+ KLD_DPF(FILE, ("linker_make_file: new file, filename='%s' for pathname='%s'\n", filename, pathname));
lf = (linker_file_t)kobj_create((kobj_class_t)lc, M_LINKER, M_WAITOK);
if (lf == NULL)
return (NULL);
@@ -542,9 +548,13 @@ linker_make_file(const char *pathname, linker_class_t lc)
lf->userrefs = 0;
lf->flags = 0;
lf->filename = linker_strdup(filename);
+ lf->pathname = linker_strdup(pathname);
LINKER_GET_NEXT_FILE_ID(lf->id);
lf->ndeps = 0;
lf->deps = NULL;
+ lf->loadcnt = ++loadcnt;
+ lf->sdt_probes = NULL;
+ lf->sdt_nprobes = 0;
STAILQ_INIT(&lf->common);
TAILQ_INIT(&lf->modules);
TAILQ_INSERT_TAIL(&linker_files, lf, link);
@@ -629,6 +639,10 @@ linker_file_unload(linker_file_t file, int flags)
free(file->filename, M_LINKER);
file->filename = NULL;
}
+ if (file->pathname) {
+ free(file->pathname, M_LINKER);
+ file->pathname = NULL;
+ }
kobj_delete((kobj_t) file, M_LINKER);
return (0);
}
@@ -920,7 +934,13 @@ kern_kldunload(struct thread *td, int fileid, int flags)
lf = linker_find_file_by_id(fileid);
if (lf) {
KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
- if (lf->userrefs == 0) {
+
+ /* Check if there are DTrace probes enabled on this file. */
+ if (lf->nenabled > 0) {
+ printf("kldunload: attempt to unload file that has"
+ " DTrace probes enabled\n");
+ error = EBUSY;
+ } else if (lf->userrefs == 0) {
/*
* XXX: maybe LINKER_UNLOAD_FORCE should override ?
*/
@@ -1041,15 +1061,18 @@ kldstat(struct thread *td, struct kldstat_args *uap)
{
struct kld_file_stat stat;
linker_file_t lf;
- int error, namelen;
+ int error, namelen, version, version_num;
/*
* Check the version of the user's structure.
*/
- error = copyin(uap->stat, &stat, sizeof(struct kld_file_stat));
- if (error)
+ if ((error = copyin(&uap->stat->version, &version, sizeof(version))) != 0)
return (error);
- if (stat.version != sizeof(struct kld_file_stat))
+ if (version == sizeof(struct kld_file_stat_1))
+ version_num = 1;
+ else if (version == sizeof(struct kld_file_stat))
+ version_num = 2;
+ else
return (EINVAL);
#ifdef MAC
@@ -1065,6 +1088,7 @@ kldstat(struct thread *td, struct kldstat_args *uap)
return (ENOENT);
}
+ /* Version 1 fields: */
namelen = strlen(lf->filename) + 1;
if (namelen > MAXPATHLEN)
namelen = MAXPATHLEN;
@@ -1073,11 +1097,18 @@ kldstat(struct thread *td, struct kldstat_args *uap)
stat.id = lf->id;
stat.address = lf->address;
stat.size = lf->size;
+ if (version_num > 1) {
+ /* Version 2 fields: */
+ namelen = strlen(lf->pathname) + 1;
+ if (namelen > MAXPATHLEN)
+ namelen = MAXPATHLEN;
+ bcopy(lf->pathname, &stat.pathname[0], namelen);
+ }
KLD_UNLOCK();
td->td_retval[0] = 0;
- return (copyout(&stat, uap->stat, sizeof(struct kld_file_stat)));
+ return (copyout(&stat, uap->stat, version));
}
int
OpenPOWER on IntegriCloud