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

Merge tag 'fsnotify_for_v5.17-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs

Pull fsnotify fixes from Jan Kara:
"Fixes for userspace breakage caused by fsnotify changes ~3 years ago
and one fanotify cleanup"

* tag 'fsnotify_for_v5.17-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
fsnotify: fix fsnotify hooks in pseudo filesystems
fsnotify: invalidate dcache before IN_DELETE event
fanotify: remove variable set but not used

+59 -26
+2 -4
fs/btrfs/ioctl.c
··· 3152 3152 btrfs_inode_lock(inode, 0); 3153 3153 err = btrfs_delete_subvolume(dir, dentry); 3154 3154 btrfs_inode_unlock(inode, 0); 3155 - if (!err) { 3156 - fsnotify_rmdir(dir, dentry); 3157 - d_delete(dentry); 3158 - } 3155 + if (!err) 3156 + d_delete_notify(dir, dentry); 3159 3157 3160 3158 out_dput: 3161 3159 dput(dentry);
+3 -3
fs/configfs/dir.c
··· 1780 1780 configfs_detach_group(&group->cg_item); 1781 1781 d_inode(dentry)->i_flags |= S_DEAD; 1782 1782 dont_mount(dentry); 1783 + d_drop(dentry); 1783 1784 fsnotify_rmdir(d_inode(parent), dentry); 1784 - d_delete(dentry); 1785 1785 inode_unlock(d_inode(parent)); 1786 1786 1787 1787 dput(dentry); ··· 1922 1922 configfs_detach_group(&group->cg_item); 1923 1923 d_inode(dentry)->i_flags |= S_DEAD; 1924 1924 dont_mount(dentry); 1925 - fsnotify_rmdir(d_inode(root), dentry); 1926 1925 inode_unlock(d_inode(dentry)); 1927 1926 1928 - d_delete(dentry); 1927 + d_drop(dentry); 1928 + fsnotify_rmdir(d_inode(root), dentry); 1929 1929 1930 1930 inode_unlock(d_inode(root)); 1931 1931
+1 -1
fs/devpts/inode.c
··· 621 621 622 622 dentry->d_fsdata = NULL; 623 623 drop_nlink(dentry->d_inode); 624 - fsnotify_unlink(d_inode(dentry->d_parent), dentry); 625 624 d_drop(dentry); 625 + fsnotify_unlink(d_inode(dentry->d_parent), dentry); 626 626 dput(dentry); /* d_alloc_name() in devpts_pty_new() */ 627 627 } 628 628
+5 -5
fs/namei.c
··· 4024 4024 dentry->d_inode->i_flags |= S_DEAD; 4025 4025 dont_mount(dentry); 4026 4026 detach_mounts(dentry); 4027 - fsnotify_rmdir(dir, dentry); 4028 4027 4029 4028 out: 4030 4029 inode_unlock(dentry->d_inode); 4031 4030 dput(dentry); 4032 4031 if (!error) 4033 - d_delete(dentry); 4032 + d_delete_notify(dir, dentry); 4034 4033 return error; 4035 4034 } 4036 4035 EXPORT_SYMBOL(vfs_rmdir); ··· 4151 4152 if (!error) { 4152 4153 dont_mount(dentry); 4153 4154 detach_mounts(dentry); 4154 - fsnotify_unlink(dir, dentry); 4155 4155 } 4156 4156 } 4157 4157 } ··· 4158 4160 inode_unlock(target); 4159 4161 4160 4162 /* We don't d_delete() NFS sillyrenamed files--they still exist. */ 4161 - if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) { 4163 + if (!error && dentry->d_flags & DCACHE_NFSFS_RENAMED) { 4164 + fsnotify_unlink(dir, dentry); 4165 + } else if (!error) { 4162 4166 fsnotify_link_count(target); 4163 - d_delete(dentry); 4167 + d_delete_notify(dir, dentry); 4164 4168 } 4165 4169 4166 4170 return error;
+3 -2
fs/nfsd/nfsctl.c
··· 1247 1247 clear_ncl(d_inode(dentry)); 1248 1248 dget(dentry); 1249 1249 ret = simple_unlink(dir, dentry); 1250 - d_delete(dentry); 1250 + d_drop(dentry); 1251 + fsnotify_unlink(dir, dentry); 1251 1252 dput(dentry); 1252 1253 WARN_ON_ONCE(ret); 1253 1254 } ··· 1339 1338 dget(dentry); 1340 1339 ret = simple_rmdir(dir, dentry); 1341 1340 WARN_ON_ONCE(ret); 1341 + d_drop(dentry); 1342 1342 fsnotify_rmdir(dir, dentry); 1343 - d_delete(dentry); 1344 1343 dput(dentry); 1345 1344 inode_unlock(dir); 1346 1345 }
-3
fs/notify/fanotify/fanotify_user.c
··· 158 158 struct fanotify_event *event) 159 159 { 160 160 size_t event_len = FAN_EVENT_METADATA_LEN; 161 - struct fanotify_info *info; 162 161 int fh_len; 163 162 int dot_len = 0; 164 163 ··· 166 167 167 168 if (fanotify_is_error_event(event->mask)) 168 169 event_len += FANOTIFY_ERROR_INFO_LEN; 169 - 170 - info = fanotify_event_info(event); 171 170 172 171 if (fanotify_event_has_any_dir_fh(event)) { 173 172 event_len += fanotify_dir_name_info_len(event);
+43 -6
include/linux/fsnotify.h
··· 225 225 } 226 226 227 227 /* 228 + * fsnotify_delete - @dentry was unlinked and unhashed 229 + * 230 + * Caller must make sure that dentry->d_name is stable. 231 + * 232 + * Note: unlike fsnotify_unlink(), we have to pass also the unlinked inode 233 + * as this may be called after d_delete() and old_dentry may be negative. 234 + */ 235 + static inline void fsnotify_delete(struct inode *dir, struct inode *inode, 236 + struct dentry *dentry) 237 + { 238 + __u32 mask = FS_DELETE; 239 + 240 + if (S_ISDIR(inode->i_mode)) 241 + mask |= FS_ISDIR; 242 + 243 + fsnotify_name(mask, inode, FSNOTIFY_EVENT_INODE, dir, &dentry->d_name, 244 + 0); 245 + } 246 + 247 + /** 248 + * d_delete_notify - delete a dentry and call fsnotify_delete() 249 + * @dentry: The dentry to delete 250 + * 251 + * This helper is used to guaranty that the unlinked inode cannot be found 252 + * by lookup of this name after fsnotify_delete() event has been delivered. 253 + */ 254 + static inline void d_delete_notify(struct inode *dir, struct dentry *dentry) 255 + { 256 + struct inode *inode = d_inode(dentry); 257 + 258 + ihold(inode); 259 + d_delete(dentry); 260 + fsnotify_delete(dir, inode, dentry); 261 + iput(inode); 262 + } 263 + 264 + /* 228 265 * fsnotify_unlink - 'name' was unlinked 229 266 * 230 267 * Caller must make sure that dentry->d_name is stable. 231 268 */ 232 269 static inline void fsnotify_unlink(struct inode *dir, struct dentry *dentry) 233 270 { 234 - /* Expected to be called before d_delete() */ 235 - WARN_ON_ONCE(d_is_negative(dentry)); 271 + if (WARN_ON_ONCE(d_is_negative(dentry))) 272 + return; 236 273 237 - fsnotify_dirent(dir, dentry, FS_DELETE); 274 + fsnotify_delete(dir, d_inode(dentry), dentry); 238 275 } 239 276 240 277 /* ··· 295 258 */ 296 259 static inline void fsnotify_rmdir(struct inode *dir, struct dentry *dentry) 297 260 { 298 - /* Expected to be called before d_delete() */ 299 - WARN_ON_ONCE(d_is_negative(dentry)); 261 + if (WARN_ON_ONCE(d_is_negative(dentry))) 262 + return; 300 263 301 - fsnotify_dirent(dir, dentry, FS_DELETE | FS_ISDIR); 264 + fsnotify_delete(dir, d_inode(dentry), dentry); 302 265 } 303 266 304 267 /*
+2 -2
net/sunrpc/rpc_pipe.c
··· 600 600 601 601 dget(dentry); 602 602 ret = simple_rmdir(dir, dentry); 603 + d_drop(dentry); 603 604 if (!ret) 604 605 fsnotify_rmdir(dir, dentry); 605 - d_delete(dentry); 606 606 dput(dentry); 607 607 return ret; 608 608 } ··· 613 613 614 614 dget(dentry); 615 615 ret = simple_unlink(dir, dentry); 616 + d_drop(dentry); 616 617 if (!ret) 617 618 fsnotify_unlink(dir, dentry); 618 - d_delete(dentry); 619 619 dput(dentry); 620 620 return ret; 621 621 }