Linux Audio

Check our new training course

Loading...
v3.15
  1/*
  2 *  Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com>
  3 *
  4 *  This program is free software; you can redistribute it and/or modify
  5 *  it under the terms of the GNU General Public License as published by
  6 *  the Free Software Foundation; either version 2, or (at your option)
  7 *  any later version.
  8 *
  9 *  This program is distributed in the hope that it will be useful,
 10 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 11 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12 *  GNU General Public License for more details.
 13 *
 14 *  You should have received a copy of the GNU General Public License
 15 *  along with this program; see the file COPYING.  If not, write to
 16 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 17 */
 18
 19/*
 20 * fsnotify inode mark locking/lifetime/and refcnting
 21 *
 22 * REFCNT:
 23 * The group->recnt and mark->refcnt tell how many "things" in the kernel
 24 * currently are referencing the objects. Both kind of objects typically will
 25 * live inside the kernel with a refcnt of 2, one for its creation and one for
 26 * the reference a group and a mark hold to each other.
 27 * If you are holding the appropriate locks, you can take a reference and the
 28 * object itself is guaranteed to survive until the reference is dropped.
 29 *
 30 * LOCKING:
 31 * There are 3 locks involved with fsnotify inode marks and they MUST be taken
 32 * in order as follows:
 33 *
 34 * group->mark_mutex
 35 * mark->lock
 
 36 * inode->i_lock
 37 *
 38 * group->mark_mutex protects the marks_list anchored inside a given group and
 39 * each mark is hooked via the g_list.  It also protects the groups private
 40 * data (i.e group limits).
 41
 42 * mark->lock protects the marks attributes like its masks and flags.
 43 * Furthermore it protects the access to a reference of the group that the mark
 44 * is assigned to as well as the access to a reference of the inode/vfsmount
 45 * that is being watched by the mark.
 46 *
 47 * inode->i_lock protects the i_fsnotify_marks list anchored inside a
 48 * given inode and each mark is hooked via the i_list. (and sorta the
 49 * free_i_list)
 50 *
 51 *
 52 * LIFETIME:
 53 * Inode marks survive between when they are added to an inode and when their
 54 * refcnt==0.
 55 *
 56 * The inode mark can be cleared for a number of different reasons including:
 57 * - The inode is unlinked for the last time.  (fsnotify_inode_remove)
 58 * - The inode is being evicted from cache. (fsnotify_inode_delete)
 59 * - The fs the inode is on is unmounted.  (fsnotify_inode_delete/fsnotify_unmount_inodes)
 60 * - Something explicitly requests that it be removed.  (fsnotify_destroy_mark)
 61 * - The fsnotify_group associated with the mark is going away and all such marks
 62 *   need to be cleaned up. (fsnotify_clear_marks_by_group)
 63 *
 64 * Worst case we are given an inode and need to clean up all the marks on that
 65 * inode.  We take i_lock and walk the i_fsnotify_marks safely.  For each
 66 * mark on the list we take a reference (so the mark can't disappear under us).
 67 * We remove that mark form the inode's list of marks and we add this mark to a
 68 * private list anchored on the stack using i_free_list; we walk i_free_list
 69 * and before we destroy the mark we make sure that we dont race with a
 70 * concurrent destroy_group by getting a ref to the marks group and taking the
 71 * groups mutex.
 72
 
 
 
 
 
 
 
 73 * Very similarly for freeing by group, except we use free_g_list.
 74 *
 75 * This has the very interesting property of being able to run concurrently with
 76 * any (or all) other directions.
 77 */
 78
 79#include <linux/fs.h>
 80#include <linux/init.h>
 81#include <linux/kernel.h>
 82#include <linux/kthread.h>
 83#include <linux/module.h>
 84#include <linux/mutex.h>
 85#include <linux/slab.h>
 86#include <linux/spinlock.h>
 87#include <linux/srcu.h>
 88
 89#include <linux/atomic.h>
 90
 91#include <linux/fsnotify_backend.h>
 92#include "fsnotify.h"
 93
 94struct srcu_struct fsnotify_mark_srcu;
 95static DEFINE_SPINLOCK(destroy_lock);
 96static LIST_HEAD(destroy_list);
 97static DECLARE_WAIT_QUEUE_HEAD(destroy_waitq);
 98
 99void fsnotify_get_mark(struct fsnotify_mark *mark)
100{
101	atomic_inc(&mark->refcnt);
102}
103
104void fsnotify_put_mark(struct fsnotify_mark *mark)
105{
106	if (atomic_dec_and_test(&mark->refcnt)) {
107		if (mark->group)
108			fsnotify_put_group(mark->group);
109		mark->free_mark(mark);
110	}
111}
112
113/*
114 * Any time a mark is getting freed we end up here.
115 * The caller had better be holding a reference to this mark so we don't actually
116 * do the final put under the mark->lock
117 */
118void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark,
119				  struct fsnotify_group *group)
120{
 
121	struct inode *inode = NULL;
122
123	BUG_ON(!mutex_is_locked(&group->mark_mutex));
124
125	spin_lock(&mark->lock);
126
 
 
127	/* something else already called this function on this mark */
128	if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) {
129		spin_unlock(&mark->lock);
130		return;
131	}
132
133	mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE;
134
 
 
135	if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) {
136		inode = mark->i.inode;
137		fsnotify_destroy_inode_mark(mark);
138	} else if (mark->flags & FSNOTIFY_MARK_FLAG_VFSMOUNT)
139		fsnotify_destroy_vfsmount_mark(mark);
140	else
141		BUG();
142
143	list_del_init(&mark->g_list);
144
 
145	spin_unlock(&mark->lock);
146
147	if (inode && (mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED))
148		iput(inode);
149	/* release lock temporarily */
150	mutex_unlock(&group->mark_mutex);
151
152	spin_lock(&destroy_lock);
153	list_add(&mark->destroy_list, &destroy_list);
154	spin_unlock(&destroy_lock);
155	wake_up(&destroy_waitq);
156	/*
157	 * We don't necessarily have a ref on mark from caller so the above destroy
158	 * may have actually freed it, unless this group provides a 'freeing_mark'
159	 * function which must be holding a reference.
160	 */
161
162	/*
163	 * Some groups like to know that marks are being freed.  This is a
164	 * callback to the group function to let it know that this mark
165	 * is being freed.
166	 */
167	if (group->ops->freeing_mark)
168		group->ops->freeing_mark(mark, group);
169
170	/*
171	 * __fsnotify_update_child_dentry_flags(inode);
172	 *
173	 * I really want to call that, but we can't, we have no idea if the inode
174	 * still exists the second we drop the mark->lock.
175	 *
176	 * The next time an event arrive to this inode from one of it's children
177	 * __fsnotify_parent will see that the inode doesn't care about it's
178	 * children and will update all of these flags then.  So really this
179	 * is just a lazy update (and could be a perf win...)
180	 */
181
182	atomic_dec(&group->num_marks);
 
183
184	mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
185}
 
 
186
187void fsnotify_destroy_mark(struct fsnotify_mark *mark,
188			   struct fsnotify_group *group)
189{
190	mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
191	fsnotify_destroy_mark_locked(mark, group);
192	mutex_unlock(&group->mark_mutex);
 
193}
194
195void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask)
196{
197	assert_spin_locked(&mark->lock);
198
199	mark->mask = mask;
200
201	if (mark->flags & FSNOTIFY_MARK_FLAG_INODE)
202		fsnotify_set_inode_mark_mask_locked(mark, mask);
203}
204
205void fsnotify_set_mark_ignored_mask_locked(struct fsnotify_mark *mark, __u32 mask)
206{
207	assert_spin_locked(&mark->lock);
208
209	mark->ignored_mask = mask;
210}
211
212/*
213 * Attach an initialized mark to a given group and fs object.
214 * These marks may be used for the fsnotify backend to determine which
215 * event types should be delivered to which group.
216 */
217int fsnotify_add_mark_locked(struct fsnotify_mark *mark,
218			     struct fsnotify_group *group, struct inode *inode,
219			     struct vfsmount *mnt, int allow_dups)
220{
221	int ret = 0;
222
223	BUG_ON(inode && mnt);
224	BUG_ON(!inode && !mnt);
225	BUG_ON(!mutex_is_locked(&group->mark_mutex));
226
227	/*
228	 * LOCKING ORDER!!!!
229	 * group->mark_mutex
230	 * mark->lock
 
231	 * inode->i_lock
232	 */
233	spin_lock(&mark->lock);
 
 
234	mark->flags |= FSNOTIFY_MARK_FLAG_ALIVE;
235
236	fsnotify_get_group(group);
237	mark->group = group;
238	list_add(&mark->g_list, &group->marks_list);
239	atomic_inc(&group->num_marks);
240	fsnotify_get_mark(mark); /* for i_list and g_list */
241
242	if (inode) {
243		ret = fsnotify_add_inode_mark(mark, group, inode, allow_dups);
244		if (ret)
245			goto err;
246	} else if (mnt) {
247		ret = fsnotify_add_vfsmount_mark(mark, group, mnt, allow_dups);
248		if (ret)
249			goto err;
250	} else {
251		BUG();
252	}
253
 
 
254	/* this will pin the object if appropriate */
255	fsnotify_set_mark_mask_locked(mark, mark->mask);
 
256	spin_unlock(&mark->lock);
257
258	if (inode)
259		__fsnotify_update_child_dentry_flags(inode);
260
261	return ret;
262err:
263	mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE;
264	list_del_init(&mark->g_list);
265	fsnotify_put_group(group);
266	mark->group = NULL;
267	atomic_dec(&group->num_marks);
268
 
269	spin_unlock(&mark->lock);
270
271	spin_lock(&destroy_lock);
272	list_add(&mark->destroy_list, &destroy_list);
273	spin_unlock(&destroy_lock);
274	wake_up(&destroy_waitq);
275
276	return ret;
277}
278
279int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group,
280		      struct inode *inode, struct vfsmount *mnt, int allow_dups)
281{
282	int ret;
283	mutex_lock(&group->mark_mutex);
284	ret = fsnotify_add_mark_locked(mark, group, inode, mnt, allow_dups);
285	mutex_unlock(&group->mark_mutex);
286	return ret;
287}
288
289/*
290 * clear any marks in a group in which mark->flags & flags is true
291 */
292void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group,
293					 unsigned int flags)
294{
295	struct fsnotify_mark *lmark, *mark;
 
296
297	mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
298	list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) {
299		if (mark->flags & flags) {
 
 
300			fsnotify_get_mark(mark);
301			fsnotify_destroy_mark_locked(mark, group);
302			fsnotify_put_mark(mark);
303		}
304	}
305	mutex_unlock(&group->mark_mutex);
 
 
 
 
 
