[Cluster-devel] cluster/gfs2/edit hexedit.c hexedit.h savemeta.c

rpeterso at sourceware.org rpeterso at sourceware.org
Thu Oct 18 19:56:42 UTC 2007


CVSROOT:	/cvs/cluster
Module name:	cluster
Changes by:	rpeterso at sourceware.org	2007-10-18 19:56:41

Modified files:
	gfs2/edit      : hexedit.c hexedit.h savemeta.c 

Log message:
	While working on bz #291551, I discovered that gfs2_edit savemeta
	only saved true metadata, but we need more than that.  There are
	lots of blocks that are considered "data" (not metadata) by the
	RG bitmaps that we still need to save.  These include:
	1. All the system journals (which may contain both metadata and
	user data, disguised as data blocks within the journal).  We
	need to pick out the parts that do not contain user data.
	2. The system files, such as statfs, inum, quota file, etc.
	These may be helpful in debugging user problems.
	3. Indirect block pointers, which may be counted as data for
	accounting purposes, even though it's metadata.
	4. Directory leaf blocks.
	
	This change allows gfs2_edit to save and restore these blocks properly,
	and also to print out a breakdown of a saved metadata file:
	gfs2_edit printsavedmeta /tmp/gfsmeta
	
	It also improves on the information given when a journal is dumped.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/edit/hexedit.c.diff?cvsroot=cluster&r1=1.21&r2=1.22
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/edit/hexedit.h.diff?cvsroot=cluster&r1=1.11&r2=1.12
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/edit/savemeta.c.diff?cvsroot=cluster&r1=1.3&r2=1.4

--- cluster/gfs2/edit/hexedit.c	2007/10/12 21:38:18	1.21
+++ cluster/gfs2/edit/hexedit.c	2007/10/18 19:56:41	1.22
@@ -47,8 +47,9 @@
 int display(int identify_only);
 extern void eol(int col);
 extern int do_indirect_extended(char *buf, struct iinfo *ii);
-extern void savemeta(const char *in_fn, const char *out_fn, int slow);
-extern void restoremeta(const char *in_fn, const char *out_device);
+extern void savemeta(const char *out_fn, int slow);
+extern void restoremeta(const char *in_fn, const char *out_device,
+			int printblocksonly);
 
 /* ------------------------------------------------------------------------ */
 /* UpdateSize - screen size changed, so update it                           */
@@ -350,7 +351,7 @@
 /* returns: metatype if block is a GFS2 structure block type                */
 /*          0 if block is not a GFS2 structure                              */
 /* ------------------------------------------------------------------------ */
-int display_block_type(const char *lpBuffer)
+int display_block_type(const char *lpBuffer, int from_restore)
 {
 	int ret_type = 0; /* return type */
 
@@ -375,12 +376,14 @@
 	}
 	else
 		print_gfs2(" ");
