git: 6a356edd4fc3 - stable/13 - Fix backward compatibility with UFS1 filesystems created before June 2002

From: Kirk McKusick <mckusick_at_FreeBSD.org>
Date: Sat, 25 Jan 2025 21:11:00 UTC
The branch stable/13 has been updated by mckusick:

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

commit 6a356edd4fc3c8d7959fcc6a2447c7193d830392
Author:     Kirk McKusick <mckusick@FreeBSD.org>
AuthorDate: 2025-01-16 18:43:48 +0000
Commit:     Kirk McKusick <mckusick@FreeBSD.org>
CommitDate: 2025-01-25 21:10:20 +0000

    Fix backward compatibility with UFS1 filesystems created before June 2002
    
    See the Pahabricator review for more details.
    
    Reviewed-by: kib
    Tested-by:   Peter Holm
    Differential-Revision: https://reviews.freebsd.org/D48472
    (cherry picked from commit 661ca921e8cd56b17fc6615bc7e596e56e0e7c31)
---
 sbin/growfs/debug.c        |  2 -
 sys/ufs/ffs/ffs_extern.h   |  2 +-
 sys/ufs/ffs/ffs_snapshot.c |  2 +-
 sys/ufs/ffs/ffs_softdep.c  |  4 +-
 sys/ufs/ffs/ffs_subr.c     | 81 +++++++++++++++++++++++++++++++++++++-
 sys/ufs/ffs/ffs_vfsops.c   | 96 +---------------------------------------------
 sys/ufs/ffs/fs.h           |  5 ++-
 7 files changed, 88 insertions(+), 104 deletions(-)

diff --git a/sbin/growfs/debug.c b/sbin/growfs/debug.c
index 456e67dbc5c2..ab4539d06a69 100644
--- a/sbin/growfs/debug.c
+++ b/sbin/growfs/debug.c
@@ -305,8 +305,6 @@ dbg_dump_fs(struct fs *sb, const char *comment)
 	    sb->fs_avgfilesize);
 	fprintf(dbg_log, "avgfpdir          int32_t          0x%08x\n",
 	    sb->fs_avgfpdir);
