[Linux-cluster] Patch to gfs2_convert

Steven Dake sdake at redhat.com
Thu Jun 8 21:16:03 UTC 2006


Bob,

Your patch looks good to me.  One issue that could occur which I'm not
sure is handled is the failure of the conversion right during the gfs1
to gfs2 inode conversion.  Is it possible for half the data structure to
be converted then failure to occur causing the inode to be in a half-
converted state?  I don't know enough about the code to be sure of this
case.

Regards
-steve

On Thu, 2006-06-08 at 16:26 -0500, Robert S Peterson wrote:
> 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 mailing list
> Linux-cluster at redhat.com
> https://www.redhat.com/mailman/listinfo/linux-cluster




More information about the Linux-cluster mailing list