Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 6 Nov 2003 09:43:34 -0800
From:      Wes Peters <wes@softweyr.com>
To:        Peter Jeremy <PeterJeremy@optushome.com.au>, kirk@mckusick.com
Cc:        arch@freebsd.org
Subject:   Re: newfs and mount vs. half-baked disks
Message-ID:  <200311060943.34284.wes@softweyr.com>
In-Reply-To: <20031105081516.GA38016@cirb503493.alcatel.com.au>
References:  <200311041737.20467.wes@softweyr.com> <20031105015709.GC28915@dan.emsphone.com> <20031105081516.GA38016@cirb503493.alcatel.com.au>

next in thread | previous in thread | raw e-mail | index | archive | help

--Boundary-00=_Ghoq/V8Jqd8uEZp
Content-Type: text/plain;
  charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

On Wednesday 05 November 2003 00:15, Peter Jeremy wrote:
> On Tue, Nov 04, 2003 at 07:57:10PM -0600, Dan Nelson wrote:
> >In the last episode (Nov 04), Wes Peters said:
> >> I emailed Kirk about this state of affairs and he confirmed that
> >> newfs was developed with operator intervention in mind.  He
> >> suggested employing one of the unused flags in the filesystem
> >> header as a 'consistent' flag, setting it to 'not consistent' at
> >> the beginning of newfs, and then updating to 'is consistent' at
> >> the end.  The performance hit in updating all superblock copies at
> >> the end is small but noticable (< 1s on a rather slow 6GB
> >> filesystem).
> >
> >Would writing a block of zeros to the first (or first n) superblock,
> >newfs'ing, then rewriting the correct data do the same thing without
> >affecting the filesystem itself?  I'm thinking about 4.x and
> > cross-OS portability here.
>
> My suggestion would be to write a non-standard magic number to
> fs_magic in the primary and first backup superblock (block 32) - I
> believe these are the only ones fsck will automatically search.  The
> "invalid" magic number means that neither mount nor fsck will
> recognize the partition.  Those two blocks can be re-written at the
> end - the additional time should be unnoticable.  The remaining
> superblocks would appear valid but if someone is silly enough to
> manually specify a alternate superblock in an incompletely newfs'd
> filesystem, they get a neat hole in their foot.  (A known
> non-standard magic number would also allow fsck to warn that the
> filesystem was incompletely newfs'd).
>
> I'm surprised that this bug hasn't been noticed previously.

I found an unused field called "fs_state" and used that, as Kirk 
suggested.  Here's the new patch, which changes fsck to notice the 
fs_state and doesn't require re-writing all of the superblocks.

This patch adds a -E (generate errors) option to fsck, causing fsck to 
exit at various stages or to otherwise leave the state of fs_state and 
fs_clean in other than pristine conditions.  I will, of course, commit 
the -E changes separately from the fs_state changes.

Thanks in advance for reviewing.  And yes, I did manage to attach the 
patch this time.  Doh!

-- 
         "Where am I, and what am I doing in this handbasket?"

Wes Peters                                              wes@softweyr.com


--Boundary-00=_Ghoq/V8Jqd8uEZp
Content-Type: text/x-diff;
  charset="iso-8859-1";
  name="fs_state.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="fs_state.patch"

--- sys/ufs/ffs/ffs_vfsops.c.orig	Tue Oct 14 12:23:07 2003
+++ sys/ufs/ffs/ffs_vfsops.c	Tue Oct 14 12:43:59 2003
@@ -654,6 +654,12 @@
 	fs->fs_fmod = 0;
 	fs->fs_flags &= ~FS_INDEXDIRS;	/* no support for directory indicies */
 	fs->fs_flags &= ~FS_UNCLEAN;
+	if (fs->fs_state != 0) {
+		printf(
+"WARNING: Filesystem on %s is incomplete, rerun newfs.\n", fs->fs_fsmnt);
+		error = EINVAL;
+		goto out;
+	}
 	if (fs->fs_clean == 0) {
 		fs->fs_flags |= FS_UNCLEAN;
 		if (ronly || (mp->mnt_flag & MNT_FORCE) ||
--- lib/libc/sys/mount.2.orig	Tue Oct 14 12:40:33 2003
+++ lib/libc/sys/mount.2	Tue Oct 14 12:41:10 2003
@@ -242,7 +242,7 @@
 No space remains in the mount table.
 .It Bq Er EINVAL
 The super block for the file system had a bad magic
-number or an out of range block size.
+number or an out of range block size, or was incomplete.
 .It Bq Er ENOMEM
 Not enough memory was available to read the cylinder
 group information for the file system.
--- sbin/newfs/newfs.h.orig	Tue Nov  4 16:27:31 2003
+++ sbin/newfs/newfs.h	Tue Nov  4 16:27:56 2003
@@ -52,6 +52,7 @@
 extern int	Oflag;		/* build UFS1 format file system */
 extern int	Rflag;		/* regression test */
 extern int	Uflag;		/* enable soft updates for file system */
+extern int	ErrorFlag;	/* exit as if error, for testing */
 extern quad_t	fssize;		/* file system size */
 extern int	sectorsize;	/* bytes/sector */
 extern int	realsectorsize;	/* bytes/sector in hardware*/
--- sbin/newfs/newfs.c.orig	Tue Nov  4 16:20:42 2003
+++ sbin/newfs/newfs.c	Tue Nov  4 16:27:02 2003
@@ -119,6 +119,7 @@
 int	Oflag = 2;		/* file system format (1 => UFS1, 2 => UFS2) */
 int	Rflag;			/* regression test */
 int	Uflag;			/* enable soft updates for file system */
+int	ErrorFlag = 0;		/* exit in middle of newfs for testing */
 quad_t	fssize;			/* file system size */
 int	sectorsize;		/* bytes/sector */
 int	realsectorsize;		/* bytes/sector in hardware */
@@ -156,8 +157,11 @@
 	off_t mediasize;
 
 	while ((ch = getopt(argc, argv,
-	    "L:NO:RS:T:Ua:b:c:d:e:f:g:h:i:m:o:s:")) != -1)
+	    "EL:NO:RS:T:Ua:b:c:d:e:f:g:h:i:m:o:s:")) != -1)
 		switch (ch) {
+		case 'E':
+			ErrorFlag++;
+			break;
 		case 'L':
 			volumelabel = optarg;
 			i = -1;
--- sbin/newfs/mkfs.c.orig	Tue Oct 14 13:53:55 2003
+++ sbin/newfs/mkfs.c	Thu Nov  6 09:01:02 2003
@@ -388,8 +388,8 @@
 	sblock.fs_pendinginodes = 0;
 	sblock.fs_fmod = 0;
 	sblock.fs_ronly = 0;
-	sblock.fs_state = 0;
-	sblock.fs_clean = 1;
+	sblock.fs_state = 0xdeadbeef;
+	sblock.fs_clean = 0;
 	sblock.fs_id[0] = (long)utime;
 	sblock.fs_id[1] = newfs_random();
 	sblock.fs_fsmnt[0] = '\0';
@@ -448,11 +448,27 @@
 	                    chdummy, SBLOCKSIZE);
 		}
 	}
+	if (!Nflag)
+		sbwrite(&disk, 0);
+	if (ErrorFlag == 1) {
+		printf("** Exiting on ErrorFlag 1\n");
+		exit(0);
+	}
 
 	/*
 	 * Now build the cylinders group blocks and
 	 * then print out indices of cylinder groups.
-	 */
+	 * The superblock backups in the cylinder groups
+	 * are created clean & stable so we don't have
+	 * to make another pass cleaning them up.
+	 */
+	if (ErrorFlag == 5)
+		printf("** Leaving superblock backups dirty on ErrorFlag 5\n");
+	else {
+		sblock.fs_state = 0;
+		sblock.fs_clean = 1;
+	}
+
 	printf("super-block backups (for fsck -b #) at:\n");
 	i = 0;
 	width = charsperline();
@@ -492,6 +508,10 @@
 	printf("\n");
 	if (Nflag)
 		exit(0);
+	if (ErrorFlag == 2) {
+		printf("** Exiting on ErrorFlag 2\n");
+		exit(0);
+	}
 	/*
 	 * Now construct the initial file system,
 	 * then write out the super-block.
@@ -503,6 +523,22 @@
 		sblock.fs_old_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree;
 		sblock.fs_old_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree;
 	}
+
+	/*
+	 * Update the primary superblock setting the state to
+	 * consistent and clean (unless the user told us not to).
+	 */
+	if (ErrorFlag == 3) {
+		printf("** Not clean on ErrorFlag 3\n");
+		sblock.fs_clean = 0;
+	} else if (ErrorFlag == 4) {
+		printf("** Not stable on ErrorFlag 4\n");
+		sblock.fs_state = 0xdeadface;
+	} else {
+		sblock.fs_state = 0;
+		sblock.fs_clean = 1;
+	}
+
 	if (!Nflag)
 		sbwrite(&disk, 0);
 	for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize)
--- sbin/fsck_ffs/setup.c.orig	Wed Nov  5 15:50:12 2003
+++ sbin/fsck_ffs/setup.c	Thu Nov  6 08:36:58 2003
@@ -307,6 +307,11 @@
 			    bflag);
 			return (0);
 		}
+		if (sblock.fs_state != 0) {
+			fprintf(stderr, "superblock %d is not finished\n",
+			    bflag);
+			return (0);
+		}
 	} else {
 		for (i = 0; sblock_try[i] != -1; i++) {
 			super = sblock_try[i] / dev_bsize;
@@ -317,9 +322,11 @@
 			     (sblock.fs_magic == FS_UFS2_MAGIC &&
 			      sblock.fs_sblockloc == sblock_try[i])) &&
 			    sblock.fs_ncg >= 1 &&
+			    sblock.fs_state == 0 &&
 			    sblock.fs_bsize >= MINBSIZE &&
-			    sblock.fs_bsize >= sizeof(struct fs))
+			    sblock.fs_bsize >= sizeof(struct fs)) {
 				break;
+			}
 		}
 		if (sblock_try[i] == -1) {
 			fprintf(stderr, "Cannot find file system superblock\n");

--Boundary-00=_Ghoq/V8Jqd8uEZp--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200311060943.34284.wes>