aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorFilipe David Borba Manana <fdmanana@gmail.com>2013-08-28 05:28:34 -0400
committerChris Mason <chris.mason@fusionio.com>2013-09-01 08:16:39 -0400
commitf45388f3874535062526ec071284d836f5a4b5de (patch)
tree49a8ee1defc26afdf607ca01f286ae6771fb8f66 /fs/btrfs
parent795a33213973cf0195198132162862fb05929425 (diff)
Btrfs: fix deadlock in uuid scan kthread
If there's an ongoing transaction when the uuid scan kthread attempts to create one, the kthread will block, waiting for that transaction to finish while it's keeping locks on the tree root, and in turn the existing transaction is waiting for those locks to be free. The stack trace reported by the kernel follows. [36700.671601] INFO: task btrfs-uuid:15480 blocked for more than 120 seconds. [36700.671602] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. [36700.671602] btrfs-uuid D 0000000000000000 0 15480 2 0x00000000 [36700.671604] ffff880710bd5b88 0000000000000046 ffff8803d36ba850 0000000000030000 [36700.671605] ffff8806d76dc530 ffff880710bd5fd8 ffff880710bd5fd8 ffff880710bd5fd8 [36700.671607] ffff8808098ac530 ffff8806d76dc530 ffff880710bd5b98 ffff8805e4508e40 [36700.671608] Call Trace: [36700.671610] [<ffffffff816f36b9>] schedule+0x29/0x70 [36700.671620] [<ffffffffa05a3bdf>] wait_current_trans.isra.33+0xbf/0x120 [btrfs] [36700.671623] [<ffffffff81066760>] ? add_wait_queue+0x60/0x60 [36700.671629] [<ffffffffa05a5b06>] start_transaction+0x3d6/0x530 [btrfs] [36700.671636] [<ffffffffa05bb1f4>] ? btrfs_get_token_32+0x64/0xf0 [btrfs] [36700.671642] [<ffffffffa05a5fbb>] btrfs_start_transaction+0x1b/0x20 [btrfs] [36700.671649] [<ffffffffa05c8a81>] btrfs_uuid_scan_kthread+0x211/0x3d0 [btrfs] [36700.671655] [<ffffffffa05c8870>] ? __btrfs_open_devices+0x2a0/0x2a0 [btrfs] [36700.671657] [<ffffffff81065fa0>] kthread+0xc0/0xd0 [36700.671659] [<ffffffff81065ee0>] ? flush_kthread_worker+0xb0/0xb0 [36700.671661] [<ffffffff816fcd1c>] ret_from_fork+0x7c/0xb0 [36700.671662] [<ffffffff81065ee0>] ? flush_kthread_worker+0xb0/0xb0 [36700.671663] INFO: task btrfs:15481 blocked for more than 120 seconds. [36700.671664] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. [36700.671665] btrfs D 0000000000000000 0 15481 15212 0x00000004 [36700.671666] ffff880248cbf4c8 0000000000000086 ffff8803d36ba700 ffff8801dbd5c280 [36700.671668] ffff880807815c40 ffff880248cbffd8 ffff880248cbffd8 ffff880248cbffd8 [36700.671669] ffff8805e86a0000 ffff880807815c40 ffff880248cbf4d8 ffff8801dbd5c280 [36700.671670] Call Trace: [36700.671672] [<ffffffff816f36b9>] schedule+0x29/0x70 [36700.671679] [<ffffffffa05d9b0d>] btrfs_tree_lock+0x6d/0x230 [btrfs] [36700.671680] [<ffffffff81066760>] ? add_wait_queue+0x60/0x60 [36700.671685] [<ffffffffa0582829>] btrfs_search_slot+0x999/0xb00 [btrfs] [36700.671691] [<ffffffffa05bd9de>] ? btrfs_lookup_first_ordered_extent+0x5e/0xb0 [btrfs] [36700.671698] [<ffffffffa05e3e54>] __btrfs_write_out_cache+0x8c4/0xa80 [btrfs] [36700.671704] [<ffffffffa05e4362>] btrfs_write_out_cache+0xb2/0xf0 [btrfs] [36700.671710] [<ffffffffa05c4441>] ? free_extent_buffer+0x61/0xc0 [btrfs] [36700.671716] [<ffffffffa0594c82>] btrfs_write_dirty_block_groups+0x562/0x650 [btrfs] [36700.671723] [<ffffffffa0610092>] commit_cowonly_roots+0x171/0x24b [btrfs] [36700.671729] [<ffffffffa05a4dde>] btrfs_commit_transaction+0x4fe/0xa10 [btrfs] [36700.671735] [<ffffffffa0610af3>] create_subvol+0x5c0/0x636 [btrfs] [36700.671742] [<ffffffffa05d49ff>] btrfs_mksubvol.isra.60+0x33f/0x3f0 [btrfs] [36700.671747] [<ffffffffa05d4bf2>] btrfs_ioctl_snap_create_transid+0x142/0x190 [btrfs] [36700.671752] [<ffffffffa05d4c6c>] ? btrfs_ioctl_snap_create+0x2c/0x80 [btrfs] [36700.671757] [<ffffffffa05d4c9e>] btrfs_ioctl_snap_create+0x5e/0x80 [btrfs] [36700.671759] [<ffffffff8113a764>] ? handle_pte_fault+0x84/0x920 [36700.671764] [<ffffffffa05d87eb>] btrfs_ioctl+0xf0b/0x1d00 [btrfs] [36700.671766] [<ffffffff8113c120>] ? handle_mm_fault+0x210/0x310 [36700.671768] [<ffffffff816f83a4>] ? __do_page_fault+0x284/0x4e0 [36700.671770] [<ffffffff81180aa6>] do_vfs_ioctl+0x96/0x550 [36700.671772] [<ffffffff81170fe3>] ? __sb_end_write+0x33/0x70 [36700.671774] [<ffffffff81180ff1>] SyS_ioctl+0x91/0xb0 [36700.671775] [<ffffffff816fcdc2>] system_call_fastpath+0x16/0x1b Signed-off-by: Filipe David Borba Manana <fdmanana@gmail.com> Signed-off-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/volumes.c35
1 files changed, 18 insertions, 17 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 603cce85764f..0db165ee4340 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -3463,7 +3463,7 @@ static int btrfs_uuid_scan_kthread(void *data)
3463 int slot; 3463 int slot;
3464 struct btrfs_root_item root_item; 3464 struct btrfs_root_item root_item;
3465 u32 item_size; 3465 u32 item_size;
3466 struct btrfs_trans_handle *trans; 3466 struct btrfs_trans_handle *trans = NULL;
3467 3467
3468 path = btrfs_alloc_path(); 3468 path = btrfs_alloc_path();
3469 if (!path) { 3469 if (!path) {
@@ -3501,13 +3501,18 @@ static int btrfs_uuid_scan_kthread(void *data)
3501 if (item_size < sizeof(root_item)) 3501 if (item_size < sizeof(root_item))
3502 goto skip; 3502 goto skip;
3503 3503
3504 trans = NULL;
3505 read_extent_buffer(eb, &root_item, 3504 read_extent_buffer(eb, &root_item,
3506 btrfs_item_ptr_offset(eb, slot), 3505 btrfs_item_ptr_offset(eb, slot),
3507 (int)sizeof(root_item)); 3506 (int)sizeof(root_item));
3508 if (btrfs_root_refs(&root_item) == 0) 3507 if (btrfs_root_refs(&root_item) == 0)
3509 goto skip; 3508 goto skip;
3510 if (!btrfs_is_empty_uuid(root_item.uuid)) { 3509
3510 if (!btrfs_is_empty_uuid(root_item.uuid) ||
3511 !btrfs_is_empty_uuid(root_item.received_uuid)) {
3512 if (trans)
3513 goto update_tree;
3514
3515 btrfs_release_path(path);
3511 /* 3516 /*
3512 * 1 - subvol uuid item 3517 * 1 - subvol uuid item
3513 * 1 - received_subvol uuid item 3518 * 1 - received_subvol uuid item
@@ -3517,6 +3522,12 @@ static int btrfs_uuid_scan_kthread(void *data)
3517 ret = PTR_ERR(trans); 3522 ret = PTR_ERR(trans);
3518 break; 3523 break;
3519 } 3524 }
3525 continue;
3526 } else {
3527 goto skip;
3528 }
3529update_tree:
3530 if (!btrfs_is_empty_uuid(root_item.uuid)) {
3520 ret = btrfs_uuid_tree_add(trans, fs_info->uuid_root, 3531 ret = btrfs_uuid_tree_add(trans, fs_info->uuid_root,
3521 root_item.uuid, 3532 root_item.uuid,
3522 BTRFS_UUID_KEY_SUBVOL, 3533 BTRFS_UUID_KEY_SUBVOL,
@@ -3524,22 +3535,11 @@ static int btrfs_uuid_scan_kthread(void *data)
3524 if (ret < 0) { 3535 if (ret < 0) {
3525 pr_warn("btrfs: uuid_tree_add failed %d\n", 3536 pr_warn("btrfs: uuid_tree_add failed %d\n",
3526 ret); 3537 ret);
3527 btrfs_end_transaction(trans,
3528 fs_info->uuid_root);
3529 break; 3538 break;
3530 } 3539 }
3531 } 3540 }
3532 3541
3533 if (!btrfs_is_empty_uuid(root_item.received_uuid)) { 3542 if (!btrfs_is_empty_uuid(root_item.received_uuid)) {
3534 if (!trans) {
3535 /* 1 - received_subvol uuid item */
3536 trans = btrfs_start_transaction(
3537 fs_info->uuid_root, 1);
3538 if (IS_ERR(trans)) {
3539 ret = PTR_ERR(trans);
3540 break;
3541 }
3542 }
3543 ret = btrfs_uuid_tree_add(trans, fs_info->uuid_root, 3543 ret = btrfs_uuid_tree_add(trans, fs_info->uuid_root,
3544 root_item.received_uuid, 3544 root_item.received_uuid,
3545 BTRFS_UUID_KEY_RECEIVED_SUBVOL, 3545 BTRFS_UUID_KEY_RECEIVED_SUBVOL,
@@ -3547,19 +3547,18 @@ static int btrfs_uuid_scan_kthread(void *data)
3547 if (ret < 0) { 3547 if (ret < 0) {
3548 pr_warn("btrfs: uuid_tree_add failed %d\n", 3548 pr_warn("btrfs: uuid_tree_add failed %d\n",
3549 ret); 3549 ret);
3550 btrfs_end_transaction(trans,
3551 fs_info->uuid_root);
3552 break; 3550 break;
3553 } 3551 }
3554 } 3552 }
3555 3553
3554skip:
3556 if (trans) { 3555 if (trans) {
3557 ret = btrfs_end_transaction(trans, fs_info->uuid_root); 3556 ret = btrfs_end_transaction(trans, fs_info->uuid_root);
3557 trans = NULL;
3558 if (ret) 3558 if (ret)
3559 break; 3559 break;
3560 } 3560 }
3561 3561
3562skip:
3563 btrfs_release_path(path); 3562 btrfs_release_path(path);
3564 if (key.offset < (u64)-1) { 3563 if (key.offset < (u64)-1) {
3565 key.offset++; 3564 key.offset++;
@@ -3578,6 +3577,8 @@ skip:
3578 3577
3579out: 3578out:
3580 btrfs_free_path(path); 3579 btrfs_free_path(path);
3580 if (trans && !IS_ERR(trans))
3581 btrfs_end_transaction(trans, fs_info->uuid_root);
3581 if (ret) 3582 if (ret)
3582 pr_warn("btrfs: btrfs_uuid_scan_kthread failed %d\n", ret); 3583 pr_warn("btrfs: btrfs_uuid_scan_kthread failed %d\n", ret);
3583 else 3584 else