FT2000+ qemu kvm 64C64G 通过频繁设置CPU online 状态导致虚拟机红旗 openEuler 操作系统假死测试用例
第十次启动,保持不动,约11秒后,不输出内核日志,宿主机查看CPU使用率也掉到接近0%。手动循环重启9次(即:运行./tcti 等开始操作CPU上下线线程跑几秒,ctrl+C中断程序,再启动)从目前看,应该是触发了bug,当前任务被调度出去,一直没能调度回来。刚开始测试时,100.0 id 数值明显不对,应该是操作CPU在线状态导致。此时在宿主机查看kvm进程CPU状态,几乎没有消耗。,新开ssh
FT2000+ kvm Redflag
宿主机配置
虚拟机配置文件
<domain type='kvm'> //如果是Xen,则type=‘xen’
<name>redflag1</name> //虚拟机名称,同一物理机唯一
<uuid>44748c15-7c00-4817-8724-675a27c3f821</uuid> //同一物理机唯一,可用uuidgen生成
<memory>67108864</memory>
<currentMemory>67108864</currentMemory> //memory这两个值最好设成一样
<vcpu>64</vcpu>
<cpu mode="host-passthrough"/>
<os>
<type arch='aarch64' machine='virt'>hvm</type>
<loader readonly='yes' type='pflash'>/usr/share/edk2/aarch64/QEMU_EFI-pflash.raw</loader>
<nvram template='/usr/share/edk2/aarch64/vars-template-pflash.raw'>/usr/share/edk2/aarch64/QEMU_VARS.fd</nvram>
</os>
<features>
<acpi/>
<apic/>
<pae/>
</features>
<clock offset='localtime'/> //虚拟机时钟设置,这里表示本地本机时间
<on_poweroff>destroy</on_poweroff> //突发事件动作
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices> //设备配置
<emulator>/usr/bin/qemu-kvm</emulator> //如果是Xen则是/usr/lib/xen/binqemu-dm
<controller type="scsi" index="0" model="virtio-scsi"/>
<controller type='usb' index='0' model='qemu-xhci' ports='15'/>
<input type='keyboard' bus='usb'/>
<input type='mouse' bus='usb'/>
<input type='tablet' bus='usb'/>
<disk type='file' device='cdrom'>//光盘
<driver name='qemu' type='raw'/>
<source file='/home/yeqiang/RedFlag-Asianux-Server-7.5-aarch64-for-Phytium-dvddisc-20210701.iso'/>
<target dev='hda' bus='scsi'/>
<readonly/>
</disk>
<disk type='file' device='disk'> //硬盘
<driver name='qemu' type='qcow2'/>
<source file='/home/yeqiang/qemu-virtual-machine/redflag.qcow2'/>
<target dev='vda' bus='virtio'/>
</disk>
<graphics type='vnc' port='5900' autoport='yes' listen='0.0.0.0' keymap='en-us'> //配置vnc,windows下可以使用vncviewer登录,获取vnc端口号:virsh vncdisplay vm0
<listen type='address' address='0.0.0.0'/>
</graphics>
<interface type='bridge'>
<source bridge='virbr0'/>
</interface>
</devices>
</domain>
测试程序
/**
tcti.cpp
参考:
https://www.cnblogs.com/organic/p/17321523.html
g++ -std=c++11 -lpthread trigger_cgroup_timer_inactive.cpp -o inactive_timer
./inactive_timer 100000 10000
*/
#include <errno.h>
#include <iostream>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#ifndef CPU_CORE_COUNT
#define CPU_CORE_COUNT 64
#endif
using namespace std;
std::string sub_cgroup_dir("/sys/fs/cgroup/cpu/test");
// common lib
bool is_dir(const std::string &path) {
struct stat statbuf;
if (stat(path.c_str(), &statbuf) == 0) {
if (0 != S_ISDIR(statbuf.st_mode)) {
return true;
}
}
return false;
}
bool write_file(const std::string &file_path, int num) {
// std::cout << file_path << " op:" << num << std::endl;
FILE *fp = fopen(file_path.c_str(), "w");
if (fp == NULL) {
return false;
}
// std::cout << file_path << " op:" << num << std::endl;
std::string write_data = to_string(num);
fputs(write_data.c_str(), fp);
fclose(fp);
return true;
}
std::string read_file(const std::string &file_path) {
FILE *fp = fopen(file_path.c_str(), "r");
if (NULL == fp) {
return "read error...\n";
}
char buff[512];
memset(buff, 0, 512);
fread(buff, 512, 1, fp);
return std::string(buff);
}
// ms
long get_ms_timestamp() {
timeval tv;
gettimeofday(&tv, NULL);
return (tv.tv_sec * 1000 + tv.tv_usec / 1000);
}
// cgroup
bool create_cgroup() {
if (is_dir(sub_cgroup_dir) == false) {
if (mkdir(sub_cgroup_dir.c_str(), S_IRWXU | S_IRGRP) != 0) {
cout << "mkdir cgroup dir fail" << endl;
return false;
}
}
int pid = getpid();
cout << "pid is " << pid << endl;
std::string procs_path = sub_cgroup_dir + "/cgroup.procs";
return write_file(procs_path, pid);
}
bool set_period(int period) {
std::string period_path = sub_cgroup_dir + "/cpu.cfs_period_us";
return write_file(period_path, period);
}
bool set_quota(int quota) {
std::string quota_path = sub_cgroup_dir + "/cpu.cfs_quota_us";
return write_file(quota_path, quota);
}
bool set_cpuOnline(int cpuId, int online) {
std::string cpuPath = std::string("/sys/devices/system/cpu/cpu") +
std::to_string(cpuId) + std::string("/online");
return write_file(cpuPath, online);
}
// thread
// param: ms interval
void *thread_func(void *param) {
int i = 0;
int interval = (long)param;
long last = get_ms_timestamp();
while (true) {
i++;
if (i % 100000 != 0) {
continue;
}
long current = get_ms_timestamp();
if ((current - last) >= interval) {
last = current;
}
}
pthread_exit(NULL);
}
void test_thread() {
const int k_thread_num = CPU_CORE_COUNT * 10;
pthread_t pthreads[k_thread_num];
for (int i = 0; i < k_thread_num; i++) {
if (pthread_create(&pthreads[i], NULL, thread_func, (void *)(i + 1)) != 0) {
cout << "create thread fail" << endl;
} else {
cout << "create thread success,tid is " << pthreads[i] << endl;
}
}
}
void *thread_cpu_online_ctl(void *param) {
int online, cpu;
bool b;
while (true) {
online = rand() % 2;
cpu = rand() % CPU_CORE_COUNT;
b = set_cpuOnline(cpu, online);
std::cout << cpu << " -> " << online << "result:" << b << std::endl;
std::cout << read_file("/sys/devices/system/cpu/online") << std::endl;
}
pthread_exit(NULL);
}
void cpu_ctl_thread() {
const int k_thread_num = CPU_CORE_COUNT;
pthread_t pthreads[k_thread_num];
for (int i = 0; i < k_thread_num; i++) {
if (pthread_create(&pthreads[i], NULL, thread_cpu_online_ctl,
(void *)(i + 1)) != 0) {
cout << "create thread fail" << endl;
} else {
cout << "create thread success,tid is " << pthreads[i] << endl;
}
}
}
int main(int argc, char *argv[]) {
int period = 100000;
int quota = CPU_CORE_COUNT * 0.8 * 100000;
cout << "period is " << period << endl;
cout << "quota is " << quota << endl;
srand(time(nullptr));
test_thread();
cpu_ctl_thread();
if (create_cgroup() == false) {
cout << "create cgroup fail" << endl;
return -1;
}
set_period(period);
set_quota(quota);
while (true) {
sleep(10000);
}
return 0;
}
编译
g++ -std=c++11 -lpthread tcti.cpp -o tcti
执行
./tcti &
vmstat监控
vmstat 1
一段时间后
此时,bash上敲击回车能换行,但是无信息输出
ctrl+C 可退出程序(又一次测试未退出,卡主了)
tcti进程 cpu 0%
kill -9 无法杀死
reboot,卡死
此时键盘输入有信息打印
卡死后,放置约14小时后,再次vnc登录,光标已不再闪烁,键盘输入也没有给出反馈,彻底死机。
此时在宿主机查看kvm进程CPU状态,几乎没有消耗
virsh 导出内核转储文件分析(64G内存,时间较长)
virsh dump --memory-only --format=kdump-zlib redflag1 redflag1-coredump-0428-stucked.zlib
重启虚拟机,分析coredump
crash调试
bt -a
ps
原本期望通过不断设置CPU在线状态,迫使CFS触发_nohz_idle_balance。实际上的故障与期望不一致,产生了新问题。
重新测试
刚开始测试时,100.0 id 数值明显不对,应该是操作CPU在线状态导致
约6分钟后,测试进程没有CPU消耗了
STAT:SI
S //处于休眠状态;
l //多线程,克隆线程(使用 CLONE_THREAD, 类似 NPTL pthreads);
参考:Linux进程状态(ps stat)详解_smartvxworks的博客-CSDN博客
说明此时线程sleep后没有再被调度器分配CPU了 。
当前CPU online状态
gdb attach上去看看
挂不上去,且无法退出
正确指令应该是 gdb attach 2034(虽然敲错了指令,但日志已显示Attatching to process 2034)
在kvm外,导出coredump
virsh dump --memory-only --format=kdump-zlib redflag1 redflag1-coredump-0428-stucked2.zlib
从目前看,应该是触发了bug,当前任务被调度出去,一直没能调度回来。该进程程序本身没有什么问题。
查看几个子线程,连号
都在这个位置
复测,待续。。。
10分51秒后,tcti CPU占用率掉到了0%
尝试手动调整cgroup限制,新开ssh窗口登录上去,方便观察top信息
cat /dev/null > /sys/fs/cgroup/cpu/test/cgroup.procs
cat /dev/null > /sys/fs/cgroup/cpu/test/tasks
查看发现无法清空
设置所有CPU online=1
ls /sys/devices/system/cpu/ | grep cpu | grep -v freq | grep -v idle | xargs -i echo "echo 1 > /sys/devices/system/cpu/"{}"/online" | bash
当前进程卡死了。。。
推测引发了内核层bug
mesg当前时段没有信息输出
FT2000+ kvm openEuler 20.03 LTS SP3 64C64G
openEuler 20.03 LTS SP3 aarch64
运行两小时,正常,说明是内核的bug
20230504补充
openEuler 20.03 LTS SP3 复测,启动时直接卡死,即:停在所有线程初始化完毕阶段。
并没有出现以下信息
复测说明:openEuler 20.03 LTS SP3内核有相似故障。
复测3
手动循环重启9次(即:运行./tcti 等开始操作CPU上下线线程跑几秒,ctrl+C中断程序,再启动)
第十次启动,保持不动,约11秒后,不输出内核日志,宿主机查看CPU使用率也掉到接近0%。任务不调度故障复现。
一段时间后,屏幕输出
task blocked for more than 120 seconds
process rngd no longer affine to cpu1
FT2000/4 台式机 红旗操作系统复现。
Kunpeng920 8核 openEuler 20.03 LTS SP3 台式机,
一次就复现,10秒左右。半小时卡死终端无输出。
FT2000+ openEuler 22.03 LTS 64C64G kvm
一个多小时,正常
FT2000/4 CentOS8
启动就卡死进程,无法kill
CPU0 killed 导致??CPU0 不能下线?
一段时间后:
task kworker blocked for more than 120 seconds
not tainted
echo 0 > /proc/sys/kernel/hung_task_timeout_secs
reboot同样造成物理机完全卡死
复测,排除CPU0下线,当 online= 0-1,3时(第一次下线就挂了),复现。排除因为CPU0下线导致。
更多推荐
所有评论(0)