brintos

brintos / linux-shallow public Read only

0
0
Text · 13.3 KiB · 3fc8dc3 Raw
560 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2013 Facebook.  All rights reserved.4 */5 6#include <linux/types.h>7#include "btrfs-tests.h"8#include "../ctree.h"9#include "../transaction.h"10#include "../disk-io.h"11#include "../qgroup.h"12#include "../backref.h"13#include "../fs.h"14#include "../accessors.h"15 16static int insert_normal_tree_ref(struct btrfs_root *root, u64 bytenr,17				  u64 num_bytes, u64 parent, u64 root_objectid)18{19	struct btrfs_trans_handle trans;20	struct btrfs_extent_item *item;21	struct btrfs_extent_inline_ref *iref;22	struct btrfs_tree_block_info *block_info;23	struct btrfs_path *path;24	struct extent_buffer *leaf;25	struct btrfs_key ins;26	u32 size = sizeof(*item) + sizeof(*iref) + sizeof(*block_info);27	int ret;28 29	btrfs_init_dummy_trans(&trans, NULL);30 31	ins.objectid = bytenr;32	ins.type = BTRFS_EXTENT_ITEM_KEY;33	ins.offset = num_bytes;34 35	path = btrfs_alloc_path();36	if (!path) {37		test_std_err(TEST_ALLOC_ROOT);38		return -ENOMEM;39	}40 41	ret = btrfs_insert_empty_item(&trans, root, path, &ins, size);42	if (ret) {43		test_err("couldn't insert ref %d", ret);44		btrfs_free_path(path);45		return ret;46	}47 48	leaf = path->nodes[0];49	item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item);50	btrfs_set_extent_refs(leaf, item, 1);51	btrfs_set_extent_generation(leaf, item, 1);52	btrfs_set_extent_flags(leaf, item, BTRFS_EXTENT_FLAG_TREE_BLOCK);53	block_info = (struct btrfs_tree_block_info *)(item + 1);54	btrfs_set_tree_block_level(leaf, block_info, 0);55	iref = (struct btrfs_extent_inline_ref *)(block_info + 1);56	if (parent > 0) {57		btrfs_set_extent_inline_ref_type(leaf, iref,58						 BTRFS_SHARED_BLOCK_REF_KEY);59		btrfs_set_extent_inline_ref_offset(leaf, iref, parent);60	} else {61		btrfs_set_extent_inline_ref_type(leaf, iref, BTRFS_TREE_BLOCK_REF_KEY);62		btrfs_set_extent_inline_ref_offset(leaf, iref, root_objectid);63	}64	btrfs_free_path(path);65	return 0;66}67 68static int add_tree_ref(struct btrfs_root *root, u64 bytenr, u64 num_bytes,69			u64 parent, u64 root_objectid)70{71	struct btrfs_trans_handle trans;72	struct btrfs_extent_item *item;73	struct btrfs_path *path;74	struct btrfs_key key;75	u64 refs;76	int ret;77 78	btrfs_init_dummy_trans(&trans, NULL);79 80	key.objectid = bytenr;81	key.type = BTRFS_EXTENT_ITEM_KEY;82	key.offset = num_bytes;83 84	path = btrfs_alloc_path();85	if (!path) {86		test_std_err(TEST_ALLOC_ROOT);87		return -ENOMEM;88	}89 90	ret = btrfs_search_slot(&trans, root, &key, path, 0, 1);91	if (ret) {92		test_err("couldn't find extent ref");93		btrfs_free_path(path);94		return ret;95	}96 97	item = btrfs_item_ptr(path->nodes[0], path->slots[0],98			      struct btrfs_extent_item);99	refs = btrfs_extent_refs(path->nodes[0], item);100	btrfs_set_extent_refs(path->nodes[0], item, refs + 1);101	btrfs_release_path(path);102 103	key.objectid = bytenr;104	if (parent) {105		key.type = BTRFS_SHARED_BLOCK_REF_KEY;106		key.offset = parent;107	} else {108		key.type = BTRFS_TREE_BLOCK_REF_KEY;109		key.offset = root_objectid;110	}111 112	ret = btrfs_insert_empty_item(&trans, root, path, &key, 0);113	if (ret)114		test_err("failed to insert backref");115	btrfs_free_path(path);116	return ret;117}118 119static int remove_extent_item(struct btrfs_root *root, u64 bytenr,120			      u64 num_bytes)121{122	struct btrfs_trans_handle trans;123	struct btrfs_key key;124	struct btrfs_path *path;125	int ret;126 127	btrfs_init_dummy_trans(&trans, NULL);128 129	key.objectid = bytenr;130	key.type = BTRFS_EXTENT_ITEM_KEY;131	key.offset = num_bytes;132 133	path = btrfs_alloc_path();134	if (!path) {135		test_std_err(TEST_ALLOC_ROOT);136		return -ENOMEM;137	}138 139	ret = btrfs_search_slot(&trans, root, &key, path, -1, 1);140	if (ret) {141		test_err("didn't find our key %d", ret);142		btrfs_free_path(path);143		return ret;144	}145	btrfs_del_item(&trans, root, path);146	btrfs_free_path(path);147	return 0;148}149 150static int remove_extent_ref(struct btrfs_root *root, u64 bytenr,151			     u64 num_bytes, u64 parent, u64 root_objectid)152{153	struct btrfs_trans_handle trans;154	struct btrfs_extent_item *item;155	struct btrfs_path *path;156	struct btrfs_key key;157	u64 refs;158	int ret;159 160	btrfs_init_dummy_trans(&trans, NULL);161 162	key.objectid = bytenr;163	key.type = BTRFS_EXTENT_ITEM_KEY;164	key.offset = num_bytes;165 166	path = btrfs_alloc_path();167	if (!path) {168		test_std_err(TEST_ALLOC_ROOT);169		return -ENOMEM;170	}171 172	ret = btrfs_search_slot(&trans, root, &key, path, 0, 1);173	if (ret) {174		test_err("couldn't find extent ref");175		btrfs_free_path(path);176		return ret;177	}178 179	item = btrfs_item_ptr(path->nodes[0], path->slots[0],180			      struct btrfs_extent_item);181	refs = btrfs_extent_refs(path->nodes[0], item);182	btrfs_set_extent_refs(path->nodes[0], item, refs - 1);183	btrfs_release_path(path);184 185	key.objectid = bytenr;186	if (parent) {187		key.type = BTRFS_SHARED_BLOCK_REF_KEY;188		key.offset = parent;189	} else {190		key.type = BTRFS_TREE_BLOCK_REF_KEY;191		key.offset = root_objectid;192	}193 194	ret = btrfs_search_slot(&trans, root, &key, path, -1, 1);195	if (ret) {196		test_err("couldn't find backref %d", ret);197		btrfs_free_path(path);198		return ret;199	}200	btrfs_del_item(&trans, root, path);201	btrfs_free_path(path);202	return ret;203}204 205static int test_no_shared_qgroup(struct btrfs_root *root,206		u32 sectorsize, u32 nodesize)207{208	struct btrfs_backref_walk_ctx ctx = { 0 };209	struct btrfs_trans_handle trans;210	struct btrfs_fs_info *fs_info = root->fs_info;211	struct ulist *old_roots = NULL;212	struct ulist *new_roots = NULL;213	int ret;214 215	btrfs_init_dummy_trans(&trans, fs_info);216 217	test_msg("running qgroup add/remove tests");218	ret = btrfs_create_qgroup(&trans, BTRFS_FS_TREE_OBJECTID);219	if (ret) {220		test_err("couldn't create a qgroup %d", ret);221		return ret;222	}223 224	ctx.bytenr = nodesize;225	ctx.trans = &trans;226	ctx.fs_info = fs_info;227 228	/*229	 * Since the test trans doesn't have the complicated delayed refs,230	 * we can only call btrfs_qgroup_account_extent() directly to test231	 * quota.232	 */233	ret = btrfs_find_all_roots(&ctx, false);234	if (ret) {235		test_err("couldn't find old roots: %d", ret);236		return ret;237	}238	old_roots = ctx.roots;239	ctx.roots = NULL;240 241	ret = insert_normal_tree_ref(root, nodesize, nodesize, 0,242				BTRFS_FS_TREE_OBJECTID);243	if (ret) {244		ulist_free(old_roots);245		return ret;246	}247 248	ret = btrfs_find_all_roots(&ctx, false);249	if (ret) {250		ulist_free(old_roots);251		test_err("couldn't find old roots: %d", ret);252		return ret;253	}254	new_roots = ctx.roots;255	ctx.roots = NULL;256 257	ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots,258					  new_roots);259	if (ret) {260		test_err("couldn't account space for a qgroup %d", ret);261		return ret;262	}263 264	/* btrfs_qgroup_account_extent() always frees the ulists passed to it. */265	old_roots = NULL;266	new_roots = NULL;267 268	if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID,269				nodesize, nodesize)) {270		test_err("qgroup counts didn't match expected values");271		return -EINVAL;272	}273 274	ret = btrfs_find_all_roots(&ctx, false);275	if (ret) {276		test_err("couldn't find old roots: %d", ret);277		return ret;278	}279	old_roots = ctx.roots;280	ctx.roots = NULL;281 282	ret = remove_extent_item(root, nodesize, nodesize);283	if (ret) {284		ulist_free(old_roots);285		return -EINVAL;286	}287 288	ret = btrfs_find_all_roots(&ctx, false);289	if (ret) {290		ulist_free(old_roots);291		test_err("couldn't find old roots: %d", ret);292		return ret;293	}294	new_roots = ctx.roots;295	ctx.roots = NULL;296 297	ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots,298					  new_roots);299	if (ret) {300		test_err("couldn't account space for a qgroup %d", ret);301		return -EINVAL;302	}303 304	if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID, 0, 0)) {305		test_err("qgroup counts didn't match expected values");306		return -EINVAL;307	}308 309	return 0;310}311 312/*313 * Add a ref for two different roots to make sure the shared value comes out314 * right, also remove one of the roots and make sure the exclusive count is315 * adjusted properly.316 */317static int test_multiple_refs(struct btrfs_root *root,318		u32 sectorsize, u32 nodesize)319{320	struct btrfs_backref_walk_ctx ctx = { 0 };321	struct btrfs_trans_handle trans;322	struct btrfs_fs_info *fs_info = root->fs_info;323	struct ulist *old_roots = NULL;324	struct ulist *new_roots = NULL;325	int ret;326 327	btrfs_init_dummy_trans(&trans, fs_info);328 329	test_msg("running qgroup multiple refs test");330 331	/*332	 * We have BTRFS_FS_TREE_OBJECTID created already from the333	 * previous test.334	 */335	ret = btrfs_create_qgroup(&trans, BTRFS_FIRST_FREE_OBJECTID);336	if (ret) {337		test_err("couldn't create a qgroup %d", ret);338		return ret;339	}340 341	ctx.bytenr = nodesize;342	ctx.trans = &trans;343	ctx.fs_info = fs_info;344 345	ret = btrfs_find_all_roots(&ctx, false);346	if (ret) {347		test_err("couldn't find old roots: %d", ret);348		return ret;349	}350	old_roots = ctx.roots;351	ctx.roots = NULL;352 353	ret = insert_normal_tree_ref(root, nodesize, nodesize, 0,354				BTRFS_FS_TREE_OBJECTID);355	if (ret) {356		ulist_free(old_roots);357		return ret;358	}359 360	ret = btrfs_find_all_roots(&ctx, false);361	if (ret) {362		ulist_free(old_roots);363		test_err("couldn't find old roots: %d", ret);364		return ret;365	}366	new_roots = ctx.roots;367	ctx.roots = NULL;368 369	ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots,370					  new_roots);371	if (ret) {372		test_err("couldn't account space for a qgroup %d", ret);373		return ret;374	}375 376	if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID,377				       nodesize, nodesize)) {378		test_err("qgroup counts didn't match expected values");379		return -EINVAL;380	}381 382	ret = btrfs_find_all_roots(&ctx, false);383	if (ret) {384		test_err("couldn't find old roots: %d", ret);385		return ret;386	}387	old_roots = ctx.roots;388	ctx.roots = NULL;389 390	ret = add_tree_ref(root, nodesize, nodesize, 0,391			BTRFS_FIRST_FREE_OBJECTID);392	if (ret) {393		ulist_free(old_roots);394		return ret;395	}396 397	ret = btrfs_find_all_roots(&ctx, false);398	if (ret) {399		ulist_free(old_roots);400		test_err("couldn't find old roots: %d", ret);401		return ret;402	}403	new_roots = ctx.roots;404	ctx.roots = NULL;405 406	ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots,407					  new_roots);408	if (ret) {409		test_err("couldn't account space for a qgroup %d", ret);410		return ret;411	}412 413	if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID,414					nodesize, 0)) {415		test_err("qgroup counts didn't match expected values");416		return -EINVAL;417	}418 419	if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FIRST_FREE_OBJECTID,420					nodesize, 0)) {421		test_err("qgroup counts didn't match expected values");422		return -EINVAL;423	}424 425	ret = btrfs_find_all_roots(&ctx, false);426	if (ret) {427		test_err("couldn't find old roots: %d", ret);428		return ret;429	}430	old_roots = ctx.roots;431	ctx.roots = NULL;432 433	ret = remove_extent_ref(root, nodesize, nodesize, 0,434				BTRFS_FIRST_FREE_OBJECTID);435	if (ret) {436		ulist_free(old_roots);437		return ret;438	}439 440	ret = btrfs_find_all_roots(&ctx, false);441	if (ret) {442		ulist_free(old_roots);443		test_err("couldn't find old roots: %d", ret);444		return ret;445	}446	new_roots = ctx.roots;447	ctx.roots = NULL;448 449	ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots,450					  new_roots);451	if (ret) {452		test_err("couldn't account space for a qgroup %d", ret);453		return ret;454	}455 456	if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FIRST_FREE_OBJECTID,457					0, 0)) {458		test_err("qgroup counts didn't match expected values");459		return -EINVAL;460	}461 462	if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID,463					nodesize, nodesize)) {464		test_err("qgroup counts didn't match expected values");465		return -EINVAL;466	}467 468	return 0;469}470 471int btrfs_test_qgroups(u32 sectorsize, u32 nodesize)472{473	struct btrfs_fs_info *fs_info = NULL;474	struct btrfs_root *root;475	struct btrfs_root *tmp_root;476	int ret = 0;477 478	fs_info = btrfs_alloc_dummy_fs_info(nodesize, sectorsize);479	if (!fs_info) {480		test_std_err(TEST_ALLOC_FS_INFO);481		return -ENOMEM;482	}483 484	root = btrfs_alloc_dummy_root(fs_info);485	if (IS_ERR(root)) {486		test_std_err(TEST_ALLOC_ROOT);487		ret = PTR_ERR(root);488		goto out;489	}490 491	/* We are using this root as our extent root */492	root->root_key.objectid = BTRFS_EXTENT_TREE_OBJECTID;493	root->root_key.type = BTRFS_ROOT_ITEM_KEY;494	root->root_key.offset = 0;495	btrfs_global_root_insert(root);496 497	/*498	 * Some of the paths we test assume we have a filled out fs_info, so we499	 * just need to add the root in there so we don't panic.500	 */501	root->fs_info->tree_root = root;502	root->fs_info->quota_root = root;503	set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);504 505	/*506	 * Can't use bytenr 0, some things freak out507	 * *cough*backref walking code*cough*508	 */509	root->node = alloc_test_extent_buffer(root->fs_info, nodesize);510	if (IS_ERR(root->node)) {511		test_err("couldn't allocate dummy buffer");512		ret = PTR_ERR(root->node);513		goto out;514	}515	btrfs_set_header_level(root->node, 0);516	btrfs_set_header_nritems(root->node, 0);517	root->alloc_bytenr += 2 * nodesize;518 519	tmp_root = btrfs_alloc_dummy_root(fs_info);520	if (IS_ERR(tmp_root)) {521		test_std_err(TEST_ALLOC_ROOT);522		ret = PTR_ERR(tmp_root);523		goto out;524	}525 526	tmp_root->root_key.objectid = BTRFS_FS_TREE_OBJECTID;527	root->fs_info->fs_root = tmp_root;528	ret = btrfs_insert_fs_root(root->fs_info, tmp_root);529	if (ret) {530		test_err("couldn't insert fs root %d", ret);531		goto out;532	}533	btrfs_put_root(tmp_root);534 535	tmp_root = btrfs_alloc_dummy_root(fs_info);536	if (IS_ERR(tmp_root)) {537		test_std_err(TEST_ALLOC_ROOT);538		ret = PTR_ERR(tmp_root);539		goto out;540	}541 542	tmp_root->root_key.objectid = BTRFS_FIRST_FREE_OBJECTID;543	ret = btrfs_insert_fs_root(root->fs_info, tmp_root);544	if (ret) {545		test_err("couldn't insert fs root %d", ret);546		goto out;547	}548	btrfs_put_root(tmp_root);549 550	test_msg("running qgroup tests");551	ret = test_no_shared_qgroup(root, sectorsize, nodesize);552	if (ret)553		goto out;554	ret = test_multiple_refs(root, sectorsize, nodesize);555out:556	btrfs_free_dummy_root(root);557	btrfs_free_dummy_fs_info(fs_info);558	return ret;559}560