Blame view

fs/notify/mark.c 24.9 KB
c82ee6d3b   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
5444e2981   Eric Paris   fsnotify: split g...
2
3
  /*
   *  Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com>
5444e2981   Eric Paris   fsnotify: split g...
4
5
6
7
8
9
   */
  
  /*
   * fsnotify inode mark locking/lifetime/and refcnting
   *
   * REFCNT:
9756b9187   Lino Sanfilippo   fsnotify: update ...
10
11
12
13
14
15
   * The group->recnt and mark->refcnt tell how many "things" in the kernel
   * currently are referencing the objects. Both kind of objects typically will
   * live inside the kernel with a refcnt of 2, one for its creation and one for
   * the reference a group and a mark hold to each other.
   * If you are holding the appropriate locks, you can take a reference and the
   * object itself is guaranteed to survive until the reference is dropped.
5444e2981   Eric Paris   fsnotify: split g...
16
17
   *
   * LOCKING:
9756b9187   Lino Sanfilippo   fsnotify: update ...
18
19
   * There are 3 locks involved with fsnotify inode marks and they MUST be taken
   * in order as follows:
5444e2981   Eric Paris   fsnotify: split g...
20
   *
9756b9187   Lino Sanfilippo   fsnotify: update ...
21
   * group->mark_mutex
5444e2981   Eric Paris   fsnotify: split g...
22
   * mark->lock
04662cab5   Jan Kara   fsnotify: Lock ob...
23
   * mark->connector->lock
5444e2981   Eric Paris   fsnotify: split g...
24
   *
9756b9187   Lino Sanfilippo   fsnotify: update ...
25
26
27
28
29
30
31
32
   * group->mark_mutex protects the marks_list anchored inside a given group and
   * each mark is hooked via the g_list.  It also protects the groups private
   * data (i.e group limits).
  
   * mark->lock protects the marks attributes like its masks and flags.
   * Furthermore it protects the access to a reference of the group that the mark
   * is assigned to as well as the access to a reference of the inode/vfsmount
   * that is being watched by the mark.
5444e2981   Eric Paris   fsnotify: split g...
33
   *
04662cab5   Jan Kara   fsnotify: Lock ob...
34
35
   * mark->connector->lock protects the list of marks anchored inside an
   * inode / vfsmount and each mark is hooked via the i_list.
5444e2981   Eric Paris   fsnotify: split g...
36
   *
04662cab5   Jan Kara   fsnotify: Lock ob...
37
38
   * A list of notification marks relating to inode / mnt is contained in
   * fsnotify_mark_connector. That structure is alive as long as there are any
6b3f05d24   Jan Kara   fsnotify: Detach ...
39
40
41
42
43
44
45
   * marks in the list and is also protected by fsnotify_mark_srcu. A mark gets
   * detached from fsnotify_mark_connector when last reference to the mark is
   * dropped.  Thus having mark reference is enough to protect mark->connector
   * pointer and to make sure fsnotify_mark_connector cannot disappear. Also
   * because we remove mark from g_list before dropping mark reference associated
   * with that, any mark found through g_list is guaranteed to have
   * mark->connector set until we drop group->mark_mutex.
5444e2981   Eric Paris   fsnotify: split g...
46
47
48
   *
   * LIFETIME:
   * Inode marks survive between when they are added to an inode and when their
c1f33073a   Jan Kara   fsnotify: Update ...
49
   * refcnt==0. Marks are also protected by fsnotify_mark_srcu.
5444e2981   Eric Paris   fsnotify: split g...
50
51
52
53
54
55
56
   *
   * The inode mark can be cleared for a number of different reasons including:
   * - The inode is unlinked for the last time.  (fsnotify_inode_remove)
   * - The inode is being evicted from cache. (fsnotify_inode_delete)
   * - The fs the inode is on is unmounted.  (fsnotify_inode_delete/fsnotify_unmount_inodes)
   * - Something explicitly requests that it be removed.  (fsnotify_destroy_mark)
   * - The fsnotify_group associated with the mark is going away and all such marks
2e37c6ca8   Jan Kara   fsnotify: Remove ...
57
   *   need to be cleaned up. (fsnotify_clear_marks_by_group)
5444e2981   Eric Paris   fsnotify: split g...
58
   *
5444e2981   Eric Paris   fsnotify: split g...
59
60
61
62
63
64
65
   * This has the very interesting property of being able to run concurrently with
   * any (or all) other directions.
   */
  
  #include <linux/fs.h>
  #include <linux/init.h>
  #include <linux/kernel.h>
75c1be487   Eric Paris   fsnotify: srcu to...
66
  #include <linux/kthread.h>
5444e2981   Eric Paris   fsnotify: split g...
67
68
69
70
  #include <linux/module.h>
  #include <linux/mutex.h>
  #include <linux/slab.h>
  #include <linux/spinlock.h>
75c1be487   Eric Paris   fsnotify: srcu to...
71
  #include <linux/srcu.h>
77115225a   Amir Goldstein   fanotify: cache f...
72
  #include <linux/ratelimit.h>
5444e2981   Eric Paris   fsnotify: split g...
73

60063497a   Arun Sharma   atomic: use <linu...
74
  #include <linux/atomic.h>
5444e2981   Eric Paris   fsnotify: split g...
75
76
77
  
  #include <linux/fsnotify_backend.h>
  #include "fsnotify.h"
0918f1c30   Jeff Layton   fsnotify: turn fs...
78
  #define FSNOTIFY_REAPER_DELAY	(1)	/* 1 jiffy */
75c1be487   Eric Paris   fsnotify: srcu to...
79
  struct srcu_struct fsnotify_mark_srcu;
9dd813c15   Jan Kara   fsnotify: Move ma...
80
  struct kmem_cache *fsnotify_mark_connector_cachep;
13d34ac6e   Jeff Layton   Revert "fsnotify:...
81
82
  static DEFINE_SPINLOCK(destroy_lock);
  static LIST_HEAD(destroy_list);
08991e83b   Jan Kara   fsnotify: Free fs...
83
  static struct fsnotify_mark_connector *connector_destroy_list;
0918f1c30   Jeff Layton   fsnotify: turn fs...
84

35e481761   Jan Kara   fsnotify: avoid s...
85
86
  static void fsnotify_mark_destroy_workfn(struct work_struct *work);
  static DECLARE_DELAYED_WORK(reaper_work, fsnotify_mark_destroy_workfn);
75c1be487   Eric Paris   fsnotify: srcu to...
87

08991e83b   Jan Kara   fsnotify: Free fs...
88
89
  static void fsnotify_connector_destroy_workfn(struct work_struct *work);
  static DECLARE_WORK(connector_reaper_work, fsnotify_connector_destroy_workfn);
5444e2981   Eric Paris   fsnotify: split g...
90
91
  void fsnotify_get_mark(struct fsnotify_mark *mark)
  {
ab97f8732   Elena Reshetova   fsnotify: convert...
92
93
  	WARN_ON_ONCE(!refcount_read(&mark->refcnt));
  	refcount_inc(&mark->refcnt);
5444e2981   Eric Paris   fsnotify: split g...
94
  }
3ac70bfcd   Amir Goldstein   fsnotify: add hel...
95
96
97
98
99
100
  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;
1e6cb7239   Amir Goldstein   fsnotify: add sup...
101
102
  	else if (conn->type == FSNOTIFY_OBJ_TYPE_SB)
  		return &fsnotify_conn_sb(conn)->s_fsnotify_mask;
3ac70bfcd   Amir Goldstein   fsnotify: add hel...
103
104
105
106
107
108
109
110
111
112
  	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);
  }
a242677bb   Jan Kara   fsnotify: Move lo...
113
  static void __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
0809ab69a   Jan Kara   fsnotify: unify i...
114
115
116
  {
  	u32 new_mask = 0;
  	struct fsnotify_mark *mark;
04662cab5   Jan Kara   fsnotify: Lock ob...
117
  	assert_spin_locked(&conn->lock);
d3bc0fa84   Jan Kara   fsnotify: fix fal...
118
119
120
  	/* We can get detached connector here when inode is getting unlinked. */
  	if (!fsnotify_valid_obj_type(conn->type))
  		return;
6b3f05d24   Jan Kara   fsnotify: Detach ...
121
122
123
124
  	hlist_for_each_entry(mark, &conn->list, obj_list) {
  		if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED)
  			new_mask |= mark->mask;
  	}
3ac70bfcd   Amir Goldstein   fsnotify: add hel...
125
  	*fsnotify_conn_mask_p(conn) = new_mask;
a242677bb   Jan Kara   fsnotify: Move lo...
126
127
128
129
  }
  
  /*
   * Calculate mask of events for a list of marks. The caller must make sure
36f10f55f   Amir Goldstein   fsnotify: let con...
130
   * connector and connector->obj cannot disappear under us.  Callers achieve
6b3f05d24   Jan Kara   fsnotify: Detach ...
131
132
   * this by holding a mark->lock or mark->group->mark_mutex for a mark on this
   * list.
a242677bb   Jan Kara   fsnotify: Move lo...
133
134
135
136
137
   */
  void fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
  {
  	if (!conn)
  		return;
04662cab5   Jan Kara   fsnotify: Lock ob...
138
  	spin_lock(&conn->lock);
a242677bb   Jan Kara   fsnotify: Move lo...
139
  	__fsnotify_recalc_mask(conn);
04662cab5   Jan Kara   fsnotify: Lock ob...
140
  	spin_unlock(&conn->lock);
d6f7b98bc   Amir Goldstein   fsnotify: use typ...
141
  	if (conn->type == FSNOTIFY_OBJ_TYPE_INODE)
36f10f55f   Amir Goldstein   fsnotify: let con...
142
143
  		__fsnotify_update_child_dentry_flags(
  					fsnotify_conn_inode(conn));
0809ab69a   Jan Kara   fsnotify: unify i...
144
  }
08991e83b   Jan Kara   fsnotify: Free fs...
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  /* Free all connectors queued for freeing once SRCU period ends */
  static void fsnotify_connector_destroy_workfn(struct work_struct *work)
  {
  	struct fsnotify_mark_connector *conn, *free;
  
  	spin_lock(&destroy_lock);
  	conn = connector_destroy_list;
  	connector_destroy_list = NULL;
  	spin_unlock(&destroy_lock);
  
  	synchronize_srcu(&fsnotify_mark_srcu);
  	while (conn) {
  		free = conn;
  		conn = conn->destroy_next;
  		kmem_cache_free(fsnotify_mark_connector_cachep, free);
  	}
  }
721fb6fbf   Jan Kara   fsnotify: Fix bus...
162
163
164
  static void *fsnotify_detach_connector_from_object(
  					struct fsnotify_mark_connector *conn,
  					unsigned int *type)
08991e83b   Jan Kara   fsnotify: Free fs...
165
166
  {
  	struct inode *inode = NULL;
721fb6fbf   Jan Kara   fsnotify: Fix bus...
167
  	*type = conn->type;
36f10f55f   Amir Goldstein   fsnotify: let con...
168
169
  	if (conn->type == FSNOTIFY_OBJ_TYPE_DETACHED)
  		return NULL;
d6f7b98bc   Amir Goldstein   fsnotify: use typ...
170
  	if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) {
36f10f55f   Amir Goldstein   fsnotify: let con...
171
  		inode = fsnotify_conn_inode(conn);
08991e83b   Jan Kara   fsnotify: Free fs...
172
  		inode->i_fsnotify_mask = 0;
721fb6fbf   Jan Kara   fsnotify: Fix bus...
173
  		atomic_long_inc(&inode->i_sb->s_fsnotify_inode_refs);
d6f7b98bc   Amir Goldstein   fsnotify: use typ...
174
  	} else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) {
36f10f55f   Amir Goldstein   fsnotify: let con...
175
  		fsnotify_conn_mount(conn)->mnt_fsnotify_mask = 0;
1e6cb7239   Amir Goldstein   fsnotify: add sup...
176
177
  	} else if (conn->type == FSNOTIFY_OBJ_TYPE_SB) {
  		fsnotify_conn_sb(conn)->s_fsnotify_mask = 0;
08991e83b   Jan Kara   fsnotify: Free fs...
178
  	}
36f10f55f   Amir Goldstein   fsnotify: let con...
179
180
181
  	rcu_assign_pointer(*(conn->obj), NULL);
  	conn->obj = NULL;
  	conn->type = FSNOTIFY_OBJ_TYPE_DETACHED;
08991e83b   Jan Kara   fsnotify: Free fs...
182
183
  	return inode;
  }
6b3f05d24   Jan Kara   fsnotify: Detach ...
184
185
  static void fsnotify_final_mark_destroy(struct fsnotify_mark *mark)
  {
054c636e5   Jan Kara   fsnotify: Move ->...
186
187
188
189
190
191
  	struct fsnotify_group *group = mark->group;
  
  	if (WARN_ON_ONCE(!group))
  		return;
  	group->ops->free_mark(mark);
  	fsnotify_put_group(group);
6b3f05d24   Jan Kara   fsnotify: Detach ...
192
  }
721fb6fbf   Jan Kara   fsnotify: Fix bus...
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
  /* Drop object reference originally held by a connector */
  static void fsnotify_drop_object(unsigned int type, void *objp)
  {
  	struct inode *inode;
  	struct super_block *sb;
  
  	if (!objp)
  		return;
  	/* Currently only inode references are passed to be dropped */
  	if (WARN_ON_ONCE(type != FSNOTIFY_OBJ_TYPE_INODE))
  		return;
  	inode = objp;
  	sb = inode->i_sb;
  	iput(inode);
  	if (atomic_long_dec_and_test(&sb->s_fsnotify_inode_refs))
  		wake_up_var(&sb->s_fsnotify_inode_refs);
  }
6b3f05d24   Jan Kara   fsnotify: Detach ...
210
  void fsnotify_put_mark(struct fsnotify_mark *mark)
