From 2cc6fe16130e482176de105d6f906cf0047e2db8 Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Tue, 23 Apr 2019 18:24:12 +0300 Subject: [PATCH] fsnotify: do not generate duplicate fsnotify events for "fake" path Overlayfs "fake" path is used for stacked file operations on underlying files. Operations on files with "fake" path must not generate events on mount marks and on parent watches, because those events have already been generated at overlayfs layer. The reported event->fd for inode/sb marks will have the wrong path (overlayfs path), but we have no choice but to report them anyway. Link: https://lore.kernel.org/linux-fsdevel/20190423065024.12695-1-jencce.kernel@gmail.com/ Reported-by: Murphy Zhou Fixes: d1d04ef8572b ("ovl: stack file ops") Signed-off-by: Amir Goldstein --- fs/notify/fsnotify.c | 18 ++++++++++++++++-- include/linux/fsnotify.h | 14 +++++++++++--- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index df06f3da166c..ee5e4ea7e5ca 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -335,9 +335,23 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is, __u32 test_mask = (mask & ALL_FSNOTIFY_EVENTS); if (data_is == FSNOTIFY_EVENT_PATH) { - mnt = real_mount(((const struct path *)data)->mnt); - mnt_or_sb_mask |= mnt->mnt_fsnotify_mask; + const struct path *path = (const struct path *)data; + + /* + * Overlayfs "fake" path used for stacked file operations on + * underlying files must not generate events on mount marks, + * because those events have already been generated at + * overlayfs layer. The reported event->fd for inode/sb marks + * will have the wrong path (overlayfs path), but we have no + * choice but to report them anyway. + */ + if (likely((mask & FS_EVENT_ON_CHILD) || + to_tell == d_inode(path->dentry))) { + mnt = real_mount(((const struct path *)data)->mnt); + mnt_or_sb_mask |= mnt->mnt_fsnotify_mask; + } } + /* An event "on child" is not intended for a mount/sb mark */ if (mask & FS_EVENT_ON_CHILD) mnt_or_sb_mask = 0; diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index 09587e2860b5..2a197799c06d 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -47,10 +47,18 @@ static inline int fsnotify_parent(const struct path *path, static inline int fsnotify_path(struct inode *inode, const struct path *path, __u32 mask) { - int ret = fsnotify_parent(path, NULL, mask); + /* + * Overlayfs "fake" path used for stacked file operations on underlying + * files must not generate events on parent, because those events have + * already been generated at overlayfs layer. + */ + if (likely(inode == d_inode(path->dentry))) { + int ret = fsnotify_parent(path, NULL, mask); + + if (ret) + return ret; + } - if (ret) - return ret; return fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0); } -- 2.17.1