diff options
author | Chris Mason <chris.mason@oracle.com> | 2010-11-21 22:20:49 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2010-11-21 22:26:02 -0500 |
commit | 784b4e29a26617589edd290dd2919735e190c06e (patch) | |
tree | 1c1806afb3aa5a7f82b272b8b38dc1e13e45d16b /fs | |
parent | 6418c96107a2b399848bb8cfc6e29f11ca74fb94 (diff) |
Btrfs: add migrate page for metadata inode
Migrate page will directly call the btrfs btree writepage function,
which isn't actually allowed.
Our writepage assumes that you have locked the extent_buffer and
flagged the block as written. Without doing these steps, we can
corrupt metadata blocks.
A later commit will remove the btree writepage function since
it is really only safely used internally by btrfs. We
use writepages for everything else.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/disk-io.c | 27 |
1 files changed, 25 insertions, 2 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index b40dfe48017b..a67b98d58c2a 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/freezer.h> | 28 | #include <linux/freezer.h> |
29 | #include <linux/crc32c.h> | 29 | #include <linux/crc32c.h> |
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | #include <linux/migrate.h> | ||
31 | #include "compat.h" | 32 | #include "compat.h" |
32 | #include "ctree.h" | 33 | #include "ctree.h" |
33 | #include "disk-io.h" | 34 | #include "disk-io.h" |
@@ -355,6 +356,8 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page) | |||
355 | ret = btree_read_extent_buffer_pages(root, eb, start + PAGE_CACHE_SIZE, | 356 | ret = btree_read_extent_buffer_pages(root, eb, start + PAGE_CACHE_SIZE, |
356 | btrfs_header_generation(eb)); | 357 | btrfs_header_generation(eb)); |
357 | BUG_ON(ret); | 358 | BUG_ON(ret); |
359 | WARN_ON(!btrfs_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN)); | ||
360 | |||
358 | found_start = btrfs_header_bytenr(eb); | 361 | found_start = btrfs_header_bytenr(eb); |
359 | if (found_start != start) { | 362 | if (found_start != start) { |
360 | WARN_ON(1); | 363 | WARN_ON(1); |
@@ -693,6 +696,26 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, | |||
693 | __btree_submit_bio_done); | 696 | __btree_submit_bio_done); |
694 | } | 697 | } |
695 | 698 | ||
699 | static int btree_migratepage(struct address_space *mapping, | ||
700 | struct page *newpage, struct page *page) | ||
701 | { | ||
702 | /* | ||
703 | * we can't safely write a btree page from here, | ||
704 | * we haven't done the locking hook | ||
705 | */ | ||
706 | if (PageDirty(page)) | ||
707 | return -EAGAIN; | ||
708 | /* | ||
709 | * Buffers may be managed in a filesystem specific way. | ||
710 | * We must have no buffers or drop them. | ||
711 | */ | ||
712 | if (page_has_private(page) && | ||
713 | !try_to_release_page(page, GFP_KERNEL)) | ||
714 | return -EAGAIN; | ||
715 | |||
716 | return migrate_page(mapping, newpage, page); | ||
717 | } | ||
718 | |||
696 | static int btree_writepage(struct page *page, struct writeback_control *wbc) | 719 | static int btree_writepage(struct page *page, struct writeback_control *wbc) |
697 | { | 720 | { |
698 | struct extent_io_tree *tree; | 721 | struct extent_io_tree *tree; |
@@ -707,8 +730,7 @@ static int btree_writepage(struct page *page, struct writeback_control *wbc) | |||
707 | } | 730 | } |
708 | 731 | ||
709 | redirty_page_for_writepage(wbc, page); | 732 | redirty_page_for_writepage(wbc, page); |
710 | eb = btrfs_find_tree_block(root, page_offset(page), | 733 | eb = btrfs_find_tree_block(root, page_offset(page), PAGE_CACHE_SIZE); |
711 | PAGE_CACHE_SIZE); | ||
712 | WARN_ON(!eb); | 734 | WARN_ON(!eb); |
713 | 735 | ||
714 | was_dirty = test_and_set_bit(EXTENT_BUFFER_DIRTY, &eb->bflags); | 736 | was_dirty = test_and_set_bit(EXTENT_BUFFER_DIRTY, &eb->bflags); |
@@ -799,6 +821,7 @@ static const struct address_space_operations btree_aops = { | |||
799 | .releasepage = btree_releasepage, | 821 | .releasepage = btree_releasepage, |
800 | .invalidatepage = btree_invalidatepage, | 822 | .invalidatepage = btree_invalidatepage, |
801 | .sync_page = block_sync_page, | 823 | .sync_page = block_sync_page, |
824 | .migratepage = btree_migratepage, | ||
802 | }; | 825 | }; |
803 | 826 | ||
804 | int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, | 827 | int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, |