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

Commit 2645b9d1 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'fsnotify_for_v4.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs

Pull fsnotify updates from Jan Kara:
 "fsnotify cleanups from Amir and a small inotify improvement"

* tag 'fsnotify_for_v4.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
  inotify: Add flag IN_MASK_CREATE for inotify_add_watch()
  fanotify: factor out helpers to add/remove mark
  fsnotify: add helper to get mask from connector
  fsnotify: let connector point to an abstract object
  fsnotify: pass connp and object type to fsnotify_add_mark()
  fsnotify: use typedef fsnotify_connp_t for brevity
parents 46e62a07 4d97f7d5
Loading
Loading
Loading
Loading
+37 −62
Original line number Diff line number Diff line
@@ -524,8 +524,8 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark,
	return mask & oldmask;
}

static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group,
					 struct vfsmount *mnt, __u32 mask,
static int fanotify_remove_mark(struct fsnotify_group *group,
				fsnotify_connp_t *connp, __u32 mask,
				unsigned int flags)
{
	struct fsnotify_mark *fsn_mark = NULL;
@@ -533,8 +533,7 @@ static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group,
	int destroy_mark;

	mutex_lock(&group->mark_mutex);
	fsn_mark = fsnotify_find_mark(&real_mount(mnt)->mnt_fsnotify_marks,
				      group);
	fsn_mark = fsnotify_find_mark(connp, group);
	if (!fsn_mark) {
		mutex_unlock(&group->mark_mutex);
		return -ENOENT;
@@ -542,47 +541,33 @@ static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group,

	removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags,
						 &destroy_mark);
	if (removed & real_mount(mnt)->mnt_fsnotify_mask)
		fsnotify_recalc_mask(real_mount(mnt)->mnt_fsnotify_marks);
	if (removed & fsnotify_conn_mask(fsn_mark->connector))
		fsnotify_recalc_mask(fsn_mark->connector);
	if (destroy_mark)
		fsnotify_detach_mark(fsn_mark);
	mutex_unlock(&group->mark_mutex);
	if (destroy_mark)
		fsnotify_free_mark(fsn_mark);

	/* matches the fsnotify_find_mark() */
	fsnotify_put_mark(fsn_mark);
	return 0;
}

static int fanotify_remove_inode_mark(struct fsnotify_group *group,
				      struct inode *inode, __u32 mask,
static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group,
					 struct vfsmount *mnt, __u32 mask,
					 unsigned int flags)
{
	struct fsnotify_mark *fsn_mark = NULL;
	__u32 removed;
	int destroy_mark;

	mutex_lock(&group->mark_mutex);
	fsn_mark = fsnotify_find_mark(&inode->i_fsnotify_marks, group);
	if (!fsn_mark) {
		mutex_unlock(&group->mark_mutex);
		return -ENOENT;
	return fanotify_remove_mark(group, &real_mount(mnt)->mnt_fsnotify_marks,
				    mask, flags);
}

	removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags,
						 &destroy_mark);
	if (removed & inode->i_fsnotify_mask)
		fsnotify_recalc_mask(inode->i_fsnotify_marks);
	if (destroy_mark)
		fsnotify_detach_mark(fsn_mark);
	mutex_unlock(&group->mark_mutex);
	if (destroy_mark)
		fsnotify_free_mark(fsn_mark);

	/* matches the fsnotify_find_mark() */
	fsnotify_put_mark(fsn_mark);

	return 0;
static int fanotify_remove_inode_mark(struct fsnotify_group *group,
				      struct inode *inode, __u32 mask,
				      unsigned int flags)
{
	return fanotify_remove_mark(group, &inode->i_fsnotify_marks, mask,
				    flags);
}

static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark,
@@ -615,8 +600,8 @@ static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark,
}