-	print_gfs2("of %" PRIu64 " (0x%" PRIX64 ")", max_block, max_block);
-	if (termlines)
-		move(line, 55);
-	else
-		printf(" ");
-
+	if (!from_restore) {
+		print_gfs2("of %" PRIu64 " (0x%" PRIX64 ")", max_block,
+			   max_block);
+		if (termlines)
+			move(line, 55);
+		else
+			printf(" ");
+	}
 	if (block == RGLIST_DUMMY_BLOCK) {
 		ret_type = GFS2_METATYPE_RG;
 		struct_len = sizeof(struct gfs2_rgrp);
@@ -447,6 +450,8 @@
 	else
 		struct_len = 512;
 	eol(0);
+	if (from_restore)
+		return ret_type;
 	if (termlines && dmode == HEX_MODE) {
 		/* calculate how much of the buffer we can fit on screen */
 		screen_chunk_size = ((termlines - 4) * 16) >> 8 << 8;
@@ -616,7 +621,7 @@
 		block = masterblock("rindex");
 	ribh = bread(&sbd, block);
 	riinode = inode_get(&sbd, ribh);
-	printf("%d RGs in this file system.\n",
+	printf("%lld RGs in this file system.\n",
 	       riinode->i_di.di_size / sizeof(struct gfs2_rindex));
 	inode_put(riinode, not_updated);
 	exit(EXIT_SUCCESS);
@@ -661,7 +666,7 @@
 	ribh = bread(&sbd, block);
 	riinode = inode_get(&sbd, ribh);
 	if (rgnum >= riinode->i_di.di_size / sizeof(struct gfs2_rindex)) {
-		fprintf(stderr, "Error: File system only has %d RGs.\n",
+		fprintf(stderr, "Error: File system only has %lld RGs.\n",
 		       riinode->i_di.di_size / sizeof(struct gfs2_rindex));
 		inode_put(riinode, not_updated);
 		brelse(ribh, not_updated);
@@ -671,8 +676,9 @@
 	bh = bread(&sbd, rgblk);
 	gfs2_rgrp_in(&rg, bh->b_data);
 	if (modify) {
-		printf("RG #%d (block %lld / 0x%llx) rg_flags changed from 0x%08x to 0x%08x\n",
-		       rgnum, rgblk, rgblk, rg.rg_flags, new_flags);
+		printf("RG #%d (block %llu / 0x%llx) rg_flags changed from 0x%08x to 0x%08x\n",
+		       rgnum, (unsigned long long)rgblk,
+		       (unsigned long long)rgblk, rg.rg_flags, new_flags);
 		rg.rg_flags = new_flags;
 		gfs2_rgrp_out(&rg, bh->b_data);
 		brelse(bh, updated);
@@ -684,8 +690,9 @@
 			gfs2_rgrp_print(&rg);
 		}
 		else
-			printf("RG #%d (block %lld / 0x%llx) rg_flags = 0x%08x\n",
-			       rgnum, rgblk, rgblk, rg.rg_flags);
+			printf("RG #%d (block %llu / 0x%llx) rg_flags = 0x%08x\n",
+			       rgnum, (unsigned long long)rgblk,
+			       (unsigned long long)rgblk, rg.rg_flags);
 		brelse(bh, not_updated);
 	}
 	inode_put(riinode, not_updated);
@@ -1078,9 +1085,9 @@
 					more_indir = malloc(sizeof(struct iinfo));
 					tmpbuf = malloc(bufsize);
 					if (tmpbuf) {
-						do_lseek(fd,
+						do_lseek(sbd.device_fd,
 							 ind->ii[pndx].block * bufsize);
-						do_read(fd, tmpbuf,
+						do_read(sbd.device_fd, tmpbuf,
 							bufsize); /* read in the desired block */
 						memset(more_indir, 0, sizeof(struct iinfo));
 						more_ind = do_indirect_extended(tmpbuf,
@@ -1278,7 +1285,7 @@
 /* ------------------------------------------------------------------------ */
 /* read_superblock - read the superblock                                    */
 /* ------------------------------------------------------------------------ */
-void read_superblock(void)
+void read_superblock(int fd)
 {
 	int x;
 
@@ -1323,9 +1330,9 @@
 /* ------------------------------------------------------------------------ */
 void read_master_dir(void)
 {
-	ioctl(fd, BLKFLSBUF, 0);
-	do_lseek(fd, sbd.sd_sb.sb_master_dir.no_addr * bufsize);
-	do_read(fd, buf, bufsize); /* read in the desired block */
+	ioctl(sbd.device_fd, BLKFLSBUF, 0);
+	do_lseek(sbd.device_fd, sbd.sd_sb.sb_master_dir.no_addr * bufsize);
+	do_read(sbd.device_fd, buf, bufsize); /* read in the desired block */
 	gfs2_dinode_in(&di, buf); /* parse disk inode into structure */
 	do_dinode_extended(&di, buf); /* get extended data, if any */
 	memcpy(&masterdir, &indirect[0], sizeof(struct indirect_info));
@@ -1348,13 +1355,13 @@
 	}
 	if (block_in_mem != blk) { /* If we changed blocks from the last read */
 		dev_offset = blk * bufsize;
-		ioctl(fd, BLKFLSBUF, 0);
-		do_lseek(fd, dev_offset);
-		do_read(fd, buf, bufsize); /* read in the desired block */
+		ioctl(sbd.device_fd, BLKFLSBUF, 0);
+		do_lseek(sbd.device_fd, dev_offset);
+		do_read(sbd.device_fd, buf, bufsize); /* read desired block */
 		block_in_mem = blk; /* remember which block is in memory */
 	}
 	line = 1;
-	gfs2_struct_type = display_block_type(buf);
+	gfs2_struct_type = display_block_type(buf, FALSE);
 	if (identify_only)
 		return 0;
 	indirect_blocks = 0;
@@ -1615,9 +1622,9 @@
 					ch += (estring[i+1] - 'A' + 0x0a);
 				buf[offset + hexoffset] = ch;
 			}
-			do_lseek(fd, dev_offset);
-			do_write(fd, buf, bufsize);
-			fsync(fd);
+			do_lseek(sbd.device_fd, dev_offset);
+			do_write(sbd.device_fd, buf, bufsize);
+			fsync(sbd.device_fd);
 		}
 	}
 }
@@ -2034,10 +2041,23 @@
 			break;
 		if (get_block_type(jbuf) == GFS2_METATYPE_LD) {
 			uint64_t *b;
-			int i = 0;
+			struct gfs2_log_descriptor ld;
+			int i = 0, ltndx;
+			const char *logtypestr[4] = {
+				"Metadata", "Revoke", "Jdata", "Unknown"};
 
-			print_gfs2("Block #%4llx: Log descriptor",
+			print_gfs2("Block #%4llx: Log descriptor, ",
 				   jb / (gfs1 ? 1 : bufsize));
+			gfs2_log_descriptor_in(&ld, jbuf);
+			print_gfs2("type %d ", ld.ld_type);
+			if (ld.ld_type >= GFS2_LOG_DESC_METADATA &&
+			    ld.ld_type <= GFS2_LOG_DESC_JDATA)
+				ltndx = ld.ld_type - GFS2_LOG_DESC_METADATA;
+			else
+				ltndx = 3;
+			print_gfs2("(%s) ", logtypestr[ltndx]);
+			print_gfs2("len:%u, data1: %u",
+				   ld.ld_length, ld.ld_data1);
 			eol(0);
 			print_gfs2("             ");
 			if (gfs1)
@@ -2083,7 +2103,9 @@
 	fprintf(stderr,"\nFormat is: gfs2_edit [-c 1] [-V] [-x] [-h] [identify] [-p structures|blocks] /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,"savemeta - save off your metadata for analysis and debugging.  The intelligent way (assume bitmap is correct).\n");
+	fprintf(stderr,"printsavedmeta - prints out the saved metadata blocks from a savemeta file.\n");
+	fprintf(stderr,"savemeta <file_system> <file> - save off your metadata for analysis and debugging.\n");
+	fprintf(stderr,"   (The intelligent way: assume bitmap is correct).\n");
 	fprintf(stderr,"savemetaslow - save off your metadata for analysis and debugging.  The SLOW way (block by block).\n");
 	fprintf(stderr,"restoremeta - restore metadata for debugging (DANGEROUS).\n");
 	fprintf(stderr,"rgcount - print how many RGs in the file system.\n");
@@ -2158,18 +2180,21 @@
 				dmode = GFS2_MODE;
 			}
 			else if (!strcasecmp(argv[i], "savemeta"))
-				savemeta(argv[i+1], argv[i+2], FALSE);
+				termlines = 0;
 			else if (!strcasecmp(argv[i], "savemetaslow"))
-				savemeta(argv[i+1], argv[i+2], TRUE);
+				termlines = 0;
+			else if (!strcasecmp(argv[i], "printsavedmeta"))
+				restoremeta(argv[i+1], argv[i+2],
+					    TRUE);
 			else if (!strcasecmp(argv[i], "restoremeta"))
-				restoremeta(argv[i+1], argv[i+2]);
+				restoremeta(argv[i+1], argv[i+2], FALSE);
 			else if (!strcmp(argv[i], "rgcount"))
 				termlines = 0;
 			else if (!strcmp(argv[i], "rgflags"))
 				termlines = 0;
 			else if (!strcmp(argv[i], "rg"))
 				termlines = 0;
-			else if (strchr(argv[i],'/'))
+			else if (!device[0] && strchr(argv[i],'/'))
 				strcpy(device, argv[i]);
 		}
 		else { /* second pass */
@@ -2262,7 +2287,6 @@
 				}
 				else if (!strcmp(argv[i], "rg")) {
 					int rg;
-					uint32_t new_flags = 0;
 					
 					i++;
 					if (i >= argc - 1) {
@@ -2276,6 +2300,10 @@
 					set_rgrp_flags(rg, 0, FALSE, TRUE);
 					exit(EXIT_SUCCESS);
 				}
+				else if (!strcasecmp(argv[i], "savemeta"))
+					savemeta(argv[i+2], FALSE);
+				else if (!strcasecmp(argv[i], "savemetaslow"))
+					savemeta(argv[i+2], TRUE);
 				else if (argv[i][0]=='0' && argv[i][1]=='x') { /* hex addr */
 					sscanf(argv[i], "%"SCNx64, &temp_blk);/* retrieve in hex */
 					push_block(temp_blk);
@@ -2309,7 +2337,7 @@
 ******************************************************************************/
 int main(int argc, char *argv[])
 {
-	int i, j;
+	int i, j, fd;
 
 	prog_name = argv[0];
 
@@ -2348,7 +2376,8 @@
 		die("can't open %s: %s\n", device, strerror(errno));
 	max_block = lseek(fd, 0, SEEK_END) / bufsize;
 
-	read_superblock();
+	read_superblock(fd);
+	strcpy(sbd.device_name, device);
 	if (!gfs1)
 		read_master_dir();
 	block_in_mem = -1;
--- cluster/gfs2/edit/hexedit.h	2007/10/12 15:37:19	1.11
+++ cluster/gfs2/edit/hexedit.h	2007/10/18 19:56:41	1.12
@@ -58,7 +58,6 @@
 #define GFS_FILE_SOCK           (102)  /* socket */
 
 EXTERN char *prog_name;
-EXTERN int fd;
 EXTERN uint64_t block INIT(0);
 EXTERN int blockhist INIT(0);
 EXTERN int edit_mode INIT(0);
@@ -96,6 +95,21 @@
 EXTERN int editing INIT(0);
 EXTERN uint64_t temp_blk;
 
+struct gfs_jindex {
+        uint64_t ji_addr;       /* starting block of the journal */
+        uint32_t ji_nsegment;   /* number (quantity) of segments in journal */
+        uint32_t ji_pad;
+
+        char ji_reserved[64];
+};
+
+EXTERN int block_is_jindex(void);
+EXTERN int block_is_inum_file(void);
+EXTERN int block_is_statfs_file(void);
+EXTERN int block_is_quota_file(void);
+EXTERN int display_block_type(const char *lpBuffer, int from_restore);
+EXTERN void gfs_jindex_in(struct gfs_jindex *jindex, char *buf);
+
 struct gfs2_dirents {
 	uint64_t block;
 	struct gfs2_dirent dirent;
@@ -163,14 +177,6 @@
 	char sb_reserved[96];
 };
 
-struct gfs_jindex {
-        uint64_t ji_addr;       /* starting block of the journal */
-        uint32_t ji_nsegment;   /* number (quantity) of segments in journal */
-        uint32_t ji_pad;
-
-        char ji_reserved[64];
-};
-
 struct gfs_log_descriptor {
 	struct gfs2_meta_header ld_header;
 
--- cluster/gfs2/edit/savemeta.c	2007/10/11 20:27:48	1.3
+++ cluster/gfs2/edit/savemeta.c	2007/10/18 19:56:41	1.4
@@ -31,11 +31,13 @@
 #include <linux/gfs2_ondisk.h>
 
 #include "osi_list.h"
+#include "gfs2hex.h"
 #include "hexedit.h"
 #include "libgfs2.h"
 
 #define BUFSIZE (4096)
 #define DFT_SAVE_FILE "/tmp/gfsmeta"
+#define MAX_JOURNALS_SAVED 256
 
 struct saved_metablock {
 	uint64_t blk;
@@ -46,6 +48,8 @@
 struct saved_metablock *savedata;
 uint64_t last_fs_block, last_reported_block, blks_saved, total_out, pct;
 struct gfs2_block_list *blocklist = NULL;
+uint64_t journal_blocks[MAX_JOURNALS_SAVED];
+int journals_found = 0;
 
 extern void read_superblock(void);
 uint64_t masterblock(const char *fn);
@@ -413,7 +417,7 @@
 		*struct_len = sizeof(struct gfs2_log_header);
 		break;
 	case GFS2_METATYPE_LD:   /* 9 (log descriptor) */
-		*struct_len = sizeof(struct gfs2_log_descriptor);
+		*struct_len = bufsize;
 		break;
 	case GFS2_METATYPE_EA:   /* 10 (extended attr hdr) */
 		*struct_len = sizeof(struct gfs2_ea_header);
@@ -448,30 +452,67 @@
 
 		seconds = tv.tv_sec;
 		if (last_fs_block) {
-			percent = (block * 100) / last_fs_block;
-			printf("\r%" PRIu64 " blocks (%"
-			       PRIu64 "%%) processed, ", block, percent);
-			printf("%" PRIu64 " blocks (%" PRIu64 "MB) %s    ",
-			       blks_saved, total_out / (1024*1024),
-			       save?"saved":"restored");
+			printf("\r");
+			if (save) {
+				percent = (block * 100) / last_fs_block;
+				printf("%" PRIu64 " metadata blocks (%"
+				       PRIu64 "%%) processed, ", block,
+				       percent);
+			}
+			if (total_out < 1024 * 1024)
+				printf("%" PRIu64 " metadata blocks (%"
+				       PRIu64 "KB) %s.    ",
+				       blks_saved, total_out / 1024,
+				       save?"saved":"restored");
+			else
+				printf("%" PRIu64 " metadata blocks (%"
+				       PRIu64 "MB) %s.    ",
+				       blks_saved, total_out / (1024*1024),
+				       save?"saved":"restored");
+			if (force)
+				printf("\n");
 			fflush(stdout);
 		}
 	}
 }
 
-void save_block(int fd, int out_fd, uint64_t blk)
+int block_is_a_journal(void)
+{
+	int j;
+
+	for (j = 0; j < journals_found; j++)
+		if (block == journal_blocks[j])
+			return TRUE;
+	return FALSE;
+}
+
+int block_is_systemfile(void)
+{
+	return block_is_jindex() ||
+		block_is_inum_file() ||
+		block_is_statfs_file() ||
+		block_is_quota_file() ||
+		block_is_a_journal();
+}
+
+int save_block(int fd, int out_fd, uint64_t blk)
 {
 	int blktype, blklen, outsz;
 	uint16_t trailing0;
 	char *p;
 
-	warm_fuzzy_stuff(blk, FALSE, TRUE);
 	memset(savedata, 0, sizeof(struct saved_metablock));
 	do_lseek(fd, blk * bufsize);
 	do_read(fd, savedata->buf, bufsize); /* read in the block */
 
-	if (get_gfs_struct_info(savedata->buf, &blktype, &blklen))
-		return; /* Not metadata, so skip it */
+	/* If this isn't metadata and isn't a system file, we don't want it.
+	   Note that we're checking "block" here rather than blk.  That's
+	   because we want to know if the source inode's "block" is a system
+	   inode, not the block within the inode "blk". They may or may not
+	   be the same thing. */
+	if (get_gfs_struct_info(savedata->buf, &blktype, &blklen) &&
+	    !block_is_systemfile())
+		return 0; /* Not metadata, and not system file, so skip it */
 	trailing0 = 0;
 	p = &savedata->buf[blklen - 1];
 	while (*p=='\0' && trailing0 < bufsize) {
@@ -486,26 +527,169 @@
 	do_write(out_fd, savedata->buf, outsz);
 	total_out += sizeof(savedata->blk) + sizeof(savedata->siglen) + outsz;
 	blks_saved++;
+	return blktype;
+}
+
+/*
+ * save_indirect_blocks - save all indirect blocks for the given buffer
+ */
+void save_indirect_blocks(int out_fd, osi_list_t *cur_list,
+			  struct gfs2_buffer_head *mybh, int height, int hgt)
+{
+	uint64_t old_block = 0;
+	uint64_t *ptr;
+	int head_size;
+	struct gfs2_buffer_head *nbh;
+
+	head_size = (hgt > 1 ?
+		     sizeof(struct gfs2_meta_header) :
+		     sizeof(struct gfs2_dinode));
+
+	for (ptr = (uint64_t *)(mybh->b_data + head_size);
+	     (char *)ptr < (mybh->b_data + mybh->b_size); ptr++) {
+		if (!*ptr)
+			continue;
+		block = be64_to_cpu(*ptr);
+		if (block == old_block)
+			continue;
+		old_block = block;
+		save_block(sbd.device_fd, out_fd, block);
+		if (height != hgt) { /* If not at max height */
+			nbh = bread(&sbd, block);
+			osi_list_add_prev(&nbh->b_altlist,
+					  cur_list);
+			brelse(nbh, not_updated);
+		}
+	} /* for all data on the indirect block */
+}
+
+/*
+ * save_inode_data - save off important data associated with an inode
+ *
+ * out_fd - 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
+ * pointers that reside on blocks on all but the highest height.
+ *
+ * For system files like statfs and inum, we want everything because they
+ * may contain important clues and no user data.
+ *
+ * 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.
+ */
+void save_inode_data(int out_fd)
+{
+	uint32_t height;
+	struct gfs2_inode *inode;
+	osi_list_t metalist[GFS2_MAX_META_HEIGHT];
+	osi_list_t *prev_list, *cur_list, *tmp;
+	struct gfs2_buffer_head *metabh, *mybh;
+	int i;
+	char *buf;
+
+	for (i = 0; i < GFS2_MAX_META_HEIGHT; i++)
+		osi_list_init(&metalist[i]);
+	buf = malloc(bufsize);
+	metabh = bread(&sbd, block);
+	inode = inode_get(&sbd, metabh);
+	height = inode->i_di.di_height;
+	/* If this is a user inode, we don't follow to the file height.
+	   We stop one level less.  That way we save off the indirect
+	   pointer blocks but not the actual file contents. */
+	if (height && !block_is_systemfile())
+		height--;
+	osi_list_add(&metabh->b_altlist, &metalist[0]);
+        for (i = 1; i <= height; i++){
+		prev_list = &metalist[i - 1];
+		cur_list = &metalist[i];
+
+		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,
+					     height, i);
+		} /* for blocks at that height */
+	} /* for height */
+	/* free metalists */
+	for (i = 0; i < GFS2_MAX_META_HEIGHT; i++) {
+		cur_list = &metalist[i];
+		while (!osi_list_empty(cur_list)) {
+			mybh = osi_list_entry(cur_list->next,
+					    struct gfs2_buffer_head,
+					    b_altlist);
+			osi_list_del(&mybh->b_altlist);
+		}
+	}
+	/* Process directory exhash inodes */
+	if (S_ISDIR(inode->i_di.di_mode)) {
+		if (inode->i_di.di_flags & GFS2_DIF_EXHASH) {
+			save_indirect_blocks(out_fd, cur_list, mybh,
+					     height, 0);
+		}
+	}
+	inode_put(inode, not_updated);
+	free(buf);
+}
+
+void get_journal_inode_blocks(void)
+{
+	int journal;
+	struct gfs2_buffer_head *bh;
+
+	journals_found = 0;
+	memset(journal_blocks, 0, sizeof(journal_blocks));
+	/* Save off all the journals--but only the metadata.
+	 * This is confusing so I'll explain.  The journals contain important 
+	 * metadata.  However, in gfs2 the journals are regular files within
+	 * the system directory.  Since they're regular files, the blocks
+	 * within the journals are considered data, not metadata.  Therefore,
+	 * they won't have been saved by the code above.  We want to dump
+	 * these blocks, but we have to be careful.  We only care about the
+	 * journal blocks that look like metadata, and we need to not save
+	 * journaled user data that may exist there as well. */
+	for (journal = 0; ; journal++) { /* while journals exist */
+		uint64_t jblock;
+		int amt;
+		struct gfs2_dinode jdi;
+		struct gfs2_inode *j_inode = NULL;
+
+		if (gfs1) {
+			struct gfs_jindex ji;
+			char jbuf[sizeof(struct gfs_jindex)];
+
+			j_inode = inode_get(&sbd, bh);
+			amt = gfs2_readi(j_inode, (void *)&jbuf,
+					 journal * sizeof(struct gfs_jindex),
+					 sizeof(struct gfs_jindex));
+			if (!amt)
+				break;
+			gfs_jindex_in(&ji, jbuf);
+			jblock = ji.ji_addr;
+			inode_put(j_inode, not_updated);
+		} else {
+			if (journal > indirect->ii[0].dirents - 3)
+				break;
+			jblock = indirect->ii[0].dirent[journal + 2].block;
+			bh = bread(&sbd, jblock);
+			j_inode = inode_get(&sbd, bh);
+			gfs2_dinode_in(&jdi, bh->b_data);
+			inode_put(j_inode, not_updated);
+		}
+		journal_blocks[journals_found++] = jblock;
+	}
 }
 
-void savemeta(const char *in_fn, const char *out_fn, int slow)
+void savemeta(const char *out_fn, int slow)
 {
 	int out_fd;
 	osi_list_t *tmp;
-	uint64_t blk;
 	uint64_t memreq;
 	int rgcount;
+	uint64_t jindex_block;
+	struct gfs2_buffer_head *bh;
 
-	memset(&sbd, 0, sizeof(struct gfs2_sbd));
-	strcpy(sbd.device_name, in_fn);
-	sbd.bsize = GFS2_DEFAULT_BSIZE;
-	sbd.rgsize = -1;
-	sbd.jsize = GFS2_DEFAULT_JSIZE;
-	sbd.qcsize = GFS2_DEFAULT_QCSIZE;
 	sbd.md.journals = 1;
-	sbd.device_fd = open(in_fn, O_RDONLY);
-	if (sbd.device_fd < 0)
-		die("Can't open %s: %s\n", in_fn, strerror(errno));
 
 	if (!out_fn)
 		out_fn = DFT_SAVE_FILE;
@@ -513,6 +697,8 @@
 	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));
 	savedata = malloc(sizeof(struct saved_metablock));
 	if (!savedata)
 		die("Can't allocate memory for the operation.\n");
@@ -540,18 +726,25 @@
 	printf("There are %" PRIu64 " blocks of %" PRIu64 " bytes.\n\n",
 	       last_fs_block, bufsize);
 	if (!slow) {
-		if (gfs1)
+		if (gfs1) {
 			sbd.md.riinode =
 				gfs2_load_inode(&sbd,
 						sbd1->sb_rindex_di.no_addr);
-		else {
+			jindex_block = sbd1->sb_jindex_di.no_addr;
+		} else {
 			sbd.master_dir =
 				gfs2_load_inode(&sbd,
 						sbd.sd_sb.sb_master_dir.no_addr);
 
 			slow = gfs2_lookupi(sbd.master_dir, "rindex", 6, 
 					    &sbd.md.riinode);
+			jindex_block = masterblock("jindex");
 		}
+		bh = bread(&sbd, jindex_block);
+		gfs2_dinode_in(&di, bh->b_data);
+		if (!gfs1)
+			do_dinode_extended(&di, bh->b_data);
+		brelse(bh, not_updated);
 	}
 	if (!slow) {
 		if (gfs1)
@@ -564,8 +757,11 @@
 		if (!blocklist)
 			slow = TRUE;
 	}
+	get_journal_inode_blocks();
 	if (!slow) {
+		/* Save off the superblock */
 		save_block(sbd.device_fd, out_fd, 0x10 * (4096 / bufsize));
+		/* Walk through the resource groups saving everything within */
 		for (tmp = sbd.rglist.next; tmp != &sbd.rglist;
 		     tmp = tmp->next){
 			struct rgrp_list *rgd;
@@ -585,28 +781,37 @@
 			}
 			first = 1;
 			/* Save off the rg and bitmaps */
-			for (blk = rgd->ri.ri_addr;
-			     blk < rgd->ri.ri_data0; blk++)
-				save_block(sbd.device_fd, out_fd, blk);
+			for (block = rgd->ri.ri_addr;
+			     block < rgd->ri.ri_data0; block++) {
+				warm_fuzzy_stuff(block, FALSE, TRUE);
+				save_block(sbd.device_fd, out_fd, block);
+			}
 			/* Save off the other metadata: inodes, etc. */
-			while (!gfs2_next_rg_meta(rgd, &blk, first)) {
-				save_block(sbd.device_fd, out_fd, blk);
+			while (!gfs2_next_rg_meta(rgd, &block, first)) {
+				int blktype;
+
+				warm_fuzzy_stuff(block, FALSE, TRUE);
+				blktype = save_block(sbd.device_fd, out_fd,
+						     block);
+				if (blktype == GFS2_METATYPE_DI)
+					save_inode_data(out_fd);
 				first = 0;
 			}
 			gfs2_rgrp_relse(rgd, not_updated);
 		}
 	}
 	if (slow) {
-		for (blk = 0; blk < last_fs_block; blk++) {
-			save_block(sbd.device_fd, out_fd, blk);
+		for (block = 0; block < last_fs_block; block++) {
+			save_block(sbd.device_fd, out_fd, block);
 		}
 	}
+	/* Clean up */
 	if (blocklist)
 		gfs2_block_list_destroy(blocklist);
 	/* There may be a gap between end of file system and end of device */
 	/* so we tell the user that we've processed everything. */
-	blk = last_fs_block;
-	warm_fuzzy_stuff(blk, TRUE, TRUE);
+	block = last_fs_block;
+	warm_fuzzy_stuff(block, TRUE, TRUE);
 	printf("\nMetadata saved to file %s.\n", out_fn);
 	free(savedata);
 	close(out_fd);
@@ -614,16 +819,16 @@
 	exit(0);
 }
 
-int restore_data(int fd, int in_fd)
+int restore_data(int fd, int in_fd, int printblocksonly)
 {
 	size_t rs;
 	uint64_t buf64, writes = 0;
 	uint16_t buf16;
 	int first = 1;
 
-	do_lseek(fd, 0);
-	blks_saved = 0;
-	total_out = 0;
+	if (!printblocksonly)
+		do_lseek(fd, 0);
+	blks_saved = total_out = 0;
 	last_fs_block = 0;
 	while (TRUE) {
 		memset(savedata, 0, sizeof(struct saved_metablock));
@@ -634,8 +839,10 @@
 			fprintf(stderr, "Error reading from file.\n");
 			return -1;
 		}
+		total_out += bufsize;
 		savedata->blk = be64_to_cpu(buf64);
-		if (last_fs_block && savedata->blk >= last_fs_block) {
+		if (!printblocksonly &&
+		    last_fs_block && savedata->blk >= last_fs_block) {
 			fprintf(stderr, "Error: File system is too small to "
 				"restore this metadata.\n");
 			fprintf(stderr, "File system is %" PRIu64 " blocks, ",
@@ -646,7 +853,6 @@
 		}
 		rs = read(in_fd, &buf16, sizeof(uint16_t));
 		savedata->siglen = be16_to_cpu(buf16);
-		total_out += rs + savedata->siglen;
 		if (savedata->siglen > 0 &&
 		    savedata->siglen <= sizeof(savedata->buf)) {
 			do_read(in_fd, savedata->buf, savedata->siglen);
@@ -666,23 +872,33 @@
 					return -1;
 				}
 				bufsize = sbd.sd_sb.sb_bsize;
-				last_fs_block =
-					lseek(fd, 0, SEEK_END) / bufsize;
-				printf("There are %" PRIu64 " blocks of %" \
-				       PRIu64 " bytes in the destination" \
-				       " file system.\n\n",
-				       last_fs_block, bufsize);
+				if (!printblocksonly) {
+					last_fs_block =
+						lseek(fd, 0, SEEK_END) /
+						bufsize;
+					printf("There are %" PRIu64 " blocks of %" \
+					       PRIu64 " bytes in the destination" \
+					       " file system.\n\n",
+					       last_fs_block, bufsize);
+				}
 				first = 0;
 			}
-			warm_fuzzy_stuff(savedata->blk, FALSE, FALSE);
-			if (savedata->blk >= last_fs_block) {
-				printf("Out of space on the destination "
-				       "device; quitting.\n");
-				break;
+			if (printblocksonly) {
+				print_gfs2("%d (l=0x%x): ", blks_saved,
+					   savedata->siglen);
+				block = savedata->blk;
+				display_block_type(savedata->buf, TRUE);
+			} else {
+				warm_fuzzy_stuff(savedata->blk, FALSE, FALSE);
+				if (savedata->blk >= last_fs_block) {
+					printf("Out of space on the destination "
+					       "device; quitting.\n");
+					break;
+				}
+				do_lseek(fd, savedata->blk * bufsize);
+				do_write(fd, savedata->buf, bufsize);
+				writes++;
 			}
-			do_lseek(fd, savedata->blk * bufsize);
-			do_write(fd, savedata->buf, bufsize);
-			writes++;
 			blks_saved++;
 		} else {
 			fprintf(stderr, "Bad record length: %d for #%"
@@ -690,44 +906,52 @@
 			return -1;
 		}
 	}
-	warm_fuzzy_stuff(savedata->blk, TRUE, FALSE);
-	printf("%" PRIu64 " blocks restored.\n", writes);
+	if (!printblocksonly)
+		warm_fuzzy_stuff(savedata->blk, TRUE, FALSE);
 	return 0;
 }
 
-void restoremeta(const char *in_fn, const char *out_device)
+void complain(const char *complaint)
+{
+	fprintf(stderr, "%s\n", complaint);
+	die("Format is: \ngfs2_edit restoremeta <file to restore> "
+	    "<dest file system>\n");
+}
+
+void restoremeta(const char *in_fn, const char *out_device,
+		 int printblocksonly)
 {
-	int in_fd;
+	int in_fd, error;
 
+	termlines = 0;
 	if (!in_fn)
-		die("No source file specified.  Format is: \ngfs2_edit "
-		    "restoremeta <file to restore> <dest file system>\n");
-	if (!out_device)
-		die("No destination file system specified.  Format is: \n"
-		    "gfs2_edit restoremeta <file to restore> <dest file "
-		    "system>\n");
+		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)
 		die("Can't open source file %s: %s\n",
 		    in_fn, strerror(errno));
 
-	fd = open(out_device, O_RDWR);
-	if (fd < 0)
-		die("Can't open destination file system %s: %s\n",
-		    out_device, strerror(errno));
-
+	if (!printblocksonly) {
+		sbd.device_fd = open(out_device, O_RDWR);
+		if (sbd.device_fd < 0)
+			die("Can't open destination file system %s: %s\n",
+			    out_device, strerror(errno));
+	}
 	savedata = malloc(sizeof(struct saved_metablock));
 	if (!savedata)
 		die("Can't allocate memory for the restore operation.\n");
 
-	blks_saved = total_out = 0;
-	if (restore_data(fd, in_fd) == 0)
-		printf("File %s restore successful.\n", in_fn);
-	else
-		printf("File %s restore error.\n", in_fn);
+	blks_saved = 0;
+	error = restore_data(sbd.device_fd, in_fd, printblocksonly);
+	printf("File %s %s %s.\n", in_fn,
+	       (printblocksonly ? "print" : "restore"),
+	       (error ? "error" : "successful"));
 	free(savedata);
 	close(in_fd);
-	close(fd);
+	if (!printblocksonly)
+		close(sbd.device_fd);
 
 	exit(0);
 }




More information about the Cluster-devel mailing list