diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 665f681dd913..1759121db50d 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -263,21 +263,31 @@ static struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark)
 /*
  * iter_info is a multi head priority queue of marks.
  * fsnotify_iter_first() picks a subset of marks from queue heads, all with the
- * same priority and clears the type_mask for other marks.
+ * same group and clears the type_mask for other marks.
  * Returns the type_mask of the chosen subset.
  */
 static unsigned int fsnotify_iter_first(struct fsnotify_iter_info *iter_info)
 {
-	struct fsnotify_mark *inode_mark = iter_info->inode_mark;
-	struct fsnotify_mark *vfsmount_mark = iter_info->vfsmount_mark;
-
-	if (inode_mark && vfsmount_mark) {
-		int cmp = fsnotify_compare_groups(inode_mark->group,
-						  vfsmount_mark->group);
-		if (cmp > 0)
-			iter_info->type_mask &= ~FSNOTIFY_OBJ_TYPE_INODE_FL;
-		else if (cmp < 0)
-			iter_info->type_mask &= ~FSNOTIFY_OBJ_TYPE_VFSMOUNT_FL;
+	struct fsnotify_group *max_prio_group = NULL;
+	unsigned int type_mask = iter_info->type_mask;
+	struct fsnotify_mark *mark;
+	int type;
+
+	if (!type_mask || is_power_of_2(type_mask))
+		return type_mask;
+
+	/* Choose max prio group among groups of all queue heads */
+	fsnotify_iter_foreach_obj_type_mark(iter_info, type, mark) {
+		if (mark &&
+		    fsnotify_compare_groups(max_prio_group, mark->group) > 0)
+			max_prio_group = mark->group;
+	}
+
+	/* Clear the type mask for marks with other groups */
+	fsnotify_iter_foreach_obj_type_mark(iter_info, type, mark) {
+		if (mark &&
+		    fsnotify_compare_groups(max_prio_group, mark->group) != 0)
+			iter_info->type_mask &= ~(1U << type);
 	}
 
 	return iter_info->type_mask;
@@ -289,17 +299,17 @@ static unsigned int fsnotify_iter_first(struct fsnotify_iter_info *iter_info)
  */
 static void fsnotify_iter_next(struct fsnotify_iter_info *iter_info)
 {
-	if (iter_info->type_mask & FSNOTIFY_OBJ_TYPE_INODE_FL)
-		fsnotify_iter_set_inode_mark(iter_info,
-			fsnotify_next_mark(iter_info->inode_mark));
-	else if (iter_info->inode_mark)
-		iter_info->type_mask |= FSNOTIFY_OBJ_TYPE_INODE_FL;
-
-	if (iter_info->type_mask & FSNOTIFY_OBJ_TYPE_VFSMOUNT_FL)
-		fsnotify_iter_set_vfsmount_mark(iter_info,
-			fsnotify_next_mark(iter_info->vfsmount_mark));
-	else if (iter_info->vfsmount_mark)
-		iter_info->type_mask |= FSNOTIFY_OBJ_TYPE_VFSMOUNT_FL;
+	int type;
+
+	fsnotify_foreach_obj_type(type) {
+		unsigned int flag = 1U << type;
+
+		if (iter_info->type_mask & flag)
+			fsnotify_iter_set_type_mark(iter_info, type,
+				fsnotify_next_mark(iter_info->marks[type]));
+		else if (iter_info->marks[type])
+			iter_info->type_mask |= flag;
+	}
 }
 
 /*
diff --git a/fs/notify/mark.c b/fs/notify/mark.c
index ef44808b28ca..3df2d5ecf0b7 100644
--- a/fs/notify/mark.c
+++ b/fs/notify/mark.c
@@ -294,12 +294,12 @@ static void fsnotify_put_mark_wake(struct fsnotify_mark *mark)
 
 bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info)
 {
-	/* This can fail if mark is being removed */
-	if (!fsnotify_get_mark_safe(iter_info->inode_mark))
-		return false;
-	if (!fsnotify_get_mark_safe(iter_info->vfsmount_mark)) {
-		fsnotify_put_mark_wake(iter_info->inode_mark);
-		return false;
+	int type;
+
+	fsnotify_foreach_obj_type(type) {
+		/* This can fail if mark is being removed */
+		if (!fsnotify_get_mark_safe(iter_info->marks[type]))
+			goto fail;
 	}
 
 	/*
@@ -310,13 +310,20 @@ bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info)
 	srcu_read_unlock(&fsnotify_mark_srcu, iter_info->srcu_idx);
 
 	return true;
+
+fail:
+	while (type-- > 0)
+		fsnotify_put_mark_wake(iter_info->marks[type]);
+	return false;
 }
 
 void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info)
 {
+	int type;
+
 	iter_info->srcu_idx = srcu_read_lock(&fsnotify_mark_srcu);
-	fsnotify_put_mark_wake(iter_info->inode_mark);
-	fsnotify_put_mark_wake(iter_info->vfsmount_mark);
+	fsnotify_foreach_obj_type(type)
+		fsnotify_put_mark_wake(iter_info->marks[type]);
 }
 
 /*
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index 62e05b8a9bc7..2f8c4255e679 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -211,34 +211,54 @@ enum fsnotify_obj_type {
 #define FSNOTIFY_OBJ_ALL_TYPES_MASK	((1U << FSNOTIFY_OBJ_TYPE_MAX) - 1)
 
 struct fsnotify_iter_info {
-	struct fsnotify_mark *inode_mark;
-	struct fsnotify_mark *vfsmount_mark;
+	struct fsnotify_mark *marks[FSNOTIFY_OBJ_TYPE_MAX];
 	unsigned int type_mask;
 	int srcu_idx;
 };
 
+static inline struct fsnotify_mark *fsnotify_iter_type_mark(
+		struct fsnotify_iter_info *iter_info, int type)
+{
+	return (iter_info->type_mask & (1U << type)) ?
+		iter_info->marks[type] : NULL;
+}
+
+static inline void fsnotify_iter_set_type_mark(
+		struct fsnotify_iter_info *iter_info,
+		int type, struct fsnotify_mark *mark)
+{
+	iter_info->marks[type] = mark;
+	if (mark)
+		iter_info->type_mask |= (1U << type);
+	else
+		iter_info->type_mask &= ~(1U << 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->type_mask & FSNOTIFY_OBJ_TYPE_##NAME##_FL) ? \
-		iter_info->name##_mark : NULL; \
+	return fsnotify_iter_type_mark(iter_info, FSNOTIFY_OBJ_TYPE_##NAME); \
 } \
 \
 static inline void fsnotify_iter_set_##name##_mark( \
 		struct fsnotify_iter_info *iter_info, \
 		struct fsnotify_mark *mark) \
 { \
-	iter_info->name##_mark = mark; \
-	if (mark) \
-		iter_info->type_mask |= FSNOTIFY_OBJ_TYPE_##NAME##_FL; \
-	else \
-		iter_info->type_mask &= ~FSNOTIFY_OBJ_TYPE_##NAME##_FL; \
+	fsnotify_iter_set_type_mark(iter_info, FSNOTIFY_OBJ_TYPE_##NAME, mark); \
 }
 
 FSNOTIFY_ITER_FUNCS(inode, INODE)
 FSNOTIFY_ITER_FUNCS(vfsmount, VFSMOUNT)
 
+#define fsnotify_foreach_obj_type(type) \
+	for (type = 0; type < FSNOTIFY_OBJ_TYPE_MAX; type++)
+
+#define fsnotify_iter_foreach_obj_type_mark(iter, type, mark) \
+	for (type = 0, mark = fsnotify_iter_type_mark(iter, type); \
+	     type < FSNOTIFY_OBJ_TYPE_MAX; \
+	     type++, mark = fsnotify_iter_type_mark(iter, type)) \
+
 /*
  * Inode / vfsmount point to this structure which tracks all marks attached to
  * the inode / vfsmount. The reference to inode / vfsmount is held by this
