Skip to content

Commit

Permalink
fsnotify: place marks on object in order of group memory address
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Eric Paris committed Jul 28, 2010
1 parent c1e5c95 commit 0c6532e
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 25 deletions.
40 changes: 29 additions & 11 deletions fs/notify/inode_mark.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
* 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,
struct fsnotify_group *group, struct inode *inode,
int allow_dups)
{
struct fsnotify_mark *lmark = NULL;
struct fsnotify_mark *lmark;
struct hlist_node *node, *last = NULL;
int ret = 0;

mark->flags = FSNOTIFY_MARK_FLAG_INODE;
Expand All @@ -192,21 +194,37 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark,

spin_lock(&inode->i_lock);

if (!allow_dups)
lmark = fsnotify_find_inode_mark_locked(group, inode);
if (!lmark) {
mark->i.inode = inode;
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);
goto out;
}

/* 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->group == group) && !allow_dups) {
ret = -EEXIST;
goto out;
}

fsnotify_recalc_inode_mask_locked(inode);
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);

if (lmark)
ret = -EEXIST;

return ret;
}

Expand Down
40 changes: 26 additions & 14 deletions fs/notify/vfsmount_mark.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,34 +141,46 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark,
struct fsnotify_group *group, struct vfsmount *mnt,
int allow_dups)
{
struct fsnotify_mark *lmark = NULL;
struct fsnotify_mark *lmark;
struct hlist_node *node, *last = NULL;
int ret = 0;

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(&group->mark_lock);

spin_lock(&mnt->mnt_root->d_lock);

if (!allow_dups)
lmark = fsnotify_find_vfsmount_mark_locked(group, mnt);
if (!lmark) {
mark->m.mnt = mnt;
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);
goto out;
}

/* 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;

fsnotify_recalc_vfsmount_mask_locked(mnt);
} else {
ret = -EEXIST;
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);

return ret;
Expand Down

0 comments on commit 0c6532e

Please sign in to comment.