aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKirk McKusick <mckusick@FreeBSD.org>2011-09-27 17:41:48 +0000
committerKirk McKusick <mckusick@FreeBSD.org>2011-09-27 17:41:48 +0000
commit8cd680f8c37bf8f42e1adfd06a5e5ba3b27dd9dd (patch)
treed4c48cac410ff095c93340a9dfe0b1a8ca201d51
parent6b3b8a2109a7d4127ea71808aabb4b9f04c24175 (diff)
downloadsrc-8cd680f8c37bf8f42e1adfd06a5e5ba3b27dd9dd.tar.gz
src-8cd680f8c37bf8f42e1adfd06a5e5ba3b27dd9dd.zip
This update eliminates a lock-order reversal warning discovered
whle tracking down the system hang reported in kern/160662 and corrected in revision 225806. The LOR is not the cause of the system hang and indeed cannot cause an actual deadlock. However, it can be easily eliminated by defering the acquisition of a buflock until after all the vnode locks have been acquired. Reported by: Hans Ottevanger PR: kern/160662
Notes
Notes: svn path=/head/; revision=225807
-rw-r--r--sys/ufs/ffs/ffs_snapshot.c45
1 files changed, 24 insertions, 21 deletions
diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c
index 9aa0f791b5fc..c8d89698e8de 100644
--- a/sys/ufs/ffs/ffs_snapshot.c
+++ b/sys/ufs/ffs/ffs_snapshot.c
@@ -212,7 +212,7 @@ ffs_snapshot(mp, snapfile)
struct fs *copy_fs = NULL, *fs;
struct thread *td = curthread;
struct inode *ip, *xp;
- struct buf *bp, *nbp, *ibp, *sbp = NULL;
+ struct buf *bp, *nbp, *ibp;
struct nameidata nd;
struct mount *wrtmp;
struct vattr vat;
@@ -460,21 +460,14 @@ restart:
* Grab a copy of the superblock and its summary information.
* We delay writing it until the suspension is released below.
*/
- error = bread(vp, lblkno(fs, fs->fs_sblockloc), fs->fs_bsize,
- KERNCRED, &sbp);
- if (error) {
- brelse(sbp);
- sbp = NULL;
- goto out1;
- }
- loc = blkoff(fs, fs->fs_sblockloc);
- copy_fs = (struct fs *)(sbp->b_data + loc);
+ copy_fs = malloc((u_long)fs->fs_bsize, M_UFSMNT, M_WAITOK);
bcopy(fs, copy_fs, fs->fs_sbsize);
if ((fs->fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) == 0)
copy_fs->fs_clean = 1;
size = fs->fs_bsize < SBLOCKSIZE ? fs->fs_bsize : SBLOCKSIZE;
if (fs->fs_sbsize < size)
- bzero(&sbp->b_data[loc + fs->fs_sbsize], size - fs->fs_sbsize);
+ bzero(&((char *)copy_fs)[fs->fs_sbsize],
+ size - fs->fs_sbsize);
size = blkroundup(fs, fs->fs_cssize);
if (fs->fs_contigsumsize > 0)
size += fs->fs_ncg * sizeof(int32_t);
@@ -490,8 +483,8 @@ restart:
len, KERNCRED, &bp)) != 0) {
brelse(bp);
free(copy_fs->fs_csp, M_UFSMNT);
- bawrite(sbp);
- sbp = NULL;
+ free(copy_fs, M_UFSMNT);
+ copy_fs = NULL;
goto out1;
}
bcopy(bp->b_data, space, (u_int)len);
@@ -606,8 +599,8 @@ loop:
vdrop(xvp);
if (error) {
free(copy_fs->fs_csp, M_UFSMNT);
- bawrite(sbp);
- sbp = NULL;
+ free(copy_fs, M_UFSMNT);
+ copy_fs = NULL;
MNT_VNODE_FOREACH_ABORT(mp, mvp);
goto out1;
}
@@ -621,8 +614,8 @@ loop:
error = softdep_journal_lookup(mp, &xvp);
if (error) {
free(copy_fs->fs_csp, M_UFSMNT);
- bawrite(sbp);
- sbp = NULL;
+ free(copy_fs, M_UFSMNT);
+ copy_fs = NULL;
goto out1;
}
xp = VTOI(xvp);
@@ -688,8 +681,8 @@ loop:
VI_UNLOCK(devvp);
ASSERT_VOP_LOCKED(vp, "ffs_snapshot vp");
out1:
- KASSERT((sn != NULL && sbp != NULL && error == 0) ||
- (sn == NULL && sbp == NULL && error != 0),
+ KASSERT((sn != NULL && copy_fs != NULL && error == 0) ||
+ (sn == NULL && copy_fs == NULL && error != 0),
("email phk@ and mckusick@"));
/*
* Resume operation on filesystem.
@@ -703,7 +696,7 @@ out1:
vp->v_mount->mnt_stat.f_mntonname, (long)endtime.tv_sec,
endtime.tv_nsec / 1000000, redo, fs->fs_ncg);
}
- if (sbp == NULL)
+ if (copy_fs == NULL)
goto out;
/*
* Copy allocation information from all the snapshots in
@@ -793,6 +786,15 @@ out1:
space = (char *)space + fs->fs_bsize;
bawrite(nbp);
}
+ error = bread(vp, lblkno(fs, fs->fs_sblockloc), fs->fs_bsize,
+ KERNCRED, &nbp);
+ if (error) {
+ brelse(nbp);
+ } else {
+ loc = blkoff(fs, fs->fs_sblockloc);
+ bcopy((char *)copy_fs, &nbp->b_data[loc], fs->fs_bsize);
+ bawrite(nbp);
+ }
/*
* As this is the newest list, it is the most inclusive, so
* should replace the previous list.
@@ -822,7 +824,8 @@ out1:
vrele(vp); /* Drop extra reference */
done:
free(copy_fs->fs_csp, M_UFSMNT);
- bawrite(sbp);
+ free(copy_fs, M_UFSMNT);
+ copy_fs = NULL;
out:
NDFREE(&nd, NDF_ONLY_PNBUF);
if (saved_nice > 0) {