diff options
Diffstat (limited to 'check/mode-lowmem.c')
-rw-r--r-- | check/mode-lowmem.c | 83 |
1 files changed, 70 insertions, 13 deletions
diff --git a/check/mode-lowmem.c b/check/mode-lowmem.c index 62bcf3d2..bfe45aba 100644 --- a/check/mode-lowmem.c +++ b/check/mode-lowmem.c @@ -390,7 +390,7 @@ static void account_bytes(struct btrfs_root *root, struct btrfs_path *path, total_extent_tree_bytes += eb->len; if (level == 0) { - btree_space_waste += btrfs_leaf_free_space(root, eb); + btree_space_waste += btrfs_leaf_free_space(root->fs_info, eb); } else { free_nrs = (BTRFS_NODEPTRS_PER_BLOCK(root->fs_info) - btrfs_header_nritems(eb)); @@ -1417,6 +1417,8 @@ static int check_file_extent(struct btrfs_root *root, struct btrfs_key *fkey, u64 csum_found; /* In byte size, sectorsize aligned */ u64 search_start; /* Logical range start we search for csum */ u64 search_len; /* Logical range len we search for csum */ + u32 max_inline_extent_size = min_t(u32, root->fs_info->sectorsize - 1, + BTRFS_MAX_INLINE_DATA_SIZE(root->fs_info)); unsigned int extent_type; unsigned int is_hole; int compressed = 0; @@ -1440,6 +1442,32 @@ static int check_file_extent(struct btrfs_root *root, struct btrfs_key *fkey, root->objectid, fkey->objectid, fkey->offset); err |= FILE_EXTENT_ERROR; } + if (compressed) { + if (extent_num_bytes > root->fs_info->sectorsize) { + error( +"root %llu EXTENT_DATA[%llu %llu] too large inline extent ram size, have %llu, max: %u", + root->objectid, fkey->objectid, + fkey->offset, extent_num_bytes, + root->fs_info->sectorsize - 1); + err |= FILE_EXTENT_ERROR; + } + if (item_inline_len > max_inline_extent_size) { + error( +"root %llu EXTENT_DATA[%llu %llu] too large inline extent on-disk size, have %u, max: %u", + root->objectid, fkey->objectid, + fkey->offset, item_inline_len, + max_inline_extent_size); + err |= FILE_EXTENT_ERROR; + } + } else { + if (extent_num_bytes > max_inline_extent_size) { + error( + "root %llu EXTENT_DATA[%llu %llu] too large inline extent size, have %llu, max: %u", + root->objectid, fkey->objectid, fkey->offset, + extent_num_bytes, max_inline_extent_size); + err |= FILE_EXTENT_ERROR; + } + } if (!compressed && extent_num_bytes != item_inline_len) { error( "root %llu EXTENT_DATA[%llu %llu] wrong inline size, have: %llu, expected: %u", @@ -1503,9 +1531,17 @@ static int check_file_extent(struct btrfs_root *root, struct btrfs_key *fkey, csum_found, search_len); } else if (extent_type == BTRFS_FILE_EXTENT_PREALLOC && csum_found > 0) { - err |= ODD_CSUM_ITEM; - error("root %llu EXTENT_DATA[%llu %llu] prealloc shouldn't have csum, but has: %llu", - root->objectid, fkey->objectid, fkey->offset, csum_found); + ret = check_prealloc_extent_written(root->fs_info, + disk_bytenr, disk_num_bytes); + if (ret < 0) + return ret; + if (ret == 0) { + err |= ODD_CSUM_ITEM; + error( +"root %llu EXTENT_DATA[%llu %llu] prealloc shouldn't have csum, but has: %llu", + root->objectid, fkey->objectid, fkey->offset, + csum_found); + } } /* Check EXTENT_DATA hole */ @@ -1861,6 +1897,24 @@ out: return ret; } +static bool has_orphan_item(struct btrfs_root *root, u64 ino) +{ + struct btrfs_path path; + struct btrfs_key key; + int ret; + + btrfs_init_path(&path); + key.objectid = BTRFS_ORPHAN_OBJECTID; + key.type = BTRFS_ORPHAN_ITEM_KEY; + key.offset = ino; + + ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0); + btrfs_release_path(&path); + if (ret == 0) + return true; + return false; +} + /* * Check INODE_ITEM and related ITEMs (the same inode number) * 1. check link count @@ -1890,6 +1944,7 @@ static int check_inode_item(struct btrfs_root *root, struct btrfs_path *path, u64 extent_size = 0; unsigned int dir; unsigned int nodatasum; + bool is_orphan = false; int slot; int ret; int err = 0; @@ -2040,10 +2095,11 @@ out: root->objectid, inode_id, nlink, refs); } } else if (!nlink) { - if (repair) + is_orphan = has_orphan_item(root, inode_id); + if (!is_orphan && repair) ret = repair_inode_orphan_item_lowmem(root, path, inode_id); - if (!repair || ret) { + if (!is_orphan && (!repair || ret)) { err |= ORPHAN_ITEM; error("root %llu INODE[%llu] is orphan item", root->objectid, inode_id); @@ -2631,9 +2687,9 @@ static int check_extent_data_item(struct btrfs_root *root, if (!(extent_flags & BTRFS_EXTENT_FLAG_DATA)) { error( - "extent[%llu %llu] backref type mismatch, wanted bit: %llx", - disk_bytenr, disk_num_bytes, - BTRFS_EXTENT_FLAG_DATA); +"file extent[%llu %llu] root %llu owner %llu backref type mismatch, wanted bit: %llx", + fi_key.objectid, fi_key.offset, root->objectid, owner, + BTRFS_EXTENT_FLAG_DATA); err |= BACKREF_MISMATCH; } @@ -2689,8 +2745,8 @@ static int check_extent_data_item(struct btrfs_root *root, /* Didn't find inlined data backref, try EXTENT_DATA_REF_KEY */ 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 - offset); + dbref_key.offset = hash_extent_data_ref(owner, fi_key.objectid, + fi_key.offset - offset); ret = btrfs_search_slot(NULL, root->fs_info->extent_root, &dbref_key, &path, 0, 0); @@ -2722,8 +2778,9 @@ out: err |= BACKREF_MISSING; btrfs_release_path(&path); if (err & BACKREF_MISSING) { - error("data extent[%llu %llu] backref lost", - disk_bytenr, disk_num_bytes); + error( + "file extent[%llu %llu] root %llu owner %llu backref lost", + fi_key.objectid, fi_key.offset, root->objectid, owner); } return err; } |