pstore 塊 oops/panic 日誌記錄器¶
簡介¶
pstore 塊 (pstore/blk) 是一個 oops/panic 日誌記錄器,它在系統崩潰之前將其日誌寫入塊裝置和非塊裝置。您可以透過掛載 pstore 檔案系統來獲取這些日誌檔案,例如
mount -t pstore pstore /sys/fs/pstore
pstore 塊概念¶
pstore/blk 為 pstore/blk 提供了高效的配置方法,它將所有配置分為兩部分,使用者配置和驅動程式配置。
使用者配置決定了 pstore/blk 的工作方式,例如 pmsg_size、kmsg_size 等。它們都支援 Kconfig 和模組引數,但模組引數的優先順序高於 Kconfig。
驅動程式配置是關於塊裝置和非塊裝置的所有資訊,例如塊裝置的總大小和讀/寫操作。
使用者配置¶
所有這些配置都支援 Kconfig 和模組引數,但模組引數的優先順序高於 Kconfig。
這是一個模組引數的示例
pstore_blk.blkdev=/dev/mmcblk0p7 pstore_blk.kmsg_size=64 best_effort=y
您可能對每個配置的詳細資訊感興趣。
blkdev¶
要使用的塊裝置。大多數情況下,它是塊裝置的一個分割槽。pstore/blk 需要它。它也用於 MTD 裝置。
當 pstore/blk 構建為模組時,“blkdev” 接受以下變體
/dev/<disk_name> 表示磁碟的裝置號
/dev/<disk_name><decimal> 表示分割槽的裝置號 - 磁碟的裝置號加上分割槽號
/dev/<disk_name>p<decimal> - 與上述相同;當分割槽磁碟的磁碟名稱以數字結尾時,使用此形式。
當 pstore/blk 構建到核心中時,“blkdev” 接受以下變體
<hex_major><hex_minor> 十六進位制表示的裝置號,沒有前導 0x,例如 b302。
PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF 表示分割槽表的唯一 id(如果分割槽表提供)。UUID 可以是 EFI/GPT UUID,也可以使用 SSSSSSSS-PP 格式引用 MSDOS 分割槽,其中 SSSSSSSS 是 32 位 “NT 磁碟簽名” 的零填充十六進位制表示,PP 是從 1 開始的分割槽號的零填充十六進位制表示。
PARTUUID=<UUID>/PARTNROFF=<int> 用於選擇與具有已知唯一 id 的分割槽相關的分割槽。
<major>:<minor> 裝置的主裝置號和次裝置號,用冒號分隔。
它接受 MTD 裝置的以下變體
<裝置名稱> MTD 裝置名稱。建議使用 “pstore”。
<裝置號> MTD 裝置號。
kmsg_size¶
oops/panic 前端的塊大小(KB)。它**必須**是 4 的倍數。如果您不關心 oops/panic 日誌,則它是可選的。
根據剩餘空間,除了其他 pstore 前端之外,oops/panic 前端有多個塊。
pstore/blk 將逐個記錄到 oops/panic 塊,如果沒有更多可用塊,則始終覆蓋最舊的塊。
pmsg_size¶
pmsg 前端的塊大小(KB)。它**必須**是 4 的倍數。如果您不關心 pmsg 日誌,則它是可選的。
與 oops/panic 前端不同,pmsg 前端只有一個塊。
Pmsg 是使用者空間可訪問的 pstore 物件。寫入 /dev/pmsg0 的內容將附加到塊中。重新啟動後,內容在 /sys/fs/pstore/pmsg-pstore-blk-0 中可用。
console_size¶
console 前端的塊大小(KB)。它**必須**是 4 的倍數。如果您不關心 console 日誌,則它是可選的。
與 pmsg 前端類似,console 前端只有一個塊。
所有 console 日誌都將附加到塊中。重新啟動後,內容在 /sys/fs/pstore/console-pstore-blk-0 中可用。
ftrace_size¶
ftrace 前端的塊大小(KB)。它**必須**是 4 的倍數。如果您不關心 ftrace 日誌,則它是可選的。
與 oops 前端類似,ftrace 前端有多個塊,具體取決於 CPU 處理器的數量。每個塊的大小等於 ftrace_size / 處理器數量。
所有 ftrace 日誌都將附加到塊中。重新啟動後,內容被組合並在 /sys/fs/pstore/ftrace-pstore-blk-0 中可用。
永續性函式跟蹤可能對除錯軟體或硬體相關的掛起很有用。這是一個用法示例
# mount -t pstore pstore /sys/fs/pstore
# mount -t debugfs debugfs /sys/kernel/debug/
# echo 1 > /sys/kernel/debug/pstore/record_ftrace
# reboot -f
[...]
# mount -t pstore pstore /sys/fs/pstore
# tail /sys/fs/pstore/ftrace-pstore-blk-0
CPU:0 ts:5914676 c0063828 c0063b94 call_cpuidle <- cpu_startup_entry+0x1b8/0x1e0
CPU:0 ts:5914678 c039ecdc c006385c cpuidle_enter_state <- call_cpuidle+0x44/0x48
CPU:0 ts:5914680 c039e9a0 c039ecf0 cpuidle_enter_freeze <- cpuidle_enter_state+0x304/0x314
CPU:0 ts:5914681 c0063870 c039ea30 sched_idle_set_state <- cpuidle_enter_state+0x44/0x314
CPU:1 ts:5916720 c0160f59 c015ee04 kernfs_unmap_bin_file <- __kernfs_remove+0x140/0x204
CPU:1 ts:5916721 c05ca625 c015ee0c __mutex_lock_slowpath <- __kernfs_remove+0x148/0x204
CPU:1 ts:5916723 c05c813d c05ca630 yield_to <- __mutex_lock_slowpath+0x314/0x358
CPU:1 ts:5916724 c05ca2d1 c05ca638 __ww_mutex_lock <- __mutex_lock_slowpath+0x31c/0x358
max_reason¶
可以透過 max_reason 值來限制儲存哪些型別的 kmsg 轉儲,如 include/linux/kmsg_dump.h 的 enum kmsg_dump_reason 中定義。例如,要儲存 Oopses 和 Panics,max_reason 應設定為 2 (KMSG_DUMP_OOPS),要僅儲存 Panics,max_reason 應設定為 1 (KMSG_DUMP_PANIC)。將其設定為 0 (KMSG_DUMP_UNDEF) 意味著原因過濾將由 printk.always_kmsg_dump 啟動引數控制:如果未設定,則為 KMSG_DUMP_OOPS,否則為 KMSG_DUMP_MAX。
驅動程式配置¶
裝置驅動程式使用 register_pstore_device 和 struct pstore_device_info 註冊到 pstore/blk。
-
int register_pstore_device(struct pstore_device_info *dev)¶
將非塊設備註冊到 pstore/blk
引數
struct pstore_device_info *dev非塊裝置資訊
返回值
0 - OK
其他 - 發生錯誤。
-
void unregister_pstore_device(struct pstore_device_info *dev)¶
從 pstore/blk 取消註冊非塊裝置
引數
struct pstore_device_info *dev非塊裝置資訊
壓縮和標頭¶
塊裝置足夠大,可以容納未壓縮的 oops 資料。實際上,我們不建議進行資料壓縮,因為 pstore/blk 會將一些資訊插入到 oops/panic 資料的第一行。例如
Panic: Total 16 times
這意味著自第一次啟動以來,這是第 16 次發生 OOPS|Panic。有時,自第一次啟動以來發生 oops|panic 的次數對於判斷系統是否穩定很重要。
以下行由 pstore 檔案系統插入。例如
Oops#2 Part1
這意味著在上一次啟動時,這是第 2 次發生 OOPS。
讀取資料¶
可以從 pstore 檔案系統中讀取轉儲資料。這些檔案的格式為 dmesg-pstore-blk-[N] 用於 oops/panic 前端,pmsg-pstore-blk-0 用於 pmsg 前端,依此類推。轉儲檔案的時間戳記錄觸發時間。要從塊裝置中刪除儲存的記錄,只需取消連結相應的 pstore 檔案。
panic 讀/寫 API 中的注意事項¶
如果在 panic 時,核心不會執行太久,任務將不會被排程,並且大多數核心資源將停止服務。它看起來像在單核計算機上執行的單執行緒程式。
以下幾點需要特別注意 panic 讀/寫 API
**不能**分配任何記憶體。如果您需要記憶體,只需在塊驅動程式初始化時分配,而不是等到發生 panic 時才分配。
必須輪詢,**不能**中斷驅動。不再進行任務排程。塊驅動程式應延遲以確保寫入成功,但**不能**睡眠。
**不能**獲取任何鎖。沒有其他任務,也沒有任何共享資源;您可以安全地打破所有鎖。
僅使用 CPU 進行傳輸。除非您確定 DMA 不會保持鎖定,否則不要使用 DMA 進行傳輸。
直接控制暫存器。請直接控制暫存器,而不是使用 Linux 核心資源。在初始化時進行 I/O 對映,而不是等到發生 panic 時才進行。
如有必要,重置您的塊裝置和控制器。如果您不確定在發生 panic 時塊裝置和控制器的狀態,您可以安全地停止並重置它們。
pstore/blk 支援 psblk_blkdev_info(),它定義在 *linux/pstore_blk.h* 中,用於獲取有關使用塊裝置的資訊,例如裝置號、扇區計數和整個磁碟的起始扇區。
pstore 塊內部結構¶
對於開發人員參考,以下是所有重要的結構和 API
-
struct psz_buffer¶
要重新整理到儲存的區域的標頭
定義:
struct psz_buffer {
#define PSZ_SIG (0x43474244) ;
uint32_t sig;
atomic_t datalen;
atomic_t start;
uint8_t data[];
};
成員
sig指示標頭的簽名 (PSZ_SIG xor PSZONE 型別值)
datalen**data** 中資料的長度
start儲存位元組的開頭開始的 **data** 中的偏移量
data區域資料。
-
struct psz_kmsg_header¶
要重新整理到儲存的 kmsg 轉儲特定標頭
定義:
struct psz_kmsg_header {
#define PSTORE_KMSG_HEADER_MAGIC 0x4dfc3ae5 ;
uint32_t magic;
struct timespec64 time;
bool compressed;
uint32_t counter;
enum kmsg_dump_reason reason;
uint8_t data[];
};
成員
magickmsg 轉儲標頭的魔數
timekmsg 轉儲觸發時間
compressed是否壓縮
counterkmsg 轉儲計數器
reasonkmsg 轉儲原因 (例如 oops, panic 等)
data指向日誌資料的指標
說明
這是 kmsg 轉儲的子標頭,位於 psz_buffer 之後。
-
struct pstore_zone¶
單個儲存緩衝區
定義:
struct pstore_zone {
loff_t off;
const char *name;
enum pstore_type_id type;
struct psz_buffer *buffer;
struct psz_buffer *oldbuf;
size_t buffer_size;
bool should_recover;
atomic_t dirty;
};
成員
off儲存的區域偏移量
name此區域的前端名稱
type此區域的前端型別
buffer指向此區域管理的緩衝區資料的指標
oldbuf指向舊緩衝區資料的指標
buffer_size**buffer->data** 中的位元組數
should_recover此區域是否應從儲存中恢復
dirty**buffer** 中的資料是否已更改
說明
記憶體中的區域結構。
-
struct psz_context¶
關於 pstore/zone 執行狀態的所有資訊
定義:
struct psz_context {
struct pstore_zone **kpszs;
struct pstore_zone *ppsz;
struct pstore_zone *cpsz;
struct pstore_zone **fpszs;
unsigned int kmsg_max_cnt;
unsigned int kmsg_read_cnt;
unsigned int kmsg_write_cnt;
unsigned int pmsg_read_cnt;
unsigned int console_read_cnt;
unsigned int ftrace_max_cnt;
unsigned int ftrace_read_cnt;
unsigned int oops_counter;
unsigned int panic_counter;
atomic_t recovered;
atomic_t on_panic;
struct mutex pstore_zone_info_lock;
struct pstore_zone_info *pstore_zone_info;
struct pstore_info pstore;
};
成員
kpszskmsg 轉儲儲存區域
ppszpmsg 儲存區域
cpszconsole 儲存區域
fpszsftrace 儲存區域
kmsg_max_cnt**kpszs** 的最大計數
kmsg_read_cnt讀取的總 kmsg 轉儲的計數器
kmsg_write_cntkmsg 轉儲寫入的總計數器
pmsg_read_cnt讀取的總 pmsg 區域的計數器
console_read_cnt讀取的總 console 區域的計數器
ftrace_max_cnt**fpszs** 的最大計數
ftrace_read_cnt讀取的最大 ftrace 區域的計數器
oops_counteroops 轉儲的計數器
panic_counterpanic 轉儲的計數器
recovered是否完成從儲存恢復資料
on_panic是否發生 panic
pstore_zone_info_lock鎖定到 **pstore_zone_info**
pstore_zone_info來自後端的資訊
pstorepstore 的結構
-
enum psz_flush_mode¶
psz_zone_write() 的重新整理模式
常量
FLUSH_NONE不要重新整理到儲存,但更新記憶體中的資料
FLUSH_PART僅重新整理包含元資料的部分資料到儲存
FLUSH_META僅重新整理區域的元資料到儲存
FLUSH_ALL重新整理所有區域
-
int psz_recovery(struct psz_context *cxt)¶
從儲存恢復資料
引數
struct psz_context *cxtpstore/zone 的上下文
說明
恢復意味著在重新啟動後從儲存中讀取回資料
返回值
成功時返回 0,失敗時返回其他值。
-
struct pstore_zone_info¶
pstore/zone 後端驅動程式結構
定義:
struct pstore_zone_info {
struct module *owner;
const char *name;
unsigned long total_size;
unsigned long kmsg_size;
int max_reason;
unsigned long pmsg_size;
unsigned long console_size;
unsigned long ftrace_size;
pstore_zone_read_op read;
pstore_zone_write_op write;
pstore_zone_erase_op erase;
pstore_zone_write_op panic_write;
};
成員
owner負責此後端驅動程式的模組。
name後端驅動程式的名稱。
total_sizepstore/zone 可以使用的總大小(以位元組為單位)。它必須大於 4096 並且是 4096 的倍數。
kmsg_sizeoops/panic 區域的大小。零表示停用,否則,它必須是 SECTOR_SIZE(512 位元組) 的倍數。
max_reason要儲存的最大 kmsg 轉儲原因。
pmsg_sizepmsg 區域的大小,與 **kmsg_size** 相同。
console_sizeconsole 區域的大小,與 **kmsg_size** 相同。
ftrace_sizeftrace 區域的大小,與 **kmsg_size** 相同。
read通用讀取操作。函式引數 **size** 和 **offset** 都是相對於儲存的值。成功時,應返回位元組數,其他值表示錯誤。
write與 **read** 相同,但以下錯誤程式碼:-EBUSY 表示稍後嘗試再次寫入。-ENOMSG 表示嘗試下一個區域。
erase用於具有特殊刪除作業的裝置的通用擦除操作。函式引數 **size** 和 **offset** 都是相對於儲存的值。成功時返回 0,失敗時返回其他值。
panic_write僅用於 panic 情況的寫入操作。如果您不關心 panic 日誌,則是可選的。引數是相對於儲存的值。成功時,應返回位元組數,除了 -ENOMSG 之外的其他值表示錯誤。-ENOMSG 表示嘗試下一個區域。
-
struct pstore_device_info¶
後端 pstore/blk 驅動程式結構。
定義:
struct pstore_device_info {
unsigned int flags;
struct pstore_zone_info zone;
};
成員
flags請參閱 linux/pstore.h 中定義的以 PSTORE_FLAGS 開頭的宏。它表示此裝置支援哪些前端。零表示所有後端,以實現相容性。
zonestruct pstore_zone_info詳細資訊。
-
struct pstore_blk_config¶
pstore_blk 後端配置
定義:
struct pstore_blk_config {
char device[80];
enum kmsg_dump_reason max_reason;
unsigned long kmsg_size;
unsigned long pmsg_size;
unsigned long console_size;
unsigned long ftrace_size;
};
成員
device所需的塊裝置的名稱
max_reason要儲存到塊裝置的最大 kmsg 轉儲原因
kmsg_size用於 kmsg 轉儲的總大小
pmsg_sizepmsg 儲存區域的總大小
console_sizeconsole 儲存區域的總大小
ftrace_size用於 ftrace 日誌記錄資料的總大小(適用於所有 CPU)
-
int pstore_blk_get_config(struct pstore_blk_config *info)¶
獲取 pstore_blk 後端配置的副本
引數
struct pstore_blk_config *info要填充的 sturct pstore_blk_config
說明
失敗返回負錯誤程式碼,成功返回 0。