@@ -237,6 +237,7 @@ static int fanotify_handle_event(struct fsnotify_group *group,
BUILD_BUG_ON(FAN_DELETE_SELF != FS_DELETE_SELF);
BUILD_BUG_ON(FAN_MOVE_SELF != FS_MOVE_SELF);
BUILD_BUG_ON(FAN_EVENT_ON_CHILD != FS_EVENT_ON_CHILD);
+ BUILD_BUG_ON(FAN_EVENT_ON_SB != FS_EVENT_ON_SB);
BUILD_BUG_ON(FAN_Q_OVERFLOW != FS_Q_OVERFLOW);
BUILD_BUG_ON(FAN_OPEN_PERM != FS_OPEN_PERM);
BUILD_BUG_ON(FAN_ACCESS_PERM != FS_ACCESS_PERM);
@@ -902,9 +902,9 @@ SYSCALL_DEFINE5(fanotify_mark, int, fanotify_fd, unsigned int, flags,
}
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
- if (mask & ~(FAN_ALL_EVENTS | FAN_ALL_PERM_EVENTS | FAN_EVENT_ON_CHILD))
+ if (mask & ~(FAN_ALL_EVENTS | FAN_ALL_PERM_EVENTS | FAN_EVENT_ON_DESCENDANT))
#else
- if (mask & ~(FAN_ALL_EVENTS | FAN_EVENT_ON_CHILD))
+ if (mask & ~(FAN_ALL_EVENTS | FAN_EVENT_ON_DESCENDANT))
#endif
return -EINVAL;
@@ -927,6 +927,12 @@ SYSCALL_DEFINE5(fanotify_mark, int, fanotify_fd, unsigned int, flags,
group->priority == FS_PRIO_0)
goto fput_and_out;
+ /* Super block root watch is not a mount watch */
+ ret = -EINVAL;
+ if ((mask & FAN_EVENT_ON_SB) &&
+ (flags & FAN_MARK_MOUNT))
+ goto fput_and_out;
+
if (flags & FAN_MARK_FLUSH) {
ret = 0;
if (flags & FAN_MARK_MOUNT)
@@ -941,7 +947,9 @@ SYSCALL_DEFINE5(fanotify_mark, int, fanotify_fd, unsigned int, flags,
goto fput_and_out;
/* inode held in place by reference to path; group by fget on fd */
- if (!(flags & FAN_MARK_MOUNT))
+ if (mask & FAN_EVENT_ON_SB)
+ inode = path.dentry->d_sb->s_root->d_inode;
+ else if (!(flags & FAN_MARK_MOUNT))
inode = path.dentry->d_inode;
/*
@@ -950,6 +958,7 @@ SYSCALL_DEFINE5(fanotify_mark, int, fanotify_fd, unsigned int, flags,
* even if the events happened on another mount point.
*/
if ((flags & FAN_MARK_MOUNT) ||
+ (mask & FAN_EVENT_ON_SB) ||
group->fanotify_data.flags & FAN_EVENT_INFO_PARENT)
mnt = path.mnt;
@@ -25,8 +25,11 @@
#define FAN_ONDIR 0x40000000 /* event occurred against dir */
+#define FAN_EVENT_ON_SB 0x01000000 /* interested in all sb inodes */
#define FAN_EVENT_ON_CHILD 0x08000000 /* interested in child events */
+#define FAN_EVENT_ON_DESCENDANT (FAN_EVENT_ON_CHILD | FAN_EVENT_ON_SB)
+
/* helper events */
#define FAN_CLOSE (FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE) /* close */
#define FAN_MOVE (FAN_MOVED_FROM | FAN_MOVED_TO) /* moves */
Set a watch on the super block's root inode including the mask bit FAN_EVENT_ON_SB to get notified on the events of all the inodes on the same super block. When requesting to add a super block root watch, any file on the file system can be passed as input argument for fanotify_mark(). The mark will be added to the root inode of the file system that file belongs to. The super block watch cannot be set with FAN_MARK_MOUNT flag, because a super block watch is an inode mark, not a mount mark. Signed-off-by: Amir Goldstein <amir73il@gmail.com> --- fs/notify/fanotify/fanotify.c | 1 + fs/notify/fanotify/fanotify_user.c | 15 ++++++++++++--- include/uapi/linux/fanotify.h | 3 +++ 3 files changed, 16 insertions(+), 3 deletions(-)