On 2018年07月31日 14:44, Qu Wenruo wrote:
>
>
> On 2018年07月31日 14:48, Su Yue wrote:
>>
>>
>> On 07/30/2018 02:17 PM, Qu Wenruo wrote:
>>> [BUG]
>>> For certains crafted image, whose csum root leaf has missing backref, if
>>> we try to trigger write with data csum, it could cause deadlock with the
>>> following kernel WARN_ON():
>>> ------
>>> WARNING: CPU: 1 PID: 41 at fs/btrfs/locking.c:230
>>> btrfs_tree_lock+0x3e2/0x400
>>> CPU: 1 PID: 41 Comm: kworker/u4:1 Not tainted 4.18.0-rc1+ #8
>>> Workqueue: btrfs-endio-write btrfs_endio_write_helper
>>> RIP: 0010:btrfs_tree_lock+0x3e2/0x400
>>> Call Trace:
>>> btrfs_alloc_tree_block+0x39f/0x770
>>> __btrfs_cow_block+0x285/0x9e0
>>> btrfs_cow_block+0x191/0x2e0
>>> btrfs_search_slot+0x492/0x1160
>>> btrfs_lookup_csum+0xec/0x280
>>> btrfs_csum_file_blocks+0x2be/0xa60
>>> add_pending_csums+0xaf/0xf0
>>> btrfs_finish_ordered_io+0x74b/0xc90
>>> finish_ordered_fn+0x15/0x20
>>> normal_work_helper+0xf6/0x500
>>> btrfs_endio_write_helper+0x12/0x20
>>> process_one_work+0x302/0x770
>>> worker_thread+0x81/0x6d0
>>> kthread+0x180/0x1d0
>>> ret_from_fork+0x35/0x40
>>> ---[ end trace 2e85051acb5f6dc1 ]---
>>> ------
>>>
>>> [CAUSE]
>>> That crafted image has missing backref for csum tree root leaf.
>>> And when we try to allocate new tree block, since there is no
>>> EXTENT/METADATA_ITEM for csum tree root, btrfs consider it's free slot
>>> and use it.
>>>
>>> However we have already locked csum tree root leaf by ourselves, thus we
>>> will ourselves to release read/write lock, and causing deadlock.
>>>
>>> [FIX]
>>> This patch will allow btrfs_tree_lock() to return error number, so
>>> most callers can exit gracefully.
>>> (Some caller doesn't really expect btrfs_tree_lock() to return error,
>>> and in that case, we use BUG_ON())
>>>
>>> Since such problem can only happen in crafted image, we will still
>>> trigger kernel warning, but with a little more meaningful warning
>>> message.
>>>
>>> Link: https://bugzilla.kernel.org/show_bug.cgi?id 0405
>>> Reported-by: Xu Wen <wen...@gatech.edu>
>>> Signed-off-by: Qu Wenruo <w...@suse.com>
>>
>> OK.. I looked through every places where the callee is called.
>> Those errors are handled gracefully as my thought.
>> Except one nitpick, the %llu about pid_t in btrfs_tree_lock.
>> However, you can add the tag:
>>
>> Reviewed-by: Su Yue <suy.f...@cn.fujitsu.com>
>
> snip
>
>>
>> Nit:
>> pid_t is as an signed integer, should be pid= .
>
> BTW, how could pid be negative?
> And why my gcc doesn't give such warning?
My fault, gcc does give warning about this.
I'll fix it soon.
Thanks,
Qu
>
> Thanks,
> Qu
>
>>
>> Thanks,
>> Su
>>
>>> + eb->start, current->pid);
>>> + return -EUCLEAN;
>>> + }
>>> again:
>>> wait_event(eb->read_lock_wq, atomic_read(&eb->blocking_readers)
>>> =0);
>>> wait_event(eb->write_lock_wq, atomic_read(&eb->blocking_writers)
>>> =0);
>>> diff --git a/fs/btrfs/locking.h b/fs/btrfs/locking.h
>>> index 29135def468e..7394d7ba2ff9 100644
>>> --- a/fs/btrfs/locking.h
>>> +++ b/fs/btrfs/locking.h
>>> @@ -11,7 +11,7 @@
>>> #define BTRFS_WRITE_LOCK_BLOCKING 3
>>> #define BTRFS_READ_LOCK_BLOCKING 4
>>> -void btrfs_tree_lock(struct extent_buffer *eb);
>>> +int btrfs_tree_lock(struct extent_buffer *eb);
>>> void btrfs_tree_unlock(struct extent_buffer *eb);
>>> void btrfs_tree_read_lock(struct extent_buffer *eb);
>>> diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
>>> index 1874a6d2e6f5..ec4351fd7537 100644
>>> --- a/fs/btrfs/qgroup.c
>>> +++ b/fs/btrfs/qgroup.c
>>> @@ -1040,7 +1040,9 @@ int btrfs_quota_disable(struct
>>> btrfs_trans_handle *trans,
>>> list_del("a_root->dirty_list);
>>> - btrfs_tree_lock(quota_root->node);
>>> + ret =trfs_tree_lock(quota_root->node);
>>> + if (ret < 0)
>>> + goto out;
>>> clean_tree_block(fs_info, quota_root->node);
>>> btrfs_tree_unlock(quota_root->node);
>>> btrfs_free_tree_block(trans, quota_root, quota_root->node, 0, 1);
>>> diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
>>> index be94c65bb4d2..a2fc0bd83a40 100644
>>> --- a/fs/btrfs/relocation.c
>>> +++ b/fs/btrfs/relocation.c
>>> @@ -1877,7 +1877,11 @@ int replace_path(struct btrfs_trans_handle *trans,
>>> free_extent_buffer(eb);
>>> break;
>>> }
>>> - btrfs_tree_lock(eb);
>>> + ret =trfs_tree_lock(eb);
>>> + if (ret < 0) {
>>> + free_extent_buffer(eb);
>>> + break;
>>> + }
>>> if (cow) {
>>> ret =trfs_cow_block(trans, dest, eb, parent,
>>> slot, &eb);
>>> @@ -2788,7 +2792,12 @@ static int do_relocation(struct
>>> btrfs_trans_handle *trans,
>>> err =EIO;
>>> goto next;
>>> }
>>> - btrfs_tree_lock(eb);
>>> + ret =trfs_tree_lock(eb);
>>> + if (ret < 0) {
>>> + free_extent_buffer(eb);
>>> + err =et;
>>> + goto next;
>>> + }
>>> btrfs_set_lock_blocking(eb);
>>> if (!node->eb) {
>>> diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
>>> index f8220ec02036..173bc15a7cd1 100644
>>> --- a/fs/btrfs/tree-log.c
>>> +++ b/fs/btrfs/tree-log.c
>>> @@ -2588,7 +2588,11 @@ static noinline int walk_down_log_tree(struct
>>> btrfs_trans_handle *trans,
>>> }
>>> if (trans) {
>>> - btrfs_tree_lock(next);
>>> + ret =trfs_tree_lock(next);
>>> + if (ret < 0) {
>>> + free_extent_buffer(next);
>>> + return ret;
>>> + }
>>> btrfs_set_lock_blocking(next);
>>> clean_tree_block(fs_info, next);
>>> btrfs_wait_tree_block_writeback(next);
>>> @@ -2672,7 +2676,9 @@ static noinline int walk_up_log_tree(struct
>>> btrfs_trans_handle *trans,
>>> next =ath->nodes[*level];
>>> if (trans) {
>>> - btrfs_tree_lock(next);
>>> + ret =trfs_tree_lock(next);
>>> + if (ret < 0)
>>> + return ret;
>>> btrfs_set_lock_blocking(next);
>>> clean_tree_block(fs_info, next);
>>> btrfs_wait_tree_block_writeback(next);
>>> @@ -2754,7 +2760,9 @@ static int walk_log_tree(struct
>>> btrfs_trans_handle *trans,
>>> next =ath->nodes[orig_level];
>>> if (trans) {
>>> - btrfs_tree_lock(next);
>>> + ret =trfs_tree_lock(next);
>>> + if (ret < 0)
>>> + goto out;
>>> btrfs_set_lock_blocking(next);
>>> clean_tree_block(fs_info, next);
>>> btrfs_wait_tree_block_writeback(next);
>>>
>>
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
>> the body of a message to majord...@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
> --
> To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html