aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/disk-io.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2009-03-13 11:00:37 -0400
committerChris Mason <chris.mason@oracle.com>2009-03-24 16:14:28 -0400
commitb9473439d3e84d9fc1a0a83faca69cc1b7566341 (patch)
treebef8321b80589026b617d61d0fabaf545d459269 /fs/btrfs/disk-io.c
parent89573b9c516b24af8a3b9958dd5afca8fa874e3d (diff)
Btrfs: leave btree locks spinning more often
btrfs_mark_buffer dirty would set dirty bits in the extent_io tree for the buffers it was dirtying. This may require a kmalloc and it was not atomic. So, anyone who called btrfs_mark_buffer_dirty had to set any btree locks they were holding to blocking first. This commit changes dirty tracking for extent buffers to just use a flag in the extent buffer. Now that we have one and only one extent buffer per page, this can be safely done without losing dirty bits along the way. This also introduces a path->leave_spinning flag that callers of btrfs_search_slot can use to indicate they will properly deal with a path returned where all the locks are spinning instead of blocking. Many of the btree search callers now expect spinning paths, resulting in better btree concurrency overall. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r--fs/btrfs/disk-io.c67
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,
668static int btree_writepage(struct page *page, struct writeback_control *wbc) 668static 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
681static int btree_writepages(struct address_space *mapping, 698static 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
2366void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr) 2396void 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)
2400int btree_lock_page_hook(struct page *page) 2430int 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);
2420out: 2461out: