Re: [RFC PATCH 4/4] btrfs: Moved repair code from inode.c to extent_io.c

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, 2011-07-22 at 16:58 +0200, Jan Schmidt wrote:
> The raid-retry code in inode.c can be generalized so that it works for
> metadata as well. Thus, this patch moves it to extent_io.c and makes the
> raid-retry code a raid-repair code.
> 
> Repair works that way: Whenever a read error occurs and we have more
> mirrors to try, note the failed mirror, and retry another. If we find a
> good one, check if we did note a failure earlier and if so, do not allow
> the read to complete until after the bad sector was written with the good
> data we just fetched. As we have the extent locked while reading, no one
> can change the data in between.
> 
> Signed-off-by: Jan Schmidt <list.btrfs@xxxxxxxxxxxxx>
> ---
>  fs/btrfs/extent_io.c |  386 +++++++++++++++++++++++++++++++++++++++++++++++++-
>  fs/btrfs/extent_io.h |   11 ++-
>  fs/btrfs/inode.c     |  155 +--------------------
>  3 files changed, 393 insertions(+), 159 deletions(-)
> 
> diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
> index b181a94..7fca3ed 100644
> --- a/fs/btrfs/extent_io.c
> +++ b/fs/btrfs/extent_io.c
> @@ -15,6 +15,7 @@
>  #include "compat.h"
>  #include "ctree.h"
>  #include "btrfs_inode.h"
> +#include "volumes.h"
>  
>  static struct kmem_cache *extent_state_cache;
>  static struct kmem_cache *extent_buffer_cache;
> @@ -1642,6 +1643,367 @@ static int check_page_writeback(struct extent_io_tree *tree,
>  	return 0;
>  }
>  
> +/*
> + * When IO fails, either with EIO or csum verification fails, we
> + * try other mirrors that might have a good copy of the data.  This
> + * io_failure_record is used to record state as we go through all the
> + * mirrors.  If another mirror has good data, the page is set up to date
> + * and things continue.  If a good mirror can't be found, the original
> + * bio end_io callback is called to indicate things have failed.
> + */
> +struct io_failure_record {
> +	struct page *page;
> +	u64 start;
> +	u64 len;
> +	u64 logical;
> +	unsigned long bio_flags;
> +	int this_mirror;
> +	int failed_mirror;
> +	int in_validation;
> +};
> +
> +static int free_io_failure(struct inode *inode, struct io_failure_record *rec,
> +				int did_repair)
> +{
> +	int ret;
> +	int err = 0;
> +	struct extent_io_tree *failure_tree = &BTRFS_I(inode)->io_failure_tree;
> +
> +	set_state_private(failure_tree, rec->start, 0);
> +	ret = clear_extent_bits(failure_tree, rec->start,
> +				rec->start + rec->len - 1,
> +				EXTENT_LOCKED | EXTENT_DIRTY, GFP_NOFS);
> +	if (ret)
> +		err = ret;
> +
> +	if (did_repair) {
> +		ret = clear_extent_bits(&BTRFS_I(inode)->io_tree, rec->start,
> +					rec->start + rec->len - 1,
> +					EXTENT_DAMAGED, GFP_NOFS);
> +		if (ret && !err)
> +			err = ret;
> +	}
> +
> +	kfree(rec);
> +	return err;
> +}
> +
> +static void repair_io_failure_callback(struct bio *bio, int err)
> +{
> +	complete(bio->bi_private);
> +}
> +
> +/*
> + * this bypasses the standard btrfs submit functions deliberately, as
> + * the standard behavior is to write all copies in a raid setup. here we only
> + * want to write the one bad copy. so we do the mapping for ourselves and issue
> + * submit_bio directly.
> + * to avoid any synchonization issues, wait for the data after writing, which
> + * actually prevents the read that triggered the error from finishing.
> + * currently, there can be no more than two copies of every data bit. thus,
> + * exactly one rewrite is required.
> + */
> +int repair_io_failure(struct btrfs_mapping_tree *map_tree, u64 start,
> +			u64 length, u64 logical, struct page *page,
> +			int mirror_num)
> +{
> +	struct bio *bio;
> +	struct btrfs_device *dev;
> +	DECLARE_COMPLETION_ONSTACK(compl);
> +	u64 map_length = 0;
> +	u64 sector;
> +	struct btrfs_bio *bbio = NULL;
> +	int ret;
> +
> +	BUG_ON(!mirror_num);
> +
> +	bio = bio_alloc(GFP_NOFS, 1);
> +	if (!bio)
> +		return -EIO;
> +	bio->bi_private = &compl;
> +	bio->bi_end_io = repair_io_failure_callback;
> +	bio->bi_size = 0;
> +	map_length = length;
> +
> +	ret = btrfs_map_block(map_tree, WRITE, logical,
> +			      &map_length, &bbio, mirror_num);
> +	if (ret) {
> +		bio_put(bio);
> +		return -EIO;
> +	}
> +	BUG_ON(mirror_num != bbio->mirror_num);
> +	sector = bbio->stripes[mirror_num-1].physical >> 9;
> +	bio->bi_sector = sector;
> +	dev = bbio->stripes[mirror_num-1].dev;
> +	kfree(bbio);
> +	if (!dev || !dev->bdev || !dev->writeable) {
> +		bio_put(bio);
> +		return -EIO;
> +	}
> +	bio->bi_bdev = dev->bdev;
> +	bio_add_page(bio, page, length, start-page_offset(page));
> +	submit_bio(WRITE_SYNC, bio);
> +	wait_for_completion(&compl);
> +
> +	if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) {
> +		/* try to remap that extent elsewhere? */
> +		bio_put(bio);
> +		return -EIO;
> +	}
> +
> +	printk(KERN_INFO "btrfs read error corrected: ino %lu off %llu (dev %s "
> +			"sector %llu)\n", page->mapping->host->i_ino, start,
> +			dev->name, sector);
> +
> +	bio_put(bio);
> +	return 0;
> +}
> +
> +/*
> + * each time an IO finishes, we do a fast check in the IO failure tree
> + * to see if we need to process or clean up an io_failure_record
> + */
> +static int clean_io_failure(u64 start, struct page *page)
> +{
> +	u64 private;
> +	u64 private_failure;
> +	struct io_failure_record *failrec;
> +	struct btrfs_mapping_tree *map_tree;
> +	struct extent_state *state;
> +	int num_copies;
> +	int did_repair = 0;
> +	int ret;
> +	struct inode *inode = page->mapping->host;
> +
> +	private = 0;
> +	ret = count_range_bits(&BTRFS_I(inode)->io_failure_tree, &private,
> +				(u64)-1, 1, EXTENT_DIRTY, 0);
> +	if (!ret)
> +		return 0;
> +
> +	ret = get_state_private(&BTRFS_I(inode)->io_failure_tree, start,
> +				&private_failure);
> +	if (ret)
> +		return 0;
> +
> +	failrec = (struct io_failure_record *)(unsigned long) private_failure;
> +	BUG_ON(!failrec->this_mirror);
> +
> +	if (failrec->in_validation) {
> +		/* there was no real error, just free the record */
> +		pr_debug("clean_io_failure: freeing dummy error at %llu\n",
> +			 failrec->start);
> +		did_repair = 1;
> +		goto out;
> +	}
> +
> +	spin_lock(&BTRFS_I(inode)->io_tree.lock);
> +	state = find_first_extent_bit_state(&BTRFS_I(inode)->io_tree,
> +					    failrec->start,
> +					    EXTENT_LOCKED);
> +	spin_unlock(&BTRFS_I(inode)->io_tree.lock);
> +
> +	if (state && state->start == failrec->start) {
> +		map_tree = &BTRFS_I(inode)->root->fs_info->mapping_tree;
> +		num_copies = btrfs_num_copies(map_tree, failrec->logical,
> +						failrec->len);
> +		if (num_copies > 1)  {
> +			ret = repair_io_failure(map_tree, start, failrec->len,
> +						failrec->logical, page,
> +						failrec->failed_mirror);
> +			did_repair = !ret;
> +		}
> +	}
> +
> +out:
> +	if (!ret)
> +		ret = free_io_failure(inode, failrec, did_repair);
> +
> +	return ret;
> +}
> +
> +/*
> + * this is a generic handler for readpage errors (default
> + * readpage_io_failed_hook). if other copies exist, read those and write back
> + * good data to the failed position. does not investigate in remapping the
> + * failed extent elsewhere, hoping the device will be smart enough to do this as
> + * needed
> + */
> +
> +static int bio_readpage_error(struct bio *failed_bio, struct page *page,
> +				u64 start, u64 end, int failed_mirror,
> +				struct extent_state *state)
> +{
> +	struct io_failure_record *failrec = NULL;
> +	u64 private;
> +	struct extent_map *em;
> +	struct inode *inode = page->mapping->host;
> +	struct extent_io_tree *failure_tree = &BTRFS_I(inode)->io_failure_tree;
> +	struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree;
> +	struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
> +	struct bio *bio;
> +	int num_copies;
> +	int ret;
> +	int read_mode;
> +	u64 logical;
> +
> +	BUG_ON(failed_bio->bi_rw & REQ_WRITE);
> +
> +	ret = get_state_private(failure_tree, start, &private);
> +	if (ret) {
> +		failrec = kzalloc(sizeof(*failrec), GFP_NOFS);
> +		if (!failrec)
> +			return -ENOMEM;
> +		failrec->start = start;
> +		failrec->len = end - start + 1;
> +		failrec->this_mirror = 0;
> +		failrec->bio_flags = 0;
> +		failrec->in_validation = 0;
> +
> +		read_lock(&em_tree->lock);
> +		em = lookup_extent_mapping(em_tree, start, failrec->len);
> +		if (!em) {

Looks like a missing "read_unlock(&em_tree->lock);" here to me?

> +			kfree(failrec);
> +			return -EIO;
> +		}
> +
> +		if (em->start > start || em->start + em->len < start) {
> +			free_extent_map(em);
> +			em = NULL;
> +		}
> +		read_unlock(&em_tree->lock);
> +
> +		if (!em || IS_ERR(em)) {
> +			kfree(failrec);
> +			return -EIO;
> +		}
> +		logical = start - em->start;
> +		logical = em->block_start + logical;
> +		if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) {
> +			logical = em->block_start;
> +			failrec->bio_flags = EXTENT_BIO_COMPRESSED;
> +			extent_set_compress_type(&failrec->bio_flags,
> +						 em->compress_type);
> +		}
> +		pr_debug("bio_readpage_error: (new) logical=%llu, start=%llu, "
> +			 "len=%llu\n", logical, start, failrec->len);
> +		failrec->logical = logical;
> +		free_extent_map(em);
> +
> +		/* set the bits in the private failure tree */
> +		ret = set_extent_bits(failure_tree, start, end,
> +					EXTENT_LOCKED | EXTENT_DIRTY, GFP_NOFS);
> +		if (ret >= 0)
> +			ret = set_state_private(failure_tree, start,
> +						(u64)(unsigned long)failrec);
> +		/* set the bits in the inode's tree */
> +		if (ret >= 0)
> +			ret = set_extent_bits(tree, start, end, EXTENT_DAMAGED,
> +						GFP_NOFS);
> +		if (ret < 0) {
> +			kfree(failrec);
> +			return ret;
> +		}
> +	} else {
> +		failrec = (struct io_failure_record *)(unsigned long)private;
> +		pr_debug("bio_readpage_error: (found) logical=%llu, "
> +			 "start=%llu, len=%llu, validation=%d\n",
> +			 failrec->logical, failrec->start, failrec->len,
> +			 failrec->in_validation);
> +		/*
> +		 * when data can be on disk more than twice, add to failrec here
> +		 * (e.g. with a list for failed_mirror) to make
> +		 * clean_io_failure() clean all those errors at once.
> +		 */
> +	}
> +	num_copies = btrfs_num_copies(
> +			      &BTRFS_I(inode)->root->fs_info->mapping_tree,
> +			      failrec->logical, failrec->len);
> +	if (num_copies == 1) {
> +		/*
> +		 * we only have a single copy of the data, so don't bother with
> +		 * all the retry and error correction code that follows. no
> +		 * matter what the error is, it is very likely to persist.
> +		 */
> +		pr_debug("bio_readpage_error: cannot repair, num_copies == 1. "
> +			 "state=%p, num_copies=%d, next_mirror %d, "
> +			 "failed_mirror %d\n", state, num_copies,
> +			 failrec->this_mirror, failed_mirror);
> +		free_io_failure(inode, failrec, 0);
> +		return -EIO;
> +	}
> +
> +	if (!state) {
> +		spin_lock(&tree->lock);
> +		state = find_first_extent_bit_state(tree, failrec->start,
> +						    EXTENT_LOCKED);
> +		if (state && state->start != failrec->start)
> +			state = NULL;
> +		spin_unlock(&tree->lock);
> +	}
> +
> +	/*
> +	 * there are two premises:
> +	 *	a) deliver good data to the caller
> +	 *	b) correct the bad sectors on disk
> +	 */
> +	if (failed_bio->bi_vcnt > 1) {
> +		/*
> +		 * to fulfill b), we need to know the exact failing sectors, as
> +		 * we don't want to rewrite any more than the failed ones. thus,
> +		 * we need separate read requests for the failed bio
> +		 *
> +		 * if the following BUG_ON triggers, our validation request got
> +		 * merged. we need separate requests for our algorithm to work.
> +		 */
> +		BUG_ON(failrec->in_validation);
> +		failrec->in_validation = 1;
> +		failrec->this_mirror = failed_mirror;
> +		read_mode = READ_SYNC | REQ_FAILFAST_DEV;
> +	} else {
> +		/*
> +		 * we're ready to fulfill a) and b) alongside. get a good copy
> +		 * of the failed sector and if we succeed, we have setup
> +		 * everything for repair_io_failure to do the rest for us.
> +		 */
> +		if (failrec->in_validation) {
> +			BUG_ON(failrec->this_mirror != failed_mirror);
> +			failrec->in_validation = 0;
> +			failrec->this_mirror = 0;
> +		}
> +		failrec->failed_mirror = failed_mirror;
> +		failrec->this_mirror++;
> +		if (failrec->this_mirror == failed_mirror)
> +			failrec->this_mirror++;
> +		read_mode = READ_SYNC;
> +	}
> +
> +	if (!state || failrec->this_mirror > num_copies) {
> +		pr_debug("bio_readpage_error: (fail) state=%p, num_copies=%d, "
> +			 "next_mirror %d, failed_mirror %d\n", state,
> +			 num_copies, failrec->this_mirror, failed_mirror);
> +		free_io_failure(inode, failrec, 0);
> +		return -EIO;
> +	}
> +
> +	bio = bio_alloc(GFP_NOFS, 1);
> +	bio->bi_private = state;
> +	bio->bi_end_io = failed_bio->bi_end_io;
> +	bio->bi_sector = failrec->logical >> 9;
> +	bio->bi_bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
> +	bio->bi_size = 0;
> +
> +	bio_add_page(bio, page, failrec->len, start - page_offset(page));
> +
> +	pr_debug("bio_readpage_error: submitting new read[%#x] to "
> +		 "this_mirror=%d, num_copies=%d, in_validation=%d\n", read_mode,
> +		 failrec->this_mirror, num_copies, failrec->in_validation);
> +
> +	tree->ops->submit_bio_hook(inode, read_mode, bio, failrec->this_mirror,
> +					failrec->bio_flags, 0);
> +	return 0;
> +}
> +
>  /* lots and lots of room for performance fixes in the end_bio funcs */
>  
>  /*
> @@ -1740,6 +2102,9 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
>  		struct extent_state *cached = NULL;
>  		struct extent_state *state;
>  
> +		pr_debug("end_bio_extent_readpage: bi_vcnt=%d, idx=%d, err=%d, "
> +			 "mirror=%ld\n", bio->bi_vcnt, bio->bi_idx, err,
> +			 (long int)bio->bi_bdev);
>  		tree = &BTRFS_I(page->mapping->host)->io_tree;
>  
>  		start = ((u64)page->index << PAGE_CACHE_SHIFT) +
> @@ -1770,11 +2135,19 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
>  							      state);
>  			if (ret)
>  				uptodate = 0;
> +			else
> +				clean_io_failure(start, page);
>  		}
> -		if (!uptodate && tree->ops &&
> -		    tree->ops->readpage_io_failed_hook) {
> -			ret = tree->ops->readpage_io_failed_hook(bio, page,
> -							 start, end, NULL);
> +		if (!uptodate) {
> +			u64 failed_mirror;
> +			failed_mirror = (u64)bio->bi_bdev;
> +			if (tree->ops && tree->ops->readpage_io_failed_hook)
> +				ret = tree->ops->readpage_io_failed_hook(
> +						bio, page, start, end,
> +						failed_mirror, NULL);
> +			else
> +				ret = bio_readpage_error(bio, page, start, end,
> +							 failed_mirror, NULL);
>  			if (ret == 0) {
>  				uptodate =
>  					test_bit(BIO_UPTODATE, &bio->bi_flags);
> @@ -1854,6 +2227,7 @@ static int submit_one_bio(int rw, struct bio *bio, int mirror_num,
>  					   mirror_num, bio_flags, start);
>  	else
>  		submit_bio(rw, bio);
> +
>  	if (bio_flagged(bio, BIO_EOPNOTSUPP))
>  		ret = -EOPNOTSUPP;
>  	bio_put(bio);
> @@ -2966,7 +3340,7 @@ out:
>  	return ret;
>  }
>  
> -static inline struct page *extent_buffer_page(struct extent_buffer *eb,
> +inline struct page *extent_buffer_page(struct extent_buffer *eb,
>  					      unsigned long i)
>  {
>  	struct page *p;
> @@ -2991,7 +3365,7 @@ static inline struct page *extent_buffer_page(struct extent_buffer *eb,
>  	return p;
>  }
>  
> -static inline unsigned long num_extent_pages(u64 start, u64 len)
> +inline unsigned long num_extent_pages(u64 start, u64 len)
>  {
>  	return ((start + len + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT) -
>  		(start >> PAGE_CACHE_SHIFT);
> diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
> index a11a92e..e29d54d 100644
> --- a/fs/btrfs/extent_io.h
> +++ b/fs/btrfs/extent_io.h
> @@ -17,6 +17,7 @@
>  #define EXTENT_NODATASUM (1 << 10)
>  #define EXTENT_DO_ACCOUNTING (1 << 11)
>  #define EXTENT_FIRST_DELALLOC (1 << 12)
> +#define EXTENT_DAMAGED (1 << 13)
>  #define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK)
>  #define EXTENT_CTLBITS (EXTENT_DO_ACCOUNTING | EXTENT_FIRST_DELALLOC)
>  
> @@ -67,7 +68,7 @@ struct extent_io_ops {
>  			      unsigned long bio_flags);
>  	int (*readpage_io_hook)(struct page *page, u64 start, u64 end);
>  	int (*readpage_io_failed_hook)(struct bio *bio, struct page *page,
> -				       u64 start, u64 end,
> +				       u64 start, u64 end, u64 failed_mirror,
>  				       struct extent_state *state);
>  	int (*writepage_io_failed_hook)(struct bio *bio, struct page *page,
>  					u64 start, u64 end,
> @@ -243,6 +244,8 @@ void free_extent_buffer(struct extent_buffer *eb);
>  int read_extent_buffer_pages(struct extent_io_tree *tree,
>  			     struct extent_buffer *eb, u64 start, int wait,
>  			     get_extent_t *get_extent, int mirror_num);
> +unsigned long num_extent_pages(u64 start, u64 len);
> +struct page *extent_buffer_page(struct extent_buffer *eb, unsigned long i);
>  
>  static inline void extent_buffer_get(struct extent_buffer *eb)
>  {
> @@ -297,4 +300,10 @@ int extent_clear_unlock_delalloc(struct inode *inode,
>  struct bio *
>  btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
>  		gfp_t gfp_flags);
> +
> +struct btrfs_mapping_tree;
> +
> +int repair_io_failure(struct btrfs_mapping_tree *map_tree, u64 start,
> +			u64 length, u64 logical, struct page *page,
> +			int mirror_num);
>  #endif
> diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
> index 6ec7a93..86195d4 100644
> --- a/fs/btrfs/inode.c
> +++ b/fs/btrfs/inode.c
> @@ -45,10 +45,10 @@
>  #include "btrfs_inode.h"
>  #include "ioctl.h"
>  #include "print-tree.h"
> -#include "volumes.h"
>  #include "ordered-data.h"
>  #include "xattr.h"
>  #include "tree-log.h"
> +#include "volumes.h"
>  #include "compression.h"
>  #include "locking.h"
>  #include "free-space-cache.h"
> @@ -1820,153 +1820,9 @@ static int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end,
>  }
>  
>  /*
> - * When IO fails, either with EIO or csum verification fails, we
> - * try other mirrors that might have a good copy of the data.  This
> - * io_failure_record is used to record state as we go through all the
> - * mirrors.  If another mirror has good data, the page is set up to date
> - * and things continue.  If a good mirror can't be found, the original
> - * bio end_io callback is called to indicate things have failed.
> - */
> -struct io_failure_record {
> -	struct page *page;
> -	u64 start;
> -	u64 len;
> -	u64 logical;
> -	unsigned long bio_flags;
> -	int last_mirror;
> -};
> -
> -static int btrfs_io_failed_hook(struct bio *failed_bio,
> -			 struct page *page, u64 start, u64 end,
> -			 struct extent_state *state)
> -{
> -	struct io_failure_record *failrec = NULL;
> -	u64 private;
> -	struct extent_map *em;
> -	struct inode *inode = page->mapping->host;
> -	struct extent_io_tree *failure_tree = &BTRFS_I(inode)->io_failure_tree;
> -	struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
> -	struct bio *bio;
> -	int num_copies;
> -	int ret;
> -	int rw;
> -	u64 logical;
> -
> -	ret = get_state_private(failure_tree, start, &private);
> -	if (ret) {
> -		failrec = kmalloc(sizeof(*failrec), GFP_NOFS);
> -		if (!failrec)
> -			return -ENOMEM;
> -		failrec->start = start;
> -		failrec->len = end - start + 1;
> -		failrec->last_mirror = 0;
> -		failrec->bio_flags = 0;
> -
> -		read_lock(&em_tree->lock);
> -		em = lookup_extent_mapping(em_tree, start, failrec->len);
> -		if (em->start > start || em->start + em->len < start) {
> -			free_extent_map(em);
> -			em = NULL;
> -		}
> -		read_unlock(&em_tree->lock);
> -
> -		if (IS_ERR_OR_NULL(em)) {
> -			kfree(failrec);
> -			return -EIO;
> -		}
> -		logical = start - em->start;
> -		logical = em->block_start + logical;
> -		if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) {
> -			logical = em->block_start;
> -			failrec->bio_flags = EXTENT_BIO_COMPRESSED;
> -			extent_set_compress_type(&failrec->bio_flags,
> -						 em->compress_type);
> -		}
> -		failrec->logical = logical;
> -		free_extent_map(em);
> -		set_extent_bits(failure_tree, start, end, EXTENT_LOCKED |
> -				EXTENT_DIRTY, GFP_NOFS);
> -		set_state_private(failure_tree, start,
> -				 (u64)(unsigned long)failrec);
> -	} else {
> -		failrec = (struct io_failure_record *)(unsigned long)private;
> -	}
> -	num_copies = btrfs_num_copies(
> -			      &BTRFS_I(inode)->root->fs_info->mapping_tree,
> -			      failrec->logical, failrec->len);
> -	failrec->last_mirror++;
> -	if (!state) {
> -		spin_lock(&BTRFS_I(inode)->io_tree.lock);
> -		state = find_first_extent_bit_state(&BTRFS_I(inode)->io_tree,
> -						    failrec->start,
> -						    EXTENT_LOCKED);
> -		if (state && state->start != failrec->start)
> -			state = NULL;
> -		spin_unlock(&BTRFS_I(inode)->io_tree.lock);
> -	}
> -	if (!state || failrec->last_mirror > num_copies) {
> -		set_state_private(failure_tree, failrec->start, 0);
> -		clear_extent_bits(failure_tree, failrec->start,
> -				  failrec->start + failrec->len - 1,
> -				  EXTENT_LOCKED | EXTENT_DIRTY, GFP_NOFS);
> -		kfree(failrec);
> -		return -EIO;
> -	}
> -	bio = bio_alloc(GFP_NOFS, 1);
> -	bio->bi_private = state;
> -	bio->bi_end_io = failed_bio->bi_end_io;
> -	bio->bi_sector = failrec->logical >> 9;
> -	bio->bi_bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
> -	bio->bi_size = 0;
> -
> -	bio_add_page(bio, page, failrec->len, start - page_offset(page));
> -	if (failed_bio->bi_rw & REQ_WRITE)
> -		rw = WRITE;
> -	else
> -		rw = READ;
> -
> -	ret = BTRFS_I(inode)->io_tree.ops->submit_bio_hook(inode, rw, bio,
> -						      failrec->last_mirror,
> -						      failrec->bio_flags, 0);
> -	return ret;
> -}
> -
> -/*
> - * each time an IO finishes, we do a fast check in the IO failure tree
> - * to see if we need to process or clean up an io_failure_record
> - */
> -static int btrfs_clean_io_failures(struct inode *inode, u64 start)
> -{
> -	u64 private;
> -	u64 private_failure;
> -	struct io_failure_record *failure;
> -	int ret;
> -
> -	private = 0;
> -	if (count_range_bits(&BTRFS_I(inode)->io_failure_tree, &private,
> -			     (u64)-1, 1, EXTENT_DIRTY, 0)) {
> -		ret = get_state_private(&BTRFS_I(inode)->io_failure_tree,
> -					start, &private_failure);
> -		if (ret == 0) {
> -			failure = (struct io_failure_record *)(unsigned long)
> -				   private_failure;
> -			set_state_private(&BTRFS_I(inode)->io_failure_tree,
> -					  failure->start, 0);
> -			clear_extent_bits(&BTRFS_I(inode)->io_failure_tree,
> -					  failure->start,
> -					  failure->start + failure->len - 1,
> -					  EXTENT_DIRTY | EXTENT_LOCKED,
> -					  GFP_NOFS);
> -			kfree(failure);
> -		}
> -	}
> -	return 0;
> -}
> -
> -/*
>   * when reads are done, we need to check csums to verify the data is correct
> - * if there's a match, we allow the bio to finish.  If not, we go through
> - * the io_failure_record routines to find good copies
> + * if there's a match, we allow the bio to finish.  If not, the code in
> + * extent_io.c will try to find good copies for us.
>   */
>  static int btrfs_readpage_end_io_hook(struct page *page, u64 start, u64 end,
>  			       struct extent_state *state)
> @@ -2012,10 +1868,6 @@ static int btrfs_readpage_end_io_hook(struct page *page, u64 start, u64 end,
>  
>  	kunmap_atomic(kaddr, KM_USER0);
>  good:
> -	/* if the io failure tree for this inode is non-empty,
> -	 * check to see if we've recovered from a failed IO
> -	 */
> -	btrfs_clean_io_failures(inode, start);
>  	return 0;
>  
>  zeroit:
> @@ -7384,7 +7236,6 @@ static struct extent_io_ops btrfs_extent_io_ops = {
>  	.readpage_end_io_hook = btrfs_readpage_end_io_hook,
>  	.writepage_end_io_hook = btrfs_writepage_end_io_hook,
>  	.writepage_start_hook = btrfs_writepage_start_hook,
> -	.readpage_io_failed_hook = btrfs_io_failed_hook,
>  	.set_bit_hook = btrfs_set_bit_hook,
>  	.clear_bit_hook = btrfs_clear_bit_hook,
>  	.merge_extent_hook = btrfs_merge_extent_hook,


--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Filesystem Development]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux