Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/ufs/ffs Change the snapshot lock:
details: https://anonhg.NetBSD.org/src/rev/e5d5e19cff36
branches: trunk
changeset: 762455:e5d5e19cff36
user: hannken <hannken%NetBSD.org@localhost>
date: Mon Feb 21 09:29:21 2011 +0000
description:
Change the snapshot lock:
- No need to take the snapshot lock while the file system is suspended.
- Allow ffs_copyonwrite() one level of recursion with snapshots locked.
- Do the block address lookup with snapshots locked.
- Take the snapshot lock while removing a snapshot from the list.
While hunting deadlocks change the transaction scope for ffs_snapremove().
We could deadlock from UFS_WAPBL_BEGIN() with a buffer held.
diffstat:
sys/ufs/ffs/ffs_snapshot.c | 105 +++++++++++++++++---------------------------
1 files changed, 41 insertions(+), 64 deletions(-)
diffs (267 lines):
diff -r c23d667b66ba -r e5d5e19cff36 sys/ufs/ffs/ffs_snapshot.c
--- a/sys/ufs/ffs/ffs_snapshot.c Mon Feb 21 08:50:45 2011 +0000
+++ b/sys/ufs/ffs/ffs_snapshot.c Mon Feb 21 09:29:21 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: ffs_snapshot.c,v 1.105 2011/02/18 14:48:54 bouyer Exp $ */
+/* $NetBSD: ffs_snapshot.c,v 1.106 2011/02/21 09:29:21 hannken Exp $ */
/*
* Copyright 2000 Marshall Kirk McKusick. All Rights Reserved.
@@ -38,7 +38,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ffs_snapshot.c,v 1.105 2011/02/18 14:48:54 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ffs_snapshot.c,v 1.106 2011/02/21 09:29:21 hannken Exp $");
#if defined(_KERNEL_OPT)
#include "opt_ffs.h"
@@ -79,6 +79,7 @@
struct snap_info {
kmutex_t si_lock; /* Lock this snapinfo */
kmutex_t si_snaplock; /* Snapshot vnode common lock */
+ lwp_t *si_owner; /* Sanplock owner */
TAILQ_HEAD(inodelst, inode) si_snapshots; /* List of active snapshots */
daddr_t *si_snapblklist; /* Snapshot block hints list */
uint32_t si_gen; /* Incremented on change */
@@ -140,6 +141,7 @@
TAILQ_INIT(&si->si_snapshots);
mutex_init(&si->si_lock, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&si->si_snaplock, MUTEX_DEFAULT, IPL_NONE);
+ si->si_owner = NULL;
si->si_gen = 0;
si->si_snapblklist = NULL;
@@ -173,7 +175,6 @@
}
#else /* defined(FFS_NO_SNAPSHOT) */
bool suspended = false;
- bool snapshot_locked = false;
int error, redo = 0, snaploc;
void *sbbuf = NULL;
daddr_t *snaplist = NULL, snaplistsize = 0;
@@ -269,11 +270,6 @@
if (error)
goto out;
/*
- * Acquire the snapshot lock.
- */
- mutex_enter(&si->si_snaplock);
- snapshot_locked = true;
- /*
* Record snapshot inode. Since this is the newest snapshot,
* it must be placed at the end of the list.
*/
@@ -376,8 +372,6 @@
si->si_gen++;
mutex_exit(&si->si_lock);
- if (snapshot_locked)
- mutex_exit(&si->si_snaplock);
if (suspended) {
vfs_resume(vp->v_mount);
#ifdef DEBUG
@@ -1354,8 +1348,7 @@
struct snap_info *si;
struct lwp *l = curlwp;
daddr_t numblks, blkno, dblk;
- int error, loc, last, n;
- const int wbreak = blocks_in_journal(fs)/8;
+ int error, loc, last;
si = VFSTOUFS(mp)->um_snapinfo;
/*
@@ -1365,6 +1358,7 @@
*
* Clear copy-on-write flag if last snapshot.
*/
+ mutex_enter(&si->si_snaplock);
mutex_enter(&si->si_lock);
if (is_active_snapshot(si, ip)) {
TAILQ_REMOVE(&si->si_snapshots, ip, i_nextsnap);
@@ -1374,18 +1368,22 @@
si->si_snapblklist = xp->i_snapblklist;
si->si_gen++;
mutex_exit(&si->si_lock);
+ mutex_exit(&si->si_snaplock);
} else {
si->si_snapblklist = 0;
si->si_gen++;
mutex_exit(&si->si_lock);
+ mutex_exit(&si->si_snaplock);
fscow_disestablish(mp, ffs_copyonwrite, devvp);
}
if (ip->i_snapblklist != NULL) {
free(ip->i_snapblklist, M_UFSMNT);
ip->i_snapblklist = NULL;
}
- } else
+ } else {
mutex_exit(&si->si_lock);
+ mutex_exit(&si->si_snaplock);
+ }
/*
* Clear all BLK_NOCOPY fields. Pass any block claims to other
* snapshots that want them (see ffs_snapblkfree below).
@@ -1402,7 +1400,7 @@
}
}
numblks = howmany(ip->i_size, fs->fs_bsize);
- for (blkno = NDADDR, n = 0; blkno < numblks; blkno += NINDIR(fs)) {
+ for (blkno = NDADDR; blkno < numblks; blkno += NINDIR(fs)) {
error = ffs_balloc(vp, lblktosize(fs, (off_t)blkno),
fs->fs_bsize, l->l_cred, B_METAONLY, &ibp);
if (error)
@@ -1412,12 +1410,6 @@
else
last = fs->fs_size - blkno;
for (loc = 0; loc < last; loc++) {
- if (wbreak > 0 && (++n % wbreak) == 0) {
- UFS_WAPBL_END(mp);
- error = UFS_WAPBL_BEGIN(mp);
- if (error)
- panic("UFS_WAPBL_BEGIN failed");
- }
dblk = idb_get(ip, ibp->b_data, loc);
if (dblk == BLK_NOCOPY || dblk == BLK_SNAP)
idb_assign(ip, ibp->b_data, loc, 0);
@@ -1429,6 +1421,9 @@
}
}
bawrite(ibp);
+ UFS_WAPBL_END(mp);
+ error = UFS_WAPBL_BEGIN(mp);
+ KASSERT(error == 0);
}
/*
* Clear snapshot flag and drop reference.
@@ -1469,25 +1464,18 @@
daddr_t lbn;
daddr_t blkno;
uint32_t gen;
- int indiroff = 0, snapshot_locked = 0, error = 0, claimedblk = 0;
+ int indiroff = 0, error = 0, claimedblk = 0;
si = VFSTOUFS(mp)->um_snapinfo;
lbn = fragstoblks(fs, bno);
+ mutex_enter(&si->si_snaplock);
mutex_enter(&si->si_lock);
+ si->si_owner = curlwp;
+
retry:
gen = si->si_gen;
TAILQ_FOREACH(ip, &si->si_snapshots, i_nextsnap) {
vp = ITOV(ip);
- if (snapshot_locked == 0) {
- if (!mutex_tryenter(&si->si_snaplock)) {
- mutex_exit(&si->si_lock);
- mutex_enter(&si->si_snaplock);
- mutex_enter(&si->si_lock);
- }
- snapshot_locked = 1;
- if (gen != si->si_gen)
- goto retry;
- }
/*
* Lookup block being written.
*/
@@ -1584,6 +1572,9 @@
error = syncsnap(vp);
else
error = 0;
+ mutex_enter(&si->si_lock);
+ si->si_owner = NULL;
+ mutex_exit(&si->si_lock);
mutex_exit(&si->si_snaplock);
return (error == 0);
}
@@ -1623,7 +1614,9 @@
if (gen != si->si_gen)
goto retry;
}
+ si->si_owner = NULL;
mutex_exit(&si->si_lock);
+ mutex_exit(&si->si_snaplock);
if (saved_data)
free(saved_data, M_UFSMNT);
/*
@@ -1632,8 +1625,6 @@
* not be freed. Although space will be lost, the snapshot
* will stay consistent.
*/
- if (snapshot_locked)
- mutex_exit(&si->si_snaplock);
return (error);
}
@@ -1846,6 +1837,15 @@
/*
* Not in the precomputed list, so check the snapshots.
*/
+ if (si->si_owner != curlwp) {
+ if (!mutex_tryenter(&si->si_snaplock)) {
+ mutex_exit(&si->si_lock);
+ mutex_enter(&si->si_snaplock);
+ mutex_enter(&si->si_lock);
+ }
+ si->si_owner = curlwp;
+ snapshot_locked = 1;
+ }
if (data_valid && bp->b_bcount == fs->fs_bsize)
saved_data = bp->b_data;
retry:
@@ -1886,34 +1886,8 @@
error = ENOMEM;
break;
}
-
- if (snapshot_locked == 0) {
- if (!mutex_tryenter(&si->si_snaplock)) {
- mutex_exit(&si->si_lock);
- mutex_enter(&si->si_snaplock);
- mutex_enter(&si->si_lock);
- }
- snapshot_locked = 1;
- if (gen != si->si_gen)
- goto retry;
-
- /* Check again if block still needs to be copied */
- if (lbn < NDADDR) {
- blkno = db_get(ip, lbn);
- } else {
- mutex_exit(&si->si_lock);
- if ((error = snapblkaddr(vp, lbn, &blkno)) != 0) {
- mutex_enter(&si->si_lock);
- break;
- }
- mutex_enter(&si->si_lock);
- if (gen != si->si_gen)
- goto retry;
- }
-
- if (blkno != 0)
- continue;
- }
+ /* Only one level of recursion allowed. */
+ KASSERT(snapshot_locked);
/*
* Allocate the block into which to do the copy. Since
* multiple processes may all try to copy the same block,
@@ -1968,11 +1942,14 @@
* have not been unlinked, and hence will be visible after
* a crash, to ensure their integrity.
*/
- mutex_exit(&si->si_lock);
+ if (snapshot_locked) {
+ si->si_owner = NULL;
+ mutex_exit(&si->si_lock);
+ mutex_exit(&si->si_snaplock);
+ } else
+ mutex_exit(&si->si_lock);
if (saved_data && saved_data != bp->b_data)
free(saved_data, M_UFSMNT);
- if (snapshot_locked)
- mutex_exit(&si->si_snaplock);
return error;
}
Home |
Main Index |
Thread Index |
Old Index