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 | |
| 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>
| -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); |
