return btrfs_commit_transaction(trans, fs_info->extent_root);
}
+static int recow_extent_buffer(struct btrfs_root *root, struct extent_buffer *eb)
+{
+ struct btrfs_path *path;
+ struct btrfs_trans_handle *trans;
+ struct btrfs_key key;
+ int ret;
+
+ printf("Recowing metadata block %llu\n", eb->start);
+ key.objectid = btrfs_header_owner(eb);
+ key.type = BTRFS_ROOT_ITEM_KEY;
+ key.offset = (u64)-1;
+
+ root = btrfs_read_fs_root(root->fs_info, &key);
+ if (IS_ERR(root)) {
+ fprintf(stderr, "Couldn't find owner root %llu\n",
+ key.objectid);
+ return PTR_ERR(root);
+ }
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+
+ trans = btrfs_start_transaction(root, 1);
+ if (IS_ERR(trans)) {
+ btrfs_free_path(path);
+ return PTR_ERR(trans);
+ }
+
+ path->lowest_level = btrfs_header_level(eb);
+ if (path->lowest_level)
+ btrfs_node_key_to_cpu(eb, &key, 0);
+ else
+ btrfs_item_key_to_cpu(eb, &key, 0);
+
+ ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
+ btrfs_commit_transaction(trans, root);
+ btrfs_free_path(path);
+ return ret;
+}
+
static struct option long_options[] = {
{ "super", 1, NULL, 's' },
{ "repair", 0, NULL, 0 },
fprintf(stderr, "checking root refs\n");
ret = check_root_refs(root, &root_cache);
+ if (ret)
+ goto out;
+
+ while (repair && !list_empty(&root->fs_info->recow_ebs)) {
+ struct extent_buffer *eb;
+
+ eb = list_first_entry(&root->fs_info->recow_ebs,
+ struct extent_buffer, recow);
+ ret = recow_extent_buffer(root, eb);
+ if (ret)
+ break;
+ }
+
+ if (!list_empty(&root->fs_info->recow_ebs)) {
+ fprintf(stderr, "Transid errors in file system\n");
+ ret = 1;
+ }
out:
free_root_recs_tree(&root_cache);
close_ctree(root);
write_extent_buffer(cow, root->fs_info->fsid,
btrfs_header_fsid(), BTRFS_FSID_SIZE);
- WARN_ON(btrfs_header_generation(buf) > trans->transid);
+ WARN_ON(!(buf->flags & EXTENT_BAD_TRANSID) &&
+ btrfs_header_generation(buf) > trans->transid);
update_ref_for_cow(trans, root, buf, cow);
btrfs_free_extent(trans, root, buf->start, buf->len,
0, root->root_key.objectid, level, 1);
}
+ if (!list_empty(&buf->recow)) {
+ list_del_init(&buf->recow);
+ free_extent_buffer(buf);
+ }
free_extent_buffer(buf);
btrfs_mark_buffer_dirty(cow);
*cow_ret = cow;
struct btrfs_extent_ops *extent_ops;
struct list_head dirty_cowonly_roots;
+ struct list_head recow_ebs;
struct btrfs_fs_devices *fs_devices;
struct list_head space_info;
(unsigned long long)parent_transid,
(unsigned long long)btrfs_header_generation(eb));
if (ignore) {
+ eb->flags |= EXTENT_BAD_TRANSID;
printk("Ignoring transid failure\n");
return 0;
}
csum_tree_block(root, eb, 1) == 0 &&
verify_parent_transid(eb->tree, eb, parent_transid, ignore)
== 0) {
+ if (eb->flags & EXTENT_BAD_TRANSID &&
+ list_empty(&eb->recow)) {
+ list_add_tail(&eb->recow,
+ &root->fs_info->recow_ebs);
+ eb->refs++;
+ }
btrfs_set_buffer_uptodate(eb);
return eb;
}
mutex_init(&fs_info->fs_mutex);
INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots);
INIT_LIST_HEAD(&fs_info->space_info);
+ INIT_LIST_HEAD(&fs_info->recow_ebs);
if (!writable)
fs_info->readonly = 1;
void btrfs_cleanup_all_caches(struct btrfs_fs_info *fs_info)
{
+ while (!list_empty(&fs_info->recow_ebs)) {
+ struct extent_buffer *eb;
+ eb = list_first_entry(&fs_info->recow_ebs,
+ struct extent_buffer, recow);
+ list_del_init(&eb->recow);
+ free_extent_buffer(eb);
+ }
free_mapping_cache_tree(&fs_info->mapping_tree.cache_tree);
extent_io_tree_cleanup(&fs_info->extent_cache);
extent_io_tree_cleanup(&fs_info->free_space_cache);
eb->dev_bytenr = (u64)-1;
eb->cache_node.start = bytenr;
eb->cache_node.size = blocksize;
+ INIT_LIST_HEAD(&eb->recow);
free_some_buffers(tree);
ret = insert_cache_extent(&tree->cache, &eb->cache_node);
struct extent_io_tree *tree = eb->tree;
BUG_ON(eb->flags & EXTENT_DIRTY);
list_del_init(&eb->lru);
+ list_del_init(&eb->recow);
remove_cache_extent(&tree->cache, &eb->cache_node);
BUG_ON(tree->cache_size < eb->len);
tree->cache_size -= eb->len;
#define EXTENT_DEFRAG_DONE (1 << 7)
#define EXTENT_BUFFER_FILLED (1 << 8)
#define EXTENT_CSUM (1 << 9)
+#define EXTENT_BAD_TRANSID (1 << 10)
#define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK)
#define BLOCK_GROUP_DATA EXTENT_WRITEBACK
u32 len;
struct extent_io_tree *tree;
struct list_head lru;
+ struct list_head recow;
int refs;
int flags;
int fd;