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