History

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

Linus Torvalds committed 4 years ago

Commit bec14d72 parents af07685 feee1ce9 files · +214 −59Browse files

Unified · Split

9 files
  1. fs/notify/fanotify/fanotify.c +11 −8
  2. fs/notify/fanotify/fanotify.h +2 −0
  3. fs/notify/fanotify/fanotify_user.c +84 −26
  4. fs/notify/fdinfo.c +3 −3
  5. fs/notify/fsnotify.c +13 −10
  6. fs/notify/inotify/inotify_user.c +1 −1
  7. include/linux/fanotify.h +9 −5
  8. include/linux/fsnotify_backend.h +83 −6
  9. include/uapi/linux/fanotify.h +8 −0
fs/notify/fanotify/fanotify.c+11−8
@@ -295,12 +295,13 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, · 294 unmodified lines
295295 const void *data, int data_type,
296296 struct inode *dir)
297297 {
298− __u32 marks_mask = 0, marks_ignored_mask = 0;
298+ __u32 marks_mask = 0, marks_ignore_mask = 0;
299299 __u32 test_mask, user_mask = FANOTIFY_OUTGOING_EVENTS |
300300 FANOTIFY_EVENT_FLAGS;
301301 const struct path *path = fsnotify_data_path(data, data_type);
302302 unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS);
303303 struct fsnotify_mark *mark;
304+ bool ondir = event_mask & FAN_ONDIR;
304305 int type;
305306
306307 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, · 8 unmodified lines
315316 return 0;
316317 } else if (!(fid_mode & FAN_REPORT_FID)) {
317318 /* Do we have a directory inode to report? */
318− if (!dir && !(event_mask & FS_ISDIR))
319+ if (!dir && !ondir)
319320 return 0;
320321 }
321322
322323 fsnotify_foreach_iter_mark_type(iter_info, mark, type) {
323− /* Apply ignore mask regardless of mark's ISDIR flag */
324− marks_ignored_mask |= mark->ignored_mask;
324+ /*
325+ * Apply ignore mask depending on event flags in ignore mask.
326+ */
327+ marks_ignore_mask |=
328+ fsnotify_effective_ignore_mask(mark, ondir, type);
325329
326330 /*
327− * If the event is on dir and this mark doesn't care about
328− * events on dir, don't send it!
331+ * Send the event depending on event flags in mark mask.
329332 */
330− if (event_mask & FS_ISDIR && !(mark->mask & FS_ISDIR))
333+ if (!fsnotify_mask_applicable(mark->mask, ondir, type))
331334 continue;
332335
333336 marks_mask |= mark->mask;
@@ -336,7 +339,7 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, · 2 unmodified lines
336339 *match_mask |= 1U << type;
337340 }
338341
339− test_mask = event_mask & marks_mask & ~marks_ignored_mask;
342+ test_mask = event_mask & marks_mask & ~marks_ignore_mask;
340343
341344 /*
342345 * For dirent modification events (create/delete/move) that do not carry
fs/notify/fanotify/fanotify.h+2−0
@@ -499,6 +499,8 @@ static inline unsigned int fanotify_mark_user_flags(struct fsnotify_mark *mark) · 498 unmodified lines
499499 mflags |= FAN_MARK_IGNORED_SURV_MODIFY;
500500 if (mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF)
501501 mflags |= FAN_MARK_EVICTABLE;
502+ if (mark->flags & FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS)
503+ mflags |= FAN_MARK_IGNORE;
502504
503505 return mflags;
504506 }
fs/notify/fanotify/fanotify_user.c+84−26
@@ -1009,10 +1009,10 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, · 1008 unmodified lines
10091009 mask &= ~umask;
10101010 spin_lock(&fsn_mark->lock);
10111011 oldmask = fsnotify_calc_mask(fsn_mark);
1012− if (!(flags & FAN_MARK_IGNORED_MASK)) {
1012+ if (!(flags & FANOTIFY_MARK_IGNORE_BITS)) {
10131013 fsn_mark->mask &= ~mask;
10141014 } else {
1015− fsn_mark->ignored_mask &= ~mask;
1015+ fsn_mark->ignore_mask &= ~mask;
10161016 }
10171017 newmask = fsnotify_calc_mask(fsn_mark);
10181018 /*
@@ -1021,7 +1021,7 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, · 2 unmodified lines
10211021 * changes to the mask.
10221022 * Destroy mark when only umask bits remain.
10231023 */
1024− *destroy = !((fsn_mark->mask | fsn_mark->ignored_mask) & ~umask);
1024+ *destroy = !((fsn_mark->mask | fsn_mark->ignore_mask) & ~umask);
10251025 spin_unlock(&fsn_mark->lock);
10261026
10271027 return oldmask & ~newmask;
@@ -1085,15 +1085,24 @@ static bool fanotify_mark_update_flags(struct fsnotify_mark *fsn_mark, · 57 unmodified lines
10851085 unsigned int fan_flags)
10861086 {
10871087 bool want_iref = !(fan_flags & FAN_MARK_EVICTABLE);
1088+ unsigned int ignore = fan_flags & FANOTIFY_MARK_IGNORE_BITS;
10881089 bool recalc = false;
10891090
1091+ /*
1092+ * When using FAN_MARK_IGNORE for the first time, mark starts using
1093+ * independent event flags in ignore mask. After that, trying to
1094+ * update the ignore mask with the old FAN_MARK_IGNORED_MASK API
1095+ * will result in EEXIST error.
1096+ */
1097+ if (ignore == FAN_MARK_IGNORE)
1098+ fsn_mark->flags |= FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS;
1099+
10901100 /*
10911101 * Setting FAN_MARK_IGNORED_SURV_MODIFY for the first time may lead to
10921102 * the removal of the FS_MODIFY bit in calculated mask if it was set
1093− * because of an ignored mask that is now going to survive FS_MODIFY.
1103+ * because of an ignore mask that is now going to survive FS_MODIFY.
10941104 */
1095− if ((fan_flags & FAN_MARK_IGNORED_MASK) &&
1096− (fan_flags & FAN_MARK_IGNORED_SURV_MODIFY) &&
1105+ if (ignore && (fan_flags & FAN_MARK_IGNORED_SURV_MODIFY) &&
10971106 !(fsn_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) {
10981107 fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY;
10991108 if (!(fsn_mark->mask & FS_MODIFY))
@@ -1120,10 +1129,10 @@ static bool fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark, · 20 unmodified lines
11201129 bool recalc;
11211130
11221131 spin_lock(&fsn_mark->lock);
1123− if (!(fan_flags & FAN_MARK_IGNORED_MASK))
1132+ if (!(fan_flags & FANOTIFY_MARK_IGNORE_BITS))
11241133 fsn_mark->mask |= mask;
11251134 else
1126− fsn_mark->ignored_mask |= mask;
1135+ fsn_mark->ignore_mask |= mask;
11271136
11281137 recalc = fsnotify_calc_mask(fsn_mark) &
11291138 ~fsnotify_conn_mask(fsn_mark->connector);
@@ -1187,6 +1196,37 @@ static int fanotify_group_init_error_pool(struct fsnotify_group *group) · 57 unmodified lines
11871196 sizeof(struct fanotify_error_event));
11881197 }
11891198
1199+static int fanotify_may_update_existing_mark(struct fsnotify_mark *fsn_mark,
1200+ unsigned int fan_flags)
1201+{
1202+ /*
1203+ * Non evictable mark cannot be downgraded to evictable mark.
1204+ */
1205+ if (fan_flags & FAN_MARK_EVICTABLE &&
1206+ !(fsn_mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF))
1207+ return -EEXIST;
1208+
1209+ /*
1210+ * New ignore mask semantics cannot be downgraded to old semantics.
1211+ */
1212+ if (fan_flags & FAN_MARK_IGNORED_MASK &&
1213+ fsn_mark->flags & FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS)
1214+ return -EEXIST;
1215+
1216+ /*
1217+ * An ignore mask that survives modify could never be downgraded to not
1218+ * survive modify. With new FAN_MARK_IGNORE semantics we make that rule
1219+ * explicit and return an error when trying to update the ignore mask
1220+ * without the original FAN_MARK_IGNORED_SURV_MODIFY value.
1221+ */
1222+ if (fan_flags & FAN_MARK_IGNORE &&
1223+ !(fan_flags & FAN_MARK_IGNORED_SURV_MODIFY) &&
1224+ fsn_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)
1225+ return -EEXIST;
1226+
1227+ return 0;
1228+}
1229+
11901230 static int fanotify_add_mark(struct fsnotify_group *group,
11911231 fsnotify_connp_t *connp, unsigned int obj_type,
11921232 __u32 mask, unsigned int fan_flags,
@@ -1208,19 +1248,18 @@ static int fanotify_add_mark(struct fsnotify_group *group, · 15 unmodified lines
12081248 }
12091249
12101250 /*
1211− * Non evictable mark cannot be downgraded to evictable mark.
1251+ * Check if requested mark flags conflict with an existing mark flags.
12121252 */
1213− if (fan_flags & FAN_MARK_EVICTABLE &&
1214− !(fsn_mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF)) {
1215− ret = -EEXIST;
1253+ ret = fanotify_may_update_existing_mark(fsn_mark, fan_flags);
1254+ if (ret)
12161255 goto out;
1217− }
12181256
12191257 /*
12201258 * Error events are pre-allocated per group, only if strictly
12211259 * needed (i.e. FAN_FS_ERROR was requested).
12221260 */
1223− if (!(fan_flags & FAN_MARK_IGNORED_MASK) && (mask & FAN_FS_ERROR)) {
1261+ if (!(fan_flags & FANOTIFY_MARK_IGNORE_BITS) &&
1262+ (mask & FAN_FS_ERROR)) {
12241263 ret = fanotify_group_init_error_pool(group);
12251264 if (ret)
12261265 goto out;
@@ -1261,10 +1300,10 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group, · 34 unmodified lines
12611300
12621301 /*
12631302 * If some other task has this inode open for write we should not add
1264− * an ignored mark, unless that ignored mark is supposed to survive
1303+ * an ignore mask, unless that ignore mask is supposed to survive
12651304 * modification changes anyway.
12661305 */
1267− if ((flags & FAN_MARK_IGNORED_MASK) &&
1306+ if ((flags & FANOTIFY_MARK_IGNORE_BITS) &&
12681307 !(flags & FAN_MARK_IGNORED_SURV_MODIFY) &&
12691308 inode_is_open_for_write(inode))
12701309 return 0;
@@ -1520,7 +1559,8 @@ static int fanotify_events_supported(struct fsnotify_group *group, · 249 unmodified lines
15201559 unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS;
15211560 /* Strict validation of events in non-dir inode mask with v5.17+ APIs */
15221561 bool strict_dir_events = FAN_GROUP_FLAG(group, FAN_REPORT_TARGET_FID) ||
1523− (mask & FAN_RENAME);
1562+ (mask & FAN_RENAME) ||
1563+ (flags & FAN_MARK_IGNORE);
15241564
15251565 /*
15261566 * 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, · 30 unmodified lines
15571597 __kernel_fsid_t __fsid, *fsid = NULL;
15581598 u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS;
15591599 unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS;
1560− bool ignored = flags & FAN_MARK_IGNORED_MASK;
1600+ unsigned int mark_cmd = flags & FANOTIFY_MARK_CMD_BITS;
1601+ unsigned int ignore = flags & FANOTIFY_MARK_IGNORE_BITS;
15611602 unsigned int obj_type, fid_mode;
15621603 u32 umask = 0;
15631604 int ret;
@@ -1586,7 +1627,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, · 22 unmodified lines
15861627 return -EINVAL;
15871628 }
15881629
1589− switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) {
1630+ switch (mark_cmd) {
15901631 case FAN_MARK_ADD:
15911632 case FAN_MARK_REMOVE:
15921633 if (!mask)
@@ -1606,9 +1647,19 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, · 13 unmodified lines
16061647 if (mask & ~valid_mask)
16071648 return -EINVAL;
16081649
1609− /* Event flags (ONDIR, ON_CHILD) are meaningless in ignored mask */
1610− if (ignored)
1650+
1651+ /* We don't allow FAN_MARK_IGNORE & FAN_MARK_IGNORED_MASK together */
1652+ if (ignore == (FAN_MARK_IGNORE | FAN_MARK_IGNORED_MASK))
1653+ return -EINVAL;
1654+
1655+ /*
1656+ * Event flags (FAN_ONDIR, FAN_EVENT_ON_CHILD) have no effect with
1657+ * FAN_MARK_IGNORED_MASK.
1658+ */
1659+ if (ignore == FAN_MARK_IGNORED_MASK) {
16111660 mask &= ~FANOTIFY_EVENT_FLAGS;
1661+ umask = FANOTIFY_EVENT_FLAGS;
1662+ }
16121663
16131664 f = fdget(fanotify_fd);
16141665 if (unlikely(!f.file))
@@ -1672,7 +1723,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, · 57 unmodified lines
16721723 if (mask & FAN_RENAME && !(fid_mode & FAN_REPORT_NAME))
16731724 goto fput_and_out;
16741725
1675− if (flags & FAN_MARK_FLUSH) {
1726+ if (mark_cmd == FAN_MARK_FLUSH) {
16761727 ret = 0;
16771728 if (mark_type == FAN_MARK_MOUNT)
16781729 fsnotify_clear_vfsmount_marks_by_group(group);
@@ -1688,7 +1739,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, · 9 unmodified lines
16881739 if (ret)
16891740 goto fput_and_out;
16901741
1691− if (flags & FAN_MARK_ADD) {
1742+ if (mark_cmd == FAN_MARK_ADD) {
16921743 ret = fanotify_events_supported(group, &path, mask, flags);
16931744 if (ret)
16941745 goto path_put_and_out;
@@ -1712,6 +1763,13 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, · 17 unmodified lines
17121763 else
17131764 mnt = path.mnt;
17141765
1766+ ret = mnt ? -EINVAL : -EISDIR;
1767+ /* FAN_MARK_IGNORE requires SURV_MODIFY for sb/mount/dir marks */
1768+ if (mark_cmd == FAN_MARK_ADD && ignore == FAN_MARK_IGNORE &&
1769+ (mnt || S_ISDIR(inode->i_mode)) &&
1770+ !(flags & FAN_MARK_IGNORED_SURV_MODIFY))
1771+ goto path_put_and_out;
1772+
17151773 /* Mask out FAN_EVENT_ON_CHILD flag for sb/mount/non-dir marks */
17161774 if (mnt || !S_ISDIR(inode->i_mode)) {
17171775 mask &= ~FAN_EVENT_ON_CHILD;
@@ -1721,12 +1779,12 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, · 3 unmodified lines
17211779 * events with parent/name info for non-directory.
17221780 */
17231781 if ((fid_mode & FAN_REPORT_DIR_FID) &&
1724− (flags & FAN_MARK_ADD) && !ignored)
1782+ (flags & FAN_MARK_ADD) && !ignore)
17251783 mask |= FAN_EVENT_ON_CHILD;
17261784 }
17271785
17281786 /* create/update an inode mark */
1729− switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE)) {
1787+ switch (mark_cmd) {
17301788 case FAN_MARK_ADD:
17311789 if (mark_type == FAN_MARK_MOUNT)
17321790 ret = fanotify_add_vfsmount_mark(group, mnt, mask,
@@ -1804,7 +1862,7 @@ static int __init fanotify_user_setup(void) · 71 unmodified lines
18041862
18051863 BUILD_BUG_ON(FANOTIFY_INIT_FLAGS & FANOTIFY_INTERNAL_GROUP_FLAGS);
18061864 BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 12);
1807− BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 10);
1865+ BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 11);
18081866
18091867 fanotify_mark_cache = KMEM_CACHE(fsnotify_mark,
18101868 SLAB_PANIC|SLAB_ACCOUNT);
fs/notify/fdinfo.c+3−3
@@ -113,7 +113,7 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark) · 112 unmodified lines
113113 return;
114114 seq_printf(m, "fanotify ino:%lx sdev:%x mflags:%x mask:%x ignored_mask:%x ",
115115 inode->i_ino, inode->i_sb->s_dev,
116− mflags, mark->mask, mark->ignored_mask);
116+ mflags, mark->mask, mark->ignore_mask);
117117 show_mark_fhandle(m, inode);
118118 seq_putc(m, '\n');
119119 iput(inode);
@@ -121,12 +121,12 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark) · 1 unmodified line
121121 struct mount *mnt = fsnotify_conn_mount(mark->connector);
122122
123123 seq_printf(m, "fanotify mnt_id:%x mflags:%x mask:%x ignored_mask:%x\n",
124− mnt->mnt_id, mflags, mark->mask, mark->ignored_mask);
124+ mnt->mnt_id, mflags, mark->mask, mark->ignore_mask);
125125 } else if (mark->connector->type == FSNOTIFY_OBJ_TYPE_SB) {
126126 struct super_block *sb = fsnotify_conn_sb(mark->connector);
127127
128128 seq_printf(m, "fanotify sdev:%x mflags:%x mask:%x ignored_mask:%x\n",
129− sb->s_dev, mflags, mark->mask, mark->ignored_mask);
129+ sb->s_dev, mflags, mark->mask, mark->ignore_mask);
130130 }
131131 }
132132
fs/notify/fsnotify.c+13−10
@@ -100,7 +100,7 @@ void fsnotify_sb_delete(struct super_block *sb) · 99 unmodified lines
100100 * Given an inode, first check if we care what happens to our children. Inotify
101101 * and dnotify both tell their parents about events. If we care about any event
102102 * on a child we run all of our children and set a dentry flag saying that the
103− * parent cares. Thus when an event happens on a child it can quickly tell if
103+ * parent cares. Thus when an event happens on a child it can quickly tell
104104 * if there is a need to find a parent and send the event to the parent.
105105 */
106106 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, · 217 unmodified lines
324324 struct fsnotify_group *group = NULL;
325325 __u32 test_mask = (mask & ALL_FSNOTIFY_EVENTS);
326326 __u32 marks_mask = 0;
327− __u32 marks_ignored_mask = 0;
327+ __u32 marks_ignore_mask = 0;
328+ bool is_dir = mask & FS_ISDIR;
328329 struct fsnotify_mark *mark;
329330 int type;
330331
@@ -336,7 +337,7 @@ static int send_to_group(__u32 mask, const void *data, int data_type, · 5 unmodified lines
336337 fsnotify_foreach_iter_mark_type(iter_info, mark, type) {
337338 if (!(mark->flags &
338339 FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
339− mark->ignored_mask = 0;
340+ mark->ignore_mask = 0;
340341 }
341342 }
342343
@@ -344,14 +345,15 @@ static int send_to_group(__u32 mask, const void *data, int data_type, · 1 unmodified line
344345 fsnotify_foreach_iter_mark_type(iter_info, mark, type) {
345346 group = mark->group;
346347 marks_mask |= mark->mask;
347− marks_ignored_mask |= mark->ignored_mask;
348+ marks_ignore_mask |=
349+ fsnotify_effective_ignore_mask(mark, is_dir, type);
348350 }
349351
350− pr_debug("%s: group=%p mask=%x marks_mask=%x marks_ignored_mask=%x data=%p data_type=%d dir=%p cookie=%d\n",
351− __func__, group, mask, marks_mask, marks_ignored_mask,
352+ pr_debug("%s: group=%p mask=%x marks_mask=%x marks_ignore_mask=%x data=%p data_type=%d dir=%p cookie=%d\n",
353+ __func__, group, mask, marks_mask, marks_ignore_mask,
352354 data, data_type, dir, cookie);
353355
354− if (!(test_mask & marks_mask & ~marks_ignored_mask))
356+ if (!(test_mask & marks_mask & ~marks_ignore_mask))
355357 return 0;
356358
357359 if (group->ops->handle_event) {
@@ -423,7 +425,8 @@ static bool fsnotify_iter_select_report_types( · 65 unmodified lines
423425 * But is *this mark* watching children?
424426 */
425427 if (type == FSNOTIFY_ITER_TYPE_PARENT &&
426− !(mark->mask & FS_EVENT_ON_CHILD))
428+ !(mark->mask & FS_EVENT_ON_CHILD) &&
429+ !(fsnotify_ignore_mask(mark) & FS_EVENT_ON_CHILD))
427430 continue;
428431
429432 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, · 102 unmodified lines
532535
533536
534537 /*
535− * If this is a modify event we may need to clear some ignored masks.
536− * In that case, the object with ignored masks will have the FS_MODIFY
538+ * If this is a modify event we may need to clear some ignore masks.
539+ * In that case, the object with ignore masks will have the FS_MODIFY
537540 * event in its mask.
538541 * Otherwise, return if none of the marks care about this type of event.
539542 */
fs/notify/inotify/inotify_user.c+1−1
@@ -136,7 +136,7 @@ static inline u32 inotify_mask_to_arg(__u32 mask) · 135 unmodified lines
136136 IN_Q_OVERFLOW);
137137 }
138138
139−/* intofiy userspace file descriptor functions */
139+/* inotify userspace file descriptor functions */
140140 static __poll_t inotify_poll(struct file *file, poll_table *wait)
141141 {
142142 struct fsnotify_group *group = file->private_data;
include/linux/fanotify.h+9−5
@@ -59,15 +59,19 @@ · 58 unmodified lines
5959 #define FANOTIFY_MARK_TYPE_BITS (FAN_MARK_INODE | FAN_MARK_MOUNT | \
6060 FAN_MARK_FILESYSTEM)
6161
62+#define FANOTIFY_MARK_CMD_BITS (FAN_MARK_ADD | FAN_MARK_REMOVE | \
63+ FAN_MARK_FLUSH)
64+
65+#define FANOTIFY_MARK_IGNORE_BITS (FAN_MARK_IGNORED_MASK | \
66+ FAN_MARK_IGNORE)
67+
6268 #define FANOTIFY_MARK_FLAGS (FANOTIFY_MARK_TYPE_BITS | \
63− FAN_MARK_ADD | \
64− FAN_MARK_REMOVE | \
69+ FANOTIFY_MARK_CMD_BITS | \
70+ FANOTIFY_MARK_IGNORE_BITS | \
6571 FAN_MARK_DONT_FOLLOW | \
6672 FAN_MARK_ONLYDIR | \
67− FAN_MARK_IGNORED_MASK | \
6873 FAN_MARK_IGNORED_SURV_MODIFY | \
69− FAN_MARK_EVICTABLE | \
70− FAN_MARK_FLUSH)
74+ FAN_MARK_EVICTABLE)
7175
7276 /*
7377 * Events that can be reported with data type FSNOTIFY_EVENT_PATH.
include/linux/fsnotify_backend.h+83−6
@@ -518,8 +518,8 @@ struct fsnotify_mark { · 517 unmodified lines
518518 struct hlist_node obj_list;
519519 /* Head of list of marks for an object [mark ref] */
520520 struct fsnotify_mark_connector *connector;
521− /* Events types to ignore [mark->lock, group->mark_mutex] */
522− __u32 ignored_mask;
521+ /* Events types and flags to ignore [mark->lock, group->mark_mutex] */
522+ __u32 ignore_mask;
523523 /* General fsnotify mark flags */
524524 #define FSNOTIFY_MARK_FLAG_ALIVE 0x0001
525525 #define FSNOTIFY_MARK_FLAG_ATTACHED 0x0002
@@ -529,6 +529,7 @@ struct fsnotify_mark { · 3 unmodified lines
529529 /* fanotify mark flags */
530530 #define FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY 0x0100
531531 #define FSNOTIFY_MARK_FLAG_NO_IREF 0x0200
532+#define FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS 0x0400
532533 unsigned int flags; /* flags [mark->lock] */
533534 };
534535
@@ -655,15 +656,91 @@ extern void fsnotify_remove_queued_event(struct fsnotify_group *group, · 120 unmodified lines
655656
656657 /* functions used to manipulate the marks attached to inodes */
657658
658−/* Get mask for calculating object interest taking ignored mask into account */
659+/*
660+ * Canonical "ignore mask" including event flags.
661+ *
662+ * Note the subtle semantic difference from the legacy ->ignored_mask.
663+ * ->ignored_mask traditionally only meant which events should be ignored,
664+ * while ->ignore_mask also includes flags regarding the type of objects on
665+ * which events should be ignored.
666+ */
667+static inline __u32 fsnotify_ignore_mask(struct fsnotify_mark *mark)
668+{
669+ __u32 ignore_mask = mark->ignore_mask;
670+
671+ /* The event flags in ignore mask take effect */
672+ if (mark->flags & FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS)
673+ return ignore_mask;
674+
675+ /*
676+ * Legacy behavior:
677+ * - Always ignore events on dir
678+ * - Ignore events on child if parent is watching children
679+ */
680+ ignore_mask |= FS_ISDIR;
681+ ignore_mask &= ~FS_EVENT_ON_CHILD;
682+ ignore_mask |= mark->mask & FS_EVENT_ON_CHILD;
683+
684+ return ignore_mask;
685+}
686+
687+/* Legacy ignored_mask - only event types to ignore */
688+static inline __u32 fsnotify_ignored_events(struct fsnotify_mark *mark)
689+{
690+ return mark->ignore_mask & ALL_FSNOTIFY_EVENTS;
691+}
692+
693+/*
694+ * Check if mask (or ignore mask) should be applied depending if victim is a
695+ * directory and whether it is reported to a watching parent.
696+ */
697+static inline bool fsnotify_mask_applicable(__u32 mask, bool is_dir,
698+ int iter_type)
699+{
700+ /* Should mask be applied to a directory? */
701+ if (is_dir && !(mask & FS_ISDIR))
702+ return false;
703+
704+ /* Should mask be applied to a child? */
705+ if (iter_type == FSNOTIFY_ITER_TYPE_PARENT &&
706+ !(mask & FS_EVENT_ON_CHILD))
707+ return false;
708+
709+ return true;
710+}
711+
712+/*
713+ * Effective ignore mask taking into account if event victim is a
714+ * directory and whether it is reported to a watching parent.
715+ */
716+static inline __u32 fsnotify_effective_ignore_mask(struct fsnotify_mark *mark,
717+ bool is_dir, int iter_type)
718+{
719+ __u32 ignore_mask = fsnotify_ignored_events(mark);
720+
721+ if (!ignore_mask)
722+ return 0;
723+
724+ /* For non-dir and non-child, no need to consult the event flags */
725+ if (!is_dir && iter_type != FSNOTIFY_ITER_TYPE_PARENT)
726+ return ignore_mask;
727+
728+ ignore_mask = fsnotify_ignore_mask(mark);
729+ if (!fsnotify_mask_applicable(ignore_mask, is_dir, iter_type))
730+ return 0;
731+
732+ return ignore_mask & ALL_FSNOTIFY_EVENTS;
733+}
734+
735+/* Get mask for calculating object interest taking ignore mask into account */
659736 static inline __u32 fsnotify_calc_mask(struct fsnotify_mark *mark)
660737 {
661738 __u32 mask = mark->mask;
662739
663− if (!mark->ignored_mask)
740+ if (!fsnotify_ignored_events(mark))
664741 return mask;
665742
666− /* Interest in FS_MODIFY may be needed for clearing ignored mask */
743+ /* Interest in FS_MODIFY may be needed for clearing ignore mask */
667744 if (!(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
668745 mask |= FS_MODIFY;
669746
@@ -671,7 +748,7 @@ static inline __u32 fsnotify_calc_mask(struct fsnotify_mark *mark) · 1 unmodified line
671748 * If mark is interested in ignoring events on children, the object must
672749 * show interest in those events for fsnotify_parent() to notice it.
673750 */
674− return mask | (mark->ignored_mask & ALL_FSNOTIFY_EVENTS);
751+ return mask | mark->ignore_mask;
675752 }
676753
677754 /* Get mask of events for a list of marks */
include/uapi/linux/fanotify.h+8−0
@@ -83,12 +83,20 @@ · 82 unmodified lines
8383 #define FAN_MARK_FLUSH 0x00000080
8484 /* FAN_MARK_FILESYSTEM is 0x00000100 */
8585 #define FAN_MARK_EVICTABLE 0x00000200
86+/* This bit is mutually exclusive with FAN_MARK_IGNORED_MASK bit */
87+#define FAN_MARK_IGNORE 0x00000400
8688
8789 /* These are NOT bitwise flags. Both bits can be used togther. */
8890 #define FAN_MARK_INODE 0x00000000
8991 #define FAN_MARK_MOUNT 0x00000010
9092 #define FAN_MARK_FILESYSTEM 0x00000100
9193
94+/*
95+ * Convenience macro - FAN_MARK_IGNORE requires FAN_MARK_IGNORED_SURV_MODIFY
96+ * for non-inode mark types.
97+ */
98+#define FAN_MARK_IGNORE_SURV (FAN_MARK_IGNORE | FAN_MARK_IGNORED_SURV_MODIFY)
99+
92100 /* Deprecated - do not use this in programs and do not add new flags here! */
93101 #define FAN_ALL_MARK_FLAGS (FAN_MARK_ADD |\
94102 FAN_MARK_REMOVE |\