Clean up orphaned indirdep dependency structures after disk failure.

During forcible unmount after a disk failure there is a bug that
causes one or more indirdep dependency structures to fail to be
deallocated. Until we manage to track down why they fail to get
cleaned up, this code tracks them down and eliminates them so that
the unmount can succeed.

Reported by:  Peter Holm
Help from:    kib
Reviewed by:  Chuck Silvers
Tested by:    Peter Holm
MFC after:    7 days
Sponsored by: Netflix
This commit is contained in:
Kirk McKusick 2021-07-29 16:31:16 -07:00
parent 412b5e40a7
commit a91716efeb
2 changed files with 47 additions and 11 deletions

View File

@ -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;
@ -14871,9 +14866,52 @@ 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
*/

View File

@ -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.