Commit 40a100d3 authored by Amir Goldstein's avatar Amir Goldstein Committed by Jan Kara

fsnotify: pass dir and inode arguments to fsnotify()

The arguments of fsnotify() are overloaded and mean different things
for different event types.

Replace the to_tell argument with separate arguments @dir and @inode,
because we may be sending to both dir and child.  Using the @data
argument to pass the child is not enough, because dirent events pass
this argument (for audit), but we do not report to child.

Document the new fsnotify() function argumenets.

Link: https://lore.kernel.org/r/20200722125849.17418-7-amir73il@gmail.comSigned-off-by: default avatarAmir Goldstein <amir73il@gmail.com>
Signed-off-by: default avatarJan Kara <jack@suse.cz>
parent 82ace1ef
...@@ -902,8 +902,9 @@ static void kernfs_notify_workfn(struct work_struct *work) ...@@ -902,8 +902,9 @@ static void kernfs_notify_workfn(struct work_struct *work)
if (parent) { if (parent) {
p_inode = ilookup(info->sb, kernfs_ino(parent)); p_inode = ilookup(info->sb, kernfs_ino(parent));
if (p_inode) { if (p_inode) {
fsnotify(p_inode, FS_MODIFY | FS_EVENT_ON_CHILD, fsnotify(FS_MODIFY | FS_EVENT_ON_CHILD,
inode, FSNOTIFY_EVENT_INODE, &name, 0); inode, FSNOTIFY_EVENT_INODE,
p_inode, &name, inode, 0);
iput(p_inode); iput(p_inode);
} }
......
...@@ -152,7 +152,7 @@ int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data, ...@@ -152,7 +152,7 @@ int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data,
{ {
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
struct dentry *parent; struct dentry *parent;
struct inode *p_inode; struct inode *p_inode = NULL;
struct name_snapshot name; struct name_snapshot name;
struct qstr *file_name = NULL; struct qstr *file_name = NULL;
int ret = 0; int ret = 0;
...@@ -171,14 +171,13 @@ int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data, ...@@ -171,14 +171,13 @@ int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data,
WARN_ON_ONCE(inode != fsnotify_data_inode(data, data_type)); WARN_ON_ONCE(inode != fsnotify_data_inode(data, data_type));
/* Notify both parent and child with child name info */ /* Notify both parent and child with child name info */
inode = p_inode;
take_dentry_name_snapshot(&name, dentry); take_dentry_name_snapshot(&name, dentry);
file_name = &name.name; file_name = &name.name;
mask |= FS_EVENT_ON_CHILD; mask |= FS_EVENT_ON_CHILD;
} }
notify: notify:
ret = fsnotify(inode, mask, data, data_type, file_name, 0); ret = fsnotify(mask, data, data_type, p_inode, file_name, inode, 0);
if (file_name) if (file_name)
release_dentry_name_snapshot(&name); release_dentry_name_snapshot(&name);
...@@ -312,18 +311,31 @@ static void fsnotify_iter_next(struct fsnotify_iter_info *iter_info) ...@@ -312,18 +311,31 @@ static void fsnotify_iter_next(struct fsnotify_iter_info *iter_info)
} }
/* /*
* This is the main call to fsnotify. The VFS calls into hook specific functions * fsnotify - This is the main call to fsnotify.
* in linux/fsnotify.h. Those functions then in turn call here. Here will call *
* out to all of the registered fsnotify_group. Those groups can then use the * The VFS calls into hook specific functions in linux/fsnotify.h.
* notification event in whatever means they feel necessary. * Those functions then in turn call here. Here will call out to all of the
* registered fsnotify_group. Those groups can then use the notification event
* in whatever means they feel necessary.
*
* @mask: event type and flags
* @data: object that event happened on
* @data_type: type of object for fanotify_data_XXX() accessors
* @dir: optional directory associated with event -
* if @file_name is not NULL, this is the directory that
* @file_name is relative to
* @file_name: optional file name associated with event
* @inode: optional inode associated with event -
* either @dir or @inode must be non-NULL.
* if both are non-NULL event may be reported to both.
* @cookie: inotify rename cookie
*/ */
int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_type, int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,
const struct qstr *file_name, u32 cookie) const struct qstr *file_name, struct inode *inode, u32 cookie)
{ {
const struct path *path = fsnotify_data_path(data, data_type); const struct path *path = fsnotify_data_path(data, data_type);
struct fsnotify_iter_info iter_info = {}; struct fsnotify_iter_info iter_info = {};
struct super_block *sb = to_tell->i_sb; struct super_block *sb;
struct inode *dir = file_name ? to_tell : NULL;
struct mount *mnt = NULL; struct mount *mnt = NULL;
struct inode *child = NULL; struct inode *child = NULL;
int ret = 0; int ret = 0;
...@@ -332,8 +344,18 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_type, ...@@ -332,8 +344,18 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_type,
if (path) if (path)
mnt = real_mount(path->mnt); mnt = real_mount(path->mnt);
if (mask & FS_EVENT_ON_CHILD) if (!inode) {
child = fsnotify_data_inode(data, data_type); /* Dirent event - report on TYPE_INODE to dir */
inode = dir;
} else if (mask & FS_EVENT_ON_CHILD) {
/*
* Event on child - report on TYPE_INODE to dir
* and on TYPE_CHILD to child.
*/
child = inode;
inode = dir;
}
sb = inode->i_sb;
/* /*
* Optimization: srcu_read_lock() has a memory barrier which can * Optimization: srcu_read_lock() has a memory barrier which can
...@@ -342,12 +364,12 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_type, ...@@ -342,12 +364,12 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_type,
* SRCU because we have no references to any objects and do not * SRCU because we have no references to any objects and do not
* need SRCU to keep them "alive". * need SRCU to keep them "alive".
*/ */
if (!to_tell->i_fsnotify_marks && !sb->s_fsnotify_marks && if (!inode->i_fsnotify_marks && !sb->s_fsnotify_marks &&
(!mnt || !mnt->mnt_fsnotify_marks) && (!mnt || !mnt->mnt_fsnotify_marks) &&
(!child || !child->i_fsnotify_marks)) (!child || !child->i_fsnotify_marks))
return 0; return 0;
marks_mask = to_tell->i_fsnotify_mask | sb->s_fsnotify_mask; marks_mask = inode->i_fsnotify_mask | sb->s_fsnotify_mask;
if (mnt) if (mnt)
marks_mask |= mnt->mnt_fsnotify_mask; marks_mask |= mnt->mnt_fsnotify_mask;
if (child) if (child)
...@@ -365,7 +387,7 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_type, ...@@ -365,7 +387,7 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_type,
iter_info.srcu_idx = srcu_read_lock(&fsnotify_mark_srcu); iter_info.srcu_idx = srcu_read_lock(&fsnotify_mark_srcu);
iter_info.marks[FSNOTIFY_OBJ_TYPE_INODE] = iter_info.marks[FSNOTIFY_OBJ_TYPE_INODE] =
fsnotify_first_mark(&to_tell->i_fsnotify_marks); fsnotify_first_mark(&inode->i_fsnotify_marks);
iter_info.marks[FSNOTIFY_OBJ_TYPE_SB] = iter_info.marks[FSNOTIFY_OBJ_TYPE_SB] =
fsnotify_first_mark(&sb->s_fsnotify_marks); fsnotify_first_mark(&sb->s_fsnotify_marks);
if (mnt) { if (mnt) {
......
...@@ -23,13 +23,14 @@ ...@@ -23,13 +23,14 @@
* have changed (i.e. renamed over). * have changed (i.e. renamed over).
* *
* Unlike fsnotify_parent(), the event will be reported regardless of the * Unlike fsnotify_parent(), the event will be reported regardless of the
* FS_EVENT_ON_CHILD mask on the parent inode. * FS_EVENT_ON_CHILD mask on the parent inode and will not be reported if only
* the child is interested and not the parent.
*/ */
static inline void fsnotify_name(struct inode *dir, __u32 mask, static inline void fsnotify_name(struct inode *dir, __u32 mask,
struct inode *child, struct inode *child,
const struct qstr *name, u32 cookie) const struct qstr *name, u32 cookie)
{ {
fsnotify(dir, mask, child, FSNOTIFY_EVENT_INODE, name, cookie); fsnotify(mask, child, FSNOTIFY_EVENT_INODE, dir, name, NULL, cookie);
} }
static inline void fsnotify_dirent(struct inode *dir, struct dentry *dentry, static inline void fsnotify_dirent(struct inode *dir, struct dentry *dentry,
...@@ -43,7 +44,7 @@ static inline void fsnotify_inode(struct inode *inode, __u32 mask) ...@@ -43,7 +44,7 @@ static inline void fsnotify_inode(struct inode *inode, __u32 mask)
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
mask |= FS_ISDIR; mask |= FS_ISDIR;
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0); fsnotify(mask, inode, FSNOTIFY_EVENT_INODE, NULL, NULL, inode, 0);
} }
/* Notify this dentry's parent about a child's events. */ /* Notify this dentry's parent about a child's events. */
...@@ -61,7 +62,7 @@ static inline int fsnotify_parent(struct dentry *dentry, __u32 mask, ...@@ -61,7 +62,7 @@ static inline int fsnotify_parent(struct dentry *dentry, __u32 mask,
return __fsnotify_parent(dentry, mask, data, data_type); return __fsnotify_parent(dentry, mask, data, data_type);
notify_child: notify_child:
return fsnotify(inode, mask, data, data_type, NULL, 0); return fsnotify(mask, data, data_type, NULL, NULL, inode, 0);
} }
/* /*
......
...@@ -387,8 +387,9 @@ struct fsnotify_mark { ...@@ -387,8 +387,9 @@ struct fsnotify_mark {
/* called from the vfs helpers */ /* called from the vfs helpers */
/* main fsnotify call to send events */ /* main fsnotify call to send events */
extern int fsnotify(struct inode *to_tell, __u32 mask, const void *data, extern int fsnotify(__u32 mask, const void *data, int data_type,
int data_type, const struct qstr *name, u32 cookie); struct inode *dir, const struct qstr *name,
struct inode *inode, u32 cookie);
extern int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data, extern int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data,
int data_type); int data_type);
extern void __fsnotify_inode_delete(struct inode *inode); extern void __fsnotify_inode_delete(struct inode *inode);
...@@ -545,8 +546,9 @@ static inline void fsnotify_init_event(struct fsnotify_event *event, ...@@ -545,8 +546,9 @@ static inline void fsnotify_init_event(struct fsnotify_event *event,
#else #else
static inline int fsnotify(struct inode *to_tell, __u32 mask, const void *data, static inline int fsnotify(__u32 mask, const void *data, int data_type,
int data_type, const struct qstr *name, u32 cookie) struct inode *dir, const struct qstr *name,
struct inode *inode, u32 cookie)
{ {
return 0; return 0;
} }
......
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