前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >linux、kernel 使用 systemtap 分析 sys_clone 失败的原因

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

原创
作者头像
皮振伟
修改2017-09-25 11:05:59
2.9K0
修改2017-09-25 11:05:59
举报
文章被收录于专栏:皮振伟的专栏皮振伟的专栏

前言:

在《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的返回值。

代码语言:javascript
复制
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脚本来监控上面的各个地方:

代码语言:javascript
复制
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脚本:

代码语言:javascript
复制
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不支持也不是特别惊奇的事情了。那么就要自己想办法修改一下这个配置了。 这个问题到此分析结束。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言:
  • 分析:
    • 1、clone fail
      • 2、stap error
        • 3、cgroup check fail
          • 4、cgroup pids
            • 5、pids
              • 6、libvirt pids
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档