svn commit: r321349 - head/sys/ufs/ffs
Konstantin Belousov
kib at FreeBSD.org
Fri Jul 21 18:42:36 UTC 2017
Author: kib
Date: Fri Jul 21 18:42:35 2017
New Revision: 321349
URL: https://svnweb.freebsd.org/changeset/base/321349
Log:
Improve publication of the newly allocated snapdata.
For freshly allocated snapdata, Lock sn_lock in advance, so
si_snapdata readers see the locked snapdata and not race.
For existing snapdata, if the thread was put to sleep waiting for
sn_lock, re-read si_snapdata. This either closes the race or makes
the reliance on LK_DRAIN less important.
Reported and tested by: pho
Sponsored by: The FreeBSD Foundation
MFC after: 2 weeks
Modified:
head/sys/ufs/ffs/ffs_snapshot.c
Modified: head/sys/ufs/ffs/ffs_snapshot.c
==============================================================================
--- head/sys/ufs/ffs/ffs_snapshot.c Fri Jul 21 18:36:17 2017 (r321348)
+++ head/sys/ufs/ffs/ffs_snapshot.c Fri Jul 21 18:42:35 2017 (r321349)
@@ -2638,8 +2638,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
@@ -2647,23 +2647,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.
*/
More information about the svn-src-all
mailing list