static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group,
						   struct inode *inode,
						   struct vfsmount *mnt)
						   fsnotify_connp_t *connp,
						   unsigned int type)
{
	struct fsnotify_mark *mark;
	int ret;
@@ -629,7 +614,7 @@ static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group,
		return ERR_PTR(-ENOMEM);

	fsnotify_init_mark(mark, group);
	ret = fsnotify_add_mark_locked(mark, inode, mnt, 0);
	ret = fsnotify_add_mark_locked(mark, connp, type, 0);
	if (ret) {
		fsnotify_put_mark(mark);
		return ERR_PTR(ret);
@@ -639,39 +624,43 @@ static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group,
}


static int fanotify_add_vfsmount_mark(struct fsnotify_group *group,
				      struct vfsmount *mnt, __u32 mask,
				      unsigned int flags)
static int fanotify_add_mark(struct fsnotify_group *group,
			     fsnotify_connp_t *connp, unsigned int type,
			     __u32 mask, unsigned int flags)
{
	struct fsnotify_mark *fsn_mark;
	__u32 added;

	mutex_lock(&group->mark_mutex);
	fsn_mark = fsnotify_find_mark(&real_mount(mnt)->mnt_fsnotify_marks,
				      group);
	fsn_mark = fsnotify_find_mark(connp, group);
	if (!fsn_mark) {
		fsn_mark = fanotify_add_new_mark(group, NULL, mnt);
		fsn_mark = fanotify_add_new_mark(group, connp, type);
		if (IS_ERR(fsn_mark)) {
			mutex_unlock(&group->mark_mutex);
			return PTR_ERR(fsn_mark);
		}
	}
	added = fanotify_mark_add_to_mask(fsn_mark, mask, flags);
	if (added & ~real_mount(mnt)->mnt_fsnotify_mask)
		fsnotify_recalc_mask(real_mount(mnt)->mnt_fsnotify_marks);
	if (added & ~fsnotify_conn_mask(fsn_mark->connector))
		fsnotify_recalc_mask(fsn_mark->connector);
	mutex_unlock(&group->mark_mutex);

	fsnotify_put_mark(fsn_mark);
	return 0;
}

static int fanotify_add_vfsmount_mark(struct fsnotify_group *group,
				      struct vfsmount *mnt, __u32 mask,
				      unsigned int flags)
{
	return fanotify_add_mark(group, &real_mount(mnt)->mnt_fsnotify_marks,
				 FSNOTIFY_OBJ_TYPE_VFSMOUNT, mask, flags);
}

static int fanotify_add_inode_mark(struct fsnotify_group *group,
				   struct inode *inode, __u32 mask,
				   unsigned int flags)
{
	struct fsnotify_mark *fsn_mark;
	__u32 added;

	pr_debug("%s: group=%p inode=%p\n", __func__, group, inode);

	/*
@@ -684,22 +673,8 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group,
	    (atomic_read(&inode->i_writecount) > 0))
		return 0;

	mutex_lock(&group->mark_mutex);
	fsn_mark = fsnotify_find_mark(&inode->i_fsnotify_marks, group);
	if (!fsn_mark) {
		fsn_mark = fanotify_add_new_mark(group, inode, NULL);
		if (IS_ERR(fsn_mark)) {
			mutex_unlock(&group->mark_mutex);
			return PTR_ERR(fsn_mark);
		}
	}
	added = fanotify_mark_add_to_mask(fsn_mark, mask, flags);
	if (added & ~inode->i_fsnotify_mask)
		fsnotify_recalc_mask(inode->i_fsnotify_marks);
	mutex_unlock(&group->mark_mutex);

	fsnotify_put_mark(fsn_mark);
	return 0;
	return fanotify_add_mark(group, &inode->i_fsnotify_marks,
				 FSNOTIFY_OBJ_TYPE_INODE, mask, flags);
}

/* fanotify syscalls */
+4 −4
Original line number Diff line number Diff line
@@ -15,7 +15,7 @@
#include <linux/exportfs.h>

#include "inotify/inotify.h"
#include "../fs/mount.h"
#include "fsnotify.h"

#if defined(CONFIG_PROC_FS)

@@ -81,7 +81,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->connector->inode);
	inode = igrab(fsnotify_conn_inode(mark->connector));
	if (inode) {
		/*
		 * IN_ALL_EVENTS represents all of the mask bits
@@ -117,7 +117,7 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
		mflags |= FAN_MARK_IGNORED_SURV_MODIFY;

	if (mark->connector->type == FSNOTIFY_OBJ_TYPE_INODE) {
		inode = igrab(mark->connector->inode);
		inode = igrab(fsnotify_conn_inode(mark->connector));
		if (!inode)
			return;
		seq_printf(m, "fanotify ino:%lx sdev:%x mflags:%x mask:%x ignored_mask:%x ",
@@ -127,7 +127,7 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
		seq_putc(m, '\n');
		iput(inode);
	} else if (mark->connector->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) {
		struct mount *mnt = real_mount(mark->connector->mnt);
		struct mount *mnt = fsnotify_conn_mount(mark->connector);

		seq_printf(m, "fanotify mnt_id:%x mflags:%x mask:%x ignored_mask:%x\n",
			   mnt->mnt_id, mflags, mark->mask, mark->ignored_mask);
+14 −2
Original line number Diff line number Diff line
@@ -9,6 +9,18 @@

#include "../mount.h"

static inline struct inode *fsnotify_conn_inode(
				struct fsnotify_mark_connector *conn)
{
	return container_of(conn->obj, struct inode, i_fsnotify_marks);
}

static inline struct mount *fsnotify_conn_mount(
				struct fsnotify_mark_connector *conn)
{
	return container_of(conn->obj, struct mount, mnt_fsnotify_marks);
}

/* destroy all events sitting in this groups notification queue */
extern void fsnotify_flush_notify(struct fsnotify_group *group);

@@ -19,8 +31,8 @@ extern struct srcu_struct fsnotify_mark_srcu;
extern int fsnotify_compare_groups(struct fsnotify_group *a,
				   struct fsnotify_group *b);

/* Destroy all marks connected via given connector */
extern void fsnotify_destroy_marks(struct fsnotify_mark_connector __rcu **connp);
/* Destroy all marks attached to an object via connector */
extern void fsnotify_destroy_marks(fsnotify_connp_t *connp);
/* run the list of all marks associated with inode and destroy them */
static inline void fsnotify_clear_marks_by_inode(struct inode *inode)
{
+8 −1
Original line number Diff line number Diff line
@@ -510,6 +510,7 @@ static int inotify_update_existing_watch(struct fsnotify_group *group,
	__u32 old_mask, new_mask;
	__u32 mask;
	int add = (arg & IN_MASK_ADD);
	int create = (arg & IN_MASK_CREATE);
	int ret;

	mask = inotify_arg_to_mask(arg);
@@ -517,6 +518,8 @@ static int inotify_update_existing_watch(struct fsnotify_group *group,
	fsn_mark = fsnotify_find_mark(&inode->i_fsnotify_marks, group);
	if (!fsn_mark)
		return -ENOENT;
	else if (create)
		return -EEXIST;

	i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);

@@ -718,6 +721,10 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname,
	if (unlikely(!f.file))
		return -EBADF;

	/* IN_MASK_ADD and IN_MASK_CREATE don't make sense together */
	if (unlikely((mask & IN_MASK_ADD) && (mask & IN_MASK_CREATE)))
		return -EINVAL;

	/* verify that this is indeed an inotify instance */
	if (unlikely(f.file->f_op != &inotify_fops)) {
		ret = -EINVAL;
@@ -806,7 +813,7 @@ static int __init inotify_user_setup(void)
	BUILD_BUG_ON(IN_ISDIR != FS_ISDIR);
	BUILD_BUG_ON(IN_ONESHOT != FS_IN_ONESHOT);

	BUG_ON(hweight32(ALL_INOTIFY_BITS) != 21);
	BUG_ON(hweight32(ALL_INOTIFY_BITS) != 22);

	inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark, SLAB_PANIC);

+55 −48
Original line number Diff line number Diff line
@@ -109,6 +109,23 @@ void fsnotify_get_mark(struct fsnotify_mark *mark)
	refcount_inc(&mark->refcnt);
}

static __u32 *fsnotify_conn_mask_p(struct fsnotify_mark_connector *conn)
{
	if (conn->type == FSNOTIFY_OBJ_TYPE_INODE)
		return &fsnotify_conn_inode(conn)->i_fsnotify_mask;
	else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT)
		return &fsnotify_conn_mount(conn)->mnt_fsnotify_mask;
	return NULL;
}

__u32 fsnotify_conn_mask(struct fsnotify_mark_connector *conn)
{
	if (WARN_ON(!fsnotify_valid_obj_type(conn->type)))
		return 0;

	return *fsnotify_conn_mask_p(conn);
}

static void __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
{
	u32 new_mask = 0;
@@ -119,15 +136,15 @@ static void __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
		if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED)
			new_mask |= mark->mask;
	}
	if (conn->type == FSNOTIFY_OBJ_TYPE_INODE)
		conn->inode->i_fsnotify_mask = new_mask;
	else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT)
		real_mount(conn->mnt)->mnt_fsnotify_mask = new_mask;
	if (WARN_ON(!fsnotify_valid_obj_type(conn->type)))
		return;

	*fsnotify_conn_mask_p(conn) = new_mask;
}

