← Documents Documentation/core-api/symbol-namespaces.rst GitHub 원문 ↗

Linux 6.18.37 · Core API

Symbol Namespaces

Kernel export symbol을 namespace로 구성하고 MODULE_IMPORT_NS, module 전용 export와 nsdeps로 사용 범위를 검증하는 방법을 설명합니다.

Source pathDocumentation/core-api/symbol-namespaces.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약과 해설

symbol-namespaces.rst:1-168

Symbol Namespace는 subsystem의 public export surface를 나누고 module이 의존성을 명시적으로 선언하게 합니다. 일반 namespace symbol을 쓰는 module은 `MODULE_IMPORT_NS()`로 import해야 합니다.

`EXPORT_SYMBOL_NS()`는 symbol별 namespace를 지정하고 `DEFAULT_SYMBOL_NAMESPACE`는 compilation unit 또는 Makefile 범위의 기본값을 제공합니다. `EXPORT_SYMBOL_FOR_MODULES()`는 import할 수 없는 module 전용 namespace로 in-tree 사용자를 제한합니다.

`modpost`와 module loader가 import 누락을 검증하며 `make nsdeps`로 일반 namespace import를 자동 추가할 수 있습니다. Module namespace에는 이 자동 import를 사용하면 안 됩니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 =================
2 Symbol Namespaces
3 =================
4
5 The following document describes how to use Symbol Namespaces to structure the
6 export surface of in-kernel symbols exported through the family of
7 EXPORT_SYMBOL() macros.
8
9 Introduction
10 ============
11
12 Symbol Namespaces have been introduced as a means to structure the export
13 surface of the in-kernel API. It allows subsystem maintainers to partition
14 their exported symbols into separate namespaces. That is useful for
15 documentation purposes (think of the SUBSYSTEM_DEBUG namespace) as well as for
16 limiting the availability of a set of symbols for use in other parts of the
17 kernel. As of today, modules that make use of symbols exported into namespaces,
18 are required to import the namespace. Otherwise the kernel will, depending on
19 its configuration, reject loading the module or warn about a missing import.
20
21 Additionally, it is possible to put symbols into a module namespace, strictly
22 limiting which modules are allowed to use these symbols.
23
24 How to define Symbol Namespaces
25 ===============================
26
27 Symbols can be exported into namespace using different methods. All of them are
28 changing the way EXPORT_SYMBOL and friends are instrumented to create ksymtab
29 entries.
30
31 Using the EXPORT_SYMBOL macros
32 ------------------------------
33
34 In addition to the macros EXPORT_SYMBOL() and EXPORT_SYMBOL_GPL(), that allow
35 exporting of kernel symbols to the kernel symbol table, variants of these are
36 available to export symbols into a certain namespace: EXPORT_SYMBOL_NS() and
37 EXPORT_SYMBOL_NS_GPL(). They take one additional argument: the namespace as a
38 string constant. Note that this string must not contain whitespaces.
39 E.g. to export the symbol ``usb_stor_suspend`` into the
40 namespace ``USB_STORAGE``, use::
41
42 EXPORT_SYMBOL_NS(usb_stor_suspend, "USB_STORAGE");
43
44 The corresponding ksymtab entry struct ``kernel_symbol`` will have the member
45 ``namespace`` set accordingly. A symbol that is exported without a namespace will
46 refer to ``NULL``. There is no default namespace if none is defined. ``modpost``
47 and kernel/module/main.c make use the namespace at build time or module load
48 time, respectively.
49
50 Using the DEFAULT_SYMBOL_NAMESPACE define
51 -----------------------------------------
52
53 Defining namespaces for all symbols of a subsystem can be very verbose and may
54 become hard to maintain. Therefore a default define (DEFAULT_SYMBOL_NAMESPACE)
55 is been provided, that, if set, will become the default for all EXPORT_SYMBOL()
56 and EXPORT_SYMBOL_GPL() macro expansions that do not specify a namespace.
57
58 There are multiple ways of specifying this define and it depends on the
59 subsystem and the maintainer's preference, which one to use. The first option
60 is to define the default namespace in the ``Makefile`` of the subsystem. E.g. to
61 export all symbols defined in usb-common into the namespace USB_COMMON, add a
62 line like this to drivers/usb/common/Makefile::
63
64 ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE='"USB_COMMON"'
65
66 That will affect all EXPORT_SYMBOL() and EXPORT_SYMBOL_GPL() statements. A
67 symbol exported with EXPORT_SYMBOL_NS() while this definition is present, will
68 still be exported into the namespace that is passed as the namespace argument
69 as this argument has preference over a default symbol namespace.
70
71 A second option to define the default namespace is directly in the compilation
72 unit as preprocessor statement. The above example would then read::
73
74 #define DEFAULT_SYMBOL_NAMESPACE "USB_COMMON"
75
76 within the corresponding compilation unit before the #include for
77 <linux/export.h>. Typically it's placed before the first #include statement.
78
79 Using the EXPORT_SYMBOL_FOR_MODULES() macro
80 -------------------------------------------
81
82 Symbols exported using this macro are put into a module namespace. This
83 namespace cannot be imported. These exports are GPL-only as they are only
84 intended for in-tree modules.
85
86 The macro takes a comma separated list of module names, allowing only those
87 modules to access this symbol. Simple tail-globs are supported.
88
89 For example::
90
91 EXPORT_SYMBOL_FOR_MODULES(preempt_notifier_inc, "kvm,kvm-*")
92
93 will limit usage of this symbol to modules whose name matches the given
94 patterns.
95
96 How to use Symbols exported in Namespaces
97 =========================================
98
99 In order to use symbols that are exported into namespaces, kernel modules need
100 to explicitly import these namespaces. Otherwise the kernel might reject to
101 load the module. The module code is required to use the macro MODULE_IMPORT_NS
102 for the namespaces it uses symbols from. E.g. a module using the
103 usb_stor_suspend symbol from above, needs to import the namespace USB_STORAGE
104 using a statement like::
105
106 MODULE_IMPORT_NS("USB_STORAGE");
107
108 This will create a ``modinfo`` tag in the module for each imported namespace.
109 This has the side effect, that the imported namespaces of a module can be
110 inspected with modinfo::
111
112 $ modinfo drivers/usb/storage/ums-karma.ko
113 [...]
114 import_ns: USB_STORAGE
115 [...]
116
117
118 It is advisable to add the MODULE_IMPORT_NS() statement close to other module
119 metadata definitions like MODULE_AUTHOR() or MODULE_LICENSE().
120
121 Loading Modules that use namespaced Symbols
122 ===========================================
123
124 At module loading time (e.g. ``insmod``), the kernel will check each symbol
125 referenced from the module for its availability and whether the namespace it
126 might be exported to has been imported by the module. The default behaviour of
127 the kernel is to reject loading modules that don't specify sufficient imports.
128 An error will be logged and loading will be failed with EINVAL. In order to
129 allow loading of modules that don't satisfy this precondition, a configuration
130 option is available: Setting MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS=y will
131 enable loading regardless, but will emit a warning.
132
133 Automatically creating MODULE_IMPORT_NS statements
134 ==================================================
135
136 Missing namespaces imports can easily be detected at build time. In fact,
137 modpost will emit a warning if a module uses a symbol from a namespace
138 without importing it.
139 MODULE_IMPORT_NS() statements will usually be added at a definite location
140 (along with other module meta data). To make the life of module authors (and
141 subsystem maintainers) easier, a script and make target is available to fixup
142 missing imports. Fixing missing imports can be done with::
143
144 $ make nsdeps
145
146 A typical scenario for module authors would be::
147
148 - write code that depends on a symbol from a not imported namespace
149 - ``make``
150 - notice the warning of modpost telling about a missing import
151 - run ``make nsdeps`` to add the import to the correct code location
152
153 For subsystem maintainers introducing a namespace, the steps are very similar.
154 Again, ``make nsdeps`` will eventually add the missing namespace imports for
155 in-tree modules::
156
157 - move or add symbols to a namespace (e.g. with EXPORT_SYMBOL_NS())
158 - ``make`` (preferably with an allmodconfig to cover all in-kernel
159 modules)
160 - notice the warning of modpost telling about a missing import
161 - run ``make nsdeps`` to add the import to the correct code location
162
163 You can also run nsdeps for external module builds. A typical usage is::
164
165 $ make -C <path_to_kernel_src> M=$PWD nsdeps
166
167 Note: it will happily generate an import statement for the module namespace;
168 which will not work and generates build and runtime failures.
169

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

Symbol Namespace 소개

1-23

Symbol Namespace

이 문서는 `EXPORT_SYMBOL()` macro family로 export하는 in-kernel symbol의 export surface를 구조화하기 위해 Symbol Namespace를 사용하는 방법을 설명합니다.

소개

Symbol Namespace는 in-kernel API의 export surface를 구조화하는 수단으로 도입되었습니다. Subsystem maintainer는 export symbol을 별도 namespace로 나눌 수 있습니다.

이는 `SUBSYSTEM_DEBUG` namespace 같은 문서화 목적뿐 아니라 kernel의 다른 부분에서 사용할 수 있는 symbol 집합을 제한하는 데도 유용합니다.

현재 namespace로 export된 symbol을 사용하는 module은 해당 namespace를 import해야 합니다. 그렇지 않으면 kernel configuration에 따라 module load를 거부하거나 import 누락 warning을 냅니다.

Symbol을 module namespace에 넣어 어떤 module이 사용할 수 있는지 엄격하게 제한할 수도 있습니다.

EXPORT_SYMBOL namespace macro

24-49

Symbol Namespace 정의 방법

Symbol을 namespace로 export하는 방법은 여러 가지이며, 모두 `EXPORT_SYMBOL` 및 관련 macro가 `ksymtab` entry를 만드는 계측 방식을 바꿉니다.

