Commit 2115133f authored by Chris Mason's avatar Chris Mason

Btrfs: tweak the delayed inode reservations again

Josef sent along an incremental to the inode reservation
code to make sure we try and fall back to directly updating
the inode item if things go horribly wrong.

This reworks that patch slightly, adding a fallback function
that will always try to update the inode item directly without
going through the delayed_inode code.
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 7fd2ae21
...@@ -692,11 +692,6 @@ static int btrfs_delayed_inode_reserve_metadata( ...@@ -692,11 +692,6 @@ static int btrfs_delayed_inode_reserve_metadata(
migrate: migrate:
ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes); ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes);
if (unlikely(ret)) {
/* This shouldn't happen */
BUG_ON(release);
return ret;
}
out: out:
/* /*
...@@ -712,9 +707,11 @@ static int btrfs_delayed_inode_reserve_metadata( ...@@ -712,9 +707,11 @@ static int btrfs_delayed_inode_reserve_metadata(
* reservation here. I think it may be time for a documentation page on * reservation here. I think it may be time for a documentation page on
* how block rsvs. work. * how block rsvs. work.
*/ */
if (!ret)
node->bytes_reserved = num_bytes;
if (release) if (release)
btrfs_block_rsv_release(root, src_rsv, num_bytes); btrfs_block_rsv_release(root, src_rsv, num_bytes);
node->bytes_reserved = num_bytes;
return ret; return ret;
} }
......
...@@ -93,6 +93,8 @@ static noinline int cow_file_range(struct inode *inode, ...@@ -93,6 +93,8 @@ static noinline int cow_file_range(struct inode *inode,
struct page *locked_page, struct page *locked_page,
u64 start, u64 end, int *page_started, u64 start, u64 end, int *page_started,
unsigned long *nr_written, int unlock); unsigned long *nr_written, int unlock);
static noinline int btrfs_update_inode_fallback(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct inode *inode);
static int btrfs_init_inode_security(struct btrfs_trans_handle *trans, static int btrfs_init_inode_security(struct btrfs_trans_handle *trans,
struct inode *inode, struct inode *dir, struct inode *inode, struct inode *dir,
...@@ -1741,7 +1743,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) ...@@ -1741,7 +1743,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
trans = btrfs_join_transaction(root); trans = btrfs_join_transaction(root);
BUG_ON(IS_ERR(trans)); BUG_ON(IS_ERR(trans));
trans->block_rsv = &root->fs_info->delalloc_block_rsv; trans->block_rsv = &root->fs_info->delalloc_block_rsv;
ret = btrfs_update_inode(trans, root, inode); ret = btrfs_update_inode_fallback(trans, root, inode);
BUG_ON(ret); BUG_ON(ret);
} }
goto out; goto out;
...@@ -1791,7 +1793,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) ...@@ -1791,7 +1793,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent); ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent);
if (!ret || !test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) { if (!ret || !test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) {
ret = btrfs_update_inode(trans, root, inode); ret = btrfs_update_inode_fallback(trans, root, inode);
BUG_ON(ret); BUG_ON(ret);
} }
ret = 0; ret = 0;
...@@ -2426,7 +2428,7 @@ static void fill_inode_item(struct btrfs_trans_handle *trans, ...@@ -2426,7 +2428,7 @@ static void fill_inode_item(struct btrfs_trans_handle *trans,
/* /*
* copy everything in the in-memory inode into the btree. * copy everything in the in-memory inode into the btree.
*/ */
noinline int btrfs_update_inode(struct btrfs_trans_handle *trans, static noinline int btrfs_update_inode_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct inode *inode) struct btrfs_root *root, struct inode *inode)
{ {
struct btrfs_inode_item *inode_item; struct btrfs_inode_item *inode_item;
...@@ -2434,21 +2436,6 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans, ...@@ -2434,21 +2436,6 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
struct extent_buffer *leaf; struct extent_buffer *leaf;
int ret; int ret;
/*
* If the inode is a free space inode, we can deadlock during commit
* if we put it into the delayed code.
*
* The data relocation inode should also be directly updated
* without delay
*/
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)
btrfs_set_inode_last_trans(trans, inode);
return ret;
}
path = btrfs_alloc_path(); path = btrfs_alloc_path();
if (!path) if (!path)
return -ENOMEM; return -ENOMEM;
...@@ -2476,6 +2463,43 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans, ...@@ -2476,6 +2463,43 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
return ret; return ret;
} }
/*
* copy everything in the in-memory inode into the btree.
*/
noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct inode *inode)
{
int ret;
/*
* If the inode is a free space inode, we can deadlock during commit
* if we put it into the delayed code.
*
* The data relocation inode should also be directly updated
* without delay
*/
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)
btrfs_set_inode_last_trans(trans, inode);
return ret;
}
return btrfs_update_inode_item(trans, root, inode);
}
static noinline int btrfs_update_inode_fallback(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct inode *inode)
{
int ret;
ret = btrfs_update_inode(trans, root, inode);
if (ret == -ENOSPC)
return btrfs_update_inode_item(trans, root, inode);
return ret;
}
/* /*
* unlink helper that gets used here in inode.c and in the tree logging * unlink helper that gets used here in inode.c and in the tree logging
* recovery code. It remove a link in a directory with a given name, and * recovery code. It remove a link in a directory with a given name, and
...@@ -5632,7 +5656,7 @@ static void btrfs_endio_direct_write(struct bio *bio, int err) ...@@ -5632,7 +5656,7 @@ static void btrfs_endio_direct_write(struct bio *bio, int err)
if (test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags)) { if (test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags)) {
ret = btrfs_ordered_update_i_size(inode, 0, ordered); ret = btrfs_ordered_update_i_size(inode, 0, ordered);
if (!ret) if (!ret)
err = btrfs_update_inode(trans, root, inode); err = btrfs_update_inode_fallback(trans, root, inode);
goto out; goto out;
} }
...@@ -5670,7 +5694,7 @@ static void btrfs_endio_direct_write(struct bio *bio, int err) ...@@ -5670,7 +5694,7 @@ static void btrfs_endio_direct_write(struct bio *bio, int err)
add_pending_csums(trans, inode, ordered->file_offset, &ordered->list); add_pending_csums(trans, inode, ordered->file_offset, &ordered->list);
ret = btrfs_ordered_update_i_size(inode, 0, ordered); ret = btrfs_ordered_update_i_size(inode, 0, ordered);
if (!ret || !test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags)) if (!ret || !test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags))
btrfs_update_inode(trans, root, inode); btrfs_update_inode_fallback(trans, root, inode);
ret = 0; ret = 0;
out_unlock: out_unlock:
unlock_extent_cached(&BTRFS_I(inode)->io_tree, ordered->file_offset, unlock_extent_cached(&BTRFS_I(inode)->io_tree, ordered->file_offset,
......
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