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

Commit 0809ab69 authored by Jan Kara's avatar Jan Kara Committed by Linus Torvalds
Browse files

fsnotify: unify inode and mount marks handling



There's a lot of common code in inode and mount marks handling.  Factor it
out to a common helper function.

Signed-off-by: default avatarJan Kara <jack@suse.cz>
Cc: Eric Paris <eparis@redhat.com>
Cc: Heinrich Schuchardt <xypron.glpk@gmx.de>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 820c12d5
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -69,8 +69,8 @@ static void dnotify_recalc_inode_mask(struct fsnotify_mark *fsn_mark)
	if (old_mask == new_mask)
		return;

	if (fsn_mark->i.inode)
		fsnotify_recalc_inode_mask(fsn_mark->i.inode);
	if (fsn_mark->inode)
		fsnotify_recalc_inode_mask(fsn_mark->inode);
}

/*
+3 −3
Original line number Diff line number Diff line
@@ -80,7 +80,7 @@ static void inotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
		return;

	inode_mark = container_of(mark, struct inotify_inode_mark, fsn_mark);
	inode = igrab(mark->i.inode);
	inode = igrab(mark->inode);
	if (inode) {
		seq_printf(m, "inotify wd:%x ino:%lx sdev:%x mask:%x ignored_mask:%x ",
			   inode_mark->wd, inode->i_ino, inode->i_sb->s_dev,
@@ -112,7 +112,7 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
		mflags |= FAN_MARK_IGNORED_SURV_MODIFY;

	if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) {
		inode = igrab(mark->i.inode);
		inode = igrab(mark->inode);
		if (!inode)
			return;
		seq_printf(m, "fanotify ino:%lx sdev:%x mflags:%x mask:%x ignored_mask:%x ",
@@ -122,7 +122,7 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
		seq_putc(m, '\n');
		iput(inode);
	} else if (mark->flags & FSNOTIFY_MARK_FLAG_VFSMOUNT) {
		struct mount *mnt = real_mount(mark->m.mnt);
		struct mount *mnt = real_mount(mark->mnt);

		seq_printf(m, "fanotify mnt_id:%x mflags:%x mask:%x ignored_mask:%x\n",
			   mnt->mnt_id, mflags, mark->mask, mark->ignored_mask);
+2 −2
Original line number Diff line number Diff line
@@ -242,13 +242,13 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,

		if (inode_node) {
			inode_mark = hlist_entry(srcu_dereference(inode_node, &fsnotify_mark_srcu),
						 struct fsnotify_mark, i.i_list);
						 struct fsnotify_mark, obj_list);
			inode_group = inode_mark->group;
		}

		if (vfsmount_node) {
			vfsmount_mark = hlist_entry(srcu_dereference(vfsmount_node, &fsnotify_mark_srcu),
							struct fsnotify_mark, m.m_list);
						    struct fsnotify_mark, obj_list);
			vfsmount_group = vfsmount_mark->group;
		}

+12 −0
Original line number Diff line number Diff line
@@ -12,12 +12,19 @@ extern void fsnotify_flush_notify(struct fsnotify_group *group);
/* protects reads of inode and vfsmount marks list */
extern struct srcu_struct fsnotify_mark_srcu;

/* Calculate mask of events for a list of marks */
extern u32 fsnotify_recalc_mask(struct hlist_head *head);

/* compare two groups for sorting of marks lists */
extern int fsnotify_compare_groups(struct fsnotify_group *a,
				   struct fsnotify_group *b);

extern void fsnotify_set_inode_mark_mask_locked(struct fsnotify_mark *fsn_mark,
						__u32 mask);
/* Add mark to a proper place in mark list */
extern int fsnotify_add_mark_list(struct hlist_head *head,
				  struct fsnotify_mark *mark,
				  int allow_dups);
/* add a mark to an inode */
extern int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
				   struct fsnotify_group *group, struct inode *inode,
@@ -31,6 +38,11 @@ extern int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark,
extern void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark);
/* inode specific destruction of a mark */
extern void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark);
/* Destroy all marks in the given list */
extern void fsnotify_destroy_marks(struct list_head *to_free);
/* Find mark belonging to given group in the list of marks */
extern struct fsnotify_mark *fsnotify_find_mark(struct hlist_head *head,
						struct fsnotify_group *group);
/* run the list of all marks associated with inode and flag them to be freed */
extern void fsnotify_clear_marks_by_inode(struct inode *inode);
/* run the list of all marks associated with vfsmount and flag them to be freed */
+18 −95
Original line number Diff line number Diff line
@@ -30,21 +30,6 @@

#include "../internal.h"

/*
 * Recalculate the mask of events relevant to a given inode locked.
 */
static void fsnotify_recalc_inode_mask_locked(struct inode *inode)
{
	struct fsnotify_mark *mark;
	__u32 new_mask = 0;

	assert_spin_locked(&inode->i_lock);

	hlist_for_each_entry(mark, &inode->i_fsnotify_marks, i.i_list)
		new_mask |= mark->mask;
	inode->i_fsnotify_mask = new_mask;
}

