summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2004-07-13 19:36:59 +0000
committerphk <phk@FreeBSD.org>2004-07-13 19:36:59 +0000
commitb0e68741889ab66096103a2dec2219bbde3c21c6 (patch)
treed2eb15e6477b3d5e7e1f7c49c1e2eed3b85ec318 /sys/kern
parent7b891087ed78b2c7943c2503f0bfdd7678a6d65c (diff)
downloadFreeBSD-src-b0e68741889ab66096103a2dec2219bbde3c21c6.zip
FreeBSD-src-b0e68741889ab66096103a2dec2219bbde3c21c6.tar.gz
Give kldunload a -f(orce) argument.
Add a MOD_QUIESCE event for modules. This should return error (EBUSY) of the module is in use. MOD_UNLOAD should now only fail if it is impossible (as opposed to inconvenient) to unload the module. Valid reasons are memory references into the module which cannot be tracked down and eliminated. When kldunloading, we abandon if MOD_UNLOAD fails, and if -force is not given, MOD_QUIESCE failing will also prevent the unload. For backwards compatibility, we treat EOPNOTSUPP from MOD_QUIESCE as success. Document that modules should return EOPNOTSUPP for unknown events.
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/init_sysent.c3
-rw-r--r--sys/kern/kern_linker.c49
-rw-r--r--sys/kern/kern_module.c8
-rw-r--r--sys/kern/link_elf.c4
-rw-r--r--sys/kern/link_elf_obj.c2
-rw-r--r--sys/kern/syscalls.c3
-rw-r--r--sys/kern/vfs_mount.c2
7 files changed, 53 insertions, 18 deletions
diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c
index 9d0ecad..1185cf8 100644
--- a/sys/kern/init_sysent.c
+++ b/sys/kern/init_sysent.c
@@ -3,7 +3,7 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: src/sys/kern/syscalls.master,v 1.174 2004/07/02 00:35:52 marcel Exp
+ * created from FreeBSD: src/sys/kern/syscalls.master,v 1.176 2004/07/13 19:35:10 phk Exp
*/
#include "opt_compat.h"
@@ -472,4 +472,5 @@ struct sysent sysent[] = {
{ SYF_MPSAFE | AS(ksem_timedwait_args), (sy_call_t *)lkmressys }, /* 441 = ksem_timedwait */
{ SYF_MPSAFE | AS(thr_suspend_args), (sy_call_t *)thr_suspend }, /* 442 = thr_suspend */
{ SYF_MPSAFE | AS(thr_wake_args), (sy_call_t *)thr_wake }, /* 443 = thr_wake */
+ { SYF_MPSAFE | AS(kldunloadf_args), (sy_call_t *)kldunloadf }, /* 444 = kldunloadf */
};
diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c
index 4ad549e..d2a2329 100644
--- a/sys/kern/kern_linker.c
+++ b/sys/kern/kern_linker.c
@@ -466,7 +466,7 @@ out:
}
int
-linker_file_unload(linker_file_t file)
+linker_file_unload(linker_file_t file, int flags)
{
module_t mod, next;
modlist_t ml, nextml;
@@ -500,7 +500,7 @@ linker_file_unload(linker_file_t file)
/*
* Give the module a chance to veto the unload.
*/
- if ((error = module_unload(mod)) != 0) {
+ if ((error = module_unload(mod, flags)) != 0) {
KLD_DPF(FILE, ("linker_file_unload: module %p"
" vetoes unload\n", mod));
goto out;
@@ -536,7 +536,7 @@ linker_file_unload(linker_file_t file)
if (file->deps) {
for (i = 0; i < file->ndeps; i++)
- linker_file_unload(file->deps[i]);
+ linker_file_unload(file->deps[i], flags);
free(file->deps, M_LINKER);
file->deps = NULL;
}
@@ -789,8 +789,8 @@ out:
/*
* MPSAFE
*/
-int
-kldunload(struct thread *td, struct kldunload_args *uap)
+static int
+kern_kldunload(struct thread *td, int fileid, int flags)
{
linker_file_t lf;
int error = 0;
@@ -803,17 +803,20 @@ kldunload(struct thread *td, struct kldunload_args *uap)
if ((error = suser(td)) != 0)
goto out;
- lf = linker_find_file_by_id(uap->fileid);
+ lf = linker_find_file_by_id(fileid);
if (lf) {
KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
if (lf->userrefs == 0) {
+ /*
+ * XXX: maybe LINKER_UNLOAD_FORCE should override ?
+ */
printf("kldunload: attempt to unload file that was"
" loaded by the kernel\n");
error = EBUSY;
goto out;
}
lf->userrefs--;
- error = linker_file_unload(lf);
+ error = linker_file_unload(lf, flags);
if (error)
lf->userrefs++;
} else
@@ -827,6 +830,29 @@ out:
* MPSAFE
*/
int
+kldunload(struct thread *td, struct kldunload_args *uap)
+{
+
+ return (kern_kldunload(td, uap->fileid, LINKER_UNLOAD_NORMAL));
+}
+
+/*
+ * MPSAFE
+ */
+int
+kldunloadf(struct thread *td, struct kldunloadf_args *uap)
+{
+
+ if (uap->flags != LINKER_UNLOAD_NORMAL &&
+ uap->flags != LINKER_UNLOAD_FORCE)
+ return (EINVAL);
+ return (kern_kldunload(td, uap->fileid, uap->flags));
+}
+
+/*
+ * MPSAFE
+ */
+int
kldfind(struct thread *td, struct kldfind_args *uap)
{
char *pathname;
@@ -1250,7 +1276,8 @@ restart:
nver) != NULL) {
printf("module %s already"
" present!\n", modname);
- linker_file_unload(lf);
+ linker_file_unload(lf,
+ LINKER_UNLOAD_FORCE);
TAILQ_REMOVE(&loaded_files,
lf, loaded);
/* we changed tailq next ptr */
@@ -1276,7 +1303,7 @@ restart:
*/
TAILQ_FOREACH(lf, &loaded_files, loaded) {
printf("KLD file %s is missing dependencies\n", lf->filename);
- linker_file_unload(lf);
+ linker_file_unload(lf, LINKER_UNLOAD_FORCE);
TAILQ_REMOVE(&loaded_files, lf, loaded);
}
@@ -1317,7 +1344,7 @@ restart:
if (error) {
printf("KLD file %s - could not finalize loading\n",
lf->filename);
- linker_file_unload(lf);
+ linker_file_unload(lf, LINKER_UNLOAD_FORCE);
continue;
}
linker_file_register_modules(lf);
@@ -1676,7 +1703,7 @@ linker_load_module(const char *kldname, const char *modname,
break;
if (modname && verinfo &&
modlist_lookup2(modname, verinfo) == NULL) {
- linker_file_unload(lfdep);
+ linker_file_unload(lfdep, LINKER_UNLOAD_FORCE);
error = ENOENT;
break;
}
diff --git a/sys/kern/kern_module.c b/sys/kern/kern_module.c
index 3832922..158612e 100644
--- a/sys/kern/kern_module.c
+++ b/sys/kern/kern_module.c
@@ -215,9 +215,15 @@ module_lookupbyid(int modid)
}
int
-module_unload(module_t mod)
+module_unload(module_t mod, int flags)
{
+ int error;
+ error = MOD_EVENT(mod, MOD_QUIESCE);
+ if (error == EOPNOTSUPP)
+ error = 0;
+ if (flags == LINKER_UNLOAD_NORMAL && error != 0)
+ return (error);
return (MOD_EVENT(mod, MOD_UNLOAD));
}
diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c
index 0f00d90..5679cbf 100644
--- a/sys/kern/link_elf.c
+++ b/sys/kern/link_elf.c
@@ -492,7 +492,7 @@ link_elf_link_preload(linker_class_t cls,
error = parse_dynamic(ef);
if (error) {
- linker_file_unload(lf);
+ linker_file_unload(lf, LINKER_UNLOAD_FORCE);
return error;
}
link_elf_reloc_local(lf);
@@ -846,7 +846,7 @@ nosyms:
out:
if (error && lf)
- linker_file_unload(lf);
+ linker_file_unload(lf, LINKER_UNLOAD_FORCE);
if (shdr)
free(shdr, M_LINKER);
if (firstpage)
diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c
index 9049880..e5fa30e 100644
--- a/sys/kern/link_elf_obj.c
+++ b/sys/kern/link_elf_obj.c
@@ -588,7 +588,7 @@ link_elf_load_file(linker_class_t cls, const char *filename,
out:
if (error && lf)
- linker_file_unload(lf);
+ linker_file_unload(lf, LINKER_UNLOAD_FORCE);
if (hdr)
free(hdr, M_LINKER);
VOP_UNLOCK(nd.ni_vp, 0, td);
diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c
index 202c7d1..9a2f795 100644
--- a/sys/kern/syscalls.c
+++ b/sys/kern/syscalls.c
@@ -3,7 +3,7 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: src/sys/kern/syscalls.master,v 1.174 2004/07/02 00:35:52 marcel Exp
+ * created from FreeBSD: src/sys/kern/syscalls.master,v 1.176 2004/07/13 19:35:10 phk Exp
*/
const char *syscallnames[] = {
@@ -451,4 +451,5 @@ const char *syscallnames[] = {
"ksem_timedwait", /* 441 = ksem_timedwait */
"thr_suspend", /* 442 = thr_suspend */
"thr_wake", /* 443 = thr_wake */
+ "kldunloadf", /* 444 = kldunloadf */
};
diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c
index d697499..cf7b7c1 100644
--- a/sys/kern/vfs_mount.c
+++ b/sys/kern/vfs_mount.c
@@ -799,7 +799,7 @@ vfs_domount(
break;
if (vfsp == NULL) {
lf->userrefs--;
- linker_file_unload(lf);
+ linker_file_unload(lf, LINKER_UNLOAD_FORCE);
vput(vp);
return (ENODEV);
}
OpenPOWER on IntegriCloud