Kernel
Threads by month
- ----- 2025 -----
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
September 2021
- 5 participants
- 16 discussions

30 Sep '21
There are cves based on OpenHarmony-4.19 as follows:
CVE-2021-3640
CVE-2021-3653
CVE-2021-3656
CVE-2021-3743
CVE-2021-3753
CVE-2021-37576
CVE-2021-3759
CVE-2021-40490
----------------------------------------------------------------------
Desmond Cheong Zhi Xi (3):
Bluetooth: schedule SCO timeouts with delayed_work
Bluetooth: avoid circular locks in sco_sock_connect
Bluetooth: switch to lock_sock in SCO
Linus Torvalds (1):
vt_kdsetmode: extend console locking
Maxim Levitsky (2):
KVM: nSVM: avoid picking up unsupported bits from L2 in int_ctl
(CVE-2021-3653)
KVM: nSVM: always intercept VMLOAD/VMSAVE when nested (CVE-2021-3656)
Nicholas Piggin (1):
KVM: PPC: Book3S: Fix H_RTAS rets buffer overflow
Pavel Skripkin (1):
net: qrtr: fix OOB Read in qrtr_endpoint_post
Tetsuo Handa (1):
Bluetooth: defer cleanup of resources in hci_unregister_dev()
Theodore Ts'o (1):
ext4: fix race writing to an inline_data file while its xattrs are
changing
Vasily Averin (1):
memcg: enable accounting of ipc resources
Xiaolong Huang (1):
net: qrtr: fix another OOB Read in qrtr_endpoint_post
arch/powerpc/kvm/book3s_rtas.c | 25 +++++++--
arch/x86/include/asm/svm.h | 2 +
arch/x86/kvm/svm.c | 18 ++++---
drivers/tty/vt/vt_ioctl.c | 11 ++--
fs/ext4/inline.c | 6 +++
include/net/bluetooth/hci_core.h | 1 +
ipc/msg.c | 2 +-
ipc/sem.c | 9 ++--
ipc/shm.c | 2 +-
net/bluetooth/hci_core.c | 16 +++---
net/bluetooth/hci_sock.c | 49 +++++++++++------
net/bluetooth/hci_sysfs.c | 3 ++
net/bluetooth/sco.c | 92 +++++++++++++++++++-------------
net/qrtr/qrtr.c | 4 +-
14 files changed, 156 insertions(+), 84 deletions(-)
--
2.22.0
2
13
《一种快速移植OpenHarmony Linux内核的方法》新出炉
https://gitee.com/openharmony/docs/blob/20d7c1cde9120b758196380075ad944d911…
欢迎各位关心内核移植的开发者朋友们对文档进行评审;
更欢迎各位开发者朋友们按文档开展OpenHarmony到三方芯片平台的移植。
任何问题和建议,欢迎反馈给内核SIG和驱动SIG,谢谢!
1
0
会议纪要
《OpenHarmony Linux内核快速移植指南》在SIG例会上评审通过。文档如下链接:
https://gitee.com/openharmony/docs/blob/20d7c1cde9120b758196380075ad944d911…
欢迎各位关心内核移植的开发者朋友们继续对文档进行评审;
更欢迎各位开发者朋友们按文档开展OpenHarmony到三方芯片平台的移植。
任何问题和建议,欢迎反馈给内核SIG和驱动SIG,谢谢!
发件人: Lijiaxin (Nina Li)
发送时间: 2021年9月24日 9:27
收件人: 'dev(a)openharmony.io' <dev(a)openharmony.io>; 'meetings(a)openharmony.io' <meetings(a)openharmony.io>; 'kernel(a)openharmony.io' <kernel(a)openharmony.io>; dongjinguang <dongjinguang(a)huawei.com>; Rengelin <rengelin(a)huawei.com>; wanchengzhen <wanchengzhen(a)huawei.com>; Houxuanzhe (George) <houxuanzhe(a)huawei.com>; Shenwei (Denny, Device OS) <denny.shenwei(a)huawei.com>; Liuyu (Ted) <liuyu82(a)huawei.com>; zhujiaxin <zhujiaxin(a)huawei.com>; Yijian (A) <salient.yijian(a)huawei.com>; zhouweilai <zhouweilai(a)huawei.com>; Zhangzhiwei (D) <weizhi.zhang(a)huawei.com>; wuzuoyu <wuzuoyu(a)huawei.com>; Wangmihu <wangmihu(a)huawei.com>; Likailong (kkup, Development Dept Seven of Device OS) <likailong(a)huawei.com>; Yangni (A) <neen.yang(a)huawei.com>; duanxichao <duanxichao(a)huawei.com>; Duxiaobo <duxiaobo(a)huawei.com>; Baoguotao <baoguotao(a)huawei.com>; Chenfeng (Scott) <chenfeng469(a)huawei.com>; Zhaohongjiang <zhaohongjiang(a)huawei.com>; weiyongjun (A) <weiyongjun1(a)huawei.com>; miaoxie (A) <miaoxie(a)huawei.com>; fangwei (I) <fangwei1(a)huawei.com>; Jianing (OS-LAB) <ning.jia(a)huawei.com>; Wangli (T) <wangli74(a)huawei.com>; Zhangxiaotian (Handy) <zhangxiaotian(a)huawei.com>; liufeihu (kevin) <liufeihu(a)huawei.com>; yuchangchun (C) <yuchangchun1(a)huawei.com>
抄送: Liyi (Nicholas, Software Engineering Device OS Dept) <nicholas.li(a)huawei.com>; dongjinguang <dongjinguang(a)huawei.com>; Yuxiaoqi <yuxiaoqi(a)huawei.com>
主题: 【会议提醒】OpenHarmony内核SIG例会,会议时间:2021年9月24日(周五)09:30-10:30
OpenHarmony内核SIG例会
序号
议题
引导人
相关与会人
时段
时长
1
SIG集体审视《OpenHarmony Linux内核快速移植指南》
杨妮
梁克雷
黄明龙
易见/吴祚煜
陈风/刘飞虎
09:30~10:30
60min
会议时间:
9月24日(周五)09:30-10:30
会议地点:
电话会议
会议主题:
OpenHarmony内核SIG例会
召集人:
李家欣
与会人:
软件所:梁克雷,黄明龙,罗未,谭小凡,李凯,徐常炜
KOL:李传钊
润和:刘洋
华为:董金光,任革林,万承臻,李家欣,沈伟,刘宇,朱佳鑫,易见,周未来,张智伟,吴祚煜,王米虎,李开龙,候选哲,陈风,杜潇泊,鲍国涛,杨妮,段夕超,赵鸿江,魏勇军,缪勰,方炜,贾宁,王力,张小田,刘飞虎,,余长春
会议接入:
· 加入会议 : Join (Host) >><http://imeeting.huawei.com/meeting/startzoom?id=8cfcda14ee1b4baa83e63202f04…>
· Join (Internal) >><http://imeeting.huawei.com/meeting/joinzoom?id=0204622857&app=welink>
· Join (External) >><https://welink.zhumu.com/j/204622857>
会议ID : 0204622857 (会议ID在本次会议结束后不可继续使用)
1
0
OpenHarmony内核SIG例会
序号
议题
引导人
相关与会人
时段
时长
1
SIG集体审视《OpenHarmony Linux内核快速移植指南》
杨妮
梁克雷
黄明龙
易见/吴祚煜
陈风/刘飞虎
09:30~10:30
60min
会议时间:
9月24日(周五)09:30-10:30
会议地点:
电话会议
会议主题:
OpenHarmony内核SIG例会
召集人:
李家欣
与会人:
软件所:梁克雷,黄明龙,罗未,谭小凡,李凯,徐常炜
KOL:李传钊
润和:刘洋
华为:董金光,任革林,万承臻,李家欣,沈伟,刘宇,朱佳鑫,易见,周未来,张智伟,吴祚煜,王米虎,李开龙,候选哲,陈风,杜潇泊,鲍国涛,杨妮,段夕超,赵鸿江,魏勇军,缪勰,方炜,贾宁,王力,张小田,刘飞虎,,余长春
会议接入:
· 加入会议 : Join (Host) >><http://imeeting.huawei.com/meeting/startzoom?id=8cfcda14ee1b4baa83e63202f04…>
· Join (Internal) >><http://imeeting.huawei.com/meeting/joinzoom?id=0204622857&app=welink>
· Join (External) >><https://welink.zhumu.com/j/204622857>
会议ID : 0204622857 (会议ID在本次会议结束后不可继续使用)
1
0
OpenHarmony内核SIG例会
序号
议题
引导人
相关与会人
时段
时长
1
SIG集体审视《OpenHarmony Linux内核快速移植指南》
杨妮
梁克雷
黄明龙
易见/吴祚煜
陈风/刘飞虎
09:30~10:30
60min
会议时间:
9月24日(周五)09:30-10:30
会议地点:
电话会议
会议主题:
OpenHarmony内核SIG例会
召集人:
李家欣
与会人:
软件所:梁克雷,黄明龙,罗未,谭小凡,李凯,徐常炜
KOL:李传钊
润和:刘洋
华为:董金光,任革林,万承臻,李家欣,沈伟,刘宇,朱佳鑫,易见,周未来,张智伟,吴祚煜,王米虎,李开龙,候选哲,陈风,杜潇泊,鲍国涛,杨妮,段夕超,赵鸿江,魏勇军,缪勰,方炜,贾宁,王力,张小田,刘飞虎,,余长春
会议接入:
· 加入会议 : Join (Host) >><http://imeeting.huawei.com/meeting/startzoom?id=8cfcda14ee1b4baa83e63202f04…>
· Join (Internal) >><http://imeeting.huawei.com/meeting/joinzoom?id=0204622857&app=welink>
· Join (External) >><https://welink.zhumu.com/j/204622857>
会议ID : 0204622857 (会议ID在本次会议结束后不可继续使用)
1
0
议题申报<https://shimo.im/sheets/VgQV6VjCJ9cXtY8G/MODOC> (点此链接申报议题)
会议时间:
9月24日(周五)09:30-10:30
会议地点:
电话会议
会议主题:
OpenHarmony内核SIG例会
召集人:
李家欣
与会人:
软件所:梁克雷,黄明龙,罗未,谭小凡,李凯,徐常炜
KOL:李传钊
润和:刘洋
华为:董金光,任革林,万承臻,李家欣,沈伟,刘宇,朱佳鑫,易见,周未来,张智伟,吴祚煜,王米虎,李开龙,候选哲,陈风,杜潇泊,鲍国涛,杨妮,段夕超,赵鸿江,魏勇军,缪勰,方炜,贾宁,王力,张小田,刘飞虎,余长春
接入信息:
· 加入会议 : Join (Host) >><http://imeeting.huawei.com/meeting/startzoom?id=8cfcda14ee1b4baa83e63202f04…>
· Join (Internal) >><http://imeeting.huawei.com/meeting/joinzoom?id=0204622857&app=welink>
· Join (External) >><https://welink.zhumu.com/j/204622857>
· 会议ID : 0204622857 (会议ID在本次会议结束后不可继续使用)
1
0
会议纪要
议题一,OpenHarmony Linux内核移植性增强方案,对patch/文档/测试用例的质量,以及移植的实际效果进行第一次review
移植尚未完全完成。本周继续移植,并同步给出patch/文档/测试用例的建议。下周例会review移植进展。 梁克雷,李凯
通过当前已经完成的移植步骤,已识别出几处文档需要整改的地方。对于文档进行修改,下周例会review修改进展。吴祚煜、刘飞虎
向Driver SIG提出对于HDF Ko化的要求。下周例会review进展 梁克雷,刘飞虎
议题二,OpenHarmony 内核GKI介绍
短期策略:吸收GKI思想,应用到OpenHarmony Linux内核移植性增强方案中。对于类似HDF等进入内核的新增特性,梳理出GKI化所需要的要求,下周例会review进展。 易见,余长春
议题三,驱动patch backport项目洞察介绍
选择一个patch,进行backport实验,看实际效果。基于实验结果,继续讨论OpenHarmony内核SIG是否借鉴backport项目,来协助各个不同版本内核上的patch生成和管理。下周例会review进展。 梁克雷,朱佳鑫
发件人: Lijiaxin (Nina Li)
发送时间: 2021年9月1日 14:16
收件人: 'dev(a)openharmony.io' <dev(a)openharmony.io<mailto:dev@openharmony.io>>; 'meetings(a)openharmony.io' <meetings(a)openharmony.io<mailto:meetings@openharmony.io>>; dongjinguang <dongjinguang(a)huawei.com<mailto:dongjinguang@huawei.com>>; Rengelin <rengelin(a)huawei.com<mailto:rengelin@huawei.com>>; wanchengzhen <wanchengzhen(a)huawei.com<mailto:wanchengzhen@huawei.com>>; Houxuanzhe (George) <houxuanzhe(a)huawei.com<mailto:houxuanzhe@huawei.com>>; Shenwei (Denny, Device OS) <denny.shenwei(a)huawei.com<mailto:denny.shenwei@huawei.com>>; Liuyu (Ted) <liuyu82(a)huawei.com<mailto:liuyu82@huawei.com>>; zhujiaxin <zhujiaxin(a)huawei.com<mailto:zhujiaxin@huawei.com>>; Yijian (A) <salient.yijian(a)huawei.com<mailto:salient.yijian@huawei.com>>; zhouweilai <zhouweilai(a)huawei.com<mailto:zhouweilai@huawei.com>>; Zhangzhiwei (D) <weizhi.zhang(a)huawei.com<mailto:weizhi.zhang@huawei.com>>; wuzuoyu <wuzuoyu(a)huawei.com<mailto:wuzuoyu@huawei.com>>; Wangmihu <wangmihu(a)huawei.com<mailto:wangmihu@huawei.com>>; Likailong (kkup, Development Dept Seven of Device OS) <likailong(a)huawei.com<mailto:likailong@huawei.com>>; Yangni (A) <neen.yang(a)huawei.com<mailto:neen.yang@huawei.com>>; duanxichao <duanxichao(a)huawei.com<mailto:duanxichao@huawei.com>>; Duxiaobo <duxiaobo(a)huawei.com<mailto:duxiaobo@huawei.com>>; Baoguotao <baoguotao(a)huawei.com<mailto:baoguotao@huawei.com>>; Chenfeng (Scott) <chenfeng469(a)huawei.com<mailto:chenfeng469@huawei.com>>; Zhaohongjiang <zhaohongjiang(a)huawei.com<mailto:zhaohongjiang@huawei.com>>; weiyongjun (A) <weiyongjun1(a)huawei.com<mailto:weiyongjun1@huawei.com>>; miaoxie (A) <miaoxie(a)huawei.com<mailto:miaoxie@huawei.com>>; fangwei (I) <fangwei1(a)huawei.com<mailto:fangwei1@huawei.com>>; Jianing (OS-LAB) <ning.jia(a)huawei.com<mailto:ning.jia@huawei.com>>; Wangli (T) <wangli74(a)huawei.com<mailto:wangli74@huawei.com>>; Zhangxiaotian (Handy) <zhangxiaotian(a)huawei.com<mailto:zhangxiaotian@huawei.com>>; liufeihu (kevin) <liufeihu(a)huawei.com<mailto:liufeihu@huawei.com>>
抄送: Liyi (Nicholas, Software Engineering Device OS Dept) <nicholas.li(a)huawei.com<mailto:nicholas.li@huawei.com>>; dongjinguang <dongjinguang(a)huawei.com<mailto:dongjinguang@huawei.com>>; Yuxiaoqi <yuxiaoqi(a)huawei.com<mailto:yuxiaoqi@huawei.com>>
主题: 【会议提醒】OpenHarmony内核SIG例会,会议时间:2021年9月1日(周三)14:30-16:30
OpenHarmony内核SIG例会
序号
议题
汇报人
相关与会人
时段
时长
1
上次例会遗留问题:
OpenHarmony Linux内核移植性增强方案,所有的patch、文档和测试用例已于8月26日提供给软件所。本次例会对于patch/文档/测试用例的质量,以及移植的实际效果进行第一次review。
梁克雷
黄明龙
吴祚煜
候选哲/刘飞虎
张小田
14:30~15:30
60min
2
OpenHarmony 内核GKI介绍
易见
15:30~16:00
30min
3
业界内核测试框架和驱动patch backport项目洞察介绍
朱佳鑫
16:00~16:30
30min
会议时间:
9月1日(周三)14:30-16:30
会议地点:
电话会议
会议主题:
OpenHarmony内核SIG例会
召集人:
李家欣
与会人:
软件所:梁克雷,黄明龙,罗未,谭小凡
KOL:李传钊
润和:刘洋
华为:董金光,任革林,万承臻,李家欣,沈伟,刘宇,朱佳鑫,易见,周未来,张智伟,吴祚煜,王米虎,李开龙,候选哲,陈风,杜潇泊,鲍国涛,杨妮,段夕超,赵鸿江,魏勇军,缪勰,方炜,贾宁,王力,张小田,刘飞虎
会议接入:
· 时间 : 2021-09-01 14:30-16:30 (UTC+08:00)Beijing
· 加入会议 : Join (Host) >><http://imeeting.huawei.com/meeting/startzoom?id=d65a9ea50ea443d9adc0f107e98…>
· Join (Internal) >><http://imeeting.huawei.com/meeting/joinzoom?id=0205777211&app=welink>
· Join (External) >><https://welink.zhumu.com/j/205777211>
· 会议ID : 0205777211 (会议ID在本次会议结束后不可继续使用)
1
0
会议纪要
议题一:OpenHarmony Linux内核移植性增强方案进展
软件所同事的上周技术验证结果,证明了当前内核SIG设计的“OpenHarmony Linux内核移植性增强方案”方向正确:开发者可以通过非常简单的步骤,快速将OpenHarmony在三方开发板(借助三方内核)上运行起来。
同时发现:内核SIG当前产出的文档,仍然存在描述不清晰易误导开发者的地方;而类似HDF的内核态特性/驱动代码,也存在一些设计细节会影响开发者移植效率。
因此接下来的工作是:先将当前的移植成果尽快先整理出文档,尽快使能开发者将OpenHarmony能够快速方便的移植到三方开发板。然后通过几周的HDF等代码整改,结合前面的移植文档整理,一起达到以下目标:开发者仅需两三步步骤、仅需半天时间,即可将OpenHarmony在三方开发板(借助三方内核)上运行起来。
分工如下:
a) 将当前已有成果,快速形成文档并发布,来指导开发者。在下周例会之前,需要将文档形成框架,并请软件所评审通过,以及给出文档章节的分工。 责任人:李家欣,杨妮
b) 陈风将本次例会上提出的HDF代码整改建议,在Driver-SIG内部讨论,下周例会介绍解决方案。 责任人:陈风,刘飞虎
c) 软件所继续验证前期提供的HDF测试用例,下周例会review进展 责任人:梁克雷
议题二:吸收GKI思路,应用于“OpenHarmony Linux内核移植性增强方案”的讨论
会上形成一致性意见:需要为今后进入内核态的特性、驱动等代码形成指导,以保持和持续提升内核的可移植性。
考虑以易见在此次例会上介绍的《内核解耦开发指导书V0.1》为基础,来最终完善和形成《内核解耦开发指导书》。本周开始对于指导书草稿版本的细节进行线下讨论,在下周例会上审视具体的设计意见。责任人:易见,梁克雷,杨妮,张小田,陈风
发件人: Lijiaxin (Nina Li) [mailto:nina.lijiaxin@huawei.com]
发送时间: 2021年9月8日 9:23
收件人: dev(a)openharmony.io<mailto:dev@openharmony.io>; meetings(a)openharmony.io<mailto:meetings@openharmony.io>; dongjinguang <dongjinguang(a)huawei.com<mailto:dongjinguang@huawei.com>>; Rengelin <rengelin(a)huawei.com<mailto:rengelin@huawei.com>>; wanchengzhen <wanchengzhen(a)huawei.com<mailto:wanchengzhen@huawei.com>>; Houxuanzhe (George) <houxuanzhe(a)huawei.com<mailto:houxuanzhe@huawei.com>>; Shenwei (Denny, Device OS) <denny.shenwei(a)huawei.com<mailto:denny.shenwei@huawei.com>>; Liuyu (Ted) <liuyu82(a)huawei.com<mailto:liuyu82@huawei.com>>; zhujiaxin <zhujiaxin(a)huawei.com<mailto:zhujiaxin@huawei.com>>; Yijian (A) <salient.yijian(a)huawei.com<mailto:salient.yijian@huawei.com>>; zhouweilai <zhouweilai(a)huawei.com<mailto:zhouweilai@huawei.com>>; Zhangzhiwei (D) <weizhi.zhang(a)huawei.com<mailto:weizhi.zhang@huawei.com>>; wuzuoyu <wuzuoyu(a)huawei.com<mailto:wuzuoyu@huawei.com>>; Wangmihu <wangmihu(a)huawei.com<mailto:wangmihu@huawei.com>>; Likailong (kkup, Development Dept Seven of Device OS) <likailong(a)huawei.com<mailto:likailong@huawei.com>>; Yangni (A) <neen.yang(a)huawei.com<mailto:neen.yang@huawei.com>>; duanxichao <duanxichao(a)huawei.com<mailto:duanxichao@huawei.com>>; Duxiaobo <duxiaobo(a)huawei.com<mailto:duxiaobo@huawei.com>>; Baoguotao <baoguotao(a)huawei.com<mailto:baoguotao@huawei.com>>; Chenfeng (Scott) <chenfeng469(a)huawei.com<mailto:chenfeng469@huawei.com>>; Zhaohongjiang <zhaohongjiang(a)huawei.com<mailto:zhaohongjiang@huawei.com>>; weiyongjun (A) <weiyongjun1(a)huawei.com<mailto:weiyongjun1@huawei.com>>; miaoxie (A) <miaoxie(a)huawei.com<mailto:miaoxie@huawei.com>>; fangwei (I) <fangwei1(a)huawei.com<mailto:fangwei1@huawei.com>>; Jianing (OS-LAB) <ning.jia(a)huawei.com<mailto:ning.jia@huawei.com>>; Wangli (T) <wangli74(a)huawei.com<mailto:wangli74@huawei.com>>; Zhangxiaotian (Handy) <zhangxiaotian(a)huawei.com<mailto:zhangxiaotian@huawei.com>>; liufeihu (kevin) <liufeihu(a)huawei.com<mailto:liufeihu@huawei.com>>; yuchangchun (C) <yuchangchun1(a)huawei.com<mailto:yuchangchun1@huawei.com>>
抄送: Liyi (Nicholas, Software Engineering Device OS Dept) <nicholas.li(a)huawei.com<mailto:nicholas.li@huawei.com>>; dongjinguang <dongjinguang(a)huawei.com<mailto:dongjinguang@huawei.com>>; Yuxiaoqi <yuxiaoqi(a)huawei.com<mailto:yuxiaoqi@huawei.com>>
主题: [Dev] 【会议提醒】OpenHarmony内核SIG例会,会议时间:2021年9月8日(周三)09:30-10:30
OpenHarmony内核SIG例会
序号
议题
引导人
相关与会人
时段
时长
1
例会遗留问题:
OpenHarmony Linux内核移植性增强方案,所有的patch、文档和测试用例已于8月26日提供给软件所。本次例会对于patch/文档/测试用例的质量,以及移植的实际效果进行第二次review。
梁克雷
黄明龙
吴祚煜
候选哲/刘飞虎
张小田
杨妮
09:30~10:00
30min
2
GKI应用于OpenHarmony Linux内核移植性增强方案的讨论
易见
余长春
10:00~10:30
30min
会议时间:
9月8日(周三)09:30-10:30
会议地点:
电话会议
会议主题:
OpenHarmony内核SIG例会
召集人:
李家欣
与会人:
软件所:梁克雷,黄明龙,罗未,谭小凡,李凯,Chandwich
KOL:李传钊
润和:刘洋
华为:董金光,任革林,万承臻,李家欣,沈伟,刘宇,朱佳鑫,易见,周未来,张智伟,吴祚煜,王米虎,李开龙,候选哲,陈风,杜潇泊,鲍国涛,杨妮,段夕超,赵鸿江,魏勇军,缪勰,方炜,贾宁,王力,张小田,刘飞虎,,余长春
会议接入:
* 时间 : 2021-09-08 09:30-10:30 (UTC+08:00)Beijing
* 加入会议 : Join (Host) >><http://imeeting.huawei.com/meeting/startzoom?id=b05cb07b20754d929e01b0e9085…>
* Join (Internal) >><http://imeeting.huawei.com/meeting/joinzoom?id=0154851414&app=welink>
* Join (External) >><https://welink.zhumu.com/j/154851414>
* 会议ID : 0154851414 (会议ID在本次会议结束后不可继续使用)
1
0
会议纪要
一,同意按照“Linux内核可移植性增强整体方案”进行试运行,迭代几次之后形成正式的流程。
二,试运行分工如下:
1,提供4.19上的hdf patch 候选哲 8/26前
2,提供hdf testcase和对应的指导文档 候选哲 8/26前
3,提供4.19上的small config 、 standard config路径和指导文档 , 吴祚煜 8/25前
4,提供启动 4.19上的init 指导文档 张小田 8/26前
5,梁克雷 找一个团队,找一个非海思平台非4.19的三方已有内核,验证在有限的技术指导之下,仅凭以上1,2,3,4提供的代码和文档,该团队是否能够独自快速把OpenHarmony在三方已有内核上跑起来,碰到的每一个Blocking问题都要记录下来,下周二SIG例会之前给大家反馈 梁克雷 8/31
6,研究特性级的移植patch案例 https://backports.wiki.kernel.org/index.php/Main_Page 下次例会讨论 候选哲 8/31
7,研究内核测试框架 https://lkft.linaro.org/ 和 https://git.lavasoftware.org/lava/lava 下次例会讨论 李家欣8/31
附:Linux内核可移植性增强整体方案的简介图
[cid:image001.png@01D798D7.C40BB090]
发件人: Lijiaxin (Nina Li) [mailto:nina.lijiaxin@huawei.com]
发送时间: 2021年8月23日 14:46
收件人: dev(a)openharmony.io<mailto:dev@openharmony.io>; dongjinguang <dongjinguang(a)huawei.com<mailto:dongjinguang@huawei.com>>; Rengelin <rengelin(a)huawei.com<mailto:rengelin@huawei.com>>; wanchengzhen <wanchengzhen(a)huawei.com<mailto:wanchengzhen@huawei.com>>; Houxuanzhe (George) <houxuanzhe(a)huawei.com<mailto:houxuanzhe@huawei.com>>; Shenwei (Denny, Device OS) <denny.shenwei(a)huawei.com<mailto:denny.shenwei@huawei.com>>; Liuyu (Ted) <liuyu82(a)huawei.com<mailto:liuyu82@huawei.com>>; zhujiaxin <zhujiaxin(a)huawei.com<mailto:zhujiaxin@huawei.com>>; Yijian (A) <salient.yijian(a)huawei.com<mailto:salient.yijian@huawei.com>>; zhouweilai <zhouweilai(a)huawei.com<mailto:zhouweilai@huawei.com>>; Zhangzhiwei (D) <weizhi.zhang(a)huawei.com<mailto:weizhi.zhang@huawei.com>>; wuzuoyu <wuzuoyu(a)huawei.com<mailto:wuzuoyu@huawei.com>>; Wangmihu <wangmihu(a)huawei.com<mailto:wangmihu@huawei.com>>; Likailong (kkup, Development Dept Seven of Device OS) <likailong(a)huawei.com<mailto:likailong@huawei.com>>; Yangni (A) <neen.yang(a)huawei.com<mailto:neen.yang@huawei.com>>; duanxichao <duanxichao(a)huawei.com<mailto:duanxichao@huawei.com>>; Duxiaobo <duxiaobo(a)huawei.com<mailto:duxiaobo@huawei.com>>; Baoguotao <baoguotao(a)huawei.com<mailto:baoguotao@huawei.com>>; Chenfeng (Scott) <chenfeng469(a)huawei.com<mailto:chenfeng469@huawei.com>>; Zhaohongjiang <zhaohongjiang(a)huawei.com<mailto:zhaohongjiang@huawei.com>>; weiyongjun (A) <weiyongjun1(a)huawei.com<mailto:weiyongjun1@huawei.com>>; miaoxie (A) <miaoxie(a)huawei.com<mailto:miaoxie@huawei.com>>; fangwei (I) <fangwei1(a)huawei.com<mailto:fangwei1@huawei.com>>; Jianing (OS-LAB) <ning.jia(a)huawei.com<mailto:ning.jia@huawei.com>>; Wangli (T) <wangli74(a)huawei.com<mailto:wangli74@huawei.com>>
抄送: Liyi (Nicholas, Software Engineering Device OS Dept) <nicholas.li(a)huawei.com<mailto:nicholas.li@huawei.com>>; dongjinguang <dongjinguang(a)huawei.com<mailto:dongjinguang@huawei.com>>; Yuxiaoqi <yuxiaoqi(a)huawei.com<mailto:yuxiaoqi@huawei.com>>
主题: [Dev] 【会议通知】OpenHarmony内核SIG例会,会议时间:2021年8月24日(周二)09:30-11:30
OpenHarmony内核SIG例会
序号
议题
汇报人
相关与会人
时段
时长
1
OpenHarmony当前已开源Linux内核的default config介绍
朱佳鑫
All
9:30~9:50
20min
2
OpenHarmony Linux内核可移植性增强整体方案已在PMC汇报通过,遗留问题讨论:
l 问题一:如何吸引开发者将OH 内核patch移植到不同的三方内核上,并引导开发者将移植之后的patch贡献给社区?
l 问题二:如果出现多个开发者同时将OH 内核patch移植到同一个三方内核,社区应如何操作?
l 问题三:OH内核patch的License是否存在GPL之外的选择?
l 问题四:是否可以构建自动化测试方式来代替手工认证,从而使开发者能够自己完成OH内核patch的自动化验证和自主发布?
l 问题五:OH 内核patch以及三方芯片平台内核patch的代码上库及发布流程细节讨论
All
9:50~10:50
60min
3
OpenHarmony Linux内核可移植性增强方案的落地分工讨论
All
10:50~11:30
40min
会议时间:
8月24日(周二)09:30-11:30
会议地点:
电话会议
会议主题:
OpenHarmony内核SIG例会
召集人:
李家欣
与会人:
软件所:梁克雷,黄明龙,罗未,夏凡
KOL:李传钊
润和:刘洋
华为:董金光,任革林,万承臻,李家欣,沈伟,刘宇,朱佳鑫,易见,周未来,张智伟,吴祚煜,王米虎,李开龙,候选哲,陈风,杜潇泊,鲍国涛,杨妮,段夕超,赵鸿江,魏勇军,缪勰,方炜,贾宁,王力
会议接入:
Join Conference
Join (Host) >><http://imeeting.huawei.com/meeting/startzoom?id=306ba1f11c80428387cd74f4a07…>
Join (Internal) >><http://imeeting.huawei.com/meeting/joinzoom?id=0152392426&app=welink>
Join (External) >><https://welink.zhumu.com/j/152392426>
Meeting ID
0152392426
1
0
会议纪要
议题一: OpenHarmony Linux内核移植性增强专项:SIG集体审视《面向开发者的移植文档》框架草稿
SIG会议上的开发者均同意移植文档草稿的框架。 (文档见邮件附件“Open Harmony Linux内核快速移植指南_20210915草稿V0.1.docx”)。
软件所同事以及华为内核、HDF团队分别在文档的基础框架下,按照分工(已标注在附件文档中)进行内容的补充。下周SIG例会集体评审补充过后的整体文档 责任人:梁克雷,刘飞虎,易见,吴祚煜
议题二: OpenHarmony Linux内核移植性增强专项:SIG集体讨论HDF驱动代码移植简化方案
SIG会议上的开发者均认为:会上介绍的优化后的HDF移植简化方案,能够达到简化移植的预期效果。此问题关闭。
议题三: OpenHarmony Linux内核移植性增强专项:“HDF自动化测试用例”的实测结果介绍
软件所当前实测了大部分HDF自动化测试用例都能成功,遗留一个用例的验证结果于下周例会之前线下沟通闭环。责任人:徐常炜,李凯
议题四:《内核解耦开发指导书》线下讨论进展介绍
向SIG会议上的开发者介绍了当前最新的《内核解耦开发指导书》草稿内容。应开发者要求,会将《内核解耦开发指导书》草稿通过石墨文档来开通共享编辑,便于开发者共同参与完善细节内容。下周SIG例会介绍进展。责任人:易见
发件人: Lijiaxin (Nina Li)
发送时间: 2021年9月14日 9:57
收件人: 'dev(a)openharmony.io' <dev(a)openharmony.io>; 'meetings(a)openharmony.io' <meetings(a)openharmony.io>; 'kernel(a)openharmony.io' <kernel(a)openharmony.io>; dongjinguang <dongjinguang(a)huawei.com>; Rengelin <rengelin(a)huawei.com>; wanchengzhen <wanchengzhen(a)huawei.com>; Houxuanzhe (George) <houxuanzhe(a)huawei.com>; Shenwei (Denny, Device OS) <denny.shenwei(a)huawei.com>; Liuyu (Ted) <liuyu82(a)huawei.com>; zhujiaxin <zhujiaxin(a)huawei.com>; Yijian (A) <salient.yijian(a)huawei.com>; zhouweilai <zhouweilai(a)huawei.com>; Zhangzhiwei (D) <weizhi.zhang(a)huawei.com>; wuzuoyu <wuzuoyu(a)huawei.com>; Wangmihu <wangmihu(a)huawei.com>; Likailong (kkup, Development Dept Seven of Device OS) <likailong(a)huawei.com>; Yangni (A) <neen.yang(a)huawei.com>; duanxichao <duanxichao(a)huawei.com>; Duxiaobo <duxiaobo(a)huawei.com>; Baoguotao <baoguotao(a)huawei.com>; Chenfeng (Scott) <chenfeng469(a)huawei.com>; Zhaohongjiang <zhaohongjiang(a)huawei.com>; weiyongjun (A) <weiyongjun1(a)huawei.com>; miaoxie (A) <miaoxie(a)huawei.com>; fangwei (I) <fangwei1(a)huawei.com>; Jianing (OS-LAB) <ning.jia(a)huawei.com>; Wangli (T) <wangli74(a)huawei.com>; Zhangxiaotian (Handy) <zhangxiaotian(a)huawei.com>; liufeihu (kevin) <liufeihu(a)huawei.com>; yuchangchun (C) <yuchangchun1(a)huawei.com>
抄送: Liyi (Nicholas, Software Engineering Device OS Dept) <nicholas.li(a)huawei.com>; dongjinguang <dongjinguang(a)huawei.com>; Yuxiaoqi <yuxiaoqi(a)huawei.com>
主题: 【会议通知】OpenHarmony内核SIG例会,会议时间:2021年9月15日(周三)09:30-11:00
OpenHarmony内核SIG例会
序号
议题
引导人
相关与会人
时段
时长
1
OpenHarmony Linux内核移植性增强专项:SIG集体审视《面向开发者的移植文档》框架草稿
李家欣
杨妮
梁克雷
黄明龙
吴祚煜
陈风/刘飞虎
张小田
09:30~09:45
15min
2
OpenHarmony Linux内核移植性增强专项:SIG集体讨论HDF驱动代码移植简化方案
陈风
梁克雷
黄明龙
09:45~10:15
30min
3
OpenHarmony Linux内核移植性增强专项:”HDF自动化测试用例”的实测结果介绍
梁克雷
黄明龙
陈风/刘飞虎
10:15~10:30
15min
4
《内核解耦开发指导书》线下讨论进展介绍
易见
梁克雷
黄明龙
杨妮
张小田
陈风
10:30~11:00
30min
会议时间:
9月15日(周三)09:30-11:00
会议地点:
电话会议
会议主题:
OpenHarmony内核SIG例会
召集人:
李家欣
与会人:
软件所:梁克雷,黄明龙,罗未,谭小凡,李凯,徐常炜
KOL:李传钊
润和:刘洋
华为:董金光,任革林,万承臻,李家欣,沈伟,刘宇,朱佳鑫,易见,周未来,张智伟,吴祚煜,王米虎,李开龙,候选哲,陈风,杜潇泊,鲍国涛,杨妮,段夕超,赵鸿江,魏勇军,缪勰,方炜,贾宁,王力,张小田,刘飞虎,,余长春
会议接入:
* 加入会议 : Join (Host) >><http://imeeting.huawei.com/meeting/startzoom?id=29833582b80f42cd8ca44c6c39d…>
* Join (Internal) >><http://imeeting.huawei.com/meeting/joinzoom?id=0800082810&app=welink>
* Join (External) >><https://welink.zhumu.com/j/800082810>
* 会议ID : 0800082810 (会议ID在本次会议结束后不可继续使用)
1
0
OpenHarmony内核SIG例会
序号
议题
引导人
相关与会人
时段
时长
1
OpenHarmony Linux内核移植性增强专项:SIG集体审视《面向开发者的移植文档》框架草稿
李家欣
杨妮
梁克雷
黄明龙
吴祚煜
陈风/刘飞虎
张小田
09:30~09:45
15min
2
OpenHarmony Linux内核移植性增强专项:SIG集体讨论HDF驱动代码移植简化方案
陈风
梁克雷
黄明龙
09:45~10:15
30min
3
OpenHarmony Linux内核移植性增强专项:”HDF自动化测试用例”的实测结果介绍
梁克雷
黄明龙
陈风/刘飞虎
10:15~10:30
15min
4
《内核解耦开发指导书》线下讨论进展介绍
易见
梁克雷
黄明龙
杨妮
张小田
陈风
10:30~11:00
30min
会议时间:
9月15日(周三)09:30-11:00
会议地点:
电话会议
会议主题:
OpenHarmony内核SIG例会
召集人:
李家欣
与会人:
软件所:梁克雷,黄明龙,罗未,谭小凡,李凯,徐常炜
KOL:李传钊
润和:刘洋
华为:董金光,任革林,万承臻,李家欣,沈伟,刘宇,朱佳鑫,易见,周未来,张智伟,吴祚煜,王米虎,李开龙,候选哲,陈风,杜潇泊,鲍国涛,杨妮,段夕超,赵鸿江,魏勇军,缪勰,方炜,贾宁,王力,张小田,刘飞虎,,余长春
会议接入:
* 加入会议 : Join (Host) >><http://imeeting.huawei.com/meeting/startzoom?id=29833582b80f42cd8ca44c6c39d…>
* Join (Internal) >><http://imeeting.huawei.com/meeting/joinzoom?id=0800082810&app=welink>
* Join (External) >><https://welink.zhumu.com/j/800082810>
* 会议ID : 0800082810 (会议ID在本次会议结束后不可继续使用)
1
0
There are cves based on OpenHarmony-4.19 as follows:
CVE-2021-38160
CVE-2021-38198
CVE-2021-3679
CVE-2021-38207
CVE-2021-38199
CVE-2021-38209
CVE-2021-38204
CVE-2021-38205
----------------------------------------------------------------------
Esben Haabendal (1):
net: ll_temac: Fix bug causing buffer descriptor overrun
Haoran Luo (1):
tracing: Fix bug in rb_per_cpu_empty() that might cause deadloop.
Jonathon Reinhart (1):
netfilter: conntrack: Make global sysctls readonly in non-init netns
Lai Jiangshan (1):
KVM: X86: MMU: Use the correct inherited permissions to get shadow
page
Mark Tomlinson (1):
usb: max-3421: Prevent corruption of freed memory
Trond Myklebust (1):
NFSv4: Initialise connection to the server in nfs4_alloc_client()
Xie Yongji (1):
virtio_console: Assure used length from device is limited
YueHaibing (1):
net: xilinx_emaclite: Do not print real IOMEM pointer
Documentation/virtual/kvm/mmu.txt | 4 +-
arch/x86/kvm/paging_tmpl.h | 14 ++--
drivers/char/virtio_console.c | 4 +-
drivers/net/ethernet/xilinx/ll_temac_main.c | 2 +-
drivers/net/ethernet/xilinx/xilinx_emaclite.c | 5 +-
drivers/usb/host/max3421-hcd.c | 44 ++++------
fs/nfs/nfs4client.c | 82 ++++++++++---------
kernel/trace/ring_buffer.c | 28 ++++++-
net/netfilter/nf_conntrack_standalone.c | 5 +-
9 files changed, 100 insertions(+), 88 deletions(-)
--
2.22.0
2
9

