Merge tag 'fsnotify_for_v5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 11 Jul 2019 03:09:17 +0000 (20:09 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 11 Jul 2019 03:09:17 +0000 (20:09 -0700)
Pull fsnotify updates from Jan Kara:
 "This contains cleanups of the fsnotify name removal hook and also a
  patch to disable fanotify permission events for 'proc' filesystem"

* tag 'fsnotify_for_v5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
  fsnotify: get rid of fsnotify_nameremove()
  fsnotify: move fsnotify_nameremove() hook out of d_delete()
  configfs: call fsnotify_rmdir() hook
  debugfs: call fsnotify_{unlink,rmdir}() hooks
  debugfs: simplify __debugfs_remove_file()
  devpts: call fsnotify_unlink() hook
  tracefs: call fsnotify_{unlink,rmdir}() hooks
  rpc_pipefs: call fsnotify_{unlink,rmdir}() hooks
  btrfs: call fsnotify_rmdir() hook
  fsnotify: add empty fsnotify_{unlink,rmdir}() hooks
  fanotify: Disallow permission events for proc filesystem

16 files changed:
fs/afs/dir_silly.c
fs/btrfs/ioctl.c
fs/configfs/dir.c
fs/dcache.c
fs/debugfs/inode.c
fs/devpts/inode.c
fs/namei.c
fs/nfs/unlink.c
fs/notify/fanotify/fanotify_user.c
fs/notify/fsnotify.c
fs/proc/root.c
fs/tracefs/inode.c
include/linux/fs.h
include/linux/fsnotify.h
include/linux/fsnotify_backend.h
net/sunrpc/rpc_pipe.c

index 057b8d3..361088a 100644 (file)
@@ -60,11 +60,6 @@ static int afs_do_silly_rename(struct afs_vnode *dvnode, struct afs_vnode *vnode
                if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
                        afs_edit_dir_add(dvnode, &new->d_name,
                                         &vnode->fid, afs_edit_dir_for_silly_1);
-
-               /* vfs_unlink and the like do not issue this when a file is
-                * sillyrenamed, so do it here.
-                */
-               fsnotify_nameremove(old, 0);
        }
 
        kfree(scb);
index 2a1be0d..56ae2f6 100644 (file)
@@ -2928,8 +2928,10 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
        inode_lock(inode);
        err = btrfs_delete_subvolume(dir, dentry);
        inode_unlock(inode);
-       if (!err)
+       if (!err) {
+               fsnotify_rmdir(dir, dentry);
                d_delete(dentry);
+       }
 
 out_dput:
        dput(dentry);
index d2ca528..9211291 100644 (file)
@@ -13,6 +13,7 @@
 #undef DEBUG
 
 #include <linux/fs.h>
+#include <linux/fsnotify.h>
 #include <linux/mount.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -1788,6 +1789,7 @@ void configfs_unregister_group(struct config_group *group)
        configfs_detach_group(&group->cg_item);
        d_inode(dentry)->i_flags |= S_DEAD;
        dont_mount(dentry);
+       fsnotify_rmdir(d_inode(parent), dentry);
        d_delete(dentry);
        inode_unlock(d_inode(parent));
 
@@ -1916,6 +1918,7 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys)
        configfs_detach_group(&group->cg_item);
        d_inode(dentry)->i_flags |= S_DEAD;
        dont_mount(dentry);
+       fsnotify_rmdir(d_inode(root), dentry);
        inode_unlock(d_inode(dentry));
 
        d_delete(dentry);
index c435398..f41121e 100644 (file)
@@ -2372,7 +2372,6 @@ EXPORT_SYMBOL(d_hash_and_lookup);
 void d_delete(struct dentry * dentry)
 {
        struct inode *inode = dentry->d_inode;
-       int isdir = d_is_dir(dentry);
 
        spin_lock(&inode->i_lock);
        spin_lock(&dentry->d_lock);
@@ -2387,7 +2386,6 @@ void d_delete(struct dentry * dentry)
                spin_unlock(&dentry->d_lock);
                spin_unlock(&inode->i_lock);
        }
-       fsnotify_nameremove(dentry, isdir);
 }
 EXPORT_SYMBOL(d_delete);
 
index acef14a..1e444fe 100644 (file)
@@ -617,13 +617,10 @@ struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent,
 }
 EXPORT_SYMBOL_GPL(debugfs_create_symlink);
 
-static void __debugfs_remove_file(struct dentry *dentry, struct dentry *parent)
+static void __debugfs_file_removed(struct dentry *dentry)
 {
        struct debugfs_fsdata *fsd;
 
-       simple_unlink(d_inode(parent), dentry);
-       d_delete(dentry);
-
        /*
         * Paired with the closing smp_mb() implied by a successful
         * cmpxchg() in debugfs_file_get(): either
@@ -644,16 +641,18 @@ static int __debugfs_remove(struct dentry *dentry, struct dentry *parent)
 
        if (simple_positive(dentry)) {
                dget(dentry);
-               if (!d_is_reg(dentry)) {
-                       if (d_is_dir(dentry))
-                               ret = simple_rmdir(d_inode(parent), dentry);
-                       else
-                               simple_unlink(d_inode(parent), dentry);
+               if (d_is_dir(dentry)) {
+                       ret = simple_rmdir(d_inode(parent), dentry);
                        if (!ret)
-                               d_delete(dentry);
+                               fsnotify_rmdir(d_inode(parent), dentry);
                } else {
-                       __debugfs_remove_file(dentry, parent);
+                       simple_unlink(d_inode(parent), dentry);
+                       fsnotify_unlink(d_inode(parent), dentry);
                }
+               if (!ret)
+                       d_delete(dentry);
+               if (d_is_reg(dentry))
+                       __debugfs_file_removed(dentry);
                dput(dentry);
        }
        return ret;
index 2c14ae0..beeadca 100644 (file)
@@ -621,6 +621,7 @@ void devpts_pty_kill(struct dentry *dentry)
 
        dentry->d_fsdata = NULL;
        drop_nlink(dentry->d_inode);
+       fsnotify_unlink(d_inode(dentry->d_parent), dentry);
        d_delete(dentry);
        dput(dentry);   /* d_alloc_name() in devpts_pty_new() */
 }
index 20831c2..209c51a 100644 (file)
@@ -3883,6 +3883,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
        dentry->d_inode->i_flags |= S_DEAD;
        dont_mount(dentry);
        detach_mounts(dentry);
+       fsnotify_rmdir(dir, dentry);
 
 out:
        inode_unlock(dentry->d_inode);
@@ -3999,6 +4000,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegate
                        if (!error) {
                                dont_mount(dentry);
                                detach_mounts(dentry);
+                               fsnotify_unlink(dir, dentry);
                        }
                }
        }
index 52d5339..0effeee 100644 (file)
@@ -396,12 +396,6 @@ nfs_complete_sillyrename(struct rpc_task *task, struct nfs_renamedata *data)
                nfs_cancel_async_unlink(dentry);
                return;
        }
-
-       /*
-        * vfs_unlink and the like do not issue this when a file is
-        * sillyrenamed, so do it here.
-        */
-       fsnotify_nameremove(dentry, 0);
 }
 
 #define SILLYNAME_PREFIX ".nfs"
index a90bb19..91006f4 100644 (file)
@@ -920,6 +920,22 @@ static int fanotify_test_fid(struct path *path, __kernel_fsid_t *fsid)
        return 0;
 }
 
