Skip to content

Commit e02f08e

Browse files
committed
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()
2 parents 4770119 + cad3f4a commit e02f08e

File tree

8 files changed

+25
-34
lines changed

8 files changed

+25
-34
lines changed

fs/nfsd/filecache.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,7 @@ nfsd_file_cache_init(void)
792792
}
793793

794794
nfsd_file_fsnotify_group = fsnotify_alloc_group(&nfsd_file_fsnotify_ops,
795-
FSNOTIFY_GROUP_NOFS);
795+
0);
796796
if (IS_ERR(nfsd_file_fsnotify_group)) {
797797
pr_err("nfsd: unable to create fsnotify group: %ld\n",
798798
PTR_ERR(nfsd_file_fsnotify_group));

fs/notify/dnotify/dnotify.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,8 +406,7 @@ static int __init dnotify_init(void)
406406
SLAB_PANIC|SLAB_ACCOUNT);
407407
dnotify_mark_cache = KMEM_CACHE(dnotify_mark, SLAB_PANIC|SLAB_ACCOUNT);
408408

409-
dnotify_group = fsnotify_alloc_group(&dnotify_fsnotify_ops,
410-
FSNOTIFY_GROUP_NOFS);
409+
dnotify_group = fsnotify_alloc_group(&dnotify_fsnotify_ops, 0);
411410
if (IS_ERR(dnotify_group))
412411
panic("unable to allocate fsnotify group for dnotify\n");
413412
dnotify_sysctl_init();

fs/notify/fanotify/fanotify_user.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1480,7 +1480,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
14801480

14811481
/* fsnotify_alloc_group takes a ref. Dropped in fanotify_release */
14821482
group = fsnotify_alloc_group(&fanotify_fsnotify_ops,
1483-
FSNOTIFY_GROUP_USER | FSNOTIFY_GROUP_NOFS);
1483+
FSNOTIFY_GROUP_USER);
14841484
if (IS_ERR(group)) {
14851485
return PTR_ERR(group);
14861486
}

fs/notify/fsnotify.c

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,10 @@ static bool fsnotify_event_needs_parent(struct inode *inode, __u32 mnt_mask,
183183
BUILD_BUG_ON(FS_EVENTS_POSS_ON_CHILD & ~FS_EVENTS_POSS_TO_PARENT);
184184

185185
/* Did either inode/sb/mount subscribe for events with parent/name? */
186-
marks_mask |= fsnotify_parent_needed_mask(inode->i_fsnotify_mask);
187-
marks_mask |= fsnotify_parent_needed_mask(inode->i_sb->s_fsnotify_mask);
186+
marks_mask |= fsnotify_parent_needed_mask(
187+
READ_ONCE(inode->i_fsnotify_mask));
188+
marks_mask |= fsnotify_parent_needed_mask(
189+
READ_ONCE(inode->i_sb->s_fsnotify_mask));
188190
marks_mask |= fsnotify_parent_needed_mask(mnt_mask);
189191

190192
/* 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,
195197
static inline bool fsnotify_object_watched(struct inode *inode, __u32 mnt_mask,
196198
__u32 mask)
197199
{
198-
__u32 marks_mask = inode->i_fsnotify_mask | mnt_mask |
199-
inode->i_sb->s_fsnotify_mask;
200+
__u32 marks_mask = READ_ONCE(inode->i_fsnotify_mask) | mnt_mask |
201+
READ_ONCE(inode->i_sb->s_fsnotify_mask);
200202

201203
return mask & marks_mask & ALL_FSNOTIFY_EVENTS;
202204
}
@@ -213,7 +215,8 @@ int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data,
213215
int data_type)
214216
{
215217
const struct path *path = fsnotify_data_path(data, data_type);
216-
__u32 mnt_mask = path ? real_mount(path->mnt)->mnt_fsnotify_mask : 0;
218+
__u32 mnt_mask = path ?
219+
READ_ONCE(real_mount(path->mnt)->mnt_fsnotify_mask) : 0;
217220
struct inode *inode = d_inode(dentry);
218221
struct dentry *parent;
219222
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,
557560
(!inode2 || !inode2->i_fsnotify_marks))
558561
return 0;
559562

560-
marks_mask = sb->s_fsnotify_mask;
563+
marks_mask = READ_ONCE(sb->s_fsnotify_mask);
561564
if (mnt)
562-
marks_mask |= mnt->mnt_fsnotify_mask;
565+
marks_mask |= READ_ONCE(mnt->mnt_fsnotify_mask);
563566
if (inode)
564-
marks_mask |= inode->i_fsnotify_mask;
567+
marks_mask |= READ_ONCE(inode->i_fsnotify_mask);
565568
if (inode2)
566-
marks_mask |= inode2->i_fsnotify_mask;
569+
marks_mask |= READ_ONCE(inode2->i_fsnotify_mask);
567570

568571

569572
/*

fs/notify/group.c

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,6 @@ static struct fsnotify_group *__fsnotify_alloc_group(
115115
const struct fsnotify_ops *ops,
116116
int flags, gfp_t gfp)
117117
{
118-
static struct lock_class_key nofs_marks_lock;
119118
struct fsnotify_group *group;
120119

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

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

150139
return group;
151140
}

fs/notify/inotify/inotify_user.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ static int inotify_update_existing_watch(struct fsnotify_group *group,
569569
/* more bits in old than in new? */
570570
int dropped = (old_mask & ~new_mask);
571571
/* more bits in this fsn_mark than the inode's mask? */
572-
int do_inode = (new_mask & ~inode->i_fsnotify_mask);
572+
int do_inode = (new_mask & ~READ_ONCE(inode->i_fsnotify_mask));
573573

574574
/* update the inode with this new fsn_mark */
575575
if (dropped || do_inode)

fs/notify/mark.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ __u32 fsnotify_conn_mask(struct fsnotify_mark_connector *conn)
128128
if (WARN_ON(!fsnotify_valid_obj_type(conn->type)))
129129
return 0;
130130

131-
return *fsnotify_conn_mask_p(conn);
131+
return READ_ONCE(*fsnotify_conn_mask_p(conn));
132132
}
133133

