From: Jeff Moyer Date: Fri, 17 Jul 2009 19:19:26 +0000 (-0400) Subject: PR10410: dentry tapset, autofs4 sample X-Git-Tag: release-0.9.9~67 X-Git-Url: https://sourceware.org/git/?a=commitdiff_plain;h=003ea323310bd597c7263344cefd232377d8d89e;p=systemtap.git PR10410: dentry tapset, autofs4 sample * tapset/dentry.stp: New d_path, d_name, reverse_path_walk. * .../examples/.../autofs4.*: New autofs demo. Signed-off-by: Frank Ch. Eigler --- diff --git a/doc/SystemTap_Tapset_Reference/tapsets.tmpl b/doc/SystemTap_Tapset_Reference/tapsets.tmpl index 835d03097..7e9d47845 100644 --- a/doc/SystemTap_Tapset_Reference/tapsets.tmpl +++ b/doc/SystemTap_Tapset_Reference/tapsets.tmpl @@ -198,5 +198,12 @@ !Itapset/signal.stp - + + Directory-entry (dentry) Tapset + + This family of functions is used to map kernel VFS + directory entriy pointers to file or full path names. + +!Itapset/dentry.stp + diff --git a/tapset/dentry.stp b/tapset/dentry.stp new file mode 100644 index 000000000..af8a866fe --- /dev/null +++ b/tapset/dentry.stp @@ -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 +#include +%} + + +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); +} diff --git a/testsuite/systemtap.examples/network/autofs4.meta b/testsuite/systemtap.examples/network/autofs4.meta new file mode 100644 index 000000000..16ae7297e --- /dev/null +++ b/testsuite/systemtap.examples/network/autofs4.meta @@ -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 index 000000000..19a27ee4a --- /dev/null +++ b/testsuite/systemtap.examples/network/autofs4.stp @@ -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") + } +}