[Linux-cluster] Patch to gfs2_convert

Robert S Peterson rpeterso at redhat.com
Thu Jun 8 21:26:41 UTC 2006


Hi,

This patch to gfs2_convert makes it much more forgiving when fs conversions
are interrupted in the middle due to power loss, interrupts, or other
reasons.  Now, if a filesystem conversion is interrupted mid-way through,
the tool should be able to pick up where it left off without damage.

As always, send questions, comments and concerns to me.  If I don't hear
from anybody, I'll commit it to cvs in a few days.

Regards,

Bob Peterson
Red Hat Cluster Suite

Index: gfs2_convert.c
===================================================================
RCS file: /cvs/cluster/cluster/gfs2/convert/gfs2_convert.c,v
retrieving revision 1.2
diff -w -u -p -u -p -r1.2 gfs2_convert.c
--- gfs2_convert.c	6 Jun 2006 14:37:47 -0000	1.2
+++ gfs2_convert.c	8 Jun 2006 21:13:37 -0000
@@ -77,12 +77,14 @@ void convert_bitmaps(struct gfs2_sbd *sd
 	int x, y;
 	struct gfs2_rindex *ri;
 	unsigned char state;
+	struct gfs2_buffer_head *bh;
 
 	ri = &rgd2->ri;
 	gfs2_compute_bitstructs(sdp, rgd2); /* mallocs bh as array */
 	for (blk = 0; blk < ri->ri_length; blk++) {
-		rgd2->bh[blk] = bget_generic(sdp, ri->ri_addr + blk, read_disk,
-									 read_disk);
+		bh = bget_generic(sdp, ri->ri_addr + blk, read_disk, read_disk);
+		if (!rgd2->bh[blk])
+			rgd2->bh[blk] = bh;
 		x = (blk) ? sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_rgrp);
 
 		for (; x < sdp->bsize; x++)
@@ -92,7 +94,6 @@ void convert_bitmaps(struct gfs2_sbd *sd
 				if (state == 0x02) /* unallocated metadata state invalid */
 					rgd2->bh[blk]->b_data[x] &= ~(0x02 << (GFS2_BIT_SIZE * y));
 			}
-		brelse(rgd2->bh[blk], updated);
 	}
 }/* convert_bitmaps */
 
@@ -134,10 +135,8 @@ static int superblock_cvt(int disk_fd, c
 	/* convert the ondisk sb structure   */
 	/* --------------------------------- */
 	sb2->sd_sb.sb_header.mh_magic = GFS2_MAGIC;
-	sb2->sd_sb.sb_fs_format = GFS2_FORMAT_FS;
 	sb2->sd_sb.sb_header.mh_type = GFS2_METATYPE_SB;
 	sb2->sd_sb.sb_header.mh_format = GFS2_FORMAT_SB;
-	sb2->sd_sb.sb_multihost_format = GFS2_FORMAT_MULTI;
 	sb2->sd_sb.sb_bsize = sb1->sd_sb.sb_bsize;
 	sb2->sd_sb.sb_bsize_shift = sb1->sd_sb.sb_bsize_shift;
 	strcpy(sb2->sd_sb.sb_lockproto, sb1->sd_sb.sb_lockproto);
@@ -174,14 +173,14 @@ static int superblock_cvt(int disk_fd, c
 		rgd2->ri.ri_data0 = rgd->rd_ri.ri_data1;
 		rgd2->ri.ri_data = rgd->rd_ri.ri_data;
 		rgd2->ri.ri_bitbytes = rgd->rd_ri.ri_bitbytes;
-		/* commit the changes to a gfs2 buffer */
-		bh = bread(sb2, rgd2->ri.ri_addr); /* get a gfs2 buffer for the rg */
-		gfs2_rgrp_out(&rgd2->rg, bh->b_data);
-		brelse(bh, updated); /* release the buffer */
 		/* Add the new gfs2 rg to our list: We'll output the index later. */
 		osi_list_add_prev((osi_list_t *)&rgd2->list,
 						  (osi_list_t *)&sb2->rglist);
 		convert_bitmaps(sb2, rgd2, TRUE);
+		/* Write the updated rgrp to the gfs2 buffer */
+		bh = bget(sb2, rgd2->ri.ri_addr); /* get a gfs2 buffer for the rg */
+		gfs2_rgrp_out(&rgd2->rg, rgd2->bh[0]->b_data);
+		brelse(bh, updated); /* release the buffer */
 	}
 	return 0;
 }/* superblock_cvt */
