diff options
author | jhb <jhb@FreeBSD.org> | 2007-02-23 19:46:59 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2007-02-23 19:46:59 +0000 |
commit | a6f25664a878648fcaa79716a1e6c5ec08ac7210 (patch) | |
tree | d87f1348e6d4f24a18293aca216ffc2dbfc4c1f3 /sys | |
parent | bba840433b3f08288c876f56e328f15bd8214686 (diff) | |
download | FreeBSD-src-a6f25664a878648fcaa79716a1e6c5ec08ac7210.zip FreeBSD-src-a6f25664a878648fcaa79716a1e6c5ec08ac7210.tar.gz |
Drop the global kernel linker lock while executing the sysinit's for a
freshly-loaded kernel module. To avoid various unload races, hide linker
files whose sysinit's are being run from userland so that they can't be
kldunloaded until after all the sysinit's have finished.
Tested by: gallatin
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/kern_linker.c | 36 |
1 files changed, 21 insertions, 15 deletions
diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c index 6d0dd0f..e5c4caf 100644 --- a/sys/kern/kern_linker.c +++ b/sys/kern/kern_linker.c @@ -403,8 +403,10 @@ linker_load_file(const char *filename, linker_file_t *result) linker_file_unload(lf, LINKER_UNLOAD_FORCE); return (error); } + KLD_UNLOCK(); linker_file_register_sysctls(lf); linker_file_sysinit(lf); + KLD_LOCK(); lf->flags |= LINKER_FILE_LINKED; *result = lf; return (0); @@ -502,7 +504,7 @@ linker_find_file_by_id(int fileid) KLD_LOCK_ASSERT(); TAILQ_FOREACH(lf, &linker_files, link) - if (lf->id == fileid) + if (lf->id == fileid && lf->flags & LINKER_FILE_LINKED) break; return (lf); } @@ -1033,21 +1035,25 @@ kldnext(struct thread *td, struct kldnext_args *uap) #endif KLD_LOCK(); - if (uap->fileid == 0) { - if (TAILQ_FIRST(&linker_files)) - td->td_retval[0] = TAILQ_FIRST(&linker_files)->id; - else - td->td_retval[0] = 0; - goto out; + if (uap->fileid == 0) + lf = TAILQ_FIRST(&linker_files); + else { + lf = linker_find_file_by_id(uap->fileid); + if (lf == NULL) { + error = ENOENT; + goto out; + } + lf = TAILQ_NEXT(lf, link); } - lf = linker_find_file_by_id(uap->fileid); - if (lf) { - if (TAILQ_NEXT(lf, link)) - td->td_retval[0] = TAILQ_NEXT(lf, link)->id; - else - td->td_retval[0] = 0; - } else - error = ENOENT; + + /* Skip partially loaded files. */ + while (lf != NULL && !(lf->flags & LINKER_FILE_LINKED)) + lf = TAILQ_NEXT(lf, link); + + if (lf) + td->td_retval[0] = lf->id; + else + td->td_retval[0] = 0; out: KLD_UNLOCK(); return (error); |