(unknown charset) some questions on kern_linker and pre-loaded modules

From: (unknown charset) Andriy Gapon <avg_at_FreeBSD.org>
Date: Sat, 26 Jan 2013 13:52:01 +0200
I.
It seems that linker_preload checks a  module for being a duplicate module only
if the module has MDT_VERSION.

This is probably designed to allow different version of the same module to
co-exist (for some definition of co-exist)?

But, OTOH, this doesn't work well if the module is version-less (no
MODULE_VERSION in the code) and is pre-loaded twice (e.g. once in kernel and
once in a preloaded file).

At present a good example of this is zfsctrl module, which could be present both
in kernel (options ZFS) and in zfs.ko.

I haven't thought about any linker-level resolution for this issue.
I've just tried a plug the ZFS hole for now.

commit ed8b18f2d6c4d1be915bff94cdec0c51a479529f
Author: Andriy Gapon <avg_at_icyb.net.ua>
Date:   Wed Dec 19 23:29:23 2012 +0200

    [bugfix] zfs: add MODULE_VERSION for zfsctrl

    This should allow the kernel linker to easily detect a situation
    when the module is present both in a kernel and in a preloaded file (zfs.ko).

diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
index 10d28c2..5721010 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
_at__at_ -5599,6 +5599,7 _at__at_ static moduledata_t zfs_mod = {
 	0
 };
 DECLARE_MODULE(zfsctrl, zfs_mod, SI_SUB_VFS, SI_ORDER_ANY);
+MODULE_VERSION(zfsctrl, 1);
 MODULE_DEPEND(zfsctrl, opensolaris, 1, 1, 1);
 MODULE_DEPEND(zfsctrl, krpc, 1, 1, 1);
 MODULE_DEPEND(zfsctrl, acl_nfs4, 1, 1, 1);


II.
It seems that linker_file_register_modules() for the kernel is called after
linker_file_register_modules() is called for all the pre-loaded files.
linker_file_register_modules() for the kernel is called from
linker_init_kernel_modules via SYSINIT(SI_SUB_KLD, SI_ORDER_ANY) and that
happens after linker_preload() which is executed via SYSINIT(SI_SUB_KLD,
SI_ORDER_MIDDLE).

Perhaps this is designed to allow modules in the preloaded files to override
modules compiled into the kernel?

But this doesn't seem to work well.
Because modules from the kernel are not registered yet,
linker_file_register_modules() would be successful for the duplicate modules in
a preloaded file and thus any sysinits present in the file will also be registered.
So, if the module is present both in the kernel and in the preloaded file and
the module has a module event handler (modeventhand_t), then the handler will
registered and called twice.

I cobbled together the following hack, but I am not sure if it is OK or if it
violates fundamental architecture/design of this subsystem.

commit 14ebf07633d0f0ea393801c3e4161d6c37393661
Author: Andriy Gapon <avg_at_icyb.net.ua>
Date:   Wed Dec 19 23:27:46 2012 +0200

    [wip][experiment] kernel linker: register kernel modules before preloaded
modules...

    Also, skip adding sysinit and sysctl stuff from preloaded modules if module
    registration fails.

    This should result in much saner behavior if a module is present in both
    the kernel and a preloaded file.
    Perhaps, the original intent was to allow the preloaded files to override
    modules present in kernel, but that was extremly fragile because of double
    sysinit registration.

diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c
index b3ab4df..be46cdf 100644
--- a/sys/kern/kern_linker.c
+++ b/sys/kern/kern_linker.c
_at__at_ -365,6 +365,7 _at__at_ linker_file_register_modules(linker_file_t lf)
 	return (first_error);
 }

+#if 0
 static void
 linker_init_kernel_modules(void)
 {
_at__at_ -374,6 +375,7 _at__at_ linker_init_kernel_modules(void)

 SYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules,
     0);
+#endif

 static int
 linker_load_file(const char *filename, linker_file_t *result)
_at__at_ -1599,7 +1601,11 _at__at_ restart:
 		printf("KLD file %s is missing dependencies\n", lf->filename);
 		linker_file_unload(lf, LINKER_UNLOAD_FORCE);
 	}
-
+#if 1
+	error = linker_file_register_modules(linker_kernel_file);
+	if (error)
+		printf("linker_file_register_modules(linker_kernel_file) failed: %d\n", error);
+#endif
 	/*
 	 * We made it. Finish off the linking in the order we determined.
 	 */
_at__at_ -1642,13 +1648,15 _at__at_ restart:
 		 * Now do relocation etc using the symbol search paths
 		 * established by the dependencies
 		 */
+		error = linker_file_register_modules(lf);
+		if (error)
+			goto fail;
 		error = LINKER_LINK_PRELOAD_FINISH(lf);
 		if (error) {
 			printf("KLD file %s - could not finalize loading\n",
 			    lf->filename);
 			goto fail;
 		}
-		linker_file_register_modules(lf);
 		if (linker_file_lookup_set(lf, "sysinit_set", &si_start,
 		    &si_stop, NULL) == 0)
 			sysinit_add(si_start, si_stop);

-- 
Andriy Gapon
Received on Sat Jan 26 2013 - 10:52:08 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:40:34 UTC