aboutsummaryrefslogtreecommitdiffstats
path: root/fs/notify
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2016-10-07 19:56:49 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-10-07 21:46:26 -0400
commit1404ff3cc3a14cb1fe8535e30b87d20da9513767 (patch)
treeb9cd46c15ce1cba5f29607455bdb8439bf242273 /fs/notify
parent87840a2b7e048018d18d60bdac5c09224de85370 (diff)
fsnotify: drop notification_mutex before destroying event
fsnotify_flush_notify() and fanotify_release() destroy notification event while holding notification_mutex. The destruction of fanotify event includes a path_put() call which may end up calling into a filesystem to delete an inode if we happen to be the last holders of dentry reference which happens to be the last holder of inode reference. That in turn may violate lock ordering for some filesystems since notification_mutex is also acquired e. g. during write when generating fanotify event. Also this is the only thing that forces notification_mutex to be a sleeping lock. So drop notification_mutex before destroying a notification event. Link: http://lkml.kernel.org/r/1473797711-14111-4-git-send-email-jack@suse.cz Signed-off-by: Jan Kara <jack@suse.cz> Cc: Miklos Szeredi <mszeredi@redhat.com> Cc: Lino Sanfilippo <LinoSanfilippo@gmx.de> Cc: Eric Paris <eparis@redhat.com> Cc: Al Viro <viro@ZenIV.linux.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/notify')
-rw-r--r--fs/notify/fanotify/fanotify_user.c6
-rw-r--r--fs/notify/notification.c2
2 files changed, 6 insertions, 2 deletions
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index a64313868d3a..46d135c4988f 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -390,9 +390,11 @@ static int fanotify_release(struct inode *ignored, struct file *file)
390 mutex_lock(&group->notification_mutex); 390 mutex_lock(&group->notification_mutex);
391 while (!fsnotify_notify_queue_is_empty(group)) { 391 while (!fsnotify_notify_queue_is_empty(group)) {
392 fsn_event = fsnotify_remove_first_event(group); 392 fsn_event = fsnotify_remove_first_event(group);
393 if (!(fsn_event->mask & FAN_ALL_PERM_EVENTS)) 393 if (!(fsn_event->mask & FAN_ALL_PERM_EVENTS)) {
394 mutex_unlock(&group->notification_mutex);
394 fsnotify_destroy_event(group, fsn_event); 395 fsnotify_destroy_event(group, fsn_event);
395 else 396 mutex_lock(&group->notification_mutex);
397 } else
396 FANOTIFY_PE(fsn_event)->response = FAN_ALLOW; 398 FANOTIFY_PE(fsn_event)->response = FAN_ALLOW;
397 } 399 }
398 mutex_unlock(&group->notification_mutex); 400 mutex_unlock(&group->notification_mutex);
diff --git a/fs/notify/notification.c b/fs/notify/notification.c
index e455e83ceeeb..7d563dea52a4 100644
--- a/fs/notify/notification.c
+++ b/fs/notify/notification.c
@@ -178,7 +178,9 @@ void fsnotify_flush_notify(struct fsnotify_group *group)
178 mutex_lock(&group->notification_mutex); 178 mutex_lock(&group->notification_mutex);
179 while (!fsnotify_notify_queue_is_empty(group)) { 179 while (!fsnotify_notify_queue_is_empty(group)) {
180 event = fsnotify_remove_first_event(group); 180 event = fsnotify_remove_first_event(group);
181 mutex_unlock(&group->notification_mutex);
181 fsnotify_destroy_event(group, event); 182 fsnotify_destroy_event(group, event);
183 mutex_lock(&group->notification_mutex);
182 } 184 }
183 mutex_unlock(&group->notification_mutex); 185 mutex_unlock(&group->notification_mutex);
184} 186}