Rethinking kernel module version dependencies..

John Baldwin 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
  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


More information about the freebsd-arch mailing list