标签 调试 下的文章

基本测试

安装好内核后,试试能不能启动它。能启动的话,检查 dmesg 看看有没有隐藏的错误。试试下面的功能:

  • 网络(Wifi 或者网线)是否可用?
  • ssh 是否可用?
  • 使用 ssh 远程传输文件。
  • 使用 git clone 和 git pull 命令。
  • 用用网络浏览器。
  • 查看 email。
  • 使用 ftp, wget 等软件下载文件。
  • 播放音频视频文件。
  • 连上 USB 鼠标等设备。

检查内核日志

使用 dmesg 查看隐藏的问题,对于定位新代码带来的 bug 是一个好方法。一般来说,dmesg 不会输出新的 crit, alert, emerg 级别的错误信息,也不应该出现新的 err 级别的信息。你要注意的是那些 warn 级别的日志信息。请注意 warn 这个级别的信息并不是坏消息,新代码带来新的警告信息,不会给内核带去严重的影响。

  • dmesg -t -l emerg
  • dmesg -t -l crit
  • dmesg -t -l alert
  • dmesg -t -l err
  • dmesg -t -l warn
  • dmesg -t -k
  • dmesg -t

下面的脚本运行了上面的命令,并且将输出保存起来,以便与老的内核的 dmesg 输出作比较(LCTT:老内核的 dmesg 输出在本系列的第二篇文章中有介绍)。然后运行 diff 命令,查看新老内核 dmesg 日志之间的不同。这个脚本需要输入老内核版本号,如果不输入参数,它只会生成新内核的 dmesg 日志文件后直接退出,不再作比较(LCTT:话是这么说没错,但点开脚本一看,没输参数的话,这货会直接退出,连新内核的 dmesg 日志也不会保存的)。如果 dmesg 日志有新的警告信息,表示新发布的内核有漏网之“虫”,这些 bug 逃过了自测和系统测试。你要看看,那些警告信息后面有没有栈跟踪信息?也许这里有很多问题需要你进一步调查分析。

压力测试

执行压力测试的一个好办法是同时跑三四个内核编译任务。下载各种版本的内核,同时编译它们,并记录时间。比较新内核跑压力测试和老内核跑压力测试所花的时间,然后可以定位新内核的性能。如果新内核跑压力测试的时间比老内核的更长,说明新内核的部分模块性能退步了。性能问题很难调试出来。第一步是找出哪里导致的性能退步。同时跑多个内核编译任务对检测内核整体性能来说是个好方法,但是这种方法涵盖了多个内核模块,比如内存管理、文件系统、DMA、驱动等(LCTT:也就是说,这种压力测试没办法定位到是哪个模块造成了性能的下降)。

time make all

内核测试工具

我们可以在 Linux 内核本身找到多种测试方法。下面介绍一个很好用的功能测试工具集: ktest 套件

ktest 是一个自动测试套件,它可以提供编译安装启动内核一条龙测试服务,也可以跑交叉编译测试,前提是你的系统有安装交叉编译所需要的软件。ktest 依赖于 flex 和 bison。详细信息请参考放在 tools/testing/ktest 目录下的文档,你可以自学成材。另外还有一些参考资料教你怎么使用 ktest:

tools/testing/selftests 套件

我们来玩玩自测吧。内核源码的多个子系统都有自己的自测工具,到目前为止,断点、cpu热插拔、efivarfs、IPC、KCMP、内存热插拔、mqueue、网络、powerpc、ptrace、rcutorture、定时器和虚拟机子系统都有自测工具。另外,用户态内存的自测工具可以利用 testusercopy 模块来测试用户态内存到内核态的拷贝过程。下面的命令演示了如何使用这些测试工具:

编译测试:

make -C tools/testing/selftests 

测试全部:(有些测试需要 root 权限,你需要以 root 用户登入系统然后运行命令)

make -C tools/testing/selftests run_tests 

只测试单个子系统:

make -C tools/testing/selftests TARGETS=vm run_tests 

tools/testing/fault-injection 套件

在 tools/testing 目录下的另一个测试套件是 fault-injection。failcmd.sh 脚本用于检测 slab 和内存页分配器的错误。这些工具可以测试内核能否很好地从错误状态中恢复回来。这些测试需要用到 root 权限。下面简单介绍了一些当前能提供的错误检测方法。随着错误检测方法的增加,这份名单也会不断增长。最新的名单请参考 Documentation/fault-injection/fault-injection.txt 文档。

failslab (默认选项)

产生 slab 分配错误。作用于 kmalloc(), kmemcachealloc() 等函数(LCTT:产生的结果是调用这些函数就会返回失败,可以模拟程序分不到内存时是否还能稳定运行下去)。

fail\_page\_alloc

产生内存页分配的错误。作用于 allocpages(), getfree\_pages() 等函数(LCTT:同上,调用这些函数,返回错误)。

fail\_make\_request

对满足条件(可以设置 /sys/block//make-it-fail 或 /sys/block///make-it-fail 文件)的磁盘产生 IO 错误,作用于 generic\_make\_request() 函数(LCTT:所有针对这块磁盘的读或写请求都会出错)。

fail\_mmc\_request

对满足条件(可以设置 /sys/kernel/debug/mmc0/fail\_mmc\_request 这个 debugfs 属性)的磁盘产生 MMC 数据错误。

你可以自己配置 fault-injection 套件的功能。fault-inject-debugfs 内核模块在系统运行时会在 debugfs 文件系统下面提供一些属性文件。你可以指定出错的概率,指定两个错误之间的时间间隔,当然本套件还能提供更多其他功能,具体请查看 Documentation/fault-injection/fault-injection.txt。 Boot 选项可以让你的系统在 debugfs 文件系统起来之前就可以产生错误,下面列出几个 boot 选项:

  • failslab=
  • fail\_page\_alloc=
  • fail\_make\_request=
  • mmc\_core.fail\_request=[interval],[probability],[space],[times]

fault-injection 套件提供接口,以便增加新的功能。下面简单介绍下增加新功能的步骤,详细信息请参考上面提到过的文档:

使用 DECLARE\_FAULT\_INJECTION(name) 定义默认属性;

详细信息可查看 fault-inject.h 中定义的 struct fault\_attr 结构体。

配置 fault 属性,新建一个 boot 选项;

这步可以使用 setup\_fault\_attr(attr, str) 函数完成,为了能在系统启动的早期产生错误,添加一个 boot 选项这一步是必须要有的。

添加 debugfs 属性;

使用 fault\_create\_debugfs\_attr(name, parent, attr) 函数,为新功能添加新的 debugfs 属性。

为模块设置参数;

为模块添加一些参数,对于配置错误属性来说是一个好主意,特别是当新功能的应用范围受限于单个内核模块的时候(LCTT:不同内核,你的新功能可能需要不同的测试参数,通过设置参数,你的功能可以不必为了迎合不同内核而每次都重新编译一遍)。

添加一个钩子函数到错误测试的代码中。

should\_fail(attr, size) —— 当这个钩子函数返回 true 时,用户的代码就应该产生一个错误。

应用程序使用这个 fault-injection 套件可以指定某个具体的内核模块产生 slab 和内存页分配的错误,这样就可以缩小性能测试的范围。


via: http://www.linuxjournal.com/content/linux-kernel-testing-and-debugging?page=0,2

译者:bazz2 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

编译安装稳定版内核

如果你用 git 下载源码,就执行以下命令:

cd linux-stable
git checkout linux-3.x.y

如果是直接下载压缩文件,用以下命令进入源码目录:

cd linux-3.x.y

如果你想把内核安装到自己的系统上,最安全的方法是使用你安装好的发行版拥有的配置文件。你可以在 /boot 目录找到当前发行版的内核配置文件:

cp /boot/config-3.x.y-z-generic .config

运行下面的命令,可以在当前内核配置的基础上修改一些小地方,然后产生新的内核配置文件。比如说新的内核比你的 Ubuntu 发行版自带的内核多了些新功能,而你正好需要用到它们,这个时候你就要修改配置了。

make oldconfig

完成配置后,就可以编译了:

make all

完成编译后,安装这个新的内核:

sudo "make modules_install install"

上面的命令安装新内核,并把新内核作为启动项添加到 grub 文件(LCTT:就是你下次开机时会多出一个开机选项)。好了你可以重启电脑,然后选择新的内核启动系统。等等!先别冲动,在重启电脑之前,我们保存下编译内核产生的日志,用于比较和查找错误(如果有错误发生的话):

dmesg -t > dmesg_current
dmesg -t -k > dmesg_kernel
dmesg -t -l emerg > dmesg_current_emerg
dmesg -t -l alert > dmesg_current_alert
dmesg -t -l crit > dmesg_current_alert
dmesg -t -l err > dmesg_current_err
dmesg -t -l warn > dmesg_current_warn

正常的话,dmesg 不会输出 emerg, alert, crit 和 err 级别的信息。如果你不幸看到这些输出了,说明内核或者你的硬件环境有问题。

再介绍一些重启前的需要执行的操作。谁也不能保证新内核能够正常启动,所以请不要潇洒地把老内核删除,至少保留一个稳定可用的内核在系统上。修改一下 /etc/default/grub 文件:

使用 earlyprink=vga 作为内核启动选项,把系统早期启动的信息打印到显示屏上:

GRUB_CMDLINE_LINUX="earlyprink=vga" 

将 GRUB\_TIMEOUT 的值设置成10秒到15秒之间的值,保证在开机启动的时候你有足够的时间来选择启动哪个内核:

取消对 GRUB\_TIMEOUT 的注释,并把它设置为10:GRUB\_TIMEOUT=10

注释掉 GRUB\_HIDDEN\_TIMEOUT 和 GRUB\_HIDDEN\_TIMEOUT\_QUIET

运行 update-grub 命令,更新 /boot 目录下的 grub 配置文件:

sudo update-grub 

现在可以重启系统了。新内核起来后,比较新老内核的 dmesg 信息,看看新的内核有没有编译错误。如果新内核启动失败,你需要通过老内核启动系统,然后分析下为什么失败。

跟上节奏,永不落后(编译最新版内核)

如果你想开上内核快车道,追求与时俱进,那就去下载 mainline 状态的内核或 linux-next 状态的内核(LCTT:读者可进入 kernel.org 获取代码,linux 代码被分为4种状态:mainline, stable, longterm, linux-next)。安装测试 mainline 状态或 linux-next 状态的内核,你就可以在正式发布之前帮助内核找到并修复里面的 bug。

mainline 状态的内核源码:

git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

linux-next 状态的内核源码:

git clone git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git

编译安装这两种内核的步骤与编译安装稳定版内核一样。按之前讲过的步骤来就行了。

打补丁

Linux 内核的补丁是一个文本文件,包含新源码与老源码之间的差异。每个补丁只包含自己所依赖的源码的改动,除非它被特意包含进一系列补丁之中。打补丁方法如下:

patch -p1 < file.patch
git apply --index file.patch 

两种方法都可以打补丁。但是,如果你要打的补丁包含一个新文件,git 命令不能识别这个新增的文件,也就是说这个新文件在 git 里面属于 untracked 文件(LCTT:玩 git 的人对这个会比较熟悉,就是文件处于未被跟踪的状态,你需要使用 git add 命令将文件放入暂存区)。git diff 命令不会将这个文件的增量显示出来,并且 git status 命令会显示这个文件处于 untracked 状态。

大多数情况下,有个没被跟踪的文件,对于编译安装内核来说没什么问题,但是 git 操作就会出现一些问题了: git reset --hard 命令不会删除这个新加的文件,并且接下来的 git pull 操作也会失败。你有多种选择来避免上面所说的状况:

选项1,不跟踪这个新文件:

如果打补丁后新添加了文件,在 git reset --hard 前使用 git clean 命令来删除没有被跟踪的文件。举个例子,git clean -dfx 命令会强制删除未被跟踪的目录和文件,忽略在 .gitigniore 文件内规定的文件。如果你不在乎哪些文件会被删除,你可以使用 -q 选项让 git clean 命令进入安静模式,不输出任何处理过程。

选项2,跟踪新文件:

你可以在使用 git apply --index file.patch 命令后让 git 跟踪打完补丁后新产生的文件(LCTT:使用 git add 命令),就是让 git 把文件放入 index 区域。做完这个后,git diff 命令会将新文件的增量打印出来,git status 也会显示者这是一个正常的新增文件。

via: http://www.linuxjournal.com/content/linux-kernel-testing-and-debugging?page=0,1

译者:bazz2 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

Linux 内核测试哲学

不管是开源还是闭源,所有软件的开发流程中,测试是一个重要的、不可或缺的环节,Linux 内核也不例外。开发人员自测、系统测试、回归测试、压力测试,都有各自不同的目的,但是从更高一个层次上看,这些测试的最终目的又是一样的:保证软件能一直运行下去,当有新功能加进去时,要保证新功能可以正常工作。

在软件释出 release 版之前,不用回归测试就能保证稳定性,并且尽量避免在软件发布后被用户发现 bug。调试被用户发现的 bug 是一项非常浪费时间和精力的工作。因此测试是一项非常重要的工作。不像闭源和专有的操作系统,Linux 内核的开发过程是完全开放的。这种处理方式即是它的优点,也是它的缺点。多个开发者持续增加新功能、修 bug、不断集成与测试 —— 当环境有新的硬件或功能时,这种开发方式能够保证内核能持续工作。在开源项目中,开发者与用户共享测试的结果,这也是开源项目与闭源项目之间的一个很重要的差别。

几乎所有 Linux 内核开发者都是活跃的 Linux 用户。内核测试人员不一定非得是内核开发者,相反,用户和开发者如果对新增的代码不是很熟悉,他们的测试效果会比代码开发人员自己测试的效果要好很多。也就是说,开发者的单元自测能验证软件的功能,但并不能保证在其他代码、其他功能、其他软件、硬件环境下面运行时会出现什么问题。开发者无法预料、也没有机会和资源来测试所有环境。因此,用户在 Linux 内核开发过程中起到非常重要的角色。

现在我们已经了解了持续集成测试的重要性,接下来我们会详细介绍测试的知识。但在此之前,我还是向你介绍一下开发的过程,以便让大家了解它是怎么工作的,以及如何把补丁打进内核主线。

全世界共有3000多个内核开发者为 Linux 内核贡献代码,每天都有新代码添加到内核,结果是大概2个月就能产生一个release ,包括几个稳定版和扩展稳定版。新功能的开发与已发布的稳定版集成测试流程在同时进行。

关于开发流程的详细描述,请参考Greg Kroah-Hartman 的 Linux 内核开发的介绍

这份教程适合与初学者以及有经验的内核开发者,如果你想加入到内核开发者行列,那么它也适合你。有经验的开发人员可以跳过那些介绍基础测试和调试的章节。

这份教程介绍如何测试和调试 Linux 内核、工具、脚本以及在回归测试和集成测试中使用的调试机制。另外,本文还会介绍如何使用 git 把针对一个 bug 的补丁分离出来,再介绍把你的补丁提交到内核的邮件列表之前需要做些什么。我将会使用 Linux PM 作为测试它调试的对象。尽管本文讨论的是 Linux 内核,但是介绍的方法也适用于任何其他软件开发项目。

配置开发与测试的系统

第一步,找一个满足你需求的开发环境,x86-64 是一个比较理想的选择,除非你必须用特别的架构。

第二步,安装 Linux 发行版,我推荐 Ubuntu,所以本教程会介绍基于 Ubuntu 的配置过程。你可以参考如何使用 Ubuntu 来安装一个 Ubuntu 系统。

在开发和测试环境,最好要保证你的 boot 分区有足够的空间来存放内核文件。你可以为 boot 分区留下 3GB 空间,或把 boot 分区直接放到根目录下,这样 boot 分区可以使用整个磁盘的空间。

安装好操作系统后,确保 root 用户可用,确保你的用户身份可以使用 sudo 命令。你的系统也许已经安装了 build-essential,它是编译内核必备的软件包,如果没安装,运行下面的命令:

sudo apt-get install build-essential

然后运行下面的命令,保证你的系统能够交叉编译内核。下面的 ncurses-dev 安装包是运行 make menuconfig 命令必须用到的。

sudo apt-get install binutils-multiarch
sudo apt-get install ncurses-dev
sudo apt-get install alien

然后安装一些每个内核开发者都会用到的工具包:

sudo apt-get install git
sudo apt-get install cscope
sudo apt-get install meld
sudo apt-get install gitk

如果你喜欢把内核通过交叉编译以支持非 x86\_64 架构的环境,请参考在 x86\_64 上交叉编译 Linux 内核

稳定的内核

使用 git 克隆一个稳定的内核,然后编译安装。你可以参考Linux 内核结构来找到最新的稳定版和开发主线。

git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git

上面的步骤将会创建一个新的目录,名为 linux-stable,并把源码下载到里面。

你也可以直接下载压缩包并解压出源码,无需使用 git:

tar xvf linux-3.x.y.tar.xz

via: http://www.linuxjournal.com/content/linux-kernel-testing-and-debugging?page=0,0

译者:bazz2 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出