Skip to content

Commit

Permalink
fs: call fsnotify_sb_delete after evict_inodes
Browse files Browse the repository at this point in the history
When a filesystem is unmounted, we currently call fsnotify_sb_delete()
before evict_inodes(), which means that fsnotify_unmount_inodes()
must iterate over all inodes on the superblock looking for any inodes
with watches.  This is inefficient and can lead to livelocks as it
iterates over many unwatched inodes.

At this point, SB_ACTIVE is gone and dropping refcount to zero kicks
the inode out out immediately, so anything processed by
fsnotify_sb_delete / fsnotify_unmount_inodes gets evicted in that loop.

After that, the call to evict_inodes will evict everything else with a
zero refcount.

This should speed things up overall, and avoid livelocks in
fsnotify_unmount_inodes().

Signed-off-by: Eric Sandeen <[email protected]>
Reviewed-by: Jan Kara <[email protected]>
Signed-off-by: Al Viro <[email protected]>
  • Loading branch information
Eric Sandeen authored and Al Viro committed Dec 18, 2019
1 parent 04646ae commit 1edc8eb
Show file tree
Hide file tree
Showing 2 changed files with 6 additions and 1 deletion.
3 changes: 3 additions & 0 deletions fs/notify/fsnotify.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ static void fsnotify_unmount_inodes(struct super_block *sb)
* doing an __iget/iput with SB_ACTIVE clear would actually
* evict all inodes with zero i_count from icache which is
* unnecessarily violent and may in fact be illegal to do.
* However, we should have been called /after/ evict_inodes
* removed all zero refcount inodes, in any case. Test to
* be sure.
*/
if (!atomic_read(&inode->i_count)) {
spin_unlock(&inode->i_lock);
Expand Down
4 changes: 3 additions & 1 deletion fs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -448,10 +448,12 @@ void generic_shutdown_super(struct super_block *sb)
sync_filesystem(sb);
sb->s_flags &= ~SB_ACTIVE;

fsnotify_sb_delete(sb);
cgroup_writeback_umount();

/* evict all inodes with zero refcount */
evict_inodes(sb);
/* only nonzero refcount inodes can have marks */
fsnotify_sb_delete(sb);

if (sb->s_dio_done_wq) {
destroy_workqueue(sb->s_dio_done_wq);
Expand Down

0 comments on commit 1edc8eb

Please sign in to comment.