diff --git a/kmod/src/inode.c b/kmod/src/inode.c index 881969a9..e395a36d 100644 --- a/kmod/src/inode.c +++ b/kmod/src/inode.c @@ -1972,7 +1972,11 @@ void scoutfs_inode_start(struct super_block *sb) schedule_orphan_dwork(inf); } -void scoutfs_inode_stop(struct super_block *sb) +/* + * Orphan scanning can instantiate inodes. We shut it down before + * calling into the vfs to tear down dentries and inodes during unmount. + */ +void scoutfs_inode_orphan_stop(struct super_block *sb) { DECLARE_INODE_SB_INFO(sb, inf); @@ -1982,6 +1986,14 @@ void scoutfs_inode_stop(struct super_block *sb) } } +void scoutfs_inode_flush_iput(struct super_block *sb) +{ + DECLARE_INODE_SB_INFO(sb, inf); + + if (inf) + flush_work(&inf->iput_work); +} + void scoutfs_inode_destroy(struct super_block *sb) { struct inode_sb_info *inf = SCOUTFS_SB(sb)->inode_sb_info; diff --git a/kmod/src/inode.h b/kmod/src/inode.h index 60e14f97..417a1825 100644 --- a/kmod/src/inode.h +++ b/kmod/src/inode.h @@ -133,7 +133,8 @@ int scoutfs_inode_init(void); int scoutfs_inode_setup(struct super_block *sb); void scoutfs_inode_start(struct super_block *sb); -void scoutfs_inode_stop(struct super_block *sb); +void scoutfs_inode_orphan_stop(struct super_block *sb); +void scoutfs_inode_flush_iput(struct super_block *sb); void scoutfs_inode_destroy(struct super_block *sb); #endif diff --git a/kmod/src/lock.c b/kmod/src/lock.c index 222f2461..e85fa7ff 100644 --- a/kmod/src/lock.c +++ b/kmod/src/lock.c @@ -1527,6 +1527,14 @@ void scoutfs_lock_unmount_begin(struct super_block *sb) } } +void scoutfs_lock_flush_invalidate(struct super_block *sb) +{ + DECLARE_LOCK_INFO(sb, linfo); + + if (linfo) + flush_work(&linfo->inv_work); +} + /* * The caller is going to be shutting down transactions and the client. * We need to make sure that locking won't call either after we return. diff --git a/kmod/src/lock.h b/kmod/src/lock.h index 9dc52441..c1848cf9 100644 --- a/kmod/src/lock.h +++ b/kmod/src/lock.h @@ -105,6 +105,7 @@ void scoutfs_free_unused_locks(struct super_block *sb); int scoutfs_lock_setup(struct super_block *sb); void scoutfs_lock_unmount_begin(struct super_block *sb); +void scoutfs_lock_flush_invalidate(struct super_block *sb); void scoutfs_lock_shutdown(struct super_block *sb); void scoutfs_lock_destroy(struct super_block *sb); diff --git a/kmod/src/super.c b/kmod/src/super.c index a54e8cf9..f9fcc133 100644 --- a/kmod/src/super.c +++ b/kmod/src/super.c @@ -255,7 +255,16 @@ static void scoutfs_put_super(struct super_block *sb) trace_scoutfs_put_super(sb); - scoutfs_inode_stop(sb); + /* + * Wait for invalidation and iput to finish with any lingering + * inode references that escaped the evict_inodes in + * generic_shutdown_super. MS_ACTIVE is clear so final iput + * will always evict. + */ + scoutfs_lock_flush_invalidate(sb); + scoutfs_inode_flush_iput(sb); + WARN_ON_ONCE(!list_empty(&sb->s_inodes)); + scoutfs_forest_stop(sb); scoutfs_srch_destroy(sb); @@ -668,8 +677,10 @@ static void scoutfs_kill_sb(struct super_block *sb) smp_wmb(); } - if (SCOUTFS_HAS_SBI(sb)) + if (SCOUTFS_HAS_SBI(sb)) { + scoutfs_inode_orphan_stop(sb); scoutfs_lock_unmount_begin(sb); + } kill_block_super(sb); }