forked from Minki/linux
fsnotify: remove global fsnotify groups lists
The global fsnotify groups lists were invented as a way to increase the performance of fsnotify by shortcutting events which were not interesting. With the changes to walk the object lists rather than global groups lists these shortcuts are not useful. Signed-off-by: Eric Paris <eparis@redhat.com>
This commit is contained in:
parent
43709a288e
commit
02436668d9
@ -219,11 +219,6 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
|
||||
/* global tests shouldn't care about events on child only the specific event */
|
||||
__u32 test_mask = (mask & ~FS_EVENT_ON_CHILD);
|
||||
|
||||
/* if no fsnotify listeners, nothing to do */
|
||||
if (list_empty(&fsnotify_inode_groups) &&
|
||||
list_empty(&fsnotify_vfsmount_groups))
|
||||
return 0;
|
||||
|
||||
if (mask & FS_MODIFY)
|
||||
__fsnotify_flush_ignored_mask(to_tell, data, data_is);
|
||||
|
||||
|
@ -6,11 +6,6 @@
|
||||
#include <linux/srcu.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/* all groups which receive inode fsnotify events */
|
||||
extern struct list_head fsnotify_inode_groups;
|
||||
/* all groups which receive vfsmount fsnotify events */
|
||||
extern struct list_head fsnotify_vfsmount_groups;
|
||||
|
||||
/* destroy all events sitting in this groups notification queue */
|
||||
extern void fsnotify_flush_notify(struct fsnotify_group *group);
|
||||
|
||||
@ -28,10 +23,6 @@ extern int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark,
|
||||
struct fsnotify_group *group, struct vfsmount *mnt,
|
||||
int allow_dups);
|
||||
|
||||
/* add a group to the inode group list */
|
||||
extern void fsnotify_add_inode_group(struct fsnotify_group *group);
|
||||
/* add a group to the vfsmount group list */
|
||||
extern void fsnotify_add_vfsmount_group(struct fsnotify_group *group);
|
||||
/* final kfree of a group */
|
||||
extern void fsnotify_final_destroy_group(struct fsnotify_group *group);
|
||||
|
||||
|
@ -28,67 +28,6 @@
|
||||
|
||||
#include <asm/atomic.h>
|
||||
|
||||
/* protects writes to fsnotify_groups and fsnotify_mask */
|
||||
static DEFINE_MUTEX(fsnotify_grp_mutex);
|
||||
/* all groups registered to receive inode filesystem notifications */
|
||||
LIST_HEAD(fsnotify_inode_groups);
|
||||
/* all groups registered to receive mount point filesystem notifications */
|
||||
LIST_HEAD(fsnotify_vfsmount_groups);
|
||||
|
||||
void fsnotify_add_vfsmount_group(struct fsnotify_group *group)
|
||||
{
|
||||
struct fsnotify_group *group_iter;
|
||||
|
||||
mutex_lock(&fsnotify_grp_mutex);
|
||||
|
||||
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 (group < group_iter) {
|
||||
/* 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);
|
||||
}
|
||||
|
||||
void fsnotify_add_inode_group(struct fsnotify_group *group)
|
||||
{
|
||||
struct fsnotify_group *group_iter;
|
||||
|
||||
mutex_lock(&fsnotify_grp_mutex);
|
||||
|
||||
/* add to global group list */
|
||||
if (!group->on_inode_group_list) {
|
||||
list_for_each_entry(group_iter, &fsnotify_inode_groups,
|
||||
inode_group_list) {
|
||||
if (group < group_iter) {
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Final freeing of a group
|
||||
*/
|
||||
@ -123,52 +62,13 @@ static void fsnotify_destroy_group(struct fsnotify_group *group)
|
||||
fsnotify_final_destroy_group(group);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove this group from the global list of groups that will get events
|
||||
* this can be done even if there are still references and things still using
|
||||
* this group. This just stops the group from getting new events.
|
||||
*/
|
||||
static void __fsnotify_evict_group(struct fsnotify_group *group)
|
||||
{
|
||||
BUG_ON(!mutex_is_locked(&fsnotify_grp_mutex));
|
||||
|
||||
if (group->on_inode_group_list)
|
||||
list_del_rcu(&group->inode_group_list);
|
||||
group->on_inode_group_list = 0;
|
||||
if (group->on_vfsmount_group_list)
|
||||
list_del_rcu(&group->vfsmount_group_list);
|
||||
group->on_vfsmount_group_list = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when a group is no longer interested in getting events. This can be
|
||||
* used if a group is misbehaving or if for some reason a group should no longer
|
||||
* get any filesystem events.
|
||||
*/
|
||||
void fsnotify_evict_group(struct fsnotify_group *group)
|
||||
{
|
||||
mutex_lock(&fsnotify_grp_mutex);
|
||||
__fsnotify_evict_group(group);
|
||||
mutex_unlock(&fsnotify_grp_mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Drop a reference to a group. Free it if it's through.
|
||||
*/
|
||||
void fsnotify_put_group(struct fsnotify_group *group)
|
||||
{
|
||||
if (!atomic_dec_and_mutex_lock(&group->refcnt, &fsnotify_grp_mutex))
|
||||
return;
|
||||
|
||||
/*
|
||||
* OK, now we know that there's no other users *and* we hold mutex,
|
||||
* so no new references will appear
|
||||
*/
|
||||
__fsnotify_evict_group(group);
|
||||
|
||||
mutex_unlock(&fsnotify_grp_mutex);
|
||||
|
||||
fsnotify_destroy_group(group);
|
||||
if (atomic_dec_and_test(&group->refcnt))
|
||||
fsnotify_destroy_group(group);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -195,9 +95,6 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops)
|
||||
init_waitqueue_head(&group->notification_waitq);
|
||||
group->max_events = UINT_MAX;
|
||||
|
||||
INIT_LIST_HEAD(&group->inode_group_list);
|
||||
INIT_LIST_HEAD(&group->vfsmount_group_list);
|
||||
|
||||
spin_lock_init(&group->mark_lock);
|
||||
INIT_LIST_HEAD(&group->marks_list);
|
||||
|
||||
|
@ -222,15 +222,6 @@ int fsnotify_add_mark(struct fsnotify_mark *mark,
|
||||
BUG_ON(inode && mnt);
|
||||
BUG_ON(!inode && !mnt);
|
||||
|
||||
/*
|
||||
* if this group isn't being testing for inode type events we need
|
||||
* to start testing
|
||||
*/
|
||||
if (inode && unlikely(list_empty(&group->inode_group_list)))
|
||||
fsnotify_add_inode_group(group);
|
||||
else if (mnt && unlikely(list_empty(&group->vfsmount_group_list)))
|
||||
fsnotify_add_vfsmount_group(group);
|
||||
|
||||
/*
|
||||
* LOCKING ORDER!!!!
|
||||
* mark->lock
|
||||
|
@ -108,17 +108,6 @@ struct fsnotify_ops {
|
||||
* everything will be cleaned up.
|
||||
*/
|
||||
struct fsnotify_group {
|
||||
/*
|
||||
* global list of all groups receiving events from fsnotify.
|
||||
* anchored by fsnotify_inode_groups and protected by either fsnotify_grp_mutex
|
||||
* or fsnotify_grp_srcu depending on write vs read.
|
||||
*/
|
||||
struct list_head inode_group_list;
|
||||
/*
|
||||
* same as above except anchored by fsnotify_vfsmount_groups
|
||||
*/
|
||||
struct list_head vfsmount_group_list;
|
||||
|
||||
/*
|
||||
* How the refcnt is used is up to each group. When the refcnt hits 0
|
||||
* fsnotify will clean up all of the resources associated with this group.
|
||||
@ -145,10 +134,6 @@ struct fsnotify_group {
|
||||
* a group */
|
||||
struct list_head marks_list; /* all inode marks for this group */
|
||||
|
||||
/* prevents double list_del of group_list. protected by global fsnotify_grp_mutex */
|
||||
bool on_inode_group_list;
|
||||
bool on_vfsmount_group_list;
|
||||
|
||||
/* groups can define private fields here or use the void *private */
|
||||
union {
|
||||
void *private;
|
||||
|
Loading…
Reference in New Issue
Block a user