134134
static void fsnotify_get_sb_watched_objects(struct super_block *sb)
@@ -245,7 +245,11 @@ static void *__fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
245245
!(mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF))
246246
want_iref = true;
247247
}
248-
*fsnotify_conn_mask_p(conn) = new_mask;
248+
/*
249+
* We use WRITE_ONCE() to prevent silly compiler optimizations from
250+
* confusing readers not holding conn->lock with partial updates.
251+
*/
252+
WRITE_ONCE(*fsnotify_conn_mask_p(conn), new_mask);
249253

250254
return fsnotify_update_iref(conn, want_iref);
251255
}

include/linux/fsnotify_backend.h

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,6 @@ struct fsnotify_group {
217217

218218
#define FSNOTIFY_GROUP_USER 0x01 /* user allocated group */
219219
#define FSNOTIFY_GROUP_DUPS 0x02 /* allow multiple marks per object */
220-
#define FSNOTIFY_GROUP_NOFS 0x04 /* group lock is not direct reclaim safe */
221220
int flags;
222221
unsigned int owner_flags; /* stored flags of mark_mutex owner */
223222

@@ -268,22 +267,19 @@ struct fsnotify_group {
268267
static inline void fsnotify_group_lock(struct fsnotify_group *group)
269268
{
270269
mutex_lock(&group->mark_mutex);
271-
if (group->flags & FSNOTIFY_GROUP_NOFS)
272-
group->owner_flags = memalloc_nofs_save();
270+
group->owner_flags = memalloc_nofs_save();
273271
}
274272

275273
static inline void fsnotify_group_unlock(struct fsnotify_group *group)
276274
{
277-
if (group->flags & FSNOTIFY_GROUP_NOFS)
278-
memalloc_nofs_restore(group->owner_flags);
275+
memalloc_nofs_restore(group->owner_flags);
279276
mutex_unlock(&group->mark_mutex);
280277
}
281278

282279
static inline void fsnotify_group_assert_locked(struct fsnotify_group *group)
283280
{
284281
WARN_ON_ONCE(!mutex_is_locked(&group->mark_mutex));
285-
if (group->flags & FSNOTIFY_GROUP_NOFS)
286-
WARN_ON_ONCE(!(current->flags & PF_MEMALLOC_NOFS));
282+
WARN_ON_ONCE(!(current->flags & PF_MEMALLOC_NOFS));
287283
}
288284

289285
/* When calling fsnotify tell it if the data is a path or inode */

0 commit comments

Comments
 (0)