git: 3dc5f8e19d8c - main - ffs: wait for trims earlier during unmount to avoid panic

From: Chuck Silvers <chs_at_FreeBSD.org>
Date: Fri, 08 Apr 2022 17:23:05 UTC
The branch main has been updated by chs:

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

commit 3dc5f8e19d8c975a5e27752d65f9aa91d67c9c9e
Author:     Chuck Silvers <chs@FreeBSD.org>
AuthorDate: 2022-04-08 17:19:40 +0000
Commit:     Chuck Silvers <chs@FreeBSD.org>
CommitDate: 2022-04-08 17:19:40 +0000

    ffs: wait for trims earlier during unmount to avoid panic
    
    All softdep processing is supposed to be completed by
    softdep_flushfiles() and no more deps are supposed to be created after
    that, but if a pending trim completes after softdep_flushfiles() and
    before softdep_unmount() then the blkfree that is performed by
    ffs_blkfree_trim_task() will create a dep when none should exist, and
    if softdep_unmount() is called before that dep is freed then the
    kernel will panic.  Prevent this by waiting for trims to complete
    earlier in the unmount process, in ffs_flushfiles(), so that any deps
    will be freed and any modified CG buffers will be flushed by the final
    fsync of the devvp in ffs_flushfiles() as intended.
    
    Reviewed by:    mckusick, kib
    Sponsored by:   Netflix
    Differential Revision:  https://reviews.freebsd.org/D34806
---
 sys/ufs/ffs/ffs_vfsops.c | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index 77361731202a..e9cbc962cd78 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -1423,9 +1423,7 @@ ffs_unmount(mp, mntflags)
 	if (susp)
 		vfs_write_resume(mp, VR_START_WRITE);
 	if (ump->um_trim_tq != NULL) {
-		while (ump->um_trim_inflight != 0)
-			pause("ufsutr", hz);
-		taskqueue_drain_all(ump->um_trim_tq);
+		MPASS(ump->um_trim_inflight == 0);
 		taskqueue_free(ump->um_trim_tq);
 		free (ump->um_trimhash, M_TRIM);
 	}
@@ -1539,6 +1537,20 @@ ffs_flushfiles(mp, flags, td)
 	if (qerror == 0 && (error = vflush(mp, 0, flags, td)) != 0)
 		return (error);
 
+	/*
+	 * If this is a forcible unmount and there were any files that
+	 * were unlinked but still open, then vflush() will have
+	 * truncated and freed those files, which might have started
+	 * some trim work.  Wait here for any trims to complete
+	 * and process the blkfrees which follow the trims.
+	 * This may create more dirty devvp buffers and softdep deps.
+	 */
+	if (ump->um_trim_tq != NULL) {
+		while (ump->um_trim_inflight != 0)
+			pause("ufsutr", hz);
+		taskqueue_drain_all(ump->um_trim_tq);
+	}
+
 	/*
 	 * Flush filesystem metadata.
 	 */