8212a6097   Jan Kara   fsnotify: Remove ...
211
  {
b1da6a518   Jan Kara   fsnotify: Fix NUL...
212
  	struct fsnotify_mark_connector *conn = READ_ONCE(mark->connector);
721fb6fbf   Jan Kara   fsnotify: Fix bus...
213
214
  	void *objp = NULL;
  	unsigned int type = FSNOTIFY_OBJ_TYPE_DETACHED;
08991e83b   Jan Kara   fsnotify: Free fs...
215
  	bool free_conn = false;
8212a6097   Jan Kara   fsnotify: Remove ...
216

6b3f05d24   Jan Kara   fsnotify: Detach ...
217
  	/* Catch marks that were actually never attached to object */
b1da6a518   Jan Kara   fsnotify: Fix NUL...
218
  	if (!conn) {
ab97f8732   Elena Reshetova   fsnotify: convert...
219
  		if (refcount_dec_and_test(&mark->refcnt))
6b3f05d24   Jan Kara   fsnotify: Detach ...
220
221
222
223
224
225
226
227
  			fsnotify_final_mark_destroy(mark);
  		return;
  	}
  
  	/*
  	 * We have to be careful so that traversals of obj_list under lock can
  	 * safely grab mark reference.
  	 */
b1da6a518   Jan Kara   fsnotify: Fix NUL...
228
  	if (!refcount_dec_and_lock(&mark->refcnt, &conn->lock))
6b3f05d24   Jan Kara   fsnotify: Detach ...
229
  		return;
8212a6097   Jan Kara   fsnotify: Remove ...
230
231
  	hlist_del_init_rcu(&mark->obj_list);
  	if (hlist_empty(&conn->list)) {
721fb6fbf   Jan Kara   fsnotify: Fix bus...
232
  		objp = fsnotify_detach_connector_from_object(conn, &type);
08991e83b   Jan Kara   fsnotify: Free fs...
233
234
235
  		free_conn = true;
  	} else {
  		__fsnotify_recalc_mask(conn);
8212a6097   Jan Kara   fsnotify: Remove ...
236
  	}
b1da6a518   Jan Kara   fsnotify: Fix NUL...
237
  	WRITE_ONCE(mark->connector, NULL);
04662cab5   Jan Kara   fsnotify: Lock ob...
238
  	spin_unlock(&conn->lock);
8212a6097   Jan Kara   fsnotify: Remove ...
239

721fb6fbf   Jan Kara   fsnotify: Fix bus...
240
  	fsnotify_drop_object(type, objp);
6b3f05d24   Jan Kara   fsnotify: Detach ...
241

08991e83b   Jan Kara   fsnotify: Free fs...
242
243
244
245
246
247
248
  	if (free_conn) {
  		spin_lock(&destroy_lock);
  		conn->destroy_next = connector_destroy_list;
  		connector_destroy_list = conn;
  		spin_unlock(&destroy_lock);
  		queue_work(system_unbound_wq, &connector_reaper_work);
  	}
6b3f05d24   Jan Kara   fsnotify: Detach ...
249
250
251
252
253
254
255
256
257
258
259
  	/*
  	 * Note that we didn't update flags telling whether inode cares about
  	 * what's happening with children. We update these flags from
  	 * __fsnotify_parent() lazily when next event happens on one of our
  	 * children.
  	 */
  	spin_lock(&destroy_lock);
  	list_add(&mark->g_list, &destroy_list);
  	spin_unlock(&destroy_lock);
  	queue_delayed_work(system_unbound_wq, &reaper_work,
  			   FSNOTIFY_REAPER_DELAY);
8212a6097   Jan Kara   fsnotify: Remove ...
260
  }
b72679ee8   Trond Myklebust   notify: export sy...
261
  EXPORT_SYMBOL_GPL(fsnotify_put_mark);
8212a6097   Jan Kara   fsnotify: Remove ...
262

24c20305c   Miklos Szeredi   fsnotify: clean u...
263
264
265
266
267
268
269
270
  /*
   * Get mark reference when we found the mark via lockless traversal of object
   * list. Mark can be already removed from the list by now and on its way to be
   * destroyed once SRCU period ends.
   *
   * Also pin the group so it doesn't disappear under us.
   */
  static bool fsnotify_get_mark_safe(struct fsnotify_mark *mark)
abc77577a   Jan Kara   fsnotify: Provide...
271
  {
24c20305c   Miklos Szeredi   fsnotify: clean u...
272
273
  	if (!mark)
  		return true;
abc77577a   Jan Kara   fsnotify: Provide...
274

ab97f8732   Elena Reshetova   fsnotify: convert...
275
  	if (refcount_inc_not_zero(&mark->refcnt)) {
9a31d7ad9   Miklos Szeredi   fsnotify: fix pin...
276
277
278
279
280
281
282
283
284
285
  		spin_lock(&mark->lock);
  		if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED) {
  			/* mark is attached, group is still alive then */
  			atomic_inc(&mark->group->user_waits);
  			spin_unlock(&mark->lock);
  			return true;
  		}
  		spin_unlock(&mark->lock);
  		fsnotify_put_mark(mark);
  	}
24c20305c   Miklos Szeredi   fsnotify: clean u...
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
  	return false;
  }
  
  /*
   * Puts marks and wakes up group destruction if necessary.
   *
   * Pairs with fsnotify_get_mark_safe()
   */
  static void fsnotify_put_mark_wake(struct fsnotify_mark *mark)
  {
  	if (mark) {
  		struct fsnotify_group *group = mark->group;
  
  		fsnotify_put_mark(mark);
  		/*
  		 * We abuse notification_waitq on group shutdown for waiting for
  		 * all marks pinned when waiting for userspace.
  		 */
  		if (atomic_dec_and_test(&group->user_waits) && group->shutdown)
  			wake_up(&group->notification_waitq);
abc77577a   Jan Kara   fsnotify: Provide...
306
  	}
24c20305c   Miklos Szeredi   fsnotify: clean u...
307
308
309
  }
  
  bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info)
00e0afb65   Jules Irenge   fsnotify: Add mis...
310
  	__releases(&fsnotify_mark_srcu)
24c20305c   Miklos Szeredi   fsnotify: clean u...
311
  {
47d9c7cc4   Amir Goldstein   fsnotify: general...
312
313
314
315
  	int type;
  
  	fsnotify_foreach_obj_type(type) {
  		/* This can fail if mark is being removed */
00e0afb65   Jules Irenge   fsnotify: Add mis...
316
317
  		if (!fsnotify_get_mark_safe(iter_info->marks[type])) {
  			__release(&fsnotify_mark_srcu);
47d9c7cc4   Amir Goldstein   fsnotify: general...
318
  			goto fail;
00e0afb65   Jules Irenge   fsnotify: Add mis...
319
  		}
abc77577a   Jan Kara   fsnotify: Provide...
320
321
322
323
324
325
326
327
328
329
  	}
  
  	/*
  	 * Now that both marks are pinned by refcount in the inode / vfsmount
  	 * lists, we can drop SRCU lock, and safely resume the list iteration
  	 * once userspace returns.
  	 */
  	srcu_read_unlock(&fsnotify_mark_srcu, iter_info->srcu_idx);
  
  	return true;
47d9c7cc4   Amir Goldstein   fsnotify: general...
330
331
332
333
334
  
  fail:
  	for (type--; type >= 0; type--)
  		fsnotify_put_mark_wake(iter_info->marks[type]);
  	return false;
abc77577a   Jan Kara   fsnotify: Provide...
335
336
337
  }
  
  void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info)
