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 25 static void init_dummy_trans(struct btrfs_trans_handle *trans) 26 { 27 memset(trans, 0, sizeof(*trans)); 28 trans->transid = 1; 29 INIT_LIST_HEAD(&trans->qgroup_ref_list); 30 trans->type = __TRANS_DUMMY; 31 } 32 33 static int insert_normal_tree_ref(struct btrfs_root *root, u64 bytenr, 34 u64 num_bytes, u64 parent, u64 root_objectid) 35 { 36 struct btrfs_trans_handle trans; 37 struct btrfs_extent_item *item; 38 struct btrfs_extent_inline_ref *iref; 39 struct btrfs_tree_block_info *block_info; 40 struct btrfs_path *path; 41 struct extent_buffer *leaf; 42 struct btrfs_key ins; 43 u32 size = sizeof(*item) + sizeof(*iref) + sizeof(*block_info); 44 int ret; 45 46 init_dummy_trans(&trans); 47 48 ins.objectid = bytenr; 49 ins.type = BTRFS_EXTENT_ITEM_KEY; 50 ins.offset = num_bytes; 51 52 path = btrfs_alloc_path(); 53 if (!path) { 54 test_msg("Couldn't allocate path\n"); 55 return -ENOMEM; 56 } 57 58 path->leave_spinning = 1; 59 ret = btrfs_insert_empty_item(&trans, root, path, &ins, size); 60 if (ret) { 61 test_msg("Couldn't insert ref %d\n", ret); 62 btrfs_free_path(path); 63 return ret; 64 } 65 66 leaf = path->nodes[0]; 67 item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); 68 btrfs_set_extent_refs(leaf, item, 1); 69 btrfs_set_extent_generation(leaf, item, 1); 70 btrfs_set_extent_flags(leaf, item, BTRFS_EXTENT_FLAG_TREE_BLOCK); 71 block_info = (struct btrfs_tree_block_info *)(item + 1); 72 btrfs_set_tree_block_level(leaf, block_info, 1); 73 iref = (struct btrfs_extent_inline_ref *)(block_info + 1); 74 if (parent > 0) { 75 btrfs_set_extent_inline_ref_type(leaf, iref, 76 BTRFS_SHARED_BLOCK_REF_KEY); 77 btrfs_set_extent_inline_ref_offset(leaf, iref, parent); 78 } else { 79 btrfs_set_extent_inline_ref_type(leaf, iref, BTRFS_TREE_BLOCK_REF_KEY); 80 btrfs_set_extent_inline_ref_offset(leaf, iref, root_objectid); 81 } 82 btrfs_free_path(path); 83 return 0; 84 } 85 86 static int add_tree_ref(struct btrfs_root *root, u64 bytenr, u64 num_bytes, 87 u64 parent, u64 root_objectid) 88 { 89 struct btrfs_trans_handle trans; 90 struct btrfs_extent_item *item; 91 struct btrfs_path *path; 92 struct btrfs_key key; 93 u64 refs; 94 int ret; 95 96 init_dummy_trans(&trans); 97 98 key.objectid = bytenr; 99 key.type = BTRFS_EXTENT_ITEM_KEY; 100 key.offset = num_bytes; 101 102 path = btrfs_alloc_path(); 103 if (!path) { 104 test_msg("Couldn't allocate path\n"); 105 return -ENOMEM; 106 } 107 108 path->leave_spinning = 1; 109 ret = btrfs_search_slot(&trans, root, &key, path, 0, 1); 110 if (ret) { 111 test_msg("Couldn't find extent ref\n"); 112 btrfs_free_path(path); 113 return ret; 114 } 115 116 item = btrfs_item_ptr(path->nodes[0], path->slots[0], 117 struct btrfs_extent_item); 118 refs = btrfs_extent_refs(path->nodes[0], item); 119 btrfs_set_extent_refs(path->nodes[0], item, refs + 1); 120 btrfs_release_path(path); 121 122 key.objectid = bytenr; 123 if (parent) { 124 key.type = BTRFS_SHARED_BLOCK_REF_KEY; 125 key.offset = parent; 126 } else { 127 key.type = BTRFS_TREE_BLOCK_REF_KEY; 128 key.offset = root_objectid; 129 } 130 131 ret = btrfs_insert_empty_item(&trans, root, path, &key, 0); 132 if (ret) 133 test_msg("Failed to insert backref\n"); 134 btrfs_free_path(path); 135 return ret; 136 } 137 138 static int remove_extent_item(struct btrfs_root *root, u64 bytenr, 139 u64 num_bytes) 140 { 141 struct btrfs_trans_handle trans; 142 struct btrfs_key key; 143 struct btrfs_path *path; 144 int ret; 145 146 init_dummy_trans(&trans); 147 148 key.objectid = bytenr; 149 key.type = BTRFS_EXTENT_ITEM_KEY; 150 key.offset = num_bytes; 151 152 path = btrfs_alloc_path(); 153 if (!path) { 154 test_msg("Couldn't allocate path\n"); 155 return -ENOMEM; 156 } 157 path->leave_spinning = 1; 158 159 ret = btrfs_search_slot(&trans, root, &key, path, -1, 1); 160 if (ret) { 161 test_msg("Didn't find our key %d\n", ret); 162 btrfs_free_path(path); 163 return ret; 164 } 165 btrfs_del_item(&trans, root, path); 166 btrfs_free_path(path); 167 return 0; 168 } 169 170 static int remove_extent_ref(struct btrfs_root *root, u64 bytenr, 171 u64 num_bytes, u64 parent, u64 root_objectid) 172 { 173 struct btrfs_trans_handle trans; 174 struct btrfs_extent_item *item; 175 struct btrfs_path *path; 176 struct btrfs_key key; 177 u64 refs; 178 int ret; 179 180 init_dummy_trans(&trans); 181 182 key.objectid = bytenr; 183 key.type = BTRFS_EXTENT_ITEM_KEY; 184 key.offset = num_bytes; 185 186 path = btrfs_alloc_path(); 187 if (!path) { 188 test_msg("Couldn't allocate path\n"); 189 return -ENOMEM; 190 } 191 192 path->leave_spinning = 1; 193 ret = btrfs_search_slot(&trans, root, &key, path, 0, 1); 194 if (ret) { 195 test_msg("Couldn't find extent ref\n"); 196 btrfs_free_path(path); 197 return ret; 198 } 199 200 item = btrfs_item_ptr(path->nodes[0], path->slots[0], 201 struct btrfs_extent_item); 202 refs = btrfs_extent_refs(path->nodes[0], item); 203 btrfs_set_extent_refs(path->nodes[0], item, refs - 1); 204 btrfs_release_path(path); 205 206 key.objectid = bytenr; 207 if (parent) { 208 key.type = BTRFS_SHARED_BLOCK_REF_KEY; 209 key.offset = parent; 210 } else { 211 key.type = BTRFS_TREE_BLOCK_REF_KEY; 212 key.offset = root_objectid; 213 } 214 215 ret = btrfs_search_slot(&trans, root, &key, path, -1, 1); 216 if (ret) { 217 test_msg("Couldn't find backref %d\n", ret); 218 btrfs_free_path(path); 219 return ret; 220 } 221 btrfs_del_item(&trans, root, path); 222 btrfs_free_path(path); 223 return ret; 224 } 225 226 static int test_no_shared_qgroup(struct btrfs_root *root) 227 { 228 struct btrfs_trans_handle trans; 229 struct btrfs_fs_info *fs_info = root->fs_info; 230 int ret; 231 232 init_dummy_trans(&trans); 233 234 test_msg("Qgroup basic add\n"); 235 ret = btrfs_create_qgroup(NULL, fs_info, 5, NULL); 236 if (ret) { 237 test_msg("Couldn't create a qgroup %d\n", ret); 238 return ret; 239 } 240 241 ret = btrfs_qgroup_record_ref(&trans, fs_info, 5, 4096, 4096, 242 BTRFS_QGROUP_OPER_ADD_EXCL, 0); 243 if (ret) { 244 test_msg("Couldn't add space to a qgroup %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_delayed_qgroup_accounting(&trans, fs_info); 253 if (ret) { 254 test_msg("Delayed qgroup accounting failed %d\n", ret); 255 return ret; 256 } 257 258 if (btrfs_verify_qgroup_counts(fs_info, 5, 4096, 4096)) { 259 test_msg("Qgroup counts didn't match expected values\n"); 260 return -EINVAL; 261 } 262 263 ret = remove_extent_item(root, 4096, 4096); 264 if (ret) 265 return -EINVAL; 266 267 ret = btrfs_qgroup_record_ref(&trans, fs_info, 5, 4096, 4096, 268 BTRFS_QGROUP_OPER_SUB_EXCL, 0); 269 if (ret) { 270 test_msg("Couldn't remove space from the qgroup %d\n", ret); 271 return -EINVAL; 272 } 273 274 ret = btrfs_delayed_qgroup_accounting(&trans, fs_info); 275 if (ret) { 276 test_msg("Qgroup accounting failed %d\n", ret); 277 return -EINVAL; 278 } 279 280 if (btrfs_verify_qgroup_counts(fs_info, 5, 0, 0)) { 281 test_msg("Qgroup counts didn't match expected values\n"); 282 return -EINVAL; 283 } 284 285 return 0; 286 } 287 288 /* 289 * Add a ref for two different roots to make sure the shared value comes out 290 * right, also remove one of the roots and make sure the exclusive count is 291 * adjusted properly. 292 */ 293 static int test_multiple_refs(struct btrfs_root *root) 294 { 295 struct btrfs_trans_handle trans; 296 struct btrfs_fs_info *fs_info = root->fs_info; 297 int ret; 298 299 init_dummy_trans(&trans); 300 301 test_msg("Qgroup multiple refs test\n"); 302 303 /* We have 5 created already from the previous test */ 304 ret = btrfs_create_qgroup(NULL, fs_info, 256, NULL); 305 if (ret) { 306 test_msg("Couldn't create a qgroup %d\n", ret); 307 return ret; 308 } 309 310 ret = insert_normal_tree_ref(root, 4096, 4096, 0, 5); 311 if (ret) 312 return ret; 313 314 ret = btrfs_qgroup_record_ref(&trans, fs_info, 5, 4096, 4096, 315 BTRFS_QGROUP_OPER_ADD_EXCL, 0); 316 if (ret) { 317 test_msg("Couldn't add space to a qgroup %d\n", ret); 318 return ret; 319 } 320 321 ret = btrfs_delayed_qgroup_accounting(&trans, fs_info); 322 if (ret) { 323 test_msg("Delayed qgroup accounting failed %d\n", ret); 324 return ret; 325 } 326 327 if (btrfs_verify_qgroup_counts(fs_info, 5, 4096, 4096)) { 328 test_msg("Qgroup counts didn't match expected values\n"); 329 return -EINVAL; 330 } 331 332 ret = add_tree_ref(root, 4096, 4096, 0, 256); 333 if (ret) 334 return ret; 335 336 ret = btrfs_qgroup_record_ref(&trans, fs_info, 256, 4096, 4096, 337 BTRFS_QGROUP_OPER_ADD_SHARED, 0); 338 if (ret) { 339 test_msg("Qgroup record ref failed %d\n", ret); 340 return ret; 341 } 342 343 ret = btrfs_delayed_qgroup_accounting(&trans, fs_info); 344 if (ret) { 345 test_msg("Qgroup accounting failed %d\n", ret); 346 return ret; 347 } 348 349 if (btrfs_verify_qgroup_counts(fs_info, 5, 4096, 0)) { 350 test_msg("Qgroup counts didn't match expected values\n"); 351 return -EINVAL; 352 } 353 354 if (btrfs_verify_qgroup_counts(fs_info, 256, 4096, 0)) { 355 test_msg("Qgroup counts didn't match expected values\n"); 356 return -EINVAL; 357 } 358 359 ret = remove_extent_ref(root, 4096, 4096, 0, 256); 360 if (ret) 361 return ret; 362 363 ret = btrfs_qgroup_record_ref(&trans, fs_info, 256, 4096, 4096, 364 BTRFS_QGROUP_OPER_SUB_SHARED, 0); 365 if (ret) { 366 test_msg("Qgroup record ref failed %d\n", ret); 367 return ret; 368 } 369 370 ret = btrfs_delayed_qgroup_accounting(&trans, fs_info); 371 if (ret) { 372 test_msg("Qgroup accounting failed %d\n", ret); 373 return ret; 374 } 375 376 if (btrfs_verify_qgroup_counts(fs_info, 256, 0, 0)) { 377 test_msg("Qgroup counts didn't match expected values\n"); 378 return -EINVAL; 379 } 380 381 if (btrfs_verify_qgroup_counts(fs_info, 5, 4096, 4096)) { 382 test_msg("Qgroup counts didn't match expected values\n"); 383 return -EINVAL; 384 } 385 386 return 0; 387 } 388 389 int btrfs_test_qgroups(void) 390 { 391 struct btrfs_root *root; 392 struct btrfs_root *tmp_root; 393 int ret = 0; 394 395 root = btrfs_alloc_dummy_root(); 396 if (IS_ERR(root)) { 397 test_msg("Couldn't allocate root\n"); 398 return PTR_ERR(root); 399 } 400 401 root->fs_info = btrfs_alloc_dummy_fs_info(); 402 if (!root->fs_info) { 403 test_msg("Couldn't allocate dummy fs info\n"); 404 ret = -ENOMEM; 405 goto out; 406 } 407 408 /* 409 * Can't use bytenr 0, some things freak out 410 * *cough*backref walking code*cough* 411 */ 412 root->node = alloc_test_extent_buffer(root->fs_info, 4096, 4096); 413 if (!root->node) { 414 test_msg("Couldn't allocate dummy buffer\n"); 415 ret = -ENOMEM; 416 goto out; 417 } 418 btrfs_set_header_level(root->node, 0); 419 btrfs_set_header_nritems(root->node, 0); 420 root->alloc_bytenr += 8192; 421 422 tmp_root = btrfs_alloc_dummy_root(); 423 if (IS_ERR(tmp_root)) { 424 test_msg("Couldn't allocate a fs root\n"); 425 ret = PTR_ERR(tmp_root); 426 goto out; 427 } 428 429 tmp_root->root_key.objectid = 5; 430 root->fs_info->fs_root = tmp_root; 431 ret = btrfs_insert_fs_root(root->fs_info, tmp_root); 432 if (ret) { 433 test_msg("Couldn't insert fs root %d\n", ret); 434 goto out; 435 } 436 437 tmp_root = btrfs_alloc_dummy_root(); 438 if (IS_ERR(tmp_root)) { 439 test_msg("Couldn't allocate a fs root\n"); 440 ret = PTR_ERR(tmp_root); 441 goto out; 442 } 443 444 tmp_root->root_key.objectid = 256; 445 ret = btrfs_insert_fs_root(root->fs_info, tmp_root); 446 if (ret) { 447 test_msg("Couldn't insert fs root %d\n", ret); 448 goto out; 449 } 450 451 /* We are using this root as our extent root */ 452 root->fs_info->extent_root = root; 453 454 /* 455 * Some of the paths we test assume we have a filled out fs_info, so we 456 * just need to addt he root in there so we don't panic. 457 */ 458 root->fs_info->tree_root = root; 459 root->fs_info->quota_root = root; 460 root->fs_info->quota_enabled = 1; 461 462 test_msg("Running qgroup tests\n"); 463 ret = test_no_shared_qgroup(root); 464 if (ret) 465 goto out; 466 ret = test_multiple_refs(root); 467 out: 468 btrfs_free_dummy_root(root); 469 return ret; 470 } 471