Skip to content

Commit a5e57b4

Browse files
amir73iljankara
authored andcommitted
fsnotify: optimize the case of no permission event watchers
Commit e43de7f ("fsnotify: optimize the case of no marks of any type") optimized the case where there are no fsnotify watchers on any of the filesystem's objects. It is quite common for a system to have a single local filesystem and it is quite common for the system to have some inotify watches on some config files or directories, so the optimization of no marks at all is often not in effect. Permission event watchers, which require high priority group are more rare, so optimizing the case of no marks og high priority groups can improve performance for more systems, especially for performance sensitive io workloads. Count per-sb watched objects by high priority groups and use that the optimize out the call to __fsnotify_parent() and fsnotify() in fsnotify permission hooks. Signed-off-by: Amir Goldstein <[email protected]> Signed-off-by: Jan Kara <[email protected]> Message-Id: <[email protected]>
1 parent 477cf91 commit a5e57b4

File tree

4 files changed

+54
-9
lines changed

4 files changed

+54
-9
lines changed

fs/notify/fsnotify.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ void fsnotify_sb_delete(struct super_block *sb)
100100
/* Wait for outstanding object references from connectors */
101101
wait_var_event(fsnotify_sb_watched_objects(sb),
102102
!atomic_long_read(fsnotify_sb_watched_objects(sb)));
103+
WARN_ON(fsnotify_sb_has_priority_watchers(sb, FSNOTIFY_PRIO_CONTENT));
104+
WARN_ON(fsnotify_sb_has_priority_watchers(sb,
105+
FSNOTIFY_PRIO_PRE_CONTENT));
103106
kfree(sbinfo);
104107
}
105108

