mirror of
https://github.com/kdave/btrfs-progs
synced 2025-04-04 23:29:20 +00:00
btrfsck: add code to rebuild extent records
This also includes a new --repair btrfsck option. For now it can only fix errors in the extent allocation tree. Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
parent
34c0fea109
commit
f5c4c4f3b7
457
btrfsck.c
457
btrfsck.c
@ -23,6 +23,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <getopt.h>
|
||||||
#include "kerncompat.h"
|
#include "kerncompat.h"
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
@ -74,9 +75,13 @@ struct extent_record {
|
|||||||
struct cache_extent cache;
|
struct cache_extent cache;
|
||||||
struct btrfs_disk_key parent_key;
|
struct btrfs_disk_key parent_key;
|
||||||
u64 start;
|
u64 start;
|
||||||
|
u64 max_size;
|
||||||
u64 nr;
|
u64 nr;
|
||||||
u64 refs;
|
u64 refs;
|
||||||
u64 extent_item_refs;
|
u64 extent_item_refs;
|
||||||
|
u64 generation;
|
||||||
|
u64 info_objectid;
|
||||||
|
u8 info_level;
|
||||||
unsigned int content_checked:1;
|
unsigned int content_checked:1;
|
||||||
unsigned int owner_ref_checked:1;
|
unsigned int owner_ref_checked:1;
|
||||||
unsigned int is_root:1;
|
unsigned int is_root:1;
|
||||||
@ -1082,7 +1087,9 @@ static int walk_down_tree(struct btrfs_root *root, struct btrfs_path *path,
|
|||||||
ret = btrfs_lookup_extent_info(NULL, root,
|
ret = btrfs_lookup_extent_info(NULL, root,
|
||||||
path->nodes[*level]->start,
|
path->nodes[*level]->start,
|
||||||
path->nodes[*level]->len, &refs, NULL);
|
path->nodes[*level]->len, &refs, NULL);
|
||||||
BUG_ON(ret);
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (refs > 1) {
|
if (refs > 1) {
|
||||||
ret = enter_shared_node(root, path->nodes[*level]->start,
|
ret = enter_shared_node(root, path->nodes[*level]->start,
|
||||||
refs, wc, *level);
|
refs, wc, *level);
|
||||||
@ -1109,7 +1116,8 @@ static int walk_down_tree(struct btrfs_root *root, struct btrfs_path *path,
|
|||||||
blocksize = btrfs_level_size(root, *level - 1);
|
blocksize = btrfs_level_size(root, *level - 1);
|
||||||
ret = btrfs_lookup_extent_info(NULL, root, bytenr, blocksize,
|
ret = btrfs_lookup_extent_info(NULL, root, bytenr, blocksize,
|
||||||
&refs, NULL);
|
&refs, NULL);
|
||||||
BUG_ON(ret);
|
if (ret < 0)
|
||||||
|
refs = 0;
|
||||||
|
|
||||||
if (refs > 1) {
|
if (refs > 1) {
|
||||||
ret = enter_shared_node(root, bytenr, refs,
|
ret = enter_shared_node(root, bytenr, refs,
|
||||||
@ -1834,12 +1842,12 @@ static int all_backpointers_checked(struct extent_record *rec, int print_errs)
|
|||||||
if (!print_errs)
|
if (!print_errs)
|
||||||
goto out;
|
goto out;
|
||||||
tback = (struct tree_backref *)back;
|
tback = (struct tree_backref *)back;
|
||||||
fprintf(stderr, "Backref %llu %s %llu not referenced\n",
|
fprintf(stderr, "Backref %llu %s %llu not referenced back %p\n",
|
||||||
(unsigned long long)rec->start,
|
(unsigned long long)rec->start,
|
||||||
back->full_backref ? "parent" : "root",
|
back->full_backref ? "parent" : "root",
|
||||||
back->full_backref ?
|
back->full_backref ?
|
||||||
(unsigned long long)tback->parent :
|
(unsigned long long)tback->parent :
|
||||||
(unsigned long long)tback->root);
|
(unsigned long long)tback->root, back);
|
||||||
}
|
}
|
||||||
if (back->is_data) {
|
if (back->is_data) {
|
||||||
dback = (struct data_backref *)back;
|
dback = (struct data_backref *)back;
|
||||||
@ -1849,7 +1857,7 @@ static int all_backpointers_checked(struct extent_record *rec, int print_errs)
|
|||||||
goto out;
|
goto out;
|
||||||
fprintf(stderr, "Incorrect local backref count"
|
fprintf(stderr, "Incorrect local backref count"
|
||||||
" on %llu %s %llu owner %llu"
|
" on %llu %s %llu owner %llu"
|
||||||
" offset %llu found %u wanted %u\n",
|
" offset %llu found %u wanted %u back %p\n",
|
||||||
(unsigned long long)rec->start,
|
(unsigned long long)rec->start,
|
||||||
back->full_backref ?
|
back->full_backref ?
|
||||||
"parent" : "root",
|
"parent" : "root",
|
||||||
@ -1858,7 +1866,7 @@ static int all_backpointers_checked(struct extent_record *rec, int print_errs)
|
|||||||
(unsigned long long)dback->root,
|
(unsigned long long)dback->root,
|
||||||
(unsigned long long)dback->owner,
|
(unsigned long long)dback->owner,
|
||||||
(unsigned long long)dback->offset,
|
(unsigned long long)dback->offset,
|
||||||
dback->found_ref, dback->num_refs);
|
dback->found_ref, dback->num_refs, back);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!back->is_data) {
|
if (!back->is_data) {
|
||||||
@ -1965,12 +1973,28 @@ static int check_block(struct btrfs_root *root,
|
|||||||
{
|
{
|
||||||
struct extent_record *rec;
|
struct extent_record *rec;
|
||||||
struct cache_extent *cache;
|
struct cache_extent *cache;
|
||||||
|
struct btrfs_key key;
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
|
int level;
|
||||||
|
|
||||||
cache = find_cache_extent(extent_cache, buf->start, buf->len);
|
cache = find_cache_extent(extent_cache, buf->start, buf->len);
|
||||||
if (!cache)
|
if (!cache)
|
||||||
return 1;
|
return 1;
|
||||||
rec = container_of(cache, struct extent_record, cache);
|
rec = container_of(cache, struct extent_record, cache);
|
||||||
|
rec->generation = btrfs_header_generation(buf);
|
||||||
|
|
||||||
|
level = btrfs_header_level(buf);
|
||||||
|
if (btrfs_header_nritems(buf) > 0) {
|
||||||
|
|
||||||
|
if (level == 0)
|
||||||
|
btrfs_item_key_to_cpu(buf, &key, 0);
|
||||||
|
else
|
||||||
|
btrfs_node_key_to_cpu(buf, &key, 0);
|
||||||
|
|
||||||
|
rec->info_objectid = key.objectid;
|
||||||
|
}
|
||||||
|
rec->info_level = level;
|
||||||
|
|
||||||
if (btrfs_is_leaf(buf)) {
|
if (btrfs_is_leaf(buf)) {
|
||||||
ret = check_leaf(root, &rec->parent_key, buf);
|
ret = check_leaf(root, &rec->parent_key, buf);
|
||||||
} else {
|
} else {
|
||||||
@ -2035,6 +2059,7 @@ static struct tree_backref *alloc_tree_backref(struct extent_record *rec,
|
|||||||
ref->node.full_backref = 0;
|
ref->node.full_backref = 0;
|
||||||
}
|
}
|
||||||
list_add_tail(&ref->node.list, &rec->backrefs);
|
list_add_tail(&ref->node.list, &rec->backrefs);
|
||||||
|
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2052,7 +2077,7 @@ static struct data_backref *find_data_backref(struct extent_record *rec,
|
|||||||
if (!node->is_data)
|
if (!node->is_data)
|
||||||
continue;
|
continue;
|
||||||
back = (struct data_backref *)node;
|
back = (struct data_backref *)node;
|
||||||
if (parent > 0) {
|
if (parent > 0) {
|
||||||
if (!node->full_backref)
|
if (!node->full_backref)
|
||||||
continue;
|
continue;
|
||||||
if (parent == back->parent)
|
if (parent == back->parent)
|
||||||
@ -2070,11 +2095,13 @@ static struct data_backref *find_data_backref(struct extent_record *rec,
|
|||||||
|
|
||||||
static struct data_backref *alloc_data_backref(struct extent_record *rec,
|
static struct data_backref *alloc_data_backref(struct extent_record *rec,
|
||||||
u64 parent, u64 root,
|
u64 parent, u64 root,
|
||||||
u64 owner, u64 offset)
|
u64 owner, u64 offset,
|
||||||
|
u64 max_size)
|
||||||
{
|
{
|
||||||
struct data_backref *ref = malloc(sizeof(*ref));
|
struct data_backref *ref = malloc(sizeof(*ref));
|
||||||
memset(&ref->node, 0, sizeof(ref->node));
|
memset(&ref->node, 0, sizeof(ref->node));
|
||||||
ref->node.is_data = 1;
|
ref->node.is_data = 1;
|
||||||
|
|
||||||
if (parent > 0) {
|
if (parent > 0) {
|
||||||
ref->parent = parent;
|
ref->parent = parent;
|
||||||
ref->owner = 0;
|
ref->owner = 0;
|
||||||
@ -2089,13 +2116,16 @@ static struct data_backref *alloc_data_backref(struct extent_record *rec,
|
|||||||
ref->found_ref = 0;
|
ref->found_ref = 0;
|
||||||
ref->num_refs = 0;
|
ref->num_refs = 0;
|
||||||
list_add_tail(&ref->node.list, &rec->backrefs);
|
list_add_tail(&ref->node.list, &rec->backrefs);
|
||||||
|
if (max_size > rec->max_size)
|
||||||
|
rec->max_size = max_size;
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_extent_rec(struct cache_tree *extent_cache,
|
static int add_extent_rec(struct cache_tree *extent_cache,
|
||||||
struct btrfs_key *parent_key,
|
struct btrfs_key *parent_key,
|
||||||
u64 start, u64 nr, u64 extent_item_refs,
|
u64 start, u64 nr, u64 extent_item_refs,
|
||||||
int is_root, int inc_ref, int set_checked)
|
int is_root, int inc_ref, int set_checked,
|
||||||
|
u64 max_size)
|
||||||
{
|
{
|
||||||
struct extent_record *rec;
|
struct extent_record *rec;
|
||||||
struct cache_extent *cache;
|
struct cache_extent *cache;
|
||||||
@ -2136,11 +2166,15 @@ static int add_extent_rec(struct cache_tree *extent_cache,
|
|||||||
if (parent_key)
|
if (parent_key)
|
||||||
btrfs_cpu_key_to_disk(&rec->parent_key, parent_key);
|
btrfs_cpu_key_to_disk(&rec->parent_key, parent_key);
|
||||||
|
|
||||||
|
if (rec->max_size < max_size)
|
||||||
|
rec->max_size = max_size;
|
||||||
|
|
||||||
maybe_free_extent_rec(extent_cache, rec);
|
maybe_free_extent_rec(extent_cache, rec);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
rec = malloc(sizeof(*rec));
|
rec = malloc(sizeof(*rec));
|
||||||
rec->start = start;
|
rec->start = start;
|
||||||
|
rec->max_size = max_size;
|
||||||
rec->nr = nr;
|
rec->nr = nr;
|
||||||
rec->content_checked = 0;
|
rec->content_checked = 0;
|
||||||
rec->owner_ref_checked = 0;
|
rec->owner_ref_checked = 0;
|
||||||
@ -2187,7 +2221,7 @@ static int add_tree_backref(struct cache_tree *extent_cache, u64 bytenr,
|
|||||||
|
|
||||||
cache = find_cache_extent(extent_cache, bytenr, 1);
|
cache = find_cache_extent(extent_cache, bytenr, 1);
|
||||||
if (!cache) {
|
if (!cache) {
|
||||||
add_extent_rec(extent_cache, NULL, bytenr, 1, 0, 0, 0, 0);
|
add_extent_rec(extent_cache, NULL, bytenr, 1, 0, 0, 0, 0, 0);
|
||||||
cache = find_cache_extent(extent_cache, bytenr, 1);
|
cache = find_cache_extent(extent_cache, bytenr, 1);
|
||||||
if (!cache)
|
if (!cache)
|
||||||
abort();
|
abort();
|
||||||
@ -2226,7 +2260,7 @@ static int add_tree_backref(struct cache_tree *extent_cache, u64 bytenr,
|
|||||||
|
|
||||||
static int add_data_backref(struct cache_tree *extent_cache, u64 bytenr,
|
static int add_data_backref(struct cache_tree *extent_cache, u64 bytenr,
|
||||||
u64 parent, u64 root, u64 owner, u64 offset,
|
u64 parent, u64 root, u64 owner, u64 offset,
|
||||||
u32 num_refs, int found_ref)
|
u32 num_refs, int found_ref, u64 max_size)
|
||||||
{
|
{
|
||||||
struct extent_record *rec;
|
struct extent_record *rec;
|
||||||
struct data_backref *back;
|
struct data_backref *back;
|
||||||
@ -2234,7 +2268,8 @@ static int add_data_backref(struct cache_tree *extent_cache, u64 bytenr,
|
|||||||
|
|
||||||
cache = find_cache_extent(extent_cache, bytenr, 1);
|
cache = find_cache_extent(extent_cache, bytenr, 1);
|
||||||
if (!cache) {
|
if (!cache) {
|
||||||
add_extent_rec(extent_cache, NULL, bytenr, 1, 0, 0, 0, 0);
|
add_extent_rec(extent_cache, NULL, bytenr, 1, 0, 0, 0, 0,
|
||||||
|
max_size);
|
||||||
cache = find_cache_extent(extent_cache, bytenr, 1);
|
cache = find_cache_extent(extent_cache, bytenr, 1);
|
||||||
if (!cache)
|
if (!cache)
|
||||||
abort();
|
abort();
|
||||||
@ -2244,9 +2279,13 @@ static int add_data_backref(struct cache_tree *extent_cache, u64 bytenr,
|
|||||||
if (rec->start != bytenr) {
|
if (rec->start != bytenr) {
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
if (rec->max_size < max_size)
|
||||||
|
rec->max_size = max_size;
|
||||||
|
|
||||||
back = find_data_backref(rec, parent, root, owner, offset);
|
back = find_data_backref(rec, parent, root, owner, offset);
|
||||||
if (!back)
|
if (!back)
|
||||||
back = alloc_data_backref(rec, parent, root, owner, offset);
|
back = alloc_data_backref(rec, parent, root, owner, offset,
|
||||||
|
max_size);
|
||||||
|
|
||||||
if (found_ref) {
|
if (found_ref) {
|
||||||
BUG_ON(num_refs != 1);
|
BUG_ON(num_refs != 1);
|
||||||
@ -2359,11 +2398,10 @@ static int process_extent_ref_v0(struct cache_tree *extent_cache,
|
|||||||
btrfs_item_key_to_cpu(leaf, &key, slot);
|
btrfs_item_key_to_cpu(leaf, &key, slot);
|
||||||
ref0 = btrfs_item_ptr(leaf, slot, struct btrfs_extent_ref_v0);
|
ref0 = btrfs_item_ptr(leaf, slot, struct btrfs_extent_ref_v0);
|
||||||
if (btrfs_ref_objectid_v0(leaf, ref0) < BTRFS_FIRST_FREE_OBJECTID) {
|
if (btrfs_ref_objectid_v0(leaf, ref0) < BTRFS_FIRST_FREE_OBJECTID) {
|
||||||
add_tree_backref(extent_cache, key.objectid, key.offset,
|
add_tree_backref(extent_cache, key.objectid, key.offset, 0, 0);
|
||||||
0, 0);
|
|
||||||
} else {
|
} else {
|
||||||
add_data_backref(extent_cache, key.objectid, key.offset, 0,
|
add_data_backref(extent_cache, key.objectid, key.offset, 0,
|
||||||
0, 0, btrfs_ref_count_v0(leaf, ref0), 0);
|
0, 0, btrfs_ref_count_v0(leaf, ref0), 0, 0);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -2396,14 +2434,14 @@ static int process_extent_item(struct cache_tree *extent_cache,
|
|||||||
BUG();
|
BUG();
|
||||||
#endif
|
#endif
|
||||||
return add_extent_rec(extent_cache, NULL, key.objectid,
|
return add_extent_rec(extent_cache, NULL, key.objectid,
|
||||||
key.offset, refs, 0, 0, 0);
|
key.offset, refs, 0, 0, 0, key.offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
ei = btrfs_item_ptr(eb, slot, struct btrfs_extent_item);
|
ei = btrfs_item_ptr(eb, slot, struct btrfs_extent_item);
|
||||||
refs = btrfs_extent_refs(eb, ei);
|
refs = btrfs_extent_refs(eb, ei);
|
||||||
|
|
||||||
add_extent_rec(extent_cache, NULL, key.objectid, key.offset,
|
add_extent_rec(extent_cache, NULL, key.objectid, key.offset,
|
||||||
refs, 0, 0, 0);
|
refs, 0, 0, 0, key.offset);
|
||||||
|
|
||||||
ptr = (unsigned long)(ei + 1);
|
ptr = (unsigned long)(ei + 1);
|
||||||
if (btrfs_extent_flags(eb, ei) & BTRFS_EXTENT_FLAG_TREE_BLOCK)
|
if (btrfs_extent_flags(eb, ei) & BTRFS_EXTENT_FLAG_TREE_BLOCK)
|
||||||
@ -2431,14 +2469,14 @@ static int process_extent_item(struct cache_tree *extent_cache,
|
|||||||
dref),
|
dref),
|
||||||
btrfs_extent_data_ref_offset(eb, dref),
|
btrfs_extent_data_ref_offset(eb, dref),
|
||||||
btrfs_extent_data_ref_count(eb, dref),
|
btrfs_extent_data_ref_count(eb, dref),
|
||||||
0);
|
0, key.offset);
|
||||||
break;
|
break;
|
||||||
case BTRFS_SHARED_DATA_REF_KEY:
|
case BTRFS_SHARED_DATA_REF_KEY:
|
||||||
sref = (struct btrfs_shared_data_ref *)(iref + 1);
|
sref = (struct btrfs_shared_data_ref *)(iref + 1);
|
||||||
add_data_backref(extent_cache, key.objectid, offset,
|
add_data_backref(extent_cache, key.objectid, offset,
|
||||||
0, 0, 0,
|
0, 0, 0,
|
||||||
btrfs_shared_data_ref_count(eb, sref),
|
btrfs_shared_data_ref_count(eb, sref),
|
||||||
0);
|
0, key.offset);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "corrupt extent record: key %Lu %u %Lu\n",
|
fprintf(stderr, "corrupt extent record: key %Lu %u %Lu\n",
|
||||||
@ -2515,6 +2553,8 @@ static int run_next_block(struct btrfs_root *root,
|
|||||||
nritems = btrfs_header_nritems(buf);
|
nritems = btrfs_header_nritems(buf);
|
||||||
|
|
||||||
ret = btrfs_lookup_extent_info(NULL, root, bytenr, size, NULL, &flags);
|
ret = btrfs_lookup_extent_info(NULL, root, bytenr, size, NULL, &flags);
|
||||||
|
if (ret < 0)
|
||||||
|
flags = BTRFS_BLOCK_FLAG_FULL_BACKREF;
|
||||||
|
|
||||||
if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) {
|
if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) {
|
||||||
parent = bytenr;
|
parent = bytenr;
|
||||||
@ -2573,7 +2613,7 @@ static int run_next_block(struct btrfs_root *root,
|
|||||||
ref),
|
ref),
|
||||||
btrfs_extent_data_ref_offset(buf, ref),
|
btrfs_extent_data_ref_offset(buf, ref),
|
||||||
btrfs_extent_data_ref_count(buf, ref),
|
btrfs_extent_data_ref_count(buf, ref),
|
||||||
0);
|
0, root->sectorsize);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (key.type == BTRFS_SHARED_DATA_REF_KEY) {
|
if (key.type == BTRFS_SHARED_DATA_REF_KEY) {
|
||||||
@ -2583,7 +2623,7 @@ static int run_next_block(struct btrfs_root *root,
|
|||||||
add_data_backref(extent_cache,
|
add_data_backref(extent_cache,
|
||||||
key.objectid, key.offset, 0, 0, 0,
|
key.objectid, key.offset, 0, 0, 0,
|
||||||
btrfs_shared_data_ref_count(buf, ref),
|
btrfs_shared_data_ref_count(buf, ref),
|
||||||
0);
|
0, root->sectorsize);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (key.type != BTRFS_EXTENT_DATA_KEY)
|
if (key.type != BTRFS_EXTENT_DATA_KEY)
|
||||||
@ -2606,26 +2646,33 @@ static int run_next_block(struct btrfs_root *root,
|
|||||||
ret = add_extent_rec(extent_cache, NULL,
|
ret = add_extent_rec(extent_cache, NULL,
|
||||||
btrfs_file_extent_disk_bytenr(buf, fi),
|
btrfs_file_extent_disk_bytenr(buf, fi),
|
||||||
btrfs_file_extent_disk_num_bytes(buf, fi),
|
btrfs_file_extent_disk_num_bytes(buf, fi),
|
||||||
0, 0, 1, 1);
|
0, 0, 1, 1,
|
||||||
|
btrfs_file_extent_disk_num_bytes(buf, fi));
|
||||||
add_data_backref(extent_cache,
|
add_data_backref(extent_cache,
|
||||||
btrfs_file_extent_disk_bytenr(buf, fi),
|
btrfs_file_extent_disk_bytenr(buf, fi),
|
||||||
parent, owner, key.objectid, key.offset -
|
parent, owner, key.objectid, key.offset -
|
||||||
btrfs_file_extent_offset(buf, fi), 1, 1);
|
btrfs_file_extent_offset(buf, fi), 1, 1,
|
||||||
|
btrfs_file_extent_disk_num_bytes(buf, fi));
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int level;
|
int level;
|
||||||
|
struct btrfs_key first_key;
|
||||||
|
|
||||||
|
first_key.objectid = 0;
|
||||||
|
|
||||||
|
if (nritems > 0)
|
||||||
|
btrfs_item_key_to_cpu(buf, &first_key, 0);
|
||||||
level = btrfs_header_level(buf);
|
level = btrfs_header_level(buf);
|
||||||
for (i = 0; i < nritems; i++) {
|
for (i = 0; i < nritems; i++) {
|
||||||
u64 ptr = btrfs_node_blockptr(buf, i);
|
u64 ptr = btrfs_node_blockptr(buf, i);
|
||||||
u32 size = btrfs_level_size(root, level - 1);
|
u32 size = btrfs_level_size(root, level - 1);
|
||||||
btrfs_node_key_to_cpu(buf, &key, i);
|
btrfs_node_key_to_cpu(buf, &key, i);
|
||||||
ret = add_extent_rec(extent_cache, &key,
|
ret = add_extent_rec(extent_cache, &key,
|
||||||
ptr, size, 0, 0, 1, 0);
|
ptr, size, 0, 0, 1, 0, size);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
|
||||||
add_tree_backref(extent_cache, ptr, parent,
|
add_tree_backref(extent_cache, ptr, parent, owner, 1);
|
||||||
owner, 1);
|
|
||||||
|
|
||||||
if (level > 1) {
|
if (level > 1) {
|
||||||
add_pending(nodes, seen, ptr, size);
|
add_pending(nodes, seen, ptr, size);
|
||||||
@ -2663,25 +2710,313 @@ static int add_root_to_pending(struct extent_buffer *buf,
|
|||||||
else
|
else
|
||||||
add_pending(pending, seen, buf->start, buf->len);
|
add_pending(pending, seen, buf->start, buf->len);
|
||||||
add_extent_rec(extent_cache, NULL, buf->start, buf->len,
|
add_extent_rec(extent_cache, NULL, buf->start, buf->len,
|
||||||
0, 1, 1, 0);
|
0, 1, 1, 0, buf->len);
|
||||||
|
|
||||||
if (root_key->objectid == BTRFS_TREE_RELOC_OBJECTID ||
|
if (root_key->objectid == BTRFS_TREE_RELOC_OBJECTID ||
|
||||||
btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV)
|
btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV)
|
||||||
add_tree_backref(extent_cache, buf->start, buf->start, 0, 1);
|
add_tree_backref(extent_cache, buf->start, buf->start,
|
||||||
|
0, 1);
|
||||||
else
|
else
|
||||||
add_tree_backref(extent_cache, buf->start, 0,
|
add_tree_backref(extent_cache, buf->start, 0,
|
||||||
root_key->objectid, 1);
|
root_key->objectid, 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int delete_extent_records(struct btrfs_trans_handle *trans,
|
||||||
|
struct btrfs_root *root,
|
||||||
|
struct btrfs_path *path,
|
||||||
|
u64 bytenr)
|
||||||
|
{
|
||||||
|
struct btrfs_key key;
|
||||||
|
struct btrfs_key found_key;
|
||||||
|
struct extent_buffer *leaf;
|
||||||
|
int ret;
|
||||||
|
int slot;
|
||||||
|
|
||||||
|
|
||||||
|
key.objectid = bytenr;
|
||||||
|
key.type = (u8)-1;
|
||||||
|
key.offset = (u64)-1;
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
ret = btrfs_search_slot(trans, root->fs_info->extent_root,
|
||||||
|
&key, path, 0, 1);
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (ret > 0) {
|
||||||
|
ret = 0;
|
||||||
|
if (path->slots[0] == 0)
|
||||||
|
break;
|
||||||
|
path->slots[0]--;
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
leaf = path->nodes[0];
|
||||||
|
slot = path->slots[0];
|
||||||
|
|
||||||
|
btrfs_item_key_to_cpu(leaf, &found_key, slot);
|
||||||
|
if (found_key.objectid != bytenr)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (found_key.type != BTRFS_EXTENT_ITEM_KEY &&
|
||||||
|
found_key.type != BTRFS_TREE_BLOCK_REF_KEY &&
|
||||||
|
found_key.type != BTRFS_EXTENT_DATA_REF_KEY &&
|
||||||
|
found_key.type != BTRFS_EXTENT_REF_V0_KEY &&
|
||||||
|
found_key.type != BTRFS_SHARED_BLOCK_REF_KEY &&
|
||||||
|
found_key.type != BTRFS_SHARED_DATA_REF_KEY) {
|
||||||
|
btrfs_release_path(NULL, path);
|
||||||
|
if (found_key.type == 0) {
|
||||||
|
if (found_key.offset == 0)
|
||||||
|
break;
|
||||||
|
key.offset = found_key.offset - 1;
|
||||||
|
key.type = found_key.type;
|
||||||
|
}
|
||||||
|
key.type = found_key.type - 1;
|
||||||
|
key.offset = (u64)-1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "repair deleting extent record: key %Lu %u %Lu\n",
|
||||||
|
found_key.objectid, found_key.type, found_key.offset);
|
||||||
|
|
||||||
|
ret = btrfs_del_item(trans, root->fs_info->extent_root, path);
|
||||||
|
if (ret)
|
||||||
|
break;
|
||||||
|
btrfs_release_path(NULL, path);
|
||||||
|
|
||||||
|
if (found_key.type == BTRFS_EXTENT_ITEM_KEY) {
|
||||||
|
ret = btrfs_update_block_group(trans, root, bytenr,
|
||||||
|
found_key.offset, 0, 1);
|
||||||
|
if (ret)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
btrfs_release_path(NULL, path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* for a single backref, this will allocate a new extent
|
||||||
|
* and add the backref to it.
|
||||||
|
*/
|
||||||
|
static int record_extent(struct btrfs_trans_handle *trans,
|
||||||
|
struct btrfs_fs_info *info,
|
||||||
|
struct btrfs_path *path,
|
||||||
|
struct extent_record *rec,
|
||||||
|
struct extent_backref *back,
|
||||||
|
int allocated, u64 flags)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct btrfs_root *extent_root = info->extent_root;
|
||||||
|
struct extent_buffer *leaf;
|
||||||
|
struct btrfs_key ins_key;
|
||||||
|
struct btrfs_extent_item *ei;
|
||||||
|
struct tree_backref *tback;
|
||||||
|
struct data_backref *dback;
|
||||||
|
struct btrfs_tree_block_info *bi;
|
||||||
|
|
||||||
|
if (!back->is_data)
|
||||||
|
rec->max_size = max_t(u64, rec->max_size,
|
||||||
|
info->extent_root->leafsize);
|
||||||
|
|
||||||
|
if (!allocated) {
|
||||||
|
u32 item_size = sizeof(*ei);
|
||||||
|
|
||||||
|
if (!back->is_data)
|
||||||
|
item_size += sizeof(*bi);
|
||||||
|
|
||||||
|
ins_key.objectid = rec->start;
|
||||||
|
ins_key.offset = rec->max_size;
|
||||||
|
ins_key.type = BTRFS_EXTENT_ITEM_KEY;
|
||||||
|
|
||||||
|
ret = btrfs_insert_empty_item(trans, extent_root, path,
|
||||||
|
&ins_key, item_size);
|
||||||
|
if (ret)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
leaf = path->nodes[0];
|
||||||
|
ei = btrfs_item_ptr(leaf, path->slots[0],
|
||||||
|
struct btrfs_extent_item);
|
||||||
|
|
||||||
|
btrfs_set_extent_refs(leaf, ei, 0);
|
||||||
|
btrfs_set_extent_generation(leaf, ei, rec->generation);
|
||||||
|
|
||||||
|
if (back->is_data) {
|
||||||
|
btrfs_set_extent_flags(leaf, ei,
|
||||||
|
BTRFS_EXTENT_FLAG_DATA);
|
||||||
|
} else {
|
||||||
|
struct btrfs_disk_key copy_key;;
|
||||||
|
|
||||||
|
tback = (struct tree_backref *)back;
|
||||||
|
bi = (struct btrfs_tree_block_info *)(ei + 1);
|
||||||
|
memset_extent_buffer(leaf, 0, (unsigned long)bi,
|
||||||
|
sizeof(*bi));
|
||||||
|
memset(©_key, 0, sizeof(copy_key));
|
||||||
|
|
||||||
|
copy_key.objectid = le64_to_cpu(rec->info_objectid);
|
||||||
|
btrfs_set_tree_block_level(leaf, bi, rec->info_level);
|
||||||
|
btrfs_set_tree_block_key(leaf, bi, ©_key);
|
||||||
|
|
||||||
|
btrfs_set_extent_flags(leaf, ei,
|
||||||
|
BTRFS_EXTENT_FLAG_TREE_BLOCK | flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
btrfs_mark_buffer_dirty(leaf);
|
||||||
|
ret = btrfs_update_block_group(trans, extent_root, rec->start,
|
||||||
|
rec->max_size, 1, 0);
|
||||||
|
if (ret)
|
||||||
|
goto fail;
|
||||||
|
btrfs_release_path(NULL, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (back->is_data) {
|
||||||
|
u64 parent;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
dback = (struct data_backref *)back;
|
||||||
|
if (back->full_backref)
|
||||||
|
parent = dback->parent;
|
||||||
|
else
|
||||||
|
parent = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < dback->found_ref; i++) {
|
||||||
|
/* if parent != 0, we're doing a full backref
|
||||||
|
* passing BTRFS_FIRST_FREE_OBJECTID as the owner
|
||||||
|
* just makes the backref allocator create a data
|
||||||
|
* backref
|
||||||
|
*/
|
||||||
|
ret = btrfs_inc_extent_ref(trans, info->extent_root,
|
||||||
|
rec->start, rec->max_size,
|
||||||
|
parent,
|
||||||
|
dback->root,
|
||||||
|
parent ?
|
||||||
|
BTRFS_FIRST_FREE_OBJECTID :
|
||||||
|
dback->owner,
|
||||||
|
dback->offset);
|
||||||
|
if (ret)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "adding new data backref"
|
||||||
|
" on %llu %s %llu owner %llu"
|
||||||
|
" offset %llu found %d\n",
|
||||||
|
(unsigned long long)rec->start,
|
||||||
|
back->full_backref ?
|
||||||
|
"parent" : "root",
|
||||||
|
back->full_backref ?
|
||||||
|
(unsigned long long)parent :
|
||||||
|
(unsigned long long)dback->root,
|
||||||
|
(unsigned long long)dback->owner,
|
||||||
|
(unsigned long long)dback->offset,
|
||||||
|
dback->found_ref);
|
||||||
|
} else {
|
||||||
|
u64 parent;
|
||||||
|
|
||||||
|
tback = (struct tree_backref *)back;
|
||||||
|
if (back->full_backref)
|
||||||
|
parent = tback->parent;
|
||||||
|
else
|
||||||
|
parent = 0;
|
||||||
|
|
||||||
|
ret = btrfs_inc_extent_ref(trans, info->extent_root,
|
||||||
|
rec->start, rec->max_size,
|
||||||
|
parent, tback->root, 0, 0);
|
||||||
|
fprintf(stderr, "adding new tree backref on "
|
||||||
|
"start %llu len %llu parent %llu root %llu\n",
|
||||||
|
rec->start, rec->max_size, tback->parent, tback->root);
|
||||||
|
}
|
||||||
|
if (ret)
|
||||||
|
goto fail;
|
||||||
|
fail:
|
||||||
|
btrfs_release_path(NULL, path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* when an incorrect extent item is found, this will delete
|
||||||
|
* all of the existing entries for it and recreate them
|
||||||
|
* based on what the tree scan found.
|
||||||
|
*/
|
||||||
|
static int fixup_extent_refs(struct btrfs_trans_handle *trans,
|
||||||
|
struct btrfs_fs_info *info,
|
||||||
|
struct extent_record *rec)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct btrfs_path *path;
|
||||||
|
struct list_head *cur = rec->backrefs.next;
|
||||||
|
struct extent_backref *back;
|
||||||
|
int allocated = 0;
|
||||||
|
u64 flags = 0;
|
||||||
|
|
||||||
|
/* remember our flags for recreating the extent */
|
||||||
|
ret = btrfs_lookup_extent_info(NULL, info->extent_root, rec->start,
|
||||||
|
rec->max_size, NULL, &flags);
|
||||||
|
if (ret < 0)
|
||||||
|
flags = BTRFS_BLOCK_FLAG_FULL_BACKREF;
|
||||||
|
|
||||||
|
path = btrfs_alloc_path();
|
||||||
|
|
||||||
|
/* step one, delete all the existing records */
|
||||||
|
ret = delete_extent_records(trans, info->extent_root, path,
|
||||||
|
rec->start);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* step two, recreate all the refs we did find */
|
||||||
|
while(cur != &rec->backrefs) {
|
||||||
|
back = list_entry(cur, struct extent_backref, list);
|
||||||
|
cur = cur->next;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if we didn't find any references, don't create a
|
||||||
|
* new extent record
|
||||||
|
*/
|
||||||
|
if (!back->found_ref)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ret = record_extent(trans, info, path, rec, back, allocated, flags);
|
||||||
|
allocated = 1;
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
btrfs_free_path(path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int check_extent_refs(struct btrfs_root *root,
|
static int check_extent_refs(struct btrfs_root *root,
|
||||||
struct cache_tree *extent_cache)
|
struct cache_tree *extent_cache, int repair)
|
||||||
{
|
{
|
||||||
struct extent_record *rec;
|
struct extent_record *rec;
|
||||||
struct cache_extent *cache;
|
struct cache_extent *cache;
|
||||||
|
struct btrfs_trans_handle *trans = NULL;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
int ret = 0;
|
||||||
|
int fixed = 0;
|
||||||
|
|
||||||
|
if (repair)
|
||||||
|
trans = btrfs_start_transaction(root, 1);
|
||||||
|
|
||||||
|
if (repair) {
|
||||||
|
/*
|
||||||
|
* if we're doing a repair, we have to make sure
|
||||||
|
* we don't allocate from the problem extents.
|
||||||
|
* In the worst case, this will be all the
|
||||||
|
* extents in the FS
|
||||||
|
*/
|
||||||
|
cache = find_first_cache_extent(extent_cache, 0);
|
||||||
|
while(cache) {
|
||||||
|
rec = container_of(cache, struct extent_record, cache);
|
||||||
|
btrfs_pin_extent(root->fs_info,
|
||||||
|
rec->start, rec->nr);
|
||||||
|
cache = next_cache_extent(cache);
|
||||||
|
}
|
||||||
|
}
|
||||||
while(1) {
|
while(1) {
|
||||||
|
fixed = 0;
|
||||||
cache = find_first_cache_extent(extent_cache, 0);
|
cache = find_first_cache_extent(extent_cache, 0);
|
||||||
if (!cache)
|
if (!cache)
|
||||||
break;
|
break;
|
||||||
@ -2693,19 +3028,39 @@ static int check_extent_refs(struct btrfs_root *root,
|
|||||||
fprintf(stderr, "extent item %llu, found %llu\n",
|
fprintf(stderr, "extent item %llu, found %llu\n",
|
||||||
(unsigned long long)rec->extent_item_refs,
|
(unsigned long long)rec->extent_item_refs,
|
||||||
(unsigned long long)rec->refs);
|
(unsigned long long)rec->refs);
|
||||||
|
if (!fixed && repair) {
|
||||||
|
ret = fixup_extent_refs(trans, root->fs_info, rec);
|
||||||
|
if (ret)
|
||||||
|
goto repair_abort;
|
||||||
|
fixed = 1;
|
||||||
|
}
|
||||||
err = 1;
|
err = 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
if (all_backpointers_checked(rec, 1)) {
|
if (all_backpointers_checked(rec, 1)) {
|
||||||
fprintf(stderr, "backpointer mismatch on [%llu %llu]\n",
|
fprintf(stderr, "backpointer mismatch on [%llu %llu]\n",
|
||||||
(unsigned long long)rec->start,
|
(unsigned long long)rec->start,
|
||||||
(unsigned long long)rec->nr);
|
(unsigned long long)rec->nr);
|
||||||
|
|
||||||
|
if (!fixed && repair) {
|
||||||
|
ret = fixup_extent_refs(trans, root->fs_info, rec);
|
||||||
|
if (ret)
|
||||||
|
goto repair_abort;
|
||||||
|
fixed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
err = 1;
|
err = 1;
|
||||||
}
|
}
|
||||||
if (!rec->owner_ref_checked) {
|
if (!rec->owner_ref_checked) {
|
||||||
fprintf(stderr, "owner ref check failed [%llu %llu]\n",
|
fprintf(stderr, "owner ref check failed [%llu %llu]\n",
|
||||||
(unsigned long long)rec->start,
|
(unsigned long long)rec->start,
|
||||||
(unsigned long long)rec->nr);
|
(unsigned long long)rec->nr);
|
||||||
|
if (!fixed && repair) {
|
||||||
|
ret = fixup_extent_refs(trans, root->fs_info, rec);
|
||||||
|
if (ret)
|
||||||
|
goto repair_abort;
|
||||||
|
fixed = 1;
|
||||||
|
}
|
||||||
err = 1;
|
err = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2713,10 +3068,18 @@ static int check_extent_refs(struct btrfs_root *root,
|
|||||||
free_all_extent_backrefs(rec);
|
free_all_extent_backrefs(rec);
|
||||||
free(rec);
|
free(rec);
|
||||||
}
|
}
|
||||||
|
repair_abort:
|
||||||
|
if (repair) {
|
||||||
|
if (ret) {
|
||||||
|
fprintf(stderr, "failed to repair damaged filesystem, aborting\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
btrfs_commit_transaction(trans, root);
|
||||||
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int check_extents(struct btrfs_root *root)
|
static int check_extents(struct btrfs_root *root, int repair)
|
||||||
{
|
{
|
||||||
struct cache_tree extent_cache;
|
struct cache_tree extent_cache;
|
||||||
struct cache_tree seen;
|
struct cache_tree seen;
|
||||||
@ -2797,7 +3160,7 @@ static int check_extents(struct btrfs_root *root)
|
|||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ret = check_extent_refs(root, &extent_cache);
|
ret = check_extent_refs(root, &extent_cache, repair);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2808,6 +3171,12 @@ static void print_usage(void)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct option long_options[] = {
|
||||||
|
{ "super", 1, NULL, 's' },
|
||||||
|
{ "repair", 0, NULL, 0 },
|
||||||
|
{ 0, 0, 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
int main(int ac, char **av)
|
int main(int ac, char **av)
|
||||||
{
|
{
|
||||||
struct cache_tree root_cache;
|
struct cache_tree root_cache;
|
||||||
@ -2816,10 +3185,13 @@ int main(int ac, char **av)
|
|||||||
u64 bytenr = 0;
|
u64 bytenr = 0;
|
||||||
int ret;
|
int ret;
|
||||||
int num;
|
int num;
|
||||||
|
int repair = 0;
|
||||||
|
int option_index = 0;
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
int c;
|
int c;
|
||||||
c = getopt(ac, av, "s:");
|
c = getopt_long(ac, av, "", long_options,
|
||||||
|
&option_index);
|
||||||
if (c < 0)
|
if (c < 0)
|
||||||
break;
|
break;
|
||||||
switch(c) {
|
switch(c) {
|
||||||
@ -2829,9 +3201,14 @@ int main(int ac, char **av)
|
|||||||
printf("using SB copy %d, bytenr %llu\n", num,
|
printf("using SB copy %d, bytenr %llu\n", num,
|
||||||
(unsigned long long)bytenr);
|
(unsigned long long)bytenr);
|
||||||
break;
|
break;
|
||||||
default:
|
case '?':
|
||||||
print_usage();
|
print_usage();
|
||||||
}
|
}
|
||||||
|
if (option_index == 1) {
|
||||||
|
printf("enabling repair mode\n");
|
||||||
|
repair = 1;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
ac = ac - optind;
|
ac = ac - optind;
|
||||||
|
|
||||||
@ -2849,15 +3226,23 @@ int main(int ac, char **av)
|
|||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
info = open_ctree_fs_info(av[optind], bytenr, 0, 0);
|
info = open_ctree_fs_info(av[optind], bytenr, repair, 1);
|
||||||
|
|
||||||
if (info == NULL)
|
if (info == NULL)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
if (!extent_buffer_uptodate(info->tree_root->node) ||
|
||||||
|
!extent_buffer_uptodate(info->dev_root->node) ||
|
||||||
|
!extent_buffer_uptodate(info->extent_root->node) ||
|
||||||
|
!extent_buffer_uptodate(info->chunk_root->node)) {
|
||||||
|
fprintf(stderr, "Critical roots corrupted, unable to fsck the FS\n");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
root = info->fs_root;
|
root = info->fs_root;
|
||||||
|
|
||||||
fprintf(stderr, "checking extents\n");
|
fprintf(stderr, "checking extents\n");
|
||||||
ret = check_extents(root);
|
ret = check_extents(root, repair);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
fprintf(stderr, "checking fs roots\n");
|
fprintf(stderr, "checking fs roots\n");
|
||||||
|
1
ctree.h
1
ctree.h
@ -1785,6 +1785,7 @@ static inline u32 btrfs_level_size(struct btrfs_root *root, int level) {
|
|||||||
btrfs_item_offset_nr(leaf, slot)))
|
btrfs_item_offset_nr(leaf, slot)))
|
||||||
|
|
||||||
/* extent-tree.c */
|
/* extent-tree.c */
|
||||||
|
void btrfs_pin_extent(struct btrfs_fs_info *fs_info, u64 bytenr, u64 num_bytes);
|
||||||
int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
|
int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root);
|
struct btrfs_root *root);
|
||||||
int btrfs_copy_pinned(struct btrfs_root *root, struct extent_io_tree *copy);
|
int btrfs_copy_pinned(struct btrfs_root *root, struct extent_io_tree *copy);
|
||||||
|
@ -1041,8 +1041,6 @@ static int lookup_inline_extent_backref(struct btrfs_trans_handle *trans,
|
|||||||
}
|
}
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printf("Failed to find [%llu, %u, %llu]\n", key.objectid, key.type, key.offset);
|
printf("Failed to find [%llu, %u, %llu]\n", key.objectid, key.type, key.offset);
|
||||||
btrfs_print_leaf(root, path->nodes[0]);
|
|
||||||
btrfs_free_path(path);
|
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1067,8 +1065,9 @@ static int lookup_inline_extent_backref(struct btrfs_trans_handle *trans,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (item_size < sizeof(*ei)) {
|
if (item_size < sizeof(*ei)) {
|
||||||
printf("Size is %u, needs to be %u, slot %d\n", item_size,
|
printf("Size is %u, needs to be %u, slot %d\n",
|
||||||
sizeof(*ei), path->slots[0]);
|
(unsigned)item_size,
|
||||||
|
(unsigned)sizeof(*ei), path->slots[0]);
|
||||||
btrfs_print_leaf(root, leaf);
|
btrfs_print_leaf(root, leaf);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@ -1460,10 +1459,8 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
btrfs_print_leaf(root, path->nodes[0]);
|
ret = -EIO;
|
||||||
printk("failed to find block number %Lu\n",
|
goto out;
|
||||||
(unsigned long long)bytenr);
|
|
||||||
BUG();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
l = path->nodes[0];
|
l = path->nodes[0];
|
||||||
@ -1484,9 +1481,8 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
|
|||||||
extent_flags = BTRFS_BLOCK_FLAG_FULL_BACKREF;
|
extent_flags = BTRFS_BLOCK_FLAG_FULL_BACKREF;
|
||||||
#else
|
#else
|
||||||
BUG();
|
BUG();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
BUG_ON(num_refs == 0);
|
|
||||||
item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
|
item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
|
||||||
if (refs)
|
if (refs)
|
||||||
*refs = num_refs;
|
*refs = num_refs;
|
||||||
@ -2033,6 +2029,12 @@ pinit:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void btrfs_pin_extent(struct btrfs_fs_info *fs_info,
|
||||||
|
u64 bytenr, u64 num_bytes)
|
||||||
|
{
|
||||||
|
update_pinned_extents(fs_info->extent_root, bytenr, num_bytes, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* remove an extent from the root, returns 0 on success
|
* remove an extent from the root, returns 0 on success
|
||||||
*/
|
*/
|
||||||
|
@ -239,7 +239,7 @@ static void print_extent_item(struct extent_buffer *eb, int slot)
|
|||||||
btrfs_shared_data_ref_count(eb, sref));
|
btrfs_shared_data_ref_count(eb, sref));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BUG();
|
return;
|
||||||
}
|
}
|
||||||
ptr += btrfs_extent_inline_ref_size(type);
|
ptr += btrfs_extent_inline_ref_size(type);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user