diff options
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r-- | fs/btrfs/transaction.c | 65 |
1 files changed, 40 insertions, 25 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index f11c2e0a3746..fedede1fe178 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 | */ |
1058 | static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | 1063 | static 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); |
1275 | fail: | 1276 | fail: |
1277 | pending->error = ret; | ||
1278 | dir_item_existed: | ||
1276 | trans->block_rsv = rsv; | 1279 | trans->block_rsv = rsv; |
1277 | trans->bytes_reserved = 0; | 1280 | trans->bytes_reserved = 0; |
1278 | no_free_objectid: | 1281 | no_free_objectid: |
@@ -1288,12 +1291,17 @@ root_item_alloc_fail: | |||
1288 | static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans, | 1291 | static 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 | ||
1299 | static void update_super_roots(struct btrfs_root *root) | 1307 | static void update_super_roots(struct btrfs_root *root) |
@@ -1449,6 +1457,13 @@ static void cleanup_transaction(struct btrfs_trans_handle *trans, | |||
1449 | btrfs_abort_transaction(trans, root, err); | 1457 | btrfs_abort_transaction(trans, root, err); |
1450 | 1458 | ||
1451 | spin_lock(&root->fs_info->trans_lock); | 1459 | spin_lock(&root->fs_info->trans_lock); |
1460 | |||
1461 | if (list_empty(&cur_trans->list)) { | ||
1462 | spin_unlock(&root->fs_info->trans_lock); | ||
1463 | btrfs_end_transaction(trans, root); | ||
1464 | return; | ||
1465 | } | ||
1466 | |||
1452 | list_del_init(&cur_trans->list); | 1467 | list_del_init(&cur_trans->list); |
1453 | if (cur_trans == root->fs_info->running_transaction) { | 1468 | if (cur_trans == root->fs_info->running_transaction) { |
1454 | root->fs_info->trans_no_join = 1; | 1469 | root->fs_info->trans_no_join = 1; |