EXPORT_SYMBOL macro 사용

Kernel symbol table로 symbol을 export하는 `EXPORT_SYMBOL()`과 `EXPORT_SYMBOL_GPL()` 외에 특정 namespace로 export하는 `EXPORT_SYMBOL_NS()`와 `EXPORT_SYMBOL_NS_GPL()` variant가 있습니다.

이 macro는 namespace를 string constant로 받는 argument 하나를 추가로 사용합니다. 이 string에는 whitespace가 들어가면 안 됩니다. 예를 들어 `usb_stor_suspend` symbol을 `USB_STORAGE` namespace로 export하려면 다음을 사용합니다.

EXPORT_SYMBOL_NS(usb_stor_suspend, "USB_STORAGE");

대응하는 `ksymtab` entry structure인 `kernel_symbol`의 `namespace` member가 그 값으로 설정됩니다. Namespace 없이 export한 symbol은 `NULL`을 참조하며, 정의하지 않았을 때의 default namespace는 없습니다.

`modpost`는 build time에, `kernel/module/main.c`는 module load time에 각각 namespace를 사용합니다.

DEFAULT_SYMBOL_NAMESPACE

50-78

DEFAULT_SYMBOL_NAMESPACE define 사용

Subsystem의 모든 symbol에 namespace를 정의하면 매우 장황하고 유지하기 어려울 수 있습니다. 그래서 `DEFAULT_SYMBOL_NAMESPACE` define을 제공하며, 이를 설정하면 namespace를 지정하지 않은 모든 `EXPORT_SYMBOL()`과 `EXPORT_SYMBOL_GPL()` macro expansion의 default가 됩니다.

이 define을 지정하는 방법은 여러 가지이며 subsystem과 maintainer의 선호에 따라 선택합니다. 첫 번째 방법은 subsystem의 `Makefile`에서 default namespace를 정의하는 것입니다.

`usb-common`에서 정의한 모든 symbol을 `USB_COMMON` namespace로 export하려면 `drivers/usb/common/Makefile`에 다음과 같은 줄을 추가합니다.

ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE='"USB_COMMON"'

이는 모든 `EXPORT_SYMBOL()`과 `EXPORT_SYMBOL_GPL()` statement에 영향을 줍니다. 이 define이 있어도 `EXPORT_SYMBOL_NS()`로 export한 symbol은 namespace argument로 전달한 namespace로 export됩니다. 명시적 argument가 default symbol namespace보다 우선하기 때문입니다.

