Index: head/sys/kern/kern_linker.c =================================================================== --- head/sys/kern/kern_linker.c +++ head/sys/kern/kern_linker.c @@ -1599,7 +1599,6 @@ if (error) panic("cannot add dependency"); } - lf->userrefs++; /* so we can (try to) kldunload it */ error = linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, NULL); if (!error) { @@ -1637,6 +1636,8 @@ goto fail; } linker_file_register_modules(lf); + if (!TAILQ_EMPTY(&lf->modules)) + lf->flags |= LINKER_FILE_MODULES; if (linker_file_lookup_set(lf, "sysinit_set", &si_start, &si_stop, NULL) == 0) sysinit_add(si_start, si_stop); @@ -1654,6 +1655,41 @@ SYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0); /* + * Handle preload files that failed to load any modules. + */ +static void +linker_preload_finish(void *arg) +{ + linker_file_t lf, nlf; + + sx_xlock(&kld_sx); + TAILQ_FOREACH_SAFE(lf, &linker_files, link, nlf) { + /* + * If all of the modules in this file failed to load, unload + * the file and return an error of ENOEXEC. (Parity with + * linker_load_file.) + */ + if ((lf->flags & LINKER_FILE_MODULES) != 0 && + TAILQ_EMPTY(&lf->modules)) { + linker_file_unload(lf, LINKER_UNLOAD_FORCE); + continue; + } + + lf->flags &= ~LINKER_FILE_MODULES; + lf->userrefs++; /* so we can (try to) kldunload it */ + } + sx_xunlock(&kld_sx); +} + +/* + * Attempt to run after all DECLARE_MODULE SYSINITs. Unfortunately they can be + * scheduled at any subsystem and order, so run this as late as possible. init + * becomes runnable in SI_SUB_KTHREAD_INIT, so go slightly before that. + */ +SYSINIT(preload_finish, SI_SUB_KTHREAD_INIT - 100, SI_ORDER_MIDDLE, + linker_preload_finish, 0); + +/* * Search for a not-loaded module by name. * * Modules may be found in the following locations: Index: head/sys/sys/linker.h =================================================================== --- head/sys/sys/linker.h +++ head/sys/sys/linker.h @@ -73,6 +73,7 @@ int userrefs; /* kldload(2) count */ int flags; #define LINKER_FILE_LINKED 0x1 /* file has been fully linked */ +#define LINKER_FILE_MODULES 0x2 /* file has >0 modules at preload */ TAILQ_ENTRY(linker_file) link; /* list of all loaded files */ char* filename; /* file which was loaded */ char* pathname; /* file name with full path */