summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds-check.c186
1 files changed, 186 insertions, 0 deletions
diff --git a/cmds-check.c b/cmds-check.c
index 4eb2ef9b..9db048c2 100644
--- a/cmds-check.c
+++ b/cmds-check.c
@@ -2823,6 +2823,187 @@ static int check_space_cache(struct btrfs_root *root)
return error ? -EINVAL : 0;
}
+static int check_extent_exists(struct btrfs_root *root, u64 bytenr,
+ u64 num_bytes)
+{
+ struct btrfs_path *path;
+ struct extent_buffer *leaf;
+ struct btrfs_key key;
+ int ret;
+
+ path = btrfs_alloc_path();
+ if (!path) {
+ fprintf(stderr, "Error allocing path\n");
+ return -ENOMEM;
+ }
+
+ key.objectid = bytenr;
+ key.type = BTRFS_EXTENT_ITEM_KEY;
+ key.offset = 0;
+
+again:
+ ret = btrfs_search_slot(NULL, root->fs_info->extent_root, &key, path,
+ 0, 0);
+ if (ret < 0) {
+ fprintf(stderr, "Error looking up extent record %d\n", ret);
+ btrfs_free_path(path);
+ return ret;
+ } else if (ret && path->slots[0]) {
+ path->slots[0]--;
+ }
+
+ while (num_bytes) {
+ if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) {
+ ret = btrfs_next_leaf(root, path);
+ if (ret < 0) {
+ fprintf(stderr, "Error going to next leaf "
+ "%d\n", ret);
+ btrfs_free_path(path);
+ return ret;
+ } else if (ret) {
+ break;
+ }
+ }
+ leaf = path->nodes[0];
+ btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
+ if (key.type != BTRFS_EXTENT_ITEM_KEY) {
+ path->slots[0]++;
+ continue;
+ }
+ if (key.objectid + key.offset < bytenr) {
+ path->slots[0]++;
+ continue;
+ }
+ if (key.objectid > bytenr + num_bytes)
+ break;
+
+ if (key.objectid == bytenr) {
+ if (key.offset >= num_bytes) {
+ num_bytes = 0;
+ break;
+ }
+ num_bytes -= key.offset;
+ bytenr += key.offset;
+ } else if (key.objectid < bytenr) {
+ if (key.objectid + key.offset >= bytenr + num_bytes) {
+ num_bytes = 0;
+ break;
+ }
+ num_bytes = (bytenr + num_bytes) -
+ (key.objectid + key.offset);
+ bytenr = key.objectid + key.offset;
+ } else {
+ if (key.objectid + key.offset < bytenr + num_bytes) {
+ u64 new_start = key.objectid + key.offset;
+ u64 new_bytes = bytenr + num_bytes - new_start;
+
+ /*
+ * Weird case, the extent is in the middle of
+ * our range, we'll have to search one side
+ * and then the other. Not sure if this happens
+ * in real life, but no harm in coding it up
+ * anyway just in case.
+ */
+ btrfs_release_path(root, path);
+ ret = check_extent_exists(root, new_start,
+ new_bytes);
+ if (ret) {
+ fprintf(stderr, "Right section didn't "
+ "have a record\n");
+ break;
+ }
+ num_bytes = key.objectid - bytenr;
+ goto again;
+ }
+ num_bytes = key.objectid - bytenr;
+ }
+ path->slots[0]++;
+ }
+ ret = 0;
+
+ if (num_bytes) {
+ fprintf(stderr, "There are no extents for csum range "
+ "%Lu-%Lu\n", bytenr, bytenr+num_bytes);
+ ret = 1;
+ }
+
+ btrfs_free_path(path);
+ return ret;
+}
+
+static int check_csums(struct btrfs_root *root)
+{
+ struct btrfs_path *path;
+ struct extent_buffer *leaf;
+ struct btrfs_key key;
+ u64 offset = 0, num_bytes = 0;
+ u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
+ int errors = 0;
+ int ret;
+
+ root = root->fs_info->csum_root;
+
+ key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
+ key.type = BTRFS_EXTENT_CSUM_KEY;
+ key.offset = 0;
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+
+ ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+ if (ret < 0) {
+ fprintf(stderr, "Error searching csum tree %d\n", ret);
+ btrfs_free_path(path);
+ return ret;
+ }
+
+ if (ret > 0 && path->slots[0])
+ path->slots[0]--;
+ ret = 0;
+
+ while (1) {
+ if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) {
+ ret = btrfs_next_leaf(root, path);
+ if (ret < 0) {
+ fprintf(stderr, "Error going to next leaf "
+ "%d\n", ret);
+ break;
+ }
+ if (ret)
+ break;
+ }
+ leaf = path->nodes[0];
+
+ btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
+ if (key.type != BTRFS_EXTENT_CSUM_KEY) {
+ path->slots[0]++;
+ continue;
+ }
+
+ if (!num_bytes) {
+ offset = key.offset;
+ } else if (key.offset != offset + num_bytes) {
+ ret = check_extent_exists(root, offset, num_bytes);
+ if (ret) {
+ fprintf(stderr, "Csum exists for %Lu-%Lu but "
+ "there is no extent record\n",
+ offset, offset+num_bytes);
+ errors++;
+ }
+ offset = key.offset;
+ num_bytes = 0;
+ }
+
+ num_bytes += (btrfs_item_size_nr(leaf, path->slots[0]) /
+ csum_size) * root->sectorsize;
+ path->slots[0]++;
+ }
+
+ btrfs_free_path(path);
+ return errors;
+}
+
static int run_next_block(struct btrfs_root *root,
struct block_info *bits,
int bits_nr,
@@ -3905,6 +4086,11 @@ int cmd_check(int argc, char **argv)
if (ret)
goto out;
+ fprintf(stderr, "checking csums\n");
+ ret = check_csums(root);
+ if (ret)
+ goto out;
+
fprintf(stderr, "checking root refs\n");
ret = check_root_refs(root, &root_cache);
out: