msdosfs: take inusemap inconsistency as an error, not invariants violation

In other words, stop silently accepting freeing free cluster in
non-debug kernels, but return the error to the caller.  Modify callers
to handle errors from usemap_free().

In collaboration with:	pho
Reviewed by:	markj, mckusick
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
Differential revision:	https://reviews.freebsd.org/D33721
This commit is contained in:
Konstantin Belousov 2021-12-25 20:39:15 +02:00
parent 595ed4d767
commit 2c9a1c22c3

View file

@ -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);