]> sourceware.org Git - systemtap.git/commitdiff
Fixed PR 11372 by removing (most) embedded-C from proc_mem.stp.
authorDavid Smith <dsmith@redhat.com>
Tue, 16 Mar 2010 20:47:36 +0000 (15:47 -0500)
committerDavid Smith <dsmith@redhat.com>
Tue, 16 Mar 2010 20:47:36 +0000 (15:47 -0500)
* tapset/proc_mem.stp: Tried to remove as much embedded-C as possible.
* tapset/atomic.stp: New file.
* testsuite/buildok/atomic.stp: New file.
* testsuite/systemtap.base/atomic.exp: Ditto.
* testsuite/systemtap.base/atomic_module.c: Ditto.
* testsuite/systemtap.base/atomic_module.makefile: Ditto.

tapset/atomic.stp [new file with mode: 0644]
tapset/proc_mem.stp
testsuite/buildok/atomic.stp [new file with mode: 0755]
testsuite/systemtap.base/atomic.exp [new file with mode: 0644]
testsuite/systemtap.base/atomic_module.c [new file with mode: 0644]
testsuite/systemtap.base/atomic_module.makefile [new file with mode: 0644]

diff --git a/tapset/atomic.stp b/tapset/atomic.stp
new file mode 100644 (file)
index 0000000..d058145
--- /dev/null
@@ -0,0 +1,19 @@
+// Atomic functions.
+// Copyright (C) 2010 Red Hat Inc.
+//
+// This file is part of systemtap, and is free software.  You can
+// redistribute it and/or modify it under the terms of the GNU General
+// Public License (GPL); either version 2, or (at your option) any
+// later version.
+
+function atomic_long_read:long(addr:long)
+%{ /* pure */
+       atomic_long_t *a = (atomic_long_t *)(long)THIS->addr;
+
+       /* We call deref() here to ensure the memory is valid to read.
+        * Note the result is thrown away, then we use the "real"
+        * atomic read function now that we know the address is safe. */
+       (void)deref(sizeof(*a), a);
+       THIS->__retvalue = atomic_long_read(a);
+       CATCH_DEREF_FAULT();
+%}
index cebc1550b773e5130da72a76bd6879405952363a..28bd13a752107d26a3e22b5bb76d5e0c29e140ca 100644 (file)
 #else
 #define _STP_PF_KTHREAD PF_KTHREAD
 #endif
-  /* Returns the mm for the current proc. Slightly paranoid. Only returns
-     if the task isn't starting, exiting or (coopted by) a kernel thread. */
-  static struct mm_struct *_stp_proc_mm(void)
-  {
-    if (current->flags & (_STP_PF_KTHREAD | PF_EXITING | PF_STARTING))
-      return NULL;
-    return current->mm;
-  }
+
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
 #include <linux/mm_types.h>
-static inline unsigned long k_get_mm_counter(struct mm_struct *mm, int member)
-{
-#if USE_SPLIT_PTLOCKS
-       return (unsigned long)atomic_long_read(&mm->rss_stat.count[member]);
 #else
-       return mm->rss_stat.count[member];
-#endif
-}
+/* Define our own mm types */
+enum {
+       MM_FILEPAGES,
+       MM_ANONPAGES
+};
 #endif
 %}
 
