Author: pjd
Date: Sat Sep 26 00:10:45 2009
New Revision: 197515
URL: http://svn.freebsd.org/changeset/base/197515

Log:
  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

Modified:
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c    Sat Sep 
26 00:08:44 2009        (r197514)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c    Sat Sep 
26 00:10:45 2009        (r197515)
@@ -1007,15 +1007,24 @@ zfsctl_snapdir_inactive(ap)
 {
        vnode_t *vp = ap->a_vp;
        zfsctl_snapdir_t *sdp = vp->v_data;
-       void *private;
+       zfs_snapentry_t *sep;
 
-       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));
+       /*
+        * 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);
 
        /*

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c    Sat Sep 
26 00:08:44 2009        (r197514)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c    Sat Sep 
26 00:10:45 2009        (r197515)
@@ -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);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to