Merge tag 'i2c-for-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
[linux-2.6-microblaze.git] / fs / btrfs / tree-checker.c
index e56c010..9e0e0ae 100644 (file)
@@ -1855,3 +1855,58 @@ out:
        return ret;
 }
 ALLOW_ERROR_INJECTION(btrfs_check_node, ERRNO);
+
+int btrfs_check_eb_owner(const struct extent_buffer *eb, u64 root_owner)
+{
+       const bool is_subvol = is_fstree(root_owner);
+       const u64 eb_owner = btrfs_header_owner(eb);
+
+       /*
+        * Skip dummy fs, as selftests don't create unique ebs for each dummy
+        * root.
+        */
+       if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &eb->fs_info->fs_state))
+               return 0;
+       /*
+        * There are several call sites (backref walking, qgroup, and data
+        * reloc) passing 0 as @root_owner, as they are not holding the
+        * tree root.  In that case, we can not do a reliable ownership check,
+        * so just exit.
+        */
+       if (root_owner == 0)
+               return 0;
+       /*
+        * These trees use key.offset as their owner, our callers don't have
+        * the extra capacity to pass key.offset here.  So we just skip them.
+        */
+       if (root_owner == BTRFS_TREE_LOG_OBJECTID ||
+           root_owner == BTRFS_TREE_RELOC_OBJECTID)
+               return 0;
+
+       if (!is_subvol) {
+               /* For non-subvolume trees, the eb owner should match root owner */
+               if (unlikely(root_owner != eb_owner)) {
+                       btrfs_crit(eb->fs_info,
+"corrupted %s, root=%llu block=%llu owner mismatch, have %llu expect %llu",
+                               btrfs_header_level(eb) == 0 ? "leaf" : "node",
+                               root_owner, btrfs_header_bytenr(eb), eb_owner,
+                               root_owner);
+                       return -EUCLEAN;
+               }
+               return 0;
+       }
+
+       /*
+        * For subvolume trees, owners can mismatch, but they should all belong
+        * to subvolume trees.
+        */
+       if (unlikely(is_subvol != is_fstree(eb_owner))) {
+               btrfs_crit(eb->fs_info,
+"corrupted %s, root=%llu block=%llu owner mismatch, have %llu expect [%llu, %llu]",
+                       btrfs_header_level(eb) == 0 ? "leaf" : "node",
+                       root_owner, btrfs_header_bytenr(eb), eb_owner,
+                       BTRFS_FIRST_FREE_OBJECTID, BTRFS_LAST_FREE_OBJECTID);
+               return -EUCLEAN;
+       }
+       return 0;
+}