From 9dec415fef268455335c088626d24f3cd5dd26fc Mon Sep 17 00:00:00 2001 From: jb Date: Mon, 22 Oct 2007 04:12:57 +0000 Subject: 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 --- sys/kern/kern_linker.c | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) (limited to 'sys/kern') 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 -- cgit v1.1