为什么systemTap脚本报告操作员错误附近的读取错误



我在CentOS Linux版本7.6.1810上运行SystemTap。SystemTap的版本为:

$ stap -V
Systemtap translator/driver (version 4.0/0.172/0.176, rpm 4.0-11.el7)
Copyright (C) 2005-2018 Red Hat, Inc. and others
This is free software; see the source for copying conditions.
tested kernel versions: 2.6.18 ... 4.19-rc7
enabled features: AVAHI BOOST_STRING_REF DYNINST BPF JAVA PYTHON2 LIBRPM LIBSQLITE3 LIBVIRT LIBXML2 NLS NSS READLINE

$ uname -rm
3.10.0-957.21.3.el7.x86_64 x86_64
$ rpm -qa | grep kernel-devel
kernel-devel-3.10.0-957.21.3.el7.x86_64
$ rpm -qa | grep kernel-debuginfo
kernel-debuginfo-3.10.0-957.21.3.el7.x86_64
kernel-debuginfo-common-x86_64-3.10.0-957.21.3.el7.x86_64

我有一个名为sg.stp的systemTap脚本,它用来监视为什么rabbitmq-集群的k8s pod偶尔会终止,退出代码为137:

global target_pid = 32719
probe signal.send{
if (sig_pid == target_pid) {
printf("%s(%d) send %s to %s(%d)n", execname(), pid(), sig_name, pid_name, sig_pid);
printf("parent of sender: %s(%d)n", pexecname(), ppid())
printf("task_ancestry:%sn", task_ancestry(pid2task(pid()), 1));
}
}

当我运行脚本时,它在一段时间后报告了一个错误:

$  stap sg.stp
ERROR: read fault [man error::fault] at 0x4a8 near operator '@cast' at /usr/share/systemtap/tapset/linux/task.stpm:2:5
epmd(29073) send SIGCHLD to rabbitmq-server(32719)
parent of sender: rabbitmq-server(32719)
WARNING: Number of errors: 1, skipped probes: 0
WARNING: /usr/bin/staprun exited with status: 1
Pass 5: run failed.  [man error::pass5]

pid2task()可以返回NULL

检查pid2task(pid())current_task()是否返回NULL,如下所示:

task = pid2task(pid());
if (task) {
printf("task_ancestry:%sn", task_ancestry(task, 1));
} else {
printf("task_ancestry more availablen");
}

注意,我不完全确定以下解释:

即使在运行pid()的上下文中,也可能发生task_struct不再可用的情况,因为进程已经死亡,并且task_struck已被清理,因为不再需要它。

在这种情况下,pid2task()返回NULL。AFAICS在以下两种情况(可能更多(下,pid()可能发生这种情况:

  • 您的探测器与正在运行的进程是异步的——在您使用信号探测器的情况下,这里似乎就是这样。

  • .return探测执行得太晚,可能是因为它在内核中停留的时间太长(比如阻塞调用(。

对于后者,似乎有一些简单的解决方法:

使用@entry(task_ancestry(current_task()))代替task_ancestry(current_task())。通过这种方式,数据是在系统调用的入口点收集的,在那里,进程很可能仍然完全活跃。

然而,在Signal的情况下,我看不到这样简单的解决方法,因此您必须检查NULL。


请注意,我不完全确定这是否是您的问题,在没有页面锁定的情况下检查NULL是完美的解决方案。因为即使你得到一个指向某个结构的指针,由于SMP,包含该结构的页面也可能会在探测过程中消失。也许stap在某种程度上可以防止这种情况。但我对此表示怀疑。像这样的竞争条件对于调试和避免来说真的很奇怪。