Blame view

fs/notify/notification.c 13.3 KB
90586523e   Eric Paris   fsnotify: unified...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  /*
   *  Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com>
   *
   *  This program is free software; you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation; either version 2, or (at your option)
   *  any later version.
   *
   *  This program is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *  along with this program; see the file COPYING.  If not, write to
   *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
   */
a2d8bc6cb   Eric Paris   fsnotify: generic...
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  /*
   * Basic idea behind the notification queue: An fsnotify group (like inotify)
   * sends the userspace notification about events asyncronously some time after
   * the event happened.  When inotify gets an event it will need to add that
   * event to the group notify queue.  Since a single event might need to be on
   * multiple group's notification queues we can't add the event directly to each
   * queue and instead add a small "event_holder" to each queue.  This event_holder
   * has a pointer back to the original event.  Since the majority of events are
   * going to end up on one, and only one, notification queue we embed one
   * event_holder into each event.  This means we have a single allocation instead
   * of always needing two.  If the embedded event_holder is already in use by
   * another group a new event_holder (from fsnotify_event_holder_cachep) will be
   * allocated and used.
   */
90586523e   Eric Paris   fsnotify: unified...
32
33
34
35
  #include <linux/fs.h>
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/list.h>
47882c6f5   Eric Paris   fsnotify: add cor...
36
  #include <linux/module.h>
90586523e   Eric Paris   fsnotify: unified...
37
38
39
40
41
42
  #include <linux/mount.h>
  #include <linux/mutex.h>
  #include <linux/namei.h>
  #include <linux/path.h>
  #include <linux/slab.h>
  #include <linux/spinlock.h>
60063497a   Arun Sharma   atomic: use <linu...
43
  #include <linux/atomic.h>
90586523e   Eric Paris   fsnotify: unified...
44
45
46
47
48
  
  #include <linux/fsnotify_backend.h>
  #include "fsnotify.h"
  
  static struct kmem_cache *fsnotify_event_cachep;
a2d8bc6cb   Eric Paris   fsnotify: generic...
49
50
51
52
53
54
55
  static struct kmem_cache *fsnotify_event_holder_cachep;
  /*
   * This is a magic event we send when the q is too full.  Since it doesn't
   * hold real event information we just keep one system wide and use it any time
   * it is needed.  It's refcnt is set 1 at kernel init time and will never
   * get set to 0 so it will never get 'freed'
   */
b4277d3dd   Eric Paris   fsnotify: use fsn...
56
  static struct fsnotify_event *q_overflow_event;
47882c6f5   Eric Paris   fsnotify: add cor...
57
58
59
60
61
62
63
64
65
66
67
  static atomic_t fsnotify_sync_cookie = ATOMIC_INIT(0);
  
  /**
   * fsnotify_get_cookie - return a unique cookie for use in synchronizing events.
   * Called from fsnotify_move, which is inlined into filesystem modules.
   */
  u32 fsnotify_get_cookie(void)
  {
  	return atomic_inc_return(&fsnotify_sync_cookie);
  }
  EXPORT_SYMBOL_GPL(fsnotify_get_cookie);
a2d8bc6cb   Eric Paris   fsnotify: generic...
68
69
70
71
72
73
74
  
  /* return true if the notify queue is empty, false otherwise */
  bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group)
  {
  	BUG_ON(!mutex_is_locked(&group->notification_mutex));
  	return list_empty(&group->notification_list) ? true : false;
  }
