Merge tag 'fsnotify_for_v5.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
Pull fsnotify updates from Jan Kara: - support for FAN_MARK_IGNORE which untangles some of the not well defined corner cases with fanotify ignore masks - small cleanups * tag 'fsnotify_for_v5.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs: fsnotify: Fix comment typo fanotify: introduce FAN_MARK_IGNORE fanotify: cleanups for fanotify_mark() input validations fanotify: prepare for setting event flags in ignore mask fs: inotify: Fix typo in inotify comment
This commit is contained in:
@@ -295,12 +295,13 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
|
||||
const void *data, int data_type,
|
||||
struct inode *dir)
|
||||
{
|
||||
__u32 marks_mask = 0, marks_ignored_mask = 0;
|
||||
__u32 marks_mask = 0, marks_ignore_mask = 0;
|
||||
__u32 test_mask, user_mask = FANOTIFY_OUTGOING_EVENTS |
|
||||
FANOTIFY_EVENT_FLAGS;
|
||||
const struct path *path = fsnotify_data_path(data, data_type);
|
||||
unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS);
|
||||
struct fsnotify_mark *mark;
|
||||
bool ondir = event_mask & FAN_ONDIR;
|
||||
int type;
|
||||
|
||||
pr_debug("%s: report_mask=%x mask=%x data=%p data_type=%d\n",
|
||||
@@ -315,19 +316,21 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
|
||||
return 0;
|
||||
} else if (!(fid_mode & FAN_REPORT_FID)) {
|
||||
/* Do we have a directory inode to report? */
|
||||
if (!dir && !(event_mask & FS_ISDIR))
|
||||
if (!dir && !ondir)
|
||||
return 0;
|
||||
}
|
||||
|
||||
fsnotify_foreach_iter_mark_type(iter_info, mark, type) {
|
||||
/* Apply ignore mask regardless of mark's ISDIR flag */
|
||||
marks_ignored_mask |= mark->ignored_mask;
|
||||
/*
|
||||
* Apply ignore mask depending on event flags in ignore mask.
|
||||
*/
|
||||
marks_ignore_mask |=
|
||||
fsnotify_effective_ignore_mask(mark, ondir, type);
|
||||
|
||||
/*
|
||||
* If the event is on dir and this mark doesn't care about
|
||||
* events on dir, don't send it!
|
||||
* Send the event depending on event flags in mark mask.
|
||||
*/
|
||||
if (event_mask & FS_ISDIR && !(mark->mask & FS_ISDIR))
|
||||
if (!fsnotify_mask_applicable(mark->mask, ondir, type))
|
||||
continue;
|
||||
|
||||
marks_mask |= mark->mask;
|
||||
@@ -336,7 +339,7 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
|
||||
*match_mask |= 1U << type;
|
||||
}
|
||||
|
||||
test_mask = event_mask & marks_mask & ~marks_ignored_mask;
|
||||
test_mask = event_mask & marks_mask & ~marks_ignore_mask;
|
||||
|
||||
/*
|
||||
* For dirent modification events (create/delete/move) that do not carry
|
||||
|
||||
@@ -499,6 +499,8 @@ static inline unsigned int fanotify_mark_user_flags(struct fsnotify_mark *mark)
|
||||
mflags |= FAN_MARK_IGNORED_SURV_MODIFY;
|
||||
if (mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF)
|
||||
mflags |= FAN_MARK_EVICTABLE;
|
||||
if (mark->flags & FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS)
|
||||
mflags |= FAN_MARK_IGNORE;
|
||||
|
||||
return mflags;
|
||||
}
|
||||
|
||||
@@ -1009,10 +1009,10 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark,
|
||||
mask &= ~umask;
|
||||
spin_lock(&fsn_mark->lock);
|
||||
oldmask = fsnotify_calc_mask(fsn_mark);
|
||||
if (!(flags & FAN_MARK_IGNORED_MASK)) {
|
||||
if (!(flags & FANOTIFY_MARK_IGNORE_BITS)) {
|
||||
fsn_mark->mask &= ~mask;
|
||||
} else {
|
||||
fsn_mark->ignored_mask &= ~mask;
|
||||
fsn_mark->ignore_mask &= ~mask;
|
||||
}
|
||||
newmask = fsnotify_calc_mask(fsn_mark);
|
||||
/*
|
||||
@@ -1021,7 +1021,7 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark,
|
||||
* changes to the mask.
|
||||
* Destroy mark when only umask bits remain.
|
||||
*/
|
||||
*destroy = !((fsn_mark->mask | fsn_mark->ignored_mask) & ~umask);
|
||||
*destroy = !((fsn_mark->mask | fsn_mark->ignore_mask) & ~umask);
|
||||
spin_unlock(&fsn_mark->lock);
|
||||
|
||||
return oldmask & ~newmask;
|
||||
@@ -1085,15 +1085,24 @@ static bool fanotify_mark_update_flags(struct fsnotify_mark *fsn_mark,
|
||||
unsigned int fan_flags)
|
||||
{
|
||||
bool want_iref = !(fan_flags & FAN_MARK_EVICTABLE);
|
||||
unsigned int ignore = fan_flags & FANOTIFY_MARK_IGNORE_BITS;
|
||||
bool recalc = false;
|
||||
|
||||
/*
|
||||
* When using FAN_MARK_IGNORE for the first time, mark starts using
|
||||
* independent event flags in ignore mask. After that, trying to
|
||||
* update the ignore mask with the old FAN_MARK_IGNORED_MASK API
|
||||
* will result in EEXIST error.
|
||||
*/
|
||||
if (ignore == FAN_MARK_IGNORE)
|
||||
fsn_mark->flags |= FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS;
|
||||
|
||||
/*
|
||||
* Setting FAN_MARK_IGNORED_SURV_MODIFY for the first time may lead to
|
||||
* the removal of the FS_MODIFY bit in calculated mask if it was set
|
||||
* because of an ignored mask that is now going to survive FS_MODIFY.
|
||||
* because of an ignore mask that is now going to survive FS_MODIFY.
|
||||
*/
|
||||
if ((fan_flags & FAN_MARK_IGNORED_MASK) &&
|
||||
(fan_flags & FAN_MARK_IGNORED_SURV_MODIFY) &&
|
||||
if (ignore && (fan_flags & FAN_MARK_IGNORED_SURV_MODIFY) &&
|
||||
!(fsn_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) {
|
||||
fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY;
|
||||
if (!(fsn_mark->mask & FS_MODIFY))
|
||||
@@ -1120,10 +1129,10 @@ static bool fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark,
|
||||
bool recalc;
|
||||
|
||||
spin_lock(&fsn_mark->lock);
|
||||
if (!(fan_flags & FAN_MARK_IGNORED_MASK))
|
||||
if (!(fan_flags & FANOTIFY_MARK_IGNORE_BITS))
|
||||
fsn_mark->mask |= mask;
|
||||
else
|
||||
fsn_mark->ignored_mask |= mask;
|
||||
fsn_mark->ignore_mask |= mask;
|
||||
|
||||
recalc = fsnotify_calc_mask(fsn_mark) &
|
||||
~fsnotify_conn_mask(fsn_mark->connector);
|
||||
@@ -1187,6 +1196,37 @@ static int fanotify_group_init_error_pool(struct fsnotify_group *group)
|
||||
sizeof(struct fanotify_error_event));
|
||||
}
|
||||
|
||||
static int fanotify_may_update_existing_mark(struct fsnotify_mark *fsn_mark,
|
||||
unsigned int fan_flags)
|
||||
{
|
||||
/*
|
||||
* Non evictable mark cannot be downgraded to evictable mark.
|
||||
*/
|
||||
if (fan_flags & FAN_MARK_EVICTABLE &&
|
||||
!(fsn_mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF))
|
||||
return -EEXIST;
|
||||
|
||||
/*
|
||||
* New ignore mask semantics cannot be downgraded to old semantics.
|
||||
*/
|
||||
if (fan_flags & FAN_MARK_IGNORED_MASK &&
|
||||
fsn_mark->flags & FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS)
|
||||
return -EEXIST;
|
||||
|
||||
/*
|
||||
* An ignore mask that survives modify could never be downgraded to not
|
||||
* survive modify. With new FAN_MARK_IGNORE semantics we make that rule
|
||||
* explicit and return an error when trying to update the ignore mask
|
||||
* without the original FAN_MARK_IGNORED_SURV_MODIFY value.
|
||||
*/
|
||||
if (fan_flags & FAN_MARK_IGNORE &&
|
||||
!(fan_flags & FAN_MARK_IGNORED_SURV_MODIFY) &&
|
||||
fsn_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)
|
||||
return -EEXIST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fanotify_add_mark(struct fsnotify_group *group,
|
||||
fsnotify_connp_t *connp, unsigned int obj_type,
|
||||
__u32 mask, unsigned int fan_flags,
|
||||
@@ -1208,19 +1248,18 @@ static int fanotify_add_mark(struct fsnotify_group *group,
|
||||
}
|
||||
|
||||
/*
|
||||
* Non evictable mark cannot be downgraded to evictable mark.
|
||||
* Check if requested mark flags conflict with an existing mark flags.
|
||||
*/
|
||||
if (fan_flags & FAN_MARK_EVICTABLE &&
|
||||
!(fsn_mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF)) {
|
||||
ret = -EEXIST;
|
||||
ret = fanotify_may_update_existing_mark(fsn_mark, fan_flags);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Error events are pre-allocated per group, only if strictly
|
||||
* needed (i.e. FAN_FS_ERROR was requested).
|
||||
*/
|
||||
if (!(fan_flags & FAN_MARK_IGNORED_MASK) && (mask & FAN_FS_ERROR)) {
|
||||
if (!(fan_flags & FANOTIFY_MARK_IGNORE_BITS) &&
|
||||
(mask & FAN_FS_ERROR)) {
|
||||
ret = fanotify_group_init_error_pool(group);
|
||||
if (ret)
|
||||
goto out;
|
||||
@@ -1261,10 +1300,10 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group,
|
||||
|
||||
/*
|
||||
* If some other task has this inode open for write we should not add
|
||||
* an ignored mark, unless that ignored mark is supposed to survive
|
||||
* an ignore mask, unless that ignore mask is supposed to survive
|
||||
* modification changes anyway.
|
||||
*/
|
||||
if ((flags & FAN_MARK_IGNORED_MASK) &&
|
||||
if ((flags & FANOTIFY_MARK_IGNORE_BITS) &&
|
||||
!(flags & FAN_MARK_IGNORED_SURV_MODIFY) &&
|
||||
inode_is_open_for_write(inode))
|
||||
return 0;
|
||||
@@ -1520,7 +1559,8 @@ static int fanotify_events_supported(struct fsnotify_group *group,
|
||||
unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS;
|
||||
/* Strict validation of events in non-dir inode mask with v5.17+ APIs */
|
||||
bool strict_dir_events = FAN_GROUP_FLAG(group, FAN_REPORT_TARGET_FID) ||
|
||||
(mask & FAN_RENAME);
|
||||
(mask & FAN_RENAME) ||
|
||||
(flags & FAN_MARK_IGNORE);
|
||||
|
||||
/*
|
||||
* Some filesystems such as 'proc' acquire unusual locks when opening
|
||||
@@ -1557,7 +1597,8 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
|
||||
__kernel_fsid_t __fsid, *fsid = NULL;
|
||||
u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS;
|
||||
unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS;
|
||||
bool ignored = flags & FAN_MARK_IGNORED_MASK;
|
||||
unsigned int mark_cmd = flags & FANOTIFY_MARK_CMD_BITS;
|
||||
unsigned int ignore = flags & FANOTIFY_MARK_IGNORE_BITS;
|
||||
unsigned int obj_type, fid_mode;
|
||||
u32 umask = 0;
|
||||
int ret;
|
||||
@@ -1586,7 +1627,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) {
|
||||
switch (mark_cmd) {
|
||||
case FAN_MARK_ADD:
|
||||
case FAN_MARK_REMOVE:
|
||||
if (!mask)
|
||||
@@ -1606,9 +1647,19 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
|
||||
if (mask & ~valid_mask)
|
||||
return -EINVAL;
|
||||
|
||||
/* Event flags (ONDIR, ON_CHILD) are meaningless in ignored mask */
|
||||
if (ignored)
|
||||
|
||||
/* We don't allow FAN_MARK_IGNORE & FAN_MARK_IGNORED_MASK together */
|
||||
if (ignore == (FAN_MARK_IGNORE | FAN_MARK_IGNORED_MASK))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Event flags (FAN_ONDIR, FAN_EVENT_ON_CHILD) have no effect with
|
||||
* FAN_MARK_IGNORED_MASK.
|
||||
*/
|
||||
if (ignore == FAN_MARK_IGNORED_MASK) {
|
||||
mask &= ~FANOTIFY_EVENT_FLAGS;
|
||||
umask = FANOTIFY_EVENT_FLAGS;
|
||||
}
|
||||
|
||||
f = fdget(fanotify_fd);
|
||||
if (unlikely(!f.file))
|
||||
@@ -1672,7 +1723,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
|
||||
if (mask & FAN_RENAME && !(fid_mode & FAN_REPORT_NAME))
|
||||
goto fput_and_out;
|
||||
|
||||
if (flags & FAN_MARK_FLUSH) {
|
||||
if (mark_cmd == FAN_MARK_FLUSH) {
|
||||
ret = 0;
|
||||
if (mark_type == FAN_MARK_MOUNT)
|
||||
fsnotify_clear_vfsmount_marks_by_group(group);
|
||||
@@ -1688,7 +1739,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
|
||||
if (ret)
|
||||
goto fput_and_out;
|
||||
|
||||
if (flags & FAN_MARK_ADD) {
|
||||
if (mark_cmd == FAN_MARK_ADD) {
|
||||
ret = fanotify_events_supported(group, &path, mask, flags);
|
||||
if (ret)
|
||||
goto path_put_and_out;
|
||||
@@ -1712,6 +1763,13 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
|
||||
else
|
||||
mnt = path.mnt;
|
||||
|
||||
ret = mnt ? -EINVAL : -EISDIR;
|
||||
/* FAN_MARK_IGNORE requires SURV_MODIFY for sb/mount/dir marks */
|
||||
if (mark_cmd == FAN_MARK_ADD && ignore == FAN_MARK_IGNORE &&
|
||||
(mnt || S_ISDIR(inode->i_mode)) &&
|
||||
!(flags & FAN_MARK_IGNORED_SURV_MODIFY))
|
||||
goto path_put_and_out;
|
||||
|
||||
/* Mask out FAN_EVENT_ON_CHILD flag for sb/mount/non-dir marks */
|
||||
if (mnt || !S_ISDIR(inode->i_mode)) {
|
||||
mask &= ~FAN_EVENT_ON_CHILD;
|
||||
@@ -1721,12 +1779,12 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
|
||||
* events with parent/name info for non-directory.
|
||||
*/
|
||||
if ((fid_mode & FAN_REPORT_DIR_FID) &&
|
||||
(flags & FAN_MARK_ADD) && !ignored)
|
||||
(flags & FAN_MARK_ADD) && !ignore)
|
||||
mask |= FAN_EVENT_ON_CHILD;
|
||||
}
|
||||
|
||||
/* create/update an inode mark */
|
||||
switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE)) {
|
||||
switch (mark_cmd) {
|
||||
case FAN_MARK_ADD:
|
||||
if (mark_type == FAN_MARK_MOUNT)
|
||||
ret = fanotify_add_vfsmount_mark(group, mnt, mask,
|
||||
@@ -1804,7 +1862,7 @@ static int __init fanotify_user_setup(void)
|
||||
|
||||
BUILD_BUG_ON(FANOTIFY_INIT_FLAGS & FANOTIFY_INTERNAL_GROUP_FLAGS);
|
||||
BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 12);
|
||||
BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 10);
|
||||
BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 11);
|
||||
|
||||
fanotify_mark_cache = KMEM_CACHE(fsnotify_mark,
|
||||
SLAB_PANIC|SLAB_ACCOUNT);
|
||||
|
||||
@@ -113,7 +113,7 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
|
||||
return;
|
||||
seq_printf(m, "fanotify ino:%lx sdev:%x mflags:%x mask:%x ignored_mask:%x ",
|
||||
inode->i_ino, inode->i_sb->s_dev,
|
||||
mflags, mark->mask, mark->ignored_mask);
|
||||
mflags, mark->mask, mark->ignore_mask);
|
||||
show_mark_fhandle(m, inode);
|
||||
seq_putc(m, '\n');
|
||||
iput(inode);
|
||||
@@ -121,12 +121,12 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
|
||||
struct mount *mnt = fsnotify_conn_mount(mark->connector);
|
||||
|
||||
seq_printf(m, "fanotify mnt_id:%x mflags:%x mask:%x ignored_mask:%x\n",
|
||||
mnt->mnt_id, mflags, mark->mask, mark->ignored_mask);
|
||||
mnt->mnt_id, mflags, mark->mask, mark->ignore_mask);
|
||||
} else if (mark->connector->type == FSNOTIFY_OBJ_TYPE_SB) {
|
||||
struct super_block *sb = fsnotify_conn_sb(mark->connector);
|
||||
|
||||
seq_printf(m, "fanotify sdev:%x mflags:%x mask:%x ignored_mask:%x\n",
|
||||
sb->s_dev, mflags, mark->mask, mark->ignored_mask);
|
||||
sb->s_dev, mflags, mark->mask, mark->ignore_mask);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ void fsnotify_sb_delete(struct super_block *sb)
|
||||
* Given an inode, first check if we care what happens to our children. Inotify
|
||||
* and dnotify both tell their parents about events. If we care about any event
|
||||
* on a child we run all of our children and set a dentry flag saying that the
|
||||
* parent cares. Thus when an event happens on a child it can quickly tell if
|
||||
* parent cares. Thus when an event happens on a child it can quickly tell
|
||||
* if there is a need to find a parent and send the event to the parent.
|
||||
*/
|
||||
void __fsnotify_update_child_dentry_flags(struct inode *inode)
|
||||
@@ -324,7 +324,8 @@ static int send_to_group(__u32 mask, const void *data, int data_type,
|
||||
struct fsnotify_group *group = NULL;
|
||||
__u32 test_mask = (mask & ALL_FSNOTIFY_EVENTS);
|
||||
__u32 marks_mask = 0;
|
||||
__u32 marks_ignored_mask = 0;
|
||||
__u32 marks_ignore_mask = 0;
|
||||
bool is_dir = mask & FS_ISDIR;
|
||||
struct fsnotify_mark *mark;
|
||||
int type;
|
||||
|
||||
@@ -336,7 +337,7 @@ static int send_to_group(__u32 mask, const void *data, int data_type,
|
||||
fsnotify_foreach_iter_mark_type(iter_info, mark, type) {
|
||||
if (!(mark->flags &
|
||||
FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
|
||||
mark->ignored_mask = 0;
|
||||
mark->ignore_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,14 +345,15 @@ static int send_to_group(__u32 mask, const void *data, int data_type,
|
||||
fsnotify_foreach_iter_mark_type(iter_info, mark, type) {
|
||||
group = mark->group;
|
||||
marks_mask |= mark->mask;
|
||||
marks_ignored_mask |= mark->ignored_mask;
|
||||
marks_ignore_mask |=
|
||||
fsnotify_effective_ignore_mask(mark, is_dir, type);
|
||||
}
|
||||
|
||||
pr_debug("%s: group=%p mask=%x marks_mask=%x marks_ignored_mask=%x data=%p data_type=%d dir=%p cookie=%d\n",
|
||||
__func__, group, mask, marks_mask, marks_ignored_mask,
|
||||
pr_debug("%s: group=%p mask=%x marks_mask=%x marks_ignore_mask=%x data=%p data_type=%d dir=%p cookie=%d\n",
|
||||
__func__, group, mask, marks_mask, marks_ignore_mask,
|
||||
data, data_type, dir, cookie);
|
||||
|
||||
if (!(test_mask & marks_mask & ~marks_ignored_mask))
|
||||
if (!(test_mask & marks_mask & ~marks_ignore_mask))
|
||||
return 0;
|
||||
|
||||
if (group->ops->handle_event) {
|
||||
@@ -423,7 +425,8 @@ static bool fsnotify_iter_select_report_types(
|
||||
* But is *this mark* watching children?
|
||||
*/
|
||||
if (type == FSNOTIFY_ITER_TYPE_PARENT &&
|
||||
!(mark->mask & FS_EVENT_ON_CHILD))
|
||||
!(mark->mask & FS_EVENT_ON_CHILD) &&
|
||||
!(fsnotify_ignore_mask(mark) & FS_EVENT_ON_CHILD))
|
||||
continue;
|
||||
|
||||
fsnotify_iter_set_report_type(iter_info, type);
|
||||
@@ -532,8 +535,8 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,
|
||||
|
||||
|
||||
/*
|
||||
* If this is a modify event we may need to clear some ignored masks.
|
||||
* In that case, the object with ignored masks will have the FS_MODIFY
|
||||
* If this is a modify event we may need to clear some ignore masks.
|
||||
* In that case, the object with ignore masks will have the FS_MODIFY
|
||||
* event in its mask.
|
||||
* Otherwise, return if none of the marks care about this type of event.
|
||||
*/
|
||||
|
||||
@@ -136,7 +136,7 @@ static inline u32 inotify_mask_to_arg(__u32 mask)
|
||||
IN_Q_OVERFLOW);
|
||||
}
|
||||
|
||||
/* intofiy userspace file descriptor functions */
|
||||
/* inotify userspace file descriptor functions */
|
||||
static __poll_t inotify_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct fsnotify_group *group = file->private_data;
|
||||
|
||||
@@ -59,15 +59,19 @@
|
||||
#define FANOTIFY_MARK_TYPE_BITS (FAN_MARK_INODE | FAN_MARK_MOUNT | \
|
||||
FAN_MARK_FILESYSTEM)
|
||||
|
||||
#define FANOTIFY_MARK_CMD_BITS (FAN_MARK_ADD | FAN_MARK_REMOVE | \
|
||||
FAN_MARK_FLUSH)
|
||||
|
||||
#define FANOTIFY_MARK_IGNORE_BITS (FAN_MARK_IGNORED_MASK | \
|
||||
FAN_MARK_IGNORE)
|
||||
|
||||
#define FANOTIFY_MARK_FLAGS (FANOTIFY_MARK_TYPE_BITS | \
|
||||
FAN_MARK_ADD | \
|
||||
FAN_MARK_REMOVE | \
|
||||
FANOTIFY_MARK_CMD_BITS | \
|
||||
FANOTIFY_MARK_IGNORE_BITS | \
|
||||
FAN_MARK_DONT_FOLLOW | \
|
||||
FAN_MARK_ONLYDIR | \
|
||||
FAN_MARK_IGNORED_MASK | \
|
||||
FAN_MARK_IGNORED_SURV_MODIFY | \
|
||||
FAN_MARK_EVICTABLE | \
|
||||
FAN_MARK_FLUSH)
|
||||
FAN_MARK_EVICTABLE)
|
||||
|
||||
/*
|
||||
* Events that can be reported with data type FSNOTIFY_EVENT_PATH.
|
||||
|
||||
@@ -518,8 +518,8 @@ struct fsnotify_mark {
|
||||
struct hlist_node obj_list;
|
||||
/* Head of list of marks for an object [mark ref] */
|
||||
struct fsnotify_mark_connector *connector;
|
||||
/* Events types to ignore [mark->lock, group->mark_mutex] */
|
||||
__u32 ignored_mask;
|
||||
/* Events types and flags to ignore [mark->lock, group->mark_mutex] */
|
||||
__u32 ignore_mask;
|
||||
/* General fsnotify mark flags */
|
||||
#define FSNOTIFY_MARK_FLAG_ALIVE 0x0001
|
||||
#define FSNOTIFY_MARK_FLAG_ATTACHED 0x0002
|
||||
@@ -529,6 +529,7 @@ struct fsnotify_mark {
|
||||
/* fanotify mark flags */
|
||||
#define FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY 0x0100
|
||||
#define FSNOTIFY_MARK_FLAG_NO_IREF 0x0200
|
||||
#define FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS 0x0400
|
||||
unsigned int flags; /* flags [mark->lock] */
|
||||
};
|
||||
|
||||
@@ -655,15 +656,91 @@ extern void fsnotify_remove_queued_event(struct fsnotify_group *group,
|
||||
|
||||
/* functions used to manipulate the marks attached to inodes */
|
||||
|
||||
/* Get mask for calculating object interest taking ignored mask into account */
|
||||
/*
|
||||
* Canonical "ignore mask" including event flags.
|
||||
*
|
||||
* Note the subtle semantic difference from the legacy ->ignored_mask.
|
||||
* ->ignored_mask traditionally only meant which events should be ignored,
|
||||
* while ->ignore_mask also includes flags regarding the type of objects on
|
||||
* which events should be ignored.
|
||||
*/
|
||||
static inline __u32 fsnotify_ignore_mask(struct fsnotify_mark *mark)
|
||||
{
|
||||
__u32 ignore_mask = mark->ignore_mask;
|
||||
|
||||
/* The event flags in ignore mask take effect */
|
||||
if (mark->flags & FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS)
|
||||
return ignore_mask;
|
||||
|
||||
/*
|
||||
* Legacy behavior:
|
||||
* - Always ignore events on dir
|
||||
* - Ignore events on child if parent is watching children
|
||||
*/
|
||||
ignore_mask |= FS_ISDIR;
|
||||
ignore_mask &= ~FS_EVENT_ON_CHILD;
|
||||
ignore_mask |= mark->mask & FS_EVENT_ON_CHILD;
|
||||
|
||||
return ignore_mask;
|
||||
}
|
||||
|
||||
/* Legacy ignored_mask - only event types to ignore */
|
||||
static inline __u32 fsnotify_ignored_events(struct fsnotify_mark *mark)
|
||||
{
|
||||
return mark->ignore_mask & ALL_FSNOTIFY_EVENTS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if mask (or ignore mask) should be applied depending if victim is a
|
||||
* directory and whether it is reported to a watching parent.
|
||||
*/
|
||||
static inline bool fsnotify_mask_applicable(__u32 mask, bool is_dir,
|
||||
int iter_type)
|
||||
{
|
||||
/* Should mask be applied to a directory? */
|
||||
if (is_dir && !(mask & FS_ISDIR))
|
||||
return false;
|
||||
|
||||
/* Should mask be applied to a child? */
|
||||
if (iter_type == FSNOTIFY_ITER_TYPE_PARENT &&
|
||||
!(mask & FS_EVENT_ON_CHILD))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Effective ignore mask taking into account if event victim is a
|
||||
* directory and whether it is reported to a watching parent.
|
||||
*/
|
||||
static inline __u32 fsnotify_effective_ignore_mask(struct fsnotify_mark *mark,
|
||||
bool is_dir, int iter_type)
|
||||
{
|
||||
__u32 ignore_mask = fsnotify_ignored_events(mark);
|
||||
|
||||
if (!ignore_mask)
|
||||
return 0;
|
||||
|
||||
/* For non-dir and non-child, no need to consult the event flags */
|
||||
if (!is_dir && iter_type != FSNOTIFY_ITER_TYPE_PARENT)
|
||||
return ignore_mask;
|
||||
|
||||
ignore_mask = fsnotify_ignore_mask(mark);
|
||||
if (!fsnotify_mask_applicable(ignore_mask, is_dir, iter_type))
|
||||
return 0;
|
||||
|
||||
return ignore_mask & ALL_FSNOTIFY_EVENTS;
|
||||
}
|
||||
|
||||
/* Get mask for calculating object interest taking ignore mask into account */
|
||||
static inline __u32 fsnotify_calc_mask(struct fsnotify_mark *mark)
|
||||
{
|
||||
__u32 mask = mark->mask;
|
||||
|
||||
if (!mark->ignored_mask)
|
||||
if (!fsnotify_ignored_events(mark))
|
||||
return mask;
|
||||
|
||||
/* Interest in FS_MODIFY may be needed for clearing ignored mask */
|
||||
/* Interest in FS_MODIFY may be needed for clearing ignore mask */
|
||||
if (!(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
|
||||
mask |= FS_MODIFY;
|
||||
|
||||
@@ -671,7 +748,7 @@ static inline __u32 fsnotify_calc_mask(struct fsnotify_mark *mark)
|
||||
* If mark is interested in ignoring events on children, the object must
|
||||
* show interest in those events for fsnotify_parent() to notice it.
|
||||
*/
|
||||
return mask | (mark->ignored_mask & ALL_FSNOTIFY_EVENTS);
|
||||
return mask | mark->ignore_mask;
|
||||
}
|
||||
|
||||
/* Get mask of events for a list of marks */
|
||||
|
||||
@@ -83,12 +83,20 @@
|
||||
#define FAN_MARK_FLUSH 0x00000080
|
||||
/* FAN_MARK_FILESYSTEM is 0x00000100 */
|
||||
#define FAN_MARK_EVICTABLE 0x00000200
|
||||
/* This bit is mutually exclusive with FAN_MARK_IGNORED_MASK bit */
|
||||
#define FAN_MARK_IGNORE 0x00000400
|
||||
|
||||
/* These are NOT bitwise flags. Both bits can be used togther. */
|
||||
#define FAN_MARK_INODE 0x00000000
|
||||
#define FAN_MARK_MOUNT 0x00000010
|
||||
#define FAN_MARK_FILESYSTEM 0x00000100
|
||||
|
||||
/*
|
||||
* Convenience macro - FAN_MARK_IGNORE requires FAN_MARK_IGNORED_SURV_MODIFY
|
||||
* for non-inode mark types.
|
||||
*/
|
||||
#define FAN_MARK_IGNORE_SURV (FAN_MARK_IGNORE | FAN_MARK_IGNORED_SURV_MODIFY)
|
||||
|
||||
/* Deprecated - do not use this in programs and do not add new flags here! */
|
||||
#define FAN_ALL_MARK_FLAGS (FAN_MARK_ADD |\
|
||||
FAN_MARK_REMOVE |\
|
||||
|
||||
Reference in New Issue
Block a user