/*
 * Recalculate the inode->i_fsnotify_mask, or the mask of all FS_* event types
 * any notifier is interested in hearing for this inode.
@@ -52,7 +37,7 @@ static void fsnotify_recalc_inode_mask_locked(struct inode *inode)
void fsnotify_recalc_inode_mask(struct inode *inode)
{
	spin_lock(&inode->i_lock);
	fsnotify_recalc_inode_mask_locked(inode);
	inode->i_fsnotify_mask = fsnotify_recalc_mask(&inode->i_fsnotify_marks);
	spin_unlock(&inode->i_lock);

	__fsnotify_update_child_dentry_flags(inode);
@@ -60,23 +45,22 @@ void fsnotify_recalc_inode_mask(struct inode *inode)

void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark)
{
	struct inode *inode = mark->i.inode;
	struct inode *inode = mark->inode;

	BUG_ON(!mutex_is_locked(&mark->group->mark_mutex));
	assert_spin_locked(&mark->lock);

	spin_lock(&inode->i_lock);

	hlist_del_init_rcu(&mark->i.i_list);
	mark->i.inode = NULL;
	hlist_del_init_rcu(&mark->obj_list);
	mark->inode = NULL;

	/*
	 * this mark is now off the inode->i_fsnotify_marks list and we
	 * hold the inode->i_lock, so this is the perfect time to update the
	 * inode->i_fsnotify_mask
	 */
	fsnotify_recalc_inode_mask_locked(inode);

	inode->i_fsnotify_mask = fsnotify_recalc_mask(&inode->i_fsnotify_marks);
	spin_unlock(&inode->i_lock);
}

@@ -85,30 +69,19 @@ void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark)
 */
void fsnotify_clear_marks_by_inode(struct inode *inode)
{
	struct fsnotify_mark *mark, *lmark;
	struct fsnotify_mark *mark;
	struct hlist_node *n;
	LIST_HEAD(free_list);

	spin_lock(&inode->i_lock);
	hlist_for_each_entry_safe(mark, n, &inode->i_fsnotify_marks, i.i_list) {
		list_add(&mark->i.free_i_list, &free_list);
		hlist_del_init_rcu(&mark->i.i_list);
	hlist_for_each_entry_safe(mark, n, &inode->i_fsnotify_marks, obj_list) {
		list_add(&mark->free_list, &free_list);
		hlist_del_init_rcu(&mark->obj_list);
		fsnotify_get_mark(mark);
	}
	spin_unlock(&inode->i_lock);

	list_for_each_entry_safe(mark, lmark, &free_list, i.free_i_list) {
		struct fsnotify_group *group;

		spin_lock(&mark->lock);
		fsnotify_get_group(mark->group);
		group = mark->group;
		spin_unlock(&mark->lock);

		fsnotify_destroy_mark(mark, group);
		fsnotify_put_mark(mark);
		fsnotify_put_group(group);
	}
	fsnotify_destroy_marks(&free_list);
}

/*
@@ -119,27 +92,6 @@ void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group)
	fsnotify_clear_marks_by_group_flags(group, FSNOTIFY_MARK_FLAG_INODE);
}

/*
 * given a group and inode, find the mark associated with that combination.
 * if found take a reference to that mark and return it, else return NULL
 */
static struct fsnotify_mark *fsnotify_find_inode_mark_locked(
		struct fsnotify_group *group,
		struct inode *inode)
{
	struct fsnotify_mark *mark;

	assert_spin_locked(&inode->i_lock);

	hlist_for_each_entry(mark, &inode->i_fsnotify_marks, i.i_list) {
		if (mark->group == group) {
			fsnotify_get_mark(mark);
			return mark;
		}
	}
	return NULL;
}

/*
 * given a group and inode, find the mark associated with that combination.
 * if found take a reference to that mark and return it, else return NULL
@@ -150,7 +102,7 @@ struct fsnotify_mark *fsnotify_find_inode_mark(struct fsnotify_group *group,
	struct fsnotify_mark *mark;

	spin_lock(&inode->i_lock);
	mark = fsnotify_find_inode_mark_locked(group, inode);
	mark = fsnotify_find_mark(&inode->i_fsnotify_marks, group);
	spin_unlock(&inode->i_lock);

	return mark;
@@ -168,10 +120,10 @@ void fsnotify_set_inode_mark_mask_locked(struct fsnotify_mark *mark,
	assert_spin_locked(&mark->lock);

	if (mask &&
	    mark->i.inode &&
	    mark->inode &&
	    !(mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED)) {
		mark->flags |= FSNOTIFY_MARK_FLAG_OBJECT_PINNED;
		inode = igrab(mark->i.inode);
		inode = igrab(mark->inode);
		/*
		 * we shouldn't be able to get here if the inode wasn't
		 * already safely held in memory.  But bug in case it
@@ -192,9 +144,7 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
			    struct fsnotify_group *group, struct inode *inode,
			    int allow_dups)
{
	struct fsnotify_mark *lmark, *last = NULL;
	int ret = 0;
	int cmp;
	int ret;

	mark->flags |= FSNOTIFY_MARK_FLAG_INODE;

@@ -202,37 +152,10 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
	assert_spin_locked(&mark->lock);

	spin_lock(&inode->i_lock);

	mark->i.inode = inode;

	/* is mark the first mark? */
	if (hlist_empty(&inode->i_fsnotify_marks)) {
		hlist_add_head_rcu(&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, &inode->i_fsnotify_marks, i.i_list) {
		last = lmark;

		if ((lmark->group == group) && !allow_dups) {
			ret = -EEXIST;
			goto out;
		}

		cmp = fsnotify_compare_groups(lmark->group, mark->group);
		if (cmp < 0)
			continue;

		hlist_add_before_rcu(&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_behind_rcu(&mark->i.i_list, &last->i.i_list);
out:
	fsnotify_recalc_inode_mask_locked(inode);
	mark->inode = inode;
	ret = fsnotify_add_mark_list(&inode->i_fsnotify_marks, mark,
				     allow_dups);
	inode->i_fsnotify_mask = fsnotify_recalc_mask(&inode->i_fsnotify_marks);
	spin_unlock(&inode->i_lock);

	return ret;
Loading