306}
307
308/*
309 * Given a group, destroy all of the marks associated with that group.
310 */
311void fsnotify_clear_marks_by_group(struct fsnotify_group *group)
312{
313	fsnotify_clear_marks_by_group_flags(group, (unsigned int)-1);
314}
315
316void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *old)
317{
318	assert_spin_locked(&old->lock);
319	new->i.inode = old->i.inode;
320	new->m.mnt = old->m.mnt;
321	if (old->group)
322		fsnotify_get_group(old->group);
323	new->group = old->group;
324	new->mask = old->mask;
325	new->free_mark = old->free_mark;
326}
327
328/*
329 * Nothing fancy, just initialize lists and locks and counters.
330 */
331void fsnotify_init_mark(struct fsnotify_mark *mark,
332			void (*free_mark)(struct fsnotify_mark *mark))
333{
334	memset(mark, 0, sizeof(*mark));
335	spin_lock_init(&mark->lock);
336	atomic_set(&mark->refcnt, 1);
337	mark->free_mark = free_mark;
338}
339
340static int fsnotify_mark_destroy(void *ignored)
341{
342	struct fsnotify_mark *mark, *next;
343	LIST_HEAD(private_destroy_list);
344
345	for (;;) {
346		spin_lock(&destroy_lock);
347		/* exchange the list head */
348		list_replace_init(&destroy_list, &private_destroy_list);
349		spin_unlock(&destroy_lock);
350
351		synchronize_srcu(&fsnotify_mark_srcu);
352
353		list_for_each_entry_safe(mark, next, &private_destroy_list, destroy_list) {
354			list_del_init(&mark->destroy_list);
355			fsnotify_put_mark(mark);
356		}
357
358		wait_event_interruptible(destroy_waitq, !list_empty(&destroy_list));
359	}
360
361	return 0;
362}
363
364static int __init fsnotify_mark_init(void)
365{
366	struct task_struct *thread;
367
368	thread = kthread_run(fsnotify_mark_destroy, NULL,
369			     "fsnotify_mark");
370	if (IS_ERR(thread))
371		panic("unable to start fsnotify mark destruction thread.");
372
373	return 0;
374}
375device_initcall(fsnotify_mark_init);
v3.5.6
  1/*
  2 *  Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com>
  3 *
  4 *  This program is free software; you can redistribute it and/or modify
  5 *  it under the terms of the GNU General Public License as published by
  6 *  the Free Software Foundation; either version 2, or (at your option)
  7 *  any later version.
  8 *
  9 *  This program is distributed in the hope that it will be useful,
 10 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 11 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12 *  GNU General Public License for more details.
 13 *
 14 *  You should have received a copy of the GNU General Public License
 15 *  along with this program; see the file COPYING.  If not, write to
 16 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 17 */
 18
 19/*
 20 * fsnotify inode mark locking/lifetime/and refcnting
 21 *
 22 * REFCNT:
 23 * The mark->refcnt tells how many "things" in the kernel currently are
 24 * referencing this object.  The object typically will live inside the kernel
 25 * with a refcnt of 2, one for each list it is on (i_list, g_list).  Any task
 26 * which can find this object holding the appropriete locks, can take a reference
 27 * and the object itself is guaranteed to survive until the reference is dropped.
 
 28 *
 29 * LOCKING:
 30 * There are 3 spinlocks involved with fsnotify inode marks and they MUST
 31 * be taken in order as follows:
 32 *
 
 33 * mark->lock
 34 * group->mark_lock
 35 * inode->i_lock
 36 *
 37 * mark->lock protects 2 things, mark->group and mark->inode.  You must hold
 38 * that lock to dereference either of these things (they could be NULL even with
 39 * the lock)
 40 *
 41 * group->mark_lock protects the marks_list anchored inside a given group
 42 * and each mark is hooked via the g_list.  It also sorta protects the
 43 * free_g_list, which when used is anchored by a private list on the stack of the
 44 * task which held the group->mark_lock.
 45 *
 46 * inode->i_lock protects the i_fsnotify_marks list anchored inside a
 47 * given inode and each mark is hooked via the i_list. (and sorta the
 48 * free_i_list)
 49 *
 50 *
 51 * LIFETIME:
 52 * Inode marks survive between when they are added to an inode and when their
 53 * refcnt==0.
 54 *
 55 * The inode mark can be cleared for a number of different reasons including:
 56 * - The inode is unlinked for the last time.  (fsnotify_inode_remove)
 57 * - The inode is being evicted from cache. (fsnotify_inode_delete)
 58 * - The fs the inode is on is unmounted.  (fsnotify_inode_delete/fsnotify_unmount_inodes)
 59 * - Something explicitly requests that it be removed.  (fsnotify_destroy_mark)
 60 * - The fsnotify_group associated with the mark is going away and all such marks
 61 *   need to be cleaned up. (fsnotify_clear_marks_by_group)
 62 *
 63 * Worst case we are given an inode and need to clean up all the marks on that
 64 * inode.  We take i_lock and walk the i_fsnotify_marks safely.  For each
 65 * mark on the list we take a reference (so the mark can't disappear under us).
 66 * We remove that mark form the inode's list of marks and we add this mark to a
 67 * private list anchored on the stack using i_free_list;  At this point we no
 68 * longer fear anything finding the mark using the inode's list of marks.
 69 *
 70 * We can safely and locklessly run the private list on the stack of everything
 71 * we just unattached from the original inode.  For each mark on the private list
 72 * we grab the mark-> and can thus dereference mark->group and mark->inode.  If
 73 * we see the group and inode are not NULL we take those locks.  Now holding all
 74 * 3 locks we can completely remove the mark from other tasks finding it in the
 75 * future.  Remember, 10 things might already be referencing this mark, but they
 76 * better be holding a ref.  We drop our reference we took before we unhooked it
 77 * from the inode.  When the ref hits 0 we can free the mark.
 78 *
 79 * Very similarly for freeing by group, except we use free_g_list.
 80 *
 81 * This has the very interesting property of being able to run concurrently with
 82 * any (or all) other directions.
 83 */
 84
 85#include <linux/fs.h>
 86#include <linux/init.h>
 87#include <linux/kernel.h>
 88#include <linux/kthread.h>
 89#include <linux/module.h>
 90#include <linux/mutex.h>
 91#include <linux/slab.h>
 92#include <linux/spinlock.h>
 93#include <linux/srcu.h>
 94
 95#include <linux/atomic.h>
 96
 97#include <linux/fsnotify_backend.h>
 98#include "fsnotify.h"
 99
