u16 csum_size;
u32 sectorsize;
- u32 leafsize;
+ u32 nodesize;
u64 generation;
u64 chunk_root_generation;
generation);
/*
* According to the current kernel code, the following
- * case is impossble, or there is something wrong in
+ * case is impossible, or there is something wrong in
* the kernel code.
*/
if (memcmp(((void *)exist) + offset,
printf("\n");
}
-static void print_device_info(struct btrfs_device *device, char *prefix)
-{
- if (prefix)
- printf("%s", prefix);
- printf("Device: id = %llu, name = %s\n",
- device->devid, device->name);
-}
-
-static void print_all_devices(struct list_head *devices)
-{
- struct btrfs_device *dev;
-
- printf("All Devices:\n");
- list_for_each_entry(dev, devices, dev_list)
- print_device_info(dev, "\t");
- printf("\n");
-}
-
static void print_scan_result(struct recover_control *rc)
{
if (!rc->verbose)
printf("DEVICE SCAN RESULT:\n");
printf("Filesystem Information:\n");
printf("\tsectorsize: %d\n", rc->sectorsize);
- printf("\tleafsize: %d\n", rc->leafsize);
+ printf("\tnodesize: %d\n", rc->nodesize);
printf("\ttree root generation: %llu\n", rc->generation);
printf("\tchunk root generation: %llu\n", rc->chunk_root_generation);
printf("\n");
btrfs_dev_extent_chunk_offset(l, dev_extent)) {
if (rc->verbose)
fprintf(stderr,
- "Device tree unmatch with chunks dev_extent[%llu, %llu], chunk[%llu, %llu]\n",
+ "Device tree mismatch with chunks dev_extent[%llu, %llu], chunk[%llu, %llu]\n",
btrfs_dev_extent_chunk_offset(l,
dev_extent),
btrfs_dev_extent_length(l, dev_extent),
if (chunk->type_flags != btrfs_disk_block_group_flags(l, bg_ptr)) {
if (rc->verbose)
fprintf(stderr,
- "Chunk[%llu, %llu]'s type(%llu) is differemt with Block Group's type(%llu)\n",
+ "Chunk[%llu, %llu]'s type(%llu) is different with Block Group's type(%llu)\n",
chunk->offset, chunk->length, chunk->type_flags,
btrfs_disk_block_group_flags(l, bg_ptr));
btrfs_release_path(&path);
if (ret)
return 1;
- buf = malloc(sizeof(*buf) + rc->leafsize);
+ buf = malloc(sizeof(*buf) + rc->nodesize);
if (!buf)
return -ENOMEM;
- buf->len = rc->leafsize;
+ buf->len = rc->nodesize;
bytenr = 0;
while (1) {
if (is_super_block_address(bytenr))
bytenr += rc->sectorsize;
- if (pread64(fd, buf->data, rc->leafsize, bytenr) <
- rc->leafsize)
+ if (pread64(fd, buf->data, rc->nodesize, bytenr) <
+ rc->nodesize)
break;
if (memcmp_extent_buffer(buf, rc->fs_devices->fsid,
break;
}
next_node:
- bytenr += rc->leafsize;
+ bytenr += rc->nodesize;
}
out:
close(fd);
u64 devid;
u8 uuid[BTRFS_UUID_SIZE];
u16 num_stripes;
+ struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_mapping_tree *map_tree;
struct map_lookup *map;
struct stripe *stripe;
- map_tree = &root->fs_info->mapping_tree;
+ map_tree = &fs_info->mapping_tree;
num_stripes = chunk->num_stripes;
map = malloc(btrfs_map_lookup_size(num_stripes));
if (!map)
devid = stripe->devid;
memcpy(uuid, stripe->dev_uuid, BTRFS_UUID_SIZE);
map->stripes[i].physical = stripe->offset;
- map->stripes[i].dev = btrfs_find_device(root, devid,
+ map->stripes[i].dev = btrfs_find_device(fs_info, devid,
uuid, NULL);
if (!map->stripes[i].dev) {
- kfree(map);
+ free(map);
return -EIO;
}
}
key.type == BTRFS_METADATA_ITEM_KEY) {
old_val = btrfs_super_bytes_used(fs_info->super_copy);
if (key.type == BTRFS_METADATA_ITEM_KEY)
- old_val += root->leafsize;
+ old_val += fs_info->nodesize;
else
old_val += key.offset;
btrfs_set_super_bytes_used(fs_info->super_copy,
if (key.objectid < end) {
if (key.type == BTRFS_BLOCK_GROUP_ITEM_KEY) {
- key.objectid += root->sectorsize;
+ key.objectid += fs_info->sectorsize;
key.type = BTRFS_EXTENT_ITEM_KEY;
key.offset = 0;
}
end = start + cache->key.offset - 1;
set_extent_bits(&info->block_group_cache, start, end,
- BLOCK_GROUP_DIRTY, GFP_NOFS);
- set_extent_dirty(&info->free_space_cache, start, end, GFP_NOFS);
+ BLOCK_GROUP_DIRTY);
+ set_extent_dirty(&info->free_space_cache, start, end);
btrfs_set_block_group_used(&cache->item, 0);
if (min_devid > dev->devid)
min_devid = dev->devid;
}
- disk_key.objectid = BTRFS_DEV_ITEMS_OBJECTID;
- disk_key.type = BTRFS_DEV_ITEM_KEY;
- disk_key.offset = min_devid;
+ btrfs_set_disk_key_objectid(&disk_key, BTRFS_DEV_ITEMS_OBJECTID);
+ btrfs_set_disk_key_type(&disk_key, BTRFS_DEV_ITEM_KEY);
+ btrfs_set_disk_key_offset(&disk_key, min_devid);
- cow = btrfs_alloc_free_block(trans, root, root->nodesize,
+ cow = btrfs_alloc_free_block(trans, root, root->fs_info->nodesize,
BTRFS_CHUNK_TREE_OBJECTID,
&disk_key, 0, 0, 0);
btrfs_set_header_bytenr(cow, cow->start);
{
struct btrfs_device *dev;
struct btrfs_key key;
- struct btrfs_dev_item *dev_item;
+ struct btrfs_dev_item dev_item_tmp;
+ struct btrfs_dev_item *dev_item = &dev_item_tmp;
int ret = 0;
- dev_item = malloc(sizeof(struct btrfs_dev_item));
- if (!dev_item)
- return -ENOMEM;
-
list_for_each_entry(dev, &rc->fs_devices->devices, dev_list) {
key.objectid = BTRFS_DEV_ITEMS_OBJECTID;
key.type = BTRFS_DEV_ITEM_KEY;
dev_item, sizeof(*dev_item));
}
- free(dev_item);
return ret;
}
key.offset = chunk_rec->offset;
ret = btrfs_insert_item(trans, chunk_root, &key, chunk,
- btrfs_chunk_item_size(chunk->num_stripes));
+ btrfs_chunk_item_size(chunk_rec->num_stripes));
free(chunk);
return ret;
}
static int rebuild_sys_array(struct recover_control *rc,
struct btrfs_root *root)
{
+ struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_chunk *chunk;
struct btrfs_key key;
struct chunk_record *chunk_rec;
int ret = 0;
u16 num_stripes;
- btrfs_set_super_sys_array_size(root->fs_info->super_copy, 0);
+ btrfs_set_super_sys_array_size(fs_info->super_copy, 0);
list_for_each_entry(chunk_rec, &rc->good_chunks, list) {
if (!(chunk_rec->type_flags & BTRFS_BLOCK_GROUP_SYSTEM))
key.type = BTRFS_CHUNK_ITEM_KEY;
key.offset = chunk_rec->offset;
- ret = btrfs_add_system_chunk(NULL, root, &key, chunk,
+ ret = btrfs_add_system_chunk(fs_info, &key, chunk,
btrfs_chunk_item_size(num_stripes));
free(chunk);
if (ret)
found_key.type != BTRFS_EXTENT_DATA_KEY)
goto next;
if (found_key.type == BTRFS_METADATA_ITEM_KEY)
- used_ret += extent_root->nodesize;
+ used_ret += extent_root->fs_info->nodesize;
else
used_ret += found_key.offset;
next:
{
struct chunk_record *chunk_rec;
struct btrfs_key search_key;
- struct btrfs_path *path;
+ struct btrfs_path path;
u64 used = 0;
int ret = 0;
if (list_empty(&rc->rebuild_chunks))
return 0;
- path = btrfs_alloc_path();
- if (!path)
- return -ENOMEM;
+ btrfs_init_path(&path);
list_for_each_entry(chunk_rec, &rc->rebuild_chunks, list) {
search_key.objectid = chunk_rec->offset;
search_key.type = BTRFS_EXTENT_ITEM_KEY;
search_key.offset = 0;
ret = btrfs_search_slot(NULL, root->fs_info->extent_root,
- &search_key, path, 0, 0);
+ &search_key, &path, 0, 0);
if (ret < 0)
goto out;
ret = calculate_bg_used(root->fs_info->extent_root,
- chunk_rec, path, &used);
+ chunk_rec, &path, &used);
/*
* Extent tree is damaged, better to rebuild the whole extent
* tree. Currently, change the used to chunk's len to prevent
"Mark the block group full to prevent block rsv problems\n");
used = chunk_rec->length;
}
- btrfs_release_path(path);
+ btrfs_release_path(&path);
ret = __insert_block_group(trans, chunk_rec,
root->fs_info->extent_root,
used);
goto out;
}
out:
- btrfs_free_path(path);
+ btrfs_release_path(&path);
return ret;
}
struct btrfs_fs_info *fs_info;
struct btrfs_super_block *disk_super;
struct extent_buffer *eb;
- u32 sectorsize;
- u32 nodesize;
- u32 leafsize;
- u32 stripesize;
int ret;
fs_info = btrfs_new_fs_info(1, BTRFS_SUPER_INFO_OFFSET);
disk_super = fs_info->super_copy;
ret = btrfs_read_dev_super(fs_info->fs_devices->latest_bdev,
- disk_super, fs_info->super_bytenr, 1);
+ disk_super, fs_info->super_bytenr,
+ SBREAD_RECOVER);
if (ret) {
fprintf(stderr, "No valid btrfs found\n");
goto out_devices;
}
memcpy(fs_info->fsid, &disk_super->fsid, BTRFS_FSID_SIZE);
+ fs_info->sectorsize = btrfs_super_sectorsize(disk_super);
+ fs_info->nodesize = btrfs_super_nodesize(disk_super);
+ fs_info->stripesize = btrfs_super_stripesize(disk_super);
- ret = btrfs_check_fs_compatibility(disk_super, 1);
+ ret = btrfs_check_fs_compatibility(disk_super, OPEN_CTREE_WRITES);
if (ret)
goto out_devices;
- nodesize = btrfs_super_nodesize(disk_super);
- leafsize = btrfs_super_leafsize(disk_super);
- sectorsize = btrfs_super_sectorsize(disk_super);
- stripesize = btrfs_super_stripesize(disk_super);
-
- __setup_root(nodesize, leafsize, sectorsize, stripesize,
- fs_info->chunk_root, fs_info, BTRFS_CHUNK_TREE_OBJECTID);
+ btrfs_setup_root(fs_info->chunk_root, fs_info,
+ BTRFS_CHUNK_TREE_OBJECTID);
ret = build_device_maps_by_chunk_records(rc, fs_info->chunk_root);
if (ret)
int ret;
int fd;
struct btrfs_super_block *sb;
+ char buf[BTRFS_SUPER_INFO_SIZE];
struct btrfs_fs_devices *fs_devices;
ret = 0;
return -1;
}
- sb = malloc(BTRFS_SUPER_INFO_SIZE);
- if (!sb) {
- fprintf(stderr, "allocating memory for sb failed.\n");
- ret = -ENOMEM;
- goto fail_close_fd;
- }
-
- ret = btrfs_read_dev_super(fd, sb, BTRFS_SUPER_INFO_OFFSET, 1);
+ sb = (struct btrfs_super_block*)buf;
+ ret = btrfs_read_dev_super(fd, sb, BTRFS_SUPER_INFO_OFFSET,
+ SBREAD_RECOVER);
if (ret) {
fprintf(stderr, "read super block error\n");
- goto fail_free_sb;
+ goto out_close_fd;
}
rc->sectorsize = btrfs_super_sectorsize(sb);
- rc->leafsize = btrfs_super_leafsize(sb);
+ rc->nodesize = btrfs_super_nodesize(sb);
rc->generation = btrfs_super_generation(sb);
rc->chunk_root_generation = btrfs_super_chunk_root_generation(sb);
rc->csum_size = btrfs_super_csum_size(sb);
if (btrfs_super_flags(sb) & BTRFS_SUPER_FLAG_SEEDING) {
fprintf(stderr, "this device is seed device\n");
ret = -1;
- goto fail_free_sb;
+ goto out_close_fd;
}
- ret = btrfs_scan_fs_devices(fd, path, &fs_devices, 0, 1, 0);
+ ret = btrfs_scan_fs_devices(fd, path, &fs_devices, 0, SBREAD_RECOVER, 0);
if (ret)
- goto fail_free_sb;
+ goto out_close_fd;
rc->fs_devices = fs_devices;
if (rc->verbose)
print_all_devices(&rc->fs_devices->devices);
-fail_free_sb:
- free(sb);
-fail_close_fd:
+out_close_fd:
close(fd);
return ret;
}
struct list_head *devexts, int ndevexts)
{
struct device_extent_record *devext;
- u64 strpie_length;
+ u64 stripe_length;
int expected_num_stripes;
expected_num_stripes = calc_num_stripes(bg->flags);
if (expected_num_stripes && expected_num_stripes != ndevexts)
return 1;
- strpie_length = calc_stripe_length(bg->flags, bg->offset, ndevexts);
+ if (check_num_stripes(bg->flags, ndevexts) < 0)
+ return 1;
+
+ stripe_length = calc_stripe_length(bg->flags, bg->offset, ndevexts);
list_for_each_entry(devext, devexts, chunk_list) {
- if (devext->length != strpie_length)
+ if (devext->length != stripe_length)
return 1;
}
return 0;
int ret = 0;
struct btrfs_root *csum_root = root->fs_info->csum_root;
struct btrfs_csum_item *csum_item;
- u32 blocksize = root->sectorsize;
+ u32 blocksize = root->fs_info->sectorsize;
u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
int csums_in_item = btrfs_item_size_nr(*leaf, *slot) / csum_size;
goto out;
}
ret = 0;
- csum_result = btrfs_csum_data(NULL, data, csum_result, len);
- btrfs_csum_final(csum_result, (char *)&csum_result);
+ csum_result = btrfs_csum_data(data, csum_result, len);
+ btrfs_csum_final(csum_result, (u8 *)&csum_result);
if (csum_result != tree_csum)
ret = 1;
out:
static u64 item_end_offset(struct btrfs_root *root, struct btrfs_key *key,
struct extent_buffer *leaf, int slot) {
- u32 blocksize = root->sectorsize;
+ u32 blocksize = root->fs_info->sectorsize;
u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
u64 offset = btrfs_item_size_nr(leaf, slot);
dev = btrfs_find_device_by_devid(rc->fs_devices, devext->objectid,
0);
if (!dev)
- return 1;
- BUG_ON(btrfs_find_device_by_devid(rc->fs_devices, devext->objectid,
- 1));
+ return -ENOENT;
+ if (btrfs_find_device_by_devid(rc->fs_devices, devext->objectid, 1)) {
+ error("unexpected: found another device with id %llu",
+ (unsigned long long)devext->objectid);
+ return -EINVAL;
+ }
chunk->stripes[index].devid = devext->objectid;
chunk->stripes[index].offset = devext->offset;
u64 chunk_end = chunk->offset + chunk->length;
u64 csum_offset = 0;
u64 data_offset;
- u32 blocksize = root->sectorsize;
+ u32 blocksize = root->fs_info->sectorsize;
u32 tree_csum;
int index = 0;
int num_unordered = 0;
chunk->sub_stripes = calc_sub_nstripes(bg->flags);
ret = insert_cache_extent(&rc->chunk, &chunk->cache);
+ if (ret == -EEXIST) {
+ error("duplicate entry in cache start %llu size %llu",
+ (unsigned long long)chunk->cache.start,
+ (unsigned long long)chunk->cache.size);
+ free(chunk);
+ return ret;
+ }
BUG_ON(ret);
list_del_init(&bg->list);
}
trans = btrfs_start_transaction(root, 1);
+ BUG_ON(IS_ERR(trans));
ret = remove_chunk_extent_item(trans, &rc, root);
BUG_ON(ret);