Thu Nov 10 10:53:29 2022 UTC ()
Some changes to "fs->fs_fmod" and "fs->fs_clean":
- clear "fs->fs_fmod" after reading the super block.
- assert we don't write a super block when mounted read-only.
- make sure "fs->fs_clean" is one of FS_ISCLEAN or FS_WASCLEAN.
- print "file system not clean" on every mount.

Should fix PR kern/57010: ffs: mounting unclean non-root fs read-only
causes spurious write to superblock


(hannken)
diff -r1.376 -r1.377 src/sys/ufs/ffs/ffs_vfsops.c

cvs diff -r1.376 -r1.377 src/sys/ufs/ffs/ffs_vfsops.c (expand / switch to unified diff)

--- src/sys/ufs/ffs/ffs_vfsops.c 2022/04/16 08:00:55 1.376
+++ src/sys/ufs/ffs/ffs_vfsops.c 2022/11/10 10:53:29 1.377
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: ffs_vfsops.c,v 1.376 2022/04/16 08:00:55 hannken Exp $ */ 1/* $NetBSD: ffs_vfsops.c,v 1.377 2022/11/10 10:53:29 hannken Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. 4 * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Wasabi Systems, Inc, and by Andrew Doran. 8 * by Wasabi Systems, Inc, and by Andrew Doran.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -51,27 +51,27 @@ @@ -51,27 +51,27 @@
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE. 58 * SUCH DAMAGE.
59 * 59 *
60 * @(#)ffs_vfsops.c 8.31 (Berkeley) 5/20/95 60 * @(#)ffs_vfsops.c 8.31 (Berkeley) 5/20/95
61 */ 61 */
62 62
63#include <sys/cdefs.h> 63#include <sys/cdefs.h>
64__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.376 2022/04/16 08:00:55 hannken Exp $"); 64__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.377 2022/11/10 10:53:29 hannken Exp $");
65 65
66#if defined(_KERNEL_OPT) 66#if defined(_KERNEL_OPT)
67#include "opt_ffs.h" 67#include "opt_ffs.h"
68#include "opt_quota.h" 68#include "opt_quota.h"
69#include "opt_wapbl.h" 69#include "opt_wapbl.h"
70#endif 70#endif
71 71
72#include <sys/param.h> 72#include <sys/param.h>
73#include <sys/systm.h> 73#include <sys/systm.h>
74#include <sys/namei.h> 74#include <sys/namei.h>
75#include <sys/proc.h> 75#include <sys/proc.h>
76#include <sys/kernel.h> 76#include <sys/kernel.h>
77#include <sys/vnode.h> 77#include <sys/vnode.h>
@@ -673,27 +673,28 @@ ffs_mount(struct mount *mp, const char * @@ -673,27 +673,28 @@ ffs_mount(struct mount *mp, const char *
673 */ 673 */
674#ifndef QUOTA2 674#ifndef QUOTA2
675 if (fs->fs_flags & FS_DOQUOTA2) { 675 if (fs->fs_flags & FS_DOQUOTA2) {
676 ump->um_flags |= UFS_QUOTA2; 676 ump->um_flags |= UFS_QUOTA2;
677 uprintf("%s: options QUOTA2 not enabled%s\n", 677 uprintf("%s: options QUOTA2 not enabled%s\n",
678 mp->mnt_stat.f_mntonname, 678 mp->mnt_stat.f_mntonname,
679 (mp->mnt_flag & MNT_FORCE) ? "" : 679 (mp->mnt_flag & MNT_FORCE) ? "" :
680 ", not mounting"); 680 ", not mounting");
681 DPRINTF("ffs_quota2 %d", EINVAL); 681 DPRINTF("ffs_quota2 %d", EINVAL);
682 return EINVAL; 682 return EINVAL;
683 } 683 }
684#endif 684#endif
685 fs->fs_ronly = 0; 685 fs->fs_ronly = 0;
686 fs->fs_clean <<= 1; 686 fs->fs_clean =
 687 fs->fs_clean == FS_ISCLEAN ? FS_WASCLEAN : 0;
687 fs->fs_fmod = 1; 688 fs->fs_fmod = 1;
688#ifdef WAPBL 689#ifdef WAPBL
689 if (fs->fs_flags & FS_DOWAPBL) { 690 if (fs->fs_flags & FS_DOWAPBL) {
690 const char *nm = mp->mnt_stat.f_mntonname; 691 const char *nm = mp->mnt_stat.f_mntonname;
691 if (!mp->mnt_wapbl_replay) { 692 if (!mp->mnt_wapbl_replay) {
692 printf("%s: log corrupted;" 693 printf("%s: log corrupted;"
693 " replay cancelled\n", nm); 694 " replay cancelled\n", nm);
694 return EFTYPE; 695 return EFTYPE;
695 } 696 }
696 printf("%s: replaying log to disk\n", nm); 697 printf("%s: replaying log to disk\n", nm);
697 error = wapbl_replay_write(mp->mnt_wapbl_replay, 698 error = wapbl_replay_write(mp->mnt_wapbl_replay,
698 devvp); 699 devvp);
699 if (error) { 700 if (error) {
@@ -733,40 +734,42 @@ ffs_mount(struct mount *mp, const char * @@ -733,40 +734,42 @@ ffs_mount(struct mount *mp, const char *
733 if (args->fspec == NULL) 734 if (args->fspec == NULL)
734 return 0; 735 return 0;
735 } 736 }
736 737
737 error = set_statvfs_info(path, UIO_USERSPACE, args->fspec, 738 error = set_statvfs_info(path, UIO_USERSPACE, args->fspec,
738 UIO_USERSPACE, mp->mnt_op->vfs_name, mp, l); 739 UIO_USERSPACE, mp->mnt_op->vfs_name, mp, l);
739 if (error == 0) 740 if (error == 0)
740 (void)strncpy(fs->fs_fsmnt, mp->mnt_stat.f_mntonname, 741 (void)strncpy(fs->fs_fsmnt, mp->mnt_stat.f_mntonname,
741 sizeof(fs->fs_fsmnt)); 742 sizeof(fs->fs_fsmnt));
742 else { 743 else {
743 DPRINTF("set_statvfs_info returned %d", error); 744 DPRINTF("set_statvfs_info returned %d", error);
744 } 745 }
745 fs->fs_flags &= ~FS_DOSOFTDEP; 746 fs->fs_flags &= ~FS_DOSOFTDEP;
746 if (fs->fs_fmod != 0) { /* XXX */ 747
 748 if ((fs->fs_ronly && (fs->fs_clean & FS_ISCLEAN) == 0) ||
 749 (!fs->fs_ronly && (fs->fs_clean & FS_WASCLEAN) == 0)) {
 750 printf("%s: file system not clean (fs_clean=%#x); "
 751 "please fsck(8)\n", mp->mnt_stat.f_mntfromname,
 752 fs->fs_clean);
 753 }
 754
 755 if (fs->fs_fmod != 0) {
747 int err; 756 int err;
748 757
749 fs->fs_fmod = 0; 758 KASSERT(!fs->fs_ronly);
 759
750 if (fs->fs_clean & FS_WASCLEAN) 760 if (fs->fs_clean & FS_WASCLEAN)
751 fs->fs_time = time_second; 761 fs->fs_time = time_second;
752 else { 762 fs->fs_fmod = 0;
753 printf("%s: file system not clean (fs_clean=%#x); " 
754 "please fsck(8)\n", mp->mnt_stat.f_mntfromname, 
755 fs->fs_clean); 
756 printf("%s: lost blocks %" PRId64 " files %d\n", 
757 mp->mnt_stat.f_mntfromname, fs->fs_pendingblocks, 
758 fs->fs_pendinginodes); 
759 } 
760 err = UFS_WAPBL_BEGIN(mp); 763 err = UFS_WAPBL_BEGIN(mp);
761 if (err == 0) { 764 if (err == 0) {
762 (void) ffs_cgupdate(ump, MNT_WAIT); 765 (void) ffs_cgupdate(ump, MNT_WAIT);
763 UFS_WAPBL_END(mp); 766 UFS_WAPBL_END(mp);
764 } 767 }
765 } 768 }
766 if ((mp->mnt_flag & MNT_SOFTDEP) != 0) { 769 if ((mp->mnt_flag & MNT_SOFTDEP) != 0) {
767 printf("%s: `-o softdep' is no longer supported, " 770 printf("%s: `-o softdep' is no longer supported, "
768 "consider `-o log'\n", mp->mnt_stat.f_mntfromname); 771 "consider `-o log'\n", mp->mnt_stat.f_mntfromname);
769 mp->mnt_flag &= ~MNT_SOFTDEP; 772 mp->mnt_flag &= ~MNT_SOFTDEP;
770 } 773 }
771 774
772 return (error); 775 return (error);
@@ -1336,26 +1339,27 @@ ffs_mountfs(struct vnode *devvp, struct  @@ -1336,26 +1339,27 @@ ffs_mountfs(struct vnode *devvp, struct
1336 ump->um_maxfilesize = fs->fs_maxfilesize; 1339 ump->um_maxfilesize = fs->fs_maxfilesize;
1337 1340
1338 if (fs->fs_flags & ~(FS_KNOWN_FLAGS | FS_INTERNAL)) { 1341 if (fs->fs_flags & ~(FS_KNOWN_FLAGS | FS_INTERNAL)) {
1339 uprintf("%s: unknown ufs flags: 0x%08"PRIx32"%s\n", 1342 uprintf("%s: unknown ufs flags: 0x%08"PRIx32"%s\n",
1340 mp->mnt_stat.f_mntonname, fs->fs_flags, 1343 mp->mnt_stat.f_mntonname, fs->fs_flags,
1341 (mp->mnt_flag & MNT_FORCE) ? "" : ", not mounting"); 1344 (mp->mnt_flag & MNT_FORCE) ? "" : ", not mounting");
1342 if ((mp->mnt_flag & MNT_FORCE) == 0) { 1345 if ((mp->mnt_flag & MNT_FORCE) == 0) {
1343 error = EINVAL; 1346 error = EINVAL;
1344 DPRINTF("no force %d", error); 1347 DPRINTF("no force %d", error);
1345 goto out; 1348 goto out;
1346 } 1349 }
1347 } 1350 }
1348 1351
 1352 fs->fs_fmod = 0;
1349 if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) { 1353 if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
1350 fs->fs_pendingblocks = 0; 1354 fs->fs_pendingblocks = 0;
1351 fs->fs_pendinginodes = 0; 1355 fs->fs_pendinginodes = 0;
1352 } 1356 }
1353 1357
1354 ump->um_fstype = fstype; 1358 ump->um_fstype = fstype;
1355 if (fs->fs_sbsize < SBLOCKSIZE) 1359 if (fs->fs_sbsize < SBLOCKSIZE)
1356 brelse(bp, BC_INVAL); 1360 brelse(bp, BC_INVAL);
1357 else 1361 else
1358 brelse(bp, 0); 1362 brelse(bp, 0);
1359 bp = NULL; 1363 bp = NULL;
1360 1364
1361 if (ffs_is_appleufs(devvp, fs)) { 1365 if (ffs_is_appleufs(devvp, fs)) {
@@ -1417,27 +1421,28 @@ ffs_mountfs(struct vnode *devvp, struct  @@ -1417,27 +1421,28 @@ ffs_mountfs(struct vnode *devvp, struct
1417 fs->fs_fsize); 1421 fs->fs_fsize);
1418 error = EINVAL; 1422 error = EINVAL;
1419 bset = BC_INVAL; 1423 bset = BC_INVAL;
1420 goto out; 1424 goto out;
1421 } 1425 }
1422 brelse(bp, BC_INVAL); 1426 brelse(bp, BC_INVAL);
1423 bp = NULL; 1427 bp = NULL;
1424 } 1428 }
1425 1429
1426 fs->fs_ronly = ronly; 1430 fs->fs_ronly = ronly;
1427 /* Don't bump fs_clean if we're replaying journal */ 1431 /* Don't bump fs_clean if we're replaying journal */
1428 if (!((fs->fs_flags & FS_DOWAPBL) && (fs->fs_clean & FS_WASCLEAN))) { 1432 if (!((fs->fs_flags & FS_DOWAPBL) && (fs->fs_clean & FS_WASCLEAN))) {
1429 if (ronly == 0) { 1433 if (ronly == 0) {
1430 fs->fs_clean <<= 1; 1434 fs->fs_clean =
 1435 fs->fs_clean == FS_ISCLEAN ? FS_WASCLEAN : 0;
1431 fs->fs_fmod = 1; 1436 fs->fs_fmod = 1;
1432 } 1437 }
1433 } 1438 }
1434 1439
1435 bsize = fs->fs_cssize; 1440 bsize = fs->fs_cssize;
1436 blks = howmany(bsize, fs->fs_fsize); 1441 blks = howmany(bsize, fs->fs_fsize);
1437 if (fs->fs_contigsumsize > 0) 1442 if (fs->fs_contigsumsize > 0)
1438 bsize += fs->fs_ncg * sizeof(int32_t); 1443 bsize += fs->fs_ncg * sizeof(int32_t);
1439 bsize += fs->fs_ncg * sizeof(*fs->fs_contigdirs); 1444 bsize += fs->fs_ncg * sizeof(*fs->fs_contigdirs);
1440 allocsbsize = bsize; 1445 allocsbsize = bsize;
1441 space = kmem_alloc((u_long)allocsbsize, KM_SLEEP); 1446 space = kmem_alloc((u_long)allocsbsize, KM_SLEEP);
1442 fs->fs_csp = space; 1447 fs->fs_csp = space;
1443 1448