Skip to content

Commit 318652e

Browse files
amir73iljankara
authored andcommitted
fsnotify: check if file is actually being watched for pre-content events on open
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. For pre-content events, it is possible to optimize things so that we don't bother trying to send pre-content events if file was not watched (through sb, mnt, parent or inode itself) on open. Set FMODE_NONOTIFY_ flags according to that. Signed-off-by: Amir Goldstein <[email protected]> Signed-off-by: Jan Kara <[email protected]> Link: https://patch.msgid.link/2ddcc9f8d1fde48d085318a6b5a889289d8871d8.1731684329.git.josef@toxicpanda.com
1 parent a94204f commit 318652e

File tree

2 files changed

+29
-3
lines changed

2 files changed

+29
-3
lines changed

fs/notify/fsnotify.c

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ static bool fsnotify_event_needs_parent(struct inode *inode, __u32 mnt_mask,
193193
return mask & marks_mask;
194194
}
195195

196-
/* Are there any inode/mount/sb objects that are interested in this event? */
196+
/* Are there any inode/mount/sb objects that watch for these events? */
197197
static inline bool fsnotify_object_watched(struct inode *inode, __u32 mnt_mask,
198198
__u32 mask)
199199
{
@@ -632,7 +632,9 @@ EXPORT_SYMBOL_GPL(fsnotify);
632632
*/
633633
void file_set_fsnotify_mode(struct file *file)
634634
{
635-
struct super_block *sb = file->f_path.dentry->d_sb;
635+
struct dentry *dentry = file->f_path.dentry, *parent;
636+
struct super_block *sb = dentry->d_sb;
637+
__u32 mnt_mask, p_mask;
636638

637639
/* Is it a file opened by fanotify? */
638640
if (FMODE_FSNOTIFY_NONE(file->f_mode))
@@ -653,11 +655,32 @@ void file_set_fsnotify_mode(struct file *file)
653655
* If there are permission event watchers but no pre-content event
654656
* watchers, set FMODE_NONOTIFY | FMODE_NONOTIFY_PERM to indicate that.
655657
*/
656-
if (likely(!fsnotify_sb_has_priority_watchers(sb,
658+
if ((!d_is_dir(dentry) && !d_is_reg(dentry)) ||
659+
likely(!fsnotify_sb_has_priority_watchers(sb,
657660
FSNOTIFY_PRIO_PRE_CONTENT))) {
658661
file->f_mode |= FMODE_NONOTIFY | FMODE_NONOTIFY_PERM;
659662
return;
660663
}
664+
665+
/*
666+
* OK, there are some pre-content watchers. Check if anybody is
667+
* watching for pre-content events on *this* file.
668+
*/
669+
mnt_mask = READ_ONCE(real_mount(file->f_path.mnt)->mnt_fsnotify_mask);
670+
if (unlikely(fsnotify_object_watched(d_inode(dentry), mnt_mask,
671+
FSNOTIFY_PRE_CONTENT_EVENTS)))
672+
return;
673+
674+
/* Is parent watching for pre-content events on this file? */
675+
if (dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED) {
676+
parent = dget_parent(dentry);
677+
p_mask = fsnotify_inode_watches_children(d_inode(parent));
678+
dput(parent);
679+
if (p_mask & FSNOTIFY_PRE_CONTENT_EVENTS)
680+
return;
681+
}
682+
/* Nobody watching for pre-content events from this file */
683+
file->f_mode |= FMODE_NONOTIFY | FMODE_NONOTIFY_PERM;
661684
}
662685
#endif
663686

include/linux/fsnotify_backend.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@
7777
*/
7878
#define ALL_FSNOTIFY_DIRENT_EVENTS (FS_CREATE | FS_DELETE | FS_MOVE | FS_RENAME)
7979

80+
/* Pre-content events can be used to fill file content */
81+
#define FSNOTIFY_PRE_CONTENT_EVENTS 0
82+
8083
#define ALL_FSNOTIFY_PERM_EVENTS (FS_OPEN_PERM | FS_ACCESS_PERM | \
8184
FS_OPEN_EXEC_PERM)
8285

0 commit comments

Comments
 (0)