00e0afb65   Jules Irenge   fsnotify: Add mis...
338
  	__acquires(&fsnotify_mark_srcu)
abc77577a   Jan Kara   fsnotify: Provide...
339
  {
47d9c7cc4   Amir Goldstein   fsnotify: general...
340
  	int type;
abc77577a   Jan Kara   fsnotify: Provide...
341
  	iter_info->srcu_idx = srcu_read_lock(&fsnotify_mark_srcu);
47d9c7cc4   Amir Goldstein   fsnotify: general...
342
343
  	fsnotify_foreach_obj_type(type)
  		fsnotify_put_mark_wake(iter_info->marks[type]);
abc77577a   Jan Kara   fsnotify: Provide...
344
  }
5444e2981   Eric Paris   fsnotify: split g...
345
  /*
6b3f05d24   Jan Kara   fsnotify: Detach ...
346
347
348
349
350
   * Mark mark as detached, remove it from group list. Mark still stays in object
   * list until its last reference is dropped. Note that we rely on mark being
   * removed from group list before corresponding reference to it is dropped. In
   * particular we rely on mark->connector being valid while we hold
   * group->mark_mutex if we found the mark through g_list.
4712e722f   Jan Kara   fsnotify: get rid...
351
   *
11375145a   Jan Kara   fsnotify: Move qu...
352
353
   * Must be called with group->mark_mutex held. The caller must either hold
   * reference to the mark or be protected by fsnotify_mark_srcu.
5444e2981   Eric Paris   fsnotify: split g...
354
   */
4712e722f   Jan Kara   fsnotify: get rid...
355
  void fsnotify_detach_mark(struct fsnotify_mark *mark)
5444e2981   Eric Paris   fsnotify: split g...
356
  {
4712e722f   Jan Kara   fsnotify: get rid...
357
  	struct fsnotify_group *group = mark->group;
5444e2981   Eric Paris   fsnotify: split g...
358

11375145a   Jan Kara   fsnotify: Move qu...
359
360
  	WARN_ON_ONCE(!mutex_is_locked(&group->mark_mutex));
  	WARN_ON_ONCE(!srcu_read_lock_held(&fsnotify_mark_srcu) &&
ab97f8732   Elena Reshetova   fsnotify: convert...
361
  		     refcount_read(&mark->refcnt) < 1 +
11375145a   Jan Kara   fsnotify: Move qu...
362
  			!!(mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED));
d5a335b84   Lino Sanfilippo   fsnotify: introdu...
363

104d06f08   Lino Sanfilippo   fsnotify: take gr...
364
  	spin_lock(&mark->lock);
700307a29   Eric Paris   fsnotify: use an ...
365
  	/* something else already called this function on this mark */
4712e722f   Jan Kara   fsnotify: get rid...
366
  	if (!(mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED)) {
5444e2981   Eric Paris   fsnotify: split g...
367
  		spin_unlock(&mark->lock);
e2a29943e   Lino Sanfilippo   fsnotify: pass gr...
368
  		return;
5444e2981   Eric Paris   fsnotify: split g...
369
  	}
4712e722f   Jan Kara   fsnotify: get rid...
370
  	mark->flags &= ~FSNOTIFY_MARK_FLAG_ATTACHED;
5444e2981   Eric Paris   fsnotify: split g...
371
  	list_del_init(&mark->g_list);
5444e2981   Eric Paris   fsnotify: split g...
372
  	spin_unlock(&mark->lock);
d5a335b84   Lino Sanfilippo   fsnotify: introdu...
373

4712e722f   Jan Kara   fsnotify: get rid...
374
  	atomic_dec(&group->num_marks);
11375145a   Jan Kara   fsnotify: Move qu...
375
376
377
  
  	/* Drop mark reference acquired in fsnotify_add_mark_locked() */
  	fsnotify_put_mark(mark);
4712e722f   Jan Kara   fsnotify: get rid...
378
379
380
  }
  
  /*
11375145a   Jan Kara   fsnotify: Move qu...
381
382
383
   * Free fsnotify mark. The mark is actually only marked as being freed.  The
   * freeing is actually happening only once last reference to the mark is
   * dropped from a workqueue which first waits for srcu period end.
35e481761   Jan Kara   fsnotify: avoid s...
384
   *
11375145a   Jan Kara   fsnotify: Move qu...
385
386
   * Caller must have a reference to the mark or be protected by
   * fsnotify_mark_srcu.
4712e722f   Jan Kara   fsnotify: get rid...
387
   */
11375145a   Jan Kara   fsnotify: Move qu...
388
  void fsnotify_free_mark(struct fsnotify_mark *mark)
4712e722f   Jan Kara   fsnotify: get rid...
389
390
391
392
393
394
395
  {
  	struct fsnotify_group *group = mark->group;
  
  	spin_lock(&mark->lock);
  	/* something else already called this function on this mark */
  	if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) {
  		spin_unlock(&mark->lock);
11375145a   Jan Kara   fsnotify: Move qu...
396
  		return;
4712e722f   Jan Kara   fsnotify: get rid...
397
398
399
  	}
  	mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE;
  	spin_unlock(&mark->lock);
5444e2981   Eric Paris   fsnotify: split g...
400

d725e66c0   Linus Torvalds   Revert "fsnotify:...
401
402
403
404
405
406
407
  	/*
  	 * Some groups like to know that marks are being freed.  This is a
  	 * callback to the group function to let it know that this mark
  	 * is being freed.
  	 */
  	if (group->ops->freeing_mark)
  		group->ops->freeing_mark(mark, group);
d5a335b84   Lino Sanfilippo   fsnotify: introdu...
408
409
410
411
412
  }
  
  void fsnotify_destroy_mark(struct fsnotify_mark *mark,
  			   struct fsnotify_group *group)
  {
6960b0d90   Lino Sanfilippo   fsnotify: change ...
413
  	mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
4712e722f   Jan Kara   fsnotify: get rid...
414
  	fsnotify_detach_mark(mark);
d5a335b84   Lino Sanfilippo   fsnotify: introdu...
415
  	mutex_unlock(&group->mark_mutex);
4712e722f   Jan Kara   fsnotify: get rid...
416
  	fsnotify_free_mark(mark);
5444e2981   Eric Paris   fsnotify: split g...
417
  }
b72679ee8   Trond Myklebust   notify: export sy...
418
  EXPORT_SYMBOL_GPL(fsnotify_destroy_mark);
5444e2981   Eric Paris   fsnotify: split g...
419
420
  
  /*
8edc6e168   Jan Kara   fanotify: fix not...
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
   * Sorting function for lists of fsnotify marks.
   *
   * Fanotify supports different notification classes (reflected as priority of
   * notification group). Events shall be passed to notification groups in
   * decreasing priority order. To achieve this marks in notification lists for
   * inodes and vfsmounts are sorted so that priorities of corresponding groups
   * are descending.
   *
   * Furthermore correct handling of the ignore mask requires processing inode
   * and vfsmount marks of each group together. Using the group address as
   * further sort criterion provides a unique sorting order and thus we can
   * merge inode and vfsmount lists of marks in linear time and find groups
   * present in both lists.
   *
   * A return value of 1 signifies that b has priority over a.
   * A return value of 0 signifies that the two marks have to be handled together.
   * A return value of -1 signifies that a has priority over b.
   */
  int fsnotify_compare_groups(struct fsnotify_group *a, struct fsnotify_group *b)
  {
  	if (a == b)
  		return 0;
  	if (!a)
  		return 1;
  	if (!b)
  		return -1;
  	if (a->priority < b->priority)
  		return 1;
  	if (a->priority > b->priority)
  		return -1;
  	if (a < b)
  		return 1;
  	return -1;
  }
