pstore
简介
pstore文件系统(是的,这是个文件系统)是Persistent Storage的缩写,最早在2010年由 Tony Luck 设计并合入Linux主分支,设计的初衷是在内核Panic/Oops时能自动转存内核日志(log_buf),在Panic重启后,把转存的日志以文件形式呈现到用户空间以分析内核崩溃问题。
这对分析那种小概率且没办法抓到现场的问题非常实用,尤其是现在智能互联网的设备逐渐普及的时候,远端的设备可以自己捕抓崩溃日志再通过网络传输到服务器,维护人员就可以根据收集来的日志定位和解决问题,然后通过OTA让设备升级迭代。
根据网上搜寻的资料,在pstore文件系统之前其实有不少类似的实现。
- apanic
 
Android最早的panic信息记录的方案。在linux 2.6的安卓的内核中找到,却没有提交到社区,后来被放弃维护了。网上找不到放弃的原因,我自己猜测是因为其只适用于mtd nand,然而现在的Android基本用的都是emmc。apanic应该是Android Panic的缩写吧,可以实现在内核崩溃时,把日志转存到mtd nand。
- ramoops
 
这里指的是最早的ramoops实现,在最新代码已经整合入pstore中,以pstore/ram的后端形式存在。ramoops可以把日志转存到重启不掉电的ram中。这里对ram有一点要求,即使重启ram的数据也不能丢失。
- crashlog
 
这是openwrt提供的内核patch,并没有提交到内核社区。它也是基于ram,只能转存Panic/Oops的日志。
- mtdoops
 
MTD子系统支持的功能,与pstore非常相似,只支持转存Panic/Oops日志,不能以文件呈现,需要用户自行解析整个MTD分区。(因为功能的相似,我实现了mtdpstore用于替代mtdoops)
- kdump
 
如果说pstore是个轻量级的内核崩溃日志转存的方案,kdump则是一个重量级的问题分析工具。在崩溃时,由kdump产生一个用于捕抓当前信息的内核,该内核会收集内存所有信息到dump core文件中。在重启后,捕抓到的信息保存在特定的文件中。类似的还有netdump和diskdump。kdump的方案适用于服务器这种有大量资源的设备,功能也非常强大,但对嵌入式设备非常不友好。
pstore经过长期迭代,除了转存Panic/Oops的日志之外(dmesg前端),还支持pmsg、console和ftrace的前端,除了pstore/ram的后端之外,还有我设计的pstore/blk后端,除了支持转存到ram之外,还有block device和mtd device。
pstore的前端,是指转存的日志类型,pstore的后端,是指转存到什么类型的设备。
目前支持以下几个前端:
- dmesg:主要是转存Panic/Oops时log_buf里面的内核日志
 - pmsg:提供给用户空间存储日志的入口,在Android里有看到被用于存储系统的日志。
 - console:终端日志
 - ftrace:function trace的信息
 
目前支持以下几种后端:
- pstore/ram:Persistent Ram,重启不会丢数据的内存
 - pstore/blk:(v5.8以后的版本)所有可写的块设备,例如磁盘、U盘、emmc、NFTL nand等
 - mtd device:(v5.8以后的版本)mtd设备,例如 mtd nand。(mtd设备的支持依赖于 pstore/blk 后端,准确来说不是一种独立后端)
 
怎么用
就像把大象装入冰箱只需要打开冰箱,把大象放进去,关上冰箱门的3个步骤,使用pstore也只需要3个步骤:
- 使能 pstore
 - 挂载 pstore文件系统
 - 读取 转存的日志文件
 
详细的说明可以看源码上的文档,本文只做基本功能的介绍。
- Documentation/admin-guide/ramoops.rst
 - Documentation/admin-guide/pstore-blk.rst
 
使能
在menuconfig中选择内核pstore模块
$ make menuconfig
|-> File systems
	|-> Miscellaneous filesystems
		|-> Persistent store support
			|-> Log kernel console messages    # console 前端
				|-> Log user space messages      # pmsg 前端
					|-> Persistent function tracer      # ftrace 前端
						|-> Log panic/oops to a RAM buffer     # pstore/ram 后端
							|-> Log panic/oops to a block device   # pstore/blk 后端
上述两个后端2选1即可,前端就根据自己的需求选择,至于dmesg前端,默认使能没得选。如果希望用在mtd设备上,还需要选择mtdpstore模块:
$ make menuconfig
	|-> Device Drivers
			|-> Memory Technology Device (MTD) support
				|-> Log panic/oops to an MTD buffer based on pstore
选上就可以用了?虽然我非常想说“是的”,但事实却有点“骨感”。即使所有前端都使用默认配置,pstore/ram至少也需要知道可用的内存范围吧?pstore/blk至少也需要知道使用哪个块设备吧?
pstore/ram支持 模块参数(cmdline)、设备树、和Platform Data的3种配置方式,从代码来看,优先级关系是:模块参数 > Platform Data > 设备树。
pstore/blk支持 Kconfig和 模块参数(cmdline)的两种配置方式,且模块参数比Kconfig有更高的优先级。
pstore/ram我接触也不多,直接介绍pstore/blk的使用方法。对新同学来说,请忽略一大堆乱七八糟的属性配置(使用默认值),只需要告诉pstore/blk后端使用哪个块设备即可。
在Kconfig中配置:
$ make menuconfig
  |-> File systems
    |-> Miscellaneous filesystems
      |-> Persistent store support
        |-> Log panic/oops to a block device   # pstore/blk 后端
          |-> () block device identifier      # 使用哪个块设备?
如果使用cmdline,可以这么写:
pstore_blk.blkdev=XXXX
或者以模块加载:
$ sudo insmod pstore_blk.ko blkdev=XXX
这里的块设备可以是代表整个磁盘的sda,也可以是代表某个分区的mmcblk0p4。虽然支持7种变体,但常用的还是两种:
- /dev/<disk_name>: 例如,使用U盘的第2个分区,则是/dev/sdb2
 - ::例如,mmc设备第6个分区,则是179:6
 
形式大概是这样:
$ sudo insmod pstore_blk.ko blkdev=/dev/sdb2
或者
$ cat /proc/cmdline.... pstore_blk.blkdev=179:6 ...
如果是mtd设备,可以直接指定mtd分区名或者编号,例如:
pstore_blk.blkdev=pstore  # 假设存在名为pstore的MTD分区
OK,对新同学来说,到这里配置就够了。可以从我的github(见参考链接[2])上看到我之前是怎么测试的。如果需要知道每个配置项的作用,还是看内核文档吧(ramoops.rst 或 pstore_blk.rst),或者在Kconfig中按h显示相关配置项的说明。
挂载
在使能且正确配置设备后,启动的时候应该会有这样的日志:
pstore_zone: registered pstore_blk as backend for kmsg(Oops,panic_write)pstore: Registered pstore_blk as persistent store backend
这代表pstore找到了设备且正常注册。接下来,我们还需要通过挂载的形式触发pstore从设备读取数据。常见的挂载是这样的:
mount -t pstore pstore /sys/fs/pstore
挂载后,通过mount能看到类似这样的信息:
mount...pstore on /sys/fs/pstore type pstore (rw,relatime)...
如果曾经触发过崩溃日志,在挂载点应该有类似这样的文件:
# ll /sys/fs/pstore...-r--r--r--    1 root     root         15521 Jan  1 00:06 dmesg-pstore_blk-0...
如果需要验证,咱们可以这样主动触发内核崩溃:
# echo c > /proc/sysrq-trigger
我是在U盘、SD卡、mmc、nand上验证的,maintainer Kees Cook 提供了另外一种基于loop的验证方法,实现用文件模拟块设备。当然这方法不适用于转存Panic日志,只能用于Oops或者其他前端:
# insmod pstore.ko compress=off# insmod pstore_zone.ko# truncate pstore-blk.raw --size 100M# losetup -f --show pstore-blk.raw/dev/loop0# insmod pstore_blk.ko blkdev=/dev/loop0 kmsg_size=16 console_size=64 best_effort=on
读取
经过上述的挂载后,可以在挂载点看到转存的日志文件。既然是文件,肯定支持文件的一系列操作,例如读取、删除。
root@TinaLinux:/sys/fs/pstore# head -n 10 dmesg-pstore_blk-1Oops: Total 2 timesOops#1 Part1<6>[    2.743794] Bluetooth: RFCOMM socket layer initialized<6>[    2.743813] Bluetooth: RFCOMM ver 1.11<6>[    2.743822] 8021q: 802.1Q VLAN Support v1.8<3>[    2.751766] reg-virt-consumer reg-virt-consumer.1: Failed to obtain supply 'drivevbus': -517<3>[    2.752330] reg-virt-consumer reg-virt-consumer.1: Failed to obtain supply 'drivevbus': -517<5>[    2.752742] ubi0: attaching mtd4<5>[    2.890302] random: crng init done<5>[    2.965927] ubi0: scanning is finished
root@TinaLinux:/sys/fs/pstore# lldrwxr-x---    2 root     root             0 Jan  1 00:11 .drwxr-xr-x    5 root     root             0 Jan  1 00:11 ..-r--r--r--    1 root     root         15521 Jan  1 00:06 dmesg-pstore_blk-0-r--r--r--    1 root     root         15128 Jan  1 00:11 dmesg-pstore_blk-1
root@TinaLinux:/sys/fs/pstore# rm dmesg-pstore_blk-1
root@TinaLinux:/sys/fs/pstore# lldrwxr-x---    2 root     root             0 Jan  1 00:13 .drwxr-xr-x    5 root     root             0 Jan  1 00:11 ..-r--r--r--    1 root     root         15521 Jan  1 00:06 dmesg-pstore_blk-0
对dmesg前端的Panic/Oops日志,pstore会自动添加两行统计信息。例如:
Oops: Total 2 times      # 表示触发了Oops,且是自系统安装后第一次启动以来第2次触发Oops。Oops#1 Part1        # 表示这是上一次运行期间第1次触发Oops的日志。
可以发现,第一行是累计总的触发次数,第二行是上一次启动触发的次数。
每个文件名的格式都是<前端名>-<后端名>-,例如dmesg-pstore_blk-1表示dmesg前端,pstore_blk后端以及是dmesg前端的第1个zone的日志。
当然,除了dmesg前端外,其他前端的名字大概是这样的:
# ll-r--r--r-- 1 root root    31 1月  15 11:53 console-pstore-blk-0-r--r--r-- 1 root root  3666 1月  15 11:53 demsg-pstore-blk-0-r--r--r-- 1 root root 65524 1月  15 11:53 ftrace-pstore-blk-0-r--r--r-- 1 root root     9 1月  15 11:53 pmsg-pstore-blk-0
除此之外,每个文件的时间戳表示 崩溃触发的时间。上例中,由于系统并没有实现同步更新系统时间,所以时间戳不合理。
展望未来
正如我前文说的,pstore在物联网设备逐渐普及的现在,能发挥很大的作用,例如智能音箱和扫地机已经用起来了。
全功能支持
到目前为止,不管是块设备还是mtd设备,社区的代码都没能做到pstore的全部前端的支持。
| 设备 | dmesg(Oops) | dmesg(Panic) | pmsg | console | ftrace | 
|---|---|---|---|---|---|
| 块设备 | Y | N | Y | Y | Y | 
| MTD设备 | Y | Y | N | N | N | 
| ram设备 | Y | Y | Y | Y | Y | 
块设备如果需要记录Panic日志,需要提供一个在Panic时写块设备的接口。我在全志的mmc和nand驱动中实现了这样的接口,却因为种种原因不适合提交到社区。社区块驱动的适配寄希望于更多同学的努力了。
MTD设备很早前就有了panic_write()的定义,因此可以支持Panic日志转存。不支持其他前端,则是因为其擦写的物理特性。对pmsg,console,ftrace等这些不能页对齐写入的前端,还需要更多的适配工作。
迁移pstore/ram
在当前pstore的目录结构是这样的:
$ tree fs/pstorefs/pstore/├── blk.c      # pstore/blk 后端的实现├── ftrace.c    # ftrace 前端的实现├── inode.c    # pstore 文件系统的注册与操作├── internal.h├── Kconfig├── Makefile├── platform.c    # pstore 前后端功能的核心├── pmsg.c    # pmsg 前端的实现├── ram.c      # pstore/ram 后端的实现├── ram_core.c    # pstore/ram 后端的实现└── zone.c      # pstore/zone 实现存储空间的分配和管理
在我的补丁之前,只支持转存日志到ram,因此如果研读代码,我们会发现ram.c和ram_core.c实现了两部分功能:
- dram空间分配与管理
 - dram的读写操作
 
我实现的blk.c支持了转存到块设备。但是后来发现不管pstore/ram还是pstore/blk,他们对于存储空间的分配和管理极度相似,我就提炼出了pstore/zone。于是乎,期望的代码层次应该是这样的:
pstore/ram要整合入pstore/zone已经与maintainer达成共识,但还需要更多同学一同努力做更多兼容,例如ecc的支持。
参考
https://git.kernel.org/torvalds/c/829f3b9401fe7cc3c1f3642bb2520751a42a87df
https://github.com/gmpy/articles/blob/master/pstore/Test-Pstore-Block.md
												
											pstore的更多相关文章
- proc文件系统
		
在shell终端里不带任何参数,直接运行mount命令可以显示正在挂载的文件系统.其中有这么一行 none on /proc type proc (rw) 这就是/proc文件系统.第一个域显示non ...
 - Android 启动过程简析
		
首先我们先来看android构架图: android系统是构建在linux系统上面的. 所以android设备启动经历3个过程. Boot Loader,Linux Kernel & Andr ...
 - Linux /proc、/dev Principle
		
目录 . /proc简介 . 内核机制相关 . 进程信息 . 硬件设备相关 . 系统信息 . /dev简介 . 内存相关 1. /proc简介 在linux的根目录下有一个/proc目录,/proc文 ...
 - Linux的一些基础
		
