diff options
-rw-r--r-- | fs/notify/group.c | 28 | ||||
-rw-r--r-- | fs/notify/inotify/inotify_fsnotify.c | 2 | ||||
-rw-r--r-- | fs/notify/inotify/inotify_user.c | 1 | ||||
-rw-r--r-- | fs/notify/mark.c | 24 |
4 files changed, 27 insertions, 28 deletions
diff --git a/fs/notify/group.c b/fs/notify/group.c index 1d57c35f1043..354044c47e23 100644 --- a/fs/notify/group.c +++ b/fs/notify/group.c | |||
@@ -33,9 +33,6 @@ | |||
33 | */ | 33 | */ |
34 | void fsnotify_final_destroy_group(struct fsnotify_group *group) | 34 | void 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,12 +40,10 @@ 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 | */ |
53 | void fsnotify_destroy_group(struct fsnotify_group *group) | 48 | void fsnotify_destroy_group(struct fsnotify_group *group) |
54 | { | 49 | { |
@@ -57,9 +52,10 @@ void fsnotify_destroy_group(struct fsnotify_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); | ||
63 | } | 59 | } |
64 | 60 | ||
65 | /* | 61 | /* |
@@ -76,7 +72,7 @@ void fsnotify_get_group(struct fsnotify_group *group) | |||
76 | void fsnotify_put_group(struct fsnotify_group *group) | 72 | void fsnotify_put_group(struct fsnotify_group *group) |
77 | { | 73 | { |
78 | if (atomic_dec_and_test(&group->refcnt)) | 74 | if (atomic_dec_and_test(&group->refcnt)) |
79 | fsnotify_destroy_group(group); | 75 | fsnotify_final_destroy_group(group); |
80 | } | 76 | } |
81 | 77 | ||
82 | /* | 78 | /* |
@@ -92,11 +88,7 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops) | |||
92 | 88 | ||
93 | /* 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 */ |
94 | atomic_set(&group->refcnt, 1); | 90 | atomic_set(&group->refcnt, 1); |
95 | /* | 91 | atomic_set(&group->num_marks, 0); |
96 | * hits 0 when there are no external references AND no marks for | ||
97 | * this group | ||
98 | */ | ||
99 | atomic_set(&group->num_marks, 1); | ||
100 | 92 | ||
101 | mutex_init(&group->notification_mutex); | 93 | mutex_init(&group->notification_mutex); |
102 | INIT_LIST_HEAD(&group->notification_list); | 94 | INIT_LIST_HEAD(&group->notification_list); |
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c index e3cbd746f64a..74977fbf5aae 100644 --- a/fs/notify/inotify/inotify_fsnotify.c +++ b/fs/notify/inotify/inotify_fsnotify.c | |||
@@ -118,6 +118,7 @@ static int inotify_handle_event(struct fsnotify_group *group, | |||
118 | 118 | ||
119 | fsn_event_priv = &event_priv->fsnotify_event_priv_data; | 119 | fsn_event_priv = &event_priv->fsnotify_event_priv_data; |
120 | 120 | ||
121 | fsnotify_get_group(group); | ||
121 | fsn_event_priv->group = group; | 122 | fsn_event_priv->group = group; |
122 | event_priv->wd = wd; | 123 | event_priv->wd = wd; |
123 | 124 | ||
@@ -210,6 +211,7 @@ void inotify_free_event_priv(struct fsnotify_event_private_data *fsn_event_priv) | |||
210 | event_priv = container_of(fsn_event_priv, struct inotify_event_private_data, | 211 | event_priv = container_of(fsn_event_priv, struct inotify_event_private_data, |
211 | fsnotify_event_priv_data); | 212 | fsnotify_event_priv_data); |
212 | 213 | ||
214 | fsnotify_put_group(fsn_event_priv->group); | ||
213 | kmem_cache_free(event_priv_cachep, event_priv); | 215 | kmem_cache_free(event_priv_cachep, event_priv); |
214 | } | 216 | } |
215 | 217 | ||
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index dbafbfc8ceca..246250f1db7a 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c | |||
@@ -531,6 +531,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark, | |||
531 | 531 | ||
532 | fsn_event_priv = &event_priv->fsnotify_event_priv_data; | 532 | fsn_event_priv = &event_priv->fsnotify_event_priv_data; |
533 | 533 | ||
534 | fsnotify_get_group(group); | ||
534 | fsn_event_priv->group = group; | 535 | fsn_event_priv->group = group; |
535 | event_priv->wd = i_mark->wd; | 536 | event_priv->wd = i_mark->wd; |
536 | 537 | ||
diff --git a/fs/notify/mark.c b/fs/notify/mark.c index f104d565b682..3c7a1699df3d 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c | |||
@@ -109,8 +109,11 @@ void fsnotify_get_mark(struct fsnotify_mark *mark) | |||
109 | 109 | ||
110 | void fsnotify_put_mark(struct fsnotify_mark *mark) | 110 | void fsnotify_put_mark(struct fsnotify_mark *mark) |
111 | { | 111 | { |
112 | if (atomic_dec_and_test(&mark->refcnt)) | 112 | if (atomic_dec_and_test(&mark->refcnt)) { |
113 | if (mark->group) | ||
114 | fsnotify_put_group(mark->group); | ||
113 | mark->free_mark(mark); | 115 | mark->free_mark(mark); |
116 | } | ||
114 | } | 117 | } |
115 | 118 | ||
116 | /* | 119 | /* |
@@ -125,12 +128,13 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark) | |||
125 | 128 | ||
126 | spin_lock(&mark->lock); | 129 | spin_lock(&mark->lock); |
127 | 130 | ||
131 | fsnotify_get_group(mark->group); | ||
128 | group = mark->group; | 132 | group = mark->group; |
129 | 133 | ||
130 | /* something else already called this function on this mark */ | 134 | /* something else already called this function on this mark */ |
131 | if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) { | 135 | if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) { |
132 | spin_unlock(&mark->lock); | 136 | spin_unlock(&mark->lock); |
133 | return; | 137 | goto put_group; |
134 | } | 138 | } |
135 | 139 | ||
136 | mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; | 140 | mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; |
@@ -177,19 +181,15 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark) | |||
177 | 181 | ||
178 | if (inode && (mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED)) | 182 | if (inode && (mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED)) |
179 | iput(inode); | 183 | iput(inode); |
180 | |||
181 | /* | 184 | /* |
182 | * We don't necessarily have a ref on mark from caller so the above iput | 185 | * We don't necessarily have a ref on mark from caller so the above iput |
183 | * may have already destroyed it. Don't touch from now on. | 186 | * may have already destroyed it. Don't touch from now on. |
184 | */ | 187 | */ |
185 | 188 | ||
186 | /* | 189 | atomic_dec(&group->num_marks); |
187 | * it's possible that this group tried to destroy itself, but this | 190 | |
188 | * this mark was simultaneously being freed by inode. If that's the | 191 | put_group: |
189 | * case, we finish freeing the group here. | 192 | fsnotify_put_group(group); |
190 | */ | ||
191 | if (unlikely(atomic_dec_and_test(&group->num_marks))) | ||
192 | fsnotify_final_destroy_group(group); | ||
193 | } | 193 | } |
194 | 194 | ||
195 | void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask) | 195 | void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask) |
@@ -234,6 +234,7 @@ int fsnotify_add_mark(struct fsnotify_mark *mark, | |||
234 | 234 | ||
235 | mark->flags |= FSNOTIFY_MARK_FLAG_ALIVE; | 235 | mark->flags |= FSNOTIFY_MARK_FLAG_ALIVE; |
236 | 236 | ||
237 | fsnotify_get_group(group); | ||
237 | mark->group = group; | 238 | mark->group = group; |
238 | list_add(&mark->g_list, &group->marks_list); | 239 | list_add(&mark->g_list, &group->marks_list); |
239 | atomic_inc(&group->num_marks); | 240 | atomic_inc(&group->num_marks); |
@@ -265,6 +266,7 @@ int fsnotify_add_mark(struct fsnotify_mark *mark, | |||
265 | err: | 266 | err: |
266 | mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; | 267 | mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; |
267 | list_del_init(&mark->g_list); | 268 | list_del_init(&mark->g_list); |
269 | fsnotify_put_group(group); | ||
268 | mark->group = NULL; | 270 | mark->group = NULL; |
269 | atomic_dec(&group->num_marks); | 271 | atomic_dec(&group->num_marks); |
270 | 272 | ||
@@ -317,6 +319,8 @@ void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *ol | |||
317 | assert_spin_locked(&old->lock); | 319 | assert_spin_locked(&old->lock); |
318 | new->i.inode = old->i.inode; | 320 | new->i.inode = old->i.inode; |
319 | new->m.mnt = old->m.mnt; | 321 | new->m.mnt = old->m.mnt; |
322 | if (old->group) | ||
323 | fsnotify_get_group(old->group); | ||
320 | new->group = old->group; | 324 | new->group = old->group; |
321 | new->mask = old->mask; | 325 | new->mask = old->mask; |
322 | new->free_mark = old->free_mark; | 326 | new->free_mark = old->free_mark; |