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