diff options
author | Miao Xie <miaox@cn.fujitsu.com> | 2012-09-06 06:00:32 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@fusionio.com> | 2012-10-01 15:19:09 -0400 |
commit | 6fa9700e734275de2acbcb0e99414bd7ddfc60f1 (patch) | |
tree | 97c65df04e339c42b0255d1058f9ef2c73ec857a /fs/btrfs/transaction.c | |
parent | cf93dccea67ad8f5e0d9163c6a0a584550bbd7cd (diff) |
Btrfs: fix error path in create_pending_snapshot()
This patch fixes the following problem:
- If we failed to deal with the delayed dir items, we should abort transaction,
just as its comment said. Fix it.
- If root reference or root back reference insertion failed, we should
abort transaction. Fix it.
- Fix the double free problem of pending->inherit.
- Do not restore the trans->rsv if we doesn't change it.
- make the error path more clearly.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r-- | fs/btrfs/transaction.c | 40 |
1 files changed, 17 insertions, 23 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index ffc6b5202d5..7be03185327 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -967,18 +967,16 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
967 | u64 root_flags; | 967 | u64 root_flags; |
968 | uuid_le new_uuid; | 968 | uuid_le new_uuid; |
969 | 969 | ||
970 | rsv = trans->block_rsv; | ||
971 | |||
972 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); | 970 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); |
973 | if (!new_root_item) { | 971 | if (!new_root_item) { |
974 | ret = pending->error = -ENOMEM; | 972 | ret = pending->error = -ENOMEM; |
975 | goto fail; | 973 | goto root_item_alloc_fail; |
976 | } | 974 | } |
977 | 975 | ||
978 | ret = btrfs_find_free_objectid(tree_root, &objectid); | 976 | ret = btrfs_find_free_objectid(tree_root, &objectid); |
979 | if (ret) { | 977 | if (ret) { |
980 | pending->error = ret; | 978 | pending->error = ret; |
981 | goto fail; | 979 | goto no_free_objectid; |
982 | } | 980 | } |
983 | 981 | ||
984 | btrfs_reloc_pre_snapshot(trans, pending, &to_reserve); | 982 | btrfs_reloc_pre_snapshot(trans, pending, &to_reserve); |
@@ -988,22 +986,22 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
988 | to_reserve); | 986 | to_reserve); |
989 | if (ret) { | 987 | if (ret) { |
990 | pending->error = ret; | 988 | pending->error = ret; |
991 | goto fail; | 989 | goto no_free_objectid; |
992 | } | 990 | } |
993 | } | 991 | } |
994 | 992 | ||
995 | ret = btrfs_qgroup_inherit(trans, fs_info, root->root_key.objectid, | 993 | ret = btrfs_qgroup_inherit(trans, fs_info, root->root_key.objectid, |
996 | objectid, pending->inherit); | 994 | objectid, pending->inherit); |
997 | kfree(pending->inherit); | ||
998 | if (ret) { | 995 | if (ret) { |
999 | pending->error = ret; | 996 | pending->error = ret; |
1000 | goto fail; | 997 | goto no_free_objectid; |
1001 | } | 998 | } |
1002 | 999 | ||
1003 | key.objectid = objectid; | 1000 | key.objectid = objectid; |
1004 | key.offset = (u64)-1; | 1001 | key.offset = (u64)-1; |
1005 | key.type = BTRFS_ROOT_ITEM_KEY; | 1002 | key.type = BTRFS_ROOT_ITEM_KEY; |
1006 | 1003 | ||
1004 | rsv = trans->block_rsv; | ||
1007 | trans->block_rsv = &pending->block_rsv; | 1005 | trans->block_rsv = &pending->block_rsv; |
1008 | 1006 | ||
1009 | dentry = pending->dentry; | 1007 | dentry = pending->dentry; |
@@ -1023,10 +1021,9 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
1023 | BTRFS_FT_DIR, index); | 1021 | BTRFS_FT_DIR, index); |
1024 | if (ret == -EEXIST) { | 1022 | if (ret == -EEXIST) { |
1025 | pending->error = -EEXIST; | 1023 | pending->error = -EEXIST; |
1026 | dput(parent); | ||
1027 | goto fail; | 1024 | goto fail; |
1028 | } else if (ret) { | 1025 | } else if (ret) { |
1029 | goto abort_trans_dput; | 1026 | goto abort_trans; |
1030 | } | 1027 | } |
1031 | 1028 | ||
1032 | btrfs_i_size_write(parent_inode, parent_inode->i_size + | 1029 | btrfs_i_size_write(parent_inode, parent_inode->i_size + |
@@ -1034,7 +1031,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
1034 | parent_inode->i_mtime = parent_inode->i_ctime = CURRENT_TIME; | 1031 | parent_inode->i_mtime = parent_inode->i_ctime = CURRENT_TIME; |
1035 | ret = btrfs_update_inode(trans, parent_root, parent_inode); | 1032 | ret = btrfs_update_inode(trans, parent_root, parent_inode); |
1036 | if (ret) | 1033 | if (ret) |
1037 | goto abort_trans_dput; | 1034 | goto abort_trans; |
1038 | 1035 | ||
1039 | /* | 1036 | /* |
1040 | * pull in the delayed directory update | 1037 | * pull in the delayed directory update |
@@ -1043,10 +1040,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
1043 | * snapshot | 1040 | * snapshot |
1044 | */ | 1041 | */ |
1045 | ret = btrfs_run_delayed_items(trans, root); | 1042 | ret = btrfs_run_delayed_items(trans, root); |
1046 | if (ret) { /* Transaction aborted */ | 1043 | if (ret) /* Transaction aborted */ |
1047 | dput(parent); | 1044 | goto abort_trans; |
1048 | goto fail; | ||
1049 | } | ||
1050 | 1045 | ||
1051 | record_root_in_trans(trans, root); | 1046 | record_root_in_trans(trans, root); |
1052 | btrfs_set_root_last_snapshot(&root->root_item, trans->transid); | 1047 | btrfs_set_root_last_snapshot(&root->root_item, trans->transid); |
@@ -1079,7 +1074,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
1079 | if (ret) { | 1074 | if (ret) { |
1080 | btrfs_tree_unlock(old); | 1075 | btrfs_tree_unlock(old); |
1081 | free_extent_buffer(old); | 1076 | free_extent_buffer(old); |
1082 | goto abort_trans_dput; | 1077 | goto abort_trans; |
1083 | } | 1078 | } |
1084 | 1079 | ||
1085 | btrfs_set_lock_blocking(old); | 1080 | btrfs_set_lock_blocking(old); |
@@ -1089,7 +1084,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
1089 | btrfs_tree_unlock(old); | 1084 | btrfs_tree_unlock(old); |
1090 | free_extent_buffer(old); | 1085 | free_extent_buffer(old); |
1091 | if (ret) | 1086 | if (ret) |
1092 | goto abort_trans_dput; | 1087 | goto abort_trans; |
1093 | 1088 | ||
1094 | /* see comments in should_cow_block() */ | 1089 | /* see comments in should_cow_block() */ |
1095 | root->force_cow = 1; | 1090 | root->force_cow = 1; |
@@ -1102,7 +1097,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
1102 | btrfs_tree_unlock(tmp); | 1097 | btrfs_tree_unlock(tmp); |
1103 | free_extent_buffer(tmp); | 1098 | free_extent_buffer(tmp); |
1104 | if (ret) | 1099 | if (ret) |
1105 | goto abort_trans_dput; | 1100 | goto abort_trans; |
1106 | 1101 | ||
1107 | /* | 1102 | /* |
1108 | * insert root back/forward references | 1103 | * insert root back/forward references |
@@ -1111,9 +1106,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
1111 | parent_root->root_key.objectid, | 1106 | parent_root->root_key.objectid, |
1112 | btrfs_ino(parent_inode), index, | 1107 | btrfs_ino(parent_inode), index, |
1113 | dentry->d_name.name, dentry->d_name.len); | 1108 | dentry->d_name.name, dentry->d_name.len); |
1114 | dput(parent); | ||
1115 | if (ret) | 1109 | if (ret) |
1116 | goto fail; | 1110 | goto abort_trans; |
1117 | 1111 | ||
1118 | key.offset = (u64)-1; | 1112 | key.offset = (u64)-1; |
1119 | pending->snap = btrfs_read_fs_root_no_name(root->fs_info, &key); | 1113 | pending->snap = btrfs_read_fs_root_no_name(root->fs_info, &key); |
@@ -1125,15 +1119,15 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
1125 | ret = btrfs_reloc_post_snapshot(trans, pending); | 1119 | ret = btrfs_reloc_post_snapshot(trans, pending); |
1126 | if (ret) | 1120 | if (ret) |
1127 | goto abort_trans; | 1121 | goto abort_trans; |
1128 | ret = 0; | ||
1129 | fail: | 1122 | fail: |
1130 | kfree(new_root_item); | 1123 | dput(parent); |
1131 | trans->block_rsv = rsv; | 1124 | trans->block_rsv = rsv; |
1125 | no_free_objectid: | ||
1126 | kfree(new_root_item); | ||
1127 | root_item_alloc_fail: | ||
1132 | btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1); | 1128 | btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1); |
1133 | return ret; | 1129 | return ret; |
1134 | 1130 | ||
1135 | abort_trans_dput: | ||
1136 | dput(parent); | ||
1137 | abort_trans: | 1131 | abort_trans: |
1138 | btrfs_abort_transaction(trans, root, ret); | 1132 | btrfs_abort_transaction(trans, root, ret); |
1139 | goto fail; | 1133 | goto fail; |