← Documents Documentation/arch/powerpc/eeh-pci-error-recovery.rst GitHub 원문 ↗

Linux 6.18.37 · Architecture

PCI Bus EEH Error Recovery

POWER PCI slot isolation, RTAS recovery, hotplug/uevent call chain과 generic 설계 tradeoff를 설명합니다.

Source pathDocumentation/arch/powerpc/eeh-pci-error-recovery.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

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

1. 요약·해설

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

요약과 해설

eeh-pci-error-recovery.rst:1-335

EEH는 faulting PCI slot을 isolate하고 RTAS, notifier, hotplug path로 개별 adapter를 재시작합니다. Driver 수정이 필요 없는 대신 network daemon과 mounted filesystem까지 흔들 수 있어 reset layer 선택이 중요합니다.

2. 영어 원문 전체

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

원문 전체 펼치기
1 ==========================
2 PCI Bus EEH Error Recovery
3 ==========================
4
5 Linas Vepstas <[email protected]>
6
7 12 January 2005
8
9
10 Overview:
11 ---------
12 The IBM POWER-based pSeries and iSeries computers include PCI bus
13 controller chips that have extended capabilities for detecting and
14 reporting a large variety of PCI bus error conditions. These features
15 go under the name of "EEH", for "Enhanced Error Handling". The EEH
16 hardware features allow PCI bus errors to be cleared and a PCI
17 card to be "rebooted", without also having to reboot the operating
18 system.
19
20 This is in contrast to traditional PCI error handling, where the
21 PCI chip is wired directly to the CPU, and an error would cause
22 a CPU machine-check/check-stop condition, halting the CPU entirely.
23 Another "traditional" technique is to ignore such errors, which
24 can lead to data corruption, both of user data or of kernel data,
25 hung/unresponsive adapters, or system crashes/lockups. Thus,
26 the idea behind EEH is that the operating system can become more
27 reliable and robust by protecting it from PCI errors, and giving
28 the OS the ability to "reboot"/recover individual PCI devices.
29
30 Future systems from other vendors, based on the PCI-E specification,
31 may contain similar features.
32
33
34 Causes of EEH Errors
35 --------------------
36 EEH was originally designed to guard against hardware failure, such
37 as PCI cards dying from heat, humidity, dust, vibration and bad
38 electrical connections. The vast majority of EEH errors seen in
39 "real life" are due to either poorly seated PCI cards, or,
40 unfortunately quite commonly, due to device driver bugs, device firmware
41 bugs, and sometimes PCI card hardware bugs.
42
43 The most common software bug, is one that causes the device to
44 attempt to DMA to a location in system memory that has not been
45 reserved for DMA access for that card. This is a powerful feature,
46 as it prevents what; otherwise, would have been silent memory
47 corruption caused by the bad DMA. A number of device driver
48 bugs have been found and fixed in this way over the past few
49 years. Other possible causes of EEH errors include data or
50 address line parity errors (for example, due to poor electrical
51 connectivity due to a poorly seated card), and PCI-X split-completion
52 errors (due to software, device firmware, or device PCI hardware bugs).
53 The vast majority of "true hardware failures" can be cured by
54 physically removing and re-seating the PCI card.
55
56
57 Detection and Recovery
58 ----------------------
59 In the following discussion, a generic overview of how to detect
60 and recover from EEH errors will be presented. This is followed
61 by an overview of how the current implementation in the Linux
62 kernel does it. The actual implementation is subject to change,
63 and some of the finer points are still being debated. These
64 may in turn be swayed if or when other architectures implement
65 similar functionality.
66
67 When a PCI Host Bridge (PHB, the bus controller connecting the
68 PCI bus to the system CPU electronics complex) detects a PCI error
69 condition, it will "isolate" the affected PCI card. Isolation
70 will block all writes (either to the card from the system, or
71 from the card to the system), and it will cause all reads to
72 return all-ff's (0xff, 0xffff, 0xffffffff for 8/16/32-bit reads).
73 This value was chosen because it is the same value you would
74 get if the device was physically unplugged from the slot.
75 This includes access to PCI memory, I/O space, and PCI config
76 space. Interrupts; however, will continue to be delivered.
77
78 Detection and recovery are performed with the aid of ppc64
79 firmware. The programming interfaces in the Linux kernel
80 into the firmware are referred to as RTAS (Run-Time Abstraction
81 Services). The Linux kernel does not (should not) access
82 the EEH function in the PCI chipsets directly, primarily because
83 there are a number of different chipsets out there, each with
84 different interfaces and quirks. The firmware provides a
85 uniform abstraction layer that will work with all pSeries
86 and iSeries hardware (and be forwards-compatible).
87
88 If the OS or device driver suspects that a PCI slot has been
89 EEH-isolated, there is a firmware call it can make to determine if
90 this is the case. If so, then the device driver should put itself
91 into a consistent state (given that it won't be able to complete any
92 pending work) and start recovery of the card. Recovery normally
93 would consist of resetting the PCI device (holding the PCI #RST
94 line high for two seconds), followed by setting up the device
95 config space (the base address registers (BAR's), latency timer,
96 cache line size, interrupt line, and so on). This is followed by a
97 reinitialization of the device driver. In a worst-case scenario,
98 the power to the card can be toggled, at least on hot-plug-capable
99 slots. In principle, layers far above the device driver probably
100 do not need to know that the PCI card has been "rebooted" in this
101 way; ideally, there should be at most a pause in Ethernet/disk/USB
102 I/O while the card is being reset.
103
104 If the card cannot be recovered after three or four resets, the
105 kernel/device driver should assume the worst-case scenario, that the
106 card has died completely, and report this error to the sysadmin.
107 In addition, error messages are reported through RTAS and also through
108 syslogd (/var/log/messages) to alert the sysadmin of PCI resets.
109 The correct way to deal with failed adapters is to use the standard
110 PCI hotplug tools to remove and replace the dead card.
111
112
113 Current PPC64 Linux EEH Implementation
114 --------------------------------------
115 At this time, a generic EEH recovery mechanism has been implemented,
116 so that individual device drivers do not need to be modified to support
117 EEH recovery. This generic mechanism piggy-backs on the PCI hotplug
118 infrastructure, and percolates events up through the userspace/udev
119 infrastructure. Following is a detailed description of how this is
120 accomplished.
121
122 EEH must be enabled in the PHB's very early during the boot process,
123 and if a PCI slot is hot-plugged. The former is performed by
124 eeh_init() in arch/powerpc/platforms/pseries/eeh.c, and the later by
125 drivers/pci/hotplug/pSeries_pci.c calling in to the eeh.c code.
126 EEH must be enabled before a PCI scan of the device can proceed.
127 Current Power5 hardware will not work unless EEH is enabled;
128 although older Power4 can run with it disabled. Effectively,
129 EEH can no longer be turned off. PCI devices *must* be
130 registered with the EEH code; the EEH code needs to know about
131 the I/O address ranges of the PCI device in order to detect an
132 error. Given an arbitrary address, the routine
133 pci_get_device_by_addr() will find the pci device associated
134 with that address (if any).
135
136 The default arch/powerpc/include/asm/io.h macros readb(), inb(), insb(),
137 etc. include a check to see if the i/o read returned all-0xff's.
138 If so, these make a call to eeh_dn_check_failure(), which in turn
139 asks the firmware if the all-ff's value is the sign of a true EEH
140 error. If it is not, processing continues as normal. The grand
141 total number of these false alarms or "false positives" can be
142 seen in /proc/ppc64/eeh (subject to change). Normally, almost
143 all of these occur during boot, when the PCI bus is scanned, where
144 a large number of 0xff reads are part of the bus scan procedure.
145
146 If a frozen slot is detected, code in
147 arch/powerpc/platforms/pseries/eeh.c will print a stack trace to
148 syslog (/var/log/messages). This stack trace has proven to be very
149 useful to device-driver authors for finding out at what point the EEH
150 error was detected, as the error itself usually occurs slightly
151 beforehand.
152
153 Next, it uses the Linux kernel notifier chain/work queue mechanism to
154 allow any interested parties to find out about the failure. Device
155 drivers, or other parts of the kernel, can use
156 `eeh_register_notifier(struct notifier_block *)` to find out about EEH
157 events. The event will include a pointer to the pci device, the
158 device node and some state info. Receivers of the event can "do as
159 they wish"; the default handler will be described further in this
160 section.
161
162 To assist in the recovery of the device, eeh.c exports the
163 following functions:
164
165 rtas_set_slot_reset()
166 assert the PCI #RST line for 1/8th of a second
167 rtas_configure_bridge()
168 ask firmware to configure any PCI bridges
169 located topologically under the pci slot.
170 eeh_save_bars() and eeh_restore_bars():
171 save and restore the PCI
172 config-space info for a device and any devices under it.
173
174
175 A handler for the EEH notifier_block events is implemented in
176 drivers/pci/hotplug/pSeries_pci.c, called handle_eeh_events().
177 It saves the device BAR's and then calls rpaphp_unconfig_pci_adapter().
178 This last call causes the device driver for the card to be stopped,
179 which causes uevents to go out to user space. This triggers
180 user-space scripts that might issue commands such as "ifdown eth0"
181 for ethernet cards, and so on. This handler then sleeps for 5 seconds,
182 hoping to give the user-space scripts enough time to complete.
183 It then resets the PCI card, reconfigures the device BAR's, and
184 any bridges underneath. It then calls rpaphp_enable_pci_slot(),
185 which restarts the device driver and triggers more user-space
186 events (for example, calling "ifup eth0" for ethernet cards).
187
188
189 Device Shutdown and User-Space Events
190 -------------------------------------
191 This section documents what happens when a pci slot is unconfigured,
192 focusing on how the device driver gets shut down, and on how the
193 events get delivered to user-space scripts.
194
195 Following is an example sequence of events that cause a device driver
196 close function to be called during the first phase of an EEH reset.
197 The following sequence is an example of the pcnet32 device driver::
198
199 rpa_php_unconfig_pci_adapter (struct slot *) // in rpaphp_pci.c
200 {
201 calls
202 pci_remove_bus_device (struct pci_dev *) // in /drivers/pci/remove.c
203 {
204 calls
205 pci_destroy_dev (struct pci_dev *)
206 {
207 calls
208 device_unregister (&dev->dev) // in /drivers/base/core.c
209 {
210 calls
211 device_del (struct device *)
212 {
213 calls
214 bus_remove_device() // in /drivers/base/bus.c
215 {
216 calls
217 device_release_driver()
218 {
219 calls
220 struct device_driver->remove() which is just
221 pci_device_remove() // in /drivers/pci/pci_driver.c
222 {
223 calls
224 struct pci_driver->remove() which is just
225 pcnet32_remove_one() // in /drivers/net/pcnet32.c
226 {
227 calls
228 unregister_netdev() // in /net/core/dev.c
229 {
230 calls
231 dev_close() // in /net/core/dev.c
232 {
233 calls dev->stop();
234 which is just pcnet32_close() // in pcnet32.c
235 {
236 which does what you wanted
237 to stop the device
238 }
239 }
240 }
241 which
242 frees pcnet32 device driver memory
243 }
244 }}}}}}
245
246
247 in drivers/pci/pci_driver.c,
248 struct device_driver->remove() is just pci_device_remove()
249 which calls struct pci_driver->remove() which is pcnet32_remove_one()
250 which calls unregister_netdev() (in net/core/dev.c)
251 which calls dev_close() (in net/core/dev.c)
252 which calls dev->stop() which is pcnet32_close()
253 which then does the appropriate shutdown.
254
255 ---
256
257 Following is the analogous stack trace for events sent to user-space
258 when the pci device is unconfigured::
259
260 rpa_php_unconfig_pci_adapter() { // in rpaphp_pci.c
261 calls
262 pci_remove_bus_device (struct pci_dev *) { // in /drivers/pci/remove.c
263 calls
264 pci_destroy_dev (struct pci_dev *) {
265 calls
266 device_unregister (&dev->dev) { // in /drivers/base/core.c
267 calls
268 device_del(struct device * dev) { // in /drivers/base/core.c
269 calls
270 kobject_del() { //in /libs/kobject.c
271 calls
272 kobject_uevent() { // in /libs/kobject.c
273 calls
274 kset_uevent() { // in /lib/kobject.c
275 calls
276 kset->uevent_ops->uevent() // which is really just
277 a call to
278 dev_uevent() { // in /drivers/base/core.c
279 calls
280 dev->bus->uevent() which is really just a call to
281 pci_uevent () { // in drivers/pci/hotplug.c
282 which prints device name, etc....
283 }
284 }
285 then kobject_uevent() sends a netlink uevent to userspace
286 --> userspace uevent
287 (during early boot, nobody listens to netlink events and
288 kobject_uevent() executes uevent_helper[], which runs the
289 event process /sbin/hotplug)
290 }
291 }
292 kobject_del() then calls sysfs_remove_dir(), which would
293 trigger any user-space daemon that was watching /sysfs,
294 and notice the delete event.
295
296
297 Pro's and Con's of the Current Design
298 -------------------------------------
299 There are several issues with the current EEH software recovery design,
300 which may be addressed in future revisions. But first, note that the
301 big plus of the current design is that no changes need to be made to
302 individual device drivers, so that the current design throws a wide net.
303 The biggest negative of the design is that it potentially disturbs
304 network daemons and file systems that didn't need to be disturbed.
305
306 - A minor complaint is that resetting the network card causes
307 user-space back-to-back ifdown/ifup burps that potentially disturb
308 network daemons, that didn't need to even know that the pci
309 card was being rebooted.
310
311 - A more serious concern is that the same reset, for SCSI devices,
312 causes havoc to mounted file systems. Scripts cannot post-facto
313 unmount a file system without flushing pending buffers, but this
314 is impossible, because I/O has already been stopped. Thus,
315 ideally, the reset should happen at or below the block layer,
316 so that the file systems are not disturbed.
317
318 Ext3fs seems to be tolerant, retrying reads/writes until it does
319 succeed. Both have been only lightly tested in this scenario.
320
321 The SCSI-generic subsystem already has built-in code for performing
322 SCSI device resets, SCSI bus resets, and SCSI host-bus-adapter
323 (HBA) resets. These are cascaded into a chain of attempted
324 resets if a SCSI command fails. These are completely hidden
325 from the block layer. It would be very natural to add an EEH
326 reset into this chain of events.
327
328 - If a SCSI error occurs for the root device, all is lost unless
329 the sysadmin had the foresight to run /bin, /sbin, /etc, /var
330 and so on, out of ramdisk/tmpfs.
331
332
333 Conclusions
334 -----------
335 There's forward progress ...
336

3. 한국어 전문 번역

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

EEH 개요

1-33

저자는 Linas Vepstas이며 문서 날짜는 2005년 1월 12일입니다. IBM POWER 기반 pSeries와 iSeries의 PCI bus controller는 다양한 PCI bus error를 감지하고 보고하는 Enhanced Error Handling (`EEH`) 기능을 제공합니다.

EEH hardware는 OS를 reboot하지 않고 PCI bus error를 clear하고 개별 PCI card를 다시 시작할 수 있게 합니다. 전통적 PCI에서는 chip이 CPU에 직접 연결되어 error가 CPU machine-check/check-stop을 일으켜 CPU 전체를 멈추거나, error를 무시해 user/kernel data corruption, adapter hang, system crash/lockup을 초래했습니다.

EEH의 목적은 OS를 PCI error에서 보호하고 개별 device를 recover해 system 신뢰성과 견고성을 높이는 것입니다. PCI-E specification 기반의 다른 vendor system도 미래에 비슷한 기능을 제공할 수 있습니다.

EEH error 원인

34-56

EEH는 원래 열, 습기, 먼지, 진동, 불량 electrical connection으로 PCI card가 고장 나는 hardware failure를 막기 위해 설계되었습니다. 실제 error의 대부분은 card가 slot에 제대로 꽂히지 않았거나 device-driver bug, firmware bug, PCI-card hardware bug 때문에 발생합니다.

가장 흔한 software bug는 device가 자기 card에 DMA access로 reserve되지 않은 system-memory location으로 DMA를 시도하는 것입니다. EEH는 bad DMA가 만들었을 silent memory corruption을 막으며, 이 방식으로 여러 driver bug가 발견되고 수정되었습니다.

다른 원인은 data/address line parity error와 PCI-X split-completion error입니다. 실제 hardware failure의 대다수는 PCI card를 물리적으로 빼서 다시 제대로 꽂으면 해결됩니다.

PHB isolation과 일반 recovery

57-112

PCI Host Bridge (`PHB`)가 PCI error를 감지하면 영향받은 card를 isolate합니다. Isolation은 system에서 card로, card에서 system으로 가는 모든 write를 막고 8/16/32-bit read가 각각 `0xff`, `0xffff`, `0xffffffff`를 반환하게 합니다. 이는 slot에서 device를 물리적으로 뺐을 때와 같은 값입니다.

PCI memory, I/O space, config space access가 모두 isolation 대상이지만 interrupt는 계속 전달됩니다.

Detection과 recovery는 ppc64 firmware의 Run-Time Abstraction Services (`RTAS`)를 통해 수행합니다. Linux가 여러 chipset의 서로 다른 interface와 quirk를 직접 다루지 않도록 firmware가 pSeries/iSeries 전체에 uniform하고 forward-compatible한 abstraction을 제공합니다.

OS나 driver가 slot isolation을 의심하면 firmware call로 확인합니다. 실제 isolation이면 driver는 pending work를 끝낼 수 없다는 전제에서 consistent state로 전환하고 card recovery를 시작합니다.

일반 recovery는 PCI #RST line을 2초 동안 assert해 device를 reset하고 BAR, latency timer, cache-line size, interrupt line 등의 config space를 재설정한 다음 driver를 다시 initialize합니다. Hot-plug slot에서는 최악의 경우 card power를 cycle할 수 있습니다. 상위 layer는 reset 동안 Ethernet/disk/USB I/O가 잠시 멈추는 것 외에는 card reboot를 몰라야 이상적입니다.

3~4회 reset 뒤에도 recover하지 못하면 card가 완전히 죽었다고 보고 sysadmin에게 알립니다. RTAS와 `syslogd`의 `/var/log/messages`에도 reset error를 기록합니다. 고장 adapter는 표준 PCI hotplug tool로 제거하고 교체해야 합니다.

EEH isolation과 recovery
PHB detects PCI errorSlot isolationReads = all-FF, writes blockedRTAS confirms EEHDriver quiesceReset/config restoreDriver reinitialize

PHB가 faulting card를 격리한 뒤 firmware와 driver가 단계적으로 복구합니다.

현재 PPC64 Linux EEH 구현

113-174

현재 구현은 개별 driver 변경 없이 동작하는 generic EEH recovery mechanism입니다. PCI hotplug infrastructure를 활용하고 userspace/udev까지 event를 전달합니다.

EEH는 boot 아주 초기에 PHB별로, 그리고 PCI slot hotplug 때 enable해야 합니다. Boot path는 `arch/powerpc/platforms/pseries/eeh.c`의 `eeh_init()`이, hotplug path는 `drivers/pci/hotplug/pSeries_pci.c`가 eeh.c를 호출해 수행합니다. Device PCI scan보다 먼저 enable해야 합니다.

Power5 hardware는 EEH가 없으면 동작하지 않고 older Power4만 disable 상태로 실행할 수 있으므로 사실상 EEH를 끌 수 없습니다. 모든 PCI device는 EEH code에 등록되어야 하며, error detection을 위해 device의 I/O address range를 알아야 합니다. 임의 address에 대응하는 device는 `pci_get_device_by_addr()`로 찾습니다.

`arch/powerpc/include/asm/io.h`의 기본 `readb()`, `inb()`, `insb()` 등은 I/O read가 all-`0xff`인지 검사합니다. 그러면 `eeh_dn_check_failure()`가 firmware에 실제 EEH error인지 묻고, 아니라면 정상 처리합니다. False alarm 총계는 변경 가능성이 있는 `/proc/ppc64/eeh`에서 볼 수 있으며 대부분 PCI scan이 많은 `0xff` read를 만드는 boot 중 발생합니다.

Frozen slot을 감지하면 `arch/powerpc/platforms/pseries/eeh.c`가 `/var/log/messages`에 stack trace를 기록합니다. Error 자체가 보통 조금 앞서 발생하므로 이 trace는 driver author가 detection 지점을 찾는 데 유용합니다.

그 다음 notifier chain/work queue로 failure event를 배포합니다. Driver나 다른 kernel component는 `eeh_register_notifier(struct notifier_block *)`로 등록하고 PCI device pointer, device node, state 정보를 받습니다.

eeh.c exportRecovery 역할
`rtas_set_slot_reset()`PCI `#RST` line을 1/8초 동안 assert
`rtas_configure_bridge()`Firmware에 해당 slot 아래 PCI bridge 구성을 요청
`eeh_save_bars()` / `eeh_restore_bars()`Device와 하위 device의 PCI config-space 정보를 저장/복원
Kernel EEH detection path
`readb()/inb()/insb()`All-FF?`eeh_dn_check_failure()`RTAS 확인EEH notifier/work queue
All-FF false positive정상 처리`/proc/ppc64/eeh` count

All-FF read는 firmware 확인 뒤 notifier event 또는 정상 처리로 갈립니다.

Hotplug handler recovery sequence

175-188

`drivers/pci/hotplug/pSeries_pci.c`의 `handle_eeh_events()`가 EEH `notifier_block` event를 처리합니다. 먼저 device BAR를 저장하고 `rpaphp_unconfig_pci_adapter()`를 호출해 card driver를 stop합니다.

Driver stop은 userspace로 uevent를 보내 Ethernet card의 `ifdown eth0` 같은 script를 trigger합니다. Handler는 script가 끝날 시간을 주려고 5초 sleep한 뒤 PCI card를 reset하고 BAR와 하위 bridge를 재구성합니다.

마지막으로 `rpaphp_enable_pci_slot()`이 driver를 재시작하고 `ifup eth0` 같은 추가 userspace event를 trigger합니다.

`handle_eeh_events()` recovery
Save BARs`rpaphp_unconfig_pci_adapter()`Driver stop + uevent5초 대기Card resetBAR/bridge restore`rpaphp_enable_pci_slot()`Driver restart + uevent

Hotplug unconfigure/reconfigure가 userspace network action을 사이에 둡니다.

Device shutdown call chain

189-255

PCI slot unconfigure의 첫 단계에서 pcnet32 driver close function까지 이어지는 원문 call sequence는 다음과 같습니다.

rpa_php_unconfig_pci_adapter (struct slot *)  // in rpaphp_pci.c
{
  calls
  pci_remove_bus_device (struct pci_dev *) // in /drivers/pci/remove.c
  {
    calls
    pci_destroy_dev (struct pci_dev *)
    {
      calls
      device_unregister (&dev->dev) // in /drivers/base/core.c
      {
        calls
        device_del (struct device *)
        {
          calls
          bus_remove_device() // in /drivers/base/bus.c
          {
            calls
            device_release_driver()
            {
              calls
              struct device_driver->remove() which is just
              pci_device_remove()  // in /drivers/pci/pci_driver.c
              {
                calls
                struct pci_driver->remove() which is just
                pcnet32_remove_one() // in /drivers/net/pcnet32.c
                {
                  calls
                  unregister_netdev() // in /net/core/dev.c
                  {
                    calls
                    dev_close()  // in /net/core/dev.c
                    {
                       calls dev->stop();
                       which is just pcnet32_close() // in pcnet32.c
                       {
                         which does what you wanted
                         to stop the device
                       }
                    }
                 }
               which
               frees pcnet32 device driver memory
            }
 }}}}}}

핵심 경로는 `rpa_php_unconfig_pci_adapter()` → `pci_remove_bus_device()` → `pci_destroy_dev()` → `device_unregister()` → `device_del()` → `bus_remove_device()` → `device_release_driver()` → `pci_device_remove()` → `pcnet32_remove_one()` → `unregister_netdev()` → `dev_close()` → `pcnet32_close()`입니다.

`pcnet32_close()`가 device를 실제로 stop하고, 상위 remove path는 pcnet32 driver memory를 free합니다. 원문 247~253행은 `drivers/pci/pci_driver.c`에서 시작하는 같은 tail sequence를 다시 요약합니다.

EEH device shutdown
RPA hotplugPCI device removalDriver core releasePCI driver `remove()`pcnet32 unregisterNetwork `dev_close()``pcnet32_close()`

중첩 pseudo-code를 subsystem 경계별 흐름으로 재구성했습니다.

Userspace uevent call chain

256-296

PCI device unconfigure가 userspace script에 event를 보내는 대응 call trace는 다음과 같습니다.

rpa_php_unconfig_pci_adapter() {             // in rpaphp_pci.c
  calls
  pci_remove_bus_device (struct pci_dev *) { // in /drivers/pci/remove.c
    calls
    pci_destroy_dev (struct pci_dev *) {
      calls
      device_unregister (&dev->dev) {        // in /drivers/base/core.c
        calls
        device_del(struct device * dev) {    // in /drivers/base/core.c
          calls
          kobject_del() {                    //in /libs/kobject.c
            calls
            kobject_uevent() {               // in /libs/kobject.c
              calls
              kset_uevent() {                // in /lib/kobject.c
                calls
                kset->uevent_ops->uevent()   // which is really just
                a call to
                dev_uevent() {               // in /drivers/base/core.c
                  calls
                  dev->bus->uevent() which is really just a call to
                  pci_uevent () {            // in drivers/pci/hotplug.c
                    which prints device name, etc....
                 }
               }
               then kobject_uevent() sends a netlink uevent to userspace
               --> userspace uevent
               (during early boot, nobody listens to netlink events and
               kobject_uevent() executes uevent_helper[], which runs the
               event process /sbin/hotplug)
           }
         }
         kobject_del() then calls sysfs_remove_dir(), which would
         trigger any user-space daemon that was watching /sysfs,
         and notice the delete event.

핵심 경로는 `device_del()` → `kobject_del()` → `kobject_uevent()` → `kset_uevent()` → `dev_uevent()` → PCI bus의 `pci_uevent()`입니다. `pci_uevent()`가 device name 등을 기록하고 `kobject_uevent()`가 netlink uevent를 userspace로 보냅니다.

Early boot에서 netlink listener가 없으면 `kobject_uevent()`가 `uevent_helper[]`를 실행해 `/sbin/hotplug` event process를 시작합니다. 이후 `kobject_del()`은 `sysfs_remove_dir()`을 호출하므로 sysfs를 감시하던 daemon도 delete event를 알아챌 수 있습니다.

EEH userspace event delivery
`device_del()``kobject_del()``kobject_uevent()``kset_uevent()``dev_uevent()``pci_uevent()`Netlink userspace event
Early boot`uevent_helper[]``/sbin/hotplug`
`kobject_del()``sysfs_remove_dir()`Watching daemon delete event

Driver-core delete가 kobject와 PCI uevent를 거쳐 userspace에 도달합니다.

현재 설계의 장단점

297-332

현재 generic design의 가장 큰 장점은 개별 device driver를 바꾸지 않아도 넓은 범위를 보호한다는 점입니다. 가장 큰 단점은 영향을 받을 필요가 없던 network daemon과 filesystem까지 방해할 수 있다는 점입니다.

  • Network card reset은 연속 `ifdown`/`ifup` userspace 동작을 만들어 card reboot를 몰라도 될 network daemon을 흔들 수 있습니다.
  • SCSI device reset은 mounted filesystem에 더 심각한 문제를 만듭니다. I/O가 이미 멈춘 뒤에는 pending buffer를 flush하며 unmount할 수 없으므로 reset을 block layer 이하에서 처리해 filesystem을 건드리지 않는 것이 이상적입니다.
  • Ext3fs는 성공할 때까지 read/write를 retry해 이 상황을 견디는 것으로 보이지만 가볍게만 test되었습니다.
  • SCSI-generic subsystem은 command failure 때 SCSI device, bus, HBA reset을 연쇄 시도하며 이를 block layer에서 숨깁니다. 이 chain에 EEH reset을 추가하는 것이 자연스럽습니다.
  • Root device에서 SCSI error가 나면 sysadmin이 `/bin`, `/sbin`, `/etc`, `/var` 등을 ramdisk/tmpfs에 배치해 두지 않은 한 system을 복구할 수 없습니다.
Generic EEH recovery tradeoff
측면장점위험/개선 방향
Driver coverage개별 driver 수정 불필요Generic hotplug path가 불필요한 component도 건드림
Network자동 driver restart`ifdown`/`ifup`이 daemon을 교란
SCSI/filesystem기존 reset chain 활용 가능Block layer 이하에서 EEH reset을 통합해야 함

Driver 수정 없는 폭넓은 적용과 상위 subsystem 교란 사이의 균형입니다.

결론

333-335

결론적으로 EEH software recovery에는 개선할 지점이 남아 있지만 forward progress가 이루어지고 있습니다.