/*
 * Calculate mask of events for a list of marks. The caller must make sure
 * connector and connector->inode cannot disappear under us.  Callers achieve
 * connector and connector->obj cannot disappear under us.  Callers achieve
 * this by holding a mark->lock or mark->group->mark_mutex for a mark on this
 * list.
 */
@@ -140,7 +157,8 @@ void fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
	__fsnotify_recalc_mask(conn);
	spin_unlock(&conn->lock);
	if (conn->type == FSNOTIFY_OBJ_TYPE_INODE)
		__fsnotify_update_child_dentry_flags(conn->inode);
		__fsnotify_update_child_dentry_flags(
					fsnotify_conn_inode(conn));
}

/* Free all connectors queued for freeing once SRCU period ends */
@@ -166,20 +184,20 @@ static struct inode *fsnotify_detach_connector_from_object(
{
	struct inode *inode = NULL;

	if (conn->type == FSNOTIFY_OBJ_TYPE_DETACHED)
		return NULL;

	if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) {
		inode = conn->inode;
		rcu_assign_pointer(inode->i_fsnotify_marks, NULL);
		inode = fsnotify_conn_inode(conn);
		inode->i_fsnotify_mask = 0;
		conn->inode = NULL;
		conn->type = FSNOTIFY_OBJ_TYPE_DETACHED;
	} else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) {
		rcu_assign_pointer(real_mount(conn->mnt)->mnt_fsnotify_marks,
				   NULL);
		real_mount(conn->mnt)->mnt_fsnotify_mask = 0;
		conn->mnt = NULL;
		conn->type = FSNOTIFY_OBJ_TYPE_DETACHED;
		fsnotify_conn_mount(conn)->mnt_fsnotify_mask = 0;
	}

	rcu_assign_pointer(*(conn->obj), NULL);
	conn->obj = NULL;
	conn->type = FSNOTIFY_OBJ_TYPE_DETACHED;

	return inode;
}

