public inbox for cluster-cvs@sourceware.org
help / color / mirror / Atom feed
* STABLE2 - GFS2: gfs2_edit savemeta doesn't work with GFS
@ 2008-11-14 15:34 Bob Peterson
  0 siblings, 0 replies; only message in thread
From: Bob Peterson @ 2008-11-14 15:34 UTC (permalink / raw)
  To: cluster-cvs-relay

Gitweb:        http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=f366a20cbc9552252cc334c9e4051dd0e038fc40
Commit:        f366a20cbc9552252cc334c9e4051dd0e038fc40
Parent:        73dd815c96248718d57f874d36d50aa146b32daa
Author:        Bob Peterson <rpeterso@redhat.com>
AuthorDate:    Fri Nov 14 09:25:45 2008 -0600
Committer:     Bob Peterson <rpeterso@redhat.com>
CommitterDate: Fri Nov 14 09:33:25 2008 -0600

GFS2: gfs2_edit savemeta doesn't work with GFS

bz 471239

This patch fixes several problems when saving and restoring
GFS and GFS2 metadata when the block size is not the default
of 4K.  Some of the problems fixed:  (1). GFS and GFS2 have
different starting offsets and lengths for indirect block
pointers.  This required a number of code adjustments.
(2). The journal index information is kept differently in GFS,
so I had to change how the journal index buffers were managed.
(3). The GFS dinode structure is slightly different from GFS2
and that was throwing off calculations because the di_height
value was in the wrong location.  Smaller block sizes made it
worse (more blocks and a bigger height required for the same
information).  (4) GFS1 indirect pointer blocks look like
metadata whereas GFS2's do not.  As a result, gfs2_edit was
improperly truncating those blocks for GFS1 (trying to avoid
capturing user data versus metadata).
---
 gfs2/edit/hexedit.c  |   31 +++++++++++++
 gfs2/edit/hexedit.h  |   47 ++++++++++++++++++++
 gfs2/edit/savemeta.c |  116 +++++++++++++++++++++++++++++++++++++++++++------
 3 files changed, 179 insertions(+), 15 deletions(-)

diff --git a/gfs2/edit/hexedit.c b/gfs2/edit/hexedit.c
index 6ee9bab..01d3cfb 100644
--- a/gfs2/edit/hexedit.c
+++ b/gfs2/edit/hexedit.c
@@ -696,6 +696,37 @@ void gfs_rgrp_out(struct gfs_rgrp *rgrp, char *buf)
 }
 
 /* ------------------------------------------------------------------------ */
+/* gfs_dinode_in */
+/* ------------------------------------------------------------------------ */
+void gfs_dinode_in(struct gfs_dinode *di, char *buf)
+{
+	struct gfs_dinode *str = (struct gfs_dinode *)buf;
+
+	gfs2_meta_header_in(&di->di_header, buf);
+	gfs2_inum_in(&di->di_num, (char *)&str->di_num);
+
+	di->di_mode = be32_to_cpu(str->di_mode);
+	di->di_uid = be32_to_cpu(str->di_uid);
+	di->di_gid = be32_to_cpu(str->di_gid);
+	di->di_nlink = be32_to_cpu(str->di_nlink);
+	di->di_size = be64_to_cpu(str->di_size);
+	di->di_blocks = be64_to_cpu(str->di_blocks);
+	di->di_atime = be64_to_cpu(str->di_atime);
+	di->di_mtime = be64_to_cpu(str->di_mtime);
+	di->di_ctime = be64_to_cpu(str->di_ctime);
+	di->di_major = be32_to_cpu(str->di_major);
+	di->di_minor = be32_to_cpu(str->di_minor);
+	di->di_goal_dblk = be64_to_cpu(str->di_goal_dblk);
+	di->di_goal_mblk = be64_to_cpu(str->di_goal_mblk);
+	di->di_flags = be32_to_cpu(str->di_flags);
+	di->di_payload_format = be32_to_cpu(str->di_payload_format);
+	di->di_height = be16_to_cpu(str->di_height);
+	di->di_depth = be16_to_cpu(str->di_depth);
+	di->di_entries = be32_to_cpu(str->di_entries);
+	di->di_eattr = be64_to_cpu(str->di_eattr);
+}
+
+/* ------------------------------------------------------------------------ */
 /* gfs_rgrp_print - print a gfs1 resource group                             */
 /* ------------------------------------------------------------------------ */
 void gfs_rgrp_print(struct gfs_rgrp *rg)
