Author: cem
Date: Thu Oct 13 02:06:23 2016
New Revision: 307163
URL: https://svnweb.freebsd.org/changeset/base/307163

Log:
  kern_linker: Handle module-loading failures in preloaded .ko files
  
  The runtime kernel loader, linker_load_file, unloads kernel files that
  failed to load all of their modules. For consistency, treat preloaded
  (loader.conf loaded) kernel files in the same way.
  
  Reviewed by:  kib
  Sponsored by: Dell EMC Isilon
  Differential Revision:        https://reviews.freebsd.org/D8200

Modified:
  head/sys/kern/kern_linker.c
  head/sys/sys/linker.h

Modified: head/sys/kern/kern_linker.c
==============================================================================
--- head/sys/kern/kern_linker.c Thu Oct 13 01:58:49 2016        (r307162)
+++ head/sys/kern/kern_linker.c Thu Oct 13 02:06:23 2016        (r307163)
@@ -1599,7 +1599,6 @@ restart:
                        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 @@ restart:
                        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 @@ fail:
 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:

Modified: head/sys/sys/linker.h
==============================================================================
--- head/sys/sys/linker.h       Thu Oct 13 01:58:49 2016        (r307162)
+++ head/sys/sys/linker.h       Thu Oct 13 02:06:23 2016        (r307163)
@@ -73,6 +73,7 @@ struct linker_file {
     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 */
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to