]> sourceware.org Git - systemtap.git/commitdiff
PR10410: dentry tapset, autofs4 sample
authorJeff Moyer <jmoyer@redhat.com>
Fri, 17 Jul 2009 19:19:26 +0000 (15:19 -0400)
committerFrank Ch. Eigler <fche@elastic.org>
Fri, 17 Jul 2009 19:19:26 +0000 (15:19 -0400)
* tapset/dentry.stp: New d_path, d_name, reverse_path_walk.
* .../examples/.../autofs4.*: New autofs demo.

Signed-off-by: Frank Ch. Eigler <fche@elastic.org>
doc/SystemTap_Tapset_Reference/tapsets.tmpl
tapset/dentry.stp [new file with mode: 0644]
testsuite/systemtap.examples/network/autofs4.meta [new file with mode: 0644]
testsuite/systemtap.examples/network/autofs4.stp [new file with mode: 0644]

index 835d030970cb869d9d5b67fed796d540c148940b..7e9d47845e0e519c5179c914410981b64db0900b 100644 (file)
     </para>
 !Itapset/signal.stp
   </chapter>
-
+  <chapter id="dentry.stp">
+    <title>Directory-entry (dentry) Tapset</title>
+    <para>
+      This family of functions is used to map kernel VFS
+      directory entriy pointers to file or full path names.
+    </para>
+!Itapset/dentry.stp
+    </chapter>
 </book>
