X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=cmds-check.c;h=99fbafc5538c2ca704135c49e3de6e666863f444;hb=cda595afa3cfabae2be30af9b8b08f2af3c31437;hp=a93ac2c88a381cb20fae02ca5e7eb6c2a8fd3168;hpb=29379da543da18f40f0a780bd61823316968607c;p=platform%2Fupstream%2Fbtrfs-progs.git diff --git a/cmds-check.c b/cmds-check.c index a93ac2c..99fbafc 100644 --- a/cmds-check.c +++ b/cmds-check.c @@ -1635,8 +1635,9 @@ static int process_dir_item(struct extent_buffer *eb, namebuf, len, filetype, key->type, error); } else { - fprintf(stderr, "invalid location in dir item %u\n", - location.type); + fprintf(stderr, + "unknown location type %d in DIR_ITEM[%llu %llu]\n", + location.type, key->objectid, key->offset); add_inode_backref(inode_cache, BTRFS_MULTIPLE_OBJECTIDS, key->objectid, key->offset, namebuf, len, filetype, key->type, error); @@ -2149,7 +2150,12 @@ static int need_check(struct btrfs_root *root, struct ulist *roots) struct rb_node *node; struct ulist_node *u; - if (roots->nnodes == 1) + /* + * @roots can be empty if it belongs to tree reloc tree + * In that case, we should always check the leaf, as we can't use + * the tree owner to ensure some other root will check it. + */ + if (roots->nnodes == 1 || roots->nnodes == 0) return 1; node = rb_first(&roots->root); @@ -2626,8 +2632,7 @@ static int repair_tree_block_ref(struct btrfs_trans_handle *trans, } btrfs_mark_buffer_dirty(eb); printf("Added an extent item [%llu %u]\n", bytenr, node_size); - btrfs_update_block_group(trans, extent_root, bytenr, node_size, - 1, 0); + btrfs_update_block_group(extent_root, bytenr, node_size, 1, 0); nrefs->refs[level] = 0; nrefs->full_backref[level] = @@ -5868,8 +5873,9 @@ static int check_file_extent(struct btrfs_root *root, struct btrfs_key *fkey, if (!repair || ret) { err |= FILE_EXTENT_ERROR; error( - "root %llu EXTENT_DATA[%llu %llu] interrupt, should start at %llu", - root->objectid, fkey->objectid, fkey->offset, *end); +"root %llu EXTENT_DATA[%llu %llu] gap exists, expected: EXTENT_DATA[%llu %llu]", + root->objectid, fkey->objectid, fkey->offset, + fkey->objectid, *end); } } @@ -6623,8 +6629,6 @@ out: return ret; } -static int pin_metadata_blocks(struct btrfs_fs_info *fs_info); - /* * Iterate all items in the tree and call check_inode_item() to check. * @@ -8362,7 +8366,13 @@ static int process_extent_item(struct btrfs_root *root, if (item_size < sizeof(*ei)) { #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 struct btrfs_extent_item_v0 *ei0; - BUG_ON(item_size != sizeof(*ei0)); + if (item_size != sizeof(*ei0)) { + error( + "invalid extent item format: ITEM[%llu %u %llu] leaf: %llu slot: %d", + key.objectid, key.type, key.offset, + btrfs_header_bytenr(eb), slot); + BUG(); + } ei0 = btrfs_item_ptr(eb, slot, struct btrfs_extent_item_v0); refs = btrfs_extent_refs_v0(eb, ei0); #else @@ -9657,7 +9667,7 @@ static int delete_extent_records(struct btrfs_trans_handle *trans, u64 bytes = (found_key.type == BTRFS_EXTENT_ITEM_KEY) ? found_key.offset : root->fs_info->nodesize; - ret = btrfs_update_block_group(trans, root, bytenr, + ret = btrfs_update_block_group(root, bytenr, bytes, 0, 0); if (ret) break; @@ -9736,7 +9746,7 @@ static int record_extent(struct btrfs_trans_handle *trans, } btrfs_mark_buffer_dirty(leaf); - ret = btrfs_update_block_group(trans, extent_root, rec->start, + ret = btrfs_update_block_group(extent_root, rec->start, rec->max_size, 1, 0); if (ret) goto fail; @@ -11697,16 +11707,12 @@ static int check_tree_block_ref(struct btrfs_root *root, u32 nodesize = root->fs_info->nodesize; u32 item_size; u64 offset; - int tree_reloc_root = 0; int found_ref = 0; int err = 0; int ret; int strict = 1; int parent = 0; - if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID && - btrfs_header_bytenr(root->node) == bytenr) - tree_reloc_root = 1; btrfs_init_path(&path); key.objectid = bytenr; if (btrfs_fs_incompat(root->fs_info, SKINNY_METADATA)) @@ -11814,8 +11820,12 @@ static int check_tree_block_ref(struct btrfs_root *root, /* * Backref of tree reloc root points to itself, no need * to check backref any more. + * + * This may be an error of loop backref, but extent tree + * checker should have already handled it. + * Here we only need to avoid infinite iteration. */ - if (tree_reloc_root) { + if (offset == bytenr) { found_ref = 1; } else { /* @@ -11847,6 +11857,30 @@ static int check_tree_block_ref(struct btrfs_root *root, if (!ret) found_ref = 1; } + /* + * Finally check SHARED BLOCK REF, any found will be good + * Here we're not doing comprehensive extent backref checking, + * only need to ensure there is some extent referring to this + * tree block. + */ + if (!found_ref) { + btrfs_release_path(&path); + key.objectid = bytenr; + key.type = BTRFS_SHARED_BLOCK_REF_KEY; + key.offset = (u64)-1; + + ret = btrfs_search_slot(NULL, extent_root, &key, &path, 0, 0); + if (ret < 0) { + err |= BACKREF_MISSING; + goto out; + } + ret = btrfs_previous_extent_item(extent_root, &path, bytenr); + if (ret) { + err |= BACKREF_MISSING; + goto out; + } + found_ref = 1; + } if (!found_ref) err |= BACKREF_MISSING; out: @@ -11945,7 +11979,7 @@ static int repair_extent_data_item(struct btrfs_trans_handle *trans, btrfs_set_extent_flags(eb, ei, BTRFS_EXTENT_FLAG_DATA); btrfs_mark_buffer_dirty(eb); - ret = btrfs_update_block_group(trans, extent_root, disk_bytenr, + ret = btrfs_update_block_group(extent_root, disk_bytenr, num_bytes, 1, 0); btrfs_release_path(&path); } @@ -12002,11 +12036,11 @@ static int check_extent_data_item(struct btrfs_root *root, u64 disk_num_bytes; u64 extent_num_bytes; u64 extent_flags; + u64 offset; u32 item_size; unsigned long end; unsigned long ptr; int type; - u64 ref_root; int found_dbackref = 0; int slot = pathp->slots[0]; int err = 0; @@ -12024,6 +12058,7 @@ static int check_extent_data_item(struct btrfs_root *root, disk_bytenr = btrfs_file_extent_disk_bytenr(eb, fi); disk_num_bytes = btrfs_file_extent_disk_num_bytes(eb, fi); extent_num_bytes = btrfs_file_extent_num_bytes(eb, fi); + offset = btrfs_file_extent_offset(eb, fi); /* Check unaligned disk_num_bytes and num_bytes */ if (!IS_ALIGNED(disk_num_bytes, root->fs_info->sectorsize)) { @@ -12078,6 +12113,11 @@ static int check_extent_data_item(struct btrfs_root *root, strict = should_check_extent_strictly(root, nrefs, -1); while (ptr < end) { + u64 ref_root; + u64 ref_objectid; + u64 ref_offset; + bool match = false; + iref = (struct btrfs_extent_inline_ref *)ptr; type = btrfs_extent_inline_ref_type(leaf, iref); dref = (struct btrfs_extent_data_ref *)(&iref->offset); @@ -12089,9 +12129,15 @@ static int check_extent_data_item(struct btrfs_root *root, } if (type == BTRFS_EXTENT_DATA_REF_KEY) { ref_root = btrfs_extent_data_ref_root(leaf, dref); - if (ref_root == root->objectid) + ref_objectid = btrfs_extent_data_ref_objectid(leaf, dref); + ref_offset = btrfs_extent_data_ref_offset(leaf, dref); + + if (ref_objectid == fi_key.objectid && + ref_offset == fi_key.offset - offset) + match = true; + if (ref_root == root->objectid && match) found_dbackref = 1; - else if (!strict && owner == ref_root) + else if (!strict && owner == ref_root && match) found_dbackref = 1; } else if (type == BTRFS_SHARED_DATA_REF_KEY) { found_dbackref = !check_tree_block_ref(root, NULL, @@ -12111,7 +12157,7 @@ static int check_extent_data_item(struct btrfs_root *root, dbref_key.objectid = btrfs_file_extent_disk_bytenr(eb, fi); dbref_key.type = BTRFS_EXTENT_DATA_REF_KEY; dbref_key.offset = hash_extent_data_ref(root->objectid, - fi_key.objectid, fi_key.offset); + fi_key.objectid, fi_key.offset - offset); ret = btrfs_search_slot(NULL, root->fs_info->extent_root, &dbref_key, &path, 0, 0); @@ -12479,11 +12525,17 @@ static int check_extent_data_backref(struct btrfs_fs_info *fs_info, * Except normal disk bytenr and disk num bytes, we still * need to do extra check on dbackref offset as * dbackref offset = file_offset - file_extent_offset + * + * Also, we must check the leaf owner. + * In case of shared tree blocks (snapshots) we can inherit + * leaves from source snapshot. + * In that case, reference from source snapshot should not + * count. */ if (btrfs_file_extent_disk_bytenr(leaf, fi) == bytenr && btrfs_file_extent_disk_num_bytes(leaf, fi) == len && (u64)(key.offset - btrfs_file_extent_offset(leaf, fi)) == - offset) + offset && btrfs_header_owner(leaf) == root_id) found_count++; next: @@ -13036,7 +13088,7 @@ static int repair_chunk_item(struct btrfs_trans_handle *trans, if (err & REFERENCER_MISSING) { ret = btrfs_make_block_group(trans, chunk_root->fs_info, 0, - type, chunk_key.objectid, chunk_key.offset, length); + type, chunk_key.offset, length); if (ret) { error("fail to add block group item[%llu %llu]", chunk_key.offset, length); @@ -13306,8 +13358,6 @@ out: return err; } -static int pin_metadata_blocks(struct btrfs_fs_info *fs_info); - /* * Low memory usage version check_chunks_and_extents. */ @@ -13326,12 +13376,6 @@ static int check_chunks_and_extents_v2(struct btrfs_fs_info *fs_info) root = fs_info->fs_root; if (repair) { - /* pin every tree block to avoid extent overwrite */ - ret = pin_metadata_blocks(fs_info); - if (ret) { - error("failed to pin metadata blocks"); - return ret; - } trans = btrfs_start_transaction(fs_info->extent_root, 1); if (IS_ERR(trans)) { error("failed to start transaction before check"); @@ -13636,8 +13680,7 @@ static int reset_block_groups(struct btrfs_fs_info *fs_info) chunk = btrfs_item_ptr(leaf, path.slots[0], struct btrfs_chunk); btrfs_add_block_group(fs_info, 0, - btrfs_chunk_type(leaf, chunk), - key.objectid, key.offset, + btrfs_chunk_type(leaf, chunk), key.offset, btrfs_chunk_length(leaf, chunk)); set_extent_dirty(&fs_info->free_space_cache, key.offset, key.offset + btrfs_chunk_length(leaf, chunk));