162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2013 Facebook. All rights reserved. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/types.h> 762306a36Sopenharmony_ci#include "btrfs-tests.h" 862306a36Sopenharmony_ci#include "../ctree.h" 962306a36Sopenharmony_ci#include "../transaction.h" 1062306a36Sopenharmony_ci#include "../disk-io.h" 1162306a36Sopenharmony_ci#include "../qgroup.h" 1262306a36Sopenharmony_ci#include "../backref.h" 1362306a36Sopenharmony_ci#include "../fs.h" 1462306a36Sopenharmony_ci#include "../accessors.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic int insert_normal_tree_ref(struct btrfs_root *root, u64 bytenr, 1762306a36Sopenharmony_ci u64 num_bytes, u64 parent, u64 root_objectid) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci struct btrfs_trans_handle trans; 2062306a36Sopenharmony_ci struct btrfs_extent_item *item; 2162306a36Sopenharmony_ci struct btrfs_extent_inline_ref *iref; 2262306a36Sopenharmony_ci struct btrfs_tree_block_info *block_info; 2362306a36Sopenharmony_ci struct btrfs_path *path; 2462306a36Sopenharmony_ci struct extent_buffer *leaf; 2562306a36Sopenharmony_ci struct btrfs_key ins; 2662306a36Sopenharmony_ci u32 size = sizeof(*item) + sizeof(*iref) + sizeof(*block_info); 2762306a36Sopenharmony_ci int ret; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci btrfs_init_dummy_trans(&trans, NULL); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci ins.objectid = bytenr; 3262306a36Sopenharmony_ci ins.type = BTRFS_EXTENT_ITEM_KEY; 3362306a36Sopenharmony_ci ins.offset = num_bytes; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci path = btrfs_alloc_path(); 3662306a36Sopenharmony_ci if (!path) { 3762306a36Sopenharmony_ci test_std_err(TEST_ALLOC_ROOT); 3862306a36Sopenharmony_ci return -ENOMEM; 3962306a36Sopenharmony_ci } 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci ret = btrfs_insert_empty_item(&trans, root, path, &ins, size); 4262306a36Sopenharmony_ci if (ret) { 4362306a36Sopenharmony_ci test_err("couldn't insert ref %d", ret); 4462306a36Sopenharmony_ci btrfs_free_path(path); 4562306a36Sopenharmony_ci return ret; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci leaf = path->nodes[0]; 4962306a36Sopenharmony_ci item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); 5062306a36Sopenharmony_ci btrfs_set_extent_refs(leaf, item, 1); 5162306a36Sopenharmony_ci btrfs_set_extent_generation(leaf, item, 1); 5262306a36Sopenharmony_ci btrfs_set_extent_flags(leaf, item, BTRFS_EXTENT_FLAG_TREE_BLOCK); 5362306a36Sopenharmony_ci block_info = (struct btrfs_tree_block_info *)(item + 1); 5462306a36Sopenharmony_ci btrfs_set_tree_block_level(leaf, block_info, 0); 5562306a36Sopenharmony_ci iref = (struct btrfs_extent_inline_ref *)(block_info + 1); 5662306a36Sopenharmony_ci if (parent > 0) { 5762306a36Sopenharmony_ci btrfs_set_extent_inline_ref_type(leaf, iref, 5862306a36Sopenharmony_ci BTRFS_SHARED_BLOCK_REF_KEY); 5962306a36Sopenharmony_ci btrfs_set_extent_inline_ref_offset(leaf, iref, parent); 6062306a36Sopenharmony_ci } else { 6162306a36Sopenharmony_ci btrfs_set_extent_inline_ref_type(leaf, iref, BTRFS_TREE_BLOCK_REF_KEY); 6262306a36Sopenharmony_ci btrfs_set_extent_inline_ref_offset(leaf, iref, root_objectid); 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci btrfs_free_path(path); 6562306a36Sopenharmony_ci return 0; 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic int add_tree_ref(struct btrfs_root *root, u64 bytenr, u64 num_bytes, 6962306a36Sopenharmony_ci u64 parent, u64 root_objectid) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci struct btrfs_trans_handle trans; 7262306a36Sopenharmony_ci struct btrfs_extent_item *item; 7362306a36Sopenharmony_ci struct btrfs_path *path; 7462306a36Sopenharmony_ci struct btrfs_key key; 7562306a36Sopenharmony_ci u64 refs; 7662306a36Sopenharmony_ci int ret; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci btrfs_init_dummy_trans(&trans, NULL); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci key.objectid = bytenr; 8162306a36Sopenharmony_ci key.type = BTRFS_EXTENT_ITEM_KEY; 8262306a36Sopenharmony_ci key.offset = num_bytes; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci path = btrfs_alloc_path(); 8562306a36Sopenharmony_ci if (!path) { 8662306a36Sopenharmony_ci test_std_err(TEST_ALLOC_ROOT); 8762306a36Sopenharmony_ci return -ENOMEM; 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci ret = btrfs_search_slot(&trans, root, &key, path, 0, 1); 9162306a36Sopenharmony_ci if (ret) { 9262306a36Sopenharmony_ci test_err("couldn't find extent ref"); 9362306a36Sopenharmony_ci btrfs_free_path(path); 9462306a36Sopenharmony_ci return ret; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci item = btrfs_item_ptr(path->nodes[0], path->slots[0], 9862306a36Sopenharmony_ci struct btrfs_extent_item); 9962306a36Sopenharmony_ci refs = btrfs_extent_refs(path->nodes[0], item); 10062306a36Sopenharmony_ci btrfs_set_extent_refs(path->nodes[0], item, refs + 1); 10162306a36Sopenharmony_ci btrfs_release_path(path); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci key.objectid = bytenr; 10462306a36Sopenharmony_ci if (parent) { 10562306a36Sopenharmony_ci key.type = BTRFS_SHARED_BLOCK_REF_KEY; 10662306a36Sopenharmony_ci key.offset = parent; 10762306a36Sopenharmony_ci } else { 10862306a36Sopenharmony_ci key.type = BTRFS_TREE_BLOCK_REF_KEY; 10962306a36Sopenharmony_ci key.offset = root_objectid; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci ret = btrfs_insert_empty_item(&trans, root, path, &key, 0); 11362306a36Sopenharmony_ci if (ret) 11462306a36Sopenharmony_ci test_err("failed to insert backref"); 11562306a36Sopenharmony_ci btrfs_free_path(path); 11662306a36Sopenharmony_ci return ret; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic int remove_extent_item(struct btrfs_root *root, u64 bytenr, 12062306a36Sopenharmony_ci u64 num_bytes) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct btrfs_trans_handle trans; 12362306a36Sopenharmony_ci struct btrfs_key key; 12462306a36Sopenharmony_ci struct btrfs_path *path; 12562306a36Sopenharmony_ci int ret; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci btrfs_init_dummy_trans(&trans, NULL); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci key.objectid = bytenr; 13062306a36Sopenharmony_ci key.type = BTRFS_EXTENT_ITEM_KEY; 13162306a36Sopenharmony_ci key.offset = num_bytes; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci path = btrfs_alloc_path(); 13462306a36Sopenharmony_ci if (!path) { 13562306a36Sopenharmony_ci test_std_err(TEST_ALLOC_ROOT); 13662306a36Sopenharmony_ci return -ENOMEM; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci ret = btrfs_search_slot(&trans, root, &key, path, -1, 1); 14062306a36Sopenharmony_ci if (ret) { 14162306a36Sopenharmony_ci test_err("didn't find our key %d", ret); 14262306a36Sopenharmony_ci btrfs_free_path(path); 14362306a36Sopenharmony_ci return ret; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci btrfs_del_item(&trans, root, path); 14662306a36Sopenharmony_ci btrfs_free_path(path); 14762306a36Sopenharmony_ci return 0; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic int remove_extent_ref(struct btrfs_root *root, u64 bytenr, 15162306a36Sopenharmony_ci u64 num_bytes, u64 parent, u64 root_objectid) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct btrfs_trans_handle trans; 15462306a36Sopenharmony_ci struct btrfs_extent_item *item; 15562306a36Sopenharmony_ci struct btrfs_path *path; 15662306a36Sopenharmony_ci struct btrfs_key key; 15762306a36Sopenharmony_ci u64 refs; 15862306a36Sopenharmony_ci int ret; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci btrfs_init_dummy_trans(&trans, NULL); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci key.objectid = bytenr; 16362306a36Sopenharmony_ci key.type = BTRFS_EXTENT_ITEM_KEY; 16462306a36Sopenharmony_ci key.offset = num_bytes; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci path = btrfs_alloc_path(); 16762306a36Sopenharmony_ci if (!path) { 16862306a36Sopenharmony_ci test_std_err(TEST_ALLOC_ROOT); 16962306a36Sopenharmony_ci return -ENOMEM; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci ret = btrfs_search_slot(&trans, root, &key, path, 0, 1); 17362306a36Sopenharmony_ci if (ret) { 17462306a36Sopenharmony_ci test_err("couldn't find extent ref"); 17562306a36Sopenharmony_ci btrfs_free_path(path); 17662306a36Sopenharmony_ci return ret; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci item = btrfs_item_ptr(path->nodes[0], path->slots[0], 18062306a36Sopenharmony_ci struct btrfs_extent_item); 18162306a36Sopenharmony_ci refs = btrfs_extent_refs(path->nodes[0], item); 18262306a36Sopenharmony_ci btrfs_set_extent_refs(path->nodes[0], item, refs - 1); 18362306a36Sopenharmony_ci btrfs_release_path(path); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci key.objectid = bytenr; 18662306a36Sopenharmony_ci if (parent) { 18762306a36Sopenharmony_ci key.type = BTRFS_SHARED_BLOCK_REF_KEY; 18862306a36Sopenharmony_ci key.offset = parent; 18962306a36Sopenharmony_ci } else { 19062306a36Sopenharmony_ci key.type = BTRFS_TREE_BLOCK_REF_KEY; 19162306a36Sopenharmony_ci key.offset = root_objectid; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci ret = btrfs_search_slot(&trans, root, &key, path, -1, 1); 19562306a36Sopenharmony_ci if (ret) { 19662306a36Sopenharmony_ci test_err("couldn't find backref %d", ret); 19762306a36Sopenharmony_ci btrfs_free_path(path); 19862306a36Sopenharmony_ci return ret; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci btrfs_del_item(&trans, root, path); 20162306a36Sopenharmony_ci btrfs_free_path(path); 20262306a36Sopenharmony_ci return ret; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic int test_no_shared_qgroup(struct btrfs_root *root, 20662306a36Sopenharmony_ci u32 sectorsize, u32 nodesize) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci struct btrfs_backref_walk_ctx ctx = { 0 }; 20962306a36Sopenharmony_ci struct btrfs_trans_handle trans; 21062306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = root->fs_info; 21162306a36Sopenharmony_ci struct ulist *old_roots = NULL; 21262306a36Sopenharmony_ci struct ulist *new_roots = NULL; 21362306a36Sopenharmony_ci int ret; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci btrfs_init_dummy_trans(&trans, fs_info); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci test_msg("running qgroup add/remove tests"); 21862306a36Sopenharmony_ci ret = btrfs_create_qgroup(&trans, BTRFS_FS_TREE_OBJECTID); 21962306a36Sopenharmony_ci if (ret) { 22062306a36Sopenharmony_ci test_err("couldn't create a qgroup %d", ret); 22162306a36Sopenharmony_ci return ret; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci ctx.bytenr = nodesize; 22562306a36Sopenharmony_ci ctx.trans = &trans; 22662306a36Sopenharmony_ci ctx.fs_info = fs_info; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci /* 22962306a36Sopenharmony_ci * Since the test trans doesn't have the complicated delayed refs, 23062306a36Sopenharmony_ci * we can only call btrfs_qgroup_account_extent() directly to test 23162306a36Sopenharmony_ci * quota. 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_ci ret = btrfs_find_all_roots(&ctx, false); 23462306a36Sopenharmony_ci if (ret) { 23562306a36Sopenharmony_ci test_err("couldn't find old roots: %d", ret); 23662306a36Sopenharmony_ci return ret; 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci old_roots = ctx.roots; 23962306a36Sopenharmony_ci ctx.roots = NULL; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci ret = insert_normal_tree_ref(root, nodesize, nodesize, 0, 24262306a36Sopenharmony_ci BTRFS_FS_TREE_OBJECTID); 24362306a36Sopenharmony_ci if (ret) { 24462306a36Sopenharmony_ci ulist_free(old_roots); 24562306a36Sopenharmony_ci return ret; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci ret = btrfs_find_all_roots(&ctx, false); 24962306a36Sopenharmony_ci if (ret) { 25062306a36Sopenharmony_ci ulist_free(old_roots); 25162306a36Sopenharmony_ci test_err("couldn't find old roots: %d", ret); 25262306a36Sopenharmony_ci return ret; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci new_roots = ctx.roots; 25562306a36Sopenharmony_ci ctx.roots = NULL; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots, 25862306a36Sopenharmony_ci new_roots); 25962306a36Sopenharmony_ci if (ret) { 26062306a36Sopenharmony_ci test_err("couldn't account space for a qgroup %d", ret); 26162306a36Sopenharmony_ci return ret; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* btrfs_qgroup_account_extent() always frees the ulists passed to it. */ 26562306a36Sopenharmony_ci old_roots = NULL; 26662306a36Sopenharmony_ci new_roots = NULL; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID, 26962306a36Sopenharmony_ci nodesize, nodesize)) { 27062306a36Sopenharmony_ci test_err("qgroup counts didn't match expected values"); 27162306a36Sopenharmony_ci return -EINVAL; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci ret = btrfs_find_all_roots(&ctx, false); 27562306a36Sopenharmony_ci if (ret) { 27662306a36Sopenharmony_ci test_err("couldn't find old roots: %d", ret); 27762306a36Sopenharmony_ci return ret; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci old_roots = ctx.roots; 28062306a36Sopenharmony_ci ctx.roots = NULL; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci ret = remove_extent_item(root, nodesize, nodesize); 28362306a36Sopenharmony_ci if (ret) { 28462306a36Sopenharmony_ci ulist_free(old_roots); 28562306a36Sopenharmony_ci return -EINVAL; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci ret = btrfs_find_all_roots(&ctx, false); 28962306a36Sopenharmony_ci if (ret) { 29062306a36Sopenharmony_ci ulist_free(old_roots); 29162306a36Sopenharmony_ci test_err("couldn't find old roots: %d", ret); 29262306a36Sopenharmony_ci return ret; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci new_roots = ctx.roots; 29562306a36Sopenharmony_ci ctx.roots = NULL; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots, 29862306a36Sopenharmony_ci new_roots); 29962306a36Sopenharmony_ci if (ret) { 30062306a36Sopenharmony_ci test_err("couldn't account space for a qgroup %d", ret); 30162306a36Sopenharmony_ci return -EINVAL; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID, 0, 0)) { 30562306a36Sopenharmony_ci test_err("qgroup counts didn't match expected values"); 30662306a36Sopenharmony_ci return -EINVAL; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci return 0; 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci/* 31362306a36Sopenharmony_ci * Add a ref for two different roots to make sure the shared value comes out 31462306a36Sopenharmony_ci * right, also remove one of the roots and make sure the exclusive count is 31562306a36Sopenharmony_ci * adjusted properly. 31662306a36Sopenharmony_ci */ 31762306a36Sopenharmony_cistatic int test_multiple_refs(struct btrfs_root *root, 31862306a36Sopenharmony_ci u32 sectorsize, u32 nodesize) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci struct btrfs_backref_walk_ctx ctx = { 0 }; 32162306a36Sopenharmony_ci struct btrfs_trans_handle trans; 32262306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = root->fs_info; 32362306a36Sopenharmony_ci struct ulist *old_roots = NULL; 32462306a36Sopenharmony_ci struct ulist *new_roots = NULL; 32562306a36Sopenharmony_ci int ret; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci btrfs_init_dummy_trans(&trans, fs_info); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci test_msg("running qgroup multiple refs test"); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci /* 33262306a36Sopenharmony_ci * We have BTRFS_FS_TREE_OBJECTID created already from the 33362306a36Sopenharmony_ci * previous test. 33462306a36Sopenharmony_ci */ 33562306a36Sopenharmony_ci ret = btrfs_create_qgroup(&trans, BTRFS_FIRST_FREE_OBJECTID); 33662306a36Sopenharmony_ci if (ret) { 33762306a36Sopenharmony_ci test_err("couldn't create a qgroup %d", ret); 33862306a36Sopenharmony_ci return ret; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci ctx.bytenr = nodesize; 34262306a36Sopenharmony_ci ctx.trans = &trans; 34362306a36Sopenharmony_ci ctx.fs_info = fs_info; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci ret = btrfs_find_all_roots(&ctx, false); 34662306a36Sopenharmony_ci if (ret) { 34762306a36Sopenharmony_ci test_err("couldn't find old roots: %d", ret); 34862306a36Sopenharmony_ci return ret; 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci old_roots = ctx.roots; 35162306a36Sopenharmony_ci ctx.roots = NULL; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci ret = insert_normal_tree_ref(root, nodesize, nodesize, 0, 35462306a36Sopenharmony_ci BTRFS_FS_TREE_OBJECTID); 35562306a36Sopenharmony_ci if (ret) { 35662306a36Sopenharmony_ci ulist_free(old_roots); 35762306a36Sopenharmony_ci return ret; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci ret = btrfs_find_all_roots(&ctx, false); 36162306a36Sopenharmony_ci if (ret) { 36262306a36Sopenharmony_ci ulist_free(old_roots); 36362306a36Sopenharmony_ci test_err("couldn't find old roots: %d", ret); 36462306a36Sopenharmony_ci return ret; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci new_roots = ctx.roots; 36762306a36Sopenharmony_ci ctx.roots = NULL; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots, 37062306a36Sopenharmony_ci new_roots); 37162306a36Sopenharmony_ci if (ret) { 37262306a36Sopenharmony_ci test_err("couldn't account space for a qgroup %d", ret); 37362306a36Sopenharmony_ci return ret; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID, 37762306a36Sopenharmony_ci nodesize, nodesize)) { 37862306a36Sopenharmony_ci test_err("qgroup counts didn't match expected values"); 37962306a36Sopenharmony_ci return -EINVAL; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci ret = btrfs_find_all_roots(&ctx, false); 38362306a36Sopenharmony_ci if (ret) { 38462306a36Sopenharmony_ci test_err("couldn't find old roots: %d", ret); 38562306a36Sopenharmony_ci return ret; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci old_roots = ctx.roots; 38862306a36Sopenharmony_ci ctx.roots = NULL; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci ret = add_tree_ref(root, nodesize, nodesize, 0, 39162306a36Sopenharmony_ci BTRFS_FIRST_FREE_OBJECTID); 39262306a36Sopenharmony_ci if (ret) { 39362306a36Sopenharmony_ci ulist_free(old_roots); 39462306a36Sopenharmony_ci return ret; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci ret = btrfs_find_all_roots(&ctx, false); 39862306a36Sopenharmony_ci if (ret) { 39962306a36Sopenharmony_ci ulist_free(old_roots); 40062306a36Sopenharmony_ci test_err("couldn't find old roots: %d", ret); 40162306a36Sopenharmony_ci return ret; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci new_roots = ctx.roots; 40462306a36Sopenharmony_ci ctx.roots = NULL; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots, 40762306a36Sopenharmony_ci new_roots); 40862306a36Sopenharmony_ci if (ret) { 40962306a36Sopenharmony_ci test_err("couldn't account space for a qgroup %d", ret); 41062306a36Sopenharmony_ci return ret; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID, 41462306a36Sopenharmony_ci nodesize, 0)) { 41562306a36Sopenharmony_ci test_err("qgroup counts didn't match expected values"); 41662306a36Sopenharmony_ci return -EINVAL; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FIRST_FREE_OBJECTID, 42062306a36Sopenharmony_ci nodesize, 0)) { 42162306a36Sopenharmony_ci test_err("qgroup counts didn't match expected values"); 42262306a36Sopenharmony_ci return -EINVAL; 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci ret = btrfs_find_all_roots(&ctx, false); 42662306a36Sopenharmony_ci if (ret) { 42762306a36Sopenharmony_ci test_err("couldn't find old roots: %d", ret); 42862306a36Sopenharmony_ci return ret; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci old_roots = ctx.roots; 43162306a36Sopenharmony_ci ctx.roots = NULL; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci ret = remove_extent_ref(root, nodesize, nodesize, 0, 43462306a36Sopenharmony_ci BTRFS_FIRST_FREE_OBJECTID); 43562306a36Sopenharmony_ci if (ret) { 43662306a36Sopenharmony_ci ulist_free(old_roots); 43762306a36Sopenharmony_ci return ret; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci ret = btrfs_find_all_roots(&ctx, false); 44162306a36Sopenharmony_ci if (ret) { 44262306a36Sopenharmony_ci ulist_free(old_roots); 44362306a36Sopenharmony_ci test_err("couldn't find old roots: %d", ret); 44462306a36Sopenharmony_ci return ret; 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci new_roots = ctx.roots; 44762306a36Sopenharmony_ci ctx.roots = NULL; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots, 45062306a36Sopenharmony_ci new_roots); 45162306a36Sopenharmony_ci if (ret) { 45262306a36Sopenharmony_ci test_err("couldn't account space for a qgroup %d", ret); 45362306a36Sopenharmony_ci return ret; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FIRST_FREE_OBJECTID, 45762306a36Sopenharmony_ci 0, 0)) { 45862306a36Sopenharmony_ci test_err("qgroup counts didn't match expected values"); 45962306a36Sopenharmony_ci return -EINVAL; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID, 46362306a36Sopenharmony_ci nodesize, nodesize)) { 46462306a36Sopenharmony_ci test_err("qgroup counts didn't match expected values"); 46562306a36Sopenharmony_ci return -EINVAL; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci return 0; 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ciint btrfs_test_qgroups(u32 sectorsize, u32 nodesize) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = NULL; 47462306a36Sopenharmony_ci struct btrfs_root *root; 47562306a36Sopenharmony_ci struct btrfs_root *tmp_root; 47662306a36Sopenharmony_ci int ret = 0; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci fs_info = btrfs_alloc_dummy_fs_info(nodesize, sectorsize); 47962306a36Sopenharmony_ci if (!fs_info) { 48062306a36Sopenharmony_ci test_std_err(TEST_ALLOC_FS_INFO); 48162306a36Sopenharmony_ci return -ENOMEM; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci root = btrfs_alloc_dummy_root(fs_info); 48562306a36Sopenharmony_ci if (IS_ERR(root)) { 48662306a36Sopenharmony_ci test_std_err(TEST_ALLOC_ROOT); 48762306a36Sopenharmony_ci ret = PTR_ERR(root); 48862306a36Sopenharmony_ci goto out; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* We are using this root as our extent root */ 49262306a36Sopenharmony_ci root->root_key.objectid = BTRFS_EXTENT_TREE_OBJECTID; 49362306a36Sopenharmony_ci root->root_key.type = BTRFS_ROOT_ITEM_KEY; 49462306a36Sopenharmony_ci root->root_key.offset = 0; 49562306a36Sopenharmony_ci btrfs_global_root_insert(root); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci /* 49862306a36Sopenharmony_ci * Some of the paths we test assume we have a filled out fs_info, so we 49962306a36Sopenharmony_ci * just need to add the root in there so we don't panic. 50062306a36Sopenharmony_ci */ 50162306a36Sopenharmony_ci root->fs_info->tree_root = root; 50262306a36Sopenharmony_ci root->fs_info->quota_root = root; 50362306a36Sopenharmony_ci set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* 50662306a36Sopenharmony_ci * Can't use bytenr 0, some things freak out 50762306a36Sopenharmony_ci * *cough*backref walking code*cough* 50862306a36Sopenharmony_ci */ 50962306a36Sopenharmony_ci root->node = alloc_test_extent_buffer(root->fs_info, nodesize); 51062306a36Sopenharmony_ci if (IS_ERR(root->node)) { 51162306a36Sopenharmony_ci test_err("couldn't allocate dummy buffer"); 51262306a36Sopenharmony_ci ret = PTR_ERR(root->node); 51362306a36Sopenharmony_ci goto out; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci btrfs_set_header_level(root->node, 0); 51662306a36Sopenharmony_ci btrfs_set_header_nritems(root->node, 0); 51762306a36Sopenharmony_ci root->alloc_bytenr += 2 * nodesize; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci tmp_root = btrfs_alloc_dummy_root(fs_info); 52062306a36Sopenharmony_ci if (IS_ERR(tmp_root)) { 52162306a36Sopenharmony_ci test_std_err(TEST_ALLOC_ROOT); 52262306a36Sopenharmony_ci ret = PTR_ERR(tmp_root); 52362306a36Sopenharmony_ci goto out; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci tmp_root->root_key.objectid = BTRFS_FS_TREE_OBJECTID; 52762306a36Sopenharmony_ci root->fs_info->fs_root = tmp_root; 52862306a36Sopenharmony_ci ret = btrfs_insert_fs_root(root->fs_info, tmp_root); 52962306a36Sopenharmony_ci if (ret) { 53062306a36Sopenharmony_ci test_err("couldn't insert fs root %d", ret); 53162306a36Sopenharmony_ci goto out; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci btrfs_put_root(tmp_root); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci tmp_root = btrfs_alloc_dummy_root(fs_info); 53662306a36Sopenharmony_ci if (IS_ERR(tmp_root)) { 53762306a36Sopenharmony_ci test_std_err(TEST_ALLOC_ROOT); 53862306a36Sopenharmony_ci ret = PTR_ERR(tmp_root); 53962306a36Sopenharmony_ci goto out; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci tmp_root->root_key.objectid = BTRFS_FIRST_FREE_OBJECTID; 54362306a36Sopenharmony_ci ret = btrfs_insert_fs_root(root->fs_info, tmp_root); 54462306a36Sopenharmony_ci if (ret) { 54562306a36Sopenharmony_ci test_err("couldn't insert fs root %d", ret); 54662306a36Sopenharmony_ci goto out; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci btrfs_put_root(tmp_root); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci test_msg("running qgroup tests"); 55162306a36Sopenharmony_ci ret = test_no_shared_qgroup(root, sectorsize, nodesize); 55262306a36Sopenharmony_ci if (ret) 55362306a36Sopenharmony_ci goto out; 55462306a36Sopenharmony_ci ret = test_multiple_refs(root, sectorsize, nodesize); 55562306a36Sopenharmony_ciout: 55662306a36Sopenharmony_ci btrfs_free_dummy_root(root); 55762306a36Sopenharmony_ci btrfs_free_dummy_fs_info(fs_info); 55862306a36Sopenharmony_ci return ret; 55962306a36Sopenharmony_ci} 560