From: Greg Kroah-Hartman Date: Thu, 23 Jun 2022 16:10:07 +0000 (+0200) Subject: 5.18-stable patches X-Git-Tag: v4.9.320~10 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bf62be6baa058ab78c63b2287d4f5bb458c78f01;p=thirdparty%2Fkernel%2Fstable-queue.git 5.18-stable patches added patches: fsnotify-consistent-behavior-for-parent-not-watching-children.patch fsnotify-introduce-mark-type-iterator.patch --- diff --git a/queue-5.18/fsnotify-consistent-behavior-for-parent-not-watching-children.patch b/queue-5.18/fsnotify-consistent-behavior-for-parent-not-watching-children.patch new file mode 100644 index 00000000000..af9c54c09e7 --- /dev/null +++ b/queue-5.18/fsnotify-consistent-behavior-for-parent-not-watching-children.patch @@ -0,0 +1,123 @@ +From e730558adffb88a52e562db089e969ee9510184a Mon Sep 17 00:00:00 2001 +From: Amir Goldstein +Date: Wed, 11 May 2022 22:02:13 +0300 +Subject: fsnotify: consistent behavior for parent not watching children + +From: Amir Goldstein + +commit e730558adffb88a52e562db089e969ee9510184a upstream. + +The logic for handling events on child in groups that have a mark on +the parent inode, but without FS_EVENT_ON_CHILD flag in the mask is +duplicated in several places and inconsistent. + +Move the logic into the preparation of mark type iterator, so that the +parent mark type will be excluded from all mark type iterations in that +case. + +This results in several subtle changes of behavior, hopefully all +desired changes of behavior, for example: + +- Group A has a mount mark with FS_MODIFY in mask +- Group A has a mark with ignore mask that does not survive FS_MODIFY + and does not watch children on directory D. +- Group B has a mark with FS_MODIFY in mask that does watch children + on directory D. +- FS_MODIFY event on file D/foo should not clear the ignore mask of + group A, but before this change it does + +And if group A ignore mask was set to survive FS_MODIFY: +- FS_MODIFY event on file D/foo should be reported to group A on account + of the mount mark, but before this change it is wrongly ignored + +Fixes: 2f02fd3fa13e ("fanotify: fix ignore mask logic for events on child and on dir") +Reported-by: Jan Kara +Link: https://lore.kernel.org/linux-fsdevel/20220314113337.j7slrb5srxukztje@quack3.lan/ +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Link: https://lore.kernel.org/r/20220511190213.831646-3-amir73il@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + fs/notify/fanotify/fanotify.c | 10 +--------- + fs/notify/fsnotify.c | 34 +++++++++++++++++++--------------- + 2 files changed, 20 insertions(+), 24 deletions(-) + +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -320,7 +320,7 @@ static u32 fanotify_group_event_mask(str + } + + fsnotify_foreach_iter_mark_type(iter_info, mark, type) { +- /* Apply ignore mask regardless of ISDIR and ON_CHILD flags */ ++ /* Apply ignore mask regardless of mark's ISDIR flag */ + marks_ignored_mask |= mark->ignored_mask; + + /* +@@ -330,14 +330,6 @@ static u32 fanotify_group_event_mask(str + if (event_mask & FS_ISDIR && !(mark->mask & FS_ISDIR)) + continue; + +- /* +- * If the event is on a child and this mark is on a parent not +- * watching children, don't send it! +- */ +- if (type == FSNOTIFY_ITER_TYPE_PARENT && +- !(mark->mask & FS_EVENT_ON_CHILD)) +- continue; +- + marks_mask |= mark->mask; + + /* Record the mark types of this group that matched the event */ +--- a/fs/notify/fsnotify.c ++++ b/fs/notify/fsnotify.c +@@ -290,22 +290,15 @@ static int fsnotify_handle_event(struct + } + + if (parent_mark) { +- /* +- * parent_mark indicates that the parent inode is watching +- * children and interested in this event, which is an event +- * possible on child. But is *this mark* watching children and +- * interested in this event? +- */ +- if (parent_mark->mask & FS_EVENT_ON_CHILD) { +- ret = fsnotify_handle_inode_event(group, parent_mark, mask, +- data, data_type, dir, name, 0); +- if (ret) +- return ret; +- } +- if (!inode_mark) +- return 0; ++ ret = fsnotify_handle_inode_event(group, parent_mark, mask, ++ data, data_type, dir, name, 0); ++ if (ret) ++ return ret; + } + ++ if (!inode_mark) ++ return 0; ++ + if (mask & FS_EVENT_ON_CHILD) { + /* + * Some events can be sent on both parent dir and child marks +@@ -422,8 +415,19 @@ static bool fsnotify_iter_select_report_ + iter_info->report_mask = 0; + fsnotify_foreach_iter_type(type) { + mark = iter_info->marks[type]; +- if (mark && mark->group == iter_info->current_group) ++ if (mark && mark->group == iter_info->current_group) { ++ /* ++ * FSNOTIFY_ITER_TYPE_PARENT indicates that this inode ++ * is watching children and interested in this event, ++ * which is an event possible on child. ++ * But is *this mark* watching children? ++ */ ++ if (type == FSNOTIFY_ITER_TYPE_PARENT && ++ !(mark->mask & FS_EVENT_ON_CHILD)) ++ continue; ++ + fsnotify_iter_set_report_type(iter_info, type); ++ } + } + + return true; diff --git a/queue-5.18/fsnotify-introduce-mark-type-iterator.patch b/queue-5.18/fsnotify-introduce-mark-type-iterator.patch new file mode 100644 index 00000000000..35a3cc0553e --- /dev/null +++ b/queue-5.18/fsnotify-introduce-mark-type-iterator.patch @@ -0,0 +1,233 @@ +From 14362a2541797cf9df0e86fb12dcd7950baf566e Mon Sep 17 00:00:00 2001 +From: Amir Goldstein +Date: Wed, 11 May 2022 22:02:12 +0300 +Subject: fsnotify: introduce mark type iterator + +From: Amir Goldstein + +commit 14362a2541797cf9df0e86fb12dcd7950baf566e upstream. + +fsnotify_foreach_iter_mark_type() is used to reduce boilerplate code +of iterating all marks of a specific group interested in an event +by consulting the iterator report_mask. + +Use an open coded version of that iterator in fsnotify_iter_next() +that collects all marks of the current iteration group without +consulting the iterator report_mask. + +At the moment, the two iterator variants are the same, but this +decoupling will allow us to exclude some of the group's marks from +reporting the event, for example for event on child and inode marks +on parent did not request to watch events on children. + +Fixes: 2f02fd3fa13e ("fanotify: fix ignore mask logic for events on child and on dir") +Reported-by: Jan Kara +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Link: https://lore.kernel.org/r/20220511190213.831646-2-amir73il@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + fs/notify/fanotify/fanotify.c | 14 ++-------- + fs/notify/fsnotify.c | 53 +++++++++++++++++++-------------------- + include/linux/fsnotify_backend.h | 31 +++++++++++++++++----- + 3 files changed, 54 insertions(+), 44 deletions(-) + +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -319,11 +319,7 @@ static u32 fanotify_group_event_mask(str + return 0; + } + +- fsnotify_foreach_iter_type(type) { +- if (!fsnotify_iter_should_report_type(iter_info, type)) +- continue; +- mark = iter_info->marks[type]; +- ++ fsnotify_foreach_iter_mark_type(iter_info, mark, type) { + /* Apply ignore mask regardless of ISDIR and ON_CHILD flags */ + marks_ignored_mask |= mark->ignored_mask; + +@@ -849,16 +845,14 @@ out: + */ + static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info) + { ++ struct fsnotify_mark *mark; + int type; + __kernel_fsid_t fsid = {}; + +- fsnotify_foreach_iter_type(type) { ++ fsnotify_foreach_iter_mark_type(iter_info, mark, type) { + struct fsnotify_mark_connector *conn; + +- if (!fsnotify_iter_should_report_type(iter_info, type)) +- continue; +- +- conn = READ_ONCE(iter_info->marks[type]->connector); ++ conn = READ_ONCE(mark->connector); + /* Mark is just getting destroyed or created? */ + if (!conn) + continue; +--- a/fs/notify/fsnotify.c ++++ b/fs/notify/fsnotify.c +@@ -335,31 +335,23 @@ static int send_to_group(__u32 mask, con + struct fsnotify_mark *mark; + int type; + +- if (WARN_ON(!iter_info->report_mask)) ++ if (!iter_info->report_mask) + return 0; + + /* clear ignored on inode modification */ + if (mask & FS_MODIFY) { +- fsnotify_foreach_iter_type(type) { +- if (!fsnotify_iter_should_report_type(iter_info, type)) +- continue; +- mark = iter_info->marks[type]; +- if (mark && +- !(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) ++ fsnotify_foreach_iter_mark_type(iter_info, mark, type) { ++ if (!(mark->flags & ++ FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) + mark->ignored_mask = 0; + } + } + +- fsnotify_foreach_iter_type(type) { +- if (!fsnotify_iter_should_report_type(iter_info, type)) +- continue; +- mark = iter_info->marks[type]; +- /* does the object mark tell us to do something? */ +- if (mark) { +- group = mark->group; +- marks_mask |= mark->mask; +- marks_ignored_mask |= mark->ignored_mask; +- } ++ /* Are any of the group marks interested in this event? */ ++ fsnotify_foreach_iter_mark_type(iter_info, mark, type) { ++ group = mark->group; ++ marks_mask |= mark->mask; ++ marks_ignored_mask |= mark->ignored_mask; + } + + pr_debug("%s: group=%p mask=%x marks_mask=%x marks_ignored_mask=%x data=%p data_type=%d dir=%p cookie=%d\n", +@@ -403,11 +395,11 @@ static struct fsnotify_mark *fsnotify_ne + + /* + * iter_info is a multi head priority queue of marks. +- * Pick a subset of marks from queue heads, all with the +- * same group and set the report_mask for selected subset. +- * Returns the report_mask of the selected subset. ++ * Pick a subset of marks from queue heads, all with the same group ++ * and set the report_mask to a subset of the selected marks. ++ * Returns false if there are no more groups to iterate. + */ +-static unsigned int fsnotify_iter_select_report_types( ++static bool fsnotify_iter_select_report_types( + struct fsnotify_iter_info *iter_info) + { + struct fsnotify_group *max_prio_group = NULL; +@@ -423,30 +415,37 @@ static unsigned int fsnotify_iter_select + } + + if (!max_prio_group) +- return 0; ++ return false; + + /* Set the report mask for marks from same group as max prio group */ ++ iter_info->current_group = max_prio_group; + iter_info->report_mask = 0; + fsnotify_foreach_iter_type(type) { + mark = iter_info->marks[type]; +- if (mark && +- fsnotify_compare_groups(max_prio_group, mark->group) == 0) ++ if (mark && mark->group == iter_info->current_group) + fsnotify_iter_set_report_type(iter_info, type); + } + +- return iter_info->report_mask; ++ return true; + } + + /* +- * Pop from iter_info multi head queue, the marks that were iterated in the ++ * Pop from iter_info multi head queue, the marks that belong to the group of + * current iteration step. + */ + static void fsnotify_iter_next(struct fsnotify_iter_info *iter_info) + { ++ struct fsnotify_mark *mark; + int type; + ++ /* ++ * We cannot use fsnotify_foreach_iter_mark_type() here because we ++ * may need to advance a mark of type X that belongs to current_group ++ * but was not selected for reporting. ++ */ + fsnotify_foreach_iter_type(type) { +- if (fsnotify_iter_should_report_type(iter_info, type)) ++ mark = iter_info->marks[type]; ++ if (mark && mark->group == iter_info->current_group) + iter_info->marks[type] = + fsnotify_next_mark(iter_info->marks[type]); + } +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -370,6 +370,7 @@ static inline bool fsnotify_valid_obj_ty + + struct fsnotify_iter_info { + struct fsnotify_mark *marks[FSNOTIFY_ITER_TYPE_COUNT]; ++ struct fsnotify_group *current_group; + unsigned int report_mask; + int srcu_idx; + }; +@@ -386,20 +387,31 @@ static inline void fsnotify_iter_set_rep + iter_info->report_mask |= (1U << iter_type); + } + +-static inline void fsnotify_iter_set_report_type_mark( +- struct fsnotify_iter_info *iter_info, int iter_type, +- struct fsnotify_mark *mark) ++static inline struct fsnotify_mark *fsnotify_iter_mark( ++ struct fsnotify_iter_info *iter_info, int iter_type) + { +- iter_info->marks[iter_type] = mark; +- iter_info->report_mask |= (1U << iter_type); ++ if (fsnotify_iter_should_report_type(iter_info, iter_type)) ++ return iter_info->marks[iter_type]; ++ return NULL; ++} ++ ++static inline int fsnotify_iter_step(struct fsnotify_iter_info *iter, int type, ++ struct fsnotify_mark **markp) ++{ ++ while (type < FSNOTIFY_ITER_TYPE_COUNT) { ++ *markp = fsnotify_iter_mark(iter, type); ++ if (*markp) ++ break; ++ type++; ++ } ++ return type; + } + + #define FSNOTIFY_ITER_FUNCS(name, NAME) \ + static inline struct fsnotify_mark *fsnotify_iter_##name##_mark( \ + struct fsnotify_iter_info *iter_info) \ + { \ +- return (iter_info->report_mask & (1U << FSNOTIFY_ITER_TYPE_##NAME)) ? \ +- iter_info->marks[FSNOTIFY_ITER_TYPE_##NAME] : NULL; \ ++ return fsnotify_iter_mark(iter_info, FSNOTIFY_ITER_TYPE_##NAME); \ + } + + FSNOTIFY_ITER_FUNCS(inode, INODE) +@@ -409,6 +421,11 @@ FSNOTIFY_ITER_FUNCS(sb, SB) + + #define fsnotify_foreach_iter_type(type) \ + for (type = 0; type < FSNOTIFY_ITER_TYPE_COUNT; type++) ++#define fsnotify_foreach_iter_mark_type(iter, mark, type) \ ++ for (type = 0; \ ++ type = fsnotify_iter_step(iter, type, &mark), \ ++ type < FSNOTIFY_ITER_TYPE_COUNT; \ ++ type++) + + /* + * fsnotify_connp_t is what we embed in objects which connector can be attached diff --git a/queue-5.18/series b/queue-5.18/series index 83ef31eeae4..157d89d4ef4 100644 --- a/queue-5.18/series +++ b/queue-5.18/series @@ -4,3 +4,5 @@ wifi-rtlwifi-remove-always-true-condition-pointed-out-by-gcc-12.patch eth-sun-cassini-remove-dead-code.patch net-wwan-iosm-remove-pointless-null-check.patch x86-boot-wrap-literal-addresses-in-absolute_pointer.patch +fsnotify-introduce-mark-type-iterator.patch +fsnotify-consistent-behavior-for-parent-not-watching-children.patch