一、问题现象
发现某些情形下,没有成功生成core文件。
运维同学经过前期定位后,反馈是core文件名称中带有空格的时候,会生成失败。
二、问题背景
使用了kernel.core_pattern指定了coredump文件的生成格式,采用管道的方式生成coredump文件。
kernel.core_pattern=|/taihang/script/core_file_handle.sh core_%e_%p_sigwq_%s_time_%t
core_file_handle.sh的定义如下:
#!/bin/bashsource /taihang/dpu_toolkit/envCOREDIR=/home/coresave# compare to 7 days ago
before_7_day=`date -d "-7 day" "+%s"`# first step
# check the generation time of the core and delete the corefile older than 7 days.
total_size=0
oldifs=$IFS
IFS=$'\n'
for corefile_des in `ls -lrt $COREDIR | grep core`; dosize=`echo $corefile_des | awk -F ' ' '{ print $5}'`filename=`echo $corefile_des | awk -F ' ' '{ print $9}'`time=`echo ${filename#*time_}`echo "$time"|[ -z "`sed -n '/^[0-9][0-9]*$/p'`" ] && time=`date '+%s' -r $COREDIR/$filename`if [[ $time -lt $before_7_day ]]; thenrm -f $COREDIR/${filename}else((total_size+=$size))fi
done# second step
# check the size of all corefile. if capacity exceeds the high water mark,
# the oldest core file will be deleted until the total capacity is lower than low water mark
if [[ $total_size -gt $COREFILE_HIGH_WATERMARK ]]; thenfor corefile_des in `ls -lrt $COREDIR | grep core`; dosize=`echo $corefile_des | awk -F ' ' '{ print $5}'`filename=`echo $corefile_des | awk -F ' ' '{ print $9}'`rm -f $COREDIR/$filename((total_size-=$size))if [[ $total_size -le $COREFILE_LOW_WATERMARK ]]; thenbreakfidone
fi
IFS="$oldifs"# third step
# generate a corefile
if [[ -n $1 ]]; thencat > ${COREDIR}/$1
fi
因为需要在每次生成core文件的时候,对过往的core文件进行清理,防止core文件占用磁盘空间过大引发系统级异常,所以使用了“管道+自定义处理脚本”的方式。
三、原因分析
因为不了解core文件的生成和配置,所以先结合内核代码和bpftrace工具测试,对原理进行了分析。记录在:
coredump文件和kernel.core_pattern-CSDN博客
通过自己写了一个简单的名称带空格的线程,令其越界访问,做测试。
#define _GNU_SOURCE
#include <stdio.h>
#include <pthread.h>void *thread_worker(void *arg)
{usleep(10000);pthread_setname_np(pthread_self(), "thread work");*(int *)(0) = 1;
}int main()
{pthread_t t0;pthread_attr_t attr;pthread_attr_init(&attr);pthread_create(&t0, &attr, thread_worker, NULL);while(1);
}
在梳理清楚原理后,定位发现问题出现在这里,因为这个脚本每次都有被调用执行,而且$1这个文件名是正确的,是一个带有空格的线程名称的字符串。
if [[ -n $1 ]]; thencat > ${COREDIR}/$1
fi
但是cat > $1就无法生成core文件。推测原因,应该是$1被替换为一个带有空格的字符串后,shell脚本将其当作两个字段了吧。
四、解决方式
最终怎么解决呢,将$1使用“”保护起来,这样shell才会将其作为一个完整的字符串,而不会看到空格认为是两个独立的字段。
if [[ -n $1 ]]; thencat > ${COREDIR}/“$1”
fi
当然,同步清楚解决方式后,运维同学在此基础上,采用了先对带有空格的字符串进行处理,将其替换为“_"的方式,这样使用起来更加友好。
if [[ -n $1 ]]; then
core_name=$(echo $1 | sed 's/ \+/_/g')cat > ${COREDIR}/$1
if [[ -n $core_name ]]; thencat > ${COREDIR}/$core_name
fi
毕竟一个名称里带有空格的文件,不管从视觉上还是文件打开的时候,都有些怪异。
PS:经过实际验证,linux的文件名称确实是可以带空格的,这个之前确实不了解哈哈。打开文件的时候需要使用转义字符\。

