diff options
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r-- | fs/btrfs/disk-io.c | 67 |
1 files changed, 54 insertions, 13 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 1f1d89b18818..9244cd7313d4 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -668,14 +668,31 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, | |||
668 | static int btree_writepage(struct page *page, struct writeback_control *wbc) | 668 | static int btree_writepage(struct page *page, struct writeback_control *wbc) |
669 | { | 669 | { |
670 | struct extent_io_tree *tree; | 670 | struct extent_io_tree *tree; |
671 | struct btrfs_root *root = BTRFS_I(page->mapping->host)->root; | ||
672 | struct extent_buffer *eb; | ||
673 | int was_dirty; | ||
674 | |||
671 | tree = &BTRFS_I(page->mapping->host)->io_tree; | 675 | tree = &BTRFS_I(page->mapping->host)->io_tree; |
676 | if (!(current->flags & PF_MEMALLOC)) { | ||
677 | return extent_write_full_page(tree, page, | ||
678 | btree_get_extent, wbc); | ||
679 | } | ||
672 | 680 | ||
673 | if (current->flags & PF_MEMALLOC) { | 681 | redirty_page_for_writepage(wbc, page); |
674 | redirty_page_for_writepage(wbc, page); | 682 | eb = btrfs_find_tree_block(root, page_offset(page), |
675 | unlock_page(page); | 683 | PAGE_CACHE_SIZE); |
676 | return 0; | 684 | WARN_ON(!eb); |
685 | |||
686 | was_dirty = test_and_set_bit(EXTENT_BUFFER_DIRTY, &eb->bflags); | ||
687 | if (!was_dirty) { | ||
688 | spin_lock(&root->fs_info->delalloc_lock); | ||
689 | root->fs_info->dirty_metadata_bytes += PAGE_CACHE_SIZE; | ||
690 | spin_unlock(&root->fs_info->delalloc_lock); | ||
677 | } | 691 | } |
678 | return extent_write_full_page(tree, page, btree_get_extent, wbc); | 692 | free_extent_buffer(eb); |
693 | |||
694 | unlock_page(page); | ||
695 | return 0; | ||
679 | } | 696 | } |
680 | 697 | ||
681 | static int btree_writepages(struct address_space *mapping, | 698 | static int btree_writepages(struct address_space *mapping, |
@@ -684,15 +701,15 @@ static int btree_writepages(struct address_space *mapping, | |||
684 | struct extent_io_tree *tree; | 701 | struct extent_io_tree *tree; |
685 | tree = &BTRFS_I(mapping->host)->io_tree; | 702 | tree = &BTRFS_I(mapping->host)->io_tree; |
686 | if (wbc->sync_mode == WB_SYNC_NONE) { | 703 | if (wbc->sync_mode == WB_SYNC_NONE) { |
704 | struct btrfs_root *root = BTRFS_I(mapping->host)->root; | ||
687 | u64 num_dirty; | 705 | u64 num_dirty; |
688 | u64 start = 0; | ||
689 | unsigned long thresh = 32 * 1024 * 1024; | 706 | unsigned long thresh = 32 * 1024 * 1024; |
690 | 707 | ||
691 | if (wbc->for_kupdate) | 708 | if (wbc->for_kupdate) |
692 | return 0; | 709 | return 0; |
693 | 710 | ||
694 | num_dirty = count_range_bits(tree, &start, (u64)-1, | 711 | /* this is a bit racy, but that's ok */ |
695 | thresh, EXTENT_DIRTY); | 712 | num_dirty = root->fs_info->dirty_metadata_bytes; |
696 | if (num_dirty < thresh) | 713 | if (num_dirty < thresh) |
697 | return 0; | 714 | return 0; |
698 | } | 715 | } |
@@ -859,9 +876,17 @@ int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
859 | root->fs_info->running_transaction->transid) { | 876 | root->fs_info->running_transaction->transid) { |
860 | btrfs_assert_tree_locked(buf); | 877 | btrfs_assert_tree_locked(buf); |
861 | 878 | ||
862 | /* ugh, clear_extent_buffer_dirty can be expensive */ | 879 | if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &buf->bflags)) { |
863 | btrfs_set_lock_blocking(buf); | 880 | spin_lock(&root->fs_info->delalloc_lock); |
881 | if (root->fs_info->dirty_metadata_bytes >= buf->len) | ||
882 | root->fs_info->dirty_metadata_bytes -= buf->len; | ||
883 | else | ||
884 | WARN_ON(1); | ||
885 | spin_unlock(&root->fs_info->delalloc_lock); | ||
886 | } | ||
864 | 887 | ||
888 | /* ugh, clear_extent_buffer_dirty needs to lock the page */ | ||
889 | btrfs_set_lock_blocking(buf); | ||
865 | clear_extent_buffer_dirty(&BTRFS_I(btree_inode)->io_tree, | 890 | clear_extent_buffer_dirty(&BTRFS_I(btree_inode)->io_tree, |
866 | buf); | 891 | buf); |
867 | } | 892 | } |
@@ -2348,8 +2373,7 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf) | |||
2348 | struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; | 2373 | struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; |
2349 | u64 transid = btrfs_header_generation(buf); | 2374 | u64 transid = btrfs_header_generation(buf); |
2350 | struct inode *btree_inode = root->fs_info->btree_inode; | 2375 | struct inode *btree_inode = root->fs_info->btree_inode; |
2351 | 2376 | int was_dirty; | |
2352 | btrfs_set_lock_blocking(buf); | ||
2353 | 2377 | ||
2354 | btrfs_assert_tree_locked(buf); | 2378 | btrfs_assert_tree_locked(buf); |
2355 | if (transid != root->fs_info->generation) { | 2379 | if (transid != root->fs_info->generation) { |
@@ -2360,7 +2384,13 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf) | |||
2360 | (unsigned long long)root->fs_info->generation); | 2384 | (unsigned long long)root->fs_info->generation); |
2361 | WARN_ON(1); | 2385 | WARN_ON(1); |
2362 | } | 2386 | } |
2363 | set_extent_buffer_dirty(&BTRFS_I(btree_inode)->io_tree, buf); | 2387 | was_dirty = set_extent_buffer_dirty(&BTRFS_I(btree_inode)->io_tree, |
2388 | buf); | ||
2389 | if (!was_dirty) { | ||
2390 | spin_lock(&root->fs_info->delalloc_lock); | ||
2391 | root->fs_info->dirty_metadata_bytes += buf->len; | ||
2392 | spin_unlock(&root->fs_info->delalloc_lock); | ||
2393 | } | ||
2364 | } | 2394 | } |
2365 | 2395 | ||
2366 | void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr) | 2396 | void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr) |
@@ -2400,6 +2430,7 @@ int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid) | |||
2400 | int btree_lock_page_hook(struct page *page) | 2430 | int btree_lock_page_hook(struct page *page) |
2401 | { | 2431 | { |
2402 | struct inode *inode = page->mapping->host; | 2432 | struct inode *inode = page->mapping->host; |
2433 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
2403 | struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; | 2434 | struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; |
2404 | struct extent_buffer *eb; | 2435 | struct extent_buffer *eb; |
2405 | unsigned long len; | 2436 | unsigned long len; |
@@ -2415,6 +2446,16 @@ int btree_lock_page_hook(struct page *page) | |||
2415 | 2446 | ||
2416 | btrfs_tree_lock(eb); | 2447 | btrfs_tree_lock(eb); |
2417 | btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN); | 2448 | btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN); |
2449 | |||
2450 | if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) { | ||
2451 | spin_lock(&root->fs_info->delalloc_lock); | ||
2452 | if (root->fs_info->dirty_metadata_bytes >= eb->len) | ||
2453 | root->fs_info->dirty_metadata_bytes -= eb->len; | ||
2454 | else | ||
2455 | WARN_ON(1); | ||
2456 | spin_unlock(&root->fs_info->delalloc_lock); | ||
2457 | } | ||
2458 | |||
2418 | btrfs_tree_unlock(eb); | 2459 | btrfs_tree_unlock(eb); |
2419 | free_extent_buffer(eb); | 2460 | free_extent_buffer(eb); |
2420 | out: | 2461 | out: |