From 112ecd54045f14aff2c42622fabb4ffab9f0d8ff Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Sun, 22 Oct 2017 11:13:10 +0300 Subject: [PATCH] fsnotify: queue an overflow event on failure to allocate event In low memory situations, non permissions events are silently dropped. It is better to queue an OVERFLOW event in that case to let the listener know about the lost event. With this change, an application can now get an FAN_Q_OVERFLOW event, even if it used flag FAN_UNLIMITED_QUEUE on fanotify_init(). Signed-off-by: Amir Goldstein --- fs/notify/fanotify/fanotify.c | 10 ++++++++-- fs/notify/inotify/inotify_fsnotify.c | 8 ++++++-- fs/notify/notification.c | 3 ++- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index 2fa99aeaa095..412a32838f58 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -212,8 +212,14 @@ static int fanotify_handle_event(struct fsnotify_group *group, mask); event = fanotify_alloc_event(inode, mask, data); - if (unlikely(!event)) - return -ENOMEM; + if (unlikely(!event)) { + if (mask & FAN_ALL_PERM_EVENTS) + return -ENOMEM; + + /* Queue an overflow event on failure to allocate event */ + fsnotify_add_event(group, group->overflow_event, NULL); + return 0; + } fsn_event = &event->fse; ret = fsnotify_add_event(group, fsn_event, fanotify_merge); diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c index 8b73332735ba..d1837da2ef15 100644 --- a/fs/notify/inotify/inotify_fsnotify.c +++ b/fs/notify/inotify/inotify_fsnotify.c @@ -99,8 +99,11 @@ int inotify_handle_event(struct fsnotify_group *group, fsn_mark); event = kmalloc(alloc_len, GFP_KERNEL); - if (unlikely(!event)) - return -ENOMEM; + if (unlikely(!event)) { + /* Queue an overflow event on failure to allocate event */ + fsnotify_add_event(group, group->overflow_event, NULL); + goto oneshot; + } fsn_event = &event->fse; fsnotify_init_event(fsn_event, inode, mask); @@ -116,6 +119,7 @@ int inotify_handle_event(struct fsnotify_group *group, fsnotify_destroy_event(group, fsn_event); } +oneshot: if (inode_mark->mask & IN_ONESHOT) fsnotify_destroy_mark(inode_mark, group); diff --git a/fs/notify/notification.c b/fs/notify/notification.c index 66f85c651c52..5abd69976a47 100644 --- a/fs/notify/notification.c +++ b/fs/notify/notification.c @@ -111,7 +111,8 @@ int fsnotify_add_event(struct fsnotify_group *group, return 2; } - if (group->q_len >= group->max_events) { + if (group->q_len >= group->max_events || + event == group->overflow_event) { ret = 2; /* Queue overflow event only if it isn't already queued */ if (!list_empty(&group->overflow_event->list)) { -- 2.7.4