diff options
author | Jan Kara <jack@suse.cz> | 2016-12-21 05:50:39 -0500 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2017-04-10 11:37:35 -0400 |
commit | e7253760587e8523fe1e8ede092a620f1403f2e8 (patch) | |
tree | 7bcf5c7a849efedfb497da81e044bbe958d88454 /fs/notify | |
parent | 08991e83b7286635167bab40927665a90fb00d81 (diff) |
inotify: Do not drop mark reference under idr_lock
Dropping mark reference can result in mark being freed. Although it
should not happen in inotify_remove_from_idr() since caller should hold
another reference, just don't risk lock up just after WARN_ON
unnecessarily. Also fold do_inotify_remove_from_idr() into the single
callsite as that function really is just two lines of real code.
Reviewed-by: Miklos Szeredi <mszeredi@redhat.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/notify')
-rw-r--r-- | fs/notify/inotify/inotify_user.c | 24 |
1 files changed, 6 insertions, 18 deletions
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index b82a507a5367..f9113e57ef33 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c | |||
@@ -395,21 +395,6 @@ static struct inotify_inode_mark *inotify_idr_find(struct fsnotify_group *group, | |||
395 | return i_mark; | 395 | return i_mark; |
396 | } | 396 | } |
397 | 397 | ||
398 | static void do_inotify_remove_from_idr(struct fsnotify_group *group, | ||
399 | struct inotify_inode_mark *i_mark) | ||
400 | { | ||
401 | struct idr *idr = &group->inotify_data.idr; | ||
402 | spinlock_t *idr_lock = &group->inotify_data.idr_lock; | ||
403 | int wd = i_mark->wd; | ||
404 | |||
405 | assert_spin_locked(idr_lock); | ||
406 | |||
407 | idr_remove(idr, wd); | ||
408 | |||
409 | /* removed from the idr, drop that ref */ | ||
410 | fsnotify_put_mark(&i_mark->fsn_mark); | ||
411 | } | ||
412 | |||
413 | /* | 398 | /* |
414 | * Remove the mark from the idr (if present) and drop the reference | 399 | * Remove the mark from the idr (if present) and drop the reference |
415 | * on the mark because it was in the idr. | 400 | * on the mark because it was in the idr. |
@@ -417,6 +402,7 @@ static void do_inotify_remove_from_idr(struct fsnotify_group *group, | |||
417 | static void inotify_remove_from_idr(struct fsnotify_group *group, | 402 | static void inotify_remove_from_idr(struct fsnotify_group *group, |
418 | struct inotify_inode_mark *i_mark) | 403 | struct inotify_inode_mark *i_mark) |
419 | { | 404 | { |
405 | struct idr *idr = &group->inotify_data.idr; | ||
420 | spinlock_t *idr_lock = &group->inotify_data.idr_lock; | 406 | spinlock_t *idr_lock = &group->inotify_data.idr_lock; |
421 | struct inotify_inode_mark *found_i_mark = NULL; | 407 | struct inotify_inode_mark *found_i_mark = NULL; |
422 | int wd; | 408 | int wd; |
@@ -468,13 +454,15 @@ static void inotify_remove_from_idr(struct fsnotify_group *group, | |||
468 | BUG(); | 454 | BUG(); |
469 | } | 455 | } |
470 | 456 | ||
471 | do_inotify_remove_from_idr(group, i_mark); | 457 | idr_remove(idr, wd); |
458 | /* Removed from the idr, drop that ref. */ | ||
459 | fsnotify_put_mark(&i_mark->fsn_mark); | ||
472 | out: | 460 | out: |
461 | i_mark->wd = -1; | ||
462 | spin_unlock(idr_lock); | ||
473 | /* match the ref taken by inotify_idr_find_locked() */ | 463 | /* match the ref taken by inotify_idr_find_locked() */ |
474 | if (found_i_mark) | 464 | if (found_i_mark) |
475 | fsnotify_put_mark(&found_i_mark->fsn_mark); | 465 | fsnotify_put_mark(&found_i_mark->fsn_mark); |
476 | i_mark->wd = -1; | ||
477 | spin_unlock(idr_lock); | ||
478 | } | 466 | } |
479 | 467 | ||
480 | /* | 468 | /* |