aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Dunlop <[email protected]>2015-05-02 15:47:06 +1000
committerBrian Behlendorf <[email protected]>2015-05-06 14:13:19 -0700
commitf0da4d15082be83547e5370e4479d3c04b56451d (patch)
treedef5b4ed713efeddb85aa081eea7348d119a3852
parent7a3066ffddcf4f87470e33a1cd414e558b90249c (diff)
Wait for all znodes to be released before tearing down the superblock
By the time we're tearing down our superblock the VFS has started releasing all our inodes/znodes. Some of this work may have been handed off to our iput taskq so we need to wait for that work to complete. However the iput from the taskq can itself result in additional work being added to the taskq: dsl_pool_iput_taskq iput iput_final evict destroy_inode zpl_inode_destroy zfs_inode_destroy zfs_iput_async(ZTOI(zp->z_xattr_parent)) taskq_dispatch(dsl_pool_iput_taskq..., iput, ...) Let's wait until all our znodes have been released. Signed-off-by: Chris Dunlop <[email protected]> Signed-off-by: Brian Behlendorf <[email protected]> Closes #3281
-rw-r--r--module/zfs/zfs_vfsops.c38
1 files changed, 30 insertions, 8 deletions
diff --git a/module/zfs/zfs_vfsops.c b/module/zfs/zfs_vfsops.c
index 41a1c4d88..59f73776c 100644
--- a/module/zfs/zfs_vfsops.c
+++ b/module/zfs/zfs_vfsops.c
@@ -1137,8 +1137,28 @@ zfs_sb_teardown(zfs_sb_t *zsb, boolean_t unmounting)
* drain the iput_taskq to ensure all active references to the
* zfs_sb_t have been handled only then can it be safely destroyed.
*/
- if (zsb->z_os)
- taskq_wait(dsl_pool_iput_taskq(dmu_objset_pool(zsb->z_os)));
+ if (zsb->z_os) {
+ /*
+ * If we're unmounting we have to wait for the list to
+ * drain completely.
+ *
+ * If we're not unmounting there's no guarantee the list
+ * will drain completely, but iputs run from the taskq
+ * may add the parents of dir-based xattrs to the taskq
+ * so we want to wait for these.
+ *
+ * We can safely read z_nr_znodes without locking because the
+ * VFS has already blocked operations which add to the
+ * z_all_znodes list and thus increment z_nr_znodes.
+ */
+ int round = 0;
+ while (zsb->z_nr_znodes > 0) {
+ taskq_wait(dsl_pool_iput_taskq(dmu_objset_pool(
+ zsb->z_os)));
+ if (++round > 1 && !unmounting)
+ break;
+ }
+ }
rrw_enter(&zsb->z_teardown_lock, RW_WRITER, FTAG);
@@ -1182,13 +1202,15 @@ zfs_sb_teardown(zfs_sb_t *zsb, boolean_t unmounting)
*
* Release all holds on dbufs.
*/
- mutex_enter(&zsb->z_znodes_lock);
- for (zp = list_head(&zsb->z_all_znodes); zp != NULL;
- zp = list_next(&zsb->z_all_znodes, zp)) {
- if (zp->z_sa_hdl)
- zfs_znode_dmu_fini(zp);
+ if (!unmounting) {
+ mutex_enter(&zsb->z_znodes_lock);
+ for (zp = list_head(&zsb->z_all_znodes); zp != NULL;
+ zp = list_next(&zsb->z_all_znodes, zp)) {
+ if (zp->z_sa_hdl)
+ zfs_znode_dmu_fini(zp);
+ }
+ mutex_exit(&zsb->z_znodes_lock);
}
- mutex_exit(&zsb->z_znodes_lock);
/*
* If we are unmounting, set the unmounted flag and let new VFS ops