diff options
author | kib <kib@FreeBSD.org> | 2017-08-04 08:20:26 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2017-08-04 08:20:26 +0000 |
commit | ebc558387908c1af01e13d650b4ab68f24f42866 (patch) | |
tree | b619f0e924fa83d48548d5bee7e2979e307290a4 | |
parent | 73bfe4ff1362714f87b0aedf13a59fd6302b419c (diff) | |
download | FreeBSD-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.c | 50 |
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. */ |