Skip to content

Commit

Permalink
Added a new "vm -M <mm_struct>" option. When a task is exiting,
Browse files Browse the repository at this point in the history
the mm_struct address pointer in its task_struct is NULL'd out, and
as a result, the "vm" command looks like this:

  crash> vm
  PID: 4563   TASK: ffff88049863f500  CPU: 8   COMMAND: "postgres"
         MM               PGD          RSS    TOTAL_VM
         0                 0            0k       0k

However, the mm_struct address can be retrieved from the task's
kernel stack and entered manually with this option, which allows the
"vm" command to attempt to dump the virtual memory data of the task.
It may, or may not, work, depending upon how far the virtual memory
deconstruction has proceeded.  This option only verifies that the
address entered is from the "mm_struct" slab cache, and that
its mm_struct.mm_count is non-zero.
(qiaonuohan@cn.fujitsu.com, anderson@redhat.com)
  • Loading branch information
Dave Anderson committed Dec 11, 2014
1 parent 8b2cb36 commit 361bdc2
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 7 deletions.
2 changes: 2 additions & 0 deletions defs.h
Expand Up @@ -464,6 +464,7 @@ struct program_context {
#define MEMTYPE_KVADDR (0x2000)
#define MOD_SECTIONS (0x4000)
#define MOD_READNOW (0x8000)
#define MM_STRUCT_FORCE (0x10000)
ulonglong curcmd_private; /* general purpose per-command info */
int cur_gdb_cmd; /* current gdb command */
int last_gdb_cmd; /* previously-executed gdb command */
Expand Down Expand Up @@ -1926,6 +1927,7 @@ struct offset_table { /* stash of commonly-used offsets */
long nsproxy_net_ns;
long atomic_t_counter;
long percpu_counter_count;
long mm_struct_mm_count;
};

struct size_table { /* stash of commonly-used sizes */
Expand Down
13 changes: 9 additions & 4 deletions help.c
Expand Up @@ -3776,8 +3776,8 @@ NULL
char *help_vm[] = {
"vm",
"virtual memory",
"[-p | -P vmaddr | -v | -m | -x | -d | [-R reference] | [-f vm_flags]]"
"\n [pid | taskp] ... ",
"[-p | -P vma | -M mm | -v | -m | -x | -d | [-R reference] [pid | task]]"
"\n [-f vm_flags]",
" This command displays basic virtual memory information of a context,",
" consisting of a pointer to its mm_struct and page dirctory, its RSS and ",
" total virtual memory size; and a list of pointers to each vm_area_struct,",
Expand All @@ -3793,8 +3793,13 @@ char *help_vm[] = {
" -p translate each virtual page to its physical address, or if",
" the page is not mapped, its swap device and offset, or",
" filename and offset.",
" -P vmaddr similar to -p, but only translate the pages belonging to the",
" -P vma similar to -p, but only translate the pages belonging to the",
" specified VM area of a context.",
" -M mm if the mm_struct address has been removed from the task_struct",
" of an exiting task, the virtual memory data cannot be displayed.",
" However, if the address can be determined from the kernel stack,",
" it can be entered manually in order to try to resurrect the",
" virtual memory data of the task.",
" -R reference search for references to this number or filename.",
" -m dump the mm_struct assocated with the task.",
" -v dump all of the vm_area_structs associated with the task.",
Expand All @@ -3804,7 +3809,7 @@ char *help_vm[] = {
" with decimal format.",
" -f vm_flags translate the bits of a FLAGS (vm_flags) value.",
" pid a process PID.",
" taskp a hexadecimal task_struct pointer.",
" task a hexadecimal task_struct pointer.",
"\nEXAMPLES",
" Display the virtual memory data of the current context:\n",
" %s> vm",
Expand Down
2 changes: 2 additions & 0 deletions main.c
Expand Up @@ -1606,6 +1606,8 @@ dump_program_context(void)
fprintf(fp, "%sMOD_SECTIONS", others ? "|" : "");
if (pc->curcmd_flags & MOD_READNOW)
fprintf(fp, "%sMOD_READNOW", others ? "|" : "");
if (pc->curcmd_flags & MM_STRUCT_FORCE)
fprintf(fp, "%sMM_STRUCT_FORCE", others ? "|" : "");
fprintf(fp, ")\n");
fprintf(fp, " curcmd_private: %llx\n", pc->curcmd_private);
fprintf(fp, " cmd_cleanup: %lx\n", (ulong)pc->cmd_cleanup);
Expand Down
64 changes: 61 additions & 3 deletions memory.c
Expand Up @@ -358,6 +358,7 @@ vm_init(void)
}
MEMBER_OFFSET_INIT(mm_struct_total_vm, "mm_struct", "total_vm");
MEMBER_OFFSET_INIT(mm_struct_start_code, "mm_struct", "start_code");
MEMBER_OFFSET_INIT(mm_struct_mm_count, "mm_struct", "mm_count");
MEMBER_OFFSET_INIT(vm_area_struct_vm_mm, "vm_area_struct", "vm_mm");
MEMBER_OFFSET_INIT(vm_area_struct_vm_next, "vm_area_struct", "vm_next");
MEMBER_OFFSET_INIT(vm_area_struct_vm_end, "vm_area_struct", "vm_end");
Expand Down Expand Up @@ -3311,9 +3312,14 @@ cmd_vm(void)
ref = NULL;
BZERO(&reference, sizeof(struct reference));

while ((c = getopt(argcnt, args, "f:pmvR:P:xd")) != EOF) {
while ((c = getopt(argcnt, args, "f:pmvR:P:xdM:")) != EOF) {
switch(c)
{
case 'M':
pc->curcmd_private = htoll(optarg, FAULT_ON_ERROR, NULL);
pc->curcmd_flags |= MM_STRUCT_FORCE;
break;

case 'f':
if (flag)
argerrs++;
Expand Down Expand Up @@ -3603,6 +3609,44 @@ get_vm_flags(char *vma_buf)
return vm_flags;
}

static void
vm_cleanup(void *arg)
{
struct task_context *tc;

pc->cmd_cleanup = NULL;
pc->cmd_cleanup_arg = NULL;

tc = (struct task_context *)arg;
tc->mm_struct = 0;
}

static int
is_valid_mm(ulong mm)
{
char kbuf[BUFSIZE];
char *p;
int mm_count;

if (!(p = vaddr_to_kmem_cache(mm, kbuf, VERBOSE)))
goto bailout;

if (!STRNEQ(p, "mm_struct"))
goto bailout;

readmem(mm + OFFSET(mm_struct_mm_count), KVADDR, &mm_count, sizeof(int),
"mm_struct mm_count", FAULT_ON_ERROR);

if (mm_count == 0)
error(FATAL, "stale mm_struct address\n");

return mm_count;

bailout:
error(FATAL, "invalid mm_struct address\n");
return 0;
}

/*
* vm_area_dump() primarily does the work for cmd_vm(), but is also called
* from IN_TASK_VMA(), do_vtop(), and foreach(). How it behaves depends
Expand Down Expand Up @@ -3735,8 +3779,22 @@ vm_area_dump(ulong task, ulong flag, ulong vaddr, struct reference *ref)
!DO_REF_SEARCH(ref))
PRINT_VM_DATA();

if (!tm->mm_struct_addr)
return (ulong)NULL;
if (!tm->mm_struct_addr) {
if (pc->curcmd_flags & MM_STRUCT_FORCE) {
if (!is_valid_mm(pc->curcmd_private))
return (ulong)NULL;

tc->mm_struct = tm->mm_struct_addr = pc->curcmd_private;

/*
* tc->mm_struct is changed, use vm_cleanup to
* restore it.
*/
pc->cmd_cleanup_arg = (void *)tc;
pc->cmd_cleanup = vm_cleanup;
} else
return (ulong)NULL;
}

if (flag & PRINT_MM_STRUCT) {
dump_struct("mm_struct", tm->mm_struct_addr, radix);
Expand Down
2 changes: 2 additions & 0 deletions symbols.c
Expand Up @@ -8079,6 +8079,8 @@ dump_offset_table(char *spec, ulong makestruct)
OFFSET(mm_struct_mmap));
fprintf(fp, " mm_struct_pgd: %ld\n",
OFFSET(mm_struct_pgd));
fprintf(fp, " mm_struct_mm_count: %ld\n",
OFFSET(mm_struct_mm_count));
fprintf(fp, " mm_struct_rss: %ld\n",
OFFSET(mm_struct_rss));
fprintf(fp, " mm_struct_anon_rss: %ld\n",
Expand Down

0 comments on commit 361bdc2

Please sign in to comment.