Commit b9a1b977 authored by Amir Goldstein's avatar Amir Goldstein Committed by Jan Kara

fsnotify: create method handle_inode_event() in fsnotify_operations

The method handle_event() grew a lot of complexity due to the design of
fanotify and merging of ignore masks.

Most backends do not care about this complex functionality, so we can hide
this complexity from them.

Introduce a method handle_inode_event() that serves those backends and
passes a single inode mark and less arguments.

This change converts all backends except fanotify and inotify to use the
simplified handle_inode_event() method.  In pricipal, inotify could have
also used the new method, but that would require passing more arguments
on the simple helper (data, data_type, cookie), so we leave it with the
handle_event() method.

Link: https://lore.kernel.org/r/20200722125849.17418-9-amir73il@gmail.comSuggested-by: default avatarJan Kara <jack@suse.cz>
Signed-off-by: default avatarAmir Goldstein <amir73il@gmail.com>
Signed-off-by: default avatarJan Kara <jack@suse.cz>
parent 691d9763
...@@ -598,14 +598,10 @@ static struct notifier_block nfsd_file_lease_notifier = { ...@@ -598,14 +598,10 @@ static struct notifier_block nfsd_file_lease_notifier = {
}; };
static int static int
nfsd_file_fsnotify_handle_event(struct fsnotify_group *group, u32 mask, nfsd_file_fsnotify_handle_event(struct fsnotify_mark *mark, u32 mask,
const void *data, int data_type, struct inode *inode, struct inode *dir,
struct inode *dir, const struct qstr *name)
const struct qstr *file_name, u32 cookie,
struct fsnotify_iter_info *iter_info)
{ {
struct inode *inode = fsnotify_data_inode(data, data_type);
trace_nfsd_file_fsnotify_handle_event(inode, mask); trace_nfsd_file_fsnotify_handle_event(inode, mask);
/* Should be no marks on non-regular files */ /* Should be no marks on non-regular files */
...@@ -626,7 +622,7 @@ nfsd_file_fsnotify_handle_event(struct fsnotify_group *group, u32 mask, ...@@ -626,7 +622,7 @@ nfsd_file_fsnotify_handle_event(struct fsnotify_group *group, u32 mask,
static const struct fsnotify_ops nfsd_file_fsnotify_ops = { static const struct fsnotify_ops nfsd_file_fsnotify_ops = {
.handle_event = nfsd_file_fsnotify_handle_event, .handle_inode_event = nfsd_file_fsnotify_handle_event,
.free_mark = nfsd_file_mark_free, .free_mark = nfsd_file_mark_free,
}; };
......
...@@ -70,8 +70,9 @@ static void dnotify_recalc_inode_mask(struct fsnotify_mark *fsn_mark) ...@@ -70,8 +70,9 @@ static void dnotify_recalc_inode_mask(struct fsnotify_mark *fsn_mark)
* destroy the dnotify struct if it was not registered to receive multiple * destroy the dnotify struct if it was not registered to receive multiple
* events. * events.
*/ */
static void dnotify_one_event(struct fsnotify_group *group, u32 mask, static int dnotify_handle_event(struct fsnotify_mark *inode_mark, u32 mask,
struct fsnotify_mark *inode_mark) struct inode *inode, struct inode *dir,
const struct qstr *name)
{ {
struct dnotify_mark *dn_mark; struct dnotify_mark *dn_mark;
struct dnotify_struct *dn; struct dnotify_struct *dn;
...@@ -79,6 +80,10 @@ static void dnotify_one_event(struct fsnotify_group *group, u32 mask, ...@@ -79,6 +80,10 @@ static void dnotify_one_event(struct fsnotify_group *group, u32 mask,
struct fown_struct *fown; struct fown_struct *fown;
__u32 test_mask = mask & ~FS_EVENT_ON_CHILD; __u32 test_mask = mask & ~FS_EVENT_ON_CHILD;
/* not a dir, dnotify doesn't care */
if (!dir && !(mask & FS_ISDIR))
return 0;
dn_mark = container_of(inode_mark, struct dnotify_mark, fsn_mark); dn_mark = container_of(inode_mark, struct dnotify_mark, fsn_mark);
spin_lock(&inode_mark->lock); spin_lock(&inode_mark->lock);
...@@ -100,33 +105,6 @@ static void dnotify_one_event(struct fsnotify_group *group, u32 mask, ...@@ -100,33 +105,6 @@ static void dnotify_one_event(struct fsnotify_group *group, u32 mask,
} }
spin_unlock(&inode_mark->lock); spin_unlock(&inode_mark->lock);
}
static int dnotify_handle_event(struct fsnotify_group *group, u32 mask,
const void *data, int data_type,
struct inode *dir,
const struct qstr *file_name, u32 cookie,
struct fsnotify_iter_info *iter_info)
{
struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info);
struct fsnotify_mark *child_mark = fsnotify_iter_child_mark(iter_info);
/* not a dir, dnotify doesn't care */
if (!dir && !(mask & FS_ISDIR))
return 0;
if (WARN_ON(fsnotify_iter_vfsmount_mark(iter_info)))
return 0;
/*
* Some events can be sent on both parent dir and subdir marks
* (e.g. DN_ATTRIB). If both parent dir and subdir are watching,
* report the event once to parent dir and once to subdir.
*/
if (inode_mark)
dnotify_one_event(group, mask, inode_mark);
if (child_mark)
dnotify_one_event(group, mask, child_mark);
return 0; return 0;
} }
...@@ -143,7 +121,7 @@ static void dnotify_free_mark(struct fsnotify_mark *fsn_mark) ...@@ -143,7 +121,7 @@ static void dnotify_free_mark(struct fsnotify_mark *fsn_mark)
} }
static const struct fsnotify_ops dnotify_fsnotify_ops = { static const struct fsnotify_ops dnotify_fsnotify_ops = {
.handle_event = dnotify_handle_event, .handle_inode_event = dnotify_handle_event,
.free_mark = dnotify_free_mark, .free_mark = dnotify_free_mark,
}; };
......
...@@ -230,6 +230,49 @@ int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data, ...@@ -230,6 +230,49 @@ int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data,
} }
EXPORT_SYMBOL_GPL(__fsnotify_parent); EXPORT_SYMBOL_GPL(__fsnotify_parent);
static int fsnotify_handle_event(struct fsnotify_group *group, __u32 mask,
const void *data, int data_type,
struct inode *dir, const struct qstr *name,
u32 cookie, struct fsnotify_iter_info *iter_info)
{
struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info);
struct fsnotify_mark *child_mark = fsnotify_iter_child_mark(iter_info);
struct inode *inode = fsnotify_data_inode(data, data_type);
const struct fsnotify_ops *ops = group->ops;
int ret;
if (WARN_ON_ONCE(!ops->handle_inode_event))
return 0;
if (WARN_ON_ONCE(fsnotify_iter_sb_mark(iter_info)) ||
WARN_ON_ONCE(fsnotify_iter_vfsmount_mark(iter_info)))
return 0;
/*
* An event can be sent on child mark iterator instead of inode mark
* iterator because of other groups that have interest of this inode
* and have marks on both parent and child. We can simplify this case.
*/
if (!inode_mark) {
inode_mark = child_mark;
child_mark = NULL;
dir = NULL;
name = NULL;
}
ret = ops->handle_inode_event(inode_mark, mask, inode, dir, name);
if (ret || !child_mark)
return ret;
/*
* Some events can be sent on both parent dir and child marks
* (e.g. FS_ATTRIB). If both parent dir and child are watching,
* report the event once to parent dir with name and once to child
* without name.
*/
return ops->handle_inode_event(child_mark, mask, inode, NULL, NULL);
}
static int send_to_group(__u32 mask, const void *data, int data_type, static int send_to_group(__u32 mask, const void *data, int data_type,
struct inode *dir, const struct qstr *file_name, struct inode *dir, const struct qstr *file_name,
u32 cookie, struct fsnotify_iter_info *iter_info) u32 cookie, struct fsnotify_iter_info *iter_info)
...@@ -275,8 +318,13 @@ static int send_to_group(__u32 mask, const void *data, int data_type, ...@@ -275,8 +318,13 @@ static int send_to_group(__u32 mask, const void *data, int data_type,
if (!(test_mask & marks_mask & ~marks_ignored_mask)) if (!(test_mask & marks_mask & ~marks_ignored_mask))
return 0; return 0;
return group->ops->handle_event(group, mask, data, data_type, dir, if (group->ops->handle_event) {
file_name, cookie, iter_info); return group->ops->handle_event(group, mask, data, data_type, dir,
file_name, cookie, iter_info);
}
return fsnotify_handle_event(group, mask, data, data_type, dir,
file_name, cookie, iter_info);
} }
static struct fsnotify_mark *fsnotify_first_mark(struct fsnotify_mark_connector **connp) static struct fsnotify_mark *fsnotify_first_mark(struct fsnotify_mark_connector **connp)
......
...@@ -128,17 +128,30 @@ struct mem_cgroup; ...@@ -128,17 +128,30 @@ struct mem_cgroup;
* @cookie: inotify rename cookie * @cookie: inotify rename cookie
* @iter_info: array of marks from this group that are interested in the event * @iter_info: array of marks from this group that are interested in the event
* *
* handle_inode_event - simple variant of handle_event() for groups that only
* have inode marks and don't have ignore mask
* @mark: mark to notify
* @mask: event type and flags
* @inode: inode that event happened on
* @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
*
* free_group_priv - called when a group refcnt hits 0 to clean up the private union * free_group_priv - called when a group refcnt hits 0 to clean up the private union
* freeing_mark - called when a mark is being destroyed for some reason. The group * freeing_mark - called when a mark is being destroyed for some reason. The group
* MUST be holding a reference on each mark and that reference must be * MUST be holding a reference on each mark and that reference must be
* dropped in this function. inotify uses this function to send * dropped in this function. inotify uses this function to send
* userspace messages that marks have been removed. * userspace messages that marks have been removed.
*/ */
struct fsnotify_ops { struct fsnotify_ops {
int (*handle_event)(struct fsnotify_group *group, u32 mask, int (*handle_event)(struct fsnotify_group *group, u32 mask,
const void *data, int data_type, struct inode *dir, const void *data, int data_type, struct inode *dir,
const struct qstr *file_name, u32 cookie, const struct qstr *file_name, u32 cookie,
struct fsnotify_iter_info *iter_info); struct fsnotify_iter_info *iter_info);
int (*handle_inode_event)(struct fsnotify_mark *mark, u32 mask,
struct inode *inode, struct inode *dir,
const struct qstr *file_name);
void (*free_group_priv)(struct fsnotify_group *group); void (*free_group_priv)(struct fsnotify_group *group);
void (*freeing_mark)(struct fsnotify_mark *mark, struct fsnotify_group *group); void (*freeing_mark)(struct fsnotify_mark *mark, struct fsnotify_group *group);
void (*free_event)(struct fsnotify_event *event); void (*free_event)(struct fsnotify_event *event);
......
...@@ -152,35 +152,31 @@ static void audit_autoremove_mark_rule(struct audit_fsnotify_mark *audit_mark) ...@@ -152,35 +152,31 @@ static void audit_autoremove_mark_rule(struct audit_fsnotify_mark *audit_mark)
} }
/* Update mark data in audit rules based on fsnotify events. */ /* Update mark data in audit rules based on fsnotify events. */
static int audit_mark_handle_event(struct fsnotify_group *group, u32 mask, static int audit_mark_handle_event(struct fsnotify_mark *inode_mark, u32 mask,
const void *data, int data_type, struct inode *inode, struct inode *dir,
struct inode *dir, const struct qstr *dname)
const struct qstr *dname, u32 cookie,
struct fsnotify_iter_info *iter_info)
{ {
struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info);
struct audit_fsnotify_mark *audit_mark; struct audit_fsnotify_mark *audit_mark;
const struct inode *inode = fsnotify_data_inode(data, data_type);
audit_mark = container_of(inode_mark, struct audit_fsnotify_mark, mark); audit_mark = container_of(inode_mark, struct audit_fsnotify_mark, mark);
BUG_ON(group != audit_fsnotify_group); if (WARN_ON_ONCE(inode_mark->group != audit_fsnotify_group) ||
WARN_ON_ONCE(!inode))
if (WARN_ON(!inode))
return 0; return 0;
if (mask & (FS_CREATE|FS_MOVED_TO|FS_DELETE|FS_MOVED_FROM)) { if (mask & (FS_CREATE|FS_MOVED_TO|FS_DELETE|FS_MOVED_FROM)) {
if (audit_compare_dname_path(dname, audit_mark->path, AUDIT_NAME_FULL)) if (audit_compare_dname_path(dname, audit_mark->path, AUDIT_NAME_FULL))
return 0; return 0;
audit_update_mark(audit_mark, inode); audit_update_mark(audit_mark, inode);
} else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF)) } else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF)) {
audit_autoremove_mark_rule(audit_mark); audit_autoremove_mark_rule(audit_mark);
}
return 0; return 0;
} }
static const struct fsnotify_ops audit_mark_fsnotify_ops = { static const struct fsnotify_ops audit_mark_fsnotify_ops = {
.handle_event = audit_mark_handle_event, .handle_inode_event = audit_mark_handle_event,
.free_mark = audit_fsnotify_free_mark, .free_mark = audit_fsnotify_free_mark,
}; };
......
...@@ -1037,11 +1037,9 @@ static void evict_chunk(struct audit_chunk *chunk) ...@@ -1037,11 +1037,9 @@ static void evict_chunk(struct audit_chunk *chunk)
audit_schedule_prune(); audit_schedule_prune();
} }
static int audit_tree_handle_event(struct fsnotify_group *group, u32 mask, static int audit_tree_handle_event(struct fsnotify_mark *mark, u32 mask,
const void *data, int data_type, struct inode *inode, struct inode *dir,
struct inode *dir, const struct qstr *file_name)
const struct qstr *file_name, u32 cookie,
struct fsnotify_iter_info *iter_info)
{ {
return 0; return 0;
} }
...@@ -1070,7 +1068,7 @@ static void audit_tree_freeing_mark(struct fsnotify_mark *mark, ...@@ -1070,7 +1068,7 @@ static void audit_tree_freeing_mark(struct fsnotify_mark *mark,
} }
static const struct fsnotify_ops audit_tree_ops = { static const struct fsnotify_ops audit_tree_ops = {
.handle_event = audit_tree_handle_event, .handle_inode_event = audit_tree_handle_event,
.freeing_mark = audit_tree_freeing_mark, .freeing_mark = audit_tree_freeing_mark,
.free_mark = audit_tree_destroy_watch, .free_mark = audit_tree_destroy_watch,
}; };
......
...@@ -464,20 +464,17 @@ void audit_remove_watch_rule(struct audit_krule *krule) ...@@ -464,20 +464,17 @@ void audit_remove_watch_rule(struct audit_krule *krule)
} }
/* Update watch data in audit rules based on fsnotify events. */ /* Update watch data in audit rules based on fsnotify events. */
static int audit_watch_handle_event(struct fsnotify_group *group, u32 mask, static int audit_watch_handle_event(struct fsnotify_mark *inode_mark, u32 mask,
const void *data, int data_type, struct inode *inode, struct inode *dir,
struct inode *dir, const struct qstr *dname)
const struct qstr *dname, u32 cookie,
struct fsnotify_iter_info *iter_info)
{ {
struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info);
const struct inode *inode = fsnotify_data_inode(data, data_type);
struct audit_parent *parent; struct audit_parent *parent;
parent = container_of(inode_mark, struct audit_parent, mark); parent = container_of(inode_mark, struct audit_parent, mark);
BUG_ON(group != audit_watch_group); if (WARN_ON_ONCE(inode_mark->group != audit_watch_group) ||
WARN_ON(!inode); WARN_ON_ONCE(!inode))
return 0;
if (mask & (FS_CREATE|FS_MOVED_TO) && inode) if (mask & (FS_CREATE|FS_MOVED_TO) && inode)
audit_update_watch(parent, dname, inode->i_sb->s_dev, inode->i_ino, 0); audit_update_watch(parent, dname, inode->i_sb->s_dev, inode->i_ino, 0);
...@@ -490,7 +487,7 @@ static int audit_watch_handle_event(struct fsnotify_group *group, u32 mask, ...@@ -490,7 +487,7 @@ static int audit_watch_handle_event(struct fsnotify_group *group, u32 mask,
} }
static const struct fsnotify_ops audit_watch_fsnotify_ops = { static const struct fsnotify_ops audit_watch_fsnotify_ops = {
.handle_event = audit_watch_handle_event, .handle_inode_event = audit_watch_handle_event,
.free_mark = audit_watch_free_mark, .free_mark = audit_watch_free_mark,
}; };
......
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