← Documents Documentation/process/stable-api-nonsense.rst GitHub 원문 ↗

Linux 6.18.37 · Kernel programming

Linux kernel 내부 driver interface가 안정 ABI가 아닌 이유

Userspace syscall ABI와 달리 in-kernel binary·source interface를 고정하지 않는 기술적 이유와 upstream driver의 이점을 설명합니다.

Source pathDocumentation/process/stable-api-nonsense.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

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

1. 요약·해설

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

안정적인 userspace ABI와 변하는 kernel 내부 API

stable-api-nonsense.rst:3-34

이 문서는 syscall 같은 kernel-to-userspace interface가 아니라 driver가 사용하는 in-kernel interface를 다룬다. Userspace syscall ABI는 장기간 호환을 유지하지만 kernel은 안정적인 binary module ABI와 고정된 내부 source API를 제공하지 않는다.

실제로 필요한 것은 고정된 내부 함수 signature가 아니라 최신 kernel에서 계속 build되고 동작하는 driver다. 이를 가장 안정적으로 얻는 방법은 driver를 mainline tree에 포함시키는 것이다.

Binary module ABI가 configuration마다 달라진다

stable-api-nonsense.rst:37-99
  • Compiler version과 option에 따라 struct padding, alignment와 inline 결정이 달라질 수 있다.
  • Kernel CONFIG에 따라 struct field가 생기거나 사라지고 function과 lock이 compile out될 수 있다.
  • Memory alignment와 object layout도 build option의 영향을 받는다.
  • Linux가 지원하는 CPU architecture마다 instruction과 calling convention이 다르다.

정확히 같은 distribution release, kernel configuration, compiler와 architecture를 대상으로 module을 각각 build하면 특정 image에는 맞출 수 있다. 하지만 distribution version, hardware별 kernel flavor와 update 조합만큼 binary를 계속 만들어야 하므로 지원 matrix가 빠르게 폭발한다.

Source interface 변경이 kernel을 개선한다

stable-api-nonsense.rst:101-160

Kernel 개발자는 내부 interface의 bug, locking 문제와 더 나은 abstraction을 발견하면 function name, parameter와 struct를 바꾸고 tree 안의 모든 caller를 같은 commit series에서 고친다.

USB subsystem은 synchronous data model을 asynchronous model로 바꿔 driver complexity를 줄이고 throughput을 높였으며, packet allocation interface에 더 많은 정보를 요구하도록 바꿔 deadlock을 없앴다. Old API 호환을 영구 유지했다면 잘못된 방식이 계속 새 driver에 사용되고 두 interface를 동시에 관리해야 했을 것이다.

Security fix도 내부 interface를 재설계해야 할 수 있다. In-tree caller를 전부 고치면 취약한 사용 pattern이 다시 생길 가능성을 차단할 수 있다. 사용자가 없는 interface는 삭제해 kernel 크기와 test surface를 줄인다.

Out-of-tree driver를 upstream으로 보낸다

stable-api-nonsense.rst:163-196

GPL-compatible driver가 mainline에 있으면 내부 interface를 바꾸는 개발자가 같은 tree의 driver도 함께 수정한다. Original author가 모든 kernel release 변화에 뒤따라갈 필요가 줄고 buildability가 지속된다.

  • 다른 reviewer가 bug와 tuning opportunity를 찾으면서 quality가 높아진다.
  • 다른 개발자가 새 hardware와 feature 지원을 추가한다.
  • 외부 interface 변화 때 tree-wide conversion에 자동 포함된다.
  • 별도 요청 없이 distribution kernel에 함께 배포된다.
  • 여러 architecture에서 build·runtime test될 기회가 늘어난다.

2. 영어 원문 전체

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

원문 전체 펼치기
1 .. _stable_api_nonsense:
2
3 The Linux Kernel Driver Interface
4 ==================================
5
6 (all of your questions answered and then some)
7
8 Greg Kroah-Hartman <greg@kroah.com>
9
10 This is being written to try to explain why Linux **does not have a binary
11 kernel interface, nor does it have a stable kernel interface**.
12
13 .. note::
14
15 Please realize that this article describes the **in kernel** interfaces, not
16 the kernel to userspace interfaces.
17
18 The kernel to userspace interface is the one that application programs use,
19 the syscall interface. That interface is **very** stable over time, and
20 will not break. I have old programs that were built on a pre 0.9something
21 kernel that still work just fine on the latest 2.6 kernel release.
22 That interface is the one that users and application programmers can count
23 on being stable.
24
25
26 Executive Summary
27 -----------------
28 You think you want a stable kernel interface, but you really do not, and
29 you don't even know it. What you want is a stable running driver, and
30 you get that only if your driver is in the main kernel tree. You also
31 get lots of other good benefits if your driver is in the main kernel
32 tree, all of which has made Linux into such a strong, stable, and mature
33 operating system which is the reason you are using it in the first
34 place.
35
36
37 Intro
38 -----
39
40 It's only the odd person who wants to write a kernel driver that needs
41 to worry about the in-kernel interfaces changing. For the majority of
42 the world, they neither see this interface, nor do they care about it at
43 all.
44
45 First off, I'm not going to address **any** legal issues about closed
46 source, hidden source, binary blobs, source wrappers, or any other term
47 that describes kernel drivers that do not have their source code
48 released under the GPL. Please consult a lawyer if you have any legal
49 questions, I'm a programmer and hence, I'm just going to be describing
50 the technical issues here (not to make light of the legal issues, they
51 are real, and you do need to be aware of them at all times.)
52
53 So, there are two main topics here, binary kernel interfaces and stable
54 kernel source interfaces. They both depend on each other, but we will
55 discuss the binary stuff first to get it out of the way.
56
57
58 Binary Kernel Interface
59 -----------------------
60 Assuming that we had a stable kernel source interface for the kernel, a
61 binary interface would naturally happen too, right? Wrong. Please
62 consider the following facts about the Linux kernel:
63
64 - Depending on the version of the C compiler you use, different kernel
65 data structures will contain different alignment of structures, and
66 possibly include different functions in different ways (putting
67 functions inline or not.) The individual function organization
68 isn't that important, but the different data structure padding is
69 very important.
70
71 - Depending on what kernel build options you select, a wide range of
72 different things can be assumed by the kernel:
73
74 - different structures can contain different fields
75 - Some functions may not be implemented at all, (i.e. some locks
76 compile away to nothing for non-SMP builds.)
77 - Memory within the kernel can be aligned in different ways,
78 depending on the build options.
79
80 - Linux runs on a wide range of different processor architectures.
81 There is no way that binary drivers from one architecture will run
82 on another architecture properly.
83
84 Now a number of these issues can be addressed by simply compiling your
85 module for the exact specific kernel configuration, using the same exact
86 C compiler that the kernel was built with. This is sufficient if you
87 want to provide a module for a specific release version of a specific
88 Linux distribution. But multiply that single build by the number of
89 different Linux distributions and the number of different supported
90 releases of the Linux distribution and you quickly have a nightmare of
91 different build options on different releases. Also realize that each
92 Linux distribution release contains a number of different kernels, all
93 tuned to different hardware types (different processor types and
94 different options), so for even a single release you will need to create
95 multiple versions of your module.
96
97 Trust me, you will go insane over time if you try to support this kind
98 of release, I learned this the hard way a long time ago...
99
100
101 Stable Kernel Source Interfaces
102 -------------------------------
103
104 This is a much more "volatile" topic if you talk to people who try to
105 keep a Linux kernel driver that is not in the main kernel tree up to
106 date over time.
107
108 Linux kernel development is continuous and at a rapid pace, never
109 stopping to slow down. As such, the kernel developers find bugs in
110 current interfaces, or figure out a better way to do things. If they do
111 that, they then fix the current interfaces to work better. When they do
112 so, function names may change, structures may grow or shrink, and
113 function parameters may be reworked. If this happens, all of the
114 instances of where this interface is used within the kernel are fixed up
115 at the same time, ensuring that everything continues to work properly.
116
117 As a specific examples of this, the in-kernel USB interfaces have
118 undergone at least three different reworks over the lifetime of this
119 subsystem. These reworks were done to address a number of different
120 issues:
121
122 - A change from a synchronous model of data streams to an asynchronous
123 one. This reduced the complexity of a number of drivers and
124 increased the throughput of all USB drivers such that we are now
125 running almost all USB devices at their maximum speed possible.
126 - A change was made in the way data packets were allocated from the
127 USB core by USB drivers so that all drivers now needed to provide
128 more information to the USB core to fix a number of documented
129 deadlocks.
130
131 This is in stark contrast to a number of closed source operating systems
132 which have had to maintain their older USB interfaces over time. This
133 provides the ability for new developers to accidentally use the old
134 interfaces and do things in improper ways, causing the stability of the
135 operating system to suffer.
136
137 In both of these instances, all developers agreed that these were
138 important changes that needed to be made, and they were made, with
139 relatively little pain. If Linux had to ensure that it will preserve a
140 stable source interface, a new interface would have been created, and
141 the older, broken one would have had to be maintained over time, leading
142 to extra work for the USB developers. Since all Linux USB developers do
143 their work on their own time, asking programmers to do extra work for no
144 gain, for free, is not a possibility.
145
146 Security issues are also very important for Linux. When a
147 security issue is found, it is fixed in a very short amount of time. A
148 number of times this has caused internal kernel interfaces to be
149 reworked to prevent the security problem from occurring. When this
150 happens, all drivers that use the interfaces were also fixed at the
151 same time, ensuring that the security problem was fixed and could not
152 come back at some future time accidentally. If the internal interfaces
153 were not allowed to change, fixing this kind of security problem and
154 insuring that it could not happen again would not be possible.
155
156 Kernel interfaces are cleaned up over time. If there is no one using a
157 current interface, it is deleted. This ensures that the kernel remains
158 as small as possible, and that all potential interfaces are tested as
159 well as they can be (unused interfaces are pretty much impossible to
160 test for validity.)
161
162
163 What to do
164 ----------
165
166 So, if you have a Linux kernel driver that is not in the main kernel
167 tree, what are you, a developer, supposed to do? Releasing a binary
168 driver for every different kernel version for every distribution is a
169 nightmare, and trying to keep up with an ever changing kernel interface
170 is also a rough job.
171
172 Simple, get your kernel driver into the main kernel tree (remember we are
173 talking about drivers released under a GPL-compatible license here, if your
174 code doesn't fall under this category, good luck, you are on your own here,
175 you leech). If your driver is in the tree, and a kernel interface changes,
176 it will be fixed up by the person who did the kernel change in the first
177 place. This ensures that your driver is always buildable, and works over
178 time, with very little effort on your part.
179
180 The very good side effects of having your driver in the main kernel tree
181 are:
182
183 - The quality of the driver will rise as the maintenance costs (to the
184 original developer) will decrease.
185 - Other developers will add features to your driver.
186 - Other people will find and fix bugs in your driver.
187 - Other people will find tuning opportunities in your driver.
188 - Other people will update the driver for you when external interface
189 changes require it.
190 - The driver automatically gets shipped in all Linux distributions
191 without having to ask the distros to add it.
192
193 As Linux supports a larger number of different devices "out of the box"
194 than any other operating system, and it supports these devices on more
195 different processor architectures than any other operating system, this
196 proven type of development model must be doing something right :)
197
198
199
200 ------
201
202 Thanks to Randy Dunlap, Andrew Morton, David Brownell, Hanna Linder,
203 Robert Love, and Nishanth Aravamudan for their review and comments on
204 early drafts of this paper.
205

3. 한국어 전문 번역

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

안정성을 보장하는 interface와 보장하지 않는 interface

1-23

Greg Kroah-Hartman이 작성한 이 문서는 Linux에 binary kernel interface도 stable in-kernel interface도 없는 이유를 설명한다.

여기서 말하는 대상은 kernel 내부 interface다. Application이 사용하는 kernel-userspace syscall interface는 시간이 지나도 매우 안정적으로 유지되며 깨지지 않는다. 오래된 kernel을 대상으로 build한 program도 훨씬 새로운 kernel에서 계속 동작한다. User와 application programmer가 안정성을 기대할 수 있는 것은 이 userspace ABI다.

원하는 것은 stable API가 아니라 계속 동작하는 driver

26-34

Developer가 원한다고 생각하는 것은 stable kernel interface일 수 있지만 실제로 필요한 것은 계속 build되고 실행되는 stable driver다. 이를 얻는 방법은 driver를 mainline kernel tree에 포함하는 것이다. Main tree 포함은 Linux를 강하고 안정적이며 성숙한 운영체제로 만든 다른 여러 이점도 함께 제공한다.

법적 문제가 아닌 기술적 설명

37-55

In-kernel interface 변경을 직접 걱정하는 사람은 kernel driver 작성자 정도다. 대부분의 사용자는 이 interface를 보지도 않고 신경 쓸 필요도 없다.

이 문서는 GPL로 source를 공개하지 않는 closed source, hidden source, binary blob, source wrapper driver의 법적 문제를 다루지 않는다. 법률 문제는 변호사에게 문의해야 하며 여기서는 binary kernel interface와 stable kernel source interface라는 기술적 문제만 설명한다.

Compiler, configuration, architecture가 binary ABI를 바꾼다

58-83
  • 사용한 C compiler version에 따라 kernel structure alignment와 padding이 달라지고 function이 inline되는 방식도 바뀔 수 있다. Function 배치보다 data structure padding 차이가 특히 중요하다.
  • Kernel build option에 따라 같은 structure의 field가 달라지고 일부 function은 아예 구현되지 않을 수 있다. 예를 들어 non-SMP build에서는 일부 lock operation이 아무 code도 만들지 않는다. Memory alignment도 configuration에 따라 달라진다.
  • Linux는 매우 다양한 processor architecture에서 실행된다. 한 architecture용 binary driver가 다른 architecture에서 올바르게 동작할 수 없다.

