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>
This commit is contained in:
parent
3bcf3860a4
commit
c1e5c95402
2 changed files with 22 additions and 0 deletions
|
@ -230,6 +230,15 @@ static void __fput(struct file *file)
|
|||
might_sleep();
|
||||
|
||||
fsnotify_close(file);
|
||||
|
||||
/*
|
||||
* fsnotify_create_event may have taken one or more references on this
|
||||
* file. If it did so it left one reference for us to drop to make sure
|
||||
* its calls to fput could not prematurely destroy the file.
|
||||
*/
|
||||
if (atomic_long_read(&file->f_count))
|
||||
return fput(file);
|
||||
|
||||
/*
|
||||
* The function eventpoll_release() should be the first called
|
||||
* in the file cleanup chain.
|
||||
|
|
|
@ -426,6 +426,19 @@ struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
|
|||
switch (data_type) {
|
||||
case FSNOTIFY_EVENT_FILE: {
|
||||
event->file = data;
|
||||
/*
|
||||
* if this file is about to disappear hold an extra reference
|
||||
* until we return to __fput so we don't have to worry about
|
||||
* future get/put destroying the file under us or generating
|
||||
* additional events. Notice that we change f_mode without
|
||||
* holding f_lock. This is safe since this is the only possible
|
||||
* reference to this object in the kernel (it was about to be
|
||||
* freed, remember?)
|
||||
*/
|
||||
if (!atomic_long_read(&event->file->f_count)) {
|
||||
event->file->f_mode |= FMODE_NONOTIFY;
|
||||
get_file(event->file);
|
||||
}
|
||||
get_file(event->file);
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue