Date: Tue, 22 Apr 2008 17:04:05 -0400 From: John Baldwin <jhb@freebsd.org> To: arch@freebsd.org Subject: Rethinking kernel module version dependencies.. Message-ID: <200804221704.05473.jhb@FreeBSD.org>
next in thread | raw e-mail | index | archive | help
So a while back I added the automatic kernel module version dependencies to HEAD where a given kernel module has a dependency on certain versions of __FreeBSD_version so that you can't kldload a 6.x module on a 7.x kernel, etc. However, the more I have thought about it, the more I think the current module version stuff is rather backwards. Specifically, the list of "supported" versions is not in the module providing the interface, but in all the client modules and I think this is backwards. So first off, some specific observations of what we have now: * A given module (or interface) has a single version (the current version). * In theory, we can apparently have multiple versions of the same module (the module dependency code supports this, and as a result we get non-useful error messages (kernel not found vs. kernel version not supported) when a version doesn't match). In practice, though, all the symbols live in a single global namespace AFAICT, so having multiple versions of a module would probably not work very well. * A client module lists a min version, a max version, and a preferred version and the module code attempts to match it to the "optimal" kernel module. * As a consequence, the current automatic kernel dependency stuff requires clients to assume they will work ok with future versions of the kernel with no way to revoke that. What stands out to me is that the model appears to be assuming that one would implement compatability for older versions of an interface/module by having a separate module with the older version. However, in other places in our existing code we don't follow that model. Instead, the newer version of the module includes its own compatiblity shims for the older version of the interface and provides both the old and new versions of the interface from a single module (as it were). For example, 'struct cdevsw' has a d_version field that is always set to the current interface version when it is compiled, and the cdevsw handling code in kern_conf.c can choose to support older versions by checking the version. With symbol versioning my understanding is that a single library will include symbols for all supported versions and that the client just specifies a single desired version of a given symbol that it requires. I'd like to change the kernel module versions to have the client modules just specify a single version (i.e. what I'm compiled against ala D_VERSION for cdevsw) and allow the kernel module declaration to specify a min,max version range. One thing I really like about this is that the modules now have control to specify exactly which interface versions they support (w/o having to have 1 MODULE_VERSION() per version). Specifically, I'd like to change the MODULE_DEPEND() and MODULE_VERSION() macros from: module implementation: MODULE_VERSION(foo, <current ver>); module client: MODULE_DEPEND(foo, <min ver>, <current ver>, <max ver>); to: module_implementation: MODULE_VERSION(foo, <min ver>, <current (max) ver>); module client: MODULE_DEPEND(foo, <current ver>); So in terms of a specific example, assume that you have a kernel with a version of 800100 and you compile a kernel module using that set of headers. The kernel currently says that it only supports version 800100. The kernel module says that it would work fine with any kernel version from 800100 to 899999. If for some reason you have a warranted ABI breakage (security hole, etc.) at 800200 then the module will still kldload ok even though it won't work and we have no easy way to prevent that. However, if you let the kernel specify the range, then instead you end up with the kernel saying that it supports versions 800000 - 800100 and the kernel module just says it wants to use version 800100. Normally the 800200 kernel would support versions of 800000 - 800200. However, if you did have an ABI breakage, then you could make the 800200 kernel have a different min version for when the ABI changed (e.g. a range of 800150 - 800200) and then the module would correctly fail to kldload. I'm not advocating ABI breakage per se, but I think that the module implementation should be the one to set the policy about which versions of an interface are supported and that a client should just specify which interface version it uses and not have to have knowledge about other interface versions. -- John Baldwin
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200804221704.05473.jhb>