diff options
Diffstat (limited to 'fs/notify/group.c')
-rw-r--r-- | fs/notify/group.c | 47 |
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 | */ |
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,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 | */ |
53 | static void fsnotify_destroy_group(struct fsnotify_group *group) | 48 | void 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 | */ | ||
64 | void 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) | |||
68 | void fsnotify_put_group(struct fsnotify_group *group) | 72 | void 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 | |||
106 | int 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 | } | ||