linux、kernel 使用 systemtap 分析 sys_clone 失败的原因

前言:

在《qemu的一次pthread create失败的分析》中分析了pthread失败的原因以及解决方法。修改了pidmax之后,一直没有看到现象发生,但是不能证明问题被解决了,因为当时的环境只有coredump文件,没有找到固定的复现规律。继续观察中。 坏消息是问题又复现了。 好消息是问题能复现了。

分析:

1、clone fail

作者写了脚本,批量启动大量的qemu进程。在启动很大量的qemu之后,会有部分qemu进程crash。结合之前的分析过程,作者判断,很可能是系统调用clone发生了失败。是时候使用systemtap了。 使用systemtap需要有debug symbol,如果是发行版,可以参考发行版提供的kernel symbol,参考官方的教程,可以搭建起来systemtap的使用环境。如果是个人维护的kernel,那么就需要保存对应的symbol。 作者写了下面的脚本来监控qemu进程调用sys_clone的返回值。

probe begin {
    printf("start moniting qemu clone syscall...\n")
}

probe kernel.function("sys_clone") {
    if (execname() == "qemu-system-x86") {
        printf("sys_clone : %s\n", execname())
    }
}

probe kernel.function("sys_clone").return {
    if (execname() == "qemu-system-x86") {
        printf("sys_clone_return : %s, %d\n", execname(), $return)
        if ($return < 0)
            printf("[error]sys_clone_return : %s, %d\n", execname(), $return)
    }
}

启动stap:stap -vv -g clone.stp 复现到问题的时候,抓到了返回值是11,也就是EAGAIN。那就说明,确确实实因为kernel的clone返回值是EAGAIN,glibc的pthread create失败

2、stap error

继续分析linux-4.4/kernel/fork.c, clone的核心实现部分在copy process中,发现在下面的逻辑中都可能返回:

上面的行号,就是出错的地方,那么继续写stap脚本来监控上面的各个地方:

probe kernel.statement("*@kernel/fork.c:1648") {
    printf("[error]copy_process@1648 : %s\n", execname())
}

probe kernel.statement("*@kernel/fork.c:1651") {
    printf("[error]copy_process@1651 : %s\n", execname())
}

probe kernel.statement("*@kernel/fork.c:1654") {
    printf("[error]copy_process@1654 : %s\n", execname())
}

probe kernel.statement("*@kernel/fork.c:1657") {
    printf("[error]copy_process@1657 : %s\n", execname())
}

probe kernel.statement("*@kernel/fork.c:1659") {
    printf("[error]copy_process@1659 : %s\n", execname())
}

probe kernel.statement("*@kernel/fork.c:1662") {
    printf("[error]copy_process@1662 : %s\n", execname())
}

probe kernel.statement("*@kernel/fork.c:1665") {
    printf("[error]copy_process@1665 : %s\n", execname())
}

probe kernel.statement("*@kernel/fork.c:1667") {
    printf("[error]copy_process@1667 : %s\n", execname())
}

probe kernel.statement("*@kernel/fork.c:1669") {
    printf("[error]copy_process@1669 : %s\n", execname())
}

probe kernel.statement("*@kernel/fork.c:1671") {
    printf("[error]copy_process@1671 : %s\n", execname())
}

probe kernel.statement("*@kernel/fork.c:1675") {
    printf("[error]copy_process@1675 : %s\n", execname())
}

probe kernel.statement("*@kernel/fork.c:1678") {
    printf("[error]copy_process@1678 : %s\n", execname())
}

probe kernel.statement("*@kernel/fork.c:1683") {
    printf("[error]copy_process@1683 : %s\n", execname())
}

probe kernel.statement("*@kernel/fork.c:1686") {
    printf("[error]copy_process@1686 : %s\n", execname())
}

在使用stap执行脚本的时候,如果stap报错,需要耐心一点,比对行号已经对应的位置上是不是有语句,不然stap会报错说指定的行数不能stap。 执行后发现,是1651行开始出错的。也就是说明,跳转到bad_fork_free_pid的地方出错了。

3、cgroup check fail

可见,是cgroup检查出错了。

4、cgroup pids

linux-4.4/kernel/cgroup.c中,继续分析:

一次检查cgroup的各个资源组。需要确定具体是哪个资源,也就是出错的时候,i的数值。 继续写stap脚本:

probe kernel.statement("*@kernel/cgroup.c:5573") {
    if ($ret != 0) {
        printf("[error]cgroup@5573 : %s\n", execname())
        printf("       cgroup@5573 : i = %d\n", $i )
    }
}

复现后发现,出错的时候,i的值是11。 结合linux-4.4/include/linux/cgroup_subsys.h发现,11就是在检查pids的时候发生的错误

5、pids

cat /proc/PID/cgroup来查看qemu使用的cgroup。 发现是10:pids:/system.slice/libvirtd.service 继续查看:/sys/fs/cgroup/pids/system.slice/libvirtd.service/pids.max 结果是512。 qemu进程中包含多个线程,在qemu比较多的时候,就容易发生pids超过限制的问题了。 这个问题的root cause就是pids限制的问题了。

6、libvirt pids

检查libvirt3.2的代码发现,libvirt中不支持pids的配置。 centos7的kernel是3.10,在linux3.10中,还不支持pids cgroup。所以libvirt不支持也不是特别惊奇的事情了。那么就要自己想办法修改一下这个配置了。 这个问题到此分析结束。

原创声明,本文系作者授权云+社区-专栏发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏進无尽的文章

扒虫篇-此构建版本无效

一个公司的项目 1.0 版本被苹果拒绝了,问题修改好,再次上传后,构建版本时,发现上传的版本都是提示:此构建版本无效。

801
来自专栏星汉技术

Sqoop简介以及安装

1402
来自专栏熊二哥

Sublime快速入门

在当前的互联网时代,任何程序语言和相关技术都只是实现互联网应用的一种手段,这也就造成了大量的互联网工程师长期与不同的语言、技术、系统环境、IDE等打交道。因此一...

1755
来自专栏区块链

如何在登录界面获取 shell?

信息安全公益宣传,信息安全知识启蒙。 教程列表见微信公众号底部菜单 ? Inception Inception是由Carsten Maartmann-Moe开发...

18410
来自专栏未闻Code

技巧总结-2018-06

MongoDB的聚合查询中,$substr只能匹配ASCII的数据,对于中文要使用$substrCP

622
来自专栏Crossin的编程教室

pycharm 如何程序运行后,仍可查看变量值?

来出自知乎同名问题。 因为觉得这个问题挺实用,且确实有很多人不了解,故将自己的回答搬运到这里。 我自己开发时候也经常遇到这样的需求:程序运行后,结果不正确,想要...

3548
来自专栏mukekeheart的iOS之旅

iOS崩溃日志ips文件解析

  测试组的同事在进行稳定性测试时,通常会遇到一些崩溃,然后他们会将这些崩溃日志(一般是ips格式的文件)反馈给开发进行分析,但是这些ips文件中的内容通常是如...

753
来自专栏前端侠2.0

vs code和node的相关使用 一一 typescript的配置

/// <reference path="underscore/underscore.d.ts" />  这样的引用,才能在ts中有提示。

301
来自专栏Java学习123

Maven学习问题解决

2828
来自专栏梦里茶室

【Chromium中文文档】OS X 沙箱设计

背景 沙箱将进程视为一种恶劣的环境,因为进程任何时候都可能被一个恶意攻击者借由缓冲区溢出或者其他这样的攻击方式所影响。一旦进程被影响,我们的目标就变成了,让这个...

1940

扫码关注云+社区