linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Liu Bo <bo.li.liu@oracle.com>
To: Naohiro Aota <naota@elisp.net>
Cc: linux-btrfs <linux-btrfs@vger.kernel.org>
Subject: Re: btrfs-progs: initial reference count of extent buffer is correct?
Date: Mon, 25 Aug 2014 14:16:05 +0800	[thread overview]
Message-ID: <20140825061604.GE22848@localhost.localdomain> (raw)
In-Reply-To: <87y4ud2l7q.fsf@elisp.net>

On Mon, Aug 25, 2014 at 02:26:49PM +0900, Naohiro Aota wrote:
> Hi, list
> 
> I'm having trouble with my btrfs FS recently and running btrfs check to
> try to fix the FS. Unfortunately, it aborted with:
> 
> btrfsck: root-tree.c:81: btrfs_update_root: Assertion `!(ret != 0)' failed.
> 
> It means that "extent tree root" is not found in "tree root tree"! Then
> I added btrfs_print_leaf() there to see what is happening there. There
> were "(... METADATA_ITEM 0)" keys listed. Well, I found "tree root
> tree"'s root extent buffer is somewhat replaced by a extent buffer from
> the extent tree.
> 
> Reading the code, it seems that free_some_buffers() reclaim extent
> buffers allocated to root trees because they are not
> extent_buffer_get()ed (i.e. @refs == 1). 
> 
> To reproduce this problem, try running this code. This program first
> print root tree node's bytenr, and scan some trees. If your FS is large
> enough to run free_some_buffers(), tree root node's bytenr after the
> scan would be different.
> 
> #include <stdio.h>
> #include "ctree.h"
> #include "disk-io.h"
> 
> void scan_tree(struct btrfs_root *root, struct extent_buffer *eb)
> {
>   u32 i;
>   u32 nr;
>   nr = btrfs_header_nritems(eb);
>   if (btrfs_is_leaf(eb)) return;
>   u32 size = btrfs_level_size(root, btrfs_header_level(eb) - 1);
>   for (i = 0; i < nr; i++) {
>     if (btrfs_is_leaf(eb)) return;
>     u64 bytenr = btrfs_node_blockptr(eb, i);
>     struct extent_buffer *next = read_tree_block(root, bytenr, size,
> 						 btrfs_node_ptr_generation(eb, i));
>     if (!next) continue;
>     scan_tree(root, next);
>   }
> }
> 
> int main(int ac, char **av)
> {
>   struct btrfs_fs_info *info;
>   struct btrfs_root *root;
>   info = open_ctree_fs_info(av[1], 0, 0, OPEN_CTREE_PARTIAL);
>   root = info->fs_root;
>   printf("tree root %lld\n", info->tree_root->node->start);
>   scan_tree(info->fs_root, info->extent_root->node);
>   scan_tree(info->fs_root, info->csum_root->node);
>   scan_tree(info->fs_root, info->fs_root->node);
>   printf("tree root %lld\n", info->tree_root->node->start);
>   return close_ctree(root);
> }
> 
> On my environment, the above code print the following result. "Tree root
> tree variable" is eventually pointing to another extent!
> 
> $ ./btrfs-reproduce /dev/sda3
> tree root 91393835008
> tree root 49102848
> 
> I found commit 53ee1bccf99cd5b474fe1aa857b7dd176e3a1407 changed the
> initial @refs to 1, stating that "we don't give enough
> free_extent_buffer() to reduce the eb's references to zero so that the
> eb can finally be freed", but I don't think this is correct. Even if
> initial @refs == 2, one free_extent_buffer() would make the @refs to 1
> and so let it reclaimed by free_some_buffer(), so it does not seems to
> be a problem for me...
> 
> I think there are some collides how to use extent buffer: should
> __alloc_extent_buffer set @refs = 2 for the caller or should the code
> call extent_buffer_get() by themselves everywhere you allocate eb before
> any other eb allocation not to let the first eb reclaimed? How to fix
> this problem? revert 53ee1bccf99cd5b474fe1aa857b7dd176e3a1407 is the
> collect way? or add "missing" extent_buffer_get() everywhere allocating
> is done?

You may think of it twice, commit 53ee1bccf99cd5b474fe1aa857b7dd176e3a1407 
is to fix a bug of assigning a free block to two different extent buffers, ie.
two different extent buffers' share the same eb->start, so it's not just bumping
a reference cnt.

Right now we want to be consistent with the kernel side, decreasing eb->refs=0
means it'd be freed, so droping free_some_buffer() can be a good choice.

And for caching extent buffer, we've increased eb->refs by 1 to keep it in the
cache rbtree.

thanks,
-liubo

  reply	other threads:[~2014-08-25  6:16 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-08-25  5:26 btrfs-progs: initial reference count of extent buffer is correct? Naohiro Aota
2014-08-25  6:16 ` Liu Bo [this message]
2014-09-30 14:39   ` naota

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20140825061604.GE22848@localhost.localdomain \
    --to=bo.li.liu@oracle.com \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=naota@elisp.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).