Skip to content

Commit

Permalink
Btrfs: Remove broken optimisations in end_bio functions.
Browse files Browse the repository at this point in the history
These ended up freeing objects while they were still using them. Under
guidance from Chris, just rip out the 'clever' bits and do things the
simple way.

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
  • Loading branch information
David Woodhouse authored and Chris Mason committed Sep 25, 2008
1 parent 5386323 commit 902b22f
Showing 1 changed file with 21 additions and 138 deletions.
159 changes: 21 additions & 138 deletions fs/btrfs/extent_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include "extent_io.h"
#include "extent_map.h"
#include "compat.h"
#include "ctree.h"
#include "btrfs_inode.h"

/* temporary define until extent_map moves out of btrfs */
struct kmem_cache *btrfs_cache_create(const char *name, size_t size,
Expand Down Expand Up @@ -1394,22 +1396,20 @@ static int end_bio_extent_writepage(struct bio *bio,
{
int uptodate = err == 0;
struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
struct extent_state *state = bio->bi_private;
struct extent_io_tree *tree = state->tree;
struct rb_node *node;
struct extent_io_tree *tree;
u64 start;
u64 end;
u64 cur;
int whole_page;
int ret;
unsigned long flags;

#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
if (bio->bi_size)
return 1;
#endif
do {
struct page *page = bvec->bv_page;
tree = &BTRFS_I(page->mapping->host)->io_tree;

start = ((u64)page->index << PAGE_CACHE_SHIFT) +
bvec->bv_offset;
end = start + bvec->bv_len - 1;
Expand All @@ -1423,17 +1423,16 @@ static int end_bio_extent_writepage(struct bio *bio,
prefetchw(&bvec->bv_page->flags);
if (tree->ops && tree->ops->writepage_end_io_hook) {
ret = tree->ops->writepage_end_io_hook(page, start,
end, state, uptodate);
end, NULL, uptodate);
if (ret)
uptodate = 0;
}

if (!uptodate && tree->ops &&
tree->ops->writepage_io_failed_hook) {
ret = tree->ops->writepage_io_failed_hook(bio, page,
start, end, state);
start, end, NULL);
if (ret == 0) {
state = NULL;
uptodate = (err == 0);
continue;
}
Expand All @@ -1445,68 +1444,7 @@ static int end_bio_extent_writepage(struct bio *bio,
SetPageError(page);
}

/*
* bios can get merged in funny ways, and so we need to
* be careful with the state variable. We know the
* state won't be merged with others because it has
* WRITEBACK set, but we can't be sure each biovec is
* sequential in the file. So, if our cached state
* doesn't match the expected end, search the tree
* for the correct one.
*/

spin_lock_irqsave(&tree->lock, flags);
if (!state || state->end != end) {
state = NULL;
node = __etree_search(tree, start, NULL, NULL);
if (node) {
state = rb_entry(node, struct extent_state,
rb_node);
if (state->end != end ||
!(state->state & EXTENT_WRITEBACK))
state = NULL;
}
if (!state) {
spin_unlock_irqrestore(&tree->lock, flags);
clear_extent_writeback(tree, start,
end, GFP_ATOMIC);
goto next_io;
}
}
cur = end;
while(1) {
struct extent_state *clear = state;
cur = state->start;
node = rb_prev(&state->rb_node);
if (node) {
state = rb_entry(node,
struct extent_state,
rb_node);
} else {
state = NULL;
}

clear_state_bit(tree, clear, EXTENT_WRITEBACK,
1, 0);
if (cur == start)
break;
if (cur < start) {
WARN_ON(1);
break;
}
if (!node)
break;
}
/* before releasing the lock, make sure the next state
* variable has the expected bits set and corresponds
* to the correct offsets in the file
*/
if (state && (state->end + 1 != start ||
!(state->state & EXTENT_WRITEBACK))) {
state = NULL;
}
spin_unlock_irqrestore(&tree->lock, flags);
next_io:
clear_extent_writeback(tree, start, end, GFP_ATOMIC);

if (whole_page)
end_page_writeback(page);
Expand Down Expand Up @@ -1539,13 +1477,9 @@ static int end_bio_extent_readpage(struct bio *bio,
{
int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
struct extent_state *state = bio->bi_private;
struct extent_io_tree *tree = state->tree;
struct rb_node *node;
struct extent_io_tree *tree;
u64 start;
u64 end;
u64 cur;
unsigned long flags;
int whole_page;
int ret;

Expand All @@ -1556,6 +1490,8 @@ static int end_bio_extent_readpage(struct bio *bio,

do {
struct page *page = bvec->bv_page;
tree = &BTRFS_I(page->mapping->host)->io_tree;

start = ((u64)page->index << PAGE_CACHE_SHIFT) +
bvec->bv_offset;
end = start + bvec->bv_len - 1;
Expand All @@ -1570,80 +1506,26 @@ static int end_bio_extent_readpage(struct bio *bio,

if (uptodate && tree->ops && tree->ops->readpage_end_io_hook) {
ret = tree->ops->readpage_end_io_hook(page, start, end,
state);
NULL);
if (ret)
uptodate = 0;
}
if (!uptodate && tree->ops &&
tree->ops->readpage_io_failed_hook) {
ret = tree->ops->readpage_io_failed_hook(bio, page,
start, end, state);
start, end, NULL);
if (ret == 0) {
state = NULL;
uptodate =
test_bit(BIO_UPTODATE, &bio->bi_flags);
continue;
}
}

spin_lock_irqsave(&tree->lock, flags);
if (!state || state->end != end) {
state = NULL;
node = __etree_search(tree, start, NULL, NULL);
if (node) {
state = rb_entry(node, struct extent_state,
rb_node);
if (state->end != end ||
!(state->state & EXTENT_LOCKED))
state = NULL;
}
if (!state) {
spin_unlock_irqrestore(&tree->lock, flags);
if (uptodate)
set_extent_uptodate(tree, start, end,
GFP_ATOMIC);
unlock_extent(tree, start, end, GFP_ATOMIC);
goto next_io;
}
}
if (uptodate)
set_extent_uptodate(tree, start, end,
GFP_ATOMIC);
unlock_extent(tree, start, end, GFP_ATOMIC);

cur = end;
while(1) {
struct extent_state *clear = state;
cur = state->start;
node = rb_prev(&state->rb_node);
if (node) {
state = rb_entry(node,
struct extent_state,
rb_node);
} else {
state = NULL;
}
if (uptodate) {
set_state_cb(tree, clear, EXTENT_UPTODATE);
clear->state |= EXTENT_UPTODATE;
}
clear_state_bit(tree, clear, EXTENT_LOCKED,
1, 0);
if (cur == start)
break;
if (cur < start) {
WARN_ON(1);
break;
}
if (!node)
break;
}
/* before releasing the lock, make sure the next state
* variable has the expected bits set and corresponds
* to the correct offsets in the file
*/
if (state && (state->end + 1 != start ||
!(state->state & EXTENT_LOCKED))) {
state = NULL;
}
spin_unlock_irqrestore(&tree->lock, flags);
next_io:
if (whole_page) {
if (uptodate) {
SetPageUptodate(page);
Expand Down Expand Up @@ -1683,8 +1565,7 @@ static int end_bio_extent_preparewrite(struct bio *bio,
{
const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
struct extent_state *state = bio->bi_private;
struct extent_io_tree *tree = state->tree;
struct extent_io_tree *tree;
u64 start;
u64 end;

Expand All @@ -1695,6 +1576,8 @@ static int end_bio_extent_preparewrite(struct bio *bio,

do {
struct page *page = bvec->bv_page;
tree = &BTRFS_I(page->mapping->host)->io_tree;

start = ((u64)page->index << PAGE_CACHE_SHIFT) +
bvec->bv_offset;
end = start + bvec->bv_len - 1;
Expand Down Expand Up @@ -1765,7 +1648,7 @@ static int submit_one_bio(int rw, struct bio *bio, int mirror_num)
BUG_ON(state->end != end);
spin_unlock_irq(&tree->lock);

bio->bi_private = state;
bio->bi_private = NULL;

bio_get(bio);

Expand Down

0 comments on commit 902b22f

Please sign in to comment.