git: 8a702ccda30d - stable/14 - MFC: fsck_msdosfs: fix status accounting for lost cluster chains

From: Xin LI <delphij_at_FreeBSD.org>
Date: Thu, 10 Sep 2026 02:32:13 UTC
The branch stable/14 has been updated by delphij:

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

commit 8a702ccda30da602007db38f1ebf91e92d72fe52
Author:     Jie Li <sheng9qing@gmail.com>
AuthorDate: 2026-09-02 06:15:05 +0000
Commit:     Xin LI <delphij@FreeBSD.org>
CommitDate: 2026-09-10 02:31:07 +0000

    MFC: fsck_msdosfs: fix status accounting for lost cluster chains
    
    (cherry picked from commit 6cf0d6c3b5777e053074200ff99dc4b750e62b96)
---
 sbin/fsck_msdosfs/fat.c | 41 ++++++++++++++++++++++++++++++++---------
 1 file changed, 32 insertions(+), 9 deletions(-)

diff --git a/sbin/fsck_msdosfs/fat.c b/sbin/fsck_msdosfs/fat.c
index bd8171043cc1..7d0ad9a595cf 100644
--- a/sbin/fsck_msdosfs/fat.c
+++ b/sbin/fsck_msdosfs/fat.c
@@ -1284,18 +1284,41 @@ checklost(struct fat_descriptor *fat)
 		}
 		if (fat_is_cl_head(fat, head)) {
 			ret = checkchain(fat, head, &chainlength);
-			if (ret != FSERROR && chainlength > 0) {
-				pwarn("Lost cluster chain at cluster %u\n"
-				    "%zd Cluster(s) lost\n",
-				    head, chainlength);
-				mod |= ret = reconnect(fat, head,
-				    chainlength);
+			/*
+			 * Record whether checkchain() has repaired the
+			 * chain (FSFATMOD) or died trying (FSFATAL) before
+			 * reconnect() overwrites ret, otherwise the repair
+			 * is never written back.
+			 */
+			if (ret != FSERROR) {
+				mod |= ret;
+				if (!(mod & FSFATAL) && chainlength > 0) {
+					pwarn(
+					    "Lost cluster chain at cluster %u\n"
+					    "%zd Cluster(s) lost\n",
+					    head, chainlength);
+					ret = reconnect(fat, head, chainlength);
+					if (ret != FSERROR)
+						mod |= ret;
+				}
 			}
 			if (mod & FSFATAL)
 				break;
-			if (ret == FSERROR && ask(0, "Clear")) {
-				clearchain(fat, head);
-				mod |= FSFATMOD;
+			/*
+			 * If reconnect() failed (or checkchain() truncation
+			 * was declined), defer folding FSERROR into mod until
+			 * the Clear fallback is known: if the lost chain is
+			 * cleared, the error has been resolved and must not
+			 * report an exit code 8; otherwise record FSERROR as
+			 * an unrecovered error.
+			 */
+			if (ret == FSERROR) {
+				if (ask(0, "Clear")) {
+					clearchain(fat, head);
+					mod |= FSFATMOD;
+				} else {
+					mod |= FSERROR;
+				}
 			}
 			chains--;
 		}