Add free page filtering logic in __exclude_unnecessary_pages. Unlike other filtering levels, the number of free pages indicated by buddy page is multiple. So I put this logic in the first position, in front of page cache, to avoid filtering the pages that has already been filtered as free pages. Basically, this mem_map array logic is in cyclic mode only. The exceptional case is that debug information necessary for mem_map logic is not available enough. Then, it is switched to freelist logic. In non cyclic mode, existing freelist logic is used. Newly introduced page_is_buddy handler abstracts condition of buddy page that varies depending on kernel versions. On the kernel versions supported by makedumpfile, there are three kinds of buddy conditions. Later patches will introduce them in order. If failing to choose a correct page_is_buddy handler due to absence of debug information, we switch the logic to freelist logic. Signed-off-by: HATAYAMA Daisuke <d.hatayama at jp.fujitsu.com> --- makedumpfile.c | 45 ++++++++++++++++++++++++++++++++++++++++----- makedumpfile.h | 5 +++++ 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/makedumpfile.c b/makedumpfile.c index 1a0151c..0e44a8b 100644 --- a/makedumpfile.c +++ b/makedumpfile.c @@ -58,6 +58,8 @@ do { \ *ptr_long_table = value; \ } while (0) +static void setup_page_is_buddy(void); + void initialize_tables(void) { @@ -2841,6 +2843,9 @@ out: if (!get_value_for_old_linux()) return FALSE; + if (info->flag_cyclic && (info->dump_level & DL_EXCLUDE_FREE)) + setup_page_is_buddy(); + return TRUE; } @@ -3663,6 +3668,18 @@ exclude_free_page(void) return TRUE; } +static void +setup_page_is_buddy(void) +{ + if (OFFSET(page.private) == NOT_FOUND_STRUCTURE) + goto out; + +out: + if (!info->page_is_buddy) + DEBUG_MSG("Can't select page_is_buddy handler; " + "follow free lists instead of mem_map array.\n"); +} + /* * If using a dumpfile in kdump-compressed format as a source file * instead of /proc/vmcore, 1st-bitmap of a new dumpfile must be @@ -3873,8 +3890,8 @@ __exclude_unnecessary_pages(unsigned long mem_map, unsigned long long pfn_read_start, pfn_read_end, index_pg; unsigned char page_cache[SIZE(page) * PGMM_CACHED]; unsigned char *pcache; - unsigned int _count; - unsigned long flags, mapping; + unsigned int _count, _mapcount = 0; + unsigned long flags, mapping, private = 0; /* * Refresh the buffer of struct page, when changing mem_map. @@ -3928,11 +3945,28 @@ __exclude_unnecessary_pages(unsigned long mem_map, flags = ULONG(pcache + OFFSET(page.flags)); _count = UINT(pcache + OFFSET(page._count)); mapping = ULONG(pcache + OFFSET(page.mapping)); + if (OFFSET(page._mapcount) != NOT_FOUND_STRUCTURE) + _mapcount = UINT(pcache + OFFSET(page._mapcount)); + if (OFFSET(page.private) != NOT_FOUND_STRUCTURE) + private = ULONG(pcache + OFFSET(page.private)); /* + * Exclude the free page managed by a buddy + */ + if ((info->dump_level & DL_EXCLUDE_FREE) + && info->flag_cyclic + && info->page_is_buddy + && info->page_is_buddy(flags, _mapcount, private, _count)) { + int i; + + for (i = 0; i < (1 << private); ++i) + clear_bit_on_2nd_bitmap_for_kernel(pfn + i); + pfn_free += i; + } + /* * Exclude the cache page without the private page. */ - if ((info->dump_level & DL_EXCLUDE_CACHE) + else if ((info->dump_level & DL_EXCLUDE_CACHE) && (isLRU(flags) || isSwapCache(flags)) && !isPrivate(flags) && !isAnon(mapping)) { if (clear_bit_on_2nd_bitmap_for_kernel(pfn)) @@ -4013,7 +4047,7 @@ exclude_unnecessary_pages_cyclic(void) */ copy_bitmap_cyclic(); - if (info->dump_level & DL_EXCLUDE_FREE) + if ((info->dump_level & DL_EXCLUDE_FREE) && !info->page_is_buddy) if (!exclude_free_page()) return FALSE; @@ -4022,7 +4056,8 @@ exclude_unnecessary_pages_cyclic(void) */ if (info->dump_level & DL_EXCLUDE_CACHE || info->dump_level & DL_EXCLUDE_CACHE_PRI || - info->dump_level & DL_EXCLUDE_USER_DATA) { + info->dump_level & DL_EXCLUDE_USER_DATA || + ((info->dump_level & DL_EXCLUDE_FREE) && info->page_is_buddy)) { gettimeofday(&tv_start, NULL); diff --git a/makedumpfile.h b/makedumpfile.h index d69bcca..c236ece 100644 --- a/makedumpfile.h +++ b/makedumpfile.h @@ -1037,6 +1037,11 @@ struct DumpInfo { */ int flag_sadump_diskset; enum sadump_format_type flag_sadump; /* sadump format type */ + /* + * for filtering free pages managed by buddy system: + */ + int (*page_is_buddy)(unsigned long flags, unsigned int _mapcount, + unsigned long private, unsigned int _count); }; extern struct DumpInfo *info;