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

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

fsnotify: vfsmount marks generic functions



Much like inode-mark.c has all of the code dealing with marks on inodes
this patch adds a vfsmount-mark.c which has similar code but is intended
for marks on vfsmounts.

Signed-off-by: default avatarEric Paris <eparis@redhat.com>
parent 2504c5d6
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
obj-$(CONFIG_FSNOTIFY)		+= fsnotify.o notification.o group.o inode_mark.o \
obj-$(CONFIG_FSNOTIFY)		+= fsnotify.o notification.o group.o inode_mark.o \
				   mark.o
				   mark.o vfsmount_mark.o


obj-y			+= dnotify/
obj-y			+= dnotify/
obj-y			+= inotify/
obj-y			+= inotify/
+6 −0
Original line number Original line Diff line number Diff line
@@ -24,6 +24,10 @@ extern void fsnotify_flush_notify(struct fsnotify_group *group);
extern int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
extern 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);
/* add a mark to a vfsmount */
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 */
/* add a group to the inode group list */
extern void fsnotify_add_inode_group(struct fsnotify_group *group);
extern void fsnotify_add_inode_group(struct fsnotify_group *group);
@@ -32,6 +36,8 @@ extern void fsnotify_add_vfsmount_group(struct fsnotify_group *group);
/* final kfree of a group */
/* final kfree of a group */
extern void fsnotify_final_destroy_group(struct fsnotify_group *group);
extern void fsnotify_final_destroy_group(struct fsnotify_group *group);


/* vfsmount specific destruction of a mark */
extern void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark);
/* inode specific destruction of a mark */
/* inode specific destruction of a mark */
extern void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark);
extern void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark);
/* run the list of all marks associated with inode and flag them to be freed */
/* run the list of all marks associated with inode and flag them to be freed */
+11 −9
Original line number Original line Diff line number Diff line
@@ -115,15 +115,11 @@ void fsnotify_put_mark(struct fsnotify_mark *mark)
void fsnotify_destroy_mark(struct fsnotify_mark *mark)
void fsnotify_destroy_mark(struct fsnotify_mark *mark)
{
{
	struct fsnotify_group *group;
	struct fsnotify_group *group;
	struct inode *inode;
	struct inode *inode = NULL;


	spin_lock(&mark->lock);
	spin_lock(&mark->lock);


	group = mark->group;
	group = mark->group;
	inode = mark->i.inode;

	BUG_ON(group && !inode);
	BUG_ON(!group && inode);


	/* if !group something else already marked this to die */
	/* if !group something else already marked this to die */
	if (!group) {
	if (!group) {
@@ -136,8 +132,11 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark)


	spin_lock(&group->mark_lock);
	spin_lock(&group->mark_lock);


	if (mark->flags & FSNOTIFY_MARK_FLAG_INODE)
	if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) {
		fsnotify_destroy_inode_mark(mark);
		fsnotify_destroy_inode_mark(mark);
		inode = mark->i.inode;
	} else if (mark->flags & FSNOTIFY_MARK_FLAG_VFSMOUNT)
		fsnotify_destroy_vfsmount_mark(mark);
	else
	else
		BUG();
		BUG();


@@ -169,7 +168,7 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark)
	 * is just a lazy update (and could be a perf win...)
	 * is just a lazy update (and could be a perf win...)
	 */
	 */



	if (inode)
		iput(inode);
		iput(inode);


	/*
	/*
@@ -192,7 +191,6 @@ int fsnotify_add_mark(struct fsnotify_mark *mark,
{
{
	int ret = 0;
	int ret = 0;


	BUG_ON(mnt);
	BUG_ON(inode && mnt);
	BUG_ON(inode && mnt);
	BUG_ON(!inode && !mnt);
	BUG_ON(!inode && !mnt);


@@ -223,6 +221,10 @@ int fsnotify_add_mark(struct fsnotify_mark *mark,
		ret = fsnotify_add_inode_mark(mark, group, inode, allow_dups);
		ret = fsnotify_add_inode_mark(mark, group, inode, allow_dups);
		if (ret)
		if (ret)
			goto err;
			goto err;
	} else if (mnt) {
		ret = fsnotify_add_vfsmount_mark(mark, group, mnt, allow_dups);
		if (ret)
			goto err;
	} else {
	} else {
		BUG();
		BUG();
	}
	}
+171 −0
Original line number Original line Diff line number Diff line
/*
 *  Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mount.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/writeback.h> /* for inode_lock */

#include <asm/atomic.h>

#include <linux/fsnotify_backend.h>
#include "fsnotify.h"

void fsnotify_clear_marks_by_mount(struct vfsmount *mnt)
{
	struct fsnotify_mark *mark, *lmark;
	struct hlist_node *pos, *n;
	LIST_HEAD(free_list);

	spin_lock(&mnt->mnt_root->d_lock);
	hlist_for_each_entry_safe(mark, pos, n, &mnt->mnt_fsnotify_marks, m.m_list) {
		list_add(&mark->m.free_m_list, &free_list);
		hlist_del_init(&mark->m.m_list);
		fsnotify_get_mark(mark);
	}
	spin_unlock(&mnt->mnt_root->d_lock);

	list_for_each_entry_safe(mark, lmark, &free_list, m.free_m_list) {
		fsnotify_destroy_mark(mark);
		fsnotify_put_mark(mark);
	}
}

/*
 * Recalculate the mask of events relevant to a given vfsmount locked.
 */
static void fsnotify_recalc_vfsmount_mask_locked(struct vfsmount *mnt)
{
	struct fsnotify_mark *mark;
	struct hlist_node *pos;
	__u32 new_mask = 0;

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

	hlist_for_each_entry(mark, pos, &mnt->mnt_fsnotify_marks, m.m_list)
		new_mask |= mark->mask;
	mnt->mnt_fsnotify_mask = new_mask;
}

/*
 * Recalculate the mnt->mnt_fsnotify_mask, or the mask of all FS_* event types
 * any notifier is interested in hearing for this mount point
 */
void fsnotify_recalc_vfsmount_mask(struct vfsmount *mnt)
{
	spin_lock(&mnt->mnt_root->d_lock);
	fsnotify_recalc_vfsmount_mask_locked(mnt);
	spin_unlock(&mnt->mnt_root->d_lock);
}

void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark)
{
	struct vfsmount *mnt = mark->m.mnt;

	assert_spin_locked(&mark->lock);
	assert_spin_locked(&mark->group->mark_lock);

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

	hlist_del_init(&mark->m.m_list);
	mark->m.mnt = NULL;

	fsnotify_recalc_vfsmount_mask_locked(mnt);

	spin_unlock(&mnt->mnt_root->d_lock);
}

