Make some code that handles marks of object types inode and vfsmount generic, so it can handle other object types. Introduce foreach_obj_type macros to iterate marks by object type with or without consulting a type mask. This is going to be used for adding mark of another object type (super block mark). Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx> --- fs/notify/fsnotify.c | 54 ++++++++++++++++++++++++---------------- fs/notify/mark.c | 23 +++++++++++------ include/linux/fsnotify_backend.h | 38 +++++++++++++++++++++------- 3 files changed, 76 insertions(+), 39 deletions(-) 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 -- 2.7.4