aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/disk-io.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2010-11-21 22:20:49 -0500
committerChris Mason <chris.mason@oracle.com>2010-11-21 22:26:02 -0500
commit784b4e29a26617589edd290dd2919735e190c06e (patch)
tree1c1806afb3aa5a7f82b272b8b38dc1e13e45d16b /fs/btrfs/disk-io.c
parent6418c96107a2b399848bb8cfc6e29f11ca74fb94 (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/btrfs/disk-io.c')
-rw-r--r--fs/btrfs/disk-io.c27
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
699static 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
696static int btree_writepage(struct page *page, struct writeback_control *wbc) 719static 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
804int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, 827int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize,