Btrfs: use the commit_root for reading free_space_inode crcs
Now that we are using regular file crcs for the free space cache, we can deadlock if we try to read the free_space_inode while we are updating the crc tree. This commit fixes things by using the commit_root to read the crcs. This is safe because we the free space cache file would already be loaded if that block group had been changed in the current transaction. Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
parent
19b6caf4ac
commit
2cf8572dac
3 changed files with 28 additions and 19 deletions
|
@ -187,4 +187,13 @@ static inline void btrfs_i_size_write(struct inode *inode, u64 size)
|
|||
BTRFS_I(inode)->disk_i_size = size;
|
||||
}
|
||||
|
||||
static inline bool btrfs_is_free_space_inode(struct btrfs_root *root,
|
||||
struct inode *inode)
|
||||
{
|
||||
if (root == root->fs_info->tree_root ||
|
||||
BTRFS_I(inode)->location.objectid == BTRFS_FREE_INO_OBJECTID)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -177,6 +177,15 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
|
|||
|
||||
WARN_ON(bio->bi_vcnt <= 0);
|
||||
|
||||
/*
|
||||
* the free space stuff is only read when it hasn't been
|
||||
* updated in the current transaction. So, we can safely
|
||||
* read from the commit root and sidestep a nasty deadlock
|
||||
* between reading the free space cache and updating the csum tree.
|
||||
*/
|
||||
if (btrfs_is_free_space_inode(root, inode))
|
||||
path->search_commit_root = 1;
|
||||
|
||||
disk_bytenr = (u64)bio->bi_sector << 9;
|
||||
if (dio)
|
||||
offset = logical_offset;
|
||||
|
|
|
@ -750,15 +750,6 @@ static u64 get_extent_allocation_hint(struct inode *inode, u64 start,
|
|||
return alloc_hint;
|
||||
}
|
||||
|
||||
static inline bool is_free_space_inode(struct btrfs_root *root,
|
||||
struct inode *inode)
|
||||
{
|
||||
if (root == root->fs_info->tree_root ||
|
||||
BTRFS_I(inode)->location.objectid == BTRFS_FREE_INO_OBJECTID)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* when extent_io.c finds a delayed allocation range in the file,
|
||||
* the call backs end up in this code. The basic idea is to
|
||||
|
@ -791,7 +782,7 @@ static noinline int cow_file_range(struct inode *inode,
|
|||
struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
|
||||
int ret = 0;
|
||||
|
||||
BUG_ON(is_free_space_inode(root, inode));
|
||||
BUG_ON(btrfs_is_free_space_inode(root, inode));
|
||||
trans = btrfs_join_transaction(root);
|
||||
BUG_ON(IS_ERR(trans));
|
||||
trans->block_rsv = &root->fs_info->delalloc_block_rsv;
|
||||
|
@ -1072,7 +1063,7 @@ static noinline int run_delalloc_nocow(struct inode *inode,
|
|||
path = btrfs_alloc_path();
|
||||
BUG_ON(!path);
|
||||
|
||||
nolock = is_free_space_inode(root, inode);
|
||||
nolock = btrfs_is_free_space_inode(root, inode);
|
||||
|
||||
if (nolock)
|
||||
trans = btrfs_join_transaction_nolock(root);
|
||||
|
@ -1341,7 +1332,7 @@ static int btrfs_set_bit_hook(struct inode *inode,
|
|||
if (!(state->state & EXTENT_DELALLOC) && (*bits & EXTENT_DELALLOC)) {
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
u64 len = state->end + 1 - state->start;
|
||||
bool do_list = !is_free_space_inode(root, inode);
|
||||
bool do_list = !btrfs_is_free_space_inode(root, inode);
|
||||
|
||||
if (*bits & EXTENT_FIRST_DELALLOC) {
|
||||
*bits &= ~EXTENT_FIRST_DELALLOC;
|
||||
|
@ -1377,7 +1368,7 @@ static int btrfs_clear_bit_hook(struct inode *inode,
|
|||
if ((state->state & EXTENT_DELALLOC) && (*bits & EXTENT_DELALLOC)) {
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
u64 len = state->end + 1 - state->start;
|
||||
bool do_list = !is_free_space_inode(root, inode);
|
||||
bool do_list = !btrfs_is_free_space_inode(root, inode);
|
||||
|
||||
if (*bits & EXTENT_FIRST_DELALLOC) {
|
||||
*bits &= ~EXTENT_FIRST_DELALLOC;
|
||||
|
@ -1487,7 +1478,7 @@ static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
|
|||
|
||||
skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
|
||||
|
||||
if (is_free_space_inode(root, inode))
|
||||
if (btrfs_is_free_space_inode(root, inode))
|
||||
ret = btrfs_bio_wq_end_io(root->fs_info, bio, 2);
|
||||
else
|
||||
ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
|
||||
|
@ -1736,7 +1727,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
|
|||
return 0;
|
||||
BUG_ON(!ordered_extent);
|
||||
|
||||
nolock = is_free_space_inode(root, inode);
|
||||
nolock = btrfs_is_free_space_inode(root, inode);
|
||||
|
||||
if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) {
|
||||
BUG_ON(!list_empty(&ordered_extent->list));
|
||||
|
@ -2670,7 +2661,7 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
|
|||
* The data relocation inode should also be directly updated
|
||||
* without delay
|
||||
*/
|
||||
if (!is_free_space_inode(root, inode)
|
||||
if (!btrfs_is_free_space_inode(root, inode)
|
||||
&& root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID) {
|
||||
ret = btrfs_delayed_update_inode(trans, root, inode);
|
||||
if (!ret)
|
||||
|
@ -3620,7 +3611,7 @@ void btrfs_evict_inode(struct inode *inode)
|
|||
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
if (inode->i_nlink && (btrfs_root_refs(&root->root_item) != 0 ||
|
||||
is_free_space_inode(root, inode)))
|
||||
btrfs_is_free_space_inode(root, inode)))
|
||||
goto no_delete;
|
||||
|
||||
if (is_bad_inode(inode)) {
|
||||
|
@ -4263,7 +4254,7 @@ int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc)
|
|||
if (BTRFS_I(inode)->dummy_inode)
|
||||
return 0;
|
||||
|
||||
if (btrfs_fs_closing(root->fs_info) && is_free_space_inode(root, inode))
|
||||
if (btrfs_fs_closing(root->fs_info) && btrfs_is_free_space_inode(root, inode))
|
||||
nolock = true;
|
||||
|
||||
if (wbc->sync_mode == WB_SYNC_ALL) {
|
||||
|
@ -6817,7 +6808,7 @@ int btrfs_drop_inode(struct inode *inode)
|
|||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
|
||||
if (btrfs_root_refs(&root->root_item) == 0 &&
|
||||
!is_free_space_inode(root, inode))
|
||||
!btrfs_is_free_space_inode(root, inode))
|
||||
return 1;
|
||||
else
|
||||
return generic_drop_inode(inode);
|
||||
|
|
Loading…
Reference in a new issue