summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2006-06-13 21:28:18 +0000
committerjhb <jhb@FreeBSD.org>2006-06-13 21:28:18 +0000
commit620ecf8adf926211b9da983579672c00b5d5a802 (patch)
tree270ece5e4c8f927d8af5127d49574476d55ef1b8 /sys
parent1484c04623030adaf78ecb33b2a2749b1bd877a4 (diff)
downloadFreeBSD-src-620ecf8adf926211b9da983579672c00b5d5a802.zip
FreeBSD-src-620ecf8adf926211b9da983579672c00b5d5a802.tar.gz
- Add a kern_kldload() that is most of the previous kldload() and push
Giant down in it. - Push Giant down in kern_kldunload() and reorganize it slightly to avoid using gotos. Also, expose this function to the rest of the kernel.
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/kern_linker.c86
-rw-r--r--sys/sys/syscallsubr.h2
2 files changed, 49 insertions, 39 deletions
diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c
index 3244dbb..23051c4 100644
--- a/sys/kern/kern_linker.c
+++ b/sys/kern/kern_linker.c
@@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <sys/libkern.h>
#include <sys/namei.h>
#include <sys/vnode.h>
+#include <sys/syscallsubr.h>
#include <sys/sysctl.h>
#include "linker_if.h"
@@ -745,45 +746,38 @@ linker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval)
* MPSAFE
*/
int
-kldload(struct thread *td, struct kldload_args *uap)
+kern_kldload(struct thread *td, const char *file, int *fileid)
{
#ifdef HWPMC_HOOKS
struct pmckern_map_in pkm;
#endif
- char *kldname, *modname;
- char *pathname = NULL;
+ const char *kldname, *modname;
linker_file_t lf;
- int error = 0;
-
- td->td_retval[0] = -1;
-
- mtx_lock(&Giant);
+ int error;
if ((error = securelevel_gt(td->td_ucred, 0)) != 0)
- goto out;
+ return (error);
if ((error = suser(td)) != 0)
- goto out;
-
- pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
- if ((error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL)) != 0)
- goto out;
+ return (error);
/*
- * If path do not contain qualified name or any dot in it
+ * If file does not contain qualified name or any dot in it
* (kldname.ko, or kldname.ver.ko) treat it as interface
* name.
*/
- if (index(pathname, '/') || index(pathname, '.')) {
- kldname = pathname;
+ if (index(file, '/') || index(file, '.')) {
+ kldname = file;
modname = NULL;
} else {
kldname = NULL;
- modname = pathname;
+ modname = file;
}
+
+ mtx_lock(&Giant);
error = linker_load_module(kldname, modname, NULL, NULL, &lf);
if (error)
- goto out;
+ goto unlock;
#ifdef HWPMC_HOOKS
pkm.pm_file = lf->filename;
@@ -791,18 +785,34 @@ kldload(struct thread *td, struct kldload_args *uap)
PMC_CALL_HOOK(td, PMC_FN_KLD_LOAD, (void *) &pkm);
#endif
lf->userrefs++;
- td->td_retval[0] = lf->id;
-out:
- if (pathname)
- free(pathname, M_TEMP);
+ if (fileid != NULL)
+ *fileid = lf->id;
+unlock:
mtx_unlock(&Giant);
return (error);
}
+int
+kldload(struct thread *td, struct kldload_args *uap)
+{
+ char *pathname = NULL;
+ int error;
+
+ td->td_retval[0] = -1;
+
+ pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
+ error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL);
+ if (error == 0)
+ error = kern_kldload(td, pathname, &td->td_retval[0]);
+
+ free(pathname, M_TEMP);
+ return (error);
+}
+
/*
* MPSAFE
*/
-static int
+int
kern_kldunload(struct thread *td, int fileid, int flags)
{
#ifdef HWPMC_HOOKS
@@ -811,14 +821,13 @@ kern_kldunload(struct thread *td, int fileid, int flags)
linker_file_t lf;
int error = 0;
- mtx_lock(&Giant);
-
if ((error = securelevel_gt(td->td_ucred, 0)) != 0)
- goto out;
+ return (error);
if ((error = suser(td)) != 0)
- goto out;
+ return (error);
+ mtx_lock(&Giant);
lf = linker_find_file_by_id(fileid);
if (lf) {
KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
@@ -828,18 +837,18 @@ kern_kldunload(struct thread *td, int fileid, int flags)
*/
printf("kldunload: attempt to unload file that was"
" loaded by the kernel\n");
- error = EBUSY;
- goto out;
- }
- lf->userrefs--;
+ error = EBUSY;
+ } else {
#ifdef HWPMC_HOOKS
- /* Save data needed by hwpmc(4) before unloading the kld. */
- pkm.pm_address = (uintptr_t) lf->address;
- pkm.pm_size = lf->size;
+ /* Save data needed by hwpmc(4) before unloading. */
+ pkm.pm_address = (uintptr_t) lf->address;
+ pkm.pm_size = lf->size;
#endif
- error = linker_file_unload(lf, flags);
- if (error)
- lf->userrefs++;
+ lf->userrefs--;
+ error = linker_file_unload(lf, flags);
+ if (error)
+ lf->userrefs++;
+ }
} else
error = ENOENT;
@@ -847,7 +856,6 @@ kern_kldunload(struct thread *td, int fileid, int flags)
if (error == 0)
PMC_CALL_HOOK(td, PMC_FN_KLD_UNLOAD, (void *) &pkm);
#endif
-out:
mtx_unlock(&Giant);
return (error);
}
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
index e6a228f..7329f6c 100644
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -86,6 +86,8 @@ int kern_getsockopt(struct thread *td, int s, int level, int name,
void *optval, enum uio_seg valseg, socklen_t *valsize);
int kern_kevent(struct thread *td, int fd, int nchanges, int nevents,
struct kevent_copyops *k_ops, const struct timespec *timeout);
+int kern_kldload(struct thread *td, const char *file, int *fileid);
+int kern_kldunload(struct thread *td, int fileid, int flags);
int kern_lchown(struct thread *td, char *path, enum uio_seg pathseg,
int uid, int gid);
int kern_link(struct thread *td, char *path, char *link,
OpenPOWER on IntegriCloud