두 번째 방법은 compilation unit 안에서 preprocessor statement로 default namespace를 직접 정의하는 것입니다. 위 예제는 다음과 같습니다.

#define DEFAULT_SYMBOL_NAMESPACE "USB_COMMON"

대응 compilation unit의 `<linux/export.h>` include보다 앞에 두며, 보통 첫 번째 `#include` statement 전에 배치합니다.

EXPORT_SYMBOL_FOR_MODULES

79-95

EXPORT_SYMBOL_FOR_MODULES() macro 사용

이 macro로 export한 symbol은 module namespace에 들어갑니다. 이 namespace는 import할 수 없습니다. In-tree module만을 위한 export이므로 GPL-only입니다.

Macro는 comma-separated module name 목록을 받아 그 module만 symbol에 접근하도록 허용합니다. 단순한 tail-glob도 지원합니다.

예:

EXPORT_SYMBOL_FOR_MODULES(preempt_notifier_inc, "kvm,kvm-*")

이 statement는 주어진 pattern에 이름이 일치하는 module로 symbol 사용을 제한합니다.

Namespace symbol 사용과 import

96-120

Namespace로 export된 symbol 사용 방법

Namespace로 export된 symbol을 사용하려면 kernel module이 해당 namespace를 명시적으로 import해야 합니다. 그렇지 않으면 kernel이 module load를 거부할 수 있습니다.

Module code는 symbol을 사용하는 namespace마다 `MODULE_IMPORT_NS` macro를 사용해야 합니다. 위의 `usb_stor_suspend` symbol을 사용하는 module은 다음 statement로 `USB_STORAGE` namespace를 import해야 합니다.

MODULE_IMPORT_NS("USB_STORAGE");

그러면 import한 namespace마다 module에 `modinfo` tag가 생깁니다. 따라서 다음과 같이 `modinfo`로 module이 import한 namespace를 확인할 수 있습니다.

$ modinfo drivers/usb/storage/ums-karma.ko
[...]
import_ns:      USB_STORAGE
[...]

`MODULE_IMPORT_NS()` statement는 `MODULE_AUTHOR()`나 `MODULE_LICENSE()` 같은 다른 module metadata definition 가까이에 추가하는 것이 좋습니다.

Namespace symbol을 쓰는 module load

121-132

Namespace symbol을 사용하는 module load

`insmod` 같은 module load 시점에 kernel은 module이 참조하는 각 symbol의 가용성과 그 symbol이 export된 namespace를 module이 import했는지 확인합니다.

Kernel의 기본 동작은 필요한 import를 충분히 지정하지 않은 module의 load를 거부하는 것입니다. Error를 log하고 load는 `EINVAL`로 실패합니다.

이 전제 조건을 만족하지 않는 module도 load하려면 `MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS=y` configuration option을 설정할 수 있습니다. 그러면 load는 허용하지만 warning을 냅니다.

MODULE_IMPORT_NS 자동 생성

133-168

MODULE_IMPORT_NS statement 자동 생성

누락된 namespace import는 build time에 쉽게 감지할 수 있습니다. 실제로 module이 namespace를 import하지 않고 그 안의 symbol을 사용하면 `modpost`가 warning을 냅니다.

`MODULE_IMPORT_NS()` statement는 보통 다른 module metadata와 함께 정해진 위치에 추가합니다. Module author와 subsystem maintainer의 작업을 돕기 위해 누락 import를 수정하는 script와 make target을 제공합니다.

누락 import는 다음 명령으로 수정합니다.

$ make nsdeps

Module author의 일반적인 작업 순서는 다음과 같습니다.

- 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

Namespace를 새로 도입하는 subsystem maintainer의 단계도 매우 비슷합니다. `make nsdeps`는 결국 in-tree module에 누락된 namespace import를 추가합니다.

- 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

External module build에도 `nsdeps`를 실행할 수 있습니다. 일반적인 사용법은 다음과 같습니다.

$ make -C <path_to_kernel_src> M=$PWD nsdeps

`nsdeps`는 module namespace에도 import statement를 생성할 수 있지만, module namespace는 import할 수 없으므로 이 결과는 동작하지 않으며 build와 runtime failure를 일으킵니다.