diff --git a/sbin/growfs/growfs.c b/sbin/growfs/growfs.c index 5e950fccd112..bce4d59adc1c 100644 --- a/sbin/growfs/growfs.c +++ b/sbin/growfs/growfs.c @@ -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, unsigned int Nflag) 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, unsigned int Nflag) 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, unsigned int Nflag) 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; diff --git a/tools/regression/sbin/Makefile b/tools/regression/sbin/Makefile new file mode 100644 index 000000000000..33d158e7d022 --- /dev/null +++ b/tools/regression/sbin/Makefile @@ -0,0 +1,5 @@ +# $FreeBSD$ + +SUBDIR= growfs + +.include diff --git a/tools/regression/sbin/growfs/Makefile b/tools/regression/sbin/growfs/Makefile new file mode 100644 index 000000000000..dc9fa6771f24 --- /dev/null +++ b/tools/regression/sbin/growfs/Makefile @@ -0,0 +1,6 @@ +# $FreeBSD$ + +all test: + prove -vmw regress.t + +clean: diff --git a/tools/regression/sbin/growfs/regress.t b/tools/regression/sbin/growfs/regress.t new file mode 100755 index 000000000000..9dbdd8523970 --- /dev/null +++ b/tools/regression/sbin/growfs/regress.t @@ -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; +}