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

Steven Whitehouse swhiteho at redhat.com
Thu Sep 29 11:26:04 UTC 2011


Hi,

ACK. Looks good to me,

Steve.

On Wed, 2011-09-28 at 17:44 +0100, Andrew Price wrote:
> 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





More information about the Cluster-devel mailing list