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
[email protected]
https://www.redhat.com/mailman/listinfo/crash-utility

Reply via email to