Skip to content

Commit 0b32f4b

Browse files
Josef Bacikchrismason-xx
authored andcommitted
Btrfs: ensure an entire eb is written at once
This patch simplifies how we track our extent buffers. Previously we could exit writepages with only having written half of an extent buffer, which meant we had to track the state of the pages and the state of the extent buffers differently. Now we only read in entire extent buffers and write out entire extent buffers, this allows us to simply set bits in our bflags to indicate the state of the eb and we no longer have to do things like track uptodate with our iotree. Thanks, Signed-off-by: Josef Bacik <[email protected]> Signed-off-by: Chris Mason <[email protected]>
1 parent 5df4235 commit 0b32f4b

File tree

4 files changed

+390
-209
lines changed

4 files changed

+390
-209
lines changed

fs/btrfs/disk-io.c

Lines changed: 35 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
333333

334334
lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1,
335335
0, &cached_state, GFP_NOFS);
336-
if (extent_buffer_uptodate(io_tree, eb, cached_state) &&
336+
if (extent_buffer_uptodate(eb) &&
337337
btrfs_header_generation(eb) == parent_transid) {
338338
ret = 0;
339339
goto out;
@@ -344,7 +344,7 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
344344
(unsigned long long)parent_transid,
345345
(unsigned long long)btrfs_header_generation(eb));
346346
ret = 1;
347-
clear_extent_buffer_uptodate(io_tree, eb, &cached_state);
347+
clear_extent_buffer_uptodate(eb);
348348
out:
349349
unlock_extent_cached(io_tree, eb->start, eb->start + eb->len - 1,
350350
&cached_state, GFP_NOFS);
@@ -566,7 +566,12 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
566566
tree = &BTRFS_I(page->mapping->host)->io_tree;
567567
eb = (struct extent_buffer *)page->private;
568568

569-
reads_done = atomic_dec_and_test(&eb->pages_reading);
569+
/* the pending IO might have been the only thing that kept this buffer
570+
* in memory. Make sure we have a ref for all this other checks
571+
*/
572+
extent_buffer_get(eb);
573+
574+
reads_done = atomic_dec_and_test(&eb->io_pages);
570575
if (!reads_done)
571576
goto err;
572577

@@ -606,14 +611,17 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
606611
ret = -EIO;
607612
}
608613

614+
if (!ret)
615+
set_extent_buffer_uptodate(eb);
609616
err:
610617
if (test_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags)) {
611618
clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags);
612619
btree_readahead_hook(root, eb, eb->start, ret);
613620
}
614621

615-
if (ret && eb)
616-
clear_extent_buffer_uptodate(tree, eb, NULL);
622+
if (ret)
623+
clear_extent_buffer_uptodate(eb);
624+
free_extent_buffer(eb);
617625
out:
618626
return ret;
619627
}
@@ -878,20 +886,6 @@ static int btree_migratepage(struct address_space *mapping,
878886
}
879887
#endif
880888

881-
static int btree_writepage(struct page *page, struct writeback_control *wbc)
882-
{
883-
struct extent_io_tree *tree;
884-
tree = &BTRFS_I(page->mapping->host)->io_tree;
885-
886-
if (!(current->flags & PF_MEMALLOC)) {
887-
return extent_write_full_page(tree, page,
888-
btree_get_extent, wbc);
889-
}
890-
891-
redirty_page_for_writepage(wbc, page);
892-
unlock_page(page);
893-
return 0;
894-
}
895889

896890
static int btree_writepages(struct address_space *mapping,
897891
struct writeback_control *wbc)
@@ -911,7 +905,7 @@ static int btree_writepages(struct address_space *mapping,
911905
if (num_dirty < thresh)
912906
return 0;
913907
}
914-
return extent_writepages(tree, mapping, btree_get_extent, wbc);
908+
return btree_write_cache_pages(mapping, wbc);
915909
}
916910

917911
static int btree_readpage(struct file *file, struct page *page)
@@ -950,15 +944,28 @@ static void btree_invalidatepage(struct page *page, unsigned long offset)
950944
}
951945
}
952946

947+
static int btree_set_page_dirty(struct page *page)
948+
{
949+
struct extent_buffer *eb;
950+
951+
BUG_ON(!PagePrivate(page));
952+
eb = (struct extent_buffer *)page->private;
953+
BUG_ON(!eb);
954+
BUG_ON(!test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags));
955+
BUG_ON(!atomic_read(&eb->refs));
956+
btrfs_assert_tree_locked(eb);
957+
return __set_page_dirty_nobuffers(page);
958+
}
959+
953960
static const struct address_space_operations btree_aops = {
954961
.readpage = btree_readpage,
955-
.writepage = btree_writepage,
956962
.writepages = btree_writepages,
957963
.releasepage = btree_releasepage,
958964
.invalidatepage = btree_invalidatepage,
959965
#ifdef CONFIG_MIGRATION
960966
.migratepage = btree_migratepage,
961967
#endif
968+
.set_page_dirty = btree_set_page_dirty,
962969
};
963970

964971
int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize,
@@ -1001,7 +1008,7 @@ int reada_tree_block_flagged(struct btrfs_root *root, u64 bytenr, u32 blocksize,
10011008
if (test_bit(EXTENT_BUFFER_CORRUPT, &buf->bflags)) {
10021009
free_extent_buffer(buf);
10031010
return -EIO;
1004-
} else if (extent_buffer_uptodate(io_tree, buf, NULL)) {
1011+
} else if (extent_buffer_uptodate(buf)) {
10051012
*eb = buf;
10061013
} else {
10071014
free_extent_buffer(buf);
@@ -1054,17 +1061,13 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
10541061
return NULL;
10551062

10561063
ret = btree_read_extent_buffer_pages(root, buf, 0, parent_transid);
1057-
1058-
if (ret == 0)
1059-
set_bit(EXTENT_BUFFER_UPTODATE, &buf->bflags);
10601064
return buf;
10611065

10621066
}
10631067

10641068
int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
10651069
struct extent_buffer *buf)
10661070
{
1067-
struct inode *btree_inode = root->fs_info->btree_inode;
10681071
if (btrfs_header_generation(buf) ==
10691072
root->fs_info->running_transaction->transid) {
10701073
btrfs_assert_tree_locked(buf);
@@ -1080,8 +1083,7 @@ int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
10801083

10811084
/* ugh, clear_extent_buffer_dirty needs to lock the page */
10821085
btrfs_set_lock_blocking(buf);
1083-
clear_extent_buffer_dirty(&BTRFS_I(btree_inode)->io_tree,
1084-
buf);
1086+
clear_extent_buffer_dirty(buf);
10851087
}
10861088
return 0;
10871089
}
@@ -1948,6 +1950,7 @@ int open_ctree(struct super_block *sb,
19481950
RB_CLEAR_NODE(&BTRFS_I(fs_info->btree_inode)->rb_node);
19491951
extent_io_tree_init(&BTRFS_I(fs_info->btree_inode)->io_tree,
19501952
fs_info->btree_inode->i_mapping);
1953+
BTRFS_I(fs_info->btree_inode)->io_tree.track_uptodate = 0;
19511954
extent_map_tree_init(&BTRFS_I(fs_info->btree_inode)->extent_tree);
19521955

19531956
BTRFS_I(fs_info->btree_inode)->io_tree.ops = &btree_extent_io_ops;
@@ -3058,8 +3061,7 @@ int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid)
30583061
int ret;
30593062
struct inode *btree_inode = buf->pages[0]->mapping->host;
30603063

3061-
ret = extent_buffer_uptodate(&BTRFS_I(btree_inode)->io_tree, buf,
3062-
NULL);
3064+
ret = extent_buffer_uptodate(buf);
30633065
if (!ret)
30643066
return ret;
30653067

@@ -3070,16 +3072,13 @@ int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid)
30703072

30713073
int btrfs_set_buffer_uptodate(struct extent_buffer *buf)
30723074
{
3073-
struct inode *btree_inode = buf->pages[0]->mapping->host;
3074-
return set_extent_buffer_uptodate(&BTRFS_I(btree_inode)->io_tree,
3075-
buf);
3075+
return set_extent_buffer_uptodate(buf);
30763076
}
30773077

30783078
void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
30793079
{
30803080
struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root;
30813081
u64 transid = btrfs_header_generation(buf);
3082-
struct inode *btree_inode = root->fs_info->btree_inode;
30833082
int was_dirty;
30843083

30853084
btrfs_assert_tree_locked(buf);
@@ -3091,8 +3090,7 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
30913090
(unsigned long long)root->fs_info->generation);
30923091
WARN_ON(1);
30933092
}
3094-
was_dirty = set_extent_buffer_dirty(&BTRFS_I(btree_inode)->io_tree,
3095-
buf);
3093+
was_dirty = set_extent_buffer_dirty(buf);
30963094
if (!was_dirty) {
30973095
spin_lock(&root->fs_info->delalloc_lock);
30983096
root->fs_info->dirty_metadata_bytes += buf->len;
@@ -3147,11 +3145,7 @@ void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
31473145
int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid)
31483146
{
31493147
struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root;
3150-
int ret;
3151-
ret = btree_read_extent_buffer_pages(root, buf, 0, parent_transid);
3152-
if (ret == 0)
3153-
set_bit(EXTENT_BUFFER_UPTODATE, &buf->bflags);
3154-
return ret;
3148+
return btree_read_extent_buffer_pages(root, buf, 0, parent_transid);
31553149
}
31563150

31573151
static int btree_lock_page_hook(struct page *page, void *data,

0 commit comments

Comments
 (0)