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
[-- Attachment #1 --]
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
[-- Attachment #2 --]
--- 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");
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200311060943.34284.wes>
