diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index 023c21b1bd3..319b6d03c6f 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -2045,6 +2045,7 @@ softdep_setup_freeblocks(ip, length, flags) MALLOC(freeblks, struct freeblks *, sizeof(struct freeblks), M_FREEBLKS, M_SOFTDEP_FLAGS|M_ZERO); freeblks->fb_list.wk_type = D_FREEBLKS; + freeblks->fb_state = ATTACHED; freeblks->fb_uid = ip->i_uid; freeblks->fb_previousinum = ip->i_number; freeblks->fb_devvp = ip->i_devvp; @@ -2180,6 +2181,20 @@ restart: ACQUIRE_LOCK(&lk); if (inodedep_lookup(fs, ip->i_number, 0, &inodedep) != 0) (void) free_inodedep(inodedep); + + if(delay) { + freeblks->fb_state |= DEPCOMPLETE; + /* + * If the inode with zeroed block pointers is now on disk + * we can start freeing blocks. Add freeblks to the worklist + * instead of calling handle_workitem_freeblocks directly as + * it is more likely that additional IO is needed to complete + * the request here than in the !delay case. + */ + if ((freeblks->fb_state & ALLCOMPLETE) == ALLCOMPLETE) + add_to_worklist(&freeblks->fb_list); + } + FREE_LOCK(&lk); /* * If the inode has never been written to disk (delay == 0), @@ -4425,6 +4440,10 @@ handle_written_inodeblock(inodedep, bp) continue; case D_FREEBLKS: + wk->wk_state |= COMPLETE; + if ((wk->wk_state & ALLCOMPLETE) != ALLCOMPLETE) + continue; + /* -- fall through -- */ case D_FREEFRAG: case D_DIRREM: add_to_worklist(wk); diff --git a/sys/ufs/ffs/softdep.h b/sys/ufs/ffs/softdep.h index 89d755e9923..38486447ac9 100644 --- a/sys/ufs/ffs/softdep.h +++ b/sys/ufs/ffs/softdep.h @@ -429,6 +429,7 @@ struct freefrag { */ struct freeblks { struct worklist fb_list; /* id_inowait or delayed worklist */ +# define fb_state fb_list.wk_state /* inode and dirty block state */ ino_t fb_previousinum; /* inode of previous owner of blocks */ uid_t fb_uid; /* uid of previous owner of blocks */ struct vnode *fb_devvp; /* filesystem device vnode */