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 : : #include <linux/list.h>
20 : : #include <linux/mutex.h>
21 : : #include <linux/slab.h>
22 : : #include <linux/srcu.h>
23 : : #include <linux/rculist.h>
24 : : #include <linux/wait.h>
25 : :
26 : : #include <linux/fsnotify_backend.h>
27 : : #include "fsnotify.h"
28 : :
29 : : #include <linux/atomic.h>
30 : :
31 : : /*
32 : : * Final freeing of a group
33 : : */
34 : 0 : void fsnotify_final_destroy_group(struct fsnotify_group *group)
35 : : {
36 [ + - ]: 8 : if (group->ops->free_group_priv)
37 : 8 : group->ops->free_group_priv(group);
38 : :
39 : 8 : kfree(group);
40 : 8 : }
41 : :
42 : : /*
43 : : * Trying to get rid of a group. Remove all marks, flush all events and release
44 : : * the group reference.
45 : : * Note that another thread calling fsnotify_clear_marks_by_group() may still
46 : : * hold a ref to the group.
47 : : */
48 : 0 : void fsnotify_destroy_group(struct fsnotify_group *group)
49 : : {
50 : : /* clear all inode marks for this group */
51 : 8 : fsnotify_clear_marks_by_group(group);
52 : :
53 : 8 : synchronize_srcu(&fsnotify_mark_srcu);
54 : :
55 : : /* clear the notification queue of all events */
56 : 8 : fsnotify_flush_notify(group);
57 : :
58 : : /*
59 : : * Destroy overflow event (we cannot use fsnotify_destroy_event() as
60 : : * that deliberately ignores overflow events.
61 : : */
62 [ + - ]: 8 : if (group->overflow_event)
63 : 8 : group->ops->free_event(group->overflow_event);
64 : :
65 : 8 : fsnotify_put_group(group);
66 : 8 : }
67 : :
68 : : /*
69 : : * Get reference to a group.
70 : : */
71 : 0 : void fsnotify_get_group(struct fsnotify_group *group)
72 : : {
73 : 33 : atomic_inc(&group->refcnt);
74 : 33 : }
75 : :
76 : : /*
77 : : * Drop a reference to a group. Free it if it's through.
78 : : */
79 : 0 : void fsnotify_put_group(struct fsnotify_group *group)
80 : : {
81 [ + + ]: 41 : if (atomic_dec_and_test(&group->refcnt))
82 : 8 : fsnotify_final_destroy_group(group);
83 : 0 : }
84 : :
85 : : /*
86 : : * Create a new fsnotify_group and hold a reference for the group returned.
87 : : */
88 : 0 : struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops)
89 : : {
90 : : struct fsnotify_group *group;
91 : :
92 : : group = kzalloc(sizeof(struct fsnotify_group), GFP_KERNEL);
93 [ + - ]: 8 : if (!group)
94 : : return ERR_PTR(-ENOMEM);
95 : :
96 : : /* set to 0 when there a no external references to this group */
97 : 8 : atomic_set(&group->refcnt, 1);
98 : 8 : atomic_set(&group->num_marks, 0);
99 : :
100 : 8 : mutex_init(&group->notification_mutex);
101 : 8 : INIT_LIST_HEAD(&group->notification_list);
102 : 8 : init_waitqueue_head(&group->notification_waitq);
103 : 8 : group->max_events = UINT_MAX;
104 : :
105 : 8 : mutex_init(&group->mark_mutex);
106 : 8 : INIT_LIST_HEAD(&group->marks_list);
107 : :
108 : 8 : group->ops = ops;
109 : :
110 : 8 : return group;
111 : : }
112 : :
113 : 0 : int fsnotify_fasync(int fd, struct file *file, int on)
114 : : {
115 : 0 : struct fsnotify_group *group = file->private_data;
116 : :
117 [ # # ]: 0 : return fasync_helper(fd, file, on, &group->fsn_fa) >= 0 ? 0 : -EIO;
118 : : }
|