summaryrefslogtreecommitdiffstats
path: root/sys/ufs
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2010-11-11 11:54:01 +0000
committerkib <kib@FreeBSD.org>2010-11-11 11:54:01 +0000
commitdadf5cd065f60f3861c85cdb6b3ee94517f2c17e (patch)
treeab55c9eb27288320841718635a55e3cdfc9b006f /sys/ufs
parent59d1af232220700389c3543e93e1b1f2e2619919 (diff)
downloadFreeBSD-src-dadf5cd065f60f3861c85cdb6b3ee94517f2c17e.zip
FreeBSD-src-dadf5cd065f60f3861c85cdb6b3ee94517f2c17e.tar.gz
The softdep_setup_freeblocks() adds worklist items before
deallocate_dependencies() is done. This opens a race between softdep thread and the thread that does the truncation: A write of the indirect block causes the freeblks to become ALLCOMPLETE while softdep_setup_freeblocks() dropped softdep lock. And then, softdep_disk_write_complete() would reassign the workitem to the mount point worklist, causing premature processing of the workitem, or journal write exhaust the fb_jfreeblkhd and handle_written_jfreeblk does the same reassign. indir_trunc() then would find the indirect block that is locked (with lock owned by kernel) but without any dependencies, causing it to hang in getblk() waiting for buffer lock. Do not mark freeblks as DEPCOMPLETE until deallocate_dependencies() finished. Analyzed, suggested and reviewed by: jeff Tested by: pho
Diffstat (limited to 'sys/ufs')
-rw-r--r--sys/ufs/ffs/ffs_softdep.c7
1 files changed, 5 insertions, 2 deletions
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c
index c92ecd3..9e347cf 100644
--- a/sys/ufs/ffs/ffs_softdep.c
+++ b/sys/ufs/ffs/ffs_softdep.c
@@ -5270,7 +5270,7 @@ softdep_setup_freeblocks(ip, length, flags)
if (delay)
WORKLIST_INSERT(&bp->b_dep, &freeblks->fb_list);
else if (needj)
- freeblks->fb_state |= DEPCOMPLETE | COMPLETE;
+ freeblks->fb_state |= COMPLETE;
/*
* Because the file length has been truncated to zero, any
* pending block allocation dependency structures associated
@@ -5332,8 +5332,9 @@ restart:
if (inodedep_lookup(mp, ip->i_number, 0, &inodedep) != 0)
(void) free_inodedep(inodedep);
- if (delay) {
+ if (delay || needj)
freeblks->fb_state |= DEPCOMPLETE;
+ if (delay) {
/*
* If the inode with zeroed block pointers is now on disk
* we can start freeing blocks. Add freeblks to the worklist
@@ -5344,6 +5345,8 @@ restart:
if ((freeblks->fb_state & ALLCOMPLETE) == ALLCOMPLETE)
add_to_worklist(&freeblks->fb_list, 1);
}
+ if (needj && LIST_EMPTY(&freeblks->fb_jfreeblkhd))
+ needj = 0;
FREE_LOCK(&lk);
/*
OpenPOWER on IntegriCloud