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

Andrew Price anprice at redhat.com
Thu Apr 14 17:08:59 UTC 2011


savemeta now outputs a gzip-compressed file by default and there is a
-nocompress option to turn off compression. restoremeta can restore from a
gzip-compressed or raw metadata file without any extra options.

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

Adds a dependency on zlib.

rhbz#695767

Signed-off-by: Andrew Price <anprice at redhat.com>
---
 configure.ac          |    1 +
 gfs2/edit/Makefile.am |    4 +-
 gfs2/edit/hexedit.c   |   16 +++--
 gfs2/edit/hexedit.h   |    2 +-
 gfs2/edit/savemeta.c  |  211 +++++++++++++++++++++++++++++++++++-------------
 gfs2/man/gfs2_edit.8  |   42 +++++-----
 6 files changed, 190 insertions(+), 86 deletions(-)

diff --git a/configure.ac b/configure.ac
index 10bcc95..3fc02d0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -119,6 +119,7 @@ PKG_CHECK_MODULES([cfg],[libcfg])
 PKG_CHECK_MODULES([fenced],[libfenced])
 PKG_CHECK_MODULES([dlmcontrol],[libdlmcontrol])
 PKG_CHECK_MODULES([quorum],[libquorum])
+PKG_CHECK_MODULES([zlib],[zlib])
 
 # old versions of ncurses don't ship pkg-config files
 PKG_CHECK_MODULES([ncurses],[ncurses],,
diff --git a/gfs2/edit/Makefile.am b/gfs2/edit/Makefile.am
index 9701c91..c4814dc 100644
--- a/gfs2/edit/Makefile.am
+++ b/gfs2/edit/Makefile.am
@@ -10,8 +10,8 @@ gfs2_edit_CPPFLAGS	= -D_FILE_OFFSET_BITS=64 -DHELPER_PROGRAM \
 			  -I$(top_srcdir)/gfs2/include \
 			  -I$(top_srcdir)/gfs2/libgfs2
 
-gfs2_edit_CFLAGS	= $(ncurses_CFLAGS)
+gfs2_edit_CFLAGS	= $(ncurses_CFLAGS) $(zlib_CFLAGS)
 
-gfs2_edit_LDFLAGS	= $(ncurses_LIBS)
+gfs2_edit_LDFLAGS	= $(ncurses_LIBS) $(zlib_LIBS)
 
 gfs2_edit_LDADD		= $(top_builddir)/gfs2/libgfs2/libgfs2.la
diff --git a/gfs2/edit/hexedit.c b/gfs2/edit/hexedit.c
index d8f8841..8f0630b 100644
--- a/gfs2/edit/hexedit.c
+++ b/gfs2/edit/hexedit.c
@@ -41,6 +41,7 @@ struct gfs2_log_header *llh;
 struct gfs2_log_descriptor *lld;
 int pgnum;
 int details = 0;
+int compressmeta = 1;
 
 int display(int identify_only);
 
@@ -3294,7 +3295,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] [-nocompress] [-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");
@@ -3335,6 +3336,7 @@ 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,"-nocompress  don't compress savemeta/savergs output\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");
@@ -3361,8 +3363,8 @@ 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 -nocompress savemeta /dev/vg/lv /tmp/metasave\n");
 }/* usage */
 
 /* ------------------------------------------------------------------------ */
@@ -3395,6 +3397,8 @@ static void parameterpass1(int argc, char *argv[], int i)
 	else if (!strcasecmp(argv[i], "-d") ||
 		 !strcasecmp(argv[i], "-details"))
 		details = 1;
+	else if (!strcasecmp(argv[i], "-nocompress"))
+		compressmeta = 0;
 	else if (!strcasecmp(argv[i], "savemeta"))
 		termlines = 0;
 	else if (!strcasecmp(argv[i], "savemetaslow"))
@@ -3559,11 +3563,11 @@ static void process_parameters(int argc, char *argv[], int pass)
 			}
 		}
 		else if (!strcasecmp(argv[i], "savemeta"))
-			savemeta(argv[i+2], 0);
+			savemeta(argv[i+2], 0, compressmeta);
 		else if (!strcasecmp(argv[i], "savemetaslow"))
-			savemeta(argv[i+2], 1);
+			savemeta(argv[i+2], 1, compressmeta);
 		else if (!strcasecmp(argv[i], "savergs"))
-			savemeta(argv[i+2], 2);
+			savemeta(argv[i+2], 2, compressmeta);
 		else if (isdigit(argv[i][0])) { /* decimal addr */
 			sscanf(argv[i], "%"SCNd64, &temp_blk);
 			push_block(temp_blk);
diff --git a/gfs2/edit/hexedit.h b/gfs2/edit/hexedit.h
index a7a3109..53a6670 100644
--- a/gfs2/edit/hexedit.h
+++ b/gfs2/edit/hexedit.h
@@ -341,7 +341,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 compressmeta);
 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 4d9f591..b96537e 100644
