|
@@ -93,6 +93,8 @@ static noinline int cow_file_range(struct inode *inode,
|
|
|
struct page *locked_page,
|
|
|
u64 start, u64 end, int *page_started,
|
|
|
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,
|
|
|
struct inode *inode, struct inode *dir,
|
|
@@ -1741,7 +1743,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
|
|
|
trans = btrfs_join_transaction(root);
|
|
|
BUG_ON(IS_ERR(trans));
|
|
|
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);
|
|
|
}
|
|
|
goto out;
|
|
@@ -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);
|
|
|
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);
|
|
|
}
|
|
|
ret = 0;
|
|
@@ -2199,6 +2201,9 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
|
|
|
if (ret)
|
|
|
goto out;
|
|
|
}
|
|
|
+ /* release the path since we're done with it */
|
|
|
+ btrfs_release_path(path);
|
|
|
+
|
|
|
root->orphan_cleanup_state = ORPHAN_CLEANUP_DONE;
|
|
|
|
|
|
if (root->orphan_block_rsv)
|
|
@@ -2426,7 +2431,7 @@ static void fill_inode_item(struct btrfs_trans_handle *trans,
|
|
|
/*
|
|
|
* 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_inode_item *inode_item;
|
|
@@ -2434,21 +2439,6 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
|
|
|
struct extent_buffer *leaf;
|
|
|
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();
|
|
|
if (!path)
|
|
|
return -ENOMEM;
|
|
@@ -2476,6 +2466,43 @@ failed:
|
|
|
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
|
|
|
* recovery code. It remove a link in a directory with a given name, and
|
|
@@ -5632,7 +5659,7 @@ again:
|
|
|
if (test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags)) {
|
|
|
ret = btrfs_ordered_update_i_size(inode, 0, ordered);
|
|
|
if (!ret)
|
|
|
- err = btrfs_update_inode(trans, root, inode);
|
|
|
+ err = btrfs_update_inode_fallback(trans, root, inode);
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
@@ -5670,7 +5697,7 @@ again:
|
|
|
add_pending_csums(trans, inode, ordered->file_offset, &ordered->list);
|
|
|
ret = btrfs_ordered_update_i_size(inode, 0, ordered);
|
|
|
if (!ret || !test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags))
|
|
|
- btrfs_update_inode(trans, root, inode);
|
|
|
+ btrfs_update_inode_fallback(trans, root, inode);
|
|
|
ret = 0;
|
|
|
out_unlock:
|
|
|
unlock_extent_cached(&BTRFS_I(inode)->io_tree, ordered->file_offset,
|
|
@@ -6529,14 +6556,16 @@ end_trans:
|
|
|
ret = btrfs_orphan_del(NULL, inode);
|
|
|
}
|
|
|
|
|
|
- trans->block_rsv = &root->fs_info->trans_block_rsv;
|
|
|
- ret = btrfs_update_inode(trans, root, inode);
|
|
|
- if (ret && !err)
|
|
|
- err = ret;
|
|
|
+ if (trans) {
|
|
|
+ trans->block_rsv = &root->fs_info->trans_block_rsv;
|
|
|
+ ret = btrfs_update_inode(trans, root, inode);
|
|
|
+ if (ret && !err)
|
|
|
+ err = ret;
|
|
|
|
|
|
- nr = trans->blocks_used;
|
|
|
- ret = btrfs_end_transaction_throttle(trans, root);
|
|
|
- btrfs_btree_balance_dirty(root, nr);
|
|
|
+ nr = trans->blocks_used;
|
|
|
+ ret = btrfs_end_transaction_throttle(trans, root);
|
|
|
+ btrfs_btree_balance_dirty(root, nr);
|
|
|
+ }
|
|
|
|
|
|
out:
|
|
|
btrfs_free_block_rsv(root, rsv);
|
|
@@ -6605,6 +6634,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
|
|
|
ei->orphan_meta_reserved = 0;
|
|
|
ei->dummy_inode = 0;
|
|
|
ei->in_defrag = 0;
|
|
|
+ ei->delalloc_meta_reserved = 0;
|
|
|
ei->force_compress = BTRFS_COMPRESS_NONE;
|
|
|
|
|
|
ei->delayed_node = NULL;
|