summaryrefslogtreecommitdiffstats
path: root/fs/notify
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2016-12-21 05:50:39 -0500
committerJan Kara <jack@suse.cz>2017-04-10 11:37:35 -0400
commite7253760587e8523fe1e8ede092a620f1403f2e8 (patch)
tree7bcf5c7a849efedfb497da81e044bbe958d88454 /fs/notify
parent08991e83b7286635167bab40927665a90fb00d81 (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.c24
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
398static 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,
417static void inotify_remove_from_idr(struct fsnotify_group *group, 402static 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);
472out: 460out:
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/*