]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.18-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 23 Jun 2022 16:10:07 +0000 (18:10 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 23 Jun 2022 16:10:07 +0000 (18:10 +0200)
added patches:
fsnotify-consistent-behavior-for-parent-not-watching-children.patch
fsnotify-introduce-mark-type-iterator.patch

queue-5.18/fsnotify-consistent-behavior-for-parent-not-watching-children.patch [new file with mode: 0644]
queue-5.18/fsnotify-introduce-mark-type-iterator.patch [new file with mode: 0644]
queue-5.18/series

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 (file)
index 0000000..af9c54c
--- /dev/null
@@ -0,0 +1,123 @@
+From e730558adffb88a52e562db089e969ee9510184a Mon Sep 17 00:00:00 2001
+From: Amir Goldstein <amir73il@gmail.com>
+Date: Wed, 11 May 2022 22:02:13 +0300
+Subject: fsnotify: consistent behavior for parent not watching children
+
+From: Amir Goldstein <amir73il@gmail.com>
+
+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 <jack@suse.com>
+Link: https://lore.kernel.org/linux-fsdevel/20220314113337.j7slrb5srxukztje@quack3.lan/
+Signed-off-by: Amir Goldstein <amir73il@gmail.com>
+Signed-off-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20220511190213.831646-3-amir73il@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..35a3cc0
--- /dev/null
@@ -0,0 +1,233 @@
+From 14362a2541797cf9df0e86fb12dcd7950baf566e Mon Sep 17 00:00:00 2001
+From: Amir Goldstein <amir73il@gmail.com>
+Date: Wed, 11 May 2022 22:02:12 +0300
+Subject: fsnotify: introduce mark type iterator
+
+From: Amir Goldstein <amir73il@gmail.com>
+
+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 <jack@suse.com>
+Signed-off-by: Amir Goldstein <amir73il@gmail.com>
+Signed-off-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20220511190213.831646-2-amir73il@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
index 83ef31eeae4f60b2a7dbe5a9df93e5e92f8fea1a..157d89d4ef4c0b62509fcbda35d3a572a9ee1103 100644 (file)
@@ -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