-	fprintf(dbg_log, "save_cgsize       int32_t          0x%08x\n",
-	    sb->fs_save_cgsize);
 	fprintf(dbg_log, "flags             int32_t          0x%08x\n",
 	    sb->fs_flags);
 	fprintf(dbg_log, "contigsumsize     int32_t          0x%08x\n",
diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h
index 89ef325b87e3..2e9b485d482b 100644
--- a/sys/ufs/ffs/ffs_extern.h
+++ b/sys/ufs/ffs/ffs_extern.h
@@ -84,7 +84,7 @@ int	ffs_inotovp(struct mount *, ino_t, uint64_t, int, struct vnode **,
 	    int);
 int	ffs_isblock(struct fs *, uint8_t *, ufs1_daddr_t);
 int	ffs_isfreeblock(struct fs *, uint8_t *, ufs1_daddr_t);
-void	ffs_oldfscompat_write(struct fs *, struct ufsmount *);
+void	ffs_oldfscompat_write(struct fs *);
 int	ffs_own_mount(const struct mount *mp);
 int	ffs_reallocblks(struct vop_reallocblks_args *);
 int	ffs_realloccg(struct inode *, ufs2_daddr_t, ufs2_daddr_t,
diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c
index bc4dbdf52e5b..6e2a8d66b54f 100644
--- a/sys/ufs/ffs/ffs_snapshot.c
+++ b/sys/ufs/ffs/ffs_snapshot.c
@@ -840,7 +840,7 @@ resumefs:
 		copy_fs->fs_fmod = 0;
 		bpfs = (struct fs *)&nbp->b_data[loc];
 		bcopy((caddr_t)copy_fs, (caddr_t)bpfs, (uint64_t)fs->fs_sbsize);
-		ffs_oldfscompat_write(bpfs, ump);
+		ffs_oldfscompat_write(bpfs);
 		bpfs->fs_ckhash = ffs_calc_sbhash(bpfs);
 		bawrite(nbp);
 	}
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c
index 62af80d7eb40..e14e333f70bb 100644
--- a/sys/ufs/ffs/ffs_softdep.c
+++ b/sys/ufs/ffs/ffs_softdep.c
@@ -9932,7 +9932,7 @@ clear_unlinked_inodedep( struct inodedep *inodedep)
 		if (pino == 0) {
 			bcopy((caddr_t)fs, bp->b_data, (uint64_t)fs->fs_sbsize);
 			bpfs = (struct fs *)bp->b_data;
-			ffs_oldfscompat_write(bpfs, ump);
+			ffs_oldfscompat_write(bpfs);
 			softdep_setup_sbupdate(ump, bpfs, bp);
 			/*
 			 * Because we may have made changes to the superblock,
@@ -9964,7 +9964,7 @@ clear_unlinked_inodedep( struct inodedep *inodedep)
 			    (int)fs->fs_sbsize, 0, 0, 0);
 			bcopy((caddr_t)fs, bp->b_data, (uint64_t)fs->fs_sbsize);
 			bpfs = (struct fs *)bp->b_data;
-			ffs_oldfscompat_write(bpfs, ump);
+			ffs_oldfscompat_write(bpfs);
 			softdep_setup_sbupdate(ump, bpfs, bp);
 			/*
 			 * Because we may have made changes to the superblock,
diff --git a/sys/ufs/ffs/ffs_subr.c b/sys/ufs/ffs/ffs_subr.c
index ca595ed5bd80..351559882ca2 100644
--- a/sys/ufs/ffs/ffs_subr.c
+++ b/sys/ufs/ffs/ffs_subr.c
@@ -130,6 +130,7 @@ ffs_update_dinode_ckhash(struct fs *fs, struct ufs2_dinode *dip)
 static off_t sblock_try[] = SBLOCKSEARCH;
 static int readsuper(void *, struct fs **, off_t, int, int,
 	int (*)(void *, off_t, void **, int));
+static void ffs_oldfscompat_read(struct fs *, ufs2_daddr_t);
 static int validate_sblock(struct fs *, int);
 
 /*
@@ -273,6 +274,7 @@ readsuper(void *devfd, struct fs **fsp, off_t sblockloc, int isaltsblk,
 	if (fs->fs_magic == FS_UFS1_MAGIC && !isaltsblk &&
 	    fs->fs_bsize == SBLOCK_UFS2 && sblockloc == SBLOCK_UFS2)
 		return (ENOENT);
+	ffs_oldfscompat_read(fs, sblockloc);
 	if ((error = validate_sblock(fs, isaltsblk)) > 0)
 		return (error);
 	/*
@@ -317,6 +319,83 @@ readsuper(void *devfd, struct fs **fsp, off_t sblockloc, int isaltsblk,
 	return (0);
 }
 
+/*
+ * Sanity checks for loading old filesystem superblocks.
+ * See ffs_oldfscompat_write below for unwound actions.
+ *
+ * XXX - Parts get retired eventually.
+ * Unfortunately new bits get added.
+ */
+static void
+ffs_oldfscompat_read(struct fs *fs, ufs2_daddr_t sblockloc)
+{
+	uint64_t maxfilesize;
+
+	/*
+	 * If not yet done, update fs_flags location and value of fs_sblockloc.
+	 */
+	if ((fs->fs_old_flags & FS_FLAGS_UPDATED) == 0) {
+		fs->fs_flags = fs->fs_old_flags;
+		fs->fs_old_flags |= FS_FLAGS_UPDATED;
+		fs->fs_sblockloc = sblockloc;
+	}
+	/*
+	 * If not yet done, update UFS1 superblock with new wider fields.
+	 */
+	if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_maxbsize != fs->fs_bsize) {
+		fs->fs_maxbsize = fs->fs_bsize;
+		fs->fs_time = fs->fs_old_time;
+		fs->fs_size = fs->fs_old_size;
+		fs->fs_dsize = fs->fs_old_dsize;
+		fs->fs_csaddr = fs->fs_old_csaddr;
+		fs->fs_cstotal.cs_ndir = fs->fs_old_cstotal.cs_ndir;
+		fs->fs_cstotal.cs_nbfree = fs->fs_old_cstotal.cs_nbfree;
+		fs->fs_cstotal.cs_nifree = fs->fs_old_cstotal.cs_nifree;
+		fs->fs_cstotal.cs_nffree = fs->fs_old_cstotal.cs_nffree;
+	}
+	if (fs->fs_magic == FS_UFS1_MAGIC &&
+	    fs->fs_old_inodefmt < FS_44INODEFMT) {
+		fs->fs_maxfilesize = ((uint64_t)1 << 31) - 1;
+		fs->fs_qbmask = ~fs->fs_bmask;
+		fs->fs_qfmask = ~fs->fs_fmask;
+	}
+	if (fs->fs_magic == FS_UFS1_MAGIC) {
+		fs->fs_save_maxfilesize = fs->fs_maxfilesize;
+		maxfilesize = (uint64_t)0x80000000 * fs->fs_bsize - 1;
+		if (fs->fs_maxfilesize > maxfilesize)
+			fs->fs_maxfilesize = maxfilesize;
+	}
+	/* Compatibility for old filesystems */
+	if (fs->fs_avgfilesize <= 0)
+		fs->fs_avgfilesize = AVFILESIZ;
+	if (fs->fs_avgfpdir <= 0)
+		fs->fs_avgfpdir = AFPDIR;
+}
+
+/*
+ * Unwinding superblock updates for old filesystems.
+ * See ffs_oldfscompat_read above for details.
+ *
+ * XXX - Parts get retired eventually.
+ * Unfortunately new bits get added.
+ */
+void
+ffs_oldfscompat_write(struct fs *fs)
+{
+
+	/*
+	 * Copy back UFS2 updated fields that UFS1 inspects.
+	 */
+	if (fs->fs_magic == FS_UFS1_MAGIC) {
+		fs->fs_old_time = fs->fs_time;
+		fs->fs_old_cstotal.cs_ndir = fs->fs_cstotal.cs_ndir;
+		fs->fs_old_cstotal.cs_nbfree = fs->fs_cstotal.cs_nbfree;
+		fs->fs_old_cstotal.cs_nifree = fs->fs_cstotal.cs_nifree;
+		fs->fs_old_cstotal.cs_nffree = fs->fs_cstotal.cs_nffree;
+		fs->fs_maxfilesize = fs->fs_save_maxfilesize;
+	}
+}
+
 /*
  * Verify the filesystem values.
  */
@@ -482,7 +561,7 @@ validate_sblock(struct fs *fs, int isaltsblk)
 		sizepb *= NINDIR(fs);
 		maxfilesize += sizepb;
 	}
-	CHK(fs->fs_maxfilesize, !=, maxfilesize, %jd);
+	CHK(fs->fs_maxfilesize, >, maxfilesize, %jd);
 	/*
 	 * These values have a tight interaction with each other that
 	 * makes it hard to tightly bound them. So we can only check
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index d97f5413c647..62d63210531a 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -85,8 +85,6 @@ static uma_zone_t uma_inode, uma_ufs1, uma_ufs2;
 VFS_SMR_DECLARE;
 
 static int	ffs_mountfs(struct vnode *, struct mount *, struct thread *);
-static void	ffs_oldfscompat_read(struct fs *, struct ufsmount *,
-		    ufs2_daddr_t);
 static void	ffs_ifree(struct ufsmount *ump, struct inode *ip);
 static int	ffs_sync_lazy(struct mount *mp);
 static int	ffs_use_bread(void *devfd, off_t loc, void **bufp, int size);
@@ -823,7 +821,6 @@ ffs_reload(struct mount *mp, int flags)
 	free(fs, M_UFSMNT);
 	fs = VFSTOUFS(mp)->um_fs = newfs;
 	ump->um_maxsymlinklen = fs->fs_maxsymlinklen;
-	ffs_oldfscompat_read(fs, VFSTOUFS(mp), fs->fs_sblockloc);
 	UFS_LOCK(ump);
 	if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
 		printf("WARNING: %s: reload pending error: blocks %jd "
@@ -1040,7 +1037,6 @@ ffs_mountfs(struct vnode *odevvp, struct mount *mp, struct thread *td)
 		ump->um_check_blkno = NULL;
 	mtx_init(UFS_MTX(ump), "FFS", "FFS Lock", MTX_DEF);
 	sx_init(&ump->um_checkpath_lock, "uchpth");
-	ffs_oldfscompat_read(fs, ump, fs->fs_sblockloc);
 	fs->fs_ronly = ronly;
 	fs->fs_active = NULL;
 	mp->mnt_data = ump;
@@ -1251,96 +1247,6 @@ ffs_use_bread(void *devfd, off_t loc, void **bufp, int size)
 	return (0);
 }
 
-static int bigcgs = 0;
-SYSCTL_INT(_debug, OID_AUTO, bigcgs, CTLFLAG_RW, &bigcgs, 0, "");
-
-/*
- * Sanity checks for loading old filesystem superblocks.
- * See ffs_oldfscompat_write below for unwound actions.
- *
- * XXX - Parts get retired eventually.
- * Unfortunately new bits get added.
- */
-static void
-ffs_oldfscompat_read(struct fs *fs,
-	struct ufsmount *ump,
-	ufs2_daddr_t sblockloc)
-{
-	off_t maxfilesize;
-
-	/*
-	 * If not yet done, update fs_flags location and value of fs_sblockloc.
-	 */
-	if ((fs->fs_old_flags & FS_FLAGS_UPDATED) == 0) {
-		fs->fs_flags = fs->fs_old_flags;
-		fs->fs_old_flags |= FS_FLAGS_UPDATED;
-		fs->fs_sblockloc = sblockloc;
-	}
-	/*
-	 * If not yet done, update UFS1 superblock with new wider fields.
-	 */
-	if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_maxbsize != fs->fs_bsize) {
-		fs->fs_maxbsize = fs->fs_bsize;
-		fs->fs_time = fs->fs_old_time;
-		fs->fs_size = fs->fs_old_size;
-		fs->fs_dsize = fs->fs_old_dsize;
-		fs->fs_csaddr = fs->fs_old_csaddr;
-		fs->fs_cstotal.cs_ndir = fs->fs_old_cstotal.cs_ndir;
-		fs->fs_cstotal.cs_nbfree = fs->fs_old_cstotal.cs_nbfree;
-		fs->fs_cstotal.cs_nifree = fs->fs_old_cstotal.cs_nifree;
-		fs->fs_cstotal.cs_nffree = fs->fs_old_cstotal.cs_nffree;
-	}
-	if (fs->fs_magic == FS_UFS1_MAGIC &&
-	    fs->fs_old_inodefmt < FS_44INODEFMT) {
-		fs->fs_maxfilesize = ((uint64_t)1 << 31) - 1;
-		fs->fs_qbmask = ~fs->fs_bmask;
-		fs->fs_qfmask = ~fs->fs_fmask;
-	}
-	if (fs->fs_magic == FS_UFS1_MAGIC) {
-		ump->um_savedmaxfilesize = fs->fs_maxfilesize;
-		maxfilesize = (uint64_t)0x80000000 * fs->fs_bsize - 1;
-		if (fs->fs_maxfilesize > maxfilesize)
-			fs->fs_maxfilesize = maxfilesize;
-	}
-	/* Compatibility for old filesystems */
-	if (fs->fs_avgfilesize <= 0)
-		fs->fs_avgfilesize = AVFILESIZ;
-	if (fs->fs_avgfpdir <= 0)
-		fs->fs_avgfpdir = AFPDIR;
-	if (bigcgs) {
-		fs->fs_save_cgsize = fs->fs_cgsize;
-		fs->fs_cgsize = fs->fs_bsize;
-	}
-}
-
-/*
- * Unwinding superblock updates for old filesystems.
- * See ffs_oldfscompat_read above for details.
- *
- * XXX - Parts get retired eventually.
- * Unfortunately new bits get added.
- */
-void
-ffs_oldfscompat_write(struct fs *fs, struct ufsmount *ump)
-{
-
-	/*
-	 * Copy back UFS2 updated fields that UFS1 inspects.
-	 */
-	if (fs->fs_magic == FS_UFS1_MAGIC) {
-		fs->fs_old_time = fs->fs_time;
-		fs->fs_old_cstotal.cs_ndir = fs->fs_cstotal.cs_ndir;
-		fs->fs_old_cstotal.cs_nbfree = fs->fs_cstotal.cs_nbfree;
-		fs->fs_old_cstotal.cs_nifree = fs->fs_cstotal.cs_nifree;
-		fs->fs_old_cstotal.cs_nffree = fs->fs_cstotal.cs_nffree;
-		fs->fs_maxfilesize = ump->um_savedmaxfilesize;
-	}
-	if (bigcgs) {
-		fs->fs_cgsize = fs->fs_save_cgsize;
-		fs->fs_save_cgsize = 0;
-	}
-}
-
 /*
  * unmount system call
  */