9b6e54345   Amir Goldstein   fsnotify: use typ...
455
  static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp,
77115225a   Amir Goldstein   fanotify: cache f...
456
457
  					       unsigned int type,
  					       __kernel_fsid_t *fsid)
9dd813c15   Jan Kara   fsnotify: Move ma...
458
  {
b812a9f58   Amir Goldstein   fsnotify: pass co...
459
  	struct inode *inode = NULL;
9dd813c15   Jan Kara   fsnotify: Move ma...
460
  	struct fsnotify_mark_connector *conn;
755b5bc68   Jan Kara   fsnotify: Remove ...
461
  	conn = kmem_cache_alloc(fsnotify_mark_connector_cachep, GFP_KERNEL);
9dd813c15   Jan Kara   fsnotify: Move ma...
462
463
  	if (!conn)
  		return -ENOMEM;
04662cab5   Jan Kara   fsnotify: Lock ob...
464
  	spin_lock_init(&conn->lock);
9dd813c15   Jan Kara   fsnotify: Move ma...
465
  	INIT_HLIST_HEAD(&conn->list);
b812a9f58   Amir Goldstein   fsnotify: pass co...
466
  	conn->type = type;
36f10f55f   Amir Goldstein   fsnotify: let con...
467
  	conn->obj = connp;
77115225a   Amir Goldstein   fanotify: cache f...
468
  	/* Cache fsid of filesystem containing the object */
c285a2f01   Amir Goldstein   fanotify: update ...
469
  	if (fsid) {
77115225a   Amir Goldstein   fanotify: cache f...
470
  		conn->fsid = *fsid;
c285a2f01   Amir Goldstein   fanotify: update ...
471
472
  		conn->flags = FSNOTIFY_CONN_FLAG_HAS_FSID;
  	} else {
77115225a   Amir Goldstein   fanotify: cache f...
473
  		conn->fsid.val[0] = conn->fsid.val[1] = 0;
c285a2f01   Amir Goldstein   fanotify: update ...
474
475
  		conn->flags = 0;
  	}
b812a9f58   Amir Goldstein   fsnotify: pass co...
476
  	if (conn->type == FSNOTIFY_OBJ_TYPE_INODE)
36f10f55f   Amir Goldstein   fsnotify: let con...
477
  		inode = igrab(fsnotify_conn_inode(conn));
9dd813c15   Jan Kara   fsnotify: Move ma...
478
  	/*
04662cab5   Jan Kara   fsnotify: Lock ob...
479
480
  	 * cmpxchg() provides the barrier so that readers of *connp can see
  	 * only initialized structure
9dd813c15   Jan Kara   fsnotify: Move ma...
481
  	 */
04662cab5   Jan Kara   fsnotify: Lock ob...
482
483
  	if (cmpxchg(connp, NULL, conn)) {
  		/* Someone else created list structure for us */
08991e83b   Jan Kara   fsnotify: Free fs...
484
485
  		if (inode)
  			iput(inode);
755b5bc68   Jan Kara   fsnotify: Remove ...
486
  		kmem_cache_free(fsnotify_mark_connector_cachep, conn);
04662cab5   Jan Kara   fsnotify: Lock ob...
487
  	}
9dd813c15   Jan Kara   fsnotify: Move ma...
488
489
490
491
492
  
  	return 0;
  }
  
  /*
08991e83b   Jan Kara   fsnotify: Free fs...
493
494
495
496
497
498
   * Get mark connector, make sure it is alive and return with its lock held.
   * This is for users that get connector pointer from inode or mount. Users that
   * hold reference to a mark on the list may directly lock connector->lock as
   * they are sure list cannot go away under them.
   */
  static struct fsnotify_mark_connector *fsnotify_grab_connector(
9b6e54345   Amir Goldstein   fsnotify: use typ...
499
  						fsnotify_connp_t *connp)
08991e83b   Jan Kara   fsnotify: Free fs...
500
501
502
503
504
505
506
507
508
  {
  	struct fsnotify_mark_connector *conn;
  	int idx;
  
  	idx = srcu_read_lock(&fsnotify_mark_srcu);
  	conn = srcu_dereference(*connp, &fsnotify_mark_srcu);
  	if (!conn)
  		goto out;
  	spin_lock(&conn->lock);
d6f7b98bc   Amir Goldstein   fsnotify: use typ...
509
  	if (conn->type == FSNOTIFY_OBJ_TYPE_DETACHED) {
08991e83b   Jan Kara   fsnotify: Free fs...
510
511
512
513
514
515
516
517
518
519
  		spin_unlock(&conn->lock);
  		srcu_read_unlock(&fsnotify_mark_srcu, idx);
  		return NULL;
  	}
  out:
  	srcu_read_unlock(&fsnotify_mark_srcu, idx);
  	return conn;
  }
  
  /*
9dd813c15   Jan Kara   fsnotify: Move ma...
520
521
522
523
524
   * Add mark into proper place in given list of marks. These marks may be used
   * for the fsnotify backend to determine which event types should be delivered
   * to which group and for which inodes. These marks are ordered according to
   * priority, highest number first, and then by the group's location in memory.
   */
755b5bc68   Jan Kara   fsnotify: Remove ...
525
  static int fsnotify_add_mark_list(struct fsnotify_mark *mark,
b812a9f58   Amir Goldstein   fsnotify: pass co...
526
  				  fsnotify_connp_t *connp, unsigned int type,
77115225a   Amir Goldstein   fanotify: cache f...
527
  				  int allow_dups, __kernel_fsid_t *fsid)
