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

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()

+25 -34
+1 -1
fs/nfsd/filecache.c
··· 792 792 } 793 793 794 794 nfsd_file_fsnotify_group = fsnotify_alloc_group(&nfsd_file_fsnotify_ops, 795 - FSNOTIFY_GROUP_NOFS); 795 + 0); 796 796 if (IS_ERR(nfsd_file_fsnotify_group)) { 797 797 pr_err("nfsd: unable to create fsnotify group: %ld\n", 798 798 PTR_ERR(nfsd_file_fsnotify_group));
+1 -2
fs/notify/dnotify/dnotify.c
··· 406 406 SLAB_PANIC|SLAB_ACCOUNT); 407 407 dnotify_mark_cache = KMEM_CACHE(dnotify_mark, SLAB_PANIC|SLAB_ACCOUNT); 408 408 409 - dnotify_group = fsnotify_alloc_group(&dnotify_fsnotify_ops, 410 - FSNOTIFY_GROUP_NOFS); 409 + dnotify_group = fsnotify_alloc_group(&dnotify_fsnotify_ops, 0); 411 410 if (IS_ERR(dnotify_group)) 412 411 panic("unable to allocate fsnotify group for dnotify\n"); 413 412 dnotify_sysctl_init();
+1 -1
fs/notify/fanotify/fanotify_user.c
··· 1480 1480 1481 1481 /* fsnotify_alloc_group takes a ref. Dropped in fanotify_release */ 1482 1482 group = fsnotify_alloc_group(&fanotify_fsnotify_ops, 1483 - FSNOTIFY_GROUP_USER | FSNOTIFY_GROUP_NOFS); 1483 + FSNOTIFY_GROUP_USER); 1484 1484 if (IS_ERR(group)) { 1485 1485 return PTR_ERR(group); 1486 1486 }
+12 -9
fs/notify/fsnotify.c
··· 183 183 BUILD_BUG_ON(FS_EVENTS_POSS_ON_CHILD & ~FS_EVENTS_POSS_TO_PARENT); 184 184 185 185 /* 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)); 188 190 marks_mask |= fsnotify_parent_needed_mask(mnt_mask); 189 191 190 192 /* Did they subscribe for this event with parent/name info? */ ··· 197 195 static inline bool fsnotify_object_watched(struct inode *inode, __u32 mnt_mask, 198 196 __u32 mask) 199 197 { 200 - __u32 marks_mask = inode->i_fsnotify_mask | mnt_mask | 201 - inode->i_sb->s_fsnotify_mask; 198 + __u32 marks_mask = READ_ONCE(inode->i_fsnotify_mask) | mnt_mask | 199 + READ_ONCE(inode->i_sb->s_fsnotify_mask); 202 200 203 201 return mask & marks_mask & ALL_FSNOTIFY_EVENTS; 204 202 } ··· 215 213 int data_type) 216 214 { 217 215 const struct path *path = fsnotify_data_path(data, data_type); 218 - __u32 mnt_mask = path ? real_mount(path->mnt)->mnt_fsnotify_mask : 0; 216 + __u32 mnt_mask = path ? 217 + READ_ONCE(real_mount(path->mnt)->mnt_fsnotify_mask) : 0; 219 218 struct inode *inode = d_inode(dentry); 220 219 struct dentry *parent; 221 220 bool parent_watched = dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED; ··· 560 557 (!inode2 || !inode2->i_fsnotify_marks)) 561 558 return 0; 562 559 563 - marks_mask = sb->s_fsnotify_mask; 560 + marks_mask = READ_ONCE(sb->s_fsnotify_mask); 564 561 if (mnt) 565 - marks_mask |= mnt->mnt_fsnotify_mask; 562 + marks_mask |= READ_ONCE(mnt->mnt_fsnotify_mask); 566 563 if (inode) 567 - marks_mask |= inode->i_fsnotify_mask; 564 + marks_mask |= READ_ONCE(inode->i_fsnotify_mask); 568 565 if (inode2) 569 - marks_mask |= inode2->i_fsnotify_mask; 566 + marks_mask |= READ_ONCE(inode2->i_fsnotify_mask); 570 567 571 568 572 569 /*
-11
fs/notify/group.c
··· 115 115 const struct fsnotify_ops *ops, 116 116 int flags, gfp_t gfp) 117 117 { 118 - static struct lock_class_key nofs_marks_lock; 119 118 struct fsnotify_group *group; 120 119 121 120 group = kzalloc(sizeof(struct fsnotify_group), gfp); ··· 135 136 136 137 group->ops = ops; 137 138 group->flags = flags; 138 - /* 139 - * For most backends, eviction of inode with a mark is not expected, 140 - * because marks hold a refcount on the inode against eviction. 141 - * 142 - * Use a different lockdep class for groups that support evictable 143 - * inode marks, because with evictable marks, mark_mutex is NOT 144 - * fs-reclaim safe - the mutex is taken when evicting inodes. 145 - */ 146 - if (flags & FSNOTIFY_GROUP_NOFS) 147 - lockdep_set_class(&group->mark_mutex, &nofs_marks_lock); 148 139 149 140 return group; 150 141 }
+1 -1
fs/notify/inotify/inotify_user.c
··· 569 569 /* more bits in old than in new? */ 570 570 int dropped = (old_mask & ~new_mask); 571 571 /* 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)); 573 573 574 574 /* update the inode with this new fsn_mark */ 575 575 if (dropped || do_inode)
+6 -2
fs/notify/mark.c
··· 128 128 if (WARN_ON(!fsnotify_valid_obj_type(conn->type))) 129 129 return 0; 130 130 131 - return *fsnotify_conn_mask_p(conn); 131 + return READ_ONCE(*fsnotify_conn_mask_p(conn)); 132 132 } 133 133 134 134 static void fsnotify_get_sb_watched_objects(struct super_block *sb) ··· 245 245 !(mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF)) 246 246 want_iref = true; 247 247 } 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); 249 253 250 254 return fsnotify_update_iref(conn, want_iref); 251 255 }
+3 -7
include/linux/fsnotify_backend.h
··· 217 217 218 218 #define FSNOTIFY_GROUP_USER 0x01 /* user allocated group */ 219 219 #define FSNOTIFY_GROUP_DUPS 0x02 /* allow multiple marks per object */ 220 - #define FSNOTIFY_GROUP_NOFS 0x04 /* group lock is not direct reclaim safe */ 221 220 int flags; 222 221 unsigned int owner_flags; /* stored flags of mark_mutex owner */ 223 222 ··· 267 268 static inline void fsnotify_group_lock(struct fsnotify_group *group) 268 269 { 269 270 mutex_lock(&group->mark_mutex); 270 - if (group->flags & FSNOTIFY_GROUP_NOFS) 271 - group->owner_flags = memalloc_nofs_save(); 271 + group->owner_flags = memalloc_nofs_save(); 272 272 } 273 273 274 274 static inline void fsnotify_group_unlock(struct fsnotify_group *group) 275 275 { 276 - if (group->flags & FSNOTIFY_GROUP_NOFS) 277 - memalloc_nofs_restore(group->owner_flags); 276 + memalloc_nofs_restore(group->owner_flags); 278 277 mutex_unlock(&group->mark_mutex); 279 278 } 280 279 281 280 static inline void fsnotify_group_assert_locked(struct fsnotify_group *group) 282 281 { 283 282 WARN_ON_ONCE(!mutex_is_locked(&group->mark_mutex)); 284 - if (group->flags & FSNOTIFY_GROUP_NOFS) 285 - WARN_ON_ONCE(!(current->flags & PF_MEMALLOC_NOFS)); 283 + WARN_ON_ONCE(!(current->flags & PF_MEMALLOC_NOFS)); 286 284 } 287 285 288 286 /* When calling fsnotify tell it if the data is a path or inode */