summaryrefslogtreecommitdiff
path: root/btrfsck.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-04-20 20:23:29 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-04-20 20:23:29 -0400
commit2f2264fc2db687415d90e2cfcaaf0d1b005696e7 (patch)
tree7af6972d623278337547034b9efae4f870846c84 /btrfsck.c
parent07eb5008f353147feee5b66c3f091cf74ef993a7 (diff)
add owner and type fields to the extents aand block headers
Diffstat (limited to 'btrfsck.c')
-rw-r--r--btrfsck.c168
1 files changed, 168 insertions, 0 deletions
diff --git a/btrfsck.c b/btrfsck.c
new file mode 100644
index 00000000..2f8630ff
--- /dev/null
+++ b/btrfsck.c
@@ -0,0 +1,168 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "kerncompat.h"
+#include "radix-tree.h"
+#include "ctree.h"
+#include "disk-io.h"
+#include "print-tree.h"
+#include "transaction.h"
+#include "bit-radix.h"
+
+u64 blocks_used = 0;
+struct extent_record {
+ u64 start;
+ u64 nr;
+ u64 owner;
+ u32 refs;
+ u8 type;
+};
+
+static int add_extent_rec(struct radix_tree_root *extent_radix,
+ u64 ref, u64 start, u64 nr, u64 owner, u8 type)
+{
+ struct extent_record *rec;
+ int ret = 0;
+ rec = radix_tree_lookup(extent_radix, start);
+ if (rec) {
+ rec->refs++;
+ if (owner != rec->owner) {
+ fprintf(stderr, "warning, owner mismatch %Lu\n", start);
+ ret = 1;
+ }
+ if (start != rec->start) {
+ fprintf(stderr, "warning, start mismatch %Lu %Lu\n",
+ rec->start, start);
+ ret = 1;
+ }
+ if (type != rec->type) {
+ fprintf(stderr, "type mismatch block %Lu %d %d\n",
+ start, type, type);
+ ret = 1;
+ }
+ return ret;
+ }
+ rec = malloc(sizeof(*rec));
+ rec->start = start;
+ rec->nr = nr;
+ rec->owner = owner;
+ rec->type = type;
+ ret = radix_tree_insert(extent_radix, start, rec);
+ BUG_ON(ret);
+ blocks_used += nr;
+ return ret;
+}
+
+static int add_pending(struct radix_tree_root *pending,
+ struct radix_tree_root *seen, u64 blocknr)
+{
+ if (test_radix_bit(seen, blocknr))
+ return -EEXIST;
+ set_radix_bit(pending, blocknr);
+ set_radix_bit(seen, blocknr);
+ return 0;
+}
+
+static int run_next_block(struct btrfs_root *root,
+ u64 *last,
+ struct radix_tree_root *pending,
+ struct radix_tree_root *seen,
+ struct radix_tree_root *extent_radix)
+{
+ struct btrfs_buffer *buf;
+ u64 blocknr;
+ int ret;
+ int i;
+ int nritems;
+ struct btrfs_leaf *leaf;
+ struct btrfs_node *node;
+ unsigned long bits;
+
+ ret = find_first_radix_bit(pending, &bits, *last, 1);
+ if (ret == 0) {
+ ret = find_first_radix_bit(pending, &bits, 0, 1);
+ if (ret == 0)
+ return 1;
+ }
+ *last = bits;
+ blocknr = bits;
+ clear_radix_bit(pending, blocknr);
+ buf = read_tree_block(root, blocknr);
+ nritems = btrfs_header_nritems(&buf->node.header);
+ if (btrfs_is_leaf(&buf->node)) {
+ leaf = &buf->leaf;
+ for (i = 0; i < nritems; i++) {
+ struct btrfs_file_extent_item *fi;
+ if (btrfs_disk_key_type(&leaf->items[i].key) !=
+ BTRFS_EXTENT_DATA_KEY)
+ continue;
+ fi = btrfs_item_ptr(leaf, i,
+ struct btrfs_file_extent_item);
+ if (btrfs_file_extent_type(fi) !=
+ BTRFS_FILE_EXTENT_REG)
+ continue;
+ ret = add_extent_rec(extent_radix, blocknr,
+ btrfs_file_extent_disk_blocknr(fi),
+ btrfs_file_extent_disk_num_blocks(fi),
+ btrfs_disk_key_objectid(&leaf->items[i].key),
+ BTRFS_EXTENT_FILE);
+ BUG_ON(ret);
+ }
+ } else {
+ node = &buf->node;
+ for (i = 0; i < nritems; i++) {
+ u64 ptr = btrfs_node_blockptr(node, i);
+ ret = add_extent_rec(extent_radix, blocknr, ptr, 1,
+ btrfs_header_owner(&node->header),
+ BTRFS_EXTENT_TREE);
+ BUG_ON(ret);
+ add_pending(pending, seen, ptr);
+ }
+ }
+ btrfs_block_release(root, buf);
+ return 0;
+}
+
+static int add_root_to_pending(struct btrfs_root *root,
+ struct radix_tree_root *extent_radix,
+ struct radix_tree_root *pending,
+ struct radix_tree_root *seen)
+{
+ add_pending(pending, seen, root->node->blocknr);
+ add_extent_rec(extent_radix, 0, root->node->blocknr, 1,
+ btrfs_header_owner(&root->node->node.header),
+ BTRFS_EXTENT_TREE);
+ return 0;
+}
+int main(int ac, char **av) {
+ struct btrfs_super_block super;
+ struct btrfs_root *root;
+ struct radix_tree_root extent_radix;
+ struct radix_tree_root seen;
+ struct radix_tree_root pending;
+ int ret;
+ u64 last = 0;
+
+ radix_tree_init();
+
+ INIT_RADIX_TREE(&extent_radix, GFP_NOFS);
+ init_bit_radix(&seen);
+ init_bit_radix(&pending);
+
+ root = open_ctree(av[1], &super);
+ add_root_to_pending(root, &extent_radix, &pending, &seen);
+ add_root_to_pending(root->fs_info->tree_root,&extent_radix,
+ &pending, &seen);
+ add_root_to_pending(root->fs_info->dev_root, &extent_radix,
+ &pending, &seen);
+ add_root_to_pending(root->fs_info->extent_root, &extent_radix,
+ &pending, &seen);
+ while(1) {
+ ret = run_next_block(root, &last, &pending,
+ &seen, &extent_radix);
+ if (ret != 0)
+ break;
+ }
+ close_ctree(root, &super);
+ printf("found %Lu blocks used\n", blocks_used);
+ return 0;
+}