From 48ec47364b6d493f0a9cdc116977bf3f34e5c3ec Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Wed, 30 Oct 2013 13:25:24 +0800 Subject: [PATCH] Btrfs: fix a crash when running balance and defrag concurrently Running balance and defrag concurrently can end up with a crash: kernel BUG at fs/btrfs/relocation.c:4528! RIP: 0010:[] [] btrfs_reloc_cow_block+ 0x1eb/0x230 [btrfs] Call Trace: [] ? update_ref_for_cow+0x241/0x380 [btrfs] [] ? copy_extent_buffer+0xad/0x110 [btrfs] [] __btrfs_cow_block+0x3a1/0x520 [btrfs] [] btrfs_cow_block+0x116/0x1b0 [btrfs] [] btrfs_search_slot+0x43d/0x970 [btrfs] [] btrfs_lookup_file_extent+0x37/0x40 [btrfs] [] __btrfs_drop_extents+0x11e/0xae0 [btrfs] [] ? generic_bin_search.constprop.39+0x8d/0x1a0 [btrfs] [] ? kmem_cache_alloc+0x1da/0x200 [] ? btrfs_alloc_path+0x1a/0x20 [btrfs] [] btrfs_drop_extents+0x60/0x90 [btrfs] [] relink_extent_backref+0x2ed/0x780 [btrfs] [] ? btrfs_submit_bio_hook+0x1e0/0x1e0 [btrfs] [] ? iterate_inodes_from_logical+0x87/0xa0 [btrfs] [] btrfs_finish_ordered_io+0x229/0xac0 [btrfs] [] finish_ordered_fn+0x15/0x20 [btrfs] [] worker_loop+0x125/0x4e0 [btrfs] [] ? btrfs_queue_worker+0x300/0x300 [btrfs] [] kthread+0xc0/0xd0 [] ? insert_kthread_work+0x40/0x40 [] ret_from_fork+0x7c/0xb0 [] ? insert_kthread_work+0x40/0x40 ---------------------------------------------------------------------- It turns out to be that balance operation will bump root's @last_snapshot, which enables snapshot-aware defrag path, and backref walking stuff will find data reloc tree as refs' parent, and hit the BUG_ON() during COW. As data reloc tree's data is just for relocation purpose, and will be deleted right after relocation is done, it's unnecessary to walk those refs belonged to data reloc tree, it'd be better to skip them. Signed-off-by: Liu Bo Signed-off-by: Josef Bacik Signed-off-by: Chris Mason --- fs/btrfs/backref.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 721936a5b2ca..30d24cfb45d4 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -185,6 +185,9 @@ static int __add_prelim_ref(struct list_head *head, u64 root_id, { struct __prelim_ref *ref; + if (root_id == BTRFS_DATA_RELOC_TREE_OBJECTID) + return 0; + ref = kmem_cache_alloc(btrfs_prelim_ref_cache, gfp_mask); if (!ref) return -ENOMEM;