Command search walks through all pages in identity mapping (i.e. virtual address space starting at PAGE_OFFSET and ending at high_memory) when it's used to search kernel memory. The new option -f allows the command to skip some uninteresting pages (e.g. LRU pages) to speed up the search. --- help.c | 11 +++++- memory.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 107 insertions(+), 27 deletions(-) diff --git a/help.c b/help.c index b2f4d21..8d45667 100644 --- a/help.c +++ b/help.c @@ -2814,7 +2814,8 @@ char *help_search[] = { "search", "search memory", "[-s start] [ -[kKV] | -u | -p | -t ] [-e end | -l length] [-m mask]\n" -" [-x count] -[cwh] [value | (expression) | symbol | string] ...", +" [-f struct-page.flags-mask] [-x count] -[cwh] " +" [value | (expression) | symbol | string] ...", " This command searches for a given value within a range of user virtual, kernel", " virtual, or physical memory space. If no end nor length value is entered, ", " then the search stops at the end of user virtual, kernel virtual, or physical", @@ -2849,6 +2850,11 @@ char *help_search[] = { " must be appropriate for the memory type specified.", " -l length Length in bytes of address range to search.", " -m mask Ignore the bits that are set in the hexadecimal mask value.", +" -f struct-page.flags-mask", +" Only search pages when page.flags & mask is true, or not true when", +" the mask is preceded by a letter n. When used multiple times, only", +" pages that meet all conditions will be searched. Only works for", +" virtual address space (either user or kernel).", " -c Search for character string values instead of unsigned longs. If", " the string contains any space(s), it must be encompassed by double", " quotes.", @@ -2986,6 +2992,9 @@ char *help_search[] = { " ffff8100399565a8: ffffffff80493d60 (anon_inode_inode)", " ffff81003a278cd0: ffffffff800649d6 (__down_interruptible+191)", " ffff81003cc23e08: ffffffff800649d6 (__down_interruptible+191)", +"\n Search kernel virtual address space for all instances of 0xdeadbeef", +" within compound (PG_head|tail) pages that are not LRU pages:\n", +" %s> search deadbeef -f c000 -f n20", NULL }; diff --git a/memory.c b/memory.c index 2208553..70649a2 100644 --- a/memory.c +++ b/memory.c @@ -77,6 +77,16 @@ struct meminfo { /* general purpose memory information structure */ }; /* + * Memory cache for struct page within range + * of kernel virtual address start and end. + */ +struct mem_map_cache { + ulong start; + ulong end; + char *cache; +}; + +/* * Search modes */ @@ -100,6 +110,9 @@ struct searchinfo { ulong vaddr_end; ulonglong paddr_start; ulonglong paddr_end; + int pg_nmasks; + char pg_mask_neg[MAXARGS]; + ulong pg_mask[MAXARGS]; union { /* default ulong search */ struct { @@ -136,7 +149,7 @@ static char *memtype_string(int, int); static char *error_handle_string(ulong); static void dump_mem_map(struct meminfo *); static void dump_mem_map_SPARSEMEM(struct meminfo *); -static void fill_mem_map_cache(ulong, ulong, char *); +static void fill_mem_map_cache(struct mem_map_cache *); static void page_flags_init(void); static int page_flags_init_from_pageflag_names(void); static int page_flags_init_from_pageflags_enum(void); @@ -4956,7 +4969,7 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) ulong i; long total_pages; int others, page_not_mapped, phys_not_mapped, page_mapping; - ulong pp, ppend; + ulong pp; physaddr_t phys, physend; ulong tmp, reserved, shared, slabs; ulong PG_reserved_flag; @@ -4970,12 +4983,12 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) char buf2[BUFSIZE]; char buf3[BUFSIZE]; char buf4[BUFSIZE]; - char *page_cache; char *pcache; ulong section, section_nr, nr_mem_sections, section_size; long buffersize; char *outputbuffer; int bufferindex; + struct mem_map_cache mmc; buffersize = 1024 * 1024; outputbuffer = GETBUF(buffersize + 512); @@ -5101,7 +5114,7 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) break; } - page_cache = GETBUF(SIZE(page) * PGMM_CACHED); + mmc.cache = GETBUF(SIZE(page) * PGMM_CACHED); done = FALSE; total_pages = 0; @@ -5166,23 +5179,23 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) i++, pp += SIZE(page), phys += PAGESIZE()) { if ((i % PGMM_CACHED) == 0) { - - ppend = pp + ((PGMM_CACHED-1) * SIZE(page)); + mmc.start = pp; + mmc.end = pp + ((PGMM_CACHED-1) * SIZE(page)); physend = phys + ((PGMM_CACHED-1) * PAGESIZE()); - if ((pg_spec && (mi->spec_addr > ppend)) || + if ((pg_spec && (mi->spec_addr > mmc.end)) || (phys_spec && (PHYSPAGEBASE(mi->spec_addr) > physend))) { i += (PGMM_CACHED-1); - pp = ppend; + pp = mmc.end; phys = physend; continue; } - fill_mem_map_cache(pp, ppend, page_cache); + fill_mem_map_cache(&mmc); } - pcache = page_cache + ((i%PGMM_CACHED) * SIZE(page)); + pcache = mmc.cache + ((i%PGMM_CACHED) * SIZE(page)); if (received_SIGINT()) restart(0); @@ -5417,7 +5430,7 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) } FREEBUF(outputbuffer); - FREEBUF(page_cache); + FREEBUF(mmc.cache); } static void @@ -5426,7 +5439,7 @@ dump_mem_map(struct meminfo *mi) long i, n; long total_pages; int others, page_not_mapped, phys_not_mapped, page_mapping; - ulong pp, ppend; + ulong pp; physaddr_t phys, physend; ulong tmp, reserved, shared, slabs; ulong PG_reserved_flag; @@ -5442,11 +5455,11 @@ dump_mem_map(struct meminfo *mi) char buf2[BUFSIZE]; char buf3[BUFSIZE]; char buf4[BUFSIZE]; - char *page_cache; char *pcache; long buffersize; char *outputbuffer; int bufferindex; + struct mem_map_cache mmc; buffersize = 1024 * 1024; outputbuffer = GETBUF(buffersize + 512); @@ -5577,7 +5590,7 @@ dump_mem_map(struct meminfo *mi) break; } - page_cache = GETBUF(SIZE(page) * PGMM_CACHED); + mmc.cache = GETBUF(SIZE(page) * PGMM_CACHED); done = FALSE; total_pages = 0; @@ -5604,22 +5617,23 @@ dump_mem_map(struct meminfo *mi) i++, pp += SIZE(page), phys += PAGESIZE()) { if ((i % PGMM_CACHED) == 0) { - ppend = pp + ((PGMM_CACHED-1) * SIZE(page)); + mmc.start = pp; + mmc.end = pp + ((PGMM_CACHED-1) * SIZE(page)); physend = phys + ((PGMM_CACHED-1) * PAGESIZE()); - if ((pg_spec && (mi->spec_addr > ppend)) || + if ((pg_spec && (mi->spec_addr > mmc.end)) || (phys_spec && (PHYSPAGEBASE(mi->spec_addr) > physend))) { i += (PGMM_CACHED-1); - pp = ppend; + pp = mmc.end; phys = physend; continue; } - fill_mem_map_cache(pp, ppend, page_cache); + fill_mem_map_cache(&mmc); } - pcache = page_cache + ((i%PGMM_CACHED) * SIZE(page)); + pcache = mmc.cache + ((i%PGMM_CACHED) * SIZE(page)); if (received_SIGINT()) restart(0); @@ -5855,7 +5869,7 @@ dump_mem_map(struct meminfo *mi) } FREEBUF(outputbuffer); - FREEBUF(page_cache); + FREEBUF(mmc.cache); } /* @@ -5866,7 +5880,7 @@ dump_mem_map(struct meminfo *mi) * that are currently mapped, leaving the unmapped ones just zeroed out. */ static void -fill_mem_map_cache(ulong pp, ulong ppend, char *page_cache) +fill_mem_map_cache(struct mem_map_cache *mmc) { long size, cnt; ulong addr; @@ -5875,7 +5889,7 @@ fill_mem_map_cache(ulong pp, ulong ppend, char *page_cache) /* * Try to read it in one fell swoop. */ - if (readmem(pp, KVADDR, page_cache, SIZE(page) * PGMM_CACHED, + if (readmem(mmc->start, KVADDR, mmc->cache, SIZE(page) * PGMM_CACHED, "page struct cache", RETURN_ON_ERROR|QUIET)) return; @@ -5884,8 +5898,8 @@ fill_mem_map_cache(ulong pp, ulong ppend, char *page_cache) * not a virtual mem_map. */ size = SIZE(page) * PGMM_CACHED; - addr = pp; - bufptr = page_cache; + addr = mmc->start; + bufptr = mmc->cache; while (size > 0) { /* @@ -5899,7 +5913,7 @@ fill_mem_map_cache(ulong pp, ulong ppend, char *page_cache) if (!readmem(addr, KVADDR, bufptr, size, "virtual page struct cache", RETURN_ON_ERROR|QUIET)) { BZERO(bufptr, size); - if (!(vt->flags & V_MEM_MAP) && ((addr+size) < ppend)) + if (!(vt->flags & V_MEM_MAP) && ((addr+size) < mmc->end)) error(WARNING, "mem_map[] from %lx to %lx not accessible\n", addr, addr+size); @@ -13500,7 +13514,7 @@ cmd_search(void) searchinfo.mode = SEARCH_ULONG; /* default search */ - while ((c = getopt(argcnt, args, "tl:ukKVps:e:v:m:hwcx:")) != EOF) { + while ((c = getopt(argcnt, args, "tl:ukKVps:e:v:m:f:hwcx:")) != EOF) { switch(c) { case 'u': @@ -13572,6 +13586,17 @@ cmd_search(void) error(FATAL, "invalid ending address: 0\n"); break; + case 'f': + if (searchinfo.pg_nmasks == MAXARGS) + break; + + c = *optarg == 'n'; + searchinfo.pg_mask_neg[searchinfo.pg_nmasks] = c; + searchinfo.pg_mask[searchinfo.pg_nmasks] = + htol(optarg + c, FAULT_ON_ERROR, NULL); + searchinfo.pg_nmasks++; + break; + case 'l': len = stol(optarg, FAULT_ON_ERROR, NULL); break; @@ -14409,6 +14434,42 @@ search_chars_p(ulong *bufptr, ulonglong addr_p, int longcnt, struct searchinfo * return addr_p; } +static int +skip_pages(struct searchinfo *si, struct mem_map_cache *mmc, ulong page, ulong *pp) +{ + int i; + ulong flags; + + if (page < mmc->start || page > mmc->end) { + mmc->start = page; + mmc->end = page + SIZE(page) * (PGMM_CACHED - 1); + fill_mem_map_cache(mmc); + } + + flags = ULONG(mmc->cache + page - mmc->start + OFFSET(page_flags)); + + for (i = 0; i < si->pg_nmasks; i++) { + if ((si->pg_mask_neg[i] && si->pg_mask[i] & flags) || + (!si->pg_mask_neg[i] && !(si->pg_mask[i] & flags))) + goto skip; + } + + if (CRASHDEBUG(4)) + fprintf(fp, "search page: struct %lx, vaddr %lx, flags %lx\n", + page, *pp, flags); + + return 0; + +skip: + if (CRASHDEBUG(5)) + fprintf(fp, "ignore page: struct %lx, vaddr %lx, flags %lx\n", + page, *pp, flags); + + *pp += PAGESIZE(); + + return 1; +} + static void search_virtual(struct searchinfo *si) { @@ -14420,6 +14481,7 @@ search_virtual(struct searchinfo *si) char *pagebuf; ulong pct, pages_read, pages_checked; time_t begin, finish; + struct mem_map_cache mmc; start = si->vaddr_start; end = si->vaddr_end; @@ -14427,6 +14489,10 @@ search_virtual(struct searchinfo *si) begin = finish = 0; pagebuf = GETBUF(PAGESIZE()); + if (si->pg_nmasks) { + mmc.start = mmc.end = 0; + mmc.cache = GETBUF(SIZE(page) * PGMM_CACHED); + } if (start & (sizeof(long)-1)) { start &= ~(sizeof(long)-1); @@ -14482,6 +14548,9 @@ search_virtual(struct searchinfo *si) break; } + if (si->pg_nmasks && skip_pages(si, &mmc, page, &pp)) + continue; + if (!readmem(paddr, PHYSADDR, pagebuf, PAGESIZE(), "search page", RETURN_ON_ERROR|QUIET)) { pp += PAGESIZE(); @@ -14536,6 +14605,8 @@ done: } FREEBUF(pagebuf); + if (si->pg_nmasks) + FREEBUF(mmc.cache); } -- 2.2.0.rc0.207.ga3a616c -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility