[Cluster-devel] [PATCH RHEL5] gfs2_edit: Add compression to savemeta and restoremeta

Andrew Price anprice at redhat.com
Wed Sep 28 16:44:55 UTC 2011


This patch adds the ability to output gzip-compressed data with savemeta and
makes it the default behaviour. It also adds a -z <0-9> option to allow the
level of compression to be controlled, 0 meaning no compression and 9 being the
default. restoremeta can now restore from a gzip-compressed or raw metadata
file without any extra options.

The file opening, closing and writing code from savemeta has been moved into
savemeta{open,close,write} functions to abstract away compressed and
non-compressed file output.

Adds a dependency on zlib.

rhbz#702296

Signed-off-by: Andrew Price <anprice at redhat.com>
---
 gfs2/edit/Makefile   |    2 +-
 gfs2/edit/hexedit.c  |   49 ++++++++--
 gfs2/edit/hexedit.h  |    2 +-
 gfs2/edit/savemeta.c |  246 ++++++++++++++++++++++++++++++++++++++------------
 gfs2/man/gfs2_edit.8 |   42 +++++----
 5 files changed, 251 insertions(+), 90 deletions(-)

diff --git a/gfs2/edit/Makefile b/gfs2/edit/Makefile
index 6121791..aac03da 100644
--- a/gfs2/edit/Makefile
+++ b/gfs2/edit/Makefile
@@ -41,7 +41,7 @@ endif
 all: gfs2_edit
 
 gfs2_edit: ${SOURCE} hexedit.h extended.h gfs2hex.h ${LIBS}/libgfs2.a
-	${CC} ${CFLAGS} ${INCLUDE} -L${LIBS} ${LDFLAGS} ${SOURCE} ${LOADLIBES} ${LDLIBS} -lncurses -o $@ -lgfs2
+	${CC} ${CFLAGS} ${INCLUDE} -L${LIBS} ${LDFLAGS} ${SOURCE} ${LOADLIBES} ${LDLIBS} -lncurses -lz -o $@ -lgfs2
 
 install: all
 	if [ ! -d ${sbindir} ]; then \
diff --git a/gfs2/edit/hexedit.c b/gfs2/edit/hexedit.c
index 6604376..3cc05f4 100644
--- a/gfs2/edit/hexedit.c
+++ b/gfs2/edit/hexedit.c
@@ -53,6 +53,7 @@ struct gfs2_log_header *llh;
 struct gfs2_log_descriptor *lld;
 int pgnum;
 int details = 0;
+long int gziplevel = 9;
 
 const char *prog_name;
 
@@ -3307,7 +3308,7 @@ static void dump_journal(const char *journal)
 /* ------------------------------------------------------------------------ */
 static void usage(void)
 {
-	fprintf(stderr,"\nFormat is: gfs2_edit [-c 1] [-V] [-x] [-h] [identify] [-p structures|blocks][blocktype][blockalloc [val]][blockbits][blockrg][find sb|rg|rb|di|in|lf|jd|lh|ld|ea|ed|lb|13|qc][field <f>[val]] /dev/device\n\n");
+	fprintf(stderr,"\nFormat is: gfs2_edit [-c 1] [-V] [-x] [-h] [identify] [-z <0-9>] [-p structures|blocks][blocktype][blockalloc [val]][blockbits][blockrg][find sb|rg|rb|di|in|lf|jd|lh|ld|ea|ed|lb|13|qc][field <f>[val]] /dev/device\n\n");
 	fprintf(stderr,"If only the device is specified, it enters into hexedit mode.\n");
 	fprintf(stderr,"identify - prints out only the block type, not the details.\n");
 	fprintf(stderr,"printsavedmeta - prints out the saved metadata blocks from a savemeta file.\n");
@@ -3348,6 +3349,8 @@ static void usage(void)
 	fprintf(stderr,"-p   <b> find sb|rg|rb|di|in|lf|jd|lh|ld|ea|ed|lb|"
 		"13|qc - find block of given type after block <b>\n");
 	fprintf(stderr,"     <b> specifies the starting block for search\n");
+	fprintf(stderr,"-z 1 use gzip compression level 1 for savemeta (default 9)\n");
+	fprintf(stderr,"-z 0 do not use compression\n");
 	fprintf(stderr,"-s   specifies a starting block such as root, rindex, quota, inum.\n");
 	fprintf(stderr,"-x   print in hexmode.\n");
 	fprintf(stderr,"-h   prints this help.\n\n");
@@ -3374,10 +3377,33 @@ static void usage(void)
 	fprintf(stderr,"     gfs2_edit -p quota find di /dev/x/y\n");
 	fprintf(stderr,"   To set the Resource Group flags for rg #7 to 3.\n");
 	fprintf(stderr,"     gfs2_edit rgflags 7 3 /dev/sdc2\n");
-	fprintf(stderr,"   To save off all metadata for /dev/vg/lv:\n");
-	fprintf(stderr,"     gfs2_edit savemeta /dev/vg/lv /tmp/metasave\n");
+	fprintf(stderr,"   To save off all metadata for /dev/vg/lv without compression:\n");
+	fprintf(stderr,"     gfs2_edit savemeta -z 0 /dev/vg/lv /tmp/metasave\n");
 }/* usage */
 
+/**
+ * getgziplevel - Process the -z parameter to savemeta operations
+ * argv - argv
+ * i    - a pointer to the argv index at which to begin processing
+ * The index pointed to by i will be incremented past the -z option if found
+ */
+static void getgziplevel(char *argv[], int *i)
+{
+	char *endptr;
+	(*i)++;
+	if (!strcasecmp(argv[*i], "-z")) {
+		(*i)++;
+		errno = 0;
+		gziplevel = strtol(argv[*i], &endptr, 10);
+		if (errno || endptr == argv[*i] || gziplevel < 0 || gziplevel > 9) {
+			fprintf(stderr, "Compression level out of range: %s\n", argv[*i]);
+			exit(-1);
+		}
+	} else {
+		(*i)--;
+	}
+}
+
 /* ------------------------------------------------------------------------ */
 /* parameterpass1 - pre-processing for command-line parameters              */
 /* ------------------------------------------------------------------------ */
@@ -3571,13 +3597,16 @@ static void process_parameters(int argc, char *argv[], int pass)
 				exit(EXIT_SUCCESS);
 			}
 		}
-		else if (!strcasecmp(argv[i], "savemeta"))
-			savemeta(argv[i+2], 0);
-		else if (!strcasecmp(argv[i], "savemetaslow"))
-			savemeta(argv[i+2], 1);
-		else if (!strcasecmp(argv[i], "savergs"))
-			savemeta(argv[i+2], 2);
-		else if (isdigit(argv[i][0])) { /* decimal addr */
+		else if (!strcasecmp(argv[i], "savemeta")) {
+			getgziplevel(argv, &i);
+			savemeta(argv[i+2], 0, gziplevel);
+		} else if (!strcasecmp(argv[i], "savemetaslow")) {
+			getgziplevel(argv, &i);
+			savemeta(argv[i+2], 1, gziplevel);
+		} else if (!strcasecmp(argv[i], "savergs")) {
+			getgziplevel(argv, &i);
+			savemeta(argv[i+2], 2, gziplevel);
+		} else if (isdigit(argv[i][0])) { /* decimal addr */
 			sscanf(argv[i], "%"SCNd64, &temp_blk);
 			push_block(temp_blk);
 		} else {
diff --git a/gfs2/edit/hexedit.h b/gfs2/edit/hexedit.h
index 81637bc..8732c27 100644
--- a/gfs2/edit/hexedit.h
+++ b/gfs2/edit/hexedit.h
@@ -365,7 +365,7 @@ extern void gfs_log_header_in(struct gfs_log_header *head,
 			      struct gfs2_buffer_head *bh);
 extern void gfs_log_header_print(struct gfs_log_header *lh);
 extern void gfs_dinode_in(struct gfs_dinode *di, struct gfs2_buffer_head *bh);
-extern void savemeta(char *out_fn, int saveoption);
+extern void savemeta(char *out_fn, int saveoption, int gziplevel);
 extern void restoremeta(const char *in_fn, const char *out_device,
 			uint64_t printblocksonly);
 extern int display(int identify_only);
diff --git a/gfs2/edit/savemeta.c b/gfs2/edit/savemeta.c
index 1ca5b42..c868edd 100644
--- a/gfs2/edit/savemeta.c
+++ b/gfs2/edit/savemeta.c
@@ -29,6 +29,7 @@
 #include <linux_endian.h>
 #include <sys/time.h>
 #include <linux/gfs2_ondisk.h>
+#include <zlib.h>
 
 #include "osi_list.h"
 #include "gfs2hex.h"
@@ -45,6 +46,13 @@ struct saved_metablock {
 	char buf[BUFSIZE];
 };
 
+struct metafd {
+	int fd;
+	gzFile gzfd;
+	const char *filename;
+	int gziplevel;
+};
+
 struct saved_metablock *savedata;
 uint64_t last_fs_block, last_reported_block, blks_saved, total_out, pct;
 uint64_t journal_blocks[MAX_JOURNALS_SAVED];
@@ -205,7 +213,97 @@ static void warm_fuzzy_stuff(uint64_t wfsblock, int force)
 	}
 }
 
-static int save_block(int fd, int out_fd, uint64_t blk)
+/**
+ * Open a file and prepare it for writing by savemeta()
+ * out_fn: the path to the file, which will be truncated if it exists
+ * gziplevel: 0   - do not compress the file,
+ *            1-9 - use gzip compression level 1-9
+ * Returns a struct metafd containing the opened file descriptor
+ */
+static struct metafd savemetaopen(char *out_fn, int gziplevel)
+{
+	struct metafd mfd = {-1, NULL, NULL, gziplevel};
+	char gzmode[3] = "w9";
+	char dft_fn[] = DFT_SAVE_FILE;
+
+	if (!out_fn) {
+		out_fn = dft_fn;
+		mfd.fd = mkstemp(out_fn);
+	} else {
+		mfd.fd = open(out_fn, O_RDWR | O_CREAT, 0644);
+	}
+	mfd.filename = out_fn;
+
+	if (mfd.fd < 0) {
+		fprintf(stderr, "Can't open %s: %s\n", out_fn, strerror(errno));
+		exit(1);
+	}
+
+	if (ftruncate(mfd.fd, 0)) {
+		fprintf(stderr, "Can't truncate %s: %s\n", out_fn, strerror(errno));
+		exit(1);
+	}
+
+	if (gziplevel > 0) {
+		gzmode[1] = '0' + gziplevel;
+		mfd.gzfd = gzdopen(mfd.fd, gzmode);
+		if (!mfd.gzfd) {
+			fprintf(stderr, "gzdopen error: %s\n", strerror(errno));
+			exit(1);
+		}
+	}
+
+	return mfd;
+}
+
+/**
+ * Write nbyte bytes from buf to a file opened with savemetaopen()
+ * mfd: the file descriptor opened using savemetaopen()
+ * buf: the buffer to write data from
+ * nbyte: the number of bytes to write
+ * Returns the number of bytes written from buf or -1 on error
+ */
+static ssize_t savemetawrite(struct metafd *mfd, const void *buf, size_t nbyte)
+{
+	ssize_t ret;
+	int gzerr;
+	const char *gzerrmsg;
+
+	if (mfd->gziplevel == 0) {
+		return write(mfd->fd, buf, nbyte);
+	}
+
+	ret = gzwrite(mfd->gzfd, buf, nbyte);
+	if (ret != nbyte) {
+		gzerrmsg = gzerror(mfd->gzfd, &gzerr);
+		if (gzerr != Z_ERRNO) {
+			fprintf(stderr, "Error: zlib: %s\n", gzerrmsg);
+		}
+	}
+	return ret;
+}
+
+/**
+ * Closes a file descriptor previously opened using savemetaopen()
+ * mfd: the file descriptor previously opened using savemetaopen()
+ * Returns 0 on success or -1 on error
+ */
+static int savemetaclose(struct metafd *mfd)
+{
+	int gzret;
+	if (mfd->gziplevel > 0) {
+		gzret = gzclose(mfd->gzfd);
+		if (gzret == Z_STREAM_ERROR) {
+			fprintf(stderr, "gzclose: file is not valid\n");
+			return -1;
+		} else if (gzret == Z_ERRNO) {
+			return -1;
+		}
+	}
+	return close(mfd->fd);
+}
+
+static int save_block(int fd, struct metafd *mfd, uint64_t blk)
 {
 	int blktype, blklen, outsz;
 	uint16_t trailing0;
@@ -240,11 +338,34 @@ static int save_block(int fd, int out_fd, uint64_t blk)
 		p--;
 	}
 	savedata->blk = cpu_to_be64(blk);
