All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrew Price <anprice@redhat.com>
To: cluster-devel.redhat.com
Subject: [Cluster-devel] [fsck.gfs2 PATCH 2 of 2] fsck.gfs2: Detect, fix and clone duplicate block refs within a dinode
Date: Thu, 02 Jul 2015 14:47:42 +0100	[thread overview]
Message-ID: <559540FE.6030606@redhat.com> (raw)
In-Reply-To: <324505055.28858416.1435762387600.JavaMail.zimbra@redhat.com>

Hi Bob,

A couple of comments in line, otherwise both patches look good to me.

On 01/07/15 15:53, Bob Peterson wrote:
> Hi,
>
> Prior to this patch, fsck.gfs2 was unable to detect and fix duplicate
> block references within the same file. This patch detects when data
> blocks are duplicated within a dinode, then tries to clone the data
> to a new block.
>
> Regards,
>
> Bob Peterson
>
> Signed-off-by: Bob Peterson <rpeterso@redhat.com>
> ---
<snip>

> diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
> index a8f3d28..c1598ff 100644
> --- a/gfs2/fsck/pass1b.c
> +++ b/gfs2/fsck/pass1b.c
> @@ -28,6 +28,11 @@ struct dup_handler {
>   	int ref_count;
>   };
>
> +struct clone_target {
> +	uint64_t dup_block;
> +	int first;
> +};
> +
>   static void log_inode_reference(struct duptree *dt, osi_list_t *tmp, int inval)
>   {
>   	char reftypestring[32];
> @@ -249,6 +254,116 @@ static void revise_dup_handler(uint64_t dup_blk, struct dup_handler *dh)
>   	}
>   }
>
> +static int clone_check_meta(struct gfs2_inode *ip, uint64_t block,
> +			    struct gfs2_buffer_head **bh, int h,
> +			    int *is_valid, int *was_duplicate, void *private)
> +{
> +	*was_duplicate = 0;
> +	*is_valid = 1;
> +	*bh = bread(ip->i_sbd, block);

Does this need a NULL check, or does check_metatree handle that?

> +	return 0;
> +}
> +
> +/* clone_data - clone a duplicate reference
> + *
> + * This function remembers the first reference to the specified block, and
> + * clones all subsequent references to it (with permission).
> + */
> +static int clone_data(struct gfs2_inode *ip, uint64_t metablock,
> +		      uint64_t block, void *private,
> +		      struct gfs2_buffer_head *bh, uint64_t *ptr)
> +{
> +	struct clone_target *clonet = (struct clone_target *)private;
> +	struct gfs2_buffer_head *clone_bh;
> +	uint64_t cloneblock;
> +	int error;
> +
> +	if (block != clonet->dup_block)
> +		return 0;
> +
> +	if (clonet->first) {
> +		log_debug(_("Inode %lld (0x%llx)'s first reference to "
> +			    "block %lld (0x%llx) is targeted for cloning.\n"),
> +			  (unsigned long long)ip->i_di.di_num.no_addr,
> +			  (unsigned long long)ip->i_di.di_num.no_addr,
> +			  (unsigned long long)block,
> +			  (unsigned long long)block);
> +		clonet->first = 0;
> +		return 0;
> +	}
> +	log_err(_("Error: Inode %lld (0x%llx)'s subsequent reference to "
> +		  "block %lld (0x%llx) is an error.\n"),
> +		(unsigned long long)ip->i_di.di_num.no_addr,
> +		(unsigned long long)ip->i_di.di_num.no_addr,
> +		(unsigned long long)block, (unsigned long long)block);
> +	if (query( _("Okay to clone the duplicated reference? (y/n) "))) {
> +		error = lgfs2_meta_alloc(ip, &cloneblock);
> +		if (!error) {
> +			clone_bh = bread(ip->i_sbd, clonet->dup_block);
> +			if (clone_bh) {
> +				fsck_blockmap_set(ip, cloneblock, _("data"),
> +						  GFS2_BLKST_USED);
> +				clone_bh->b_blocknr = cloneblock;
> +				bmodified(clone_bh);
> +				brelse(clone_bh);
> +				/* Now fix the reference: */
> +				*ptr = cpu_to_be64(cloneblock);
> +				bmodified(bh);
> +				log_err(_("Duplicate reference to block %lld "
> +					  "(0x%llx) was cloned to block %lld "
> +					  "(0x%llx).\n"),
> +					(unsigned long long)block,
> +					(unsigned long long)block,
> +					(unsigned long long)cloneblock,
> +					(unsigned long long)cloneblock);
> +				return 0;
> +			}
> +		}
> +		log_err(_("Error: Unable to allocate a new data block.\n"));
> +		if (!query("Should I zero the reference instead? (y/n)")) {
> +			log_err(_("Duplicate reference to block %lld "
> +				  "(0x%llx) was not fixed.\n"),
> +				(unsigned long long)block,
> +				(unsigned long long)block);
> +			return 0;
> +		}
> +		*ptr = 0;
> +		bmodified(bh);
> +		log_err(_("Duplicate reference to block %lld (0x%llx) was "
> +			  "zeroed.\n"),
> +			(unsigned long long)block,
> +			(unsigned long long)block);
> +	} else {
> +		log_err(_("Duplicate reference to block %lld (0x%llx) "
> +			  "was not fixed.\n"), (unsigned long long)block,
> +			(unsigned long long)block);
> +	}
> +	return 0;
> +}
> +
> +/* clone_dup_ref_in_inode - clone a duplicate reference within a single inode
> + *
> + * This function traverses the metadata tree of an inode, cloning all
> + * but the first reference to a duplicate block reference.
> + */
> +static void clone_dup_ref_in_inode(struct gfs2_inode *ip, struct duptree *dt)
> +{
> +	int error;
> +	struct clone_target clonet = {.dup_block = dt->block, .first = 1};
> +	struct metawalk_fxns pass1b_fxns_clone = {
> +		.private = &clonet,
> +		.check_metalist = clone_check_meta,
> +		.check_data = clone_data,
> +	};
> +
> +	error = check_metatree(ip, &pass1b_fxns_clone);
> +	if (error) {
> +		log_err(_("Error cloning duplicate reference(s) to block %lld "
> +			  "(0x%llx).\n"), (unsigned long long)dt->block,
> +			(unsigned long long)dt->block);
> +	}
> +}

Void functions with error paths always ring alarm bells in my head, 
should this one return the error value?

Andy

> +
>   /* handle_dup_blk - handle a duplicate block reference.
>    *
>    * This function should resolve and delete the duplicate block reference given,
> @@ -389,6 +504,9 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *dt)
>   			   (unsigned long long)id->block_no);
>   		ip = fsck_load_inode(sdp, id->block_no);
>
> +		if (dt->dup_flags & DUPFLAG_REF1_IS_DUPL)
> +			clone_dup_ref_in_inode(ip, dt);
> +
>   		q = block_type(id->block_no);
>   		if (q == GFS2_BLKST_UNLINKED) {
>   			log_debug( _("The remaining reference inode %lld "
> @@ -468,7 +586,8 @@ static int check_metalist_refs(struct gfs2_inode *ip, uint64_t block,
>   }
>
>   static int check_data_refs(struct gfs2_inode *ip, uint64_t metablock,
> -			   uint64_t block, void *private)
> +			   uint64_t block, void *private,
> +			   struct gfs2_buffer_head *bh, uint64_t *ptr)
>   {
>   	return add_duplicate_ref(ip, block, ref_as_data, 1, INODE_VALID);
>   }
> diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
> index b31fbd4..900d4e1 100644
> --- a/gfs2/fsck/pass2.c
> +++ b/gfs2/fsck/pass2.c
> @@ -1580,7 +1580,8 @@ static int check_metalist_qc(struct gfs2_inode *ip, uint64_t block,
>   }
>
>   static int check_data_qc(struct gfs2_inode *ip, uint64_t metablock,
> -			 uint64_t block, void *private)
> +			 uint64_t block, void *private,
> +			 struct gfs2_buffer_head *bbh, uint64_t *ptr)
>   {
>   	struct gfs2_buffer_head *bh;
>
> diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c
> index 4022fee..a6a5cdc 100644
> --- a/gfs2/fsck/util.c
> +++ b/gfs2/fsck/util.c
> @@ -339,15 +339,16 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
>   	   resolve it. The first reference can't be the second reference. */
>   	if (id && first && !(dt->dup_flags & DUPFLAG_REF1_FOUND)) {
>   		log_info(_("Original reference to block %llu (0x%llx) was "
> -			   "previously found to be bad and deleted.\n"),
> +			   "either found to be bad and deleted, or else "
> +			   "a duplicate within the same inode.\n"),
>   			 (unsigned long long)block,
>   			 (unsigned long long)block);
>   		log_info(_("I'll consider the reference from inode %llu "
>   			   "(0x%llx) the first reference.\n"),
>   			 (unsigned long long)ip->i_di.di_num.no_addr,
>   			 (unsigned long long)ip->i_di.di_num.no_addr);
> -		dt->dup_flags |= DUPFLAG_REF1_FOUND;
> -		return meta_is_good;
> +		dt->dup_flags |= DUPFLAG_REF1_IS_DUPL;
> +		dt->refs++;
>   	}
>
>   	/* The first time this is called from pass1 is actually the second
>



  reply	other threads:[~2015-07-02 13:47 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <1151762892.28857097.1435762308924.JavaMail.zimbra@redhat.com>
2015-07-01 14:53 ` [Cluster-devel] [fsck.gfs2 PATCH 2 of 2] fsck.gfs2: Detect, fix and clone duplicate block refs within a dinode Bob Peterson
2015-07-02 13:47   ` Andrew Price [this message]
2015-07-02 14:38     ` Bob Peterson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=559540FE.6030606@redhat.com \
    --to=anprice@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.