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 条评论
登录 后参与评论

相关文章

来自专栏jojo的技术小屋

原 荐 七牛 JSSDK 配置+常见问题

作者:汪娇娇 时间:2017年7月7日 一、铺垫 依靠七牛上传图片,其实有很多方法,先说说有哪些方法,以及这些方法各自的优缺点吧(移动端)。 way1:前端只负...

5435
来自专栏用户画像

4.4 文件系统疑难点 3-4

为了创建一个文件,应用程序调用逻辑文件系统。逻辑文件系统知道目录结构形式。它将分配一个新的FCB给文件,把相应目录读入内存,用新的文件名更新该目录和FCB,并将...

671
来自专栏IT派

入门 node.js 你必须知道的那些事

exports 是 module.exports 的一个引用,意思就是指向同一块内存地址,node 中真正生效的是 module.exports, 修改 exp...

1190
来自专栏Spring相关

动态加载布局的技巧

1.在res下面新建一个layout-large的文件夹,下面建一个activity_main.xml:

814
来自专栏Linux运维学习之路

zabbix使用(自定义监控、自动报警)

自定义监控(制作模板) zabbix自带模板Template OS Linux (Template App Zabbix Agent)提供CPU、内存、磁盘、网...

3756
来自专栏玩转JavaEE

MongoDB基本操作

上篇文章我们简单介绍了MongoDB安装以及启动命令,本文我们来看看基本的增删改查,对MongoDB有一个直观的认识。 ---- 客户端安装配置 上篇文章我们提...

3664
来自专栏北京马哥教育

fail2ban保护linux安全

一、下载安装 #wget http://cdnetworks-kr-2.dl.sourceforge.net/project/fail2ban/fail...

3248
来自专栏禁心尽力

Solr_全文检索引擎系统

Solr介绍: Solr 是Apache下的一个顶级开源项目,采用Java开发,它是基于Lucene的全文搜索服务。Solr可以独立运行在Jetty、Tomca...

1918
来自专栏沈唁志

YII2框架访问gii、debug页面404的错误解决方法

之前在介绍Yii框架的时候就说过 Yii 支持 gii 功能, gii 去自动生成 Web 站点常用功能的代码,也就是我们经常说的 CURD 操作,增删改查。使...

1142
来自专栏Web项目聚集地

Linux知识点总结

1153

扫码关注云+社区