[PATCH v2 7/8] makedumpfile: Add erased information in compressed kdump file
Ken'ichi Ohmichi
oomichi at mxs.nes.nec.co.jp
Fri Aug 12 04:10:13 EDT 2011
Hi Mahesh,
On Wed, 18 May 2011 01:36:17 +0530
Mahesh J Salgaonkar <mahesh at linux.vnet.ibm.com> wrote:
> --- a/makedumpfile.c
> +++ b/makedumpfile.c
> @@ -29,6 +29,8 @@ struct DumpInfo *info = NULL;
> struct module_sym_table mod_st = { 0 };
> struct filter_info *filter_info = NULL;
> struct filter_config filter_config;
> +struct erase_info *erase_info = NULL;
> +unsigned long num_erase_info = 1; /* Node 0 is unused. */
I cannot understand erase_info[0] is unused.
> @@ -6000,10 +6007,17 @@ write_kdump_header(void)
> kh.size_vmcoreinfo = info->size_vmcoreinfo;
> }
> }
> - if (!write_buffer(info->fd_dumpfile, dh->block_size, &kh,
> - size, info->name_dumpfile))
> - goto out;
> + /*
> + * While writing dump data to STDOUT, delay the writing of sub header
> + * untill we gather erase info offset and size.
> + */
> + if (!info->flag_flatten) {
> + if (!write_buffer(info->fd_dumpfile, dh->block_size, &kh,
> + size, info->name_dumpfile))
> + goto out;
> + }
Does makedumpfile work wrong if removing the above change ?
I'd like to check this patch carefully, and I will review the remainder
next week.
Thanks
Ken'ichi Ohmichi
> @@ -6061,12 +6075,39 @@ split_filter_info(struct filter_info *prev, unsigned long long next_paddr,
> return;
> }
> new->nullify = prev->nullify;
> + new->erase_info_idx = prev->erase_info_idx;
> + new->size_idx = prev->size_idx;
> new->paddr = next_paddr;
> new->size = size;
> new->next = prev->next;
> prev->next = new;
> }
>
> +void
> +update_erase_info(struct filter_info *fi)
> +{
> + struct erase_info *ei;
> +
> + if (!fi->erase_info_idx)
> + return;
> +
> + ei = &erase_info[fi->erase_info_idx];
> +
> + if (!ei->sizes) {
> + /* First time, allocate sizes array */
> + ei->sizes = calloc(ei->num_sizes, sizeof(long));
> + if (!ei->sizes) {
> + ERRMSG("Can't allocate memory for erase info sizes\n");
> + return;
> + }
> + }
> + ei->erased = 1;
> + if (!fi->nullify)
> + ei->sizes[fi->size_idx] += fi->size;
> + else
> + ei->sizes[fi->size_idx] = -1;
> +}
> +
> int
> extract_filter_info(unsigned long long start_paddr,
> unsigned long long end_paddr,
> @@ -6100,6 +6141,7 @@ extract_filter_info(unsigned long long start_paddr,
> filter_info = fi->next;
> else
> prev->next = fi->next;
> + update_erase_info(fi);
> free(fi);
> return TRUE;
> }
> @@ -6567,6 +6609,159 @@ out:
> return ret;
> }
>
> +/*
> + * Copy eraseinfo from input dumpfile/vmcore to output dumpfile.
> + */
> +static int
> +copy_eraseinfo(struct cache_data *cd_eraseinfo)
> +{
> + char *buf = NULL;
> + int ret = FALSE;
> +
> + buf = malloc(info->size_eraseinfo);
> + if (buf == NULL) {
> + ERRMSG("Can't allocate memory for erase info section. %s\n",
> + strerror(errno));
> + return FALSE;
> + }
> + if (lseek(info->fd_memory, info->offset_eraseinfo, SEEK_SET) < 0) {
> + ERRMSG("Can't seek the dump memory(%s). %s\n",
> + info->name_memory, strerror(errno));
> + goto out;
> + }
> + if (read(info->fd_memory, buf, info->size_eraseinfo)
> + != info->size_eraseinfo) {
> + ERRMSG("Can't read the dump memory(%s). %s\n",
> + info->name_memory, strerror(errno));
> + goto out;
> + }
> + if (!write_cache(cd_eraseinfo, buf, info->size_eraseinfo))
> + goto out;
> + ret = TRUE;
> +out:
> + if (buf)
> + free(buf);
> + return ret;
> +}
> +
> +static int
> +update_sub_header(void)
> +{
> + off_t offset;
> +
> + /* seek to kdump sub header offset */
> + offset = DISKDUMP_HEADER_BLOCKS * info->page_size;
> +
> + info->sub_header.offset_eraseinfo = info->offset_eraseinfo;
> + info->sub_header.size_eraseinfo = info->size_eraseinfo;
> +
> + if (!write_buffer(info->fd_dumpfile, offset, &info->sub_header,
> + sizeof(struct kdump_sub_header), info->name_dumpfile))
> + return FALSE;
> +
> + return TRUE;
> +}
> +
> +/*
> + * Traverse through eraseinfo nodes and write it to the o/p dumpfile if the
> + * node has erased flag set.
> + */
> +int
> +write_eraseinfo(struct cache_data *cd_page, unsigned long *size_out)
> +{
> + int i, j, obuf_size = 0, ei_size = 0;
> + int ret = FALSE;
> + unsigned long size_eraseinfo = 0;
> + char *obuf = NULL;
> + char size_str[MAX_SIZE_STR_LEN];
> +
> + for (i = 1; i < num_erase_info; i++) {
> + if (!erase_info[i].erased)
> + continue;
> + for (j = 0; j < erase_info[i].num_sizes; j++) {
> + if (erase_info[i].sizes[j] > 0)
> + sprintf(size_str, "%ld\n",
> + erase_info[i].sizes[j]);
> + else if (erase_info[i].sizes[j] == -1)
> + sprintf(size_str, "nullify\n");
> +
> + /* Calculate the required buffer size. */
> + ei_size = strlen("erase ") +
> + strlen(erase_info[i].symbol_expr) + 1 +
> + strlen(size_str) +
> + 1;
> + /*
> + * If obuf is allocated in the previous run and is
> + * big enough to hold current erase info string then
> + * reuse it otherwise realloc.
> + */
> + if (ei_size > obuf_size) {
> + obuf_size = ei_size;
> + obuf = realloc(obuf, obuf_size);
> + if (!obuf) {
> + ERRMSG("Can't allocate memory for"
> + " output buffer\n");
> + return FALSE;
> + }
> + }
> + sprintf(obuf, "erase %s %s", erase_info[i].symbol_expr,
> + size_str);
> + DEBUG_MSG(obuf);
> + if (!write_cache(cd_page, obuf, strlen(obuf)))
> + goto out;
> + size_eraseinfo += strlen(obuf);
> + }
> + }
> + /*
> + * Write the remainder.
> + */
> + if (!write_cache_bufsz(cd_page))
> + goto out;
> +
> + *size_out = size_eraseinfo;
> + ret = TRUE;
> +out:
> + if (obuf)
> + free(obuf);
> +
> + return ret;
> +}
> +
> +int
> +write_kdump_eraseinfo(struct cache_data *cd_page)
> +{
> + off_t offset_eraseinfo;
> + unsigned long size_eraseinfo;
> +
> + DEBUG_MSG("Writing erase info...\n");
> + offset_eraseinfo = cd_page->offset;
> +
> + /*
> + * In case of refiltering copy the existing eraseinfo from input
> + * dumpfile to o/p dumpfile.
> + */
> + if (info->offset_eraseinfo && info->size_eraseinfo) {
> + if (!copy_eraseinfo(cd_page))
> + return FALSE;
> + }
> +
> + /* Initialize eraseinfo offset with new offset value. */
> + info->offset_eraseinfo = offset_eraseinfo;
> +
> + if (!write_eraseinfo(cd_page, &size_eraseinfo))
> + return FALSE;
> +
> + info->size_eraseinfo += size_eraseinfo;
> + DEBUG_MSG("offset_eraseinfo: %lx, size_eraseinfo: %ld\n",
> + info->offset_eraseinfo, info->size_eraseinfo);
> +
> + /* Update the erase info offset and size in kdump sub header */
> + if (!update_sub_header())
> + return FALSE;
> +
> + return TRUE;
> +}
> +
> int
> write_kdump_bitmap(void)
> {
> @@ -7391,6 +7586,8 @@ writeout_dumpfile(void)
> goto out;
> if (!write_kdump_pages(&cd_header, &cd_page))
> goto out;
> + if (!write_kdump_eraseinfo(&cd_page))
> + goto out;
> if (!write_kdump_bitmap())
> goto out;
> }
> @@ -7781,6 +7978,8 @@ free_config_entry(struct config_entry *ce)
> free(p->name);
> if (p->type_name)
> free(p->type_name);
> + if (p->symbol_expr)
> + free(p->symbol_expr);
> free(p);
> }
> }
> @@ -8129,6 +8328,13 @@ read_filter_entry(struct config *config, int line)
> line);
> return FALSE;
> }
> +
> + /*
> + * Save the symbol expression string for generation of eraseinfo data
> + * later while writing dumpfile.
> + */
> + config->filter_symbol[idx]->symbol_expr = strdup(token);
> +
> if (config->iter_entry) {
> if (strcmp(config->filter_symbol[idx]->name,
> config->iter_entry->name)) {
> @@ -8726,8 +8932,11 @@ resolve_list_entry(struct config_entry *ce, unsigned long long base_addr,
> * Insert the filter info node using insertion sort.
> * If filter node for a given paddr is aready present then update the size
> * and delete the fl_info node passed.
> + *
> + * Return 1 on successfull insertion.
> + * Return 0 if filter node with same paddr is found.
> */
> -void
> +int
> insert_filter_info(struct filter_info *fl_info)
> {
> struct filter_info *prev = NULL;
> @@ -8735,7 +8944,7 @@ insert_filter_info(struct filter_info *fl_info)
>
> if (!ptr) {
> filter_info = fl_info;
> - return;
> + return 1;
> }
>
> while (ptr) {
> @@ -8748,7 +8957,7 @@ insert_filter_info(struct filter_info *fl_info)
> if (fl_info->size > ptr->size)
> ptr->size = fl_info->size;
> free(fl_info);
> - return;
> + return 0;
> }
>
> if (prev) {
> @@ -8759,7 +8968,80 @@ insert_filter_info(struct filter_info *fl_info)
> fl_info->next = filter_info;
> filter_info = fl_info;
> }
> - return;
> + return 1;
> +}
> +
> +/*
> + * Create an erase info node for each erase command. One node per erase
> + * command even if it is part of loop construct.
> + * For erase commands that are not part of loop construct, the num_sizes will
> + * always be 1
> + * For erase commands that are part of loop construct, the num_sizes may be
> + * 1 or >1 depending on number iterations. This function will called multiple
> + * times depending on iterations. At first invokation create a node and
> + * increment num_sizes for subsequent invokations.
> + *
> + * The valid erase info node starts from index value 1. (index 0 is invalid
> + * index).
> + *
> + * Index 0 1 2 3
> + * +------+--------+--------+--------+
> + * erase_info->|Unused| | | |......
> + * +------+--------+--------+--------+
> + * | . . .....
> + * V
> + * +---------+
> + * | char* |----> Original erase command string
> + * +---------+
> + * |num_sizes|
> + * +---------+ +--+--+--+
> + * | sizes |----> | | | |... Sizes array of num_sizes
> + * +---------+ +--+--+--+
> + *
> + * On success, return the index value of erase node for given erase command.
> + * On failure, return 0.
> + */
> +static int
> +add_erase_info_node(struct config_entry *filter_symbol)
> +{
> + int idx = filter_symbol->erase_info_idx;
> +
> + /*
> + * Check if node is already created, if yes, increment the num_sizes.
> + */
> + if (idx) {
> + erase_info[idx].num_sizes++;
> + return idx;
> + }
> +
> + /* Allocate a new node. */
> + DEBUG_MSG("Allocating new erase info node for command \"%s\"\n",
> + filter_symbol->symbol_expr);
> + idx = num_erase_info++;
> + erase_info = realloc(erase_info,
> + sizeof(struct erase_info) * num_erase_info);
> + if (!erase_info) {
> + ERRMSG("Can't get memory to create erase information.\n");
> + return 0;
> + }
> +
> + memset(&erase_info[idx], 0, sizeof(struct erase_info));
> + erase_info[idx].symbol_expr = filter_symbol->symbol_expr;
> + erase_info[idx].num_sizes = 1;
> +
> + filter_symbol->symbol_expr = NULL;
> + filter_symbol->erase_info_idx = idx;
> +
> + return idx;
> +}
> +
> +/* Return the index value in sizes array for given erase command index. */
> +static inline int
> +get_size_index(int ei_idx)
> +{
> + if (ei_idx)
> + return erase_info[ei_idx].num_sizes - 1;
> + return 0;
> }
>
> int
> @@ -8798,7 +9080,10 @@ update_filter_info(struct config_entry *filter_symbol,
> fl_info->size = size;
> fl_info->nullify = filter_symbol->nullify;
>
> - insert_filter_info(fl_info);
> + if (insert_filter_info(fl_info)) {
> + fl_info->erase_info_idx = add_erase_info_node(filter_symbol);
> + fl_info->size_idx = get_size_index(fl_info->erase_info_idx);
> + }
> return TRUE;
> }
>
> @@ -9049,6 +9334,7 @@ void
> clear_filter_info(void)
> {
> struct filter_info *prev, *fi = filter_info;
> + int i;
>
> /* Delete filter_info nodes that are left out. */
> while (fi) {
> @@ -9057,6 +9343,13 @@ clear_filter_info(void)
> free(prev);
> }
> filter_info = NULL;
> + if (erase_info) {
> + for (i = 1; i < num_erase_info; i++) {
> + free(erase_info[i].symbol_expr);
> + free(erase_info[i].sizes);
> + }
> + free(erase_info);
> + }
> }
>
> int
> @@ -9245,6 +9538,8 @@ store_splitting_info(void)
> }
> SPLITTING_START_PFN(i) = kh.start_pfn;
> SPLITTING_END_PFN(i) = kh.end_pfn;
> + SPLITTING_OFFSET_EI(i) = kh.offset_eraseinfo;
> + SPLITTING_SIZE_EI(i) = kh.size_eraseinfo;
> }
> return TRUE;
> }
> @@ -9452,6 +9747,7 @@ reassemble_kdump_pages(void)
> struct cache_data cd_pd, cd_data;
> struct timeval tv_start;
> char *data = NULL;
> + unsigned long data_buf_size = info->page_size;
>
> initialize_2nd_bitmap(&bitmap2);
>
> @@ -9465,7 +9761,7 @@ reassemble_kdump_pages(void)
> free_cache_data(&cd_pd);
> return FALSE;
> }
> - if ((data = malloc(info->page_size)) == NULL) {
> + if ((data = malloc(data_buf_size)) == NULL) {
> ERRMSG("Can't allcate memory for page data.\n");
> free_cache_data(&cd_pd);
> free_cache_data(&cd_data);
> @@ -9570,6 +9866,49 @@ reassemble_kdump_pages(void)
> if (!write_cache_bufsz(&cd_data))
> goto out;
>
> + info->offset_eraseinfo = cd_data.offset;
> + /* Copy eraseinfo from split dumpfiles to o/p dumpfile */
> + for (i = 0; i < info->num_dumpfile; i++) {
> + if (!SPLITTING_SIZE_EI(i))
> + continue;
> +
> + if (SPLITTING_SIZE_EI(i) > data_buf_size) {
> + data_buf_size = SPLITTING_SIZE_EI(i);
> + if ((data = realloc(data, data_buf_size)) == NULL) {
> + ERRMSG("Can't allcate memory for eraseinfo"
> + " data.\n");
> + goto out;
> + }
> + }
> + if ((fd = open(SPLITTING_DUMPFILE(i), O_RDONLY)) < 0) {
> + ERRMSG("Can't open a file(%s). %s\n",
> + SPLITTING_DUMPFILE(i), strerror(errno));
> + goto out;
> + }
> + if (lseek(fd, SPLITTING_OFFSET_EI(i), SEEK_SET) < 0) {
> + ERRMSG("Can't seek a file(%s). %s\n",
> + SPLITTING_DUMPFILE(i), strerror(errno));
> + goto out;
> + }
> + if (read(fd, data, SPLITTING_SIZE_EI(i)) !=
> + SPLITTING_SIZE_EI(i)) {
> + ERRMSG("Can't read a file(%s). %s\n",
> + SPLITTING_DUMPFILE(i), strerror(errno));
> + goto out;
> + }
> + if (!write_cache(&cd_data, data, SPLITTING_SIZE_EI(i)))
> + goto out;
> + info->size_eraseinfo += SPLITTING_SIZE_EI(i);
> +
> + close(fd);
> + fd = 0;
> + }
> + if (!write_cache_bufsz(&cd_data))
> + goto out;
> +
> + if (!update_sub_header())
> + goto out;
> +
> print_progress(PROGRESS_COPY, num_dumpable, num_dumpable);
> print_execution_time(PROGRESS_COPY, &tv_start);
>
> diff --git a/makedumpfile.h b/makedumpfile.h
> index 1c61edb..2e4b902 100644
> --- a/makedumpfile.h
> +++ b/makedumpfile.h
> @@ -434,6 +434,8 @@ do { \
> #define SPLITTING_FD_BITMAP(i) info->splitting_info[i].fd_bitmap
> #define SPLITTING_START_PFN(i) info->splitting_info[i].start_pfn
> #define SPLITTING_END_PFN(i) info->splitting_info[i].end_pfn
> +#define SPLITTING_OFFSET_EI(i) info->splitting_info[i].offset_eraseinfo
> +#define SPLITTING_SIZE_EI(i) info->splitting_info[i].size_eraseinfo
>
> /*
> * kernel version
> @@ -499,6 +501,8 @@ do { \
> #define XEN_ELFNOTE_CRASH_INFO (0x1000001)
> #define SIZE_XEN_CRASH_INFO_V2 (sizeof(unsigned long) * 10)
>
> +#define MAX_SIZE_STR_LEN (21)
> +
> /*
> * The value of dependence on machine
> */
> @@ -841,6 +845,8 @@ struct splitting_info {
> int fd_bitmap;
> unsigned long long start_pfn;
> unsigned long long end_pfn;
> + off_t offset_eraseinfo;
> + unsigned long size_eraseinfo;
> } splitting_info_t;
>
> struct DumpInfo {
> @@ -905,6 +911,7 @@ struct DumpInfo {
> struct dump_bitmap *bitmap1;
> struct dump_bitmap *bitmap2;
> struct disk_dump_header *dump_header;
> + struct kdump_sub_header sub_header;
>
> /*
> * ELF header info:
> @@ -973,6 +980,12 @@ struct DumpInfo {
> unsigned long size_note;
>
> /*
> + * erased information in dump memory image info:
> + */
> + off_t offset_eraseinfo;
> + unsigned long size_eraseinfo;
> +
> + /*
> * for Xen extraction
> */
> off_t offset_xen_crash_info;
> @@ -1280,12 +1293,27 @@ struct dwarf_info {
> extern struct dwarf_info dwarf_info;
>
> /*
> + * Erase information, original symbol expressions.
> + */
> +struct erase_info {
> + char *symbol_expr;
> + int num_sizes;
> + long *sizes;
> + int erased; /* 1= erased, 0= Not erased */
> +};
> +
> +/*
> * Filtering information
> */
> struct filter_info {
> unsigned long long address;
> unsigned long long paddr;
> long size;
> +
> + /* direct access to update erase information node */
> + int erase_info_idx; /* 0= invalid index */
> + int size_idx;
> +
> struct filter_info *next;
> unsigned short nullify;
> };
> @@ -1293,6 +1321,7 @@ struct filter_info {
> struct config_entry {
> char *name;
> char *type_name;
> + char *symbol_expr; /* original symbol expression */
> unsigned short flag;
> unsigned short nullify;
> unsigned long long sym_addr; /* Symbol address */
> @@ -1305,6 +1334,7 @@ struct config_entry {
> long index;
> long size;
> int line; /* Line number in config file. */
> + int erase_info_idx; /* 0= invalid index */
> struct config_entry *refer_to;
> struct config_entry *next;
> };
>
More information about the kexec
mailing list