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
Unified · Split
| @@ -295,12 +295,13 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, · 294 unmodified lines | |||
| 295 | const void *data, int data_type, | 295 | const void *data, int data_type, |
| 296 | struct inode *dir) | 296 | struct inode *dir) |
| 297 | { | 297 | { |
| 298 | __u32 marks_mask = 0, marks_ignored_mask = 0; | 298 | __u32 marks_mask = 0, marks_ignore_mask = 0; |
| 299 | __u32 test_mask, user_mask = FANOTIFY_OUTGOING_EVENTS | | 299 | __u32 test_mask, user_mask = FANOTIFY_OUTGOING_EVENTS | |
| 300 | FANOTIFY_EVENT_FLAGS; | 300 | FANOTIFY_EVENT_FLAGS; |
| 301 | const struct path *path = fsnotify_data_path(data, data_type); | 301 | const struct path *path = fsnotify_data_path(data, data_type); |
| 302 | unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); | 302 | unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); |
| 303 | struct fsnotify_mark *mark; | 303 | struct fsnotify_mark *mark; |
| 304 | bool ondir = event_mask & FAN_ONDIR; | ||
| 304 | int type; | 305 | int type; |
| 305 | 306 | ||
| 306 | pr_debug("%s: report_mask=%x mask=%x data=%p data_type=%d\n", | 307 | 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 | |||
| 315 | return 0; | 316 | return 0; |
| 316 | } else if (!(fid_mode & FAN_REPORT_FID)) { | 317 | } else if (!(fid_mode & FAN_REPORT_FID)) { |
| 317 | /* Do we have a directory inode to report? */ | 318 | /* Do we have a directory inode to report? */ |
| 318 | if (!dir && !(event_mask & FS_ISDIR)) | 319 | if (!dir && !ondir) |
| 319 | return 0; | 320 | return 0; |
| 320 | } | 321 | } |
| 321 | 322 | ||
| 322 | fsnotify_foreach_iter_mark_type(iter_info, mark, type) { | 323 | fsnotify_foreach_iter_mark_type(iter_info, mark, type) { |
| 323 | /* Apply ignore mask regardless of mark's ISDIR flag */ | 324 | /* |
| 324 | marks_ignored_mask |= mark->ignored_mask; | 325 | * Apply ignore mask depending on event flags in ignore mask. |
| 326 | */ | ||
| 327 | marks_ignore_mask |= | ||
| 328 | fsnotify_effective_ignore_mask(mark, ondir, type); | ||
| 325 | 329 | ||
| 326 | /* | 330 | /* |
| 327 | * If the event is on dir and this mark doesn't care about | 331 | * Send the event depending on event flags in mark mask. |
| 328 | * events on dir, don't send it! | ||
| 329 | */ | 332 | */ |
| 330 | if (event_mask & FS_ISDIR && !(mark->mask & FS_ISDIR)) | 333 | if (!fsnotify_mask_applicable(mark->mask, ondir, type)) |
| 331 | continue; | 334 | continue; |
| 332 | 335 | ||
| 333 | marks_mask |= mark->mask; | 336 | marks_mask |= mark->mask; |
| @@ -336,7 +339,7 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, · 2 unmodified lines | |||
| 336 | *match_mask |= 1U << type; | 339 | *match_mask |= 1U << type; |
| 337 | } | 340 | } |
| 338 | 341 | ||
| 339 | test_mask = event_mask & marks_mask & ~marks_ignored_mask; | 342 | test_mask = event_mask & marks_mask & ~marks_ignore_mask; |
| 340 | 343 | ||
| 341 | /* | 344 | /* |
| 342 | * For dirent modification events (create/delete/move) that do not carry | 345 | * 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) · 498 unmodified lines | |||
| 499 | mflags |= FAN_MARK_IGNORED_SURV_MODIFY; | 499 | mflags |= FAN_MARK_IGNORED_SURV_MODIFY; |
| 500 | if (mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF) | 500 | if (mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF) |
| 501 | mflags |= FAN_MARK_EVICTABLE; | 501 | mflags |= FAN_MARK_EVICTABLE; |
| 502 | if (mark->flags & FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS) | ||
| 503 | mflags |= FAN_MARK_IGNORE; | ||
| 502 | 504 | ||
| 503 | return mflags; | 505 | return mflags; |
| 504 | } | 506 | } |
| @@ -1009,10 +1009,10 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, · 1008 unmodified lines | |||
| 1009 | mask &= ~umask; | 1009 | mask &= ~umask; |
| 1010 | spin_lock(&fsn_mark->lock); | 1010 | spin_lock(&fsn_mark->lock); |
| 1011 | oldmask = fsnotify_calc_mask(fsn_mark); | 1011 | oldmask = fsnotify_calc_mask(fsn_mark); |
| 1012 | if (!(flags & FAN_MARK_IGNORED_MASK)) { | 1012 | if (!(flags & FANOTIFY_MARK_IGNORE_BITS)) { |
| 1013 | fsn_mark->mask &= ~mask; | 1013 | fsn_mark->mask &= ~mask; |
| 1014 | } else { | 1014 | } else { |
| 1015 | fsn_mark->ignored_mask &= ~mask; | 1015 | fsn_mark->ignore_mask &= ~mask; |
| 1016 | } | 1016 | } |
| 1017 | newmask = fsnotify_calc_mask(fsn_mark); | 1017 | newmask = fsnotify_calc_mask(fsn_mark); |
| 1018 | /* | 1018 | /* |
| @@ -1021,7 +1021,7 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, · 2 unmodified lines | |||
| 1021 | * changes to the mask. | 1021 | * changes to the mask. |
| 1022 | * Destroy mark when only umask bits remain. | 1022 | * Destroy mark when only umask bits remain. |
| 1023 | */ | 1023 | */ |
| 1024 | *destroy = !((fsn_mark->mask | fsn_mark->ignored_mask) & ~umask); | 1024 | *destroy = !((fsn_mark->mask | fsn_mark->ignore_mask) & ~umask); |
| 1025 | spin_unlock(&fsn_mark->lock); | 1025 | spin_unlock(&fsn_mark->lock); |
| 1026 | 1026 | ||
| 1027 | return oldmask & ~newmask; | 1027 | return oldmask & ~newmask; |
| @@ -1085,15 +1085,24 @@ static bool fanotify_mark_update_flags(struct fsnotify_mark *fsn_mark, · 57 unmodified lines | |||
| 1085 | unsigned int fan_flags) | 1085 | unsigned int fan_flags) |
| 1086 | { | 1086 | { |
| 1087 | bool want_iref = !(fan_flags & FAN_MARK_EVICTABLE); | 1087 | bool want_iref = !(fan_flags & FAN_MARK_EVICTABLE); |
| 1088 | unsigned int ignore = fan_flags & FANOTIFY_MARK_IGNORE_BITS; | ||
| 1088 | bool recalc = false; | 1089 | bool recalc = false; |
| 1089 | 1090 | ||
| 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 | |||
| 1090 | /* | 1100 | /* |
| 1091 | * Setting FAN_MARK_IGNORED_SURV_MODIFY for the first time may lead to | 1101 | * Setting FAN_MARK_IGNORED_SURV_MODIFY for the first time may lead to |
| 1092 | * the removal of the FS_MODIFY bit in calculated mask if it was set | 1102 | * 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. |
| 1094 | */ | 1104 | */ |
| 1095 | if ((fan_flags & FAN_MARK_IGNORED_MASK) && | 1105 | if (ignore && (fan_flags & FAN_MARK_IGNORED_SURV_MODIFY) && |
| 1096 | (fan_flags & FAN_MARK_IGNORED_SURV_MODIFY) && | ||
| 1097 | !(fsn_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) { | 1106 | !(fsn_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) { |
| 1098 | fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY; | 1107 | fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY; |
| 1099 | if (!(fsn_mark->mask & FS_MODIFY)) | 1108 | 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 | |||
| 1120 | bool recalc; | 1129 | bool recalc; |
| 1121 | 1130 | ||
| 1122 | spin_lock(&fsn_mark->lock); | 1131 | spin_lock(&fsn_mark->lock); |
| 1123 | if (!(fan_flags & FAN_MARK_IGNORED_MASK)) | 1132 | if (!(fan_flags & FANOTIFY_MARK_IGNORE_BITS)) |
| 1124 | fsn_mark->mask |= mask; | 1133 | fsn_mark->mask |= mask; |
| 1125 | else | 1134 | else |
| 1126 | fsn_mark->ignored_mask |= mask; | 1135 | fsn_mark->ignore_mask |= mask; |
| 1127 | 1136 | ||
| 1128 | recalc = fsnotify_calc_mask(fsn_mark) & | 1137 | recalc = fsnotify_calc_mask(fsn_mark) & |
| 1129 | ~fsnotify_conn_mask(fsn_mark->connector); | 1138 | ~fsnotify_conn_mask(fsn_mark->connector); |
| @@ -1187,6 +1196,37 @@ static int fanotify_group_init_error_pool(struct fsnotify_group *group) · 57 unmodified lines | |||
| 1187 | sizeof(struct fanotify_error_event)); | 1196 | sizeof(struct fanotify_error_event)); |
| 1188 | } | 1197 | } |
| 1189 | 1198 | ||
| 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 | |||
| 1190 | static int fanotify_add_mark(struct fsnotify_group *group, | 1230 | static int fanotify_add_mark(struct fsnotify_group *group, |
| 1191 | fsnotify_connp_t *connp, unsigned int obj_type, | 1231 | fsnotify_connp_t *connp, unsigned int obj_type, |
| 1192 | __u32 mask, unsigned int fan_flags, | 1232 | __u32 mask, unsigned int fan_flags, |
| @@ -1208,19 +1248,18 @@ static int fanotify_add_mark(struct fsnotify_group *group, · 15 unmodified lines | |||
| 1208 | } | 1248 | } |
| 1209 | 1249 | ||
| 1210 | /* | 1250 | /* |
| 1211 | * Non evictable mark cannot be downgraded to evictable mark. | 1251 | * Check if requested mark flags conflict with an existing mark flags. |
| 1212 | */ | 1252 | */ |
| 1213 | if (fan_flags & FAN_MARK_EVICTABLE && | 1253 | ret = fanotify_may_update_existing_mark(fsn_mark, fan_flags); |
| 1214 | !(fsn_mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF)) { | 1254 | if (ret) |
| 1215 | ret = -EEXIST; | ||
| 1216 | goto out; | 1255 | goto out; |
| 1217 | } | ||
| 1218 | 1256 | ||
| 1219 | /* | 1257 | /* |
| 1220 | * Error events are pre-allocated per group, only if strictly | 1258 | * Error events are pre-allocated per group, only if strictly |
| 1221 | * needed (i.e. FAN_FS_ERROR was requested). | 1259 | * needed (i.e. FAN_FS_ERROR was requested). |
| 1222 | */ | 1260 | */ |
| 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)) { | ||
| 1224 | ret = fanotify_group_init_error_pool(group); | 1263 | ret = fanotify_group_init_error_pool(group); |
| 1225 | if (ret) | 1264 | if (ret) |
| 1226 | goto out; | 1265 | goto out; |
| @@ -1261,10 +1300,10 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group, · 34 unmodified lines | |||
| 1261 | 1300 | ||
| 1262 | /* | 1301 | /* |
| 1263 | * If some other task has this inode open for write we should not add | 1302 | * 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 |
| 1265 | * modification changes anyway. | 1304 | * modification changes anyway. |
| 1266 | */ | 1305 | */ |
| 1267 | if ((flags & FAN_MARK_IGNORED_MASK) && | 1306 | if ((flags & FANOTIFY_MARK_IGNORE_BITS) && |
| 1268 | !(flags & FAN_MARK_IGNORED_SURV_MODIFY) && | 1307 | !(flags & FAN_MARK_IGNORED_SURV_MODIFY) && |
| 1269 | inode_is_open_for_write(inode)) | 1308 | inode_is_open_for_write(inode)) |
| 1270 | return 0; | 1309 | return 0; |
| @@ -1520,7 +1559,8 @@ static int fanotify_events_supported(struct fsnotify_group *group, · 249 unmodified lines | |||
| 1520 | unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS; | 1559 | unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS; |
| 1521 | /* Strict validation of events in non-dir inode mask with v5.17+ APIs */ | 1560 | /* Strict validation of events in non-dir inode mask with v5.17+ APIs */ |
| 1522 | bool strict_dir_events = FAN_GROUP_FLAG(group, FAN_REPORT_TARGET_FID) || | 1561 | 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); | ||
| 1524 | 1564 | ||
| 1525 | /* | 1565 | /* |
| 1526 | * Some filesystems such as 'proc' acquire unusual locks when opening | 1566 | * 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 | |||
| 1557 | __kernel_fsid_t __fsid, *fsid = NULL; | 1597 | __kernel_fsid_t __fsid, *fsid = NULL; |
| 1558 | u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS; | 1598 | u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS; |
| 1559 | unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS; | 1599 | 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; | ||
| 1561 | unsigned int obj_type, fid_mode; | 1602 | unsigned int obj_type, fid_mode; |
| 1562 | u32 umask = 0; | 1603 | u32 umask = 0; |
| 1563 | int ret; | 1604 | int ret; |
| @@ -1586,7 +1627,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, · 22 unmodified lines | |||
| 1586 | return -EINVAL; | 1627 | return -EINVAL; |
| 1587 | } | 1628 | } |
| 1588 | 1629 | ||
| 1589 | switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) { | 1630 | switch (mark_cmd) { |
| 1590 | case FAN_MARK_ADD: | 1631 | case FAN_MARK_ADD: |
| 1591 | case FAN_MARK_REMOVE: | 1632 | case FAN_MARK_REMOVE: |
| 1592 | if (!mask) | 1633 | if (!mask) |
| @@ -1606,9 +1647,19 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, · 13 unmodified lines | |||
| 1606 | if (mask & ~valid_mask) | 1647 | if (mask & ~valid_mask) |
| 1607 | return -EINVAL; | 1648 | return -EINVAL; |
| 1608 | 1649 | ||
| 1609 | /* Event flags (ONDIR, ON_CHILD) are meaningless in ignored mask */ | 1650 | |
| 1610 | if (ignored) | 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) { | ||
| 1611 | mask &= ~FANOTIFY_EVENT_FLAGS; | 1660 | mask &= ~FANOTIFY_EVENT_FLAGS; |
| 1661 | umask = FANOTIFY_EVENT_FLAGS; | ||
| 1662 | } | ||
| 1612 | 1663 | ||
| 1613 | f = fdget(fanotify_fd); | 1664 | f = fdget(fanotify_fd); |
| 1614 | if (unlikely(!f.file)) | 1665 | if (unlikely(!f.file)) |
| @@ -1672,7 +1723,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, · 57 unmodified lines | |||
| 1672 | if (mask & FAN_RENAME && !(fid_mode & FAN_REPORT_NAME)) | 1723 | if (mask & FAN_RENAME && !(fid_mode & FAN_REPORT_NAME)) |
| 1673 | goto fput_and_out; | 1724 | goto fput_and_out; |
| 1674 | 1725 | ||
| 1675 | if (flags & FAN_MARK_FLUSH) { | 1726 | if (mark_cmd == FAN_MARK_FLUSH) { |
| 1676 | ret = 0; | 1727 | ret = 0; |
| 1677 | if (mark_type == FAN_MARK_MOUNT) | 1728 | if (mark_type == FAN_MARK_MOUNT) |
| 1678 | fsnotify_clear_vfsmount_marks_by_group(group); | 1729 | 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 | |||
| 1688 | if (ret) | 1739 | if (ret) |
| 1689 | goto fput_and_out; | 1740 | goto fput_and_out; |
| 1690 | 1741 | ||
| 1691 | if (flags & FAN_MARK_ADD) { | 1742 | if (mark_cmd == FAN_MARK_ADD) { |
| 1692 | ret = fanotify_events_supported(group, &path, mask, flags); | 1743 | ret = fanotify_events_supported(group, &path, mask, flags); |
| 1693 | if (ret) | 1744 | if (ret) |
| 1694 | goto path_put_and_out; | 1745 | 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 | |||
| 1712 | else | 1763 | else |
| 1713 | mnt = path.mnt; | 1764 | mnt = path.mnt; |
| 1714 | 1765 | ||
| 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 | |||
| 1715 | /* Mask out FAN_EVENT_ON_CHILD flag for sb/mount/non-dir marks */ | 1773 | /* Mask out FAN_EVENT_ON_CHILD flag for sb/mount/non-dir marks */ |
| 1716 | if (mnt || !S_ISDIR(inode->i_mode)) { | 1774 | if (mnt || !S_ISDIR(inode->i_mode)) { |
| 1717 | mask &= ~FAN_EVENT_ON_CHILD; | 1775 | 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 | |||
| 1721 | * events with parent/name info for non-directory. | 1779 | * events with parent/name info for non-directory. |
| 1722 | */ | 1780 | */ |
| 1723 | if ((fid_mode & FAN_REPORT_DIR_FID) && | 1781 | if ((fid_mode & FAN_REPORT_DIR_FID) && |
| 1724 | (flags & FAN_MARK_ADD) && !ignored) | 1782 | (flags & FAN_MARK_ADD) && !ignore) |
| 1725 | mask |= FAN_EVENT_ON_CHILD; | 1783 | mask |= FAN_EVENT_ON_CHILD; |
| 1726 | } | 1784 | } |
| 1727 | 1785 | ||
| 1728 | /* create/update an inode mark */ | 1786 | /* create/update an inode mark */ |
| 1729 | switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE)) { | 1787 | switch (mark_cmd) { |
| 1730 | case FAN_MARK_ADD: | 1788 | case FAN_MARK_ADD: |
| 1731 | if (mark_type == FAN_MARK_MOUNT) | 1789 | if (mark_type == FAN_MARK_MOUNT) |
| 1732 | ret = fanotify_add_vfsmount_mark(group, mnt, mask, | 1790 | ret = fanotify_add_vfsmount_mark(group, mnt, mask, |
| @@ -1804,7 +1862,7 @@ static int __init fanotify_user_setup(void) · 71 unmodified lines | |||
| 1804 | 1862 | ||
| 1805 | BUILD_BUG_ON(FANOTIFY_INIT_FLAGS & FANOTIFY_INTERNAL_GROUP_FLAGS); | 1863 | BUILD_BUG_ON(FANOTIFY_INIT_FLAGS & FANOTIFY_INTERNAL_GROUP_FLAGS); |
| 1806 | BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 12); | 1864 | 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); |
| 1808 | 1866 | ||
| 1809 | fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, | 1867 | fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, |
| 1810 | SLAB_PANIC|SLAB_ACCOUNT); | 1868 | SLAB_PANIC|SLAB_ACCOUNT); |
| @@ -113,7 +113,7 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark) · 112 unmodified lines | |||
| 113 | return; | 113 | return; |
| 114 | seq_printf(m, "fanotify ino:%lx sdev:%x mflags:%x mask:%x ignored_mask:%x ", | 114 | seq_printf(m, "fanotify ino:%lx sdev:%x mflags:%x mask:%x ignored_mask:%x ", |
| 115 | inode->i_ino, inode->i_sb->s_dev, | 115 | inode->i_ino, inode->i_sb->s_dev, |
| 116 | mflags, mark->mask, mark->ignored_mask); | 116 | mflags, mark->mask, mark->ignore_mask); |
| 117 | show_mark_fhandle(m, inode); | 117 | show_mark_fhandle(m, inode); |
| 118 | seq_putc(m, '\n'); | 118 | seq_putc(m, '\n'); |
| 119 | iput(inode); | 119 | iput(inode); |
| @@ -121,12 +121,12 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark) · 1 unmodified line | |||
| 121 | struct mount *mnt = fsnotify_conn_mount(mark->connector); | 121 | struct mount *mnt = fsnotify_conn_mount(mark->connector); |
| 122 | 122 | ||
| 123 | seq_printf(m, "fanotify mnt_id:%x mflags:%x mask:%x ignored_mask:%x\n", | 123 | 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); |
| 125 | } else if (mark->connector->type == FSNOTIFY_OBJ_TYPE_SB) { | 125 | } else if (mark->connector->type == FSNOTIFY_OBJ_TYPE_SB) { |
| 126 | struct super_block *sb = fsnotify_conn_sb(mark->connector); | 126 | struct super_block *sb = fsnotify_conn_sb(mark->connector); |
| 127 | 127 | ||
| 128 | seq_printf(m, "fanotify sdev:%x mflags:%x mask:%x ignored_mask:%x\n", | 128 | 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); |
| 130 | } | 130 | } |
| 131 | } | 131 | } |
| 132 | 132 | ||
| @@ -100,7 +100,7 @@ void fsnotify_sb_delete(struct super_block *sb) · 99 unmodified lines | |||
| 100 | * Given an inode, first check if we care what happens to our children. Inotify | 100 | * Given an inode, first check if we care what happens to our children. Inotify |
| 101 | * and dnotify both tell their parents about events. If we care about any event | 101 | * and dnotify both tell their parents about events. If we care about any event |
| 102 | * on a child we run all of our children and set a dentry flag saying that the | 102 | * 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 |
| 104 | * if there is a need to find a parent and send the event to the parent. | 104 | * if there is a need to find a parent and send the event to the parent. |
| 105 | */ | 105 | */ |
| 106 | void __fsnotify_update_child_dentry_flags(struct inode *inode) | 106 | 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 | |||
| 324 | struct fsnotify_group *group = NULL; | 324 | struct fsnotify_group *group = NULL; |
| 325 | __u32 test_mask = (mask & ALL_FSNOTIFY_EVENTS); | 325 | __u32 test_mask = (mask & ALL_FSNOTIFY_EVENTS); |
| 326 | __u32 marks_mask = 0; | 326 | __u32 marks_mask = 0; |
| 327 | __u32 marks_ignored_mask = 0; | 327 | __u32 marks_ignore_mask = 0; |
| 328 | bool is_dir = mask & FS_ISDIR; | ||
| 328 | struct fsnotify_mark *mark; | 329 | struct fsnotify_mark *mark; |
| 329 | int type; | 330 | int type; |
| 330 | 331 | ||
| @@ -336,7 +337,7 @@ static int send_to_group(__u32 mask, const void *data, int data_type, · 5 unmodified lines | |||
| 336 | fsnotify_foreach_iter_mark_type(iter_info, mark, type) { | 337 | fsnotify_foreach_iter_mark_type(iter_info, mark, type) { |
| 337 | if (!(mark->flags & | 338 | if (!(mark->flags & |
| 338 | FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) | 339 | FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) |
| 339 | mark->ignored_mask = 0; | 340 | mark->ignore_mask = 0; |
| 340 | } | 341 | } |
| 341 | } | 342 | } |
| 342 | 343 | ||
| @@ -344,14 +345,15 @@ static int send_to_group(__u32 mask, const void *data, int data_type, · 1 unmodified line | |||
| 344 | fsnotify_foreach_iter_mark_type(iter_info, mark, type) { | 345 | fsnotify_foreach_iter_mark_type(iter_info, mark, type) { |
| 345 | group = mark->group; | 346 | group = mark->group; |
| 346 | marks_mask |= mark->mask; | 347 | marks_mask |= mark->mask; |
| 347 | marks_ignored_mask |= mark->ignored_mask; | 348 | marks_ignore_mask |= |
| 349 | fsnotify_effective_ignore_mask(mark, is_dir, type); | ||
| 348 | } | 350 | } |
| 349 | 351 | ||
| 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", | 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", |
| 351 | __func__, group, mask, marks_mask, marks_ignored_mask, | 353 | __func__, group, mask, marks_mask, marks_ignore_mask, |
| 352 | data, data_type, dir, cookie); | 354 | data, data_type, dir, cookie); |
| 353 | 355 | ||
| 354 | if (!(test_mask & marks_mask & ~marks_ignored_mask)) | 356 | if (!(test_mask & marks_mask & ~marks_ignore_mask)) |
| 355 | return 0; | 357 | return 0; |
| 356 | 358 | ||
| 357 | if (group->ops->handle_event) { | 359 | if (group->ops->handle_event) { |
| @@ -423,7 +425,8 @@ static bool fsnotify_iter_select_report_types( · 65 unmodified lines | |||
| 423 | * But is *this mark* watching children? | 425 | * But is *this mark* watching children? |
| 424 | */ | 426 | */ |
| 425 | if (type == FSNOTIFY_ITER_TYPE_PARENT && | 427 | 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)) | ||
| 427 | continue; | 430 | continue; |
| 428 | 431 | ||
| 429 | fsnotify_iter_set_report_type(iter_info, type); | 432 | 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 | |||
| 532 | 535 | ||
| 533 | 536 | ||
| 534 | /* | 537 | /* |
| 535 | * If this is a modify event we may need to clear some ignored masks. | 538 | * If this is a modify event we may need to clear some ignore masks. |
| 536 | * In that case, the object with ignored masks will have the FS_MODIFY | 539 | * In that case, the object with ignore masks will have the FS_MODIFY |
| 537 | * event in its mask. | 540 | * event in its mask. |
| 538 | * Otherwise, return if none of the marks care about this type of event. | 541 | * Otherwise, return if none of the marks care about this type of event. |
| 539 | */ | 542 | */ |
| @@ -136,7 +136,7 @@ static inline u32 inotify_mask_to_arg(__u32 mask) · 135 unmodified lines | |||
| 136 | IN_Q_OVERFLOW); | 136 | IN_Q_OVERFLOW); |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | /* intofiy userspace file descriptor functions */ | 139 | /* inotify userspace file descriptor functions */ |
| 140 | static __poll_t inotify_poll(struct file *file, poll_table *wait) | 140 | static __poll_t inotify_poll(struct file *file, poll_table *wait) |
| 141 | { | 141 | { |
| 142 | struct fsnotify_group *group = file->private_data; | 142 | struct fsnotify_group *group = file->private_data; |
| @@ -59,15 +59,19 @@ · 58 unmodified lines | |||
| 59 | #define FANOTIFY_MARK_TYPE_BITS (FAN_MARK_INODE | FAN_MARK_MOUNT | \ | 59 | #define FANOTIFY_MARK_TYPE_BITS (FAN_MARK_INODE | FAN_MARK_MOUNT | \ |
| 60 | FAN_MARK_FILESYSTEM) | 60 | FAN_MARK_FILESYSTEM) |
| 61 | 61 | ||
| 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 | |||
| 62 | #define FANOTIFY_MARK_FLAGS (FANOTIFY_MARK_TYPE_BITS | \ | 68 | #define FANOTIFY_MARK_FLAGS (FANOTIFY_MARK_TYPE_BITS | \ |
| 63 | FAN_MARK_ADD | \ | 69 | FANOTIFY_MARK_CMD_BITS | \ |
| 64 | FAN_MARK_REMOVE | \ | 70 | FANOTIFY_MARK_IGNORE_BITS | \ |
| 65 | FAN_MARK_DONT_FOLLOW | \ | 71 | FAN_MARK_DONT_FOLLOW | \ |
| 66 | FAN_MARK_ONLYDIR | \ | 72 | FAN_MARK_ONLYDIR | \ |
| 67 | FAN_MARK_IGNORED_MASK | \ | ||
| 68 | FAN_MARK_IGNORED_SURV_MODIFY | \ | 73 | FAN_MARK_IGNORED_SURV_MODIFY | \ |
| 69 | FAN_MARK_EVICTABLE | \ | 74 | FAN_MARK_EVICTABLE) |
| 70 | FAN_MARK_FLUSH) | ||
| 71 | 75 | ||
| 72 | /* | 76 | /* |
| 73 | * Events that can be reported with data type FSNOTIFY_EVENT_PATH. | 77 | * Events that can be reported with data type FSNOTIFY_EVENT_PATH. |
| @@ -518,8 +518,8 @@ struct fsnotify_mark { · 517 unmodified lines | |||
| 518 | struct hlist_node obj_list; | 518 | struct hlist_node obj_list; |
| 519 | /* Head of list of marks for an object [mark ref] */ | 519 | /* Head of list of marks for an object [mark ref] */ |
| 520 | struct fsnotify_mark_connector *connector; | 520 | struct fsnotify_mark_connector *connector; |
| 521 | /* Events types to ignore [mark->lock, group->mark_mutex] */ | 521 | /* Events types and flags to ignore [mark->lock, group->mark_mutex] */ |
| 522 | __u32 ignored_mask; | 522 | __u32 ignore_mask; |
| 523 | /* General fsnotify mark flags */ | 523 | /* General fsnotify mark flags */ |
| 524 | #define FSNOTIFY_MARK_FLAG_ALIVE 0x0001 | 524 | #define FSNOTIFY_MARK_FLAG_ALIVE 0x0001 |
| 525 | #define FSNOTIFY_MARK_FLAG_ATTACHED 0x0002 | 525 | #define FSNOTIFY_MARK_FLAG_ATTACHED 0x0002 |
| @@ -529,6 +529,7 @@ struct fsnotify_mark { · 3 unmodified lines | |||
| 529 | /* fanotify mark flags */ | 529 | /* fanotify mark flags */ |
| 530 | #define FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY 0x0100 | 530 | #define FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY 0x0100 |
| 531 | #define FSNOTIFY_MARK_FLAG_NO_IREF 0x0200 | 531 | #define FSNOTIFY_MARK_FLAG_NO_IREF 0x0200 |
| 532 | #define FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS 0x0400 | ||
| 532 | unsigned int flags; /* flags [mark->lock] */ | 533 | unsigned int flags; /* flags [mark->lock] */ |
| 533 | }; | 534 | }; |
| 534 | 535 | ||
| @@ -655,15 +656,91 @@ extern void fsnotify_remove_queued_event(struct fsnotify_group *group, · 120 unmodified lines | |||
| 655 | 656 | ||
| 656 | /* functions used to manipulate the marks attached to inodes */ | 657 | /* functions used to manipulate the marks attached to inodes */ |
| 657 | 658 | ||
| 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 */ | ||
| 659 | static inline __u32 fsnotify_calc_mask(struct fsnotify_mark *mark) | 736 | static inline __u32 fsnotify_calc_mask(struct fsnotify_mark *mark) |
| 660 | { | 737 | { |
| 661 | __u32 mask = mark->mask; | 738 | __u32 mask = mark->mask; |
| 662 | 739 | ||
| 663 | if (!mark->ignored_mask) | 740 | if (!fsnotify_ignored_events(mark)) |
| 664 | return mask; | 741 | return mask; |
| 665 | 742 | ||
| 666 | /* Interest in FS_MODIFY may be needed for clearing ignored mask */ | 743 | /* Interest in FS_MODIFY may be needed for clearing ignore mask */ |
| 667 | if (!(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) | 744 | if (!(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) |
| 668 | mask |= FS_MODIFY; | 745 | mask |= FS_MODIFY; |
| 669 | 746 | ||
| @@ -671,7 +748,7 @@ static inline __u32 fsnotify_calc_mask(struct fsnotify_mark *mark) · 1 unmodified line | |||
| 671 | * If mark is interested in ignoring events on children, the object must | 748 | * If mark is interested in ignoring events on children, the object must |
| 672 | * show interest in those events for fsnotify_parent() to notice it. | 749 | * show interest in those events for fsnotify_parent() to notice it. |
| 673 | */ | 750 | */ |
| 674 | return mask | (mark->ignored_mask & ALL_FSNOTIFY_EVENTS); | 751 | return mask | mark->ignore_mask; |
| 675 | } | 752 | } |
| 676 | 753 | ||
| 677 | /* Get mask of events for a list of marks */ | 754 | /* Get mask of events for a list of marks */ |
| @@ -83,12 +83,20 @@ · 82 unmodified lines | |||
| 83 | #define FAN_MARK_FLUSH 0x00000080 | 83 | #define FAN_MARK_FLUSH 0x00000080 |
| 84 | /* FAN_MARK_FILESYSTEM is 0x00000100 */ | 84 | /* FAN_MARK_FILESYSTEM is 0x00000100 */ |
| 85 | #define FAN_MARK_EVICTABLE 0x00000200 | 85 | #define FAN_MARK_EVICTABLE 0x00000200 |
| 86 | /* This bit is mutually exclusive with FAN_MARK_IGNORED_MASK bit */ | ||
| 87 | #define FAN_MARK_IGNORE 0x00000400 | ||
| 86 | 88 | ||
| 87 | /* These are NOT bitwise flags. Both bits can be used togther. */ | 89 | /* These are NOT bitwise flags. Both bits can be used togther. */ |
| 88 | #define FAN_MARK_INODE 0x00000000 | 90 | #define FAN_MARK_INODE 0x00000000 |
| 89 | #define FAN_MARK_MOUNT 0x00000010 | 91 | #define FAN_MARK_MOUNT 0x00000010 |
| 90 | #define FAN_MARK_FILESYSTEM 0x00000100 | 92 | #define FAN_MARK_FILESYSTEM 0x00000100 |
| 91 | 93 | ||
| 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 | |||
| 92 | /* Deprecated - do not use this in programs and do not add new flags here! */ | 100 | /* Deprecated - do not use this in programs and do not add new flags here! */ |
| 93 | #define FAN_ALL_MARK_FLAGS (FAN_MARK_ADD |\ | 101 | #define FAN_ALL_MARK_FLAGS (FAN_MARK_ADD |\ |
| 94 | FAN_MARK_REMOVE |\ | 102 | FAN_MARK_REMOVE |\ |