summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2018-04-20 16:10:52 -0700
committerJan Kara <jack@suse.cz>2018-05-18 14:58:22 +0200
commit47d9c7cc457adc5d6d8ca966482a51459f81e852 (patch)
tree5022fd69ab92a6f522b55ddb69b9ea2b22d84590
parentd9a6f30bb89309a7f2473028a00b83b020049cb4 (diff)
downloadlinux-47d9c7cc457adc5d6d8ca966482a51459f81e852.tar.gz
linux-47d9c7cc457adc5d6d8ca966482a51459f81e852.tar.bz2
linux-47d9c7cc457adc5d6d8ca966482a51459f81e852.zip
fsnotify: generalize iteration of marks by object type
Make some code that handles marks of object types inode and vfsmount generic, so it can handle other object types. Introduce fsnotify_foreach_obj_type macro to iterate marks by object type and fsnotify_iter_{should|set}_report_type macros to set/test report_mask. This is going to be used for adding mark of another object type (super block mark). Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Jan Kara <jack@suse.cz>
-rw-r--r--fs/notify/fsnotify.c52
-rw-r--r--fs/notify/inotify/inotify_user.c8
-rw-r--r--fs/notify/mark.c23
-rw-r--r--include/linux/fsnotify_backend.h28
4 files changed, 72 insertions, 39 deletions
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 98e91037b11d..bc9a51480156 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -269,25 +269,29 @@ static struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark)
static unsigned int fsnotify_iter_select_report_types(
struct fsnotify_iter_info *iter_info)
{
- struct fsnotify_mark *inode_mark = iter_info->inode_mark;
- struct fsnotify_mark *vfsmount_mark = iter_info->vfsmount_mark;
- int cmp;
+ struct fsnotify_group *max_prio_group = NULL;
+ struct fsnotify_mark *mark;
+ int type;
+
+ /* Choose max prio group among groups of all queue heads */
+ fsnotify_foreach_obj_type(type) {
+ mark = iter_info->marks[type];
+ if (mark &&
+ fsnotify_compare_groups(max_prio_group, mark->group) > 0)
+ max_prio_group = mark->group;
+ }
- if (!inode_mark && !vfsmount_mark)
+ if (!max_prio_group)
return 0;
- if (inode_mark && vfsmount_mark) {
- cmp = fsnotify_compare_groups(inode_mark->group,
- vfsmount_mark->group);
- } else {
- cmp = inode_mark ? -1 : 1;
- }
-
+ /* Set the report mask for marks from same group as max prio group */
iter_info->report_mask = 0;
- if (cmp <= 0)
- iter_info->report_mask |= FSNOTIFY_OBJ_TYPE_INODE_FL;
- if (cmp >= 0)
- iter_info->report_mask |= FSNOTIFY_OBJ_TYPE_VFSMOUNT_FL;
+ fsnotify_foreach_obj_type(type) {
+ mark = iter_info->marks[type];
+ if (mark &&
+ fsnotify_compare_groups(max_prio_group, mark->group) == 0)
+ fsnotify_iter_set_report_type(iter_info, type);
+ }
return iter_info->report_mask;
}
@@ -298,13 +302,13 @@ static unsigned int fsnotify_iter_select_report_types(
*/
static void fsnotify_iter_next(struct fsnotify_iter_info *iter_info)
{
- if (iter_info->report_mask & FSNOTIFY_OBJ_TYPE_INODE_FL)
- iter_info->inode_mark =
- fsnotify_next_mark(iter_info->inode_mark);
+ int type;
- if (iter_info->report_mask & FSNOTIFY_OBJ_TYPE_VFSMOUNT_FL)
- iter_info->vfsmount_mark =
- fsnotify_next_mark(iter_info->vfsmount_mark);
+ fsnotify_foreach_obj_type(type) {
+ if (fsnotify_iter_should_report_type(iter_info, type))
+ iter_info->marks[type] =
+ fsnotify_next_mark(iter_info->marks[type]);
+ }
}
/*
@@ -351,15 +355,15 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is,
if ((mask & FS_MODIFY) ||
(test_mask & to_tell->i_fsnotify_mask)) {
- iter_info.inode_mark =
+ iter_info.marks[FSNOTIFY_OBJ_TYPE_INODE] =
fsnotify_first_mark(&to_tell->i_fsnotify_marks);
}
if (mnt && ((mask & FS_MODIFY) ||
(test_mask & mnt->mnt_fsnotify_mask))) {
- iter_info.inode_mark =
+ iter_info.marks[FSNOTIFY_OBJ_TYPE_INODE] =
fsnotify_first_mark(&to_tell->i_fsnotify_marks);
- iter_info.vfsmount_mark =
+ iter_info.marks[FSNOTIFY_OBJ_TYPE_VFSMOUNT] =
fsnotify_first_mark(&mnt->mnt_fsnotify_marks);
}
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index 22a3d0471fee..6a408ab3169d 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -485,10 +485,10 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
struct fsnotify_group *group)
{
struct inotify_inode_mark *i_mark;
- struct fsnotify_iter_info iter_info = {
- .inode_mark = fsn_mark,
- .report_mask = FSNOTIFY_OBJ_TYPE_INODE_FL,
- };
+ struct fsnotify_iter_info iter_info = { };
+
+ fsnotify_iter_set_report_type_mark(&iter_info, FSNOTIFY_OBJ_TYPE_INODE,
+ fsn_mark);
/* Queue ignore event for the watch */
inotify_handle_event(group, NULL, FS_IN_IGNORED, NULL,
diff --git a/fs/notify/mark.c b/fs/notify/mark.c
index ef44808b28ca..61f4c5fa34c7 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:
+ for (type--; type >= 0; type--)
+ 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 9da5edf4ac0f..763423bfa3d6 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -211,23 +211,45 @@ enum fsnotify_obj_type {
#define FSNOTIFY_OBJ_ALL_TYPES_MASK ((1U << FSNOTIFY_OBJ_TYPE_COUNT) - 1)
struct fsnotify_iter_info {
- struct fsnotify_mark *inode_mark;
- struct fsnotify_mark *vfsmount_mark;
+ struct fsnotify_mark *marks[FSNOTIFY_OBJ_TYPE_COUNT];
unsigned int report_mask;
int srcu_idx;
};
+static inline bool fsnotify_iter_should_report_type(
+ struct fsnotify_iter_info *iter_info, int type)
+{
+ return (iter_info->report_mask & (1U << type));
+}
+
+static inline void fsnotify_iter_set_report_type(
+ struct fsnotify_iter_info *iter_info, int type)
+{
+ iter_info->report_mask |= (1U << type);
+}
+
+static inline void fsnotify_iter_set_report_type_mark(
+ struct fsnotify_iter_info *iter_info, int type,
+ struct fsnotify_mark *mark)
+{
+ iter_info->marks[type] = mark;
+ iter_info->report_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->report_mask & FSNOTIFY_OBJ_TYPE_##NAME##_FL) ? \
- iter_info->name##_mark : NULL; \
+ iter_info->marks[FSNOTIFY_OBJ_TYPE_##NAME] : NULL; \
}
FSNOTIFY_ITER_FUNCS(inode, INODE)
FSNOTIFY_ITER_FUNCS(vfsmount, VFSMOUNT)
+#define fsnotify_foreach_obj_type(type) \
+ for (type = 0; type < FSNOTIFY_OBJ_TYPE_COUNT; 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