gfs2_edit: Add compression to savemeta and restoremeta
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.
");
+ fprintf(stderr,"
Format 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
");
fprintf(stderr,"If only the device is specified, it enters into hexedit mode.
");
fprintf(stderr,"identify - prints out only the block type, not the details.
");
fprintf(stderr,"printsavedmeta - prints out the saved metadata blocks from a savemeta file.
");
@@ -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>
");
fprintf(stderr," <b> specifies the starting block for search
");
+ fprintf(stderr,"-nocompress don't compress savemeta/savergs output
");
fprintf(stderr,"-s specifies a starting block such as root, rindex, quota, inum.
");
fprintf(stderr,"-x print in hexmode.
");
fprintf(stderr,"-h prints this help.
");
@@ -3361,8 +3363,8 @@ static void usage(void)
fprintf(stderr," gfs2_edit -p quota find di /dev/x/y
");
fprintf(stderr," To set the Resource Group flags for rg #7 to 3.
");
fprintf(stderr," gfs2_edit rgflags 7 3 /dev/sdc2
");
- fprintf(stderr," To save off all metadata for /dev/vg/lv:
");
- fprintf(stderr," gfs2_edit savemeta /dev/vg/lv /tmp/metasave
");
+ fprintf(stderr," To save off all metadata for /dev/vg/lv without compression:
");
+ fprintf(stderr," gfs2_edit -nocompress savemeta /dev/vg/lv /tmp/metasave
");
}/* usage */
-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.
");
- 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
", out_fn, strerror(errno));
+ mfd = savemetaopen(out_fn, compressmeta);
- if (ftruncate(out_fd, 0))
- die("Can't truncate %s: %s
", out_fn, strerror(errno));
savedata = malloc(sizeof(struct saved_metablock));
if (!savedata)
die("Can't allocate memory for the operation.
");
@@ -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
", 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("
Metadata saved to file %s.
", out_fn);
+ printf("
Metadata saved to file %s.
", 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.
");
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)
", 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)
",
+ 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, "
Bad 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)
",
- 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
",
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.
");
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-xfP
Print in hex mode.
-
+.TP
+fB-nocompressfP
+Do not compress metadata.
.TP
fBrgfP 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
fBsavemetaslowfP 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
fBsavergsfP 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
fBrestoremetafP 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. fBWARNINGfP:
-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.
+fBWARNINGfP: 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