[PATCH v2] makedumpfile: Fix a bug in generating incomplete kdump core

Atsushi Kumagai ats-kumagai at wm.jp.nec.com
Thu Jul 16 23:18:14 PDT 2015


Hello Zhou,

>In current implementation, there is a bug in generating incomplete
>kdump core.
>The current implementation behaves as the following:
>
>1. Write page header into the buffer cd_header.
>2. If cd_header is full, flush the cd_header.
>3. Write page data into the buffer cd_page.
>4. If cd_page is full, flush the cd_page.
>
>When ENOSPC occurs in flushing cd_page, there's still data left in
>cd_header. We cannot read page data corresponding to the page
>headers in the cd_header even if the page data has been flushed into
>disk. The size of page data is 170 times larger than the size of
>page header per a single page frame. The difference becomes bigger
>if we use compression.
>
>The patch fixs the bug by changing the logic and the new logic is:
>
>1. Before writing page header and data into buffers, if either of the
>   buffers will be full, write the data of the buffer into file.
>2. When enospc occurs in writing the cd_header into file, fill the
>   cd_header with zero and re-write the cd_header.
>3. When enospc occurs in writing the cd_page into file, fill part
>   of the cd_header with zero according to how many pages in cd_page
>   have been written.
>4. Then, write the page header and data info buffers.

This version looks good to me, I'll merge it into v1.5.9.

Thanks
Atsushi Kumagai

>Signed-off-by: Zhou Wenjian <zhouwj-fnst at cn.fujitsu.com>
>---
> makedumpfile.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
> 1 file changed, 91 insertions(+), 11 deletions(-)
>
>diff --git a/makedumpfile.c b/makedumpfile.c
>index cc71f20..b056528 100644
>--- a/makedumpfile.c
>+++ b/makedumpfile.c
>@@ -6286,6 +6286,92 @@ write_elf_pages_cyclic(struct cache_data *cd_header, struct cache_data *cd_page)
> }
>
> int
>+write_cd_buf(struct cache_data *cd)
>+{
>+	if (cd->buf_size == 0)
>+		return TRUE;
>+
>+	if (!write_buffer(cd->fd, cd->offset, cd->buf,
>+			cd->buf_size, cd->file_name)) {
>+		return FALSE;
>+	}
>+
>+	return TRUE;
>+}
>+
>+/*
>+ * get_nr_pages is used for generating incomplete kdump core.
>+ * When enospac occurs in writing the buf cd_page, it can be used to
>+ * get how many pages have been written.
>+ */
>+int
>+get_nr_pages(void *buf, struct cache_data *cd_page){
>+	int size, file_end, nr_pages;
>+	page_desc_t *pd = buf;

I prefer to

+int
+get_nr_pages(struct cache_data *cd_header, struct cache_data *cd_page){
+	int size, file_end, nr_pages;
+	page_desc_t *pd = cd_header->buf;

>+
>+	file_end = lseek(cd_page->fd, 0, SEEK_END);
>+	if (file_end < 0) {
>+		ERRMSG("Can't seek end of the dump file(%s).\n", cd_page->file_name);
>+		return -1;
>+	}
>+
>+	size = pd->size;
>+	nr_pages = 0;
>+	while (size <= file_end - cd_page->offset) {
>+		nr_pages++;
>+		pd++;
>+		size += pd->size;
>+	}
>+
>+	return nr_pages;
>+}
>+
>+int
>+write_kdump_page(struct cache_data *cd_header, struct cache_data *cd_page,
>+		struct page_desc *pd, void *page_data)
>+{
>+	int written_headers_size;
>+
>+	/*
>+	 * If either cd_header or cd_page is nearly full,
>+	 * write the buffer cd_header into dumpfile and then write the cd_page.
>+	 * With that, when enospc occurs, we can save more useful information.
>+	 */
>+	if (cd_header->buf_size + sizeof(*pd) > cd_header->cache_size
>+		|| cd_page->buf_size + pd->size > cd_page->cache_size){
>+		if( !write_cd_buf(cd_header) ) {
>+			memset(cd_header->buf, 0, cd_header->cache_size);
>+			write_cd_buf(cd_header);
>+
>+			return FALSE;
>+		}
>+
>+		if( !write_cd_buf(cd_page) ) {
>+			written_headers_size = sizeof(page_desc_t) *
>+					get_nr_pages(cd_header->buf, cd_page);
>+			if (written_headers_size < 0)
>+				return FALSE;
>+
>+			memset(cd_header->buf, 0, cd_header->cache_size);
>+			cd_header->offset += written_headers_size;
>+			cd_header->buf_size -= written_headers_size;
>+			write_cd_buf(cd_header);
>+
>+			return FALSE;
>+		}
>+		cd_header->offset += cd_header->buf_size;
>+		cd_page->offset += cd_page->buf_size;
>+		cd_header->buf_size = 0;
>+		cd_page->buf_size = 0;
>+	}
>+
>+	write_cache(cd_header, pd, sizeof(page_desc_t));
>+	write_cache(cd_page, page_data, pd->size);
>+
>+	return TRUE;
>+}
>+
>+int
> write_kdump_pages_cyclic(struct cache_data *cd_header, struct cache_data *cd_page,
> 			 struct page_desc *pd_zero, off_t *offset_data, struct cycle *cycle)
> {
>@@ -6424,17 +6510,11 @@ write_kdump_pages_cyclic(struct cache_data *cd_header, struct cache_data *cd_pag
> 		pd.offset     = *offset_data;
> 		*offset_data  += pd.size;
>
>-                /*
>-                 * Write the page header.
>-                 */
>-                if (!write_cache(cd_header, &pd, sizeof(page_desc_t)))
>-                        goto out;
>-
>-                /*
>-                 * Write the page data.
>-                 */
>-		if (!write_cache(cd_page, pd.flags ? buf_out : buf, pd.size))
>-                        goto out;
>+               /*
>+                * Write the page header and the page data
>+                */
>+               if (!write_kdump_page(cd_header, cd_page, &pd, pd.flags ? buf_out : buf))
>+                       goto out;
>         }
>
> 	ret = TRUE;
>--
>1.8.3.1
>
>
>_______________________________________________
>kexec mailing list
>kexec at lists.infradead.org
>http://lists.infradead.org/mailman/listinfo/kexec



More information about the kexec mailing list