summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorpjd <pjd@FreeBSD.org>2009-09-26 00:10:45 +0000
committerpjd <pjd@FreeBSD.org>2009-09-26 00:10:45 +0000
commitf4593287a1446823bffff8af7c9b347b58747b25 (patch)
tree6e7492fb03f6728ed0af3c2a37d59806424c6b30 /sys
parent6da7f61b4860d1e85f0f9564f88ae8e7b6dbc1b9 (diff)
downloadFreeBSD-src-f4593287a1446823bffff8af7c9b347b58747b25.zip
FreeBSD-src-f4593287a1446823bffff8af7c9b347b58747b25.tar.gz
Handle cases where virtual (GFS) vnodes are referenced when doing forced
unmount. In that case we cannot depend on the proper order of invalidating vnodes, so we have to free resources when we have a chance. PR: kern/139062 Reported by: trasz MFC after: 3 days
Diffstat (limited to 'sys')
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c34
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c3
2 files changed, 22 insertions, 15 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
index 65b3262..7820293 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
@@ -1007,15 +1007,24 @@ zfsctl_snapdir_inactive(ap)
{
vnode_t *vp = ap->a_vp;
zfsctl_snapdir_t *sdp = vp->v_data;
- void *private;
-
- private = gfs_dir_inactive(vp);
- if (private != NULL) {
- ASSERT(avl_numnodes(&sdp->sd_snaps) == 0);
- mutex_destroy(&sdp->sd_lock);
- avl_destroy(&sdp->sd_snaps);
- kmem_free(private, sizeof (zfsctl_snapdir_t));
+ zfs_snapentry_t *sep;
+
+ /*
+ * On forced unmount we have to free snapshots from here.
+ */
+ mutex_enter(&sdp->sd_lock);
+ while ((sep = avl_first(&sdp->sd_snaps)) != NULL) {
+ avl_remove(&sdp->sd_snaps, sep);
+ kmem_free(sep->se_name, strlen(sep->se_name) + 1);
+ kmem_free(sep, sizeof (zfs_snapentry_t));
}
+ mutex_exit(&sdp->sd_lock);
+ gfs_dir_inactive(vp);
+ ASSERT(avl_numnodes(&sdp->sd_snaps) == 0);
+ mutex_destroy(&sdp->sd_lock);
+ avl_destroy(&sdp->sd_snaps);
+ kmem_free(sdp, sizeof (zfsctl_snapdir_t));
+
return (0);
}
@@ -1073,6 +1082,9 @@ zfsctl_snapshot_inactive(ap)
int locked;
vnode_t *dvp;
+ if (vp->v_count > 0)
+ goto end;
+
VERIFY(gfs_dir_lookup(vp, "..", &dvp, cr, 0, NULL, NULL) == 0);
sdp = dvp->v_data;
VOP_UNLOCK(dvp, 0);
@@ -1080,11 +1092,6 @@ zfsctl_snapshot_inactive(ap)
if (!(locked = MUTEX_HELD(&sdp->sd_lock)))
mutex_enter(&sdp->sd_lock);
- if (vp->v_count > 1) {
- if (!locked)
- mutex_exit(&sdp->sd_lock);
- return (0);
- }
ASSERT(!vn_ismntpt(vp));
sep = avl_first(&sdp->sd_snaps);
@@ -1104,6 +1111,7 @@ zfsctl_snapshot_inactive(ap)
if (!locked)
mutex_exit(&sdp->sd_lock);
VN_RELE(dvp);
+end:
VFS_RELE(vp->v_vfsp);
/*
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
index b9a4b2f..08996ee 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
@@ -1107,8 +1107,7 @@ zfs_umount(vfs_t *vfsp, int fflag)
if (zfsvfs->z_issnap) {
vnode_t *svp = vfsp->mnt_vnodecovered;
- ASSERT(svp->v_count == 2 || svp->v_count == 1);
- if (svp->v_count == 2)
+ if (svp->v_count >= 2)
VN_RELE(svp);
}
zfs_freevfs(vfsp);
OpenPOWER on IntegriCloud