summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2017-08-04 08:20:26 +0000
committerkib <kib@FreeBSD.org>2017-08-04 08:20:26 +0000
commitebc558387908c1af01e13d650b4ab68f24f42866 (patch)
treeb619f0e924fa83d48548d5bee7e2979e307290a4
parent73bfe4ff1362714f87b0aedf13a59fd6302b419c (diff)
downloadFreeBSD-src-ebc558387908c1af01e13d650b4ab68f24f42866.zip
FreeBSD-src-ebc558387908c1af01e13d650b4ab68f24f42866.tar.gz
MFC r321349:
Improve publication of the newly allocated snapdata.
-rw-r--r--sys/ufs/ffs/ffs_snapshot.c50
1 files changed, 32 insertions, 18 deletions
diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c
index 3c56a25..5e2db3d 100644
--- a/sys/ufs/ffs/ffs_snapshot.c
+++ b/sys/ufs/ffs/ffs_snapshot.c
@@ -2647,8 +2647,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
@@ -2656,23 +2656,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.
*/
OpenPOWER on IntegriCloud