cluster-devel.redhat.com archive mirror
 help / color / mirror / Atom feed
* [Cluster-devel] [PATCH 1/3] libgfs2: New function lgfs2_rindex_read_one()
@ 2016-03-29 11:26 Andrew Price
  2016-03-29 11:26 ` [Cluster-devel] [PATCH 2/3] gfs2-utils tests: Add helper program to damage rgrps Andrew Price
  2016-03-29 11:26 ` [Cluster-devel] [PATCH 3/3] gfs2-utils tests: Add fsck.gfs2 rgrp/rindex repair tests Andrew Price
  0 siblings, 2 replies; 3+ messages in thread
From: Andrew Price @ 2016-03-29 11:26 UTC (permalink / raw)
  To: cluster-devel.redhat.com

Add a simple function to read an rindex entry into a set of resource
groups.

Signed-off-by: Andrew Price <anprice@redhat.com>
---
 gfs2/libgfs2/libgfs2.h |  2 ++
 gfs2/libgfs2/rgrp.c    | 32 ++++++++++++++++++++++++++++++++
 2 files changed, 34 insertions(+)

diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index 7c87884..d6c54b3 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -177,6 +177,7 @@ struct gfs2_bitmap
 };
 
 struct gfs2_sbd;
+struct gfs2_inode;
 typedef struct _lgfs2_rgrps *lgfs2_rgrps_t;
 
 struct rgrp_tree {
@@ -196,6 +197,7 @@ extern lgfs2_rgrps_t lgfs2_rgrps_init(struct gfs2_sbd *sdp, uint64_t align, uint
 extern void lgfs2_rgrps_free(lgfs2_rgrps_t *rgs);
 extern uint64_t lgfs2_rindex_entry_new(lgfs2_rgrps_t rgs, struct gfs2_rindex *entry, uint64_t addr, uint32_t len);
 extern unsigned lgfs2_rindex_read_fd(int fd, lgfs2_rgrps_t rgs);
+extern const struct gfs2_rindex *lgfs2_rindex_read_one(struct gfs2_inode *rip, lgfs2_rgrps_t rgs, unsigned i);
 extern uint64_t lgfs2_rgrp_align_addr(const lgfs2_rgrps_t rgs, uint64_t addr);
 extern uint32_t lgfs2_rgrp_align_len(const lgfs2_rgrps_t rgs, uint32_t len);
 extern unsigned lgfs2_rgsize_for_data(uint64_t blksreq, unsigned bsize);
diff --git a/gfs2/libgfs2/rgrp.c b/gfs2/libgfs2/rgrp.c
index 766bdfc..7066a5c 100644
--- a/gfs2/libgfs2/rgrp.c
+++ b/gfs2/libgfs2/rgrp.c
@@ -430,6 +430,38 @@ unsigned lgfs2_rindex_read_fd(int fd, lgfs2_rgrps_t rgs)
 }
 
 /**
+ * Read a rindex entry into a set of resource groups
+ * rip: The inode of the rindex file
+ * rgs: The set of resource groups.
+ * i: The index of the entry to read from the rindex file
+ * Returns the new rindex entry added to the set or NULL on error with errno
+ * set.
+ */
+const struct gfs2_rindex *lgfs2_rindex_read_one(struct gfs2_inode *rip, lgfs2_rgrps_t rgs, unsigned i)
+{
+	uint64_t off = i * sizeof(struct gfs2_rindex);
+	char buf[sizeof(struct gfs2_rindex)];
+	struct gfs2_rindex ri;
+	lgfs2_rgrp_t rg;
+	int ret;
+
+	errno = EINVAL;
+	if (rip == NULL || rgs == NULL)
+		return NULL;
+
+	ret = gfs2_readi(rip, buf, off, sizeof(struct gfs2_rindex));
+	if (ret != sizeof(struct gfs2_rindex))
+		return NULL;
+
+	gfs2_rindex_in(&ri, buf);
+	rg = lgfs2_rgrps_append(rgs, &ri);
+	if (rg == NULL)
+		return NULL;
+
+	return &rg->ri;
+}
+
+/**
  * Free a set of resource groups created with lgfs2_rgrps_append() etc. This
  * does not write any dirty buffers to disk. See lgfs2_rgrp_write().
  * rgs: A pointer to the set of resource groups to be freed.
-- 
2.4.3



^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [Cluster-devel] [PATCH 2/3] gfs2-utils tests: Add helper program to damage rgrps
  2016-03-29 11:26 [Cluster-devel] [PATCH 1/3] libgfs2: New function lgfs2_rindex_read_one() Andrew Price
@ 2016-03-29 11:26 ` Andrew Price
  2016-03-29 11:26 ` [Cluster-devel] [PATCH 3/3] gfs2-utils tests: Add fsck.gfs2 rgrp/rindex repair tests Andrew Price
  1 sibling, 0 replies; 3+ messages in thread
From: Andrew Price @ 2016-03-29 11:26 UTC (permalink / raw)
  To: cluster-devel.redhat.com

Add a small program named nukerg, based on Bob Peterson's program of the
same name, which can be used to scribble over resource groups and rindex
entries to test resource group repair in fsck.gfs2.

Signed-off-by: Andrew Price <anprice@redhat.com>
---
 .gitignore        |   1 +
 tests/Makefile.am |  13 ++
 tests/nukerg.c    | 348 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 362 insertions(+)
 create mode 100644 tests/nukerg.c

diff --git a/.gitignore b/.gitignore
index bc8236e..b615b87 100644
--- a/.gitignore
+++ b/.gitignore
@@ -47,6 +47,7 @@ gfs2/tune/tunegfs2
 test-driver
 tests/check_meta
 tests/check_rgrp
+tests/nukerg
 tests/testvol
 tests/testsuite.log
 tests/testsuite.dir
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 5a37319..1f98cb4 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -11,6 +11,19 @@ DISTCLEANFILES = \
 
 CLEANFILES = testvol
 
+noinst_PROGRAMS = nukerg
+
+nukerg_SOURCES = nukerg.c
+nukerg_CPPFLAGS = \
+	-D_FILE_OFFSET_BITS=64 \
+	-D_LARGEFILE64_SOURCE \
+	-D_GNU_SOURCE
+nukerg_CFLAGS = \
+	-I$(top_srcdir)/gfs2/libgfs2 \
+	-I$(top_srcdir)/gfs2/include
+nukerg_LDADD = \
+	$(top_builddir)/gfs2/libgfs2/libgfs2.la
+
 if HAVE_CHECK
 UNIT_TESTS = \
 	check_meta \
diff --git a/tests/nukerg.c b/tests/nukerg.c
new file mode 100644
index 0000000..f2018fb
--- /dev/null
+++ b/tests/nukerg.c
@@ -0,0 +1,348 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include <libgfs2.h>
+
+const char *prog_name = "nukerg";
+
+static void usage(void)
+{
+	printf("%s zeroes a list of gfs2 resource groups or rindex entries.\n", prog_name);
+	printf("\n");
+	printf("Usage:\n");
+	printf("    %s -r <num_list>|-i <num_list> /dev/your/device\n", prog_name);
+	printf("\n");
+	printf("      -r: Destroy resource groups\n");
+	printf("      -i: Destroy resource group index (rindex) entries\n");
+	printf("\n");
+	printf("num_list: A comma- or space-separated list of resource group or rindex\n");
+	printf("          numbers (0-indexed) to be destroyed. Use '*' for all.\n");
+	printf("\n");
+	printf("Both -r and -i can be specified. Resource groups will necessarily\n");
+	printf("be destroyed before rindex entries.\n");
+}
+
+#define RGNUMS_SIZE (256)
+
+struct opts {
+	const char *device;
+	unsigned rgnums[RGNUMS_SIZE];
+	size_t rgnum_count;
+	unsigned rinums[RGNUMS_SIZE];
+	size_t rinum_count;
+
+	unsigned got_help:1;
+	unsigned got_device:1;
+	unsigned got_rgnums:1;
+	unsigned got_rinums:1;
+};
+
+static int parse_uint(char *str, unsigned *uint)
+{
+	long long tmpll;
+	char *endptr;
+
+	if (str == NULL || *str == '\0')
+		return 1;
+
+	errno = 0;
+	tmpll = strtoll(str, &endptr, 10);
+	if (errno || tmpll < 0 || tmpll > UINT_MAX || *endptr != '\0')
+		return 1;
+
+	*uint = (unsigned)tmpll;
+	return 0;
+}
+
+#define ALL_RGS ((unsigned)-1)
+
+static size_t parse_uint_list(char *str, unsigned *list, char **tokp, size_t nleft)
+{
+	const char *delim = " ,";
+	size_t i;
+
+	for (i = 0, *tokp = strsep(&str, delim); *tokp != NULL;
+	       i++, *tokp = strsep(&str, delim))
+	{
+		int ret;
+
+		if (i >= nleft)
+			return (size_t)-1; /* List would overflow */
+
+		/* Allow * to denote "all" */
+		if (strcmp(*tokp, "*") == 0) {
+			list[0] = ALL_RGS;
+			return 1;
+		}
+		ret = parse_uint(*tokp, &list[i]);
+		if (ret != 0)
+			return 0; /* Invalid token, *tokp points to it */
+	}
+	return i; /* Will be 0 if str is NULL or empty (*tokp is NULL in that case) */
+}
+
+static int parse_ri_list(char *str, struct opts *opts)
+{
+	unsigned *rinums = opts->rinums + opts->rinum_count;
+	size_t nleft = RGNUMS_SIZE - opts->rinum_count;
+	char *errtok = NULL;
+	size_t n;
+
+	n = parse_uint_list(str, rinums, &errtok, nleft);
+	if (n == 0) {
+		if (errtok == NULL)
+			fprintf(stderr, "No rindex entries given\n");
+		else
+			fprintf(stderr, "Invalid rindex entry: '%s'\n", errtok);
+		return 1;
+	}
+	else if (n == (size_t)-1) {
+		fprintf(stderr, "Too many rindex entries\n");
+		return 1;
+	}
+	opts->rinum_count += n;
+	opts->got_rinums = 1;
+	return 0;
+}
+
+static int parse_rg_list(char *str, struct opts *opts)
+{
+	unsigned *rgnums = opts->rgnums + opts->rgnum_count;
+	size_t nleft = RGNUMS_SIZE - opts->rgnum_count;
+	char *errtok = NULL;
+	size_t n;
+
+	n = parse_uint_list(optarg, rgnums, &errtok, nleft);
+	if (n == 0) {
+		if (errtok == NULL)
+			fprintf(stderr, "No resource groups given\n");
+		else
+			fprintf(stderr, "Invalid resource group number: '%s'\n", errtok);
+		return 1;
+	} else if (n == (size_t)-1) {
+		fprintf(stderr, "Too many resource group numbers\n");
+		return 1;
+	}
+	opts->rgnum_count += n;
+	opts->got_rgnums = 1;
+	return 0;
+}
+
+static int opts_get(int argc, char *argv[], struct opts *opts)
+{
+	int c;
+
+	memset(opts, 0, sizeof(*opts));
+
+	while (1) {
+		c = getopt(argc, argv, "-hi:r:");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'h':
+			opts->got_help = 1;
+			usage();
+			return 0;
+		case 'i':
+			if (parse_ri_list(optarg, opts))
+				return 1;
+			break;
+		case 'r':
+			if (parse_rg_list(optarg, opts))
+				return 1;
+			break;
+		case 1:
+			if (opts->got_device) {
+				fprintf(stderr, "More than one device specified. ");
+				fprintf(stderr, "Try -h for help.\n");
+				return 1;
+			}
+			opts->device = optarg;
+			opts->got_device = 1;
+			break;
+		case '?':
+		default:
+			usage();
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static int nuke_rgs(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, unsigned *rgnums, size_t count)
+{
+	struct gfs2_rgrp blankrg;
+	lgfs2_rgrp_t rg;
+	unsigned i;
+
+	memset(&blankrg, 0, sizeof(blankrg));
+
+	for (rg = lgfs2_rgrp_first(rgs), i = 0; rg; rg = lgfs2_rgrp_next(rg), i++) {
+		const struct gfs2_rindex *ri = lgfs2_rgrp_index(rg);
+		unsigned j;
+
+		for (j = 0; j < count; j++) {
+			uint64_t addr = ri->ri_addr;
+			off_t off = addr * sdp->bsize;
+			ssize_t bytes;
+
+			if (i != rgnums[j] && rgnums[j] != ALL_RGS)
+				continue;
+
+			printf("Nuking rg #%u at block 0x%"PRIx64"\n", i, addr);
+
+			bytes = pwrite(sdp->device_fd, &blankrg, sizeof(blankrg), off);
+			if (bytes != sizeof(blankrg)) {
+				fprintf(stderr, "Write failed (%u bytes): %s",
+				             (unsigned)bytes, strerror(errno));
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+static int nuke_ris(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, unsigned *rinums, size_t count)
+{
+	struct gfs2_rindex blankri;
+	lgfs2_rgrp_t rg;
+	unsigned i;
+
+	memset(&blankri, 0, sizeof(blankri));
+
+	for (rg = lgfs2_rgrp_first(rgs), i = 0; rg; rg = lgfs2_rgrp_next(rg), i++) {
+		unsigned j;
+
+		for (j = 0; j < count; j++) {
+			int bytes = 0;
+			uint64_t off;
+
+			if (i != rinums[j] && rinums[j] != ALL_RGS)
+				continue;
+
+			printf("Nuking rindex entry %u.\n", i);
+
+			off = i * sizeof(struct gfs2_rindex);
+			bytes = gfs2_writei(sdp->md.riinode, &blankri, off,
+						sizeof(struct gfs2_rindex));
+			if (bytes != sizeof(struct gfs2_rindex)) {
+				fprintf(stderr, "Write failed (%d bytes): %s",
+						       bytes, strerror(errno));
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+static lgfs2_rgrps_t read_rindex(struct gfs2_sbd *sdp)
+{
+	lgfs2_rgrps_t rgs;
+	unsigned rgcount;
+	unsigned i;
+
+	gfs2_lookupi(sdp->master_dir, "rindex", 6, &sdp->md.riinode);
+	if (sdp->md.riinode == NULL) {
+		perror("Failed to look up rindex");
+		return NULL;
+	}
+	rgs = lgfs2_rgrps_init(sdp, 0, 0);
+	if (rgs == NULL) {
+		fprintf(stderr, "Failed to initialize resource group set: %s\n",
+		                                                strerror(errno));
+		return NULL;
+	}
+	rgcount = sdp->md.riinode->i_di.di_size / sizeof(struct gfs2_rindex);
+	for (i = 0; i < rgcount; i++) {
+		const struct gfs2_rindex *ri;
+
+		ri = lgfs2_rindex_read_one(sdp->md.riinode, rgs, i);
+		if (ri == NULL) {
+			fprintf(stderr, "Failed to read rindex entry %u: %s\n",
+			                                    i, strerror(errno));
+			return NULL;
+		}
+	}
+	printf("%u rindex entries found.\n", i);
+	return rgs;
+}
+
+static int fill_super_block(struct gfs2_sbd *sdp)
+{
+	sdp->sd_sb.sb_bsize = GFS2_BASIC_BLOCK;
+	sdp->bsize = sdp->sd_sb.sb_bsize;
+
+	if (compute_constants(sdp) != 0) {
+		fprintf(stderr, "Failed to compute file system constants.\n");
+		return 1;
+	}
+	if (read_sb(sdp) != 0) {
+		perror("Failed to read superblock\n");
+		return 1;
+	}
+	sdp->master_dir = lgfs2_inode_read(sdp, sdp->sd_sb.sb_master_dir.no_addr);
+	if (sdp->master_dir == NULL) {
+		fprintf(stderr, "Failed to read master directory inode.\n");
+		return 1;
+	}
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	struct gfs2_sbd sbd;
+	lgfs2_rgrps_t rgs;
+	struct opts opts;
+	int ret;
+
+	memset(&sbd, 0, sizeof(sbd));
+
+	ret = opts_get(argc, argv, &opts);
+	if (ret != 0 || opts.got_help)
+		exit(ret);
+
+	if (!opts.got_device) {
+		fprintf(stderr, "No device specified.\n");
+		usage();
+		exit(1);
+	}
+	if (!opts.got_rgnums && !opts.got_rinums) {
+		fprintf(stderr, "No resource groups or rindex entries specified.\n");
+		usage();
+		exit(1);
+	}
+	if ((sbd.device_fd = open(opts.device, O_RDWR)) < 0) {
+		perror(opts.device);
+		exit(1);
+	}
+	if (fill_super_block(&sbd) != 0)
+		exit(1);
+
+	rgs = read_rindex(&sbd);
+	if (rgs == NULL)
+		exit(1);
+
+	if (opts.got_rgnums && nuke_rgs(&sbd, rgs, opts.rgnums, opts.rgnum_count) != 0)
+		exit(1);
+
+	if (opts.got_rinums && nuke_ris(&sbd, rgs, opts.rinums, opts.rinum_count) != 0)
+		exit(1);
+
+	inode_put(&sbd.md.riinode);
+	inode_put(&sbd.master_dir);
+	lgfs2_rgrps_free(&rgs);
+	fsync(sbd.device_fd);
+	close(sbd.device_fd);
+	exit(0);
+}
+
+/* This function is for libgfs2's sake. */
+void print_it(const char *label, const char *fmt, const char *fmt2, ...) {}
-- 
2.4.3



^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [Cluster-devel] [PATCH 3/3] gfs2-utils tests: Add fsck.gfs2 rgrp/rindex repair tests
  2016-03-29 11:26 [Cluster-devel] [PATCH 1/3] libgfs2: New function lgfs2_rindex_read_one() Andrew Price
  2016-03-29 11:26 ` [Cluster-devel] [PATCH 2/3] gfs2-utils tests: Add helper program to damage rgrps Andrew Price
@ 2016-03-29 11:26 ` Andrew Price
  1 sibling, 0 replies; 3+ messages in thread
From: Andrew Price @ 2016-03-29 11:26 UTC (permalink / raw)
  To: cluster-devel.redhat.com

Add some tests which exercise fsck.gfs2's resource group and rindex
repair code. Two of the tests currently fail (more work to do there) so
they're left commented out.

Adds a GFS_NUKERG_CHECK macro to make writing tests like these simpler.

Signed-off-by: Andrew Price <anprice@redhat.com>
---
 tests/fsck.at      | 20 ++++++++++++++++++++
 tests/testsuite.at | 11 ++++++++++-
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/tests/fsck.at b/tests/fsck.at
index 4d25f40..5e49985 100644
--- a/tests/fsck.at
+++ b/tests/fsck.at
@@ -14,3 +14,23 @@ AT_SETUP([Fix invalid goal blocks])
 AT_KEYWORDS(fsck.gfs2 fsck)
 GFS_LANG_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], [set '/' { di_goal_meta: 0 }])
 AT_CLEANUP
+
+AT_SETUP([Fix bad resource group #0])
+AT_KEYWORDS(fsck.gfs2 fsck)
+GFS_NUKERG_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], [-r 0])
+AT_CLEANUP
+
+#AT_SETUP([Fix bad resource group #1])
+#AT_KEYWORDS(fsck.gfs2 fsck)
+#GFS_NUKERG_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], [-r 1])
+#AT_CLEANUP
+
+#AT_SETUP([Fix bad rindex entry #0])
+#AT_KEYWORDS(fsck.gfs2 fsck)
+#GFS_NUKERG_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], [-i 0])
+#AT_CLEANUP
+
+AT_SETUP([Fix bad rindex entry #1])
+AT_KEYWORDS(fsck.gfs2 fsck)
+GFS_NUKERG_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], [-i 1])
+AT_CLEANUP
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 0422b02..cc1bd54 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -12,7 +12,7 @@ AT_CHECK($1, 0, [ignore], [ignore])
 AT_CHECK([fsck.gfs2 -n $GFS_TGT], 0, [ignore], [ignore])])
 
 # Regenerate, mkfs, modify fs with gfs2l, fsck
-# Usage: GFS_TGT_REGEN ([<mkfs.gfs2 command>], [<gfs2l script>])
+# Usage: GFS_LANG_CHECK ([<mkfs.gfs2 command>], [<gfs2l script>])
 m4_define([GFS_LANG_CHECK],
 [GFS_TGT_REGEN
 AT_CHECK($1, 0, [ignore], [ignore])
@@ -20,6 +20,15 @@ AT_CHECK([echo "$2" | gfs2l ${GFS_TGT}], 0, [ignore], [ignore])
 AT_CHECK([fsck.gfs2 -y $GFS_TGT], 1, [ignore], [ignore])
 AT_CHECK([fsck.gfs2 -n $GFS_TGT], 0, [ignore], [ignore])])
 
+# Regenerate, mkfs, modify fs with nukerg, fsck
+# Usage: GFS_NUKERG_CHECK ([<mkfs.gfs2 command>], [<gfs2l script>])
+m4_define([GFS_NUKERG_CHECK],
+[GFS_TGT_REGEN
+AT_CHECK($1, 0, [ignore], [ignore])
+AT_CHECK([nukerg $2 $GFS_TGT], 0, [ignore], [ignore])
+AT_CHECK([fsck.gfs2 -y $GFS_TGT], 1, [ignore], [ignore])
+AT_CHECK([fsck.gfs2 -n $GFS_TGT], 0, [ignore], [ignore])])
+
 # Set up a unit test, skipping if unit tests are disabled
 # Usage: GFS_UNIT_TEST ([name], [keywords])
 m4_define([GFS_UNIT_TEST],
-- 
2.4.3



^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2016-03-29 11:26 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-03-29 11:26 [Cluster-devel] [PATCH 1/3] libgfs2: New function lgfs2_rindex_read_one() Andrew Price
2016-03-29 11:26 ` [Cluster-devel] [PATCH 2/3] gfs2-utils tests: Add helper program to damage rgrps Andrew Price
2016-03-29 11:26 ` [Cluster-devel] [PATCH 3/3] gfs2-utils tests: Add fsck.gfs2 rgrp/rindex repair tests Andrew Price

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).