在第二个内核以类似ro root=LABEL=/ rhgb quiet irqpoll maxcpus=1 reset_devices memmap=exactmap memmap=640K@0K memmap=5264K@16384K memmap=125152K@22288K
elfcorehdr=147440K memmap=56K#1834688K memmap=136K#1834744K
memmap=128K#1834880K memmap=1024K$4193280K启动时,再次调用/etc/init.d/kdump start来启动
,由于此时/proc/vmcore存在且大小不为0,所以,
unction save_core()
{
local kdump_path
kdump_path=`grep ^path $KDUMP_CONFIG_FILE | cut -d' ' -f2-`
if [ -z "$kdump_path" ]; then
coredir="/var/crash/`date +"%Y-%m-%d-%H:%M"`"
else
coredir="${kdump_path}/`date +"%Y-%m-%d-%H:%M"`"
fi
mkdir -p $coredir
cp --sparse=always /proc/vmcore $coredir/vmcore-incomplete
exitcode=$?
if [ $exitcode == 0 ]; then
mv $coredir/vmcore-incomplete $coredir/vmcore
$LOGGER "saved a vmcore to $coredir"
else
$LOGGER "failed to save a vmcore to $coredir"
fi
return $exitcode
} function do_final_action() { reboot }
if [ -s /proc/vmcore ]; then #第二个内核启动后走此步!
run_kdump_pre
save_core
run_kdump_post $?
do_final_action |
当初测试发现自动保存vmcore到/var/crash后会自动重启, 这个当时没明白,其实是由于do_final_action里调用重启命令了....(其实上述过程一般是走不到的,因为默认没挂载真实/分区之前就重启了,见下面分析!)
另外在/etc/kdump.conf中配置了makedumpfile来过滤和压缩页的,一直没有找到哪里使用这个文件及makedumpfile的, 后来才发现是在/sbin/mkdumprd(一个shell脚本)制作第二个 内核需要的initrd时使用的,第二个内核启动时以此initrd做临时根文件系统,initrd中的init来调用makedumpfile过滤压缩页的, 完了之后还是会重启机器的,看了下代码,其实后面还是可以像正常一样挂载真实的/文件系统。至于为啥此时就重启机器,我猜原因一是因为已经收集到需要的信息;原因二是由于此时能使用的内存有限,此时只能使用128M物理内存,加载剩余驱动或者服务等所需内存可能不够,测试中发现有时会在挂载真实的/文件系统时kernel panic.
用一张图总结下:
至于/sbin/kdump也就是kexec-tools中的kdump,没找到在哪里调用这个?看了下代码,这个只接受一个参数elfcorehdr,将原内存中相关信息Ehdr,pt_note(多个合并成一个),pt_load,note_bytes,Segments等等最终输出到stdout上,这个在使用时应该重定向到一个文件中才是?????
int main(int argc, char **argv)
{
char *start_addr_str, *end;
unsigned long long start_addr;
Elf64_Ehdr *ehdr;
Elf64_Phdr *phdr;
void *notes, *headers;
size_t note_bytes, header_bytes;
int fd;
int i;
start_addr_str = 0;
if (argc > 2) {
fprintf(stderr, "Invalid argument count\n");
exit(9);
}
if (argc == 2) {
start_addr_str = argv[1];//第一个内核的ELF头所在的物理地址先传给kdump,然后被作为命令行参数(elfcorehdr=)传递给新启动的转储内核.第二个内核的启动参数最终大概为这个终形式
//root=/=Label irqpoll maxcpus=1 reset_device memmap=exactmap memmap=640K@0 memmap=X@16384 elfcorehdr=Z memmap=Y@U ....
}
if (!start_addr_str) {
start_addr_str = getenv("elfcorehdr");
}
if (!start_addr_str) {
fprintf(stderr, "Cannot find the start of the core dump\n");
exit(1);
}
start_addr = strtoull(start_addr_str, &end, 0);
if ((start_addr_str == end) || (*end != '\0')) {
fprintf(stderr, "Bad core dump start addres: %s\n",
start_addr_str);
exit(2);
}
fd = open(DEV_MEM, O_RDONLY);//打开第一个内核的内存/dev/mem !!!!!
if (fd < 0) {
fprintf(stderr, "Cannot open " DEV_MEM ": %s\n",
strerror(errno));
exit(3);
}
/* Get the elf header */
ehdr = map_addr(fd, sizeof(*ehdr), start_addr);
/* Verify the ELF header */
if ( (ehdr->e_ident[EI_MAG0] != ELFMAG0) ||
(ehdr->e_ident[EI_MAG1] != ELFMAG1) ||
(ehdr->e_ident[EI_MAG2] != ELFMAG2) ||
(ehdr->e_ident[EI_MAG3] != ELFMAG3) ||
(ehdr->e_ident[EI_CLASS] != ELFCLASS64) ||
(ehdr->e_ident[EI_DATA] != ELFDATALOCAL) ||
(ehdr->e_ident[EI_VERSION] != EV_CURRENT) ||
(ehdr->e_type != ET_CORE) ||
(ehdr->e_version != EV_CURRENT) ||
(ehdr->e_ehsize != sizeof(Elf64_Ehdr)) ||
(ehdr->e_phentsize != sizeof(Elf64_Phdr)) ||
(ehdr->e_phnum == 0))
{
fprintf(stderr, "Invalid Elf header\n");
exit(4);
}
/* Get the program header */
phdr = map_addr(fd, sizeof(*phdr)*(ehdr->e_phnum), ehdr->e_phoff);
/* Collect up the notes */
note_bytes = 0;
notes = collect_notes(fd, ehdr, phdr, ¬e_bytes);
/* Generate new headers */
header_bytes = 0;
headers = generate_new_headers(ehdr, phdr, note_bytes, &header_bytes);//=====>
/* Write out everything */
//由于刚开始第一个内核可能不止一个p_note段,这里合并成一个,写到STDOUT_FILENO
//最后布局如下
write_all(STDOUT_FILENO, headers, header_bytes);
write_all(STDOUT_FILENO, notes, note_bytes);
for(i = 0; i < ehdr->e_phnum; i++) {
unsigned long long offset, size;
size_t wsize;
if (phdr[i].p_type != PT_NOTE) {
continue;
}
offset = phdr[i].p_offset;
size = phdr[i].p_filesz;
wsize = MAP_WINDOW_SIZE;
if (wsize > size) {
wsize = size;
}
for(;size > 0; size -= wsize, offset += wsize) {
void *buf;
wsize = MAP_WINDOW_SIZE;
if (wsize > size) {
wsize = size;
}
buf = map_addr(fd, wsize, offset);
write_all(STDOUT_FILENO, buf, wsize);
unmap_addr(buf, wsize);
}
}
free(notes);
close(fd);
return 0;
}
|
阅读(5614) | 评论(0) | 转发(2) |