Skip to content

Commit 1edc8eb

Browse files
Eric SandeenAl Viro
authored andcommitted
fs: call fsnotify_sb_delete after evict_inodes
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]>
1 parent 04646ae commit 1edc8eb

File tree

2 files changed

+6
-1
lines changed

2 files changed

+6
-1
lines changed

fs/notify/fsnotify.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ static void fsnotify_unmount_inodes(struct super_block *sb)
5757
* doing an __iget/iput with SB_ACTIVE clear would actually
5858
* evict all inodes with zero i_count from icache which is
5959
* unnecessarily violent and may in fact be illegal to do.
60+
* However, we should have been called /after/ evict_inodes
61+
* removed all zero refcount inodes, in any case. Test to
62+
* be sure.
6063
*/
6164
if (!atomic_read(&inode->i_count)) {
6265
spin_unlock(&inode->i_lock);

fs/super.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,10 +448,12 @@ void generic_shutdown_super(struct super_block *sb)
448448
sync_filesystem(sb);
449449
sb->s_flags &= ~SB_ACTIVE;
450450

451-
fsnotify_sb_delete(sb);
452451
cgroup_writeback_umount();
453452

453+
/* evict all inodes with zero refcount */
454454
evict_inodes(sb);
455+
/* only nonzero refcount inodes can have marks */
456+
fsnotify_sb_delete(sb);
455457

456458
if (sb->s_dio_done_wq) {
457459
destroy_workqueue(sb->s_dio_done_wq);

0 commit comments

Comments
 (0)