Skip to content

Commit d6084bb

Browse files
committed
Merge tag 'fsnotify_for_v6.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
Pull fsnotify updates from Jan Kara: "A couple of small improvements for fsnotify subsystem. The most interesting is probably Amir's change modifying the meaning of fsnotify fmode bits (and I spell it out specifically because I know you care about those). There's no change for the common cases of no fsnotify watches or no permission event watches. But when there are permission watches (either for open or for pre-content events) but no FAN_ACCESS_PERM watch (which nobody uses in practice) we are now able optimize away unnecessary cache loads from the read path" * tag 'fsnotify_for_v6.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs: fsnotify: optimize FMODE_NONOTIFY_PERM for the common cases fsnotify: merge file_set_fsnotify_mode_from_watchers() with open perm hook samples: fix building fs-monitor on musl systems fanotify: sanitize handle_type values when reporting fid
2 parents 440e6d7 + 0d4c4d4 commit d6084bb

File tree

7 files changed

+82
-75
lines changed

7 files changed

+82
-75
lines changed

fs/file_table.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ static int init_file(struct file *f, int flags, const struct cred *cred)
199199
file_ref_init(&f->f_ref, 1);
200200
/*
201201
* Disable permission and pre-content events for all files by default.
202-
* They may be enabled later by file_set_fsnotify_mode_from_watchers().
202+
* They may be enabled later by fsnotify_open_perm_and_set_mode().
203203
*/
204204
file_set_fsnotify_mode(f, FMODE_NONOTIFY_PERM);
205205
return 0;

fs/notify/fanotify/fanotify.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,13 @@ static int fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode,
454454
dwords = fh_len >> 2;
455455
type = exportfs_encode_fid(inode, buf, &dwords);
456456
err = -EINVAL;
457-
if (type <= 0 || type == FILEID_INVALID || fh_len != dwords << 2)
457+
/*
458+
* Unlike file_handle, type and len of struct fanotify_fh are u8.
459+
* Traditionally, filesystem return handle_type < 0xff, but there
460+
* is no enforecement for that in vfs.
461+
*/
462+
BUILD_BUG_ON(MAX_HANDLE_SZ > 0xff || FILEID_INVALID > 0xff);
463+
if (type <= 0 || type >= FILEID_INVALID || fh_len != dwords << 2)
458464
goto out_err;
459465

460466
fh->type = type;

fs/notify/fsnotify.c

Lines changed: 53 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,8 @@ static bool fsnotify_event_needs_parent(struct inode *inode, __u32 mnt_mask,
199199
}
200200