[PATCH OpenHarmony-4.19] Revert "proc: Convert proc_mount to use mount_ns."
by Yu Changchun 09 Sep '21
by Yu Changchun 09 Sep '21
09 Sep '21
ohos inclusion
category: bugfix
issue: #I46HO0
CVE: NA
------------------------------------------
This reverts commit e94591d0d90c13166cb6eb54ce5f96ed13d81b55.
Original patch was a minor cleanup, but the parsing of procfs
mount parameters was broken by moving proc_parse_options() to
proc_fill_super(). Kernel calls proc_fill_super as the first mount
referrence in start_kernel -> alloc_pid -> pid_ns_prepare_proc ->
mount_ns -> proc_fill_super with SB_KERNMOUNT.
Then userspace mount procfs will just return root dentry by ignoring
parsing options.
Upstream 5.x fix the issue after refactoring vfs/procfs(introducing fs_context)
and support multiple mount instances.
fa10fed30f25 proc: allow to mount many instances of proc in one pid namespace
69879c01a0c3 proc: Remove the now unnecessary internal mount of proc
66f592e2ece0 proc: Add fs_context support to procfs
60a3c3a58e2e procfs: Move proc_fill_super() to fs/proc/root.c
cb50b348c71f convenience helpers: vfs_get_super() and sget_fc()
3e1aeb00e6d1 vfs: Implement a filesystem superblock creation/configuration context
......
It is a little complicated and no need to do the backport.
Just revert it to hornor the option of 'hidepid=2' for init.
Signed-off-by: Yu Changchun <yuchangchun1(a)huawei.com>
---
fs/proc/inode.c | 10 +++------
fs/proc/internal.h | 3 +--
fs/proc/root.c | 52 ++++++++++++++++++++++++++++++++++++++++++----
3 files changed, 52 insertions(+), 13 deletions(-)
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 31bf3bb8ddae..fd6a01a9629a 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -491,17 +491,13 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de)
return inode;
}
-int proc_fill_super(struct super_block *s, void *data, int silent)
+int proc_fill_super(struct super_block *s)
{
- struct pid_namespace *ns = get_pid_ns(s->s_fs_info);
struct inode *root_inode;
int ret;
- if (!proc_parse_options(data, ns))
- return -EINVAL;
-
- /* User space would break if executables or devices appear on proc */
- s->s_iflags |= SB_I_USERNS_VISIBLE | SB_I_NOEXEC | SB_I_NODEV;
+ /* User space would break if devices appear on proc */
+ s->s_iflags |= SB_I_USERNS_VISIBLE | SB_I_NODEV;
s->s_flags |= SB_NODIRATIME | SB_NOSUID | SB_NOEXEC;
s->s_blocksize = 1024;
s->s_blocksize_bits = 10;
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 95b14196f284..6e64cac02829 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -212,7 +212,7 @@ extern const struct inode_operations proc_pid_link_inode_operations;
void proc_init_kmemcache(void);
void set_proc_pid_nlink(void);
extern struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *);
-extern int proc_fill_super(struct super_block *, void *data, int flags);
+extern int proc_fill_super(struct super_block *);
extern void proc_entry_rundown(struct proc_dir_entry *);
/*
@@ -270,7 +270,6 @@ static inline void proc_tty_init(void) {}
* root.c
*/
extern struct proc_dir_entry proc_root;
-extern int proc_parse_options(char *options, struct pid_namespace *pid);
extern void proc_self_init(void);
extern int proc_remount(struct super_block *, int *, char *);
diff --git a/fs/proc/root.c b/fs/proc/root.c
index f4b1a9d2eca6..c4e76846033e 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -26,6 +26,21 @@
#include "internal.h"
+static int proc_test_super(struct super_block *sb, void *data)
+{
+ return sb->s_fs_info == data;
+}
+
+static int proc_set_super(struct super_block *sb, void *data)
+{
+ int err = set_anon_super(sb, NULL);
+ if (!err) {
+ struct pid_namespace *ns = (struct pid_namespace *)data;
+ sb->s_fs_info = get_pid_ns(ns);
+ }
+ return err;
+}
+
enum {
Opt_gid, Opt_hidepid, Opt_err,
};
@@ -36,7 +51,7 @@ static const match_table_t tokens = {
{Opt_err, NULL},
};
-int proc_parse_options(char *options, struct pid_namespace *pid)
+static int proc_parse_options(char *options, struct pid_namespace *pid)
{
char *p;
substring_t args[MAX_OPT_ARGS];
@@ -89,16 +104,45 @@ int proc_remount(struct super_block *sb, int *flags, char *data)
static struct dentry *proc_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
+ int err;
+ struct super_block *sb;
struct pid_namespace *ns;
+ char *options;
if (flags & SB_KERNMOUNT) {
- ns = data;
- data = NULL;
+ ns = (struct pid_namespace *)data;
+ options = NULL;
} else {
ns = task_active_pid_ns(current);
+ options = data;
+
+ /* Does the mounter have privilege over the pid namespace? */
+ if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
+ return ERR_PTR(-EPERM);
+ }
+
+ sb = sget(fs_type, proc_test_super, proc_set_super, flags, ns);
+ if (IS_ERR(sb))
+ return ERR_CAST(sb);
+
+ if (!proc_parse_options(options, ns)) {
+ deactivate_locked_super(sb);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (!sb->s_root) {
+ err = proc_fill_super(sb);
+ if (err) {
+ deactivate_locked_super(sb);
+ return ERR_PTR(err);
+ }
+
+ sb->s_flags |= SB_ACTIVE;
+ /* User space would break if executables appear on proc */
+ sb->s_iflags |= SB_I_NOEXEC;
}
- return mount_ns(fs_type, flags, data, ns, ns->user_ns, proc_fill_super);
+ return dget(sb->s_root);
}
static void proc_kill_sb(struct super_block *sb)
--
2.22.0
1
0
*Hello dear,*
*How are you? if you are still using this email address please reply me*
1
0

[PATCH OpenHarmony-4.19] OpenHarmony-4.19 pstore/blk: Introduce backend for block devices
by Kongzhengrong 08 Sep '21
by Kongzhengrong 08 Sep '21
08 Sep '21
mainline inclusion
from mainline-5.8
category: feature
commit:17639f67c1d61aba3c05e7703f75cd468f9d484f
issue: #I4919J
--------------------------------
Author: WeiXiong Liao <gmpy.liaowx(a)gmail.com<mailto:gmpy.liaowx@gmail.com>>
Date: Wed Mar 25 16:54:57 2020 +0800
pstore/blk: Introduce backend for block devices
pstore/blk is similar to pstore/ram, but uses a block device as the
storage rather than persistent ram.
The pstore/blk backend solves two common use-cases that used to preclude
using pstore/ram:
- not all devices have a battery that could be used to persist
regular RAM across power failures.
- most embedded intelligent equipment have no persistent ram, which
increases costs, instead preferring cheaper solutions, like block
devices.
pstore/blk provides separate configurations for the end user and for the
block drivers. User configuration determines how pstore/blk operates, such
as record sizes, max kmsg dump reasons, etc. These can be set by Kconfig
and/or module parameters, but module parameter have priority over Kconfig.
Driver configuration covers all the details about the target block device,
such as total size of the device and how to perform read/write operations.
These are provided by block drivers, calling pstore_register_blkdev(),
including an optional panic_write callback used to bypass regular IO
APIs in an effort to avoid potentially destabilized kernel code during
a panic.
Signed-off-by: WeiXiong Liao <liaoweixiong(a)allwinnertech.com<mailto:liaoweixiong@allwinnertech.com>>
Signed-off-by: stesen <stesen.ma(a)huawei.com<mailto:stesen.ma@huawei.com>>
Signed-off-by: roger <kongzhengrong(a)huawei.com<mailto:kongzhengrong@huawei.com>>
---
fs/pstore/Kconfig | 118 +++
fs/pstore/Makefile | 6 +
fs/pstore/blk.c | 517 ++++++++++++
fs/pstore/ftrace.c | 84 +-
fs/pstore/inode.c | 197 ++---
fs/pstore/internal.h | 11 +-
fs/pstore/platform.c | 65 +-
fs/pstore/pmsg.c | 1 +
fs/pstore/ram.c | 337 ++++----
fs/pstore/ram_core.c | 88 ++-
fs/pstore/zone.c | 1469 +++++++++++++++++++++++++++++++++++
include/linux/pstore.h | 51 +-
include/linux/pstore_blk.h | 118 +++
include/linux/pstore_ram.h | 66 +-
include/linux/pstore_zone.h | 60 ++
15 files changed, 2807 insertions(+), 381 deletions(-)
create mode 100644 fs/pstore/blk.c
create mode 100644 fs/pstore/zone.c
create mode 100644 include/linux/pstore_blk.h
create mode 100644 include/linux/pstore_zone.h
diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig
index 503086f7f..d863e5920 100644
--- a/fs/pstore/Kconfig
+++ b/fs/pstore/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
config PSTORE
tristate "Persistent store support"
select CRYPTO if PSTORE_COMPRESS
@@ -13,6 +14,14 @@ config PSTORE
If you don't have a platform persistent store driver,
say N.
+config PSTORE_DEFAULT_KMSG_BYTES
+ int "Default kernel log storage space" if EXPERT
+ depends on PSTORE
+ default "10240"
+ help
+ Defines default size of pstore kernel log storage.
+ Can be enlarged if needed, not recommended to shrink it.
+
config PSTORE_DEFLATE_COMPRESS
tristate "DEFLATE (ZLIB) compression"
default y
@@ -153,3 +162,112 @@ config PSTORE_RAM
"ramoops.ko".
For more information, see Documentation/admin-guide/ramoops.rst.
+
+config PSTORE_ZONE
+ tristate
+ depends on PSTORE
+ help
+ The common layer for pstore/blk (and pstore/ram in the future)
+ to manage storage in zones.
+
+config PSTORE_BLK
+ tristate "Log panic/oops to a block device"
+ depends on PSTORE
+ depends on BLOCK
+ select PSTORE_ZONE
+ default n
+ help
+ This enables panic and oops message to be logged to a block dev
+ where it can be read back at some later point.
+
+ For more information, see Documentation/admin-guide/pstore-blk.rst
+
+ If unsure, say N.
+
+config PSTORE_BLK_BLKDEV
+ string "block device identifier"
+ depends on PSTORE_BLK
+ default ""
+ help
+ Which block device should be used for pstore/blk.
+
+ It accepts the following variants:
+ 1) <hex_major><hex_minor> device number in hexadecimal representation,
+ with no leading 0x, for example b302.
+ 2) /dev/<disk_name> represents the device name of disk
+ 3) /dev/<disk_name><decimal> represents the device name and number
+ of partition - device number of disk plus the partition number
+ 4) /dev/<disk_name>p<decimal> - same as the above, this form is
+ used when disk name of partitioned disk ends with a digit.
+ 5) PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF representing the
+ unique id of a partition if the partition table provides it.
+ The UUID may be either an EFI/GPT UUID, or refer to an MSDOS
+ partition using the format SSSSSSSS-PP, where SSSSSSSS is a zero-
+ filled hex representation of the 32-bit "NT disk signature", and PP
+ is a zero-filled hex representation of the 1-based partition number.
+ 6) PARTUUID=<UUID>/PARTNROFF=<int> to select a partition in relation
+ to a partition with a known unique id.
+ 7) <major>:<minor> major and minor number of the device separated by
+ a colon.
+
+ NOTE that, both Kconfig and module parameters can configure
+ pstore/blk, but module parameters have priority over Kconfig.
+
+config PSTORE_BLK_KMSG_SIZE
+ int "Size in Kbytes of kmsg dump log to store"
+ depends on PSTORE_BLK
+ default 64
+ help
+ This just sets size of kmsg dump (oops, panic, etc) log for
+ pstore/blk. The size is in KB and must be a multiple of 4.
+
+ NOTE that, both Kconfig and module parameters can configure
+ pstore/blk, but module parameters have priority over Kconfig.
+
+config PSTORE_BLK_MAX_REASON
+ int "Maximum kmsg dump reason to store"
+ depends on PSTORE_BLK
+ default 2
+ help
+ The maximum reason for kmsg dumps to store. The default is
+ 2 (KMSG_DUMP_OOPS), see include/linux/kmsg_dump.h's
+ enum kmsg_dump_reason for more details.
+
+ NOTE that, both Kconfig and module parameters can configure
+ pstore/blk, but module parameters have priority over Kconfig.
+
+config PSTORE_BLK_PMSG_SIZE
+ int "Size in Kbytes of pmsg to store"
+ depends on PSTORE_BLK
+ depends on PSTORE_PMSG
+ default 64
+ help
+ This just sets size of pmsg (pmsg_size) for pstore/blk. The size is
+ in KB and must be a multiple of 4.
+
+ NOTE that, both Kconfig and module parameters can configure
+ pstore/blk, but module parameters have priority over Kconfig.
+
+config PSTORE_BLK_CONSOLE_SIZE
+ int "Size in Kbytes of console log to store"
+ depends on PSTORE_BLK
+ depends on PSTORE_CONSOLE
+ default 64
+ help
+ This just sets size of console log (console_size) to store via
+ pstore/blk. The size is in KB and must be a multiple of 4.
+
+ NOTE that, both Kconfig and module parameters can configure
+ pstore/blk, but module parameters have priority over Kconfig.
+
+config PSTORE_BLK_FTRACE_SIZE
+ int "Size in Kbytes of ftrace log to store"
+ depends on PSTORE_BLK
+ depends on PSTORE_FTRACE
+ default 64
+ help
+ This just sets size of ftrace log (ftrace_size) for pstore/blk. The
+ size is in KB and must be a multiple of 4.
+
+ NOTE that, both Kconfig and module parameters can configure
+ pstore/blk, but module parameters have priority over Kconfig.
diff --git a/fs/pstore/Makefile b/fs/pstore/Makefile
index 967b5891f..c270467ae 100644
--- a/fs/pstore/Makefile
+++ b/fs/pstore/Makefile
@@ -12,3 +12,9 @@ pstore-$(CONFIG_PSTORE_PMSG) += pmsg.o
ramoops-objs += ram.o ram_core.o
obj-$(CONFIG_PSTORE_RAM) += ramoops.o
+
+pstore_zone-objs += zone.o
+obj-$(CONFIG_PSTORE_ZONE) += pstore_zone.o
+
+pstore_blk-objs += blk.o
+obj-$(CONFIG_PSTORE_BLK) += pstore_blk.o
diff --git a/fs/pstore/blk.c b/fs/pstore/blk.c
new file mode 100644
index 000000000..bc567c8a3
--- /dev/null
+++ b/fs/pstore/blk.c
@@ -0,0 +1,517 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Implements pstore backend driver that write to block (or non-block) storage
+ * devices, using the pstore/zone API.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include "../../block/blk.h"
+#include <linux/blkdev.h>
+#include <linux/string.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/pstore_blk.h>
+#include <linux/mount.h>
+#include <linux/uio.h>
+
+static long kmsg_size = CONFIG_PSTORE_BLK_KMSG_SIZE;
+module_param(kmsg_size, long, 0400);
+MODULE_PARM_DESC(kmsg_size, "kmsg dump record size in kbytes");
+
+static int max_reason = CONFIG_PSTORE_BLK_MAX_REASON;
+module_param(max_reason, int, 0400);
+MODULE_PARM_DESC(max_reason,
+ "maximum reason for kmsg dump (default 2: Oops and Panic)");
+
+#if IS_ENABLED(CONFIG_PSTORE_PMSG)
+static long pmsg_size = CONFIG_PSTORE_BLK_PMSG_SIZE;
+#else
+static long pmsg_size = -1;
+#endif
+module_param(pmsg_size, long, 0400);
+MODULE_PARM_DESC(pmsg_size, "pmsg size in kbytes");
+
+#if IS_ENABLED(CONFIG_PSTORE_CONSOLE)
+static long console_size = CONFIG_PSTORE_BLK_CONSOLE_SIZE;
+#else
+static long console_size = -1;
+#endif
+module_param(console_size, long, 0400);
+MODULE_PARM_DESC(console_size, "console size in kbytes");
+
+#if IS_ENABLED(CONFIG_PSTORE_FTRACE)
+static long ftrace_size = CONFIG_PSTORE_BLK_FTRACE_SIZE;
+#else
+static long ftrace_size = -1;
+#endif
+module_param(ftrace_size, long, 0400);
+MODULE_PARM_DESC(ftrace_size, "ftrace size in kbytes");
+
+static bool best_effort;
+module_param(best_effort, bool, 0400);
+MODULE_PARM_DESC(best_effort, "use best effort to write (i.e. do not require storage driver pstore support, default: off)");
+
+/*
+ * blkdev - the block device to use for pstore storage
+ *
+ * Usually, this will be a partition of a block device.
+ *
+ * blkdev accepts the following variants:
+ * 1) <hex_major><hex_minor> device number in hexadecimal representation,
+ * with no leading 0x, for example b302.
+ * 2) /dev/<disk_name> represents the device number of disk
+ * 3) /dev/<disk_name><decimal> represents the device number
+ * of partition - device number of disk plus the partition number
+ * 4) /dev/<disk_name>p<decimal> - same as the above, that form is
+ * used when disk name of partitioned disk ends on a digit.
+ * 5) PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF representing the
+ * unique id of a partition if the partition table provides it.
+ * The UUID may be either an EFI/GPT UUID, or refer to an MSDOS
+ * partition using the format SSSSSSSS-PP, where SSSSSSSS is a zero-
+ * filled hex representation of the 32-bit "NT disk signature", and PP
+ * is a zero-filled hex representation of the 1-based partition number.
+ * 6) PARTUUID=<UUID>/PARTNROFF=<int> to select a partition in relation to
+ * a partition with a known unique id.
+ * 7) <major>:<minor> major and minor number of the device separated by
+ * a colon.
+ */
+static char blkdev[80] = CONFIG_PSTORE_BLK_BLKDEV;
+module_param_string(blkdev, blkdev, 80, 0400);
+MODULE_PARM_DESC(blkdev, "block device for pstore storage");
+
+/*
+ * All globals must only be accessed under the pstore_blk_lock
+ * during the register/unregister functions.
+ */
+static DEFINE_MUTEX(pstore_blk_lock);
+static struct block_device *psblk_bdev;
+static struct pstore_zone_info *pstore_zone_info;
+static pstore_blk_panic_write_op blkdev_panic_write;
+
+struct bdev_info {
+ dev_t devt;
+ sector_t nr_sects;
+ sector_t start_sect;
+};
+
+#define check_size(name, alignsize) ({ \
+ long _##name_ = (name); \
+ _##name_ = _##name_ <= 0 ? 0 : (_##name_ * 1024); \
+ if (_##name_ & ((alignsize) - 1)) { \
+ pr_info(#name " must align to %d\n", \
+ (alignsize)); \
+ _##name_ = ALIGN(name, (alignsize)); \
+ } \
+ _##name_; \
+})
+
+static int __register_pstore_device(struct pstore_device_info *dev)
+{
+ int ret;
+
+ lockdep_assert_held(&pstore_blk_lock);
+
+ if (!dev || !dev->total_size || !dev->read || !dev->write)
+ return -EINVAL;
+
+ /* someone already registered before */
+ if (pstore_zone_info)
+ return -EBUSY;
+
+ pstore_zone_info = kzalloc(sizeof(struct pstore_zone_info), GFP_KERNEL);
+ if (!pstore_zone_info)
+ return -ENOMEM;
+
+ /* zero means not limit on which backends to attempt to store. */
+ if (!dev->flags)
+ dev->flags = UINT_MAX;
+
+#define verify_size(name, alignsize, enabled) { \
+ long _##name_; \
+ if (enabled) \
+ _##name_ = check_size(name, alignsize); \
+ else \
+ _##name_ = 0; \
+ name = _##name_ / 1024; \
+ pstore_zone_info->name = _##name_; \
+ }
+
+ verify_size(kmsg_size, 4096, dev->flags & PSTORE_FLAGS_DMESG);
+ verify_size(pmsg_size, 4096, dev->flags & PSTORE_FLAGS_PMSG);
+ verify_size(console_size, 4096, dev->flags & PSTORE_FLAGS_CONSOLE);
+ verify_size(ftrace_size, 4096, dev->flags & PSTORE_FLAGS_FTRACE);
+#undef verify_size
+
+ pstore_zone_info->total_size = dev->total_size;
+ pstore_zone_info->max_reason = max_reason;
+ pstore_zone_info->read = dev->read;
+ pstore_zone_info->write = dev->write;
+ pstore_zone_info->erase = dev->erase;
+ pstore_zone_info->panic_write = dev->panic_write;
+ pstore_zone_info->name = KBUILD_MODNAME;
+ pstore_zone_info->owner = THIS_MODULE;
+
+ ret = register_pstore_zone(pstore_zone_info);
+ if (ret) {
+ kfree(pstore_zone_info);
+ pstore_zone_info = NULL;
+ }
+ return ret;
+}
+/**
+ * register_pstore_device() - register non-block device to pstore/blk
+ *
+ * @dev: non-block device information
+ *
+ * Return:
+ * * 0 - OK
+ * * Others - something error.
+ */
+int register_pstore_device(struct pstore_device_info *dev)
+{
+ int ret;
+
+ mutex_lock(&pstore_blk_lock);
+ ret = __register_pstore_device(dev);
+ mutex_unlock(&pstore_blk_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(register_pstore_device);
+
+static void __unregister_pstore_device(struct pstore_device_info *dev)
+{
+ lockdep_assert_held(&pstore_blk_lock);
+ if (pstore_zone_info && pstore_zone_info->read == dev->read) {
+ unregister_pstore_zone(pstore_zone_info);
+ kfree(pstore_zone_info);
+ pstore_zone_info = NULL;
+ }
+}
+
+/**
+ * unregister_pstore_device() - unregister non-block device from pstore/blk
+ *
+ * @dev: non-block device information
+ */
+void unregister_pstore_device(struct pstore_device_info *dev)
+{
+ mutex_lock(&pstore_blk_lock);
+ __unregister_pstore_device(dev);
+ mutex_unlock(&pstore_blk_lock);
+}
+EXPORT_SYMBOL_GPL(unregister_pstore_device);
+
+/**
+ * psblk_get_bdev() - open block device
+ *
+ * @holder: Exclusive holder identifier
+ * @info: Information about bdev to fill in
+ *
+ * Return: pointer to block device on success and others on error.
+ *
+ * On success, the returned block_device has reference count of one.
+ */
+static struct block_device *psblk_get_bdev(void *holder,
+ struct bdev_info *info)
+{
+ struct block_device *bdev = ERR_PTR(-ENODEV);
+ fmode_t mode = FMODE_READ | FMODE_WRITE;
+ sector_t nr_sects;
+
+ lockdep_assert_held(&pstore_blk_lock);
+
+ if (pstore_zone_info)
+ return ERR_PTR(-EBUSY);
+
+ if (!blkdev[0])
+ return ERR_PTR(-ENODEV);
+
+ if (holder)
+ mode |= FMODE_EXCL;
+ bdev = blkdev_get_by_path(blkdev, mode, holder);
+ if (IS_ERR(bdev)) {
+ dev_t devt;
+
+ devt = name_to_dev_t(blkdev);
+ if (devt == 0)
+ return ERR_PTR(-ENODEV);
+ bdev = blkdev_get_by_dev(devt, mode, holder);
+ if (IS_ERR(bdev))
+ return bdev;
+ }
+
+ nr_sects = part_nr_sects_read(bdev->bd_part);
+ if (!nr_sects) {
+ pr_err("not enough space for '%s'\n", blkdev);
+ blkdev_put(bdev, mode);
+ return ERR_PTR(-ENOSPC);
+ }
+
+ if (info) {
+ info->devt = bdev->bd_dev;
+ info->nr_sects = nr_sects;
+ info->start_sect = get_start_sect(bdev);
+ }
+
+ return bdev;
+}
+
+static void psblk_put_bdev(struct block_device *bdev, void *holder)
+{
+ fmode_t mode = FMODE_READ | FMODE_WRITE;
+
+ lockdep_assert_held(&pstore_blk_lock);
+
+ if (!bdev)
+ return;
+
+ if (holder)
+ mode |= FMODE_EXCL;
+ blkdev_put(bdev, mode);
+}
+
+static ssize_t psblk_generic_blk_read(char *buf, size_t bytes, loff_t pos)
+{
+ struct block_device *bdev = psblk_bdev;
+ struct file file;
+ struct kiocb kiocb;
+ struct iov_iter iter;
+ struct kvec iov = {.iov_base = buf, .iov_len = bytes};
+
+ if (!bdev)
+ return -ENODEV;
+
+ memset(&file, 0, sizeof(struct file));
+ file.f_mapping = bdev->bd_inode->i_mapping;
+ file.f_flags = O_DSYNC | __O_SYNC | O_NOATIME;
+ file.f_inode = bdev->bd_inode;
+ file_ra_state_init(&file.f_ra, file.f_mapping);
+
+ init_sync_kiocb(&kiocb, &file);
+ kiocb.ki_pos = pos;
+ iov_iter_kvec(&iter, READ | ITER_KVEC, &iov, 1, bytes);
+
+ return generic_file_read_iter(&kiocb, &iter);
+}
+
+static ssize_t psblk_generic_blk_write(const char *buf, size_t bytes,
+ loff_t pos)
+{
+ struct block_device *bdev = psblk_bdev;
+ struct iov_iter iter;
+ struct kiocb kiocb;
+ struct file file;
+ ssize_t ret;
+ struct kvec iov = {.iov_base = (void *)buf, .iov_len = bytes};
+
+ if (!bdev)
+ return -ENODEV;
+
+ /* Console/Ftrace backend may handle buffer until flush dirty zones */
+ if (in_interrupt() || irqs_disabled())
+ return -EBUSY;
+
+ memset(&file, 0, sizeof(struct file));
+ file.f_mapping = bdev->bd_inode->i_mapping;
+ file.f_flags = O_DSYNC | __O_SYNC | O_NOATIME;
+ file.f_inode = bdev->bd_inode;
+
+ init_sync_kiocb(&kiocb, &file);
+ kiocb.ki_pos = pos;
+ iov_iter_kvec(&iter, WRITE | ITER_KVEC, &iov, 1, bytes);
+
+ inode_lock(bdev->bd_inode);
+ ret = generic_write_checks(&kiocb, &iter);
+ if (ret > 0)
+ ret = generic_perform_write(&file, &iter, pos);
+ inode_unlock(bdev->bd_inode);
+
+ if (likely(ret > 0)) {
+ const struct file_operations f_op = {.fsync = blkdev_fsync};
+
+ file.f_op = &f_op;
+ kiocb.ki_pos += ret;
+ ret = generic_write_sync(&kiocb, ret);
+ }
+ return ret;
+}
+
+static ssize_t psblk_blk_panic_write(const char *buf, size_t size,
+ loff_t off)
+{
+ int ret;
+
+ if (!blkdev_panic_write)
+ return -EOPNOTSUPP;
+
+ /* size and off must align to SECTOR_SIZE for block device */
+ ret = blkdev_panic_write(buf, off >> SECTOR_SHIFT,
+ size >> SECTOR_SHIFT);
+ /* try next zone */
+ if (ret == -ENOMSG)
+ return ret;
+ return ret ? -EIO : size;
+}
+
+static int __register_pstore_blk(struct pstore_blk_info *info)
+{
+ char bdev_name[BDEVNAME_SIZE];
+ struct block_device *bdev;
+ struct pstore_device_info dev;
+ struct bdev_info binfo;
+ void *holder = blkdev;
+ int ret = -ENODEV;
+
+ lockdep_assert_held(&pstore_blk_lock);
+
+ /* hold bdev exclusively */
+ memset(&binfo, 0, sizeof(binfo));
+ bdev = psblk_get_bdev(holder, &binfo);
+ if (IS_ERR(bdev)) {
+ pr_err("failed to open '%s'!\n", blkdev);
+ return PTR_ERR(bdev);
+ }
+
+ /* only allow driver matching the @blkdev */
+ if (!binfo.devt || (!best_effort &&
+ MAJOR(binfo.devt) != info->major)) {
+ pr_debug("invalid major %u (expect %u)\n",
+ info->major, MAJOR(binfo.devt));
+ ret = -ENODEV;
+ goto err_put_bdev;
+ }
+
+ /* psblk_bdev must be assigned before register to pstore/blk */
+ psblk_bdev = bdev;
+ blkdev_panic_write = info->panic_write;
+
+ /* Copy back block device details. */
+ info->devt = binfo.devt;
+ info->nr_sects = binfo.nr_sects;
+ info->start_sect = binfo.start_sect;
+
+ memset(&dev, 0, sizeof(dev));
+ dev.total_size = info->nr_sects << SECTOR_SHIFT;
+ dev.flags = info->flags;
+ dev.read = psblk_generic_blk_read;
+ dev.write = psblk_generic_blk_write;
+ dev.erase = NULL;
+ dev.panic_write = info->panic_write ? psblk_blk_panic_write : NULL;
+
+ ret = __register_pstore_device(&dev);
+ if (ret)
+ goto err_put_bdev;
+
+ bdevname(bdev, bdev_name);
+ pr_info("attached %s%s\n", bdev_name,
+ info->panic_write ? "" : " (no dedicated panic_write!)");
+ return 0;
+
+err_put_bdev:
+ psblk_bdev = NULL;
+ blkdev_panic_write = NULL;
+ psblk_put_bdev(bdev, holder);
+ return ret;
+}
+
+/**
+ * register_pstore_blk() - register block device to pstore/blk
+ *
+ * @info: details on the desired block device interface
+ *
+ * Return:
+ * * 0 - OK
+ * * Others - something error.
+ */
+int register_pstore_blk(struct pstore_blk_info *info)
+{
+ int ret;
+
+ mutex_lock(&pstore_blk_lock);
+ ret = __register_pstore_blk(info);
+ mutex_unlock(&pstore_blk_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(register_pstore_blk);
+
+static void __unregister_pstore_blk(unsigned int major)
+{
+ struct pstore_device_info dev = { .read = psblk_generic_blk_read };
+ void *holder = blkdev;
+
+ lockdep_assert_held(&pstore_blk_lock);
+ if (psblk_bdev && MAJOR(psblk_bdev->bd_dev) == major) {
+ __unregister_pstore_device(&dev);
+ psblk_put_bdev(psblk_bdev, holder);
+ blkdev_panic_write = NULL;
+ psblk_bdev = NULL;
+ }
+}
+
+/**
+ * unregister_pstore_blk() - unregister block device from pstore/blk
+ *
+ * @major: the major device number of device
+ */
+void unregister_pstore_blk(unsigned int major)
+{
+ mutex_lock(&pstore_blk_lock);
+ __unregister_pstore_blk(major);
+ mutex_unlock(&pstore_blk_lock);
+}
+EXPORT_SYMBOL_GPL(unregister_pstore_blk);
+
+/* get information of pstore/blk */
+int pstore_blk_get_config(struct pstore_blk_config *info)
+{
+ strncpy(info->device, blkdev, 80);
+ info->max_reason = max_reason;
+ info->kmsg_size = check_size(kmsg_size, 4096);
+ info->pmsg_size = check_size(pmsg_size, 4096);
+ info->ftrace_size = check_size(ftrace_size, 4096);
+ info->console_size = check_size(console_size, 4096);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pstore_blk_get_config);
+
+static int __init pstore_blk_init(void)
+{
+ struct pstore_blk_info info = { };
+ int ret = 0;
+
+ mutex_lock(&pstore_blk_lock);
+ if (!pstore_zone_info && best_effort && blkdev[0])
+ ret = __register_pstore_blk(&info);
+ mutex_unlock(&pstore_blk_lock);
+
+ return ret;
+}
+late_initcall(pstore_blk_init);
+
+static void __exit pstore_blk_exit(void)
+{
+ mutex_lock(&pstore_blk_lock);
+ if (psblk_bdev)
+ __unregister_pstore_blk(MAJOR(psblk_bdev->bd_dev));
+ else {
+ struct pstore_device_info dev = { };
+
+ if (pstore_zone_info)
+ dev.read = pstore_zone_info->read;
+ __unregister_pstore_device(&dev);
+ }
+ mutex_unlock(&pstore_blk_lock);
+}
+module_exit(pstore_blk_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("WeiXiong Liao <liaoweixiong(a)allwinnertech.com<mailto:liaoweixiong@allwinnertech.com>>");
+MODULE_AUTHOR("Kees Cook <keescook(a)chromium.org<mailto:keescook@chromium.org>>");
+MODULE_DESCRIPTION("pstore backend for block devices");
diff --git a/fs/pstore/ftrace.c b/fs/pstore/ftrace.c
index 06aab07b6..5c0450701 100644
--- a/fs/pstore/ftrace.c
+++ b/fs/pstore/ftrace.c
@@ -1,14 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2012 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/kernel.h>
@@ -24,6 +16,7 @@
#include <linux/debugfs.h>
#include <linux/err.h>
#include <linux/cache.h>
+#include <linux/slab.h>
#include <asm/barrier.h>
#include "internal.h"
@@ -120,27 +113,13 @@ static struct dentry *pstore_ftrace_dir;
void pstore_register_ftrace(void)
{
- struct dentry *file;
-
if (!psinfo->write)
return;
pstore_ftrace_dir = debugfs_create_dir("pstore", NULL);
- if (!pstore_ftrace_dir) {
- pr_err("%s: unable to create pstore directory\n", __func__);
- return;
- }
-
- file = debugfs_create_file("record_ftrace", 0600, pstore_ftrace_dir,
- NULL, &pstore_knob_fops);
- if (!file) {
- pr_err("%s: unable to create record_ftrace file\n", __func__);
- goto err_file;
- }
- return;
-err_file:
- debugfs_remove(pstore_ftrace_dir);
+ debugfs_create_file("record_ftrace", 0600, pstore_ftrace_dir, NULL,
+ &pstore_knob_fops);
}
void pstore_unregister_ftrace(void)
@@ -148,9 +127,62 @@ void pstore_unregister_ftrace(void)
mutex_lock(&pstore_ftrace_lock);
if (pstore_ftrace_enabled) {
unregister_ftrace_function(&pstore_ftrace_ops);
- pstore_ftrace_enabled = 0;
+ pstore_ftrace_enabled = false;
}
mutex_unlock(&pstore_ftrace_lock);
debugfs_remove_recursive(pstore_ftrace_dir);
}
+
+ssize_t pstore_ftrace_combine_log(char **dest_log, size_t *dest_log_size,
+ const char *src_log, size_t src_log_size)
+{
+ size_t dest_size, src_size, total, dest_off, src_off;
+ size_t dest_idx = 0, src_idx = 0, merged_idx = 0;
+ void *merged_buf;
+ struct pstore_ftrace_record *drec, *srec, *mrec;
+ size_t record_size = sizeof(struct pstore_ftrace_record);
+
+ dest_off = *dest_log_size % record_size;
+ dest_size = *dest_log_size - dest_off;
+
+ src_off = src_log_size % record_size;
+ src_size = src_log_size - src_off;
+
+ total = dest_size + src_size;
+ merged_buf = kmalloc(total, GFP_KERNEL);
+ if (!merged_buf)
+ return -ENOMEM;
+
+ drec = (struct pstore_ftrace_record *)(*dest_log + dest_off);
+ srec = (struct pstore_ftrace_record *)(src_log + src_off);
+ mrec = (struct pstore_ftrace_record *)(merged_buf);
+
+ while (dest_size > 0 && src_size > 0) {
+ if (pstore_ftrace_read_timestamp(&drec[dest_idx]) <
+ pstore_ftrace_read_timestamp(&srec[src_idx])) {
+ mrec[merged_idx++] = drec[dest_idx++];
+ dest_size -= record_size;
+ } else {
+ mrec[merged_idx++] = srec[src_idx++];
+ src_size -= record_size;
+ }
+ }
+
+ while (dest_size > 0) {
+ mrec[merged_idx++] = drec[dest_idx++];
+ dest_size -= record_size;
+ }
+
+ while (src_size > 0) {
+ mrec[merged_idx++] = srec[src_idx++];
+ src_size -= record_size;
+ }
+
+ kfree(*dest_log);
+ *dest_log = merged_buf;
+ *dest_log_size = total;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pstore_ftrace_combine_log);
diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
index 6f51c6d7b..c331efe8d 100644
--- a/fs/pstore/inode.c
+++ b/fs/pstore/inode.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Persistent Storage - ramfs parts.
*
* Copyright (C) 2010 Intel Corporation <tony.luck(a)intel.com<mailto:tony.luck@intel.com>>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
@@ -34,18 +22,21 @@
#include <linux/magic.h>
#include <linux/pstore.h>
#include <linux/slab.h>
-#include <linux/spinlock.h>
#include <linux/uaccess.h>
#include "internal.h"
#define PSTORE_NAMELEN 64
-static DEFINE_SPINLOCK(allpstore_lock);
-static LIST_HEAD(allpstore);
+static DEFINE_MUTEX(records_list_lock);
+static LIST_HEAD(records_list);
+
+static DEFINE_MUTEX(pstore_sb_lock);
+static struct super_block *pstore_sb;
struct pstore_private {
struct list_head list;
+ struct dentry *dentry;
struct pstore_record *record;
size_t total_size;
};
@@ -118,7 +109,7 @@ static int pstore_ftrace_seq_show(struct seq_file *s, void *v)
rec = (struct pstore_ftrace_record *)(ps->record->buf + data->off);
- seq_printf(s, "CPU:%d ts:%llu %08lx %08lx %pf <- %pF\n",
+ seq_printf(s, "CPU:%d ts:%llu %08lx %08lx %ps <- %pS\n",
pstore_ftrace_decode_cpu(rec),
pstore_ftrace_read_timestamp(rec),
rec->ip, rec->parent_ip, (void *)rec->ip,
@@ -190,10 +181,22 @@ static int pstore_unlink(struct inode *dir, struct dentry *dentry)
{
struct pstore_private *p = d_inode(dentry)->i_private;
struct pstore_record *record = p->record;
+ int rc = 0;
if (!record->psi->erase)
return -EPERM;
+ /* Make sure we can't race while removing this file. */
+ mutex_lock(&records_list_lock);
+ if (!list_empty(&p->list))
+ list_del_init(&p->list);
+ else
+ rc = -ENOENT;
+ p->dentry = NULL;
+ mutex_unlock(&records_list_lock);
+ if (rc)
+ return rc;
+
mutex_lock(&record->psi->read_mutex);
record->psi->erase(record);
mutex_unlock(&record->psi->read_mutex);
@@ -204,15 +207,9 @@ static int pstore_unlink(struct inode *dir, struct dentry *dentry)
static void pstore_evict_inode(struct inode *inode)
{
struct pstore_private *p = inode->i_private;
- unsigned long flags;
clear_inode(inode);
- if (p) {
- spin_lock_irqsave(&allpstore_lock, flags);
- list_del(&p->list);
- spin_unlock_irqrestore(&allpstore_lock, flags);
- free_pstore_private(p);
- }
+ free_pstore_private(p);
}
static const struct inode_operations pstore_dir_inode_operations = {
@@ -290,11 +287,54 @@ static const struct super_operations pstore_ops = {
.show_options = pstore_show_options,
};
-static struct super_block *pstore_sb;
+static struct dentry *psinfo_lock_root(void)
+{
+ struct dentry *root;
-bool pstore_is_mounted(void)
+ mutex_lock(&pstore_sb_lock);
+ /*
+ * Having no backend is fine -- no records appear.
+ * Not being mounted is fine -- nothing to do.
+ */
+ if (!psinfo || !pstore_sb) {
+ mutex_unlock(&pstore_sb_lock);
+ return NULL;
+ }
+
+ root = pstore_sb->s_root;
+ inode_lock(d_inode(root));
+ mutex_unlock(&pstore_sb_lock);
+
+ return root;
+}
+
+int pstore_put_backend_records(struct pstore_info *psi)
{
- return pstore_sb != NULL;
+ struct pstore_private *pos, *tmp;
+ struct dentry *root;
+ int rc = 0;
+
+ root = psinfo_lock_root();
+ if (!root)
+ return 0;
+
+ mutex_lock(&records_list_lock);
+ list_for_each_entry_safe(pos, tmp, &records_list, list) {
+ if (pos->record->psi == psi) {
+ list_del_init(&pos->list);
+ rc = simple_unlink(d_inode(root), pos->dentry);
+ if (WARN_ON(rc))
+ break;
+ d_drop(pos->dentry);
+ dput(pos->dentry);
+ pos->dentry = NULL;
+ }
+ }
+ mutex_unlock(&records_list_lock);
+
+ inode_unlock(d_inode(root));
+
+ return rc;
}
/*
@@ -309,23 +349,20 @@ int pstore_mkfile(struct dentry *root, struct pstore_record *record)
int rc = 0;
char name[PSTORE_NAMELEN];
struct pstore_private *private, *pos;
- unsigned long flags;
size_t size = record->size + record->ecc_notice_size;
- WARN_ON(!inode_is_locked(d_inode(root)));
+ if (WARN_ON(!inode_is_locked(d_inode(root))))
+ return -EINVAL;
- spin_lock_irqsave(&allpstore_lock, flags);
- list_for_each_entry(pos, &allpstore, list) {
+ rc = -EEXIST;
+ /* Skip records that are already present in the filesystem. */
+ mutex_lock(&records_list_lock);
+ list_for_each_entry(pos, &records_list, list) {
if (pos->record->type == record->type &&
pos->record->id == record->id &&
- pos->record->psi == record->psi) {
- rc = -EEXIST;
- break;
- }
+ pos->record->psi == record->psi)
+ goto fail;
}
- spin_unlock_irqrestore(&allpstore_lock, flags);
- if (rc)
- return rc;
rc = -ENOMEM;
inode = pstore_get_inode(root->d_sb);
@@ -333,54 +370,10 @@ int pstore_mkfile(struct dentry *root, struct pstore_record *record)
goto fail;
inode->i_mode = S_IFREG | 0444;
inode->i_fop = &pstore_file_operations;
-
- switch (record->type) {
- case PSTORE_TYPE_DMESG:
- scnprintf(name, sizeof(name), "dmesg-%s-%llu%s",
- record->psi->name, record->id,
- record->compressed ? ".enc.z" : "");
- break;
- case PSTORE_TYPE_CONSOLE:
- scnprintf(name, sizeof(name), "console-%s-%llu",
- record->psi->name, record->id);
- break;
- case PSTORE_TYPE_FTRACE:
- scnprintf(name, sizeof(name), "ftrace-%s-%llu",
- record->psi->name, record->id);
- break;
- case PSTORE_TYPE_MCE:
- scnprintf(name, sizeof(name), "mce-%s-%llu",
- record->psi->name, record->id);
- break;
- case PSTORE_TYPE_PPC_RTAS:
- scnprintf(name, sizeof(name), "rtas-%s-%llu",
- record->psi->name, record->id);
- break;
- case PSTORE_TYPE_PPC_OF:
- scnprintf(name, sizeof(name), "powerpc-ofw-%s-%llu",
- record->psi->name, record->id);
- break;
- case PSTORE_TYPE_PPC_COMMON:
- scnprintf(name, sizeof(name), "powerpc-common-%s-%llu",
- record->psi->name, record->id);
- break;
- case PSTORE_TYPE_PMSG:
- scnprintf(name, sizeof(name), "pmsg-%s-%llu",
- record->psi->name, record->id);
- break;
- case PSTORE_TYPE_PPC_OPAL:
- scnprintf(name, sizeof(name), "powerpc-opal-%s-%llu",
- record->psi->name, record->id);
- break;
- case PSTORE_TYPE_UNKNOWN:
- scnprintf(name, sizeof(name), "unknown-%s-%llu",
- record->psi->name, record->id);
- break;
- default:
- scnprintf(name, sizeof(name), "type%d-%s-%llu",
- record->type, record->psi->name, record->id);
- break;
- }
+ scnprintf(name, sizeof(name), "%s-%s-%llu%s",
+ pstore_type_to_name(record->type),
+ record->psi->name, record->id,
+ record->compressed ? ".enc.z" : "");
private = kzalloc(sizeof(*private), GFP_KERNEL);
if (!private)
@@ -390,6 +383,7 @@ int pstore_mkfile(struct dentry *root, struct pstore_record *record)
if (!dentry)
goto fail_private;
+ private->dentry = dentry;
private->record = record;
inode->i_size = private->total_size = size;
inode->i_private = private;
@@ -399,9 +393,8 @@ int pstore_mkfile(struct dentry *root, struct pstore_record *record)
d_add(dentry, inode);
- spin_lock_irqsave(&allpstore_lock, flags);
- list_add(&private->list, &allpstore);
- spin_unlock_irqrestore(&allpstore_lock, flags);
+ list_add(&private->list, &records_list);
+ mutex_unlock(&records_list_lock);
return 0;
@@ -409,8 +402,8 @@ int pstore_mkfile(struct dentry *root, struct pstore_record *record)
free_pstore_private(private);
fail_inode:
iput(inode);
-
fail:
+ mutex_unlock(&records_list_lock);
return rc;
}
@@ -422,16 +415,13 @@ int pstore_mkfile(struct dentry *root, struct pstore_record *record)
*/
void pstore_get_records(int quiet)
{
- struct pstore_info *psi = psinfo;
struct dentry *root;
- if (!psi || !pstore_sb)
+ root = psinfo_lock_root();
+ if (!root)
return;
- root = pstore_sb->s_root;
-
- inode_lock(d_inode(root));
- pstore_get_backend_records(psi, root, quiet);
+ pstore_get_backend_records(psinfo, root, quiet);
inode_unlock(d_inode(root));
}
@@ -439,8 +429,6 @@ static int pstore_fill_super(struct super_block *sb, void *data, int silent)
{
struct inode *inode;
- pstore_sb = sb;
-
sb->s_maxbytes = MAX_LFS_FILESIZE;
sb->s_blocksize = PAGE_SIZE;
sb->s_blocksize_bits = PAGE_SHIFT;
@@ -461,6 +449,10 @@ static int pstore_fill_super(struct super_block *sb, void *data, int silent)
if (!sb->s_root)
return -ENOMEM;
+ mutex_lock(&pstore_sb_lock);
+ pstore_sb = sb;
+ mutex_unlock(&pstore_sb_lock);
+
pstore_get_records(0);
return 0;
@@ -474,8 +466,17 @@ static struct dentry *pstore_mount(struct file_system_type *fs_type,
static void pstore_kill_sb(struct super_block *sb)
{
+ mutex_lock(&pstore_sb_lock);
+ WARN_ON(pstore_sb != sb);
+
kill_litter_super(sb);
pstore_sb = NULL;
+
+ mutex_lock(&records_list_lock);
+ INIT_LIST_HEAD(&records_list);
+ mutex_unlock(&records_list_lock);
+
+ mutex_unlock(&pstore_sb_lock);
}
static struct file_system_type pstore_fs_type = {
diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h
index 7062ea4bc..7fb219042 100644
--- a/fs/pstore/internal.h
+++ b/fs/pstore/internal.h
@@ -12,9 +12,18 @@ extern unsigned long kmsg_bytes;
#ifdef CONFIG_PSTORE_FTRACE
extern void pstore_register_ftrace(void);
extern void pstore_unregister_ftrace(void);
+ssize_t pstore_ftrace_combine_log(char **dest_log, size_t *dest_log_size,
+ const char *src_log, size_t src_log_size);
#else
static inline void pstore_register_ftrace(void) {}
static inline void pstore_unregister_ftrace(void) {}
+static inline ssize_t
+pstore_ftrace_combine_log(char **dest_log, size_t *dest_log_size,
+ const char *src_log, size_t src_log_size)
+{
+ *dest_log_size = 0;
+ return 0;
+}
#endif
#ifdef CONFIG_PSTORE_PMSG
@@ -31,9 +40,9 @@ extern void pstore_set_kmsg_bytes(int);
extern void pstore_get_records(int);
extern void pstore_get_backend_records(struct pstore_info *psi,
struct dentry *root, int quiet);
+extern int pstore_put_backend_records(struct pstore_info *psi);
extern int pstore_mkfile(struct dentry *root,
struct pstore_record *record);
-extern bool pstore_is_mounted(void);
extern void pstore_record_init(struct pstore_record *record,
struct pstore_info *psi);
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index 2197bf68f..0ce3962d4 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -56,9 +56,22 @@ static int pstore_update_ms = -1;
module_param_named(update_ms, pstore_update_ms, int, 0600);
MODULE_PARM_DESC(update_ms, "milliseconds before pstore updates its content "
"(default is -1, which means runtime updates are disabled; "
- "enabling this option is not safe, it may lead to further "
+ "enabling this option may not be safe; it may lead to further "
"corruption on Oopses)");
+/* Names should be in the same order as the enum pstore_type_id */
+static const char * const pstore_type_names[] = {
+ "dmesg",
+ "mce",
+ "console",
+ "ftrace",
+ "rtas",
+ "powerpc-ofw",
+ "powerpc-common",
+ "pmsg",
+ "powerpc-opal",
+};
+
static int pstore_new_entry;
static void pstore_timefunc(struct timer_list *);
@@ -75,12 +88,17 @@ static DEFINE_SPINLOCK(pstore_lock);
struct pstore_info *psinfo;
static char *backend;
+module_param(backend, charp, 0444);
+MODULE_PARM_DESC(backend, "specific backend to use");
+
static char *compress =
#ifdef CONFIG_PSTORE_COMPRESS_DEFAULT
CONFIG_PSTORE_COMPRESS_DEFAULT;
#else
NULL;
#endif
+module_param(compress, charp, 0444);
+MODULE_PARM_DESC(compress, "compression to use");
/* Compression parameters */
static struct crypto_comp *tfm;
@@ -104,7 +122,7 @@ void pstore_set_kmsg_bytes(int bytes)
/* Tag each group of saved records with a sequence number */
static int oopscount;
-static const char *get_reason_str(enum kmsg_dump_reason reason)
+const char *get_reason_str(enum kmsg_dump_reason reason)
{
switch (reason) {
case KMSG_DUMP_PANIC:
@@ -124,6 +142,30 @@ static const char *get_reason_str(enum kmsg_dump_reason reason)
}
}
+const char *pstore_type_to_name(enum pstore_type_id type)
+{
+ BUILD_BUG_ON(ARRAY_SIZE(pstore_type_names) != PSTORE_TYPE_MAX);
+
+ if (WARN_ON_ONCE(type >= PSTORE_TYPE_MAX))
+ return "unknown";
+
+ return pstore_type_names[type];
+}
+EXPORT_SYMBOL_GPL(pstore_type_to_name);
+
+enum pstore_type_id pstore_name_to_type(const char *name)
+{
+ int i;
+
+ for (i = 0; i < PSTORE_TYPE_MAX; i++) {
+ if (!strcmp(pstore_type_names[i], name))
+ return i;
+ }
+
+ return PSTORE_TYPE_MAX;
+}
+EXPORT_SYMBOL_GPL(pstore_name_to_type);
+
/*
* Should pstore_dump() wait for a concurrent pstore_dump()? If
* not, the current pstore_dump() will report a failure to dump
@@ -322,7 +364,7 @@ static void allocate_buf_for_compression(void)
big_oops_buf_sz = size;
big_oops_buf = buf;
- pr_info("Using compression: %s\n", zbackend->name);
+ pr_info("Using crash dump compression: %s\n", zbackend->name);
}
static void free_buf_for_compression(void)
@@ -452,7 +494,7 @@ static void pstore_dump(struct kmsg_dumper *dumper,
}
ret = psinfo->write(&record);
- if (ret == 0 && reason == KMSG_DUMP_OOPS && pstore_is_mounted())
+ if (ret == 0 && reason == KMSG_DUMP_OOPS)
pstore_new_entry = 1;
total += record.size;
@@ -484,6 +526,9 @@ static void pstore_console_write(struct console *con, const char *s, unsigned c)
{
struct pstore_record record;
+ if (!c)
+ return;
+
pstore_record_init(&record, psinfo);
record.type = PSTORE_TYPE_CONSOLE;
@@ -589,8 +634,7 @@ int pstore_register(struct pstore_info *psi)
if (psi->flags & PSTORE_FLAGS_DMESG)
allocate_buf_for_compression();
- if (pstore_is_mounted())
- pstore_get_records(0);
+ pstore_get_records(0);
if (psi->flags & PSTORE_FLAGS_DMESG)
pstore_register_kmsg();
@@ -612,7 +656,7 @@ int pstore_register(struct pstore_info *psi)
* Update the module parameter backend, so it is visible
* through /sys/module/pstore/parameters/backend
*/
- backend = psi->name;
+ backend = kstrdup(psi->name, GFP_KERNEL);
pr_info("Registered %s as persistent store backend\n", psi->name);
@@ -641,6 +685,7 @@ void pstore_unregister(struct pstore_info *psi)
free_buf_for_compression();
psinfo = NULL;
+ kfree(backend);
backend = NULL;
}
EXPORT_SYMBOL_GPL(pstore_unregister);
@@ -817,11 +862,5 @@ static void __exit pstore_exit(void)
}
module_exit(pstore_exit)
-module_param(compress, charp, 0444);
-MODULE_PARM_DESC(compress, "Pstore compression to use");
-
-module_param(backend, charp, 0444);
-MODULE_PARM_DESC(backend, "Pstore backend to use");
-
MODULE_AUTHOR("Tony Luck <tony.luck(a)intel.com<mailto:tony.luck@intel.com>>");
MODULE_LICENSE("GPL");
diff --git a/fs/pstore/pmsg.c b/fs/pstore/pmsg.c
index 24db02de1..754f6c7dd 100644
--- a/fs/pstore/pmsg.c
+++ b/fs/pstore/pmsg.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2014 Google, Inc.
*
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index bafbab2dd..127ad7ea4 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -1,23 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* RAM Oops/Panic logger
*
* Copyright (C) 2010 Marco Stornelli <marco.stornelli(a)gmail.com<mailto:marco.stornelli@gmail.com>>
* Copyright (C) 2011 Kees Cook <keescook(a)chromium.org<mailto:keescook@chromium.org>>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -35,6 +21,7 @@
#include <linux/pstore_ram.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include "internal.h"
#define RAMOOPS_KERNMSG_HDR "===="
#define MIN_MEM_SIZE 4096UL
@@ -67,22 +54,27 @@ MODULE_PARM_DESC(mem_size,
"size of reserved RAM used to store oops/panic logs");
static unsigned int mem_type;
-module_param(mem_type, uint, 0600);
+module_param(mem_type, uint, 0400);
MODULE_PARM_DESC(mem_type,
"set to 1 to try to use unbuffered memory (default 0)");
-static int dump_oops = 1;
-module_param(dump_oops, int, 0600);
-MODULE_PARM_DESC(dump_oops,
- "set to 1 to dump oopses, 0 to only dump panics (default 1)");
+static int ramoops_max_reason = -1;
+module_param_named(max_reason, ramoops_max_reason, int, 0400);
+MODULE_PARM_DESC(max_reason,
+ "maximum reason for kmsg dump (default 2: Oops and Panic) ");
static int ramoops_ecc;
-module_param_named(ecc, ramoops_ecc, int, 0600);
+module_param_named(ecc, ramoops_ecc, int, 0400);
MODULE_PARM_DESC(ramoops_ecc,
"if non-zero, the option enables ECC support and specifies "
"ECC buffer size in bytes (1 is a special value, means 16 "
"bytes ECC)");
+static int ramoops_dump_oops = -1;
+module_param_named(dump_oops, ramoops_dump_oops, int, 0400);
+MODULE_PARM_DESC(dump_oops,
+ "(deprecated: use max_reason instead) set to 1 to dump oopses & panics, 0 to only dump panics");
+
struct ramoops_context {
struct persistent_ram_zone **dprzs; /* Oops dump zones */
struct persistent_ram_zone *cprz; /* Console zone */
@@ -95,7 +87,6 @@ struct ramoops_context {
size_t console_size;
size_t ftrace_size;
size_t pmsg_size;
- int dump_oops;
u32 flags;
struct persistent_ram_ecc_info ecc_info;
unsigned int max_dump_cnt;
@@ -110,7 +101,6 @@ struct ramoops_context {
};
static struct platform_device *dummy;
-static struct ramoops_platform_data *dummy_data;
static int ramoops_pstore_open(struct pstore_info *psi)
{
@@ -124,31 +114,28 @@ static int ramoops_pstore_open(struct pstore_info *psi)
}
static struct persistent_ram_zone *
-ramoops_get_next_prz(struct persistent_ram_zone *przs[], uint *c, uint max,
- u64 *id,
- enum pstore_type_id *typep, enum pstore_type_id type,
- bool update)
+ramoops_get_next_prz(struct persistent_ram_zone *przs[], int id,
+ struct pstore_record *record)
{
struct persistent_ram_zone *prz;
- int i = (*c)++;
/* Give up if we never existed or have hit the end. */
- if (!przs || i >= max)
+ if (!przs)
return NULL;
- prz = przs[i];
+ prz = przs[id];
if (!prz)
return NULL;
/* Update old/shadowed buffer. */
- if (update)
+ if (prz->type == PSTORE_TYPE_DMESG)
persistent_ram_save_old(prz);
if (!persistent_ram_old_size(prz))
return NULL;
- *typep = type;
- *id = i;
+ record->type = prz->type;
+ record->id = id;
return prz;
}
@@ -186,58 +173,6 @@ static bool prz_ok(struct persistent_ram_zone *prz)
persistent_ram_ecc_string(prz, NULL, 0));
}
-static ssize_t ftrace_log_combine(struct persistent_ram_zone *dest,
- struct persistent_ram_zone *src)
-{
- size_t dest_size, src_size, total, dest_off, src_off;
- size_t dest_idx = 0, src_idx = 0, merged_idx = 0;
- void *merged_buf;
- struct pstore_ftrace_record *drec, *srec, *mrec;
- size_t record_size = sizeof(struct pstore_ftrace_record);
-
- dest_off = dest->old_log_size % record_size;
- dest_size = dest->old_log_size - dest_off;
-
- src_off = src->old_log_size % record_size;
- src_size = src->old_log_size - src_off;
-
- total = dest_size + src_size;
- merged_buf = kmalloc(total, GFP_KERNEL);
- if (!merged_buf)
- return -ENOMEM;
-
- drec = (struct pstore_ftrace_record *)(dest->old_log + dest_off);
- srec = (struct pstore_ftrace_record *)(src->old_log + src_off);
- mrec = (struct pstore_ftrace_record *)(merged_buf);
-
- while (dest_size > 0 && src_size > 0) {
- if (pstore_ftrace_read_timestamp(&drec[dest_idx]) <
- pstore_ftrace_read_timestamp(&srec[src_idx])) {
- mrec[merged_idx++] = drec[dest_idx++];
- dest_size -= record_size;
- } else {
- mrec[merged_idx++] = srec[src_idx++];
- src_size -= record_size;
- }
- }
-
- while (dest_size > 0) {
- mrec[merged_idx++] = drec[dest_idx++];
- dest_size -= record_size;
- }
-
- while (src_size > 0) {
- mrec[merged_idx++] = srec[src_idx++];
- src_size -= record_size;
- }
-
- kfree(dest->old_log);
- dest->old_log = merged_buf;
- dest->old_log_size = total;
-
- return 0;
-}
-
static ssize_t ramoops_pstore_read(struct pstore_record *record)
{
ssize_t size = 0;
@@ -257,10 +192,8 @@ static ssize_t ramoops_pstore_read(struct pstore_record *record)
/* Find the next valid persistent_ram_zone for DMESG */
while (cxt->dump_read_cnt < cxt->max_dump_cnt && !prz) {
- prz = ramoops_get_next_prz(cxt->dprzs, &cxt->dump_read_cnt,
- cxt->max_dump_cnt, &record->id,
- &record->type,
- PSTORE_TYPE_DMESG, 1);
+ prz = ramoops_get_next_prz(cxt->dprzs, cxt->dump_read_cnt++,
+ record);
if (!prz_ok(prz))
continue;
header_length = ramoops_read_kmsg_hdr(persistent_ram_old(prz),
@@ -274,22 +207,18 @@ static ssize_t ramoops_pstore_read(struct pstore_record *record)
}
}
- if (!prz_ok(prz))
- prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt,
- 1, &record->id, &record->type,
- PSTORE_TYPE_CONSOLE, 0);
+ if (!prz_ok(prz) && !cxt->console_read_cnt++)
+ prz = ramoops_get_next_prz(&cxt->cprz, 0 /* single */, record);
- if (!prz_ok(prz))
- prz = ramoops_get_next_prz(&cxt->mprz, &cxt->pmsg_read_cnt,
- 1, &record->id, &record->type,
- PSTORE_TYPE_PMSG, 0);
+ if (!prz_ok(prz) && !cxt->pmsg_read_cnt++)
+ prz = ramoops_get_next_prz(&cxt->mprz, 0 /* single */, record);
/* ftrace is last since it may want to dynamically allocate memory. */
if (!prz_ok(prz)) {
- if (!(cxt->flags & RAMOOPS_FLAG_FTRACE_PER_CPU)) {
- prz = ramoops_get_next_prz(cxt->fprzs,
- &cxt->ftrace_read_cnt, 1, &record->id,
- &record->type, PSTORE_TYPE_FTRACE, 0);
+ if (!(cxt->flags & RAMOOPS_FLAG_FTRACE_PER_CPU) &&
+ !cxt->ftrace_read_cnt++) {
+ prz = ramoops_get_next_prz(cxt->fprzs, 0 /* single */,
+ record);
} else {
/*
* Build a new dummy record which combines all the
@@ -306,11 +235,7 @@ static ssize_t ramoops_pstore_read(struct pstore_record *record)
while (cxt->ftrace_read_cnt < cxt->max_ftrace_cnt) {
prz_next = ramoops_get_next_prz(cxt->fprzs,
- &cxt->ftrace_read_cnt,
- cxt->max_ftrace_cnt,
- &record->id,
- &record->type,
- PSTORE_TYPE_FTRACE, 0);
+ cxt->ftrace_read_cnt++, record);
if (!prz_ok(prz_next))
continue;
@@ -319,7 +244,12 @@ static ssize_t ramoops_pstore_read(struct pstore_record *record)
tmp_prz->corrected_bytes +=
prz_next->corrected_bytes;
tmp_prz->bad_blocks += prz_next->bad_blocks;
- size = ftrace_log_combine(tmp_prz, prz_next);
+
+ size = pstore_ftrace_combine_log(
+ &tmp_prz->old_log,
+ &tmp_prz->old_log_size,
+ prz_next->old_log,
+ prz_next->old_log_size);
if (size)
goto out;
}
@@ -361,17 +291,15 @@ static ssize_t ramoops_pstore_read(struct pstore_record *record)
static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz,
struct pstore_record *record)
{
- char *hdr;
+ char hdr[36]; /* "===="(4), %lld(20), "."(1), %06lu(6), "-%c\n"(3) */
size_t len;
- hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR "%lld.%06lu-%c\n",
+ len = scnprintf(hdr, sizeof(hdr),
+ RAMOOPS_KERNMSG_HDR "%lld.%06lu-%c\n",
(time64_t)record->time.tv_sec,
record->time.tv_nsec / 1000,
record->compressed ? 'C' : 'D');
- WARN_ON_ONCE(!hdr);
- len = hdr ? strlen(hdr) : 0;
persistent_ram_write(prz, hdr, len);
- kfree(hdr);
return len;
}
@@ -412,16 +340,14 @@ static int notrace ramoops_pstore_write(struct pstore_record *record)
return -EINVAL;
/*
- * Out of the various dmesg dump types, ramoops is currently designed
- * to only store crash logs, rather than storing general kernel logs.
+ * We could filter on record->reason here if we wanted to (which
+ * would duplicate what happened before the "max_reason" setting
+ * was added), but that would defeat the purpose of a system
+ * changing printk.always_kmsg_dump, so instead log everything that
+ * the kmsg dumper sends us, since it should be doing the filtering
+ * based on the combination of printk.always_kmsg_dump and our
+ * requested "max_reason".
*/
- if (record->reason != KMSG_DUMP_OOPS &&
- record->reason != KMSG_DUMP_PANIC)
- return -EINVAL;
-
- /* Skip Oopes when configured to do so. */
- if (record->reason == KMSG_DUMP_OOPS && !cxt->dump_oops)
- return -EINVAL;
/*
* Explicitly only take the first part of any new crash.
@@ -450,6 +376,9 @@ static int notrace ramoops_pstore_write(struct pstore_record *record)
/* Build header and append record contents. */
hlen = ramoops_write_kmsg_hdr(prz, record);
+ if (!hlen)
+ return -ENOMEM;
+
size = record->size;
if (size + hlen > prz->buffer_size)
size = prz->buffer_size - hlen;
@@ -600,9 +529,17 @@ static int ramoops_init_przs(const char *name,
goto fail;
for (i = 0; i < *cnt; i++) {
+ char *label;
+
+ if (*cnt == 1)
+ label = kasprintf(GFP_KERNEL, "ramoops:%s", name);
+ else
+ label = kasprintf(GFP_KERNEL, "ramoops:%s(%d/%d)",
+ name, i, *cnt - 1);
prz_ar[i] = persistent_ram_new(*paddr, zone_sz, sig,
- &cxt->ecc_info,
- cxt->memtype, flags);
+ &cxt->ecc_info,
+ cxt->memtype, flags, label);
+ kfree(label);
if (IS_ERR(prz_ar[i])) {
err = PTR_ERR(prz_ar[i]);
dev_err(dev, "failed to request %s mem region (0x%zx@0x%llx): %d\n",
@@ -617,6 +554,7 @@ static int ramoops_init_przs(const char *name,
goto fail;
}
*paddr += zone_sz;
+ prz_ar[i]->type = pstore_name_to_type(name);
}
*przs = prz_ar;
@@ -632,6 +570,8 @@ static int ramoops_init_prz(const char *name,
struct persistent_ram_zone **prz,
phys_addr_t *paddr, size_t sz, u32 sig)
{
+ char *label;
+
if (!sz)
return 0;
@@ -642,8 +582,10 @@ static int ramoops_init_prz(const char *name,
return -ENOMEM;
}
+ label = kasprintf(GFP_KERNEL, "ramoops:%s", name);
*prz = persistent_ram_new(*paddr, sz, sig, &cxt->ecc_info,
- cxt->memtype, 0);
+ cxt->memtype, PRZ_FLAG_ZAP_OLD, label);
+ kfree(label);
if (IS_ERR(*prz)) {
int err = PTR_ERR(*prz);
@@ -652,26 +594,31 @@ static int ramoops_init_prz(const char *name,
return err;
}
- persistent_ram_zap(*prz);
-
*paddr += sz;
+ (*prz)->type = pstore_name_to_type(name);
return 0;
}
-static int ramoops_parse_dt_size(struct platform_device *pdev,
- const char *propname, u32 *value)
+/* Read a u32 from a dt property and make sure it's safe for an int. */
+static int ramoops_parse_dt_u32(struct platform_device *pdev,
+ const char *propname,
+ u32 default_value, u32 *value)
{
u32 val32 = 0;
int ret;
ret = of_property_read_u32(pdev->dev.of_node, propname, &val32);
- if (ret < 0 && ret != -EINVAL) {
+ if (ret == -EINVAL) {
+ /* field is missing, use default value. */
+ val32 = default_value;
+ } else if (ret < 0) {
dev_err(&pdev->dev, "failed to parse property %s: %d\n",
propname, ret);
return ret;
}
+ /* Sanity check our results. */
if (val32 > INT_MAX) {
dev_err(&pdev->dev, "%s %u > INT_MAX\n", propname, val32);
return -EOVERFLOW;
@@ -685,6 +632,7 @@ static int ramoops_parse_dt(struct platform_device *pdev,
struct ramoops_platform_data *pdata)
{
struct device_node *of_node = pdev->dev.of_node;
+ struct device_node *parent_node;
struct resource *res;
u32 value;
int ret;
@@ -700,24 +648,58 @@ static int ramoops_parse_dt(struct platform_device *pdev,
pdata->mem_size = resource_size(res);
pdata->mem_address = res->start;
+ /*
+ * Setting "unbuffered" is deprecated and will be ignored if
+ * "mem_type" is also specified.
+ */
pdata->mem_type = of_property_read_bool(of_node, "unbuffered");
- pdata->dump_oops = !of_property_read_bool(of_node, "no-dump-oops");
-
-#define parse_size(name, field) { \
- ret = ramoops_parse_dt_size(pdev, name, &value); \
+ /*
+ * Setting "no-dump-oops" is deprecated and will be ignored if
+ * "max_reason" is also specified.
+ */
+ if (of_property_read_bool(of_node, "no-dump-oops"))
+ pdata->max_reason = KMSG_DUMP_PANIC;
+ else
+ pdata->max_reason = KMSG_DUMP_OOPS;
+
+#define parse_u32(name, field, default_value) { \
+ ret = ramoops_parse_dt_u32(pdev, name, default_value, \
+ &value); \
if (ret < 0) \
return ret; \
field = value; \
}
- parse_size("record-size", pdata->record_size);
- parse_size("console-size", pdata->console_size);
- parse_size("ftrace-size", pdata->ftrace_size);
- parse_size("pmsg-size", pdata->pmsg_size);
- parse_size("ecc-size", pdata->ecc_info.ecc_size);
- parse_size("flags", pdata->flags);
+ parse_u32("mem-type", pdata->record_size, pdata->mem_type);
+ parse_u32("record-size", pdata->record_size, 0);
+ parse_u32("console-size", pdata->console_size, 0);
+ parse_u32("ftrace-size", pdata->ftrace_size, 0);
+ parse_u32("pmsg-size", pdata->pmsg_size, 0);
+ parse_u32("ecc-size", pdata->ecc_info.ecc_size, 0);
+ parse_u32("flags", pdata->flags, 0);
+ parse_u32("max-reason", pdata->max_reason, pdata->max_reason);
-#undef parse_size
+#undef parse_u32
+
+ /*
+ * Some old Chromebooks relied on the kernel setting the
+ * console_size and pmsg_size to the record size since that's
+ * what the downstream kernel did. These same Chromebooks had
+ * "ramoops" straight under the root node which isn't
+ * according to the current upstream bindings (though it was
+ * arguably acceptable under a prior version of the bindings).
+ * Let's make those old Chromebooks work by detecting that
+ * we're not a child of "reserved-memory" and mimicking the
+ * expected behavior.
+ */
+ parent_node = of_get_parent(of_node);
+ if (!of_node_name_eq(parent_node, "reserved-memory") &&
+ !pdata->console_size && !pdata->ftrace_size &&
+ !pdata->pmsg_size && !pdata->ecc_info.ecc_size) {
+ pdata->console_size = pdata->record_size;
+ pdata->pmsg_size = pdata->record_size;
+ }
+ of_node_put(parent_node);
return 0;
}
@@ -732,15 +714,6 @@ static int ramoops_probe(struct platform_device *pdev)
phys_addr_t paddr;
int err = -EINVAL;
- if (dev_of_node(dev) && !pdata) {
- pdata = &pdata_local;
- memset(pdata, 0, sizeof(*pdata));
-
- err = ramoops_parse_dt(pdev, pdata);
- if (err < 0)
- goto fail_out;
- }
-
/*
* Only a single ramoops area allowed at a time, so fail extra
* probes.
@@ -750,6 +723,15 @@ static int ramoops_probe(struct platform_device *pdev)
goto fail_out;
}
+ if (dev_of_node(dev) && !pdata) {
+ pdata = &pdata_local;
+ memset(pdata, 0, sizeof(*pdata));
+
+ err = ramoops_parse_dt(pdev, pdata);
+ if (err < 0)
+ goto fail_out;
+ }
+
/* Make sure we didn't get bogus platform data pointer. */
if (!pdata) {
pr_err("NULL platform data\n");
@@ -779,7 +761,6 @@ static int ramoops_probe(struct platform_device *pdev)
cxt->console_size = pdata->console_size;
cxt->ftrace_size = pdata->ftrace_size;
cxt->pmsg_size = pdata->pmsg_size;
- cxt->dump_oops = pdata->dump_oops;
cxt->flags = pdata->flags;
cxt->ecc_info = pdata->ecc_info;
@@ -787,7 +768,7 @@ static int ramoops_probe(struct platform_device *pdev)
dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size
- cxt->pmsg_size;
- err = ramoops_init_przs("dump", dev, cxt, &cxt->dprzs, &paddr,
+ err = ramoops_init_przs("dmesg", dev, cxt, &cxt->dprzs, &paddr,
dump_mem_sz, cxt->record_size,
&cxt->max_dump_cnt, 0, 0);
if (err)
@@ -822,8 +803,10 @@ static int ramoops_probe(struct platform_device *pdev)
* the single region size is how to check.
*/
cxt->pstore.flags = 0;
- if (cxt->max_dump_cnt)
+ if (cxt->max_dump_cnt) {
cxt->pstore.flags |= PSTORE_FLAGS_DMESG;
+ cxt->pstore.max_reason = pdata->max_reason;
+ }
if (cxt->console_size)
cxt->pstore.flags |= PSTORE_FLAGS_CONSOLE;
if (cxt->max_ftrace_cnt)
@@ -859,14 +842,14 @@ static int ramoops_probe(struct platform_device *pdev)
mem_size = pdata->mem_size;
mem_address = pdata->mem_address;
record_size = pdata->record_size;
- dump_oops = pdata->dump_oops;
+ ramoops_max_reason = pdata->max_reason;
ramoops_console_size = pdata->console_size;
ramoops_pmsg_size = pdata->pmsg_size;
ramoops_ftrace_size = pdata->ftrace_size;
- pr_info("attached 0x%lx@0x%llx, ecc: %d/%d\n",
+ pr_info("using 0x%lx@0x%llx, ecc: %d\n",
cxt->size, (unsigned long long)cxt->phys_addr,
- cxt->ecc_info.ecc_size, cxt->ecc_info.block_size);
+ cxt->ecc_info.ecc_size);
return 0;
@@ -918,13 +901,12 @@ static inline void ramoops_unregister_dummy(void)
{
platform_device_unregister(dummy);
dummy = NULL;
-
- kfree(dummy_data);
- dummy_data = NULL;
}
static void __init ramoops_register_dummy(void)
{
+ struct ramoops_platform_data pdata;
+
/*
* Prepare a dummy platform data structure to carry the module
* parameters. If mem_size isn't set, then there are no module
@@ -935,35 +917,38 @@ static void __init ramoops_register_dummy(void)
pr_info("using module parameters\n");
- dummy_data = kzalloc(sizeof(*dummy_data), GFP_KERNEL);
- if (!dummy_data) {
- pr_info("could not allocate pdata\n");
- return;
- }
-
- dummy_data->mem_size = mem_size;
- dummy_data->mem_address = mem_address;
- dummy_data->mem_type = mem_type;
- dummy_data->record_size = record_size;
- dummy_data->console_size = ramoops_console_size;
- dummy_data->ftrace_size = ramoops_ftrace_size;
- dummy_data->pmsg_size = ramoops_pmsg_size;
- dummy_data->dump_oops = dump_oops;
- dummy_data->flags = RAMOOPS_FLAG_FTRACE_PER_CPU;
+ memset(&pdata, 0, sizeof(pdata));
+ pdata.mem_size = mem_size;
+ pdata.mem_address = mem_address;
+ pdata.mem_type = mem_type;
+ pdata.record_size = record_size;
+ pdata.console_size = ramoops_console_size;
+ pdata.ftrace_size = ramoops_ftrace_size;
+ pdata.pmsg_size = ramoops_pmsg_size;
+ /* If "max_reason" is set, its value has priority over "dump_oops". */
+ if (ramoops_max_reason >= 0)
+ pdata.max_reason = ramoops_max_reason;
+ /* Otherwise, if "dump_oops" is set, parse it into "max_reason". */
+ else if (ramoops_dump_oops != -1)
+ pdata.max_reason = ramoops_dump_oops ? KMSG_DUMP_OOPS
+ : KMSG_DUMP_PANIC;
+ /* And if neither are explicitly set, use the default. */
+ else
+ pdata.max_reason = KMSG_DUMP_OOPS;
+ pdata.flags = RAMOOPS_FLAG_FTRACE_PER_CPU;
/*
* For backwards compatibility ramoops.ecc=1 means 16 bytes ECC
* (using 1 byte for ECC isn't much of use anyway).
*/
- dummy_data->ecc_info.ecc_size = ramoops_ecc == 1 ? 16 : ramoops_ecc;
+ pdata.ecc_info.ecc_size = ramoops_ecc == 1 ? 16 : ramoops_ecc;
dummy = platform_device_register_data(NULL, "ramoops", -1,
- dummy_data, sizeof(struct ramoops_platform_data));
+ &pdata, sizeof(pdata));
if (IS_ERR(dummy)) {
pr_info("could not create platform device: %ld\n",
PTR_ERR(dummy));
dummy = NULL;
- ramoops_unregister_dummy();
}
}
diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c
index 3c777ec80..fe5305028 100644
--- a/fs/pstore/ram_core.c
+++ b/fs/pstore/ram_core.c
@@ -1,18 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
-#define pr_fmt(fmt) "persistent_ram: " fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/device.h>
#include <linux/err.h>
@@ -29,11 +20,21 @@
#include <linux/vmalloc.h>
#include <asm/page.h>
+/**
+ * struct persistent_ram_buffer - persistent circular RAM buffer
+ *
+ * @sig:
+ * signature to indicate header (PERSISTENT_RAM_SIG xor PRZ-type value)
+ * @start:
+ * offset into @data where the beginning of the stored bytes begin
+ * @size:
+ * number of valid bytes stored in @data
+ */
struct persistent_ram_buffer {
uint32_t sig;
atomic_t start;
atomic_t size;
- uint8_t data[0];
+ uint8_t data[];
};
#define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */
@@ -245,7 +246,7 @@ static int persistent_ram_init_ecc(struct persistent_ram_zone *prz,
pr_info("error in header, %d\n", numerr);
prz->corrected_bytes += numerr;
} else if (numerr < 0) {
- pr_info("uncorrectable error in header\n");
+ pr_info_ratelimited("uncorrectable error in header\n");
prz->bad_blocks++;
}
@@ -282,7 +283,7 @@ static int notrace persistent_ram_update_user(struct persistent_ram_zone *prz,
const void __user *s, unsigned int start, unsigned int count)
{
struct persistent_ram_buffer *buffer = prz->buffer;
- int ret = unlikely(__copy_from_user(buffer->data + start, s, count)) ?
+ int ret = unlikely(copy_from_user(buffer->data + start, s, count)) ?
-EFAULT : 0;
persistent_ram_update_ecc(prz, start, count);
return ret;
@@ -347,8 +348,6 @@ int notrace persistent_ram_write_user(struct persistent_ram_zone *prz,
int rem, ret = 0, c = count;
size_t start;
- if (unlikely(!access_ok(VERIFY_READ, s, count)))
- return -EFAULT;
if (unlikely(c > prz->buffer_size)) {
s += c - prz->buffer_size;
c = prz->buffer_size;
@@ -397,6 +396,10 @@ void persistent_ram_zap(struct persistent_ram_zone *prz)
persistent_ram_update_header_ecc(prz);
}
+#define MEM_TYPE_WCOMBINE 0
+#define MEM_TYPE_NONCACHED 1
+#define MEM_TYPE_NORMAL 2
+
static void *persistent_ram_vmap(phys_addr_t start, size_t size,
unsigned int memtype)
{
@@ -410,10 +413,20 @@ static void *persistent_ram_vmap(phys_addr_t start, size_t size,
page_start = start - offset_in_page(start);
page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE);
- if (memtype)
+ switch (memtype) {
+ case MEM_TYPE_NORMAL:
+ prot = PAGE_KERNEL;
+ break;
+ case MEM_TYPE_NONCACHED:
prot = pgprot_noncached(PAGE_KERNEL);
- else
+ break;
+ case MEM_TYPE_WCOMBINE:
prot = pgprot_writecombine(PAGE_KERNEL);
+ break;
+ default:
+ pr_err("invalid mem_type=%d\n", memtype);
+ return NULL;
+ }
pages = kmalloc_array(page_count, sizeof(struct page *), GFP_KERNEL);
if (!pages) {
@@ -438,12 +451,13 @@ static void *persistent_ram_vmap(phys_addr_t start, size_t size,
}
static void *persistent_ram_iomap(phys_addr_t start, size_t size,
- unsigned int memtype)
+ unsigned int memtype, char *label)
{
void *va;
- if (!request_mem_region(start, size, "persistent_ram")) {
- pr_err("request mem region (0x%llx@0x%llx) failed\n",
+ if (!request_mem_region(start, size, label ?: "ramoops")) {
+ pr_err("request mem region (%s 0x%llx@0x%llx) failed\n",
+ label ?: "ramoops",
(unsigned long long)size, (unsigned long long)start);
return NULL;
}
@@ -470,7 +484,8 @@ static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
if (pfn_valid(start >> PAGE_SHIFT))
prz->vaddr = persistent_ram_vmap(start, size, memtype);
else
- prz->vaddr = persistent_ram_iomap(start, size, memtype);
+ prz->vaddr = persistent_ram_iomap(start, size, memtype,
+ prz->label);
if (!prz->vaddr) {
pr_err("%s: Failed to map 0x%llx pages at 0x%llx\n", __func__,
@@ -488,10 +503,13 @@ static int persistent_ram_post_init(struct persistent_ram_zone *prz, u32 sig,
struct persistent_ram_ecc_info *ecc_info)
{
int ret;
+ bool zap = !!(prz->flags & PRZ_FLAG_ZAP_OLD);
ret = persistent_ram_init_ecc(prz, ecc_info);
- if (ret)
+ if (ret) {
+ pr_warn("ECC failed %s\n", prz->label);
return ret;
+ }
sig ^= PERSISTENT_RAM_SIG;
@@ -502,23 +520,25 @@ static int persistent_ram_post_init(struct persistent_ram_zone *prz, u32 sig,
}
if (buffer_size(prz) > prz->buffer_size ||
- buffer_start(prz) > buffer_size(prz))
+ buffer_start(prz) > buffer_size(prz)) {
pr_info("found existing invalid buffer, size %zu, start %zu\n",
buffer_size(prz), buffer_start(prz));
- else {
+ zap = true;
+ } else {
pr_debug("found existing buffer, size %zu, start %zu\n",
buffer_size(prz), buffer_start(prz));
persistent_ram_save_old(prz);
- return 0;
}
} else {
pr_debug("no valid data in buffer (sig = 0x%08x)\n",
prz->buffer->sig);
+ prz->buffer->sig = sig;
+ zap = true;
}
- /* Rewind missing or invalid memory area. */
- prz->buffer->sig = sig;
- persistent_ram_zap(prz);
+ /* Reset missing, invalid, or single-use memory area. */
+ if (zap)
+ persistent_ram_zap(prz);
return 0;
}
@@ -546,12 +566,13 @@ void persistent_ram_free(struct persistent_ram_zone *prz)
prz->ecc_info.par = NULL;
persistent_ram_free_old(prz);
+ kfree(prz->label);
kfree(prz);
}
struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
u32 sig, struct persistent_ram_ecc_info *ecc_info,
- unsigned int memtype, u32 flags)
+ unsigned int memtype, u32 flags, char *label)
{
struct persistent_ram_zone *prz;
int ret = -ENOMEM;
@@ -565,6 +586,7 @@ struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
/* Initialize general buffer state. */
raw_spin_lock_init(&prz->buffer_lock);
prz->flags = flags;
+ prz->label = kstrdup(label, GFP_KERNEL);
ret = persistent_ram_buffer_map(start, size, prz, memtype);
if (ret)
@@ -574,6 +596,12 @@ struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
if (ret)
goto err;
+ pr_debug("attached %s 0x%zx@0x%llx: %zu header, %zu data, %zu ecc (%d/%d)\n",
+ prz->label, prz->size, (unsigned long long)prz->paddr,
+ sizeof(*prz->buffer), prz->buffer_size,
+ prz->size - sizeof(*prz->buffer) - prz->buffer_size,
+ prz->ecc_info.ecc_size, prz->ecc_info.block_size);
+
return prz;
err:
persistent_ram_free(prz);
diff --git a/fs/pstore/zone.c b/fs/pstore/zone.c
new file mode 100644
index 000000000..ce73cd880
--- /dev/null
+++ b/fs/pstore/zone.c
@@ -0,0 +1,1469 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Provide a pstore intermediate backend, organized into kernel memory
+ * allocated zones that are then mapped and flushed into a single
+ * contiguous region on a storage backend of some kind (block, mtd, etc).
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mount.h>
+#include <linux/printk.h>
+#include <linux/fs.h>
+#include <linux/pstore.h>
+#include <linux/pstore_zone.h>
+#include <linux/kdev_t.h>
+#include <linux/device.h>
+#include <linux/namei.h>
+#include <linux/fcntl.h>
+#include <linux/uio.h>
+#include <linux/writeback.h>
+#include "internal.h"
+
+#ifndef SECTOR_SIZE
+#define SECTOR_SIZE 512
+#endif
+
+/**
+ * struct psz_head - header of zone to flush to storage
+ *
+ * @sig: signature to indicate header (PSZ_SIG xor PSZONE-type value)
+ * @datalen: length of data in @data
+ * @start: offset into @data where the beginning of the stored bytes begin
+ * @data: zone data.
+ */
+struct psz_buffer {
+#define PSZ_SIG (0x43474244) /* DBGC */
+ uint32_t sig;
+ atomic_t datalen;
+ atomic_t start;
+ uint8_t data[];
+};
+
+/**
+ * struct psz_kmsg_header - kmsg dump-specific header to flush to storage
+ *
+ * @magic: magic num for kmsg dump header
+ * @time: kmsg dump trigger time
+ * @compressed: whether conpressed
+ * @counter: kmsg dump counter
+ * @reason: the kmsg dump reason (e.g. oops, panic, etc)
+ * @data: pointer to log data
+ *
+ * This is a sub-header for a kmsg dump, trailing after &psz_buffer.
+ */
+struct psz_kmsg_header {
+#define PSTORE_KMSG_HEADER_MAGIC 0x4dfc3ae5 /* Just a random number */
+ uint32_t magic;
+ struct timespec64 time;
+ bool compressed;
+ uint32_t counter;
+ enum kmsg_dump_reason reason;
+ uint8_t data[];
+};
+
+/**
+ * struct pstore_zone - single stored buffer
+ *
+ * @off: zone offset of storage
+ * @type: front-end type for this zone
+ * @name: front-end name for this zone
+ * @buffer: pointer to data buffer managed by this zone
+ * @oldbuf: pointer to old data buffer
+ * @buffer_size: bytes in @buffer->data
+ * @should_recover: whether this zone should recover from storage
+ * @dirty: whether the data in @buffer dirty
+ *
+ * zone structure in memory.
+ */
+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;
+};
+
+/**
+ * struct psz_context - all about running state of pstore/zone
+ *
+ * @kpszs: kmsg dump storage zones
+ * @ppsz: pmsg storage zone
+ * @cpsz: console storage zone
+ * @fpszs: ftrace storage zones
+ * @kmsg_max_cnt: max count of @kpszs
+ * @kmsg_read_cnt: counter of total read kmsg dumps
+ * @kmsg_write_cnt: counter of total kmsg dump writes
+ * @pmsg_read_cnt: counter of total read pmsg zone
+ * @console_read_cnt: counter of total read console zone
+ * @ftrace_max_cnt: max count of @fpszs
+ * @ftrace_read_cnt: counter of max read ftrace zone
+ * @oops_counter: counter of oops dumps
+ * @panic_counter: counter of panic dumps
+ * @recovered: whether finished recovering data from storage
+ * @on_panic: whether panic is happening
+ * @pstore_zone_info_lock: lock to @pstore_zone_info
+ * @pstore_zone_info: information from backend
+ * @pstore: structure for pstore
+ */
+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;
+ /*
+ * These counters should be calculated during recovery.
+ * It records the oops/panic times after crashes rather than boots.
+ */
+ unsigned int oops_counter;
+ unsigned int panic_counter;
+ atomic_t recovered;
+ atomic_t on_panic;
+
+ /*
+ * pstore_zone_info_lock protects this entire structure during calls
+ * to register_pstore_zone()/unregister_pstore_zone().
+ */
+ struct mutex pstore_zone_info_lock;
+ struct pstore_zone_info *pstore_zone_info;
+ struct pstore_info pstore;
+};
+static struct psz_context pstore_zone_cxt;
+
+static void psz_flush_all_dirty_zones(struct work_struct *);
+static DECLARE_DELAYED_WORK(psz_cleaner, psz_flush_all_dirty_zones);
+
+/**
+ * enum psz_flush_mode - flush mode for psz_zone_write()
+ *
+ * @FLUSH_NONE: do not flush to storage but update data on memory
+ * @FLUSH_PART: just flush part of data including meta data to storage
+ * @FLUSH_META: just flush meta data of zone to storage
+ * @FLUSH_ALL: flush all of zone
+ */
+enum psz_flush_mode {
+ FLUSH_NONE = 0,
+ FLUSH_PART,
+ FLUSH_META,
+ FLUSH_ALL,
+};
+
+static inline int buffer_datalen(struct pstore_zone *zone)
+{
+ return atomic_read(&zone->buffer->datalen);
+}
+
+static inline int buffer_start(struct pstore_zone *zone)
+{
+ return atomic_read(&zone->buffer->start);
+}
+
+static inline bool is_on_panic(void)
+{
+ return atomic_read(&pstore_zone_cxt.on_panic);
+}
+
+static ssize_t psz_zone_read_buffer(struct pstore_zone *zone, char *buf,
+ size_t len, unsigned long off)
+{
+ if (!buf || !zone || !zone->buffer)
+ return -EINVAL;
+ if (off > zone->buffer_size)
+ return -EINVAL;
+ len = min_t(size_t, len, zone->buffer_size - off);
+ memcpy(buf, zone->buffer->data + off, len);
+ return len;
+}
+
+static int psz_zone_read_oldbuf(struct pstore_zone *zone, char *buf,
+ size_t len, unsigned long off)
+{
+ if (!buf || !zone || !zone->oldbuf)
+ return -EINVAL;
+ if (off > zone->buffer_size)
+ return -EINVAL;
+ len = min_t(size_t, len, zone->buffer_size - off);
+ memcpy(buf, zone->oldbuf->data + off, len);
+ return 0;
+}
+
+static int psz_zone_write(struct pstore_zone *zone,
+ enum psz_flush_mode flush_mode, const char *buf,
+ size_t len, unsigned long off)
+{
+ struct pstore_zone_info *info = pstore_zone_cxt.pstore_zone_info;
+ ssize_t wcnt = 0;
+ ssize_t (*writeop)(const char *buf, size_t bytes, loff_t pos);
+ size_t wlen;
+
+ if (off > zone->buffer_size)
+ return -EINVAL;
+
+ wlen = min_t(size_t, len, zone->buffer_size - off);
+ if (buf && wlen) {
+ memcpy(zone->buffer->data + off, buf, wlen);
+ atomic_set(&zone->buffer->datalen, wlen + off);
+ }
+
+ /* avoid to damage old records */
+ if (!is_on_panic() && !atomic_read(&pstore_zone_cxt.recovered))
+ goto dirty;
+
+ writeop = is_on_panic() ? info->panic_write : info->write;
+ if (!writeop)
+ goto dirty;
+
+ switch (flush_mode) {
+ case FLUSH_NONE:
+ if (unlikely(buf && wlen))
+ goto dirty;
+ return 0;
+ case FLUSH_PART:
+ wcnt = writeop((const char *)zone->buffer->data + off, wlen,
+ zone->off + sizeof(*zone->buffer) + off);
+ if (wcnt != wlen)
+ goto dirty;
+ /* fallthrough */
+ case FLUSH_META:
+ wlen = sizeof(struct psz_buffer);
+ wcnt = writeop((const char *)zone->buffer, wlen, zone->off);
+ if (wcnt != wlen)
+ goto dirty;
+ break;
+ case FLUSH_ALL:
+ wlen = zone->buffer_size + sizeof(*zone->buffer);
+ wcnt = writeop((const char *)zone->buffer, wlen, zone->off);
+ if (wcnt != wlen)
+ goto dirty;
+ break;
+ }
+
+ return 0;
+dirty:
+ /* no need to mark dirty if going to try next zone */
+ if (wcnt == -ENOMSG)
+ return -ENOMSG;
+ atomic_set(&zone->dirty, true);
+ /* flush dirty zones nicely */
+ if (wcnt == -EBUSY && !is_on_panic())
+ schedule_delayed_work(&psz_cleaner, msecs_to_jiffies(500));
+ return -EBUSY;
+}
+
+static int psz_flush_dirty_zone(struct pstore_zone *zone)
+{
+ int ret;
+
+ if (unlikely(!zone))
+ return -EINVAL;
+
+ if (unlikely(!atomic_read(&pstore_zone_cxt.recovered)))
+ return -EBUSY;
+
+ if (!atomic_xchg(&zone->dirty, false))
+ return 0;
+
+ ret = psz_zone_write(zone, FLUSH_ALL, NULL, 0, 0);
+ if (ret)
+ atomic_set(&zone->dirty, true);
+ return ret;
+}
+
+static int psz_flush_dirty_zones(struct pstore_zone **zones, unsigned int cnt)
+{
+ int i, ret;
+ struct pstore_zone *zone;
+
+ if (!zones)
+ return -EINVAL;
+
+ for (i = 0; i < cnt; i++) {
+ zone = zones[i];
+ if (!zone)
+ return -EINVAL;
+ ret = psz_flush_dirty_zone(zone);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static int psz_move_zone(struct pstore_zone *old, struct pstore_zone *new)
+{
+ const char *data = (const char *)old->buffer->data;
+ int ret;
+
+ ret = psz_zone_write(new, FLUSH_ALL, data, buffer_datalen(old), 0);
+ if (ret) {
+ atomic_set(&new->buffer->datalen, 0);
+ atomic_set(&new->dirty, false);
+ return ret;
+ }
+ atomic_set(&old->buffer->datalen, 0);
+ return 0;
+}
+
+static void psz_flush_all_dirty_zones(struct work_struct *work)
+{
+ struct psz_context *cxt = &pstore_zone_cxt;
+ int ret = 0;
+
+ if (cxt->ppsz)
+ ret |= psz_flush_dirty_zone(cxt->ppsz);
+ if (cxt->cpsz)
+ ret |= psz_flush_dirty_zone(cxt->cpsz);
+ if (cxt->kpszs)
+ ret |= psz_flush_dirty_zones(cxt->kpszs, cxt->kmsg_max_cnt);
+ if (cxt->fpszs)
+ ret |= psz_flush_dirty_zones(cxt->fpszs, cxt->ftrace_max_cnt);
+ if (ret && cxt->pstore_zone_info)
+ schedule_delayed_work(&psz_cleaner, msecs_to_jiffies(1000));
+}
+
+static int psz_kmsg_recover_data(struct psz_context *cxt)
+{
+ struct pstore_zone_info *info = cxt->pstore_zone_info;
+ struct pstore_zone *zone = NULL;
+ struct psz_buffer *buf;
+ unsigned long i;
+ ssize_t rcnt;
+
+ if (!info->read)
+ return -EINVAL;
+
+ for (i = 0; i < cxt->kmsg_max_cnt; i++) {
+ zone = cxt->kpszs[i];
+ if (unlikely(!zone))
+ return -EINVAL;
+ if (atomic_read(&zone->dirty)) {
+ unsigned int wcnt = cxt->kmsg_write_cnt;
+ struct pstore_zone *new = cxt->kpszs[wcnt];
+ int ret;
+
+ ret = psz_move_zone(zone, new);
+ if (ret) {
+ pr_err("move zone from %lu to %d failed\n",
+ i, wcnt);
+ return ret;
+ }
+ cxt->kmsg_write_cnt = (wcnt + 1) % cxt->kmsg_max_cnt;
+ }
+ if (!zone->should_recover)
+ continue;
+ buf = zone->buffer;
+ rcnt = info->read((char *)buf, zone->buffer_size + sizeof(*buf),
+ zone->off);
+ if (rcnt != zone->buffer_size + sizeof(*buf))
+ return (int)rcnt < 0 ? (int)rcnt : -EIO;
+ }
+ return 0;
+}
+
+static int psz_kmsg_recover_meta(struct psz_context *cxt)
+{
+ struct pstore_zone_info *info = cxt->pstore_zone_info;
+ struct pstore_zone *zone;
+ size_t rcnt, len;
+ struct psz_buffer *buf;
+ struct psz_kmsg_header *hdr;
+ struct timespec64 time = { };
+ unsigned long i;
+ /*
+ * Recover may on panic, we can't allocate any memory by kmalloc.
+ * So, we use local array instead.
+ */
+ char buffer_header[sizeof(*buf) + sizeof(*hdr)] = {0};
+
+ if (!info->read)
+ return -EINVAL;
+
+ len = sizeof(*buf) + sizeof(*hdr);
+ buf = (struct psz_buffer *)buffer_header;
+ for (i = 0; i < cxt->kmsg_max_cnt; i++) {
+ zone = cxt->kpszs[i];
+ if (unlikely(!zone))
+ return -EINVAL;
+
+ rcnt = info->read((char *)buf, len, zone->off);
+ if (rcnt == -ENOMSG) {
+ pr_debug("%s with id %lu may be broken, skip\n",
+ zone->name, i);
+ continue;
+ } else if (rcnt != len) {
+ pr_err("read %s with id %lu failed\n", zone->name, i);
+ return (int)rcnt < 0 ? (int)rcnt : -EIO;
+ }
+
+ if (buf->sig != zone->buffer->sig) {
+ pr_debug("no valid data in kmsg dump zone %lu\n", i);
+ continue;
+ }
+
+ if (zone->buffer_size < atomic_read(&buf->datalen)) {
+ pr_info("found overtop zone: %s: id %lu, off %lld, size %zu\n",
+ zone->name, i, zone->off,
+ zone->buffer_size);
+ continue;
+ }
+
+ hdr = (struct psz_kmsg_header *)buf->data;
+ if (hdr->magic != PSTORE_KMSG_HEADER_MAGIC) {
+ pr_info("found invalid zone: %s: id %lu, off %lld, size %zu\n",
+ zone->name, i, zone->off,
+ zone->buffer_size);
+ continue;
+ }
+
+ /*
+ * we get the newest zone, and the next one must be the oldest
+ * or unused zone, because we do write one by one like a circle.
+ */
+ if (hdr->time.tv_sec >= time.tv_sec) {
+ time.tv_sec = hdr->time.tv_sec;
+ cxt->kmsg_write_cnt = (i + 1) % cxt->kmsg_max_cnt;
+ }
+
+ if (hdr->reason == KMSG_DUMP_OOPS)
+ cxt->oops_counter =
+ max(cxt->oops_counter, hdr->counter);
+ else if (hdr->reason == KMSG_DUMP_PANIC)
+ cxt->panic_counter =
+ max(cxt->panic_counter, hdr->counter);
+
+ if (!atomic_read(&buf->datalen)) {
+ pr_debug("found erased zone: %s: id %lu, off %lld, size %zu, datalen %d\n",
+ zone->name, i, zone->off,
+ zone->buffer_size,
+ atomic_read(&buf->datalen));
+ continue;
+ }
+
+ if (!is_on_panic())
+ zone->should_recover = true;
+ pr_debug("found nice zone: %s: id %lu, off %lld, size %zu, datalen %d\n",
+ zone->name, i, zone->off,
+ zone->buffer_size, atomic_read(&buf->datalen));
+ }
+
+ return 0;
+}
+
+static int psz_kmsg_recover(struct psz_context *cxt)
+{
+ int ret;
+
+ if (!cxt->kpszs)
+ return 0;
+
+ ret = psz_kmsg_recover_meta(cxt);
+ if (ret)
+ goto recover_fail;
+
+ ret = psz_kmsg_recover_data(cxt);
+ if (ret)
+ goto recover_fail;
+
+ return 0;
+recover_fail:
+ pr_debug("psz_recover_kmsg failed\n");
+ return ret;
+}
+
+static int psz_recover_zone(struct psz_context *cxt, struct pstore_zone *zone)
+{
+ struct pstore_zone_info *info = cxt->pstore_zone_info;
+ struct psz_buffer *oldbuf, tmpbuf;
+ int ret = 0;
+ char *buf;
+ ssize_t rcnt, len, start, off;
+
+ if (!zone || zone->oldbuf)
+ return 0;
+
+ if (is_on_panic()) {
+ /* save data as much as possible */
+ psz_flush_dirty_zone(zone);
+ return 0;
+ }
+
+ if (unlikely(!info->read))
+ return -EINVAL;
+
+ len = sizeof(struct psz_buffer);
+ rcnt = info->read((char *)&tmpbuf, len, zone->off);
+ if (rcnt != len) {
+ pr_debug("read zone %s failed\n", zone->name);
+ return (int)rcnt < 0 ? (int)rcnt : -EIO;
+ }
+
+ if (tmpbuf.sig != zone->buffer->sig) {
+ pr_debug("no valid data in zone %s\n", zone->name);
+ return 0;
+ }
+
+ if (zone->buffer_size < atomic_read(&tmpbuf.datalen) ||
+ zone->buffer_size < atomic_read(&tmpbuf.start)) {
+ pr_info("found overtop zone: %s: off %lld, size %zu\n",
+ zone->name, zone->off, zone->buffer_size);
+ /* just keep going */
+ return 0;
+ }
+
+ if (!atomic_read(&tmpbuf.datalen)) {
+ pr_debug("found erased zone: %s: off %lld, size %zu, datalen %d\n",
+ zone->name, zone->off, zone->buffer_size,
+ atomic_read(&tmpbuf.datalen));
+ return 0;
+ }
+
+ pr_debug("found nice zone: %s: off %lld, size %zu, datalen %d\n",
+ zone->name, zone->off, zone->buffer_size,
+ atomic_read(&tmpbuf.datalen));
+
+ len = atomic_read(&tmpbuf.datalen) + sizeof(*oldbuf);
+ oldbuf = kzalloc(len, GFP_KERNEL);
+ if (!oldbuf)
+ return -ENOMEM;
+
+ memcpy(oldbuf, &tmpbuf, sizeof(*oldbuf));
+ buf = (char *)oldbuf + sizeof(*oldbuf);
+ len = atomic_read(&oldbuf->datalen);
+ start = atomic_read(&oldbuf->start);
+ off = zone->off + sizeof(*oldbuf);
+
+ /* get part of data */
+ rcnt = info->read(buf, len - start, off + start);
+ if (rcnt != len - start) {
+ pr_err("read zone %s failed\n", zone->name);
+ ret = (int)rcnt < 0 ? (int)rcnt : -EIO;
+ goto free_oldbuf;
+ }
+
+ /* get the rest of data */
+ rcnt = info->read(buf + len - start, start, off);
+ if (rcnt != start) {
+ pr_err("read zone %s failed\n", zone->name);
+ ret = (int)rcnt < 0 ? (int)rcnt : -EIO;
+ goto free_oldbuf;
+ }
+
+ zone->oldbuf = oldbuf;
+ psz_flush_dirty_zone(zone);
+ return 0;
+
+free_oldbuf:
+ kfree(oldbuf);
+ return ret;
+}
+
+static int psz_recover_zones(struct psz_context *cxt,
+ struct pstore_zone **zones, unsigned int cnt)
+{
+ int ret;
+ unsigned int i;
+ struct pstore_zone *zone;
+
+ if (!zones)
+ return 0;
+
+ for (i = 0; i < cnt; i++) {
+ zone = zones[i];
+ if (unlikely(!zone))
+ continue;
+ ret = psz_recover_zone(cxt, zone);
+ if (ret)
+ goto recover_fail;
+ }
+
+ return 0;
+recover_fail:
+ pr_debug("recover %s[%u] failed\n", zone->name, i);
+ return ret;
+}
+
+/**
+ * psz_recovery() - recover data from storage
+ * @cxt: the context of pstore/zone
+ *
+ * recovery means reading data back from storage after rebooting
+ *
+ * Return: 0 on success, others on failure.
+ */
+static inline int psz_recovery(struct psz_context *cxt)
+{
+ int ret;
+
+ if (atomic_read(&cxt->recovered))
+ return 0;
+
+ ret = psz_kmsg_recover(cxt);
+ if (ret)
+ goto out;
+
+ ret = psz_recover_zone(cxt, cxt->ppsz);
+ if (ret)
+ goto out;
+
+ ret = psz_recover_zone(cxt, cxt->cpsz);
+ if (ret)
+ goto out;
+
+ ret = psz_recover_zones(cxt, cxt->fpszs, cxt->ftrace_max_cnt);
+
+out:
+ if (unlikely(ret))
+ pr_err("recover failed\n");
+ else {
+ pr_debug("recover end!\n");
+ atomic_set(&cxt->recovered, 1);
+ }
+ return ret;
+}
+
+static int psz_pstore_open(struct pstore_info *psi)
+{
+ struct psz_context *cxt = psi->data;
+
+ cxt->kmsg_read_cnt = 0;
+ cxt->pmsg_read_cnt = 0;
+ cxt->console_read_cnt = 0;
+ cxt->ftrace_read_cnt = 0;
+ return 0;
+}
+
+static inline bool psz_old_ok(struct pstore_zone *zone)
+{
+ if (zone && zone->oldbuf && atomic_read(&zone->oldbuf->datalen))
+ return true;
+ return false;
+}
+
+static inline bool psz_ok(struct pstore_zone *zone)
+{
+ if (zone && zone->buffer && buffer_datalen(zone))
+ return true;
+ return false;
+}
+
+static inline int psz_kmsg_erase(struct psz_context *cxt,
+ struct pstore_zone *zone, struct pstore_record *record)
+{
+ struct psz_buffer *buffer = zone->buffer;
+ struct psz_kmsg_header *hdr =
+ (struct psz_kmsg_header *)buffer->data;
+ size_t size;
+
+ if (unlikely(!psz_ok(zone)))
+ return 0;
+
+ /* this zone is already updated, no need to erase */
+ if (record->count != hdr->counter)
+ return 0;
+
+ size = buffer_datalen(zone) + sizeof(*zone->buffer);
+ atomic_set(&zone->buffer->datalen, 0);
+ if (cxt->pstore_zone_info->erase)
+ return cxt->pstore_zone_info->erase(size, zone->off);
+ else
+ return psz_zone_write(zone, FLUSH_META, NULL, 0, 0);
+}
+
+static inline int psz_record_erase(struct psz_context *cxt,
+ struct pstore_zone *zone)
+{
+ if (unlikely(!psz_old_ok(zone)))
+ return 0;
+
+ kfree(zone->oldbuf);
+ zone->oldbuf = NULL;
+ /*
+ * if there are new data in zone buffer, that means the old data
+ * are already invalid. It is no need to flush 0 (erase) to
+ * block device.
+ */
+ if (!buffer_datalen(zone))
+ return psz_zone_write(zone, FLUSH_META, NULL, 0, 0);
+ psz_flush_dirty_zone(zone);
+ return 0;
+}
+
+static int psz_pstore_erase(struct pstore_record *record)
+{
+ struct psz_context *cxt = record->psi->data;
+
+ switch (record->type) {
+ case PSTORE_TYPE_DMESG:
+ if (record->id >= cxt->kmsg_max_cnt)
+ return -EINVAL;
+ return psz_kmsg_erase(cxt, cxt->kpszs[record->id], record);
+ case PSTORE_TYPE_PMSG:
+ return psz_record_erase(cxt, cxt->ppsz);
+ case PSTORE_TYPE_CONSOLE:
+ return psz_record_erase(cxt, cxt->cpsz);
+ case PSTORE_TYPE_FTRACE:
+ if (record->id >= cxt->ftrace_max_cnt)
+ return -EINVAL;
+ return psz_record_erase(cxt, cxt->fpszs[record->id]);
+ default: return -EINVAL;
+ }
+}
+
+static void psz_write_kmsg_hdr(struct pstore_zone *zone,
+ struct pstore_record *record)
+{
+ struct psz_context *cxt = record->psi->data;
+ struct psz_buffer *buffer = zone->buffer;
+ struct psz_kmsg_header *hdr =
+ (struct psz_kmsg_header *)buffer->data;
+
+ hdr->magic = PSTORE_KMSG_HEADER_MAGIC;
+ hdr->compressed = record->compressed;
+ hdr->time.tv_sec = record->time.tv_sec;
+ hdr->time.tv_nsec = record->time.tv_nsec;
+ hdr->reason = record->reason;
+ if (hdr->reason == KMSG_DUMP_OOPS)
+ hdr->counter = ++cxt->oops_counter;
+ else if (hdr->reason == KMSG_DUMP_PANIC)
+ hdr->counter = ++cxt->panic_counter;
+ else
+ hdr->counter = 0;
+}
+
+/*
+ * In case zone is broken, which may occur to MTD device, we try each zones,
+ * start at cxt->kmsg_write_cnt.
+ */
+static inline int notrace psz_kmsg_write_record(struct psz_context *cxt,
+ struct pstore_record *record)
+{
+ size_t size, hlen;
+ struct pstore_zone *zone;
+ unsigned int i;
+
+ for (i = 0; i < cxt->kmsg_max_cnt; i++) {
+ unsigned int zonenum, len;
+ int ret;
+
+ zonenum = (cxt->kmsg_write_cnt + i) % cxt->kmsg_max_cnt;
+ zone = cxt->kpszs[zonenum];
+ if (unlikely(!zone))
+ return -ENOSPC;
+
+ /* avoid destroying old data, allocate a new one */
+ len = zone->buffer_size + sizeof(*zone->buffer);
+ zone->oldbuf = zone->buffer;
+ zone->buffer = kzalloc(len, GFP_KERNEL);
+ if (!zone->buffer) {
+ zone->buffer = zone->oldbuf;
+ return -ENOMEM;
+ }
+ zone->buffer->sig = zone->oldbuf->sig;
+
+ pr_debug("write %s to zone id %d\n", zone->name, zonenum);
+ psz_write_kmsg_hdr(zone, record);
+ hlen = sizeof(struct psz_kmsg_header);
+ size = min_t(size_t, record->size, zone->buffer_size - hlen);
+ ret = psz_zone_write(zone, FLUSH_ALL, record->buf, size, hlen);
+ if (likely(!ret || ret != -ENOMSG)) {
+ cxt->kmsg_write_cnt = zonenum + 1;
+ cxt->kmsg_write_cnt %= cxt->kmsg_max_cnt;
+ /* no need to try next zone, free last zone buffer */
+ kfree(zone->oldbuf);
+ zone->oldbuf = NULL;
+ return ret;
+ }
+
+ pr_debug("zone %u may be broken, try next dmesg zone\n",
+ zonenum);
+ kfree(zone->buffer);
+ zone->buffer = zone->oldbuf;
+ zone->oldbuf = NULL;
+ }
+
+ return -EBUSY;
+}
+
+static int notrace psz_kmsg_write(struct psz_context *cxt,
+ struct pstore_record *record)
+{
+ int ret;
+
+ /*
+ * Explicitly only take the first part of any new crash.
+ * If our buffer is larger than kmsg_bytes, this can never happen,
+ * and if our buffer is smaller than kmsg_bytes, we don't want the
+ * report split across multiple records.
+ */
+ if (record->part != 1)
+ return -ENOSPC;
+
+ if (!cxt->kpszs)
+ return -ENOSPC;
+
+ ret = psz_kmsg_write_record(cxt, record);
+ if (!ret && is_on_panic()) {
+ /* ensure all data are flushed to storage when panic */
+ pr_debug("try to flush other dirty zones\n");
+ psz_flush_all_dirty_zones(NULL);
+ }
+
+ /* always return 0 as we had handled it on buffer */
+ return 0;
+}
+
+static int notrace psz_record_write(struct pstore_zone *zone,
+ struct pstore_record *record)
+{
+ size_t start, rem;
+ bool is_full_data = false;
+ char *buf;
+ int cnt;
+
+ if (!zone || !record)
+ return -ENOSPC;
+
+ if (atomic_read(&zone->buffer->datalen) >= zone->buffer_size)
+ is_full_data = true;
+
+ cnt = record->size;
+ buf = record->buf;
+ if (unlikely(cnt > zone->buffer_size)) {
+ buf += cnt - zone->buffer_size;
+ cnt = zone->buffer_size;
+ }
+
+ start = buffer_start(zone);
+ rem = zone->buffer_size - start;
+ if (unlikely(rem < cnt)) {
+ psz_zone_write(zone, FLUSH_PART, buf, rem, start);
+ buf += rem;
+ cnt -= rem;
+ start = 0;
+ is_full_data = true;
+ }
+
+ atomic_set(&zone->buffer->start, cnt + start);
+ psz_zone_write(zone, FLUSH_PART, buf, cnt, start);
+
+ /**
+ * psz_zone_write will set datalen as start + cnt.
+ * It work if actual data length lesser than buffer size.
+ * If data length greater than buffer size, pmsg will rewrite to
+ * beginning of zone, which make buffer->datalen wrongly.
+ * So we should reset datalen as buffer size once actual data length
+ * greater than buffer size.
+ */
+ if (is_full_data) {
+ atomic_set(&zone->buffer->datalen, zone->buffer_size);
+ psz_zone_write(zone, FLUSH_META, NULL, 0, 0);
+ }
+ return 0;
+}
+
+static int notrace psz_pstore_write(struct pstore_record *record)
+{
+ struct psz_context *cxt = record->psi->data;
+
+ if (record->type == PSTORE_TYPE_DMESG &&
+ record->reason == KMSG_DUMP_PANIC)
+ atomic_set(&cxt->on_panic, 1);
+
+ /*
+ * if on panic, do not write except panic records
+ * Fix case that panic_write prints log which wakes up console backend.
+ */
+ if (is_on_panic() && record->type != PSTORE_TYPE_DMESG)
+ return -EBUSY;
+
+ switch (record->type) {
+ case PSTORE_TYPE_DMESG:
+ return psz_kmsg_write(cxt, record);
+ case PSTORE_TYPE_CONSOLE:
+ return psz_record_write(cxt->cpsz, record);
+ case PSTORE_TYPE_PMSG:
+ return psz_record_write(cxt->ppsz, record);
+ case PSTORE_TYPE_FTRACE: {
+ int zonenum = smp_processor_id();
+
+ if (!cxt->fpszs)
+ return -ENOSPC;
+ return psz_record_write(cxt->fpszs[zonenum], record);
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static struct pstore_zone *psz_read_next_zone(struct psz_context *cxt)
+{
+ struct pstore_zone *zone = NULL;
+
+ while (cxt->kmsg_read_cnt < cxt->kmsg_max_cnt) {
+ zone = cxt->kpszs[cxt->kmsg_read_cnt++];
+ if (psz_ok(zone))
+ return zone;
+ }
+
+ if (cxt->ftrace_read_cnt < cxt->ftrace_max_cnt)
+ /*
+ * No need psz_old_ok(). Let psz_ftrace_read() do so for
+ * combination. psz_ftrace_read() should traverse over
+ * all zones in case of some zone without data.
+ */
+ return cxt->fpszs[cxt->ftrace_read_cnt++];
+
+ if (cxt->pmsg_read_cnt == 0) {
+ cxt->pmsg_read_cnt++;
+ zone = cxt->ppsz;
+ if (psz_old_ok(zone))
+ return zone;
+ }
+
+ if (cxt->console_read_cnt == 0) {
+ cxt->console_read_cnt++;
+ zone = cxt->cpsz;
+ if (psz_old_ok(zone))
+ return zone;
+ }
+
+ return NULL;
+}
+
+static int psz_kmsg_read_hdr(struct pstore_zone *zone,
+ struct pstore_record *record)
+{
+ struct psz_buffer *buffer = zone->buffer;
+ struct psz_kmsg_header *hdr =
+ (struct psz_kmsg_header *)buffer->data;
+
+ if (hdr->magic != PSTORE_KMSG_HEADER_MAGIC)
+ return -EINVAL;
+ record->compressed = hdr->compressed;
+ record->time.tv_sec = hdr->time.tv_sec;
+ record->time.tv_nsec = hdr->time.tv_nsec;
+ record->reason = hdr->reason;
+ record->count = hdr->counter;
+ return 0;
+}
+
+static ssize_t psz_kmsg_read(struct pstore_zone *zone,
+ struct pstore_record *record)
+{
+ ssize_t size, hlen = 0;
+
+ size = buffer_datalen(zone);
+ /* Clear and skip this kmsg dump record if it has no valid header */
+ if (psz_kmsg_read_hdr(zone, record)) {
+ atomic_set(&zone->buffer->datalen, 0);
+ atomic_set(&zone->dirty, 0);
+ return -ENOMSG;
+ }
+ size -= sizeof(struct psz_kmsg_header);
+
+ if (!record->compressed) {
+ char *buf = kasprintf(GFP_KERNEL, "%s: Total %d times\n",
+ get_reason_str(record->reason),
+ record->count);
+ hlen = strlen(buf);
+ record->buf = krealloc(buf, hlen + size, GFP_KERNEL);
+ if (!record->buf) {
+ kfree(buf);
+ return -ENOMEM;
+ }
+ } else {
+ record->buf = kmalloc(size, GFP_KERNEL);
+ if (!record->buf)
+ return -ENOMEM;
+ }
+
+ size = psz_zone_read_buffer(zone, record->buf + hlen, size,
+ sizeof(struct psz_kmsg_header));
+ if (unlikely(size < 0)) {
+ kfree(record->buf);
+ return -ENOMSG;
+ }
+
+ return size + hlen;
+}
+
+/* try to combine all ftrace zones */
+static ssize_t psz_ftrace_read(struct pstore_zone *zone,
+ struct pstore_record *record)
+{
+ struct psz_context *cxt;
+ struct psz_buffer *buf;
+ int ret;
+
+ if (!zone || !record)
+ return -ENOSPC;
+
+ if (!psz_old_ok(zone))
+ goto out;
+
+ buf = (struct psz_buffer *)zone->oldbuf;
+ if (!buf)
+ return -ENOMSG;
+
+ ret = pstore_ftrace_combine_log(&record->buf, &record->size,
+ (char *)buf->data, atomic_read(&buf->datalen));
+ if (unlikely(ret))
+ return ret;
+
+out:
+ cxt = record->psi->data;
+ if (cxt->ftrace_read_cnt < cxt->ftrace_max_cnt)
+ /* then, read next ftrace zone */
+ return -ENOMSG;
+ record->id = 0;
+ return record->size ? record->size : -ENOMSG;
+}
+
+static ssize_t psz_record_read(struct pstore_zone *zone,
+ struct pstore_record *record)
+{
+ size_t len;
+ struct psz_buffer *buf;
+
+ if (!zone || !record)
+ return -ENOSPC;
+
+ buf = (struct psz_buffer *)zone->oldbuf;
+ if (!buf)
+ return -ENOMSG;
+
+ len = atomic_read(&buf->datalen);
+ record->buf = kmalloc(len, GFP_KERNEL);
+ if (!record->buf)
+ return -ENOMEM;
+
+ if (unlikely(psz_zone_read_oldbuf(zone, record->buf, len, 0))) {
+ kfree(record->buf);
+ return -ENOMSG;
+ }
+
+ return len;
+}
+
+static ssize_t psz_pstore_read(struct pstore_record *record)
+{
+ struct psz_context *cxt = record->psi->data;
+ ssize_t (*readop)(struct pstore_zone *zone,
+ struct pstore_record *record);
+ struct pstore_zone *zone;
+ ssize_t ret;
+
+ /* before read, we must recover from storage */
+ ret = psz_recovery(cxt);
+ if (ret)
+ return ret;
+
+next_zone:
+ zone = psz_read_next_zone(cxt);
+ if (!zone)
+ return 0;
+
+ record->type = zone->type;
+ switch (record->type) {
+ case PSTORE_TYPE_DMESG:
+ readop = psz_kmsg_read;
+ record->id = cxt->kmsg_read_cnt - 1;
+ break;
+ case PSTORE_TYPE_FTRACE:
+ readop = psz_ftrace_read;
+ break;
+ case PSTORE_TYPE_CONSOLE:
+ /* fallthrough */
+ case PSTORE_TYPE_PMSG:
+ readop = psz_record_read;
+ break;
+ default:
+ goto next_zone;
+ }
+
+ ret = readop(zone, record);
+ if (ret == -ENOMSG)
+ goto next_zone;
+ return ret;
+}
+
+static struct psz_context pstore_zone_cxt = {
+ .pstore_zone_info_lock =
+ __MUTEX_INITIALIZER(pstore_zone_cxt.pstore_zone_info_lock),
+ .recovered = ATOMIC_INIT(0),
+ .on_panic = ATOMIC_INIT(0),
+ .pstore = {
+ .owner = THIS_MODULE,
+ .open = psz_pstore_open,
+ .read = psz_pstore_read,
+ .write = psz_pstore_write,
+ .erase = psz_pstore_erase,
+ },
+};
+
+static void psz_free_zone(struct pstore_zone **pszone)
+{
+ struct pstore_zone *zone = *pszone;
+
+ if (!zone)
+ return;
+
+ kfree(zone->buffer);
+ kfree(zone);
+ *pszone = NULL;
+}
+
+static void psz_free_zones(struct pstore_zone ***pszones, unsigned int *cnt)
+{
+ struct pstore_zone **zones = *pszones;
+
+ if (!zones)
+ return;
+
+ while (*cnt > 0) {
+ (*cnt)--;
+ psz_free_zone(&(zones[*cnt]));
+ }
+ kfree(zones);
+ *pszones = NULL;
+}
+
+static void psz_free_all_zones(struct psz_context *cxt)
+{
+ if (cxt->kpszs)
+ psz_free_zones(&cxt->kpszs, &cxt->kmsg_max_cnt);
+ if (cxt->ppsz)
+ psz_free_zone(&cxt->ppsz);
+ if (cxt->cpsz)
+ psz_free_zone(&cxt->cpsz);
+ if (cxt->fpszs)
+ psz_free_zones(&cxt->fpszs, &cxt->ftrace_max_cnt);
+}
+
+static struct pstore_zone *psz_init_zone(enum pstore_type_id type,
+ loff_t *off, size_t size)
+{
+ struct pstore_zone_info *info = pstore_zone_cxt.pstore_zone_info;
+ struct pstore_zone *zone;
+ const char *name = pstore_type_to_name(type);
+
+ if (!size)
+ return NULL;
+
+ if (*off + size > info->total_size) {
+ pr_err("no room for %s (0x%zx@0x%llx over 0x%lx)\n",
+ name, size, *off, info->total_size);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ zone = kzalloc(sizeof(struct pstore_zone), GFP_KERNEL);
+ if (!zone)
+ return ERR_PTR(-ENOMEM);
+
+ zone->buffer = kmalloc(size, GFP_KERNEL);
+ if (!zone->buffer) {
+ kfree(zone);
+ return ERR_PTR(-ENOMEM);
+ }
+ memset(zone->buffer, 0xFF, size);
+ zone->off = *off;
+ zone->name = name;
+ zone->type = type;
+ zone->buffer_size = size - sizeof(struct psz_buffer);
+ zone->buffer->sig = type ^ PSZ_SIG;
+ zone->oldbuf = NULL;
+ atomic_set(&zone->dirty, 0);
+ atomic_set(&zone->buffer->datalen, 0);
+ atomic_set(&zone->buffer->start, 0);
+
+ *off += size;
+
+ pr_debug("pszone %s: off 0x%llx, %zu header, %zu data\n", zone->name,
+ zone->off, sizeof(*zone->buffer), zone->buffer_size);
+ return zone;
+}
+
+static struct pstore_zone **psz_init_zones(enum pstore_type_id type,
+ loff_t *off, size_t total_size, ssize_t record_size,
+ unsigned int *cnt)
+{
+ struct pstore_zone_info *info = pstore_zone_cxt.pstore_zone_info;
+ struct pstore_zone **zones, *zone;
+ const char *name = pstore_type_to_name(type);
+ int c, i;
+
+ *cnt = 0;
+ if (!total_size || !record_size)
+ return NULL;
+
+ if (*off + total_size > info->total_size) {
+ pr_err("no room for zones %s (0x%zx@0x%llx over 0x%lx)\n",
+ name, total_size, *off, info->total_size);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ c = total_size / record_size;
+ zones = kcalloc(c, sizeof(*zones), GFP_KERNEL);
+ if (!zones) {
+ pr_err("allocate for zones %s failed\n", name);
+ return ERR_PTR(-ENOMEM);
+ }
+ memset(zones, 0, c * sizeof(*zones));
+
+ for (i = 0; i < c; i++) {
+ zone = psz_init_zone(type, off, record_size);
+ if (!zone || IS_ERR(zone)) {
+ pr_err("initialize zones %s failed\n", name);
+ psz_free_zones(&zones, &i);
+ return (void *)zone;
+ }
+ zones[i] = zone;
+ }
+
+ *cnt = c;
+ return zones;
+}
+
+static int psz_alloc_zones(struct psz_context *cxt)
+{
+ struct pstore_zone_info *info = cxt->pstore_zone_info;
+ loff_t off = 0;
+ int err;
+ size_t off_size = 0;
+
+ off_size += info->pmsg_size;
+ cxt->ppsz = psz_init_zone(PSTORE_TYPE_PMSG, &off, info->pmsg_size);
+ if (IS_ERR(cxt->ppsz)) {
+ err = PTR_ERR(cxt->ppsz);
+ cxt->ppsz = NULL;
+ goto free_out;
+ }
+
+ off_size += info->console_size;
+ cxt->cpsz = psz_init_zone(PSTORE_TYPE_CONSOLE, &off,
+ info->console_size);
+ if (IS_ERR(cxt->cpsz)) {
+ err = PTR_ERR(cxt->cpsz);
+ cxt->cpsz = NULL;
+ goto free_out;
+ }
+
+ off_size += info->ftrace_size;
+ cxt->fpszs = psz_init_zones(PSTORE_TYPE_FTRACE, &off,
+ info->ftrace_size,
+ info->ftrace_size / nr_cpu_ids,
+ &cxt->ftrace_max_cnt);
+ if (IS_ERR(cxt->fpszs)) {
+ err = PTR_ERR(cxt->fpszs);
+ cxt->fpszs = NULL;
+ goto free_out;
+ }
+
+ cxt->kpszs = psz_init_zones(PSTORE_TYPE_DMESG, &off,
+ info->total_size - off_size,
+ info->kmsg_size, &cxt->kmsg_max_cnt);
+ if (IS_ERR(cxt->kpszs)) {
+ err = PTR_ERR(cxt->kpszs);
+ cxt->kpszs = NULL;
+ goto free_out;
+ }
+
+ return 0;
+free_out:
+ psz_free_all_zones(cxt);
+ return err;
+}
+
+/**
+ * register_pstore_zone() - register to pstore/zone
+ *
+ * @info: back-end driver information. See &struct pstore_zone_info.
+ *
+ * Only one back-end at one time.
+ *
+ * Return: 0 on success, others on failure.
+ */
+int register_pstore_zone(struct pstore_zone_info *info)
+{
+ int err = -EINVAL;
+ struct psz_context *cxt = &pstore_zone_cxt;
+
+ if (info->total_size < 4096) {
+ pr_warn("total_size must be >= 4096\n");
+ return -EINVAL;
+ }
+
+ if (!info->kmsg_size && !info->pmsg_size && !info->console_size &&
+ !info->ftrace_size) {
+ pr_warn("at least one record size must be non-zero\n");
+ return -EINVAL;
+ }
+
+ if (!info->name || !info->name[0])
+ return -EINVAL;
+
+#define check_size(name, size) { \
+ if (info->name > 0 && info->name < (size)) { \
+ pr_err(#name " must be over %d\n", (size)); \
+ return -EINVAL; \
+ } \
+ if (info->name & (size - 1)) { \
+ pr_err(#name " must be a multiple of %d\n", \
+ (size)); \
+ return -EINVAL; \
+ } \
+ }
+
+ check_size(total_size, 4096);
+ check_size(kmsg_size, SECTOR_SIZE);
+ check_size(pmsg_size, SECTOR_SIZE);
+ check_size(console_size, SECTOR_SIZE);
+ check_size(ftrace_size, SECTOR_SIZE);
+
+#undef check_size
+
+ /*
+ * the @read and @write must be applied.
+ * if no @read, pstore may mount failed.
+ * if no @write, pstore do not support to remove record file.
+ */
+ if (!info->read || !info->write) {
+ pr_err("no valid general read/write interface\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&cxt->pstore_zone_info_lock);
+ if (cxt->pstore_zone_info) {
+ pr_warn("'%s' already loaded: ignoring '%s'\n",
+ cxt->pstore_zone_info->name, info->name);
+ mutex_unlock(&cxt->pstore_zone_info_lock);
+ return -EBUSY;
+ }
+ cxt->pstore_zone_info = info;
+
+ pr_debug("register %s with properties:\n", info->name);
+ pr_debug("\ttotal size : %ld Bytes\n", info->total_size);
+ pr_debug("\tkmsg size : %ld Bytes\n", info->kmsg_size);
+ pr_debug("\tpmsg size : %ld Bytes\n", info->pmsg_size);
+ pr_debug("\tconsole size : %ld Bytes\n", info->console_size);
+ pr_debug("\tftrace size : %ld Bytes\n", info->ftrace_size);
+
+ err = psz_alloc_zones(cxt);
+ if (err) {
+ pr_err("alloc zones failed\n");
+ goto fail_out;
+ }
+
+ if (info->kmsg_size) {
+ cxt->pstore.bufsize = cxt->kpszs[0]->buffer_size -
+ sizeof(struct psz_kmsg_header);
+ cxt->pstore.buf = kzalloc(cxt->pstore.bufsize, GFP_KERNEL);
+ if (!cxt->pstore.buf) {
+ err = -ENOMEM;
+ goto fail_free;
+ }
+ }
+ cxt->pstore.data = cxt;
+
+ pr_info("registered %s as backend for", info->name);
+ cxt->pstore.max_reason = info->max_reason;
+ cxt->pstore.name = info->name;
+ if (info->kmsg_size) {
+ cxt->pstore.flags |= PSTORE_FLAGS_DMESG;
+ pr_cont(" kmsg(%s", get_reason_str(cxt->pstore.max_reason));
+ if (cxt->pstore_zone_info->panic_write)
+ pr_cont(",panic_write");
+ pr_cont(")");
+ }
+ if (info->pmsg_size) {
+ cxt->pstore.flags |= PSTORE_FLAGS_PMSG;
+ pr_cont(" pmsg");
+ }
+ if (info->console_size) {
+ cxt->pstore.flags |= PSTORE_FLAGS_CONSOLE;
+ pr_cont(" console");
+ }
+ if (info->ftrace_size) {
+ cxt->pstore.flags |= PSTORE_FLAGS_FTRACE;
+ pr_cont(" ftrace");
+ }
+ pr_cont("\n");
+
+ err = pstore_register(&cxt->pstore);
+ if (err) {
+ pr_err("registering with pstore failed\n");
+ goto fail_free;
+ }
+ mutex_unlock(&pstore_zone_cxt.pstore_zone_info_lock);
+
+ return 0;
+
+fail_free:
+ kfree(cxt->pstore.buf);
+ cxt->pstore.buf = NULL;
+ cxt->pstore.bufsize = 0;
+ psz_free_all_zones(cxt);
+fail_out:
+ pstore_zone_cxt.pstore_zone_info = NULL;
+ mutex_unlock(&pstore_zone_cxt.pstore_zone_info_lock);
+ return err;
+}
+EXPORT_SYMBOL_GPL(register_pstore_zone);
+
+/**
+ * unregister_pstore_zone() - unregister to pstore/zone
+ *
+ * @info: back-end driver information. See struct pstore_zone_info.
+ */
+void unregister_pstore_zone(struct pstore_zone_info *info)
+{
+ struct psz_context *cxt = &pstore_zone_cxt;
+
+ mutex_lock(&cxt->pstore_zone_info_lock);
+ if (!cxt->pstore_zone_info) {
+ mutex_unlock(&cxt->pstore_zone_info_lock);
+ return;
+ }
+
+ /* Stop incoming writes from pstore. */
+ pstore_unregister(&cxt->pstore);
+
+ /* Flush any pending writes. */
+ psz_flush_all_dirty_zones(NULL);
+ flush_delayed_work(&psz_cleaner);
+
+ /* Clean up allocations. */
+ kfree(cxt->pstore.buf);
+ cxt->pstore.buf = NULL;
+ cxt->pstore.bufsize = 0;
+ cxt->pstore_zone_info = NULL;
+
+ psz_free_all_zones(cxt);
+
+ /* Clear counters and zone state. */
+ cxt->oops_counter = 0;
+ cxt->panic_counter = 0;
+ atomic_set(&cxt->recovered, 0);
+ atomic_set(&cxt->on_panic, 0);
+
+ mutex_unlock(&cxt->pstore_zone_info_lock);
+}
+EXPORT_SYMBOL_GPL(unregister_pstore_zone);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("WeiXiong Liao <liaoweixiong(a)allwinnertech.com>");
+MODULE_AUTHOR("Kees Cook <keescook(a)chromium.org>");
+MODULE_DESCRIPTION("Storage Manager for pstore/blk");
diff --git a/include/linux/pstore.h b/include/linux/pstore.h
index de9093d6e..fb95293a5 100644
--- a/include/linux/pstore.h
+++ b/include/linux/pstore.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Persistent Storage - pstore.h
*
@@ -5,19 +6,6 @@
*
* This code is the generic layer to export data records from platform
* level persistent storage via a file system.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LINUX_PSTORE_H
#define _LINUX_PSTORE_H
@@ -32,21 +20,33 @@
struct module;
-/* pstore record types (see fs/pstore/inode.c for filename templates) */
+/*
+ * pstore record types (see fs/pstore/platform.c for pstore_type_names[])
+ * These values may be written to storage (see EFI vars backend), so
+ * they are kind of an ABI. Be careful changing the mappings.
+ */
enum pstore_type_id {
+ /* Frontend storage types */
PSTORE_TYPE_DMESG = 0,
PSTORE_TYPE_MCE = 1,
PSTORE_TYPE_CONSOLE = 2,
PSTORE_TYPE_FTRACE = 3,
- /* PPC64 partition types */
+
+ /* PPC64-specific partition types */
PSTORE_TYPE_PPC_RTAS = 4,
PSTORE_TYPE_PPC_OF = 5,
PSTORE_TYPE_PPC_COMMON = 6,
PSTORE_TYPE_PMSG = 7,
PSTORE_TYPE_PPC_OPAL = 8,
- PSTORE_TYPE_UNKNOWN = 255
+
+ /* End of the list */
+ PSTORE_TYPE_MAX
};
+const char *pstore_type_to_name(enum pstore_type_id type);
+enum pstore_type_id pstore_name_to_type(const char *name);
+const char *get_reason_str(enum kmsg_dump_reason reason);
+
struct pstore_info;
/**
* struct pstore_record - details of a pstore record entry
@@ -85,7 +85,7 @@ struct pstore_record {
/**
* struct pstore_info - backend pstore driver structure
*
- * @owner: module which is repsonsible for this backend driver
+ * @owner: module which is responsible for this backend driver
* @name: name of the backend driver
*
* @buf_lock: semaphore to serialize access to @buf
@@ -97,6 +97,12 @@ struct pstore_record {
*
* @read_mutex: serializes @open, @read, @close, and @erase callbacks
* @flags: bitfield of frontends the backend can accept writes for
+ * @max_reason: Used when PSTORE_FLAGS_DMESG is set. Contains the
+ * kmsg_dump_reason enum value. KMSG_DUMP_UNDEF means
+ * "use existing kmsg_dump() filtering, based on the
+ * printk.always_kmsg_dump boot param" (which is either
+ * KMSG_DUMP_OOPS when false, or KMSG_DUMP_MAX when
+ * true); see printk.always_kmsg_dump for more details.
* @data: backend-private pointer passed back during callbacks
*
* Callbacks:
@@ -171,7 +177,7 @@ struct pstore_record {
*/
struct pstore_info {
struct module *owner;
- char *name;
+ const char *name;
struct semaphore buf_lock;
char *buf;
@@ -180,6 +186,7 @@ struct pstore_info {
struct mutex read_mutex;
int flags;
+ int max_reason;
void *data;
int (*open)(struct pstore_info *psi);
@@ -192,10 +199,10 @@ struct pstore_info {
};
/* Supported frontends */
-#define PSTORE_FLAGS_DMESG (1 << 0)
-#define PSTORE_FLAGS_CONSOLE (1 << 1)
-#define PSTORE_FLAGS_FTRACE (1 << 2)
-#define PSTORE_FLAGS_PMSG (1 << 3)
+#define PSTORE_FLAGS_DMESG BIT(0)
+#define PSTORE_FLAGS_CONSOLE BIT(1)
+#define PSTORE_FLAGS_FTRACE BIT(2)
+#define PSTORE_FLAGS_PMSG BIT(3)
extern int pstore_register(struct pstore_info *);
extern void pstore_unregister(struct pstore_info *);
diff --git a/include/linux/pstore_blk.h b/include/linux/pstore_blk.h
new file mode 100644
index 000000000..61e914522
--- /dev/null
+++ b/include/linux/pstore_blk.h
@@ -0,0 +1,118 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __PSTORE_BLK_H_
+#define __PSTORE_BLK_H_
+
+#include <linux/types.h>
+#include <linux/pstore.h>
+#include <linux/pstore_zone.h>
+
+/**
+ * typedef pstore_blk_panic_write_op - panic write operation to block device
+ *
+ * @buf: the data to write
+ * @start_sect: start sector to block device
+ * @sects: sectors count on buf
+ *
+ * Return: On success, zero should be returned. Others excluding -ENOMSG
+ * mean error. -ENOMSG means to try next zone.
+ *
+ * Panic write to block device must be aligned to SECTOR_SIZE.
+ */
+typedef int (*pstore_blk_panic_write_op)(const char *buf, sector_t start_sect,
+ sector_t sects);
+
+/**
+ * struct pstore_blk_info - pstore/blk registration details
+ *
+ * @major: Which major device number to support with pstore/blk
+ * @flags: The supported PSTORE_FLAGS_* from linux/pstore.h.
+ * @panic_write:The write operation only used for the panic case.
+ * This can be NULL, but is recommended to avoid losing
+ * crash data if the kernel's IO path or work queues are
+ * broken during a panic.
+ * @devt: The dev_t that pstore/blk has attached to.
+ * @nr_sects: Number of sectors on @devt.
+ * @start_sect: Starting sector on @devt.
+ */
+struct pstore_blk_info {
+ unsigned int major;
+ unsigned int flags;
+ pstore_blk_panic_write_op panic_write;
+
+ /* Filled in by pstore/blk after registration. */
+ dev_t devt;
+ sector_t nr_sects;
+ sector_t start_sect;
+};
+
+int register_pstore_blk(struct pstore_blk_info *info);
+void unregister_pstore_blk(unsigned int major);
+
+/**
+ * struct pstore_device_info - back-end pstore/blk driver structure.
+ *
+ * @total_size: The total size in bytes pstore/blk can use. It must be greater
+ * than 4096 and be multiple of 4096.
+ * @flags: Refer to macro starting with PSTORE_FLAGS defined in
+ * linux/pstore.h. It means what front-ends this device support.
+ * Zero means all backends for compatible.
+ * @read: The general read operation. Both of the function parameters
+ * @size and @offset are relative value to bock device (not the
+ * whole disk).
+ * On success, the number of bytes should be returned, others
+ * means error.
+ * @write: The same as @read, but the following error number:
+ * -EBUSY means try to write again later.
+ * -ENOMSG means to try next zone.
+ * @erase: The general erase operation for device with special removing
+ * job. Both of the function parameters @size and @offset are
+ * relative value to storage.
+ * Return 0 on success and others on failure.
+ * @panic_write:The write operation only used for panic case. It's optional
+ * if you do not care panic log. The parameters are relative
+ * value to storage.
+ * On success, the number of bytes should be returned, others
+ * excluding -ENOMSG mean error. -ENOMSG means to try next zone.
+ */
+struct pstore_device_info {
+ unsigned long total_size;
+ unsigned int flags;
+ pstore_zone_read_op read;
+ pstore_zone_write_op write;
+ pstore_zone_erase_op erase;
+ pstore_zone_write_op panic_write;
+};
+
+int register_pstore_device(struct pstore_device_info *dev);
+void unregister_pstore_device(struct pstore_device_info *dev);
+
+/**
+ * struct pstore_blk_config - the pstore_blk backend configuration
+ *
+ * @device: Name of the desired block device
+ * @max_reason: Maximum kmsg dump reason to store to block device
+ * @kmsg_size: Total size of for kmsg dumps
+ * @pmsg_size: Total size of the pmsg storage area
+ * @console_size: Total size of the console storage area
+ * @ftrace_size: Total size for ftrace logging data (for all CPUs)
+ */
+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;
+};
+
+/**
+ * pstore_blk_get_config - get a copy of the pstore_blk backend configuration
+ *
+ * @info: The sturct pstore_blk_config to be filled in
+ *
+ * Failure returns negative error code, and success returns 0.
+ */
+int pstore_blk_get_config(struct pstore_blk_config *info);
+
+#endif
diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h
index e6d226464..9f16afec7 100644
--- a/include/linux/pstore_ram.h
+++ b/include/linux/pstore_ram.h
@@ -1,17 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2010 Marco Stornelli <marco.stornelli(a)gmail.com>
* Copyright (C) 2011 Kees Cook <keescook(a)chromium.org>
* Copyright (C) 2011 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __LINUX_PSTORE_RAM_H__
@@ -22,6 +13,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/list.h>
+#include <linux/pstore.h>
#include <linux/types.h>
/*
@@ -30,6 +22,11 @@
* PRZ_FLAG_NO_LOCK is used. For all other cases, locking is required.
*/
#define PRZ_FLAG_NO_LOCK BIT(0)
+/*
+ * If a PRZ should only have a single-boot lifetime, this marks it as
+ * getting wiped after its contents get copied out after boot.
+ */
+#define PRZ_FLAG_ZAP_OLD BIT(1)
struct persistent_ram_buffer;
struct rs_control;
@@ -42,16 +39,55 @@ struct persistent_ram_ecc_info {
uint16_t *par;
};
+/**
+ * struct persistent_ram_zone - Details of a persistent RAM zone (PRZ)
+ * used as a pstore backend
+ *
+ * @paddr: physical address of the mapped RAM area
+ * @size: size of mapping
+ * @label: unique name of this PRZ
+ * @type: frontend type for this PRZ
+ * @flags: holds PRZ_FLAGS_* bits
+ *
+ * @buffer_lock:
+ * locks access to @buffer "size" bytes and "start" offset
+ * @buffer:
+ * pointer to actual RAM area managed by this PRZ
+ * @buffer_size:
+ * bytes in @buffer->data (not including any trailing ECC bytes)
+ *
+ * @par_buffer:
+ * pointer into @buffer->data containing ECC bytes for @buffer->data
+ * @par_header:
+ * pointer into @buffer->data containing ECC bytes for @buffer header
+ * (i.e. all fields up to @data)
+ * @rs_decoder:
+ * RSLIB instance for doing ECC calculations
+ * @corrected_bytes:
+ * ECC corrected bytes accounting since boot
+ * @bad_blocks:
+ * ECC uncorrectable bytes accounting since boot
+ * @ecc_info:
+ * ECC configuration details
+ *
+ * @old_log:
+ * saved copy of @buffer->data prior to most recent wipe
+ * @old_log_size:
+ * bytes contained in @old_log
+ *
+ */
struct persistent_ram_zone {
phys_addr_t paddr;
size_t size;
void *vaddr;
- struct persistent_ram_buffer *buffer;
- size_t buffer_size;
+ char *label;
+ enum pstore_type_id type;
u32 flags;
+
raw_spinlock_t buffer_lock;
+ struct persistent_ram_buffer *buffer;
+ size_t buffer_size;
- /* ECC correction */
char *par_buffer;
char *par_header;
struct rs_control *rs_decoder;
@@ -65,7 +101,7 @@ struct persistent_ram_zone {
struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
u32 sig, struct persistent_ram_ecc_info *ecc_info,
- unsigned int memtype, u32 flags);
+ unsigned int memtype, u32 flags, char *label);
void persistent_ram_free(struct persistent_ram_zone *prz);
void persistent_ram_zap(struct persistent_ram_zone *prz);
@@ -97,7 +133,7 @@ struct ramoops_platform_data {
unsigned long console_size;
unsigned long ftrace_size;
unsigned long pmsg_size;
- int dump_oops;
+ int max_reason;
u32 flags;
struct persistent_ram_ecc_info ecc_info;
};
diff --git a/include/linux/pstore_zone.h b/include/linux/pstore_zone.h
new file mode 100644
index 000000000..1e35eaa33
--- /dev/null
+++ b/include/linux/pstore_zone.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __PSTORE_ZONE_H_
+#define __PSTORE_ZONE_H_
+
+#include <linux/types.h>
+
+typedef ssize_t (*pstore_zone_read_op)(char *, size_t, loff_t);
+typedef ssize_t (*pstore_zone_write_op)(const char *, size_t, loff_t);
+typedef ssize_t (*pstore_zone_erase_op)(size_t, loff_t);
+/**
+ * struct pstore_zone_info - pstore/zone back-end driver structure
+ *
+ * @owner: Module which is responsible for this back-end driver.
+ * @name: Name of the back-end driver.
+ * @total_size: The total size in bytes pstore/zone can use. It must be greater
+ * than 4096 and be multiple of 4096.
+ * @kmsg_size: The size of oops/panic zone. Zero means disabled, otherwise,
+ * it must be multiple of SECTOR_SIZE(512 Bytes).
+ * @max_reason: Maximum kmsg dump reason to store.
+ * @pmsg_size: The size of pmsg zone which is the same as @kmsg_size.
+ * @console_size:The size of console zone which is the same as @kmsg_size.
+ * @ftrace_size:The size of ftrace zone which is the same as @kmsg_size.
+ * @read: The general read operation. Both of the function parameters
+ * @size and @offset are relative value to storage.
+ * On success, the number of bytes should be returned, others
+ * mean error.
+ * @write: The same as @read, but the following error number:
+ * -EBUSY means try to write again later.
+ * -ENOMSG means to try next zone.
+ * @erase: The general erase operation for device with special removing
+ * job. Both of the function parameters @size and @offset are
+ * relative value to storage.
+ * Return 0 on success and others on failure.
+ * @panic_write:The write operation only used for panic case. It's optional
+ * if you do not care panic log. The parameters are relative
+ * value to storage.
+ * On success, the number of bytes should be returned, others
+ * excluding -ENOMSG mean error. -ENOMSG means to try next 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;
+};
+
+extern int register_pstore_zone(struct pstore_zone_info *info);
+extern void unregister_pstore_zone(struct pstore_zone_info *info);
+
+#endif
--
2.17.1
孔峥嵘
消费者BG软件架构设计部
华为消费者BG
上海浦东新区新金桥路1599号东方万国D栋 [3楼-21岛-4号]
Mobile:+86 13391368870
Email: kongzhengrong(a)huawei.com
[cid:image001.png@01D7A4AC.9F7034A0]
本邮件及其附件含有华为公司的保密信息,仅限于发送给上面地址中列出的个人或群组。
禁止任何其他人以任何形式使用(包括但不限于全部或部分地泄露、复制、或散发)本邮件中的信息。
如果您错收了本邮件,请您立即电话或邮件通知发件人并删除本邮件。
1
0

08 Sep '21
hi,
The following patches are for OpenHarmony 5.10 kernel.
These patches refer to some bugfixes (crypto/jbd2/block/scsi/perf/net, etc)
from upstream or local test.
-------------------------------------------------------------
Andrew Morton (1):
mm/vmalloc.c:__vmalloc_area_node(): avoid 32-bit overflow
Andrey Konovalov (1):
kasan: fix conflict with page poisoning
Ard Biesheuvel (11):
arm64: assembler: add cond_yield macro
crypto: arm64/sha1-ce - simplify NEON yield
crypto: arm64/sha2-ce - simplify NEON yield
crypto: arm64/sha3-ce - simplify NEON yield
crypto: arm64/sha512-ce - simplify NEON yield
crypto: arm64/aes-neonbs - remove NEON yield calls
crypto: arm64/aes-ce-mac - simplify NEON yield
crypto: arm64/crc-t10dif - move NEON yield to C code
arm64: assembler: remove conditional NEON yield macros
arm64: assembler: introduce wxN aliases for wN registers
arm64: fpsimd: run kernel mode NEON with softirqs disabled
Arnaldo Carvalho de Melo (1):
perf parse-events: Check if the software events array slots are
populated
Athira Rajeev (1):
powerpc/perf: Invoke per-CPU variable access with disabled interrupts
Christoph Hellwig (1):
writeback: don't warn on an unregistered BDI in __mark_inode_dirty
Cui GaoSheng (1):
arm32: kaslr: Fix the bitmap error
Dan Williams (1):
mm: fix page reference leak in soft_offline_page()
Eric W. Biederman (2):
exec: Don't open code get_close_on_exec
exec: Move unshare_files to fix posix file locking during exec
Eyal Birger (2):
vti: fix ipv4 pmtu check to honor ip header df
vti6: fix ipv4 pmtu check to honor ip header df
Gong, Sishuai (1):
net: fix a concurrency bug in l2tp_tunnel_register()
Huang Guobin (1):
netfilter: nftables: avoid potential overflows on 32bit arches
Ido Schimmel (1):
netfilter: Dissect flow after packet mangling
Jakub Kicinski (1):
net: make sure devices go through netdev_wait_all_refs
Jan Kara (1):
bdev: Do not return EBUSY if bdev discard races with write
Jason Yan (1):
scsi: core: Treat device offline as a failure
Jeffle Xu (1):
block: fix inflight statistics of part0
Jia Cheng Hu (1):
block, bfq: set next_rq to waker_bfqq->next_rq in waker injection
Jia-Ju Bai (1):
crypto: sun8i-ce - fix error return code in sun8i_ce_prng_generate()
Jianlin Lv (1):
perf tools: Fix arm64 build error with gcc-11
Kefeng Wang (6):
ARM: mm: Rafactor the __do_page_fault()
ARM: mm: Kill task_struct argument for __do_page_fault()
ARM: mm: Cleanup access_error()
ARM: mm: Kill page table base print in show_pte()
ARM: mm: Provide die_kernel_fault() helper
ARM: mm: Fix PXN process with LPAE feature
Liu Jian (1):
igmp: Add ip_mc_list lock in ip_check_mc_rcu
Liu Xiang (1):
mm: hugetlb: fix type of delta parameter and related local variables
in gather_surplus_pages()
Marco Elver (1):
kcsan: Never set up watchpoints on NULL pointers
Martin K. Petersen (1):
Revert "Revert "scsi: megaraid_sas: Added support for shared host
tagset for cpuhotplug""
Martin Liška (1):
perf annotate: Fix jump parsing for C++ code.
Mike Christie (6):
scsi: libiscsi: Drop taskqueuelock
scsi: libiscsi: Fix iscsi_task use after free()
scsi: libiscsi: Fix iSCSI host workq destruction
scsi: libiscsi: Add helper to calculate max SCSI cmds per session
scsi: iscsi_tcp: Fix shost can_queue initialization
scsi: libiscsi: Reset max/exp cmdsn during recovery
Ming Lei (3):
blk-mq: add new API of blk_mq_hctx_set_fq_lock_class
nvme-loop: use blk_mq_hctx_set_fq_lock_class to set loop's lock class
Revert "block: Fix a lockdep complaint triggered by request queue
flushing"
Mingrui Ren (1):
tty/serial/imx: Enable TXEN bit in imx_poll_init().
Muchun Song (2):
mm/page_alloc: speed up the iteration of max_order
mm/page_isolation: do not isolate the max order page
Namhyung Kim (1):
perf record: Fix memory leak in vDSO found using ASAN
Ondrej Mosnacek (1):
debugfs: fix security_locked_down() call for SELinux
Riccardo Mancini (2):
perf env: Fix memory leak of bpf_prog_info_linear member
perf symbol-elf: Fix memory leak by freeing sdt_note.args
Sargun Dhillon (2):
NFS: NFSv2/NFSv3: Use cred from fs_context during mount
NFSv4: Refactor to use user namespaces for nfs4idmap
Theodore Ts'o (2):
ext4: fix possible UAF when remounting r/o a mmp-protected file system
ext4: inline jbd2_journal_[un]register_shrinker()
Tian Tao (2):
mm/zswap: add the flag can_sleep_mapped
mm: set the sleep_mapped to true for zbud and z3fold
Vijayanand Jitta (1):
mm: vmalloc: prevent use after free in _vm_unmap_aliases
Vlad Buslov (1):
net: fib_notifier: don't return positive values on fib registration
Walter Wu (1):
kasan: fix null pointer dereference in kasan_record_aux_stack
Wang Hai (1):
usb: gadget: rndis: Fix info leak of rndis
Yang Li (1):
crypto: nx - add missing call to of_node_put()
Yang Shi (1):
mm: vmscan: use a new flag to indicate shrinker is registered
Ye Bin (1):
ext4: fix WARN_ON_ONCE(!buffer_uptodate) after an error writing the
superblock
Yonghong Song (1):
bpf: Fix NULL pointer dereference in bpf_get_local_storage() helper
YueHaibing (1):
mm/zswap: fix passing zero to 'PTR_ERR' warning
Yufen Yu (2):
scsi: remove unused kobj map for sd devie to avoid memleak
block: check disk exist before trying to add partition
Zhang Yi (9):
jbd2: remove the out label in __jbd2_journal_remove_checkpoint()
jbd2: ensure abort the journal if detect IO error when writing
original buffer back
jbd2: don't abort the journal when freeing buffers
jbd2: remove redundant buffer io error checks
jbd2,ext4: add a shrinker to release checkpointed buffers
jbd2: simplify journal_clean_one_cp_list()
ext4: remove bdev_try_to_free_page() callback
fs: remove bdev_try_to_free_page callback
jbd2: export jbd2_journal_[un]register_shrinker()
Zhihao Cheng (2):
mtd: mtd_blkdevs: Initialize rq.limits.discard_granularity
ubifs: Remove ui_mutex in ubifs_xattr_get and change_xattr
zhangyi (F) (2):
block_dump: remove block_dump feature
block_dump: remove comments in docs
.../admin-guide/laptops/laptop-mode.rst | 11 -
Documentation/admin-guide/sysctl/vm.rst | 8 -
arch/arm/boot/compressed/kaslr.c | 17 +-
arch/arm/mm/fault.c | 119 +++---
arch/arm/mm/fault.h | 4 +
arch/arm64/crypto/aes-glue.c | 21 +-
arch/arm64/crypto/aes-modes.S | 52 +--
arch/arm64/crypto/aes-neonbs-core.S | 8 +-
arch/arm64/crypto/crct10dif-ce-core.S | 43 +--
arch/arm64/crypto/crct10dif-ce-glue.c | 30 +-
arch/arm64/crypto/sha1-ce-core.S | 47 +--
arch/arm64/crypto/sha1-ce-glue.c | 22 +-
arch/arm64/crypto/sha2-ce-core.S | 38 +-
arch/arm64/crypto/sha2-ce-glue.c | 22 +-
arch/arm64/crypto/sha3-ce-core.S | 81 ++---
arch/arm64/crypto/sha3-ce-glue.c | 14 +-
arch/arm64/crypto/sha512-ce-core.S | 29 +-
arch/arm64/crypto/sha512-ce-glue.c | 53 ++-
arch/arm64/include/asm/assembler.h | 100 ++----
arch/arm64/kernel/asm-offsets.c | 2 +
arch/arm64/kernel/fpsimd.c | 4 +-
arch/powerpc/perf/core-book3s.c | 10 +-
block/bfq-iosched.c | 2 +-
block/blk-core.c | 9 -
block/blk-flush.c | 30 +-
block/blk-mq.c | 3 +-
block/blk.h | 1 -
block/genhd.c | 8 +
block/partitions/core.c | 19 +-
drivers/base/map.c | 28 ++
.../crypto/allwinner/sun8i-ce/sun8i-ce-prng.c | 1 +
drivers/crypto/nx/nx-common-powernv.c | 4 +-
drivers/mtd/mtd_blkdevs.c | 1 +
drivers/nvme/target/loop.c | 10 +
drivers/scsi/bnx2i/bnx2i_iscsi.c | 2 -
drivers/scsi/iscsi_tcp.c | 9 +-
drivers/scsi/libiscsi.c | 339 +++++++++++-------
drivers/scsi/libiscsi_tcp.c | 86 +++--
drivers/scsi/megaraid/megaraid_sas_base.c | 39 ++
drivers/scsi/megaraid/megaraid_sas_fusion.c | 29 +-
drivers/scsi/sd.c | 1 +
drivers/tty/serial/imx.c | 2 +-
drivers/usb/gadget/composite.c | 2 +-
drivers/usb/gadget/function/rndis.c | 37 +-
fs/block_dev.c | 25 +-
fs/debugfs/inode.c | 9 +-
fs/exec.c | 32 +-
fs/ext4/ext4_jbd2.c | 2 +-
fs/ext4/mmp.c | 31 +-
fs/ext4/super.c | 39 +-
fs/fs-writeback.c | 4 -
fs/jbd2/checkpoint.c | 206 +++++++++--
fs/jbd2/journal.c | 74 ++++
fs/jbd2/transaction.c | 17 -
fs/nfs/client.c | 4 +-
fs/nfs/nfs4client.c | 2 +-
fs/ubifs/xattr.c | 4 -
include/linux/blk-mq.h | 3 +
include/linux/bpf-cgroup.h | 57 ++-
include/linux/bpf.h | 43 ++-
include/linux/fs.h | 1 -
include/linux/genhd.h | 2 +
include/linux/jbd2.h | 35 ++
include/linux/kobj_map.h | 2 +
include/linux/shrinker.h | 7 +-
include/linux/writeback.h | 1 -
include/linux/zpool.h | 3 +
include/scsi/libiscsi.h | 6 +-
include/scsi/scsi.h | 54 +--
include/trace/events/jbd2.h | 101 ++++++
kernel/bpf/helpers.c | 15 +-
kernel/bpf/local_storage.c | 5 +-
kernel/kcsan/encoding.h | 6 +-
kernel/sysctl.c | 8 -
mm/hugetlb.c | 7 +-
mm/kasan/generic.c | 2 +
mm/memory-failure.c | 20 +-
mm/page-writeback.c | 5 -
mm/page_alloc.c | 8 +-
mm/page_isolation.c | 2 +-
mm/page_poison.c | 4 +-
mm/vmalloc.c | 6 +-
mm/vmscan.c | 39 +-
mm/z3fold.c | 1 +
mm/zbud.c | 1 +
mm/zpool.c | 13 +
mm/zswap.c | 52 ++-
net/bpf/test_run.c | 6 +-
net/core/dev.c | 14 +-
net/ipv4/igmp.c | 2 +
net/ipv4/ip_vti.c | 6 +-
net/ipv4/netfilter.c | 2 +
net/ipv6/ip6_fib.c | 5 +-
net/ipv6/ip6_vti.c | 6 +-
net/ipv6/netfilter.c | 2 +
net/l2tp/l2tp_core.c | 10 +-
net/netfilter/nf_tables_api.c | 7 +-
net/netfilter/nft_set_hash.c | 10 +-
tools/perf/arch/arm/include/perf_regs.h | 2 +-
tools/perf/arch/arm64/include/perf_regs.h | 2 +-
tools/perf/arch/csky/include/perf_regs.h | 2 +-
tools/perf/arch/powerpc/include/perf_regs.h | 2 +-
tools/perf/arch/riscv/include/perf_regs.h | 2 +-
tools/perf/arch/s390/include/perf_regs.h | 2 +-
tools/perf/arch/x86/include/perf_regs.h | 2 +-
tools/perf/util/annotate.c | 8 +
tools/perf/util/annotate.h | 1 +
tools/perf/util/env.c | 1 +
tools/perf/util/parse-events.c | 9 +-
tools/perf/util/perf_regs.h | 7 +
tools/perf/util/symbol-elf.c | 1 +
tools/perf/util/vdso.c | 2 +
112 files changed, 1560 insertions(+), 908 deletions(-)
--
2.22.0
1
89