一次物理机反复重启的问题排查

  1. 问题背景
  2. 调查

问题背景

某台机器硬件故障,报修完成后,启动失败。

通过ilo查看发现系统反复重启,但是换回报修之前的内核可以正常启动(这里说明一下,我们在这个机器上提前安装了一个新版的内核,恰好这次报修重启使用上了新版本的内核)。

调查

首先需要明确反复重启的点在哪?

这是一张图片

通过ilo可以看到,在系统启动51秒左右的时间就突然重启,反复如此。

而这时候,可以看到还没进行switch_root,所以应该还是在initramfs阶段。

那是不是这个新内核的initramfs有问题呢?对比一下该版本的initramfs大小和可以正常启动的内核的initramfs的包大小,发现该异常内核的initramfs包要小了将近7M。

然后把有问题的initramfs包和没问题的initramfs包分别解压对比一下里面的内容。

发现有问题的机器initramfs中的usr/lib64下比没问题的机器同路径下少了很多内容,而且,有问题的机器的initramfs中为什么有一些so库在opt/compiler/gcc-12的目录下?

//没有问题
[yzwddsg lib64]$ ls |wc -l
173
//有问题
[yzwddsg lib64]$ ls |wc -l
14
[yzwddsg gcc-12]$ pwd
/home/wfs/aaa/you/opt/compiler/gcc-12
[yzwddsg gcc-12]$ ll
total 4
drwxr-xr-x 2 wfs wfs 4096 Feb 28 16:26 lib
lrwxrwxrwx 1 wfs wfs    3 Feb 28 16:26 lib64 -> lib
[yzwddsg gcc-12]$ ls lib
ld-2.33.so            libc.so.6      libgcc_s.so    libm.so.6           libresolv-2.33.so  librt.so    libz.so.1.2.11
ld-linux-x86-64.so.2  libdl-2.33.so  libgcc_s.so.1  libpthread-2.33.so  libresolv.so       librt.so.1
libc-2.33.so          libdl.so       libm-2.33.so   libpthread.so       libresolv.so.2     libz.so
libc.so               libdl.so.2     libm.so        libpthread.so.0     librt-2.33.so      libz.so.1

这里就可以先大致猜测一下,是不是有人修改了基础环境,导致制作initramfs的时候,去优先找gcc-12路径下的内容了,导致打包的initramfs有问题。

先实锤一下上面的结论,从正常机器上直接挪一个异常内核版本对应的initramfs包并替换,直接重启一把,没问题。

所以基本确定就是因为有人搞坏了基础环境导致的。

但还得追查一下,到底是哪里被修改了呢?

直接把/opt/compiler/gcc-12挪走,dracut -f重新制作initramfs,发现initramfs中不仅没有opt/compiler/gcc-12目录了,连usr/lib64都没有任何so库了!

尝试dracut -f -v打印更多日志,没发现什么有效信息。

ldconfig -p动态库缓存中没有gcc-12相关内容

在/usr/lib/dracut/dracut-functions.sh脚本中加上set -x,并在最后添加一些打印内容,比如

echo $PATH
echo $LD_LIBRARY_PATH
echo $LD_PRELOAD
ldd /usr/bin/ls
...

发现只有$PATH变成了/usr/sbin:/usr/bin,这个是正常的,在制作initramfs的时候会修改一下$PATH

但是ldd的结果明显是有问题的

+++ ldd /usr/bin/ls
    linux-vdso.so.1 (0x00007ffdc31db000)
    libselinux.so.1 => not found
    libcap.so.2 => not found
    libacl.so.1 => not found
    libc.so.6 => /opt/compiler/gcc-12/lib/libc.so.6 (0x00007f1941807000)
    /lib64/ld-linux-x86-64.so.2 => /opt/compiler/gcc-12/lib64/ld-linux-x86-64.so.2 (0x00007f19419cf000)

这里ldd的so库就是去gcc-12中去找了,直接在shell中执行ldd /usr/bin/ls是正常的

所以,肯定是dracut制作期间的环境改变导致的

继续在/usr/lib/dracut/dracut-functions.sh中添加了更多打印,尝试打印一下/lib64/ld-linux-x86-64.so.2 这些是不是在dracut制作期间软链接到了,也都是正常的

然后打印一下which ldd

发现问题了,原来dracut制作期间使用的ldd实际上是一个软链接,链接到gcc-12中的ldd,而在shell中直接执行ldd,使用的是正常的环境下的ldd。

问题根因如下(试试新学的画图工具):

1.一般在shell中执行一个命令,先在环境变量中查找这个binary所在的位置,找到后再执行这个binary。在dracut制作initramfs的时候,dracut的一些脚本会修改环境变量,这样dracut制作过程中执行ldd的话,就会在新的环境变量中去查找ldd这个binary。

这是一张图片

2.有人在安装gcc-12的时候,把原来的/usr/bin/ldd删掉了,改为软链接到/opt/compiler/gcc-12/bin/ldd。原本,不修改环境变量的情况下,使用的是/gcc-8/bin下的ldd,所以不会出现问题。而在dracut制作initramfs的时候,环境变量被修改了,需要在/usr/sbin:/usr/bin这种路径下去查找ldd binary,但这时候/usr/bin/ldd已经变成了软链接,链接到gcc-12的ldd。所以,在制作initramfs的时候,相当于使用/opt/compiler/gcc-12/bin/ldd了,制作出来的initramfs自然会少许多so库,且位置不对。

这是一张图片


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 857879363@qq.com