[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <2ddcc9f8d1fde48d085318a6b5a889289d8871d8.1731684329.git.josef@toxicpanda.com>
Date: Fri, 15 Nov 2024 10:30:16 -0500
From: Josef Bacik <josef@...icpanda.com>
To: kernel-team@...com,
linux-fsdevel@...r.kernel.org,
jack@...e.cz,
amir73il@...il.com,
brauner@...nel.org,
torvalds@...ux-foundation.org,
viro@...iv.linux.org.uk,
linux-xfs@...r.kernel.org,
linux-btrfs@...r.kernel.org,
linux-mm@...ck.org,
linux-ext4@...r.kernel.org
Subject: [PATCH v8 03/19] fsnotify: add helper to check if file is actually being watched
From: Amir Goldstein <amir73il@...il.com>
So far, we set FMODE_NONOTIFY_ flags at open time if we know that there
are no permission event watchers at all on the filesystem, but lack of
FMODE_NONOTIFY_ flags does not mean that the file is actually watched.
To make the flags more accurate we add a helper that checks if the
file's inode, mount, sb or parent are being watched for a set of events.
This is going to be used for setting FMODE_NONOTIFY_HSM only when the
specific file is actually watched for pre-content events.
Signed-off-by: Amir Goldstein <amir73il@...il.com>
---
fs/notify/fsnotify.c | 36 +++++++++++++++++++++++++-------
include/linux/fsnotify_backend.h | 7 +++++++
2 files changed, 36 insertions(+), 7 deletions(-)
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index f976949d2634..33576a848a9f 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -193,16 +193,38 @@ static bool fsnotify_event_needs_parent(struct inode *inode, __u32 mnt_mask,
return mask & marks_mask;
}
-/* Are there any inode/mount/sb objects that are interested in this event? */
-static inline bool fsnotify_object_watched(struct inode *inode, __u32 mnt_mask,
- __u32 mask)
+/* Are there any inode/mount/sb objects that watch for these events? */
+static inline __u32 fsnotify_object_watched(struct inode *inode, __u32 mnt_mask,
+ __u32 events_mask)
{
__u32 marks_mask = READ_ONCE(inode->i_fsnotify_mask) | mnt_mask |
READ_ONCE(inode->i_sb->s_fsnotify_mask);
- return mask & marks_mask & ALL_FSNOTIFY_EVENTS;
+ return events_mask & marks_mask;
}
+/* Are there any inode/mount/sb/parent objects that watch for these events? */
+__u32 fsnotify_file_object_watched(struct file *file, __u32 events_mask)
+{
+ struct dentry *dentry = file->f_path.dentry;
+ struct dentry *parent;
+ __u32 marks_mask, mnt_mask =
+ READ_ONCE(real_mount(file->f_path.mnt)->mnt_fsnotify_mask);
+
+ marks_mask = fsnotify_object_watched(d_inode(dentry), mnt_mask,
+ events_mask);
+
+ if (likely(!(dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED)))
+ return marks_mask;
+
+ parent = dget_parent(dentry);
+ marks_mask |= fsnotify_inode_watches_children(d_inode(parent));
+ dput(parent);
+
+ return marks_mask & events_mask;
+}
+EXPORT_SYMBOL_GPL(fsnotify_file_object_watched);
+
/*
* Notify this dentry's parent about a child's events with child name info
* if parent is watching or if inode/sb/mount are interested in events with
@@ -221,7 +243,7 @@ int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data,
struct dentry *parent;
bool parent_watched = dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED;
bool parent_needed, parent_interested;
- __u32 p_mask;
+ __u32 p_mask, test_mask = mask & ALL_FSNOTIFY_EVENTS;
struct inode *p_inode = NULL;
struct name_snapshot name;
struct qstr *file_name = NULL;
@@ -229,7 +251,7 @@ int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data,
/* Optimize the likely case of nobody watching this path */
if (likely(!parent_watched &&
- !fsnotify_object_watched(inode, mnt_mask, mask)))
+ !fsnotify_object_watched(inode, mnt_mask, test_mask)))
return 0;
parent = NULL;
@@ -248,7 +270,7 @@ int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data,
* Include parent/name in notification either if some notification
* groups require parent info or the parent is interested in this event.
*/
- parent_interested = mask & p_mask & ALL_FSNOTIFY_EVENTS;
+ parent_interested = p_mask & test_mask;
if (parent_needed || parent_interested) {
/* When notifying parent, child should be passed as data */
WARN_ON_ONCE(inode != fsnotify_data_inode(data, data_type));
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index 3ecf7768e577..99d81c3c11d7 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -855,8 +855,15 @@ static inline void fsnotify_init_event(struct fsnotify_event *event)
INIT_LIST_HEAD(&event->list);
}
+__u32 fsnotify_file_object_watched(struct file *file, __u32 mask);
+
#else
+static inline __u32 fsnotify_file_object_watched(struct file *file, __u32 mask)
+{
+ return 0;
+}
+
static inline int fsnotify(__u32 mask, const void *data, int data_type,
struct inode *dir, const struct qstr *name,
struct inode *inode, u32 cookie)
--
2.43.0
Powered by blists - more mailing lists