[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