debugfs: debugfs_remove_recursive() must not rely on list_empty(d_subdirs)
authorOleg Nesterov <oleg@redhat.com>
Fri, 26 Jul 2013 15:12:56 +0000 (17:12 +0200)
committerSteven Rostedt <rostedt@goodmis.org>
Wed, 31 Jul 2013 16:16:31 +0000 (12:16 -0400)
commit776164c1faac4966ab14418bb0922e1820da1d19
treec59ca51e2b86468841c2f44aa68073f27b7ca31b
parent8c4f3c3fa9681dc549cd35419b259496082fef8b
debugfs: debugfs_remove_recursive() must not rely on list_empty(d_subdirs)

debugfs_remove_recursive() is wrong,

1. it wrongly assumes that !list_empty(d_subdirs) means that this
   dir should be removed.

   This is not that bad by itself, but:

2. if d_subdirs does not becomes empty after __debugfs_remove()
   it gives up and silently fails, it doesn't even try to remove
   other entries.

   However ->d_subdirs can be non-empty because it still has the
   already deleted !debugfs_positive() entries.

3. simple_release_fs() is called even if __debugfs_remove() fails.

Suppose we have

dir1/
dir2/
file2
file1

and someone opens dir1/dir2/file2.

Now, debugfs_remove_recursive(dir1/dir2) succeeds, and dir1/dir2 goes
away.

But debugfs_remove_recursive(dir1) silently fails and doesn't remove
this directory. Because it tries to delete (the already deleted)
dir1/dir2/file2 again and then fails due to "Avoid infinite loop"
logic.

Test-case:

#!/bin/sh

cd /sys/kernel/debug/tracing
echo 'p:probe/sigprocmask sigprocmask' >> kprobe_events
sleep 1000 < events/probe/sigprocmask/id &
echo -n >| kprobe_events

[ -d events/probe ] && echo "ERR!! failed to rm probe"

And after that it is not possible to create another probe entry.

With this patch debugfs_remove_recursive() skips !debugfs_positive()
files although this is not strictly needed. The most important change
is that it does not try to make ->d_subdirs empty, it simply scans
the whole list(s) recursively and removes as much as possible.

Link: http://lkml.kernel.org/r/20130726151256.GC19472@redhat.com
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
fs/debugfs/inode.c