0809ab69a   Jan Kara   fsnotify: unify i...
528
529
  {
  	struct fsnotify_mark *lmark, *last = NULL;
9dd813c15   Jan Kara   fsnotify: Move ma...
530
  	struct fsnotify_mark_connector *conn;
0809ab69a   Jan Kara   fsnotify: unify i...
531
  	int cmp;
755b5bc68   Jan Kara   fsnotify: Remove ...
532
  	int err = 0;
b812a9f58   Amir Goldstein   fsnotify: pass co...
533
  	if (WARN_ON(!fsnotify_valid_obj_type(type)))
755b5bc68   Jan Kara   fsnotify: Remove ...
534
  		return -EINVAL;
77115225a   Amir Goldstein   fanotify: cache f...
535
536
537
538
  
  	/* Backend is expected to check for zero fsid (e.g. tmpfs) */
  	if (fsid && WARN_ON_ONCE(!fsid->val[0] && !fsid->val[1]))
  		return -ENODEV;
08991e83b   Jan Kara   fsnotify: Free fs...
539
540
541
542
543
  restart:
  	spin_lock(&mark->lock);
  	conn = fsnotify_grab_connector(connp);
  	if (!conn) {
  		spin_unlock(&mark->lock);
77115225a   Amir Goldstein   fanotify: cache f...
544
  		err = fsnotify_attach_connector_to_object(connp, type, fsid);
9dd813c15   Jan Kara   fsnotify: Move ma...
545
546
  		if (err)
  			return err;
08991e83b   Jan Kara   fsnotify: Free fs...
547
  		goto restart;
c285a2f01   Amir Goldstein   fanotify: update ...
548
549
550
551
552
553
  	} else if (fsid && !(conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID)) {
  		conn->fsid = *fsid;
  		/* Pairs with smp_rmb() in fanotify_get_fsid() */
  		smp_wmb();
  		conn->flags |= FSNOTIFY_CONN_FLAG_HAS_FSID;
  	} else if (fsid && (conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID) &&
77115225a   Amir Goldstein   fanotify: cache f...
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
  		   (fsid->val[0] != conn->fsid.val[0] ||
  		    fsid->val[1] != conn->fsid.val[1])) {
  		/*
  		 * Backend is expected to check for non uniform fsid
  		 * (e.g. btrfs), but maybe we missed something?
  		 * Only allow setting conn->fsid once to non zero fsid.
  		 * inotify and non-fid fanotify groups do not set nor test
  		 * conn->fsid.
  		 */
  		pr_warn_ratelimited("%s: fsid mismatch on object of type %u: "
  				    "%x.%x != %x.%x
  ", __func__, conn->type,
  				    fsid->val[0], fsid->val[1],
  				    conn->fsid.val[0], conn->fsid.val[1]);
  		err = -EXDEV;
  		goto out_err;
9dd813c15   Jan Kara   fsnotify: Move ma...
570
  	}
0809ab69a   Jan Kara   fsnotify: unify i...
571
572
  
  	/* is mark the first mark? */
9dd813c15   Jan Kara   fsnotify: Move ma...
573
574
  	if (hlist_empty(&conn->list)) {
  		hlist_add_head_rcu(&mark->obj_list, &conn->list);
86ffe245c   Jan Kara   fsnotify: Move ob...
575
  		goto added;
0809ab69a   Jan Kara   fsnotify: unify i...
576
577
578
  	}
  
  	/* should mark be in the middle of the current list? */
9dd813c15   Jan Kara   fsnotify: Move ma...
579
  	hlist_for_each_entry(lmark, &conn->list, obj_list) {
0809ab69a   Jan Kara   fsnotify: unify i...
580
  		last = lmark;
6b3f05d24   Jan Kara   fsnotify: Detach ...
581
582
583
  		if ((lmark->group == mark->group) &&
  		    (lmark->flags & FSNOTIFY_MARK_FLAG_ATTACHED) &&
  		    !allow_dups) {
755b5bc68   Jan Kara   fsnotify: Remove ...
584
585
586
  			err = -EEXIST;
  			goto out_err;
  		}
0809ab69a   Jan Kara   fsnotify: unify i...
587
588
589
590
  
  		cmp = fsnotify_compare_groups(lmark->group, mark->group);
  		if (cmp >= 0) {
  			hlist_add_before_rcu(&mark->obj_list, &lmark->obj_list);
86ffe245c   Jan Kara   fsnotify: Move ob...
591
  			goto added;
0809ab69a   Jan Kara   fsnotify: unify i...
592
593
594
595
596
597
  		}
  	}
  
  	BUG_ON(last == NULL);
  	/* mark should be the last entry.  last is the current last entry */
  	hlist_add_behind_rcu(&mark->obj_list, &last->obj_list);
86ffe245c   Jan Kara   fsnotify: Move ob...
598
  added:
11a6f8e2d   Jan Kara   fsnotify: Clarify...
599
600
601
602
603
  	/*
  	 * Since connector is attached to object using cmpxchg() we are
  	 * guaranteed that connector initialization is fully visible by anyone
  	 * seeing mark->connector set.
  	 */
b1da6a518   Jan Kara   fsnotify: Fix NUL...
604
  	WRITE_ONCE(mark->connector, conn);
755b5bc68   Jan Kara   fsnotify: Remove ...
605
  out_err:
04662cab5   Jan Kara   fsnotify: Lock ob...
606
  	spin_unlock(&conn->lock);
755b5bc68   Jan Kara   fsnotify: Remove ...
607
608
  	spin_unlock(&mark->lock);
  	return err;
0809ab69a   Jan Kara   fsnotify: unify i...
609
  }
8edc6e168   Jan Kara   fanotify: fix not...
610
  /*
5444e2981   Eric Paris   fsnotify: split g...
611
612
613
614
   * Attach an initialized mark to a given group and fs object.
   * These marks may be used for the fsnotify backend to determine which
   * event types should be delivered to which group.
   */
b812a9f58   Amir Goldstein   fsnotify: pass co...
615
616
  int fsnotify_add_mark_locked(struct fsnotify_mark *mark,
  			     fsnotify_connp_t *connp, unsigned int type,
77115225a   Amir Goldstein   fanotify: cache f...
617
  			     int allow_dups, __kernel_fsid_t *fsid)
5444e2981   Eric Paris   fsnotify: split g...
618
  {
7b1293234   Jan Kara   fsnotify: Add gro...
619
  	struct fsnotify_group *group = mark->group;
5444e2981   Eric Paris   fsnotify: split g...
620
  	int ret = 0;
d5a335b84   Lino Sanfilippo   fsnotify: introdu...
621
  	BUG_ON(!mutex_is_locked(&group->mark_mutex));
5444e2981   Eric Paris   fsnotify: split g...
622
623
  
  	/*
5444e2981   Eric Paris   fsnotify: split g...
624
  	 * LOCKING ORDER!!!!
986ab0980   Lino Sanfilippo   fsnotify: use a m...
625
  	 * group->mark_mutex
104d06f08   Lino Sanfilippo   fsnotify: take gr...
626
  	 * mark->lock
04662cab5   Jan Kara   fsnotify: Lock ob...
627
  	 * mark->connector->lock
5444e2981   Eric Paris   fsnotify: split g...
628
  	 */
104d06f08   Lino Sanfilippo   fsnotify: take gr...
629
  	spin_lock(&mark->lock);
4712e722f   Jan Kara   fsnotify: get rid...
630
  	mark->flags |= FSNOTIFY_MARK_FLAG_ALIVE | FSNOTIFY_MARK_FLAG_ATTACHED;
700307a29   Eric Paris   fsnotify: use an ...
631

5444e2981   Eric Paris   fsnotify: split g...
632
633
  	list_add(&mark->g_list, &group->marks_list);
  	atomic_inc(&group->num_marks);
6b3f05d24   Jan Kara   fsnotify: Detach ...
634
  	fsnotify_get_mark(mark); /* for g_list */
5444e2981   Eric Paris   fsnotify: split g...
635
  	spin_unlock(&mark->lock);
77115225a   Amir Goldstein   fanotify: cache f...
636
  	ret = fsnotify_add_mark_list(mark, connp, type, allow_dups, fsid);
755b5bc68   Jan Kara   fsnotify: Remove ...
637
638
  	if (ret)
  		goto err;
a242677bb   Jan Kara   fsnotify: Move lo...
639
640
  	if (mark->mask)
  		fsnotify_recalc_mask(mark->connector);
5444e2981   Eric Paris   fsnotify: split g...
641
642
643
  
  	return ret;
  err:
9cf90cef3   Jan Kara   fsnotify: Protect...
644
  	spin_lock(&mark->lock);
11375145a   Jan Kara   fsnotify: Move qu...
645
646
  	mark->flags &= ~(FSNOTIFY_MARK_FLAG_ALIVE |
  			 FSNOTIFY_MARK_FLAG_ATTACHED);
5444e2981   Eric Paris   fsnotify: split g...
647
  	list_del_init(&mark->g_list);
9cf90cef3   Jan Kara   fsnotify: Protect...
648
  	spin_unlock(&mark->lock);
5444e2981   Eric Paris   fsnotify: split g...
649
  	atomic_dec(&group->num_marks);
5444e2981   Eric Paris   fsnotify: split g...
650

11375145a   Jan Kara   fsnotify: Move qu...
651
  	fsnotify_put_mark(mark);
5444e2981   Eric Paris   fsnotify: split g...
652
653
  	return ret;
  }
