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 | 295 | const void *data, int data_type, |
| 296 | 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 | 299 | __u32 test_mask, user_mask = FANOTIFY_OUTGOING_EVENTS | |
| 300 | 300 | FANOTIFY_EVENT_FLAGS; |
| 301 | 301 | const struct path *path = fsnotify_data_path(data, data_type); |
| 302 | 302 | unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); |
| 303 | 303 | struct fsnotify_mark *mark; |
| 304 | + bool ondir = event_mask & FAN_ONDIR; | |
| 304 | 305 | int type; |
| 305 | 306 | |
| 306 | 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 | 316 | return 0; |
| 316 | 317 | } else if (!(fid_mode & FAN_REPORT_FID)) { |
| 317 | 318 | /* Do we have a directory inode to report? */ |
| 318 | − if (!dir && !(event_mask & FS_ISDIR)) | |
| 319 | + if (!dir && !ondir) | |
| 319 | 320 | return 0; |
| 320 | 321 | } |
| 321 | 322 | |
| 322 | 323 | 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); | |
| 325 | 329 | |
| 326 | 330 | /* |
| 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. | |
| 329 | 332 | */ |
| 330 | − if (event_mask & FS_ISDIR && !(mark->mask & FS_ISDIR)) | |
| 333 | + if (!fsnotify_mask_applicable(mark->mask, ondir, type)) | |
| 331 | 334 | continue; |
| 332 | 335 | |
| 333 | 336 | marks_mask |= mark->mask; |
| @@ -336,7 +339,7 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, · 2 unmodified lines | ||
| 336 | 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 | 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 | 499 | mflags |= FAN_MARK_IGNORED_SURV_MODIFY; |
| 500 | 500 | if (mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF) |
| 501 | 501 | mflags |= FAN_MARK_EVICTABLE; |
| 502 | + if (mark->flags & FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS) | |
| 503 | + mflags |= FAN_MARK_IGNORE; | |
| 502 | 504 | |
| 503 | 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 | 1009 | mask &= ~umask; |
| 1010 | 1010 | spin_lock(&fsn_mark->lock); |
| 1011 | 1011 | oldmask = fsnotify_calc_mask(fsn_mark); |
| 1012 | − if (!(flags & FAN_MARK_IGNORED_MASK)) { | |
| 1012 | + if (!(flags & FANOTIFY_MARK_IGNORE_BITS)) { | |
| 1013 | 1013 | fsn_mark->mask &= ~mask; |
| 1014 | 1014 | } else { |
| 1015 | − fsn_mark->ignored_mask &= ~mask; | |
| 1015 | + fsn_mark->ignore_mask &= ~mask; | |
| 1016 | 1016 | } |
| 1017 | 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 | 1021 | * changes to the mask. |
| 1022 | 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 | 1025 | spin_unlock(&fsn_mark->lock); |
| 1026 | 1026 | |
| 1027 | 1027 | return oldmask & ~newmask; |
| @@ -1085,15 +1085,24 @@ static bool fanotify_mark_update_flags(struct fsnotify_mark *fsn_mark, · 57 unmodified lines | ||
| 1085 | 1085 | unsigned int fan_flags) |
| 1086 | 1086 | { |
| 1087 | 1087 | bool want_iref = !(fan_flags & FAN_MARK_EVICTABLE); |
| 1088 | + unsigned int ignore = fan_flags & FANOTIFY_MARK_IGNORE_BITS; | |
| 1088 | 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 | 1101 | * Setting FAN_MARK_IGNORED_SURV_MODIFY for the first time may lead to |
| 1092 | 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) && | |
| 1096 | − (fan_flags & FAN_MARK_IGNORED_SURV_MODIFY) && | |
| 1105 | + if (ignore && (fan_flags & FAN_MARK_IGNORED_SURV_MODIFY) && | |
| 1097 | 1106 | !(fsn_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) { |
| 1098 | 1107 | fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY; |
| 1099 | 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 | 1129 | bool recalc; |
| 1121 | 1130 | |
| 1122 | 1131 | spin_lock(&fsn_mark->lock); |
| 1123 | − if (!(fan_flags & FAN_MARK_IGNORED_MASK)) | |
| 1132 | + if (!(fan_flags & FANOTIFY_MARK_IGNORE_BITS)) | |
| 1124 | 1133 | fsn_mark->mask |= mask; |
| 1125 | 1134 | else |
| 1126 | − fsn_mark->ignored_mask |= mask; | |
| 1135 | + fsn_mark->ignore_mask |= mask; | |
| 1127 | 1136 | |
| 1128 | 1137 | recalc = fsnotify_calc_mask(fsn_mark) & |
| 1129 | 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 | 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 | 1230 | static int fanotify_add_mark(struct fsnotify_group *group, |
| 1191 | 1231 | fsnotify_connp_t *connp, unsigned int obj_type, |
| 1192 | 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 && | |
| 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) | |
| 1216 | 1255 | goto out; |
| 1217 | − } | |
| 1218 | 1256 | |
| 1219 | 1257 | /* |
| 1220 | 1258 | * Error events are pre-allocated per group, only if strictly |
| 1221 | 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 | 1263 | ret = fanotify_group_init_error_pool(group); |
| 1225 | 1264 | if (ret) |
| 1226 | 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 | 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 | 1304 | * modification changes anyway. |
| 1266 | 1305 | */ |
| 1267 | − if ((flags & FAN_MARK_IGNORED_MASK) && | |
| 1306 | + if ((flags & FANOTIFY_MARK_IGNORE_BITS) && | |
| 1268 | 1307 | !(flags & FAN_MARK_IGNORED_SURV_MODIFY) && |
| 1269 | 1308 | inode_is_open_for_write(inode)) |
| 1270 | 1309 | return 0; |
| @@ -1520,7 +1559,8 @@ static int fanotify_events_supported(struct fsnotify_group *group, · 249 unmodified lines | ||
| 1520 | 1559 | unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS; |
| 1521 | 1560 | /* Strict validation of events in non-dir inode mask with v5.17+ APIs */ |
| 1522 | 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 | 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 | 1597 | __kernel_fsid_t __fsid, *fsid = NULL; |
| 1558 | 1598 | u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS; |
| 1559 | 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 | 1602 | unsigned int obj_type, fid_mode; |
| 1562 | 1603 | u32 umask = 0; |
| 1563 | 1604 | int ret; |
| @@ -1586,7 +1627,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, · 22 unmodified lines | ||
| 1586 | 1627 | return -EINVAL; |
| 1587 | 1628 | } |
| 1588 | 1629 | |
| 1589 | − switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) { | |
| 1630 | + switch (mark_cmd) { | |
| 1590 | 1631 | case FAN_MARK_ADD: |
| 1591 | 1632 | case FAN_MARK_REMOVE: |
| 1592 | 1633 | if (!mask) |
| @@ -1606,9 +1647,19 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, · 13 unmodified lines | ||
| 1606 | 1647 | if (mask & ~valid_mask) |
| 1607 | 1648 | return -EINVAL; |
| 1608 | 1649 | |
| 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) { | |
| 1611 | 1660 | mask &= ~FANOTIFY_EVENT_FLAGS; |
| 1661 | + umask = FANOTIFY_EVENT_FLAGS; | |
| 1662 | + } | |
| 1612 | 1663 | |
| 1613 | 1664 | f = fdget(fanotify_fd); |
| 1614 | 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 | 1723 | if (mask & FAN_RENAME && !(fid_mode & FAN_REPORT_NAME)) |
| 1673 | 1724 | goto fput_and_out; |
| 1674 | 1725 | |
| 1675 | − if (flags & FAN_MARK_FLUSH) { | |
| 1726 | + if (mark_cmd == FAN_MARK_FLUSH) { | |
| 1676 | 1727 | ret = 0; |
| 1677 | 1728 | if (mark_type == FAN_MARK_MOUNT) |
| 1678 | 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 | 1739 | if (ret) |
| 1689 | 1740 | goto fput_and_out; |
| 1690 | 1741 | |
| 1691 | − if (flags & FAN_MARK_ADD) { | |
| 1742 | + if (mark_cmd == FAN_MARK_ADD) { | |
| 1692 | 1743 | ret = fanotify_events_supported(group, &path, mask, flags); |
| 1693 | 1744 | if (ret) |
| 1694 | 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 | 1763 | else |
| 1713 | 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 | 1773 | /* Mask out FAN_EVENT_ON_CHILD flag for sb/mount/non-dir marks */ |
| 1716 | 1774 | if (mnt || !S_ISDIR(inode->i_mode)) { |
| 1717 | 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 | 1779 | * events with parent/name info for non-directory. |
| 1722 | 1780 | */ |
| 1723 | 1781 | if ((fid_mode & FAN_REPORT_DIR_FID) && |
| 1724 | − (flags & FAN_MARK_ADD) && !ignored) | |
| 1782 | + (flags & FAN_MARK_ADD) && !ignore) | |
| 1725 | 1783 | mask |= FAN_EVENT_ON_CHILD; |
| 1726 | 1784 | } |
| 1727 | 1785 | |
| 1728 | 1786 | /* create/update an inode mark */ |
| 1729 | − switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE)) { | |
| 1787 | + switch (mark_cmd) { | |
| 1730 | 1788 | case FAN_MARK_ADD: |
| 1731 | 1789 | if (mark_type == FAN_MARK_MOUNT) |
| 1732 | 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 | 1863 | BUILD_BUG_ON(FANOTIFY_INIT_FLAGS & FANOTIFY_INTERNAL_GROUP_FLAGS); |
| 1806 | 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 | 1867 | fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, |
| 1810 | 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 | 113 | return; |
| 114 | 114 | seq_printf(m, "fanotify ino:%lx sdev:%x mflags:%x mask:%x ignored_mask:%x ", |
| 115 | 115 | inode->i_ino, inode->i_sb->s_dev, |
| 116 | − mflags, mark->mask, mark->ignored_mask); | |
| 116 | + mflags, mark->mask, mark->ignore_mask); | |
| 117 | 117 | show_mark_fhandle(m, inode); |
| 118 | 118 | seq_putc(m, '\n'); |
| 119 | 119 | iput(inode); |
| @@ -121,12 +121,12 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark) · 1 unmodified line | ||
| 121 | 121 | struct mount *mnt = fsnotify_conn_mount(mark->connector); |
| 122 | 122 | |
| 123 | 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 | 125 | } else if (mark->connector->type == FSNOTIFY_OBJ_TYPE_SB) { |
| 126 | 126 | struct super_block *sb = fsnotify_conn_sb(mark->connector); |
| 127 | 127 | |
| 128 | 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 | 100 | * Given an inode, first check if we care what happens to our children. Inotify |
| 101 | 101 | * and dnotify both tell their parents about events. If we care about any event |
| 102 | 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 | 104 | * if there is a need to find a parent and send the event to the parent. |
| 105 | 105 | */ |
| 106 | 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 | 324 | struct fsnotify_group *group = NULL; |
| 325 | 325 | __u32 test_mask = (mask & ALL_FSNOTIFY_EVENTS); |
| 326 | 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 | 329 | struct fsnotify_mark *mark; |
| 329 | 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 | 337 | fsnotify_foreach_iter_mark_type(iter_info, mark, type) { |
| 337 | 338 | if (!(mark->flags & |
| 338 | 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 | 345 | fsnotify_foreach_iter_mark_type(iter_info, mark, type) { |
| 345 | 346 | group = mark->group; |
| 346 | 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", | |
| 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, | |
| 352 | 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 | 357 | return 0; |
| 356 | 358 | |
| 357 | 359 | if (group->ops->handle_event) { |
| @@ -423,7 +425,8 @@ static bool fsnotify_iter_select_report_types( · 65 unmodified lines | ||
| 423 | 425 | * But is *this mark* watching children? |
| 424 | 426 | */ |
| 425 | 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 | 430 | continue; |
| 428 | 431 | |
| 429 | 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. | |
| 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 | |
| 537 | 540 | * event in its mask. |
| 538 | 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 | 136 | IN_Q_OVERFLOW); |
| 137 | 137 | } |
| 138 | 138 | |
| 139 | −/* intofiy userspace file descriptor functions */ | |
| 139 | +/* inotify userspace file descriptor functions */ | |
| 140 | 140 | static __poll_t inotify_poll(struct file *file, poll_table *wait) |
| 141 | 141 | { |
| 142 | 142 | struct fsnotify_group *group = file->private_data; |
| @@ -59,15 +59,19 @@ · 58 unmodified lines | ||
| 59 | 59 | #define FANOTIFY_MARK_TYPE_BITS (FAN_MARK_INODE | FAN_MARK_MOUNT | \ |
| 60 | 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 | 68 | #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 | \ | |
| 65 | 71 | FAN_MARK_DONT_FOLLOW | \ |
| 66 | 72 | FAN_MARK_ONLYDIR | \ |
| 67 | − FAN_MARK_IGNORED_MASK | \ | |
| 68 | 73 | FAN_MARK_IGNORED_SURV_MODIFY | \ |
| 69 | − FAN_MARK_EVICTABLE | \ | |
| 70 | − FAN_MARK_FLUSH) | |
| 74 | + FAN_MARK_EVICTABLE) | |
| 71 | 75 | |
| 72 | 76 | /* |
| 73 | 77 | * Events that can be reported with data type FSNOTIFY_EVENT_PATH. |
| @@ -518,8 +518,8 @@ struct fsnotify_mark { · 517 unmodified lines | ||
| 518 | 518 | struct hlist_node obj_list; |
| 519 | 519 | /* Head of list of marks for an object [mark ref] */ |
| 520 | 520 | 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; | |
| 523 | 523 | /* General fsnotify mark flags */ |
| 524 | 524 | #define FSNOTIFY_MARK_FLAG_ALIVE 0x0001 |
| 525 | 525 | #define FSNOTIFY_MARK_FLAG_ATTACHED 0x0002 |
| @@ -529,6 +529,7 @@ struct fsnotify_mark { · 3 unmodified lines | ||
| 529 | 529 | /* fanotify mark flags */ |
| 530 | 530 | #define FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY 0x0100 |
| 531 | 531 | #define FSNOTIFY_MARK_FLAG_NO_IREF 0x0200 |
| 532 | +#define FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS 0x0400 | |
| 532 | 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 | 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 | 736 | static inline __u32 fsnotify_calc_mask(struct fsnotify_mark *mark) |
| 660 | 737 | { |
| 661 | 738 | __u32 mask = mark->mask; |
| 662 | 739 | |
| 663 | − if (!mark->ignored_mask) | |
| 740 | + if (!fsnotify_ignored_events(mark)) | |
| 664 | 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 | 744 | if (!(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) |
| 668 | 745 | mask |= FS_MODIFY; |
| 669 | 746 | |
| @@ -671,7 +748,7 @@ static inline __u32 fsnotify_calc_mask(struct fsnotify_mark *mark) · 1 unmodified line | ||
| 671 | 748 | * If mark is interested in ignoring events on children, the object must |
| 672 | 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 | 754 | /* Get mask of events for a list of marks */ |
| @@ -83,12 +83,20 @@ · 82 unmodified lines | ||
| 83 | 83 | #define FAN_MARK_FLUSH 0x00000080 |
| 84 | 84 | /* FAN_MARK_FILESYSTEM is 0x00000100 */ |
| 85 | 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 | 89 | /* These are NOT bitwise flags. Both bits can be used togther. */ |
| 88 | 90 | #define FAN_MARK_INODE 0x00000000 |
| 89 | 91 | #define FAN_MARK_MOUNT 0x00000010 |
| 90 | 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 | 100 | /* Deprecated - do not use this in programs and do not add new flags here! */ |
| 93 | 101 | #define FAN_ALL_MARK_FLAGS (FAN_MARK_ADD |\ |
| 94 | 102 | FAN_MARK_REMOVE |\ |