Commit e6983afd authored by Linus Torvalds's avatar Linus Torvalds

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

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
parents 988052f4 7377f5be
...@@ -60,11 +60,6 @@ static int afs_do_silly_rename(struct afs_vnode *dvnode, struct afs_vnode *vnode ...@@ -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)) if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
afs_edit_dir_add(dvnode, &new->d_name, afs_edit_dir_add(dvnode, &new->d_name,
&vnode->fid, afs_edit_dir_for_silly_1); &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); kfree(scb);
......
...@@ -2928,8 +2928,10 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, ...@@ -2928,8 +2928,10 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
inode_lock(inode); inode_lock(inode);
err = btrfs_delete_subvolume(dir, dentry); err = btrfs_delete_subvolume(dir, dentry);
inode_unlock(inode); inode_unlock(inode);
if (!err) if (!err) {
fsnotify_rmdir(dir, dentry);
d_delete(dentry); d_delete(dentry);
}
out_dput: out_dput:
dput(dentry); dput(dentry);
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#undef DEBUG #undef DEBUG
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/fsnotify.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -1788,6 +1789,7 @@ void configfs_unregister_group(struct config_group *group) ...@@ -1788,6 +1789,7 @@ void configfs_unregister_group(struct config_group *group)
configfs_detach_group(&group->cg_item); configfs_detach_group(&group->cg_item);
d_inode(dentry)->i_flags |= S_DEAD; d_inode(dentry)->i_flags |= S_DEAD;
dont_mount(dentry); dont_mount(dentry);
fsnotify_rmdir(d_inode(parent), dentry);
d_delete(dentry); d_delete(dentry);
inode_unlock(d_inode(parent)); inode_unlock(d_inode(parent));
...@@ -1916,6 +1918,7 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys) ...@@ -1916,6 +1918,7 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys)
configfs_detach_group(&group->cg_item); configfs_detach_group(&group->cg_item);
d_inode(dentry)->i_flags |= S_DEAD; d_inode(dentry)->i_flags |= S_DEAD;
dont_mount(dentry); dont_mount(dentry);
fsnotify_rmdir(d_inode(root), dentry);
inode_unlock(d_inode(dentry)); inode_unlock(d_inode(dentry));
d_delete(dentry); d_delete(dentry);
......
...@@ -2372,7 +2372,6 @@ EXPORT_SYMBOL(d_hash_and_lookup); ...@@ -2372,7 +2372,6 @@ EXPORT_SYMBOL(d_hash_and_lookup);
void d_delete(struct dentry * dentry) void d_delete(struct dentry * dentry)
{ {
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
int isdir = d_is_dir(dentry);
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
...@@ -2387,7 +2386,6 @@ void d_delete(struct dentry * dentry) ...@@ -2387,7 +2386,6 @@ void d_delete(struct dentry * dentry)
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
fsnotify_nameremove(dentry, isdir);
} }
EXPORT_SYMBOL(d_delete); EXPORT_SYMBOL(d_delete);
......
...@@ -617,13 +617,10 @@ struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent, ...@@ -617,13 +617,10 @@ struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent,
} }
EXPORT_SYMBOL_GPL(debugfs_create_symlink); 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; struct debugfs_fsdata *fsd;
simple_unlink(d_inode(parent), dentry);
d_delete(dentry);
/* /*
* Paired with the closing smp_mb() implied by a successful * Paired with the closing smp_mb() implied by a successful
* cmpxchg() in debugfs_file_get(): either * cmpxchg() in debugfs_file_get(): either
...@@ -644,16 +641,18 @@ static int __debugfs_remove(struct dentry *dentry, struct dentry *parent) ...@@ -644,16 +641,18 @@ static int __debugfs_remove(struct dentry *dentry, struct dentry *parent)
if (simple_positive(dentry)) { if (simple_positive(dentry)) {
dget(dentry); dget(dentry);
if (!d_is_reg(dentry)) { if (d_is_dir(dentry)) {
if (d_is_dir(dentry))
ret = simple_rmdir(d_inode(parent), dentry); ret = simple_rmdir(d_inode(parent), dentry);
else
simple_unlink(d_inode(parent), dentry);
if (!ret) if (!ret)
d_delete(dentry); fsnotify_rmdir(d_inode(parent), dentry);
} else { } 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); dput(dentry);
} }
return ret; return ret;
......
...@@ -621,6 +621,7 @@ void devpts_pty_kill(struct dentry *dentry) ...@@ -621,6 +621,7 @@ void devpts_pty_kill(struct dentry *dentry)
dentry->d_fsdata = NULL; dentry->d_fsdata = NULL;
drop_nlink(dentry->d_inode); drop_nlink(dentry->d_inode);
fsnotify_unlink(d_inode(dentry->d_parent), dentry);
d_delete(dentry); d_delete(dentry);
dput(dentry); /* d_alloc_name() in devpts_pty_new() */ dput(dentry); /* d_alloc_name() in devpts_pty_new() */
} }
......
...@@ -3883,6 +3883,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -3883,6 +3883,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
dentry->d_inode->i_flags |= S_DEAD; dentry->d_inode->i_flags |= S_DEAD;
dont_mount(dentry); dont_mount(dentry);
detach_mounts(dentry); detach_mounts(dentry);
fsnotify_rmdir(dir, dentry);
out: out:
inode_unlock(dentry->d_inode); inode_unlock(dentry->d_inode);
...@@ -3999,6 +4000,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegate ...@@ -3999,6 +4000,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegate
if (!error) { if (!error) {
dont_mount(dentry); dont_mount(dentry);
detach_mounts(dentry); detach_mounts(dentry);
fsnotify_unlink(dir, dentry);
} }
} }
} }
......
...@@ -396,12 +396,6 @@ nfs_complete_sillyrename(struct rpc_task *task, struct nfs_renamedata *data) ...@@ -396,12 +396,6 @@ nfs_complete_sillyrename(struct rpc_task *task, struct nfs_renamedata *data)
nfs_cancel_async_unlink(dentry); nfs_cancel_async_unlink(dentry);
return; 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" #define SILLYNAME_PREFIX ".nfs"
......
...@@ -920,6 +920,22 @@ static int fanotify_test_fid(struct path *path, __kernel_fsid_t *fsid) ...@@ -920,6 +920,22 @@ static int fanotify_test_fid(struct path *path, __kernel_fsid_t *fsid)
return 0; 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, static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
int dfd, const char __user *pathname) int dfd, const char __user *pathname)
{ {
...@@ -1018,6 +1034,12 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, ...@@ -1018,6 +1034,12 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
if (ret) if (ret)
goto fput_and_out; 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)) { if (FAN_GROUP_FLAG(group, FAN_REPORT_FID)) {
ret = fanotify_test_fid(&path, &__fsid); ret = fanotify_test_fid(&path, &__fsid);
if (ret) if (ret)
......
...@@ -94,47 +94,6 @@ void fsnotify_sb_delete(struct super_block *sb) ...@@ -94,47 +94,6 @@ void fsnotify_sb_delete(struct super_block *sb)
fsnotify_clear_marks_by_sb(sb); fsnotify_clear_marks_by_sb(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 * 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 * and dnotify both tell their parents about events. If we care about any event
......
...@@ -211,7 +211,7 @@ static struct file_system_type proc_fs_type = { ...@@ -211,7 +211,7 @@ static struct file_system_type proc_fs_type = {
.init_fs_context = proc_init_fs_context, .init_fs_context = proc_init_fs_context,
.parameters = &proc_fs_parameters, .parameters = &proc_fs_parameters,
.kill_sb = proc_kill_sb, .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) void __init proc_root_init(void)
......
...@@ -505,9 +505,12 @@ static int __tracefs_remove(struct dentry *dentry, struct dentry *parent) ...@@ -505,9 +505,12 @@ static int __tracefs_remove(struct dentry *dentry, struct dentry *parent)
switch (dentry->d_inode->i_mode & S_IFMT) { switch (dentry->d_inode->i_mode & S_IFMT) {
case S_IFDIR: case S_IFDIR:
ret = simple_rmdir(parent->d_inode, dentry); ret = simple_rmdir(parent->d_inode, dentry);
if (!ret)
fsnotify_rmdir(parent->d_inode, dentry);
break; break;
default: default:
simple_unlink(parent->d_inode, dentry); simple_unlink(parent->d_inode, dentry);
fsnotify_unlink(parent->d_inode, dentry);
break; break;
} }
if (!ret) if (!ret)
......
...@@ -2184,6 +2184,7 @@ struct file_system_type { ...@@ -2184,6 +2184,7 @@ struct file_system_type {
#define FS_BINARY_MOUNTDATA 2 #define FS_BINARY_MOUNTDATA 2
#define FS_HAS_SUBTYPE 4 #define FS_HAS_SUBTYPE 4
#define FS_USERNS_MOUNT 8 /* Can be mounted by userns root */ #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. */ #define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() during rename() internally. */
int (*init_fs_context)(struct fs_context *); int (*init_fs_context)(struct fs_context *);
const struct fs_parameter_description *parameters; const struct fs_parameter_description *parameters;
......
...@@ -188,6 +188,19 @@ static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct ...@@ -188,6 +188,19 @@ static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct
fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE, &new_dentry->d_name, 0); fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE, &new_dentry->d_name, 0);
} }
/*
* 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 * fsnotify_mkdir - directory 'name' was created
*/ */
...@@ -198,6 +211,19 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry) ...@@ -198,6 +211,19 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
fsnotify_dirent(inode, dentry, FS_CREATE | FS_ISDIR); fsnotify_dirent(inode, dentry, FS_CREATE | FS_ISDIR);
} }
/*
* 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 * fsnotify_access - file was read
*/ */
......
...@@ -357,7 +357,6 @@ extern int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u ...@@ -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_inode_delete(struct inode *inode);
extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt); extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt);
extern void fsnotify_sb_delete(struct super_block *sb); extern void fsnotify_sb_delete(struct super_block *sb);
extern void fsnotify_nameremove(struct dentry *dentry, int isdir);
extern u32 fsnotify_get_cookie(void); extern u32 fsnotify_get_cookie(void);
static inline int fsnotify_inode_watches_children(struct inode *inode) static inline int fsnotify_inode_watches_children(struct inode *inode)
...@@ -527,9 +526,6 @@ static inline void __fsnotify_vfsmount_delete(struct vfsmount *mnt) ...@@ -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_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) static inline void fsnotify_update_flags(struct dentry *dentry)
{} {}
......
...@@ -598,6 +598,8 @@ static int __rpc_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -598,6 +598,8 @@ static int __rpc_rmdir(struct inode *dir, struct dentry *dentry)
dget(dentry); dget(dentry);
ret = simple_rmdir(dir, dentry); ret = simple_rmdir(dir, dentry);
if (!ret)
fsnotify_rmdir(dir, dentry);
d_delete(dentry); d_delete(dentry);
dput(dentry); dput(dentry);
return ret; return ret;
...@@ -609,6 +611,8 @@ static int __rpc_unlink(struct inode *dir, struct dentry *dentry) ...@@ -609,6 +611,8 @@ static int __rpc_unlink(struct inode *dir, struct dentry *dentry)
dget(dentry); dget(dentry);
ret = simple_unlink(dir, dentry); ret = simple_unlink(dir, dentry);
if (!ret)
fsnotify_unlink(dir, dentry);
d_delete(dentry); d_delete(dentry);
dput(dentry); dput(dentry);
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment