aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorFilipe Manana <fdmanana@suse.com>2014-11-26 10:28:51 -0500
committerChris Mason <clm@fb.com>2014-12-02 21:19:17 -0500
commit4f69cb987ecbb6a87b5b1d56d6e9f9b5fee69737 (patch)
tree130978dd10c76638b886b34d03e0906eec6a84c5 /fs/btrfs
parent292cbd51ecf85d73195a3e3193937fa770f6ea71 (diff)
Btrfs: fix crash caused by block group removal
If we remove a block group (because it became empty), we might have left a caching_ctl structure in fs_info->caching_block_groups that points to the block group and is accessed at transaction commit time. This results in accessing an invalid or incorrect block group. This issue became visible after Josef's patch "Btrfs: remove empty block groups automatically". So if the block group is removed make sure we don't leave a dangling caching_ctl in caching_block_groups. Sample crash trace: [58380.439449] BUG: unable to handle kernel paging request at ffff8801446eaeb8 [58380.439707] IP: [<ffffffffa03f6d05>] block_group_cache_done.isra.21+0xc/0x1c [btrfs] [58380.440879] PGD 1acb067 PUD 23f5ff067 PMD 23f5db067 PTE 80000001446ea060 [58380.441220] Oops: 0000 [#1] SMP DEBUG_PAGEALLOC [58380.441486] Modules linked in: btrfs crc32c_generic xor raid6_pq nfsd auth_rpcgss oid_registry nfs_acl nfs lockd fscache sunrpc loop psmouse processor i2c_piix4 parport_pc parport pcspkr serio_raw evdev i2ccore thermal_sys microcode button ext4 crc16 jbd2 mbcache sr_mod cdrom ata_generic sg sd_mod crc_t10dif crct10dif_generic crct10dif_common virtio_scsi floppy ata_piix e1000 libata virtio_pci scsi_mod virtio_ring virtio [last unloaded: btrfs] [58380.443238] CPU: 3 PID: 25728 Comm: btrfs-transacti Tainted: G W 3.17.0-rc5-btrfs-next-1+ #1 [58380.443238] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014 [58380.443238] task: ffff88013ac82090 ti: ffff88013896c000 task.ti: ffff88013896c000 [58380.443238] RIP: 0010:[<ffffffffa03f6d05>] [<ffffffffa03f6d05>] block_group_cache_done.isra.21+0xc/0x1c [btrfs] [58380.443238] RSP: 0018:ffff88013896fdd8 EFLAGS: 00010283 [58380.443238] RAX: ffff880222cae850 RBX: ffff880119ba74c0 RCX: 0000000000000000 [58380.443238] RDX: 0000000000000000 RSI: ffff880185e16800 RDI: ffff8801446eaeb8 [58380.443238] RBP: ffff88013896fdd8 R08: ffff8801a9ca9fa8 R09: ffff88013896fc60 [58380.443238] R10: ffff88013896fd28 R11: 0000000000000000 R12: ffff880222cae000 [58380.443238] R13: ffff880222cae850 R14: ffff880222cae6b0 R15: ffff8801446eae00 [58380.443238] FS: 0000000000000000(0000) GS:ffff88023ed80000(0000) knlGS:0000000000000000 [58380.443238] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [58380.443238] CR2: ffff8801446eaeb8 CR3: 0000000001811000 CR4: 00000000000006e0 [58380.443238] Stack: [58380.443238] ffff88013896fe18 ffffffffa03fe2d5 ffff880222cae850 ffff880185e16800 [58380.443238] ffff88000dc41c20 0000000000000000 ffff8801a9ca9f00 0000000000000000 [58380.443238] ffff88013896fe80 ffffffffa040fbcf ffff88018b0dcdb0 ffff88013ac82090 [58380.443238] Call Trace: [58380.443238] [<ffffffffa03fe2d5>] btrfs_prepare_extent_commit+0x5a/0xd7 [btrfs] [58380.443238] [<ffffffffa040fbcf>] btrfs_commit_transaction+0x45c/0x882 [btrfs] [58380.443238] [<ffffffffa040c058>] transaction_kthread+0xf2/0x1a4 [btrfs] [58380.443238] [<ffffffffa040bf66>] ? btrfs_cleanup_transaction+0x3d8/0x3d8 [btrfs] [58380.443238] [<ffffffff8105966b>] kthread+0xb7/0xbf [58380.443238] [<ffffffff810595b4>] ? __kthread_parkme+0x67/0x67 [58380.443238] [<ffffffff813ebeac>] ret_from_fork+0x7c/0xb0 [58380.443238] [<ffffffff810595b4>] ? __kthread_parkme+0x67/0x67 Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.h1
-rw-r--r--fs/btrfs/extent-tree.c27
2 files changed, 28 insertions, 0 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index fc73e86235e8..302f37c56546 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1278,6 +1278,7 @@ struct btrfs_block_group_cache {
1278 unsigned int ro:1; 1278 unsigned int ro:1;
1279 unsigned int dirty:1; 1279 unsigned int dirty:1;
1280 unsigned int iref:1; 1280 unsigned int iref:1;
1281 unsigned int has_caching_ctl:1;
1281 1282
1282 int disk_cache_state; 1283 int disk_cache_state;
1283 1284
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index c21cd85a2e3a..c57bf387e502 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -607,6 +607,7 @@ static int cache_block_group(struct btrfs_block_group_cache *cache,
607 cache->cached = BTRFS_CACHE_NO; 607 cache->cached = BTRFS_CACHE_NO;
608 } else { 608 } else {
609 cache->cached = BTRFS_CACHE_STARTED; 609 cache->cached = BTRFS_CACHE_STARTED;
610 cache->has_caching_ctl = 1;
610 } 611 }
611 } 612 }
612 spin_unlock(&cache->lock); 613 spin_unlock(&cache->lock);
@@ -627,6 +628,7 @@ static int cache_block_group(struct btrfs_block_group_cache *cache,
627 cache->cached = BTRFS_CACHE_NO; 628 cache->cached = BTRFS_CACHE_NO;
628 } else { 629 } else {
629 cache->cached = BTRFS_CACHE_STARTED; 630 cache->cached = BTRFS_CACHE_STARTED;
631 cache->has_caching_ctl = 1;
630 } 632 }
631 spin_unlock(&cache->lock); 633 spin_unlock(&cache->lock);
632 wake_up(&caching_ctl->wait); 634 wake_up(&caching_ctl->wait);
@@ -9317,6 +9319,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
9317 int ret; 9319 int ret;
9318 int index; 9320 int index;
9319 int factor; 9321 int factor;
9322 struct btrfs_caching_control *caching_ctl = NULL;
9320 9323
9321 root = root->fs_info->extent_root; 9324 root = root->fs_info->extent_root;
9322 9325
@@ -9425,8 +9428,32 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
9425 kobject_put(kobj); 9428 kobject_put(kobj);
9426 } 9429 }
9427 9430
9431 if (block_group->has_caching_ctl)
9432 caching_ctl = get_caching_control(block_group);
9428 if (block_group->cached == BTRFS_CACHE_STARTED) 9433 if (block_group->cached == BTRFS_CACHE_STARTED)
9429 wait_block_group_cache_done(block_group); 9434 wait_block_group_cache_done(block_group);
9435 if (block_group->has_caching_ctl) {
9436 down_write(&root->fs_info->commit_root_sem);
9437 if (!caching_ctl) {
9438 struct btrfs_caching_control *ctl;
9439
9440 list_for_each_entry(ctl,
9441 &root->fs_info->caching_block_groups, list)
9442 if (ctl->block_group == block_group) {
9443 caching_ctl = ctl;
9444 atomic_inc(&caching_ctl->count);
9445 break;
9446 }
9447 }
9448 if (caching_ctl)
9449 list_del_init(&caching_ctl->list);
9450 up_write(&root->fs_info->commit_root_sem);
9451 if (caching_ctl) {
9452 /* Once for the caching bgs list and once for us. */
9453 put_caching_control(caching_ctl);
9454 put_caching_control(caching_ctl);
9455 }
9456 }
9430 9457
9431 btrfs_remove_free_space_cache(block_group); 9458 btrfs_remove_free_space_cache(block_group);
9432 9459