@@ -72,7 +72,7 @@ static int fanotify_get_response(struct fsnotify_group *group,
/* userspace responded, convert to something usable */
switch (event->response) {
case FAN_ALLOW:
- ret = 0;
+ ret = FSNOTIFY_DONE;
break;
case FAN_DENY:
default:
@@ -193,7 +193,7 @@ static int fanotify_handle_event(struct fsnotify_group *group,
if (!fanotify_should_send_event(inode_mark, fanotify_mark, mask, data,
data_type))
- return 0;
+ return FSNOTIFY_DROPPED;
pr_debug("%s: group=%p inode=%p mask=%x\n", __func__, group, inode,
mask);
@@ -210,7 +210,7 @@ static int fanotify_handle_event(struct fsnotify_group *group,
/* Our event wasn't used in the end. Free it. */
fsnotify_destroy_event(group, fsn_event);
- return 0;
+ return FSNOTIFY_DONE;
}
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
@@ -189,7 +189,7 @@ static int send_to_group(struct inode *to_tell,
ignored_mask, data, data_is, cookie);
if (!inode_test_mask && !vfsmount_test_mask)
- return 0;
+ return FSNOTIFY_DROPPED;
return group->ops->handle_event(group, to_tell, inode_mark,
vfsmount_mark, mask, data, data_is,
@@ -290,7 +290,7 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is,
ret = send_to_group(to_tell, inode_mark, vfsmount_mark, mask,
data, data_is, cookie, file_name);
- if (ret && (mask & ALL_FSNOTIFY_PERM_EVENTS))
+ if (ret < 0 && (mask & ALL_FSNOTIFY_PERM_EVENTS))
goto out;
if (inode_group)
@@ -81,6 +81,22 @@ struct fsnotify_event_private_data;
struct fsnotify_fname;
/*
+ * handle_event() may return a negative error value or one of the values below.
+ * FSNOTIFY_DONE indicates that the group has processed the event and that
+ * there is no need for the group to handle the same event again.
+ * FSNOTIFY_DROPPED indicates that event was not acted upon by group nor did
+ * it change any group internal state.
+ * This semantic difference matters in case there are several marks of the same
+ * group (i.e. vfsmount_mark and inode_mark) that may process the same event.
+ * If handle_event() with one of the marks returns FSNOTIFY_DONE, the event
+ * won't be sent to the other group marks.
+ * If handle_event() with one of the marks returns FSNOTIFY_DROPPED, the event
+ * will be sent to the other group marks.
+ */
+#define FSNOTIFY_DONE 0 /* group is done handling this event */
+#define FSNOTIFY_DROPPED 1 /* group did not handle this event */
+
+/*
* Each group much define these ops. The fsnotify infrastructure will call
* these operations for each relevant group.
*
The handle_event() op returns a negative value on error and 0 on success - when event was either queued, merged, delivered (permission) or dropped. Split the single success 0 value to 2 return values: FSNOTIFY_DONE (0) indicates that the group has processed the event (e.g. queued, merged, delivered), which may have also changed group interenal state. FSNOTIFY_DROPPED (1) indicates that event was not acted upon by group nor did it change any group internal state. This semantic difference matters in case there are several marks of the same group (i.e. vfsmount_mark and inode_mark) that may process the same event. If handle_event() with one of the marks returns FSNOTIFY_DONE, the event won't be sent to the other group marks. If handle_event() with one of the marks returns FSNOTIFY_DROPPED, the event will be sent to the other group marks. This change has no visible effects, because fsnotify() ignores non-negative return values from handle_event(). Only fanotify_handle_event() and the common should_send_to_group() functions were modified to return FSNOTIFY_DROPPED, because the rest of the backends don't support vfsmount marks, so they are not aware of this semantic change. Signed-off-by: Amir Goldstein <amir73il@gmail.com> --- fs/notify/fanotify/fanotify.c | 6 +++--- fs/notify/fsnotify.c | 4 ++-- include/linux/fsnotify_backend.h | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 5 deletions(-)