Rethinking kernel module version dependencies..
jhb at freebsd.org
Tue Apr 22 21:04:34 UTC 2008
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
* 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_VERSION(foo, <current ver>);
MODULE_DEPEND(foo, <min ver>, <current ver>, <max ver>);
MODULE_VERSION(foo, <min ver>, <current (max) ver>);
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
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
More information about the freebsd-arch