diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index 8ed68c3..950167f 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -6143,20 +6143,19 @@ indir_trunc(freework, dbn, lbn) */ cnt = 0; LIST_FOREACH_SAFE(wk, &wkhd, wk_list, wkn) { - struct workhead freewk; if (wk->wk_type != D_JNEWBLK) continue; - WORKLIST_REMOVE_UNLOCKED(wk); - LIST_INIT(&freewk); - WORKLIST_INSERT_UNLOCKED(&freewk, wk); + ACQUIRE_LOCK(&lk); + WORKLIST_REMOVE(wk); + FREE_LOCK(&lk); jnewblk = WK_JNEWBLK(wk); if (jnewblk->jn_lbn > 0) i = (jnewblk->jn_lbn - -lbn) / lbnadd; else - i = (jnewblk->jn_lbn - (lbn + 1)) / lbnadd; + i = (jnewblk->jn_lbn - (lbn + level)) / lbnadd; KASSERT(i >= 0 && i < NINDIR(fs), - ("indir_trunc: Index out of range %d parent %jd lbn %jd", - i, lbn, jnewblk->jn_lbn)); + ("indir_trunc: Index out of range %d parent %jd lbn %jd level %d", + i, lbn, jnewblk->jn_lbn, level)); /* Clear the pointer so it isn't found below. */ if (ufs1fmt) { nb = bap1[i]; @@ -6168,8 +6167,26 @@ indir_trunc(freework, dbn, lbn) KASSERT(nb == jnewblk->jn_blkno, ("indir_trunc: Block mismatch %jd != %jd", nb, jnewblk->jn_blkno)); - ffs_blkfree(ump, fs, freeblks->fb_devvp, jnewblk->jn_blkno, - fs->fs_bsize, freeblks->fb_previousinum, &freewk); + if (level != 0) { + ufs_lbn_t nlbn; + + nlbn = (lbn + 1) - (i * lbnadd); + nfreework = newfreework(freeblks, freework, + nlbn, nb, fs->fs_frag, 0); + WORKLIST_INSERT_UNLOCKED(&nfreework->fw_jwork, wk); + freedeps++; + indir_trunc(nfreework, fsbtodb(fs, nb), nlbn); + } else { + struct workhead freewk; + + LIST_INIT(&freewk); + ACQUIRE_LOCK(&lk); + WORKLIST_INSERT(&freewk, wk); + FREE_LOCK(&lk); + ffs_blkfree(ump, fs, freeblks->fb_devvp, + jnewblk->jn_blkno, fs->fs_bsize, + freeblks->fb_previousinum, &freewk); + } cnt++; } ACQUIRE_LOCK(&lk); @@ -6779,7 +6796,8 @@ cancel_diradd(dap, dirrem, jremref, dotremref, dotdotremref) mkdir->md_jaddref = NULL; if (mkdir->md_state & MKDIR_PARENT) { if (cancel_jaddref(jaddref, NULL, - &dirrem->dm_jwork) == 0) { + &dirrem->dm_jwork) == 0 && + dotdotremref != NULL) { free_jremref(dotdotremref); dotdotremref = NULL; }