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>