@@ -195,8 +194,12 @@ int adjust_inode(struct gfs2_sbd *sbp, s
 {
 	struct gfs2_inode *inode;
 	struct inode_block *fixdir;
+	int inode_was_gfs1;
 
 	inode = inode_get(sbp, bh);
+
+	inode_was_gfs1 = (inode->i_di.di_num.no_formal_ino ==
+					  inode->i_di.di_num.no_addr);
 	/* Fix the inode number: */
 	inode->i_di.di_num.no_formal_ino = sbp->md.next_inum;           ;
 	
@@ -240,11 +243,23 @@ int adjust_inode(struct gfs2_sbd *sbp, s
 	/* di_goal_meta has shifted locations and di_goal_data has     */
 	/* changed from 32-bits to 64-bits.  The following code        */
 	/* adjusts for the shift.                                      */
+	/*                                                             */
+	/* Note: It may sound absurd, but we need to check if this     */
+	/*       inode has already been converted to gfs2 or if it's   */
+	/*       still a gfs1 inode.  That's just in case there was a  */
+	/*       prior attempt to run gfs2_convert that never finished */
+	/*       (due to power out, ctrl-c, kill, segfault, whatever.) */
+	/*       If it is unconverted gfs1 we want to do a full        */
+	/*       conversion.  If it's a gfs2 inode from a prior run,   */
+	/*       we still need to renumber the inode, but here we      */
+	/*       don't want to shift the data around.                  */
 	/* ----------------------------------------------------------- */
+	if (inode_was_gfs1) {
 	inode->i_di.di_goal_meta = inode->i_di.di_goal_data;
 	inode->i_di.di_goal_data = 0; /* make sure the upper 32b are 0 */
 	inode->i_di.di_goal_data = inode->i_di.__pad[0];
 	inode->i_di.__pad[1] = 0;
+	}
 	
 	gfs2_dinode_out(&inode->i_di, bh->b_data);
 	sbp->md.next_inum++; /* update inode count */
@@ -344,7 +359,7 @@ int inode_renumber(struct gfs2_sbd *sbp,
 /* ------------------------------------------------------------------------- */
 /* fetch_inum - fetch an inum entry from disk, given its block               */
 /* ------------------------------------------------------------------------- */
-int fetch_and_fix_inum(struct gfs2_sbd *sbp, uint64_t iblock,
+int fetch_inum(struct gfs2_sbd *sbp, uint64_t iblock,
 					   struct gfs2_inum *inum)
 {
 	struct gfs2_buffer_head *bh_fix;
@@ -356,7 +371,7 @@ int fetch_and_fix_inum(struct gfs2_sbd *
 	inum->no_addr = fix_inode->i_di.di_num.no_addr;
 	brelse(bh_fix, updated);
 	return 0;
-}/* fetch_and_fix_inum */
+}/* fetch_inum */
 
 /* ------------------------------------------------------------------------- */
 /* process_dirent_info - fix one dirent (directory entry) buffer             */
@@ -382,6 +397,7 @@ int process_dirent_info(struct gfs2_inod
 	/* Turns out you can't trust dir_entries is correct.     */
 	for (de = 0; ; de++) {
 		struct gfs2_inum inum;
+		int dent_was_gfs1;
 		
 		gettimeofday(&tv, NULL);
 		/* Do more warm fuzzy stuff for the customer. */
@@ -394,18 +410,24 @@ int process_dirent_info(struct gfs2_inod
 		}
 		/* fix the dirent's inode number based on the inode */
 		gfs2_inum_in(&inum, (char *)&dent->de_inum);
+		dent_was_gfs1 = (dent->de_inum.no_addr == dent->de_inum.no_formal_ino);
 		if (inum.no_formal_ino) { /* if not a sentinel (placeholder) */
-			error = fetch_and_fix_inum(sbp, inum.no_addr, &inum);
+			error = fetch_inum(sbp, inum.no_addr, &inum);
 			if (error) {
 				printf("Error retrieving inode %" PRIx64 "\n", inum.no_addr);
 				break;
 			}
+			/* fix the dirent's inode number from the fetched inum. */
+			dent->de_inum.no_formal_ino = cpu_to_be64(inum.no_formal_ino);
 		}
 		/* Fix the dirent's filename hash: They are the same as gfs1 */
 		/* dent->de_hash = cpu_to_be32(gfs2_disk_hash((char *)(dent + 1), */
 		/*                             be16_to_cpu(dent->de_name_len))); */
 		/* Fix the dirent's file type.  Gfs1 used home-grown values.  */
 		/* Gfs2 uses standard values from include/linux/fs.h          */
+		/* Only do this if the dent was a true gfs1 dent, and not a   */
+		/* gfs2 dent converted from a previously aborted run.         */
+		if (dent_was_gfs1) {
 		switch be16_to_cpu(dent->de_type) {
 		case GFS_FILE_NON:
 			dent->de_type = cpu_to_be16(DT_UNKNOWN);
@@ -432,7 +454,7 @@ int process_dirent_info(struct gfs2_inod
 			dent->de_type = cpu_to_be16(DT_SOCK);
 			break;
 		}
-
+		}
 		error = gfs2_dirent_next(dip, bh, &dent);
 		if (error)
 			break;
@@ -948,26 +970,33 @@ int main(int argc, char **argv)
 		inode_put(sb2.md.inum, updated);
 		inode_put(sb2.md.statfs, updated);
 
-		bh = bread(&sb2, sb2.sb_addr);
-		gfs2_sb_out(&sb2.sd_sb, bh->b_data);
-		brelse(bh, updated);
 		bcommit(&sb2); /* write the buffers to disk */
 
 		/* Now delete the now-obsolete gfs1 files: */
 		printf("Removing obsolete gfs1 structures.\n");
 		fflush(stdout);
-		/* Delete the Journal index: */
+		/* Delete the old gfs1 Journal index: */
 		gfs2_freedi(&sb2, sb.sd_sb.sb_jindex_di.no_addr);
-		/* Delete the rgindex: */
+		/* Delete the old gfs1 rgindex: */
 		gfs2_freedi(&sb2, sb.sd_sb.sb_rindex_di.no_addr);
-		/* Delete the Quota file: */
+		/* Delete the old gfs1 Quota file: */
 		gfs2_freedi(&sb2, sb.sd_sb.sb_quota_di.no_addr);
-		/* Delete the License file: */
+		/* Delete the old gfs1 License file: */
 		gfs2_freedi(&sb2, sb.sd_sb.sb_license_di.no_addr);
-		/* Now free all the rgrps */
+		/* Now free all the in memory */
 		gfs2_rgrp_free(&sb2, updated);
 		printf("Committing changes to disk.\n");
 		fflush(stdout);
+		/* Set filesystem type in superblock to gfs2.  We do this at the */
+		/* end because if the tool is interrupted in the middle, we want */
+		/* it to not reject the partially converted fs as already done   */
+		/* when it's run a second time.                                  */
+		bh = bread(&sb2, sb2.sb_addr);
+		sb2.sd_sb.sb_fs_format = GFS2_FORMAT_FS;
+		sb2.sd_sb.sb_multihost_format = GFS2_FORMAT_MULTI;
+		gfs2_sb_out(&sb2.sd_sb, bh->b_data);
+		brelse(bh, updated);
+
 		bsync(&sb2); /* write the buffers to disk */
 		error = fsync(disk_fd);
 		if (error)





More information about the Linux-cluster mailing list