diff options
Diffstat (limited to 'fs/notify/group.c')
-rw-r--r-- | fs/notify/group.c | 49 |
1 files changed, 48 insertions, 1 deletions
diff --git a/fs/notify/group.c b/fs/notify/group.c index c6812953b968..a29d2fa67927 100644 --- a/fs/notify/group.c +++ b/fs/notify/group.c | |||
@@ -55,6 +55,29 @@ void fsnotify_recalc_global_mask(void) | |||
55 | } | 55 | } |
56 | 56 | ||
57 | /* | 57 | /* |
58 | * Update the group->mask by running all of the marks associated with this | ||
59 | * group and finding the bitwise | of all of the mark->mask. If we change | ||
60 | * the group->mask we need to update the global mask of events interesting | ||
61 | * to the system. | ||
62 | */ | ||
63 | void fsnotify_recalc_group_mask(struct fsnotify_group *group) | ||
64 | { | ||
65 | __u32 mask = 0; | ||
66 | __u32 old_mask = group->mask; | ||
67 | struct fsnotify_mark_entry *entry; | ||
68 | |||
69 | spin_lock(&group->mark_lock); | ||
70 | list_for_each_entry(entry, &group->mark_entries, g_list) | ||
71 | mask |= entry->mask; | ||
72 | spin_unlock(&group->mark_lock); | ||
73 | |||
74 | group->mask = mask; | ||
75 | |||
76 | if (old_mask != mask) | ||
77 | fsnotify_recalc_global_mask(); | ||
78 | } | ||
79 | |||
80 | /* | ||
58 | * Take a reference to a group so things found under the fsnotify_grp_mutex | 81 | * Take a reference to a group so things found under the fsnotify_grp_mutex |
59 | * can't get freed under us | 82 | * can't get freed under us |
60 | */ | 83 | */ |
@@ -66,7 +89,7 @@ static void fsnotify_get_group(struct fsnotify_group *group) | |||
66 | /* | 89 | /* |
67 | * Final freeing of a group | 90 | * Final freeing of a group |
68 | */ | 91 | */ |
69 | static void fsnotify_destroy_group(struct fsnotify_group *group) | 92 | void fsnotify_final_destroy_group(struct fsnotify_group *group) |
70 | { | 93 | { |
71 | if (group->ops->free_group_priv) | 94 | if (group->ops->free_group_priv) |
72 | group->ops->free_group_priv(group); | 95 | group->ops->free_group_priv(group); |
@@ -75,6 +98,24 @@ static void fsnotify_destroy_group(struct fsnotify_group *group) | |||
75 | } | 98 | } |
76 | 99 | ||
77 | /* | 100 | /* |
101 | * Trying to get rid of a group. We need to first get rid of any outstanding | ||
102 | * allocations and then free the group. Remember that fsnotify_clear_marks_by_group | ||
103 | * could miss marks that are being freed by inode and those marks could still | ||
104 | * hold a reference to this group (via group->num_marks) If we get into that | ||
105 | * situtation, the fsnotify_final_destroy_group will get called when that final | ||
106 | * mark is freed. | ||
107 | */ | ||
108 | static void fsnotify_destroy_group(struct fsnotify_group *group) | ||
109 | { | ||
110 | /* clear all inode mark entries for this group */ | ||
111 | fsnotify_clear_marks_by_group(group); | ||
112 | |||
113 | /* past the point of no return, matches the initial value of 1 */ | ||
114 | if (atomic_dec_and_test(&group->num_marks)) | ||
115 | fsnotify_final_destroy_group(group); | ||
116 | } | ||
117 | |||
118 | /* | ||
78 | * Remove this group from the global list of groups that will get events | 119 | * Remove this group from the global list of groups that will get events |
79 | * this can be done even if there are still references and things still using | 120 | * this can be done even if there are still references and things still using |
80 | * this group. This just stops the group from getting new events. | 121 | * this group. This just stops the group from getting new events. |
@@ -173,6 +214,10 @@ struct fsnotify_group *fsnotify_obtain_group(unsigned int group_num, __u32 mask, | |||
173 | group->group_num = group_num; | 214 | group->group_num = group_num; |
174 | group->mask = mask; | 215 | group->mask = mask; |
175 | 216 | ||
217 | spin_lock_init(&group->mark_lock); | ||
218 | atomic_set(&group->num_marks, 0); | ||
219 | INIT_LIST_HEAD(&group->mark_entries); | ||
220 | |||
176 | group->ops = ops; | 221 | group->ops = ops; |
177 | 222 | ||
178 | mutex_lock(&fsnotify_grp_mutex); | 223 | mutex_lock(&fsnotify_grp_mutex); |
@@ -188,6 +233,8 @@ struct fsnotify_group *fsnotify_obtain_group(unsigned int group_num, __u32 mask, | |||
188 | /* group not found, add a new one */ | 233 | /* group not found, add a new one */ |
189 | list_add_rcu(&group->group_list, &fsnotify_groups); | 234 | list_add_rcu(&group->group_list, &fsnotify_groups); |
190 | group->on_group_list = 1; | 235 | group->on_group_list = 1; |
236 | /* being on the fsnotify_groups list holds one num_marks */ | ||
237 | atomic_inc(&group->num_marks); | ||
191 | 238 | ||
192 | mutex_unlock(&fsnotify_grp_mutex); | 239 | mutex_unlock(&fsnotify_grp_mutex); |
193 | 240 | ||