Commit e02f08e2 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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

Pull fsnotify fixes from Jan Kara:
 "Fixes for an inotify deadlock and a data race in fsnotify"

* tag 'fsnotify_for_v6.12-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
  inotify: Fix possible deadlock in fsnotify_destroy_mark
  fsnotify: Avoid data race between fsnotify_recalc_mask() and fsnotify_object_watched()
parents 4770119d cad3f4a2
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -792,7 +792,7 @@ nfsd_file_cache_init(void)
	}

	nfsd_file_fsnotify_group = fsnotify_alloc_group(&nfsd_file_fsnotify_ops,
							FSNOTIFY_GROUP_NOFS);
							0);
	if (IS_ERR(nfsd_file_fsnotify_group)) {
		pr_err("nfsd: unable to create fsnotify group: %ld\n",
			PTR_ERR(nfsd_file_fsnotify_group));
+1 −2
Original line number Diff line number Diff line
@@ -406,8 +406,7 @@ static int __init dnotify_init(void)
					  SLAB_PANIC|SLAB_ACCOUNT);
	dnotify_mark_cache = KMEM_CACHE(dnotify_mark, SLAB_PANIC|SLAB_ACCOUNT);

	dnotify_group = fsnotify_alloc_group(&dnotify_fsnotify_ops,
					     FSNOTIFY_GROUP_NOFS);
	dnotify_group = fsnotify_alloc_group(&dnotify_fsnotify_ops, 0);
	if (IS_ERR(dnotify_group))
		panic("unable to allocate fsnotify group for dnotify\n");
	dnotify_sysctl_init();
+1 −1
Original line number Diff line number Diff line
@@ -1480,7 +1480,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)

	/* fsnotify_alloc_group takes a ref.  Dropped in fanotify_release */
	group = fsnotify_alloc_group(&fanotify_fsnotify_ops,
				     FSNOTIFY_GROUP_USER | FSNOTIFY_GROUP_NOFS);
				     FSNOTIFY_GROUP_USER);
	if (IS_ERR(group)) {
		return PTR_ERR(group);
	}
+12 −9
Original line number Diff line number Diff line
@@ -183,8 +183,10 @@ static bool fsnotify_event_needs_parent(struct inode *inode, __u32 mnt_mask,
	BUILD_BUG_ON(FS_EVENTS_POSS_ON_CHILD & ~FS_EVENTS_POSS_TO_PARENT);

	/* Did either inode/sb/mount subscribe for events with parent/name? */
	marks_mask |= fsnotify_parent_needed_mask(inode->i_fsnotify_mask);
	marks_mask |= fsnotify_parent_needed_mask(inode->i_sb->s_fsnotify_mask);
	marks_mask |= fsnotify_parent_needed_mask(
				READ_ONCE(inode->i_fsnotify_mask));
	marks_mask |= fsnotify_parent_needed_mask(
				READ_ONCE(inode->i_sb->s_fsnotify_mask));
	marks_mask |= fsnotify_parent_needed_mask(mnt_mask);

	/* Did they subscribe for this event with parent/name info? */
@@ -195,8 +197,8 @@ static bool fsnotify_event_needs_parent(struct inode *inode, __u32 mnt_mask,
static inline bool fsnotify_object_watched(struct inode *inode, __u32 mnt_mask,
					   __u32 mask)
{
	__u32 marks_mask = inode->i_fsnotify_mask | mnt_mask |
			   inode->i_sb->s_fsnotify_mask;
	__u32 marks_mask = READ_ONCE(inode->i_fsnotify_mask) | mnt_mask |
			   READ_ONCE(inode->i_sb->s_fsnotify_mask);

	return mask & marks_mask & ALL_FSNOTIFY_EVENTS;
}
@@ -213,7 +215,8 @@ int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data,
		      int data_type)
{
	const struct path *path = fsnotify_data_path(data, data_type);
	__u32 mnt_mask = path ? real_mount(path->mnt)->mnt_fsnotify_mask : 0;
	__u32 mnt_mask = path ?
		READ_ONCE(real_mount(path->mnt)->mnt_fsnotify_mask) : 0;
	struct inode *inode = d_inode(dentry);
	struct dentry *parent;
	bool parent_watched = dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED;
@@ -557,13 +560,13 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,
	    (!inode2 || !inode2->i_fsnotify_marks))
		return 0;

	marks_mask = sb->s_fsnotify_mask;
	marks_mask = READ_ONCE(sb->s_fsnotify_mask);
	if (mnt)
		marks_mask |= mnt->mnt_fsnotify_mask;
		marks_mask |= READ_ONCE(mnt->mnt_fsnotify_mask);
	if (inode)
		marks_mask |= inode->i_fsnotify_mask;
		marks_mask |= READ_ONCE(inode->i_fsnotify_mask);
	if (inode2)
		marks_mask |= inode2->i_fsnotify_mask;
		marks_mask |= READ_ONCE(inode2->i_fsnotify_mask);


	/*
+0 −11
Original line number Diff line number Diff line
@@ -115,7 +115,6 @@ static struct fsnotify_group *__fsnotify_alloc_group(
				const struct fsnotify_ops *ops,
				int flags, gfp_t gfp)
{
	static struct lock_class_key nofs_marks_lock;
	struct fsnotify_group *group;

	group = kzalloc(sizeof(struct fsnotify_group), gfp);
@@ -136,16 +135,6 @@ static struct fsnotify_group *__fsnotify_alloc_group(

	group->ops = ops;
	group->flags = flags;
	/*
	 * For most backends, eviction of inode with a mark is not expected,
	 * because marks hold a refcount on the inode against eviction.
	 *
	 * Use a different lockdep class for groups that support evictable
	 * inode marks, because with evictable marks, mark_mutex is NOT
	 * fs-reclaim safe - the mutex is taken when evicting inodes.
	 */
	if (flags & FSNOTIFY_GROUP_NOFS)
		lockdep_set_class(&group->mark_mutex, &nofs_marks_lock);

	return group;
}
Loading