diff --git a/sys/ufs/ffs/ffs_inode.c b/sys/ufs/ffs/ffs_inode.c index ffbe16e..ba2813d 100644 --- a/sys/ufs/ffs/ffs_inode.c +++ b/sys/ufs/ffs/ffs_inode.c @@ -582,9 +582,7 @@ ffs_indirtrunc(ip, lbn, dbn, lastbn, level, countp) * block to be kept. -1 indicates the entire * block so we need not calculate the index. */ - factor = 1; - for (i = SINGLE; i < level; i++) - factor *= NINDIR(fs); + factor = lbn_offset(fs, level); last = lastbn; if (lastbn > 0) last /= factor; diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index ca4ea0b..5bd3346 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -2270,7 +2270,6 @@ journal_mount(mp, fs, cred) int error; int i; - mp->mnt_kern_flag |= MNTK_SUJ; error = softdep_journal_lookup(mp, &vp); if (error != 0) { printf("Failed to find journal. Use tunefs to create one\n"); @@ -2295,20 +2294,26 @@ journal_mount(mp, fs, cred) } jblocks->jb_low = jblocks->jb_free / 3; /* Reserve 33%. */ jblocks->jb_min = jblocks->jb_free / 10; /* Suspend at 10%. */ - /* - * Only validate the journal contents if the filesystem is clean, - * otherwise we write the logs but they'll never be used. If the - * filesystem was still dirty when we mounted it the journal is - * invalid and a new journal can only be valid if it starts from a - * clean mount. - */ - if (fs->fs_clean) { - DIP_SET(ip, i_modrev, fs->fs_mtime); - ip->i_flags |= IN_MODIFIED; - ffs_update(vp, 1); - } VFSTOUFS(mp)->softdep_jblocks = jblocks; out: + if (error == 0) { + MNT_ILOCK(mp); + mp->mnt_kern_flag |= MNTK_SUJ; + MNT_IUNLOCK(mp); + /* + * Only validate the journal contents if the + * filesystem is clean, otherwise we write the logs + * but they'll never be used. If the filesystem was + * still dirty when we mounted it the journal is + * invalid and a new journal can only be valid if it + * starts from a clean mount. + */ + if (fs->fs_clean) { + DIP_SET(ip, i_modrev, fs->fs_mtime); + ip->i_flags |= IN_MODIFIED; + ffs_update(vp, 1); + } + } vput(vp); return (error); } @@ -5265,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 @@ -5327,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 @@ -5339,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); /* @@ -5488,7 +5496,7 @@ cancel_allocdirect(adphead, adp, freeblks, delay) newblk = (struct newblk *)adp; /* * If the journal hasn't been written the jnewblk must be passed - * to the call to ffs_freeblk that reclaims the space. We accomplish + * to the call to ffs_blkfree that reclaims the space. We accomplish * this by linking the journal dependency into the freework to be * freed when freework_freeblock() is called. If the journal has * been written we can simply reclaim the journal space when the @@ -6016,11 +6024,11 @@ handle_complete_freeblocks(freeblks) vput(vp); } -#ifdef INVARIANTS - if (freeblks->fb_chkcnt != 0 && - ((fs->fs_flags & FS_UNCLEAN) == 0 || (flags & LK_NOWAIT) != 0)) - printf("handle_workitem_freeblocks: block count\n"); -#endif /* INVARIANTS */ + KASSERT(freeblks->fb_chkcnt == 0 || + ((fs->fs_flags & FS_UNCLEAN) != 0 && (flags & LK_NOWAIT) == 0), + ("handle_workitem_freeblocks: inode %ju block count %jd\n", + (uintmax_t)freeblks->fb_previousinum, + (intmax_t)freeblks->fb_chkcnt)); ACQUIRE_LOCK(&lk); /* @@ -6075,9 +6083,7 @@ indir_trunc(freework, dbn, lbn) fs_pendingblocks = 0; freedeps = 0; needj = UFSTOVFS(ump)->mnt_kern_flag & MNTK_SUJ; - lbnadd = 1; - for (i = level; i > 0; i--) - lbnadd *= NINDIR(fs); + lbnadd = lbn_offset(fs, level); /* * Get buffer of block pointers to be freed. This routine is not * called until the zero'ed inode has been written, so it is safe @@ -6136,20 +6142,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]; @@ -6161,8 +6166,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); @@ -6772,7 +6795,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; } diff --git a/sys/ufs/ffs/fs.h b/sys/ufs/ffs/fs.h index 42c4cfe..ba98ed3 100644 --- a/sys/ufs/ffs/fs.h +++ b/sys/ufs/ffs/fs.h @@ -607,6 +607,11 @@ struct cg { : (fragroundup(fs, blkoff(fs, (size))))) /* + * Number of indirects in a filesystem block. + */ +#define NINDIR(fs) ((fs)->fs_nindir) + +/* * Indirect lbns are aligned on NDADDR addresses where single indirects * are the negated address of the lowest lbn reachable, double indirects * are this lbn - 1 and triple indirects are this lbn - 2. This yields @@ -631,6 +636,17 @@ lbn_level(ufs_lbn_t lbn) } return (-1); } + +static inline ufs_lbn_t +lbn_offset(struct fs *fs, int level) +{ + ufs_lbn_t res; + + for (res = 1; level > 0; level--) + res *= NINDIR(fs); + return (res); +} + /* * Number of inodes in a secondary storage block/fragment. */ @@ -638,11 +654,6 @@ lbn_level(ufs_lbn_t lbn) #define INOPF(fs) ((fs)->fs_inopb >> (fs)->fs_fragshift) /* - * Number of indirects in a filesystem block. - */ -#define NINDIR(fs) ((fs)->fs_nindir) - -/* * Softdep journal record format. */