Fix backward compatibility with UFS1 filesystems created before June 2002

Reviewed-by: kib
Tested-by:   Peter Holm
Differential-Revision: https://reviews.freebsd.org/D48472
(cherry picked from commit 661ca921e8cd56b17fc6615bc7e596e56e0e7c31)
This commit is contained in:
Kirk McKusick 2025-01-16 10:43:48 -08:00
parent f31c37f8ac
commit 26c483aec0
7 changed files with 88 additions and 104 deletions

View file

@ -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",

View file

@ -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_sbsearch(void *, struct fs **, int, struct malloc_type *,
int (*)(void *, off_t, void **, int));

View file

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

View file

@ -9941,7 +9941,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,
@ -9973,7 +9973,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,

View file

@ -126,6 +126,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 (*)(void *, off_t, void **, int));
static void ffs_oldfscompat_read(struct fs *, ufs2_daddr_t);
static int validate_sblock(struct fs *, int);
/*
@ -271,6 +272,7 @@ readsuper(void *devfd, struct fs **fsp, off_t sblockloc, int flags,
if (fs->fs_magic == FS_UFS1_MAGIC && (flags & UFS_ALTSBLK) == 0 &&
fs->fs_bsize == SBLOCK_UFS2 && sblockloc == SBLOCK_UFS2)
return (ENOENT);
ffs_oldfscompat_read(fs, sblockloc);
if ((error = validate_sblock(fs, flags)) > 0)
return (error);
/*
@ -319,6 +321,83 @@ readsuper(void *devfd, struct fs **fsp, off_t sblockloc, int flags,
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.
*/
@ -564,7 +643,7 @@ validate_sblock(struct fs *fs, int flags)
sizepb *= NINDIR(fs);
maxfilesize += sizepb;
}
WCHK(fs->fs_maxfilesize, !=, maxfilesize, %jd);
WCHK(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

View file

@ -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);
@ -797,7 +795,6 @@ ffs_reload(struct mount *mp, int flags)
fs = VFSTOUFS(mp)->um_fs = newfs;
ump->um_bsize = fs->fs_bsize;
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 "
@ -1012,7 +1009,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;
@ -1221,96 +1217,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
*/
@ -2194,7 +2100,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);

View file

@ -413,7 +413,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 */
@ -426,7 +427,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 */