在第二个内核以类似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, & note_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; }