diff options
author | Jan Kara <jack@suse.cz> | 2014-12-12 19:58:36 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-13 15:42:53 -0500 |
commit | 0809ab69a2782afac8c4d7f3d35cd123050aab9a (patch) | |
tree | 373ed29c67e9ffd46a53d04e6fc68f4d96b6ba2d /fs/notify/vfsmount_mark.c | |
parent | 820c12d5d6c0890bc93dd63893924a13041fdc35 (diff) |
fsnotify: unify inode and mount marks handling
There's a lot of common code in inode and mount marks handling. Factor it
out to a common helper function.
Signed-off-by: Jan Kara <jack@suse.cz>
Cc: Eric Paris <eparis@redhat.com>
Cc: Heinrich Schuchardt <xypron.glpk@gmx.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/notify/vfsmount_mark.c')
-rw-r--r-- | fs/notify/vfsmount_mark.c | 109 |
1 files changed, 19 insertions, 90 deletions
diff --git a/fs/notify/vfsmount_mark.c b/fs/notify/vfsmount_mark.c index faefa72a11eb..326b148e623c 100644 --- a/fs/notify/vfsmount_mark.c +++ b/fs/notify/vfsmount_mark.c | |||
@@ -32,31 +32,20 @@ | |||
32 | 32 | ||
33 | void fsnotify_clear_marks_by_mount(struct vfsmount *mnt) | 33 | void fsnotify_clear_marks_by_mount(struct vfsmount *mnt) |
34 | { | 34 | { |
35 | struct fsnotify_mark *mark, *lmark; | 35 | struct fsnotify_mark *mark; |
36 | struct hlist_node *n; | 36 | struct hlist_node *n; |
37 | struct mount *m = real_mount(mnt); | 37 | struct mount *m = real_mount(mnt); |
38 | LIST_HEAD(free_list); | 38 | LIST_HEAD(free_list); |
39 | 39 | ||
40 | spin_lock(&mnt->mnt_root->d_lock); | 40 | spin_lock(&mnt->mnt_root->d_lock); |
41 | hlist_for_each_entry_safe(mark, n, &m->mnt_fsnotify_marks, m.m_list) { | 41 | hlist_for_each_entry_safe(mark, n, &m->mnt_fsnotify_marks, obj_list) { |
42 | list_add(&mark->m.free_m_list, &free_list); | 42 | list_add(&mark->free_list, &free_list); |
43 | hlist_del_init_rcu(&mark->m.m_list); | 43 | hlist_del_init_rcu(&mark->obj_list); |
44 | fsnotify_get_mark(mark); | 44 | fsnotify_get_mark(mark); |
45 | } | 45 | } |
46 | spin_unlock(&mnt->mnt_root->d_lock); | 46 | spin_unlock(&mnt->mnt_root->d_lock); |
47 | 47 | ||
48 | list_for_each_entry_safe(mark, lmark, &free_list, m.free_m_list) { | 48 | fsnotify_destroy_marks(&free_list); |
49 | struct fsnotify_group *group; | ||
50 | |||
51 | spin_lock(&mark->lock); | ||
52 | fsnotify_get_group(mark->group); | ||
53 | group = mark->group; | ||
54 | spin_unlock(&mark->lock); | ||
55 | |||
56 | fsnotify_destroy_mark(mark, group); | ||
57 | fsnotify_put_mark(mark); | ||
58 | fsnotify_put_group(group); | ||
59 | } | ||
60 | } | 49 | } |
61 | 50 | ||
62 | void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group) | 51 | void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group) |
@@ -65,66 +54,35 @@ void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group) | |||
65 | } | 54 | } |
66 | 55 | ||
67 | /* | 56 | /* |
68 | * Recalculate the mask of events relevant to a given vfsmount locked. | ||
69 | */ | ||
70 | static void fsnotify_recalc_vfsmount_mask_locked(struct vfsmount *mnt) | ||
71 | { | ||
72 | struct mount *m = real_mount(mnt); | ||
73 | struct fsnotify_mark *mark; | ||
74 | __u32 new_mask = 0; | ||
75 | |||
76 | assert_spin_locked(&mnt->mnt_root->d_lock); | ||
77 | |||
78 | hlist_for_each_entry(mark, &m->mnt_fsnotify_marks, m.m_list) | ||
79 | new_mask |= mark->mask; | ||
80 | m->mnt_fsnotify_mask = new_mask; | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * Recalculate the mnt->mnt_fsnotify_mask, or the mask of all FS_* event types | 57 | * Recalculate the mnt->mnt_fsnotify_mask, or the mask of all FS_* event types |
85 | * any notifier is interested in hearing for this mount point | 58 | * any notifier is interested in hearing for this mount point |
86 | */ | 59 | */ |
87 | void fsnotify_recalc_vfsmount_mask(struct vfsmount *mnt) | 60 | void fsnotify_recalc_vfsmount_mask(struct vfsmount *mnt) |
88 | { | 61 | { |
62 | struct mount *m = real_mount(mnt); | ||
63 | |||
89 | spin_lock(&mnt->mnt_root->d_lock); | 64 | spin_lock(&mnt->mnt_root->d_lock); |
90 | fsnotify_recalc_vfsmount_mask_locked(mnt); | 65 | m->mnt_fsnotify_mask = fsnotify_recalc_mask(&m->mnt_fsnotify_marks); |
91 | spin_unlock(&mnt->mnt_root->d_lock); | 66 | spin_unlock(&mnt->mnt_root->d_lock); |
92 | } | 67 | } |
93 | 68 | ||
94 | void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark) | 69 | void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark) |
95 | { | 70 | { |
96 | struct vfsmount *mnt = mark->m.mnt; | 71 | struct vfsmount *mnt = mark->mnt; |
72 | struct mount *m = real_mount(mnt); | ||
97 | 73 | ||
98 | BUG_ON(!mutex_is_locked(&mark->group->mark_mutex)); | 74 | BUG_ON(!mutex_is_locked(&mark->group->mark_mutex)); |
99 | assert_spin_locked(&mark->lock); | 75 | assert_spin_locked(&mark->lock); |
100 | 76 | ||
101 | spin_lock(&mnt->mnt_root->d_lock); | 77 | spin_lock(&mnt->mnt_root->d_lock); |
102 | 78 | ||
103 | hlist_del_init_rcu(&mark->m.m_list); | 79 | hlist_del_init_rcu(&mark->obj_list); |
104 | mark->m.mnt = NULL; | 80 | mark->mnt = NULL; |
105 | |||
106 | fsnotify_recalc_vfsmount_mask_locked(mnt); | ||
107 | 81 | ||
82 | m->mnt_fsnotify_mask = fsnotify_recalc_mask(&m->mnt_fsnotify_marks); | ||
108 | spin_unlock(&mnt->mnt_root->d_lock); | 83 | spin_unlock(&mnt->mnt_root->d_lock); |
109 | } | 84 | } |
110 | 85 | ||
111 | static struct fsnotify_mark *fsnotify_find_vfsmount_mark_locked(struct fsnotify_group *group, | ||
112 | struct vfsmount *mnt) | ||
113 | { | ||
114 | struct mount *m = real_mount(mnt); | ||
115 | struct fsnotify_mark *mark; | ||
116 | |||
117 | assert_spin_locked(&mnt->mnt_root->d_lock); | ||
118 | |||
119 | hlist_for_each_entry(mark, &m->mnt_fsnotify_marks, m.m_list) { | ||
120 | if (mark->group == group) { | ||
121 | fsnotify_get_mark(mark); | ||
122 | return mark; | ||
123 | } | ||
124 | } | ||
125 | return NULL; | ||
126 | } | ||
127 | |||
128 | /* | 86 | /* |
129 | * given a group and vfsmount, find the mark associated with that combination. | 87 | * given a group and vfsmount, find the mark associated with that combination. |
130 | * if found take a reference to that mark and return it, else return NULL | 88 | * if found take a reference to that mark and return it, else return NULL |
@@ -132,10 +90,11 @@ static struct fsnotify_mark *fsnotify_find_vfsmount_mark_locked(struct fsnotify_ | |||
132 | struct fsnotify_mark *fsnotify_find_vfsmount_mark(struct fsnotify_group *group, | 90 | struct fsnotify_mark *fsnotify_find_vfsmount_mark(struct fsnotify_group *group, |
133 | struct vfsmount *mnt) | 91 | struct vfsmount *mnt) |
134 | { | 92 | { |
93 | struct mount *m = real_mount(mnt); | ||
135 | struct fsnotify_mark *mark; | 94 | struct fsnotify_mark *mark; |
136 | 95 | ||
137 | spin_lock(&mnt->mnt_root->d_lock); | 96 | spin_lock(&mnt->mnt_root->d_lock); |
138 | mark = fsnotify_find_vfsmount_mark_locked(group, mnt); | 97 | mark = fsnotify_find_mark(&m->mnt_fsnotify_marks, group); |
139 | spin_unlock(&mnt->mnt_root->d_lock); | 98 | spin_unlock(&mnt->mnt_root->d_lock); |
140 | 99 | ||
141 | return mark; | 100 | return mark; |
@@ -151,9 +110,7 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, | |||
151 | int allow_dups) | 110 | int allow_dups) |
152 | { | 111 | { |
153 | struct mount *m = real_mount(mnt); | 112 | struct mount *m = real_mount(mnt); |
154 | struct fsnotify_mark *lmark, *last = NULL; | 113 | int ret; |
155 | int ret = 0; | ||
156 | int cmp; | ||
157 | 114 | ||
158 | mark->flags |= FSNOTIFY_MARK_FLAG_VFSMOUNT; | 115 | mark->flags |= FSNOTIFY_MARK_FLAG_VFSMOUNT; |
159 | 116 | ||
@@ -161,37 +118,9 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, | |||
161 | assert_spin_locked(&mark->lock); | 118 | assert_spin_locked(&mark->lock); |
162 | 119 | ||
163 | spin_lock(&mnt->mnt_root->d_lock); | 120 | spin_lock(&mnt->mnt_root->d_lock); |
164 | 121 | mark->mnt = mnt; | |
165 | mark->m.mnt = mnt; | 122 | ret = fsnotify_add_mark_list(&m->mnt_fsnotify_marks, mark, allow_dups); |
166 | 123 | m->mnt_fsnotify_mask = fsnotify_recalc_mask(&m->mnt_fsnotify_marks); | |
167 | /* is mark the first mark? */ | ||
168 | if (hlist_empty(&m->mnt_fsnotify_marks)) { | ||
169 | hlist_add_head_rcu(&mark->m.m_list, &m->mnt_fsnotify_marks); | ||
170 | goto out; | ||
171 | } | ||
172 | |||
173 | /* should mark be in the middle of the current list? */ | ||
174 | hlist_for_each_entry(lmark, &m->mnt_fsnotify_marks, m.m_list) { | ||
175 | last = lmark; | ||
176 | |||
177 | if ((lmark->group == group) && !allow_dups) { | ||
178 | ret = -EEXIST; | ||
179 | goto out; | ||
180 | } | ||
181 | |||
182 | cmp = fsnotify_compare_groups(lmark->group, mark->group); | ||
183 | if (cmp < 0) | ||
184 | continue; | ||
185 | |||
186 | hlist_add_before_rcu(&mark->m.m_list, &lmark->m.m_list); | ||
187 | goto out; | ||
188 | } | ||
189 | |||
190 | BUG_ON(last == NULL); | ||
191 | /* mark should be the last entry. last is the current last entry */ | ||
192 | hlist_add_behind_rcu(&mark->m.m_list, &last->m.m_list); | ||
193 | out: | ||
194 | fsnotify_recalc_vfsmount_mask_locked(mnt); | ||
195 | spin_unlock(&mnt->mnt_root->d_lock); | 124 | spin_unlock(&mnt->mnt_root->d_lock); |
196 | 125 | ||
197 | return ret; | 126 | return ret; |