[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