在第二个内核以类似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 //最后布局如下 ![](http://blogimg.chinaunix.net/blog/upfile2/111004163021.jpg) 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; } |