git: c2cd605e8c8a - main - Get consistent updates for UFS superblocks.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 19 Mar 2025 23:34:31 UTC
The branch main has been updated by mckusick: URL: https://cgit.FreeBSD.org/src/commit/?id=c2cd605e8c8a15e545dfd3e50aef2f660d460b30 commit c2cd605e8c8a15e545dfd3e50aef2f660d460b30 Author: Kirk McKusick <mckusick@FreeBSD.org> AuthorDate: 2025-03-19 23:32:39 +0000 Commit: Kirk McKusick <mckusick@FreeBSD.org> CommitDate: 2025-03-19 23:33:59 +0000 Get consistent updates for UFS superblocks. Superblocks are written by Freebsd clients using the ffs_sbput() routine (exported from the kernel in sys/ufs/ffs/ffs_subr.c). These clients include the kernel, some geom modules, and system utilities using libufs. Currently backward compatible updates of UFS superblocks are done only when the kernel writes them. These updates should be done whenever any call to ffs_sbput() is done. This commit moves these UFS superblock compatibility updates from the kernel-specific superblock update to ffs_sbput() so that all clients make these compatibility updates when they write superblocks. Reviewed-by: kib Tested-by: Peter Holm MFC-after: 1 week Differential Revision: https://reviews.freebsd.org/D49276 Sponsored-by: Netflix --- sys/ufs/ffs/ffs_subr.c | 62 +++++++++++++++++++++++++++++++++--------------- sys/ufs/ffs/ffs_vfsops.c | 42 +++++++++++++------------------- 2 files changed, 59 insertions(+), 45 deletions(-) diff --git a/sys/ufs/ffs/ffs_subr.c b/sys/ufs/ffs/ffs_subr.c index c293cbbcbfb0..67c423d3127c 100644 --- a/sys/ufs/ffs/ffs_subr.c +++ b/sys/ufs/ffs/ffs_subr.c @@ -384,16 +384,35 @@ void ffs_oldfscompat_write(struct fs *fs) { - /* - * Copy back UFS2 updated fields that UFS1 inspects. - */ - if (fs->fs_magic == FS_UFS1_MAGIC) { + switch (fs->fs_magic) { + case FS_UFS1_MAGIC: + if (fs->fs_sblockloc != SBLOCK_UFS1 && + (fs->fs_old_flags & FS_FLAGS_UPDATED) == 0) { + printf( + "WARNING: %s: correcting fs_sblockloc from %jd to %d\n", + fs->fs_fsmnt, fs->fs_sblockloc, SBLOCK_UFS1); + fs->fs_sblockloc = SBLOCK_UFS1; + } + /* + * Copy back UFS2 updated fields that UFS1 inspects. + */ 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; + if (fs->fs_save_maxfilesize != 0) + fs->fs_maxfilesize = fs->fs_save_maxfilesize; + break; + case FS_UFS2_MAGIC: + if (fs->fs_sblockloc != SBLOCK_UFS2 && + (fs->fs_old_flags & FS_FLAGS_UPDATED) == 0) { + printf( + "WARNING: %s: correcting fs_sblockloc from %jd to %d\n", + fs->fs_fsmnt, fs->fs_sblockloc, SBLOCK_UFS2); + fs->fs_sblockloc = SBLOCK_UFS2; + } + break; } } @@ -931,6 +950,7 @@ int ffs_sbput(void *devfd, struct fs *fs, off_t loc, int (*writefunc)(void *devfd, off_t loc, void *buf, int size)) { + struct fs_summary_info *fs_si; int i, error, blks, size; uint8_t *space; @@ -953,23 +973,27 @@ ffs_sbput(void *devfd, struct fs *fs, off_t loc, } } fs->fs_fmod = 0; -#ifndef _KERNEL - { - struct fs_summary_info *fs_si; - - fs->fs_time = time(NULL); - /* Clear the pointers for the duration of writing. */ - fs_si = fs->fs_si; - fs->fs_si = NULL; - fs->fs_ckhash = ffs_calc_sbhash(fs); - error = (*writefunc)(devfd, loc, fs, fs->fs_sbsize); - fs->fs_si = fs_si; - } -#else /* _KERNEL */ + ffs_oldfscompat_write(fs); +#ifdef _KERNEL fs->fs_time = time_second; +#else /* User Code */ + fs->fs_time = time(NULL); +#endif + /* Clear the pointers for the duration of writing. */ + fs_si = fs->fs_si; + fs->fs_si = NULL; fs->fs_ckhash = ffs_calc_sbhash(fs); error = (*writefunc)(devfd, loc, fs, fs->fs_sbsize); -#endif /* _KERNEL */ + /* + * A negative error code is returned when a copy of the + * superblock has been made which is discarded when the I/O + * is done. So the fs_si field does not and indeed cannot be + * restored after the write is done. Convert the error code + * back to its usual positive value when returning it. + */ + if (error < 0) + return (-error - 1); + fs->fs_si = fs_si; return (error); } diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 498ef61d7cf1..891e490a7031 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -2032,9 +2032,15 @@ ffs_sbupdate(struct ufsmount *ump, int waitfor, int suspended) panic("ffs_sbupdate: write read-only filesystem"); /* * We use the superblock's buf to serialize calls to ffs_sbupdate(). + * Copy superblock to this buffer and have it written out. */ sbbp = getblk(ump->um_devvp, btodb(fs->fs_sblockloc), (int)fs->fs_sbsize, 0, 0, 0); + UFS_LOCK(ump); + fs->fs_fmod = 0; + bcopy((caddr_t)fs, sbbp->b_data, (uint64_t)fs->fs_sbsize); + UFS_UNLOCK(ump); + fs = (struct fs *)sbbp->b_data; /* * Initialize info needed for write function. */ @@ -2060,7 +2066,8 @@ ffs_use_bwrite(void *devfd, off_t loc, void *buf, int size) devfdp = devfd; ump = devfdp->ump; - fs = ump->um_fs; + bp = devfdp->sbbp; + fs = (struct fs *)bp->b_data; /* * Writing the superblock summary information. */ @@ -2077,44 +2084,27 @@ ffs_use_bwrite(void *devfd, off_t loc, void *buf, int size) } /* * Writing the superblock itself. We need to do special checks for it. + * A negative error code is returned to indicate that a copy of the + * superblock has been made and that the copy is discarded when the + * I/O is done. So the the caller should not attempt to restore the + * fs_si field after the write is done. The caller will convert the + * error code back to its usual positive value when returning it. */ - bp = devfdp->sbbp; if (ffs_fsfail_cleanup(ump, devfdp->error)) devfdp->error = 0; if (devfdp->error != 0) { brelse(bp); - return (devfdp->error); - } - if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_sblockloc != SBLOCK_UFS1 && - (fs->fs_old_flags & FS_FLAGS_UPDATED) == 0) { - printf("WARNING: %s: correcting fs_sblockloc from %jd to %d\n", - fs->fs_fsmnt, fs->fs_sblockloc, SBLOCK_UFS1); - fs->fs_sblockloc = SBLOCK_UFS1; - } - if (fs->fs_magic == FS_UFS2_MAGIC && fs->fs_sblockloc != SBLOCK_UFS2 && - (fs->fs_old_flags & FS_FLAGS_UPDATED) == 0) { - printf("WARNING: %s: correcting fs_sblockloc from %jd to %d\n", - fs->fs_fsmnt, fs->fs_sblockloc, SBLOCK_UFS2); - fs->fs_sblockloc = SBLOCK_UFS2; + return (-devfdp->error - 1); } if (MOUNTEDSOFTDEP(ump->um_mountp)) - softdep_setup_sbupdate(ump, (struct fs *)bp->b_data, bp); - UFS_LOCK(ump); - bcopy((caddr_t)fs, bp->b_data, (uint64_t)fs->fs_sbsize); - UFS_UNLOCK(ump); - fs = (struct fs *)bp->b_data; - fs->fs_fmod = 0; - ffs_oldfscompat_write(fs); - fs->fs_si = NULL; - /* Recalculate the superblock hash */ - fs->fs_ckhash = ffs_calc_sbhash(fs); + softdep_setup_sbupdate(ump, fs, bp); if (devfdp->suspended) bp->b_flags |= B_VALIDSUSPWRT; if (devfdp->waitfor != MNT_WAIT) bawrite(bp); else if ((error = bwrite(bp)) != 0) devfdp->error = error; - return (devfdp->error); + return (-devfdp->error - 1); } static int