Skip to content

Commit 082fd1e

Browse files
amir73iljankara
authored andcommitted
fsnotify: optimize the case of no parent watcher
If parent inode is not watching, check for the event in masks of sb/mount/inode masks early to optimize out most of the code in __fsnotify_parent() and avoid calling fsnotify(). Jens has reported that this optimization improves BW and IOPS in an io_uring benchmark by more than 10% and reduces perf reported CPU usage. before: + 4.51% io_uring [kernel.vmlinux] [k] fsnotify + 3.67% io_uring [kernel.vmlinux] [k] __fsnotify_parent after: + 2.37% io_uring [kernel.vmlinux] [k] __fsnotify_parent Reported-and-tested-by: Jens Axboe <axboe@kernel.dk> Link: https://lore.kernel.org/linux-fsdevel/b45bd8ff-5654-4e67-90a6-aad5e6759e0b@kernel.dk/ Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Jan Kara <jack@suse.cz> Message-Id: <20240116113247.758848-1-amir73il@gmail.com>
1 parent 615d300 commit 082fd1e

File tree

1 file changed

+17
-11
lines changed

1 file changed

+17
-11
lines changed

fs/notify/fsnotify.c

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode)
141141
}
142142

143143
/* Are inode/sb/mount interested in parent and name info with this event? */
144-
static bool fsnotify_event_needs_parent(struct inode *inode, struct mount *mnt,
144+
static bool fsnotify_event_needs_parent(struct inode *inode, __u32 mnt_mask,
145145
__u32 mask)
146146
{
147147
__u32 marks_mask = 0;
@@ -160,13 +160,22 @@ static bool fsnotify_event_needs_parent(struct inode *inode, struct mount *mnt,
160160
/* Did either inode/sb/mount subscribe for events with parent/name? */
161161
marks_mask |= fsnotify_parent_needed_mask(inode->i_fsnotify_mask);
162162
marks_mask |= fsnotify_parent_needed_mask(inode->i_sb->s_fsnotify_mask);
163-
if (mnt)
164-
marks_mask |= fsnotify_parent_needed_mask(mnt->mnt_fsnotify_mask);
163+
marks_mask |= fsnotify_parent_needed_mask(mnt_mask);
165164

166165
/* Did they subscribe for this event with parent/name info? */
167166
return mask & marks_mask;
168167
}
169168

169+
/* Are there any inode/mount/sb objects that are interested in this event? */
170+
static inline bool fsnotify_object_watched(struct inode *inode, __u32 mnt_mask,
171+
__u32 mask)
172+
{
173+
__u32 marks_mask = inode->i_fsnotify_mask | mnt_mask |
174+
inode->i_sb->s_fsnotify_mask;
175+
176+
return mask & marks_mask & ALL_FSNOTIFY_EVENTS;
177+
}
178+
170179
/*
171180
* Notify this dentry's parent about a child's events with child name info
172181
* if parent is watching or if inode/sb/mount are interested in events with
@@ -179,7 +188,7 @@ int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data,
179188
int data_type)
180189
{
181190
const struct path *path = fsnotify_data_path(data, data_type);
182-
struct mount *mnt = path ? real_mount(path->mnt) : NULL;
191+
__u32 mnt_mask = path ? real_mount(path->mnt)->mnt_fsnotify_mask : 0;
183192
struct inode *inode = d_inode(dentry);
184193
struct dentry *parent;
185194
bool parent_watched = dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED;
@@ -190,16 +199,13 @@ int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data,
190199
struct qstr *file_name = NULL;
191200
int ret = 0;
192201

193-
/*
194-
* Do inode/sb/mount care about parent and name info on non-dir?
195-
* Do they care about any event at all?
196-
*/
197-
if (!inode->i_fsnotify_marks && !inode->i_sb->s_fsnotify_marks &&
198-
(!mnt || !mnt->mnt_fsnotify_marks) && !parent_watched)
202+
/* Optimize the likely case of nobody watching this path */
203+
if (likely(!parent_watched &&
204+
!fsnotify_object_watched(inode, mnt_mask, mask)))
199205
return 0;
200206

201207
parent = NULL;
202-
parent_needed = fsnotify_event_needs_parent(inode, mnt, mask);
208+
parent_needed = fsnotify_event_needs_parent(inode, mnt_mask, mask);
203209
if (!parent_watched && !parent_needed)
204210
goto notify;
205211

0 commit comments

Comments
 (0)