Branch data Line data Source code
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 : : * Basic idea behind the notification queue: An fsnotify group (like inotify)
21 : : * sends the userspace notification about events asynchronously some time after
22 : : * the event happened. When inotify gets an event it will need to add that
23 : : * event to the group notify queue. Since a single event might need to be on
24 : : * multiple group's notification queues we can't add the event directly to each
25 : : * queue and instead add a small "event_holder" to each queue. This event_holder
26 : : * has a pointer back to the original event. Since the majority of events are
27 : : * going to end up on one, and only one, notification queue we embed one
28 : : * event_holder into each event. This means we have a single allocation instead
29 : : * of always needing two. If the embedded event_holder is already in use by
30 : : * another group a new event_holder (from fsnotify_event_holder_cachep) will be
31 : : * allocated and used.
32 : : */
33 : :
34 : : #include <linux/fs.h>
35 : : #include <linux/init.h>
36 : : #include <linux/kernel.h>
37 : : #include <linux/list.h>
38 : : #include <linux/module.h>
39 : : #include <linux/mount.h>
40 : : #include <linux/mutex.h>
41 : : #include <linux/namei.h>
42 : : #include <linux/path.h>
43 : : #include <linux/slab.h>
44 : : #include <linux/spinlock.h>
45 : :
46 : : #include <linux/atomic.h>
47 : :
48 : : #include <linux/fsnotify_backend.h>
49 : : #include "fsnotify.h"
50 : :
51 : : static struct kmem_cache *fsnotify_event_cachep;
52 : : static struct kmem_cache *fsnotify_event_holder_cachep;
53 : : /*
54 : : * This is a magic event we send when the q is too full. Since it doesn't
55 : : * hold real event information we just keep one system wide and use it any time
56 : : * it is needed. It's refcnt is set 1 at kernel init time and will never
57 : : * get set to 0 so it will never get 'freed'
58 : : */
59 : : static struct fsnotify_event *q_overflow_event;
60 : : static atomic_t fsnotify_sync_cookie = ATOMIC_INIT(0);
61 : :
62 : : /**
63 : : * fsnotify_get_cookie - return a unique cookie for use in synchronizing events.
64 : : * Called from fsnotify_move, which is inlined into filesystem modules.
65 : : */
66 : 0 : u32 fsnotify_get_cookie(void)
67 : : {
68 : 194550 : return atomic_inc_return(&fsnotify_sync_cookie);
69 : : }
70 : : EXPORT_SYMBOL_GPL(fsnotify_get_cookie);
71 : :
72 : : /* return true if the notify queue is empty, false otherwise */
73 : 0 : bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group)
74 : : {
75 [ - + ]: 148613 : BUG_ON(!mutex_is_locked(&group->notification_mutex));
76 : 297226 : return list_empty(&group->notification_list) ? true : false;
77 : : }
78 : :
79 : 0 : void fsnotify_get_event(struct fsnotify_event *event)
80 : : {
81 : 27643 : atomic_inc(&event->refcnt);
82 : 71 : }
83 : :
84 : 0 : void fsnotify_put_event(struct fsnotify_event *event)
85 : : {
86 [ + ]: 55284 : if (!event)
87 : 0 : return;
88 : :
89 [ + + ]: 55283 : if (atomic_dec_and_test(&event->refcnt)) {
90 : : pr_debug("%s: event=%p\n", __func__, event);
91 : :
92 [ + + ]: 27643 : if (event->data_type == FSNOTIFY_EVENT_PATH)
93 : 13616 : path_put(&event->path);
94 : :
95 [ - + ]: 27643 : BUG_ON(!list_empty(&event->private_data_list));
96 : :
97 : 27643 : kfree(event->file_name);
98 : 27643 : put_pid(event->tgid);
99 : 27643 : kmem_cache_free(fsnotify_event_cachep, event);
100 : : }
101 : : }
102 : :
103 : 0 : struct fsnotify_event_holder *fsnotify_alloc_event_holder(void)
104 : : {
105 : 0 : return kmem_cache_alloc(fsnotify_event_holder_cachep, GFP_KERNEL);
106 : : }
107 : :
108 : 0 : void fsnotify_destroy_event_holder(struct fsnotify_event_holder *holder)
109 : : {
110 [ # # ][ # # ]: 71 : if (holder)
[ - + ][ # # ]
[ # # ]
111 : 0 : kmem_cache_free(fsnotify_event_holder_cachep, holder);
112 : 0 : }
113 : :
114 : : /*
115 : : * Find the private data that the group previously attached to this event when
116 : : * the group added the event to the notification queue (fsnotify_add_notify_event)
117 : : */
118 : 0 : struct fsnotify_event_private_data *fsnotify_remove_priv_from_event(struct fsnotify_group *group, struct fsnotify_event *event)
119 : : {
120 : : struct fsnotify_event_private_data *lpriv;
121 : : struct fsnotify_event_private_data *priv = NULL;
122 : :
123 [ - + ]: 27572 : assert_spin_locked(&event->lock);
124 : :
125 [ + - ]: 27572 : list_for_each_entry(lpriv, &event->private_data_list, event_list) {
126 [ + - ]: 27572 : if (lpriv->group == group) {
127 : : priv = lpriv;
128 : : list_del(&priv->event_list);
129 : : break;
130 : : }
131 : : }
132 : 0 : return priv;
133 : : }
134 : :
135 : : /*
136 : : * Add an event to the group notification queue. The group can later pull this
137 : : * event off the queue to deal with. If the event is successfully added to the
138 : : * group's notification queue, a reference is taken on event.
139 : : */
140 : 0 : struct fsnotify_event *fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event,
141 : : struct fsnotify_event_private_data *priv,
142 : : struct fsnotify_event *(*merge)(struct list_head *,
143 : : struct fsnotify_event *))
144 : : {
145 : : struct fsnotify_event *return_event = NULL;
146 : : struct fsnotify_event_holder *holder = NULL;
147 : 27643 : struct list_head *list = &group->notification_list;
148 : :
149 : : pr_debug("%s: group=%p event=%p priv=%p\n", __func__, group, event, priv);
150 : :
151 : : /*
152 : : * There is one fsnotify_event_holder embedded inside each fsnotify_event.
153 : : * Check if we expect to be able to use that holder. If not alloc a new
154 : : * holder.
155 : : * For the overflow event it's possible that something will use the in
156 : : * event holder before we get the lock so we may need to jump back and
157 : : * alloc a new holder, this can't happen for most events...
158 : : */
159 [ - + ]: 27643 : if (!list_empty(&event->holder.event_list)) {
160 : : alloc_holder:
161 : : holder = fsnotify_alloc_event_holder();
162 [ # # ]: 0 : if (!holder)
163 : : return ERR_PTR(-ENOMEM);
164 : : }
165 : :
166 : 27643 : mutex_lock(&group->notification_mutex);
167 : :
168 [ - + ]: 27643 : if (group->q_len >= group->max_events) {
169 : 0 : event = q_overflow_event;
170 : :
171 : : /*
172 : : * we need to return the overflow event
173 : : * which means we need a ref
174 : : */
175 : : fsnotify_get_event(event);
176 : : return_event = event;
177 : :
178 : : /* sorry, no private data on the overflow event */
179 : : priv = NULL;
180 : : }
181 : :
182 [ + + ][ + + ]: 27643 : if (!list_empty(list) && merge) {
183 : : struct fsnotify_event *tmp;
184 : :
185 : 6561 : tmp = merge(list, event);
186 [ + + ]: 6561 : if (tmp) {
187 : 71 : mutex_unlock(&group->notification_mutex);
188 : :
189 [ - + ]: 71 : if (return_event)
190 : 0 : fsnotify_put_event(return_event);
191 [ + - ]: 71 : if (holder != &event->holder)
192 : : fsnotify_destroy_event_holder(holder);
193 : 71 : return tmp;
194 : : }
195 : : }
196 : :
197 : : spin_lock(&event->lock);
198 : :
199 [ + - ]: 27572 : if (list_empty(&event->holder.event_list)) {
200 [ - + ]: 27572 : if (unlikely(holder))
201 : : fsnotify_destroy_event_holder(holder);
202 : 27572 : holder = &event->holder;
203 [ # # ]: 0 : } else if (unlikely(!holder)) {
204 : : /* between the time we checked above and got the lock the in
205 : : * event holder was used, go back and get a new one */
206 : : spin_unlock(&event->lock);
207 : 0 : mutex_unlock(&group->notification_mutex);
208 : :
209 [ # # ]: 0 : if (return_event) {
210 : 0 : fsnotify_put_event(return_event);
211 : : return_event = NULL;
212 : : }
213 : :
214 : : goto alloc_holder;
215 : : }
216 : :
217 : 27572 : group->q_len++;
218 : 27572 : holder->event = event;
219 : :
220 : : fsnotify_get_event(event);
221 : 27572 : list_add_tail(&holder->event_list, list);
222 [ + - ]: 27572 : if (priv)
223 : 27572 : list_add_tail(&priv->event_list, &event->private_data_list);
224 : : spin_unlock(&event->lock);
225 : 27572 : mutex_unlock(&group->notification_mutex);
226 : :
227 : 27572 : wake_up(&group->notification_waitq);
228 : 27572 : kill_fasync(&group->fsn_fa, SIGIO, POLL_IN);
229 : 27572 : return return_event;
230 : : }
231 : :
232 : : /*
233 : : * Remove and return the first event from the notification list. There is a
234 : : * reference held on this event since it was on the list. It is the responsibility
235 : : * of the caller to drop this reference.
236 : : */
237 : 0 : struct fsnotify_event *fsnotify_remove_notify_event(struct fsnotify_group *group)
238 : : {
239 : : struct fsnotify_event *event;
240 : : struct fsnotify_event_holder *holder;
241 : :
242 [ - + ]: 27572 : BUG_ON(!mutex_is_locked(&group->notification_mutex));
243 : :
244 : : pr_debug("%s: group=%p\n", __func__, group);
245 : :
246 : 27572 : holder = list_first_entry(&group->notification_list, struct fsnotify_event_holder, event_list);
247 : :
248 : 27572 : event = holder->event;
249 : :
250 : : spin_lock(&event->lock);
251 : 27572 : holder->event = NULL;
252 : 27572 : list_del_init(&holder->event_list);
253 : : spin_unlock(&event->lock);
254 : :
255 : : /* event == holder means we are referenced through the in event holder */
256 [ - + ]: 27572 : if (holder != &event->holder)
257 : : fsnotify_destroy_event_holder(holder);
258 : :
259 : 0 : group->q_len--;
260 : :
261 : 0 : return event;
262 : : }
263 : :
264 : : /*
265 : : * This will not remove the event, that must be done with fsnotify_remove_notify_event()
266 : : */
267 : 0 : struct fsnotify_event *fsnotify_peek_notify_event(struct fsnotify_group *group)
268 : : {
269 : : struct fsnotify_event *event;
270 : : struct fsnotify_event_holder *holder;
271 : :
272 [ - + ]: 27570 : BUG_ON(!mutex_is_locked(&group->notification_mutex));
273 : :
274 : 27570 : holder = list_first_entry(&group->notification_list, struct fsnotify_event_holder, event_list);
275 : 27570 : event = holder->event;
276 : :
277 : 27570 : return event;
278 : : }
279 : :
280 : : /*
281 : : * Called when a group is being torn down to clean up any outstanding
282 : : * event notifications.
283 : : */
284 : 0 : void fsnotify_flush_notify(struct fsnotify_group *group)
285 : : {
286 : : struct fsnotify_event *event;
287 : : struct fsnotify_event_private_data *priv;
288 : :
289 : 7 : mutex_lock(&group->notification_mutex);
290 [ + + ]: 9 : while (!fsnotify_notify_queue_is_empty(group)) {
291 : 2 : event = fsnotify_remove_notify_event(group);
292 : : /* if they don't implement free_event_priv they better not have attached any */
293 [ + - ]: 2 : if (group->ops->free_event_priv) {
294 : : spin_lock(&event->lock);
295 : 2 : priv = fsnotify_remove_priv_from_event(group, event);
296 : : spin_unlock(&event->lock);
297 [ + - ]: 2 : if (priv)
298 : 2 : group->ops->free_event_priv(priv);
299 : : }
300 : 2 : fsnotify_put_event(event); /* matches fsnotify_add_notify_event */
301 : : }
302 : 7 : mutex_unlock(&group->notification_mutex);
303 : 7 : }
304 : :
305 : : static void initialize_event(struct fsnotify_event *event)
306 : : {
307 : 27643 : INIT_LIST_HEAD(&event->holder.event_list);
308 : 27643 : atomic_set(&event->refcnt, 1);
309 : :
310 : 27643 : spin_lock_init(&event->lock);
311 : :
312 : 27643 : INIT_LIST_HEAD(&event->private_data_list);
313 : : }
314 : :
315 : : /*
316 : : * Caller damn well better be holding whatever mutex is protecting the
317 : : * old_holder->event_list and the new_event must be a clean event which
318 : : * cannot be found anywhere else in the kernel.
319 : : */
320 : 0 : int fsnotify_replace_event(struct fsnotify_event_holder *old_holder,
321 : : struct fsnotify_event *new_event)
322 : : {
323 : 0 : struct fsnotify_event *old_event = old_holder->event;
324 : : struct fsnotify_event_holder *new_holder = &new_event->holder;
325 : :
326 : : enum event_spinlock_class {
327 : : SPINLOCK_OLD,
328 : : SPINLOCK_NEW,
329 : : };
330 : :
331 : : pr_debug("%s: old_event=%p new_event=%p\n", __func__, old_event, new_event);
332 : :
333 : : /*
334 : : * if the new_event's embedded holder is in use someone
335 : : * screwed up and didn't give us a clean new event.
336 : : */
337 [ # # ]: 0 : BUG_ON(!list_empty(&new_holder->event_list));
338 : :
339 : 0 : spin_lock_nested(&old_event->lock, SPINLOCK_OLD);
340 : 0 : spin_lock_nested(&new_event->lock, SPINLOCK_NEW);
341 : :
342 : 0 : new_holder->event = new_event;
343 : 0 : list_replace_init(&old_holder->event_list, &new_holder->event_list);
344 : :
345 : : spin_unlock(&new_event->lock);
346 : : spin_unlock(&old_event->lock);
347 : :
348 : : /* event == holder means we are referenced through the in event holder */
349 [ # # ]: 0 : if (old_holder != &old_event->holder)
350 : : fsnotify_destroy_event_holder(old_holder);
351 : :
352 : : fsnotify_get_event(new_event); /* on the list take reference */
353 : 0 : fsnotify_put_event(old_event); /* off the list, drop reference */
354 : :
355 : 0 : return 0;
356 : : }
357 : :
358 : 0 : struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_event)
359 : : {
360 : : struct fsnotify_event *event;
361 : :
362 : 0 : event = kmem_cache_alloc(fsnotify_event_cachep, GFP_KERNEL);
363 [ # # ]: 0 : if (!event)
364 : : return NULL;
365 : :
366 : : pr_debug("%s: old_event=%p new_event=%p\n", __func__, old_event, event);
367 : :
368 : 0 : memcpy(event, old_event, sizeof(*event));
369 : : initialize_event(event);
370 : :
371 [ # # ]: 0 : if (event->name_len) {
372 : 0 : event->file_name = kstrdup(old_event->file_name, GFP_KERNEL);
373 [ # # ]: 0 : if (!event->file_name) {
374 : 0 : kmem_cache_free(fsnotify_event_cachep, event);
375 : 0 : return NULL;
376 : : }
377 : : }
378 : 0 : event->tgid = get_pid(old_event->tgid);
379 [ # # ]: 0 : if (event->data_type == FSNOTIFY_EVENT_PATH)
380 : 0 : path_get(&event->path);
381 : :
382 : 0 : return event;
383 : : }
384 : :
385 : : /*
386 : : * fsnotify_create_event - Allocate a new event which will be sent to each
387 : : * group's handle_event function if the group was interested in this
388 : : * particular event.
389 : : *
390 : : * @to_tell the inode which is supposed to receive the event (sometimes a
391 : : * parent of the inode to which the event happened.
392 : : * @mask what actually happened.
393 : : * @data pointer to the object which was actually affected
394 : : * @data_type flag indication if the data is a file, path, inode, nothing...
395 : : * @name the filename, if available
396 : : */
397 : 0 : struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask, void *data,
398 : : int data_type, const unsigned char *name,
399 : : u32 cookie, gfp_t gfp)
400 : : {
401 : : struct fsnotify_event *event;
402 : :
403 : 27642 : event = kmem_cache_zalloc(fsnotify_event_cachep, gfp);
404 [ + - ]: 27643 : if (!event)
405 : : return NULL;
406 : :
407 : : pr_debug("%s: event=%p to_tell=%p mask=%x data=%p data_type=%d\n",
408 : : __func__, event, to_tell, mask, data, data_type);
409 : :
410 : : initialize_event(event);
411 : :
412 [ + + ]: 27643 : if (name) {
413 : 27625 : event->file_name = kstrdup(name, gfp);
414 [ - + ]: 27625 : if (!event->file_name) {
415 : 0 : kmem_cache_free(fsnotify_event_cachep, event);
416 : 0 : return NULL;
417 : : }
418 : 27625 : event->name_len = strlen(event->file_name);
419 : : }
420 : :
421 : 55286 : event->tgid = get_pid(task_tgid(current));
422 : 27643 : event->sync_cookie = cookie;
423 : 27643 : event->to_tell = to_tell;
424 : 27643 : event->data_type = data_type;
425 : :
426 [ + + + - ]: 55285 : switch (data_type) {
427 : : case FSNOTIFY_EVENT_PATH: {
428 : : struct path *path = data;
429 : 13616 : event->path.dentry = path->dentry;
430 : 13616 : event->path.mnt = path->mnt;
431 : 13616 : path_get(&event->path);
432 : 13616 : break;
433 : : }
434 : : case FSNOTIFY_EVENT_INODE:
435 : 14023 : event->inode = data;
436 : 14023 : break;
437 : : case FSNOTIFY_EVENT_NONE:
438 : 4 : event->inode = NULL;
439 : 4 : event->path.dentry = NULL;
440 : : event->path.mnt = NULL;
441 : 4 : break;
442 : : default:
443 : 0 : BUG();
444 : : }
445 : :
446 : 27643 : event->mask = mask;
447 : :
448 : 27643 : return event;
449 : : }
450 : :
451 : 0 : static __init int fsnotify_notification_init(void)
452 : : {
453 : 0 : fsnotify_event_cachep = KMEM_CACHE(fsnotify_event, SLAB_PANIC);
454 : 0 : fsnotify_event_holder_cachep = KMEM_CACHE(fsnotify_event_holder, SLAB_PANIC);
455 : :
456 : 0 : q_overflow_event = fsnotify_create_event(NULL, FS_Q_OVERFLOW, NULL,
457 : : FSNOTIFY_EVENT_NONE, NULL, 0,
458 : : GFP_KERNEL);
459 [ # # ]: 0 : if (!q_overflow_event)
460 : 0 : panic("unable to allocate fsnotify q_overflow_event\n");
461 : :
462 : 0 : return 0;
463 : : }
464 : : subsys_initcall(fsnotify_notification_init);
|