Commit 3bcf3860 authored by Eric Paris's avatar Eric Paris

fsnotify: store struct file not struct path

Al explains that calling dentry_open() with a mnt/dentry pair is only
garunteed to be safe if they are already used in an open struct file.  To
make sure this is the case don't store and use a struct path in fsnotify,
always use a struct file.
Signed-off-by: default avatarEric Paris <eparis@redhat.com>
parent f70ab54c
...@@ -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_PATH): case (FSNOTIFY_EVENT_FILE):
if ((old->path.mnt == new->path.mnt) && if ((old->file->f_path.mnt == new->file->f_path.mnt) &&
(old->path.dentry == new->path.dentry)) (old->file->f_path.dentry == new->file->f_path.dentry))
return true; return true;
case (FSNOTIFY_EVENT_NONE): case (FSNOTIFY_EVENT_NONE):
return true; return true;
...@@ -226,7 +226,7 @@ static bool fanotify_should_send_event(struct fsnotify_group *group, struct inod ...@@ -226,7 +226,7 @@ static bool fanotify_should_send_event(struct fsnotify_group *group, struct inod
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_PATH) if (data_type != FSNOTIFY_EVENT_FILE)
return false; return false;
if (mnt) if (mnt)
......
...@@ -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_PATH) { if (event->data_type != FSNOTIFY_EVENT_FILE) {
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->path.dentry); dentry = dget(event->file->f_path.dentry);
mnt = mntget(event->path.mnt); mnt = mntget(event->file->f_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 path *path, struct dentry *dentry, __u32 mask) void __fsnotify_parent(struct file *file, 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 path *path, struct dentry *dentry, __u32 mask) ...@@ -92,7 +92,7 @@ void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
bool should_update_children = false; bool should_update_children = false;
if (!dentry) if (!dentry)
dentry = path->dentry; dentry = file->f_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 path *path, struct dentry *dentry, __u32 mask) ...@@ -124,8 +124,8 @@ void __fsnotify_parent(struct path *path, 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 (path) if (file)
fsnotify(p_inode, mask, path, FSNOTIFY_EVENT_PATH, fsnotify(p_inode, mask, file, FSNOTIFY_EVENT_FILE,
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,
...@@ -154,10 +154,10 @@ void __fsnotify_flush_ignored_mask(struct inode *inode, void *data, int data_is) ...@@ -154,10 +154,10 @@ void __fsnotify_flush_ignored_mask(struct inode *inode, void *data, int data_is)
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
if (data_is == FSNOTIFY_EVENT_PATH) { if (data_is == FSNOTIFY_EVENT_FILE) {
struct vfsmount *mnt; struct vfsmount *mnt;
mnt = ((struct path *)data)->mnt; mnt = ((struct file *)data)->f_path.mnt;
if (mnt && !hlist_empty(&mnt->mnt_fsnotify_marks)) { if (mnt && !hlist_empty(&mnt->mnt_fsnotify_marks)) {
spin_lock(&mnt->mnt_root->d_lock); spin_lock(&mnt->mnt_root->d_lock);
hlist_for_each_entry(mark, node, &mnt->mnt_fsnotify_marks, m.m_list) { hlist_for_each_entry(mark, node, &mnt->mnt_fsnotify_marks, m.m_list) {
...@@ -228,8 +228,8 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, ...@@ -228,8 +228,8 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
!(test_mask & fsnotify_vfsmount_mask)) !(test_mask & fsnotify_vfsmount_mask))
return 0; return 0;
if (data_is == FSNOTIFY_EVENT_PATH) if (data_is == FSNOTIFY_EVENT_FILE)
mnt = ((struct path *)data)->mnt; mnt = ((struct file *)data)->f_path.mnt;
/* if this inode's directed listeners don't care and nothing on the vfsmount /* if this inode's directed listeners don't care and nothing on the vfsmount
* listeners list cares, nothing to do */ * listeners list cares, nothing to do */
......
...@@ -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_PATH): case (FSNOTIFY_EVENT_FILE):
if ((old->path.mnt == new->path.mnt) && if ((old->file->f_path.mnt == new->file->f_path.mnt) &&
(old->path.dentry == new->path.dentry)) (old->file->f_path.dentry == new->file->f_path.dentry))
return true; return true;
break; break;
case (FSNOTIFY_EVENT_NONE): case (FSNOTIFY_EVENT_NONE):
...@@ -165,10 +165,10 @@ static bool inotify_should_send_event(struct fsnotify_group *group, struct inode ...@@ -165,10 +165,10 @@ static bool inotify_should_send_event(struct fsnotify_group *group, struct inode
send = (fsn_mark->mask & mask); send = (fsn_mark->mask & mask);
if (send && (fsn_mark->mask & FS_EXCL_UNLINK) && if (send && (fsn_mark->mask & FS_EXCL_UNLINK) &&
(data_type == FSNOTIFY_EVENT_PATH)) { (data_type == FSNOTIFY_EVENT_FILE)) {
struct path *path = data; struct file *file = data;
if (d_unlinked(path->dentry)) if (d_unlinked(file->f_path.dentry))
send = false; send = false;
} }
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
* 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>
...@@ -89,8 +90,8 @@ void fsnotify_put_event(struct fsnotify_event *event) ...@@ -89,8 +90,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_PATH) if (event->data_type == FSNOTIFY_EVENT_FILE)
path_put(&event->path); fput(event->file);
BUG_ON(!list_empty(&event->private_data_list)); BUG_ON(!list_empty(&event->private_data_list));
...@@ -375,8 +376,8 @@ struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_event) ...@@ -375,8 +376,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_PATH) if (event->data_type == FSNOTIFY_EVENT_FILE)
path_get(&event->path); get_file(event->file);
return event; return event;
} }
...@@ -423,11 +424,9 @@ struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask, ...@@ -423,11 +424,9 @@ 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_PATH: { case FSNOTIFY_EVENT_FILE: {
struct path *path = data; event->file = data;
event->path.dentry = path->dentry; get_file(event->file);
event->path.mnt = path->mnt;
path_get(&event->path);
break; break;
} }
case FSNOTIFY_EVENT_INODE: case FSNOTIFY_EVENT_INODE:
...@@ -435,8 +434,7 @@ struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask, ...@@ -435,8 +434,7 @@ 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->path.dentry = NULL; event->file = NULL;
event->path.mnt = NULL;
break; break;
default: default:
BUG(); BUG();
......
...@@ -26,19 +26,18 @@ static inline void fsnotify_d_instantiate(struct dentry *dentry, ...@@ -26,19 +26,18 @@ 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 path *path, struct dentry *dentry, __u32 mask) static inline void fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask)
{ {
if (!dentry) if (!dentry)
dentry = path->dentry; dentry = file->f_path.dentry;
__fsnotify_parent(path, dentry, mask); __fsnotify_parent(file, 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 path *path = &file->f_path; struct inode *inode = file->f_path.dentry->d_inode;
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)
...@@ -52,7 +51,7 @@ static inline int fsnotify_perm(struct file *file, int mask) ...@@ -52,7 +51,7 @@ static inline int fsnotify_perm(struct file *file, int mask)
else else
BUG(); BUG();
return fsnotify(inode, fsnotify_mask, path, FSNOTIFY_EVENT_PATH, NULL, 0); return fsnotify(inode, fsnotify_mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
} }
/* /*
...@@ -187,16 +186,15 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry) ...@@ -187,16 +186,15 @@ 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 path *path = &file->f_path; struct inode *inode = file->f_path.dentry->d_inode;
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(path, NULL, mask); fsnotify_parent(file, NULL, mask);
fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0); fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
} }
} }
...@@ -205,16 +203,15 @@ static inline void fsnotify_access(struct file *file) ...@@ -205,16 +203,15 @@ 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 path *path = &file->f_path; struct inode *inode = file->f_path.dentry->d_inode;
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(path, NULL, mask); fsnotify_parent(file, NULL, mask);
fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0); fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
} }
} }
...@@ -223,16 +220,15 @@ static inline void fsnotify_modify(struct file *file) ...@@ -223,16 +220,15 @@ 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 path *path = &file->f_path; struct inode *inode = file->f_path.dentry->d_inode;
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(path, NULL, mask); fsnotify_parent(file, NULL, mask);
fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0); fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
} }
} }
...@@ -241,7 +237,6 @@ static inline void fsnotify_open(struct file *file) ...@@ -241,7 +237,6 @@ 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;
...@@ -250,8 +245,8 @@ static inline void fsnotify_close(struct file *file) ...@@ -250,8 +245,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(path, NULL, mask); fsnotify_parent(file, NULL, mask);
fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0); fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
} }
} }
......
...@@ -223,20 +223,20 @@ struct fsnotify_event { ...@@ -223,20 +223,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 path or inode * depending on the event type we should have either a file or inode
* We hold a reference on path, but NOT on inode. Since we have the ref on * We hold a reference on file, but NOT on inode. Since we have the ref on
* the path, it may be dereferenced at any point during this object's * the file, 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 path, the inode may * 0. If this event contains an inode instead of a file, the inode may
* ONLY be used during handle_event(). * ONLY be used during handle_event().
*/ */
union { union {
struct path path; struct file *file;
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_PATH 1 #define FSNOTIFY_EVENT_FILE 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 */
...@@ -311,7 +311,7 @@ struct fsnotify_mark { ...@@ -311,7 +311,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 path *path, struct dentry *dentry, __u32 mask); extern void __fsnotify_parent(struct file *file, 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);
...@@ -444,7 +444,7 @@ static inline int fsnotify(struct inode *to_tell, __u32 mask, void *data, int da ...@@ -444,7 +444,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 path *path, struct dentry *dentry, __u32 mask) static inline void __fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask)
{} {}
static inline void __fsnotify_inode_delete(struct inode *inode) static inline void __fsnotify_inode_delete(struct inode *inode)
......
...@@ -545,8 +545,8 @@ static int audit_watch_handle_event(struct fsnotify_group *group, struct fsnotif ...@@ -545,8 +545,8 @@ static int audit_watch_handle_event(struct fsnotify_group *group, struct fsnotif
return 0; return 0;
switch (event->data_type) { switch (event->data_type) {
case (FSNOTIFY_EVENT_PATH): case (FSNOTIFY_EVENT_FILE):
inode = event->path.dentry->d_inode; inode = event->file->f_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