diff options
Diffstat (limited to 'fs/btrfs/extent_io.c')
-rw-r--r-- | fs/btrfs/extent_io.c | 54 |
1 files changed, 28 insertions, 26 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 782f3bc4651d..43af5a61ad25 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -4560,36 +4560,37 @@ static void btrfs_release_extent_buffer_page(struct extent_buffer *eb) | |||
4560 | do { | 4560 | do { |
4561 | index--; | 4561 | index--; |
4562 | page = eb->pages[index]; | 4562 | page = eb->pages[index]; |
4563 | if (page && mapped) { | 4563 | if (!page) |
4564 | continue; | ||
4565 | if (mapped) | ||
4564 | spin_lock(&page->mapping->private_lock); | 4566 | spin_lock(&page->mapping->private_lock); |
4567 | /* | ||
4568 | * We do this since we'll remove the pages after we've | ||
4569 | * removed the eb from the radix tree, so we could race | ||
4570 | * and have this page now attached to the new eb. So | ||
4571 | * only clear page_private if it's still connected to | ||
4572 | * this eb. | ||
4573 | */ | ||
4574 | if (PagePrivate(page) && | ||
4575 | page->private == (unsigned long)eb) { | ||
4576 | BUG_ON(test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)); | ||
4577 | BUG_ON(PageDirty(page)); | ||
4578 | BUG_ON(PageWriteback(page)); | ||
4565 | /* | 4579 | /* |
4566 | * We do this since we'll remove the pages after we've | 4580 | * We need to make sure we haven't be attached |
4567 | * removed the eb from the radix tree, so we could race | 4581 | * to a new eb. |
4568 | * and have this page now attached to the new eb. So | ||
4569 | * only clear page_private if it's still connected to | ||
4570 | * this eb. | ||
4571 | */ | 4582 | */ |
4572 | if (PagePrivate(page) && | 4583 | ClearPagePrivate(page); |
4573 | page->private == (unsigned long)eb) { | 4584 | set_page_private(page, 0); |
4574 | BUG_ON(test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)); | 4585 | /* One for the page private */ |
4575 | BUG_ON(PageDirty(page)); | ||
4576 | BUG_ON(PageWriteback(page)); | ||
4577 | /* | ||
4578 | * We need to make sure we haven't be attached | ||
4579 | * to a new eb. | ||
4580 | */ | ||
4581 | ClearPagePrivate(page); | ||
4582 | set_page_private(page, 0); | ||
4583 | /* One for the page private */ | ||
4584 | page_cache_release(page); | ||
4585 | } | ||
4586 | spin_unlock(&page->mapping->private_lock); | ||
4587 | |||
4588 | } | ||
4589 | if (page) { | ||
4590 | /* One for when we alloced the page */ | ||
4591 | page_cache_release(page); | 4586 | page_cache_release(page); |
4592 | } | 4587 | } |
4588 | |||
4589 | if (mapped) | ||
4590 | spin_unlock(&page->mapping->private_lock); | ||
4591 | |||
4592 | /* One for when we alloced the page */ | ||
4593 | page_cache_release(page); | ||
4593 | } while (index != 0); | 4594 | } while (index != 0); |
4594 | } | 4595 | } |
4595 | 4596 | ||
@@ -4870,6 +4871,7 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info, | |||
4870 | mark_extent_buffer_accessed(exists, p); | 4871 | mark_extent_buffer_accessed(exists, p); |
4871 | goto free_eb; | 4872 | goto free_eb; |
4872 | } | 4873 | } |
4874 | exists = NULL; | ||
4873 | 4875 | ||
4874 | /* | 4876 | /* |
4875 | * Do this so attach doesn't complain and we need to | 4877 | * Do this so attach doesn't complain and we need to |
@@ -4933,12 +4935,12 @@ again: | |||
4933 | return eb; | 4935 | return eb; |
4934 | 4936 | ||
4935 | free_eb: | 4937 | free_eb: |
4938 | WARN_ON(!atomic_dec_and_test(&eb->refs)); | ||
4936 | for (i = 0; i < num_pages; i++) { | 4939 | for (i = 0; i < num_pages; i++) { |
4937 | if (eb->pages[i]) | 4940 | if (eb->pages[i]) |
4938 | unlock_page(eb->pages[i]); | 4941 | unlock_page(eb->pages[i]); |
4939 | } | 4942 | } |
4940 | 4943 | ||
4941 | WARN_ON(!atomic_dec_and_test(&eb->refs)); | ||
4942 | btrfs_release_extent_buffer(eb); | 4944 | btrfs_release_extent_buffer(eb); |
4943 | return exists; | 4945 | return exists; |
4944 | } | 4946 | } |