aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2010-07-28 10:18:38 -0400
committerEric Paris <eparis@redhat.com>2010-07-28 10:18:51 -0400
commitc1e5c954020e123d30b4abf4038ce501861bcf9f (patch)
treee8c9071ae4f37464e114fab79deea4716857f7ad
parent3bcf3860a4ff9bbc522820b4b765e65e4deceb3e (diff)
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>
-rw-r--r--fs/file_table.c9
-rw-r--r--fs/notify/notification.c13
2 files changed, 22 insertions, 0 deletions
diff --git a/fs/file_table.c b/fs/file_table.c
index 5c7d10ead4ad..b8a0bb63cbd7 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -230,6 +230,15 @@ static void __fput(struct file *file)
230 might_sleep(); 230 might_sleep();
231 231
232 fsnotify_close(file); 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 * The function eventpoll_release() should be the first called 243 * The function eventpoll_release() should be the first called
235 * in the file cleanup chain. 244 * in the file cleanup chain.
diff --git a/fs/notify/notification.c b/fs/notify/notification.c
index c106cdd7ff5e..d6c435adc7a2 100644
--- a/fs/notify/notification.c
+++ b/fs/notify/notification.c
@@ -426,6 +426,19 @@ struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
426 switch (data_type) { 426 switch (data_type) {
427 case FSNOTIFY_EVENT_FILE: { 427 case FSNOTIFY_EVENT_FILE: {
428 event->file = data; 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 get_file(event->file); 442 get_file(event->file);
430 break; 443 break;
431 } 444 }