* 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);
*
* 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