Re: About displaying virtual memory information of exiting task

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 12/06/2014 04:11 AM, Dave Anderson wrote:
Interestingly enough, today I was asked to look at a vmcore in which an oops
occurred during task exit after tsk->mm had been NULL'd out in exit_mm():

It almost matches what I am facing, when tsk->mm is set to NULL and memory
mapping is supposed to be displayed. This is a more simple implementation.
I have tried to command like vm [taskp | pid | [-M mm_struct]]. But it have
to modify a lot of thing.

By the way, I feel the code is becoming more and more complicated, maybe a
reconstruction is needed.


Of course it has its limitations.  Since the page tables are being broken down in this case,
"vm -p" fails:

  crash>  vm -M ffff880495120dc0 -p
   PID: 4563   TASK: ffff88049863f500  CPU: 8   COMMAND: "postgres"
          MM               PGD          RSS    TOTAL_VM
          0                 0            0k       0k
         VMA           START       END     FLAGS FILE
   ffff8804a085ce90     400000     f56000 8001875 /usr/local/greenplum-db-4.3.3.1/bin/postgres
   VIRTUAL     PHYSICAL
   vm: invalid kernel virtual address: 50  type: "mm_struct pgd"
   crash>

After a glance, the pgd comes from the mm of task_struct. We need a lot of work to make it
replaced by argument of -M, I don't think it worse it right now.


But it does seems like a worthwhile addition.

The patch doesn't check whether mm->owner or mm->mm_count are legitimate, but I'm not
sure whether it's even worth it?  If it fails, it fails, and the help page should just
indicate that the command option is not guaranteed to work.  Does the attached patch work
for you?

Similar to the core I got. And I modified the patch to add some check. At least I think
we need to make sure the address still belongs to a mm_struct object.

--
Regards
Qiao Nuohan
diff --git a/defs.h b/defs.h
index 2e52bc4..e2e2277 100755
--- a/defs.h
+++ b/defs.h
@@ -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 */
@@ -1923,6 +1924,7 @@ struct offset_table {                    /* stash of commonly-used offsets */
 	long kernfs_node_parent;
 	long kmem_cache_cpu_partial;
 	long kmem_cache_cpu_cache;
+	long mm_struct_mm_users;
 };
 
 struct size_table {         /* stash of commonly-used sizes */
diff --git a/main.c b/main.c
index d16ef12..c4ed229 100755
--- a/main.c
+++ b/main.c
@@ -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);
diff --git a/memory.c b/memory.c
index 3ac928d..7493110 100755
--- a/memory.c
+++ b/memory.c
@@ -357,6 +357,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_users, "mm_struct", "mm_users");
         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");
@@ -3302,9 +3303,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++;
@@ -3594,6 +3600,29 @@ get_vm_flags(char *vma_buf)
 	return vm_flags;
 }
 
+static int
+is_valid_mm(ulong mm)
+{
+	char kbuf[BUFSIZE];
+	char *p;
+	int mm_users;
+
+	if (!(p = vaddr_to_kmem_cache(mm, kbuf, VERBOSE)))
+		goto bailout;
+
+	if (!STRNEQ(p, "mm_struct"))
+		goto bailout;
+
+	readmem(mm + OFFSET(mm_struct_mm_users), KVADDR, &mm_users, sizeof(int),
+		"mm_struct mm_users", FAULT_ON_ERROR);
+
+	return mm_users;
+
+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
@@ -3726,8 +3755,14 @@ 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) {
+			tm->mm_struct_addr = pc->curcmd_private;
+			if (!is_valid_mm(tm->mm_struct_addr))
+				return (ulong)NULL;
+		} else
+                	return (ulong)NULL;
+	}
 
 	if (flag & PRINT_MM_STRUCT) {
 		dump_struct("mm_struct", tm->mm_struct_addr, radix);
--
Crash-utility mailing list
Crash-utility@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/crash-utility

[Index of Archives]     [Fedora Development]     [Fedora Desktop]     [Fedora SELinux]     [Yosemite News]     [KDE Users]     [Fedora Tools]

 

Powered by Linux