Commit 013f1b12 authored by Chris Mason's avatar Chris Mason

Btrfs: make sure the async caching thread advances the key

The async caching thread can end up looping forever if a given
search puts it at the last key in a leaf.  It will end up calling
btrfs_next_leaf and then checking if it needs to politely drop
the read semaphore.

Most of the time this looping isn't noticed because it is able to
make progress the next time around.  But, during log replay,
we wait on the async caching thread to finish, and the async thread
is waiting on the commit, and no progress is really made.

The fix used here is to copy the key out of the next leaf,
that way our search lands there properly.
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 6606bb97
...@@ -265,10 +265,6 @@ static int caching_kthread(void *data) ...@@ -265,10 +265,6 @@ static int caching_kthread(void *data)
atomic_inc(&block_group->space_info->caching_threads); atomic_inc(&block_group->space_info->caching_threads);
last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET); last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET);
again:
/* need to make sure the commit_root doesn't disappear */
down_read(&fs_info->extent_commit_sem);
/* /*
* We don't want to deadlock with somebody trying to allocate a new * We don't want to deadlock with somebody trying to allocate a new
* extent for the extent root while also trying to search the extent * extent for the extent root while also trying to search the extent
...@@ -282,6 +278,10 @@ static int caching_kthread(void *data) ...@@ -282,6 +278,10 @@ static int caching_kthread(void *data)
key.objectid = last; key.objectid = last;
key.offset = 0; key.offset = 0;
btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
again:
/* need to make sure the commit_root doesn't disappear */
down_read(&fs_info->extent_commit_sem);
ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0); ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0);
if (ret < 0) if (ret < 0)
goto err; goto err;
...@@ -304,6 +304,19 @@ static int caching_kthread(void *data) ...@@ -304,6 +304,19 @@ static int caching_kthread(void *data)
if (need_resched() || if (need_resched() ||
btrfs_transaction_in_commit(fs_info)) { btrfs_transaction_in_commit(fs_info)) {
leaf = path->nodes[0];
/* this shouldn't happen, but if the
* leaf is empty just move on.
*/
if (btrfs_header_nritems(leaf) == 0)
break;
/*
* we need to copy the key out so that
* we are sure the next search advances
* us forward in the btree.
*/
btrfs_item_key_to_cpu(leaf, &key, 0);
btrfs_release_path(fs_info->extent_root, path); btrfs_release_path(fs_info->extent_root, path);
up_read(&fs_info->extent_commit_sem); up_read(&fs_info->extent_commit_sem);
schedule_timeout(1); schedule_timeout(1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment