Author: kib
Date: Fri Aug  4 08:27:34 2017
New Revision: 322048
URL: https://svnweb.freebsd.org/changeset/base/322048

Log:
  MFC r321349:
  Improve publication of the newly allocated snapdata.

Modified:
  stable/10/sys/ufs/ffs/ffs_snapshot.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/ufs/ffs/ffs_snapshot.c
==============================================================================
--- stable/10/sys/ufs/ffs/ffs_snapshot.c        Fri Aug  4 08:26:19 2017        
(r322047)
+++ stable/10/sys/ufs/ffs/ffs_snapshot.c        Fri Aug  4 08:27:34 2017        
(r322048)
@@ -2643,8 +2643,8 @@ try_free_snapdata(struct vnode *devvp)
 static struct snapdata *
 ffs_snapdata_acquire(struct vnode *devvp)
 {
-       struct snapdata *nsn;
-       struct snapdata *sn;
+       struct snapdata *nsn, *sn;
+       int error;
 
        /*
         * Allocate a free snapdata.  This is done before acquiring the
@@ -2652,23 +2652,37 @@ ffs_snapdata_acquire(struct vnode *devvp)
         * held.
         */
        nsn = ffs_snapdata_alloc();
-       /*
-        * If there snapshots already exist on this filesystem grab a
-        * reference to the shared lock.  Otherwise this is the first
-        * snapshot on this filesystem and we need to use our
-        * pre-allocated snapdata.
-        */
-       VI_LOCK(devvp);
-       if (devvp->v_rdev->si_snapdata == NULL) {
-               devvp->v_rdev->si_snapdata = nsn;
-               nsn = NULL;
+
+       for (;;) {
+               VI_LOCK(devvp);
+               sn = devvp->v_rdev->si_snapdata;
+               if (sn == NULL) {
+                       /*
+                        * This is the first snapshot on this
+                        * filesystem and we use our pre-allocated
+                        * snapdata.  Publish sn with the sn_lock
+                        * owned by us, to avoid the race.
+                        */
+                       error = lockmgr(&nsn->sn_lock, LK_EXCLUSIVE |
+                           LK_NOWAIT, NULL);
+                       if (error != 0)
+                               panic("leaked sn, lockmgr error %d", error);
+                       sn = devvp->v_rdev->si_snapdata = nsn;
+                       VI_UNLOCK(devvp);
+                       nsn = NULL;
+                       break;
+               }
+
+               /*
+                * There is a snapshots which already exists on this
+                * filesystem, grab a reference to the common lock.
+                */
+               error = lockmgr(&sn->sn_lock, LK_INTERLOCK |
+                   LK_EXCLUSIVE | LK_SLEEPFAIL, VI_MTX(devvp));
+               if (error == 0)
+                       break;
        }
-       sn = devvp->v_rdev->si_snapdata;
-       /*
-        * Acquire the snapshot lock.
-        */
-       lockmgr(&sn->sn_lock,
-           LK_INTERLOCK | LK_EXCLUSIVE | LK_RETRY, VI_MTX(devvp));
+
        /*
         * Free any unused snapdata.
         */
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to