@@ -436,11 +454,10 @@ int fsnotify_compare_groups(struct fsnotify_group *a, struct fsnotify_group *b)
	return -1;
}

static int fsnotify_attach_connector_to_object(
				struct fsnotify_mark_connector __rcu **connp,
				struct inode *inode,
				struct vfsmount *mnt)
static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp,
					       unsigned int type)
{
	struct inode *inode = NULL;
	struct fsnotify_mark_connector *conn;

	conn = kmem_cache_alloc(fsnotify_mark_connector_cachep, GFP_KERNEL);
@@ -448,13 +465,10 @@ static int fsnotify_attach_connector_to_object(
		return -ENOMEM;
	spin_lock_init(&conn->lock);
	INIT_HLIST_HEAD(&conn->list);
	if (inode) {
		conn->type = FSNOTIFY_OBJ_TYPE_INODE;
		conn->inode = igrab(inode);
	} else {
		conn->type = FSNOTIFY_OBJ_TYPE_VFSMOUNT;
		conn->mnt = mnt;
	}
	conn->type = type;
	conn->obj = connp;
	if (conn->type == FSNOTIFY_OBJ_TYPE_INODE)
		inode = igrab(fsnotify_conn_inode(conn));
	/*
	 * cmpxchg() provides the barrier so that readers of *connp can see
	 * only initialized structure
@@ -476,7 +490,7 @@ static int fsnotify_attach_connector_to_object(
 * they are sure list cannot go away under them.
 */
static struct fsnotify_mark_connector *fsnotify_grab_connector(
				struct fsnotify_mark_connector __rcu **connp)
						fsnotify_connp_t *connp)
{
	struct fsnotify_mark_connector *conn;
	int idx;
@@ -503,27 +517,22 @@ static struct fsnotify_mark_connector *fsnotify_grab_connector(
 * priority, highest number first, and then by the group's location in memory.
 */
static int fsnotify_add_mark_list(struct fsnotify_mark *mark,
				  struct inode *inode, struct vfsmount *mnt,
				  fsnotify_connp_t *connp, unsigned int type,
				  int allow_dups)
{
	struct fsnotify_mark *lmark, *last = NULL;
	struct fsnotify_mark_connector *conn;
	struct fsnotify_mark_connector __rcu **connp;
	int cmp;
	int err = 0;

	if (WARN_ON(!inode && !mnt))
	if (WARN_ON(!fsnotify_valid_obj_type(type)))
		return -EINVAL;
	if (inode)
		connp = &inode->i_fsnotify_marks;
	else
		connp = &real_mount(mnt)->mnt_fsnotify_marks;
restart:
	spin_lock(&mark->lock);
	conn = fsnotify_grab_connector(connp);
	if (!conn) {
		spin_unlock(&mark->lock);
		err = fsnotify_attach_connector_to_object(connp, inode, mnt);
		err = fsnotify_attach_connector_to_object(connp, type);
		if (err)
			return err;
		goto restart;
@@ -569,14 +578,13 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark,
 * These marks may be used for the fsnotify backend to determine which
 * event types should be delivered to which group.
 */
int fsnotify_add_mark_locked(struct fsnotify_mark *mark, struct inode *inode,
			     struct vfsmount *mnt, int allow_dups)
int fsnotify_add_mark_locked(struct fsnotify_mark *mark,
			     fsnotify_connp_t *connp, unsigned int type,
			     int allow_dups)
{
	struct fsnotify_group *group = mark->group;
	int ret = 0;

	BUG_ON(inode && mnt);
	BUG_ON(!inode && !mnt);
	BUG_ON(!mutex_is_locked(&group->mark_mutex));

	/*
@@ -593,7 +601,7 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark, struct inode *inode,
	fsnotify_get_mark(mark); /* for g_list */
	spin_unlock(&mark->lock);

	ret = fsnotify_add_mark_list(mark, inode, mnt, allow_dups);
	ret = fsnotify_add_mark_list(mark, connp, type, allow_dups);
	if (ret)
		goto err;

@@ -613,14 +621,14 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark, struct inode *inode,
	return ret;
}

int fsnotify_add_mark(struct fsnotify_mark *mark, struct inode *inode,
		      struct vfsmount *mnt, int allow_dups)
int fsnotify_add_mark(struct fsnotify_mark *mark, fsnotify_connp_t *connp,
		      unsigned int type, int allow_dups)
{
	int ret;
	struct fsnotify_group *group = mark->group;

	mutex_lock(&group->mark_mutex);
	ret = fsnotify_add_mark_locked(mark, inode, mnt, allow_dups);
	ret = fsnotify_add_mark_locked(mark, connp, type, allow_dups);
	mutex_unlock(&group->mark_mutex);
	return ret;
}
@@ -629,8 +637,7 @@ int fsnotify_add_mark(struct fsnotify_mark *mark, struct inode *inode,
 * Given a list of marks, find the mark associated with given group. If found
 * take a reference to that mark and return it, else return NULL.
 */
struct fsnotify_mark *fsnotify_find_mark(
				struct fsnotify_mark_connector __rcu **connp,
struct fsnotify_mark *fsnotify_find_mark(fsnotify_connp_t *connp,
					 struct fsnotify_group *group)
{
	struct fsnotify_mark_connector *conn;
@@ -697,8 +704,8 @@ void fsnotify_clear_marks_by_group(struct fsnotify_group *group,
	}
}

/* Destroy all marks attached to inode / vfsmount */
void fsnotify_destroy_marks(struct fsnotify_mark_connector __rcu **connp)
/* Destroy all marks attached to an object via connector */
void fsnotify_destroy_marks(fsnotify_connp_t *connp)
{
	struct fsnotify_mark_connector *conn;
	struct fsnotify_mark *mark, *old_mark = NULL;
Loading