90586523e   Eric Paris   fsnotify: unified...
75
76
77
78
79
80
81
82
83
84
85
86
  
  void fsnotify_get_event(struct fsnotify_event *event)
  {
  	atomic_inc(&event->refcnt);
  }
  
  void fsnotify_put_event(struct fsnotify_event *event)
  {
  	if (!event)
  		return;
  
  	if (atomic_dec_and_test(&event->refcnt)) {
5ba08e2ee   Eric Paris   fsnotify: add pr_...
87
88
  		pr_debug("%s: event=%p
  ", __func__, event);
2069601b3   Linus Torvalds   Revert "fsnotify:...
89
90
  		if (event->data_type == FSNOTIFY_EVENT_PATH)
  			path_put(&event->path);
90586523e   Eric Paris   fsnotify: unified...
91

e4aff1173   Eric Paris   fsnotify: allow g...
92
  		BUG_ON(!list_empty(&event->private_data_list));
62ffe5dfb   Eric Paris   fsnotify: include...
93
  		kfree(event->file_name);
32c326322   Andreas Gruenbacher   fanotify: Add pid...
94
  		put_pid(event->tgid);
90586523e   Eric Paris   fsnotify: unified...
95
96
97
  		kmem_cache_free(fsnotify_event_cachep, event);
  	}
  }
a2d8bc6cb   Eric Paris   fsnotify: generic...
98
99
100
101
102
103
104
  struct fsnotify_event_holder *fsnotify_alloc_event_holder(void)
  {
  	return kmem_cache_alloc(fsnotify_event_holder_cachep, GFP_KERNEL);
  }
  
  void fsnotify_destroy_event_holder(struct fsnotify_event_holder *holder)
  {
74766bbfa   Eric Paris   fsnotify: per gro...
105
106
  	if (holder)
  		kmem_cache_free(fsnotify_event_holder_cachep, holder);
a2d8bc6cb   Eric Paris   fsnotify: generic...
107
108
109
  }
  
  /*
e4aff1173   Eric Paris   fsnotify: allow g...
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
   * Find the private data that the group previously attached to this event when
   * the group added the event to the notification queue (fsnotify_add_notify_event)
   */
  struct fsnotify_event_private_data *fsnotify_remove_priv_from_event(struct fsnotify_group *group, struct fsnotify_event *event)
  {
  	struct fsnotify_event_private_data *lpriv;
  	struct fsnotify_event_private_data *priv = NULL;
  
  	assert_spin_locked(&event->lock);
  
  	list_for_each_entry(lpriv, &event->private_data_list, event_list) {
  		if (lpriv->group == group) {
  			priv = lpriv;
  			list_del(&priv->event_list);
  			break;
  		}
  	}
  	return priv;
  }
  
  /*
a2d8bc6cb   Eric Paris   fsnotify: generic...
131
132
133
   * Add an event to the group notification queue.  The group can later pull this
   * event off the queue to deal with.  If the event is successfully added to the
   * group's notification queue, a reference is taken on event.
90586523e   Eric Paris   fsnotify: unified...
134
   */
f70ab54cc   Eric Paris   fsnotify: fsnotif...
135
136
137
138
  struct fsnotify_event *fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event,
  						 struct fsnotify_event_private_data *priv,
  						 struct fsnotify_event *(*merge)(struct list_head *,
  										 struct fsnotify_event *))
