aboutsummaryrefslogtreecommitdiffstats
path: root/fs/notify/group.c
diff options
context:
space:
mode:
authorLino Sanfilippo <LinoSanfilippo@gmx.de>2011-06-14 11:29:47 -0400
committerEric Paris <eparis@redhat.com>2012-12-11 13:29:44 -0500
commit23e964c284ca0a767b80a30482bd53b059d30391 (patch)
tree43d3cd8c5836a3c43f853366bce51f621773dedc /fs/notify/group.c
parent986129520479d689962a42c31acdeaf854ac91f5 (diff)
fsnotify: use reference counting for groups
Get a group ref for each mark that is added to the groups list and release that ref when the mark is freed in fsnotify_put_mark(). We also use get a group reference for duplicated marks and for private event data. Now we dont free a group any more when the number of marks becomes 0 but when the groups ref count does. Since this will only happen when all marks are removed from a groups mark list, we dont have to set the groups number of marks to 1 at group creation. Beside clearing all marks in fsnotify_destroy_group() we do also flush the groups event queue. This is since events may hold references to groups (due to private event data) and we have to put those references first before we get a chance to put the final ref, which will result in a call to fsnotify_final_destroy_group(). Signed-off-by: Lino Sanfilippo <LinoSanfilippo@gmx.de> Signed-off-by: Eric Paris <eparis@redhat.com>
Diffstat (limited to 'fs/notify/group.c')
-rw-r--r--fs/notify/group.c28
1 files changed, 10 insertions, 18 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 */
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,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 */
53void fsnotify_destroy_group(struct fsnotify_group *group) 48void 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)
76void fsnotify_put_group(struct fsnotify_group *group) 72void 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);