Subject: kern/11470: fsck_lfs doesn't check or fix bad dirty/clean LFS segment count
To: None <gnats-bugs@gnats.netbsd.org>
From: None <joff@gci-net.com>
List: netbsd-bugs
Date: 11/11/2000 22:19:17
>Number: 11470
>Category: kern
>Synopsis: fsck_lfs doesn't check or fix bad dirty/clean LFS segment count
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: kern-bug-people
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Sat Nov 11 22:19:01 PST 2000
>Closed-Date:
>Last-Modified:
>Originator: Jesse Off
>Release: 1.5BETA
>Organization:
>Environment:
NetBSD construct.home 1.5_BETA NetBSD 1.5_BETA (CONSTRUCT) #9: Sat Nov 11 21:36:11 MST 2000 joff@construct.home:/usr/src/sys/arch/i386/compile/CONSTRUCT i386
>Description:
I recently found out that the source of some of my problems in LFS were
due to the fact that the nclean member of the superblock and cleanerinfo
block were wrong on my FS. I don't know how my FS became corrupted in
this way, but I'm sure it had to do with some of my past
testing and may not be any fault of LFS. Anyway, it would have been nice
if fsck_lfs could have detected and fixed this.
The problem shows up as an abnormally higher than actual number of free
space returned from a 'df'. It also is apparent if you
dumplfs and count dirty/clean segments in the segment summary section.
Somehow, my filesystem with 299 segments was listing 101 segments clean
when in fact there were only 71.
>How-To-Repeat:
Not quite sure how my FS got this way, but I suppose you could take
a hexeditor on the superblock to make nclean wrong and then do
a df and fsck_lfs and see that it does not fix or detect the problem.
>Fix:
I've included a few patches here:
1) change to pass5.c for fsck_lfs that warns and gives the option
to fix nclean if it detects that it is wrong
2) chang to sys/ufs/lfs/lfs_vfsops.c that reinitializes the cleanerinfo
block on mount according to information its found in the superblock.
3) change to /usr/sbin/dumplfs to display the nclean and minfreeseg in
the superblock and also the clean, dirty, avail, and bfree counts
found in the cleanerinfo block. (was useful during debugging, but
somewhat unrelated to the fix)
#1
===================================================================
RCS file: /cvsroot/basesrc/sbin/fsck_lfs/pass5.c,v
retrieving revision 1.5.2.1
diff -u -r1.5.2.1 pass5.c
--- pass5.c 2000/09/14 18:53:21 1.5.2.1
+++ pass5.c 2000/11/12 06:10:38
@@ -59,11 +59,13 @@
unsigned long bb; /* total number of used blocks (lower bound) */
unsigned long ubb; /* upper bound number of used blocks */
unsigned long avail; /* blocks available for writing */
+ int nclean; /* clean segments */
/*
* Check segment holdings against actual holdings. Check for
* "clean" segments that contain live data.
*/
+ nclean = 0;
avail = 0;
bb = ubb = 0;
for (i = 0; i < sblock.lfs_nseg; i++) {
@@ -96,6 +98,7 @@
bb += btodb(su->su_nbytes) + su->su_nsums;
ubb += btodb(su->su_nbytes) + su->su_nsums + fsbtodb(&sblock, su->su_ninos);
} else {
+ nclean++;
avail += fsbtodb(&sblock, sblock.lfs_ssize);
if (su->su_flags & SEGUSE_SUPERBLOCK)
avail -= btodb(LFS_SBPAD);
@@ -117,6 +120,15 @@
sbdirty();
}
}
+ if (nclean != sblock.lfs_nclean) {
+ pwarn("nclean given as %d, should be %d\n", sblock.lfs_nclean,
+ nclean);
+ if (preen || reply("fix")) {
+ sblock.lfs_nclean = nclean;
+ sbdirty();
+ }
+ }
+
if (sblock.lfs_bfree > sblock.lfs_dsize - bb ||
sblock.lfs_bfree < sblock.lfs_dsize - ubb) {
pwarn("bfree given as %d, should be between %ld and %ld\n",
#2
Index: lfs_vfsops.c
===================================================================
RCS file: /cvsroot/syssrc/sys/ufs/lfs/lfs_vfsops.c,v
retrieving revision 1.52.4.2
diff -u -r1.52.4.2 lfs_vfsops.c
--- lfs_vfsops.c 2000/09/14 18:50:20 1.52.4.2
+++ lfs_vfsops.c 2000/11/12 06:11:57
@@ -339,7 +339,8 @@
dev_t dev;
int error, i, ronly, size;
struct ucred *cred;
- SEGUSE *sup;
+ CLEANERINFO *cip;
+ SEGUSE *sup;
cred = p ? p->p_ucred : NOCRED;
/*
@@ -475,6 +476,17 @@
fs->lfs_ivnode = vp;
VREF(vp);
vput(vp);
+
+ /*
+ * Initialize the ifile cleaner info with information from
+ * the superblock.
+ */
+ LFS_CLEANERINFO(cip, fs, bp);
+ cip->clean = fs->lfs_nclean;
+ cip->dirty = fs->lfs_nseg - fs->lfs_nclean;
+ cip->avail = fs->lfs_avail;
+ cip->bfree = fs->lfs_bfree;
+ (void) VOP_BWRITE(bp);
/*
* Mark the current segment as ACTIVE, since we're going to
#3
Index: dumplfs.c
===================================================================
RCS file: /cvsroot/basesrc/usr.sbin/dumplfs/dumplfs.c,v
retrieving revision 1.14.2.1
diff -u -r1.14.2.1 dumplfs.c
--- dumplfs.c 2000/08/28 05:52:34 1.14.2.1
+++ dumplfs.c 2000/11/12 06:13:02
@@ -606,6 +606,10 @@
"cksum ", lfsp->lfs_cksum,
"maxfilesize ", (long long)lfsp->lfs_maxfilesize);
+ (void)printf("%s%d\t%s%d\n",
+ "nclean ", lfsp->lfs_nclean,
+ "minfreeseg ", lfsp->lfs_minfreeseg);
+
(void)printf("Superblock disk addresses:\t");
for (i = 0; i < LFS_MAXNUMSB; i++) {
(void)printf(" 0x%x", lfsp->lfs_sboffs[i]);
@@ -667,8 +671,11 @@
CLEANERINFO *cip;
cip = (CLEANERINFO *)ipage;
- (void)printf("segments clean\t%d\tsegments dirty\t%d\n\n",
+ (void)printf("segments clean\t%d\tsegments dirty\t%d\n",
cip->clean, cip->dirty);
+ (void)printf("avail\t%d\tbfree\t%d\n\n",
+ cip->avail, cip->bfree);
+
}
static void
>Release-Note:
>Audit-Trail:
>Unformatted: