[Cluster-devel] [fsck.gfs2 PATCH] fsck.gfs2: Reprocess nodes if anything changed

Abhijith Das adas at redhat.com
Thu Jan 15 18:08:04 UTC 2015


Hi,

ACK.

Cheers!
--Abhi

----- Original Message -----
> From: "Bob Peterson" <rpeterso at redhat.com>
> To: "cluster-devel" <cluster-devel at redhat.com>
> Sent: Thursday, January 15, 2015 10:55:21 AM
> Subject: [Cluster-devel] [fsck.gfs2 PATCH] fsck.gfs2: Reprocess nodes if	anything changed
> 
> Hi,
> 
> Before this patch, fsck.gfs2 called "reprocess_inode" in several
> places, especially when the number of blocks had changed from the
> original. That works in almost all cases. However, there's a corner
> case where a block may be deleted, due to errors (for example, a
> bad directory leaf), and another block takes its place. In that
> case the count of the number of blocks is still the same, but the
> inode should be reprocessed anyway, because the deleted blocks
> and replacement blocks may be at different locations or maybe of
> different types. A hash table block may be "data" when it's freed,
> but if the block is reused, it may be repurposed as a "leaf" block.
> That may confuse subsequent processing. Another reason to call
> reprocess_inode is when the goal block changes to a value outside
> the resource group, due to block allocations for repairs.
> 
> Regards,
> 
> Bob Peterson
> Red Hat File Systems
> 
> Signed-off-by: Bob Peterson <rpeterso at redhat.com>
> ---
> diff --git a/gfs2/fsck/lost_n_found.c b/gfs2/fsck/lost_n_found.c
> index 9672c7a..b2e35e2 100644
> --- a/gfs2/fsck/lost_n_found.c
> +++ b/gfs2/fsck/lost_n_found.c
> @@ -174,7 +174,6 @@ void make_sure_lf_exists(struct gfs2_inode *ip)
>  int add_inode_to_lf(struct gfs2_inode *ip){
>  	char tmp_name[256];
>  	__be32 inode_type;
> -	uint64_t lf_blocks;
>  	struct gfs2_sbd *sdp = ip->i_sbd;
>  	int err = 0;
>  	uint32_t mode;
> @@ -184,7 +183,6 @@ int add_inode_to_lf(struct gfs2_inode *ip){
>  		log_err( _("Trying to add lost+found to itself...skipping"));
>  		return 0;
>  	}
> -	lf_blocks = lf_dip->i_di.di_blocks;
>  
>  	if (sdp->gfs1)
>  		mode = gfs_to_gfs2_mode(ip);
> @@ -242,10 +240,6 @@ int add_inode_to_lf(struct gfs2_inode *ip){
>  			 tmp_name, strerror(errno));
>  		exit(FSCK_ERROR);
>  	}
> -	/* If the lf directory had new blocks added we have to mark them
> -	   properly in the bitmap so they're not freed. */
> -	if (lf_dip->i_di.di_blocks != lf_blocks)
> -		reprocess_inode(lf_dip, "lost+found");
>  
>  	/* This inode is linked from lost+found */
>  	incr_link_count(ip->i_di.di_num, lf_dip, _("from lost+found"));
> diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
> index 16faafb..217bb07 100644
> --- a/gfs2/fsck/metawalk.c
> +++ b/gfs2/fsck/metawalk.c
> @@ -1693,11 +1693,11 @@ int check_dir(struct gfs2_sbd *sdp, uint64_t block,
> struct metawalk_fxns *pass)
>  {
>  	struct gfs2_inode *ip;
>  	int error = 0;
> -	uint64_t cur_blks;
> +	struct alloc_state as;
>  
>  	ip = fsck_load_inode(sdp, block);
>  
> -	cur_blks = ip->i_di.di_blocks;
> +	astate_save(ip, &as);
>  
>  	if (ip->i_di.di_flags & GFS2_DIF_EXHASH)
>  		error = check_leaf_blks(ip, pass);
> @@ -1707,7 +1707,7 @@ int check_dir(struct gfs2_sbd *sdp, uint64_t block,
> struct metawalk_fxns *pass)
>  	if (error < 0)
>  		stack;
>  
> -	if (ip->i_di.di_blocks != cur_blks)
> +	if (astate_changed(ip, &as))
>  		reprocess_inode(ip, _("Current"));
>  
>  	fsck_inode_put(&ip); /* does a brelse */
> diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
> index 4ea322a..74bcc26 100644
> --- a/gfs2/fsck/pass2.c
> +++ b/gfs2/fsck/pass2.c
> @@ -1723,7 +1723,8 @@ build_it:
>  static int check_system_dir(struct gfs2_inode *sysinode, const char
>  *dirname,
>  		     int builder(struct gfs2_sbd *sdp))
>  {
> -	uint64_t iblock = 0, cur_blks;
> +	uint64_t iblock = 0;
> +	struct alloc_state as;
>  	struct dir_status ds = {0};
>  	int error = 0;
>  
> @@ -1740,14 +1741,14 @@ static int check_system_dir(struct gfs2_inode
> *sysinode, const char *dirname,
>  
>  	pass2_fxns.private = (void *) &ds;
>  	if (ds.q == gfs2_bad_block) {
> -		cur_blks = sysinode->i_di.di_blocks;
> +		astate_save(sysinode, &as);
>  		/* First check that the directory's metatree is valid */
>  		error = check_metatree(sysinode, &pass2_fxns);
>  		if (error < 0) {
>  			stack;
>  			return error;
>  		}
> -		if (sysinode->i_di.di_blocks != cur_blks)
> +		if (astate_changed(sysinode, &as))
>  			reprocess_inode(sysinode, _("System inode"));
>  	}
>  	error = check_dir(sysinode->i_sbd, iblock, &pass2_fxns);
> @@ -1768,7 +1769,7 @@ static int check_system_dir(struct gfs2_inode
> *sysinode, const char *dirname,
>  	if (!ds.dotdir) {
>  		log_err( _("No '.' entry found for %s directory.\n"), dirname);
>  		if (query( _("Is it okay to add '.' entry? (y/n) "))) {
> -			cur_blks = sysinode->i_di.di_blocks;
> +			astate_save(sysinode, &as);
>  			log_warn( _("Adding '.' entry\n"));
>  			error = dir_add(sysinode, ".", 1, &(sysinode->i_di.di_num),
>  			                (sysinode->i_sbd->gfs1 ? GFS_FILE_DIR : DT_DIR));
> @@ -1777,7 +1778,7 @@ static int check_system_dir(struct gfs2_inode
> *sysinode, const char *dirname,
>  				         strerror(errno));
>  				return -errno;
>  			}
> -			if (cur_blks != sysinode->i_di.di_blocks)
> +			if (astate_changed(sysinode, &as))
>  				reprocess_inode(sysinode, dirname);
>  			/* This system inode is linked to itself via '.' */
>  			incr_link_count(sysinode->i_di.di_num, sysinode,
> @@ -1859,7 +1860,8 @@ static inline int is_system_dir(struct gfs2_sbd *sdp,
> uint64_t block)
>   */
>  int pass2(struct gfs2_sbd *sdp)
>  {
> -	uint64_t dirblk, cur_blks;
> +	uint64_t dirblk;
> +	struct alloc_state as;
>  	uint8_t q;
>  	struct dir_status ds = {0};
>  	struct gfs2_inode *ip;
> @@ -1926,14 +1928,14 @@ int pass2(struct gfs2_sbd *sdp)
>  			/* First check that the directory's metatree
>  			 * is valid */
>  			ip = fsck_load_inode(sdp, dirblk);
> -			cur_blks = ip->i_di.di_blocks;
> +			astate_save(ip, &as);
>  			error = check_metatree(ip, &pass2_fxns);
>  			if (error < 0) {
>  				stack;
>  				fsck_inode_put(&ip);
>  				return error;
>  			}
> -			if (ip->i_di.di_blocks != cur_blks)
> +			if (astate_changed(ip, &as))
>  				reprocess_inode(ip, "current");
>  			fsck_inode_put(&ip);
>  		}
> @@ -1994,7 +1996,7 @@ int pass2(struct gfs2_sbd *sdp)
>  				(unsigned long long)dirblk);
>  
>  			if (query( _("Is it okay to add '.' entry? (y/n) "))) {
> -				cur_blks = ip->i_di.di_blocks;
> +				astate_save(ip, &as);
>  				error = dir_add(ip, ".", 1, &(ip->i_di.di_num),
>  						(sdp->gfs1 ? GFS_FILE_DIR : DT_DIR));
>  				if (error) {
> @@ -2003,7 +2005,7 @@ int pass2(struct gfs2_sbd *sdp)
>  					fsck_inode_put(&ip);
>  					return -errno;
>  				}
> -				if (cur_blks != ip->i_di.di_blocks) {
> +				if (astate_changed(ip, &as)) {
>  					char dirname[80];
>  
>  					sprintf(dirname, _("Directory at %lld "
> diff --git a/gfs2/fsck/pass3.c b/gfs2/fsck/pass3.c
> index 33865df..3e183e5 100644
> --- a/gfs2/fsck/pass3.c
> +++ b/gfs2/fsck/pass3.c
> @@ -24,7 +24,7 @@ static int attach_dotdot_to(struct gfs2_sbd *sdp, uint64_t
> newdotdot,
>  	int filename_len = 2;
>  	int err;
>  	struct gfs2_inode *ip, *pip;
> -	uint64_t cur_blks;
> +	struct alloc_state as;
>  
>  	ip = fsck_load_inode(sdp, block);
>  	pip = fsck_load_inode(sdp, newdotdot);
> @@ -39,7 +39,7 @@ static int attach_dotdot_to(struct gfs2_sbd *sdp, uint64_t
> newdotdot,
>  		log_warn( _("Unable to remove \"..\" directory entry.\n"));
>  	else
>  		decr_link_count(olddotdot, block, _("old \"..\""));
> -	cur_blks = ip->i_di.di_blocks;
> +	astate_save(ip, &as);
>  	err = dir_add(ip, filename, filename_len, &pip->i_di.di_num,
>  		      (sdp->gfs1 ? GFS_FILE_DIR : DT_DIR));
>  	if (err) {
> @@ -47,7 +47,7 @@ static int attach_dotdot_to(struct gfs2_sbd *sdp, uint64_t
> newdotdot,
>  		        filename, strerror(errno));
>  		exit(FSCK_ERROR);
>  	}
> -	if (cur_blks != ip->i_di.di_blocks) {
> +	if (astate_changed(ip, &as)) {
>  		char dirname[80];
>  
>  		sprintf(dirname, _("Directory at %lld (0x%llx)"),
> @@ -179,6 +179,7 @@ int pass3(struct gfs2_sbd *sdp)
>  	struct dir_info *di, *tdi;
>  	struct gfs2_inode *ip;
>  	uint8_t q;
> +	struct alloc_state lf_as = {.as_blocks = 0, .as_meta_goal = 0};
>  
>  	di = dirtree_find(sdp->md.rooti->i_di.di_num.no_addr);
>  	if (di) {
> @@ -225,6 +226,8 @@ int pass3(struct gfs2_sbd *sdp)
>  	 */
>  	log_info( _("Checking directory linkage.\n"));
>  	for (tmp = osi_first(&dirtree); tmp; tmp = next) {
> +		if (lf_dip && lf_as.as_blocks == 0)
> +			astate_save(lf_dip, &lf_as);
>  		next = osi_next(tmp);
>  		di = (struct dir_info *)tmp;
>  		while (!di->checked) {
> @@ -330,8 +333,14 @@ int pass3(struct gfs2_sbd *sdp)
>  			break;
>  		}
>  	}
> -	if (lf_dip)
> +	if (lf_dip) {
> +		/* If the lf directory had new blocks added we have to mark
> +		   them properly in the blockmap so they're not freed. */
> +		if (astate_changed(lf_dip, &lf_as))
> +			reprocess_inode(lf_dip, "lost+found");
> +
>  		log_debug( _("At end of pass3, lost+found entries is %u\n"),
>  				  lf_dip->i_di.di_entries);
> +	}
>  	return FSCK_OK;
>  }
> diff --git a/gfs2/fsck/pass4.c b/gfs2/fsck/pass4.c
> index f9d08dc..324ea9f 100644
> --- a/gfs2/fsck/pass4.c
> +++ b/gfs2/fsck/pass4.c
> @@ -48,12 +48,15 @@ static int scan_inode_list(struct gfs2_sbd *sdp) {
>  	struct gfs2_inode *ip;
>  	int lf_addition = 0;
>  	uint8_t q;
> +	struct alloc_state lf_as = {.as_blocks = 0, .as_meta_goal = 0};
>  
>  	/* FIXME: should probably factor this out into a generic
>  	 * scanning fxn */
>  	for (tmp = osi_first(&inodetree); tmp; tmp = next) {
>  		if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
>  			return 0;
> +		if (lf_dip && lf_as.as_blocks == 0)
> +			astate_save(lf_dip, &lf_as);
>  		next = osi_next(tmp);
>  		ii = (struct inode_info *)tmp;
>  		/* Don't check reference counts on the special gfs files */
> @@ -179,6 +182,9 @@ static int scan_inode_list(struct gfs2_sbd *sdp) {
>  			 (unsigned long long)ii->di_num.no_addr, ii->di_nlink);
>  	} /* osi_list_foreach(tmp, list) */
>  
> +	if (lf_dip && astate_changed(lf_dip, &lf_as))
> +		reprocess_inode(lf_dip, "lost+found");
> +
>  	if (lf_addition) {
>  		if (!(ii = inodetree_find(lf_dip->i_di.di_num.no_addr))) {
>  			log_crit( _("Unable to find lost+found inode in inode_hash!!\n"));
> diff --git a/gfs2/fsck/util.h b/gfs2/fsck/util.h
> index 276c726..66b9c7a 100644
> --- a/gfs2/fsck/util.h
> +++ b/gfs2/fsck/util.h
> @@ -12,6 +12,11 @@
>  #define INODE_VALID 1
>  #define INODE_INVALID 0
>  
> +struct alloc_state {
> +	uint64_t as_blocks;
> +	uint64_t as_meta_goal;
> +};
> +
>  struct di_info *search_list(osi_list_t *list, uint64_t addr);
>  void big_file_comfort(struct gfs2_inode *ip, uint64_t blks_checked);
>  void warm_fuzzy_stuff(uint64_t block);
> @@ -27,6 +32,21 @@ extern const char *reftypes[ref_types + 1];
>  #define BLOCKMAP_BYTE_OFFSET4(x) (((x) & 0x0000000000000001) << 2)
>  #define BLOCKMAP_MASK4 (0xf)
>  
> +static inline void astate_save(struct gfs2_inode *ip, struct alloc_state
> *as)
> +{
> +	as->as_blocks = ip->i_di.di_blocks;
> +	as->as_meta_goal = ip->i_di.di_goal_meta;
> +}
> +
> +static inline int astate_changed(struct gfs2_inode *ip, struct alloc_state
> *as)
> +{
> +	if (as->as_blocks != ip->i_di.di_blocks)
> +		return 1;
> +	if (as->as_meta_goal != ip->i_di.di_goal_meta)
> +		return 1;
> +	return 0;
> +}
> +
>  static inline uint8_t block_type(uint64_t bblock)
>  {
>  	static unsigned char *byte;
> 
> 




More information about the Cluster-devel mailing list