|
|
Subscribe / Log in / New account

Exported-symbol changes in 5.13

By Jonathan Corbet
May 17, 2021
There have been many disagreements over the years in the kernel community concerning the exporting of internal kernel symbols to loadable modules. Exporting a symbol often exposes implementation decisions to outside code, makes it possible to use (or abuse) kernel functionality in unintended ways, and makes future changes harder. That said, there is no authority overseeing the exporting of symbols and no process for approving exports; discussions only tend to arise when somebody notices a change that they don't like. But it is not particularly hard to detect changes in symbol exports from one kernel version to the next, and doing so can give some insights into the kinds of changes that are happening under the hood.

The kernel has many thousands of functions and data structures; most of those are private to a given source file, while others are made available to the kernel as a whole. Loadable modules are special, though; they only have access to symbols that have been explicitly exported to them with EXPORT_SYMBOL() (or one of a few variants); many symbols that are available to code built into the kernel image are unavailable to loadable modules. The intent of this limitation is to keep the interface to modules relatively narrow and manageable.

It is far from clear that this objective has been achieved, though. The 5.12 kernel exported 31,695 symbols to modules, which does not create an impression of a narrow interface. That number grew to 31,822 in 5.13-rc1. That is an increase of 127 symbols, but the actual story is a bit more complicated than that; 244 exported symbols were removed over this time, while 371 were added. The curious can see the full sets of added and removed symbols on this page.

Some changes qualify more as a renaming than a removal or an addition. For example, pmbus_do_probe() is no longer exported in 5.13, at least in that form; it is now listed (using a notation your editor made up on the spot) as PMBUS::pmbus_do_probe(). In other words, this symbol has been moved out of the global namespace into a subsystem-specific one. Namespacing for exported kernel symbols was added in 2018, but uptake has been relatively slow. The 5.13 kernel adds one new namespace (PMBUS) and that subsystem's exported symbols are moving into it. There are now 18 namespaces for symbols in the kernel:

CRYPTO_INTERNAL, FIRMWARE_LOADER_PRIVATE, LTC2497, MCB, NVME_TARGET_PASSTHRU, PMBUS, SND_INTEL_SOUNDWIRE_ACPI, SND_SOC_SOF_INTEL_HDA_COMMON, SND_SOC_SOF_MERRIFIELD, SND_SOC_SOF_HDA_AUDIO_CODEC, SND_SOC_SOF_HDA_AUDIO_CODEC_I915, SND_SOC_SOF_INTEL_HIFI_EP_IPC, SND_SOC_SOF_INTEL_HIFI_EP_IPC, SND_SOC_SOF_ACPI_DEV, SND_SOC_SOF_PCI_DEV, SND_SOC_SOF_XTENSA, SOUNDWIRE_INTEL_INIT, and TEST_FIRMWARE.

The sound subsystem has clearly been the most enthusiastic user of symbol namespaces thus far.

Many other changes in exported symbols are the result of code refactoring within the kernel. Some optimizations in the bit-finding library caused functions like find_first_bit() to be turned into inline functions in header files, which need not be exported. But they fall back to functions like _find_first_bit(), which now do need to be exported. The generic-sounding vmem_map symbol was specific to the ia64 architecture; it went away when ia64 dropped support for the VMEMMAP memory model. Various wimax_ symbols disappeared along with the unloved WiMAX drivers that exported them. Functions like rt_mutex_destroy() were deleted because they were unused.

Many of the new symbols correspond to new features; alloc_pages() came with batch page allocation, for example. Others are a bit less clear; what, for example, is dotdot_name? The commit that added this export explains it as "useful constants: struct qstr for '..'", which may be seen by some as less than fully enlightening. It provides a shortcut for filesystem code wanting to refer to directories named ".." without going to the trouble of wrapping it in the "quick string" structure used to pass strings around in the virtual filesystem layer. Several filesystems make use of it in 5.13.

As a general rule, kernel symbols should not be exported unless there is a user of them in the mainline kernel. That rule is generally respected, but there are exceptions. As an example, zynqmp_pm_pinctrl_get_function() was exported in 5.13-rc1, but has no in-kernel users. The other zynqmp_ (all related to functionality on Xilinx Zynq systems-on-chip) symbols that have been exported are not widely used and would be good candidates for hiding within their own namespace. Another exported-but-unused symbol is __cfi_slowpath_diag(), which is part of the Clang control-flow integrity implementation that was merged in this cycle. The reason for the exporting of this symbol is not entirely clear. __cpu_dying_mask() was also introduced and exported in 5.13 with no in-kernel users. There are many others as well; "export it just in case" seems to be a fairly common reflex for kernel developers.

The 5.13 kernel saw the addition of eleven devm_ exports, plus two with the internal __devm_ prefix. Not all of these are used either, but they do represent the type of symbol that one would expect to be exported to modules. These "managed device" functions are intended to make device drivers easier to write and safer by taking care of the freeing of allocated resources when a device is shut down. There are over 300 of these functions exported to modules now, and the list looks likely to continue to grow.

The direct rendering manager (DRM) graphics subsystem added 17 drm_ exports this time around. DRM is clearly one of the most complex driver APIs in the kernel, with no less than 850 exported symbols in 5.13. One begins to understand why the developers of this subsystem have prioritized documentation; this API would be unapproachable without it. That, of course, is a reflection of the problem space; graphics processors are complex devices.

Given that it requires nearly 32,000 exported symbols for a "limited" module interface, the kernel as a whole is also a complex environment. That complexity is reflected in the increasing size of the interface it offers to user space, but also in the growing interface it presents to loadable modules. This interface has increased significantly in size over the years, often without a lot of review. The good news is that, as an internal kernel interface, the set of exported symbols can be changed at any time. So perhaps this list might shrink someday, but that will not happen in the 5.13 cycle.

Index entries for this article
KernelModules/Exported symbols
KernelReleases/5.13


to post comments

Exported-symbol changes in 5.13

Posted May 18, 2021 9:36 UTC (Tue) by ColinIanKing (guest, #57499) [Link]

Sometimes one hits issues with macros that use inlined functions that have different EXPORT_SYMBOL behaviour on different architectures. For example, get_user() on powerpc was recently changed [1] to access mmu_feature_keys[] that is now an EXPORT_SYMBOL_GPL symbol. So some out of tree non-GPL'd kernel modules now fail to build because of this on a specific architecture. I don't believe there are any sanity checks on the kernel to check for these inconsistencies.

[1] 7613f5a66becfd0e43a0f34de8518695888f5458 ("powerpc/64s/kuap: Use mmu_has_feature()")


Copyright © 2021, Eklektix, Inc.
This article may be redistributed under the terms of the Creative Commons CC BY-SA 4.0 license
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds