요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
Independent reader와 overwrite recovery
dev-kmsg:24-50각 open reader는 첫 record부터 독립적으로 읽습니다. Record가 없으면 block 또는 O_NONBLOCK의 -EAGAIN이고, overwrite를 따라잡지 못하면 -EPIPE 뒤 다음 available record로 이동합니다. 64-bit sequence로 손실량과 위치를 복원할 수 있습니다.
지원 seek와 historical errors
dev-kmsg:52-71SEEK_SET·SEEK_END·SEEK_DATA의 offset 0만 지원합니다. Non-zero offset은 -ESPIPE, SEEK_CUR 같은 다른 operation은 -EINVAL이며 historical userspace compatibility 때문에 유지됩니다.
Record prefix·text·context format
dev-kmsg:73-100Comma-separated prefix는 syslog value, 64-bit sequence, monotonic microsecond timestamp, flags를 담고 semicolon 뒤 text가 newline까지 이어집니다. Space로 시작하는 continuation line은 machine-readable key/value context입니다.
DEVICE identity와 fragment handling
dev-kmsg:101-127DEVICE key는 block·char dev_t, netdev ifindex, subsystem:devname을 구분합니다. Flag c는 line fragment 힌트이며 interleaving될 수 있으므로 consumer가 fragment concatenation을 구현하도록 권장합니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
What: /dev/kmsg
Date: Mai 2012
KernelVersion: 3.5
Contact: Kay Sievers <kay@vrfy.org>
Description: The /dev/kmsg character device node provides userspace access
to the kernel's printk buffer.
Injecting messages:
Every write() to the opened device node places a log entry in
the kernel's printk buffer.
The logged line can be prefixed with a <N> syslog prefix, which
carries the syslog priority and facility. The single decimal
prefix number is composed of the 3 lowest bits being the syslog
priority and the next 8 bits the syslog facility number.
If no prefix is given, the priority number is the default kernel
log priority and the facility number is set to LOG_USER (1). It
is not possible to inject messages from userspace with the
facility number LOG_KERN (0), to make sure that the origin of
the messages can always be reliably determined.
Accessing the buffer:
Every read() from the opened device node receives one record
of the kernel's printk buffer.
The first read() directly following an open() always returns
first message in the buffer; there is no kernel-internal
persistent state; many readers can concurrently open the device
and read from it, without affecting other readers.
Every read() will receive the next available record. If no more
records are available read() will block, or if O_NONBLOCK is
used -EAGAIN returned.
Messages in the record ring buffer get overwritten as whole,
there are never partial messages received by read().
In case messages get overwritten in the circular buffer while
the device is kept open, the next read() will return -EPIPE,
and the seek position be updated to the next available record.
Subsequent reads() will return available records again.
Unlike the classic syslog() interface, the 64 bit record
sequence numbers allow to calculate the amount of lost
messages, in case the buffer gets overwritten. And they allow
to reconnect to the buffer and reconstruct the read position
if needed, without limiting the interface to a single reader.
The device supports seek with the following parameters:
SEEK_SET, 0
seek to the first entry in the buffer
SEEK_END, 0
seek after the last entry in the buffer
SEEK_DATA, 0
seek after the last record available at the time
the last SYSLOG_ACTION_CLEAR was issued.
Other seek operations or offsets are not supported because of
the special behavior this device has. The device allows to read
or write only whole variable length messages (records) that are
stored in a ring buffer.
Because of the non-standard behavior also the error values are
non-standard. -ESPIPE is returned for non-zero offset. -EINVAL
is returned for other operations, e.g. SEEK_CUR. This behavior
and values are historical and could not be modified without the
risk of breaking userspace.
The output format consists of a prefix carrying the syslog
prefix including priority and facility, the 64 bit message
sequence number and the monotonic timestamp in microseconds,
and a flag field. All fields are separated by a ','.
Future extensions might add more comma separated values before
the terminating ';'. Unknown fields and values should be
gracefully ignored.
The human readable text string starts directly after the ';'
and is terminated by a '\n'. Untrusted values derived from
hardware or other facilities are printed, therefore
all non-printable characters and '\' itself in the log message
are escaped by "\x00" C-style hex encoding.
A line starting with ' ', is a continuation line, adding
key/value pairs to the log message, which provide the machine
readable context of the message, for reliable processing in
userspace.
Example::
7,160,424069,-;pci_root PNP0A03:00: host bridge window [io 0x0000-0x0cf7] (ignored)
SUBSYSTEM=acpi
DEVICE=+acpi:PNP0A03:00
6,339,5140900,-;NET: Registered protocol family 10
30,340,5690716,-;udevd[80]: starting version 181
The DEVICE= key uniquely identifies devices the following way:
============ =================
b12:8 block dev_t
c127:3 char dev_t
n8 netdev ifindex
+sound:card0 subsystem:devname
============ =================
The flags field carries '-' by default. A 'c' indicates a
fragment of a line. Note, that these hints about continuation
lines are not necessarily correct, and the stream could be
interleaved with unrelated messages, but merging the lines in
the output usually produces better human readable results. A
similar logic is used internally when messages are printed to
the console, /proc/kmsg or the syslog() syscall.
By default, kernel tries to avoid fragments by concatenating
when it can and fragments are rare; however, when extended
console support is enabled, the in-kernel concatenation is
disabled and /dev/kmsg output will contain more fragments. If
the log consumer performs concatenation, the end result
should be the same. In the future, the in-kernel concatenation
may be removed entirely and /dev/kmsg users are recommended to
implement fragment handling.
Users: dmesg(1), userspace kernel log consumers
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
Printk buffer에 message 주입
1-22| 항목 | 내용 |
|---|---|
| What | /dev/kmsg |
| Date | Mai 2012, 원문 표기 |
| KernelVersion | 3.5 |
| Contact | Kay Sievers <kay@vrfy.org> |
| Description | /dev/kmsg character device node는 kernel printk buffer에 대한 userspace access를 제공합니다. |
열린 device node에 write()할 때마다 kernel printk buffer에 log entry 하나를 넣습니다.
기록할 line 앞에는 syslog priority와 facility를 전달하는 <N> syslog prefix를 붙일 수 있습니다. 이 하나의 decimal prefix number에서 가장 낮은 3 bits는 syslog priority이고 그다음 8 bits는 syslog facility number입니다.
Prefix가 없으면 priority number는 default kernel log priority이고 facility number는 LOG_USER(1)로 설정됩니다. Message 출처를 언제나 신뢰성 있게 판별할 수 있도록 userspace에서 facility number LOG_KERN(0)인 message를 주입할 수는 없습니다.
Printk record ring buffer 읽기
24-50열린 device node에서 read()할 때마다 kernel printk buffer의 record 하나를 받습니다.
open() 직후 첫 read()는 항상 buffer의 첫 message를 반환합니다. Kernel 내부에 persistent state는 없습니다. 여러 reader가 device를 동시에 열어 다른 reader에 영향을 주지 않고 읽을 수 있습니다.
각 read()는 다음 available record를 받습니다. 더 available한 record가 없으면 read()가 block하고, O_NONBLOCK을 사용했다면 -EAGAIN을 반환합니다.
Record ring buffer의 message는 전체 단위로 overwrite되므로 read()가 partial message를 받는 일은 없습니다.
Device를 계속 연 상태에서 circular buffer의 message가 overwrite되면 다음 read()는 -EPIPE를 반환하고 seek position을 다음 available record로 갱신합니다. 그 뒤의 read()는 다시 available record를 반환합니다.
Classic syslog() interface와 달리 64-bit record sequence number를 이용하면 buffer overwrite 때 손실된 message 수를 계산할 수 있습니다. 또한 interface를 reader 하나로 제한하지 않고도 buffer에 다시 연결해 필요하면 read position을 재구성할 수 있습니다.
/dev/kmsg seek semantics
52-71| Seek | 의미 |
|---|---|
| SEEK_SET, 0 | Buffer의 첫 entry로 이동 |
| SEEK_END, 0 | Buffer의 마지막 entry 뒤로 이동 |
| SEEK_DATA, 0 | 마지막 SYSLOG_ACTION_CLEAR를 실행한 시점에 available했던 마지막 record 뒤로 이동 |
이 device의 특수한 동작 때문에 다른 seek operation이나 offset은 지원하지 않습니다. Device는 ring buffer에 저장된 가변 길이 message, 즉 record 전체 단위로만 읽고 쓸 수 있습니다.
동작이 표준적이지 않으므로 error value도 표준적이지 않습니다. Non-zero offset에는 -ESPIPE를 반환하고 SEEK_CUR 같은 다른 operation에는 -EINVAL을 반환합니다. 이 동작과 값은 역사적으로 정해졌고 userspace를 깨뜨릴 위험 없이 변경할 수 없습니다.
/dev/kmsg output record format
73-100Output format은 priority와 facility를 포함한 syslog prefix, 64-bit message sequence number, microseconds 단위 monotonic timestamp, flag field를 전달하는 prefix로 구성됩니다. 모든 field는 comma로 구분합니다.
향후 확장에서 끝나는 semicolon 앞에 comma-separated value가 더 추가될 수 있습니다. 알 수 없는 field와 value는 문제없이 무시해야 합니다.
사람이 읽을 수 있는 text string은 semicolon 바로 뒤에서 시작해 '\n'으로 끝납니다. Hardware나 다른 facility에서 유래한 신뢰할 수 없는 값을 출력하므로 log message의 모든 non-printable character와 '\' 자체는 "\x00" C-style hex encoding으로 escape합니다.
Space로 시작하는 line은 continuation line입니다. Log message에 key/value pair를 추가해 userspace에서 신뢰성 있게 처리할 수 있는 machine-readable context를 제공합니다.
예:
7,160,424069,-;pci_root PNP0A03:00: host bridge window [io 0x0000-0x0cf7] (ignored)
SUBSYSTEM=acpi
DEVICE=+acpi:PNP0A03:00
6,339,5140900,-;NET: Registered protocol family 10
30,340,5690716,-;udevd[80]: starting version 181
DEVICE key와 line fragment
101-127DEVICE= key는 다음 방식으로 device를 고유하게 식별합니다.
| 표현 | 식별 대상 |
|---|---|
| b12:8 | block dev_t |
| c127:3 | char dev_t |
| n8 | netdev ifindex |
| +sound:card0 | subsystem:devname |
Flags field는 기본적으로 '-'를 전달합니다. 'c'는 line fragment를 나타냅니다. Continuation line에 관한 이 hint가 반드시 정확하지는 않고 stream에 관련 없는 message가 끼어들 수 있지만, output line을 합치면 대개 사람이 읽기 좋은 결과가 됩니다. Console, /proc/kmsg 또는 syslog() syscall에 message를 출력할 때도 내부적으로 비슷한 logic을 사용합니다.
기본적으로 kernel은 가능할 때 fragment를 concatenate해 fragment 생성을 피하므로 fragment는 드뭅니다. 하지만 extended console support를 활성화하면 in-kernel concatenation을 비활성화하므로 /dev/kmsg output에 fragment가 더 많아집니다. Log consumer가 concatenation을 수행하면 최종 결과는 같아야 합니다. 향후 in-kernel concatenation을 완전히 제거할 수도 있으므로 /dev/kmsg user는 fragment handling을 구현하는 것이 좋습니다.
| Users | 내용 |
|---|---|
| Consumers | dmesg(1), userspace kernel log consumers |
Writer는 whole record를 ring에 넣고 각 reader는 독립 sequence cursor로 소비하며 overwrite와 fragment를 명시적으로 처리한다.
Userspace message injection
dev-kmsg:1-22각 write는 printk buffer에 record 하나를 넣습니다. <N>의 하위 3 bits는 priority, 다음 8 bits는 facility이며 prefix가 없으면 default kernel priority와 LOG_USER(1)를 사용합니다. Userspace는 LOG_KERN(0)을 주입할 수 없습니다.