diff options
author | Lino Sanfilippo <LinoSanfilippo@gmx.de> | 2011-06-14 11:29:48 -0400 |
---|---|---|
committer | Eric Paris <eparis@redhat.com> | 2012-12-11 13:29:45 -0500 |
commit | 104d06f08ea59247cb0e7e548c5a5d22d21dcfd5 (patch) | |
tree | 91f380d7fd26cbcab88635327c99524e9164d36f /fs | |
parent | 23e964c284ca0a767b80a30482bd53b059d30391 (diff) |
fsnotify: take groups mark_lock before mark lock
Race-free addition and removal of a mark to a groups mark list would be easier
if we could lock the mark list of group before we lock the specific mark.
This patch changes the order used to add/remove marks to/from mark lists from
1. mark->lock
2. group->mark_lock
3. inode->i_lock
to
1. group->mark_lock
2. mark->lock
3. inode->i_lock
Signed-off-by: Lino Sanfilippo <LinoSanfilippo@gmx.de>
Signed-off-by: Eric Paris <eparis@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/notify/mark.c | 26 |
1 files changed, 16 insertions, 10 deletions
diff --git a/fs/notify/mark.c b/fs/notify/mark.c index 3c7a1699df3d..32447dc06c07 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c | |||
@@ -127,20 +127,27 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark) | |||
127 | struct inode *inode = NULL; | 127 | struct inode *inode = NULL; |
128 | 128 | ||
129 | spin_lock(&mark->lock); | 129 | spin_lock(&mark->lock); |
130 | 130 | /* dont get the group from a mark that is not alive yet */ | |
131 | if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) { | ||
132 | spin_unlock(&mark->lock); | ||
133 | return; | ||
134 | } | ||
131 | fsnotify_get_group(mark->group); | 135 | fsnotify_get_group(mark->group); |
132 | group = mark->group; | 136 | group = mark->group; |
137 | spin_unlock(&mark->lock); | ||
138 | |||
139 | spin_lock(&group->mark_lock); | ||
140 | spin_lock(&mark->lock); | ||
133 | 141 | ||
134 | /* something else already called this function on this mark */ | 142 | /* something else already called this function on this mark */ |
135 | if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) { | 143 | if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) { |
136 | spin_unlock(&mark->lock); | 144 | spin_unlock(&mark->lock); |
145 | spin_unlock(&group->mark_lock); | ||
137 | goto put_group; | 146 | goto put_group; |
138 | } | 147 | } |
139 | 148 | ||
140 | mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; | 149 | mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; |
141 | 150 | ||
142 | spin_lock(&group->mark_lock); | ||
143 | |||
144 | if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) { | 151 | if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) { |
145 | inode = mark->i.inode; | 152 | inode = mark->i.inode; |
146 | fsnotify_destroy_inode_mark(mark); | 153 | fsnotify_destroy_inode_mark(mark); |
@@ -151,8 +158,8 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark) | |||
151 | 158 | ||
152 | list_del_init(&mark->g_list); | 159 | list_del_init(&mark->g_list); |
153 | 160 | ||
154 | spin_unlock(&group->mark_lock); | ||
155 | spin_unlock(&mark->lock); | 161 | spin_unlock(&mark->lock); |
162 | spin_unlock(&group->mark_lock); | ||
156 | 163 | ||
157 | spin_lock(&destroy_lock); | 164 | spin_lock(&destroy_lock); |
158 | list_add(&mark->destroy_list, &destroy_list); | 165 | list_add(&mark->destroy_list, &destroy_list); |
@@ -225,13 +232,13 @@ int fsnotify_add_mark(struct fsnotify_mark *mark, | |||
225 | 232 | ||
226 | /* | 233 | /* |
227 | * LOCKING ORDER!!!! | 234 | * LOCKING ORDER!!!! |
228 | * mark->lock | ||
229 | * group->mark_lock | 235 | * group->mark_lock |
236 | * mark->lock | ||
230 | * inode->i_lock | 237 | * inode->i_lock |
231 | */ | 238 | */ |
232 | spin_lock(&mark->lock); | ||
233 | spin_lock(&group->mark_lock); | 239 | spin_lock(&group->mark_lock); |
234 | 240 | ||
241 | spin_lock(&mark->lock); | ||
235 | mark->flags |= FSNOTIFY_MARK_FLAG_ALIVE; | 242 | mark->flags |= FSNOTIFY_MARK_FLAG_ALIVE; |
236 | 243 | ||
237 | fsnotify_get_group(group); | 244 | fsnotify_get_group(group); |
@@ -252,13 +259,12 @@ int fsnotify_add_mark(struct fsnotify_mark *mark, | |||
252 | BUG(); | 259 | BUG(); |
253 | } | 260 | } |
254 | 261 | ||
255 | spin_unlock(&group->mark_lock); | ||
256 | |||
257 | /* this will pin the object if appropriate */ | 262 | /* this will pin the object if appropriate */ |
258 | fsnotify_set_mark_mask_locked(mark, mark->mask); | 263 | fsnotify_set_mark_mask_locked(mark, mark->mask); |
259 | |||
260 | spin_unlock(&mark->lock); | 264 | spin_unlock(&mark->lock); |
261 | 265 | ||
266 | spin_unlock(&group->mark_lock); | ||
267 | |||
262 | if (inode) | 268 | if (inode) |
263 | __fsnotify_update_child_dentry_flags(inode); | 269 | __fsnotify_update_child_dentry_flags(inode); |
264 | 270 | ||
@@ -270,8 +276,8 @@ err: | |||
270 | mark->group = NULL; | 276 | mark->group = NULL; |
271 | atomic_dec(&group->num_marks); | 277 | atomic_dec(&group->num_marks); |
272 | 278 | ||
273 | spin_unlock(&group->mark_lock); | ||
274 | spin_unlock(&mark->lock); | 279 | spin_unlock(&mark->lock); |
280 | spin_unlock(&group->mark_lock); | ||
275 | 281 | ||
276 | spin_lock(&destroy_lock); | 282 | spin_lock(&destroy_lock); |
277 | list_add(&mark->destroy_list, &destroy_list); | 283 | list_add(&mark->destroy_list, &destroy_list); |