[Cluster-devel] [libgfs2 PATCH] libgfs2: Make rg repair do better sanity checks on rindex
Andrew Price
anprice at redhat.com
Fri Jan 13 14:33:57 UTC 2017
Hi Bob,
On 13/01/17 13:40, Bob Peterson wrote:
> Hi,
>
> This patch changes the checks done on the rindex file. Before, if
> the rindex addresses weren't perfectly aligned and equally spaced,
> it considered the rindex not sane. However, in most cases it should
> be sane. Rather than flag this as a violation, I use it to trigger
> a read from disk to see if the rindex really DOES point to an rgrp
> in these cases, and if not, THEN flag the rindex as not sane.
> I also added some basic checks on the rindex values, such as
> checking if the number of bitmaps is sane, and if most of the fields
> have values we'd expect.
>
> Signed-off-by: Bob Peterson <rpeterso at redhat.com>
Thanks for working on this. Unfortunately it makes one of the nukerg
tests fail:
<snip>
Nuking rindex entry 1.
./fsck.at:35: fsck.gfs2 -y $GFS_TGT
stderr:
(level 1 failed: Some damage was found; we need to take remedial measures)
Block #-1 (0xffffffffffffffff) (-17 of 0) is not GFS2_METATYPE_RB.
Attempting to repair the rgrp.
bad read: Invalid argument from rewrite_rg_block:892: block
18446744073709551615 (0xffffffffffffffff) count: 1 size: 4096 ret: -1
<snip>
You can reproduce this with: make check TOPTS='-k fsck' and the log will
be in tests/testsuite.dir/21/testsuite.log
Or, manually, the test is:
$ truncate -s 10G testvol
$ gfs2/mkfs/mkfs.gfs2 -Oplock_nolock testvol
$ tests/nukerg -i 1 testvol
$ gfs2/fsck/fsck.gfs2 -y testvol
$ gfs2/fsck/fsck.gfs2 -n testvol
Andy
> ---
> diff --git a/gfs2/libgfs2/super.c b/gfs2/libgfs2/super.c
> index 81834b3..2983f35 100644
> --- a/gfs2/libgfs2/super.c
> +++ b/gfs2/libgfs2/super.c
> @@ -127,6 +127,59 @@ int read_sb(struct gfs2_sbd *sdp)
> return 0;
> }
>
> +/* rgd_seems_sane - check some general things about the rindex entry
> + *
> + * If rg lengths are not consistent, it's not sane (or it's converted from
> + * gfs1). The first RG will be a different length due to space reserved for
> + * the superblock, so we can't detect this until we check rgrp 3, when we
> + * can compare the distance between rgrp 1 and rgrp 2.
> + *
> + * Returns: 1 if the rgd seems relatively sane
> + */
> +static int rgd_seems_sane(struct gfs2_sbd *sdp, struct rgrp_tree *rgd)
> +{
> + uint32_t most_bitmaps_possible;
> +
> + /* rg length must be at least 1 */
> + if (rgd->ri.ri_length == 0)
> + return 0;
> +
> + /* A max rgrp, 2GB, divided into blocksize, divided by blocks/byte
> + represented in the bitmap, NBBY. Rough approximation only, due to
> + metadata headers. I'm doing the math this way to avoid overflow. */
> + most_bitmaps_possible = (GFS2_MAX_RGSIZE * 1024 * 256) / sdp->bsize;
> + if (rgd->ri.ri_length > most_bitmaps_possible)
> + return 0;
> +
> + if (rgd->ri.ri_data0 != rgd->ri.ri_addr + rgd->ri.ri_length)
> + return 0;
> +
> + if (rgd->ri.ri_bitbytes != rgd->ri.ri_data / GFS2_NBBY)
> + return 0;
> +
> + return 1;
> +}
> +
> +/* good_on_disk - check if the rindex points to what looks like an rgrp on disk
> + *
> + * This is only called when the rindex pointers aren't spaced evenly, which
> + * isn't often. The rindex is pointing to an unexpected location, so we
> + * check if the block it is pointing to is really an rgrp. If so, we count the
> + * rindex entry as "sane" (after all, it did pass the previous checks above.)
> + * If not, we count it as not sane, and therefore, the whole rindex is not to
> + * be trusted by fsck.gfs2.
> + */
> +static int good_on_disk(struct gfs2_sbd *sdp, struct rgrp_tree *rgd)
> +{
> + struct gfs2_buffer_head *bh;
> + int is_rgrp;
> +
> + bh = bread(sdp, rgd->ri.ri_addr);
> + is_rgrp = (gfs2_check_meta(bh, GFS2_METATYPE_RG) == 0);
> + brelse(bh);
> + return is_rgrp;
> +}
> +
> /**
> * rindex_read - read in the rg index file
> * @sdp: the incore superblock pointer
> @@ -182,17 +235,12 @@ int rindex_read(struct gfs2_sbd *sdp, int fd, uint64_t *count1, int *sane)
> if (!sdp->gfs1) {
> if (prev_rgd->start >= rgd->start)
> *sane = 0;
> - /* If rg lengths are not consistent, it's not
> - sane (or it's converted from gfs1). The
> - first RG will be a different length due to
> - space allocated for the superblock, so we
> - can't detect this until we check rgrp 3,
> - when we can compare the distance between
> - rgrp 1 and rgrp 2. */
> - if (rg > 2 && prev_length &&
> + else if (!rgd_seems_sane(sdp, rgd))
> + *sane = 0;
> + else if (rg > 2 && prev_length &&
> prev_length != rgd->start -
> prev_rgd->start)
> - *sane = 0;
> + *sane = good_on_disk(sdp, rgd);
> }
> prev_length = rgd->start - prev_rgd->start;
> prev_rgd->length = rgrp_size(prev_rgd);
>
More information about the Cluster-devel
mailing list