aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/transaction.c
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2013-03-04 04:44:29 -0500
committerJosef Bacik <jbacik@fusionio.com>2013-03-04 16:33:22 -0500
commitaec8030a8745221c8658f2033b22c98528897b13 (patch)
tree58634fad399097dbde3d4969e498cb913a48aa96 /fs/btrfs/transaction.c
parent9bf7a4890518186238d2579be16ecc5190a707c0 (diff)
Btrfs: fix wrong handle at error path of create_snapshot() when the commit fails
There are several bugs at error path of create_snapshot() when the transaction commitment failed. - access the freed transaction handler. At the end of the transaction commitment, the transaction handler was freed, so we should not access it after the transaction commitment. - we were not aware of the error which happened during the snapshot creation if we submitted a async transaction commitment. - pending snapshot access vs pending snapshot free. when something wrong happened after we submitted a async transaction commitment, the transaction committer would cleanup the pending snapshots and free them. But the snapshot creators were not aware of it, they would access the freed pending snapshots. This patch fixes the above problems by: - remove the dangerous code that accessed the freed handler - assign ->error if the error happens during the snapshot creation - the transaction committer doesn't free the pending snapshots, just assigns the error number and evicts them before we unblock the transaction. Reported-by: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r--fs/btrfs/transaction.c58
1 files changed, 33 insertions, 25 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index f11c2e0a3746..d8fce6fe9cf8 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -1053,7 +1053,12 @@ int btrfs_defrag_root(struct btrfs_root *root)
1053 1053
1054/* 1054/*
1055 * new snapshots need to be created at a very specific time in the 1055 * new snapshots need to be created at a very specific time in the
1056 * transaction commit. This does the actual creation 1056 * transaction commit. This does the actual creation.
1057 *
1058 * Note:
1059 * If the error which may affect the commitment of the current transaction
1060 * happens, we should return the error number. If the error which just affect
1061 * the creation of the pending snapshots, just return 0.
1057 */ 1062 */
1058static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, 1063static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
1059 struct btrfs_fs_info *fs_info, 1064 struct btrfs_fs_info *fs_info,
@@ -1072,7 +1077,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
1072 struct extent_buffer *tmp; 1077 struct extent_buffer *tmp;
1073 struct extent_buffer *old; 1078 struct extent_buffer *old;
1074 struct timespec cur_time = CURRENT_TIME; 1079 struct timespec cur_time = CURRENT_TIME;
1075 int ret; 1080 int ret = 0;
1076 u64 to_reserve = 0; 1081 u64 to_reserve = 0;
1077 u64 index = 0; 1082 u64 index = 0;
1078 u64 objectid; 1083 u64 objectid;
@@ -1081,40 +1086,36 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
1081 1086
1082 path = btrfs_alloc_path(); 1087 path = btrfs_alloc_path();
1083 if (!path) { 1088 if (!path) {
1084 ret = pending->error = -ENOMEM; 1089 pending->error = -ENOMEM;
1085 return ret; 1090 return 0;
1086 } 1091 }
1087 1092
1088 new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); 1093 new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS);
1089 if (!new_root_item) { 1094 if (!new_root_item) {
1090 ret = pending->error = -ENOMEM; 1095 pending->error = -ENOMEM;
1091 goto root_item_alloc_fail; 1096 goto root_item_alloc_fail;
1092 } 1097 }
1093 1098
1094 ret = btrfs_find_free_objectid(tree_root, &objectid); 1099 pending->error = btrfs_find_free_objectid(tree_root, &objectid);
1095 if (ret) { 1100 if (pending->error)
1096 pending->error = ret;
1097 goto no_free_objectid; 1101 goto no_free_objectid;
1098 }
1099 1102
1100 btrfs_reloc_pre_snapshot(trans, pending, &to_reserve); 1103 btrfs_reloc_pre_snapshot(trans, pending, &to_reserve);
1101 1104
1102 if (to_reserve > 0) { 1105 if (to_reserve > 0) {
1103 ret = btrfs_block_rsv_add(root, &pending->block_rsv, 1106 pending->error = btrfs_block_rsv_add(root,
1104 to_reserve, 1107 &pending->block_rsv,
1105 BTRFS_RESERVE_NO_FLUSH); 1108 to_reserve,
1106 if (ret) { 1109 BTRFS_RESERVE_NO_FLUSH);
1107 pending->error = ret; 1110 if (pending->error)
1108 goto no_free_objectid; 1111 goto no_free_objectid;
1109 }
1110 } 1112 }
1111 1113
1112 ret = btrfs_qgroup_inherit(trans, fs_info, root->root_key.objectid, 1114 pending->error = btrfs_qgroup_inherit(trans, fs_info,
1113 objectid, pending->inherit); 1115 root->root_key.objectid,
1114 if (ret) { 1116 objectid, pending->inherit);
1115 pending->error = ret; 1117 if (pending->error)
1116 goto no_free_objectid; 1118 goto no_free_objectid;
1117 }
1118 1119
1119 key.objectid = objectid; 1120 key.objectid = objectid;
1120 key.offset = (u64)-1; 1121 key.offset = (u64)-1;
@@ -1142,7 +1143,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
1142 dentry->d_name.len, 0); 1143 dentry->d_name.len, 0);
1143 if (dir_item != NULL && !IS_ERR(dir_item)) { 1144 if (dir_item != NULL && !IS_ERR(dir_item)) {
1144 pending->error = -EEXIST; 1145 pending->error = -EEXIST;
1145 goto fail; 1146 goto dir_item_existed;
1146 } else if (IS_ERR(dir_item)) { 1147 } else if (IS_ERR(dir_item)) {
1147 ret = PTR_ERR(dir_item); 1148 ret = PTR_ERR(dir_item);
1148 btrfs_abort_transaction(trans, root, ret); 1149 btrfs_abort_transaction(trans, root, ret);
@@ -1273,6 +1274,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
1273 if (ret) 1274 if (ret)
1274 btrfs_abort_transaction(trans, root, ret); 1275 btrfs_abort_transaction(trans, root, ret);
1275fail: 1276fail:
1277 pending->error = ret;
1278dir_item_existed:
1276 trans->block_rsv = rsv; 1279 trans->block_rsv = rsv;
1277 trans->bytes_reserved = 0; 1280 trans->bytes_reserved = 0;
1278no_free_objectid: 1281no_free_objectid:
@@ -1288,12 +1291,17 @@ root_item_alloc_fail:
1288static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans, 1291static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans,
1289 struct btrfs_fs_info *fs_info) 1292 struct btrfs_fs_info *fs_info)
1290{ 1293{
1291 struct btrfs_pending_snapshot *pending; 1294 struct btrfs_pending_snapshot *pending, *next;
1292 struct list_head *head = &trans->transaction->pending_snapshots; 1295 struct list_head *head = &trans->transaction->pending_snapshots;
1296 int ret = 0;
1293 1297
1294 list_for_each_entry(pending, head, list) 1298 list_for_each_entry_safe(pending, next, head, list) {
1295 create_pending_snapshot(trans, fs_info, pending); 1299 list_del(&pending->list);
1296 return 0; 1300 ret = create_pending_snapshot(trans, fs_info, pending);
1301 if (ret)
1302 break;
1303 }
1304 return ret;
1297} 1305}
1298 1306
1299static void update_super_roots(struct btrfs_root *root) 1307static void update_super_roots(struct btrfs_root *root)