summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_vfsops.c39
1 files changed, 28 insertions, 11 deletions
diff --git a/usr/src/uts/common/fs/zfs/zfs_vfsops.c b/usr/src/uts/common/fs/zfs/zfs_vfsops.c
index d504e15457..9e2758aab0 100644
--- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c
+++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c
@@ -25,6 +25,7 @@
* Copyright 2016 Nexenta Systems, Inc. All rights reserved.
* Copyright 2019 Joyent, Inc.
* Copyright 2020 Joshua M. Clulow <josh@sysmgr.org>
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
*/
/* Portions Copyright 2010 Robert Milkowski */
@@ -2228,18 +2229,34 @@ zfs_umount(vfs_t *vfsp, int fflag, cred_t *cr)
* Our count is maintained in the vfs structure, but the
* number is off by 1 to indicate a hold on the vfs
* structure itself.
- *
- * The '.zfs' directory maintains a reference of its
- * own, and any active references underneath are
- * reflected in the vnode count.
*/
- if (zfsvfs->z_ctldir == NULL) {
- if (vfsp->vfs_count > 1)
- return (SET_ERROR(EBUSY));
- } else {
- if (vfsp->vfs_count > 2 ||
- zfsvfs->z_ctldir->v_count > 1)
- return (SET_ERROR(EBUSY));
+ boolean_t draining;
+ uint_t thresh = 1;
+
+ /*
+ * The '.zfs' directory maintains a reference of its own, and
+ * any active references underneath are reflected in the vnode
+ * count. Allow one additional reference for it.
+ */
+ if (zfsvfs->z_ctldir != NULL)
+ thresh++;
+
+ /*
+ * If it's running, the asynchronous unlinked drain task needs
+ * to be stopped before the number of active vnodes can be
+ * reliably checked.
+ */
+ draining = zfsvfs->z_draining;
+ if (draining)
+ zfs_unlinked_drain_stop_wait(zfsvfs);
+
+ if (vfsp->vfs_count > thresh || (zfsvfs->z_ctldir != NULL &&
+ zfsvfs->z_ctldir->v_count > 1)) {
+ if (draining) {
+ /* If it was draining, restart the task */
+ zfs_unlinked_drain(zfsvfs);
+ }
+ return (SET_ERROR(EBUSY));
}
}