Kdump之kdump分析(续)

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

你可能感兴趣的:(Date,function,header,测试,action,Path)