From b8fb634afadea6b66e03f56e4d4c8e3bb6f12c8a Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Tue, 4 Aug 2009 16:58:09 -0700 Subject: [PATCH] kernel module loader - fix load dependencies from preload modules by kernel The boot loader is supposed to load module dependencies but it misses a few when e.g. 'snd_hda' is specified in loader.conf. This resulted in the kernel itself trying to load the missing dependencies, but the kernel was running the sysinits for those dependencies immediately during the preload stage instead of registering them. Pass a flag to the loader chain to register the sysinits instead of running them if a dependency is loaded during the preload stage. This fixes the problem. And also, by the way, the loader does not need to load dependencies any more (though it still does). Reported-by: corecode, swildner --- sys/kern/kern_linker.c | 48 +++++++++++++++++++++++++++------ sys/kern/link_aout.c | 21 ++++++++------- sys/kern/link_elf.c | 20 +++++++------- sys/kern/vfs_syscalls.c | 2 +- sys/netgraph/netgraph/ng_base.c | 2 +- sys/sys/linker.h | 8 ++++-- 6 files changed, 69 insertions(+), 32 deletions(-) diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c index 638b78eb91..6606a3c491 100644 --- a/sys/kern/kern_linker.c +++ b/sys/kern/kern_linker.c @@ -236,7 +236,7 @@ linker_file_unregister_sysctls(linker_file_t lf) } int -linker_load_file(const char* filename, linker_file_t* result) +linker_load_file(const char *filename, linker_file_t *result, int load_flags) { linker_class_t lc; linker_file_t lf; @@ -269,19 +269,51 @@ linker_load_file(const char* filename, linker_file_t* result) KLD_DPF(FILE, ("linker_load_file: trying to load %s as %s\n", filename, lc->desc)); - error = lc->ops->load_file(koname, &lf); /* First with .ko */ - if (lf == NULL && error == ENOENT) - error = lc->ops->load_file(filename, &lf); /* Then try without */ + /* First with .ko */ + error = lc->ops->load_file(koname, &lf, load_flags); + if (lf == NULL && error == ENOENT) { + /* Then try without */ + error = lc->ops->load_file(filename, &lf, load_flags); + } /* * If we got something other than ENOENT, then it exists but we cannot * load it for some other reason. */ if (error != ENOENT) foundfile = 1; + + /* + * Finish up. If this is part of a preload chain the sysinits + * have to be installed for later execution, otherwise we run + * them immediately. + */ if (lf) { - linker_file_register_sysctls(lf); - error = linker_file_sysinit(lf); + if (load_flags & LINKER_LOAD_FILE_PRELOAD) { + struct sysinit **si_start, **si_stop; + struct sysinit **sipp; + const moduledata_t *moddata; + + error = 0; + if (linker_file_lookup_set(lf, "sysinit_set", + &si_start, &si_stop, NULL) == 0) { + for (sipp = si_start; sipp < si_stop; sipp++) { + if ((*sipp)->func == module_register_init) { + moddata = (*sipp)->udata; + error = module_register(moddata, lf); + if (error) { + kprintf("Preloaded dependency \"%s\" " + "failed to register: %d\n", + koname, error); + } + } + } + sysinit_add(si_start, si_stop); + } + } else { + error = linker_file_sysinit(lf); + } + linker_file_register_sysctls(lf); *result = lf; goto out; } @@ -720,7 +752,7 @@ sys_kldload(struct kldload_args *uap) goto out; } - if ((error = linker_load_file(filename, &lf)) != 0) + if ((error = linker_load_file(filename, &lf, 0)) != 0) goto out; lf->userrefs++; @@ -1022,7 +1054,7 @@ linker_preload(void* arg) } lf = NULL; TAILQ_FOREACH(lc, &classes, link) { - error = lc->ops->load_file(modname, &lf); + error = lc->ops->load_file(modname, &lf, LINKER_LOAD_FILE_PRELOAD); if (error) { lf = NULL; break; diff --git a/sys/kern/link_aout.c b/sys/kern/link_aout.c index a8a7c604d9..69b0a82991 100644 --- a/sys/kern/link_aout.c +++ b/sys/kern/link_aout.c @@ -55,9 +55,9 @@ #include #include -static int link_aout_load_module(const char*, linker_file_t*); +static int link_aout_load_module(const char*, linker_file_t*,int); -static int link_aout_load_file(const char*, linker_file_t*); +static int link_aout_load_file(const char*, linker_file_t*,int); static int link_aout_lookup_symbol(linker_file_t, const char*, c_linker_sym_t*); @@ -94,7 +94,7 @@ typedef struct aout_file { struct _dynamic* dynamic; /* Symbol table etc. */ } *aout_file_t; -static int load_dependancies(linker_file_t lf); +static int load_dependancies(linker_file_t lf, int load_flags); static int relocate_file(linker_file_t lf); /* @@ -136,7 +136,8 @@ link_aout_init(void* arg) SYSINIT(link_aout, SI_BOOT2_KLD, SI_ORDER_THIRD, link_aout_init, 0); static int -link_aout_load_module(const char* filename, linker_file_t* result) +link_aout_load_module(const char *filename, linker_file_t *result, + int load_flags) { caddr_t modptr, baseptr; char *type; @@ -147,7 +148,7 @@ link_aout_load_module(const char* filename, linker_file_t* result) /* Look to see if we have the module preloaded. */ if ((modptr = preload_search_by_name(filename)) == NULL) - return(link_aout_load_file(filename, result)); + return(link_aout_load_file(filename, result, load_flags)); /* It's preloaded, check we can handle it and collect information. */ if (((type = (char *)preload_search_info(modptr, MODINFO_TYPE)) == NULL) || @@ -179,7 +180,7 @@ link_aout_load_module(const char* filename, linker_file_t* result) lf->size = ehdr->a_text + ehdr->a_data + ehdr->a_bss; /* Try to load dependancies */ - if (((error = load_dependancies(lf)) != 0) || + if (((error = load_dependancies(lf, load_flags)) != 0) || ((error = relocate_file(lf)) != 0)) { linker_file_unload(lf); return(error); @@ -190,7 +191,7 @@ link_aout_load_module(const char* filename, linker_file_t* result) } static int -link_aout_load_file(const char* filename, linker_file_t* result) +link_aout_load_file(const char *filename, linker_file_t *result, int load_flags) { struct nlookupdata nd; struct thread *td = curthread; @@ -276,7 +277,7 @@ link_aout_load_file(const char* filename, linker_file_t* result) lf->address = af->address; lf->size = header.a_text + header.a_data + header.a_bss; - if ((error = load_dependancies(lf)) != 0 + if ((error = load_dependancies(lf, load_flags)) != 0 || (error = relocate_file(lf)) != 0) { linker_file_unload(lf); goto out; @@ -318,7 +319,7 @@ link_aout_unload_module(linker_file_t file) #define AOUT_RELOC(af, type, off) (type*) ((af)->address + (off)) static int -load_dependancies(linker_file_t lf) +load_dependancies(linker_file_t lf, int load_flags) { aout_file_t af = lf->priv; linker_file_t lfdep; @@ -345,7 +346,7 @@ load_dependancies(linker_file_t lf) sodp = AOUT_RELOC(af, struct sod, off); name = AOUT_RELOC(af, char, sodp->sod_name); - error = linker_load_file(name, &lfdep); + error = linker_load_file(name, &lfdep, load_flags); if (error) goto out; linker_file_add_dependancy(lf, lfdep); diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c index 6a15cca369..575a54feb3 100644 --- a/sys/kern/link_elf.c +++ b/sys/kern/link_elf.c @@ -50,8 +50,8 @@ #include #include -static int link_elf_load_module(const char*, linker_file_t*); -static int link_elf_load_file(const char*, linker_file_t*); +static int link_elf_load_module(const char*, linker_file_t*, int); +static int link_elf_load_file(const char*, linker_file_t*, int); static int link_elf_lookup_symbol(linker_file_t, const char*, c_linker_sym_t*); static int link_elf_symbol_values(linker_file_t, c_linker_sym_t, linker_symval_t*); @@ -116,7 +116,7 @@ typedef struct elf_file { } *elf_file_t; static int parse_dynamic(linker_file_t lf); -static int load_dependancies(linker_file_t lf); +static int load_dependancies(linker_file_t lf, int load_flags); static int relocate_file(linker_file_t lf); static int parse_module_symbols(linker_file_t lf); @@ -321,7 +321,7 @@ link_elf_error(const char *s) } static int -link_elf_load_module(const char *filename, linker_file_t *result) +link_elf_load_module(const char *filename, linker_file_t *result, int load_flags) { caddr_t modptr, baseptr, sizeptr, dynptr; char *type; @@ -335,7 +335,7 @@ link_elf_load_module(const char *filename, linker_file_t *result) */ modptr = preload_search_by_name(filename); if (modptr == NULL) - return (link_elf_load_file(filename, result)); + return (link_elf_load_file(filename, result, load_flags)); /* It's preloaded, check we can handle it and collect information */ type = (char *)preload_search_info(modptr, MODINFO_TYPE); @@ -368,7 +368,7 @@ link_elf_load_module(const char *filename, linker_file_t *result) linker_file_unload(lf); return error; } - error = load_dependancies(lf); + error = load_dependancies(lf, load_flags); if (error) { linker_file_unload(lf); return error; @@ -385,7 +385,7 @@ link_elf_load_module(const char *filename, linker_file_t *result) } static int -link_elf_load_file(const char* filename, linker_file_t* result) +link_elf_load_file(const char* filename, linker_file_t* result, int load_flags) { struct nlookupdata nd; struct thread *td = curthread; /* XXX */ @@ -621,7 +621,7 @@ link_elf_load_file(const char* filename, linker_file_t* result) error = parse_dynamic(lf); if (error) goto out; - error = load_dependancies(lf); + error = load_dependancies(lf, load_flags); if (error) goto out; error = relocate_file(lf); @@ -725,7 +725,7 @@ link_elf_unload_module(linker_file_t file) } static int -load_dependancies(linker_file_t lf) +load_dependancies(linker_file_t lf, int load_flags) { elf_file_t ef = lf->priv; linker_file_t lfdep; @@ -745,7 +745,7 @@ load_dependancies(linker_file_t lf) if (dp->d_tag == DT_NEEDED) { name = ef->strtab + dp->d_un.d_val; - error = linker_load_file(name, &lfdep); + error = linker_load_file(name, &lfdep, load_flags); if (error) goto out; linker_file_add_dependancy(lf, lfdep); diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 3929ac3c84..40207fe1a6 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -273,7 +273,7 @@ sys_mount(struct mount_args *uap) vput(vp); return error; } - error = linker_load_file(fstypename, &lf); + error = linker_load_file(fstypename, &lf, 0); if (error || lf == NULL) { cache_drop(&nch); vput(vp); diff --git a/sys/netgraph/netgraph/ng_base.c b/sys/netgraph/netgraph/ng_base.c index 2d458d20d1..39de6503ff 100644 --- a/sys/netgraph/netgraph/ng_base.c +++ b/sys/netgraph/netgraph/ng_base.c @@ -334,7 +334,7 @@ ng_load_module(const char *name) ksnprintf(filename, sizeof(filename), "ng_%s.ko", name); if ((path = linker_search_path(filename)) == NULL) return (ENXIO); - error = linker_load_file(path, &lf); + error = linker_load_file(path, &lf, 0); FREE(path, M_LINKER); if (error == 0) lf->userrefs++; /* pretend kldload'ed */ diff --git a/sys/sys/linker.h b/sys/sys/linker.h index a7f8c780c5..081d319b91 100644 --- a/sys/sys/linker.h +++ b/sys/sys/linker.h @@ -134,9 +134,12 @@ struct linker_class_ops { * file and zero returned. If some other error is detected an * appropriate errno should be returned. */ - int (*load_file)(const char* filename, linker_file_t* result); + int (*load_file)(const char *filename, linker_file_t *result, + int load_flags); }; +#define LINKER_LOAD_FILE_PRELOAD 0x0001 + struct linker_class { TAILQ_ENTRY(linker_class) link; /* list of all file classes */ const char* desc; /* description (e.g. "a.out") */ @@ -165,7 +168,8 @@ int linker_add_class(const char* _desc, void* _priv, /* * Load a file, trying each file class until one succeeds. */ -int linker_load_file(const char* _filename, linker_file_t* _result); +int linker_load_file(const char *_filename, linker_file_t *_result, + int _load_flags); /* * Find a currently loaded file given its filename. -- 2.41.0