← Documents Documentation/admin-guide/ramoops.rst GitHub 원문 ↗

Linux 6.18.37 · Administration

Ramoops oops/panic logger

Persistent RAM에 oops, panic, function trace를 보존하는 ramoops의 memory layout, 설정 경로, ECC, dump 회수를 설명합니다.

Source pathDocumentation/admin-guide/ramoops.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

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

1. 요약·해설

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

요약과 해설

ramoops.rst:1-177

Ramoops는 crash 직전의 kmsg와 function trace를 persistent RAM에 기록해 reboot 뒤 pstore에서 회수합니다. 저장 영역은 고정 크기 record로 나뉘며 restart 뒤 counter가 초기화되면 새 dump가 오래된 record를 덮어쓸 수 있습니다.

안정적인 구성에서는 platform의 atomic operation 특성에 맞는 `mem_type`을 고르고 memory reservation이 다른 allocator와 충돌하지 않게 해야 합니다. `reserve_mem`은 위치가 달라질 수 있으므로 고정 Device Tree나 platform data보다 신뢰도가 낮은 best-effort 선택입니다.

영역핵심
저장 위치`mem_address`, `mem_size`, `mem_name`/`reserve_mem`
Memory mapping`mem_type=0` write-combine, `1` noncached, `2` normal cached
Record`record_size` 단위 circular buffer; 크기는 2의 거듭제곱으로 내림
Dump filter`max_reason`과 `enum kmsg_dump_reason`
복구력Software ECC로 reset 뒤 일부 RAM 손상 복구 가능
설정 경로Module parameter, Device Tree, platform data, `reserve_mem`
읽기·삭제pstore의 `dmesg-ramoops-N`; unlink로 RAM record 삭제
Tracing`record_ftrace`를 켜고 reboot 뒤 `ftrace-ramoops` 확인

2. 영어 원문 전체

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

원문 전체 펼치기
1 Ramoops oops/panic logger
2 =========================
3
4 Sergiu Iordache <[email protected]>
5
6 Updated: 10 Feb 2021
7
8 Introduction
9 ------------
10
11 Ramoops is an oops/panic logger that writes its logs to RAM before the system
12 crashes. It works by logging oopses and panics in a circular buffer. Ramoops
13 needs a system with persistent RAM so that the content of that area can
14 survive after a restart.
15
16 Ramoops concepts
17 ----------------
18
19 Ramoops uses a predefined memory area to store the dump. The start and size
20 and type of the memory area are set using three variables:
21
22 * ``mem_address`` for the start
23 * ``mem_size`` for the size. The memory size will be rounded down to a
24 power of two.
25 * ``mem_type`` to specify if the memory type (default is pgprot_writecombine).
26 * ``mem_name`` to specify a memory region defined by ``reserve_mem`` command
27 line parameter.
28
29 Typically the default value of ``mem_type=0`` should be used as that sets the pstore
30 mapping to pgprot_writecombine. Setting ``mem_type=1`` attempts to use
31 ``pgprot_noncached``, which only works on some platforms. This is because pstore
32 depends on atomic operations. At least on ARM, pgprot_noncached causes the
33 memory to be mapped strongly ordered, and atomic operations on strongly ordered
34 memory are implementation defined, and won't work on many ARMs such as omaps.
35 Setting ``mem_type=2`` attempts to treat the memory region as normal memory,
36 which enables full cache on it. This can improve the performance.
37
38 The memory area is divided into ``record_size`` chunks (also rounded down to
39 power of two) and each kmesg dump writes a ``record_size`` chunk of
40 information.
41
42 Limiting which kinds of kmsg dumps are stored can be controlled via
43 the ``max_reason`` value, as defined in include/linux/kmsg_dump.h's
44 ``enum kmsg_dump_reason``. For example, to store both Oopses and Panics,
45 ``max_reason`` should be set to 2 (KMSG_DUMP_OOPS), to store only Panics
46 ``max_reason`` should be set to 1 (KMSG_DUMP_PANIC). Setting this to 0
47 (KMSG_DUMP_UNDEF), means the reason filtering will be controlled by the
48 ``printk.always_kmsg_dump`` boot param: if unset, it'll be KMSG_DUMP_OOPS,
49 otherwise KMSG_DUMP_MAX.
50
51 The module uses a counter to record multiple dumps but the counter gets reset
52 on restart (i.e. new dumps after the restart will overwrite old ones).
53
54 Ramoops also supports software ECC protection of persistent memory regions.
55 This might be useful when a hardware reset was used to bring the machine back
56 to life (i.e. a watchdog triggered). In such cases, RAM may be somewhat
57 corrupt, but usually it is restorable.
58
59 Setting the parameters
60 ----------------------
61
62 Setting the ramoops parameters can be done in several different manners:
63
64 A. Use the module parameters (which have the names of the variables described
65 as before). For quick debugging, you can also reserve parts of memory during
66 boot and then use the reserved memory for ramoops. For example, assuming a
67 machine with > 128 MB of memory, the following kernel command line will tell
68 the kernel to use only the first 128 MB of memory, and place ECC-protected
69 ramoops region at 128 MB boundary::
70
71 mem=128M ramoops.mem_address=0x8000000 ramoops.ecc=1
72
73 B. Use Device Tree bindings, as described in
74 ``Documentation/devicetree/bindings/reserved-memory/ramoops.yaml``.
75 For example::
76
77 reserved-memory {
78 #address-cells = <2>;
79 #size-cells = <2>;
80 ranges;
81
82 ramoops@8f000000 {
83 compatible = "ramoops";
84 reg = <0 0x8f000000 0 0x100000>;
85 record-size = <0x4000>;
86 console-size = <0x4000>;
87 };
88 };
89
90 C. Use a platform device and set the platform data. The parameters can then
91 be set through that platform data. An example of doing that is:
92
93 .. code-block:: c
94
95 #include <linux/pstore_ram.h>
96 [...]
97
98 static struct ramoops_platform_data ramoops_data = {
99 .mem_size = <...>,
100 .mem_address = <...>,
101 .mem_type = <...>,
102 .record_size = <...>,
103 .max_reason = <...>,
104 .ecc = <...>,
105 };
106
107 static struct platform_device ramoops_dev = {
108 .name = "ramoops",
109 .dev = {
110 .platform_data = &ramoops_data,
111 },
112 };
113
114 [... inside a function ...]
115 int ret;
116
117 ret = platform_device_register(&ramoops_dev);
118 if (ret) {
119 printk(KERN_ERR "unable to register platform device\n");
120 return ret;
121 }
122
123 D. Using a region of memory reserved via ``reserve_mem`` command line
124 parameter. The address and size will be defined by the ``reserve_mem``
125 parameter. Note, that ``reserve_mem`` may not always allocate memory
126 in the same location, and cannot be relied upon. Testing will need
127 to be done, and it may not work on every machine, nor every kernel.
128 Consider this a "best effort" approach. The ``reserve_mem`` option
129 takes a size, alignment and name as arguments. The name is used
130 to map the memory to a label that can be retrieved by ramoops.
131
132 reserve_mem=2M:4096:oops ramoops.mem_name=oops
133
134 You can specify either RAM memory or peripheral devices' memory. However, when
135 specifying RAM, be sure to reserve the memory by issuing memblock_reserve()
136 very early in the architecture code, e.g.::
137
138 #include <linux/memblock.h>
139
140 memblock_reserve(ramoops_data.mem_address, ramoops_data.mem_size);
141
142 Dump format
143 -----------
144
145 The data dump begins with a header, currently defined as ``====`` followed by a
146 timestamp and a new line. The dump then continues with the actual data.
147
148 Reading the data
149 ----------------
150
151 The dump data can be read from the pstore filesystem. The format for these
152 files is ``dmesg-ramoops-N``, where N is the record number in memory. To delete
153 a stored record from RAM, simply unlink the respective pstore file.
154
155 Persistent function tracing
156 ---------------------------
157
158 Persistent function tracing might be useful for debugging software or hardware
159 related hangs. The functions call chain log is stored in a ``ftrace-ramoops``
160 file. Here is an example of usage::
161
162 # mount -t debugfs debugfs /sys/kernel/debug/
163 # echo 1 > /sys/kernel/debug/pstore/record_ftrace
164 # reboot -f
165 [...]
166 # mount -t pstore pstore /mnt/
167 # tail /mnt/ftrace-ramoops
168 0 ffffffff8101ea64 ffffffff8101bcda native_apic_mem_read <- disconnect_bsp_APIC+0x6a/0xc0
169 0 ffffffff8101ea44 ffffffff8101bcf6 native_apic_mem_write <- disconnect_bsp_APIC+0x86/0xc0
170 0 ffffffff81020084 ffffffff8101a4b5 hpet_disable <- native_machine_shutdown+0x75/0x90
171 0 ffffffff81005f94 ffffffff8101a4bb iommu_shutdown_noop <- native_machine_shutdown+0x7b/0x90
172 0 ffffffff8101a6a1 ffffffff8101a437 native_machine_emergency_restart <- native_machine_restart+0x37/0x40
173 0 ffffffff811f9876 ffffffff8101a73a acpi_reboot <- native_machine_emergency_restart+0xaa/0x1e0
174 0 ffffffff8101a514 ffffffff8101a772 mach_reboot_fixups <- native_machine_emergency_restart+0xe2/0x1e0
175 0 ffffffff811d9c54 ffffffff8101a7a0 __const_udelay <- native_machine_emergency_restart+0x110/0x1e0
176 0 ffffffff811d9c34 ffffffff811d9c80 __delay <- __const_udelay+0x30/0x40
177 0 ffffffff811d9d14 ffffffff811d9c3f delay_tsc <- __delay+0xf/0x20
178

3. 한국어 전문 번역

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

소개, memory 구성, ECC

1-58

이 문서의 제목은 'Ramoops oops/panic logger'이며 Sergiu Iordache `<[email protected]>`가 작성했고 2021년 2월 10일에 갱신되었습니다.

Ramoops는 system이 crash하기 전에 log를 RAM에 쓰는 oops/panic logger입니다. Oops와 panic을 circular buffer에 기록하며, restart 뒤에도 해당 영역의 content가 살아남는 persistent RAM system이 필요합니다.

Ramoops는 미리 정한 memory area에 dump를 저장합니다. `mem_address`는 시작 주소, `mem_size`는 크기이며 2의 거듭제곱으로 내림합니다. `mem_type`은 memory type을 정하고 기본 mapping은 `pgprot_writecombine`입니다. `mem_name`은 `reserve_mem` command-line parameter로 정의한 memory region을 지정합니다.

일반적으로 `mem_type=0`을 사용해야 합니다. 이 값은 pstore mapping을 `pgprot_writecombine`으로 설정합니다. `mem_type=1`은 `pgprot_noncached`를 시도하지만 일부 platform에서만 동작합니다.

제한의 이유는 pstore가 atomic operation에 의존하기 때문입니다. 적어도 ARM에서 `pgprot_noncached`는 memory를 strongly ordered로 mapping하고, strongly ordered memory의 atomic operation은 implementation-defined라 OMAP을 포함한 많은 ARM에서 동작하지 않습니다.

`mem_type=2`는 memory region을 normal memory로 취급해 full cache를 사용하며 성능을 높일 수 있습니다.

Memory area는 `record_size` chunk로 나뉘며 이 크기도 2의 거듭제곱으로 내림합니다. Kmesg dump 하나는 `record_size`만큼의 정보 chunk 하나를 기록합니다.

저장할 kmsg dump 종류는 `include/linux/kmsg_dump.h`의 `enum kmsg_dump_reason`에 정의된 `max_reason`으로 제한합니다. Oops와 panic을 모두 저장하려면 `max_reason=2`, 즉 `KMSG_DUMP_OOPS`를 사용하고 panic만 저장하려면 `max_reason=1`, 즉 `KMSG_DUMP_PANIC`을 사용합니다.

`max_reason=0`, 즉 `KMSG_DUMP_UNDEF`이면 `printk.always_kmsg_dump` boot parameter가 reason filtering을 제어합니다. Parameter가 설정되지 않으면 `KMSG_DUMP_OOPS`, 설정되면 `KMSG_DUMP_MAX`가 됩니다.

Module은 counter로 여러 dump를 기록하지만 restart 때 counter가 reset되므로 restart 뒤의 새 dump가 이전 dump를 덮어씁니다.

Ramoops는 persistent memory region의 software ECC 보호도 지원합니다. Watchdog trigger 같은 hardware reset으로 machine을 되살렸을 때 RAM이 일부 손상될 수 있지만 대개 복구 가능하므로 유용합니다.

Parameter 설정 방법

59-141

Ramoops parameter는 여러 방식으로 설정할 수 있습니다. 첫째, 앞에서 설명한 variable과 같은 이름의 module parameter를 사용합니다. 빠른 debugging에서는 boot 중 memory 일부를 예약하고 그 영역을 ramoops에 쓸 수도 있습니다.

Memory가 128MB보다 큰 machine에서 다음 kernel command line은 kernel이 처음 128MB만 사용하게 하고, 128MB 경계에 ECC로 보호한 ramoops region을 둡니다.

mem=128M ramoops.mem_address=0x8000000 ramoops.ecc=1

둘째, `Documentation/devicetree/bindings/reserved-memory/ramoops.yaml`에 설명된 Device Tree binding을 사용합니다. 다음 예제는 `0x8f000000`에서 1MB를 예약하고 record와 console에 각각 `0x4000` byte를 할당합니다.

reserved-memory {
        #address-cells = <2>;
        #size-cells = <2>;
        ranges;

        ramoops@8f000000 {
                compatible = "ramoops";
                reg = <0 0x8f000000 0 0x100000>;
                record-size = <0x4000>;
                console-size = <0x4000>;
        };
};

셋째, platform device를 만들고 platform data로 parameter를 설정합니다. 다음 C 예제는 `struct ramoops_platform_data`에 memory, record, dump reason, ECC 값을 넣고 `platform_device_register()`로 `ramoops` device를 등록합니다.

#include <linux/pstore_ram.h>
[...]

static struct ramoops_platform_data ramoops_data = {
      .mem_size               = <...>,
      .mem_address            = <...>,
      .mem_type               = <...>,
      .record_size            = <...>,
      .max_reason             = <...>,
      .ecc                    = <...>,
};

static struct platform_device ramoops_dev = {
      .name = "ramoops",
      .dev = {
              .platform_data = &ramoops_data,
      },
};

[... inside a function ...]
int ret;

ret = platform_device_register(&ramoops_dev);
if (ret) {
      printk(KERN_ERR "unable to register platform device\n");
      return ret;
}

넷째, `reserve_mem` command-line parameter로 예약한 memory region을 사용합니다. Address와 size는 `reserve_mem`이 정합니다. 다만 이 옵션은 항상 같은 위치에 memory를 할당하지 않아 신뢰할 수 없고 machine이나 kernel에 따라 동작하지 않을 수 있으므로 test가 필요합니다. Best-effort 방식으로 취급해야 합니다.

`reserve_mem` option은 size, alignment, name을 argument로 받습니다. Name은 memory를 ramoops가 가져올 수 있는 label에 mapping합니다.

reserve_mem=2M:4096:oops  ramoops.mem_name=oops

RAM memory와 peripheral device memory를 모두 지정할 수 있습니다. RAM을 지정한다면 architecture code의 매우 이른 시점에 `memblock_reserve()`를 호출해 반드시 그 memory를 예약해야 합니다.

#include <linux/memblock.h>

memblock_reserve(ramoops_data.mem_address, ramoops_data.mem_size);

Dump 형식, 읽기, 삭제

142-154

Data dump는 현재 `====`로 정의된 header로 시작하고 그 뒤에 timestamp와 newline이 옵니다. 이어서 실제 data가 기록됩니다.

Dump data는 pstore filesystem에서 읽습니다. File 형식은 `dmesg-ramoops-N`이며 `N`은 memory의 record number입니다. RAM에 저장된 record를 삭제하려면 해당 pstore file을 unlink하면 됩니다.

Persistent function tracing

155-177

Persistent function tracing은 software 또는 hardware 관련 hang을 debug할 때 유용할 수 있습니다. Function call chain log는 `ftrace-ramoops` file에 저장됩니다. 다음은 사용 예제와 실제 trace 일부입니다.

# mount -t debugfs debugfs /sys/kernel/debug/
# echo 1 > /sys/kernel/debug/pstore/record_ftrace
# reboot -f
[...]
# mount -t pstore pstore /mnt/
# tail /mnt/ftrace-ramoops
0 ffffffff8101ea64  ffffffff8101bcda  native_apic_mem_read <- disconnect_bsp_APIC+0x6a/0xc0
0 ffffffff8101ea44  ffffffff8101bcf6  native_apic_mem_write <- disconnect_bsp_APIC+0x86/0xc0
0 ffffffff81020084  ffffffff8101a4b5  hpet_disable <- native_machine_shutdown+0x75/0x90
0 ffffffff81005f94  ffffffff8101a4bb  iommu_shutdown_noop <- native_machine_shutdown+0x7b/0x90
0 ffffffff8101a6a1  ffffffff8101a437  native_machine_emergency_restart <- native_machine_restart+0x37/0x40
0 ffffffff811f9876  ffffffff8101a73a  acpi_reboot <- native_machine_emergency_restart+0xaa/0x1e0
0 ffffffff8101a514  ffffffff8101a772  mach_reboot_fixups <- native_machine_emergency_restart+0xe2/0x1e0
0 ffffffff811d9c54  ffffffff8101a7a0  __const_udelay <- native_machine_emergency_restart+0x110/0x1e0
0 ffffffff811d9c34  ffffffff811d9c80  __delay <- __const_udelay+0x30/0x40
0 ffffffff811d9d14  ffffffff811d9c3f  delay_tsc <- __delay+0xf/0x20
Persistent ftrace 기록과 회수
debugfs를 /sys/kernel/debug/에 mount/sys/kernel/debug/pstore/record_ftrace를 1로 설정Function call chain을 ftrace-ramoops 영역에 기록reboot -f로 강제 restartpstore를 mount하고 ftrace-ramoops를 읽음

Ramoops는 강제 reboot를 가로질러 function call chain을 persistent RAM에 남깁니다.