a2d8bc6cb   Eric Paris   fsnotify: generic...
139
  {
f70ab54cc   Eric Paris   fsnotify: fsnotif...
140
  	struct fsnotify_event *return_event = NULL;
a2d8bc6cb   Eric Paris   fsnotify: generic...
141
142
  	struct fsnotify_event_holder *holder = NULL;
  	struct list_head *list = &group->notification_list;
e4aff1173   Eric Paris   fsnotify: allow g...
143

5ba08e2ee   Eric Paris   fsnotify: add pr_...
144
145
  	pr_debug("%s: group=%p event=%p priv=%p
  ", __func__, group, event, priv);
a2d8bc6cb   Eric Paris   fsnotify: generic...
146
147
148
149
150
151
152
153
154
155
156
157
  	/*
  	 * There is one fsnotify_event_holder embedded inside each fsnotify_event.
  	 * Check if we expect to be able to use that holder.  If not alloc a new
  	 * holder.
  	 * For the overflow event it's possible that something will use the in
  	 * event holder before we get the lock so we may need to jump back and
  	 * alloc a new holder, this can't happen for most events...
  	 */
  	if (!list_empty(&event->holder.event_list)) {
  alloc_holder:
  		holder = fsnotify_alloc_event_holder();
  		if (!holder)
f70ab54cc   Eric Paris   fsnotify: fsnotif...
158
  			return ERR_PTR(-ENOMEM);
a2d8bc6cb   Eric Paris   fsnotify: generic...
159
160
161
  	}
  
  	mutex_lock(&group->notification_mutex);
e4aff1173   Eric Paris   fsnotify: allow g...
162
  	if (group->q_len >= group->max_events) {
b4277d3dd   Eric Paris   fsnotify: use fsn...
163
  		event = q_overflow_event;
f70ab54cc   Eric Paris   fsnotify: fsnotif...
164
165
166
167
168
169
170
  
  		/*
  		 * we need to return the overflow event
  		 * which means we need a ref
  		 */
  		fsnotify_get_event(event);
  		return_event = event;
e4aff1173   Eric Paris   fsnotify: allow g...
171
172
173
  		/* sorry, no private data on the overflow event */
  		priv = NULL;
  	}
a2d8bc6cb   Eric Paris   fsnotify: generic...
174

74766bbfa   Eric Paris   fsnotify: per gro...
175
  	if (!list_empty(list) && merge) {
f70ab54cc   Eric Paris   fsnotify: fsnotif...
176
  		struct fsnotify_event *tmp;
74766bbfa   Eric Paris   fsnotify: per gro...
177

f70ab54cc   Eric Paris   fsnotify: fsnotif...
178
179
  		tmp = merge(list, event);
  		if (tmp) {
74766bbfa   Eric Paris   fsnotify: per gro...
180
  			mutex_unlock(&group->notification_mutex);
f70ab54cc   Eric Paris   fsnotify: fsnotif...
181
182
183
  
  			if (return_event)
  				fsnotify_put_event(return_event);
74766bbfa   Eric Paris   fsnotify: per gro...
184
185
  			if (holder != &event->holder)
  				fsnotify_destroy_event_holder(holder);
f70ab54cc   Eric Paris   fsnotify: fsnotif...
186
  			return tmp;
74766bbfa   Eric Paris   fsnotify: per gro...
187
188
  		}
  	}
a2d8bc6cb   Eric Paris   fsnotify: generic...
189
190
191
192
193
194
195
196
197
198
199
  	spin_lock(&event->lock);
  
  	if (list_empty(&event->holder.event_list)) {
  		if (unlikely(holder))
  			fsnotify_destroy_event_holder(holder);
  		holder = &event->holder;
  	} else if (unlikely(!holder)) {
  		/* between the time we checked above and got the lock the in
  		 * event holder was used, go back and get a new one */
  		spin_unlock(&event->lock);
  		mutex_unlock(&group->notification_mutex);
f70ab54cc   Eric Paris   fsnotify: fsnotif...
200
201
202
203
204
  
  		if (return_event) {
  			fsnotify_put_event(return_event);
  			return_event = NULL;
  		}
a2d8bc6cb   Eric Paris   fsnotify: generic...
205
206
  		goto alloc_holder;
  	}
a2d8bc6cb   Eric Paris   fsnotify: generic...
207
208
209
210
211
  	group->q_len++;
  	holder->event = event;
  
  	fsnotify_get_event(event);
  	list_add_tail(&holder->event_list, list);
e4aff1173   Eric Paris   fsnotify: allow g...
212
213
  	if (priv)
  		list_add_tail(&priv->event_list, &event->private_data_list);
a2d8bc6cb   Eric Paris   fsnotify: generic...
214
215
216
217
  	spin_unlock(&event->lock);
  	mutex_unlock(&group->notification_mutex);
  
  	wake_up(&group->notification_waitq);
f70ab54cc   Eric Paris   fsnotify: fsnotif...
218
  	return return_event;
a2d8bc6cb   Eric Paris   fsnotify: generic...
219
220
221
222
223
224
225
226
  }
  
  /*
   * Remove and return the first event from the notification list.  There is a
   * reference held on this event since it was on the list.  It is the responsibility
   * of the caller to drop this reference.
   */
  struct fsnotify_event *fsnotify_remove_notify_event(struct fsnotify_group *group)
90586523e   Eric Paris   fsnotify: unified...
227
228
  {
  	struct fsnotify_event *event;
a2d8bc6cb   Eric Paris   fsnotify: generic...
229
  	struct fsnotify_event_holder *holder;
90586523e   Eric Paris   fsnotify: unified...
230

a2d8bc6cb   Eric Paris   fsnotify: generic...
231
  	BUG_ON(!mutex_is_locked(&group->notification_mutex));
90586523e   Eric Paris   fsnotify: unified...
232

5ba08e2ee   Eric Paris   fsnotify: add pr_...
233
234
  	pr_debug("%s: group=%p
  ", __func__, group);
a2d8bc6cb   Eric Paris   fsnotify: generic...
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
  	holder = list_first_entry(&group->notification_list, struct fsnotify_event_holder, event_list);
  
  	event = holder->event;
  
  	spin_lock(&event->lock);
  	holder->event = NULL;
  	list_del_init(&holder->event_list);
  	spin_unlock(&event->lock);
  
  	/* event == holder means we are referenced through the in event holder */
  	if (holder != &event->holder)
  		fsnotify_destroy_event_holder(holder);
  
  	group->q_len--;
  
  	return event;
  }
  
  /*
   * This will not remove the event, that must be done with fsnotify_remove_notify_event()
   */
  struct fsnotify_event *fsnotify_peek_notify_event(struct fsnotify_group *group)
  {
  	struct fsnotify_event *event;
  	struct fsnotify_event_holder *holder;
  
  	BUG_ON(!mutex_is_locked(&group->notification_mutex));
  
  	holder = list_first_entry(&group->notification_list, struct fsnotify_event_holder, event_list);
  	event = holder->event;
  
  	return event;
  }
  
  /*
   * Called when a group is being torn down to clean up any outstanding
   * event notifications.
   */
  void fsnotify_flush_notify(struct fsnotify_group *group)
  {
  	struct fsnotify_event *event;
e4aff1173   Eric Paris   fsnotify: allow g...
276
  	struct fsnotify_event_private_data *priv;
a2d8bc6cb   Eric Paris   fsnotify: generic...
277
278
279
280
  
  	mutex_lock(&group->notification_mutex);
  	while (!fsnotify_notify_queue_is_empty(group)) {
  		event = fsnotify_remove_notify_event(group);
e4aff1173   Eric Paris   fsnotify: allow g...
281
282
283
284
285
286
287
288
  		/* if they don't implement free_event_priv they better not have attached any */
  		if (group->ops->free_event_priv) {
  			spin_lock(&event->lock);
  			priv = fsnotify_remove_priv_from_event(group, event);
  			spin_unlock(&event->lock);
  			if (priv)
  				group->ops->free_event_priv(priv);
  		}
a2d8bc6cb   Eric Paris   fsnotify: generic...
289
290
291
292
293
294
295
  		fsnotify_put_event(event); /* matches fsnotify_add_notify_event */
  	}
  	mutex_unlock(&group->notification_mutex);
  }
  
  static void initialize_event(struct fsnotify_event *event)
  {
a2d8bc6cb   Eric Paris   fsnotify: generic...
296
  	INIT_LIST_HEAD(&event->holder.event_list);
90586523e   Eric Paris   fsnotify: unified...
297
298
299
  	atomic_set(&event->refcnt, 1);
  
  	spin_lock_init(&event->lock);
e4aff1173   Eric Paris   fsnotify: allow g...
300
  	INIT_LIST_HEAD(&event->private_data_list);
a2d8bc6cb   Eric Paris   fsnotify: generic...
301
  }
1201a5361   Eric Paris   fsnotify: replace...
302
303
  /*
   * Caller damn well better be holding whatever mutex is protecting the
cac69dad3   Eric Paris   fsnotify: lock an...
304
305
   * old_holder->event_list and the new_event must be a clean event which
   * cannot be found anywhere else in the kernel.
1201a5361   Eric Paris   fsnotify: replace...
306
307
308
309
310
   */
  int fsnotify_replace_event(struct fsnotify_event_holder *old_holder,
  			   struct fsnotify_event *new_event)
  {
  	struct fsnotify_event *old_event = old_holder->event;
cac69dad3   Eric Paris   fsnotify: lock an...
311
312
313
314
315
316
  	struct fsnotify_event_holder *new_holder = &new_event->holder;
  
  	enum event_spinlock_class {
  		SPINLOCK_OLD,
  		SPINLOCK_NEW,
  	};
1201a5361   Eric Paris   fsnotify: replace...
317

5ba08e2ee   Eric Paris   fsnotify: add pr_...
318
319
  	pr_debug("%s: old_event=%p new_event=%p
  ", __func__, old_event, new_event);
1201a5361   Eric Paris   fsnotify: replace...
320
  	/*
cac69dad3   Eric Paris   fsnotify: lock an...
321
322
  	 * if the new_event's embedded holder is in use someone
  	 * screwed up and didn't give us a clean new event.
1201a5361   Eric Paris   fsnotify: replace...
323
  	 */
cac69dad3   Eric Paris   fsnotify: lock an...
324
  	BUG_ON(!list_empty(&new_holder->event_list));
1201a5361   Eric Paris   fsnotify: replace...
325

cac69dad3   Eric Paris   fsnotify: lock an...
326
327
  	spin_lock_nested(&old_event->lock, SPINLOCK_OLD);
  	spin_lock_nested(&new_event->lock, SPINLOCK_NEW);
1201a5361   Eric Paris   fsnotify: replace...
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
  
  	new_holder->event = new_event;
  	list_replace_init(&old_holder->event_list, &new_holder->event_list);
  
  	spin_unlock(&new_event->lock);
  	spin_unlock(&old_event->lock);
  
  	/* event == holder means we are referenced through the in event holder */
  	if (old_holder != &old_event->holder)
  		fsnotify_destroy_event_holder(old_holder);
  
  	fsnotify_get_event(new_event); /* on the list take reference */
  	fsnotify_put_event(old_event); /* off the list, drop reference */
  
  	return 0;
  }
b4e4e1407   Eric Paris   fsnotify: clone e...
344
345
346
347
348
349
350
  struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_event)
  {
  	struct fsnotify_event *event;
  
  	event = kmem_cache_alloc(fsnotify_event_cachep, GFP_KERNEL);
  	if (!event)
  		return NULL;
5ba08e2ee   Eric Paris   fsnotify: add pr_...
351
352
  	pr_debug("%s: old_event=%p new_event=%p
  ", __func__, old_event, event);
b4e4e1407   Eric Paris   fsnotify: clone e...
353
354
355
356
357
358
359
360
361
362
  	memcpy(event, old_event, sizeof(*event));
  	initialize_event(event);
  
  	if (event->name_len) {
  		event->file_name = kstrdup(old_event->file_name, GFP_KERNEL);
  		if (!event->file_name) {
  			kmem_cache_free(fsnotify_event_cachep, event);
  			return NULL;
  		}
  	}
32c326322   Andreas Gruenbacher   fanotify: Add pid...
363
  	event->tgid = get_pid(old_event->tgid);
2069601b3   Linus Torvalds   Revert "fsnotify:...
364
365
  	if (event->data_type == FSNOTIFY_EVENT_PATH)
  		path_get(&event->path);
b4e4e1407   Eric Paris   fsnotify: clone e...
366
367
368
  
  	return event;
  }
a2d8bc6cb   Eric Paris   fsnotify: generic...
369
370
371
372
373
374
375
376
377
378
  /*
   * fsnotify_create_event - Allocate a new event which will be sent to each
   * group's handle_event function if the group was interested in this
   * particular event.
   *
   * @to_tell the inode which is supposed to receive the event (sometimes a
   *	parent of the inode to which the event happened.
   * @mask what actually happened.
   * @data pointer to the object which was actually affected
   * @data_type flag indication if the data is a file, path, inode, nothing...
62ffe5dfb   Eric Paris   fsnotify: include...
379
   * @name the filename, if available
a2d8bc6cb   Eric Paris   fsnotify: generic...
380
   */
47882c6f5   Eric Paris   fsnotify: add cor...
381
  struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask, void *data,
59b0df211   Eric Paris   fsnotify: use uns...
382
383
  					     int data_type, const unsigned char *name,
  					     u32 cookie, gfp_t gfp)
a2d8bc6cb   Eric Paris   fsnotify: generic...
384
385
  {
  	struct fsnotify_event *event;
6f3a539e3   Eric Paris   fsnotify: use kme...
386
  	event = kmem_cache_zalloc(fsnotify_event_cachep, gfp);
a2d8bc6cb   Eric Paris   fsnotify: generic...
387
388
  	if (!event)
  		return NULL;
5ba08e2ee   Eric Paris   fsnotify: add pr_...
389
390
391
  	pr_debug("%s: event=%p to_tell=%p mask=%x data=%p data_type=%d
  ",
  		 __func__, event, to_tell, mask, data, data_type);
a2d8bc6cb   Eric Paris   fsnotify: generic...
392
  	initialize_event(event);
62ffe5dfb   Eric Paris   fsnotify: include...
393
394
  
  	if (name) {
f44aebcc5   Eric Paris   inotify: use GFP_...
395
  		event->file_name = kstrdup(name, gfp);
62ffe5dfb   Eric Paris   fsnotify: include...
396
397
398
399
400
401
  		if (!event->file_name) {
  			kmem_cache_free(fsnotify_event_cachep, event);
  			return NULL;
  		}
  		event->name_len = strlen(event->file_name);
  	}
47882c6f5   Eric Paris   fsnotify: add cor...
402

32c326322   Andreas Gruenbacher   fanotify: Add pid...
403
  	event->tgid = get_pid(task_tgid(current));
47882c6f5   Eric Paris   fsnotify: add cor...
404
  	event->sync_cookie = cookie;
90586523e   Eric Paris   fsnotify: unified...
405
  	event->to_tell = to_tell;
b4e4e1407   Eric Paris   fsnotify: clone e...
406
  	event->data_type = data_type;
90586523e   Eric Paris   fsnotify: unified...
407
408
  
  	switch (data_type) {
2069601b3   Linus Torvalds   Revert "fsnotify:...
409
410
411
412
413
  	case FSNOTIFY_EVENT_PATH: {
  		struct path *path = data;
  		event->path.dentry = path->dentry;
  		event->path.mnt = path->mnt;
  		path_get(&event->path);
90586523e   Eric Paris   fsnotify: unified...
414
415
416
417
  		break;
  	}
  	case FSNOTIFY_EVENT_INODE:
  		event->inode = data;
90586523e   Eric Paris   fsnotify: unified...
418
419
420
  		break;
  	case FSNOTIFY_EVENT_NONE:
  		event->inode = NULL;
2069601b3   Linus Torvalds   Revert "fsnotify:...
421
422
  		event->path.dentry = NULL;
  		event->path.mnt = NULL;
90586523e   Eric Paris   fsnotify: unified...
423
424
425
426
427
428
429
430
431
432
433
434
435
  		break;
  	default:
  		BUG();
  	}
  
  	event->mask = mask;
  
  	return event;
  }
  
  __init int fsnotify_notification_init(void)
  {
  	fsnotify_event_cachep = KMEM_CACHE(fsnotify_event, SLAB_PANIC);
a2d8bc6cb   Eric Paris   fsnotify: generic...
436
  	fsnotify_event_holder_cachep = KMEM_CACHE(fsnotify_event_holder, SLAB_PANIC);
b4277d3dd   Eric Paris   fsnotify: use fsn...
437
438
439
440
441
442
  	q_overflow_event = fsnotify_create_event(NULL, FS_Q_OVERFLOW, NULL,
  						 FSNOTIFY_EVENT_NONE, NULL, 0,
  						 GFP_KERNEL);
  	if (!q_overflow_event)
  		panic("unable to allocate fsnotify q_overflow_event
  ");
90586523e   Eric Paris   fsnotify: unified...
443
444
445
446
  
  	return 0;
  }
  subsys_initcall(fsnotify_notification_init);