-	do_write(out_fd, &savedata->blk, sizeof(savedata->blk));
+	if (savemetawrite(mfd, &savedata->blk, sizeof(savedata->blk)) !=
+	    sizeof(savedata->blk)) {
+		fprintf(stderr, "write error: %s from %s:%d: "
+			"block %lld (0x%llx)\n", strerror(errno),
+			__FUNCTION__, __LINE__,
+			(unsigned long long)savedata->blk,
+			(unsigned long long)savedata->blk);
+		exit(-1);
+	}
 	outsz = blklen - trailing0;
 	savedata->siglen = cpu_to_be16(outsz);
-	do_write(out_fd, &savedata->siglen, sizeof(savedata->siglen));
-	do_write(out_fd, savedata->buf, outsz);
+	if (savemetawrite(mfd, &savedata->siglen, sizeof(savedata->siglen)) !=
+	    sizeof(savedata->siglen)) {
+		fprintf(stderr, "write error: %s from %s:%d: "
+			"block %lld (0x%llx)\n", strerror(errno),
+			__FUNCTION__, __LINE__,
+			(unsigned long long)savedata->blk,
+			(unsigned long long)savedata->blk);
+		exit(-1);
+	}
+	if (savemetawrite(mfd, savedata->buf, outsz) != outsz) {
+		fprintf(stderr, "write error: %s from %s:%d: "
+			"block %lld (0x%llx)\n", strerror(errno),
+			__FUNCTION__, __LINE__,
+			(unsigned long long)savedata->blk,
+			(unsigned long long)savedata->blk);
+		exit(-1);
+	}
 	total_out += sizeof(savedata->blk) + sizeof(savedata->siglen) + outsz;
 	blks_saved++;
 	brelse(savebh);
@@ -254,7 +375,7 @@ static int save_block(int fd, int out_fd, uint64_t blk)
 /*
  * save_ea_block - save off an extended attribute block
  */
-static void save_ea_block(int out_fd, struct gfs2_buffer_head *metabh)
+static void save_ea_block(struct metafd *mfd, struct gfs2_buffer_head *metabh)
 {
 	int i, e, ea_len = sbd.bsize;
 	struct gfs2_ea_header ea;
@@ -272,7 +393,7 @@ static void save_ea_block(int out_fd, struct gfs2_buffer_head *metabh)
 			b = (uint64_t *)(metabh->b_data);
 			b += charoff + i;
 			blk = be64_to_cpu(*b);
-			save_block(sbd.device_fd, out_fd, blk);
+			save_block(sbd.device_fd, mfd, blk);
 		}
 		if (!ea.ea_rec_len)
 			break;
@@ -283,7 +404,7 @@ static void save_ea_block(int out_fd, struct gfs2_buffer_head *metabh)
 /*
  * save_indirect_blocks - save all indirect blocks for the given buffer
  */
