Building header files into the kernel

Benefits for LWN subscribers The primary benefit from subscribing to LWN is helping to keep us publishing, but, beyond that, subscribers get immediate access to all site content and access to a number of extra site features. Please sign up today!

Kernel developers learn, one way or another, to be careful about memory use; any memory taken by the kernel is not available for use by the actual applications that people keep the computer around to run. So it is unsurprising that eyebrows went up when Joel Fernandes proposed building the source for all of the kernel's headers files into the kernel itself, at a cost of nearly 4MB of unswappable, kernel-space memory. The discussion is ongoing, but it has already highlighted some pain points felt by Android developers in particular.

Fernandes first posted this work in January; version 5 was posted on March 20. As part of the build process, it gathers up all of the kernel's headers (the " .h " files) and a few other artifacts into a compressed tar file; that file is then built into a kernel module. If that module is loaded into the running kernel, the tar file containing the headers can be read from /proc/kheaders.tgz . This is, thus, a way of allowing applications to access the header files that were used to build whatever kernel is running at the moment.

The purpose of this mechanism is to make those header files available in situations where they are otherwise unavailable. In particular, developers building kernel modules need access to this information, as do those who are building BPF programs to analyze a system's behavior. In some systems, notably Android-based devices, those header files are almost certainly not easily available. Fernandes has tried other solutions to this problem, such as BPFd, in the past, but all have fallen short. Providing headers with the kernel itself is the solution he has settled on.

Some of the initial reviews were less than entirely favorable; Christoph Hellwig described it as "a pretty horrible idea and waste of kernel memory" while Alexey Dobriyan said that it was "gross". H. Peter Anvin also questioned the memory use and suggested that the data should, at a minimum, be stored in a swappable filesystem. Numerous others chimed in as well, describing the work as a "hack" and saying that, rather than building the tar file into a kernel module, it would be far more straightforward to just place that file in the module directory where it could be read directly. At the same time, a number of other developers have indicated that this feature would be useful; Daniel Colascione even asked whether it could be expanded to hold all of the kernel source.

Nobody seems to disagree with the overall objective of this work. There are times when the kernel headers are needed for development, but those headers tend to be absent on systems like Android. The disagreement is over the idea of building those headers into the kernel itself. This opposition is easy enough to understand; the kernel itself does not need that information to function, so there would have to be a strong reason indeed to sacrifice that much system memory to hold it in kernel space.

There are indeed reasons for doing so, many of which seem to come down to how Android systems are built rather than something more technical. It would be nice if Android simply had a "kernel headers" package but, as Fernandes explained, that is not really practical:

In the Android ecosystem, the Android teams only provide a "userspace system image" which goes on the system partition of the flash. This image is not GPL and doesn't contain anything GPL. It is thus not possible to put kernel headers on the system image and I already had many discussions on the subject with the teams, it is something that is just not done. Now for kernel modules, there's another image called the "vendor image" which is flashed onto the vendor partition, this is where kernel modules go. This vendor image is not provided by Google for non-Pixel devices. So we have no control over what goes there.

The seeming aversion to putting anything GPL-licensed into the system image rubs some developers the wrong way, but it is consistent with the GPL avoidance practiced in most of the Android system. There is another reason why putting the kernel headers there is not a complete solution, though: developers will often cross-build a kernel and ship it to a device for direct booting with the fastboot command. Any headers stored on the device itself will not match that new kernel, so they are useless at best. If the headers are built into the kernel itself, though, they will transfer to the device with that kernel and always be correct.

Even for kernels shipped with devices, though, the "store the headers in the filesystem" solution is problematic. As Fernandes noted, the Android project does not have much control over what vendors put onto their devices or where it goes, so it would be difficult (if not impossible) to mandate the presence of the kernel headers in any sort of standard location. Android can, though, mandate that specific kernel configuration options must be set; with this patch merged, vendors could be made to ship the headers for their kernels in a place where they could always be found. Even if vendors tend to hide their kernel modules in strange places (and they are vendors, so of course they do), the user space code on any given device knows how to find and load them.

In other words, building this information into the kernel is, among other things, a technical solution to the social problem of getting vendors to provide that information in a consistent way. Sometimes such solutions can be what is needed. As Colascione put it: "here's the bottom line: without this work, doing certain kinds of system tracing is a nightmare, and with this patch, it Just Works". Or, as Karim Yaghmour described it:

That, in my view, is a big part of the problem Joel's patch solves: in a system whose functionality requires multiple *independent* parties to work together, I can still get the necessary kernel headers for user-space tools to properly operate regardless of which part of the system is being substituted or replaced.

Proponents argue that, since the information is built into a kernel module, it can be configured out (or simply not loaded) when it is not needed. Anvin worried, though, that mechanisms like this tend to grow into a mandatory role over time.

One associated question is whether providing kernel header files is the best way to provide the needed information to user space. Steve Rostedt said that he would rather have a table describing the kernel's structures, including the offset, size, and type of each field. That is the information that is actually needed much of the time, and it could be more compact than the source code is. Colascione sympathized with the desire for a cleaner format, but argued that it would be better to go with what works now: "Think of the headers as encoding this information and more and the C compiler as a magical decoder ring". Header files also include macros, constant definitions, and other information needed to build BPF programs.

The discussion has gone on at length, provoked anew by each new posting of the patch set. It does not appear to have changed a lot of minds on either side of the debate. Sooner or later, presumably as the 5.2 merge window approaches, somebody (most likely Andrew Morton) will have to make a decision. Given the evident advantages from this patch set, it seems likely that Android kernels may ship it regardless, so it may be mostly a matter of whether the mainline follows suit.

