git: a91716efeb68 - main - Clean up orphaned indirdep dependency structures after disk failure.

Kirk McKusick mckusick at FreeBSD.org
Thu Jul 29 23:32:17 UTC 2021


The branch main has been updated by mckusick:

URL: https://cgit.FreeBSD.org/src/commit/?id=a91716efeb684c50289c0e1136f5432f880dc873

commit a91716efeb684c50289c0e1136f5432f880dc873
Author:     Kirk McKusick <mckusick at FreeBSD.org>
AuthorDate: 2021-07-29 23:31:16 +0000
Commit:     Kirk McKusick <mckusick at FreeBSD.org>
CommitDate: 2021-07-29 23:31:16 +0000

    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
---
 sys/ufs/ffs/ffs_softdep.c | 54 ++++++++++++++++++++++++++++++++++++++++-------
 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;
@@ -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
 	 */
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.


More information about the dev-commits-src-main mailing list