diff --git a/gfs2/edit/hexedit.h b/gfs2/edit/hexedit.h
index 8992072..98a0a7b 100644
--- a/gfs2/edit/hexedit.h
+++ b/gfs2/edit/hexedit.h
@@ -156,6 +156,52 @@ struct gfs_rgrp {
 	char rg_reserved[64];
 };
 
+struct gfs_dinode {
+	struct gfs2_meta_header di_header;
+
+	struct gfs2_inum di_num; /* formal inode # and block address */
+
+	uint32_t di_mode;	/* mode of file */
+	uint32_t di_uid;	/* owner's user id */
+	uint32_t di_gid;	/* owner's group id */
+	uint32_t di_nlink;	/* number (qty) of links to this file */
+	uint64_t di_size;	/* number (qty) of bytes in file */
+	uint64_t di_blocks;	/* number (qty) of blocks in file */
+	int64_t di_atime;	/* time last accessed */
+	int64_t di_mtime;	/* time last modified */
+	int64_t di_ctime;	/* time last changed */
+
+	/*  Non-zero only for character or block device nodes  */
+	uint32_t di_major;	/* device major number */
+	uint32_t di_minor;	/* device minor number */
+
+	/*  Block allocation strategy  */
+	uint64_t di_rgrp;	/* dinode rgrp block number */
+	uint64_t di_goal_rgrp;	/* rgrp to alloc from next */
+	uint32_t di_goal_dblk;	/* data block goal */
+	uint32_t di_goal_mblk;	/* metadata block goal */
+
+	uint32_t di_flags;	/* GFS_DIF_... */
+
+	/*  struct gfs_rindex, struct gfs_jindex, or struct gfs_dirent */
+	uint32_t di_payload_format;  /* GFS_FORMAT_... */
+	uint16_t di_type;	/* GFS_FILE_... type of file */
+	uint16_t di_height;	/* height of metadata (0 == stuffed) */
+	uint32_t di_incarn;	/* incarnation (unused, see gfs_meta_header) */
+	uint16_t di_pad;
+
+	/*  These only apply to directories  */
+	uint16_t di_depth;	/* Number of bits in the table */
+	uint32_t di_entries;	/* The # (qty) of entries in the directory */
+
+	/*  This formed an on-disk chain of unused dinodes  */
+	struct gfs2_inum di_next_unused;  /* used in old versions only */
+
+	uint64_t di_eattr;	/* extended attribute block number */
+
+	char di_reserved[56];
+};
+
 EXTERN int block_is_jindex(void);
 EXTERN int block_is_rindex(void);
 EXTERN int block_is_inum_file(void);
@@ -165,6 +211,7 @@ EXTERN int display_block_type(const char *lpBuffer, int from_restore);
 EXTERN void gfs_jindex_in(struct gfs_jindex *jindex, char *buf);
 EXTERN void gfs_log_header_in(struct gfs_log_header *head, char *buf);
 EXTERN void gfs_log_header_print(struct gfs_log_header *lh);
+EXTERN void gfs_dinode_in(struct gfs_dinode *di, char *buf);
 
 struct gfs2_dirents {
 	uint64_t block;
diff --git a/gfs2/edit/savemeta.c b/gfs2/edit/savemeta.c
index 901d28c..2cee71c 100644
--- a/gfs2/edit/savemeta.c
+++ b/gfs2/edit/savemeta.c
@@ -68,7 +68,7 @@ metapointer(struct gfs2_buffer_head *bh, unsigned int height,
 			struct metapath *mp)
 {
 	unsigned int head_size = (height > 0) ?
-		sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_dinode);
+		sizeof(struct gfs_indirect) : sizeof(struct gfs_dinode);
 
 	return ((uint64_t *)(bh->b_data + head_size)) + mp->mp_list[height];
 }
