1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2013 Fusion IO. All rights reserved. 4 */ 5 6 #include <linux/types.h> 7 #include "btrfs-tests.h" 8 #include "../ctree.h" 9 #include "../btrfs_inode.h" 10 #include "../disk-io.h" 11 #include "../extent_io.h" 12 #include "../volumes.h" 13 #include "../compression.h" 14 15 static void insert_extent(struct btrfs_root *root, u64 start, u64 len, 16 u64 ram_bytes, u64 offset, u64 disk_bytenr, 17 u64 disk_len, u32 type, u8 compression, int slot) 18 { 19 struct btrfs_path path; 20 struct btrfs_file_extent_item *fi; 21 struct extent_buffer *leaf = root->node; 22 struct btrfs_key key; 23 u32 value_len = sizeof(struct btrfs_file_extent_item); 24 25 if (type == BTRFS_FILE_EXTENT_INLINE) 26 value_len += len; 27 memset(&path, 0, sizeof(path)); 28 29 path.nodes[0] = leaf; 30 path.slots[0] = slot; 31 32 key.objectid = BTRFS_FIRST_FREE_OBJECTID; 33 key.type = BTRFS_EXTENT_DATA_KEY; 34 key.offset = start; 35 36 setup_items_for_insert(root, &path, &key, &value_len, 1); 37 fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); 38 btrfs_set_file_extent_generation(leaf, fi, 1); 39 btrfs_set_file_extent_type(leaf, fi, type); 40 btrfs_set_file_extent_disk_bytenr(leaf, fi, disk_bytenr); 41 btrfs_set_file_extent_disk_num_bytes(leaf, fi, disk_len); 42 btrfs_set_file_extent_offset(leaf, fi, offset); 43 btrfs_set_file_extent_num_bytes(leaf, fi, len); 44 btrfs_set_file_extent_ram_bytes(leaf, fi, ram_bytes); 45 btrfs_set_file_extent_compression(leaf, fi, compression); 46 btrfs_set_file_extent_encryption(leaf, fi, 0); 47 btrfs_set_file_extent_other_encoding(leaf, fi, 0); 48 } 49 50 static void insert_inode_item_key(struct btrfs_root *root) 51 { 52 struct btrfs_path path; 53 struct extent_buffer *leaf = root->node; 54 struct btrfs_key key; 55 u32 value_len = 0; 56 57 memset(&path, 0, sizeof(path)); 58 59 path.nodes[0] = leaf; 60 path.slots[0] = 0; 61 62 key.objectid = BTRFS_INODE_ITEM_KEY; 63 key.type = BTRFS_INODE_ITEM_KEY; 64 key.offset = 0; 65 66 setup_items_for_insert(root, &path, &key, &value_len, 1); 67 } 68 69 /* 70 * Build the most complicated map of extents the earth has ever seen. We want 71 * this so we can test all of the corner cases of btrfs_get_extent. Here is a 72 * diagram of how the extents will look though this may not be possible we still 73 * want to make sure everything acts normally (the last number is not inclusive) 74 * 75 * [0 - 5][5 - 6][ 6 - 4096 ][ 4096 - 4100][4100 - 8195][8195 - 12291] 76 * [hole ][inline][hole but no extent][ hole ][ regular ][regular1 split] 77 * 78 * [12291 - 16387][16387 - 24579][24579 - 28675][ 28675 - 32771][32771 - 36867 ] 79 * [ hole ][regular1 split][ prealloc ][ prealloc1 ][prealloc1 written] 80 * 81 * [36867 - 45059][45059 - 53251][53251 - 57347][57347 - 61443][61443- 69635] 82 * [ prealloc1 ][ compressed ][ compressed1 ][ regular ][ compressed1] 83 * 84 * [69635-73731][ 73731 - 86019 ][86019-90115] 85 * [ regular ][ hole but no extent][ regular ] 86 */ 87 static void setup_file_extents(struct btrfs_root *root, u32 sectorsize) 88 { 89 int slot = 0; 90 u64 disk_bytenr = SZ_1M; 91 u64 offset = 0; 92 93 /* First we want a hole */ 94 insert_extent(root, offset, 5, 5, 0, 0, 0, BTRFS_FILE_EXTENT_REG, 0, 95 slot); 96 slot++; 97 offset += 5; 98 99 /* 100 * Now we want an inline extent, I don't think this is possible but hey 101 * why not? Also keep in mind if we have an inline extent it counts as 102 * the whole first page. If we were to expand it we would have to cow 103 * and we wouldn't have an inline extent anymore. 104 */ 105 insert_extent(root, offset, 1, 1, 0, 0, 0, BTRFS_FILE_EXTENT_INLINE, 0, 106 slot); 107 slot++; 108 offset = sectorsize; 109 110 /* Now another hole */ 111 insert_extent(root, offset, 4, 4, 0, 0, 0, BTRFS_FILE_EXTENT_REG, 0, 112 slot); 113 slot++; 114 offset += 4; 115 116 /* Now for a regular extent */ 117 insert_extent(root, offset, sectorsize - 1, sectorsize - 1, 0, 118 disk_bytenr, sectorsize, BTRFS_FILE_EXTENT_REG, 0, slot); 119 slot++; 120 disk_bytenr += sectorsize; 121 offset += sectorsize - 1; 122 123 /* 124 * Now for 3 extents that were split from a hole punch so we test 125 * offsets properly. 126 */ 127 insert_extent(root, offset, sectorsize, 4 * sectorsize, 0, disk_bytenr, 128 4 * sectorsize, BTRFS_FILE_EXTENT_REG, 0, slot); 129 slot++; 130 offset += sectorsize; 131 insert_extent(root, offset, sectorsize, sectorsize, 0, 0, 0, 132 BTRFS_FILE_EXTENT_REG, 0, slot); 133 slot++; 134 offset += sectorsize; 135 insert_extent(root, offset, 2 * sectorsize, 4 * sectorsize, 136 2 * sectorsize, disk_bytenr, 4 * sectorsize, 137 BTRFS_FILE_EXTENT_REG, 0, slot); 138 slot++; 139 offset += 2 * sectorsize; 140 disk_bytenr += 4 * sectorsize; 141 142 /* Now for a unwritten prealloc extent */ 143 insert_extent(root, offset, sectorsize, sectorsize, 0, disk_bytenr, 144 sectorsize, BTRFS_FILE_EXTENT_PREALLOC, 0, slot); 145 slot++; 146 offset += sectorsize; 147 148 /* 149 * We want to jack up disk_bytenr a little more so the em stuff doesn't 150 * merge our records. 151 */ 152 disk_bytenr += 2 * sectorsize; 153 154 /* 155 * Now for a partially written prealloc extent, basically the same as 156 * the hole punch example above. Ram_bytes never changes when you mark 157 * extents written btw. 158 */ 159 insert_extent(root, offset, sectorsize, 4 * sectorsize, 0, disk_bytenr, 160 4 * sectorsize, BTRFS_FILE_EXTENT_PREALLOC, 0, slot); 161 slot++; 162 offset += sectorsize; 163 insert_extent(root, offset, sectorsize, 4 * sectorsize, sectorsize, 164 disk_bytenr, 4 * sectorsize, BTRFS_FILE_EXTENT_REG, 0, 165 slot); 166 slot++; 167 offset += sectorsize; 168 insert_extent(root, offset, 2 * sectorsize, 4 * sectorsize, 169 2 * sectorsize, disk_bytenr, 4 * sectorsize, 170 BTRFS_FILE_EXTENT_PREALLOC, 0, slot); 171 slot++; 172 offset += 2 * sectorsize; 173 disk_bytenr += 4 * sectorsize; 174 175 /* Now a normal compressed extent */ 176 insert_extent(root, offset, 2 * sectorsize, 2 * sectorsize, 0, 177 disk_bytenr, sectorsize, BTRFS_FILE_EXTENT_REG, 178 BTRFS_COMPRESS_ZLIB, slot); 179 slot++; 180 offset += 2 * sectorsize; 181 /* No merges */ 182 disk_bytenr += 2 * sectorsize; 183 184 /* Now a split compressed extent */ 185 insert_extent(root, offset, sectorsize, 4 * sectorsize, 0, disk_bytenr, 186 sectorsize, BTRFS_FILE_EXTENT_REG, 187 BTRFS_COMPRESS_ZLIB, slot); 188 slot++; 189 offset += sectorsize; 190 insert_extent(root, offset, sectorsize, sectorsize, 0, 191 disk_bytenr + sectorsize, sectorsize, 192 BTRFS_FILE_EXTENT_REG, 0, slot); 193 slot++; 194 offset += sectorsize; 195 insert_extent(root, offset, 2 * sectorsize, 4 * sectorsize, 196 2 * sectorsize, disk_bytenr, sectorsize, 197 BTRFS_FILE_EXTENT_REG, BTRFS_COMPRESS_ZLIB, slot); 198 slot++; 199 offset += 2 * sectorsize; 200 disk_bytenr += 2 * sectorsize; 201 202 /* Now extents that have a hole but no hole extent */ 203 insert_extent(root, offset, sectorsize, sectorsize, 0, disk_bytenr, 204 sectorsize, BTRFS_FILE_EXTENT_REG, 0, slot); 205 slot++; 206 offset += 4 * sectorsize; 207 disk_bytenr += sectorsize; 208 insert_extent(root, offset, sectorsize, sectorsize, 0, disk_bytenr, 209 sectorsize, BTRFS_FILE_EXTENT_REG, 0, slot); 210 } 211 212 static unsigned long prealloc_only = 0; 213 static unsigned long compressed_only = 0; 214 static unsigned long vacancy_only = 0; 215 216 static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize) 217 { 218 struct btrfs_fs_info *fs_info = NULL; 219 struct inode *inode = NULL; 220 struct btrfs_root *root = NULL; 221 struct extent_map *em = NULL; 222 u64 orig_start; 223 u64 disk_bytenr; 224 u64 offset; 225 int ret = -ENOMEM; 226 227 test_msg("running btrfs_get_extent tests"); 228 229 inode = btrfs_new_test_inode(); 230 if (!inode) { 231 test_std_err(TEST_ALLOC_INODE); 232 return ret; 233 } 234 235 inode->i_mode = S_IFREG; 236 BTRFS_I(inode)->location.type = BTRFS_INODE_ITEM_KEY; 237 BTRFS_I(inode)->location.objectid = BTRFS_FIRST_FREE_OBJECTID; 238 BTRFS_I(inode)->location.offset = 0; 239 240 fs_info = btrfs_alloc_dummy_fs_info(nodesize, sectorsize); 241 if (!fs_info) { 242 test_std_err(TEST_ALLOC_FS_INFO); 243 goto out; 244 } 245 246 root = btrfs_alloc_dummy_root(fs_info); 247 if (IS_ERR(root)) { 248 test_std_err(TEST_ALLOC_ROOT); 249 goto out; 250 } 251 252 root->node = alloc_dummy_extent_buffer(fs_info, nodesize); 253 if (!root->node) { 254 test_std_err(TEST_ALLOC_ROOT); 255 goto out; 256 } 257 258 btrfs_set_header_nritems(root->node, 0); 259 btrfs_set_header_level(root->node, 0); 260 ret = -EINVAL; 261 262 /* First with no extents */ 263 BTRFS_I(inode)->root = root; 264 em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, 0, sectorsize); 265 if (IS_ERR(em)) { 266 em = NULL; 267 test_err("got an error when we shouldn't have"); 268 goto out; 269 } 270 if (em->block_start != EXTENT_MAP_HOLE) { 271 test_err("expected a hole, got %llu", em->block_start); 272 goto out; 273 } 274 free_extent_map(em); 275 btrfs_drop_extent_cache(BTRFS_I(inode), 0, (u64)-1, 0); 276 277 /* 278 * All of the magic numbers are based on the mapping setup in 279 * setup_file_extents, so if you change anything there you need to 280 * update the comment and update the expected values below. 281 */ 282 setup_file_extents(root, sectorsize); 283 284 em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, 0, (u64)-1); 285 if (IS_ERR(em)) { 286 test_err("got an error when we shouldn't have"); 287 goto out; 288 } 289 if (em->block_start != EXTENT_MAP_HOLE) { 290 test_err("expected a hole, got %llu", em->block_start); 291 goto out; 292 } 293 if (em->start != 0 || em->len != 5) { 294 test_err( 295 "unexpected extent wanted start 0 len 5, got start %llu len %llu", 296 em->start, em->len); 297 goto out; 298 } 299 if (em->flags != 0) { 300 test_err("unexpected flags set, want 0 have %lu", em->flags); 301 goto out; 302 } 303 offset = em->start + em->len; 304 free_extent_map(em); 305 306 em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize); 307 if (IS_ERR(em)) { 308 test_err("got an error when we shouldn't have"); 309 goto out; 310 } 311 if (em->block_start != EXTENT_MAP_INLINE) { 312 test_err("expected an inline, got %llu", em->block_start); 313 goto out; 314 } 315 316 if (em->start != offset || em->len != (sectorsize - 5)) { 317 test_err( 318 "unexpected extent wanted start %llu len 1, got start %llu len %llu", 319 offset, em->start, em->len); 320 goto out; 321 } 322 if (em->flags != 0) { 323 test_err("unexpected flags set, want 0 have %lu", em->flags); 324 goto out; 325 } 326 /* 327 * We don't test anything else for inline since it doesn't get set 328 * unless we have a page for it to write into. Maybe we should change 329 * this? 330 */ 331 offset = em->start + em->len; 332 free_extent_map(em); 333 334 em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize); 335 if (IS_ERR(em)) { 336 test_err("got an error when we shouldn't have"); 337 goto out; 338 } 339 if (em->block_start != EXTENT_MAP_HOLE) { 340 test_err("expected a hole, got %llu", em->block_start); 341 goto out; 342 } 343 if (em->start != offset || em->len != 4) { 344 test_err( 345 "unexpected extent wanted start %llu len 4, got start %llu len %llu", 346 offset, em->start, em->len); 347 goto out; 348 } 349 if (em->flags != 0) { 350 test_err("unexpected flags set, want 0 have %lu", em->flags); 351 goto out; 352 } 353 offset = em->start + em->len; 354 free_extent_map(em); 355 356 /* Regular extent */ 357 em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize); 358 if (IS_ERR(em)) { 359 test_err("got an error when we shouldn't have"); 360 goto out; 361 } 362 if (em->block_start >= EXTENT_MAP_LAST_BYTE) { 363 test_err("expected a real extent, got %llu", em->block_start); 364 goto out; 365 } 366 if (em->start != offset || em->len != sectorsize - 1) { 367 test_err( 368 "unexpected extent wanted start %llu len 4095, got start %llu len %llu", 369 offset, em->start, em->len); 370 goto out; 371 } 372 if (em->flags != 0) { 373 test_err("unexpected flags set, want 0 have %lu", em->flags); 374 goto out; 375 } 376 if (em->orig_start != em->start) { 377 test_err("wrong orig offset, want %llu, have %llu", em->start, 378 em->orig_start); 379 goto out; 380 } 381 offset = em->start + em->len; 382 free_extent_map(em); 383 384 /* The next 3 are split extents */ 385 em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize); 386 if (IS_ERR(em)) { 387 test_err("got an error when we shouldn't have"); 388 goto out; 389 } 390 if (em->block_start >= EXTENT_MAP_LAST_BYTE) { 391 test_err("expected a real extent, got %llu", em->block_start); 392 goto out; 393 } 394 if (em->start != offset || em->len != sectorsize) { 395 test_err( 396 "unexpected extent start %llu len %u, got start %llu len %llu", 397 offset, sectorsize, em->start, em->len); 398 goto out; 399 } 400 if (em->flags != 0) { 401 test_err("unexpected flags set, want 0 have %lu", em->flags); 402 goto out; 403 } 404 if (em->orig_start != em->start) { 405 test_err("wrong orig offset, want %llu, have %llu", em->start, 406 em->orig_start); 407 goto out; 408 } 409 disk_bytenr = em->block_start; 410 orig_start = em->start; 411 offset = em->start + em->len; 412 free_extent_map(em); 413 414 em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize); 415 if (IS_ERR(em)) { 416 test_err("got an error when we shouldn't have"); 417 goto out; 418 } 419 if (em->block_start != EXTENT_MAP_HOLE) { 420 test_err("expected a hole, got %llu", em->block_start); 421 goto out; 422 } 423 if (em->start != offset || em->len != sectorsize) { 424 test_err( 425 "unexpected extent wanted start %llu len %u, got start %llu len %llu", 426 offset, sectorsize, em->start, em->len); 427 goto out; 428 } 429 if (em->flags != 0) { 430 test_err("unexpected flags set, want 0 have %lu", em->flags); 431 goto out; 432 } 433 offset = em->start + em->len; 434 free_extent_map(em); 435 436 em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize); 437 if (IS_ERR(em)) { 438 test_err("got an error when we shouldn't have"); 439 goto out; 440 } 441 if (em->block_start >= EXTENT_MAP_LAST_BYTE) { 442 test_err("expected a real extent, got %llu", em->block_start); 443 goto out; 444 } 445 if (em->start != offset || em->len != 2 * sectorsize) { 446 test_err( 447 "unexpected extent wanted start %llu len %u, got start %llu len %llu", 448 offset, 2 * sectorsize, em->start, em->len); 449 goto out; 450 } 451 if (em->flags != 0) { 452 test_err("unexpected flags set, want 0 have %lu", em->flags); 453 goto out; 454 } 455 if (em->orig_start != orig_start) { 456 test_err("wrong orig offset, want %llu, have %llu", 457 orig_start, em->orig_start); 458 goto out; 459 } 460 disk_bytenr += (em->start - orig_start); 461 if (em->block_start != disk_bytenr) { 462 test_err("wrong block start, want %llu, have %llu", 463 disk_bytenr, em->block_start); 464 goto out; 465 } 466 offset = em->start + em->len; 467 free_extent_map(em); 468 469 /* Prealloc extent */ 470 em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize); 471 if (IS_ERR(em)) { 472 test_err("got an error when we shouldn't have"); 473 goto out; 474 } 475 if (em->block_start >= EXTENT_MAP_LAST_BYTE) { 476 test_err("expected a real extent, got %llu", em->block_start); 477 goto out; 478 } 479 if (em->start != offset || em->len != sectorsize) { 480 test_err( 481 "unexpected extent wanted start %llu len %u, got start %llu len %llu", 482 offset, sectorsize, em->start, em->len); 483 goto out; 484 } 485 if (em->flags != prealloc_only) { 486 test_err("unexpected flags set, want %lu have %lu", 487 prealloc_only, em->flags); 488 goto out; 489 } 490 if (em->orig_start != em->start) { 491 test_err("wrong orig offset, want %llu, have %llu", em->start, 492 em->orig_start); 493 goto out; 494 } 495 offset = em->start + em->len; 496 free_extent_map(em); 497 498 /* The next 3 are a half written prealloc extent */ 499 em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize); 500 if (IS_ERR(em)) { 501 test_err("got an error when we shouldn't have"); 502 goto out; 503 } 504 if (em->block_start >= EXTENT_MAP_LAST_BYTE) { 505 test_err("expected a real extent, got %llu", em->block_start); 506 goto out; 507 } 508 if (em->start != offset || em->len != sectorsize) { 509 test_err( 510 "unexpected extent wanted start %llu len %u, got start %llu len %llu", 511 offset, sectorsize, em->start, em->len); 512 goto out; 513 } 514 if (em->flags != prealloc_only) { 515 test_err("unexpected flags set, want %lu have %lu", 516 prealloc_only, em->flags); 517 goto out; 518 } 519 if (em->orig_start != em->start) { 520 test_err("wrong orig offset, want %llu, have %llu", em->start, 521 em->orig_start); 522 goto out; 523 } 524 disk_bytenr = em->block_start; 525 orig_start = em->start; 526 offset = em->start + em->len; 527 free_extent_map(em); 528 529 em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize); 530 if (IS_ERR(em)) { 531 test_err("got an error when we shouldn't have"); 532 goto out; 533 } 534 if (em->block_start >= EXTENT_MAP_HOLE) { 535 test_err("expected a real extent, got %llu", em->block_start); 536 goto out; 537 } 538 if (em->start != offset || em->len != sectorsize) { 539 test_err( 540 "unexpected extent wanted start %llu len %u, got start %llu len %llu", 541 offset, sectorsize, em->start, em->len); 542 goto out; 543 } 544 if (em->flags != 0) { 545 test_err("unexpected flags set, want 0 have %lu", em->flags); 546 goto out; 547 } 548 if (em->orig_start != orig_start) { 549 test_err("unexpected orig offset, wanted %llu, have %llu", 550 orig_start, em->orig_start); 551 goto out; 552 } 553 if (em->block_start != (disk_bytenr + (em->start - em->orig_start))) { 554 test_err("unexpected block start, wanted %llu, have %llu", 555 disk_bytenr + (em->start - em->orig_start), 556 em->block_start); 557 goto out; 558 } 559 offset = em->start + em->len; 560 free_extent_map(em); 561 562 em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize); 563 if (IS_ERR(em)) { 564 test_err("got an error when we shouldn't have"); 565 goto out; 566 } 567 if (em->block_start >= EXTENT_MAP_LAST_BYTE) { 568 test_err("expected a real extent, got %llu", em->block_start); 569 goto out; 570 } 571 if (em->start != offset || em->len != 2 * sectorsize) { 572 test_err( 573 "unexpected extent wanted start %llu len %u, got start %llu len %llu", 574 offset, 2 * sectorsize, em->start, em->len); 575 goto out; 576 } 577 if (em->flags != prealloc_only) { 578 test_err("unexpected flags set, want %lu have %lu", 579 prealloc_only, em->flags); 580 goto out; 581 } 582 if (em->orig_start != orig_start) { 583 test_err("wrong orig offset, want %llu, have %llu", orig_start, 584 em->orig_start); 585 goto out; 586 } 587 if (em->block_start != (disk_bytenr + (em->start - em->orig_start))) { 588 test_err("unexpected block start, wanted %llu, have %llu", 589 disk_bytenr + (em->start - em->orig_start), 590 em->block_start); 591 goto out; 592 } 593 offset = em->start + em->len; 594 free_extent_map(em); 595 596 /* Now for the compressed extent */ 597 em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize); 598 if (IS_ERR(em)) { 599 test_err("got an error when we shouldn't have"); 600 goto out; 601 } 602 if (em->block_start >= EXTENT_MAP_LAST_BYTE) { 603 test_err("expected a real extent, got %llu", em->block_start); 604 goto out; 605 } 606 if (em->start != offset || em->len != 2 * sectorsize) { 607 test_err( 608 "unexpected extent wanted start %llu len %u, got start %llu len %llu", 609 offset, 2 * sectorsize, em->start, em->len); 610 goto out; 611 } 612 if (em->flags != compressed_only) { 613 test_err("unexpected flags set, want %lu have %lu", 614 compressed_only, em->flags); 615 goto out; 616 } 617 if (em->orig_start != em->start) { 618 test_err("wrong orig offset, want %llu, have %llu", 619 em->start, em->orig_start); 620 goto out; 621 } 622 if (em->compress_type != BTRFS_COMPRESS_ZLIB) { 623 test_err("unexpected compress type, wanted %d, got %d", 624 BTRFS_COMPRESS_ZLIB, em->compress_type); 625 goto out; 626 } 627 offset = em->start + em->len; 628 free_extent_map(em); 629 630 /* Split compressed extent */ 631 em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize); 632 if (IS_ERR(em)) { 633 test_err("got an error when we shouldn't have"); 634 goto out; 635 } 636 if (em->block_start >= EXTENT_MAP_LAST_BYTE) { 637 test_err("expected a real extent, got %llu", em->block_start); 638 goto out; 639 } 640 if (em->start != offset || em->len != sectorsize) { 641 test_err( 642 "unexpected extent wanted start %llu len %u, got start %llu len %llu", 643 offset, sectorsize, em->start, em->len); 644 goto out; 645 } 646 if (em->flags != compressed_only) { 647 test_err("unexpected flags set, want %lu have %lu", 648 compressed_only, em->flags); 649 goto out; 650 } 651 if (em->orig_start != em->start) { 652 test_err("wrong orig offset, want %llu, have %llu", 653 em->start, em->orig_start); 654 goto out; 655 } 656 if (em->compress_type != BTRFS_COMPRESS_ZLIB) { 657 test_err("unexpected compress type, wanted %d, got %d", 658 BTRFS_COMPRESS_ZLIB, em->compress_type); 659 goto out; 660 } 661 disk_bytenr = em->block_start; 662 orig_start = em->start; 663 offset = em->start + em->len; 664 free_extent_map(em); 665 666 em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize); 667 if (IS_ERR(em)) { 668 test_err("got an error when we shouldn't have"); 669 goto out; 670 } 671 if (em->block_start >= EXTENT_MAP_LAST_BYTE) { 672 test_err("expected a real extent, got %llu", em->block_start); 673 goto out; 674 } 675 if (em->start != offset || em->len != sectorsize) { 676 test_err( 677 "unexpected extent wanted start %llu len %u, got start %llu len %llu", 678 offset, sectorsize, em->start, em->len); 679 goto out; 680 } 681 if (em->flags != 0) { 682 test_err("unexpected flags set, want 0 have %lu", em->flags); 683 goto out; 684 } 685 if (em->orig_start != em->start) { 686 test_err("wrong orig offset, want %llu, have %llu", em->start, 687 em->orig_start); 688 goto out; 689 } 690 offset = em->start + em->len; 691 free_extent_map(em); 692 693 em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize); 694 if (IS_ERR(em)) { 695 test_err("got an error when we shouldn't have"); 696 goto out; 697 } 698 if (em->block_start != disk_bytenr) { 699 test_err("block start does not match, want %llu got %llu", 700 disk_bytenr, em->block_start); 701 goto out; 702 } 703 if (em->start != offset || em->len != 2 * sectorsize) { 704 test_err( 705 "unexpected extent wanted start %llu len %u, got start %llu len %llu", 706 offset, 2 * sectorsize, em->start, em->len); 707 goto out; 708 } 709 if (em->flags != compressed_only) { 710 test_err("unexpected flags set, want %lu have %lu", 711 compressed_only, em->flags); 712 goto out; 713 } 714 if (em->orig_start != orig_start) { 715 test_err("wrong orig offset, want %llu, have %llu", 716 em->start, orig_start); 717 goto out; 718 } 719 if (em->compress_type != BTRFS_COMPRESS_ZLIB) { 720 test_err("unexpected compress type, wanted %d, got %d", 721 BTRFS_COMPRESS_ZLIB, em->compress_type); 722 goto out; 723 } 724 offset = em->start + em->len; 725 free_extent_map(em); 726 727 /* A hole between regular extents but no hole extent */ 728 em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset + 6, sectorsize); 729 if (IS_ERR(em)) { 730 test_err("got an error when we shouldn't have"); 731 goto out; 732 } 733 if (em->block_start >= EXTENT_MAP_LAST_BYTE) { 734 test_err("expected a real extent, got %llu", em->block_start); 735 goto out; 736 } 737 if (em->start != offset || em->len != sectorsize) { 738 test_err( 739 "unexpected extent wanted start %llu len %u, got start %llu len %llu", 740 offset, sectorsize, em->start, em->len); 741 goto out; 742 } 743 if (em->flags != 0) { 744 test_err("unexpected flags set, want 0 have %lu", em->flags); 745 goto out; 746 } 747 if (em->orig_start != em->start) { 748 test_err("wrong orig offset, want %llu, have %llu", em->start, 749 em->orig_start); 750 goto out; 751 } 752 offset = em->start + em->len; 753 free_extent_map(em); 754 755 em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, SZ_4M); 756 if (IS_ERR(em)) { 757 test_err("got an error when we shouldn't have"); 758 goto out; 759 } 760 if (em->block_start != EXTENT_MAP_HOLE) { 761 test_err("expected a hole extent, got %llu", em->block_start); 762 goto out; 763 } 764 /* 765 * Currently we just return a length that we requested rather than the 766 * length of the actual hole, if this changes we'll have to change this 767 * test. 768 */ 769 if (em->start != offset || em->len != 3 * sectorsize) { 770 test_err( 771 "unexpected extent wanted start %llu len %u, got start %llu len %llu", 772 offset, 3 * sectorsize, em->start, em->len); 773 goto out; 774 } 775 if (em->flags != vacancy_only) { 776 test_err("unexpected flags set, want %lu have %lu", 777 vacancy_only, em->flags); 778 goto out; 779 } 780 if (em->orig_start != em->start) { 781 test_err("wrong orig offset, want %llu, have %llu", em->start, 782 em->orig_start); 783 goto out; 784 } 785 offset = em->start + em->len; 786 free_extent_map(em); 787 788 em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize); 789 if (IS_ERR(em)) { 790 test_err("got an error when we shouldn't have"); 791 goto out; 792 } 793 if (em->block_start >= EXTENT_MAP_LAST_BYTE) { 794 test_err("expected a real extent, got %llu", em->block_start); 795 goto out; 796 } 797 if (em->start != offset || em->len != sectorsize) { 798 test_err( 799 "unexpected extent wanted start %llu len %u, got start %llu len %llu", 800 offset, sectorsize, em->start, em->len); 801 goto out; 802 } 803 if (em->flags != 0) { 804 test_err("unexpected flags set, want 0 have %lu", em->flags); 805 goto out; 806 } 807 if (em->orig_start != em->start) { 808 test_err("wrong orig offset, want %llu, have %llu", em->start, 809 em->orig_start); 810 goto out; 811 } 812 ret = 0; 813 out: 814 if (!IS_ERR(em)) 815 free_extent_map(em); 816 iput(inode); 817 btrfs_free_dummy_root(root); 818 btrfs_free_dummy_fs_info(fs_info); 819 return ret; 820 } 821 822 static int test_hole_first(u32 sectorsize, u32 nodesize) 823 { 824 struct btrfs_fs_info *fs_info = NULL; 825 struct inode *inode = NULL; 826 struct btrfs_root *root = NULL; 827 struct extent_map *em = NULL; 828 int ret = -ENOMEM; 829 830 test_msg("running hole first btrfs_get_extent test"); 831 832 inode = btrfs_new_test_inode(); 833 if (!inode) { 834 test_std_err(TEST_ALLOC_INODE); 835 return ret; 836 } 837 838 BTRFS_I(inode)->location.type = BTRFS_INODE_ITEM_KEY; 839 BTRFS_I(inode)->location.objectid = BTRFS_FIRST_FREE_OBJECTID; 840 BTRFS_I(inode)->location.offset = 0; 841 842 fs_info = btrfs_alloc_dummy_fs_info(nodesize, sectorsize); 843 if (!fs_info) { 844 test_std_err(TEST_ALLOC_FS_INFO); 845 goto out; 846 } 847 848 root = btrfs_alloc_dummy_root(fs_info); 849 if (IS_ERR(root)) { 850 test_std_err(TEST_ALLOC_ROOT); 851 goto out; 852 } 853 854 root->node = alloc_dummy_extent_buffer(fs_info, nodesize); 855 if (!root->node) { 856 test_std_err(TEST_ALLOC_ROOT); 857 goto out; 858 } 859 860 btrfs_set_header_nritems(root->node, 0); 861 btrfs_set_header_level(root->node, 0); 862 BTRFS_I(inode)->root = root; 863 ret = -EINVAL; 864 865 /* 866 * Need a blank inode item here just so we don't confuse 867 * btrfs_get_extent. 868 */ 869 insert_inode_item_key(root); 870 insert_extent(root, sectorsize, sectorsize, sectorsize, 0, sectorsize, 871 sectorsize, BTRFS_FILE_EXTENT_REG, 0, 1); 872 em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, 0, 2 * sectorsize); 873 if (IS_ERR(em)) { 874 test_err("got an error when we shouldn't have"); 875 goto out; 876 } 877 if (em->block_start != EXTENT_MAP_HOLE) { 878 test_err("expected a hole, got %llu", em->block_start); 879 goto out; 880 } 881 if (em->start != 0 || em->len != sectorsize) { 882 test_err( 883 "unexpected extent wanted start 0 len %u, got start %llu len %llu", 884 sectorsize, em->start, em->len); 885 goto out; 886 } 887 if (em->flags != vacancy_only) { 888 test_err("wrong flags, wanted %lu, have %lu", vacancy_only, 889 em->flags); 890 goto out; 891 } 892 free_extent_map(em); 893 894 em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, sectorsize, 2 * sectorsize); 895 if (IS_ERR(em)) { 896 test_err("got an error when we shouldn't have"); 897 goto out; 898 } 899 if (em->block_start != sectorsize) { 900 test_err("expected a real extent, got %llu", em->block_start); 901 goto out; 902 } 903 if (em->start != sectorsize || em->len != sectorsize) { 904 test_err( 905 "unexpected extent wanted start %u len %u, got start %llu len %llu", 906 sectorsize, sectorsize, em->start, em->len); 907 goto out; 908 } 909 if (em->flags != 0) { 910 test_err("unexpected flags set, wanted 0 got %lu", 911 em->flags); 912 goto out; 913 } 914 ret = 0; 915 out: 916 if (!IS_ERR(em)) 917 free_extent_map(em); 918 iput(inode); 919 btrfs_free_dummy_root(root); 920 btrfs_free_dummy_fs_info(fs_info); 921 return ret; 922 } 923 924 static int test_extent_accounting(u32 sectorsize, u32 nodesize) 925 { 926 struct btrfs_fs_info *fs_info = NULL; 927 struct inode *inode = NULL; 928 struct btrfs_root *root = NULL; 929 int ret = -ENOMEM; 930 931 test_msg("running outstanding_extents tests"); 932 933 inode = btrfs_new_test_inode(); 934 if (!inode) { 935 test_std_err(TEST_ALLOC_INODE); 936 return ret; 937 } 938 939 fs_info = btrfs_alloc_dummy_fs_info(nodesize, sectorsize); 940 if (!fs_info) { 941 test_std_err(TEST_ALLOC_FS_INFO); 942 goto out; 943 } 944 945 root = btrfs_alloc_dummy_root(fs_info); 946 if (IS_ERR(root)) { 947 test_std_err(TEST_ALLOC_ROOT); 948 goto out; 949 } 950 951 BTRFS_I(inode)->root = root; 952 953 /* [BTRFS_MAX_EXTENT_SIZE] */ 954 ret = btrfs_set_extent_delalloc(BTRFS_I(inode), 0, 955 BTRFS_MAX_EXTENT_SIZE - 1, 0, NULL); 956 if (ret) { 957 test_err("btrfs_set_extent_delalloc returned %d", ret); 958 goto out; 959 } 960 if (BTRFS_I(inode)->outstanding_extents != 1) { 961 ret = -EINVAL; 962 test_err("miscount, wanted 1, got %u", 963 BTRFS_I(inode)->outstanding_extents); 964 goto out; 965 } 966 967 /* [BTRFS_MAX_EXTENT_SIZE][sectorsize] */ 968 ret = btrfs_set_extent_delalloc(BTRFS_I(inode), BTRFS_MAX_EXTENT_SIZE, 969 BTRFS_MAX_EXTENT_SIZE + sectorsize - 1, 970 0, NULL); 971 if (ret) { 972 test_err("btrfs_set_extent_delalloc returned %d", ret); 973 goto out; 974 } 975 if (BTRFS_I(inode)->outstanding_extents != 2) { 976 ret = -EINVAL; 977 test_err("miscount, wanted 2, got %u", 978 BTRFS_I(inode)->outstanding_extents); 979 goto out; 980 } 981 982 /* [BTRFS_MAX_EXTENT_SIZE/2][sectorsize HOLE][the rest] */ 983 ret = clear_extent_bit(&BTRFS_I(inode)->io_tree, 984 BTRFS_MAX_EXTENT_SIZE >> 1, 985 (BTRFS_MAX_EXTENT_SIZE >> 1) + sectorsize - 1, 986 EXTENT_DELALLOC | EXTENT_DELALLOC_NEW | 987 EXTENT_UPTODATE, 0, 0, NULL); 988 if (ret) { 989 test_err("clear_extent_bit returned %d", ret); 990 goto out; 991 } 992 if (BTRFS_I(inode)->outstanding_extents != 2) { 993 ret = -EINVAL; 994 test_err("miscount, wanted 2, got %u", 995 BTRFS_I(inode)->outstanding_extents); 996 goto out; 997 } 998 999 /* [BTRFS_MAX_EXTENT_SIZE][sectorsize] */ 1000 ret = btrfs_set_extent_delalloc(BTRFS_I(inode), BTRFS_MAX_EXTENT_SIZE >> 1, 1001 (BTRFS_MAX_EXTENT_SIZE >> 1) 1002 + sectorsize - 1, 1003 0, NULL); 1004 if (ret) { 1005 test_err("btrfs_set_extent_delalloc returned %d", ret); 1006 goto out; 1007 } 1008 if (BTRFS_I(inode)->outstanding_extents != 2) { 1009 ret = -EINVAL; 1010 test_err("miscount, wanted 2, got %u", 1011 BTRFS_I(inode)->outstanding_extents); 1012 goto out; 1013 } 1014 1015 /* 1016 * [BTRFS_MAX_EXTENT_SIZE+sectorsize][sectorsize HOLE][BTRFS_MAX_EXTENT_SIZE+sectorsize] 1017 */ 1018 ret = btrfs_set_extent_delalloc(BTRFS_I(inode), 1019 BTRFS_MAX_EXTENT_SIZE + 2 * sectorsize, 1020 (BTRFS_MAX_EXTENT_SIZE << 1) + 3 * sectorsize - 1, 1021 0, NULL); 1022 if (ret) { 1023 test_err("btrfs_set_extent_delalloc returned %d", ret); 1024 goto out; 1025 } 1026 if (BTRFS_I(inode)->outstanding_extents != 4) { 1027 ret = -EINVAL; 1028 test_err("miscount, wanted 4, got %u", 1029 BTRFS_I(inode)->outstanding_extents); 1030 goto out; 1031 } 1032 1033 /* 1034 * [BTRFS_MAX_EXTENT_SIZE+sectorsize][sectorsize][BTRFS_MAX_EXTENT_SIZE+sectorsize] 1035 */ 1036 ret = btrfs_set_extent_delalloc(BTRFS_I(inode), 1037 BTRFS_MAX_EXTENT_SIZE + sectorsize, 1038 BTRFS_MAX_EXTENT_SIZE + 2 * sectorsize - 1, 0, NULL); 1039 if (ret) { 1040 test_err("btrfs_set_extent_delalloc returned %d", ret); 1041 goto out; 1042 } 1043 if (BTRFS_I(inode)->outstanding_extents != 3) { 1044 ret = -EINVAL; 1045 test_err("miscount, wanted 3, got %u", 1046 BTRFS_I(inode)->outstanding_extents); 1047 goto out; 1048 } 1049 1050 /* [BTRFS_MAX_EXTENT_SIZE+4k][4K HOLE][BTRFS_MAX_EXTENT_SIZE+4k] */ 1051 ret = clear_extent_bit(&BTRFS_I(inode)->io_tree, 1052 BTRFS_MAX_EXTENT_SIZE + sectorsize, 1053 BTRFS_MAX_EXTENT_SIZE + 2 * sectorsize - 1, 1054 EXTENT_DELALLOC | EXTENT_DELALLOC_NEW | 1055 EXTENT_UPTODATE, 0, 0, NULL); 1056 if (ret) { 1057 test_err("clear_extent_bit returned %d", ret); 1058 goto out; 1059 } 1060 if (BTRFS_I(inode)->outstanding_extents != 4) { 1061 ret = -EINVAL; 1062 test_err("miscount, wanted 4, got %u", 1063 BTRFS_I(inode)->outstanding_extents); 1064 goto out; 1065 } 1066 1067 /* 1068 * Refill the hole again just for good measure, because I thought it 1069 * might fail and I'd rather satisfy my paranoia at this point. 1070 */ 1071 ret = btrfs_set_extent_delalloc(BTRFS_I(inode), 1072 BTRFS_MAX_EXTENT_SIZE + sectorsize, 1073 BTRFS_MAX_EXTENT_SIZE + 2 * sectorsize - 1, 0, NULL); 1074 if (ret) { 1075 test_err("btrfs_set_extent_delalloc returned %d", ret); 1076 goto out; 1077 } 1078 if (BTRFS_I(inode)->outstanding_extents != 3) { 1079 ret = -EINVAL; 1080 test_err("miscount, wanted 3, got %u", 1081 BTRFS_I(inode)->outstanding_extents); 1082 goto out; 1083 } 1084 1085 /* Empty */ 1086 ret = clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, (u64)-1, 1087 EXTENT_DELALLOC | EXTENT_DELALLOC_NEW | 1088 EXTENT_UPTODATE, 0, 0, NULL); 1089 if (ret) { 1090 test_err("clear_extent_bit returned %d", ret); 1091 goto out; 1092 } 1093 if (BTRFS_I(inode)->outstanding_extents) { 1094 ret = -EINVAL; 1095 test_err("miscount, wanted 0, got %u", 1096 BTRFS_I(inode)->outstanding_extents); 1097 goto out; 1098 } 1099 ret = 0; 1100 out: 1101 if (ret) 1102 clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, (u64)-1, 1103 EXTENT_DELALLOC | EXTENT_DELALLOC_NEW | 1104 EXTENT_UPTODATE, 0, 0, NULL); 1105 iput(inode); 1106 btrfs_free_dummy_root(root); 1107 btrfs_free_dummy_fs_info(fs_info); 1108 return ret; 1109 } 1110 1111 int btrfs_test_inodes(u32 sectorsize, u32 nodesize) 1112 { 1113 int ret; 1114 1115 test_msg("running inode tests"); 1116 1117 set_bit(EXTENT_FLAG_COMPRESSED, &compressed_only); 1118 set_bit(EXTENT_FLAG_PREALLOC, &prealloc_only); 1119 1120 ret = test_btrfs_get_extent(sectorsize, nodesize); 1121 if (ret) 1122 return ret; 1123 ret = test_hole_first(sectorsize, nodesize); 1124 if (ret) 1125 return ret; 1126 return test_extent_accounting(sectorsize, nodesize); 1127 } 1128