diff --git a/tapset/dentry.stp b/tapset/dentry.stp
new file mode 100644 (file)
index 0000000..af8a866
--- /dev/null
@@ -0,0 +1,117 @@
+// dentry tapset
+// Copyright (c) 2009 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 __dentry_IS_ROOT:long(dentry:long)
+{
+        return (@cast(dentry, "dentry")->d_parent == dentry)
+}
+
+
+function __dentry_prepend:string(dentry:long,name:string)
+{
+        dname = d_name(dentry)
+
+        /*
+         * In case we are following down a mount point trigger, we can get
+         * multiple instances of a root mount.
+         */
+        c = substr(name, strlen(name)-1, strlen(name)-1)
+        if (dname == "/" && c == "/")
+                return name;
+
+        return sprintf("%s/%s", dname, name);
+}
+
+
+
+%{
+#include <linux/sched.h>
+#include <linux/fs_struct.h>
+%}
+
+
+function __dentry_get_current_root:long()
+%{
+        THIS->__retvalue = (long)&current->fs->root;
+%}
+
+
+
+
+/**
+ *   sfunction d_name - get the dirent name
+ *
+ *   Returns the dirent name (path basename).
+ *   @dentry: Pointer to dentry.
+ */
+function d_name:string(dentry:long)
+{
+        len = @cast(dentry, "dentry")->d_name->len;
+        return kernel_string_n(@cast(dentry, "dentry")->d_name->name, len);
+}
+
+
+
+/**
+ *   sfunction reverse_path_walk - get the full dirent path
+ *
+ *   Returns the path name (partial path to mount point).
+ *   @dentry: Pointer to dentry.
+ */
+function reverse_path_walk:string(dentry:long)
+{
+        while(1) {
+                name = __dentry_prepend(dentry, name);
+                dentry = @cast(dentry, "dentry")->d_parent;
+                if (__dentry_IS_ROOT(dentry))
+                        return name;
+        }
+}
+
+
+
+/**
+ *   sfunction d_path - get the full nameidata path
+ *
+ *   Returns the full dirent name (full path to the root), like
+ *   the kernel d_path function.
+ *   @nd: Pointer to nameidata.
+ */
+function d_path:string(nd:long)
+{
+        root = __dentry_get_current_root()
+        dentry = %( kernel_vr < "2.6.25"
+                 %? @cast(nd,"nameidata")->dentry
+                 %: @cast(nd,"nameidata")->path->dentry 
+                 %)
+        vfsmnt = %( kernel_vr < "2.6.25"
+                 %? @cast(nd,"nameidata")->mnt
+                 %: @cast(nd,"nameidata")->path->mnt 
+                 %)
+        while (1) {
+                if (dentry == @cast(root, "path")->dentry &&
+                    vfsmnt == @cast(root, "path")->mnt)
+                        break;
+
+                if (dentry == @cast(vfsmnt, "vfsmount")->mnt_root ||
+                    __dentry_IS_ROOT(dentry)) {
+                        /* Global root? */
+                        if (@cast(vfsmnt, "vfsmount")->mnt_parent == vfsmnt)
+                                return sprintf("/%s", name);
+
+                        dentry = @cast(vfsmnt, "vfsmount")->mnt_mountpoint;
+                        vfsmnt = @cast(vfsmnt, "vfsmount")->mnt_parent;
+                        continue;
+                }
+                name = __dentry_prepend(dentry, name);
+                dentry = @cast(dentry, "dentry")->d_parent;
+        }
+
+        return sprintf("/%s", name);
+}
diff --git a/testsuite/systemtap.examples/network/autofs4.meta b/testsuite/systemtap.examples/network/autofs4.meta
new file mode 100644 (file)
index 0000000..16ae729
--- /dev/null
@@ -0,0 +1,8 @@
+title: Watch autofs4 operations
+description: Trace key autofs4 operations such as mounting or unmounting remote filesystems.
+name: autofs4.stp
+author: Jeff Moyer
+keywords: network autofs nfs
+subsystem: network
+test_check: stap -p4 autofs4.stp
+test_installcheck: stap autofs4.stp -c "sleep 10"
diff --git a/testsuite/systemtap.examples/network/autofs4.stp b/testsuite/systemtap.examples/network/autofs4.stp
new file mode 100644 (file)
index 0000000..19a27ee
--- /dev/null
@@ -0,0 +1,94 @@
+#! /usr/bin/env stap
+
+// Copyright (c) 2009 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.
+
+
+probe module("autofs4").function("autofs4_lookup")
+{
+        /*
+         * Don't log automounts travels in its own directory hierarchy, as
+         * they are treated differently, and certainly not something that is
+         * useful for admins to see.
+         */
+        if (!isinstr(execname(), "automount")) {
+                printf("%s process %s[%d] looking up %s%s\n",
+                       ctime(gettimeofday_s()), execname(), pid(),
+                       d_path($nd), d_name($dentry));
+        }
+}
+
+
+probe module("autofs4").function("autofs4_follow_link")
+{
+        if (!isinstr(execname(), "automount")) {
+                /*
+                 * dentry->d_name will be '/' for the mount trigger.  Thus,
+                 * the path that the trigger lives on is one level up the
+                 * directory stack, and the root of that is yet another level
+                 * up.
+                 */
+                printf("%s process %s[%d] following mount trigger %s\n",
+                       ctime(gettimeofday_s()), execname(), pid(),
+                       d_path($nd));
+        }
+}
+
+
+/*
+probe module("autofs4").function("autofs4_expire_direct").return
+{
+        if ($return != 0) {
+                relative_path = reverse_path_walk($mnt->mnt_mountpoint)
+                root_path = reverse_path_walk($mnt->mnt_parent->mnt_mountpoint)
+                printf("%s process %s[%d] expiring direct mount /%s/%s\n",
+                       ctime(gettimeofday_s()), execname(), pid(),
+                       root_path, relative_path)
+        }
+}
+
+probe
+module("autofs4").statement("autofs4_expire_direct@fs/autofs4/expire.c+17") ?
+{
+        relative_path = reverse_path_walk($mnt->mnt_mountpoint)
+        root_path = reverse_path_walk($mnt->mnt_parent->mnt_mountpoint)
+        printf("%s process %s[%d] expiring direct mount /%s/%s\n",
+               ctime(gettimeofday_s()), execname(), pid(),
+               root_path, relative_path)
+}
+*/
+
+probe module("autofs4").function("autofs4_expire_indirect").return
+{
+        if ($return != 0) {
+                relative_path = reverse_path_walk($return)
+                root_path = reverse_path_walk($mnt->mnt_mountpoint)
+                printf("%s process %s[%d] expiring indirect mount /%s%s\n",
+                       ctime(gettimeofday_s()), execname(), pid(),
+                       root_path, relative_path)
+        }
+}
+
+
+/*
+ * The struct dentry's name may be '/' if this is a mount trigger, which
+ * is not really something that is useful to print out.  Instead, we just
+ * indicate whether a mount or umount succeeded or failed.  Coupled with the
+ * messages printed out when looking up a directory and traversing a symlink,
+ * this should be relatively easy to correlate to the appropriate directory.
+ */
+probe module("autofs4").function("autofs4_wait").return
+{
+        if ($notify > 0) {
+                dname = d_name($dentry)
+                printf("%s %s of %s %s\n",
+                       ctime(gettimeofday_s()),
+                       ($notify==1?"mount":"unmount"),
+                       dname,
+                       $return == 0?"succeeded":"failed")
+        }
+}
This page took 0.032035 seconds and 5 git commands to generate.