201201
/* Are there any inode/mount/sb objects that watch for these events? */
202-
static inline bool fsnotify_object_watched(struct inode *inode, __u32 mnt_mask,
203-
__u32 mask)
202+
static inline __u32 fsnotify_object_watched(struct inode *inode, __u32 mnt_mask,
203+
__u32 mask)
204204
{
205205
__u32 marks_mask = READ_ONCE(inode->i_fsnotify_mask) | mnt_mask |
206206
READ_ONCE(inode->i_sb->s_fsnotify_mask);
@@ -656,20 +656,20 @@ EXPORT_SYMBOL_GPL(fsnotify);
656656

657657
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
658658
/*
659-
* At open time we check fsnotify_sb_has_priority_watchers() and set the
660-
* FMODE_NONOTIFY_ mode bits accordignly.
659+
* At open time we check fsnotify_sb_has_priority_watchers(), call the open perm
660+
* hook and set the FMODE_NONOTIFY_ mode bits accordignly.
661661
* Later, fsnotify permission hooks do not check if there are permission event
662662
* watches, but that there were permission event watches at open time.
663663
*/
664-
void file_set_fsnotify_mode_from_watchers(struct file *file)
664+
int fsnotify_open_perm_and_set_mode(struct file *file)
665665
{
666666
struct dentry *dentry = file->f_path.dentry, *parent;
667667
struct super_block *sb = dentry->d_sb;
668-
__u32 mnt_mask, p_mask;
668+
__u32 mnt_mask, p_mask = 0;
669669

670670
/* Is it a file opened by fanotify? */
671671
if (FMODE_FSNOTIFY_NONE(file->f_mode))
672-
return;
672+
return 0;
673673

674674
/*
675675
* Permission events is a super set of pre-content events, so if there
@@ -679,45 +679,64 @@ void file_set_fsnotify_mode_from_watchers(struct file *file)
679679
if (likely(!fsnotify_sb_has_priority_watchers(sb,
680680
FSNOTIFY_PRIO_CONTENT))) {
681681
file_set_fsnotify_mode(file, FMODE_NONOTIFY_PERM);
682-
return;
682+
return 0;
683683
}
684684

685685
/*
686-
* If there are permission event watchers but no pre-content event
687-
* watchers, set FMODE_NONOTIFY | FMODE_NONOTIFY_PERM to indicate that.
686+
* OK, there are some permission event watchers. Check if anybody is
687+
* watching for permission events on *this* file.
688688
*/
689-
if ((!d_is_dir(dentry) && !d_is_reg(dentry)) ||
690-
likely(!fsnotify_sb_has_priority_watchers(sb,
691-
FSNOTIFY_PRIO_PRE_CONTENT))) {
692-
file_set_fsnotify_mode(file, FMODE_NONOTIFY | FMODE_NONOTIFY_PERM);
693-
return;
689+
mnt_mask = READ_ONCE(real_mount(file->f_path.mnt)->mnt_fsnotify_mask);
690+
p_mask = fsnotify_object_watched(d_inode(dentry), mnt_mask,
691+
ALL_FSNOTIFY_PERM_EVENTS);
692+
if (dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED) {
693+
parent = dget_parent(dentry);
694+
p_mask |= fsnotify_inode_watches_children(d_inode(parent));
695+
dput(parent);
694696
}
695697

696698
/*
697-
* OK, there are some pre-content watchers. Check if anybody is
698-
* watching for pre-content events on *this* file.
699+
* Legacy FAN_ACCESS_PERM events have very high performance overhead,
700+
* so unlikely to be used in the wild. If they are used there will be
701+
* no optimizations at all.
699702
*/
700-
mnt_mask = READ_ONCE(real_mount(file->f_path.mnt)->mnt_fsnotify_mask);
701-
if (unlikely(fsnotify_object_watched(d_inode(dentry), mnt_mask,
702-
FSNOTIFY_PRE_CONTENT_EVENTS))) {
703-
/* Enable pre-content events */
703+
if (unlikely(p_mask & FS_ACCESS_PERM)) {
704+
/* Enable all permission and pre-content events */
704705
file_set_fsnotify_mode(file, 0);
705-
return;
706+
goto open_perm;
706707
}
707708

708-
/* Is parent watching for pre-content events on this file? */
709-
if (dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED) {
710-
parent = dget_parent(dentry);
711-
p_mask = fsnotify_inode_watches_children(d_inode(parent));
712-
dput(parent);
713-
if (p_mask & FSNOTIFY_PRE_CONTENT_EVENTS) {
714-
/* Enable pre-content events */
715-
file_set_fsnotify_mode(file, 0);
716-
return;
717-
}
709+
/*
710+
* Pre-content events are only supported on regular files.
711+
* If there are pre-content event watchers and no permission access
712+
* watchers, set FMODE_NONOTIFY | FMODE_NONOTIFY_PERM to indicate that.
713+
* That is the common case with HSM service.
714+
*/
715+
if (d_is_reg(dentry) && (p_mask & FSNOTIFY_PRE_CONTENT_EVENTS)) {
716+
file_set_fsnotify_mode(file, FMODE_NONOTIFY |
717+
FMODE_NONOTIFY_PERM);
718+
goto open_perm;
718719
}
719-
/* Nobody watching for pre-content events from this file */
720-
file_set_fsnotify_mode(file, FMODE_NONOTIFY | FMODE_NONOTIFY_PERM);
720+
721+
/* Nobody watching permission and pre-content events on this file */
722+
file_set_fsnotify_mode(file, FMODE_NONOTIFY_PERM);
723+
724+
open_perm:
725+
/*
726+
* Send open perm events depending on object masks and regardless of
727+
* FMODE_NONOTIFY_PERM.
728+
*/
729+
if (file->f_flags & __FMODE_EXEC && p_mask & FS_OPEN_EXEC_PERM) {
730+
int ret = fsnotify_path(&file->f_path, FS_OPEN_EXEC_PERM);
731+
732+
if (ret)
733+
return ret;
734+
}
735+
736+
if (p_mask & FS_OPEN_PERM)
737+
return fsnotify_path(&file->f_path, FS_OPEN_PERM);
738+
739+
return 0;
721740
}
722741
#endif
723742

fs/open.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -944,12 +944,12 @@ static int do_dentry_open(struct file *f,
944944
goto cleanup_all;
945945

946946
/*
947-
* Set FMODE_NONOTIFY_* bits according to existing permission watches.
947+
* Call fsnotify open permission hook and set FMODE_NONOTIFY_* bits
948+
* according to existing permission watches.
948949
* If FMODE_NONOTIFY mode was already set for an fanotify fd or for a
949950
* pseudo file, this call will not change the mode.
950951
*/
951-
file_set_fsnotify_mode_from_watchers(f);
952-
error = fsnotify_open_perm(f);
952+
error = fsnotify_open_perm_and_set_mode(f);
953953
if (error)
954954
goto cleanup_all;
955955

include/linux/fs.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -200,26 +200,26 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
200200

201201
/*
202202
* The two FMODE_NONOTIFY* define which fsnotify events should not be generated
203-
* for a file. These are the possible values of (f->f_mode &
204-
* FMODE_FSNOTIFY_MASK) and their meaning:
203+
* for an open file. These are the possible values of
204+
* (f->f_mode & FMODE_FSNOTIFY_MASK) and their meaning:
205205
*
206206
* FMODE_NONOTIFY - suppress all (incl. non-permission) events.
207207
* FMODE_NONOTIFY_PERM - suppress permission (incl. pre-content) events.
208-
* FMODE_NONOTIFY | FMODE_NONOTIFY_PERM - suppress only pre-content events.
208+
* FMODE_NONOTIFY | FMODE_NONOTIFY_PERM - suppress only FAN_ACCESS_PERM.
209209
*/
210210
#define FMODE_FSNOTIFY_MASK \
211211
(FMODE_NONOTIFY | FMODE_NONOTIFY_PERM)
212212

213213
#define FMODE_FSNOTIFY_NONE(mode) \
214214
((mode & FMODE_FSNOTIFY_MASK) == FMODE_NONOTIFY)
215215
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
216-
#define FMODE_FSNOTIFY_PERM(mode) \
216+
#define FMODE_FSNOTIFY_HSM(mode) \
217217
((mode & FMODE_FSNOTIFY_MASK) == 0 || \
218218
(mode & FMODE_FSNOTIFY_MASK) == (FMODE_NONOTIFY | FMODE_NONOTIFY_PERM))
219-
#define FMODE_FSNOTIFY_HSM(mode) \
219+
#define FMODE_FSNOTIFY_ACCESS_PERM(mode) \
220220
((mode & FMODE_FSNOTIFY_MASK) == 0)
221221
#else
222-
#define FMODE_FSNOTIFY_PERM(mode) 0
222+
#define FMODE_FSNOTIFY_ACCESS_PERM(mode) 0
223223
#define FMODE_FSNOTIFY_HSM(mode) 0
224224
#endif
225225

include/linux/fsnotify.h

Lines changed: 5 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ static inline int fsnotify_file(struct file *file, __u32 mask)
129129

130130
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
131131

132-
void file_set_fsnotify_mode_from_watchers(struct file *file);
132+
int fsnotify_open_perm_and_set_mode(struct file *file);
133133

134134
/*
135135
* fsnotify_file_area_perm - permission hook before access to file range
@@ -147,9 +147,6 @@ static inline int fsnotify_file_area_perm(struct file *file, int perm_mask,
147147
if (!(perm_mask & (MAY_READ | MAY_WRITE | MAY_ACCESS)))
148148
return 0;
149149

150-
if (likely(!FMODE_FSNOTIFY_PERM(file->f_mode)))
151-
return 0;
152-
153150
/*
154151
* read()/write() and other types of access generate pre-content events.
155152
*/
@@ -160,7 +157,8 @@ static inline int fsnotify_file_area_perm(struct file *file, int perm_mask,
160157
return ret;
161158
}
162159

163-
if (!(perm_mask & MAY_READ))
160+
if (!(perm_mask & MAY_READ) ||
161+
likely(!FMODE_FSNOTIFY_ACCESS_PERM(file->f_mode)))
164162
return 0;
165163

166164
/*
@@ -208,28 +206,10 @@ static inline int fsnotify_file_perm(struct file *file, int perm_mask)
208206
return fsnotify_file_area_perm(file, perm_mask, NULL, 0);
209207
}
210208

211-
/*
212-
* fsnotify_open_perm - permission hook before file open
213-
*/
214-
static inline int fsnotify_open_perm(struct file *file)
215-
{
216-
int ret;
217-
218-
if (likely(!FMODE_FSNOTIFY_PERM(file->f_mode)))
219-
return 0;
220-
221-
if (file->f_flags & __FMODE_EXEC) {
222-
ret = fsnotify_path(&file->f_path, FS_OPEN_EXEC_PERM);
223-
if (ret)
224-
return ret;
225-
}
226-
227-
return fsnotify_path(&file->f_path, FS_OPEN_PERM);
228-
}
229-
230209
#else
231-
static inline void file_set_fsnotify_mode_from_watchers(struct file *file)
210+
static inline int fsnotify_open_perm_and_set_mode(struct file *file)
232211
{
212+
return 0;
233213
}
234214

235215
static inline int fsnotify_file_area_perm(struct file *file, int perm_mask,
@@ -253,11 +233,6 @@ static inline int fsnotify_file_perm(struct file *file, int perm_mask)
253233
{
254234
return 0;
255235
}
256-
257-
static inline int fsnotify_open_perm(struct file *file)
258-
{
259-
return 0;
260-
}
261236
#endif
262237

263238
/*

samples/fanotify/fs-monitor.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
#include <sys/fanotify.h>
1313
#include <sys/types.h>
1414
#include <unistd.h>
15+
#ifndef __GLIBC__
16+
#include <asm-generic/int-ll64.h>
17+
#endif
1518

1619
#ifndef FAN_FS_ERROR
1720
#define FAN_FS_ERROR 0x00008000
@@ -95,7 +98,11 @@ static void handle_notifications(char *buffer, int len)
9598
fid = (struct fanotify_event_info_fid *) info;
9699

97100
printf("\tfsid: %x%x\n",
101+
#if defined(__GLIBC__)
98102
fid->fsid.val[0], fid->fsid.val[1]);
103+
#else
104+
fid->fsid.__val[0], fid->fsid.__val[1]);
105+
#endif
99106
print_fh((struct file_handle *) &fid->handle);
100107
break;
101108

0 commit comments

Comments
 (0)