int need_commit = 2;
int have_pinned_space;
int have_bg_delete_sem = 0;
+ bool free_space_inode = btrfs_is_free_space_inode(inode);
/* make sure bytes are sectorsize aligned */
bytes = ALIGN(bytes, root->sectorsize);
- if (btrfs_is_free_space_inode(inode)) {
+ if (free_space_inode) {
need_commit = 0;
ASSERT(current->journal_info);
}
+ /*
+ * Here we shouldn't call down_read(bg_delete_sem) for free space inode,
+ * there is lock order between bg_delete_sem and "wait current trans
+ * finished". Meanwhile because we only do the data space reservation
+ * for free space cache in the transaction context,
+ * btrfs_delete_unused_bgs() will either have finished its job, or start
+ * a new transaction waiting current transaction to complete, there will
+ * be no unused block groups to be deleted, so it's safe to not call
+ * down_read(bg_delete_sem).
+ */
data_sinfo = fs_info->data_sinfo;
if (!data_sinfo) {
- down_read(&root->fs_info->bg_delete_sem);
- have_bg_delete_sem = 1;
+ if (!free_space_inode) {
+ down_read(&root->fs_info->bg_delete_sem);
+ have_bg_delete_sem = 1;
+ }
goto alloc;
}
* We may need to allocate new chunk, so we should block
* btrfs_delete_unused_bgs()
*/
- if (!have_bg_delete_sem) {
+ if (!have_bg_delete_sem && !free_space_inode) {
spin_unlock(&data_sinfo->lock);
down_read(&root->fs_info->bg_delete_sem);
have_bg_delete_sem = 1;
*/
trans = btrfs_join_transaction(root);
if (IS_ERR(trans)) {
- up_read(&root->fs_info->bg_delete_sem);
- return PTR_ERR(trans);
+ ret = PTR_ERR(trans);
+ goto out;
}
ret = do_chunk_alloc(trans, root->fs_info->extent_root,
CHUNK_ALLOC_NO_FORCE);
btrfs_end_transaction(trans, root);
if (ret < 0) {
- if (ret != -ENOSPC) {
- up_read(&root->fs_info->bg_delete_sem);
- return ret;
- } else {
+ if (ret != -ENOSPC)
+ goto out;
+ else {
have_pinned_space = 1;
goto commit_trans;
}
trans = btrfs_join_transaction(root);
if (IS_ERR(trans)) {
- up_read(&root->fs_info->bg_delete_sem);
- return PTR_ERR(trans);
+ ret = PTR_ERR(trans);
+ goto out;
}
if (have_pinned_space >= 0 ||
test_bit(BTRFS_TRANS_HAVE_FREE_BGS,
&trans->transaction->flags) ||
need_commit > 0) {
ret = btrfs_commit_transaction(trans, root);
- if (ret) {
- up_read(&root->fs_info->bg_delete_sem);
- return ret;
- }
+ if (ret)
+ goto out;
/*
* The cleaner kthread might still be doing iput
* operations. Wait for it to finish so that
trace_btrfs_space_reservation(root->fs_info,
"space_info:enospc",
data_sinfo->flags, bytes, 1);
- up_read(&root->fs_info->bg_delete_sem);
- return -ENOSPC;
+ ret = -ENOSPC;
+ goto out;
}
data_sinfo->bytes_may_use += bytes;
trace_btrfs_space_reservation(root->fs_info, "space_info",
data_sinfo->flags, bytes, 1);
spin_unlock(&data_sinfo->lock);
- if (have_bg_delete_sem)
+out:
+ if (have_bg_delete_sem && !free_space_inode)
up_read(&root->fs_info->bg_delete_sem);
return ret;