@@ -2224,7 +2130,7 @@ ffs_use_bwrite(void *devfd, off_t loc, void *buf, int size)
 	UFS_UNLOCK(ump);
 	fs = (struct fs *)bp->b_data;
 	fs->fs_fmod = 0;
-	ffs_oldfscompat_write(fs, ump);
+	ffs_oldfscompat_write(fs);
 	fs->fs_si = NULL;
 	/* Recalculate the superblock hash */
 	fs->fs_ckhash = ffs_calc_sbhash(fs);
diff --git a/sys/ufs/ffs/fs.h b/sys/ufs/ffs/fs.h
index cc89df9aca66..1c8890fa94ff 100644
--- a/sys/ufs/ffs/fs.h
+++ b/sys/ufs/ffs/fs.h
@@ -374,7 +374,8 @@ struct fs {
 	int64_t	 fs_unrefs;		/* number of unreferenced inodes */
 	int64_t  fs_providersize;	/* size of underlying GEOM provider */
 	int64_t	 fs_metaspace;		/* size of area reserved for metadata */
-	int64_t	 fs_sparecon64[13];	/* old rotation block list head */
+	uint64_t fs_save_maxfilesize;	/* save old UFS1 maxfilesize */
+	int64_t	 fs_sparecon64[12];	/* old rotation block list head */
 	int64_t	 fs_sblockactualloc;	/* byte offset of this superblock */
 	int64_t	 fs_sblockloc;		/* byte offset of standard superblock */
 	struct	csum_total fs_cstotal;	/* (u) cylinder summary information */
@@ -387,7 +388,7 @@ struct fs {
 	uint32_t fs_snapinum[FSMAXSNAP];/* list of snapshot inode numbers */
 	uint32_t fs_avgfilesize;	/* expected average file size */
 	uint32_t fs_avgfpdir;		/* expected # of files per directory */
-	int32_t	 fs_save_cgsize;	/* save real cg size to use fs_bsize */
+	uint32_t fs_available_spare;	/* old scratch space */
 	ufs_time_t fs_mtime;		/* Last mount or fsck time. */
 	int32_t  fs_sujfree;		/* SUJ free list */
 	int32_t	 fs_sparecon32[21];	/* reserved for future constants */