Commit 2069601b authored by Linus Torvalds's avatar Linus Torvalds

Revert "fsnotify: store struct file not struct path"

This reverts commit 3bcf3860 (and the
accompanying commit c1e5c954 "vfs/fsnotify: fsnotify_close can delay
the final work in fput" that was a horribly ugly hack to make it work at
all).

The 'struct file' approach not only causes that disgusting hack, it
somehow breaks pulseaudio, probably due to some other subtlety with
f_count handling.

Fix up various conflicts due to later fsnotify work.
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent ad41a1e0
...@@ -230,15 +230,6 @@ static void __fput(struct file *file) ...@@ -230,15 +230,6 @@ static void __fput(struct file *file)
might_sleep(); might_sleep();
fsnotify_close(file); 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 * The function eventpoll_release() should be the first called
* in the file cleanup chain. * in the file cleanup chain.
......
...@@ -17,9 +17,9 @@ static bool should_merge(struct fsnotify_event *old, struct fsnotify_event *new) ...@@ -17,9 +17,9 @@ static bool should_merge(struct fsnotify_event *old, struct fsnotify_event *new)
old->data_type == new->data_type && old->data_type == new->data_type &&
old->tgid == new->tgid) { old->tgid == new->tgid) {
switch (old->data_type) { switch (old->data_type) {
case (FSNOTIFY_EVENT_FILE): case (FSNOTIFY_EVENT_PATH):
if ((old->file->f_path.mnt == new->file->f_path.mnt) && if ((old->path.mnt == new->path.mnt) &&
(old->file->f_path.dentry == new->file->f_path.dentry)) (old->path.dentry == new->path.dentry))
return true; return true;
case (FSNOTIFY_EVENT_NONE): case (FSNOTIFY_EVENT_NONE):
return true; return true;
...@@ -174,7 +174,7 @@ static bool fanotify_should_send_event(struct fsnotify_group *group, ...@@ -174,7 +174,7 @@ static bool fanotify_should_send_event(struct fsnotify_group *group,
return false; return false;
/* if we don't have enough info to send an event to userspace say no */ /* if we don't have enough info to send an event to userspace say no */
if (data_type != FSNOTIFY_EVENT_FILE) if (data_type != FSNOTIFY_EVENT_PATH)
return false; return false;
if (inode_mark && vfsmnt_mark) { if (inode_mark && vfsmnt_mark) {
......
...@@ -65,7 +65,7 @@ static int create_fd(struct fsnotify_group *group, struct fsnotify_event *event) ...@@ -65,7 +65,7 @@ static int create_fd(struct fsnotify_group *group, struct fsnotify_event *event)
if (client_fd < 0) if (client_fd < 0)
return client_fd; return client_fd;
if (event->data_type != FSNOTIFY_EVENT_FILE) { if (event->data_type != FSNOTIFY_EVENT_PATH) {
WARN_ON(1); WARN_ON(1);
put_unused_fd(client_fd); put_unused_fd(client_fd);
return -EINVAL; return -EINVAL;
...@@ -75,8 +75,8 @@ static int create_fd(struct fsnotify_group *group, struct fsnotify_event *event) ...@@ -75,8 +75,8 @@ static int create_fd(struct fsnotify_group *group, struct fsnotify_event *event)
* we need a new file handle for the userspace program so it can read even if it was * we need a new file handle for the userspace program so it can read even if it was
* originally opened O_WRONLY. * originally opened O_WRONLY.
*/ */
dentry = dget(event->file->f_path.dentry); dentry = dget(event->path.dentry);
mnt = mntget(event->file->f_path.mnt); mnt = mntget(event->path.mnt);
/* it's possible this event was an overflow event. in that case dentry and mnt /* it's possible this event was an overflow event. in that case dentry and mnt
* are NULL; That's fine, just don't call dentry open */ * are NULL; That's fine, just don't call dentry open */
if (dentry && mnt) if (dentry && mnt)
......
...@@ -84,7 +84,7 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode) ...@@ -84,7 +84,7 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode)
} }
/* Notify this dentry's parent about a child's events. */ /* Notify this dentry's parent about a child's events. */
void __fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask) void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
{ {
struct dentry *parent; struct dentry *parent;
struct inode *p_inode; struct inode *p_inode;
...@@ -92,7 +92,7 @@ void __fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask) ...@@ -92,7 +92,7 @@ void __fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask)
bool should_update_children = false; bool should_update_children = false;
if (!dentry) if (!dentry)
dentry = file->f_path.dentry; dentry = path->dentry;
if (!(dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED)) if (!(dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED))
return; return;
...@@ -124,8 +124,8 @@ void __fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask) ...@@ -124,8 +124,8 @@ void __fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask)
* specifies these are events which came from a child. */ * specifies these are events which came from a child. */
mask |= FS_EVENT_ON_CHILD; mask |= FS_EVENT_ON_CHILD;
if (file) if (path)
fsnotify(p_inode, mask, file, FSNOTIFY_EVENT_FILE, fsnotify(p_inode, mask, path, FSNOTIFY_EVENT_PATH,
dentry->d_name.name, 0); dentry->d_name.name, 0);
else else
fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE, fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE,
...@@ -217,8 +217,8 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, ...@@ -217,8 +217,8 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
/* global tests shouldn't care about events on child only the specific event */ /* global tests shouldn't care about events on child only the specific event */
__u32 test_mask = (mask & ~FS_EVENT_ON_CHILD); __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD);
if (data_is == FSNOTIFY_EVENT_FILE) if (data_is == FSNOTIFY_EVENT_PATH)
mnt = ((struct file *)data)->f_path.mnt; mnt = ((struct path *)data)->mnt;
else else
mnt = NULL; mnt = NULL;
......
...@@ -52,9 +52,9 @@ static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new ...@@ -52,9 +52,9 @@ static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new
!strcmp(old->file_name, new->file_name)) !strcmp(old->file_name, new->file_name))
return true; return true;
break; break;
case (FSNOTIFY_EVENT_FILE): case (FSNOTIFY_EVENT_PATH):
if ((old->file->f_path.mnt == new->file->f_path.mnt) && if ((old->path.mnt == new->path.mnt) &&
(old->file->f_path.dentry == new->file->f_path.dentry)) (old->path.dentry == new->path.dentry))
return true; return true;
break; break;
case (FSNOTIFY_EVENT_NONE): case (FSNOTIFY_EVENT_NONE):
...@@ -147,10 +147,10 @@ static bool inotify_should_send_event(struct fsnotify_group *group, struct inode ...@@ -147,10 +147,10 @@ static bool inotify_should_send_event(struct fsnotify_group *group, struct inode
__u32 mask, void *data, int data_type) __u32 mask, void *data, int data_type)
{ {
if ((inode_mark->mask & FS_EXCL_UNLINK) && if ((inode_mark->mask & FS_EXCL_UNLINK) &&
(data_type == FSNOTIFY_EVENT_FILE)) { (data_type == FSNOTIFY_EVENT_PATH)) {
struct file *file = data; struct path *path = data;
if (d_unlinked(file->f_path.dentry)) if (d_unlinked(path->dentry))
return false; return false;
} }
......
...@@ -31,7 +31,6 @@ ...@@ -31,7 +31,6 @@
* allocated and used. * allocated and used.
*/ */
#include <linux/file.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -90,8 +89,8 @@ void fsnotify_put_event(struct fsnotify_event *event) ...@@ -90,8 +89,8 @@ void fsnotify_put_event(struct fsnotify_event *event)
if (atomic_dec_and_test(&event->refcnt)) { if (atomic_dec_and_test(&event->refcnt)) {
pr_debug("%s: event=%p\n", __func__, event); pr_debug("%s: event=%p\n", __func__, event);
if (event->data_type == FSNOTIFY_EVENT_FILE) if (event->data_type == FSNOTIFY_EVENT_PATH)
fput(event->file); path_put(&event->path);
BUG_ON(!list_empty(&event->private_data_list)); BUG_ON(!list_empty(&event->private_data_list));
...@@ -376,8 +375,8 @@ struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_event) ...@@ -376,8 +375,8 @@ struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_event)
} }
} }
event->tgid = get_pid(old_event->tgid); event->tgid = get_pid(old_event->tgid);
if (event->data_type == FSNOTIFY_EVENT_FILE) if (event->data_type == FSNOTIFY_EVENT_PATH)
get_file(event->file); path_get(&event->path);
return event; return event;
} }
...@@ -424,22 +423,11 @@ struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask, ...@@ -424,22 +423,11 @@ struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
event->data_type = data_type; event->data_type = data_type;
switch (data_type) { switch (data_type) {
case FSNOTIFY_EVENT_FILE: { case FSNOTIFY_EVENT_PATH: {
event->file = data; struct path *path = data;
/* event->path.dentry = path->dentry;
* if this file is about to disappear hold an extra reference event->path.mnt = path->mnt;
* until we return to __fput so we don't have to worry about path_get(&event->path);
* 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; break;
} }
case FSNOTIFY_EVENT_INODE: case FSNOTIFY_EVENT_INODE:
...@@ -447,7 +435,8 @@ struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask, ...@@ -447,7 +435,8 @@ struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
break; break;
case FSNOTIFY_EVENT_NONE: case FSNOTIFY_EVENT_NONE:
event->inode = NULL; event->inode = NULL;
event->file = NULL; event->path.dentry = NULL;
event->path.mnt = NULL;
break; break;
default: default:
BUG(); BUG();
......
...@@ -26,18 +26,19 @@ static inline void fsnotify_d_instantiate(struct dentry *dentry, ...@@ -26,18 +26,19 @@ static inline void fsnotify_d_instantiate(struct dentry *dentry,
} }
/* Notify this dentry's parent about a child's events. */ /* Notify this dentry's parent about a child's events. */
static inline void fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask) static inline void fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
{ {
if (!dentry) if (!dentry)
dentry = file->f_path.dentry; dentry = path->dentry;
__fsnotify_parent(file, dentry, mask); __fsnotify_parent(path, dentry, mask);
} }
/* simple call site for access decisions */ /* simple call site for access decisions */
static inline int fsnotify_perm(struct file *file, int mask) static inline int fsnotify_perm(struct file *file, int mask)
{ {
struct inode *inode = file->f_path.dentry->d_inode; struct path *path = &file->f_path;
struct inode *inode = path->dentry->d_inode;
__u32 fsnotify_mask = 0; __u32 fsnotify_mask = 0;
if (file->f_mode & FMODE_NONOTIFY) if (file->f_mode & FMODE_NONOTIFY)
...@@ -51,7 +52,7 @@ static inline int fsnotify_perm(struct file *file, int mask) ...@@ -51,7 +52,7 @@ static inline int fsnotify_perm(struct file *file, int mask)
else else
BUG(); BUG();
return fsnotify(inode, fsnotify_mask, file, FSNOTIFY_EVENT_FILE, NULL, 0); return fsnotify(inode, fsnotify_mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
} }
/* /*
...@@ -186,15 +187,16 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry) ...@@ -186,15 +187,16 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
*/ */
static inline void fsnotify_access(struct file *file) static inline void fsnotify_access(struct file *file)
{ {
struct inode *inode = file->f_path.dentry->d_inode; struct path *path = &file->f_path;
struct inode *inode = path->dentry->d_inode;
__u32 mask = FS_ACCESS; __u32 mask = FS_ACCESS;
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
mask |= FS_IN_ISDIR; mask |= FS_IN_ISDIR;
if (!(file->f_mode & FMODE_NONOTIFY)) { if (!(file->f_mode & FMODE_NONOTIFY)) {
fsnotify_parent(file, NULL, mask); fsnotify_parent(path, NULL, mask);
fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0); fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
} }
} }
...@@ -203,15 +205,16 @@ static inline void fsnotify_access(struct file *file) ...@@ -203,15 +205,16 @@ static inline void fsnotify_access(struct file *file)
*/ */
static inline void fsnotify_modify(struct file *file) static inline void fsnotify_modify(struct file *file)
{ {
struct inode *inode = file->f_path.dentry->d_inode; struct path *path = &file->f_path;
struct inode *inode = path->dentry->d_inode;
__u32 mask = FS_MODIFY; __u32 mask = FS_MODIFY;
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
mask |= FS_IN_ISDIR; mask |= FS_IN_ISDIR;
if (!(file->f_mode & FMODE_NONOTIFY)) { if (!(file->f_mode & FMODE_NONOTIFY)) {
fsnotify_parent(file, NULL, mask); fsnotify_parent(path, NULL, mask);
fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0); fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
} }
} }
...@@ -220,15 +223,16 @@ static inline void fsnotify_modify(struct file *file) ...@@ -220,15 +223,16 @@ static inline void fsnotify_modify(struct file *file)
*/ */
static inline void fsnotify_open(struct file *file) static inline void fsnotify_open(struct file *file)
{ {
struct inode *inode = file->f_path.dentry->d_inode; struct path *path = &file->f_path;
struct inode *inode = path->dentry->d_inode;
__u32 mask = FS_OPEN; __u32 mask = FS_OPEN;
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
mask |= FS_IN_ISDIR; mask |= FS_IN_ISDIR;
if (!(file->f_mode & FMODE_NONOTIFY)) { if (!(file->f_mode & FMODE_NONOTIFY)) {
fsnotify_parent(file, NULL, mask); fsnotify_parent(path, NULL, mask);
fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0); fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
} }
} }
...@@ -237,6 +241,7 @@ static inline void fsnotify_open(struct file *file) ...@@ -237,6 +241,7 @@ static inline void fsnotify_open(struct file *file)
*/ */
static inline void fsnotify_close(struct file *file) static inline void fsnotify_close(struct file *file)
{ {
struct path *path = &file->f_path;
struct inode *inode = file->f_path.dentry->d_inode; struct inode *inode = file->f_path.dentry->d_inode;
fmode_t mode = file->f_mode; fmode_t mode = file->f_mode;
__u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE; __u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE;
...@@ -245,8 +250,8 @@ static inline void fsnotify_close(struct file *file) ...@@ -245,8 +250,8 @@ static inline void fsnotify_close(struct file *file)
mask |= FS_IN_ISDIR; mask |= FS_IN_ISDIR;
if (!(file->f_mode & FMODE_NONOTIFY)) { if (!(file->f_mode & FMODE_NONOTIFY)) {
fsnotify_parent(file, NULL, mask); fsnotify_parent(path, NULL, mask);
fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0); fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
} }
} }
......
...@@ -203,20 +203,20 @@ struct fsnotify_event { ...@@ -203,20 +203,20 @@ struct fsnotify_event {
/* to_tell may ONLY be dereferenced during handle_event(). */ /* to_tell may ONLY be dereferenced during handle_event(). */
struct inode *to_tell; /* either the inode the event happened to or its parent */ struct inode *to_tell; /* either the inode the event happened to or its parent */
/* /*
* depending on the event type we should have either a file or inode * depending on the event type we should have either a path or inode
* We hold a reference on file, but NOT on inode. Since we have the ref on * We hold a reference on path, but NOT on inode. Since we have the ref on
* the file, it may be dereferenced at any point during this object's * the path, it may be dereferenced at any point during this object's
* lifetime. That reference is dropped when this object's refcnt hits * lifetime. That reference is dropped when this object's refcnt hits
* 0. If this event contains an inode instead of a file, the inode may * 0. If this event contains an inode instead of a path, the inode may
* ONLY be used during handle_event(). * ONLY be used during handle_event().
*/ */
union { union {
struct file *file; struct path path;
struct inode *inode; struct inode *inode;
}; };
/* when calling fsnotify tell it if the data is a path or inode */ /* when calling fsnotify tell it if the data is a path or inode */
#define FSNOTIFY_EVENT_NONE 0 #define FSNOTIFY_EVENT_NONE 0
#define FSNOTIFY_EVENT_FILE 1 #define FSNOTIFY_EVENT_PATH 1
#define FSNOTIFY_EVENT_INODE 2 #define FSNOTIFY_EVENT_INODE 2
int data_type; /* which of the above union we have */ int data_type; /* which of the above union we have */
atomic_t refcnt; /* how many groups still are using/need to send this event */ atomic_t refcnt; /* how many groups still are using/need to send this event */
...@@ -293,7 +293,7 @@ struct fsnotify_mark { ...@@ -293,7 +293,7 @@ struct fsnotify_mark {
/* main fsnotify call to send events */ /* main fsnotify call to send events */
extern int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, extern int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
const unsigned char *name, u32 cookie); const unsigned char *name, u32 cookie);
extern void __fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask); extern void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask);
extern void __fsnotify_inode_delete(struct inode *inode); extern void __fsnotify_inode_delete(struct inode *inode);
extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt); extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt);
extern u32 fsnotify_get_cookie(void); extern u32 fsnotify_get_cookie(void);
...@@ -422,7 +422,7 @@ static inline int fsnotify(struct inode *to_tell, __u32 mask, void *data, int da ...@@ -422,7 +422,7 @@ static inline int fsnotify(struct inode *to_tell, __u32 mask, void *data, int da
return 0; return 0;
} }
static inline void __fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask) static inline void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
{} {}
static inline void __fsnotify_inode_delete(struct inode *inode) static inline void __fsnotify_inode_delete(struct inode *inode)
......
...@@ -526,8 +526,8 @@ static int audit_watch_handle_event(struct fsnotify_group *group, ...@@ -526,8 +526,8 @@ static int audit_watch_handle_event(struct fsnotify_group *group,
BUG_ON(group != audit_watch_group); BUG_ON(group != audit_watch_group);
switch (event->data_type) { switch (event->data_type) {
case (FSNOTIFY_EVENT_FILE): case (FSNOTIFY_EVENT_PATH):
inode = event->file->f_path.dentry->d_inode; inode = event->path.dentry->d_inode;
break; break;
case (FSNOTIFY_EVENT_INODE): case (FSNOTIFY_EVENT_INODE):
inode = event->inode; inode = event->inode;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment