|
@@ -1335,8 +1335,11 @@ next_slot:
|
|
leaf = path->nodes[0];
|
|
leaf = path->nodes[0];
|
|
if (path->slots[0] >= btrfs_header_nritems(leaf)) {
|
|
if (path->slots[0] >= btrfs_header_nritems(leaf)) {
|
|
ret = btrfs_next_leaf(root, path);
|
|
ret = btrfs_next_leaf(root, path);
|
|
- if (ret < 0)
|
|
|
|
|
|
+ if (ret < 0) {
|
|
|
|
+ if (cow_start != (u64)-1)
|
|
|
|
+ cur_offset = cow_start;
|
|
goto error;
|
|
goto error;
|
|
|
|
+ }
|
|
if (ret > 0)
|
|
if (ret > 0)
|
|
break;
|
|
break;
|
|
leaf = path->nodes[0];
|
|
leaf = path->nodes[0];
|
|
@@ -3385,6 +3388,11 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans,
|
|
ret = btrfs_orphan_reserve_metadata(trans, inode);
|
|
ret = btrfs_orphan_reserve_metadata(trans, inode);
|
|
ASSERT(!ret);
|
|
ASSERT(!ret);
|
|
if (ret) {
|
|
if (ret) {
|
|
|
|
+ /*
|
|
|
|
+ * dec doesn't need spin_lock as ->orphan_block_rsv
|
|
|
|
+ * would be released only if ->orphan_inodes is
|
|
|
|
+ * zero.
|
|
|
|
+ */
|
|
atomic_dec(&root->orphan_inodes);
|
|
atomic_dec(&root->orphan_inodes);
|
|
clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED,
|
|
clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED,
|
|
&inode->runtime_flags);
|
|
&inode->runtime_flags);
|
|
@@ -3399,12 +3407,17 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans,
|
|
if (insert >= 1) {
|
|
if (insert >= 1) {
|
|
ret = btrfs_insert_orphan_item(trans, root, btrfs_ino(inode));
|
|
ret = btrfs_insert_orphan_item(trans, root, btrfs_ino(inode));
|
|
if (ret) {
|
|
if (ret) {
|
|
- atomic_dec(&root->orphan_inodes);
|
|
|
|
if (reserve) {
|
|
if (reserve) {
|
|
clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED,
|
|
clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED,
|
|
&inode->runtime_flags);
|
|
&inode->runtime_flags);
|
|
btrfs_orphan_release_metadata(inode);
|
|
btrfs_orphan_release_metadata(inode);
|
|
}
|
|
}
|
|
|
|
+ /*
|
|
|
|
+ * btrfs_orphan_commit_root may race with us and set
|
|
|
|
+ * ->orphan_block_rsv to zero, in order to avoid that,
|
|
|
|
+ * decrease ->orphan_inodes after everything is done.
|
|
|
|
+ */
|
|
|
|
+ atomic_dec(&root->orphan_inodes);
|
|
if (ret != -EEXIST) {
|
|
if (ret != -EEXIST) {
|
|
clear_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,
|
|
clear_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,
|
|
&inode->runtime_flags);
|
|
&inode->runtime_flags);
|
|
@@ -3436,28 +3449,26 @@ static int btrfs_orphan_del(struct btrfs_trans_handle *trans,
|
|
{
|
|
{
|
|
struct btrfs_root *root = inode->root;
|
|
struct btrfs_root *root = inode->root;
|
|
int delete_item = 0;
|
|
int delete_item = 0;
|
|
- int release_rsv = 0;
|
|
|
|
int ret = 0;
|
|
int ret = 0;
|
|
|
|
|
|
- spin_lock(&root->orphan_lock);
|
|
|
|
if (test_and_clear_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,
|
|
if (test_and_clear_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,
|
|
&inode->runtime_flags))
|
|
&inode->runtime_flags))
|
|
delete_item = 1;
|
|
delete_item = 1;
|
|
|
|
|
|
|
|
+ if (delete_item && trans)
|
|
|
|
+ ret = btrfs_del_orphan_item(trans, root, btrfs_ino(inode));
|
|
|
|
+
|
|
if (test_and_clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED,
|
|
if (test_and_clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED,
|
|
&inode->runtime_flags))
|
|
&inode->runtime_flags))
|
|
- release_rsv = 1;
|
|
|
|
- spin_unlock(&root->orphan_lock);
|
|
|
|
|
|
+ btrfs_orphan_release_metadata(inode);
|
|
|
|
|
|
- if (delete_item) {
|
|
|
|
|
|
+ /*
|
|
|
|
+ * btrfs_orphan_commit_root may race with us and set ->orphan_block_rsv
|
|
|
|
+ * to zero, in order to avoid that, decrease ->orphan_inodes after
|
|
|
|
+ * everything is done.
|
|
|
|
+ */
|
|
|
|
+ if (delete_item)
|
|
atomic_dec(&root->orphan_inodes);
|
|
atomic_dec(&root->orphan_inodes);
|
|
- if (trans)
|
|
|
|
- ret = btrfs_del_orphan_item(trans, root,
|
|
|
|
- btrfs_ino(inode));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (release_rsv)
|
|
|
|
- btrfs_orphan_release_metadata(inode);
|
|
|
|
|
|
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
@@ -5281,7 +5292,7 @@ void btrfs_evict_inode(struct inode *inode)
|
|
trace_btrfs_inode_evict(inode);
|
|
trace_btrfs_inode_evict(inode);
|
|
|
|
|
|
if (!root) {
|
|
if (!root) {
|
|
- kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode));
|
|
|
|
|
|
+ clear_inode(inode);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|