[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