162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com>
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci/*
762306a36Sopenharmony_ci * fsnotify inode mark locking/lifetime/and refcnting
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * REFCNT:
1062306a36Sopenharmony_ci * The group->recnt and mark->refcnt tell how many "things" in the kernel
1162306a36Sopenharmony_ci * currently are referencing the objects. Both kind of objects typically will
1262306a36Sopenharmony_ci * live inside the kernel with a refcnt of 2, one for its creation and one for
1362306a36Sopenharmony_ci * the reference a group and a mark hold to each other.
1462306a36Sopenharmony_ci * If you are holding the appropriate locks, you can take a reference and the
1562306a36Sopenharmony_ci * object itself is guaranteed to survive until the reference is dropped.
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * LOCKING:
1862306a36Sopenharmony_ci * There are 3 locks involved with fsnotify inode marks and they MUST be taken
1962306a36Sopenharmony_ci * in order as follows:
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * group->mark_mutex
2262306a36Sopenharmony_ci * mark->lock
2362306a36Sopenharmony_ci * mark->connector->lock
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * group->mark_mutex protects the marks_list anchored inside a given group and
2662306a36Sopenharmony_ci * each mark is hooked via the g_list.  It also protects the groups private
2762306a36Sopenharmony_ci * data (i.e group limits).
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci * mark->lock protects the marks attributes like its masks and flags.
3062306a36Sopenharmony_ci * Furthermore it protects the access to a reference of the group that the mark
3162306a36Sopenharmony_ci * is assigned to as well as the access to a reference of the inode/vfsmount
3262306a36Sopenharmony_ci * that is being watched by the mark.
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci * mark->connector->lock protects the list of marks anchored inside an
3562306a36Sopenharmony_ci * inode / vfsmount and each mark is hooked via the i_list.
3662306a36Sopenharmony_ci *
3762306a36Sopenharmony_ci * A list of notification marks relating to inode / mnt is contained in
3862306a36Sopenharmony_ci * fsnotify_mark_connector. That structure is alive as long as there are any
3962306a36Sopenharmony_ci * marks in the list and is also protected by fsnotify_mark_srcu. A mark gets
4062306a36Sopenharmony_ci * detached from fsnotify_mark_connector when last reference to the mark is
4162306a36Sopenharmony_ci * dropped.  Thus having mark reference is enough to protect mark->connector
4262306a36Sopenharmony_ci * pointer and to make sure fsnotify_mark_connector cannot disappear. Also
4362306a36Sopenharmony_ci * because we remove mark from g_list before dropping mark reference associated
4462306a36Sopenharmony_ci * with that, any mark found through g_list is guaranteed to have
4562306a36Sopenharmony_ci * mark->connector set until we drop group->mark_mutex.
4662306a36Sopenharmony_ci *
4762306a36Sopenharmony_ci * LIFETIME:
4862306a36Sopenharmony_ci * Inode marks survive between when they are added to an inode and when their
4962306a36Sopenharmony_ci * refcnt==0. Marks are also protected by fsnotify_mark_srcu.
5062306a36Sopenharmony_ci *
5162306a36Sopenharmony_ci * The inode mark can be cleared for a number of different reasons including:
5262306a36Sopenharmony_ci * - The inode is unlinked for the last time.  (fsnotify_inode_remove)
5362306a36Sopenharmony_ci * - The inode is being evicted from cache. (fsnotify_inode_delete)
5462306a36Sopenharmony_ci * - The fs the inode is on is unmounted.  (fsnotify_inode_delete/fsnotify_unmount_inodes)
5562306a36Sopenharmony_ci * - Something explicitly requests that it be removed.  (fsnotify_destroy_mark)
5662306a36Sopenharmony_ci * - The fsnotify_group associated with the mark is going away and all such marks
5762306a36Sopenharmony_ci *   need to be cleaned up. (fsnotify_clear_marks_by_group)
5862306a36Sopenharmony_ci *
5962306a36Sopenharmony_ci * This has the very interesting property of being able to run concurrently with
6062306a36Sopenharmony_ci * any (or all) other directions.
6162306a36Sopenharmony_ci */
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#include <linux/fs.h>
6462306a36Sopenharmony_ci#include <linux/init.h>
6562306a36Sopenharmony_ci#include <linux/kernel.h>
6662306a36Sopenharmony_ci#include <linux/kthread.h>
6762306a36Sopenharmony_ci#include <linux/module.h>
6862306a36Sopenharmony_ci#include <linux/mutex.h>
6962306a36Sopenharmony_ci#include <linux/slab.h>
7062306a36Sopenharmony_ci#include <linux/spinlock.h>
7162306a36Sopenharmony_ci#include <linux/srcu.h>
7262306a36Sopenharmony_ci#include <linux/ratelimit.h>
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci#include <linux/atomic.h>
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#include <linux/fsnotify_backend.h>
7762306a36Sopenharmony_ci#include "fsnotify.h"
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci#define FSNOTIFY_REAPER_DELAY	(1)	/* 1 jiffy */
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistruct srcu_struct fsnotify_mark_srcu;
8262306a36Sopenharmony_cistruct kmem_cache *fsnotify_mark_connector_cachep;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic DEFINE_SPINLOCK(destroy_lock);
8562306a36Sopenharmony_cistatic LIST_HEAD(destroy_list);
8662306a36Sopenharmony_cistatic struct fsnotify_mark_connector *connector_destroy_list;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic void fsnotify_mark_destroy_workfn(struct work_struct *work);
8962306a36Sopenharmony_cistatic DECLARE_DELAYED_WORK(reaper_work, fsnotify_mark_destroy_workfn);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic void fsnotify_connector_destroy_workfn(struct work_struct *work);
9262306a36Sopenharmony_cistatic DECLARE_WORK(connector_reaper_work, fsnotify_connector_destroy_workfn);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_civoid fsnotify_get_mark(struct fsnotify_mark *mark)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	WARN_ON_ONCE(!refcount_read(&mark->refcnt));
9762306a36Sopenharmony_ci	refcount_inc(&mark->refcnt);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic __u32 *fsnotify_conn_mask_p(struct fsnotify_mark_connector *conn)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	if (conn->type == FSNOTIFY_OBJ_TYPE_INODE)
10362306a36Sopenharmony_ci		return &fsnotify_conn_inode(conn)->i_fsnotify_mask;
10462306a36Sopenharmony_ci	else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT)
10562306a36Sopenharmony_ci		return &fsnotify_conn_mount(conn)->mnt_fsnotify_mask;
10662306a36Sopenharmony_ci	else if (conn->type == FSNOTIFY_OBJ_TYPE_SB)
10762306a36Sopenharmony_ci		return &fsnotify_conn_sb(conn)->s_fsnotify_mask;
10862306a36Sopenharmony_ci	return NULL;
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci__u32 fsnotify_conn_mask(struct fsnotify_mark_connector *conn)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	if (WARN_ON(!fsnotify_valid_obj_type(conn->type)))
11462306a36Sopenharmony_ci		return 0;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	return *fsnotify_conn_mask_p(conn);
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic void fsnotify_get_inode_ref(struct inode *inode)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	ihold(inode);
12262306a36Sopenharmony_ci	atomic_long_inc(&inode->i_sb->s_fsnotify_connectors);
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci/*
12662306a36Sopenharmony_ci * Grab or drop inode reference for the connector if needed.
12762306a36Sopenharmony_ci *
12862306a36Sopenharmony_ci * When it's time to drop the reference, we only clear the HAS_IREF flag and
12962306a36Sopenharmony_ci * return the inode object. fsnotify_drop_object() will be resonsible for doing
13062306a36Sopenharmony_ci * iput() outside of spinlocks. This happens when last mark that wanted iref is
13162306a36Sopenharmony_ci * detached.
13262306a36Sopenharmony_ci */
13362306a36Sopenharmony_cistatic struct inode *fsnotify_update_iref(struct fsnotify_mark_connector *conn,
13462306a36Sopenharmony_ci					  bool want_iref)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	bool has_iref = conn->flags & FSNOTIFY_CONN_FLAG_HAS_IREF;
13762306a36Sopenharmony_ci	struct inode *inode = NULL;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	if (conn->type != FSNOTIFY_OBJ_TYPE_INODE ||
14062306a36Sopenharmony_ci	    want_iref == has_iref)
14162306a36Sopenharmony_ci		return NULL;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	if (want_iref) {
14462306a36Sopenharmony_ci		/* Pin inode if any mark wants inode refcount held */
14562306a36Sopenharmony_ci		fsnotify_get_inode_ref(fsnotify_conn_inode(conn));
14662306a36Sopenharmony_ci		conn->flags |= FSNOTIFY_CONN_FLAG_HAS_IREF;
14762306a36Sopenharmony_ci	} else {
14862306a36Sopenharmony_ci		/* Unpin inode after detach of last mark that wanted iref */
14962306a36Sopenharmony_ci		inode = fsnotify_conn_inode(conn);
15062306a36Sopenharmony_ci		conn->flags &= ~FSNOTIFY_CONN_FLAG_HAS_IREF;
15162306a36Sopenharmony_ci	}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	return inode;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic void *__fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	u32 new_mask = 0;
15962306a36Sopenharmony_ci	bool want_iref = false;
16062306a36Sopenharmony_ci	struct fsnotify_mark *mark;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	assert_spin_locked(&conn->lock);
16362306a36Sopenharmony_ci	/* We can get detached connector here when inode is getting unlinked. */
16462306a36Sopenharmony_ci	if (!fsnotify_valid_obj_type(conn->type))
16562306a36Sopenharmony_ci		return NULL;
16662306a36Sopenharmony_ci	hlist_for_each_entry(mark, &conn->list, obj_list) {
16762306a36Sopenharmony_ci		if (!(mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED))
16862306a36Sopenharmony_ci			continue;
16962306a36Sopenharmony_ci		new_mask |= fsnotify_calc_mask(mark);
17062306a36Sopenharmony_ci		if (conn->type == FSNOTIFY_OBJ_TYPE_INODE &&
17162306a36Sopenharmony_ci		    !(mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF))
17262306a36Sopenharmony_ci			want_iref = true;
17362306a36Sopenharmony_ci	}
17462306a36Sopenharmony_ci	*fsnotify_conn_mask_p(conn) = new_mask;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	return fsnotify_update_iref(conn, want_iref);
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci/*
18062306a36Sopenharmony_ci * Calculate mask of events for a list of marks. The caller must make sure
18162306a36Sopenharmony_ci * connector and connector->obj cannot disappear under us.  Callers achieve
18262306a36Sopenharmony_ci * this by holding a mark->lock or mark->group->mark_mutex for a mark on this
18362306a36Sopenharmony_ci * list.
18462306a36Sopenharmony_ci */
18562306a36Sopenharmony_civoid fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	if (!conn)
18862306a36Sopenharmony_ci		return;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	spin_lock(&conn->lock);
19162306a36Sopenharmony_ci	__fsnotify_recalc_mask(conn);
19262306a36Sopenharmony_ci	spin_unlock(&conn->lock);
19362306a36Sopenharmony_ci	if (conn->type == FSNOTIFY_OBJ_TYPE_INODE)
19462306a36Sopenharmony_ci		__fsnotify_update_child_dentry_flags(
19562306a36Sopenharmony_ci					fsnotify_conn_inode(conn));
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci/* Free all connectors queued for freeing once SRCU period ends */
19962306a36Sopenharmony_cistatic void fsnotify_connector_destroy_workfn(struct work_struct *work)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	struct fsnotify_mark_connector *conn, *free;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	spin_lock(&destroy_lock);
20462306a36Sopenharmony_ci	conn = connector_destroy_list;
20562306a36Sopenharmony_ci	connector_destroy_list = NULL;
20662306a36Sopenharmony_ci	spin_unlock(&destroy_lock);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	synchronize_srcu(&fsnotify_mark_srcu);
20962306a36Sopenharmony_ci	while (conn) {
21062306a36Sopenharmony_ci		free = conn;
21162306a36Sopenharmony_ci		conn = conn->destroy_next;
21262306a36Sopenharmony_ci		kmem_cache_free(fsnotify_mark_connector_cachep, free);
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic void fsnotify_put_inode_ref(struct inode *inode)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	struct super_block *sb = inode->i_sb;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	iput(inode);
22162306a36Sopenharmony_ci	if (atomic_long_dec_and_test(&sb->s_fsnotify_connectors))
22262306a36Sopenharmony_ci		wake_up_var(&sb->s_fsnotify_connectors);
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic void fsnotify_get_sb_connectors(struct fsnotify_mark_connector *conn)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	struct super_block *sb = fsnotify_connector_sb(conn);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	if (sb)
23062306a36Sopenharmony_ci		atomic_long_inc(&sb->s_fsnotify_connectors);
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistatic void fsnotify_put_sb_connectors(struct fsnotify_mark_connector *conn)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	struct super_block *sb = fsnotify_connector_sb(conn);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	if (sb && atomic_long_dec_and_test(&sb->s_fsnotify_connectors))
23862306a36Sopenharmony_ci		wake_up_var(&sb->s_fsnotify_connectors);
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic void *fsnotify_detach_connector_from_object(
24262306a36Sopenharmony_ci					struct fsnotify_mark_connector *conn,
24362306a36Sopenharmony_ci					unsigned int *type)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	struct inode *inode = NULL;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	*type = conn->type;
24862306a36Sopenharmony_ci	if (conn->type == FSNOTIFY_OBJ_TYPE_DETACHED)
24962306a36Sopenharmony_ci		return NULL;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) {
25262306a36Sopenharmony_ci		inode = fsnotify_conn_inode(conn);
25362306a36Sopenharmony_ci		inode->i_fsnotify_mask = 0;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci		/* Unpin inode when detaching from connector */
25662306a36Sopenharmony_ci		if (!(conn->flags & FSNOTIFY_CONN_FLAG_HAS_IREF))
25762306a36Sopenharmony_ci			inode = NULL;
25862306a36Sopenharmony_ci	} else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) {
25962306a36Sopenharmony_ci		fsnotify_conn_mount(conn)->mnt_fsnotify_mask = 0;
26062306a36Sopenharmony_ci	} else if (conn->type == FSNOTIFY_OBJ_TYPE_SB) {
26162306a36Sopenharmony_ci		fsnotify_conn_sb(conn)->s_fsnotify_mask = 0;
26262306a36Sopenharmony_ci	}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	fsnotify_put_sb_connectors(conn);
26562306a36Sopenharmony_ci	rcu_assign_pointer(*(conn->obj), NULL);
26662306a36Sopenharmony_ci	conn->obj = NULL;
26762306a36Sopenharmony_ci	conn->type = FSNOTIFY_OBJ_TYPE_DETACHED;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	return inode;
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic void fsnotify_final_mark_destroy(struct fsnotify_mark *mark)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	struct fsnotify_group *group = mark->group;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	if (WARN_ON_ONCE(!group))
27762306a36Sopenharmony_ci		return;
27862306a36Sopenharmony_ci	group->ops->free_mark(mark);
27962306a36Sopenharmony_ci	fsnotify_put_group(group);
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci/* Drop object reference originally held by a connector */
28362306a36Sopenharmony_cistatic void fsnotify_drop_object(unsigned int type, void *objp)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	if (!objp)
28662306a36Sopenharmony_ci		return;
28762306a36Sopenharmony_ci	/* Currently only inode references are passed to be dropped */
28862306a36Sopenharmony_ci	if (WARN_ON_ONCE(type != FSNOTIFY_OBJ_TYPE_INODE))
28962306a36Sopenharmony_ci		return;
29062306a36Sopenharmony_ci	fsnotify_put_inode_ref(objp);
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_civoid fsnotify_put_mark(struct fsnotify_mark *mark)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	struct fsnotify_mark_connector *conn = READ_ONCE(mark->connector);
29662306a36Sopenharmony_ci	void *objp = NULL;
29762306a36Sopenharmony_ci	unsigned int type = FSNOTIFY_OBJ_TYPE_DETACHED;
29862306a36Sopenharmony_ci	bool free_conn = false;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	/* Catch marks that were actually never attached to object */
30162306a36Sopenharmony_ci	if (!conn) {
30262306a36Sopenharmony_ci		if (refcount_dec_and_test(&mark->refcnt))
30362306a36Sopenharmony_ci			fsnotify_final_mark_destroy(mark);
30462306a36Sopenharmony_ci		return;
30562306a36Sopenharmony_ci	}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	/*
30862306a36Sopenharmony_ci	 * We have to be careful so that traversals of obj_list under lock can
30962306a36Sopenharmony_ci	 * safely grab mark reference.
31062306a36Sopenharmony_ci	 */
31162306a36Sopenharmony_ci	if (!refcount_dec_and_lock(&mark->refcnt, &conn->lock))
31262306a36Sopenharmony_ci		return;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	hlist_del_init_rcu(&mark->obj_list);
31562306a36Sopenharmony_ci	if (hlist_empty(&conn->list)) {
31662306a36Sopenharmony_ci		objp = fsnotify_detach_connector_from_object(conn, &type);
31762306a36Sopenharmony_ci		free_conn = true;
31862306a36Sopenharmony_ci	} else {
31962306a36Sopenharmony_ci		objp = __fsnotify_recalc_mask(conn);
32062306a36Sopenharmony_ci		type = conn->type;
32162306a36Sopenharmony_ci	}
32262306a36Sopenharmony_ci	WRITE_ONCE(mark->connector, NULL);
32362306a36Sopenharmony_ci	spin_unlock(&conn->lock);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	fsnotify_drop_object(type, objp);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	if (free_conn) {
32862306a36Sopenharmony_ci		spin_lock(&destroy_lock);
32962306a36Sopenharmony_ci		conn->destroy_next = connector_destroy_list;
33062306a36Sopenharmony_ci		connector_destroy_list = conn;
33162306a36Sopenharmony_ci		spin_unlock(&destroy_lock);
33262306a36Sopenharmony_ci		queue_work(system_unbound_wq, &connector_reaper_work);
33362306a36Sopenharmony_ci	}
33462306a36Sopenharmony_ci	/*
33562306a36Sopenharmony_ci	 * Note that we didn't update flags telling whether inode cares about
33662306a36Sopenharmony_ci	 * what's happening with children. We update these flags from
33762306a36Sopenharmony_ci	 * __fsnotify_parent() lazily when next event happens on one of our
33862306a36Sopenharmony_ci	 * children.
33962306a36Sopenharmony_ci	 */
34062306a36Sopenharmony_ci	spin_lock(&destroy_lock);
34162306a36Sopenharmony_ci	list_add(&mark->g_list, &destroy_list);
34262306a36Sopenharmony_ci	spin_unlock(&destroy_lock);
34362306a36Sopenharmony_ci	queue_delayed_work(system_unbound_wq, &reaper_work,
34462306a36Sopenharmony_ci			   FSNOTIFY_REAPER_DELAY);
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fsnotify_put_mark);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci/*
34962306a36Sopenharmony_ci * Get mark reference when we found the mark via lockless traversal of object
35062306a36Sopenharmony_ci * list. Mark can be already removed from the list by now and on its way to be
35162306a36Sopenharmony_ci * destroyed once SRCU period ends.
35262306a36Sopenharmony_ci *
35362306a36Sopenharmony_ci * Also pin the group so it doesn't disappear under us.
35462306a36Sopenharmony_ci */
35562306a36Sopenharmony_cistatic bool fsnotify_get_mark_safe(struct fsnotify_mark *mark)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	if (!mark)
35862306a36Sopenharmony_ci		return true;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	if (refcount_inc_not_zero(&mark->refcnt)) {
36162306a36Sopenharmony_ci		spin_lock(&mark->lock);
36262306a36Sopenharmony_ci		if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED) {
36362306a36Sopenharmony_ci			/* mark is attached, group is still alive then */
36462306a36Sopenharmony_ci			atomic_inc(&mark->group->user_waits);
36562306a36Sopenharmony_ci			spin_unlock(&mark->lock);
36662306a36Sopenharmony_ci			return true;
36762306a36Sopenharmony_ci		}
36862306a36Sopenharmony_ci		spin_unlock(&mark->lock);
36962306a36Sopenharmony_ci		fsnotify_put_mark(mark);
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci	return false;
37262306a36Sopenharmony_ci}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci/*
37562306a36Sopenharmony_ci * Puts marks and wakes up group destruction if necessary.
37662306a36Sopenharmony_ci *
37762306a36Sopenharmony_ci * Pairs with fsnotify_get_mark_safe()
37862306a36Sopenharmony_ci */
37962306a36Sopenharmony_cistatic void fsnotify_put_mark_wake(struct fsnotify_mark *mark)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	if (mark) {
38262306a36Sopenharmony_ci		struct fsnotify_group *group = mark->group;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci		fsnotify_put_mark(mark);
38562306a36Sopenharmony_ci		/*
38662306a36Sopenharmony_ci		 * We abuse notification_waitq on group shutdown for waiting for
38762306a36Sopenharmony_ci		 * all marks pinned when waiting for userspace.
38862306a36Sopenharmony_ci		 */
38962306a36Sopenharmony_ci		if (atomic_dec_and_test(&group->user_waits) && group->shutdown)
39062306a36Sopenharmony_ci			wake_up(&group->notification_waitq);
39162306a36Sopenharmony_ci	}
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cibool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info)
39562306a36Sopenharmony_ci	__releases(&fsnotify_mark_srcu)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	int type;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	fsnotify_foreach_iter_type(type) {
40062306a36Sopenharmony_ci		/* This can fail if mark is being removed */
40162306a36Sopenharmony_ci		if (!fsnotify_get_mark_safe(iter_info->marks[type])) {
40262306a36Sopenharmony_ci			__release(&fsnotify_mark_srcu);
40362306a36Sopenharmony_ci			goto fail;
40462306a36Sopenharmony_ci		}
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	/*
40862306a36Sopenharmony_ci	 * Now that both marks are pinned by refcount in the inode / vfsmount
40962306a36Sopenharmony_ci	 * lists, we can drop SRCU lock, and safely resume the list iteration
41062306a36Sopenharmony_ci	 * once userspace returns.
41162306a36Sopenharmony_ci	 */
41262306a36Sopenharmony_ci	srcu_read_unlock(&fsnotify_mark_srcu, iter_info->srcu_idx);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	return true;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_cifail:
41762306a36Sopenharmony_ci	for (type--; type >= 0; type--)
41862306a36Sopenharmony_ci		fsnotify_put_mark_wake(iter_info->marks[type]);
41962306a36Sopenharmony_ci	return false;
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_civoid fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info)
42362306a36Sopenharmony_ci	__acquires(&fsnotify_mark_srcu)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	int type;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	iter_info->srcu_idx = srcu_read_lock(&fsnotify_mark_srcu);
42862306a36Sopenharmony_ci	fsnotify_foreach_iter_type(type)
42962306a36Sopenharmony_ci		fsnotify_put_mark_wake(iter_info->marks[type]);
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci/*
43362306a36Sopenharmony_ci * Mark mark as detached, remove it from group list. Mark still stays in object
43462306a36Sopenharmony_ci * list until its last reference is dropped. Note that we rely on mark being
43562306a36Sopenharmony_ci * removed from group list before corresponding reference to it is dropped. In
43662306a36Sopenharmony_ci * particular we rely on mark->connector being valid while we hold
43762306a36Sopenharmony_ci * group->mark_mutex if we found the mark through g_list.
43862306a36Sopenharmony_ci *
43962306a36Sopenharmony_ci * Must be called with group->mark_mutex held. The caller must either hold
44062306a36Sopenharmony_ci * reference to the mark or be protected by fsnotify_mark_srcu.
44162306a36Sopenharmony_ci */
44262306a36Sopenharmony_civoid fsnotify_detach_mark(struct fsnotify_mark *mark)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	fsnotify_group_assert_locked(mark->group);
44562306a36Sopenharmony_ci	WARN_ON_ONCE(!srcu_read_lock_held(&fsnotify_mark_srcu) &&
44662306a36Sopenharmony_ci		     refcount_read(&mark->refcnt) < 1 +
44762306a36Sopenharmony_ci			!!(mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED));
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	spin_lock(&mark->lock);
45062306a36Sopenharmony_ci	/* something else already called this function on this mark */
45162306a36Sopenharmony_ci	if (!(mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED)) {
45262306a36Sopenharmony_ci		spin_unlock(&mark->lock);
45362306a36Sopenharmony_ci		return;
45462306a36Sopenharmony_ci	}
45562306a36Sopenharmony_ci	mark->flags &= ~FSNOTIFY_MARK_FLAG_ATTACHED;
45662306a36Sopenharmony_ci	list_del_init(&mark->g_list);
45762306a36Sopenharmony_ci	spin_unlock(&mark->lock);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	/* Drop mark reference acquired in fsnotify_add_mark_locked() */
46062306a36Sopenharmony_ci	fsnotify_put_mark(mark);
46162306a36Sopenharmony_ci}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci/*
46462306a36Sopenharmony_ci * Free fsnotify mark. The mark is actually only marked as being freed.  The
46562306a36Sopenharmony_ci * freeing is actually happening only once last reference to the mark is
46662306a36Sopenharmony_ci * dropped from a workqueue which first waits for srcu period end.
46762306a36Sopenharmony_ci *
46862306a36Sopenharmony_ci * Caller must have a reference to the mark or be protected by
46962306a36Sopenharmony_ci * fsnotify_mark_srcu.
47062306a36Sopenharmony_ci */
47162306a36Sopenharmony_civoid fsnotify_free_mark(struct fsnotify_mark *mark)
47262306a36Sopenharmony_ci{
47362306a36Sopenharmony_ci	struct fsnotify_group *group = mark->group;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	spin_lock(&mark->lock);
47662306a36Sopenharmony_ci	/* something else already called this function on this mark */
47762306a36Sopenharmony_ci	if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) {
47862306a36Sopenharmony_ci		spin_unlock(&mark->lock);
47962306a36Sopenharmony_ci		return;
48062306a36Sopenharmony_ci	}
48162306a36Sopenharmony_ci	mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE;
48262306a36Sopenharmony_ci	spin_unlock(&mark->lock);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	/*
48562306a36Sopenharmony_ci	 * Some groups like to know that marks are being freed.  This is a
48662306a36Sopenharmony_ci	 * callback to the group function to let it know that this mark
48762306a36Sopenharmony_ci	 * is being freed.
48862306a36Sopenharmony_ci	 */
48962306a36Sopenharmony_ci	if (group->ops->freeing_mark)
49062306a36Sopenharmony_ci		group->ops->freeing_mark(mark, group);
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_civoid fsnotify_destroy_mark(struct fsnotify_mark *mark,
49462306a36Sopenharmony_ci			   struct fsnotify_group *group)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	fsnotify_group_lock(group);
49762306a36Sopenharmony_ci	fsnotify_detach_mark(mark);
49862306a36Sopenharmony_ci	fsnotify_group_unlock(group);
49962306a36Sopenharmony_ci	fsnotify_free_mark(mark);
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fsnotify_destroy_mark);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci/*
50462306a36Sopenharmony_ci * Sorting function for lists of fsnotify marks.
50562306a36Sopenharmony_ci *
50662306a36Sopenharmony_ci * Fanotify supports different notification classes (reflected as priority of
50762306a36Sopenharmony_ci * notification group). Events shall be passed to notification groups in
50862306a36Sopenharmony_ci * decreasing priority order. To achieve this marks in notification lists for
50962306a36Sopenharmony_ci * inodes and vfsmounts are sorted so that priorities of corresponding groups
51062306a36Sopenharmony_ci * are descending.
51162306a36Sopenharmony_ci *
51262306a36Sopenharmony_ci * Furthermore correct handling of the ignore mask requires processing inode
51362306a36Sopenharmony_ci * and vfsmount marks of each group together. Using the group address as
51462306a36Sopenharmony_ci * further sort criterion provides a unique sorting order and thus we can
51562306a36Sopenharmony_ci * merge inode and vfsmount lists of marks in linear time and find groups
51662306a36Sopenharmony_ci * present in both lists.
51762306a36Sopenharmony_ci *
51862306a36Sopenharmony_ci * A return value of 1 signifies that b has priority over a.
51962306a36Sopenharmony_ci * A return value of 0 signifies that the two marks have to be handled together.
52062306a36Sopenharmony_ci * A return value of -1 signifies that a has priority over b.
52162306a36Sopenharmony_ci */
52262306a36Sopenharmony_ciint fsnotify_compare_groups(struct fsnotify_group *a, struct fsnotify_group *b)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	if (a == b)
52562306a36Sopenharmony_ci		return 0;
52662306a36Sopenharmony_ci	if (!a)
52762306a36Sopenharmony_ci		return 1;
52862306a36Sopenharmony_ci	if (!b)
52962306a36Sopenharmony_ci		return -1;
53062306a36Sopenharmony_ci	if (a->priority < b->priority)
53162306a36Sopenharmony_ci		return 1;
53262306a36Sopenharmony_ci	if (a->priority > b->priority)
53362306a36Sopenharmony_ci		return -1;
53462306a36Sopenharmony_ci	if (a < b)
53562306a36Sopenharmony_ci		return 1;
53662306a36Sopenharmony_ci	return -1;
53762306a36Sopenharmony_ci}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_cistatic int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp,
54062306a36Sopenharmony_ci					       unsigned int obj_type,
54162306a36Sopenharmony_ci					       __kernel_fsid_t *fsid)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	struct fsnotify_mark_connector *conn;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	conn = kmem_cache_alloc(fsnotify_mark_connector_cachep, GFP_KERNEL);
54662306a36Sopenharmony_ci	if (!conn)
54762306a36Sopenharmony_ci		return -ENOMEM;
54862306a36Sopenharmony_ci	spin_lock_init(&conn->lock);
54962306a36Sopenharmony_ci	INIT_HLIST_HEAD(&conn->list);
55062306a36Sopenharmony_ci	conn->flags = 0;
55162306a36Sopenharmony_ci	conn->type = obj_type;
55262306a36Sopenharmony_ci	conn->obj = connp;
55362306a36Sopenharmony_ci	/* Cache fsid of filesystem containing the object */
55462306a36Sopenharmony_ci	if (fsid) {
55562306a36Sopenharmony_ci		conn->fsid = *fsid;
55662306a36Sopenharmony_ci		conn->flags = FSNOTIFY_CONN_FLAG_HAS_FSID;
55762306a36Sopenharmony_ci	} else {
55862306a36Sopenharmony_ci		conn->fsid.val[0] = conn->fsid.val[1] = 0;
55962306a36Sopenharmony_ci		conn->flags = 0;
56062306a36Sopenharmony_ci	}
56162306a36Sopenharmony_ci	fsnotify_get_sb_connectors(conn);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	/*
56462306a36Sopenharmony_ci	 * cmpxchg() provides the barrier so that readers of *connp can see
56562306a36Sopenharmony_ci	 * only initialized structure
56662306a36Sopenharmony_ci	 */
56762306a36Sopenharmony_ci	if (cmpxchg(connp, NULL, conn)) {
56862306a36Sopenharmony_ci		/* Someone else created list structure for us */
56962306a36Sopenharmony_ci		fsnotify_put_sb_connectors(conn);
57062306a36Sopenharmony_ci		kmem_cache_free(fsnotify_mark_connector_cachep, conn);
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	return 0;
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci/*
57762306a36Sopenharmony_ci * Get mark connector, make sure it is alive and return with its lock held.
57862306a36Sopenharmony_ci * This is for users that get connector pointer from inode or mount. Users that
57962306a36Sopenharmony_ci * hold reference to a mark on the list may directly lock connector->lock as
58062306a36Sopenharmony_ci * they are sure list cannot go away under them.
58162306a36Sopenharmony_ci */
58262306a36Sopenharmony_cistatic struct fsnotify_mark_connector *fsnotify_grab_connector(
58362306a36Sopenharmony_ci						fsnotify_connp_t *connp)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	struct fsnotify_mark_connector *conn;
58662306a36Sopenharmony_ci	int idx;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	idx = srcu_read_lock(&fsnotify_mark_srcu);
58962306a36Sopenharmony_ci	conn = srcu_dereference(*connp, &fsnotify_mark_srcu);
59062306a36Sopenharmony_ci	if (!conn)
59162306a36Sopenharmony_ci		goto out;
59262306a36Sopenharmony_ci	spin_lock(&conn->lock);
59362306a36Sopenharmony_ci	if (conn->type == FSNOTIFY_OBJ_TYPE_DETACHED) {
59462306a36Sopenharmony_ci		spin_unlock(&conn->lock);
59562306a36Sopenharmony_ci		srcu_read_unlock(&fsnotify_mark_srcu, idx);
59662306a36Sopenharmony_ci		return NULL;
59762306a36Sopenharmony_ci	}
59862306a36Sopenharmony_ciout:
59962306a36Sopenharmony_ci	srcu_read_unlock(&fsnotify_mark_srcu, idx);
60062306a36Sopenharmony_ci	return conn;
60162306a36Sopenharmony_ci}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci/*
60462306a36Sopenharmony_ci * Add mark into proper place in given list of marks. These marks may be used
60562306a36Sopenharmony_ci * for the fsnotify backend to determine which event types should be delivered
60662306a36Sopenharmony_ci * to which group and for which inodes. These marks are ordered according to
60762306a36Sopenharmony_ci * priority, highest number first, and then by the group's location in memory.
60862306a36Sopenharmony_ci */
60962306a36Sopenharmony_cistatic int fsnotify_add_mark_list(struct fsnotify_mark *mark,
61062306a36Sopenharmony_ci				  fsnotify_connp_t *connp,
61162306a36Sopenharmony_ci				  unsigned int obj_type,
61262306a36Sopenharmony_ci				  int add_flags, __kernel_fsid_t *fsid)
61362306a36Sopenharmony_ci{
61462306a36Sopenharmony_ci	struct fsnotify_mark *lmark, *last = NULL;
61562306a36Sopenharmony_ci	struct fsnotify_mark_connector *conn;
61662306a36Sopenharmony_ci	int cmp;
61762306a36Sopenharmony_ci	int err = 0;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	if (WARN_ON(!fsnotify_valid_obj_type(obj_type)))
62062306a36Sopenharmony_ci		return -EINVAL;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	/* Backend is expected to check for zero fsid (e.g. tmpfs) */
62362306a36Sopenharmony_ci	if (fsid && WARN_ON_ONCE(!fsid->val[0] && !fsid->val[1]))
62462306a36Sopenharmony_ci		return -ENODEV;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_cirestart:
62762306a36Sopenharmony_ci	spin_lock(&mark->lock);
62862306a36Sopenharmony_ci	conn = fsnotify_grab_connector(connp);
62962306a36Sopenharmony_ci	if (!conn) {
63062306a36Sopenharmony_ci		spin_unlock(&mark->lock);
63162306a36Sopenharmony_ci		err = fsnotify_attach_connector_to_object(connp, obj_type,
63262306a36Sopenharmony_ci							  fsid);
63362306a36Sopenharmony_ci		if (err)
63462306a36Sopenharmony_ci			return err;
63562306a36Sopenharmony_ci		goto restart;
63662306a36Sopenharmony_ci	} else if (fsid && !(conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID)) {
63762306a36Sopenharmony_ci		conn->fsid = *fsid;
63862306a36Sopenharmony_ci		/* Pairs with smp_rmb() in fanotify_get_fsid() */
63962306a36Sopenharmony_ci		smp_wmb();
64062306a36Sopenharmony_ci		conn->flags |= FSNOTIFY_CONN_FLAG_HAS_FSID;
64162306a36Sopenharmony_ci	} else if (fsid && (conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID) &&
64262306a36Sopenharmony_ci		   (fsid->val[0] != conn->fsid.val[0] ||
64362306a36Sopenharmony_ci		    fsid->val[1] != conn->fsid.val[1])) {
64462306a36Sopenharmony_ci		/*
64562306a36Sopenharmony_ci		 * Backend is expected to check for non uniform fsid
64662306a36Sopenharmony_ci		 * (e.g. btrfs), but maybe we missed something?
64762306a36Sopenharmony_ci		 * Only allow setting conn->fsid once to non zero fsid.
64862306a36Sopenharmony_ci		 * inotify and non-fid fanotify groups do not set nor test
64962306a36Sopenharmony_ci		 * conn->fsid.
65062306a36Sopenharmony_ci		 */
65162306a36Sopenharmony_ci		pr_warn_ratelimited("%s: fsid mismatch on object of type %u: "
65262306a36Sopenharmony_ci				    "%x.%x != %x.%x\n", __func__, conn->type,
65362306a36Sopenharmony_ci				    fsid->val[0], fsid->val[1],
65462306a36Sopenharmony_ci				    conn->fsid.val[0], conn->fsid.val[1]);
65562306a36Sopenharmony_ci		err = -EXDEV;
65662306a36Sopenharmony_ci		goto out_err;
65762306a36Sopenharmony_ci	}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	/* is mark the first mark? */
66062306a36Sopenharmony_ci	if (hlist_empty(&conn->list)) {
66162306a36Sopenharmony_ci		hlist_add_head_rcu(&mark->obj_list, &conn->list);
66262306a36Sopenharmony_ci		goto added;
66362306a36Sopenharmony_ci	}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	/* should mark be in the middle of the current list? */
66662306a36Sopenharmony_ci	hlist_for_each_entry(lmark, &conn->list, obj_list) {
66762306a36Sopenharmony_ci		last = lmark;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci		if ((lmark->group == mark->group) &&
67062306a36Sopenharmony_ci		    (lmark->flags & FSNOTIFY_MARK_FLAG_ATTACHED) &&
67162306a36Sopenharmony_ci		    !(mark->group->flags & FSNOTIFY_GROUP_DUPS)) {
67262306a36Sopenharmony_ci			err = -EEXIST;
67362306a36Sopenharmony_ci			goto out_err;
67462306a36Sopenharmony_ci		}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci		cmp = fsnotify_compare_groups(lmark->group, mark->group);
67762306a36Sopenharmony_ci		if (cmp >= 0) {
67862306a36Sopenharmony_ci			hlist_add_before_rcu(&mark->obj_list, &lmark->obj_list);
67962306a36Sopenharmony_ci			goto added;
68062306a36Sopenharmony_ci		}
68162306a36Sopenharmony_ci	}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	BUG_ON(last == NULL);
68462306a36Sopenharmony_ci	/* mark should be the last entry.  last is the current last entry */
68562306a36Sopenharmony_ci	hlist_add_behind_rcu(&mark->obj_list, &last->obj_list);
68662306a36Sopenharmony_ciadded:
68762306a36Sopenharmony_ci	/*
68862306a36Sopenharmony_ci	 * Since connector is attached to object using cmpxchg() we are
68962306a36Sopenharmony_ci	 * guaranteed that connector initialization is fully visible by anyone
69062306a36Sopenharmony_ci	 * seeing mark->connector set.
69162306a36Sopenharmony_ci	 */
69262306a36Sopenharmony_ci	WRITE_ONCE(mark->connector, conn);
69362306a36Sopenharmony_ciout_err:
69462306a36Sopenharmony_ci	spin_unlock(&conn->lock);
69562306a36Sopenharmony_ci	spin_unlock(&mark->lock);
69662306a36Sopenharmony_ci	return err;
69762306a36Sopenharmony_ci}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci/*
70062306a36Sopenharmony_ci * Attach an initialized mark to a given group and fs object.
70162306a36Sopenharmony_ci * These marks may be used for the fsnotify backend to determine which
70262306a36Sopenharmony_ci * event types should be delivered to which group.
70362306a36Sopenharmony_ci */
70462306a36Sopenharmony_ciint fsnotify_add_mark_locked(struct fsnotify_mark *mark,
70562306a36Sopenharmony_ci			     fsnotify_connp_t *connp, unsigned int obj_type,
70662306a36Sopenharmony_ci			     int add_flags, __kernel_fsid_t *fsid)
70762306a36Sopenharmony_ci{
70862306a36Sopenharmony_ci	struct fsnotify_group *group = mark->group;
70962306a36Sopenharmony_ci	int ret = 0;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	fsnotify_group_assert_locked(group);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	/*
71462306a36Sopenharmony_ci	 * LOCKING ORDER!!!!
71562306a36Sopenharmony_ci	 * group->mark_mutex
71662306a36Sopenharmony_ci	 * mark->lock
71762306a36Sopenharmony_ci	 * mark->connector->lock
71862306a36Sopenharmony_ci	 */
71962306a36Sopenharmony_ci	spin_lock(&mark->lock);
72062306a36Sopenharmony_ci	mark->flags |= FSNOTIFY_MARK_FLAG_ALIVE | FSNOTIFY_MARK_FLAG_ATTACHED;
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	list_add(&mark->g_list, &group->marks_list);
72362306a36Sopenharmony_ci	fsnotify_get_mark(mark); /* for g_list */
72462306a36Sopenharmony_ci	spin_unlock(&mark->lock);
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	ret = fsnotify_add_mark_list(mark, connp, obj_type, add_flags, fsid);
72762306a36Sopenharmony_ci	if (ret)
72862306a36Sopenharmony_ci		goto err;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	fsnotify_recalc_mask(mark->connector);
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	return ret;
73362306a36Sopenharmony_cierr:
73462306a36Sopenharmony_ci	spin_lock(&mark->lock);
73562306a36Sopenharmony_ci	mark->flags &= ~(FSNOTIFY_MARK_FLAG_ALIVE |
73662306a36Sopenharmony_ci			 FSNOTIFY_MARK_FLAG_ATTACHED);
73762306a36Sopenharmony_ci	list_del_init(&mark->g_list);
73862306a36Sopenharmony_ci	spin_unlock(&mark->lock);
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	fsnotify_put_mark(mark);
74162306a36Sopenharmony_ci	return ret;
74262306a36Sopenharmony_ci}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ciint fsnotify_add_mark(struct fsnotify_mark *mark, fsnotify_connp_t *connp,
74562306a36Sopenharmony_ci		      unsigned int obj_type, int add_flags,
74662306a36Sopenharmony_ci		      __kernel_fsid_t *fsid)
74762306a36Sopenharmony_ci{
74862306a36Sopenharmony_ci	int ret;
74962306a36Sopenharmony_ci	struct fsnotify_group *group = mark->group;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	fsnotify_group_lock(group);
75262306a36Sopenharmony_ci	ret = fsnotify_add_mark_locked(mark, connp, obj_type, add_flags, fsid);
75362306a36Sopenharmony_ci	fsnotify_group_unlock(group);
75462306a36Sopenharmony_ci	return ret;
75562306a36Sopenharmony_ci}
75662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fsnotify_add_mark);
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci/*
75962306a36Sopenharmony_ci * Given a list of marks, find the mark associated with given group. If found
76062306a36Sopenharmony_ci * take a reference to that mark and return it, else return NULL.
76162306a36Sopenharmony_ci */
76262306a36Sopenharmony_cistruct fsnotify_mark *fsnotify_find_mark(fsnotify_connp_t *connp,
76362306a36Sopenharmony_ci					 struct fsnotify_group *group)
76462306a36Sopenharmony_ci{
76562306a36Sopenharmony_ci	struct fsnotify_mark_connector *conn;
76662306a36Sopenharmony_ci	struct fsnotify_mark *mark;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	conn = fsnotify_grab_connector(connp);
76962306a36Sopenharmony_ci	if (!conn)
77062306a36Sopenharmony_ci		return NULL;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	hlist_for_each_entry(mark, &conn->list, obj_list) {
77362306a36Sopenharmony_ci		if (mark->group == group &&
77462306a36Sopenharmony_ci		    (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED)) {
77562306a36Sopenharmony_ci			fsnotify_get_mark(mark);
77662306a36Sopenharmony_ci			spin_unlock(&conn->lock);
77762306a36Sopenharmony_ci			return mark;
77862306a36Sopenharmony_ci		}
77962306a36Sopenharmony_ci	}
78062306a36Sopenharmony_ci	spin_unlock(&conn->lock);
78162306a36Sopenharmony_ci	return NULL;
78262306a36Sopenharmony_ci}
78362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fsnotify_find_mark);
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci/* Clear any marks in a group with given type mask */
78662306a36Sopenharmony_civoid fsnotify_clear_marks_by_group(struct fsnotify_group *group,
78762306a36Sopenharmony_ci				   unsigned int obj_type)
78862306a36Sopenharmony_ci{
78962306a36Sopenharmony_ci	struct fsnotify_mark *lmark, *mark;
79062306a36Sopenharmony_ci	LIST_HEAD(to_free);
79162306a36Sopenharmony_ci	struct list_head *head = &to_free;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	/* Skip selection step if we want to clear all marks. */
79462306a36Sopenharmony_ci	if (obj_type == FSNOTIFY_OBJ_TYPE_ANY) {
79562306a36Sopenharmony_ci		head = &group->marks_list;
79662306a36Sopenharmony_ci		goto clear;
79762306a36Sopenharmony_ci	}
79862306a36Sopenharmony_ci	/*
79962306a36Sopenharmony_ci	 * We have to be really careful here. Anytime we drop mark_mutex, e.g.
80062306a36Sopenharmony_ci	 * fsnotify_clear_marks_by_inode() can come and free marks. Even in our
80162306a36Sopenharmony_ci	 * to_free list so we have to use mark_mutex even when accessing that
80262306a36Sopenharmony_ci	 * list. And freeing mark requires us to drop mark_mutex. So we can
80362306a36Sopenharmony_ci	 * reliably free only the first mark in the list. That's why we first
80462306a36Sopenharmony_ci	 * move marks to free to to_free list in one go and then free marks in
80562306a36Sopenharmony_ci	 * to_free list one by one.
80662306a36Sopenharmony_ci	 */
80762306a36Sopenharmony_ci	fsnotify_group_lock(group);
80862306a36Sopenharmony_ci	list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) {
80962306a36Sopenharmony_ci		if (mark->connector->type == obj_type)
81062306a36Sopenharmony_ci			list_move(&mark->g_list, &to_free);
81162306a36Sopenharmony_ci	}
81262306a36Sopenharmony_ci	fsnotify_group_unlock(group);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ciclear:
81562306a36Sopenharmony_ci	while (1) {
81662306a36Sopenharmony_ci		fsnotify_group_lock(group);
81762306a36Sopenharmony_ci		if (list_empty(head)) {
81862306a36Sopenharmony_ci			fsnotify_group_unlock(group);
81962306a36Sopenharmony_ci			break;
82062306a36Sopenharmony_ci		}
82162306a36Sopenharmony_ci		mark = list_first_entry(head, struct fsnotify_mark, g_list);
82262306a36Sopenharmony_ci		fsnotify_get_mark(mark);
82362306a36Sopenharmony_ci		fsnotify_detach_mark(mark);
82462306a36Sopenharmony_ci		fsnotify_group_unlock(group);
82562306a36Sopenharmony_ci		fsnotify_free_mark(mark);
82662306a36Sopenharmony_ci		fsnotify_put_mark(mark);
82762306a36Sopenharmony_ci	}
82862306a36Sopenharmony_ci}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci/* Destroy all marks attached to an object via connector */
83162306a36Sopenharmony_civoid fsnotify_destroy_marks(fsnotify_connp_t *connp)
83262306a36Sopenharmony_ci{
83362306a36Sopenharmony_ci	struct fsnotify_mark_connector *conn;
83462306a36Sopenharmony_ci	struct fsnotify_mark *mark, *old_mark = NULL;
83562306a36Sopenharmony_ci	void *objp;
83662306a36Sopenharmony_ci	unsigned int type;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	conn = fsnotify_grab_connector(connp);
83962306a36Sopenharmony_ci	if (!conn)
84062306a36Sopenharmony_ci		return;
84162306a36Sopenharmony_ci	/*
84262306a36Sopenharmony_ci	 * We have to be careful since we can race with e.g.
84362306a36Sopenharmony_ci	 * fsnotify_clear_marks_by_group() and once we drop the conn->lock, the
84462306a36Sopenharmony_ci	 * list can get modified. However we are holding mark reference and
84562306a36Sopenharmony_ci	 * thus our mark cannot be removed from obj_list so we can continue
84662306a36Sopenharmony_ci	 * iteration after regaining conn->lock.
84762306a36Sopenharmony_ci	 */
84862306a36Sopenharmony_ci	hlist_for_each_entry(mark, &conn->list, obj_list) {
84962306a36Sopenharmony_ci		fsnotify_get_mark(mark);
85062306a36Sopenharmony_ci		spin_unlock(&conn->lock);
85162306a36Sopenharmony_ci		if (old_mark)
85262306a36Sopenharmony_ci			fsnotify_put_mark(old_mark);
85362306a36Sopenharmony_ci		old_mark = mark;
85462306a36Sopenharmony_ci		fsnotify_destroy_mark(mark, mark->group);
85562306a36Sopenharmony_ci		spin_lock(&conn->lock);
85662306a36Sopenharmony_ci	}
85762306a36Sopenharmony_ci	/*
85862306a36Sopenharmony_ci	 * Detach list from object now so that we don't pin inode until all
85962306a36Sopenharmony_ci	 * mark references get dropped. It would lead to strange results such
86062306a36Sopenharmony_ci	 * as delaying inode deletion or blocking unmount.
86162306a36Sopenharmony_ci	 */
86262306a36Sopenharmony_ci	objp = fsnotify_detach_connector_from_object(conn, &type);
86362306a36Sopenharmony_ci	spin_unlock(&conn->lock);
86462306a36Sopenharmony_ci	if (old_mark)
86562306a36Sopenharmony_ci		fsnotify_put_mark(old_mark);
86662306a36Sopenharmony_ci	fsnotify_drop_object(type, objp);
86762306a36Sopenharmony_ci}
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci/*
87062306a36Sopenharmony_ci * Nothing fancy, just initialize lists and locks and counters.
87162306a36Sopenharmony_ci */
87262306a36Sopenharmony_civoid fsnotify_init_mark(struct fsnotify_mark *mark,
87362306a36Sopenharmony_ci			struct fsnotify_group *group)
87462306a36Sopenharmony_ci{
87562306a36Sopenharmony_ci	memset(mark, 0, sizeof(*mark));
87662306a36Sopenharmony_ci	spin_lock_init(&mark->lock);
87762306a36Sopenharmony_ci	refcount_set(&mark->refcnt, 1);
87862306a36Sopenharmony_ci	fsnotify_get_group(group);
87962306a36Sopenharmony_ci	mark->group = group;
88062306a36Sopenharmony_ci	WRITE_ONCE(mark->connector, NULL);
88162306a36Sopenharmony_ci}
88262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fsnotify_init_mark);
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci/*
88562306a36Sopenharmony_ci * Destroy all marks in destroy_list, waits for SRCU period to finish before
88662306a36Sopenharmony_ci * actually freeing marks.
88762306a36Sopenharmony_ci */
88862306a36Sopenharmony_cistatic void fsnotify_mark_destroy_workfn(struct work_struct *work)
88962306a36Sopenharmony_ci{
89062306a36Sopenharmony_ci	struct fsnotify_mark *mark, *next;
89162306a36Sopenharmony_ci	struct list_head private_destroy_list;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	spin_lock(&destroy_lock);
89462306a36Sopenharmony_ci	/* exchange the list head */
89562306a36Sopenharmony_ci	list_replace_init(&destroy_list, &private_destroy_list);
89662306a36Sopenharmony_ci	spin_unlock(&destroy_lock);
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	synchronize_srcu(&fsnotify_mark_srcu);
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	list_for_each_entry_safe(mark, next, &private_destroy_list, g_list) {
90162306a36Sopenharmony_ci		list_del_init(&mark->g_list);
90262306a36Sopenharmony_ci		fsnotify_final_mark_destroy(mark);
90362306a36Sopenharmony_ci	}
90462306a36Sopenharmony_ci}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci/* Wait for all marks queued for destruction to be actually destroyed */
90762306a36Sopenharmony_civoid fsnotify_wait_marks_destroyed(void)
90862306a36Sopenharmony_ci{
90962306a36Sopenharmony_ci	flush_delayed_work(&reaper_work);
91062306a36Sopenharmony_ci}
91162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fsnotify_wait_marks_destroyed);
912