Skip to content
Permalink
Browse files
btrfs: disk-io: introduce subpage metadata validation check
For subpage metadata validation check, there are some difference:
- Read must finish in one bvec
  Since we're just reading one subpage range in one page, it should
  never be split into two bios nor two bvecs.

- How to grab the existing eb
  Instead of grabbing eb using page->private, we have to go search radix
  tree as we don't have any direct pointer at hand.

Signed-off-by: Qu Wenruo <wqu@suse.com>
  • Loading branch information
adam900710 authored and intel-lab-lkp committed Dec 10, 2020
1 parent c96b40a commit e01cdf51d0d32647697616c0dd08f2cc3220bde4
Showing 1 changed file with 82 additions and 0 deletions.
@@ -591,6 +591,84 @@ static int validate_extent_buffer(struct extent_buffer *eb)
return ret;
}

static int validate_subpage_buffer(struct page *page, u64 start, u64 end,
int mirror)
{
struct btrfs_fs_info *fs_info = btrfs_sb(page->mapping->host->i_sb);
struct extent_buffer *eb;
int reads_done;
int ret = 0;

if (!IS_ALIGNED(start, fs_info->sectorsize) ||
!IS_ALIGNED(end - start + 1, fs_info->sectorsize) ||
!IS_ALIGNED(end - start + 1, fs_info->nodesize)) {
WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG));
btrfs_err(fs_info, "invalid tree read bytenr");
return -EUCLEAN;
}

/*
* We don't allow bio merge for subpage metadata read, so we should
* only get one eb for each endio hook.
*/
ASSERT(end == start + fs_info->nodesize - 1);
ASSERT(PagePrivate(page));

rcu_read_lock();
eb = radix_tree_lookup(&fs_info->buffer_radix,
start / fs_info->sectorsize);
rcu_read_unlock();

/*
* When we are reading one tree block, eb must have been
* inserted into the radix tree. If not something is wrong.
*/
if (!eb) {
WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG));
btrfs_err(fs_info,
"can't find extent buffer for bytenr %llu",
start);
return -EUCLEAN;
}
/*
* The pending IO might have been the only thing that kept
* this buffer in memory. Make sure we have a ref for all
* this other checks
*/
atomic_inc(&eb->refs);

reads_done = atomic_dec_and_test(&eb->io_pages);
/* Subpage read must finish in page read */
ASSERT(reads_done);

eb->read_mirror = mirror;
if (test_bit(EXTENT_BUFFER_READ_ERR, &eb->bflags)) {
ret = -EIO;
goto err;
}
ret = validate_extent_buffer(eb);
if (ret < 0)
goto err;

if (test_and_clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags))
btree_readahead_hook(eb, ret);

set_extent_buffer_uptodate(eb);

free_extent_buffer(eb);
return ret;
err:
/*
* our io error hook is going to dec the io pages
* again, we have to make sure it has something to
* decrement
*/
atomic_inc(&eb->io_pages);
clear_extent_buffer_uptodate(eb);
free_extent_buffer(eb);
return ret;
}

int btrfs_validate_metadata_buffer(struct btrfs_io_bio *io_bio,
struct page *page, u64 start, u64 end,
int mirror)
@@ -600,6 +678,10 @@ int btrfs_validate_metadata_buffer(struct btrfs_io_bio *io_bio,
int reads_done;

ASSERT(page->private);

if (btrfs_sb(page->mapping->host->i_sb)->sectorsize < PAGE_SIZE)
return validate_subpage_buffer(page, start, end, mirror);

eb = (struct extent_buffer *)page->private;


0 comments on commit e01cdf5

Please sign in to comment.