--- a/gfs2/edit/savemeta.c
+++ b/gfs2/edit/savemeta.c
@@ -18,6 +18,7 @@
 #include <limits.h>
 #include <sys/time.h>
 #include <linux/gfs2_ondisk.h>
+#include <zlib.h>
 
 #include "osi_list.h"
 #include "gfs2hex.h"
@@ -34,6 +35,13 @@ struct saved_metablock {
 	char buf[BUFSIZE];
 };
 
+struct metafd {
+	int fd;
+	gzFile gzfd;
+	const char *filename;
+	int compressed;
+};
+
 struct saved_metablock *savedata;
 uint64_t last_fs_block, last_reported_block, blks_saved, total_out, pct;
 uint64_t journal_blocks[MAX_JOURNALS_SAVED];
@@ -193,7 +201,98 @@ 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
+ * compressed: 0 - do not compress the file, 1 - compress the file
+ * Returns a struct metafd containing the opened file descriptor
+ */
+static struct metafd savemetaopen(char *out_fn, int compressed)
+{
+	struct metafd mfd;
+
+	if (!out_fn) {
+		out_fn = strdup(DFT_SAVE_FILE);
+		if (!out_fn) {
+			fprintf(stderr, "Can't allocate memory for the operation.\n");
+			exit(1);
+		}
+		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);
+	}
+
+	mfd.compressed = compressed;
+	if (compressed) {
+		mfd.gzfd = gzdopen(mfd.fd, "rwb5");
+		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->compressed) {
+		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->compressed) {
+		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;
@@ -228,7 +327,7 @@ static int save_block(int fd, int out_fd, uint64_t blk)
 		p--;
 	}
 	savedata->blk = cpu_to_be64(blk);
-	if (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),
@@ -239,7 +338,7 @@ static int save_block(int fd, int out_fd, uint64_t blk)
 	}
 	outsz = blklen - trailing0;
 	savedata->siglen = cpu_to_be16(outsz);
-	if (write(out_fd, &savedata->siglen, sizeof(savedata->siglen)) !=
+	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),
@@ -248,7 +347,7 @@ static int save_block(int fd, int out_fd, uint64_t blk)
 			(unsigned long long)savedata->blk);
 		exit(-1);
 	}
-	if (write(out_fd, savedata->buf, outsz) != outsz) {
+	if (savemetawrite(mfd, savedata->buf, outsz) != outsz) {
 		fprintf(stderr, "write error: %s from %s:%d: "
 			"block %lld (0x%llx)\n", strerror(errno),
 			__FUNCTION__, __LINE__,
@@ -265,7 +364,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;
@@ -283,7 +382,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;
@@ -294,7 +393,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;
@@ -314,10 +413,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 */
@@ -333,7 +432,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
@@ -345,7 +444,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;
@@ -382,7 +481,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 */
@@ -410,7 +509,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);
 		}
 	}
@@ -419,17 +518,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 "
@@ -529,32 +628,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 compressmeta)
 {
-	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));
+	mfd = savemetaopen(out_fn, compressmeta);
 
-	if (ftruncate(out_fd, 0))
-		die("Can't truncate %s: %s\n", out_fn, strerror(errno));
 	savedata = malloc(sizeof(struct saved_metablock));
 	if (!savedata)
 		die("Can't allocate memory for the operation.\n");
@@ -649,15 +737,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);
@@ -665,7 +753,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 */
@@ -687,7 +775,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) {
@@ -696,9 +784,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.
@@ -707,7 +795,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;
 				}
 			}
@@ -716,7 +804,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 */
@@ -724,28 +812,28 @@ 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.\n", mfd.filename);
 	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)
 		lseek(fd, 0, SEEK_SET);
-	lseek(in_fd, 0, SEEK_SET);
-	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;
@@ -759,7 +847,7 @@ static int restore_data(int fd, int in_fd, int printblocksonly,
 	}
 	if (pos == sizeof(rdbuf) - sizeof(uint64_t) - sizeof(uint16_t))
 		pos = 0;
-	if (lseek(in_fd, pos, SEEK_SET) != 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,
@@ -772,7 +860,7 @@ static int restore_data(int fd, int in_fd, int printblocksonly,
 		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)) {
@@ -791,7 +879,15 @@ static int restore_data(int fd, int in_fd, int printblocksonly,
 				(unsigned long long)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 #%llu"
@@ -801,11 +897,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);
@@ -910,15 +1006,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));
 
@@ -935,13 +1032,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 2546c7b..c5489a5 100644
--- a/gfs2/man/gfs2_edit.8
+++ b/gfs2/man/gfs2_edit.8
@@ -138,7 +138,9 @@ Print program version information only.
 .TP
 \fB-x\fP
 Print in hex mode.
-
+.TP
+\fB-nocompress\fP
+Do not compress metadata.
 .TP
 \fBrg\fP \fI<rg>\fR \fI<device>\fR
 Print the contents of Resource Group \fI<rg>\fR on \fI<device>\fR.
@@ -169,35 +171,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 -nocompress 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
+-nocompress 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 -nocompress 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.2




More information about the Cluster-devel mailing list