static struct fsnotify_mark *fsnotify_find_vfsmount_mark_locked(struct fsnotify_group *group,
								struct vfsmount *mnt)
{
	struct fsnotify_mark *mark;
	struct hlist_node *pos;

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

	hlist_for_each_entry(mark, pos, &mnt->mnt_fsnotify_marks, m.m_list) {
		if (mark->group == group) {
			fsnotify_get_mark(mark);
			return mark;
		}
	}
	return NULL;
}

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

	spin_lock(&mnt->mnt_root->d_lock);
	mark = fsnotify_find_vfsmount_mark_locked(group, mnt);
	spin_unlock(&mnt->mnt_root->d_lock);

	return mark;
}

/*
 * Attach an initialized mark to a given group and vfsmount.
 * These marks may be used for the fsnotify backend to determine which
 * event types should be delivered to which groups.
 */
int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark,
			       struct fsnotify_group *group, struct vfsmount *mnt,
			       int allow_dups)
{
	struct fsnotify_mark *lmark = 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;

		hlist_add_head(&mark->m.m_list, &mnt->mnt_fsnotify_marks);

		fsnotify_recalc_vfsmount_mask_locked(mnt);
	} else {
		ret = -EEXIST;
	}

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

	return ret;
}
+2 −0
Original line number Original line Diff line number Diff line
@@ -360,6 +360,8 @@ extern struct fsnotify_event *fsnotify_remove_notify_event(struct fsnotify_group


/* functions used to manipulate the marks attached to inodes */
/* functions used to manipulate the marks attached to inodes */


/* run all marks associated with a vfsmount and update mnt->mnt_fsnotify_mask */
extern void fsnotify_recalc_vfsmount_mask(struct vfsmount *mnt);
/* run all marks associated with an inode and update inode->i_fsnotify_mask */
/* run all marks associated with an inode and update inode->i_fsnotify_mask */
extern void fsnotify_recalc_inode_mask(struct inode *inode);
extern void fsnotify_recalc_inode_mask(struct inode *inode);
extern void fsnotify_init_mark(struct fsnotify_mark *mark, void (*free_mark)(struct fsnotify_mark *mark));
extern void fsnotify_init_mark(struct fsnotify_mark *mark, void (*free_mark)(struct fsnotify_mark *mark));