100struct srcu_struct fsnotify_mark_srcu;
101static DEFINE_SPINLOCK(destroy_lock);
102static LIST_HEAD(destroy_list);
103static DECLARE_WAIT_QUEUE_HEAD(destroy_waitq);
104
105void fsnotify_get_mark(struct fsnotify_mark *mark)
106{
107	atomic_inc(&mark->refcnt);
108}
109
110void fsnotify_put_mark(struct fsnotify_mark *mark)
111{
112	if (atomic_dec_and_test(&mark->refcnt))
 
 
113		mark->free_mark(mark);
 
114}
115
116/*
117 * Any time a mark is getting freed we end up here.
118 * The caller had better be holding a reference to this mark so we don't actually
119 * do the final put under the mark->lock
120 */
121void fsnotify_destroy_mark(struct fsnotify_mark *mark)
 
122{
123	struct fsnotify_group *group;
124	struct inode *inode = NULL;
125
 
 
126	spin_lock(&mark->lock);
127
128	group = mark->group;
129
130	/* something else already called this function on this mark */
131	if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) {
132		spin_unlock(&mark->lock);
133		return;
134	}
135
136	mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE;
137
138	spin_lock(&group->mark_lock);
139
140	if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) {
141		inode = mark->i.inode;
142		fsnotify_destroy_inode_mark(mark);
143	} else if (mark->flags & FSNOTIFY_MARK_FLAG_VFSMOUNT)
144		fsnotify_destroy_vfsmount_mark(mark);
145	else
146		BUG();
147
148	list_del_init(&mark->g_list);
149
150	spin_unlock(&group->mark_lock);
151	spin_unlock(&mark->lock);
152
 
 
 
 
 
153	spin_lock(&destroy_lock);
154	list_add(&mark->destroy_list, &destroy_list);
155	spin_unlock(&destroy_lock);
156	wake_up(&destroy_waitq);
 
 
 
 
 
