Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+85 -78
+1 -1
fs/file_table.c
··· 199 199 file_ref_init(&f->f_ref, 1); 200 200 /* 201 201 * 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(). 203 203 */ 204 204 file_set_fsnotify_mode(f, FMODE_NONOTIFY_PERM); 205 205 return 0;
+7 -1
fs/notify/fanotify/fanotify.c
··· 454 454 dwords = fh_len >> 2; 455 455 type = exportfs_encode_fid(inode, buf, &dwords); 456 456 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) 458 464 goto out_err; 459 465 460 466 fh->type = type;
+56 -37
fs/notify/fsnotify.c
··· 199 199 } 200 200 201 201 /* 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) 204 204 { 205 205 __u32 marks_mask = READ_ONCE(inode->i_fsnotify_mask) | mnt_mask | 206 206 READ_ONCE(inode->i_sb->s_fsnotify_mask); ··· 656 656 657 657 #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS 658 658 /* 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. 661 661 * Later, fsnotify permission hooks do not check if there are permission event 662 662 * watches, but that there were permission event watches at open time. 663 663 */ 664 - void file_set_fsnotify_mode_from_watchers(struct file *file) 664 + int fsnotify_open_perm_and_set_mode(struct file *file) 665 665 { 666 666 struct dentry *dentry = file->f_path.dentry, *parent; 667 667 struct super_block *sb = dentry->d_sb; 668 - __u32 mnt_mask, p_mask; 668 + __u32 mnt_mask, p_mask = 0; 669 669 670 670 /* Is it a file opened by fanotify? */ 671 671 if (FMODE_FSNOTIFY_NONE(file->f_mode)) 672 - return; 672 + return 0; 673 673 674 674 /* 675 675 * Permission events is a super set of pre-content events, so if there ··· 679 679 if (likely(!fsnotify_sb_has_priority_watchers(sb, 680 680 FSNOTIFY_PRIO_CONTENT))) { 681 681 file_set_fsnotify_mode(file, FMODE_NONOTIFY_PERM); 682 - return; 682 + return 0; 683 683 } 684 684 685 685 /* 686 - * If there are permission event watchers but no pre-content event 687 - * watchers, set FMODE_NONOTIFY | FMODE_NONOTIFY_PERM to indicate that. 688 - */ 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; 694 - } 695 - 696 - /* 697 - * OK, there are some pre-content watchers. Check if anybody is 698 - * watching for pre-content events on *this* file. 686 + * OK, there are some permission event watchers. Check if anybody is 687 + * watching for permission events on *this* file. 699 688 */ 700 689 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 */ 704 - file_set_fsnotify_mode(file, 0); 705 - return; 706 - } 707 - 708 - /* Is parent watching for pre-content events on this file? */ 690 + p_mask = fsnotify_object_watched(d_inode(dentry), mnt_mask, 691 + ALL_FSNOTIFY_PERM_EVENTS); 709 692 if (dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED) { 710 693 parent = dget_parent(dentry); 711 - p_mask = fsnotify_inode_watches_children(d_inode(parent)); 694 + p_mask |= fsnotify_inode_watches_children(d_inode(parent)); 712 695 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 - } 718 696 } 719 - /* Nobody watching for pre-content events from this file */ 720 - file_set_fsnotify_mode(file, FMODE_NONOTIFY | FMODE_NONOTIFY_PERM); 697 + 698 + /* 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. 702 + */ 703 + if (unlikely(p_mask & FS_ACCESS_PERM)) { 704 + /* Enable all permission and pre-content events */ 705 + file_set_fsnotify_mode(file, 0); 706 + goto open_perm; 707 + } 708 + 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; 719 + } 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; 721 740 } 722 741 #endif 723 742
+3 -3
fs/open.c
··· 944 944 goto cleanup_all; 945 945 946 946 /* 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. 948 949 * If FMODE_NONOTIFY mode was already set for an fanotify fd or for a 949 950 * pseudo file, this call will not change the mode. 950 951 */ 951 - file_set_fsnotify_mode_from_watchers(f); 952 - error = fsnotify_open_perm(f); 952 + error = fsnotify_open_perm_and_set_mode(f); 953 953 if (error) 954 954 goto cleanup_all; 955 955
+6 -6
include/linux/fs.h
··· 200 200 201 201 /* 202 202 * 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: 205 205 * 206 206 * FMODE_NONOTIFY - suppress all (incl. non-permission) events. 207 207 * 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. 209 209 */ 210 210 #define FMODE_FSNOTIFY_MASK \ 211 211 (FMODE_NONOTIFY | FMODE_NONOTIFY_PERM) ··· 213 213 #define FMODE_FSNOTIFY_NONE(mode) \ 214 214 ((mode & FMODE_FSNOTIFY_MASK) == FMODE_NONOTIFY) 215 215 #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS 216 - #define FMODE_FSNOTIFY_PERM(mode) \ 216 + #define FMODE_FSNOTIFY_HSM(mode) \ 217 217 ((mode & FMODE_FSNOTIFY_MASK) == 0 || \ 218 218 (mode & FMODE_FSNOTIFY_MASK) == (FMODE_NONOTIFY | FMODE_NONOTIFY_PERM)) 219 - #define FMODE_FSNOTIFY_HSM(mode) \ 219 + #define FMODE_FSNOTIFY_ACCESS_PERM(mode) \ 220 220 ((mode & FMODE_FSNOTIFY_MASK) == 0) 221 221 #else 222 - #define FMODE_FSNOTIFY_PERM(mode) 0 222 + #define FMODE_FSNOTIFY_ACCESS_PERM(mode) 0 223 223 #define FMODE_FSNOTIFY_HSM(mode) 0 224 224 #endif 225 225
+5 -30
include/linux/fsnotify.h
··· 129 129 130 130 #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS 131 131 132 - void file_set_fsnotify_mode_from_watchers(struct file *file); 132 + int fsnotify_open_perm_and_set_mode(struct file *file); 133 133 134 134 /* 135 135 * fsnotify_file_area_perm - permission hook before access to file range ··· 147 147 if (!(perm_mask & (MAY_READ | MAY_WRITE | MAY_ACCESS))) 148 148 return 0; 149 149 150 - if (likely(!FMODE_FSNOTIFY_PERM(file->f_mode))) 151 - return 0; 152 - 153 150 /* 154 151 * read()/write() and other types of access generate pre-content events. 155 152 */ ··· 157 160 return ret; 158 161 } 159 162 160 - if (!(perm_mask & MAY_READ)) 163 + if (!(perm_mask & MAY_READ) || 164 + likely(!FMODE_FSNOTIFY_ACCESS_PERM(file->f_mode))) 161 165 return 0; 162 166 163 167 /* ··· 206 208 return fsnotify_file_area_perm(file, perm_mask, NULL, 0); 207 209 } 208 210 209 - /* 210 - * fsnotify_open_perm - permission hook before file open 211 - */ 212 - static inline int fsnotify_open_perm(struct file *file) 213 - { 214 - int ret; 215 - 216 - if (likely(!FMODE_FSNOTIFY_PERM(file->f_mode))) 217 - return 0; 218 - 219 - if (file->f_flags & __FMODE_EXEC) { 220 - ret = fsnotify_path(&file->f_path, FS_OPEN_EXEC_PERM); 221 - if (ret) 222 - return ret; 223 - } 224 - 225 - return fsnotify_path(&file->f_path, FS_OPEN_PERM); 226 - } 227 - 228 211 #else 229 - static inline void file_set_fsnotify_mode_from_watchers(struct file *file) 212 + static inline int fsnotify_open_perm_and_set_mode(struct file *file) 230 213 { 214 + return 0; 231 215 } 232 216 233 217 static inline int fsnotify_file_area_perm(struct file *file, int perm_mask, ··· 230 250 } 231 251 232 252 static inline int fsnotify_file_perm(struct file *file, int perm_mask) 233 - { 234 - return 0; 235 - } 236 - 237 - static inline int fsnotify_open_perm(struct file *file) 238 253 { 239 254 return 0; 240 255 }
+7
samples/fanotify/fs-monitor.c
··· 12 12 #include <sys/fanotify.h> 13 13 #include <sys/types.h> 14 14 #include <unistd.h> 15 + #ifndef __GLIBC__ 16 + #include <asm-generic/int-ll64.h> 17 + #endif 15 18 16 19 #ifndef FAN_FS_ERROR 17 20 #define FAN_FS_ERROR 0x00008000 ··· 98 95 fid = (struct fanotify_event_info_fid *) info; 99 96 100 97 printf("\tfsid: %x%x\n", 98 + #if defined(__GLIBC__) 101 99 fid->fsid.val[0], fid->fsid.val[1]); 100 + #else 101 + fid->fsid.__val[0], fid->fsid.__val[1]); 102 + #endif 102 103 print_fh((struct file_handle *) &fid->handle); 103 104 break; 104 105