svn commit: r212839 - in head: sbin/growfs tools/regression/sbin tools/regression/sbin/growfs

Brian Somers brian at FreeBSD.org
Sun Sep 19 08:18:56 UTC 2010


Author: brian
Date: Sun Sep 19 08:18:56 2010
New Revision: 212839
URL: http://svn.freebsd.org/changeset/base/212839

Log:
  Revise r197763 which fixes filesystem corruption when extending
  into un-zeroed storage.
  
  The original patch was questioned by Kirk as it forces the filesystem
  to do excessive work initialising inodes on first use, and was never
  MFC'd.  This change mimics the newfs(8) approach of zeroing two
  blocks of inodes for each new cylinder group.
  
  Reviewed by:	mckusick
  MFC after:	3 weeks

Added:
  head/tools/regression/sbin/
  head/tools/regression/sbin/Makefile   (contents, props changed)
  head/tools/regression/sbin/growfs/
  head/tools/regression/sbin/growfs/Makefile   (contents, props changed)
  head/tools/regression/sbin/growfs/regress.t   (contents, props changed)
Modified:
  head/sbin/growfs/growfs.c

Modified: head/sbin/growfs/growfs.c
==============================================================================
--- head/sbin/growfs/growfs.c	Sun Sep 19 05:42:29 2010	(r212838)
+++ head/sbin/growfs/growfs.c	Sun Sep 19 08:18:56 2010	(r212839)
@@ -371,16 +371,16 @@ static void
 initcg(int cylno, time_t utime, int fso, unsigned int Nflag)
 {
 	DBG_FUNC("initcg")
-	static void *iobuf;
+	static caddr_t iobuf;
 	long blkno, start;
 	ufs2_daddr_t i, cbase, dmax;
 	struct ufs1_dinode *dp1;
 	struct csum *cs;
 	uint d, dupper, dlower;
 
-	if (iobuf == NULL && (iobuf = malloc(sblock.fs_bsize)) == NULL) {
+	if (iobuf == NULL && (iobuf = malloc(sblock.fs_bsize * 3)) == NULL)
 		errx(37, "panic: cannot allocate I/O buffer");
-	}
+
 	/*
 	 * Determine block bounds for cylinder group.
 	 * Allow space for super block summary information in first
@@ -396,17 +396,12 @@ initcg(int cylno, time_t utime, int fso,
 		dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
 	cs = &fscs[cylno];
 	memset(&acg, 0, sblock.fs_cgsize);
-	/*
-	 * Note that we do not set cg_initediblk at all.
-	 * In this extension of a previous filesystem
-	 * we have no inodes initialized for the cylinder
-	 * group at all. The first access to that cylinder
-	 * group will do the correct initialization.
-	 */
 	acg.cg_time = utime;
 	acg.cg_magic = CG_MAGIC;
 	acg.cg_cgx = cylno;
 	acg.cg_niblk = sblock.fs_ipg;
+	acg.cg_initediblk = sblock.fs_ipg < 2 * INOPB(&sblock) ?
+	    sblock.fs_ipg : 2 * INOPB(&sblock);
 	acg.cg_ndblk = dmax - cbase;
 	if (sblock.fs_contigsumsize > 0)
 		acg.cg_nclusterblks = acg.cg_ndblk / sblock.fs_frag;
@@ -419,6 +414,7 @@ initcg(int cylno, time_t utime, int fso,
 		acg.cg_time = 0;
 		acg.cg_old_niblk = acg.cg_niblk;
 		acg.cg_niblk = 0;
+		acg.cg_initediblk = 0;
 		acg.cg_old_btotoff = start;
 		acg.cg_old_boff = acg.cg_old_btotoff +
 		    sblock.fs_old_cpg * sizeof(int32_t);
@@ -538,11 +534,14 @@ initcg(int cylno, time_t utime, int fso,
 	sblock.fs_cstotal.cs_nbfree += acg.cg_cs.cs_nbfree;
 	sblock.fs_cstotal.cs_nifree += acg.cg_cs.cs_nifree;
 	*cs = acg.cg_cs;
+
+	memcpy(iobuf, &acg, sblock.fs_cgsize);
+	memset(iobuf + sblock.fs_cgsize, '\0',
+	    sblock.fs_bsize * 3 - sblock.fs_cgsize);
+
 	wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)),
-		sblock.fs_bsize, (char *)&acg, fso, Nflag);
-	DBG_DUMP_CG(&sblock,
-	    "new cg",
-	    &acg);
+	    sblock.fs_bsize * 3, iobuf, fso, Nflag);
+	DBG_DUMP_CG(&sblock, "new cg", &acg);
 
 	DBG_LEAVE;
 	return;

Added: head/tools/regression/sbin/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/regression/sbin/Makefile	Sun Sep 19 08:18:56 2010	(r212839)
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+SUBDIR=	growfs
+
+.include <bsd.subdir.mk>

Added: head/tools/regression/sbin/growfs/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/regression/sbin/growfs/Makefile	Sun Sep 19 08:18:56 2010	(r212839)
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+all test:
+	prove -vmw regress.t
+
+clean:

Added: head/tools/regression/sbin/growfs/regress.t
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/regression/sbin/growfs/regress.t	Sun Sep 19 08:18:56 2010	(r212839)
@@ -0,0 +1,91 @@
+#! /usr/bin/perl
+#
+# $FreeBSD$
+
+use strict;
+use warnings;
+use Test::More tests => 19;
+use Fcntl qw(:DEFAULT :seek);
+
+use constant BLK => 512;
+use constant BLKS_PER_MB => 2048;
+
+my $unit;
+END { system "mdconfig -du$unit" if defined $unit };
+
+sub setsize {
+    my ($partszMB, $unitszMB) = @_;
+
+    open my $fd, "|-", "disklabel -R md$unit /dev/stdin" or die;
+    print $fd "a: ", ($partszMB * BLKS_PER_MB), " 0 4.2BSD 1024 8192\n";
+    print $fd "c: ", ($unitszMB * BLKS_PER_MB), " 0 unused 0 0\n";
+    close $fd;
+}
+
+sub fill {
+    my ($start, $size, $content) = @_;
+
+    my $content512 = $content x (int(512 / length $content) + 1);
+    substr($content512, 512) = "";
+    sysopen my $fd, "/dev/md$unit", O_RDWR or die "/dev/md$unit: $!";
+    seek($fd, $start * BLK, SEEK_SET);
+    while ($size) {
+	syswrite($fd, $content512) == 512 or die "write: $!";
+	$size--;
+    }
+}
+
+SKIP: {
+    skip "Cannot test without UID 0", 19 if $<;
+
+    chomp(my $md = `mdconfig -s40m`);
+    like($md, qr/^md\d+$/, "Created $md with size 40m") or die;
+    $unit = substr $md, 2;
+
+    for my $type (1..2) {
+
+	initialise: {
+	    ok(setsize(10, 40), "Sized ${md}a to 10m");
+	    system "newfs -O $type -U ${md}a >/dev/null";
+	    is($?, 0, "Initialised the filesystem on ${md}a as UFS$type");
+	    chomp(my @out = `fsck -tufs -y ${md}a`);
+	    ok(!grep(/MODIFIED/, @out), "fsck says ${md}a is clean, " .
+		scalar(@out) . " lines of output");
+	}
+
+	extend20_zeroed: {
+	    ok(setsize(20, 40), "Sized ${md}a to 20m");
+	    diag "Filling the extent with zeros";
+	    fill(10 * BLKS_PER_MB, 10 * BLKS_PER_MB, chr(0));
+	    my $out = `growfs -y ${md}a`;
+	    is($?, 0, "Extended the filesystem on ${md}a") or print $out;
+
+	    my ($unallocated) = $out =~ m{\d+ sectors cannot be allocated};
+	    fill(30 * BLKS_PER_MB - $unallocated, $unallocated, chr(0))
+		if $unallocated;
+
+	    chomp(my @out = `fsck -tufs -y ${md}a`);
+	    ok(!grep(/MODIFIED/, @out), "fsck says ${md}a is clean, " .
+		scalar(@out) . " lines of output");
+	}
+
+	extend30_garbaged: {
+	    ok(setsize(30, 40), "Sized ${md}a to 30m");
+	    diag "Filling the extent with garbage";
+	    fill(20 * BLKS_PER_MB, 10 * BLKS_PER_MB, chr(0xaa) . chr(0x55));
+	    my $out = `growfs -y ${md}a`;
+	    is($?, 0, "Extended the filesystem on ${md}a") or print $out;
+
+	    my ($unallocated) = $out =~ m{\d+ sectors cannot be allocated};
+	    fill(30 * BLKS_PER_MB - $unallocated, $unallocated, chr(0))
+		if $unallocated;
+
+	    chomp(my @out = `fsck -tufs -y ${md}a`);
+	    ok(!grep(/MODIFIED/, @out), "fsck says ${md}a is clean, " .
+		scalar(@out) . " lines of output");
+	}
+    }
+
+    system "mdconfig -du$unit";
+    undef $unit;
+}


More information about the svn-src-all mailing list