diff options
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r-- | fs/btrfs/transaction.c | 76 |
1 files changed, 45 insertions, 31 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index e52da6fb1165..50767bbaad6c 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -625,14 +625,13 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
625 | 625 | ||
626 | btrfs_trans_release_metadata(trans, root); | 626 | btrfs_trans_release_metadata(trans, root); |
627 | trans->block_rsv = NULL; | 627 | trans->block_rsv = NULL; |
628 | /* | ||
629 | * the same root has to be passed to start_transaction and | ||
630 | * end_transaction. Subvolume quota depends on this. | ||
631 | */ | ||
632 | WARN_ON(trans->root != root); | ||
633 | 628 | ||
634 | if (trans->qgroup_reserved) { | 629 | if (trans->qgroup_reserved) { |
635 | btrfs_qgroup_free(root, trans->qgroup_reserved); | 630 | /* |
631 | * the same root has to be passed here between start_transaction | ||
632 | * and end_transaction. Subvolume quota depends on this. | ||
633 | */ | ||
634 | btrfs_qgroup_free(trans->root, trans->qgroup_reserved); | ||
636 | trans->qgroup_reserved = 0; | 635 | trans->qgroup_reserved = 0; |
637 | } | 636 | } |
638 | 637 | ||
@@ -1052,7 +1051,12 @@ int btrfs_defrag_root(struct btrfs_root *root) | |||
1052 | 1051 | ||
1053 | /* | 1052 | /* |
1054 | * new snapshots need to be created at a very specific time in the | 1053 | * new snapshots need to be created at a very specific time in the |
1055 | * transaction commit. This does the actual creation | 1054 | * transaction commit. This does the actual creation. |
1055 | * | ||
1056 | * Note: | ||
1057 | * If the error which may affect the commitment of the current transaction | ||
1058 | * happens, we should return the error number. If the error which just affect | ||
1059 | * the creation of the pending snapshots, just return 0. | ||
1056 | */ | 1060 | */ |
1057 | static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | 1061 | static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, |
1058 | struct btrfs_fs_info *fs_info, | 1062 | struct btrfs_fs_info *fs_info, |
@@ -1071,7 +1075,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
1071 | struct extent_buffer *tmp; | 1075 | struct extent_buffer *tmp; |
1072 | struct extent_buffer *old; | 1076 | struct extent_buffer *old; |
1073 | struct timespec cur_time = CURRENT_TIME; | 1077 | struct timespec cur_time = CURRENT_TIME; |
1074 | int ret; | 1078 | int ret = 0; |
1075 | u64 to_reserve = 0; | 1079 | u64 to_reserve = 0; |
1076 | u64 index = 0; | 1080 | u64 index = 0; |
1077 | u64 objectid; | 1081 | u64 objectid; |
@@ -1080,40 +1084,36 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
1080 | 1084 | ||
1081 | path = btrfs_alloc_path(); | 1085 | path = btrfs_alloc_path(); |
1082 | if (!path) { | 1086 | if (!path) { |
1083 | ret = pending->error = -ENOMEM; | 1087 | pending->error = -ENOMEM; |
1084 | return ret; | 1088 | return 0; |
1085 | } | 1089 | } |
1086 | 1090 | ||
1087 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); | 1091 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); |
1088 | if (!new_root_item) { | 1092 | if (!new_root_item) { |
1089 | ret = pending->error = -ENOMEM; | 1093 | pending->error = -ENOMEM; |
1090 | goto root_item_alloc_fail; | 1094 | goto root_item_alloc_fail; |
1091 | } | 1095 | } |
1092 | 1096 | ||
1093 | ret = btrfs_find_free_objectid(tree_root, &objectid); | 1097 | pending->error = btrfs_find_free_objectid(tree_root, &objectid); |
1094 | if (ret) { | 1098 | if (pending->error) |
1095 | pending->error = ret; | ||
1096 | goto no_free_objectid; | 1099 | goto no_free_objectid; |
1097 | } | ||
1098 | 1100 | ||
1099 | btrfs_reloc_pre_snapshot(trans, pending, &to_reserve); | 1101 | btrfs_reloc_pre_snapshot(trans, pending, &to_reserve); |
1100 | 1102 | ||
1101 | if (to_reserve > 0) { | 1103 | if (to_reserve > 0) { |
1102 | ret = btrfs_block_rsv_add(root, &pending->block_rsv, | 1104 | pending->error = btrfs_block_rsv_add(root, |
1103 | to_reserve, | 1105 | &pending->block_rsv, |
1104 | BTRFS_RESERVE_NO_FLUSH); | 1106 | to_reserve, |
1105 | if (ret) { | 1107 | BTRFS_RESERVE_NO_FLUSH); |
1106 | pending->error = ret; | 1108 | if (pending->error) |
1107 | goto no_free_objectid; | 1109 | goto no_free_objectid; |
1108 | } | ||
1109 | } | 1110 | } |
1110 | 1111 | ||
1111 | ret = btrfs_qgroup_inherit(trans, fs_info, root->root_key.objectid, | 1112 | pending->error = btrfs_qgroup_inherit(trans, fs_info, |
1112 | objectid, pending->inherit); | 1113 | root->root_key.objectid, |
1113 | if (ret) { | 1114 | objectid, pending->inherit); |
1114 | pending->error = ret; | 1115 | if (pending->error) |
1115 | goto no_free_objectid; | 1116 | goto no_free_objectid; |
1116 | } | ||
1117 | 1117 | ||
1118 | key.objectid = objectid; | 1118 | key.objectid = objectid; |
1119 | key.offset = (u64)-1; | 1119 | key.offset = (u64)-1; |
@@ -1141,7 +1141,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
1141 | dentry->d_name.len, 0); | 1141 | dentry->d_name.len, 0); |
1142 | if (dir_item != NULL && !IS_ERR(dir_item)) { | 1142 | if (dir_item != NULL && !IS_ERR(dir_item)) { |
1143 | pending->error = -EEXIST; | 1143 | pending->error = -EEXIST; |
1144 | goto fail; | 1144 | goto dir_item_existed; |
1145 | } else if (IS_ERR(dir_item)) { | 1145 | } else if (IS_ERR(dir_item)) { |
1146 | ret = PTR_ERR(dir_item); | 1146 | ret = PTR_ERR(dir_item); |
1147 | btrfs_abort_transaction(trans, root, ret); | 1147 | btrfs_abort_transaction(trans, root, ret); |
@@ -1272,6 +1272,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
1272 | if (ret) | 1272 | if (ret) |
1273 | btrfs_abort_transaction(trans, root, ret); | 1273 | btrfs_abort_transaction(trans, root, ret); |
1274 | fail: | 1274 | fail: |
1275 | pending->error = ret; | ||
1276 | dir_item_existed: | ||
1275 | trans->block_rsv = rsv; | 1277 | trans->block_rsv = rsv; |
1276 | trans->bytes_reserved = 0; | 1278 | trans->bytes_reserved = 0; |
1277 | no_free_objectid: | 1279 | no_free_objectid: |
@@ -1287,12 +1289,17 @@ root_item_alloc_fail: | |||
1287 | static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans, | 1289 | static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans, |
1288 | struct btrfs_fs_info *fs_info) | 1290 | struct btrfs_fs_info *fs_info) |
1289 | { | 1291 | { |
1290 | struct btrfs_pending_snapshot *pending; | 1292 | struct btrfs_pending_snapshot *pending, *next; |
1291 | struct list_head *head = &trans->transaction->pending_snapshots; | 1293 | struct list_head *head = &trans->transaction->pending_snapshots; |
1294 | int ret = 0; | ||
1292 | 1295 | ||
1293 | list_for_each_entry(pending, head, list) | 1296 | list_for_each_entry_safe(pending, next, head, list) { |
1294 | create_pending_snapshot(trans, fs_info, pending); | 1297 | list_del(&pending->list); |
1295 | return 0; | 1298 | ret = create_pending_snapshot(trans, fs_info, pending); |
1299 | if (ret) | ||
1300 | break; | ||
1301 | } | ||
1302 | return ret; | ||
1296 | } | 1303 | } |
1297 | 1304 | ||
1298 | static void update_super_roots(struct btrfs_root *root) | 1305 | static void update_super_roots(struct btrfs_root *root) |
@@ -1448,6 +1455,13 @@ static void cleanup_transaction(struct btrfs_trans_handle *trans, | |||
1448 | btrfs_abort_transaction(trans, root, err); | 1455 | btrfs_abort_transaction(trans, root, err); |
1449 | 1456 | ||
1450 | spin_lock(&root->fs_info->trans_lock); | 1457 | spin_lock(&root->fs_info->trans_lock); |
1458 | |||
1459 | if (list_empty(&cur_trans->list)) { | ||
1460 | spin_unlock(&root->fs_info->trans_lock); | ||
1461 | btrfs_end_transaction(trans, root); | ||
1462 | return; | ||
1463 | } | ||
1464 | |||
1451 | list_del_init(&cur_trans->list); | 1465 | list_del_init(&cur_trans->list); |
1452 | if (cur_trans == root->fs_info->running_transaction) { | 1466 | if (cur_trans == root->fs_info->running_transaction) { |
1453 | root->fs_info->trans_no_join = 1; | 1467 | root->fs_info->trans_no_join = 1; |