+static int fanotify_events_supported(struct path *path, __u64 mask)
+{
+       /*
+        * Some filesystems such as 'proc' acquire unusual locks when opening
+        * files. For them fanotify permission events have high chances of
+        * deadlocking the system - open done when reporting fanotify event
+        * blocks on this "unusual" lock while another process holding the lock
+        * waits for fanotify permission event to be answered. Just disallow
+        * permission events for such filesystems.
+        */
+       if (mask & FANOTIFY_PERM_EVENTS &&
+           path->mnt->mnt_sb->s_type->fs_flags & FS_DISALLOW_NOTIFY_PERM)
+               return -EINVAL;
+       return 0;
+}
+
 static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
                            int dfd, const char  __user *pathname)
 {
@@ -1018,6 +1034,12 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
        if (ret)
                goto fput_and_out;
 
+       if (flags & FAN_MARK_ADD) {
+               ret = fanotify_events_supported(&path, mask);
+               if (ret)
+                       goto path_put_and_out;
+       }
+
        if (FAN_GROUP_FLAG(group, FAN_REPORT_FID)) {
                ret = fanotify_test_fid(&path, &__fsid);
                if (ret)
index 4eb2ebf..2ecef61 100644 (file)
@@ -95,47 +95,6 @@ void fsnotify_sb_delete(struct super_block *sb)
 }
 
 /*
- * fsnotify_nameremove - a filename was removed from a directory
- *
- * This is mostly called under parent vfs inode lock so name and
- * dentry->d_parent should be stable. However there are some corner cases where
- * inode lock is not held. So to be on the safe side and be reselient to future
- * callers and out of tree users of d_delete(), we do not assume that d_parent
- * and d_name are stable and we use dget_parent() and
- * take_dentry_name_snapshot() to grab stable references.
- */
-void fsnotify_nameremove(struct dentry *dentry, int isdir)
-{
-       struct dentry *parent;
-       struct name_snapshot name;
-       __u32 mask = FS_DELETE;
-
-       /* d_delete() of pseudo inode? (e.g. __ns_get_path() playing tricks) */
-       if (IS_ROOT(dentry))
-               return;
-
-       if (isdir)
-               mask |= FS_ISDIR;
-
-       parent = dget_parent(dentry);
-       /* Avoid unneeded take_dentry_name_snapshot() */
-       if (!(d_inode(parent)->i_fsnotify_mask & FS_DELETE) &&
-           !(dentry->d_sb->s_fsnotify_mask & FS_DELETE))
-               goto out_dput;
-
-       take_dentry_name_snapshot(&name, dentry);
-
-       fsnotify(d_inode(parent), mask, d_inode(dentry), FSNOTIFY_EVENT_INODE,
-                &name.name, 0);
-
-       release_dentry_name_snapshot(&name);
-
-out_dput:
-       dput(parent);
-}
-EXPORT_SYMBOL(fsnotify_nameremove);
-
-/*
  * Given an inode, first check if we care what happens to our children.  Inotify
  * and dnotify both tell their parents about events.  If we care about any event
  * on a child we run all of our children and set a dentry flag saying that the
index 8b145e7..522199e 100644 (file)
@@ -211,7 +211,7 @@ static struct file_system_type proc_fs_type = {
        .init_fs_context        = proc_init_fs_context,
        .parameters             = &proc_fs_parameters,
        .kill_sb                = proc_kill_sb,
-       .fs_flags               = FS_USERNS_MOUNT,
+       .fs_flags               = FS_USERNS_MOUNT | FS_DISALLOW_NOTIFY_PERM,
 };
 
 void __init proc_root_init(void)
index a5bab19..eeeae04 100644 (file)
@@ -505,9 +505,12 @@ static int __tracefs_remove(struct dentry *dentry, struct dentry *parent)
                        switch (dentry->d_inode->i_mode & S_IFMT) {
                        case S_IFDIR:
                                ret = simple_rmdir(parent->d_inode, dentry);
+                               if (!ret)
+                                       fsnotify_rmdir(parent->d_inode, dentry);
                                break;
                        default:
                                simple_unlink(parent->d_inode, dentry);
+                               fsnotify_unlink(parent->d_inode, dentry);
                                break;
                        }
                        if (!ret)
index 4fb399b..201ebb1 100644 (file)
@@ -2184,6 +2184,7 @@ struct file_system_type {
 #define FS_BINARY_MOUNTDATA    2
 #define FS_HAS_SUBTYPE         4
 #define FS_USERNS_MOUNT                8       /* Can be mounted by userns root */
+#define FS_DISALLOW_NOTIFY_PERM        16      /* Disable fanotify permission events */
 #define FS_RENAME_DOES_D_MOVE  32768   /* FS will handle d_move() during rename() internally. */
        int (*init_fs_context)(struct fs_context *);
        const struct fs_parameter_description *parameters;
index 94972e8..a2d5d17 100644 (file)
@@ -189,6 +189,19 @@ static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct
 }
 
 /*
+ * fsnotify_unlink - 'name' was unlinked
+ *
+ * Caller must make sure that dentry->d_name is stable.
+ */
+static inline void fsnotify_unlink(struct inode *dir, struct dentry *dentry)
+{
+       /* Expected to be called before d_delete() */
+       WARN_ON_ONCE(d_is_negative(dentry));
+
+       fsnotify_dirent(dir, dentry, FS_DELETE);
+}
+
+/*
  * fsnotify_mkdir - directory 'name' was created
  */
 static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
@@ -199,6 +212,19 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
 }
 
 /*
+ * fsnotify_rmdir - directory 'name' was removed
+ *
+ * Caller must make sure that dentry->d_name is stable.
+ */
+static inline void fsnotify_rmdir(struct inode *dir, struct dentry *dentry)
+{
+       /* Expected to be called before d_delete() */
+       WARN_ON_ONCE(d_is_negative(dentry));
+
+       fsnotify_dirent(dir, dentry, FS_DELETE | FS_ISDIR);
+}
+
+/*
  * fsnotify_access - file was read
  */
 static inline void fsnotify_access(struct file *file)
index d4844ca..2de3b2d 100644 (file)
@@ -357,7 +357,6 @@ extern int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u
 extern void __fsnotify_inode_delete(struct inode *inode);
 extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt);
 extern void fsnotify_sb_delete(struct super_block *sb);
-extern void fsnotify_nameremove(struct dentry *dentry, int isdir);
 extern u32 fsnotify_get_cookie(void);
 
 static inline int fsnotify_inode_watches_children(struct inode *inode)
@@ -527,9 +526,6 @@ static inline void __fsnotify_vfsmount_delete(struct vfsmount *mnt)
 static inline void fsnotify_sb_delete(struct super_block *sb)
 {}
 
-static inline void fsnotify_nameremove(struct dentry *dentry, int isdir)
-{}
-
 static inline void fsnotify_update_flags(struct dentry *dentry)
 {}
 
index 126d314..73bd629 100644 (file)
@@ -598,6 +598,8 @@ static int __rpc_rmdir(struct inode *dir, struct dentry *dentry)
 
        dget(dentry);
        ret = simple_rmdir(dir, dentry);
+       if (!ret)
+               fsnotify_rmdir(dir, dentry);
        d_delete(dentry);
        dput(dentry);
        return ret;
@@ -609,6 +611,8 @@ static int __rpc_unlink(struct inode *dir, struct dentry *dentry)
 
        dget(dentry);
        ret = simple_unlink(dir, dentry);
+       if (!ret)
+               fsnotify_unlink(dir, dentry);
        d_delete(dentry);
        dput(dentry);
        return ret;