fs/notify/mark.c

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,13 +161,36 @@ static void fsnotify_put_inode_ref(struct inode *inode)
161161
static void fsnotify_update_sb_watchers(struct super_block *sb,
162162
struct fsnotify_mark_connector *conn)
163163
{
164+
struct fsnotify_sb_info *sbinfo = fsnotify_sb_info(sb);
164165
bool is_watched = conn->flags & FSNOTIFY_CONN_FLAG_IS_WATCHED;
165-
bool has_marks = conn->obj && !hlist_empty(&conn->list);
166+
struct fsnotify_mark *first_mark = NULL;
167+
unsigned int highest_prio = 0;
166168

167-
if (has_marks && !is_watched) {
169+
if (conn->obj)
170+
first_mark = hlist_entry_safe(conn->list.first,
171+
struct fsnotify_mark, obj_list);
172+
if (first_mark)
173+
highest_prio = first_mark->group->priority;
174+
if (WARN_ON(highest_prio >= __FSNOTIFY_PRIO_NUM))
175+
highest_prio = 0;
176+
177+
/*
178+
* If the highest priority of group watching this object is prio,
179+
* then watched object has a reference on counters [0..prio].
180+
* Update priority >= 1 watched objects counters.
181+
*/
182+
for (unsigned int p = conn->prio + 1; p <= highest_prio; p++)
183+
atomic_long_inc(&sbinfo->watched_objects[p]);
184+
for (unsigned int p = conn->prio; p > highest_prio; p--)
185+
atomic_long_dec(&sbinfo->watched_objects[p]);
186+
conn->prio = highest_prio;
187+
188+
/* Update priority >= 0 (a.k.a total) watched objects counter */
189+
BUILD_BUG_ON(FSNOTIFY_PRIO_NORMAL != 0);
190+
if (first_mark && !is_watched) {
168191
conn->flags |= FSNOTIFY_CONN_FLAG_IS_WATCHED;
169192
fsnotify_get_sb_watched_objects(sb);
170-
} else if (!has_marks && is_watched) {
193+
} else if (!first_mark && is_watched) {
171194
conn->flags &= ~FSNOTIFY_CONN_FLAG_IS_WATCHED;
172195
fsnotify_put_sb_watched_objects(sb);
173196
}
@@ -600,6 +623,7 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp,
600623
spin_lock_init(&conn->lock);
601624
INIT_HLIST_HEAD(&conn->list);
602625
conn->flags = 0;
626+
conn->prio = 0;
603627
conn->type = obj_type;
604628
conn->obj = obj;
605629

include/linux/fsnotify.h

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,23 @@
1717
#include <linux/slab.h>
1818
#include <linux/bug.h>
1919

20-
/* Are there any inode/mount/sb objects that are being watched at all? */
21-
static inline bool fsnotify_sb_has_watchers(struct super_block *sb)
20+
/* Are there any inode/mount/sb objects watched with priority prio or above? */
21+
static inline bool fsnotify_sb_has_priority_watchers(struct super_block *sb,
22+
int prio)
2223
{
2324
struct fsnotify_sb_info *sbinfo = fsnotify_sb_info(sb);
2425

2526
/* Were any marks ever added to any object on this sb? */
2627
if (!sbinfo)
2728
return false;
2829

29-
return atomic_long_read(&sbinfo->watched_objects);
30+
return atomic_long_read(&sbinfo->watched_objects[prio]);
31+
}
32+
33+
/* Are there any inode/mount/sb objects that are being watched at all? */
34+
static inline bool fsnotify_sb_has_watchers(struct super_block *sb)
35+
{
36+
return fsnotify_sb_has_priority_watchers(sb, 0);
3037
}
3138

3239
/*
@@ -109,6 +116,12 @@ static inline int fsnotify_file(struct file *file, __u32 mask)
109116
return 0;
110117

111118
path = &file->f_path;
119+
/* Permission events require group prio >= FSNOTIFY_PRIO_CONTENT */
120+
if (mask & ALL_FSNOTIFY_PERM_EVENTS &&
121+
!fsnotify_sb_has_priority_watchers(path->dentry->d_sb,
122+
FSNOTIFY_PRIO_CONTENT))
123+
return 0;
124+
112125
return fsnotify_parent(path->dentry, mask, path, FSNOTIFY_EVENT_PATH);
113126
}
114127

include/linux/fsnotify_backend.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,8 @@ FSNOTIFY_ITER_FUNCS(sb, SB)
468468
*/
469469
struct fsnotify_mark_connector {
470470
spinlock_t lock;
471-
unsigned short type; /* Type of object [lock] */
471+
unsigned char type; /* Type of object [lock] */
472+
unsigned char prio; /* Highest priority group */
472473
#define FSNOTIFY_CONN_FLAG_IS_WATCHED 0x01
473474
#define FSNOTIFY_CONN_FLAG_HAS_IREF 0x02
474475
unsigned short flags; /* flags [lock] */
@@ -490,8 +491,12 @@ struct fsnotify_sb_info {
490491
/*
491492
* Number of inode/mount/sb objects that are being watched in this sb.
492493
* Note that inodes objects are currently double-accounted.
494+
*
495+
* The value in watched_objects[prio] is the number of objects that are
496+
* watched by groups of priority >= prio, so watched_objects[0] is the
497+
* total number of watched objects in this sb.
493498
*/
494-
atomic_long_t watched_objects;
499+
atomic_long_t watched_objects[__FSNOTIFY_PRIO_NUM];
495500
};
496501

497502
static inline struct fsnotify_sb_info *fsnotify_sb_info(struct super_block *sb)
@@ -505,7 +510,7 @@ static inline struct fsnotify_sb_info *fsnotify_sb_info(struct super_block *sb)
505510

506511
static inline atomic_long_t *fsnotify_sb_watched_objects(struct super_block *sb)
507512
{
508-
return &fsnotify_sb_info(sb)->watched_objects;
513+
return &fsnotify_sb_info(sb)->watched_objects[0];
509514
}
510515

511516
/*

0 commit comments

Comments
 (0)