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: Chris Mason <chris.mason@oracle.com>

+17 -4
+17 -4
fs/btrfs/extent-tree.c
··· 265 265 266 266 atomic_inc(&block_group->space_info->caching_threads); 267 267 last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET); 268 - again: 269 - /* need to make sure the commit_root doesn't disappear */ 270 - down_read(&fs_info->extent_commit_sem); 271 - 272 268 /* 273 269 * We don't want to deadlock with somebody trying to allocate a new 274 270 * extent for the extent root while also trying to search the extent ··· 278 282 key.objectid = last; 279 283 key.offset = 0; 280 284 btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); 285 + again: 286 + /* need to make sure the commit_root doesn't disappear */ 287 + down_read(&fs_info->extent_commit_sem); 288 + 281 289 ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0); 282 290 if (ret < 0) 283 291 goto err; ··· 304 304 305 305 if (need_resched() || 306 306 btrfs_transaction_in_commit(fs_info)) { 307 + leaf = path->nodes[0]; 308 + 309 + /* this shouldn't happen, but if the 310 + * leaf is empty just move on. 311 + */ 312 + if (btrfs_header_nritems(leaf) == 0) 313 + break; 314 + /* 315 + * we need to copy the key out so that 316 + * we are sure the next search advances 317 + * us forward in the btree. 318 + */ 319 + btrfs_item_key_to_cpu(leaf, &key, 0); 307 320 btrfs_release_path(fs_info->extent_root, path); 308 321 up_read(&fs_info->extent_commit_sem); 309 322 schedule_timeout(1);