Modules updates for v5.4
Summary of modules changes for the 5.4 merge window: - Introduce exported symbol namespaces. This new feature allows subsystem maintainers to partition and categorize their exported symbols into explicit namespaces. Module authors are now required to import the namespaces they need. Some of the main motivations of this feature include: allowing kernel developers to better manage the export surface, allow subsystem maintainers to explicitly state that usage of some exported symbols should only be limited to certain users (think: inter-module or inter-driver symbols, debugging symbols, etc), as well as more easily limiting the availability of namespaced symbols to other parts of the kernel. With the module import requirement, it is also easier to spot the misuse of exported symbols during patch review. Two new macros are introduced: EXPORT_SYMBOL_NS() and EXPORT_SYMBOL_NS_GPL(). The API is thoroughly documented in Documentation/kbuild/namespaces.rst. - Some small code and kbuild cleanups here and there. -----BEGIN PGP SIGNATURE----- iQIcBAABCgAGBQJdh3n8AAoJEMBFfjjOO8Fy94kP+QHZF39QDvLbxAzEYAETAS+o CFu6wix/DrAwFkTU/kX1eAsAwDBEz0xkMciR4BsLX3sIafUVERxtDXVAui/dA1+6 zfw2c3ObyVwPEk6aUPFprgkj+08gxujsJFlYTsQQUhtRbmxg6R7hD6t6ANxiHaY2 AQe5TzOWXoIa2hHO+7rPMqf8l6qiFCaL0s3v5jrmBXa5mHmc4PVy95h1J6xQVw2u b+SlvKeylHv+OtCtvthkAJS3hfS35J/1TNb/RNYIvh60IfEguEuFsGuQ9JiSSAZS pv1cJ+I5d4v8Y/md1rZpdjTJL9gCrq/UUC67+UkejCOn0C+7XM2eR4Bu/jWvdMSn ZQDHcPhFSIfmP7FaKomPogaBbw1sI1FvM5930pPJzHnyO9+cefBXe7rWaaB+y0At GAxOtmk1dKh01BT7YO/C0oVuX87csWd74NHypVsbs0TgQo5jBFdZRheyDrq5YB+s tVK+5H0nqQrCcfo/TvhcsZlgITTGtgTPenaW99/i7qNa9mRUtxC/VkE+aob6HNRF 1iBxxopOTxGN8akyKOVumtkuTQH3EJfouZee//pWbXLzyDmScg/k67vuao8kxbyq NA1piFAGJAHFsHATxrbvNOq6jZ5bfUT8pwSTs83JppuR++8Hxk7zaShS3/LvsvHt 6ist/epOwTZ7oiNQ04nj =72Uy -----END PGP SIGNATURE----- Merge tag 'modules-for-v5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux Pull modules updates from Jessica Yu: "The main bulk of this pull request introduces a new exported symbol namespaces feature. The number of exported symbols is increasingly growing with each release (we're at about 31k exports as of 5.3-rc7) and we currently have no way of visualizing how these symbols are "clustered" or making sense of this huge export surface. Namespacing exported symbols allows kernel developers to more explicitly partition and categorize exported symbols, as well as more easily limiting the availability of namespaced symbols to other parts of the kernel. For starters, we have introduced the USB_STORAGE namespace to demonstrate the API's usage. I have briefly summarized the feature and its main motivations in the tag below. Summary: - Introduce exported symbol namespaces. This new feature allows subsystem maintainers to partition and categorize their exported symbols into explicit namespaces. Module authors are now required to import the namespaces they need. Some of the main motivations of this feature include: allowing kernel developers to better manage the export surface, allow subsystem maintainers to explicitly state that usage of some exported symbols should only be limited to certain users (think: inter-module or inter-driver symbols, debugging symbols, etc), as well as more easily limiting the availability of namespaced symbols to other parts of the kernel. With the module import requirement, it is also easier to spot the misuse of exported symbols during patch review. Two new macros are introduced: EXPORT_SYMBOL_NS() and EXPORT_SYMBOL_NS_GPL(). The API is thoroughly documented in Documentation/kbuild/namespaces.rst. - Some small code and kbuild cleanups here and there" * tag 'modules-for-v5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux: module: Remove leftover '#undef' from export header module: remove unneeded casts in cmp_name() module: move CONFIG_UNUSED_SYMBOLS to the sub-menu of MODULES module: remove redundant 'depends on MODULES' module: Fix link failure due to invalid relocation on namespace offset usb-storage: export symbols in USB_STORAGE namespace usb-storage: remove single-use define for debugging docs: Add documentation for Symbol Namespaces scripts: Coccinelle script for namespace dependencies. modpost: add support for generating namespace dependencies export: allow definition default namespaces in Makefiles or sources module: add config option MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS modpost: add support for symbol namespaces module: add support for symbol namespaces. export: explicitly align struct kernel_symbol module: support reading multiple values per modinfo tag
This commit is contained in:
commit
e070355664
|
@ -32,6 +32,7 @@
|
|||
*.lzo
|
||||
*.mod
|
||||
*.mod.c
|
||||
*.ns_deps
|
||||
*.o
|
||||
*.o.*
|
||||
*.patch
|
||||
|
|
|
@ -470,9 +470,12 @@ build.
|
|||
|
||||
The syntax of the Module.symvers file is::
|
||||
|
||||
<CRC> <Symbol> <module>
|
||||
<CRC> <Symbol> <Namespace> <Module> <Export Type>
|
||||
|
||||
0x2d036834 scsi_remove_host drivers/scsi/scsi_mod
|
||||
0xe1cc2a05 usb_stor_suspend USB_STORAGE drivers/usb/storage/usb-storage EXPORT_SYMBOL_GPL
|
||||
|
||||
The fields are separated by tabs and values may be empty (e.g.
|
||||
if no namespace is defined for an exported symbol).
|
||||
|
||||
For a kernel build without CONFIG_MODVERSIONS enabled, the CRC
|
||||
would read 0x00000000.
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
=================
|
||||
Symbol Namespaces
|
||||
=================
|
||||
|
||||
The following document describes how to use Symbol Namespaces to structure the
|
||||
export surface of in-kernel symbols exported through the family of
|
||||
EXPORT_SYMBOL() macros.
|
||||
|
||||
.. Table of Contents
|
||||
|
||||
=== 1 Introduction
|
||||
=== 2 How to define Symbol Namespaces
|
||||
--- 2.1 Using the EXPORT_SYMBOL macros
|
||||
--- 2.2 Using the DEFAULT_SYMBOL_NAMESPACE define
|
||||
=== 3 How to use Symbols exported in Namespaces
|
||||
=== 4 Loading Modules that use namespaced Symbols
|
||||
=== 5 Automatically creating MODULE_IMPORT_NS statements
|
||||
|
||||
1. Introduction
|
||||
===============
|
||||
|
||||
Symbol Namespaces have been introduced as a means to structure the export
|
||||
surface of the in-kernel API. It allows subsystem maintainers to partition
|
||||
their exported symbols into separate namespaces. That is useful for
|
||||
documentation purposes (think of the SUBSYSTEM_DEBUG namespace) as well as for
|
||||
limiting the availability of a set of symbols for use in other parts of the
|
||||
kernel. As of today, modules that make use of symbols exported into namespaces,
|
||||
are required to import the namespace. Otherwise the kernel will, depending on
|
||||
its configuration, reject loading the module or warn about a missing import.
|
||||
|
||||
2. How to define Symbol Namespaces
|
||||
==================================
|
||||
|
||||
Symbols can be exported into namespace using different methods. All of them are
|
||||
changing the way EXPORT_SYMBOL and friends are instrumented to create ksymtab
|
||||
entries.
|
||||
|
||||
2.1 Using the EXPORT_SYMBOL macros
|
||||
==================================
|
||||
|
||||
In addition to the macros EXPORT_SYMBOL() and EXPORT_SYMBOL_GPL(), that allow
|
||||
exporting of kernel symbols to the kernel symbol table, variants of these are
|
||||
available to export symbols into a certain namespace: EXPORT_SYMBOL_NS() and
|
||||
EXPORT_SYMBOL_NS_GPL(). They take one additional argument: the namespace.
|
||||
Please note that due to macro expansion that argument needs to be a
|
||||
preprocessor symbol. E.g. to export the symbol `usb_stor_suspend` into the
|
||||
namespace `USB_STORAGE`, use::
|
||||
|
||||
EXPORT_SYMBOL_NS(usb_stor_suspend, USB_STORAGE);
|
||||
|
||||
The corresponding ksymtab entry struct `kernel_symbol` will have the member
|
||||
`namespace` set accordingly. A symbol that is exported without a namespace will
|
||||
refer to `NULL`. There is no default namespace if none is defined. `modpost`
|
||||
and kernel/module.c make use the namespace at build time or module load time,
|
||||
respectively.
|
||||
|
||||
2.2 Using the DEFAULT_SYMBOL_NAMESPACE define
|
||||
=============================================
|
||||
|
||||
Defining namespaces for all symbols of a subsystem can be very verbose and may
|
||||
become hard to maintain. Therefore a default define (DEFAULT_SYMBOL_NAMESPACE)
|
||||
is been provided, that, if set, will become the default for all EXPORT_SYMBOL()
|
||||
and EXPORT_SYMBOL_GPL() macro expansions that do not specify a namespace.
|
||||
|
||||
There are multiple ways of specifying this define and it depends on the
|
||||
subsystem and the maintainer's preference, which one to use. The first option
|
||||
is to define the default namespace in the `Makefile` of the subsystem. E.g. to
|
||||
export all symbols defined in usb-common into the namespace USB_COMMON, add a
|
||||
line like this to drivers/usb/common/Makefile::
|
||||
|
||||
ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=USB_COMMON
|
||||
|
||||
That will affect all EXPORT_SYMBOL() and EXPORT_SYMBOL_GPL() statements. A
|
||||
symbol exported with EXPORT_SYMBOL_NS() while this definition is present, will
|
||||
still be exported into the namespace that is passed as the namespace argument
|
||||
as this argument has preference over a default symbol namespace.
|
||||
|
||||
A second option to define the default namespace is directly in the compilation
|
||||
unit as preprocessor statement. The above example would then read::
|
||||
|
||||
#undef DEFAULT_SYMBOL_NAMESPACE
|
||||
#define DEFAULT_SYMBOL_NAMESPACE USB_COMMON
|
||||
|
||||
within the corresponding compilation unit before any EXPORT_SYMBOL macro is
|
||||
used.
|
||||
|
||||
3. How to use Symbols exported in Namespaces
|
||||
============================================
|
||||
|
||||
In order to use symbols that are exported into namespaces, kernel modules need
|
||||
to explicitly import these namespaces. Otherwise the kernel might reject to
|
||||
load the module. The module code is required to use the macro MODULE_IMPORT_NS
|
||||
for the namespaces it uses symbols from. E.g. a module using the
|
||||
usb_stor_suspend symbol from above, needs to import the namespace USB_STORAGE
|
||||
using a statement like::
|
||||
|
||||
MODULE_IMPORT_NS(USB_STORAGE);
|
||||
|
||||
This will create a `modinfo` tag in the module for each imported namespace.
|
||||
This has the side effect, that the imported namespaces of a module can be
|
||||
inspected with modinfo::
|
||||
|
||||
$ modinfo drivers/usb/storage/ums-karma.ko
|
||||
[...]
|
||||
import_ns: USB_STORAGE
|
||||
[...]
|
||||
|
||||
|
||||
It is advisable to add the MODULE_IMPORT_NS() statement close to other module
|
||||
metadata definitions like MODULE_AUTHOR() or MODULE_LICENSE(). Refer to section
|
||||
5. for a way to create missing import statements automatically.
|
||||
|
||||
4. Loading Modules that use namespaced Symbols
|
||||
==============================================
|
||||
|
||||
At module loading time (e.g. `insmod`), the kernel will check each symbol
|
||||
referenced from the module for its availability and whether the namespace it
|
||||
might be exported to has been imported by the module. The default behaviour of
|
||||
the kernel is to reject loading modules that don't specify sufficient imports.
|
||||
An error will be logged and loading will be failed with EINVAL. In order to
|
||||
allow loading of modules that don't satisfy this precondition, a configuration
|
||||
option is available: Setting MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS=y will
|
||||
enable loading regardless, but will emit a warning.
|
||||
|
||||
5. Automatically creating MODULE_IMPORT_NS statements
|
||||
=====================================================
|
||||
|
||||
Missing namespaces imports can easily be detected at build time. In fact,
|
||||
modpost will emit a warning if a module uses a symbol from a namespace
|
||||
without importing it.
|
||||
MODULE_IMPORT_NS() statements will usually be added at a definite location
|
||||
(along with other module meta data). To make the life of module authors (and
|
||||
subsystem maintainers) easier, a script and make target is available to fixup
|
||||
missing imports. Fixing missing imports can be done with::
|
||||
|
||||
$ make nsdeps
|
||||
|
||||
A typical scenario for module authors would be::
|
||||
|
||||
- write code that depends on a symbol from a not imported namespace
|
||||
- `make`
|
||||
- notice the warning of modpost telling about a missing import
|
||||
- run `make nsdeps` to add the import to the correct code location
|
||||
|
||||
For subsystem maintainers introducing a namespace, the steps are very similar.
|
||||
Again, `make nsdeps` will eventually add the missing namespace imports for
|
||||
in-tree modules::
|
||||
|
||||
- move or add symbols to a namespace (e.g. with EXPORT_SYMBOL_NS())
|
||||
- `make` (preferably with an allmodconfig to cover all in-kernel
|
||||
modules)
|
||||
- notice the warning of modpost telling about a missing import
|
||||
- run `make nsdeps` to add the import to the correct code location
|
||||
|
|
@ -594,6 +594,24 @@ internal implementation issue, and not really an interface. Some
|
|||
maintainers and developers may however require EXPORT_SYMBOL_GPL()
|
||||
when adding any new APIs or functionality.
|
||||
|
||||
:c:func:`EXPORT_SYMBOL_NS()`
|
||||
----------------------------
|
||||
|
||||
Defined in ``include/linux/export.h``
|
||||
|
||||
This is the variant of `EXPORT_SYMBOL()` that allows specifying a symbol
|
||||
namespace. Symbol Namespaces are documented in
|
||||
``Documentation/kbuild/namespaces.rst``.
|
||||
|
||||
:c:func:`EXPORT_SYMBOL_NS_GPL()`
|
||||
--------------------------------
|
||||
|
||||
Defined in ``include/linux/export.h``
|
||||
|
||||
This is the variant of `EXPORT_SYMBOL_GPL()` that allows specifying a symbol
|
||||
namespace. Symbol Namespaces are documented in
|
||||
``Documentation/kbuild/namespaces.rst``.
|
||||
|
||||
Routines and Conventions
|
||||
========================
|
||||
|
||||
|
|
|
@ -11523,6 +11523,11 @@ S: Maintained
|
|||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/wtarreau/nolibc.git
|
||||
F: tools/include/nolibc/
|
||||
|
||||
NSDEPS
|
||||
M: Matthias Maennich <maennich@google.com>
|
||||
S: Maintained
|
||||
F: scripts/nsdeps
|
||||
|
||||
NTB AMD DRIVER
|
||||
M: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
|
||||
L: linux-ntb@googlegroups.com
|
||||
|
|
14
Makefile
14
Makefile
|
@ -1498,6 +1498,9 @@ help:
|
|||
@echo ' headerdep - Detect inclusion cycles in headers'
|
||||
@echo ' coccicheck - Check with Coccinelle'
|
||||
@echo ''
|
||||
@echo 'Tools:'
|
||||
@echo ' nsdeps - Generate missing symbol namespace dependencies'
|
||||
@echo ''
|
||||
@echo 'Kernel selftest:'
|
||||
@echo ' kselftest - Build and run kernel selftest (run as root)'
|
||||
@echo ' Build, install, and boot kernel before'
|
||||
|
@ -1679,7 +1682,7 @@ clean: $(clean-dirs)
|
|||
-o -name '*.ko.*' \
|
||||
-o -name '*.dtb' -o -name '*.dtb.S' -o -name '*.dt.yaml' \
|
||||
-o -name '*.dwo' -o -name '*.lst' \
|
||||
-o -name '*.su' -o -name '*.mod' \
|
||||
-o -name '*.su' -o -name '*.mod' -o -name '*.ns_deps' \
|
||||
-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
|
||||
-o -name '*.lex.c' -o -name '*.tab.[ch]' \
|
||||
-o -name '*.asn1.[ch]' \
|
||||
|
@ -1697,6 +1700,15 @@ quiet_cmd_tags = GEN $@
|
|||
tags TAGS cscope gtags: FORCE
|
||||
$(call cmd,tags)
|
||||
|
||||
# Script to generate missing namespace dependencies
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
PHONY += nsdeps
|
||||
|
||||
nsdeps: modules
|
||||
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost nsdeps
|
||||
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/$@
|
||||
|
||||
# Scripts to check various things for consistency
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
#define KSYM_ALIGN 2
|
||||
#define KCRC_ALIGN 2
|
||||
#include <asm-generic/export.h>
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
ccflags-y := -I $(srctree)/drivers/scsi
|
||||
|
||||
ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=USB_STORAGE
|
||||
|
||||
obj-$(CONFIG_USB_UAS) += uas.o
|
||||
obj-$(CONFIG_USB_STORAGE) += usb-storage.o
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
MODULE_DESCRIPTION("Driver for Alauda-based card readers");
|
||||
MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(USB_STORAGE);
|
||||
|
||||
/*
|
||||
* Status bytes
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
MODULE_DESCRIPTION("SAT support for Cypress USB/ATA bridges with ATACB");
|
||||
MODULE_AUTHOR("Matthieu Castet <castet.matthieu@free.fr>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(USB_STORAGE);
|
||||
|
||||
/*
|
||||
* The table of devices
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
MODULE_DESCRIPTION("Driver for Datafab USB Compact Flash reader");
|
||||
MODULE_AUTHOR("Jimmie Mayfield <mayfield+datafab@sackheads.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(USB_STORAGE);
|
||||
|
||||
struct datafab_info {
|
||||
unsigned long sectors; /* total sector count */
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
MODULE_DESCRIPTION("Driver for ENE UB6250 reader");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(USB_STORAGE);
|
||||
MODULE_FIRMWARE(SD_INIT1_FIRMWARE);
|
||||
MODULE_FIRMWARE(SD_INIT2_FIRMWARE);
|
||||
MODULE_FIRMWARE(SD_RW_FIRMWARE);
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
MODULE_DESCRIPTION("Driver for Freecom USB/IDE adaptor");
|
||||
MODULE_AUTHOR("David Brown <usb-storage@davidb.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(USB_STORAGE);
|
||||
|
||||
#ifdef CONFIG_USB_STORAGE_DEBUG
|
||||
static void pdump(struct us_data *us, void *ibuffer, int length);
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
MODULE_DESCRIPTION("Driver for In-System Design, Inc. ISD200 ASIC");
|
||||
MODULE_AUTHOR("Björn Stenberg <bjorn@haxx.se>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(USB_STORAGE);
|
||||
|
||||
static int isd200_Initialization(struct us_data *us);
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
MODULE_DESCRIPTION("Driver for Lexar \"Jumpshot\" Compact Flash reader");
|
||||
MODULE_AUTHOR("Jimmie Mayfield <mayfield+usb@sackheads.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(USB_STORAGE);
|
||||
|
||||
/*
|
||||
* The table of devices
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
MODULE_DESCRIPTION("Driver for Rio Karma");
|
||||
MODULE_AUTHOR("Bob Copeland <me@bobcopeland.com>, Keith Bennett <keith@mcs.st-and.ac.uk>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(USB_STORAGE);
|
||||
|
||||
#define RIO_PREFIX "RIOP\x00"
|
||||
#define RIO_PREFIX_LEN 5
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
MODULE_DESCRIPTION("Maxtor USB OneTouch hard drive button driver");
|
||||
MODULE_AUTHOR("Nick Sillik <n.sillik@temple.edu>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(USB_STORAGE);
|
||||
|
||||
#define ONETOUCH_PKT_LEN 0x02
|
||||
#define ONETOUCH_BUTTON KEY_PROG1
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
MODULE_DESCRIPTION("Driver for Realtek USB Card Reader");
|
||||
MODULE_AUTHOR("wwang <wei_wang@realsil.com.cn>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(USB_STORAGE);
|
||||
|
||||
static int auto_delink_en = 1;
|
||||
module_param(auto_delink_en, int, S_IRUGO | S_IWUSR);
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
MODULE_DESCRIPTION("Driver for SanDisk SDDR-09 SmartMedia reader");
|
||||
MODULE_AUTHOR("Andries Brouwer <aeb@cwi.nl>, Robert Baruch <autophile@starband.net>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(USB_STORAGE);
|
||||
|
||||
static int usb_stor_sddr09_dpcm_init(struct us_data *us);
|
||||
static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us);
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
MODULE_DESCRIPTION("Driver for SanDisk SDDR-55 SmartMedia reader");
|
||||
MODULE_AUTHOR("Simon Munton");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(USB_STORAGE);
|
||||
|
||||
/*
|
||||
* The table of devices
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
MODULE_DESCRIPTION("Driver for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable");
|
||||
MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>, Robert Baruch <autophile@starband.net>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(USB_STORAGE);
|
||||
|
||||
/* Supported device types */
|
||||
#define USBAT_DEV_HP8200 0x01
|
||||
|
|
|
@ -1219,5 +1219,6 @@ static struct usb_driver uas_driver = {
|
|||
module_usb_driver(uas_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(USB_STORAGE);
|
||||
MODULE_AUTHOR(
|
||||
"Hans de Goede <hdegoede@redhat.com>, Matthew Wilcox and Sarah Sharp");
|
||||
|
|
|
@ -4,14 +4,12 @@
|
|||
#ifndef KSYM_FUNC
|
||||
#define KSYM_FUNC(x) x
|
||||
#endif
|
||||
#ifdef CONFIG_64BIT
|
||||
#ifndef KSYM_ALIGN
|
||||
#define KSYM_ALIGN 8
|
||||
#endif
|
||||
#else
|
||||
#ifndef KSYM_ALIGN
|
||||
#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
|
||||
#define KSYM_ALIGN 4
|
||||
#elif defined(CONFIG_64BIT)
|
||||
#define KSYM_ALIGN 8
|
||||
#else
|
||||
#define KSYM_ALIGN 4
|
||||
#endif
|
||||
#endif
|
||||
#ifndef KCRC_ALIGN
|
||||
#define KCRC_ALIGN 4
|
||||
|
@ -19,11 +17,11 @@
|
|||
|
||||
.macro __put, val, name
|
||||
#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
|
||||
.long \val - ., \name - .
|
||||
.long \val - ., \name - ., 0
|
||||
#elif defined(CONFIG_64BIT)
|
||||
.quad \val, \name
|
||||
.quad \val, \name, 0
|
||||
#else
|
||||
.long \val, \name
|
||||
.long \val, \name, 0
|
||||
#endif
|
||||
.endm
|
||||
|
||||
|
@ -57,7 +55,6 @@ __kcrctab_\name:
|
|||
#endif
|
||||
#endif
|
||||
.endm
|
||||
#undef __put
|
||||
|
||||
#if defined(CONFIG_TRIM_UNUSED_KSYMS)
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@ extern struct module __this_module;
|
|||
#define THIS_MODULE ((struct module *)0)
|
||||
#endif
|
||||
|
||||
#define NS_SEPARATOR "."
|
||||
|
||||
#ifdef CONFIG_MODVERSIONS
|
||||
/* Mark the CRC weak since genksyms apparently decides not to
|
||||
* generate a checksums for some symbols */
|
||||
|
@ -26,13 +28,13 @@ extern struct module __this_module;
|
|||
asm(" .section \"___kcrctab" sec "+" #sym "\", \"a\" \n" \
|
||||
" .weak __crc_" #sym " \n" \
|
||||
" .long __crc_" #sym " - . \n" \
|
||||
" .previous \n");
|
||||
" .previous \n")
|
||||
#else
|
||||
#define __CRC_SYMBOL(sym, sec) \
|
||||
asm(" .section \"___kcrctab" sec "+" #sym "\", \"a\" \n" \
|
||||
" .weak __crc_" #sym " \n" \
|
||||
" .long __crc_" #sym " \n" \
|
||||
" .previous \n");
|
||||
" .previous \n")
|
||||
#endif
|
||||
#else
|
||||
#define __CRC_SYMBOL(sym, sec)
|
||||
|
@ -46,44 +48,77 @@ extern struct module __this_module;
|
|||
* absolute relocations that require runtime processing on relocatable
|
||||
* kernels.
|
||||
*/
|
||||
#define __KSYMTAB_ENTRY_NS(sym, sec, ns) \
|
||||
__ADDRESSABLE(sym) \
|
||||
asm(" .section \"___ksymtab" sec "+" #sym "\", \"a\" \n" \
|
||||
" .balign 4 \n" \
|
||||
"__ksymtab_" #sym NS_SEPARATOR #ns ": \n" \
|
||||
" .long " #sym "- . \n" \
|
||||
" .long __kstrtab_" #sym "- . \n" \
|
||||
" .long __kstrtab_ns_" #sym "- . \n" \
|
||||
" .previous \n")
|
||||
|
||||
#define __KSYMTAB_ENTRY(sym, sec) \
|
||||
__ADDRESSABLE(sym) \
|
||||
asm(" .section \"___ksymtab" sec "+" #sym "\", \"a\" \n" \
|
||||
" .balign 8 \n" \
|
||||
" .balign 4 \n" \
|
||||
"__ksymtab_" #sym ": \n" \
|
||||
" .long " #sym "- . \n" \
|
||||
" .long __kstrtab_" #sym "- . \n" \
|
||||
" .long 0 \n" \
|
||||
" .previous \n")
|
||||
|
||||
struct kernel_symbol {
|
||||
int value_offset;
|
||||
int name_offset;
|
||||
int namespace_offset;
|
||||
};
|
||||
#else
|
||||
#define __KSYMTAB_ENTRY_NS(sym, sec, ns) \
|
||||
static const struct kernel_symbol __ksymtab_##sym##__##ns \
|
||||
asm("__ksymtab_" #sym NS_SEPARATOR #ns) \
|
||||
__attribute__((section("___ksymtab" sec "+" #sym), used)) \
|
||||
__aligned(sizeof(void *)) \
|
||||
= { (unsigned long)&sym, __kstrtab_##sym, __kstrtab_ns_##sym }
|
||||
|
||||
#define __KSYMTAB_ENTRY(sym, sec) \
|
||||
static const struct kernel_symbol __ksymtab_##sym \
|
||||
asm("__ksymtab_" #sym) \
|
||||
__attribute__((section("___ksymtab" sec "+" #sym), used)) \
|
||||
= { (unsigned long)&sym, __kstrtab_##sym }
|
||||
__aligned(sizeof(void *)) \
|
||||
= { (unsigned long)&sym, __kstrtab_##sym, NULL }
|
||||
|
||||
struct kernel_symbol {
|
||||
unsigned long value;
|
||||
const char *name;
|
||||
const char *namespace;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef __GENKSYMS__
|
||||
|
||||
#define ___EXPORT_SYMBOL(sym, sec) __GENKSYMS_EXPORT_SYMBOL(sym)
|
||||
#define ___EXPORT_SYMBOL(sym,sec) __GENKSYMS_EXPORT_SYMBOL(sym)
|
||||
#define ___EXPORT_SYMBOL_NS(sym,sec,ns) __GENKSYMS_EXPORT_SYMBOL(sym)
|
||||
|
||||
#else
|
||||
|
||||
/* For every exported symbol, place a struct in the __ksymtab section */
|
||||
#define ___EXPORT_SYMBOL(sym, sec) \
|
||||
#define ___export_symbol_common(sym, sec) \
|
||||
extern typeof(sym) sym; \
|
||||
__CRC_SYMBOL(sym, sec) \
|
||||
__CRC_SYMBOL(sym, sec); \
|
||||
static const char __kstrtab_##sym[] \
|
||||
__attribute__((section("__ksymtab_strings"), used, aligned(1))) \
|
||||
= #sym; \
|
||||
= #sym \
|
||||
|
||||
/* For every exported symbol, place a struct in the __ksymtab section */
|
||||
#define ___EXPORT_SYMBOL_NS(sym, sec, ns) \
|
||||
___export_symbol_common(sym, sec); \
|
||||
static const char __kstrtab_ns_##sym[] \
|
||||
__attribute__((section("__ksymtab_strings"), used, aligned(1))) \
|
||||
= #ns; \
|
||||
__KSYMTAB_ENTRY_NS(sym, sec, ns)
|
||||
|
||||
#define ___EXPORT_SYMBOL(sym, sec) \
|
||||
___export_symbol_common(sym, sec); \
|
||||
__KSYMTAB_ENTRY(sym, sec)
|
||||
|
||||
#endif
|
||||
|
@ -95,6 +130,7 @@ struct kernel_symbol {
|
|||
* be reused in other execution contexts such as the UEFI stub or the
|
||||
* decompressor.
|
||||
*/
|
||||
#define __EXPORT_SYMBOL_NS(sym, sec, ns)
|
||||
#define __EXPORT_SYMBOL(sym, sec)
|
||||
|
||||
#elif defined(CONFIG_TRIM_UNUSED_KSYMS)
|
||||
|
@ -121,15 +157,35 @@ struct kernel_symbol {
|
|||
#define __cond_export_sym_1(sym, sec) ___EXPORT_SYMBOL(sym, sec)
|
||||
#define __cond_export_sym_0(sym, sec) /* nothing */
|
||||
|
||||
#define __EXPORT_SYMBOL_NS(sym, sec, ns) \
|
||||
__ksym_marker(sym); \
|
||||
__cond_export_ns_sym(sym, sec, ns, __is_defined(__KSYM_##sym))
|
||||
#define __cond_export_ns_sym(sym, sec, ns, conf) \
|
||||
___cond_export_ns_sym(sym, sec, ns, conf)
|
||||
#define ___cond_export_ns_sym(sym, sec, ns, enabled) \
|
||||
__cond_export_ns_sym_##enabled(sym, sec, ns)
|
||||
#define __cond_export_ns_sym_1(sym, sec, ns) ___EXPORT_SYMBOL_NS(sym, sec, ns)
|
||||
#define __cond_export_ns_sym_0(sym, sec, ns) /* nothing */
|
||||
|
||||
#else
|
||||
|
||||
#define __EXPORT_SYMBOL(sym, sec) ___EXPORT_SYMBOL(sym, sec)
|
||||
#define __EXPORT_SYMBOL_NS(sym,sec,ns) ___EXPORT_SYMBOL_NS(sym,sec,ns)
|
||||
#define __EXPORT_SYMBOL(sym,sec) ___EXPORT_SYMBOL(sym,sec)
|
||||
|
||||
#endif /* CONFIG_MODULES */
|
||||
|
||||
#ifdef DEFAULT_SYMBOL_NAMESPACE
|
||||
#undef __EXPORT_SYMBOL
|
||||
#define __EXPORT_SYMBOL(sym, sec) \
|
||||
__EXPORT_SYMBOL_NS(sym, sec, DEFAULT_SYMBOL_NAMESPACE)
|
||||
#endif
|
||||
|
||||
#define EXPORT_SYMBOL(sym) __EXPORT_SYMBOL(sym, "")
|
||||
#define EXPORT_SYMBOL_GPL(sym) __EXPORT_SYMBOL(sym, "_gpl")
|
||||
#define EXPORT_SYMBOL_GPL_FUTURE(sym) __EXPORT_SYMBOL(sym, "_gpl_future")
|
||||
#define EXPORT_SYMBOL_NS(sym, ns) __EXPORT_SYMBOL_NS(sym, "", ns)
|
||||
#define EXPORT_SYMBOL_NS_GPL(sym, ns) __EXPORT_SYMBOL_NS(sym, "_gpl", ns)
|
||||
|
||||
#ifdef CONFIG_UNUSED_SYMBOLS
|
||||
#define EXPORT_UNUSED_SYMBOL(sym) __EXPORT_SYMBOL(sym, "_unused")
|
||||
#define EXPORT_UNUSED_SYMBOL_GPL(sym) __EXPORT_SYMBOL(sym, "_unused_gpl")
|
||||
|
|
|
@ -280,6 +280,8 @@ struct notifier_block;
|
|||
|
||||
#ifdef CONFIG_MODULES
|
||||
|
||||
#define MODULE_IMPORT_NS(ns) MODULE_INFO(import_ns, #ns)
|
||||
|
||||
extern int modules_disabled; /* for sysctl */
|
||||
/* Get/put a kernel symbol (calls must be symmetric) */
|
||||
void *__symbol_get(const char *symbol);
|
||||
|
|
33
init/Kconfig
33
init/Kconfig
|
@ -2047,7 +2047,6 @@ config MODULE_SRCVERSION_ALL
|
|||
|
||||
config MODULE_SIG
|
||||
bool "Module signature verification"
|
||||
depends on MODULES
|
||||
select SYSTEM_DATA_VERIFICATION
|
||||
help
|
||||
Check modules for valid signatures upon load: the signature
|
||||
|
@ -2124,7 +2123,6 @@ config MODULE_SIG_HASH
|
|||
|
||||
config MODULE_COMPRESS
|
||||
bool "Compress modules on installation"
|
||||
depends on MODULES
|
||||
help
|
||||
|
||||
Compresses kernel modules when 'make modules_install' is run; gzip or
|
||||
|
@ -2160,9 +2158,38 @@ config MODULE_COMPRESS_XZ
|
|||
|
||||
endchoice
|
||||
|
||||
config MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS
|
||||
bool "Allow loading of modules with missing namespace imports"
|
||||
help
|
||||
Symbols exported with EXPORT_SYMBOL_NS*() are considered exported in
|
||||
a namespace. A module that makes use of a symbol exported with such a
|
||||
namespace is required to import the namespace via MODULE_IMPORT_NS().
|
||||
There is no technical reason to enforce correct namespace imports,
|
||||
but it creates consistency between symbols defining namespaces and
|
||||
users importing namespaces they make use of. This option relaxes this
|
||||
requirement and lifts the enforcement when loading a module.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config UNUSED_SYMBOLS
|
||||
bool "Enable unused/obsolete exported symbols"
|
||||
default y if X86
|
||||
help
|
||||
Unused but exported symbols make the kernel needlessly bigger. For
|
||||
that reason most of these unused exports will soon be removed. This
|
||||
option is provided temporarily to provide a transition period in case
|
||||
some external kernel module needs one of these symbols anyway. If you
|
||||
encounter such a case in your module, consider if you are actually
|
||||
using the right API. (rationale: since nobody in the kernel is using
|
||||
this in a module, there is a pretty good chance it's actually the
|
||||
wrong interface to use). If you really need the symbol, please send a
|
||||
mail to the linux kernel mailing list mentioning the symbol and why
|
||||
you really need it, and what the merge plan to the mainline kernel for
|
||||
your module is.
|
||||
|
||||
config TRIM_UNUSED_KSYMS
|
||||
bool "Trim unused exported kernel symbols"
|
||||
depends on MODULES && !UNUSED_SYMBOLS
|
||||
depends on !UNUSED_SYMBOLS
|
||||
help
|
||||
The kernel and some modules make many symbols available for
|
||||
other modules to use via EXPORT_SYMBOL() and variants. Depending
|
||||
|
|
|
@ -544,12 +544,20 @@ static const char *kernel_symbol_name(const struct kernel_symbol *sym)
|
|||
#endif
|
||||
}
|
||||
|
||||
static int cmp_name(const void *va, const void *vb)
|
||||
static const char *kernel_symbol_namespace(const struct kernel_symbol *sym)
|
||||
{
|
||||
const char *a;
|
||||
const struct kernel_symbol *b;
|
||||
a = va; b = vb;
|
||||
return strcmp(a, kernel_symbol_name(b));
|
||||
#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
|
||||
if (!sym->namespace_offset)
|
||||
return NULL;
|
||||
return offset_to_ptr(&sym->namespace_offset);
|
||||
#else
|
||||
return sym->namespace;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int cmp_name(const void *name, const void *sym)
|
||||
{
|
||||
return strcmp(name, kernel_symbol_name(sym));
|
||||
}
|
||||
|
||||
static bool find_exported_symbol_in_section(const struct symsearch *syms,
|
||||
|
@ -1379,6 +1387,41 @@ static inline int same_magic(const char *amagic, const char *bmagic,
|
|||
}
|
||||
#endif /* CONFIG_MODVERSIONS */
|
||||
|
||||
static char *get_modinfo(const struct load_info *info, const char *tag);
|
||||
static char *get_next_modinfo(const struct load_info *info, const char *tag,
|
||||
char *prev);
|
||||
|
||||
static int verify_namespace_is_imported(const struct load_info *info,
|
||||
const struct kernel_symbol *sym,
|
||||
struct module *mod)
|
||||
{
|
||||
const char *namespace;
|
||||
char *imported_namespace;
|
||||
|
||||
namespace = kernel_symbol_namespace(sym);
|
||||
if (namespace) {
|
||||
imported_namespace = get_modinfo(info, "import_ns");
|
||||
while (imported_namespace) {
|
||||
if (strcmp(namespace, imported_namespace) == 0)
|
||||
return 0;
|
||||
imported_namespace = get_next_modinfo(
|
||||
info, "import_ns", imported_namespace);
|
||||
}
|
||||
#ifdef CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS
|
||||
pr_warn(
|
||||
#else
|
||||
pr_err(
|
||||
#endif
|
||||
"%s: module uses symbol (%s) from namespace %s, but does not import it.\n",
|
||||
mod->name, kernel_symbol_name(sym), namespace);
|
||||
#ifndef CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS
|
||||
return -EINVAL;
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Resolve a symbol for this module. I.e. if we find one, record usage. */
|
||||
static const struct kernel_symbol *resolve_symbol(struct module *mod,
|
||||
const struct load_info *info,
|
||||
|
@ -1407,6 +1450,12 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
|
|||
goto getname;
|
||||
}
|
||||
|
||||
err = verify_namespace_is_imported(info, sym, mod);
|
||||
if (err) {
|
||||
sym = ERR_PTR(err);
|
||||
goto getname;
|
||||
}
|
||||
|
||||
err = ref_module(mod, owner);
|
||||
if (err) {
|
||||
sym = ERR_PTR(err);
|
||||
|
@ -2481,7 +2530,8 @@ static char *next_string(char *string, unsigned long *secsize)
|
|||
return string;
|
||||
}
|
||||
|
||||
static char *get_modinfo(struct load_info *info, const char *tag)
|
||||
static char *get_next_modinfo(const struct load_info *info, const char *tag,
|
||||
char *prev)
|
||||
{
|
||||
char *p;
|
||||
unsigned int taglen = strlen(tag);
|
||||
|
@ -2492,13 +2542,25 @@ static char *get_modinfo(struct load_info *info, const char *tag)
|
|||
* get_modinfo() calls made before rewrite_section_headers()
|
||||
* must use sh_offset, as sh_addr isn't set!
|
||||
*/
|
||||
for (p = (char *)info->hdr + infosec->sh_offset; p; p = next_string(p, &size)) {
|
||||
char *modinfo = (char *)info->hdr + infosec->sh_offset;
|
||||
|
||||
if (prev) {
|
||||
size -= prev - modinfo;
|
||||
modinfo = next_string(prev, &size);
|
||||
}
|
||||
|
||||
for (p = modinfo; p; p = next_string(p, &size)) {
|
||||
if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
|
||||
return p + taglen + 1;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *get_modinfo(const struct load_info *info, const char *tag)
|
||||
{
|
||||
return get_next_modinfo(info, tag, NULL);
|
||||
}
|
||||
|
||||
static void setup_modinfo(struct module *mod, struct load_info *info)
|
||||
{
|
||||
struct module_attribute *attr;
|
||||
|
|
|
@ -277,22 +277,6 @@ config READABLE_ASM
|
|||
to keep kernel developers who have to stare a lot at assembler listings
|
||||
sane.
|
||||
|
||||
config UNUSED_SYMBOLS
|
||||
bool "Enable unused/obsolete exported symbols"
|
||||
default y if X86
|
||||
help
|
||||
Unused but exported symbols make the kernel needlessly bigger. For
|
||||
that reason most of these unused exports will soon be removed. This
|
||||
option is provided temporarily to provide a transition period in case
|
||||
some external kernel module needs one of these symbols anyway. If you
|
||||
encounter such a case in your module, consider if you are actually
|
||||
using the right API. (rationale: since nobody in the kernel is using
|
||||
this in a module, there is a pretty good chance it's actually the
|
||||
wrong interface to use). If you really need the symbol, please send a
|
||||
mail to the linux kernel mailing list mentioning the symbol and why
|
||||
you really need it, and what the merge plan to the mainline kernel for
|
||||
your module is.
|
||||
|
||||
config DEBUG_FS
|
||||
bool "Debug Filesystem"
|
||||
help
|
||||
|
|
|
@ -54,7 +54,8 @@ MODPOST = scripts/mod/modpost \
|
|||
$(if $(KBUILD_EXTMOD),$(addprefix -e ,$(KBUILD_EXTRA_SYMBOLS))) \
|
||||
$(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \
|
||||
$(if $(CONFIG_SECTION_MISMATCH_WARN_ONLY),,-E) \
|
||||
$(if $(KBUILD_MODPOST_WARN),-w)
|
||||
$(if $(KBUILD_MODPOST_WARN),-w) \
|
||||
$(if $(filter nsdeps,$(MAKECMDGOALS)),-d)
|
||||
|
||||
ifdef MODPOST_VMLINUX
|
||||
|
||||
|
@ -95,6 +96,8 @@ ifneq ($(KBUILD_MODPOST_NOFINAL),1)
|
|||
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modfinal
|
||||
endif
|
||||
|
||||
nsdeps: __modpost
|
||||
|
||||
endif
|
||||
|
||||
.PHONY: $(PHONY)
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
//
|
||||
/// Adds missing MODULE_IMPORT_NS statements to source files
|
||||
///
|
||||
/// This script is usually called from scripts/nsdeps with -D ns=<namespace> to
|
||||
/// add a missing namespace tag to a module source file.
|
||||
///
|
||||
|
||||
@has_ns_import@
|
||||
declarer name MODULE_IMPORT_NS;
|
||||
identifier virtual.ns;
|
||||
@@
|
||||
MODULE_IMPORT_NS(ns);
|
||||
|
||||
// Add missing imports, but only adjacent to a MODULE_LICENSE statement.
|
||||
// That ensures we are adding it only to the main module source file.
|
||||
@do_import depends on !has_ns_import@
|
||||
declarer name MODULE_LICENSE;
|
||||
expression license;
|
||||
identifier virtual.ns;
|
||||
@@
|
||||
MODULE_LICENSE(license);
|
||||
+ MODULE_IMPORT_NS(ns);
|
|
@ -94,7 +94,7 @@ if (defined $opt{'o'}) {
|
|||
#
|
||||
while ( <$module_symvers> ) {
|
||||
chomp;
|
||||
my (undef, $symbol, $module, $gpl) = split;
|
||||
my (undef, $symbol, $namespace, $module, $gpl) = split('\t');
|
||||
$SYMBOL { $symbol } = [ $module , "0" , $symbol, $gpl];
|
||||
}
|
||||
close($module_symvers);
|
||||
|
|
|
@ -38,6 +38,8 @@ static int sec_mismatch_count = 0;
|
|||
static int sec_mismatch_fatal = 0;
|
||||
/* ignore missing files */
|
||||
static int ignore_missing_files;
|
||||
/* write namespace dependencies */
|
||||
static int write_namespace_deps;
|
||||
|
||||
enum export {
|
||||
export_plain, export_unused, export_gpl,
|
||||
|
@ -164,6 +166,7 @@ struct symbol {
|
|||
struct module *module;
|
||||
unsigned int crc;
|
||||
int crc_valid;
|
||||
const char *namespace;
|
||||
unsigned int weak:1;
|
||||
unsigned int vmlinux:1; /* 1 if symbol is defined in vmlinux */
|
||||
unsigned int kernel:1; /* 1 if symbol is from kernel
|
||||
|
@ -235,6 +238,37 @@ static struct symbol *find_symbol(const char *name)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static bool contains_namespace(struct namespace_list *list,
|
||||
const char *namespace)
|
||||
{
|
||||
struct namespace_list *ns_entry;
|
||||
|
||||
for (ns_entry = list; ns_entry != NULL; ns_entry = ns_entry->next)
|
||||
if (strcmp(ns_entry->namespace, namespace) == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void add_namespace(struct namespace_list **list, const char *namespace)
|
||||
{
|
||||
struct namespace_list *ns_entry;
|
||||
|
||||
if (!contains_namespace(*list, namespace)) {
|
||||
ns_entry = NOFAIL(malloc(sizeof(struct namespace_list) +
|
||||
strlen(namespace) + 1));
|
||||
strcpy(ns_entry->namespace, namespace);
|
||||
ns_entry->next = *list;
|
||||
*list = ns_entry;
|
||||
}
|
||||
}
|
||||
|
||||
static bool module_imports_namespace(struct module *module,
|
||||
const char *namespace)
|
||||
{
|
||||
return contains_namespace(module->imported_namespaces, namespace);
|
||||
}
|
||||
|
||||
static const struct {
|
||||
const char *str;
|
||||
enum export export;
|
||||
|
@ -314,23 +348,39 @@ static enum export export_from_sec(struct elf_info *elf, unsigned int sec)
|
|||
return export_unknown;
|
||||
}
|
||||
|
||||
static const char *sym_extract_namespace(const char **symname)
|
||||
{
|
||||
size_t n;
|
||||
char *dupsymname;
|
||||
|
||||
n = strcspn(*symname, ".");
|
||||
if (n < strlen(*symname) - 1) {
|
||||
dupsymname = NOFAIL(strdup(*symname));
|
||||
dupsymname[n] = '\0';
|
||||
*symname = dupsymname;
|
||||
return dupsymname + n + 1;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an exported symbol - it may have already been added without a
|
||||
* CRC, in this case just update the CRC
|
||||
**/
|
||||
static struct symbol *sym_add_exported(const char *name, struct module *mod,
|
||||
enum export export)
|
||||
static struct symbol *sym_add_exported(const char *name, const char *namespace,
|
||||
struct module *mod, enum export export)
|
||||
{
|
||||
struct symbol *s = find_symbol(name);
|
||||
|
||||
if (!s) {
|
||||
s = new_symbol(name, mod, export);
|
||||
s->namespace = namespace;
|
||||
} else {
|
||||
if (!s->preloaded) {
|
||||
warn("%s: '%s' exported twice. Previous export "
|
||||
"was in %s%s\n", mod->name, name,
|
||||
s->module->name,
|
||||
is_vmlinux(s->module->name) ?"":".ko");
|
||||
warn("%s: '%s' exported twice. Previous export was in %s%s\n",
|
||||
mod->name, name, s->module->name,
|
||||
is_vmlinux(s->module->name) ? "" : ".ko");
|
||||
} else {
|
||||
/* In case Module.symvers was out of date */
|
||||
s->module = mod;
|
||||
|
@ -622,6 +672,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
|
|||
unsigned int crc;
|
||||
enum export export;
|
||||
bool is_crc = false;
|
||||
const char *name, *namespace;
|
||||
|
||||
if ((!is_vmlinux(mod->name) || mod->is_dot_o) &&
|
||||
strstarts(symname, "__ksymtab"))
|
||||
|
@ -693,8 +744,9 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
|
|||
default:
|
||||
/* All exported symbols */
|
||||
if (strstarts(symname, "__ksymtab_")) {
|
||||
sym_add_exported(symname + strlen("__ksymtab_"), mod,
|
||||
export);
|
||||
name = symname + strlen("__ksymtab_");
|
||||
namespace = sym_extract_namespace(&name);
|
||||
sym_add_exported(name, namespace, mod, export);
|
||||
}
|
||||
if (strcmp(symname, "init_module") == 0)
|
||||
mod->has_init = 1;
|
||||
|
@ -1945,6 +1997,7 @@ static void read_symbols(const char *modname)
|
|||
const char *symname;
|
||||
char *version;
|
||||
char *license;
|
||||
char *namespace;
|
||||
struct module *mod;
|
||||
struct elf_info info = { };
|
||||
Elf_Sym *sym;
|
||||
|
@ -1976,6 +2029,12 @@ static void read_symbols(const char *modname)
|
|||
license = get_next_modinfo(&info, "license", license);
|
||||
}
|
||||
|
||||
namespace = get_modinfo(&info, "import_ns");
|
||||
while (namespace) {
|
||||
add_namespace(&mod->imported_namespaces, namespace);
|
||||
namespace = get_next_modinfo(&info, "import_ns", namespace);
|
||||
}
|
||||
|
||||
for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
|
||||
symname = remove_dot(info.strtab + sym->st_name);
|
||||
|
||||
|
@ -2135,6 +2194,18 @@ static int check_exports(struct module *mod)
|
|||
basename++;
|
||||
else
|
||||
basename = mod->name;
|
||||
|
||||
if (exp->namespace) {
|
||||
add_namespace(&mod->required_namespaces,
|
||||
exp->namespace);
|
||||
|
||||
if (!write_namespace_deps &&
|
||||
!module_imports_namespace(mod, exp->namespace)) {
|
||||
warn("module %s uses symbol %s from namespace %s, but does not import it.\n",
|
||||
basename, exp->name, exp->namespace);
|
||||
}
|
||||
}
|
||||
|
||||
if (!mod->gpl_compatible)
|
||||
check_for_gpl_usage(exp->export, basename, exp->name);
|
||||
check_for_unused(exp->export, basename, exp->name);
|
||||
|
@ -2354,7 +2425,7 @@ static void read_dump(const char *fname, unsigned int kernel)
|
|||
return;
|
||||
|
||||
while ((line = get_next_line(&pos, file, size))) {
|
||||
char *symname, *modname, *d, *export, *end;
|
||||
char *symname, *namespace, *modname, *d, *export, *end;
|
||||
unsigned int crc;
|
||||
struct module *mod;
|
||||
struct symbol *s;
|
||||
|
@ -2362,7 +2433,10 @@ static void read_dump(const char *fname, unsigned int kernel)
|
|||
if (!(symname = strchr(line, '\t')))
|
||||
goto fail;
|
||||
*symname++ = '\0';
|
||||
if (!(modname = strchr(symname, '\t')))
|
||||
if (!(namespace = strchr(symname, '\t')))
|
||||
goto fail;
|
||||
*namespace++ = '\0';
|
||||
if (!(modname = strchr(namespace, '\t')))
|
||||
goto fail;
|
||||
*modname++ = '\0';
|
||||
if ((export = strchr(modname, '\t')) != NULL)
|
||||
|
@ -2379,7 +2453,8 @@ static void read_dump(const char *fname, unsigned int kernel)
|
|||
mod = new_module(modname);
|
||||
mod->skip = 1;
|
||||
}
|
||||
s = sym_add_exported(symname, mod, export_no(export));
|
||||
s = sym_add_exported(symname, namespace, mod,
|
||||
export_no(export));
|
||||
s->kernel = kernel;
|
||||
s->preloaded = 1;
|
||||
s->is_static = 0;
|
||||
|
@ -2409,16 +2484,20 @@ static void write_dump(const char *fname)
|
|||
{
|
||||
struct buffer buf = { };
|
||||
struct symbol *symbol;
|
||||
const char *namespace;
|
||||
int n;
|
||||
|
||||
for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
|
||||
symbol = symbolhash[n];
|
||||
while (symbol) {
|
||||
if (dump_sym(symbol))
|
||||
buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n",
|
||||
symbol->crc, symbol->name,
|
||||
symbol->module->name,
|
||||
export_str(symbol->export));
|
||||
if (dump_sym(symbol)) {
|
||||
namespace = symbol->namespace;
|
||||
buf_printf(&buf, "0x%08x\t%s\t%s\t%s\t%s\n",
|
||||
symbol->crc, symbol->name,
|
||||
namespace ? namespace : "",
|
||||
symbol->module->name,
|
||||
export_str(symbol->export));
|
||||
}
|
||||
symbol = symbol->next;
|
||||
}
|
||||
}
|
||||
|
@ -2426,6 +2505,31 @@ static void write_dump(const char *fname)
|
|||
free(buf.p);
|
||||
}
|
||||
|
||||
static void write_namespace_deps_files(void)
|
||||
{
|
||||
struct module *mod;
|
||||
struct namespace_list *ns;
|
||||
struct buffer ns_deps_buf = {};
|
||||
|
||||
for (mod = modules; mod; mod = mod->next) {
|
||||
char fname[PATH_MAX];
|
||||
|
||||
if (mod->skip)
|
||||
continue;
|
||||
|
||||
ns_deps_buf.pos = 0;
|
||||
|
||||
for (ns = mod->required_namespaces; ns; ns = ns->next)
|
||||
buf_printf(&ns_deps_buf, "%s\n", ns->namespace);
|
||||
|
||||
if (ns_deps_buf.pos == 0)
|
||||
continue;
|
||||
|
||||
sprintf(fname, "%s.ns_deps", mod->name);
|
||||
write_if_changed(&ns_deps_buf, fname);
|
||||
}
|
||||
}
|
||||
|
||||
struct ext_sym_list {
|
||||
struct ext_sym_list *next;
|
||||
const char *file;
|
||||
|
@ -2443,7 +2547,7 @@ int main(int argc, char **argv)
|
|||
struct ext_sym_list *extsym_iter;
|
||||
struct ext_sym_list *extsym_start = NULL;
|
||||
|
||||
while ((opt = getopt(argc, argv, "i:I:e:mnsT:o:awE")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "i:I:e:mnsT:o:awEd")) != -1) {
|
||||
switch (opt) {
|
||||
case 'i':
|
||||
kernel_read = optarg;
|
||||
|
@ -2484,6 +2588,9 @@ int main(int argc, char **argv)
|
|||
case 'E':
|
||||
sec_mismatch_fatal = 1;
|
||||
break;
|
||||
case 'd':
|
||||
write_namespace_deps = 1;
|
||||
break;
|
||||
default:
|
||||
exit(1);
|
||||
}
|
||||
|
@ -2518,6 +2625,9 @@ int main(int argc, char **argv)
|
|||
|
||||
err |= check_modname_len(mod);
|
||||
err |= check_exports(mod);
|
||||
if (write_namespace_deps)
|
||||
continue;
|
||||
|
||||
add_header(&buf, mod);
|
||||
add_intree_flag(&buf, !external_module);
|
||||
add_retpoline(&buf);
|
||||
|
@ -2530,6 +2640,12 @@ int main(int argc, char **argv)
|
|||
sprintf(fname, "%s.mod.c", mod->name);
|
||||
write_if_changed(&buf, fname);
|
||||
}
|
||||
|
||||
if (write_namespace_deps) {
|
||||
write_namespace_deps_files();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dump_write)
|
||||
write_dump(dump_write);
|
||||
if (sec_mismatch_count && sec_mismatch_fatal)
|
||||
|
|
|
@ -109,6 +109,11 @@ buf_printf(struct buffer *buf, const char *fmt, ...);
|
|||
void
|
||||
buf_write(struct buffer *buf, const char *s, int len);
|
||||
|
||||
struct namespace_list {
|
||||
struct namespace_list *next;
|
||||
char namespace[0];
|
||||
};
|
||||
|
||||
struct module {
|
||||
struct module *next;
|
||||
const char *name;
|
||||
|
@ -121,6 +126,10 @@ struct module {
|
|||
struct buffer dev_table_buf;
|
||||
char srcversion[25];
|
||||
int is_dot_o;
|
||||
// Required namespace dependencies
|
||||
struct namespace_list *required_namespaces;
|
||||
// Actual imported namespaces
|
||||
struct namespace_list *imported_namespaces;
|
||||
};
|
||||
|
||||
struct elf_info {
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Linux kernel symbol namespace import generator
|
||||
#
|
||||
# This script requires a minimum spatch version.
|
||||
SPATCH_REQ_VERSION="1.0.4"
|
||||
|
||||
DIR="$(dirname $(readlink -f $0))/.."
|
||||
SPATCH="`which ${SPATCH:=spatch}`"
|
||||
if [ ! -x "$SPATCH" ]; then
|
||||
echo 'spatch is part of the Coccinelle project and is available at http://coccinelle.lip6.fr/'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SPATCH_REQ_VERSION_NUM=$(echo $SPATCH_REQ_VERSION | ${DIR}/scripts/ld-version.sh)
|
||||
SPATCH_VERSION=$($SPATCH --version | head -1 | awk '{print $3}')
|
||||
SPATCH_VERSION_NUM=$(echo $SPATCH_VERSION | ${DIR}/scripts/ld-version.sh)
|
||||
|
||||
if [ "$SPATCH_VERSION_NUM" -lt "$SPATCH_REQ_VERSION_NUM" ] ; then
|
||||
echo "spatch needs to be version $SPATCH_REQ_VERSION or higher"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
generate_deps_for_ns() {
|
||||
$SPATCH --very-quiet --in-place --sp-file \
|
||||
$srctree/scripts/coccinelle/misc/add_namespace.cocci -D ns=$1 $2
|
||||
}
|
||||
|
||||
generate_deps() {
|
||||
local mod_name=`basename $@ .ko`
|
||||
local mod_file=`echo $@ | sed -e 's/\.ko/\.mod/'`
|
||||
local ns_deps_file=`echo $@ | sed -e 's/\.ko/\.ns_deps/'`
|
||||
if [ ! -f "$ns_deps_file" ]; then return; fi
|
||||
local mod_source_files=`cat $mod_file | sed -n 1p \
|
||||
| sed -e 's/\.o/\.c/g' \
|
||||
| sed "s/[^ ]* */${srctree}\/&/g"`
|
||||
for ns in `cat $ns_deps_file`; do
|
||||
echo "Adding namespace $ns to module $mod_name (if needed)."
|
||||
generate_deps_for_ns $ns $mod_source_files
|
||||
# sort the imports
|
||||
for source_file in $mod_source_files; do
|
||||
sed '/MODULE_IMPORT_NS/Q' $source_file > ${source_file}.tmp
|
||||
offset=$(wc -l ${source_file}.tmp | awk '{print $1;}')
|
||||
cat $source_file | grep MODULE_IMPORT_NS | sort -u >> ${source_file}.tmp
|
||||
tail -n +$((offset +1)) ${source_file} | grep -v MODULE_IMPORT_NS >> ${source_file}.tmp
|
||||
if ! diff -q ${source_file} ${source_file}.tmp; then
|
||||
mv ${source_file}.tmp ${source_file}
|
||||
else
|
||||
rm ${source_file}.tmp
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
for f in `cat $objtree/modules.order`; do
|
||||
generate_deps $f
|
||||
done
|
||||
|
Loading…
Reference in New Issue