Distribution별 binary module build matrix

84-98

특정 distribution의 특정 release와 특정 kernel configuration만 지원한다면 kernel과 정확히 같은 compiler와 configuration으로 module을 build해 일부 문제를 피할 수 있다.

그러나 Linux distribution 수, 각 distribution이 지원하는 release 수, 한 release 안에서 hardware별로 제공하는 여러 kernel flavor를 곱하면 유지해야 할 module build가 폭발적으로 늘어난다. 이런 release 방식을 장기간 지원하는 것은 현실적으로 감당하기 어렵다.

Kernel source interface가 계속 바뀌는 이유

101-115

Main kernel tree 밖의 driver를 오래 유지하는 사람에게 stable kernel source interface는 특히 민감한 문제다. Linux kernel 개발은 멈추지 않고 빠르게 진행된다.

Developer가 현재 interface의 bug나 더 나은 설계를 찾으면 interface 자체를 고친다. Function 이름, structure 크기와 field, function parameter가 바뀔 수 있다. 이때 kernel tree 안에서 해당 interface를 사용하는 모든 call site도 같은 변경으로 함께 수정하므로 전체 tree는 계속 올바르게 동작한다.

USB subsystem interface 개편 사례

117-145

In-kernel USB interface는 subsystem lifetime 동안 적어도 세 차례 크게 개편되었다.

  • Data stream을 synchronous model에서 asynchronous model로 바꾸어 여러 driver의 복잡성을 낮추고 throughput을 높였다. 그 결과 거의 모든 USB device를 가능한 최대 속도에 가깝게 실행할 수 있게 되었다.
  • USB driver가 USB core에서 data packet을 allocate하는 방식을 바꾸어 driver가 core에 더 많은 정보를 제공하게 했다. 이를 통해 문서화된 여러 deadlock을 수정했다.

오래된 USB interface까지 계속 유지해야 하는 closed-source 운영체제에서는 새 developer가 낡은 interface를 실수로 사용하고 잘못된 방식으로 code를 작성해 system 안정성을 떨어뜨릴 수 있다.

Linux에 stable source interface 보존 의무가 있었다면 새 interface를 추가하면서 깨진 옛 interface도 계속 유지해야 했다. 이는 자원봉사로 일하는 USB developer에게 아무 이익 없이 추가 작업을 요구하는 결과가 된다.

Security 수정과 unused interface 제거

146-160

Security issue가 발견되면 Linux는 매우 빠르게 수정한다. 재발을 막으려면 internal interface 자체를 바꾸어야 할 때가 있고, kernel tree 안의 모든 driver도 동시에 수정한다. Internal interface 변경을 금지하면 이런 보안 문제를 완전하게 고치고 미래의 재발을 막기 어렵다.

Kernel interface는 시간이 지나며 정리된다. 아무도 사용하지 않는 interface는 삭제해 kernel을 가능한 한 작게 유지하고 남은 interface가 실제로 test되도록 한다. 사용자가 없는 interface는 유효성을 현실적으로 시험하기 어렵다.

해결책은 mainline 포함

163-178

Main tree 밖의 GPL-compatible Linux driver를 유지하면서 모든 kernel version과 distribution용 binary를 배포하고 변하는 interface를 따라가는 일은 매우 어렵다. 해결책은 driver를 main kernel tree에 포함하는 것이다.

Tree 안의 driver는 kernel interface를 바꾸는 developer가 같은 patch series에서 함께 수정한다. Driver owner가 매번 별도로 따라가지 않아도 driver는 계속 build되고 동작한다.

Main tree driver가 얻는 이점

180-196
  • 원래 developer의 maintenance cost는 줄고 driver 품질은 높아진다.
  • 다른 developer가 feature를 추가한다.
  • 다른 사람이 bug를 발견하고 수정한다.
  • 다른 사람이 성능 tuning 기회를 찾는다.
  • 외부 interface 변경이 필요할 때 다른 developer가 driver를 갱신한다.
  • Distribution에 별도 포함 요청을 하지 않아도 driver가 모든 Linux distribution에 자동으로 배포된다.

Linux는 다른 운영체제보다 더 많은 device를 기본 지원하고 더 다양한 processor architecture에서 이를 제공한다. 이는 mainline 중심 개발 model이 실제로 효과가 있음을 보여 준다.

검토 기여

200-204

초기 초안을 검토하고 의견을 준 Randy Dunlap, Andrew Morton, David Brownell, Hanna Linder, Robert Love, Nishanth Aravamudan에게 감사를 표한다.