通过二分查找,找到Linux kernel哪一个patch解决了问题。

一、问题背景

linux开发工作种往往会碰到一种情况,那就是低版本kernel有问题,高版本kernel无问题,而解决问题的patch就在这其中的某一次提交中,自己没有明确的排查想法,最后只能尝试用最笨的二分实验来查找。

二、具体的二分查找patch

1.kernel源码包级别

初始采用从网站(如https://mirrors.aliyun.com/centos/)下载特定的tar包,编译kernel后逐次实验,最终定位到问题修复版本区间为4.18.20----4.19.0.

但由于kernel开发布局影响,两个版本分属不同的开发分支:

kernel-4.18 --- v4.19-rc1 --- v4.19-rc2 ………… v4.19-rc8 --- v4.19.0 (主开发分支)

        \

           \ ----- v4.18.1 --- v4.18.2 …………v4.18.20 (维护分支)

于是退回到 v4.18---v4.19 开始重新二分,由于没有现成的tar包,所以采用从git中按tag二分。

首先下载linux的git仓库,然后从linux-4.19.y分支中依次抽取v4.19分支,v4.19-rcX分支,最终实验出 4.19.0-rc1可以。

2.git log页级别

由于4.18到4.19.0-rc1属于补丁合入窗口,期间有五千多补丁,所以初期按照git log 中以页为单位划分,最终将区间缩小到git提交中的一页,于是范围缩小到page3--page4.

4.18不可以---4.18-p3不可以-----------------4.18-p4可以--- 4.18-p10可以-- 4.19.0-rc1可以

然后针对page3--page4中的各个提交继续二分,以此为主线的测试结果为

4.18不可以--4.18-p2不可以--4.18-acpi不行-p3不行---ACPICA不行--ib不行---mail不行---plat不行---

  ------4.18-harden可以---4.18-p4可以--- 4.18-p10可以-- 4.19.0-rc1可以

但此时存在问题(其实是个人对git log的误解),比如v4.18-ACPICA分支,明明在p3--p4之间,但针对该分支查看log,发现其仅处在p2之前,还没有p3的标记,出现错乱。

其实这些错乱源自于git 的merge属性,由于存在大量merge tag,有些很早就提交的patch经过merge后反而被git log --oneline显示在前面,这样针对这个被merge过来的提交创建新分支,其代码不知道老旧到什么地步了。

正确的做法应该是把merge提交全部打开,或者说是按merge顺序反方向去revert,这样就能避免log 错乱问题。其实更简单的,在git log 时加上--graph参数,就能窥见全貌不再错乱。

有以下几个git命令组合比较有帮助:

//隐去细节,宏观查看所有提交,不管是merge还是commit平等对待
git log --oneline --first-parent  <tag1>^1..<tag2>
git log --oneline --first-parent  v6.6..v6.7

//打开一个merge,查看该merge中的所有补丁
git log --oneline  --decorate  <merge_commit>^1..<merge_commit>
git log --oneline  --decorate    ba70ffa7d20d^1..ba70ffa7d20d

//宏观查看该branch的整个历史演进,merge及其提交均通过支流显示
git log --oneline --decorate  --graph    <commit>^1..<commit>
git log --oneline --decorate  --graph    v4.18-x86^1..v4.18-au


3.git中自行创建的branch级别

所以,先根据之前测试【成功-失败】的区间,找一个最近范围的如【v4.18-harden到v4.18-acpi】总体看一下区间中的merge记录,(--first-parent)

然后再详细看一下merge打开的记录(--graph)

记住只针对graph显示中首行为*的提交创建新分支(其实也就是--first-parent的显示)。因为那是主流汇集点,也就是merge过来形成的节点,属于大河交汇处,是第一级目录,所以针对这个二分就不会顺序错乱。

然后进行二分,即针对节点是*的提交拉去新分支去编译kernel,然后安装去二分实验,最终将范围缩小到两个一级标签之间【v4.18-au到v4.18-x86】

可以发现他们之间已经没有任何一级提交点了,最终的patch就在这俩tag之间,而且基本都是以patch的形式存在,就算有merge记录打开查看也是很小的提交记录。

4.git提交级别(单个patch)

以此开始,可以有两种方法继续排查。

1.可以在好的节点v4.18-au开始一个个反方向回退(二分打多个),也就是git revert 打上退回的补丁,逐一实验。

2.也可在坏的节点v4.18-x86处开始按真实的历史一个个正向打补丁(二分打多个),逐一实验。

由于这两个tag之间的patch不多只有90多个,所以我选择第2种正向打补丁测试。

首先用 git format-patch一次性获取这两个tag之间的所有补丁。

获得补丁后,以v4.18-x86为基准(每次切换到这个分支后进行copy)通过脚本的方式一次性对kernel源码打一半补丁-->实验后二分-->继续打一半补丁,直到最终找到那一个补丁或一个补丁集。

#cat dopa.sh
----------------------------------
for p in $(ls -v *.patch); do
    echo "应用: $p"
    if ! patch -p1 < "$p"; then
        echo "失败于: $p"
        break
    fi
done

二分之前稍微看下补丁内容,结合所遇问题基本就能断出几个位置,最终的二分实验结果如下:

x86不行---p22不行---p29不可以---p33不可以-------p34可以---p49可以---au可以

于是最终锁定了那个patch34:https://patchwork.kernel.org/project/linux-arm-kernel/patch/20180625130552.5636-1-lorenzo.pieralisi@arm.com/

三、过程中其他记录

1.给一个配置静态IP的方法,其实就是3行配置(ip三元素) + 2行改动(bootproto=static及onboot=yes)

[root@localhost ~]# cd /etc/sysconfig/network-scripts/
[root@localhost network-scripts]# cat ifcfg-enP11s111f0
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=none
IPADDR=10.5.102.189
PREFIX=24
GATEWAY=10.5.102.254
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=enP11s111f0
UUID=31e25947-93cf-4c7c-9dd1-91b85792fc73
DEVICE=enP11s111f0
ONBOOT=yes

静态配置网卡IP,记得要重启机器,只重启NetworkManager服务没用。

2.给一个进入grub后,重新找到kernel并启动的方法,其实就是手动设置kernel+initrd

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值