[PATCH] oprofile: report anonymous region samples

The below patch passes samples from anonymous regions to userspace instead
of just dropping them.  This provides the support needed for reporting
anonymous-region code samples (today: basic accumulated results; later:
Java and other dynamically compiled code).

As this changes the format, an upgrade to the just-released 0.9 release of
the userspace tools is required.

This patch is based upon an earlier one by Will Cohen <wcohen@redhat.com>

Signed-off-by: John Levon <levon@movementarian.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
diff --git a/Documentation/Changes b/Documentation/Changes
index 57542bc..b376007 100644
--- a/Documentation/Changes
+++ b/Documentation/Changes
@@ -63,7 +63,7 @@
 o  isdn4k-utils           3.1pre1                 # isdnctrl 2>&1|grep version
 o  nfs-utils              1.0.5                   # showmount --version
 o  procps                 3.2.0                   # ps --version
-o  oprofile               0.5.3                   # oprofiled --version
+o  oprofile               0.9                     # oprofiled --version
 
 Kernel compilation
 ==================
diff --git a/Documentation/basic_profiling.txt b/Documentation/basic_profiling.txt
index 65e3dc2..8764e9f 100644
--- a/Documentation/basic_profiling.txt
+++ b/Documentation/basic_profiling.txt
@@ -27,9 +27,13 @@
 
 Oprofile
 --------
-Get the source (I use 0.8) from http://oprofile.sourceforge.net/
-and add "idle=poll" to the kernel command line
+
+Get the source (see Changes for required version) from
+http://oprofile.sourceforge.net/ and add "idle=poll" to the kernel command
+line.
+
 Configure with CONFIG_PROFILING=y and CONFIG_OPROFILE=y & reboot on new kernel
+
 ./configure --with-kernel-support
 make install
 
@@ -46,7 +50,7 @@
 stop		opcontrol --stop
 dump output	opreport >  output_file
 
-To only report on the kernel, run opreport /boot/vmlinux > output_file
+To only report on the kernel, run opreport -l /boot/vmlinux > output_file
 
 A reset is needed to clear old statistics, which survive a reboot.
 
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
index 745a141..531b073 100644
--- a/drivers/oprofile/buffer_sync.c
+++ b/drivers/oprofile/buffer_sync.c
@@ -206,7 +206,7 @@
  */
 static unsigned long get_exec_dcookie(struct mm_struct * mm)
 {
-	unsigned long cookie = 0;
+	unsigned long cookie = NO_COOKIE;
 	struct vm_area_struct * vma;
  
 	if (!mm)
@@ -234,35 +234,42 @@
  */
 static unsigned long lookup_dcookie(struct mm_struct * mm, unsigned long addr, off_t * offset)
 {
-	unsigned long cookie = 0;
+	unsigned long cookie = NO_COOKIE;
 	struct vm_area_struct * vma;
 
 	for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) {
  
-		if (!vma->vm_file)
-			continue;
-
 		if (addr < vma->vm_start || addr >= vma->vm_end)
 			continue;
 
-		cookie = fast_get_dcookie(vma->vm_file->f_dentry,
-			vma->vm_file->f_vfsmnt);
-		*offset = (vma->vm_pgoff << PAGE_SHIFT) + addr - vma->vm_start; 
+		if (vma->vm_file) {
+			cookie = fast_get_dcookie(vma->vm_file->f_dentry,
+				vma->vm_file->f_vfsmnt);
+			*offset = (vma->vm_pgoff << PAGE_SHIFT) + addr -
+				vma->vm_start;
+		} else {
+			/* must be an anonymous map */
+			*offset = addr;
+		}
+
 		break;
 	}
 
+	if (!vma)
+		cookie = INVALID_COOKIE;
+
 	return cookie;
 }
 
 
-static unsigned long last_cookie = ~0UL;
+static unsigned long last_cookie = INVALID_COOKIE;
  
 static void add_cpu_switch(int i)
 {
 	add_event_entry(ESCAPE_CODE);
 	add_event_entry(CPU_SWITCH_CODE);
 	add_event_entry(i);
-	last_cookie = ~0UL;
+	last_cookie = INVALID_COOKIE;
 }
 
 static void add_kernel_ctx_switch(unsigned int in_kernel)
@@ -317,7 +324,7 @@
  
  	cookie = lookup_dcookie(mm, s->eip, &offset);
  
-	if (!cookie) {
+	if (cookie == INVALID_COOKIE) {
 		atomic_inc(&oprofile_stats.sample_lost_no_mapping);
 		return 0;
 	}
diff --git a/drivers/oprofile/event_buffer.h b/drivers/oprofile/event_buffer.h
index 442aaad..0180236 100644
--- a/drivers/oprofile/event_buffer.h
+++ b/drivers/oprofile/event_buffer.h
@@ -35,6 +35,9 @@
 #define TRACE_BEGIN_CODE		8
 #define TRACE_END_CODE			9
  
+#define INVALID_COOKIE ~0UL
+#define NO_COOKIE 0UL
+
 /* add data to the event buffer */
 void add_event_entry(unsigned long data);