Commit 5cf1ab56 authored by Josef Bacik's avatar Josef Bacik Committed by David Sterba

Btrfs: always store the mirror we read the eb from

A user reported a panic where we were trying to fix a bad mirror but the
mirror number we were giving was 0, which is invalid.  This is because we
don't do the transid verification until after the read, so as far as the
read code is concerned the read was a success.  So instead store the mirror
we read from so that if there is some failure post read we know which mirror
to try next and which mirror needs to be fixed if we find a good copy of the
block.  Thanks,
Signed-off-by: default avatarJosef Bacik <josef@redhat.com>
parent 48d28232
...@@ -383,17 +383,16 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root, ...@@ -383,17 +383,16 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root,
if (test_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags)) if (test_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags))
break; break;
if (!failed_mirror) {
failed = 1;
printk(KERN_ERR "failed mirror was %d\n", eb->failed_mirror);
failed_mirror = eb->failed_mirror;
}
num_copies = btrfs_num_copies(&root->fs_info->mapping_tree, num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
eb->start, eb->len); eb->start, eb->len);
if (num_copies == 1) if (num_copies == 1)
break; break;
if (!failed_mirror) {
failed = 1;
failed_mirror = eb->read_mirror;
}
mirror_num++; mirror_num++;
if (mirror_num == failed_mirror) if (mirror_num == failed_mirror)
mirror_num++; mirror_num++;
...@@ -564,7 +563,7 @@ struct extent_buffer *find_eb_for_page(struct extent_io_tree *tree, ...@@ -564,7 +563,7 @@ struct extent_buffer *find_eb_for_page(struct extent_io_tree *tree,
} }
static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end, static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
struct extent_state *state) struct extent_state *state, int mirror)
{ {
struct extent_io_tree *tree; struct extent_io_tree *tree;
u64 found_start; u64 found_start;
...@@ -589,6 +588,7 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end, ...@@ -589,6 +588,7 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
if (!reads_done) if (!reads_done)
goto err; goto err;
eb->read_mirror = mirror;
if (test_bit(EXTENT_BUFFER_IOERR, &eb->bflags)) { if (test_bit(EXTENT_BUFFER_IOERR, &eb->bflags)) {
ret = -EIO; ret = -EIO;
goto err; goto err;
...@@ -652,7 +652,7 @@ static int btree_io_failed_hook(struct page *page, int failed_mirror) ...@@ -652,7 +652,7 @@ static int btree_io_failed_hook(struct page *page, int failed_mirror)
eb = (struct extent_buffer *)page->private; eb = (struct extent_buffer *)page->private;
set_bit(EXTENT_BUFFER_IOERR, &eb->bflags); set_bit(EXTENT_BUFFER_IOERR, &eb->bflags);
eb->failed_mirror = failed_mirror; eb->read_mirror = failed_mirror;
if (test_and_clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags)) if (test_and_clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags))
btree_readahead_hook(root, eb, eb->start, -EIO); btree_readahead_hook(root, eb, eb->start, -EIO);
return -EIO; /* we fixed nothing */ return -EIO; /* we fixed nothing */
......
...@@ -2304,7 +2304,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err) ...@@ -2304,7 +2304,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
u64 start; u64 start;
u64 end; u64 end;
int whole_page; int whole_page;
int failed_mirror; int mirror;
int ret; int ret;
if (err) if (err)
...@@ -2343,20 +2343,18 @@ static void end_bio_extent_readpage(struct bio *bio, int err) ...@@ -2343,20 +2343,18 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
} }
spin_unlock(&tree->lock); spin_unlock(&tree->lock);
mirror = (int)(unsigned long)bio->bi_bdev;
if (uptodate && tree->ops && tree->ops->readpage_end_io_hook) { if (uptodate && tree->ops && tree->ops->readpage_end_io_hook) {
ret = tree->ops->readpage_end_io_hook(page, start, end, ret = tree->ops->readpage_end_io_hook(page, start, end,
state); state, mirror);
if (ret) if (ret)
uptodate = 0; uptodate = 0;
else else
clean_io_failure(start, page); clean_io_failure(start, page);
} }
if (!uptodate)
failed_mirror = (int)(unsigned long)bio->bi_bdev;
if (!uptodate && tree->ops && tree->ops->readpage_io_failed_hook) { if (!uptodate && tree->ops && tree->ops->readpage_io_failed_hook) {
ret = tree->ops->readpage_io_failed_hook(page, failed_mirror); ret = tree->ops->readpage_io_failed_hook(page, mirror);
if (!ret && !err && if (!ret && !err &&
test_bit(BIO_UPTODATE, &bio->bi_flags)) test_bit(BIO_UPTODATE, &bio->bi_flags))
uptodate = 1; uptodate = 1;
...@@ -2371,8 +2369,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err) ...@@ -2371,8 +2369,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
* can't handle the error it will return -EIO and we * can't handle the error it will return -EIO and we
* remain responsible for that page. * remain responsible for that page.
*/ */
ret = bio_readpage_error(bio, page, start, end, ret = bio_readpage_error(bio, page, start, end, mirror, NULL);
failed_mirror, NULL);
if (ret == 0) { if (ret == 0) {
uptodate = uptodate =
test_bit(BIO_UPTODATE, &bio->bi_flags); test_bit(BIO_UPTODATE, &bio->bi_flags);
...@@ -4465,7 +4462,7 @@ int read_extent_buffer_pages(struct extent_io_tree *tree, ...@@ -4465,7 +4462,7 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
} }
clear_bit(EXTENT_BUFFER_IOERR, &eb->bflags); clear_bit(EXTENT_BUFFER_IOERR, &eb->bflags);
eb->failed_mirror = 0; eb->read_mirror = 0;
atomic_set(&eb->io_pages, num_reads); atomic_set(&eb->io_pages, num_reads);
for (i = start_i; i < num_pages; i++) { for (i = start_i; i < num_pages; i++) {
page = extent_buffer_page(eb, i); page = extent_buffer_page(eb, i);
......
...@@ -79,7 +79,7 @@ struct extent_io_ops { ...@@ -79,7 +79,7 @@ struct extent_io_ops {
u64 start, u64 end, u64 start, u64 end,
struct extent_state *state); struct extent_state *state);
int (*readpage_end_io_hook)(struct page *page, u64 start, u64 end, int (*readpage_end_io_hook)(struct page *page, u64 start, u64 end,
struct extent_state *state); struct extent_state *state, int mirror);
int (*writepage_end_io_hook)(struct page *page, u64 start, u64 end, int (*writepage_end_io_hook)(struct page *page, u64 start, u64 end,
struct extent_state *state, int uptodate); struct extent_state *state, int uptodate);
void (*set_bit_hook)(struct inode *inode, struct extent_state *state, void (*set_bit_hook)(struct inode *inode, struct extent_state *state,
...@@ -135,7 +135,7 @@ struct extent_buffer { ...@@ -135,7 +135,7 @@ struct extent_buffer {
spinlock_t refs_lock; spinlock_t refs_lock;
atomic_t refs; atomic_t refs;
atomic_t io_pages; atomic_t io_pages;
int failed_mirror; int read_mirror;
struct list_head leak_list; struct list_head leak_list;
struct rcu_head rcu_head; struct rcu_head rcu_head;
pid_t lock_owner; pid_t lock_owner;
......
...@@ -1947,7 +1947,7 @@ static int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end, ...@@ -1947,7 +1947,7 @@ static int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end,
* extent_io.c will try to find good copies for us. * 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, static int btrfs_readpage_end_io_hook(struct page *page, u64 start, u64 end,
struct extent_state *state) struct extent_state *state, int mirror)
{ {
size_t offset = start - ((u64)page->index << PAGE_CACHE_SHIFT); size_t offset = start - ((u64)page->index << PAGE_CACHE_SHIFT);
struct inode *inode = page->mapping->host; struct inode *inode = page->mapping->host;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment