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