0001
0002
0003
0004
0005
0006 #include <linux/types.h>
0007 #include "btrfs-tests.h"
0008 #include "../ctree.h"
0009 #include "../transaction.h"
0010 #include "../disk-io.h"
0011 #include "../qgroup.h"
0012 #include "../backref.h"
0013
0014 static int insert_normal_tree_ref(struct btrfs_root *root, u64 bytenr,
0015 u64 num_bytes, u64 parent, u64 root_objectid)
0016 {
0017 struct btrfs_trans_handle trans;
0018 struct btrfs_extent_item *item;
0019 struct btrfs_extent_inline_ref *iref;
0020 struct btrfs_tree_block_info *block_info;
0021 struct btrfs_path *path;
0022 struct extent_buffer *leaf;
0023 struct btrfs_key ins;
0024 u32 size = sizeof(*item) + sizeof(*iref) + sizeof(*block_info);
0025 int ret;
0026
0027 btrfs_init_dummy_trans(&trans, NULL);
0028
0029 ins.objectid = bytenr;
0030 ins.type = BTRFS_EXTENT_ITEM_KEY;
0031 ins.offset = num_bytes;
0032
0033 path = btrfs_alloc_path();
0034 if (!path) {
0035 test_std_err(TEST_ALLOC_ROOT);
0036 return -ENOMEM;
0037 }
0038
0039 ret = btrfs_insert_empty_item(&trans, root, path, &ins, size);
0040 if (ret) {
0041 test_err("couldn't insert ref %d", ret);
0042 btrfs_free_path(path);
0043 return ret;
0044 }
0045
0046 leaf = path->nodes[0];
0047 item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item);
0048 btrfs_set_extent_refs(leaf, item, 1);
0049 btrfs_set_extent_generation(leaf, item, 1);
0050 btrfs_set_extent_flags(leaf, item, BTRFS_EXTENT_FLAG_TREE_BLOCK);
0051 block_info = (struct btrfs_tree_block_info *)(item + 1);
0052 btrfs_set_tree_block_level(leaf, block_info, 0);
0053 iref = (struct btrfs_extent_inline_ref *)(block_info + 1);
0054 if (parent > 0) {
0055 btrfs_set_extent_inline_ref_type(leaf, iref,
0056 BTRFS_SHARED_BLOCK_REF_KEY);
0057 btrfs_set_extent_inline_ref_offset(leaf, iref, parent);
0058 } else {
0059 btrfs_set_extent_inline_ref_type(leaf, iref, BTRFS_TREE_BLOCK_REF_KEY);
0060 btrfs_set_extent_inline_ref_offset(leaf, iref, root_objectid);
0061 }
0062 btrfs_free_path(path);
0063 return 0;
0064 }
0065
0066 static int add_tree_ref(struct btrfs_root *root, u64 bytenr, u64 num_bytes,
0067 u64 parent, u64 root_objectid)
0068 {
0069 struct btrfs_trans_handle trans;
0070 struct btrfs_extent_item *item;
0071 struct btrfs_path *path;
0072 struct btrfs_key key;
0073 u64 refs;
0074 int ret;
0075
0076 btrfs_init_dummy_trans(&trans, NULL);
0077
0078 key.objectid = bytenr;
0079 key.type = BTRFS_EXTENT_ITEM_KEY;
0080 key.offset = num_bytes;
0081
0082 path = btrfs_alloc_path();
0083 if (!path) {
0084 test_std_err(TEST_ALLOC_ROOT);
0085 return -ENOMEM;
0086 }
0087
0088 ret = btrfs_search_slot(&trans, root, &key, path, 0, 1);
0089 if (ret) {
0090 test_err("couldn't find extent ref");
0091 btrfs_free_path(path);
0092 return ret;
0093 }
0094
0095 item = btrfs_item_ptr(path->nodes[0], path->slots[0],
0096 struct btrfs_extent_item);
0097 refs = btrfs_extent_refs(path->nodes[0], item);
0098 btrfs_set_extent_refs(path->nodes[0], item, refs + 1);
0099 btrfs_release_path(path);
0100
0101 key.objectid = bytenr;
0102 if (parent) {
0103 key.type = BTRFS_SHARED_BLOCK_REF_KEY;
0104 key.offset = parent;
0105 } else {
0106 key.type = BTRFS_TREE_BLOCK_REF_KEY;
0107 key.offset = root_objectid;
0108 }
0109
0110 ret = btrfs_insert_empty_item(&trans, root, path, &key, 0);
0111 if (ret)
0112 test_err("failed to insert backref");
0113 btrfs_free_path(path);
0114 return ret;
0115 }
0116
0117 static int remove_extent_item(struct btrfs_root *root, u64 bytenr,
0118 u64 num_bytes)
0119 {
0120 struct btrfs_trans_handle trans;
0121 struct btrfs_key key;
0122 struct btrfs_path *path;
0123 int ret;
0124
0125 btrfs_init_dummy_trans(&trans, NULL);
0126
0127 key.objectid = bytenr;
0128 key.type = BTRFS_EXTENT_ITEM_KEY;
0129 key.offset = num_bytes;
0130
0131 path = btrfs_alloc_path();
0132 if (!path) {
0133 test_std_err(TEST_ALLOC_ROOT);
0134 return -ENOMEM;
0135 }
0136
0137 ret = btrfs_search_slot(&trans, root, &key, path, -1, 1);
0138 if (ret) {
0139 test_err("didn't find our key %d", ret);
0140 btrfs_free_path(path);
0141 return ret;
0142 }
0143 btrfs_del_item(&trans, root, path);
0144 btrfs_free_path(path);
0145 return 0;
0146 }
0147
0148 static int remove_extent_ref(struct btrfs_root *root, u64 bytenr,
0149 u64 num_bytes, u64 parent, u64 root_objectid)
0150 {
0151 struct btrfs_trans_handle trans;
0152 struct btrfs_extent_item *item;
0153 struct btrfs_path *path;
0154 struct btrfs_key key;
0155 u64 refs;
0156 int ret;
0157
0158 btrfs_init_dummy_trans(&trans, NULL);
0159
0160 key.objectid = bytenr;
0161 key.type = BTRFS_EXTENT_ITEM_KEY;
0162 key.offset = num_bytes;
0163
0164 path = btrfs_alloc_path();
0165 if (!path) {
0166 test_std_err(TEST_ALLOC_ROOT);
0167 return -ENOMEM;
0168 }
0169
0170 ret = btrfs_search_slot(&trans, root, &key, path, 0, 1);
0171 if (ret) {
0172 test_err("couldn't find extent ref");
0173 btrfs_free_path(path);
0174 return ret;
0175 }
0176
0177 item = btrfs_item_ptr(path->nodes[0], path->slots[0],
0178 struct btrfs_extent_item);
0179 refs = btrfs_extent_refs(path->nodes[0], item);
0180 btrfs_set_extent_refs(path->nodes[0], item, refs - 1);
0181 btrfs_release_path(path);
0182
0183 key.objectid = bytenr;
0184 if (parent) {
0185 key.type = BTRFS_SHARED_BLOCK_REF_KEY;
0186 key.offset = parent;
0187 } else {
0188 key.type = BTRFS_TREE_BLOCK_REF_KEY;
0189 key.offset = root_objectid;
0190 }
0191
0192 ret = btrfs_search_slot(&trans, root, &key, path, -1, 1);
0193 if (ret) {
0194 test_err("couldn't find backref %d", ret);
0195 btrfs_free_path(path);
0196 return ret;
0197 }
0198 btrfs_del_item(&trans, root, path);
0199 btrfs_free_path(path);
0200 return ret;
0201 }
0202
0203 static int test_no_shared_qgroup(struct btrfs_root *root,
0204 u32 sectorsize, u32 nodesize)
0205 {
0206 struct btrfs_trans_handle trans;
0207 struct btrfs_fs_info *fs_info = root->fs_info;
0208 struct ulist *old_roots = NULL;
0209 struct ulist *new_roots = NULL;
0210 int ret;
0211
0212 btrfs_init_dummy_trans(&trans, fs_info);
0213
0214 test_msg("running qgroup add/remove tests");
0215 ret = btrfs_create_qgroup(&trans, BTRFS_FS_TREE_OBJECTID);
0216 if (ret) {
0217 test_err("couldn't create a qgroup %d", ret);
0218 return ret;
0219 }
0220
0221
0222
0223
0224
0225
0226 ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &old_roots, false);
0227 if (ret) {
0228 ulist_free(old_roots);
0229 test_err("couldn't find old roots: %d", ret);
0230 return ret;
0231 }
0232
0233 ret = insert_normal_tree_ref(root, nodesize, nodesize, 0,
0234 BTRFS_FS_TREE_OBJECTID);
0235 if (ret)
0236 return ret;
0237
0238 ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &new_roots, false);
0239 if (ret) {
0240 ulist_free(old_roots);
0241 ulist_free(new_roots);
0242 test_err("couldn't find old roots: %d", ret);
0243 return ret;
0244 }
0245
0246 ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots,
0247 new_roots);
0248 if (ret) {
0249 test_err("couldn't account space for a qgroup %d", ret);
0250 return ret;
0251 }
0252
0253 if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID,
0254 nodesize, nodesize)) {
0255 test_err("qgroup counts didn't match expected values");
0256 return -EINVAL;
0257 }
0258 old_roots = NULL;
0259 new_roots = NULL;
0260
0261 ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &old_roots, false);
0262 if (ret) {
0263 ulist_free(old_roots);
0264 test_err("couldn't find old roots: %d", ret);
0265 return ret;
0266 }
0267
0268 ret = remove_extent_item(root, nodesize, nodesize);
0269 if (ret)
0270 return -EINVAL;
0271
0272 ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &new_roots, false);
0273 if (ret) {
0274 ulist_free(old_roots);
0275 ulist_free(new_roots);
0276 test_err("couldn't find old roots: %d", ret);
0277 return ret;
0278 }
0279
0280 ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots,
0281 new_roots);
0282 if (ret) {
0283 test_err("couldn't account space for a qgroup %d", ret);
0284 return -EINVAL;
0285 }
0286
0287 if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID, 0, 0)) {
0288 test_err("qgroup counts didn't match expected values");
0289 return -EINVAL;
0290 }
0291
0292 return 0;
0293 }
0294
0295
0296
0297
0298
0299
0300 static int test_multiple_refs(struct btrfs_root *root,
0301 u32 sectorsize, u32 nodesize)
0302 {
0303 struct btrfs_trans_handle trans;
0304 struct btrfs_fs_info *fs_info = root->fs_info;
0305 struct ulist *old_roots = NULL;
0306 struct ulist *new_roots = NULL;
0307 int ret;
0308
0309 btrfs_init_dummy_trans(&trans, fs_info);
0310
0311 test_msg("running qgroup multiple refs test");
0312
0313
0314
0315
0316
0317 ret = btrfs_create_qgroup(&trans, BTRFS_FIRST_FREE_OBJECTID);
0318 if (ret) {
0319 test_err("couldn't create a qgroup %d", ret);
0320 return ret;
0321 }
0322
0323 ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &old_roots, false);
0324 if (ret) {
0325 ulist_free(old_roots);
0326 test_err("couldn't find old roots: %d", ret);
0327 return ret;
0328 }
0329
0330 ret = insert_normal_tree_ref(root, nodesize, nodesize, 0,
0331 BTRFS_FS_TREE_OBJECTID);
0332 if (ret)
0333 return ret;
0334
0335 ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &new_roots, false);
0336 if (ret) {
0337 ulist_free(old_roots);
0338 ulist_free(new_roots);
0339 test_err("couldn't find old roots: %d", ret);
0340 return ret;
0341 }
0342
0343 ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots,
0344 new_roots);
0345 if (ret) {
0346 test_err("couldn't account space for a qgroup %d", ret);
0347 return ret;
0348 }
0349
0350 if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID,
0351 nodesize, nodesize)) {
0352 test_err("qgroup counts didn't match expected values");
0353 return -EINVAL;
0354 }
0355
0356 ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &old_roots, false);
0357 if (ret) {
0358 ulist_free(old_roots);
0359 test_err("couldn't find old roots: %d", ret);
0360 return ret;
0361 }
0362
0363 ret = add_tree_ref(root, nodesize, nodesize, 0,
0364 BTRFS_FIRST_FREE_OBJECTID);
0365 if (ret)
0366 return ret;
0367
0368 ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &new_roots, false);
0369 if (ret) {
0370 ulist_free(old_roots);
0371 ulist_free(new_roots);
0372 test_err("couldn't find old roots: %d", ret);
0373 return ret;
0374 }
0375
0376 ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots,
0377 new_roots);
0378 if (ret) {
0379 test_err("couldn't account space for a qgroup %d", ret);
0380 return ret;
0381 }
0382
0383 if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID,
0384 nodesize, 0)) {
0385 test_err("qgroup counts didn't match expected values");
0386 return -EINVAL;
0387 }
0388
0389 if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FIRST_FREE_OBJECTID,
0390 nodesize, 0)) {
0391 test_err("qgroup counts didn't match expected values");
0392 return -EINVAL;
0393 }
0394
0395 ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &old_roots, false);
0396 if (ret) {
0397 ulist_free(old_roots);
0398 test_err("couldn't find old roots: %d", ret);
0399 return ret;
0400 }
0401
0402 ret = remove_extent_ref(root, nodesize, nodesize, 0,
0403 BTRFS_FIRST_FREE_OBJECTID);
0404 if (ret)
0405 return ret;
0406
0407 ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &new_roots, false);
0408 if (ret) {
0409 ulist_free(old_roots);
0410 ulist_free(new_roots);
0411 test_err("couldn't find old roots: %d", ret);
0412 return ret;
0413 }
0414
0415 ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots,
0416 new_roots);
0417 if (ret) {
0418 test_err("couldn't account space for a qgroup %d", ret);
0419 return ret;
0420 }
0421
0422 if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FIRST_FREE_OBJECTID,
0423 0, 0)) {
0424 test_err("qgroup counts didn't match expected values");
0425 return -EINVAL;
0426 }
0427
0428 if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID,
0429 nodesize, nodesize)) {
0430 test_err("qgroup counts didn't match expected values");
0431 return -EINVAL;
0432 }
0433
0434 return 0;
0435 }
0436
0437 int btrfs_test_qgroups(u32 sectorsize, u32 nodesize)
0438 {
0439 struct btrfs_fs_info *fs_info = NULL;
0440 struct btrfs_root *root;
0441 struct btrfs_root *tmp_root;
0442 int ret = 0;
0443
0444 fs_info = btrfs_alloc_dummy_fs_info(nodesize, sectorsize);
0445 if (!fs_info) {
0446 test_std_err(TEST_ALLOC_FS_INFO);
0447 return -ENOMEM;
0448 }
0449
0450 root = btrfs_alloc_dummy_root(fs_info);
0451 if (IS_ERR(root)) {
0452 test_std_err(TEST_ALLOC_ROOT);
0453 ret = PTR_ERR(root);
0454 goto out;
0455 }
0456
0457
0458 root->root_key.objectid = BTRFS_EXTENT_TREE_OBJECTID;
0459 root->root_key.type = BTRFS_ROOT_ITEM_KEY;
0460 root->root_key.offset = 0;
0461 btrfs_global_root_insert(root);
0462
0463
0464
0465
0466
0467 root->fs_info->tree_root = root;
0468 root->fs_info->quota_root = root;
0469 set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
0470
0471
0472
0473
0474
0475 root->node = alloc_test_extent_buffer(root->fs_info, nodesize);
0476 if (IS_ERR(root->node)) {
0477 test_err("couldn't allocate dummy buffer");
0478 ret = PTR_ERR(root->node);
0479 goto out;
0480 }
0481 btrfs_set_header_level(root->node, 0);
0482 btrfs_set_header_nritems(root->node, 0);
0483 root->alloc_bytenr += 2 * nodesize;
0484
0485 tmp_root = btrfs_alloc_dummy_root(fs_info);
0486 if (IS_ERR(tmp_root)) {
0487 test_std_err(TEST_ALLOC_ROOT);
0488 ret = PTR_ERR(tmp_root);
0489 goto out;
0490 }
0491
0492 tmp_root->root_key.objectid = BTRFS_FS_TREE_OBJECTID;
0493 root->fs_info->fs_root = tmp_root;
0494 ret = btrfs_insert_fs_root(root->fs_info, tmp_root);
0495 if (ret) {
0496 test_err("couldn't insert fs root %d", ret);
0497 goto out;
0498 }
0499 btrfs_put_root(tmp_root);
0500
0501 tmp_root = btrfs_alloc_dummy_root(fs_info);
0502 if (IS_ERR(tmp_root)) {
0503 test_std_err(TEST_ALLOC_ROOT);
0504 ret = PTR_ERR(tmp_root);
0505 goto out;
0506 }
0507
0508 tmp_root->root_key.objectid = BTRFS_FIRST_FREE_OBJECTID;
0509 ret = btrfs_insert_fs_root(root->fs_info, tmp_root);
0510 if (ret) {
0511 test_err("couldn't insert fs root %d", ret);
0512 goto out;
0513 }
0514 btrfs_put_root(tmp_root);
0515
0516 test_msg("running qgroup tests");
0517 ret = test_no_shared_qgroup(root, sectorsize, nodesize);
0518 if (ret)
0519 goto out;
0520 ret = test_multiple_refs(root, sectorsize, nodesize);
0521 out:
0522 btrfs_free_dummy_root(root);
0523 btrfs_free_dummy_fs_info(fs_info);
0524 return ret;
0525 }