Commit c1e5c954020e123d30b4abf4038ce501861bcf9f

Authored by Eric Paris
1 parent 3bcf3860a4

vfs/fsnotify: fsnotify_close can delay the final work in fput

fanotify almost works like so:

user context calls fsnotify_* function with a struct file.
   fsnotify takes a reference on the struct path
user context goes about it's buissiness

at some later point in time the fsnotify listener gets the struct path
   fanotify listener calls dentry_open() to create a file which userspace can deal with
      listener drops the reference on the struct path
at some later point the listener calls close() on it's new file

With the switch from struct path to struct file this presents a problem for
fput() and fsnotify_close().  fsnotify_close() is called when the filp has
already reached 0 and __fput() wants to do it's cleanup.

The solution presented here is a bit odd.  If an event is created from a
struct file we take a reference on the file.  We check however if the f_count
was already 0 and if so we take an EXTRA reference EVEN THOUGH IT WAS ZERO.
In __fput() (where we know the f_count hit 0 once) we check if the f_count is
non-zero and if so we drop that 'extra' ref and return without destroying the
file.

Signed-off-by: Eric Paris <eparis@redhat.com>

Showing 2 changed files with 22 additions and 0 deletions Side-by-side Diff

... ... @@ -230,6 +230,15 @@
230 230 might_sleep();
231 231  
232 232 fsnotify_close(file);
  233 +
  234 + /*
  235 + * fsnotify_create_event may have taken one or more references on this
  236 + * file. If it did so it left one reference for us to drop to make sure
  237 + * its calls to fput could not prematurely destroy the file.
  238 + */
  239 + if (atomic_long_read(&file->f_count))
  240 + return fput(file);
  241 +
233 242 /*
234 243 * The function eventpoll_release() should be the first called
235 244 * in the file cleanup chain.
fs/notify/notification.c
... ... @@ -426,6 +426,19 @@
426 426 switch (data_type) {
427 427 case FSNOTIFY_EVENT_FILE: {
428 428 event->file = data;
  429 + /*
  430 + * if this file is about to disappear hold an extra reference
  431 + * until we return to __fput so we don't have to worry about
  432 + * future get/put destroying the file under us or generating
  433 + * additional events. Notice that we change f_mode without
  434 + * holding f_lock. This is safe since this is the only possible
  435 + * reference to this object in the kernel (it was about to be
  436 + * freed, remember?)
  437 + */
  438 + if (!atomic_long_read(&event->file->f_count)) {
  439 + event->file->f_mode |= FMODE_NONOTIFY;
  440 + get_file(event->file);
  441 + }
429 442 get_file(event->file);
430 443 break;
431 444 }