summaryrefslogtreecommitdiff
path: root/check/mode-common.c
diff options
context:
space:
mode:
Diffstat (limited to 'check/mode-common.c')
-rw-r--r--check/mode-common.c147
1 files changed, 142 insertions, 5 deletions
diff --git a/check/mode-common.c b/check/mode-common.c
index e857d44d..15e2bbd1 100644
--- a/check/mode-common.c
+++ b/check/mode-common.c
@@ -379,18 +379,14 @@ int insert_inode_item(struct btrfs_trans_handle *trans,
time_t now = time(NULL);
int ret;
+ memset(&ii, 0, sizeof(ii));
btrfs_set_stack_inode_size(&ii, size);
btrfs_set_stack_inode_nbytes(&ii, nbytes);
btrfs_set_stack_inode_nlink(&ii, nlink);
btrfs_set_stack_inode_mode(&ii, mode);
btrfs_set_stack_inode_generation(&ii, trans->transid);
- btrfs_set_stack_timespec_nsec(&ii.atime, 0);
btrfs_set_stack_timespec_sec(&ii.ctime, now);
- btrfs_set_stack_timespec_nsec(&ii.ctime, 0);
btrfs_set_stack_timespec_sec(&ii.mtime, now);
- btrfs_set_stack_timespec_nsec(&ii.mtime, 0);
- btrfs_set_stack_timespec_sec(&ii.otime, 0);
- btrfs_set_stack_timespec_nsec(&ii.otime, 0);
ret = btrfs_insert_inode(trans, root, ino, &ii);
ASSERT(!ret);
@@ -605,3 +601,144 @@ void reset_cached_block_groups(struct btrfs_fs_info *fs_info)
start = cache->key.objectid + cache->key.offset;
}
}
+
+static int traverse_tree_blocks(struct btrfs_fs_info *fs_info,
+ struct extent_buffer *eb, int tree_root,
+ int pin)
+{
+ struct extent_buffer *tmp;
+ struct btrfs_root_item *ri;
+ struct btrfs_key key;
+ struct extent_io_tree *tree;
+ u64 bytenr;
+ int level = btrfs_header_level(eb);
+ int nritems;
+ int ret;
+ int i;
+ u64 end = eb->start + eb->len;
+
+ if (pin)
+ tree = &fs_info->pinned_extents;
+ else
+ tree = fs_info->excluded_extents;
+ /*
+ * If we have pinned/excluded this block before, don't do it again.
+ * This can not only avoid forever loop with broken filesystem
+ * but also give us some speedups.
+ */
+ if (test_range_bit(tree, eb->start, end - 1, EXTENT_DIRTY, 0))
+ return 0;
+
+ if (pin)
+ btrfs_pin_extent(fs_info, eb->start, eb->len);
+ else
+ set_extent_dirty(tree, eb->start, end - 1);
+
+ nritems = btrfs_header_nritems(eb);
+ for (i = 0; i < nritems; i++) {
+ if (level == 0) {
+ bool is_extent_root;
+ btrfs_item_key_to_cpu(eb, &key, i);
+ if (key.type != BTRFS_ROOT_ITEM_KEY)
+ continue;
+ /* Skip the extent root and reloc roots */
+ if (key.objectid == BTRFS_TREE_RELOC_OBJECTID ||
+ key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID)
+ continue;
+ is_extent_root =
+ key.objectid == BTRFS_EXTENT_TREE_OBJECTID;
+ /* If pin, skip the extent root */
+ if (pin && is_extent_root)
+ continue;
+ ri = btrfs_item_ptr(eb, i, struct btrfs_root_item);
+ bytenr = btrfs_disk_root_bytenr(eb, ri);
+
+ /*
+ * If at any point we start needing the real root we
+ * will have to build a stump root for the root we are
+ * in, but for now this doesn't actually use the root so
+ * just pass in extent_root.
+ */
+ tmp = read_tree_block(fs_info, bytenr, 0);
+ if (!extent_buffer_uptodate(tmp)) {
+ fprintf(stderr, "Error reading root block\n");
+ return -EIO;
+ }
+ ret = traverse_tree_blocks(fs_info, tmp, 0, pin);
+ free_extent_buffer(tmp);
+ if (ret)
+ return ret;
+ } else {
+ bytenr = btrfs_node_blockptr(eb, i);
+
+ /* If we aren't the tree root don't read the block */
+ if (level == 1 && !tree_root) {
+ btrfs_pin_extent(fs_info, bytenr,
+ fs_info->nodesize);
+ continue;
+ }
+
+ tmp = read_tree_block(fs_info, bytenr, 0);
+ if (!extent_buffer_uptodate(tmp)) {
+ fprintf(stderr, "Error reading tree block\n");
+ return -EIO;
+ }
+ ret = traverse_tree_blocks(fs_info, tmp, tree_root,
+ pin);
+ free_extent_buffer(tmp);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int pin_down_tree_blocks(struct btrfs_fs_info *fs_info,
+ struct extent_buffer *eb, int tree_root)
+{
+ return traverse_tree_blocks(fs_info, eb, tree_root, 1);
+}
+
+int pin_metadata_blocks(struct btrfs_fs_info *fs_info)
+{
+ int ret;
+
+ ret = pin_down_tree_blocks(fs_info, fs_info->chunk_root->node, 0);
+ if (ret)
+ return ret;
+
+ return pin_down_tree_blocks(fs_info, fs_info->tree_root->node, 1);
+}
+
+static int exclude_tree_blocks(struct btrfs_fs_info *fs_info,
+ struct extent_buffer *eb, int tree_root)
+{
+ return traverse_tree_blocks(fs_info, eb, tree_root, 0);
+}
+
+int exclude_metadata_blocks(struct btrfs_fs_info *fs_info)
+{
+ int ret;
+ struct extent_io_tree *excluded_extents;
+
+ excluded_extents = malloc(sizeof(*excluded_extents));
+ if (!excluded_extents)
+ return -ENOMEM;
+ extent_io_tree_init(excluded_extents);
+ fs_info->excluded_extents = excluded_extents;
+
+ ret = exclude_tree_blocks(fs_info, fs_info->chunk_root->node, 0);
+ if (ret)
+ return ret;
+ return exclude_tree_blocks(fs_info, fs_info->tree_root->node, 1);
+}
+
+void cleanup_excluded_extents(struct btrfs_fs_info *fs_info)
+{
+ if (fs_info->excluded_extents) {
+ extent_io_tree_cleanup(fs_info->excluded_extents);
+ free(fs_info->excluded_extents);
+ }
+ fs_info->excluded_extents = NULL;
+}