forked from Minki/linux
fsnotify: place marks on object in order of group memory address
fsnotify_marks currently are placed on objects (inodes or vfsmounts) in arbitrary order. This patch places them in order of the group memory address. Signed-off-by: Eric Paris <eparis@redhat.com>
This commit is contained in:
parent
c1e5c95402
commit
0c6532e4e3
@ -174,15 +174,17 @@ void fsnotify_set_inode_mark_mask_locked(struct fsnotify_mark *mark,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Attach an initialized mark to a given group and inode.
|
* Attach an initialized mark to a given inode.
|
||||||
* These marks may be used for the fsnotify backend to determine which
|
* These marks may be used for the fsnotify backend to determine which
|
||||||
* event types should be delivered to which group and for which inodes.
|
* event types should be delivered to which group and for which inodes. These
|
||||||
|
* marks are ordered according to the group's location in memory.
|
||||||
*/
|
*/
|
||||||
int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
|
int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
|
||||||
struct fsnotify_group *group, struct inode *inode,
|
struct fsnotify_group *group, struct inode *inode,
|
||||||
int allow_dups)
|
int allow_dups)
|
||||||
{
|
{
|
||||||
struct fsnotify_mark *lmark = NULL;
|
struct fsnotify_mark *lmark;
|
||||||
|
struct hlist_node *node, *last = NULL;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
mark->flags = FSNOTIFY_MARK_FLAG_INODE;
|
mark->flags = FSNOTIFY_MARK_FLAG_INODE;
|
||||||
@ -192,20 +194,36 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
|
|||||||
|
|
||||||
spin_lock(&inode->i_lock);
|
spin_lock(&inode->i_lock);
|
||||||
|
|
||||||
if (!allow_dups)
|
mark->i.inode = inode;
|
||||||
lmark = fsnotify_find_inode_mark_locked(group, inode);
|
|
||||||
if (!lmark) {
|
|
||||||
mark->i.inode = inode;
|
|
||||||
|
|
||||||
|
/* is mark the first mark? */
|
||||||
|
if (hlist_empty(&inode->i_fsnotify_marks)) {
|
||||||
hlist_add_head(&mark->i.i_list, &inode->i_fsnotify_marks);
|
hlist_add_head(&mark->i.i_list, &inode->i_fsnotify_marks);
|
||||||
|
goto out;
|
||||||
fsnotify_recalc_inode_mask_locked(inode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock(&inode->i_lock);
|
/* should mark be in the middle of the current list? */
|
||||||
|
hlist_for_each_entry(lmark, node, &inode->i_fsnotify_marks, i.i_list) {
|
||||||
|
last = node;
|
||||||
|
|
||||||
if (lmark)
|
if ((lmark->group == group) && !allow_dups) {
|
||||||
ret = -EEXIST;
|
ret = -EEXIST;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mark->group < lmark->group)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
hlist_add_before(&mark->i.i_list, &lmark->i.i_list);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
BUG_ON(last == NULL);
|
||||||
|
/* mark should be the last entry. last is the current last entry */
|
||||||
|
hlist_add_after(last, &mark->i.i_list);
|
||||||
|
out:
|
||||||
|
fsnotify_recalc_inode_mask_locked(inode);
|
||||||
|
spin_unlock(&inode->i_lock);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -141,34 +141,46 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark,
|
|||||||
struct fsnotify_group *group, struct vfsmount *mnt,
|
struct fsnotify_group *group, struct vfsmount *mnt,
|
||||||
int allow_dups)
|
int allow_dups)
|
||||||
{
|
{
|
||||||
struct fsnotify_mark *lmark = NULL;
|
struct fsnotify_mark *lmark;
|
||||||
|
struct hlist_node *node, *last = NULL;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
mark->flags = FSNOTIFY_MARK_FLAG_VFSMOUNT;
|
mark->flags = FSNOTIFY_MARK_FLAG_VFSMOUNT;
|
||||||
|
|
||||||
/*
|
|
||||||
* LOCKING ORDER!!!!
|
|
||||||
* mark->lock
|
|
||||||
* group->mark_lock
|
|
||||||
* mnt->mnt_root->d_lock
|
|
||||||
*/
|
|
||||||
assert_spin_locked(&mark->lock);
|
assert_spin_locked(&mark->lock);
|
||||||
assert_spin_locked(&group->mark_lock);
|
assert_spin_locked(&group->mark_lock);
|
||||||
|
|
||||||
spin_lock(&mnt->mnt_root->d_lock);
|
spin_lock(&mnt->mnt_root->d_lock);
|
||||||
|
|
||||||
if (!allow_dups)
|
mark->m.mnt = mnt;
|
||||||
lmark = fsnotify_find_vfsmount_mark_locked(group, mnt);
|
|
||||||
if (!lmark) {
|
|
||||||
mark->m.mnt = mnt;
|
|
||||||
|
|
||||||
|
/* is mark the first mark? */
|
||||||
|
if (hlist_empty(&mnt->mnt_fsnotify_marks)) {
|
||||||
hlist_add_head(&mark->m.m_list, &mnt->mnt_fsnotify_marks);
|
hlist_add_head(&mark->m.m_list, &mnt->mnt_fsnotify_marks);
|
||||||
|
goto out;
|
||||||
fsnotify_recalc_vfsmount_mask_locked(mnt);
|
|
||||||
} else {
|
|
||||||
ret = -EEXIST;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* should mark be in the middle of the current list? */
|
||||||
|
hlist_for_each_entry(lmark, node, &mnt->mnt_fsnotify_marks, m.m_list) {
|
||||||
|
last = node;
|
||||||
|
|
||||||
|
if ((lmark->group == group) && !allow_dups) {
|
||||||
|
ret = -EEXIST;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mark->group < lmark->group)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
hlist_add_before(&mark->m.m_list, &lmark->m.m_list);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
BUG_ON(last == NULL);
|
||||||
|
/* mark should be the last entry. last is the current last entry */
|
||||||
|
hlist_add_after(last, &mark->m.m_list);
|
||||||
|
out:
|
||||||
|
fsnotify_recalc_vfsmount_mask_locked(mnt);
|
||||||
spin_unlock(&mnt->mnt_root->d_lock);
|
spin_unlock(&mnt->mnt_root->d_lock);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
Loading…
Reference in New Issue
Block a user