summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/notify/fanotify/fanotify_user.c4
-rw-r--r--fs/notify/group.c40
-rw-r--r--include/linux/fsnotify_backend.h1
3 files changed, 41 insertions, 4 deletions
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 9fe760baf69f..84d3e2047de3 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -463,8 +463,6 @@ SYSCALL_DEFINE3(fanotify_init, unsigned int, flags, unsigned int, event_f_flags,
if (event_f_flags)
return -EINVAL;
- if (priority)
- return -EINVAL;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
@@ -483,6 +481,8 @@ SYSCALL_DEFINE3(fanotify_init, unsigned int, flags, unsigned int, event_f_flags,
if (IS_ERR(group))
return PTR_ERR(group);
+ group->priority = priority;
+
fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags);
if (fd < 0)
goto out_put_group;
diff --git a/fs/notify/group.c b/fs/notify/group.c
index 9e9eb406afdd..ada913fd4f7f 100644
--- a/fs/notify/group.c
+++ b/fs/notify/group.c
@@ -89,10 +89,27 @@ void fsnotify_recalc_group_mask(struct fsnotify_group *group)
void fsnotify_add_vfsmount_group(struct fsnotify_group *group)
{
+ struct fsnotify_group *group_iter;
+ unsigned int priority = group->priority;
+
mutex_lock(&fsnotify_grp_mutex);
- if (!group->on_vfsmount_group_list)
+ if (!group->on_vfsmount_group_list) {
+ list_for_each_entry(group_iter, &fsnotify_vfsmount_groups,
+ vfsmount_group_list) {
+ /* insert in front of this one? */
+ if (priority < group_iter->priority) {
+ /* list_add_tail() insert in front of group_iter */
+ list_add_tail_rcu(&group->inode_group_list,
+ &group_iter->inode_group_list);
+ goto out;
+ }
+ }
+
+ /* apparently we need to be the last entry */
list_add_tail_rcu(&group->vfsmount_group_list, &fsnotify_vfsmount_groups);
+ }
+out:
group->on_vfsmount_group_list = 1;
mutex_unlock(&fsnotify_grp_mutex);
@@ -100,10 +117,27 @@ void fsnotify_add_vfsmount_group(struct fsnotify_group *group)
void fsnotify_add_inode_group(struct fsnotify_group *group)
{
+ struct fsnotify_group *group_iter;
+ unsigned int priority = group->priority;
+
mutex_lock(&fsnotify_grp_mutex);
- if (!group->on_inode_group_list)
+ /* add to global group list, priority 0 first, UINT_MAX last */
+ if (!group->on_inode_group_list) {
+ list_for_each_entry(group_iter, &fsnotify_inode_groups,
+ inode_group_list) {
+ if (priority < group_iter->priority) {
+ /* list_add_tail() insert in front of group_iter */
+ list_add_tail_rcu(&group->inode_group_list,
+ &group_iter->inode_group_list);
+ goto out;
+ }
+ }
+
+ /* apparently we need to be the last entry */
list_add_tail_rcu(&group->inode_group_list, &fsnotify_inode_groups);
+ }
+out:
group->on_inode_group_list = 1;
mutex_unlock(&fsnotify_grp_mutex);
@@ -226,6 +260,8 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops)
spin_lock_init(&group->mark_lock);
INIT_LIST_HEAD(&group->marks_list);
+ group->priority = UINT_MAX;
+
group->ops = ops;
return group;
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index be4a36ed2008..8b2e095e5907 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -140,6 +140,7 @@ struct fsnotify_group {
* a group */
struct list_head marks_list; /* all inode marks for this group */
+ unsigned int priority; /* order of this group compared to others */
/* prevents double list_del of group_list. protected by global fsnotify_grp_mutex */
bool on_inode_group_list;
bool on_vfsmount_group_list;