git: 472f57606443 - stable/13 - msdosfs: take inusemap inconsistency as an error, not invariants violation

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sat, 15 Jan 2022 00:51:37 UTC
The branch stable/13 has been updated by kib:

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

commit 472f5760644320e59abc2b5362e84635dc650daf
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2021-12-25 18:39:15 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2022-01-14 18:11:01 +0000

    msdosfs: take inusemap inconsistency as an error, not invariants violation
    
    (cherry picked from commit 2c9a1c22c323b069d1f4883170349545c94b7b8d)
---
 sys/fs/msdosfs/msdosfs_fat.c | 41 +++++++++++++++++++++++++++--------------
 1 file changed, 27 insertions(+), 14 deletions(-)

diff --git a/sys/fs/msdosfs/msdosfs_fat.c b/sys/fs/msdosfs/msdosfs_fat.c
index 6d5bfc7fa46e..202feeef0102 100644
--- a/sys/fs/msdosfs/msdosfs_fat.c
+++ b/sys/fs/msdosfs/msdosfs_fat.c
@@ -80,8 +80,7 @@ static void	updatefats(struct msdosfsmount *pmp, struct buf *bp,
 		    u_long fatbn);
 static __inline void
 		usemap_alloc(struct msdosfsmount *pmp, u_long cn);
-static __inline void
-		usemap_free(struct msdosfsmount *pmp, u_long cn);
+static int	usemap_free(struct msdosfsmount *pmp, u_long cn);
 static int	clusteralloc1(struct msdosfsmount *pmp, u_long start,
 		    u_long count, u_long fillwith, u_long *retcluster,
 		    u_long *got);
@@ -398,7 +397,7 @@ usemap_alloc(struct msdosfsmount *pmp, u_long cn)
 	pmp->pm_flags |= MSDOSFS_FSIMOD;
 }
 
-static __inline void
+static int
 usemap_free(struct msdosfsmount *pmp, u_long cn)
 {
 
@@ -408,13 +407,17 @@ usemap_free(struct msdosfsmount *pmp, u_long cn)
 	    pmp->pm_maxcluster));
 	KASSERT((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0,
 	    ("usemap_free on ro msdosfs mount"));
+	if ((pmp->pm_inusemap[cn / N_INUSEBITS] &
+	    (1U << (cn % N_INUSEBITS))) == 0) {
+		printf("%s: Freeing unused sector %ld %ld %x\n",
+		    pmp->pm_mountp->mnt_stat.f_mntonname, cn, cn % N_INUSEBITS,
+		    (unsigned)pmp->pm_inusemap[cn / N_INUSEBITS]);
+		return (EINTEGRITY);
+	}
 	pmp->pm_freeclustercount++;
 	pmp->pm_flags |= MSDOSFS_FSIMOD;
-	KASSERT((pmp->pm_inusemap[cn / N_INUSEBITS] &
-	    (1U << (cn % N_INUSEBITS))) != 0,
-	    ("Freeing unused sector %ld %ld %x", cn, cn % N_INUSEBITS,
-	    (unsigned)pmp->pm_inusemap[cn / N_INUSEBITS]));
 	pmp->pm_inusemap[cn / N_INUSEBITS] &= ~(1U << (cn % N_INUSEBITS));
+	return (0);
 }
 
 int
@@ -432,11 +435,11 @@ clusterfree(struct msdosfsmount *pmp, u_long cluster, u_long *oldcnp)
 	 * bit in the "in use" cluster bit map.
 	 */
 	MSDOSFS_LOCK_MP(pmp);
-	usemap_free(pmp, cluster);
+	error = usemap_free(pmp, cluster);
 	MSDOSFS_UNLOCK_MP(pmp);
-	if (oldcnp)
+	if (error == 0 && oldcnp != NULL)
 		*oldcnp = oldcn;
-	return (0);
+	return (error);
 }
 
 /*
@@ -712,7 +715,7 @@ chainalloc(struct msdosfsmount *pmp, u_long start, u_long count,
 	error = fatchain(pmp, start, count, fillwith);
 	if (error != 0) {
 		for (cl = start, n = count; n-- > 0;)
-			usemap_free(pmp, cl++);
+			(void)usemap_free(pmp, cl++);
 		return (error);
 	}
 #ifdef MSDOSFS_DEBUG
@@ -846,7 +849,12 @@ freeclusterchain(struct msdosfsmount *pmp, u_long cluster)
 			}
 			lbn = bn;
 		}
-		usemap_free(pmp, cluster);
+		error = usemap_free(pmp, cluster);
+		if (error != 0) {
+			updatefats(pmp, bp, lbn);
+			MSDOSFS_UNLOCK_MP(pmp);
+			return (error);
+		}
 		switch (pmp->pm_fatmask) {
 		case FAT12_MASK:
 			readcn = getushort(bp->b_data + bo);
@@ -940,8 +948,13 @@ fillinusemap(struct msdosfsmount *pmp)
 #endif
 			brelse(bp);
 			return (EINVAL);
-		} else if (readcn == CLUST_FREE)
-			usemap_free(pmp, cn);
+		} else if (readcn == CLUST_FREE) {
+			error = usemap_free(pmp, cn);
+			if (error != 0) {
+				brelse(bp);
+				return (error);
+			}
+		}
 	}
 	if (bp != NULL)
 		brelse(bp);