想要知道你的 Linux 支持的文件系统有哪些,可以察看底下这个目录: [root@www ~]# ls -l /lib/modules/$(uname -r)/kernel/fs 系统目前已加载到内 ...
 - server-pc--------------->lspci,lsusb,meminfo等配置信息
		
安装yum install pciutils usbutils [root@server09 ~]# [root@server09 ~]# lspci00:00.0 Host bridge: Inte ...
 - mypc--------------->lspci,lsusb,meminfo cpuinfo  ioports  filesystems  interrupts  mounts  net partitions  pagetypeinfo  slabinfo  timer_list  uptime  version  zoneinfo 等配置信息
		
[user@username home]$ lspci00:00.0 Host bridge: Intel Corporation 4th Gen Core Processor DRAM Contro ...
 - 【转发】Linux下如何查看当前支持的文件系统及各分区的文件系统类型
		
Linux下查看当前内核系统支持的文件系统: 一般都在 /lib/modules/kernl-version/kernel/fs/ 目录下包含了当前内核版本支持的文件系统: ls /lib/modul ...
 - Linux用户磁盘配额
		
一:内核中支持QUOTA: [root@localhost /]# grep CONFIG_QUOTA /boot/config-3.10.0-123.el7.x86_64 CONFIG_QUOTA ...
 - Crontab could not create directory .ssh
		
最近在利用 crontab 构建自动备份时,遇到了一个问题.我的脚本中包含了用于服务器用户切换使用的 ssh 命令.当我登录到服务器上时,脚本执行正常:当我没有登录到服务器上时,脚本执行失败,错误提示 ...
 - Linux系统中cgroup功能介绍
		
1 Cgroups简介 1.1 What are cgroups ? Cgroups(控制组)是Linux内核的一个功能,用来限制.统计和分离一个进程组的资源(CPU.内存.磁盘输入输出等).换句话 ...
 
随机推荐
- 一张图看懂 SQL 的各种 JOIN 用法(含数据集和韦恩图)
 - RHCA rh442 009 磁盘算法 RAID相关 磁盘压力测试
			
磁盘 一个数据在磁盘A位置,一个数据在磁盘B位置,他们如果隔着很远.这对磁盘来说性能很差 (机械盘,磁头来回移动) 一个数据写进来,他会把数据放到缓存中,经过磁盘调度算法来调度,最后写到硬盘 io读写 ...
 - 拜登开始在YouTube上打竞选广告了 —— 美国总统的竞选广告已经开始媒体投放了
			
哈哈哈,老拜登,跑到YouTube上打广告了,这个画面真的太难想象,如果美国有"椰树"广告,估计拜登能弄个泳装上去打广告.有时不得不佩服西方搞的这种全民选举,最后搞的就和看小品似的 ...
 - pip install --user 使用方法和注意事项——python中安装module库到用户packages路径中
			
pip install --user 是python中安装module库到用户packages路径中的方法. 参考: https://blog.csdn.net/The_Time_Runner/a ...
 - 【转载】 在PyTorch训练一个epoch时,模型不能接着训练,Dataloader卡死——在pytorch中尽量不要使用opencv而是使用PIL
			
版权声明:本文为CSDN博主「时光碎了天」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明.原文链接:https://blog.csdn.net/u013289254/ ...
 - Apache DolphinScheduler 3.2.1 版本发布:增强功能与安全性的全面升级
			
近期,Apache DolphinScheduler 社区激动地宣布 3.2.1 版本的发布.此次更新不仅着力解决了前一版本(3.2.0)中遗留的问题,而且引入了一系列的功能增强和优化措施. 原先的问 ...
 - 首次尝试SeaTunnel同步Doris至Hive?这些坑你不能不避
			
笔者使用SeaTunnel 2.3.2版本将Doris数据同步到Hive(cdh-6.3.2)首次运行时有如下报错,并附上报错的解决方案: java.lang.NoClassDefFoundError ...
 - 在lcd屏幕上的任意位置显示任意大小的图片
			
/************************************************* * * file name:ShowBmp2.c * author :momolyl@126.co ...
 - unity游戏源码和教程:智能分析话语的三维唯美世界
			
我不想和任何人说话,大家不要打扰我. 这个游戏的源码(含教程文档)我放到了夸克网盘https://pan.quark.cn/s/618fb9459029 小区: 小区傍晚的雪: 小区的晚上: 家里: ...
 - 从0实现基于Linux socket聊天室-实现聊天室的登录、注册功能-3
			
上一篇我们已经讲了如何搭建一个多线程的服务器模型,可以支持多个客户端同时连接服务器,本篇我们来实现多个客户端,如何实现向服务器注册信息,并实现登录的功能. 数据结构 接着上一篇的实例代码继续增加功能. ...