b812a9f58   Amir Goldstein   fsnotify: pass co...
654
  int fsnotify_add_mark(struct fsnotify_mark *mark, fsnotify_connp_t *connp,
77115225a   Amir Goldstein   fanotify: cache f...
655
  		      unsigned int type, int allow_dups, __kernel_fsid_t *fsid)
d5a335b84   Lino Sanfilippo   fsnotify: introdu...
656
657
  {
  	int ret;
7b1293234   Jan Kara   fsnotify: Add gro...
658
  	struct fsnotify_group *group = mark->group;
d5a335b84   Lino Sanfilippo   fsnotify: introdu...
659
  	mutex_lock(&group->mark_mutex);
77115225a   Amir Goldstein   fanotify: cache f...
660
  	ret = fsnotify_add_mark_locked(mark, connp, type, allow_dups, fsid);
d5a335b84   Lino Sanfilippo   fsnotify: introdu...
661
662
663
  	mutex_unlock(&group->mark_mutex);
  	return ret;
  }
b72679ee8   Trond Myklebust   notify: export sy...
664
  EXPORT_SYMBOL_GPL(fsnotify_add_mark);
d5a335b84   Lino Sanfilippo   fsnotify: introdu...
665

5444e2981   Eric Paris   fsnotify: split g...
666
  /*
0809ab69a   Jan Kara   fsnotify: unify i...
667
668
669
   * 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.
   */
9b6e54345   Amir Goldstein   fsnotify: use typ...
670
671
  struct fsnotify_mark *fsnotify_find_mark(fsnotify_connp_t *connp,
  					 struct fsnotify_group *group)
0809ab69a   Jan Kara   fsnotify: unify i...
672
  {
08991e83b   Jan Kara   fsnotify: Free fs...
673
  	struct fsnotify_mark_connector *conn;
0809ab69a   Jan Kara   fsnotify: unify i...
674
  	struct fsnotify_mark *mark;
08991e83b   Jan Kara   fsnotify: Free fs...
675
  	conn = fsnotify_grab_connector(connp);
9dd813c15   Jan Kara   fsnotify: Move ma...
676
677
678
679
  	if (!conn)
  		return NULL;
  
  	hlist_for_each_entry(mark, &conn->list, obj_list) {
6b3f05d24   Jan Kara   fsnotify: Detach ...
680
681
  		if (mark->group == group &&
  		    (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED)) {
0809ab69a   Jan Kara   fsnotify: unify i...
682
  			fsnotify_get_mark(mark);
04662cab5   Jan Kara   fsnotify: Lock ob...
683
  			spin_unlock(&conn->lock);
0809ab69a   Jan Kara   fsnotify: unify i...
684
685
686
  			return mark;
  		}
  	}
04662cab5   Jan Kara   fsnotify: Lock ob...
687
  	spin_unlock(&conn->lock);
0809ab69a   Jan Kara   fsnotify: unify i...
688
689
  	return NULL;
  }
b72679ee8   Trond Myklebust   notify: export sy...
690
  EXPORT_SYMBOL_GPL(fsnotify_find_mark);
0809ab69a   Jan Kara   fsnotify: unify i...
691

d6f7b98bc   Amir Goldstein   fsnotify: use typ...
692
  /* Clear any marks in a group with given type mask */
18f2e0d3a   Jan Kara   fsnotify: Rename ...
693
  void fsnotify_clear_marks_by_group(struct fsnotify_group *group,
d6f7b98bc   Amir Goldstein   fsnotify: use typ...
694
  				   unsigned int type_mask)
5444e2981   Eric Paris   fsnotify: split g...
695
696
  {
  	struct fsnotify_mark *lmark, *mark;
8f2f3eb59   Jan Kara   fsnotify: fix oop...
697
  	LIST_HEAD(to_free);
2e37c6ca8   Jan Kara   fsnotify: Remove ...
698
  	struct list_head *head = &to_free;
5444e2981   Eric Paris   fsnotify: split g...
699

2e37c6ca8   Jan Kara   fsnotify: Remove ...
700
  	/* Skip selection step if we want to clear all marks. */
d6f7b98bc   Amir Goldstein   fsnotify: use typ...
701
  	if (type_mask == FSNOTIFY_OBJ_ALL_TYPES_MASK) {
2e37c6ca8   Jan Kara   fsnotify: Remove ...
702
703
704
  		head = &group->marks_list;
  		goto clear;
  	}
8f2f3eb59   Jan Kara   fsnotify: fix oop...
705
706
707
708
709
710
711
712
713
  	/*
  	 * We have to be really careful here. Anytime we drop mark_mutex, e.g.
  	 * fsnotify_clear_marks_by_inode() can come and free marks. Even in our
  	 * to_free list so we have to use mark_mutex even when accessing that
  	 * list. And freeing mark requires us to drop mark_mutex. So we can
  	 * reliably free only the first mark in the list. That's why we first
  	 * move marks to free to to_free list in one go and then free marks in
  	 * to_free list one by one.
  	 */
6960b0d90   Lino Sanfilippo   fsnotify: change ...
714
  	mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
5444e2981   Eric Paris   fsnotify: split g...
715
  	list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) {
d6f7b98bc   Amir Goldstein   fsnotify: use typ...
716
  		if ((1U << mark->connector->type) & type_mask)
8f2f3eb59   Jan Kara   fsnotify: fix oop...
717
  			list_move(&mark->g_list, &to_free);
5444e2981   Eric Paris   fsnotify: split g...
718
  	}
986ab0980   Lino Sanfilippo   fsnotify: use a m...
719
  	mutex_unlock(&group->mark_mutex);
8f2f3eb59   Jan Kara   fsnotify: fix oop...
720

2e37c6ca8   Jan Kara   fsnotify: Remove ...
721
  clear:
8f2f3eb59   Jan Kara   fsnotify: fix oop...
722
723
  	while (1) {
  		mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
2e37c6ca8   Jan Kara   fsnotify: Remove ...
724
  		if (list_empty(head)) {
8f2f3eb59   Jan Kara   fsnotify: fix oop...
725
726
727
  			mutex_unlock(&group->mark_mutex);
  			break;
  		}
2e37c6ca8   Jan Kara   fsnotify: Remove ...
728
  		mark = list_first_entry(head, struct fsnotify_mark, g_list);
8f2f3eb59   Jan Kara   fsnotify: fix oop...
729
  		fsnotify_get_mark(mark);
4712e722f   Jan Kara   fsnotify: get rid...
730
  		fsnotify_detach_mark(mark);
8f2f3eb59   Jan Kara   fsnotify: fix oop...
731
  		mutex_unlock(&group->mark_mutex);
4712e722f   Jan Kara   fsnotify: get rid...
732
  		fsnotify_free_mark(mark);
8f2f3eb59   Jan Kara   fsnotify: fix oop...
733
734
  		fsnotify_put_mark(mark);
  	}
5444e2981   Eric Paris   fsnotify: split g...
735
  }
9b6e54345   Amir Goldstein   fsnotify: use typ...
736
737
  /* Destroy all marks attached to an object via connector */
  void fsnotify_destroy_marks(fsnotify_connp_t *connp)
0810b4f9f   Jan Kara   fsnotify: Move fs...
738
  {
08991e83b   Jan Kara   fsnotify: Free fs...
739
  	struct fsnotify_mark_connector *conn;
6b3f05d24   Jan Kara   fsnotify: Detach ...
740
  	struct fsnotify_mark *mark, *old_mark = NULL;
721fb6fbf   Jan Kara   fsnotify: Fix bus...
741
742
  	void *objp;
  	unsigned int type;
0810b4f9f   Jan Kara   fsnotify: Move fs...
743

6b3f05d24   Jan Kara   fsnotify: Detach ...
744
745
746
747
748
749
750
751
752
753
754
  	conn = fsnotify_grab_connector(connp);
  	if (!conn)
  		return;
  	/*
  	 * We have to be careful since we can race with e.g.
  	 * fsnotify_clear_marks_by_group() and once we drop the conn->lock, the
  	 * list can get modified. However we are holding mark reference and
  	 * thus our mark cannot be removed from obj_list so we can continue
  	 * iteration after regaining conn->lock.
  	 */
  	hlist_for_each_entry(mark, &conn->list, obj_list) {
0810b4f9f   Jan Kara   fsnotify: Move fs...
755
  		fsnotify_get_mark(mark);
04662cab5   Jan Kara   fsnotify: Lock ob...
756
  		spin_unlock(&conn->lock);
6b3f05d24   Jan Kara   fsnotify: Detach ...
757
758
759
  		if (old_mark)
  			fsnotify_put_mark(old_mark);
  		old_mark = mark;
0810b4f9f   Jan Kara   fsnotify: Move fs...
760
  		fsnotify_destroy_mark(mark, mark->group);
6b3f05d24   Jan Kara   fsnotify: Detach ...
761
  		spin_lock(&conn->lock);
0810b4f9f   Jan Kara   fsnotify: Move fs...
762
  	}
6b3f05d24   Jan Kara   fsnotify: Detach ...
763
764
765
766
767
  	/*
  	 * Detach list from object now so that we don't pin inode until all
  	 * mark references get dropped. It would lead to strange results such
  	 * as delaying inode deletion or blocking unmount.
  	 */
721fb6fbf   Jan Kara   fsnotify: Fix bus...
768
  	objp = fsnotify_detach_connector_from_object(conn, &type);
6b3f05d24   Jan Kara   fsnotify: Detach ...
769
770
771
  	spin_unlock(&conn->lock);
  	if (old_mark)
  		fsnotify_put_mark(old_mark);
721fb6fbf   Jan Kara   fsnotify: Fix bus...
772
  	fsnotify_drop_object(type, objp);
0810b4f9f   Jan Kara   fsnotify: Move fs...
773
  }
5444e2981   Eric Paris   fsnotify: split g...
774
775
776
777
  /*
   * Nothing fancy, just initialize lists and locks and counters.
   */
  void fsnotify_init_mark(struct fsnotify_mark *mark,
054c636e5   Jan Kara   fsnotify: Move ->...
778
  			struct fsnotify_group *group)
5444e2981   Eric Paris   fsnotify: split g...
779
  {
ba643f04c   Eric Paris   fsnotify: clear m...
780
  	memset(mark, 0, sizeof(*mark));
5444e2981   Eric Paris   fsnotify: split g...
781
  	spin_lock_init(&mark->lock);
ab97f8732   Elena Reshetova   fsnotify: convert...
782
  	refcount_set(&mark->refcnt, 1);
7b1293234   Jan Kara   fsnotify: Add gro...
783
784
  	fsnotify_get_group(group);
  	mark->group = group;
b1da6a518   Jan Kara   fsnotify: Fix NUL...
785
  	WRITE_ONCE(mark->connector, NULL);
5444e2981   Eric Paris   fsnotify: split g...
786
  }
b72679ee8   Trond Myklebust   notify: export sy...
787
  EXPORT_SYMBOL_GPL(fsnotify_init_mark);
13d34ac6e   Jeff Layton   Revert "fsnotify:...
788

35e481761   Jan Kara   fsnotify: avoid s...
789
790
791
792
  /*
   * Destroy all marks in destroy_list, waits for SRCU period to finish before
   * actually freeing marks.
   */
f09b04a03   Jan Kara   fsnotify: Remove ...
793
  static void fsnotify_mark_destroy_workfn(struct work_struct *work)
13d34ac6e   Jeff Layton   Revert "fsnotify:...
794
795
796
  {
  	struct fsnotify_mark *mark, *next;
  	struct list_head private_destroy_list;
0918f1c30   Jeff Layton   fsnotify: turn fs...
797
798
799
800
  	spin_lock(&destroy_lock);
  	/* exchange the list head */
  	list_replace_init(&destroy_list, &private_destroy_list);
  	spin_unlock(&destroy_lock);
13d34ac6e   Jeff Layton   Revert "fsnotify:...
801

0918f1c30   Jeff Layton   fsnotify: turn fs...
802
  	synchronize_srcu(&fsnotify_mark_srcu);
13d34ac6e   Jeff Layton   Revert "fsnotify:...
803

0918f1c30   Jeff Layton   fsnotify: turn fs...
804
805
  	list_for_each_entry_safe(mark, next, &private_destroy_list, g_list) {
  		list_del_init(&mark->g_list);
6b3f05d24   Jan Kara   fsnotify: Detach ...
806
  		fsnotify_final_mark_destroy(mark);
13d34ac6e   Jeff Layton   Revert "fsnotify:...
807
  	}
13d34ac6e   Jeff Layton   Revert "fsnotify:...
808
  }
35e481761   Jan Kara   fsnotify: avoid s...
809

f09b04a03   Jan Kara   fsnotify: Remove ...
810
811
  /* Wait for all marks queued for destruction to be actually destroyed */
  void fsnotify_wait_marks_destroyed(void)
35e481761   Jan Kara   fsnotify: avoid s...
812
  {
f09b04a03   Jan Kara   fsnotify: Remove ...
813
  	flush_delayed_work(&reaper_work);
35e481761   Jan Kara   fsnotify: avoid s...
814
  }
b72679ee8   Trond Myklebust   notify: export sy...
815
  EXPORT_SYMBOL_GPL(fsnotify_wait_marks_destroyed);