157
158	/*
159	 * Some groups like to know that marks are being freed.  This is a
160	 * callback to the group function to let it know that this mark
161	 * is being freed.
162	 */
163	if (group->ops->freeing_mark)
164		group->ops->freeing_mark(mark, group);
165
166	/*
167	 * __fsnotify_update_child_dentry_flags(inode);
168	 *
169	 * I really want to call that, but we can't, we have no idea if the inode
170	 * still exists the second we drop the mark->lock.
171	 *
172	 * The next time an event arrive to this inode from one of it's children
173	 * __fsnotify_parent will see that the inode doesn't care about it's
174	 * children and will update all of these flags then.  So really this
175	 * is just a lazy update (and could be a perf win...)
176	 */
177
178	if (inode && (mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED))
179		iput(inode);
180
181	/*
182	 * We don't necessarily have a ref on mark from caller so the above iput
183	 * may have already destroyed it.  Don't touch from now on.
184	 */
185
186	/*
187	 * it's possible that this group tried to destroy itself, but this
188	 * this mark was simultaneously being freed by inode.  If that's the
189	 * case, we finish freeing the group here.
190	 */
191	if (unlikely(atomic_dec_and_test(&group->num_marks)))
192		fsnotify_final_destroy_group(group);
193}
194
195void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask)
196{
197	assert_spin_locked(&mark->lock);
198
199	mark->mask = mask;
200
201	if (mark->flags & FSNOTIFY_MARK_FLAG_INODE)
202		fsnotify_set_inode_mark_mask_locked(mark, mask);
203}
204
205void fsnotify_set_mark_ignored_mask_locked(struct fsnotify_mark *mark, __u32 mask)
206{
207	assert_spin_locked(&mark->lock);
208
209	mark->ignored_mask = mask;
210}
211
212/*
213 * Attach an initialized mark to a given group and fs object.
214 * These marks may be used for the fsnotify backend to determine which
215 * event types should be delivered to which group.
216 */
217int fsnotify_add_mark(struct fsnotify_mark *mark,
218		      struct fsnotify_group *group, struct inode *inode,
219		      struct vfsmount *mnt, int allow_dups)
220{
221	int ret = 0;
222
223	BUG_ON(inode && mnt);
224	BUG_ON(!inode && !mnt);
 
225
226	/*
227	 * LOCKING ORDER!!!!
 
228	 * mark->lock
229	 * group->mark_lock
230	 * inode->i_lock
231	 */
232	spin_lock(&mark->lock);
233	spin_lock(&group->mark_lock);
234
235	mark->flags |= FSNOTIFY_MARK_FLAG_ALIVE;
236
 
237	mark->group = group;
238	list_add(&mark->g_list, &group->marks_list);
239	atomic_inc(&group->num_marks);
240	fsnotify_get_mark(mark); /* for i_list and g_list */
241
242	if (inode) {
243		ret = fsnotify_add_inode_mark(mark, group, inode, allow_dups);
244		if (ret)
245			goto err;
246	} else if (mnt) {
247		ret = fsnotify_add_vfsmount_mark(mark, group, mnt, allow_dups);
248		if (ret)
249			goto err;
250	} else {
251		BUG();
252	}
253
254	spin_unlock(&group->mark_lock);
255
256	/* this will pin the object if appropriate */
257	fsnotify_set_mark_mask_locked(mark, mark->mask);
258
259	spin_unlock(&mark->lock);
260
261	if (inode)
262		__fsnotify_update_child_dentry_flags(inode);
263
264	return ret;
265err:
266	mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE;
267	list_del_init(&mark->g_list);
 
268	mark->group = NULL;
269	atomic_dec(&group->num_marks);
270
271	spin_unlock(&group->mark_lock);
272	spin_unlock(&mark->lock);
273
274	spin_lock(&destroy_lock);
275	list_add(&mark->destroy_list, &destroy_list);
276	spin_unlock(&destroy_lock);
277	wake_up(&destroy_waitq);
278
279	return ret;
280}
281
 
 
 
 
 
 
 
 
 
 
282/*
283 * clear any marks in a group in which mark->flags & flags is true
284 */
285void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group,
286					 unsigned int flags)
287{
288	struct fsnotify_mark *lmark, *mark;
289	LIST_HEAD(free_list);
290
291	spin_lock(&group->mark_lock);
292	list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) {
293		if (mark->flags & flags) {
294			list_add(&mark->free_g_list, &free_list);
295			list_del_init(&mark->g_list);
296			fsnotify_get_mark(mark);
 
 
297		}
298	}
299	spin_unlock(&group->mark_lock);
300
301	list_for_each_entry_safe(mark, lmark, &free_list, free_g_list) {
302		fsnotify_destroy_mark(mark);
303		fsnotify_put_mark(mark);
304	}
305}
306
307/*
308 * Given a group, destroy all of the marks associated with that group.
309 */
310void fsnotify_clear_marks_by_group(struct fsnotify_group *group)
311{
312	fsnotify_clear_marks_by_group_flags(group, (unsigned int)-1);
313}
314
315void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *old)
316{
317	assert_spin_locked(&old->lock);
318	new->i.inode = old->i.inode;
319	new->m.mnt = old->m.mnt;
 
 
320	new->group = old->group;
321	new->mask = old->mask;
322	new->free_mark = old->free_mark;
323}
324
325/*
326 * Nothing fancy, just initialize lists and locks and counters.
327 */
328void fsnotify_init_mark(struct fsnotify_mark *mark,
329			void (*free_mark)(struct fsnotify_mark *mark))
330{
331	memset(mark, 0, sizeof(*mark));
332	spin_lock_init(&mark->lock);
333	atomic_set(&mark->refcnt, 1);
334	mark->free_mark = free_mark;
335}
336
337static int fsnotify_mark_destroy(void *ignored)
338{
339	struct fsnotify_mark *mark, *next;
340	LIST_HEAD(private_destroy_list);
341
342	for (;;) {
343		spin_lock(&destroy_lock);
344		/* exchange the list head */
345		list_replace_init(&destroy_list, &private_destroy_list);
346		spin_unlock(&destroy_lock);
347
348		synchronize_srcu(&fsnotify_mark_srcu);
349
350		list_for_each_entry_safe(mark, next, &private_destroy_list, destroy_list) {
351			list_del_init(&mark->destroy_list);
352			fsnotify_put_mark(mark);
353		}
354
355		wait_event_interruptible(destroy_waitq, !list_empty(&destroy_list));
356	}
357
358	return 0;
359}
360
361static int __init fsnotify_mark_init(void)
362{
363	struct task_struct *thread;
364
365	thread = kthread_run(fsnotify_mark_destroy, NULL,
366			     "fsnotify_mark");
367	if (IS_ERR(thread))
368		panic("unable to start fsnotify mark destruction thread.");
369
370	return 0;
371}
372device_initcall(fsnotify_mark_init);