@@ -199,7 +199,7 @@ int gfs1_readi(struct gfs2_inode *ip, void *buf,
 {
 	struct gfs2_sbd *sdp = ip->i_sbd;
 	struct gfs2_buffer_head *bh;
-	uint64_t lblock, dblock;
+	uint64_t lblock, dblock = 0;
 	uint32_t extlen = 0;
 	unsigned int amount;
 	int not_new = 0;
@@ -224,7 +224,7 @@ int gfs1_readi(struct gfs2_inode *ip, void *buf,
 	}
 
 	if (!ip->i_di.di_height) /* stuffed */
-		offset += sizeof(struct gfs2_dinode);
+		offset += sizeof(struct gfs_dinode);
 	else if (journaled)
 		offset += sizeof(struct gfs2_meta_header);
 
@@ -344,6 +344,10 @@ int gfs1_ri_update(struct gfs2_sbd *sdp, int fd, int *rgcount)
 		else
 			gfs2_rgrp_relse(rgd, f);
 		count2++;
+		if (count2 % 100 == 0) {
+			printf(".");
+			fflush(stdout);
+		}
 	}
 
 	*rgcount = count1;
@@ -400,7 +404,13 @@ int get_gfs_struct_info(char *buf, int *block_type, int *struct_len)
 		*struct_len = sbd.bsize; /*sizeof(struct gfs_leaf);*/
 		break;
 	case GFS2_METATYPE_JD:   /* 7 (journal data) */
-		*struct_len = sizeof(struct gfs2_meta_header);
+		/* GFS1 keeps indirect pointers in GFS2_METATYPE_JD blocks
+		   so we need to save the whole block.  For GFS2, we don't
+		   want to, or we might capture user data, which is bad.  */
+		if (gfs1)
+			*struct_len = sbd.bsize;
+		else
+			*struct_len = sizeof(struct gfs2_meta_header);
 		break;
 	case GFS2_METATYPE_LH:   /* 8 (log header) */
 		*struct_len = sizeof(struct gfs2_log_header);
@@ -559,6 +569,42 @@ void save_indirect_blocks(int out_fd, osi_list_t *cur_list,
 	} /* for all data on the indirect block */
 }
 