-static void save_indirect_blocks(int out_fd, osi_list_t *cur_list,
+static void save_indirect_blocks(struct metafd *mfd, osi_list_t *cur_list,
 			  struct gfs2_buffer_head *mybh, int height, int hgt)
 {
 	uint64_t old_block = 0, indir_block;
@@ -303,10 +424,10 @@ static void save_indirect_blocks(int out_fd, osi_list_t *cur_list,
 		if (indir_block == old_block)
 			continue;
 		old_block = indir_block;
-		blktype = save_block(sbd.device_fd, out_fd, indir_block);
+		blktype = save_block(sbd.device_fd, mfd, indir_block);
 		if (blktype == GFS2_METATYPE_EA) {
 			nbh = bread(&sbd, indir_block);
-			save_ea_block(out_fd, nbh);
+			save_ea_block(mfd, nbh);
 			brelse(nbh);
 		}
 		if (height != hgt) { /* If not at max height */
@@ -322,7 +443,7 @@ static void save_indirect_blocks(int out_fd, osi_list_t *cur_list,
 /*
  * save_inode_data - save off important data associated with an inode
  *
- * out_fd - destination file descriptor
+ * mfd - destination file descriptor
  * block - block number of the inode to save the data for
  * 
  * For user files, we don't want anything except all the indirect block
@@ -334,7 +455,7 @@ static void save_indirect_blocks(int out_fd, osi_list_t *cur_list,
  * For file system journals, the "data" is a mixture of metadata and
  * journaled data.  We want all the metadata and none of the user data.
  */
-static void save_inode_data(int out_fd)
+static void save_inode_data(struct metafd *mfd)
 {
 	uint32_t height;
 	struct gfs2_inode *inode;
@@ -371,7 +492,7 @@ static void save_inode_data(int out_fd)
 		for (tmp = prev_list->next; tmp != prev_list; tmp = tmp->next){
 			mybh = osi_list_entry(tmp, struct gfs2_buffer_head,
 					      b_altlist);
-			save_indirect_blocks(out_fd, cur_list, mybh,
+			save_indirect_blocks(mfd, cur_list, mybh,
 					     height, i);
 		} /* for blocks at that height */
 	} /* for height */
@@ -399,7 +520,7 @@ static void save_inode_data(int out_fd)
 			old_leaf = leaf_no;
 			mybh = bread(&sbd, leaf_no);
 			if (gfs2_check_meta(mybh, GFS2_METATYPE_LF) == 0)
-				save_block(sbd.device_fd, out_fd, leaf_no);
+				save_block(sbd.device_fd, mfd, leaf_no);
 			brelse(mybh);
 		}
 	}
@@ -408,17 +529,17 @@ static void save_inode_data(int out_fd)
 		struct gfs2_buffer_head *lbh;
 
 		lbh = bread(&sbd, inode->i_di.di_eattr);
-		save_block(sbd.device_fd, out_fd, inode->i_di.di_eattr);
+		save_block(sbd.device_fd, mfd, inode->i_di.di_eattr);
 		gfs2_meta_header_in(&mh, lbh);
 		if (mh.mh_magic == GFS2_MAGIC &&
 		    mh.mh_type == GFS2_METATYPE_EA)
-			save_ea_block(out_fd, lbh);
+			save_ea_block(mfd, lbh);
 		else if (mh.mh_magic == GFS2_MAGIC &&
 			 mh.mh_type == GFS2_METATYPE_IN)
-			save_indirect_blocks(out_fd, cur_list, lbh, 2, 2);
+			save_indirect_blocks(mfd, cur_list, lbh, 2, 2);
 		else {
 			if (mh.mh_magic == GFS2_MAGIC) /* if it's metadata */
-				save_block(sbd.device_fd, out_fd,
+				save_block(sbd.device_fd, mfd,
 					   inode->i_di.di_eattr);
 			fprintf(stderr,
 				"\nWarning: corrupt extended "
@@ -518,32 +639,21 @@ static int next_rg_freemeta(struct gfs2_sbd *sdp, struct rgrp_list *rgd,
 	return 0;
 }
 
-void savemeta(char *out_fn, int saveoption)
+void savemeta(char *out_fn, int saveoption, int gziplevel)
 {
-	int out_fd;
 	int slow;
 	osi_list_t *tmp;
 	int rgcount;
 	uint64_t jindex_block;
 	struct gfs2_buffer_head *lbh;
 	struct rgrp_list *last_rgd, *prev_rgd;
+	struct metafd mfd;
 
 	slow = (saveoption == 1);
 	sbd.md.journals = 1;
 
-	if (!out_fn) {
-		out_fn = strdup(DFT_SAVE_FILE);
-		if (!out_fn)
-			die("Can't allocate memory for the operation.\n");
-		out_fd = mkstemp(out_fn);
-	} else
-		out_fd = open(out_fn, O_RDWR | O_CREAT, 0644);
-
-	if (out_fd < 0)
-		die("Can't open %s: %s\n", out_fn, strerror(errno));
-
-	if (ftruncate(out_fd, 0))
-		die("Can't truncate %s: %s\n", out_fn, strerror(errno));
+	mfd = savemetaopen(out_fn, gziplevel);
+
 	savedata = malloc(sizeof(struct saved_metablock));
 	if (!savedata)
 		die("Can't allocate memory for the operation.\n");
@@ -628,15 +738,15 @@ void savemeta(char *out_fn, int saveoption)
 	get_journal_inode_blocks();
 	if (!slow) {
 		/* Save off the superblock */
-		save_block(sbd.device_fd, out_fd, 0x10 * (4096 / sbd.bsize));
+		save_block(sbd.device_fd, &mfd, 0x10 * (4096 / sbd.bsize));
 		/* If this is gfs1, save off the rindex because it's not
 		   part of the file system as it is in gfs2. */
 		if (gfs1) {
 			int j;
 
 			block = sbd1->sb_rindex_di.no_addr;
-			save_block(sbd.device_fd, out_fd, block);
-			save_inode_data(out_fd);
+			save_block(sbd.device_fd, &mfd, block);
+			save_inode_data(&mfd);
 			/* In GFS1, journals aren't part of the RG space */
 			for (j = 0; j < journals_found; j++) {
 				log_debug("Saving journal #%d\n", j + 1);
@@ -644,7 +754,7 @@ void savemeta(char *out_fn, int saveoption)
 				     block < journal_blocks[j] +
 					     gfs1_journal_size;
 				     block++)
-					save_block(sbd.device_fd, out_fd, block);
+					save_block(sbd.device_fd, &mfd, block);
 			}
 		}
 		/* Walk through the resource groups saving everything within */
@@ -666,7 +776,7 @@ void savemeta(char *out_fn, int saveoption)
 			for (block = rgd->ri.ri_addr;
 			     block < rgd->ri.ri_data0; block++) {
 				warm_fuzzy_stuff(block, FALSE);
-				save_block(sbd.device_fd, out_fd, block);
+				save_block(sbd.device_fd, &mfd, block);
 			}
 			/* Save off the other metadata: inodes, etc. */
 			if (saveoption != 2) {
@@ -675,9 +785,9 @@ void savemeta(char *out_fn, int saveoption)
 				while (!gfs2_next_rg_meta(rgd, &block, first)){
 					warm_fuzzy_stuff(block, FALSE);
 					blktype = save_block(sbd.device_fd,
-							     out_fd, block);
+							     &mfd, block);
 					if (blktype == GFS2_METATYPE_DI)
-						save_inode_data(out_fd);
+						save_inode_data(&mfd);
 					first = 0;
 				}
 				/* Save off the free/unlinked meta blocks too.
@@ -686,7 +796,7 @@ void savemeta(char *out_fn, int saveoption)
 				while (!next_rg_freemeta(&sbd, rgd, &block,
 							 first)) {
 					blktype = save_block(sbd.device_fd,
-							     out_fd, block);
+							     &mfd, block);
 					first = 0;
 				}
 			}
@@ -695,7 +805,7 @@ void savemeta(char *out_fn, int saveoption)
 	}
 	if (slow) {
 		for (block = 0; block < last_fs_block; block++) {
-			save_block(sbd.device_fd, out_fd, block);
+			save_block(sbd.device_fd, &mfd, block);
 		}
 	}
 	/* Clean up */
@@ -703,28 +813,33 @@ void savemeta(char *out_fn, int saveoption)
 	/* so we tell the user that we've processed everything. */
 	block = last_fs_block;
 	warm_fuzzy_stuff(block, TRUE);
-	printf("\nMetadata saved to file %s.\n", out_fn);
+	printf("\nMetadata saved to file %s ", mfd.filename);
+	if (mfd.gziplevel) {
+		printf("(gzipped, level %d).\n", mfd.gziplevel);
+	} else {
+		printf("(uncompressed).\n");
+	}
 	free(savedata);
-	close(out_fd);
+	savemetaclose(&mfd);
 	close(sbd.device_fd);
 	exit(0);
 }
 
-static int restore_data(int fd, int in_fd, int printblocksonly,
+static int restore_data(int fd, gzFile *gzin_fd, int printblocksonly,
 			int find_highblk)
 {
 	size_t rs;
 	uint64_t buf64, writes = 0, highest_valid_block = 0;
 	uint16_t buf16;
-	int first = 1, pos;
+	int first = 1, pos, gzerr;
 	char rdbuf[256];
 	char gfs_superblock_id[8] = {0x01, 0x16, 0x19, 0x70,
 				     0x00, 0x00, 0x00, 0x01};
 
 	if (!printblocksonly)
 		do_lseek(fd, 0);
-	do_lseek(in_fd, 0);
-	rs = read(in_fd, rdbuf, sizeof(rdbuf));
+	gzseek(gzin_fd, 0, SEEK_SET);
+	rs = gzread(gzin_fd, rdbuf, sizeof(rdbuf));
 	if (rs != sizeof(rdbuf)) {
 		fprintf(stderr, "Error: File is too small.\n");
 		return -1;
@@ -738,14 +853,20 @@ static int restore_data(int fd, int in_fd, int printblocksonly,
 	}
 	if (pos == sizeof(rdbuf) - sizeof(uint64_t) - sizeof(uint16_t))
 		pos = 0;
-	do_lseek(in_fd, pos);
+	if (gzseek(gzin_fd, pos, SEEK_SET) != pos) {
+		fprintf(stderr, "bad seek: %s from %s:%d: "
+			"offset %lld (0x%llx)\n", strerror(errno),
+			__FUNCTION__, __LINE__, (unsigned long long)pos,
+			(unsigned long long)pos);
+		exit(-1);
+	}
 	blks_saved = total_out = 0;
 	last_fs_block = 0;
 	while (TRUE) {
 		struct gfs2_buffer_head dummy_bh;
 
 		memset(savedata, 0, sizeof(struct saved_metablock));
-		rs = read(in_fd, &buf64, sizeof(uint64_t));
+		rs = gzread(gzin_fd, &buf64, sizeof(uint64_t));
 		if (!rs)
 			break;
 		if (rs != sizeof(uint64_t)) {
@@ -764,7 +885,15 @@ static int restore_data(int fd, int in_fd, int printblocksonly,
 				savedata->blk);
 			return -1;
 		}
-		rs = read(in_fd, &buf16, sizeof(uint16_t));
+		if (gzread(gzin_fd, &buf16, sizeof(uint16_t)) !=
+		    sizeof(uint16_t)) {
+			fprintf(stderr, "read error: %s from %s:%d: "
+				"block %lld (0x%llx)\n",
+				gzerror(gzin_fd, &gzerr), __FUNCTION__, __LINE__,
+				(unsigned long long)savedata->blk,
+				(unsigned long long)savedata->blk);
+			exit(-1);
+		}
 		savedata->siglen = be16_to_cpu(buf16);
 		if (savedata->siglen > sizeof(savedata->buf)) {
 			fprintf(stderr, "\nBad record length: %d for block #%"
@@ -773,11 +902,11 @@ static int restore_data(int fd, int in_fd, int printblocksonly,
 			return -1;
 		}
 		if (savedata->siglen &&
-		    read(in_fd, savedata->buf, savedata->siglen) !=
+		    gzread(gzin_fd, savedata->buf, savedata->siglen) !=
 		    savedata->siglen) {
 			fprintf(stderr, "read error: %s from %s:%d: "
 				"block %lld (0x%llx)\n",
-				strerror(errno), __FUNCTION__, __LINE__,
+				gzerror(gzin_fd, &gzerr), __FUNCTION__, __LINE__,
 				(unsigned long long)savedata->blk,
 				(unsigned long long)savedata->blk);
 			exit(-1);
@@ -883,15 +1012,16 @@ static void complain(const char *complaint)
 void restoremeta(const char *in_fn, const char *out_device,
 		 uint64_t printblocksonly)
 {
-	int in_fd, error;
+	int error;
+	gzFile gzfd;
 
 	termlines = 0;
 	if (!in_fn)
 		complain("No source file specified.");
 	if (!printblocksonly && !out_device)
 		complain("No destination file system specified.");
-	in_fd = open(in_fn, O_RDONLY);
-	if (in_fd < 0)
+	gzfd = gzopen(in_fn, "rb");
+	if (!gzfd)
 		die("Can't open source file %s: %s\n",
 		    in_fn, strerror(errno));
 
@@ -908,13 +1038,13 @@ void restoremeta(const char *in_fn, const char *out_device,
 		die("Can't allocate memory for the restore operation.\n");
 
 	blks_saved = 0;
-	restore_data(sbd.device_fd, in_fd, printblocksonly, 1);
-	error = restore_data(sbd.device_fd, in_fd, printblocksonly, 0);
+	restore_data(sbd.device_fd, gzfd, printblocksonly, 1);
+	error = restore_data(sbd.device_fd, gzfd, printblocksonly, 0);
 	printf("File %s %s %s.\n", in_fn,
 	       (printblocksonly ? "print" : "restore"),
 	       (error ? "error" : "successful"));
 	free(savedata);
-	close(in_fd);
+	gzclose(gzfd);
 	if (!printblocksonly)
 		close(sbd.device_fd);
 
diff --git a/gfs2/man/gfs2_edit.8 b/gfs2/man/gfs2_edit.8
index d133956..cade7c8 100644
--- a/gfs2/man/gfs2_edit.8
+++ b/gfs2/man/gfs2_edit.8
@@ -140,7 +140,9 @@ Print program version information only.
 .TP
 \fB-x\fP
 Print in hex mode.
-
+.TP
+\fB-z <0-9>\fP
+Compress metadata with gzip compression level 1 to 9 (default 9). 0 means no compression at all.
 .TP
 \fBrg\fP \fI<rg>\fR \fI<device>\fR
 Print the contents of Resource Group \fI<rg>\fR on \fI<device>\fR.
@@ -171,35 +173,35 @@ that may be contained in the files.  This option works quickly by
 using the system bitmap blocks in the resource groups to determine the
 location of all the metadata.  If there is corruption
 in the bitmaps, resource groups or rindex file, this method may fail and
-you may need to use the savemetaslow option.
-The destination file is not compressed.  You may want to compress it
-with a program such as bzip2 before sending it for analysis.
+you may need to use the savemetaslow option.  The destination file is
+compressed using gzip unless -z 0 is specified.
 .TP
 \fBsavemetaslow\fP \fI<device>\fR \fI<filename>\fR
 Save off GFS2 metadata, as with the savemeta option, examining every
 block in the file system for metadata.  This option is less prone to failure
 due to file system corruption than the savemeta option, but it is 
-extremely slow.
+extremely slow.  The destination file is compressed using gzip unless
+-z 0 is specified.
 .TP
 \fBsavergs\fP \fI<device>\fR \fI<filename>\fR
 Save off only the GFS2 resource group metadata for the file system on the
-specified device to a file given by <filename>.
+specified device to a file given by <filename>.  The destination file is
+compressed using gzip unless -z 0 is specified.
 .TP
 \fBrestoremeta\fP \fI<filename>\fR \fI<dest device>\fR
-Take a file created with the savemeta option and restores its
-contents on top of the specified destination device.  \fBWARNING\fP:
-When you use this option, the file system and all data on the 
-destination device is destroyed.  Since only metadata (but no data) 
-is restored, every file in the resulting file system is likely to be
-corrupt.  The ONLY purpose of this option is to examine and debug file
-system problems by restoring and examining the state of the saved metadata.
-If the destination file system is the same size or larger than the source
-file system where the metadata was saved, the resulting file system
-will be the same size as the source.  If the destination device is
-smaller than the source file system, gfs2_edit will restore as much as
-it can, then quit, leaving you with a file system that probably will not
-mount, but from which you might still be able to figure out what is
-wrong with the source file system.
+Take a compressed or uncompressed file created with the savemeta option and
+restores its contents on top of the specified destination device.
+\fBWARNING\fP: When you use this option, the file system and all data on the
+destination device is destroyed.  Since only metadata (but no data) is
+restored, every file in the resulting file system is likely to be corrupt.  The
+ONLY purpose of this option is to examine and debug file system problems by
+restoring and examining the state of the saved metadata.  If the destination
+file system is the same size or larger than the source file system where the
+metadata was saved, the resulting file system will be the same size as the
+source.  If the destination device is smaller than the source file system,
+gfs2_edit will restore as much as it can, then quit, leaving you with a file
+system that probably will not mount, but from which you might still be able to
+figure out what is wrong with the source file system.
 
 .SH INTERACTIVE MODE
 If you specify a device on the gfs2_edit command line and you specify
-- 
1.7.4.1




More information about the Cluster-devel mailing list