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) -- Linux-cluster@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/linux-cluster