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

dnotify: use fsnotify group lock helpers

Before commit 9542e6a643fc6 ("nfsd: Containerise filecache laundrette")
nfsd would close open files in direct reclaim context. There is no
guarantee that others memory shrinkers don't do the same and no
guarantee that future shrinkers won't do that.

For example, if overlayfs implements inode cache of fscache would
keep open files to cached objects, inode shrinkers could end up closing
open files to underlying fs.

Direct reclaim from dnotify mark allocation context may try to close
open files that have dnotify marks of the same group and hit a deadlock
on mark_mutex.

Set the FSNOTIFY_GROUP_NOFS flag to prevent going into direct reclaim
from allocations under dnotify group lock and use the safe group lock
helpers.

Link: https://lore.kernel.org/r/20220422120327.3459282-11-amir73il@gmail.com
Suggested-by: Jan Kara <jack@suse.cz>
Link: https://lore.kernel.org/r/20220321112310.vpr7oxro2xkz5llh@quack3.lan/
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Jan Kara <jack@suse.cz>

authored by

Amir Goldstein and committed by
Jan Kara
aabb45fd b8962a9d

+7 -6
+7 -6
fs/notify/dnotify/dnotify.c
··· 168 168 return; 169 169 dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark); 170 170 171 - mutex_lock(&dnotify_group->mark_mutex); 171 + fsnotify_group_lock(dnotify_group); 172 172 173 173 spin_lock(&fsn_mark->lock); 174 174 prev = &dn_mark->dn; ··· 191 191 free = true; 192 192 } 193 193 194 - mutex_unlock(&dnotify_group->mark_mutex); 194 + fsnotify_group_unlock(dnotify_group); 195 195 196 196 if (free) 197 197 fsnotify_free_mark(fsn_mark); ··· 324 324 new_dn_mark->dn = NULL; 325 325 326 326 /* this is needed to prevent the fcntl/close race described below */ 327 - mutex_lock(&dnotify_group->mark_mutex); 327 + fsnotify_group_lock(dnotify_group); 328 328 329 329 /* add the new_fsn_mark or find an old one. */ 330 330 fsn_mark = fsnotify_find_mark(&inode->i_fsnotify_marks, dnotify_group); ··· 334 334 } else { 335 335 error = fsnotify_add_inode_mark_locked(new_fsn_mark, inode, 0); 336 336 if (error) { 337 - mutex_unlock(&dnotify_group->mark_mutex); 337 + fsnotify_group_unlock(dnotify_group); 338 338 goto out_err; 339 339 } 340 340 spin_lock(&new_fsn_mark->lock); ··· 383 383 384 384 if (destroy) 385 385 fsnotify_detach_mark(fsn_mark); 386 - mutex_unlock(&dnotify_group->mark_mutex); 386 + fsnotify_group_unlock(dnotify_group); 387 387 if (destroy) 388 388 fsnotify_free_mark(fsn_mark); 389 389 fsnotify_put_mark(fsn_mark); ··· 401 401 SLAB_PANIC|SLAB_ACCOUNT); 402 402 dnotify_mark_cache = KMEM_CACHE(dnotify_mark, SLAB_PANIC|SLAB_ACCOUNT); 403 403 404 - dnotify_group = fsnotify_alloc_group(&dnotify_fsnotify_ops, 0); 404 + dnotify_group = fsnotify_alloc_group(&dnotify_fsnotify_ops, 405 + FSNOTIFY_GROUP_NOFS); 405 406 if (IS_ERR(dnotify_group)) 406 407 panic("unable to allocate fsnotify group for dnotify\n"); 407 408 dnotify_sysctl_init();