*/
function task_dentry_path:string(task:long,dentry:long,vfsmnt:long)
{
+ /*
+ * There are various synthetic filesystems that never get
+ * mounted. Filesystems needing to implement special "root
+ * names" do so with dentry->d_op->d_dname(). Unfortunately,
+ * it isn't really safe for us to call
+ * dentry->d_op->d_dname(). We can't really validate the
+ * function pointer or know that it can be called safely in
+ * the current context.
+ *
+ * Some pseudo inodes are mountable. When they are mounted,
+ * dentry == vfsmnt->mnt_root. In that case, we'll just go
+ * ahead and handle them normally.
+ */
+ if (@defined(@cast(0, "dentry")->d_op->d_dname)
+ && @cast(dentry, "dentry")->d_op
+ && @cast(dentry, "dentry")->d_op->d_dname
+ && (!__dentry_IS_ROOT(dentry)
+ || dentry != @cast(vfsmnt, "vfsmount")->mnt_root))
+ return "UNKNOWN"
+
root = & @cast(task, "task_struct")->fs->root
while (1) {
--- /dev/null
+# This testcase tests the fix for PR16991 - infinite loop in
+# task_dentry_path. When task_dentry_path hit a dentry from an
+# unmounted synthentic filesystem, it would go into an infinite loop
+# (until killed by MAXACTION).
+
+set test "task_dentry_path"
+spawn stap $srcdir/$subdir/$test.stp -c "sh $srcdir/$subdir/$test.sh"
+set ok 0
+expect {
+ -timeout 150
+ -re {ERROR.*MAXACTION} { incr ok; exp_continue }
+ timeout { fail "$test (timeout)" }
+ eof { }
+}
+catch {close}; catch {wait}
+if {$ok == 1} { fail "$test ($ok)" } { pass "$test ($ok)" }
--- /dev/null
+global FSNOTIFY_EVENT_PATH = 1
+
+probe kernel.function("fsnotify") ?
+{
+ if (!target_set_pid(pid())) {
+ next
+ }
+ if ($data_is == FSNOTIFY_EVENT_PATH) {
+ path = task_dentry_path(task_current(), @cast($data, "path")->dentry,
+ @cast($data, "path")->mnt);
+ println(path);
+ }
+}
+
+probe begin
+{
+ printf("begin\n")
+}