aboutsummaryrefslogtreecommitdiffstats
path: root/fs/notify/group.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/notify/group.c')
-rw-r--r--fs/notify/group.c47
1 files changed, 27 insertions, 20 deletions
diff --git a/fs/notify/group.c b/fs/notify/group.c
index 63fc294a4692..bd2625bd88b4 100644
--- a/fs/notify/group.c
+++ b/fs/notify/group.c
@@ -33,9 +33,6 @@
33 */ 33 */
34void fsnotify_final_destroy_group(struct fsnotify_group *group) 34void fsnotify_final_destroy_group(struct fsnotify_group *group)
35{ 35{
36 /* clear the notification queue of all events */
37 fsnotify_flush_notify(group);
38
39 if (group->ops->free_group_priv) 36 if (group->ops->free_group_priv)
40 group->ops->free_group_priv(group); 37 group->ops->free_group_priv(group);
41 38
@@ -43,23 +40,30 @@ void fsnotify_final_destroy_group(struct fsnotify_group *group)
43} 40}
44 41
45/* 42/*
46 * Trying to get rid of a group. We need to first get rid of any outstanding 43 * Trying to get rid of a group. Remove all marks, flush all events and release
47 * allocations and then free the group. Remember that fsnotify_clear_marks_by_group 44 * the group reference.
48 * could miss marks that are being freed by inode and those marks could still 45 * Note that another thread calling fsnotify_clear_marks_by_group() may still
49 * hold a reference to this group (via group->num_marks) If we get into that 46 * hold a ref to the group.
50 * situtation, the fsnotify_final_destroy_group will get called when that final
51 * mark is freed.
52 */ 47 */
53static void fsnotify_destroy_group(struct fsnotify_group *group) 48void fsnotify_destroy_group(struct fsnotify_group *group)
54{ 49{
55 /* clear all inode marks for this group */ 50 /* clear all inode marks for this group */
56 fsnotify_clear_marks_by_group(group); 51 fsnotify_clear_marks_by_group(group);
57 52
58 synchronize_srcu(&fsnotify_mark_srcu); 53 synchronize_srcu(&fsnotify_mark_srcu);
59 54
60 /* past the point of no return, matches the initial value of 1 */ 55 /* clear the notification queue of all events */
61 if (atomic_dec_and_test(&group->num_marks)) 56 fsnotify_flush_notify(group);
62 fsnotify_final_destroy_group(group); 57
58 fsnotify_put_group(group);
59}
60
61/*
62 * Get reference to a group.
63 */
64void fsnotify_get_group(struct fsnotify_group *group)
65{
66 atomic_inc(&group->refcnt);
63} 67}
64 68
65/* 69/*
@@ -68,7 +72,7 @@ static void fsnotify_destroy_group(struct fsnotify_group *group)
68void fsnotify_put_group(struct fsnotify_group *group) 72void fsnotify_put_group(struct fsnotify_group *group)
69{ 73{
70 if (atomic_dec_and_test(&group->refcnt)) 74 if (atomic_dec_and_test(&group->refcnt))
71 fsnotify_destroy_group(group); 75 fsnotify_final_destroy_group(group);
72} 76}
73 77
74/* 78/*
@@ -84,21 +88,24 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops)
84 88
85 /* set to 0 when there a no external references to this group */ 89 /* set to 0 when there a no external references to this group */
86 atomic_set(&group->refcnt, 1); 90 atomic_set(&group->refcnt, 1);
87 /* 91 atomic_set(&group->num_marks, 0);
88 * hits 0 when there are no external references AND no marks for
89 * this group
90 */
91 atomic_set(&group->num_marks, 1);
92 92
93 mutex_init(&group->notification_mutex); 93 mutex_init(&group->notification_mutex);
94 INIT_LIST_HEAD(&group->notification_list); 94 INIT_LIST_HEAD(&group->notification_list);
95 init_waitqueue_head(&group->notification_waitq); 95 init_waitqueue_head(&group->notification_waitq);
96 group->max_events = UINT_MAX; 96 group->max_events = UINT_MAX;
97 97
98 spin_lock_init(&group->mark_lock); 98 mutex_init(&group->mark_mutex);
99 INIT_LIST_HEAD(&group->marks_list); 99 INIT_LIST_HEAD(&group->marks_list);
100 100
101 group->ops = ops; 101 group->ops = ops;
102 102
103 return group; 103 return group;
104} 104}
105
106int fsnotify_fasync(int fd, struct file *file, int on)
107{
108 struct fsnotify_group *group = file->private_data;
109
110 return fasync_helper(fd, file, on, &group->fsn_fa) >= 0 ? 0 : -EIO;
111}