|
@@ -2766,6 +2766,20 @@ static int btrfs_relocate_chunk(struct btrfs_root *root,
|
|
root = root->fs_info->chunk_root;
|
|
root = root->fs_info->chunk_root;
|
|
extent_root = root->fs_info->extent_root;
|
|
extent_root = root->fs_info->extent_root;
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Prevent races with automatic removal of unused block groups.
|
|
|
|
+ * After we relocate and before we remove the chunk with offset
|
|
|
|
+ * chunk_offset, automatic removal of the block group can kick in,
|
|
|
|
+ * resulting in a failure when calling btrfs_remove_chunk() below.
|
|
|
|
+ *
|
|
|
|
+ * Make sure to acquire this mutex before doing a tree search (dev
|
|
|
|
+ * or chunk trees) to find chunks. Otherwise the cleaner kthread might
|
|
|
|
+ * call btrfs_remove_chunk() (through btrfs_delete_unused_bgs()) after
|
|
|
|
+ * we release the path used to search the chunk/dev tree and before
|
|
|
|
+ * the current task acquires this mutex and calls us.
|
|
|
|
+ */
|
|
|
|
+ ASSERT(mutex_is_locked(&root->fs_info->delete_unused_bgs_mutex));
|
|
|
|
+
|
|
ret = btrfs_can_relocate(extent_root, chunk_offset);
|
|
ret = btrfs_can_relocate(extent_root, chunk_offset);
|
|
if (ret)
|
|
if (ret)
|
|
return -ENOSPC;
|
|
return -ENOSPC;
|
|
@@ -2814,13 +2828,18 @@ again:
|
|
key.type = BTRFS_CHUNK_ITEM_KEY;
|
|
key.type = BTRFS_CHUNK_ITEM_KEY;
|
|
|
|
|
|
while (1) {
|
|
while (1) {
|
|
|
|
+ mutex_lock(&root->fs_info->delete_unused_bgs_mutex);
|
|
ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0);
|
|
ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0);
|
|
- if (ret < 0)
|
|
|
|
|
|
+ if (ret < 0) {
|
|
|
|
+ mutex_unlock(&root->fs_info->delete_unused_bgs_mutex);
|
|
goto error;
|
|
goto error;
|
|
|
|
+ }
|
|
BUG_ON(ret == 0); /* Corruption */
|
|
BUG_ON(ret == 0); /* Corruption */
|
|
|
|
|
|
ret = btrfs_previous_item(chunk_root, path, key.objectid,
|
|
ret = btrfs_previous_item(chunk_root, path, key.objectid,
|
|
key.type);
|
|
key.type);
|
|
|
|
+ if (ret)
|
|
|
|
+ mutex_unlock(&root->fs_info->delete_unused_bgs_mutex);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
goto error;
|
|
goto error;
|
|
if (ret > 0)
|
|
if (ret > 0)
|
|
@@ -2843,6 +2862,7 @@ again:
|
|
else
|
|
else
|
|
BUG_ON(ret);
|
|
BUG_ON(ret);
|
|
}
|
|
}
|
|
|
|
+ mutex_unlock(&root->fs_info->delete_unused_bgs_mutex);
|
|
|
|
|
|
if (found_key.offset == 0)
|
|
if (found_key.offset == 0)
|
|
break;
|
|
break;
|
|
@@ -3299,9 +3319,12 @@ again:
|
|
goto error;
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ mutex_lock(&fs_info->delete_unused_bgs_mutex);
|
|
ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0);
|
|
ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0);
|
|
- if (ret < 0)
|
|
|
|
|
|
+ if (ret < 0) {
|
|
|
|
+ mutex_unlock(&fs_info->delete_unused_bgs_mutex);
|
|
goto error;
|
|
goto error;
|
|
|
|
+ }
|
|
|
|
|
|
/*
|
|
/*
|
|
* this shouldn't happen, it means the last relocate
|
|
* this shouldn't happen, it means the last relocate
|
|
@@ -3313,6 +3336,7 @@ again:
|
|
ret = btrfs_previous_item(chunk_root, path, 0,
|
|
ret = btrfs_previous_item(chunk_root, path, 0,
|
|
BTRFS_CHUNK_ITEM_KEY);
|
|
BTRFS_CHUNK_ITEM_KEY);
|
|
if (ret) {
|
|
if (ret) {
|
|
|
|
+ mutex_unlock(&fs_info->delete_unused_bgs_mutex);
|
|
ret = 0;
|
|
ret = 0;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -3321,8 +3345,10 @@ again:
|
|
slot = path->slots[0];
|
|
slot = path->slots[0];
|
|
btrfs_item_key_to_cpu(leaf, &found_key, slot);
|
|
btrfs_item_key_to_cpu(leaf, &found_key, slot);
|
|
|
|
|
|
- if (found_key.objectid != key.objectid)
|
|
|
|
|
|
+ if (found_key.objectid != key.objectid) {
|
|
|
|
+ mutex_unlock(&fs_info->delete_unused_bgs_mutex);
|
|
break;
|
|
break;
|
|
|
|
+ }
|
|
|
|
|
|
chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk);
|
|
chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk);
|
|
|
|
|
|
@@ -3335,10 +3361,13 @@ again:
|
|
ret = should_balance_chunk(chunk_root, leaf, chunk,
|
|
ret = should_balance_chunk(chunk_root, leaf, chunk,
|
|
found_key.offset);
|
|
found_key.offset);
|
|
btrfs_release_path(path);
|
|
btrfs_release_path(path);
|
|
- if (!ret)
|
|
|
|
|
|
+ if (!ret) {
|
|
|
|
+ mutex_unlock(&fs_info->delete_unused_bgs_mutex);
|
|
goto loop;
|
|
goto loop;
|
|
|
|
+ }
|
|
|
|
|
|
if (counting) {
|
|
if (counting) {
|
|
|
|
+ mutex_unlock(&fs_info->delete_unused_bgs_mutex);
|
|
spin_lock(&fs_info->balance_lock);
|
|
spin_lock(&fs_info->balance_lock);
|
|
bctl->stat.expected++;
|
|
bctl->stat.expected++;
|
|
spin_unlock(&fs_info->balance_lock);
|
|
spin_unlock(&fs_info->balance_lock);
|
|
@@ -3348,6 +3377,7 @@ again:
|
|
ret = btrfs_relocate_chunk(chunk_root,
|
|
ret = btrfs_relocate_chunk(chunk_root,
|
|
found_key.objectid,
|
|
found_key.objectid,
|
|
found_key.offset);
|
|
found_key.offset);
|
|
|
|
+ mutex_unlock(&fs_info->delete_unused_bgs_mutex);
|
|
if (ret && ret != -ENOSPC)
|
|
if (ret && ret != -ENOSPC)
|
|
goto error;
|
|
goto error;
|
|
if (ret == -ENOSPC) {
|
|
if (ret == -ENOSPC) {
|
|
@@ -4087,11 +4117,16 @@ again:
|
|
key.type = BTRFS_DEV_EXTENT_KEY;
|
|
key.type = BTRFS_DEV_EXTENT_KEY;
|
|
|
|
|
|
do {
|
|
do {
|
|
|
|
+ mutex_lock(&root->fs_info->delete_unused_bgs_mutex);
|
|
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
|
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
|
- if (ret < 0)
|
|
|
|
|
|
+ if (ret < 0) {
|
|
|
|
+ mutex_unlock(&root->fs_info->delete_unused_bgs_mutex);
|
|
goto done;
|
|
goto done;
|
|
|
|
+ }
|
|
|
|
|
|
ret = btrfs_previous_item(root, path, 0, key.type);
|
|
ret = btrfs_previous_item(root, path, 0, key.type);
|
|
|
|
+ if (ret)
|
|
|
|
+ mutex_unlock(&root->fs_info->delete_unused_bgs_mutex);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
goto done;
|
|
goto done;
|
|
if (ret) {
|
|
if (ret) {
|
|
@@ -4105,6 +4140,7 @@ again:
|
|
btrfs_item_key_to_cpu(l, &key, path->slots[0]);
|
|
btrfs_item_key_to_cpu(l, &key, path->slots[0]);
|
|
|
|
|
|
if (key.objectid != device->devid) {
|
|
if (key.objectid != device->devid) {
|
|
|
|
+ mutex_unlock(&root->fs_info->delete_unused_bgs_mutex);
|
|
btrfs_release_path(path);
|
|
btrfs_release_path(path);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -4113,6 +4149,7 @@ again:
|
|
length = btrfs_dev_extent_length(l, dev_extent);
|
|
length = btrfs_dev_extent_length(l, dev_extent);
|
|
|
|
|
|
if (key.offset + length <= new_size) {
|
|
if (key.offset + length <= new_size) {
|
|
|
|
+ mutex_unlock(&root->fs_info->delete_unused_bgs_mutex);
|
|
btrfs_release_path(path);
|
|
btrfs_release_path(path);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -4122,6 +4159,7 @@ again:
|
|
btrfs_release_path(path);
|
|
btrfs_release_path(path);
|
|
|
|
|
|
ret = btrfs_relocate_chunk(root, chunk_objectid, chunk_offset);
|
|
ret = btrfs_relocate_chunk(root, chunk_objectid, chunk_offset);
|
|
|
|
+ mutex_unlock(&root->fs_info->delete_unused_bgs_mutex);
|
|
if (ret && ret != -ENOSPC)
|
|
if (ret && ret != -ENOSPC)
|
|
goto done;
|
|
goto done;
|
|
if (ret == -ENOSPC)
|
|
if (ret == -ENOSPC)
|