libbtrfsutil: fix memory leak in deleted_subvolumes()
[platform/upstream/btrfs-progs.git] / check / mode-lowmem.c
index f37b1b2..dac3201 100644 (file)
@@ -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);
@@ -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);