Author: mm
Date: Mon Oct 11 09:34:46 2010
New Revision: 213683
URL: http://svn.freebsd.org/changeset/base/213683

Log:
  MFC r210470:
  
  Import two changesets from OpenSolaris to make future updates easier.
  
  The changes do not affect FreeBSD code because
  zfs_znode_move(), cleanlocks() and cleanshares() are not used.
  
  OpenSolaris onnv changeset:   9788:f660bc44f2e8, 9909:aa280f585a3e
  
  Approved by:  pjd, delphij (mentor)
  Obtained from:        OpenSolaris (Bug ID 6843700, 6790232)

Modified:
  stable/8/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
  stable/8/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
  stable/8/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/xen/xenpci/   (props changed)

Modified: stable/8/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
==============================================================================
--- stable/8/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c        
Mon Oct 11 09:27:37 2010        (r213682)
+++ stable/8/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c        
Mon Oct 11 09:34:46 2010        (r213683)
@@ -955,11 +955,22 @@ zfsvfs_setup(zfsvfs_t *zfsvfs, boolean_t
        return (0);
 }
 
+extern krwlock_t zfsvfs_lock; /* in zfs_znode.c */
+
 void
 zfsvfs_free(zfsvfs_t *zfsvfs)
 {
        int i;
 
+       /*
+        * This is a barrier to prevent the filesystem from going away in
+        * zfs_znode_move() until we can safely ensure that the filesystem is
+        * not unmounted. We consider the filesystem valid before the barrier
+        * and invalid after the barrier.
+        */
+       rw_enter(&zfsvfs_lock, RW_READER);
+       rw_exit(&zfsvfs_lock);
+
        zfs_fuid_destroy(zfsvfs);
 
        mutex_destroy(&zfsvfs->z_znodes_lock);

Modified: stable/8/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
==============================================================================
--- stable/8/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c Mon Oct 
11 09:27:37 2010        (r213682)
+++ stable/8/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c Mon Oct 
11 09:34:46 2010        (r213683)
@@ -200,6 +200,12 @@ zfs_close(vnode_t *vp, int flag, int cou
        znode_t *zp = VTOZ(vp);
        zfsvfs_t *zfsvfs = zp->z_zfsvfs;
 
+       /*
+        * Clean up any locks held by this process on the vp.
+        */
+       cleanlocks(vp, ddi_get_pid(), 0);
+       cleanshares(vp, ddi_get_pid());
+
        ZFS_ENTER(zfsvfs);
        ZFS_VERIFY_ZP(zp);
 
@@ -207,12 +213,6 @@ zfs_close(vnode_t *vp, int flag, int cou
        if ((flag & (FSYNC | FDSYNC)) && (count == 1))
                atomic_dec_32(&zp->z_sync_cnt);
 
-       /*
-        * Clean up any locks held by this process on the vp.
-        */
-       cleanlocks(vp, ddi_get_pid(), 0);
-       cleanshares(vp, ddi_get_pid());
-
        if (!zfs_has_ctldir(zp) && zp->z_zfsvfs->z_vscan &&
            ZTOV(zp)->v_type == VREG &&
            !(zp->z_phys->zp_flags & ZFS_AV_QUARANTINED) &&

Modified: stable/8/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
==============================================================================
--- stable/8/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c Mon Oct 
11 09:27:37 2010        (r213682)
+++ stable/8/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c Mon Oct 
11 09:34:46 2010        (r213683)
@@ -87,6 +87,12 @@ SYSCTL_INT(_debug_sizeof, OID_AUTO, znod
  * (such as VFS logic) that will not compile easily in userland.
  */
 #ifdef _KERNEL
+/*
+ * Needed to close a small window in zfs_znode_move() that allows the zfsvfs to
+ * be freed before it can be safely accessed.
+ */
+krwlock_t zfsvfs_lock;
+
 static kmem_cache_t *znode_cache = NULL;
 
 /*ARGSUSED*/
@@ -200,8 +206,9 @@ zfs_znode_cache_destructor(void *buf, vo
 #ifdef ZNODE_STATS
 static struct {
        uint64_t zms_zfsvfs_invalid;
+       uint64_t zms_zfsvfs_recheck1;
        uint64_t zms_zfsvfs_unmounted;
-       uint64_t zms_zfsvfs_recheck_invalid;
+       uint64_t zms_zfsvfs_recheck2;
        uint64_t zms_obj_held;
        uint64_t zms_vnode_locked;
        uint64_t zms_not_only_dnlc;
@@ -285,15 +292,32 @@ zfs_znode_move(void *buf, void *newbuf, 
        }
 
        /*
-        * Ensure that the filesystem is not unmounted during the move.
-        * This is the equivalent to ZFS_ENTER().
+        * Close a small window in which it's possible that the filesystem could
+        * be unmounted and freed, and zfsvfs, though valid in the previous
+        * statement, could point to unrelated memory by the time we try to
+        * prevent the filesystem from being unmounted.
+        */
+       rw_enter(&zfsvfs_lock, RW_WRITER);
+       if (zfsvfs != ozp->z_zfsvfs) {
+               rw_exit(&zfsvfs_lock);
+               ZNODE_STAT_ADD(znode_move_stats.zms_zfsvfs_recheck1);
+               return (KMEM_CBRC_DONT_KNOW);
+       }
+
+       /*
+        * If the znode is still valid, then so is the file system. We know that
+        * no valid file system can be freed while we hold zfsvfs_lock, so we
+        * can safely ensure that the filesystem is not and will not be
+        * unmounted. The next statement is equivalent to ZFS_ENTER().
         */
        rrw_enter(&zfsvfs->z_teardown_lock, RW_READER, FTAG);
        if (zfsvfs->z_unmounted) {
                ZFS_EXIT(zfsvfs);
+               rw_exit(&zfsvfs_lock);
                ZNODE_STAT_ADD(znode_move_stats.zms_zfsvfs_unmounted);
                return (KMEM_CBRC_DONT_KNOW);
        }
+       rw_exit(&zfsvfs_lock);
 
        mutex_enter(&zfsvfs->z_znodes_lock);
        /*
@@ -303,7 +327,7 @@ zfs_znode_move(void *buf, void *newbuf, 
        if (zfsvfs != ozp->z_zfsvfs) {
                mutex_exit(&zfsvfs->z_znodes_lock);
                ZFS_EXIT(zfsvfs);
-               ZNODE_STAT_ADD(znode_move_stats.zms_zfsvfs_recheck_invalid);
+               ZNODE_STAT_ADD(znode_move_stats.zms_zfsvfs_recheck2);
                return (KMEM_CBRC_DONT_KNOW);
        }
 
@@ -360,6 +384,7 @@ zfs_znode_init(void)
        /*
         * Initialize zcache
         */
+       rw_init(&zfsvfs_lock, NULL, RW_DEFAULT, NULL);
        ASSERT(znode_cache == NULL);
        znode_cache = kmem_cache_create("zfs_znode_cache",
            sizeof (znode_t), 0, /* zfs_znode_cache_constructor */ NULL,
@@ -378,6 +403,7 @@ zfs_znode_fini(void)
        if (znode_cache)
                kmem_cache_destroy(znode_cache);
        znode_cache = NULL;
+       rw_destroy(&zfsvfs_lock);
 }
 
 int
_______________________________________________
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