Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0c6532e4 authored by Eric Paris's avatar Eric Paris
Browse files

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: default avatarEric Paris <eparis@redhat.com>
parent c1e5c954
Loading
Loading
Loading
Loading
+29 −11
Original line number Diff line number Diff line
@@ -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;
@@ -192,20 +194,36 @@ 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;

	/* is mark the first mark? */
	if (hlist_empty(&inode->i_fsnotify_marks)) {
		hlist_add_head(&mark->i.i_list, &inode->i_fsnotify_marks);

		fsnotify_recalc_inode_mask_locked(inode);
		goto out;
	}

	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;
			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;
}
+26 −14
Original line number Diff line number Diff line
@@ -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;

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

		fsnotify_recalc_vfsmount_mask_locked(mnt);
	} else {
	/* 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);

	return ret;