Message ID | 1474664704-2612-1-git-send-email-bo.li.liu@oracle.com (mailing list archive) |
---|---|
State | Accepted |
Headers | show |
On Fri, Sep 23, 2016 at 02:05:04PM -0700, Liu Bo wrote: > While updating btree, we try to push items between sibling > nodes/leaves in order to keep height as low as possible. > But we don't memset the original places with zero when > pushing items so that we could end up leaving stale content > in nodes/leaves. One may read the above stale content by > increasing btree blocks' @nritems. > > One case I've come across is that in fs tree, a leaf has two > parent nodes, hence running balance ends up with processing > this leaf with two parent nodes, but it can only reach the > valid parent node through btrfs_search_slot, so it'd be like, > > do_relocation > for P in all parent nodes of block A: > if !P->eb: > btrfs_search_slot(key); --> get path from P to A. > if lowest: > BUG_ON(A->bytenr != bytenr of A recorded in P); > btrfs_cow_block(P, A); --> change A's bytenr in P. > > After btrfs_cow_block, P has the new bytenr of A, but with the > same @key, we get the same path again, and get panic by BUG_ON. > > Note that this is only happening in a corrupted fs, for a > regular fs in which we have correct @nritems so that we won't > read stale content in any case. > > Reviewed-by: Josef Bacik <jbacik@fb.com> > Signed-off-by: Liu Bo <bo.li.liu@oracle.com> > --- > v2: - use new internal error EFSCORRUPTED as "Filesystem is corrupted", > suggested by David Sterba. Sorry I steered it to EFSCORRUPTED, we should introduce the error code separately and audit the call chains. I'll drop the parts and change it back to EIO. -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 67d71c0..8b23410 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -127,6 +127,8 @@ static inline unsigned long btrfs_chunk_item_size(int num_stripes) #define BTRFS_OLD_BACKREF_REV 0 #define BTRFS_MIXED_BACKREF_REV 1 +#define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */ + /* * every tree block (leaf or node) starts with this header. */ diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index c0c13dc..6f8b952 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -2712,7 +2712,14 @@ static int do_relocation(struct btrfs_trans_handle *trans, bytenr = btrfs_node_blockptr(upper->eb, slot); if (lowest) { - BUG_ON(bytenr != node->bytenr); + if (bytenr != node->bytenr) { + btrfs_err(root->fs_info, + "lowest leaf/node mismatch: bytenr %llu node->bytenr %llu slot %d upper %llu", + bytenr, node->bytenr, slot, + upper->eb->start); + err = -EFSCORRUPTED; + goto next; + } } else { if (node->eb->start == bytenr) goto next;