* [PATCH] Btrfs: set page->private to the eb
@ 2012-03-08 18:37 Josef Bacik
2012-03-09 1:27 ` Liu Bo
0 siblings, 1 reply; 3+ messages in thread
From: Josef Bacik @ 2012-03-08 18:37 UTC (permalink / raw)
To: linux-btrfs
We spend a lot of time looking up extent buffers from pages when we could just
store the pointer to the eb the page is associated with in page->private. This
patch does just that, and it makes things a little simpler and reduces a bit of
CPU overhead involved with doing metadata IO. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
fs/btrfs/disk-io.c | 92 ++++++++++++-------------------------------------
fs/btrfs/extent_io.c | 92 ++++++++++++++++++++++++++++++++++++-------------
fs/btrfs/extent_io.h | 1 +
3 files changed, 91 insertions(+), 94 deletions(-)
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 33114bc..6f97129 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -403,39 +403,28 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
struct extent_io_tree *tree;
u64 start = (u64)page->index << PAGE_CACHE_SHIFT;
u64 found_start;
- unsigned long len;
struct extent_buffer *eb;
tree = &BTRFS_I(page->mapping->host)->io_tree;
- if (page->private == EXTENT_PAGE_PRIVATE)
- goto out;
- if (!page->private) {
- WARN_ON(1);
- goto out;
- }
- len = page->private >> 2;
- WARN_ON(len == 0);
-
- eb = find_extent_buffer(tree, start, len);
+ eb = (struct extent_buffer *)page->private;
+ if (page != eb->pages[0])
+ return 0;
found_start = btrfs_header_bytenr(eb);
if (found_start != start) {
WARN_ON(1);
- goto err;
+ return 0;
}
if (eb->pages[0] != page) {
WARN_ON(1);
- goto err;
+ return 0;
}
if (!PageUptodate(page)) {
WARN_ON(1);
- goto err;
+ return 0;
}
csum_tree_block(root, eb, 0);
-err:
- free_extent_buffer(eb);
-out:
return 0;
}
@@ -566,7 +555,6 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
struct extent_io_tree *tree;
u64 found_start;
int found_level;
- unsigned long len;
struct extent_buffer *eb;
struct btrfs_root *root = BTRFS_I(page->mapping->host)->root;
int ret = 0;
@@ -576,13 +564,8 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
goto out;
tree = &BTRFS_I(page->mapping->host)->io_tree;
- len = page->private >> 2;
+ eb = (struct extent_buffer *)page->private;
- eb = find_eb_for_page(tree, page, max(root->leafsize, root->nodesize));
- if (!eb) {
- ret = -EIO;
- goto out;
- }
reads_done = atomic_dec_and_test(&eb->pages_reading);
if (!reads_done)
goto err;
@@ -631,7 +614,6 @@ err:
if (ret && eb)
clear_extent_buffer_uptodate(tree, eb, NULL);
- free_extent_buffer(eb);
out:
return ret;
}
@@ -640,31 +622,17 @@ static int btree_io_failed_hook(struct bio *failed_bio,
struct page *page, u64 start, u64 end,
int mirror_num, struct extent_state *state)
{
- struct extent_io_tree *tree;
- unsigned long len;
struct extent_buffer *eb;
struct btrfs_root *root = BTRFS_I(page->mapping->host)->root;
- tree = &BTRFS_I(page->mapping->host)->io_tree;
- if (page->private == EXTENT_PAGE_PRIVATE)
- goto out;
- if (!page->private)
- goto out;
-
- len = page->private >> 2;
- WARN_ON(len == 0);
-
- eb = alloc_extent_buffer(tree, start, len);
- if (eb == NULL)
- goto out;
+ eb = (struct extent_buffer *)page->private;
+ if (page != eb->pages[0])
+ return -EIO;
if (test_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags)) {
clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags);
btree_readahead_hook(root, eb, eb->start, -EIO);
}
- free_extent_buffer(eb);
-
-out:
return -EIO; /* we fixed nothing */
}
@@ -955,10 +923,8 @@ static int btree_readpage(struct file *file, struct page *page)
static int btree_releasepage(struct page *page, gfp_t gfp_flags)
{
- struct extent_io_tree *tree;
struct extent_map_tree *map;
- struct extent_buffer *eb;
- struct btrfs_root *root;
+ struct extent_io_tree *tree;
int ret;
if (PageWriteback(page) || PageDirty(page))
@@ -967,26 +933,11 @@ static int btree_releasepage(struct page *page, gfp_t gfp_flags)
tree = &BTRFS_I(page->mapping->host)->io_tree;
map = &BTRFS_I(page->mapping->host)->extent_tree;
- root = BTRFS_I(page->mapping->host)->root;
- if (page->private == EXTENT_PAGE_PRIVATE) {
- eb = find_eb_for_page(tree, page, max(root->leafsize, root->nodesize));
- free_extent_buffer(eb);
- if (eb)
- return 0;
- }
-
ret = try_release_extent_state(map, tree, page, gfp_flags);
if (!ret)
return 0;
- ret = try_release_extent_buffer(tree, page);
- if (ret == 1) {
- ClearPagePrivate(page);
- set_page_private(page, 0);
- page_cache_release(page);
- }
-
- return ret;
+ return try_release_extent_buffer(tree, page);
}
static void btree_invalidatepage(struct page *page, unsigned long offset)
@@ -3173,17 +3124,21 @@ static int btree_lock_page_hook(struct page *page, void *data,
{
struct inode *inode = page->mapping->host;
struct btrfs_root *root = BTRFS_I(inode)->root;
- struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
struct extent_buffer *eb;
- unsigned long len;
- u64 bytenr = page_offset(page);
- if (page->private == EXTENT_PAGE_PRIVATE)
+ /*
+ * We culled this eb but the page is still hanging out on the mapping,
+ * carry on.
+ */
+ if (!PagePrivate(page))
goto out;
- len = page->private >> 2;
- eb = find_extent_buffer(io_tree, bytenr, len);
- if (!eb)
+ eb = (struct extent_buffer *)page->private;
+ if (!eb) {
+ WARN_ON(1);
+ goto out;
+ }
+ if (page != eb->pages[0])
goto out;
if (!btrfs_try_tree_write_lock(eb)) {
@@ -3202,7 +3157,6 @@ static int btree_lock_page_hook(struct page *page, void *data,
}
btrfs_tree_unlock(eb);
- free_extent_buffer(eb);
out:
if (!trylock_page(page)) {
flush_fn(data);
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index d4795fc..197595a 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -2462,19 +2462,24 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree,
return ret;
}
-void set_page_extent_mapped(struct page *page)
+void attach_extent_buffer_page(struct extent_buffer *eb, struct page *page)
{
if (!PagePrivate(page)) {
SetPagePrivate(page);
page_cache_get(page);
- set_page_private(page, EXTENT_PAGE_PRIVATE);
+ set_page_private(page, (unsigned long)eb);
+ } else {
+ WARN_ON(page->private != (unsigned long)eb);
}
}
-static void set_page_extent_head(struct page *page, unsigned long len)
+void set_page_extent_mapped(struct page *page)
{
- WARN_ON(!PagePrivate(page));
- set_page_private(page, EXTENT_PAGE_PRIVATE_FIRST_PAGE | len << 2);
+ if (!PagePrivate(page)) {
+ SetPagePrivate(page);
+ page_cache_get(page);
+ set_page_private(page, EXTENT_PAGE_PRIVATE);
+ }
}
/*
@@ -3567,6 +3572,7 @@ static struct extent_buffer *__alloc_extent_buffer(struct extent_io_tree *tree,
return NULL;
eb->start = start;
eb->len = len;
+ eb->tree = tree;
rwlock_init(&eb->lock);
atomic_set(&eb->write_locks, 0);
atomic_set(&eb->read_locks, 0);
@@ -3619,8 +3625,31 @@ static void btrfs_release_extent_buffer_page(struct extent_buffer *eb,
do {
index--;
page = extent_buffer_page(eb, index);
- if (page)
+ if (page) {
+ spin_lock(&page->mapping->private_lock);
+ /*
+ * We do this since we'll remove the pages after we've
+ * removed the eb from the radix tree, so we could race
+ * and have this page now attached to the new eb. So
+ * only clear page_private if it's still connected to
+ * this eb.
+ */
+ if (PagePrivate(page) &&
+ page->private == (unsigned long)eb) {
+ /*
+ * We need to make sure we haven't be attached
+ * to a new eb.
+ */
+ ClearPagePrivate(page);
+ set_page_private(page, 0);
+ /* One for the page private */
+ page_cache_release(page);
+ }
+ spin_unlock(&page->mapping->private_lock);
+
+ /* One for when we alloced the page */
page_cache_release(page);
+ }
} while (index != start_idx);
}
@@ -3665,6 +3694,32 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
WARN_ON(1);
goto free_eb;
}
+
+ spin_lock(&mapping->private_lock);
+ if (PagePrivate(p)) {
+ /*
+ * We could have already allocated an eb for this page
+ * and attached one so lets see if we can get a ref on
+ * the existing eb, and if we can we know it's good and
+ * we can just return that one, else we know we can just
+ * overwrite page->private.
+ */
+ exists = (struct extent_buffer *)p->private;
+ if (atomic_inc_not_zero(&exists->refs)) {
+ spin_unlock(&mapping->private_lock);
+ unlock_page(p);
+ goto free_eb;
+ }
+
+ /*
+ * Do this so attach doesn't complain and we need to
+ * drop the ref the old guy had.
+ */
+ ClearPagePrivate(p);
+ page_cache_release(p);
+ }
+ attach_extent_buffer_page(eb, p);
+ spin_unlock(&mapping->private_lock);
mark_page_accessed(p);
eb->pages[i] = p;
if (!PageUptodate(p))
@@ -3687,7 +3742,6 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
if (ret == -EEXIST) {
exists = radix_tree_lookup(&tree->buffer,
start >> PAGE_CACHE_SHIFT);
- /* add one reference for the caller */
atomic_inc(&exists->refs);
spin_unlock(&tree->buffer_lock);
radix_tree_preload_end();
@@ -3707,12 +3761,9 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
* after the extent buffer is in the radix tree so
* it doesn't get lost
*/
- set_page_extent_mapped(eb->pages[0]);
- set_page_extent_head(eb->pages[0], eb->len);
SetPageChecked(eb->pages[0]);
for (i = 1; i < num_pages; i++) {
p = extent_buffer_page(eb, i);
- set_page_extent_mapped(p);
ClearPageChecked(p);
unlock_page(p);
}
@@ -3776,10 +3827,6 @@ int clear_extent_buffer_dirty(struct extent_io_tree *tree,
lock_page(page);
WARN_ON(!PagePrivate(page));
- set_page_extent_mapped(page);
- if (i == 0)
- set_page_extent_head(page, eb->len);
-
clear_page_dirty_for_io(page);
spin_lock_irq(&page->mapping->tree_lock);
if (!PageDirty(page)) {
@@ -3991,9 +4038,6 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
atomic_set(&eb->pages_reading, num_reads);
for (i = start_i; i < num_pages; i++) {
page = extent_buffer_page(eb, i);
- set_page_extent_mapped(page);
- if (i == 0)
- set_page_extent_head(page, eb->len);
if (!PageUptodate(page)) {
ClearPageError(page);
err = __extent_read_full_page(tree, page,
@@ -4376,22 +4420,19 @@ static inline void btrfs_release_extent_buffer_rcu(struct rcu_head *head)
struct extent_buffer *eb =
container_of(head, struct extent_buffer, rcu_head);
- btrfs_release_extent_buffer(eb);
+ __free_extent_buffer(eb);
}
int try_release_extent_buffer(struct extent_io_tree *tree, struct page *page)
{
u64 start = page_offset(page);
- struct extent_buffer *eb;
+ struct extent_buffer *eb = (struct extent_buffer *)page->private;
int ret = 1;
- spin_lock(&tree->buffer_lock);
- eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT);
- if (!eb) {
- spin_unlock(&tree->buffer_lock);
- return ret;
- }
+ if (!PagePrivate(page) || !eb)
+ return 1;
+ spin_lock(&tree->buffer_lock);
if (atomic_read(&eb->refs) > 1 ||
test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) {
ret = 0;
@@ -4407,6 +4448,7 @@ int try_release_extent_buffer(struct extent_io_tree *tree, struct page *page)
goto out;
}
radix_tree_delete(&tree->buffer, start >> PAGE_CACHE_SHIFT);
+ btrfs_release_extent_buffer_page(eb, 0);
out:
spin_unlock(&tree->buffer_lock);
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
index 9b6c8f3..f030a2d 100644
--- a/fs/btrfs/extent_io.h
+++ b/fs/btrfs/extent_io.h
@@ -127,6 +127,7 @@ struct extent_buffer {
unsigned long map_start;
unsigned long map_len;
unsigned long bflags;
+ struct extent_io_tree *tree;
atomic_t refs;
atomic_t pages_reading;
struct list_head leak_list;
--
1.7.7.5
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] Btrfs: set page->private to the eb
2012-03-08 18:37 [PATCH] Btrfs: set page->private to the eb Josef Bacik
@ 2012-03-09 1:27 ` Liu Bo
2012-03-09 13:43 ` David Sterba
0 siblings, 1 reply; 3+ messages in thread
From: Liu Bo @ 2012-03-09 1:27 UTC (permalink / raw)
To: Josef Bacik; +Cc: linux-btrfs
On 03/09/2012 02:37 AM, Josef Bacik wrote:
> We spend a lot of time looking up extent buffers from pages when we could just
> store the pointer to the eb the page is associated with in page->private. This
> patch does just that, and it makes things a little simpler and reduces a bit of
> CPU overhead involved with doing metadata IO. Thanks,
>
Hi Josef,
This is not against the normal branch, so we must inform people that. :)
Have a quick look, and I guess it is for "Btrfs: allow metadata blocks larger than the page size", isn't it?
thanks,
liubo
> Signed-off-by: Josef Bacik <josef@redhat.com>
> ---
> fs/btrfs/disk-io.c | 92 ++++++++++++-------------------------------------
> fs/btrfs/extent_io.c | 92 ++++++++++++++++++++++++++++++++++++-------------
> fs/btrfs/extent_io.h | 1 +
> 3 files changed, 91 insertions(+), 94 deletions(-)
>
> diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
> index 33114bc..6f97129 100644
> --- a/fs/btrfs/disk-io.c
> +++ b/fs/btrfs/disk-io.c
> @@ -403,39 +403,28 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
> struct extent_io_tree *tree;
> u64 start = (u64)page->index << PAGE_CACHE_SHIFT;
> u64 found_start;
> - unsigned long len;
> struct extent_buffer *eb;
>
> tree = &BTRFS_I(page->mapping->host)->io_tree;
>
> - if (page->private == EXTENT_PAGE_PRIVATE)
> - goto out;
> - if (!page->private) {
> - WARN_ON(1);
> - goto out;
> - }
> - len = page->private >> 2;
> - WARN_ON(len == 0);
> -
> - eb = find_extent_buffer(tree, start, len);
> + eb = (struct extent_buffer *)page->private;
> + if (page != eb->pages[0])
> + return 0;
>
> found_start = btrfs_header_bytenr(eb);
> if (found_start != start) {
> WARN_ON(1);
> - goto err;
> + return 0;
> }
> if (eb->pages[0] != page) {
> WARN_ON(1);
> - goto err;
> + return 0;
> }
> if (!PageUptodate(page)) {
> WARN_ON(1);
> - goto err;
> + return 0;
> }
> csum_tree_block(root, eb, 0);
> -err:
> - free_extent_buffer(eb);
> -out:
> return 0;
> }
>
> @@ -566,7 +555,6 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
> struct extent_io_tree *tree;
> u64 found_start;
> int found_level;
> - unsigned long len;
> struct extent_buffer *eb;
> struct btrfs_root *root = BTRFS_I(page->mapping->host)->root;
> int ret = 0;
> @@ -576,13 +564,8 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
> goto out;
>
> tree = &BTRFS_I(page->mapping->host)->io_tree;
> - len = page->private >> 2;
> + eb = (struct extent_buffer *)page->private;
>
> - eb = find_eb_for_page(tree, page, max(root->leafsize, root->nodesize));
> - if (!eb) {
> - ret = -EIO;
> - goto out;
> - }
> reads_done = atomic_dec_and_test(&eb->pages_reading);
> if (!reads_done)
> goto err;
> @@ -631,7 +614,6 @@ err:
>
> if (ret && eb)
> clear_extent_buffer_uptodate(tree, eb, NULL);
> - free_extent_buffer(eb);
> out:
> return ret;
> }
> @@ -640,31 +622,17 @@ static int btree_io_failed_hook(struct bio *failed_bio,
> struct page *page, u64 start, u64 end,
> int mirror_num, struct extent_state *state)
> {
> - struct extent_io_tree *tree;
> - unsigned long len;
> struct extent_buffer *eb;
> struct btrfs_root *root = BTRFS_I(page->mapping->host)->root;
>
> - tree = &BTRFS_I(page->mapping->host)->io_tree;
> - if (page->private == EXTENT_PAGE_PRIVATE)
> - goto out;
> - if (!page->private)
> - goto out;
> -
> - len = page->private >> 2;
> - WARN_ON(len == 0);
> -
> - eb = alloc_extent_buffer(tree, start, len);
> - if (eb == NULL)
> - goto out;
> + eb = (struct extent_buffer *)page->private;
> + if (page != eb->pages[0])
> + return -EIO;
>
> if (test_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags)) {
> clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags);
> btree_readahead_hook(root, eb, eb->start, -EIO);
> }
> - free_extent_buffer(eb);
> -
> -out:
> return -EIO; /* we fixed nothing */
> }
>
> @@ -955,10 +923,8 @@ static int btree_readpage(struct file *file, struct page *page)
>
> static int btree_releasepage(struct page *page, gfp_t gfp_flags)
> {
> - struct extent_io_tree *tree;
> struct extent_map_tree *map;
> - struct extent_buffer *eb;
> - struct btrfs_root *root;
> + struct extent_io_tree *tree;
> int ret;
>
> if (PageWriteback(page) || PageDirty(page))
> @@ -967,26 +933,11 @@ static int btree_releasepage(struct page *page, gfp_t gfp_flags)
> tree = &BTRFS_I(page->mapping->host)->io_tree;
> map = &BTRFS_I(page->mapping->host)->extent_tree;
>
> - root = BTRFS_I(page->mapping->host)->root;
> - if (page->private == EXTENT_PAGE_PRIVATE) {
> - eb = find_eb_for_page(tree, page, max(root->leafsize, root->nodesize));
> - free_extent_buffer(eb);
> - if (eb)
> - return 0;
> - }
> -
> ret = try_release_extent_state(map, tree, page, gfp_flags);
> if (!ret)
> return 0;
>
> - ret = try_release_extent_buffer(tree, page);
> - if (ret == 1) {
> - ClearPagePrivate(page);
> - set_page_private(page, 0);
> - page_cache_release(page);
> - }
> -
> - return ret;
> + return try_release_extent_buffer(tree, page);
> }
>
> static void btree_invalidatepage(struct page *page, unsigned long offset)
> @@ -3173,17 +3124,21 @@ static int btree_lock_page_hook(struct page *page, void *data,
> {
> struct inode *inode = page->mapping->host;
> struct btrfs_root *root = BTRFS_I(inode)->root;
> - struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
> struct extent_buffer *eb;
> - unsigned long len;
> - u64 bytenr = page_offset(page);
>
> - if (page->private == EXTENT_PAGE_PRIVATE)
> + /*
> + * We culled this eb but the page is still hanging out on the mapping,
> + * carry on.
> + */
> + if (!PagePrivate(page))
> goto out;
>
> - len = page->private >> 2;
> - eb = find_extent_buffer(io_tree, bytenr, len);
> - if (!eb)
> + eb = (struct extent_buffer *)page->private;
> + if (!eb) {
> + WARN_ON(1);
> + goto out;
> + }
> + if (page != eb->pages[0])
> goto out;
>
> if (!btrfs_try_tree_write_lock(eb)) {
> @@ -3202,7 +3157,6 @@ static int btree_lock_page_hook(struct page *page, void *data,
> }
>
> btrfs_tree_unlock(eb);
> - free_extent_buffer(eb);
> out:
> if (!trylock_page(page)) {
> flush_fn(data);
> diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
> index d4795fc..197595a 100644
> --- a/fs/btrfs/extent_io.c
> +++ b/fs/btrfs/extent_io.c
> @@ -2462,19 +2462,24 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree,
> return ret;
> }
>
> -void set_page_extent_mapped(struct page *page)
> +void attach_extent_buffer_page(struct extent_buffer *eb, struct page *page)
> {
> if (!PagePrivate(page)) {
> SetPagePrivate(page);
> page_cache_get(page);
> - set_page_private(page, EXTENT_PAGE_PRIVATE);
> + set_page_private(page, (unsigned long)eb);
> + } else {
> + WARN_ON(page->private != (unsigned long)eb);
> }
> }
>
> -static void set_page_extent_head(struct page *page, unsigned long len)
> +void set_page_extent_mapped(struct page *page)
> {
> - WARN_ON(!PagePrivate(page));
> - set_page_private(page, EXTENT_PAGE_PRIVATE_FIRST_PAGE | len << 2);
> + if (!PagePrivate(page)) {
> + SetPagePrivate(page);
> + page_cache_get(page);
> + set_page_private(page, EXTENT_PAGE_PRIVATE);
> + }
> }
>
> /*
> @@ -3567,6 +3572,7 @@ static struct extent_buffer *__alloc_extent_buffer(struct extent_io_tree *tree,
> return NULL;
> eb->start = start;
> eb->len = len;
> + eb->tree = tree;
> rwlock_init(&eb->lock);
> atomic_set(&eb->write_locks, 0);
> atomic_set(&eb->read_locks, 0);
> @@ -3619,8 +3625,31 @@ static void btrfs_release_extent_buffer_page(struct extent_buffer *eb,
> do {
> index--;
> page = extent_buffer_page(eb, index);
> - if (page)
> + if (page) {
> + spin_lock(&page->mapping->private_lock);
> + /*
> + * We do this since we'll remove the pages after we've
> + * removed the eb from the radix tree, so we could race
> + * and have this page now attached to the new eb. So
> + * only clear page_private if it's still connected to
> + * this eb.
> + */
> + if (PagePrivate(page) &&
> + page->private == (unsigned long)eb) {
> + /*
> + * We need to make sure we haven't be attached
> + * to a new eb.
> + */
> + ClearPagePrivate(page);
> + set_page_private(page, 0);
> + /* One for the page private */
> + page_cache_release(page);
> + }
> + spin_unlock(&page->mapping->private_lock);
> +
> + /* One for when we alloced the page */
> page_cache_release(page);
> + }
> } while (index != start_idx);
> }
>
> @@ -3665,6 +3694,32 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
> WARN_ON(1);
> goto free_eb;
> }
> +
> + spin_lock(&mapping->private_lock);
> + if (PagePrivate(p)) {
> + /*
> + * We could have already allocated an eb for this page
> + * and attached one so lets see if we can get a ref on
> + * the existing eb, and if we can we know it's good and
> + * we can just return that one, else we know we can just
> + * overwrite page->private.
> + */
> + exists = (struct extent_buffer *)p->private;
> + if (atomic_inc_not_zero(&exists->refs)) {
> + spin_unlock(&mapping->private_lock);
> + unlock_page(p);
> + goto free_eb;
> + }
> +
> + /*
> + * Do this so attach doesn't complain and we need to
> + * drop the ref the old guy had.
> + */
> + ClearPagePrivate(p);
> + page_cache_release(p);
> + }
> + attach_extent_buffer_page(eb, p);
> + spin_unlock(&mapping->private_lock);
> mark_page_accessed(p);
> eb->pages[i] = p;
> if (!PageUptodate(p))
> @@ -3687,7 +3742,6 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
> if (ret == -EEXIST) {
> exists = radix_tree_lookup(&tree->buffer,
> start >> PAGE_CACHE_SHIFT);
> - /* add one reference for the caller */
> atomic_inc(&exists->refs);
> spin_unlock(&tree->buffer_lock);
> radix_tree_preload_end();
> @@ -3707,12 +3761,9 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
> * after the extent buffer is in the radix tree so
> * it doesn't get lost
> */
> - set_page_extent_mapped(eb->pages[0]);
> - set_page_extent_head(eb->pages[0], eb->len);
> SetPageChecked(eb->pages[0]);
> for (i = 1; i < num_pages; i++) {
> p = extent_buffer_page(eb, i);
> - set_page_extent_mapped(p);
> ClearPageChecked(p);
> unlock_page(p);
> }
> @@ -3776,10 +3827,6 @@ int clear_extent_buffer_dirty(struct extent_io_tree *tree,
> lock_page(page);
> WARN_ON(!PagePrivate(page));
>
> - set_page_extent_mapped(page);
> - if (i == 0)
> - set_page_extent_head(page, eb->len);
> -
> clear_page_dirty_for_io(page);
> spin_lock_irq(&page->mapping->tree_lock);
> if (!PageDirty(page)) {
> @@ -3991,9 +4038,6 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
> atomic_set(&eb->pages_reading, num_reads);
> for (i = start_i; i < num_pages; i++) {
> page = extent_buffer_page(eb, i);
> - set_page_extent_mapped(page);
> - if (i == 0)
> - set_page_extent_head(page, eb->len);
> if (!PageUptodate(page)) {
> ClearPageError(page);
> err = __extent_read_full_page(tree, page,
> @@ -4376,22 +4420,19 @@ static inline void btrfs_release_extent_buffer_rcu(struct rcu_head *head)
> struct extent_buffer *eb =
> container_of(head, struct extent_buffer, rcu_head);
>
> - btrfs_release_extent_buffer(eb);
> + __free_extent_buffer(eb);
> }
>
> int try_release_extent_buffer(struct extent_io_tree *tree, struct page *page)
> {
> u64 start = page_offset(page);
> - struct extent_buffer *eb;
> + struct extent_buffer *eb = (struct extent_buffer *)page->private;
> int ret = 1;
>
> - spin_lock(&tree->buffer_lock);
> - eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT);
> - if (!eb) {
> - spin_unlock(&tree->buffer_lock);
> - return ret;
> - }
> + if (!PagePrivate(page) || !eb)
> + return 1;
>
> + spin_lock(&tree->buffer_lock);
> if (atomic_read(&eb->refs) > 1 ||
> test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) {
> ret = 0;
> @@ -4407,6 +4448,7 @@ int try_release_extent_buffer(struct extent_io_tree *tree, struct page *page)
> goto out;
> }
> radix_tree_delete(&tree->buffer, start >> PAGE_CACHE_SHIFT);
> + btrfs_release_extent_buffer_page(eb, 0);
> out:
> spin_unlock(&tree->buffer_lock);
>
> diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
> index 9b6c8f3..f030a2d 100644
> --- a/fs/btrfs/extent_io.h
> +++ b/fs/btrfs/extent_io.h
> @@ -127,6 +127,7 @@ struct extent_buffer {
> unsigned long map_start;
> unsigned long map_len;
> unsigned long bflags;
> + struct extent_io_tree *tree;
> atomic_t refs;
> atomic_t pages_reading;
> struct list_head leak_list;
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] Btrfs: set page->private to the eb
2012-03-09 1:27 ` Liu Bo
@ 2012-03-09 13:43 ` David Sterba
0 siblings, 0 replies; 3+ messages in thread
From: David Sterba @ 2012-03-09 13:43 UTC (permalink / raw)
To: Liu Bo; +Cc: Josef Bacik, linux-btrfs
On Fri, Mar 09, 2012 at 09:27:08AM +0800, Liu Bo wrote:
> This is not against the normal branch, so we must inform people that. :)
>
> Have a quick look, and I guess it is for "Btrfs: allow metadata blocks
> larger than the page size", isn't it?
yes it is.
david
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2012-03-09 13:43 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-03-08 18:37 [PATCH] Btrfs: set page->private to the eb Josef Bacik
2012-03-09 1:27 ` Liu Bo
2012-03-09 13:43 ` David Sterba
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.