Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2013 Facebook.  All rights reserved.
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      * Since the test trans doesn't have the complicated delayed refs,
0223      * we can only call btrfs_qgroup_account_extent() directly to test
0224      * quota.
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  * Add a ref for two different roots to make sure the shared value comes out
0297  * right, also remove one of the roots and make sure the exclusive count is
0298  * adjusted properly.
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      * We have BTRFS_FS_TREE_OBJECTID created already from the
0315      * previous test.
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     /* We are using this root as our extent root */
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      * Some of the paths we test assume we have a filled out fs_info, so we
0465      * just need to add the root in there so we don't panic.
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      * Can't use bytenr 0, some things freak out
0473      * *cough*backref walking code*cough*
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 }