diff options
| -rw-r--r-- | sys/ufs/ffs/ffs_softdep.c | 54 | ||||
| -rw-r--r-- | sys/ufs/ffs/softdep.h | 4 |
2 files changed, 47 insertions, 11 deletions
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index da80f28bc814..e518cc5c5deb 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -1233,9 +1233,7 @@ workitem_free(item, type) ump->um_fs->fs_fsmnt, TYPENAME(item->wk_type))); atomic_subtract_long(&dep_current[item->wk_type], 1); ump->softdep_curdeps[item->wk_type] -= 1; -#ifdef INVARIANTS LIST_REMOVE(item, wk_all); -#endif free(item, DtoM(type)); } @@ -1262,9 +1260,7 @@ workitem_alloc(item, type, mp) ump->softdep_curdeps[type] += 1; ump->softdep_deps++; ump->softdep_accdeps++; -#ifdef INVARIANTS LIST_INSERT_HEAD(&ump->softdep_alldeps[type], item, wk_all); -#endif FREE_LOCK(ump); } @@ -1293,10 +1289,8 @@ workitem_reassign(item, newtype) dep_total[newtype]++; FREE_GBLLOCK(&lk); item->wk_type = newtype; -#ifdef INVARIANTS LIST_REMOVE(item, wk_all); LIST_INSERT_HEAD(&ump->softdep_alldeps[newtype], item, wk_all); -#endif } /* @@ -2713,10 +2707,8 @@ softdep_mount(devvp, mp, fs, cred) sdp->sd_indirhashsize = i - 1; for (i = 0; i <= sdp->sd_indirhashsize; i++) TAILQ_INIT(&sdp->sd_indirhash[i]); -#ifdef INVARIANTS for (i = 0; i <= D_LAST; i++) LIST_INIT(&sdp->sd_alldeps[i]); -#endif ACQUIRE_GBLLOCK(&lk); TAILQ_INSERT_TAIL(&softdepmounts, sdp, sd_next); FREE_GBLLOCK(&lk); @@ -14793,9 +14785,12 @@ softdep_check_suspend(struct mount *mp, int secondary_writes, int secondary_accwrites) { + struct buf *bp; struct bufobj *bo; struct ufsmount *ump; struct inodedep *inodedep; + struct indirdep *indirdep; + struct worklist *wk, *nextwk; int error, unlinked; bo = &devvp->v_bufobj; @@ -14872,8 +14867,51 @@ softdep_check_suspend(struct mount *mp, } /* + * XXX Check for orphaned indirdep dependency structures. + * + * During forcible unmount after a disk failure there is a + * bug that causes one or more indirdep dependency structures + * to fail to be deallocated. We check for them here and clean + * them up so that the unmount can succeed. + */ + if ((ump->um_flags & UM_FSFAIL_CLEANUP) != 0 && ump->softdep_deps > 0 && + ump->softdep_deps == ump->softdep_curdeps[D_INDIRDEP]) { + LIST_FOREACH_SAFE(wk, &ump->softdep_alldeps[D_INDIRDEP], + wk_all, nextwk) { + indirdep = WK_INDIRDEP(wk); + if ((indirdep->ir_state & (GOINGAWAY | DEPCOMPLETE)) != + (GOINGAWAY | DEPCOMPLETE) || + !TAILQ_EMPTY(&indirdep->ir_trunc) || + !LIST_EMPTY(&indirdep->ir_completehd) || + !LIST_EMPTY(&indirdep->ir_writehd) || + !LIST_EMPTY(&indirdep->ir_donehd) || + !LIST_EMPTY(&indirdep->ir_deplisthd) || + indirdep->ir_saveddata != NULL || + indirdep->ir_savebp == NULL) { + printf("%s: skipping orphaned indirdep %p\n", + __FUNCTION__, indirdep); + continue; + } + printf("%s: freeing orphaned indirdep %p\n", + __FUNCTION__, indirdep); + bp = indirdep->ir_savebp; + indirdep->ir_savebp = NULL; + free_indirdep(indirdep); + FREE_LOCK(ump); + brelse(bp); + while (!TRY_ACQUIRE_LOCK(ump)) { + BO_UNLOCK(bo); + ACQUIRE_LOCK(ump); + FREE_LOCK(ump); + BO_LOCK(bo); + } + } + } + + /* * Reasons for needing more work before suspend: * - Dirty buffers on devvp. + * - Dependency structures still exist * - Softdep activity occurred after start of vnode sync loop * - Secondary writes occurred after start of vnode sync loop */ diff --git a/sys/ufs/ffs/softdep.h b/sys/ufs/ffs/softdep.h index 3493aadafc98..41728be3ec0f 100644 --- a/sys/ufs/ffs/softdep.h +++ b/sys/ufs/ffs/softdep.h @@ -213,10 +213,10 @@ struct worklist { struct mount *wk_mp; /* Mount we live in */ unsigned int wk_type:8, /* type of request */ wk_state:24; /* state flags */ + LIST_ENTRY(worklist) wk_all; /* list of deps of this type */ #ifdef INVARIANTS const char *wk_func; /* func where added / removed */ int wk_line; /* line where added / removed */ - LIST_ENTRY(worklist) wk_all; /* list of deps of this type */ #endif }; #define WK_DATA(wk) ((void *)(wk)) @@ -1075,9 +1075,7 @@ struct mount_softdeps { TAILQ_ENTRY(mount_softdeps) sd_next; /* List of softdep filesystem */ struct ufsmount *sd_ump; /* our ufsmount structure */ u_long sd_curdeps[D_LAST + 1]; /* count of current deps */ -#ifdef INVARIANTS struct workhead sd_alldeps[D_LAST + 1];/* Lists of all deps */ -#endif }; /* * Flags for communicating with the syncer thread. |
