* 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>
</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>
--- /dev/null
+// 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)¤t->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);
+}
--- /dev/null
+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"
--- /dev/null
+#! /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")
+ }
+}