-function _stp_get_mm_counter_file_rss:long(mm:long)
-%(kernel_v >= "2.6.34" %?
-%{ /* pure */  /* unprivileged */
-  THIS->__retvalue =  k_get_mm_counter((struct mm_struct*)(unsigned long)THIS->mm, MM_FILEPAGES);
+/* Try to be slightly paranoid. Only returns 1 if the task isn't
+   starting, exiting or (coopted by) a kernel thread. */
+function _stp_valid_task:long(tsk:long)
+%{
+  struct task_struct *tsk = (struct task_struct *)(long)THIS->tsk;
+
+  THIS->__retvalue = 0;
+  if (tsk) {
+    unsigned int flags = kread(&(tsk->flags));
+
+    if (flags & ~(_STP_PF_KTHREAD | PF_EXITING | PF_STARTING))
+      THIS->__retvalue = 1;
+  }
+  CATCH_DEREF_FAULT();
 %}
-%:
+
+function _MM_FILEPAGES:long()
+%{ /* pure */ /* unprivileged */
+  THIS->__retvalue = MM_FILEPAGES;
+%}
+
+function _MM_ANONPAGES:long()
+%{ /* pure */ /* unprivileged */
+  THIS->__retvalue = MM_ANONPAGES;
+%}
+
+function _stp_get_mm_counter:long(mm:long, member:long)
 {
+%(kernel_v >= "2.6.34" %?
 %( CONFIG_NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS %?
-  return @cast(mm, "mm_struct", "kernel<linux/sched.h>")->_file_rss->counter;
+  val = atomic_long_read(&@cast(mm, "mm_struct", "kernel<linux/sched.h>")->rss_stat->count[member])
 %:
-  return @cast(mm, "mm_struct", "kernel<linux/sched.h>")->_file_rss;
+  val = @cast(mm, "mm_struct", "kernel<linux/sched.h>")->rss_stat->count[member]
 %)
-}
-%)
-
-function _stp_get_mm_counter_anon_rss(mm:long)
-%(kernel_v >= "2.6.34" %?
-%{ /* pure */  /* unprivileged */
-  THIS->__retvalue =  k_get_mm_counter((struct mm_struct*)(unsigned long)THIS->mm, MM_ANONPAGES);
-%}
+  if (val < 0)
+    return 0
+%:     /* kernel < 2.6.34 */
+  if (member == _MM_FILEPAGES()) {
+%( CONFIG_NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS %?
+    val = atomic_long_read(&@cast(mm, "mm_struct", "kernel<linux/sched.h>")->_file_rss)
 %:
-{
+    val = @cast(mm, "mm_struct", "kernel<linux/sched.h>")->_file_rss
+%)
+  }
+  else if (member == _MM_ANONPAGES()) {
 %( CONFIG_NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS %?
-  return @cast(mm, "mm_struct", "kernel<linux/sched.h>")->_anon_rss->counter;
+    val = atomic_long_read(&@cast(mm, "mm_struct", "kernel<linux/sched.h>")->_anon_rss)
 %:
-  return @cast(mm, "mm_struct", "kernel<linux/sched.h>")->_anon_rss;
+    val = @cast(mm, "mm_struct", "kernel<linux/sched.h>")->_anon_rss
 %)
-}
+  }
 %)
+  return val
+}
 
 /**
  * sfunction proc_mem_size - Total program virtual memory size in pages
@@ -81,13 +97,15 @@ function _stp_get_mm_counter_anon_rss(mm:long)
  * number of pages couldn't be retrieved.
  */
 function proc_mem_size:long ()
-%{ /* pure */ /* unprivileged */
-   struct mm_struct *mm = _stp_proc_mm ();
-   if (mm)
-     THIS->__retvalue = mm->total_vm;
-   else
-     THIS->__retvalue = 0;
-%}
+{
+   task = task_current()
+   if (_stp_valid_task(task)) {
+     mm = @cast(task, "task_struct", "kernel<linux/sched.h>")->mm
+     if (mm != 0)
+       return @cast(mm, "mm_struct", "kernel<linux/sched.h>")->total_vm
+   }
+   return 0
+}
 
 /**
  * sfunction proc_mem_size_pid - Total program virtual memory size in pages
@@ -100,14 +118,13 @@ function proc_mem_size:long ()
  */
 function proc_mem_size_pid:long (pid:long)
 {
-  task = pid2task(pid);
-  if (task != 0)
-    {
-      mm = @cast(task, "task_struct", "kernel<linux/sched.h>")->mm;
-      if (mm != 0)
-        return @cast(mm, "mm_struct", "kernel<linux/sched.h>")->total_vm;
-    }
-  return 0;
+  task = pid2task(pid)
+  if (_stp_valid_task(task)) {
+    mm = @cast(task, "task_struct", "kernel<linux/sched.h>")->mm
+    if (mm != 0)
+      return @cast(mm, "mm_struct", "kernel<linux/sched.h>")->total_vm
+  }
+  return 0
 }
 
 /**
@@ -118,19 +135,16 @@ function proc_mem_size_pid:long (pid:long)
  * pages couldn't be retrieved.
  */
 function proc_mem_rss:long ()
-%{ /* pure */ /* unprivileged */
-   struct mm_struct *mm = _stp_proc_mm ();
-   if (mm)
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
-     THIS->__retvalue = k_get_mm_counter(mm, MM_FILEPAGES)
-                         + k_get_mm_counter(mm, MM_ANONPAGES);
-#else
-     THIS->__retvalue = (get_mm_counter(mm, file_rss)
-                         + get_mm_counter(mm, anon_rss));
-#endif
-   else
-     THIS->__retvalue = 0;
-%}
+{
+  task = task_current()
+  if (_stp_valid_task(task)) {
+    mm = @cast(task, "task_struct", "kernel<linux/sched.h>")->mm
+    if (mm != 0)
+      return (_stp_get_mm_counter(mm, _MM_FILEPAGES())
+             + _stp_get_mm_counter(mm, _MM_ANONPAGES()))
+  }
+  return 0
+}
 
 /**
  * sfunction proc_mem_rss_pid - Program resident set size in pages
@@ -143,15 +157,14 @@ function proc_mem_rss:long ()
  */
 function proc_mem_rss_pid:long (pid:long)
 {
-  task = pid2task(pid);
-  if (task)
-    {
-      mm = @cast(task, "task_struct", "kernel<linux/sched.h>")->mm;
-      if (mm != 0)
-        return (_stp_get_mm_counter_file_rss (mm)
-                + _stp_get_mm_counter_anon_rss (mm));
-    }
-  return 0;
+  task = pid2task(pid)
+  if (_stp_valid_task(task)) {
+    mm = @cast(task, "task_struct", "kernel<linux/sched.h>")->mm
+    if (mm != 0)
+        return (_stp_get_mm_counter(mm, _MM_FILEPAGES())
+                + _stp_get_mm_counter(mm, _MM_ANONPAGES()))
+  }
+  return 0
 }
 
 /**
@@ -162,17 +175,15 @@ function proc_mem_rss_pid:long (pid:long)
  * number of pages couldn't be retrieved.
  */
 function proc_mem_shr:long ()
-%{ /* pure */ /* unprivileged */
-   struct mm_struct *mm = _stp_proc_mm ();
-   if (mm)
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
-     THIS->__retvalue = k_get_mm_counter(mm, MM_FILEPAGES);
-#else
-     THIS->__retvalue = get_mm_counter(mm, file_rss);
-#endif
-   else
-     THIS->__retvalue = 0;
-%}
+{
+  task = task_current()
+  if (_stp_valid_task(task)) {
+    mm = @cast(task, "task_struct", "kernel<linux/sched.h>")->mm
+    if (mm != 0)
+      return _stp_get_mm_counter(mm, _MM_FILEPAGES())
+  }
+  return 0
+}
 
 /**
  * sfunction proc_mem_shr_pid - Program shared pages (from shared mappings)
@@ -185,16 +196,23 @@ function proc_mem_shr:long ()
  */
 function proc_mem_shr_pid:long (pid:long)
 {
-  task = pid2task(pid);
-  if (task)
-    {
-      mm = @cast(task, "task_struct", "kernel<linux/sched.h>")->mm;
-      if (mm !=        0)
-        return _stp_get_mm_counter_file_rss (mm);
-    }
-  return 0;
+  task = pid2task(pid)
+  if (_stp_valid_task(task)) {
+    mm = @cast(task, "task_struct", "kernel<linux/sched.h>")->mm
+    if (mm != 0)
+      return _stp_get_mm_counter(mm, _MM_FILEPAGES())
+  }
+  return 0
 }
 
+function _stp_mem_txt_adjust:long (start_code:long, end_code:long)
+%{ /* pure */
+  unsigned long start_code = (unsigned long) THIS->start_code;
+  unsigned long end_code = (unsigned long) THIS->end_code;
+  THIS->__retvalue = (PAGE_ALIGN(end_code)
+                      - (start_code & PAGE_MASK)) >> PAGE_SHIFT;
+%}
+
 /**
  * sfunction proc_mem_txt - Program text (code) size in pages
  *
@@ -203,22 +221,18 @@ function proc_mem_shr_pid:long (pid:long)
  * couldn't be retrieved.
  */
 function proc_mem_txt:long ()
-%{ /* pure */ /* unprivileged */
-   struct mm_struct *mm = _stp_proc_mm ();
-   if (mm)
-     THIS->__retvalue = (PAGE_ALIGN(mm->end_code)
-                         - (mm->start_code & PAGE_MASK)) >> PAGE_SHIFT;
-   else
-     THIS->__retvalue = 0;
-%}
-
-function _stp_mem_txt_adjust:long (start_code:long, end_code:long)
-%{ /* pure */
-  unsigned long start_code = (unsigned long) THIS->start_code;
-  unsigned long end_code = (unsigned long) THIS->end_code;
-  THIS->__retvalue = (PAGE_ALIGN(end_code)
-                      - (start_code & PAGE_MASK)) >> PAGE_SHIFT;
-%}
+{
+  task = task_current()
+  if (_stp_valid_task(task)) {
+    mm = @cast(task, "task_struct", "kernel<linux/sched.h>")->mm
+    if (mm != 0) {
+      s = @cast(mm, "mm_struct", "kernel<linux/sched.h>")->start_code
+      e = @cast(mm, "mm_struct", "kernel<linux/sched.h>")->end_code
+      return _stp_mem_txt_adjust(s, e)
+    }
+  }
+  return 0
+}
 
 /**
  * sfunction proc_mem_txt_pid - Program text (code) size in pages
@@ -231,18 +245,16 @@ function _stp_mem_txt_adjust:long (start_code:long, end_code:long)
  */
 function proc_mem_txt_pid:long (pid:long)
 {
-  task = pid2task(pid);
-  if (task != 0)
-    {
-      mm = @cast(task, "task_struct", "kernel<linux/sched.h>")->mm;
-      if (mm != 0)
-        {
-          s = @cast(mm, "mm_struct", "kernel<linux/sched.h>")->start_code;
-          e = @cast(mm, "mm_struct", "kernel<linux/sched.h>")->end_code;
-          return _stp_mem_txt_adjust (s, e);
-        }
+  task = pid2task(pid)
+  if (_stp_valid_task(task)) {
+    mm = @cast(task, "task_struct", "kernel<linux/sched.h>")->mm
+    if (mm != 0) {
+      s = @cast(mm, "mm_struct", "kernel<linux/sched.h>")->start_code
+      e = @cast(mm, "mm_struct", "kernel<linux/sched.h>")->end_code
+      return _stp_mem_txt_adjust (s, e)
     }
-  return 0;
+  }
+  return 0
 }
 
 /**
@@ -253,13 +265,18 @@ function proc_mem_txt_pid:long (pid:long)
  * pages couldn't be retrieved.
  */
 function proc_mem_data:long ()
-%{ /* pure */ /* unprivileged */
-   struct mm_struct *mm = _stp_proc_mm ();
-   if (mm)
-     THIS->__retvalue = mm->total_vm - mm->shared_vm;
-   else
-     THIS->__retvalue = 0;
-%}
+{
+  task = task_current()
+  if (_stp_valid_task(task)) {
+    mm = @cast(task, "task_struct", "kernel<linux/sched.h>")->mm
+    if (mm != 0) {
+      t = @cast(mm, "mm_struct", "kernel<linux/sched.h>")->total_vm
+      s = @cast(mm, "mm_struct", "kernel<linux/sched.h>")->shared_vm
+      return (t - s)
+    }
+  }
+  return 0
+}
 
 /**
  * sfunction proc_mem_data_pid - Program data size (data + stack) in pages
@@ -272,18 +289,16 @@ function proc_mem_data:long ()
  */
 function proc_mem_data_pid:long (pid:long)
 {
-  task = pid2task(pid);
-  if (task != 0)
-    {
-      mm = @cast(task, "task_struct", "kernel<linux/sched.h>")->mm;
-      if (mm != 0)
-        {
-          t = @cast(mm, "mm_struct", "kernel<linux/sched.h>")->total_vm;
-          s = @cast(mm, "mm_struct", "kernel<linux/sched.h>")->shared_vm;
-          return t - s;
-        }
+  task = pid2task(pid)
+  if (_stp_valid_task(task)) {
+    mm = @cast(task, "task_struct", "kernel<linux/sched.h>")->mm
+    if (mm != 0) {
+      t = @cast(mm, "mm_struct", "kernel<linux/sched.h>")->total_vm
+      s = @cast(mm, "mm_struct", "kernel<linux/sched.h>")->shared_vm
+      return t - s
     }
-  return 0;
+  }
+  return 0
 }
 
 /**
diff --git a/testsuite/buildok/atomic.stp b/testsuite/buildok/atomic.stp
new file mode 100755 (executable)
index 0000000..0069045
--- /dev/null
@@ -0,0 +1,6 @@
+#! stap -p4
+
+probe begin {
+  printf("%d\n", atomic_long_read(0))
+  exit()
+}
diff --git a/testsuite/systemtap.base/atomic.exp b/testsuite/systemtap.base/atomic.exp
new file mode 100644 (file)
index 0000000..4b4fa58
--- /dev/null
@@ -0,0 +1,115 @@
+set test "atomic"
+
+if {![installtest_p]} {untested $test; return}
+
+set script_template {
+    probe begin {
+       print("systemtap starting probe\n")
+       exit()
+    }
+
+    probe end {
+       print("systemtap ending probe\n")
+       printf("%%d\n", atomic_long_read(%s))
+    }
+}
+
+# First try reading from address 0, which should fail.
+set test "atomic1"
+set error {kernel read fault at 0x[^\r]+}
+set script [format $script_template "0"]
+stap_run_error $test 1 $error "" -e $script
+
+# Try reading from address -1 (top of memory), which should fail.
+set test "atomic2"
+set script [format $script_template "-1"]
+stap_run_error $test 1 $error "" -e $script
+
+# Try reading from address 3, which should fail (if nothing else
+# because it isn't aligned properly).
+set test "atomic3"
+set script [format $script_template "3"]
+stap_run_error $test 1 $error "" -e $script
+
+
+set build_dir ""
+
+proc cleanup_module {} {
+    global build_dir
+    as_root [list /sbin/rmmod atomic_module]
+    catch { exec rm -rf $build_dir }
+}
+
+proc build_and_install_module {} {
+    global build_dir
+    global srcdir subdir
+
+    # Create the build directory and populate it
+    if {[catch {exec mktemp -d staptestXXXXXX} build_dir]} {
+       verbose -log "Failed to create temporary directory: $build_dir"
+       return 0
+    }
+    exec cp $srcdir/$subdir/atomic_module.c $build_dir/
+    exec cp -p $srcdir/$subdir/atomic_module.makefile $build_dir/Makefile
+
+    # Build the module
+    if {[catch {exec make -C $build_dir clean} res]} {
+       verbose -log "$res"
+       return 0
+    }
+    catch {exec make -C $build_dir} res
+    if {![file exists $build_dir/atomic_module.ko]} {
+       verbose -log "$res"
+       return 0
+    }
+
+    # Install the module
+    set res [as_root [list /sbin/insmod $build_dir/atomic_module.ko]]
+    if {$res != 0} {
+       return 0
+    }
+
+    return 1
+}
+
+set test "atomic_module_build"
+if {[build_and_install_module] == 0} {
+    verbose -log "BUILD FAILED"
+    fail "$test - could not build/install module"
+    cleanup_module
+    return
+} else {
+    pass $test
+}
+
+set script_module_template {
+    function get_atomic_addr:long()
+    %%{
+       extern atomic_long_t *stp_get_atomic_long_addr(void);
+       atomic_long_t *a = stp_get_atomic_long_addr();
+       THIS->__retvalue = (long)a;
+    %%}
+
+    probe begin {
+       print("systemtap starting probe\n")
+       exit()
+    }
+
+    probe end {
+       print("systemtap ending probe\n")
+       printf("%%d\n", atomic_long_read(get_atomic_addr() + %s))
+    }
+}
+
+set test "atomic4"
+set script [format $script_module_template "0"]
+stap_run_error $test 0 $error "5\r\n" -ge $script
+
+# We should be able to check for trying to read the atomic_long_t with
+# bad alignment here, but it succeeds on {x86, x86_64} and fails on
+# ia64.  Since it doesn't fail consistently, we'll comment this out.
+#set test "atomic5"
+#set script [format $script_module_template "3"]
+#stap_run_error $test 1 $error "" -ge $script
+
+cleanup_module
diff --git a/testsuite/systemtap.base/atomic_module.c b/testsuite/systemtap.base/atomic_module.c
new file mode 100644 (file)
index 0000000..5b4e395
--- /dev/null
@@ -0,0 +1,50 @@
+/* -*- linux-c -*- 
+ * Systemtap Atomic Test Module
+ * Copyright (C) 2010 Red Hat Inc.
+ *
+ * This file is part of systemtap, and is free software.  You can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License (GPL); either version 2, or (at your option) any
+ * later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/atomic.h>
+
+/* The purpose of this module is to provide a bunch of functions that */
+/* do nothing important, and then call them in different contexts. */
+/* We use a /proc file to trigger function calls from user context. */
+/* Then systemtap scripts set probes on the functions and run tests */
+/* to see if the expected output is received. This is better than using */
+/* the kernel because kernel internals frequently change. */
+
+
+/************ Below are the functions to create this module ************/
+
+struct {
+       ulong barrier1;
+       atomic_long_t a;
+       ulong barrier2;
+} stp_atomic_struct;
+
+atomic_long_t *stp_get_atomic_long_addr(void)
+{
+       return(&stp_atomic_struct.a);
+}
+EXPORT_SYMBOL(stp_get_atomic_long_addr);
+
+int init_module(void)
+{
+       stp_atomic_struct.barrier1 = ULONG_MAX;
+       atomic_long_set(&stp_atomic_struct.a, 5);
+        stp_atomic_struct.barrier2 = ULONG_MAX;
+       return 0;
+}
+
+void cleanup_module(void)
+{
+}
+
+MODULE_DESCRIPTION("systemtap atomic test module");
+MODULE_LICENSE("GPL");
diff --git a/testsuite/systemtap.base/atomic_module.makefile b/testsuite/systemtap.base/atomic_module.makefile
new file mode 100644 (file)
index 0000000..14d2b8e
--- /dev/null
@@ -0,0 +1,13 @@
+obj-m := atomic_module.o
+KDIR := /lib/modules/$(shell uname -r)/build
+PWD := $(shell pwd)
+
+CLEAN_FILES := $(shell echo *.mod.c *.ko *.o .*.cmd *~ *.sgn)
+CLEAN_FILES += Module.markers modules.order Module.symvers
+CLEAN_DIRS  := .tmp_versions
+
+default:
+       $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
+clean:
+       rm -f $(CLEAN_FILES)
+       rm -rf $(CLEAN_DIRS)
This page took 0.04401 seconds and 5 git commands to generate.