]>
Commit | Line | Data |
---|---|---|
08dc4bc5 GKH |
1 | From 4d8e7055a4058ee191296699803c5090e14f0dff Mon Sep 17 00:00:00 2001 |
2 | From: Amir Goldstein <amir73il@gmail.com> | |
3 | Date: Sun, 5 May 2019 12:15:49 +0300 | |
4 | Subject: fsnotify: fix unlink performance regression | |
5 | ||
6 | From: Amir Goldstein <amir73il@gmail.com> | |
7 | ||
8 | commit 4d8e7055a4058ee191296699803c5090e14f0dff upstream. | |
9 | ||
10 | __fsnotify_parent() has an optimization in place to avoid unneeded | |
11 | take_dentry_name_snapshot(). When fsnotify_nameremove() was changed | |
12 | not to call __fsnotify_parent(), we left out the optimization. | |
13 | Kernel test robot reported a 5% performance regression in concurrent | |
14 | unlink() workload. | |
15 | ||
16 | Reported-by: kernel test robot <rong.a.chen@intel.com> | |
17 | Link: https://lore.kernel.org/lkml/20190505062153.GG29809@shao2-debian/ | |
18 | Link: https://lore.kernel.org/linux-fsdevel/20190104090357.GD22409@quack2.suse.cz/ | |
19 | Fixes: 5f02a8776384 ("fsnotify: annotate directory entry modification events") | |
20 | CC: stable@vger.kernel.org | |
21 | Signed-off-by: Amir Goldstein <amir73il@gmail.com> | |
22 | Signed-off-by: Jan Kara <jack@suse.cz> | |
23 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
24 | ||
25 | --- | |
26 | fs/notify/fsnotify.c | 41 +++++++++++++++++++++++++++++++++++++++ | |
27 | include/linux/fsnotify.h | 33 ------------------------------- | |
28 | include/linux/fsnotify_backend.h | 4 +++ | |
29 | 3 files changed, 45 insertions(+), 33 deletions(-) | |
30 | ||
31 | --- a/fs/notify/fsnotify.c | |
32 | +++ b/fs/notify/fsnotify.c | |
33 | @@ -108,6 +108,47 @@ void fsnotify_sb_delete(struct super_blo | |
34 | } | |
35 | ||
36 | /* | |
37 | + * fsnotify_nameremove - a filename was removed from a directory | |
38 | + * | |
39 | + * This is mostly called under parent vfs inode lock so name and | |
40 | + * dentry->d_parent should be stable. However there are some corner cases where | |
41 | + * inode lock is not held. So to be on the safe side and be reselient to future | |
42 | + * callers and out of tree users of d_delete(), we do not assume that d_parent | |
43 | + * and d_name are stable and we use dget_parent() and | |
44 | + * take_dentry_name_snapshot() to grab stable references. | |
45 | + */ | |
46 | +void fsnotify_nameremove(struct dentry *dentry, int isdir) | |
47 | +{ | |
48 | + struct dentry *parent; | |
49 | + struct name_snapshot name; | |
50 | + __u32 mask = FS_DELETE; | |
51 | + | |
52 | + /* d_delete() of pseudo inode? (e.g. __ns_get_path() playing tricks) */ | |
53 | + if (IS_ROOT(dentry)) | |
54 | + return; | |
55 | + | |
56 | + if (isdir) | |
57 | + mask |= FS_ISDIR; | |
58 | + | |
59 | + parent = dget_parent(dentry); | |
60 | + /* Avoid unneeded take_dentry_name_snapshot() */ | |
61 | + if (!(d_inode(parent)->i_fsnotify_mask & FS_DELETE) && | |
62 | + !(dentry->d_sb->s_fsnotify_mask & FS_DELETE)) | |
63 | + goto out_dput; | |
64 | + | |
65 | + take_dentry_name_snapshot(&name, dentry); | |
66 | + | |
67 | + fsnotify(d_inode(parent), mask, d_inode(dentry), FSNOTIFY_EVENT_INODE, | |
68 | + name.name, 0); | |
69 | + | |
70 | + release_dentry_name_snapshot(&name); | |
71 | + | |
72 | +out_dput: | |
73 | + dput(parent); | |
74 | +} | |
75 | +EXPORT_SYMBOL(fsnotify_nameremove); | |
76 | + | |
77 | +/* | |
78 | * Given an inode, first check if we care what happens to our children. Inotify | |
79 | * and dnotify both tell their parents about events. If we care about any event | |
80 | * on a child we run all of our children and set a dentry flag saying that the | |
81 | --- a/include/linux/fsnotify.h | |
82 | +++ b/include/linux/fsnotify.h | |
83 | @@ -152,39 +152,6 @@ static inline void fsnotify_vfsmount_del | |
84 | } | |
85 | ||
86 | /* | |
87 | - * fsnotify_nameremove - a filename was removed from a directory | |
88 | - * | |
89 | - * This is mostly called under parent vfs inode lock so name and | |
90 | - * dentry->d_parent should be stable. However there are some corner cases where | |
91 | - * inode lock is not held. So to be on the safe side and be reselient to future | |
92 | - * callers and out of tree users of d_delete(), we do not assume that d_parent | |
93 | - * and d_name are stable and we use dget_parent() and | |
94 | - * take_dentry_name_snapshot() to grab stable references. | |
95 | - */ | |
96 | -static inline void fsnotify_nameremove(struct dentry *dentry, int isdir) | |
97 | -{ | |
98 | - struct dentry *parent; | |
99 | - struct name_snapshot name; | |
100 | - __u32 mask = FS_DELETE; | |
101 | - | |
102 | - /* d_delete() of pseudo inode? (e.g. __ns_get_path() playing tricks) */ | |
103 | - if (IS_ROOT(dentry)) | |
104 | - return; | |
105 | - | |
106 | - if (isdir) | |
107 | - mask |= FS_ISDIR; | |
108 | - | |
109 | - parent = dget_parent(dentry); | |
110 | - take_dentry_name_snapshot(&name, dentry); | |
111 | - | |
112 | - fsnotify(d_inode(parent), mask, d_inode(dentry), FSNOTIFY_EVENT_INODE, | |
113 | - name.name, 0); | |
114 | - | |
115 | - release_dentry_name_snapshot(&name); | |
116 | - dput(parent); | |
117 | -} | |
118 | - | |
119 | -/* | |
120 | * fsnotify_inoderemove - an inode is going away | |
121 | */ | |
122 | static inline void fsnotify_inoderemove(struct inode *inode) | |
123 | --- a/include/linux/fsnotify_backend.h | |
124 | +++ b/include/linux/fsnotify_backend.h | |
125 | @@ -355,6 +355,7 @@ extern int __fsnotify_parent(const struc | |
126 | extern void __fsnotify_inode_delete(struct inode *inode); | |
127 | extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt); | |
128 | extern void fsnotify_sb_delete(struct super_block *sb); | |
129 | +extern void fsnotify_nameremove(struct dentry *dentry, int isdir); | |
130 | extern u32 fsnotify_get_cookie(void); | |
131 | ||
132 | static inline int fsnotify_inode_watches_children(struct inode *inode) | |
133 | @@ -524,6 +525,9 @@ static inline void __fsnotify_vfsmount_d | |
134 | static inline void fsnotify_sb_delete(struct super_block *sb) | |
135 | {} | |
136 | ||
137 | +static inline void fsnotify_nameremove(struct dentry *dentry, int isdir) | |
138 | +{} | |
139 | + | |
140 | static inline void fsnotify_update_flags(struct dentry *dentry) | |
141 | {} | |
142 |