+struct gfs2_inode *gfs_inode_get(struct gfs2_sbd *sdp,
+				 struct gfs2_buffer_head *bh)
+{
+	struct gfs_dinode gfs1_dinode;
+	struct gfs2_inode *ip;
+
+	zalloc(ip, sizeof(struct gfs2_inode));
+	gfs_dinode_in(&gfs1_dinode, bh->b_data);
+	memcpy(&ip->i_di.di_header, &gfs1_dinode.di_header,
+	       sizeof(struct gfs2_meta_header));
+	memcpy(&ip->i_di.di_num, &gfs1_dinode.di_num,
+	       sizeof(struct gfs2_inum));
+	ip->i_di.di_mode = gfs1_dinode.di_mode;
+	ip->i_di.di_uid = gfs1_dinode.di_uid;
+	ip->i_di.di_gid = gfs1_dinode.di_gid;
+	ip->i_di.di_nlink = gfs1_dinode.di_nlink;
+	ip->i_di.di_size = gfs1_dinode.di_size;
+	ip->i_di.di_blocks = gfs1_dinode.di_blocks;
+	ip->i_di.di_atime = gfs1_dinode.di_atime;
+	ip->i_di.di_mtime = gfs1_dinode.di_mtime;
+	ip->i_di.di_ctime = gfs1_dinode.di_ctime;
+	ip->i_di.di_major = gfs1_dinode.di_major;
+	ip->i_di.di_minor = gfs1_dinode.di_minor;
+	ip->i_di.di_goal_data = gfs1_dinode.di_goal_dblk;
+	ip->i_di.di_goal_meta = gfs1_dinode.di_goal_mblk;
+	ip->i_di.di_flags = gfs1_dinode.di_flags;
+	ip->i_di.di_payload_format = gfs1_dinode.di_payload_format;
+	ip->i_di.di_height = gfs1_dinode.di_height;
+	ip->i_di.di_depth = gfs1_dinode.di_depth;
+	ip->i_di.di_entries = gfs1_dinode.di_entries;
+	ip->i_di.di_eattr = gfs1_dinode.di_eattr;
+	ip->i_bh = bh;
+	ip->i_sbd = sdp;
+	return ip;
+}
+
 /*
  * save_inode_data - save off important data associated with an inode
  *
@@ -588,7 +634,10 @@ void save_inode_data(int out_fd)
 		osi_list_init(&metalist[i]);
 	buf = malloc(sbd.bsize);
 	metabh = bread(&sbd, block);
-	inode = inode_get(&sbd, metabh);
+	if (gfs1)
+		inode = inode_get(&sbd, metabh);
+	else
+		inode = gfs_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
@@ -691,11 +740,11 @@ void get_journal_inode_blocks(void)
 			char jbuf[sizeof(struct gfs_jindex)];
 
 			bh = bread(&sbd, sbd1->sb_jindex_di.no_addr);
-			j_inode = inode_get(&sbd, bh);
-			brelse(bh, not_updated);
+			j_inode = gfs_inode_get(&sbd, bh);
 			amt = gfs2_readi(j_inode, (void *)&jbuf,
 					 journal * sizeof(struct gfs_jindex),
 					 sizeof(struct gfs_jindex));
+			brelse(bh, not_updated);
 			if (!amt)
 				break;
 			gfs_jindex_in(&ji, jbuf);
@@ -746,7 +795,8 @@ void savemeta(char *out_fn, int saveoption)
 
 	do_lseek(sbd.device_fd, 0);
 	blks_saved = total_out = last_reported_block = 0;
-	sbd.bsize = BUFSIZE;
+	if (!gfs1)
+		sbd.bsize = BUFSIZE;
 	if (!slow) {
 		int i;
 
@@ -756,12 +806,29 @@ void savemeta(char *out_fn, int saveoption)
 		osi_list_init(&sbd.buf_list);
 		for(i = 0; i < BUF_HASH_SIZE; i++)
 			osi_list_init(&sbd.buf_hash[i]);
-		sbd.sd_sb.sb_bsize = GFS2_DEFAULT_BSIZE;
+		if (!gfs1)
+			sbd.sd_sb.sb_bsize = GFS2_DEFAULT_BSIZE;
 		compute_constants(&sbd);
-		if(!gfs1 && read_sb(&sbd) < 0)
-			slow = TRUE;
-		else
-			sbd.bsize = sbd.bsize = sbd.sd_sb.sb_bsize;
+		if(gfs1) {
+			sbd.bsize = sbd.sd_sb.sb_bsize;
+			sbd.sd_inptrs = (sbd.bsize -
+					 sizeof(struct gfs_indirect)) /
+				sizeof(uint64_t);
+			sbd.sd_diptrs = (sbd.bsize -
+					  sizeof(struct gfs_dinode)) /
+				sizeof(uint64_t);
+		} else {
+			if (read_sb(&sbd) < 0)
+				slow = TRUE;
+			else {
+				sbd.sd_inptrs = (sbd.bsize -
+					 sizeof(struct gfs2_meta_header)) /
+					sizeof(uint64_t);
+				sbd.sd_diptrs = (sbd.bsize -
+					  sizeof(struct gfs2_dinode)) /
+					sizeof(uint64_t);
+			}
+		}
 	}
 	last_fs_block = lseek(sbd.device_fd, 0, SEEK_END) / sbd.bsize;
 	printf("There are %" PRIu64 " blocks of %u bytes.\n",
@@ -890,10 +957,29 @@ int restore_data(int fd, int in_fd, int printblocksonly)
 	size_t rs;
 	uint64_t buf64, writes = 0;
 	uint16_t buf16;
-	int first = 1;
+	int first = 1, pos;
+	char buf[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, buf, sizeof(buf));
+	if (rs != sizeof(buf)) {
+		fprintf(stderr, "Error: File is too small.\n");
+		return -1;
+	}
+	for (pos = 0; pos < sizeof(buf) - sizeof(uint64_t) - sizeof(uint16_t);
+	     pos++) {
+		if (!memcmp(&buf[pos + sizeof(uint64_t) + sizeof(uint16_t)],
+			    gfs_superblock_id, sizeof(gfs_superblock_id))) {
+			break;
+		}
+	}
+	if (pos == sizeof(buf) - sizeof(uint64_t) - sizeof(uint16_t))
+		pos = 0;
+	do_lseek(in_fd, pos);
 	blks_saved = total_out = 0;
 	last_fs_block = 0;
 	while (TRUE) {
@@ -967,7 +1053,7 @@ int restore_data(int fd, int in_fd, int printblocksonly)
 			}
 			blks_saved++;
 		} else {
-			fprintf(stderr, "Bad record length: %d for #%"
+			fprintf(stderr, "Bad record length: %d for block #%"
 				PRIu64".\n", savedata->siglen, savedata->blk);
 			return -1;
 		}


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2008-11-14 15:34 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-11-14 15:34 STABLE2 - GFS2: gfs2_edit savemeta doesn't work with GFS Bob Peterson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).