diff options
author | Konstantin Belousov <kib@FreeBSD.org> | 2007-04-10 09:30:41 +0000 |
---|---|---|
committer | Konstantin Belousov <kib@FreeBSD.org> | 2007-04-10 09:30:41 +0000 |
commit | 9724167c2a85684a2d03b8a951bafc6d43c07a3e (patch) | |
tree | 0a3706d9c22c63cbf546166c51e74a259be6eb24 /sys/ufs | |
parent | 23743f6a118b6809c9b87ef29e0282b5fd5d0da9 (diff) | |
download | src-9724167c2a85684a2d03b8a951bafc6d43c07a3e.tar.gz src-9724167c2a85684a2d03b8a951bafc6d43c07a3e.zip |
Recalculate the NEWBLOCK flag for pagedep structure after the softdep
lock is dropped, since pagedep may be already processed and deallocated.
Found and tested by: kris
MFC after: 2 weeks
Notes
Notes:
svn path=/head/; revision=168575
Diffstat (limited to 'sys/ufs')
-rw-r--r-- | sys/ufs/ffs/ffs_softdep.c | 31 |
1 files changed, 26 insertions, 5 deletions
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index 49c522c5f747..ae422dbfe16b 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -5008,7 +5008,7 @@ softdep_fsync(vp) struct buf *bp; struct fs *fs; struct thread *td = curthread; - int error, flushparent; + int error, flushparent, pagedep_new_block; ino_t parentino; ufs_lbn_t lbn; @@ -5086,15 +5086,36 @@ softdep_fsync(vp) * then we do the slower ffs_syncvnode of the directory. */ if (flushparent) { + int locked; + if ((error = ffs_update(pvp, 1)) != 0) { vput(pvp); return (error); } - if ((pagedep->pd_state & NEWBLOCK) && - (error = ffs_syncvnode(pvp, MNT_WAIT))) { - vput(pvp); - return (error); + ACQUIRE_LOCK(&lk); + locked = 1; + if (inodedep_lookup(mp, ip->i_number, 0, &inodedep) != 0) { + if ((wk = LIST_FIRST(&inodedep->id_pendinghd)) != NULL) { + if (wk->wk_type != D_DIRADD) + panic("softdep_fsync: Unexpected type %s", + TYPENAME(wk->wk_type)); + dap = WK_DIRADD(wk); + if (dap->da_state & DIRCHG) + pagedep = dap->da_previous->dm_pagedep; + else + pagedep = dap->da_pagedep; + pagedep_new_block = pagedep->pd_state & NEWBLOCK; + FREE_LOCK(&lk); + locked = 0; + if (pagedep_new_block && + (error = ffs_syncvnode(pvp, MNT_WAIT))) { + vput(pvp); + return (error); + } + } } + if (locked) + FREE_LOCK(&lk); } /* * Flush directory page containing the inode's name. |