Btrfs: update converter for the new disk format

This patch updates the ext3 to btrfs converter for the new
disk format. This mainly involves changing the convert's
data relocation and free space management code. This patch
also ports some functions from kernel module to btrfs-progs.
Thank you,

Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
master
Yan Zheng 2008-12-17 16:10:07 -05:00 committed by Chris Mason
parent b238b4b072
commit 0d53b212d8
12 changed files with 825 additions and 363 deletions

393
convert.c
View File

@ -41,7 +41,11 @@
#include <ext2fs/ext2_fs.h>
#include <ext2fs/ext2fs.h>
#include <ext2fs/ext2_ext_attr.h>
#define INO_OFFSET (BTRFS_FIRST_FREE_OBJECTID - EXT2_ROOT_INO)
#define STRIPE_LEN (64 * 1024)
#define EXT2_IMAGE_SUBVOL_OBJECTID BTRFS_FIRST_FREE_OBJECTID
/*
* Open Ext2fs in readonly mode, read block allocation bitmap and
* inode bitmap into memory.
@ -101,7 +105,7 @@ static int ext2_free_block(ext2_filsys fs, u64 block)
static int cache_free_extents(struct btrfs_root *root, ext2_filsys ext2_fs)
{
int ret = 0;
int i, ret = 0;
blk_t block;
u64 bytenr;
u64 blocksize = ext2_fs->blocksize;
@ -113,10 +117,19 @@ static int cache_free_extents(struct btrfs_root *root, ext2_filsys ext2_fs)
bytenr = block * blocksize;
ret = set_extent_dirty(&root->fs_info->free_space_cache,
bytenr, bytenr + blocksize - 1, 0);
if (ret)
break;
BUG_ON(ret);
}
return ret;
for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
bytenr = btrfs_sb_offset(i);
bytenr &= ~((u64)STRIPE_LEN - 1);
if (bytenr >= blocksize * ext2_fs->super->s_blocks_count)
break;
clear_extent_dirty(&root->fs_info->free_space_cache, bytenr,
bytenr + STRIPE_LEN - 1, 0);
}
return 0;
}
static int custom_alloc_extent(struct btrfs_root *root, u64 num_bytes,
@ -172,10 +185,26 @@ fail:
return -ENOSPC;
}
static int intersect_with_sb(u64 bytenr, u64 num_bytes)
{
int i;
u64 offset;
for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
offset = btrfs_sb_offset(i);
offset &= ~((u64)STRIPE_LEN - 1);
if (bytenr < offset + STRIPE_LEN &&
bytenr + num_bytes > offset)
return 1;
}
return 0;
}
static int custom_free_extent(struct btrfs_root *root, u64 bytenr,
u64 num_bytes)
{
return 0;
return intersect_with_sb(bytenr, num_bytes);
}
struct btrfs_extent_ops extent_ops = {
@ -238,15 +267,17 @@ static int dir_iterate_proc(ext2_ino_t dir, int entry,
ret = btrfs_insert_dir_item(idata->trans, idata->root,
dirent->name, dirent->name_len,
idata->objectid, &location,
filetype_conversion_table[file_type]);
filetype_conversion_table[file_type],
idata->index_cnt);
if (ret)
goto fail;
ret = btrfs_insert_inode_ref(idata->trans, idata->root,
dirent->name, dirent->name_len,
objectid, idata->objectid,
idata->index_cnt++);
idata->index_cnt);
if (ret)
goto fail;
idata->index_cnt++;
inode_size = btrfs_stack_inode_size(idata->inode) +
dirent->name_len * 2;
btrfs_set_stack_inode_size(idata->inode, inode_size);
@ -323,7 +354,7 @@ static int record_file_extent(struct btrfs_trans_handle *trans,
struct btrfs_path path;
struct btrfs_extent_item extent_item;
u32 blocksize = root->sectorsize;
u64 nblocks;
u64 nbytes;
u64 bytes_used;
if (disk_bytenr == 0) {
@ -348,9 +379,11 @@ static int record_file_extent(struct btrfs_trans_handle *trans,
blocksize, buffer);
if (ret)
break;
ret = btrfs_csum_file_block(trans, root, inode,
objectid, file_pos + offset,
buffer, blocksize);
ret = btrfs_csum_file_block(trans,
root->fs_info->csum_root,
disk_bytenr + num_bytes,
disk_bytenr + offset,
buffer, blocksize);
if (ret)
break;
}
@ -375,10 +408,14 @@ static int record_file_extent(struct btrfs_trans_handle *trans,
btrfs_set_file_extent_disk_num_bytes(leaf, fi, num_bytes);
btrfs_set_file_extent_offset(leaf, fi, 0);
btrfs_set_file_extent_num_bytes(leaf, fi, num_bytes);
btrfs_set_file_extent_ram_bytes(leaf, fi, num_bytes);
btrfs_set_file_extent_compression(leaf, fi, 0);
btrfs_set_file_extent_encryption(leaf, fi, 0);
btrfs_set_file_extent_other_encoding(leaf, fi, 0);
btrfs_mark_buffer_dirty(leaf);
nblocks = btrfs_stack_inode_nblocks(inode) + num_bytes / 512;
btrfs_set_stack_inode_nblocks(inode, nblocks);
nbytes = btrfs_stack_inode_nbytes(inode) + num_bytes;
btrfs_set_stack_inode_nbytes(inode, nbytes);
bytes_used = btrfs_root_used(&root->root_item);
btrfs_set_root_used(&root->root_item, bytes_used + num_bytes);
@ -393,6 +430,10 @@ static int record_file_extent(struct btrfs_trans_handle *trans,
bytes_used = btrfs_super_bytes_used(&info->super_copy);
btrfs_set_super_bytes_used(&info->super_copy, bytes_used +
num_bytes);
ret = btrfs_update_block_group(trans, root, disk_bytenr,
num_bytes, 1, 0);
if (ret)
goto fail;
} else if (ret != -EEXIST) {
goto fail;
}
@ -400,7 +441,7 @@ static int record_file_extent(struct btrfs_trans_handle *trans,
ret = btrfs_inc_extent_ref(trans, root, disk_bytenr, num_bytes,
leaf->start, root->root_key.objectid,
trans->transid, objectid, file_pos);
trans->transid, objectid);
if (ret)
goto fail;
ret = 0;
@ -440,13 +481,16 @@ static int block_iterate_proc(ext2_filsys ext2_fs,
struct blk_iterate_data *idata)
{
int ret;
int sb_region;
int do_barrier;
struct btrfs_root *root = idata->root;
struct btrfs_trans_handle *trans = idata->trans;
struct btrfs_block_group_cache *cache;
u64 bytenr;
u64 bytenr = disk_block * root->sectorsize;
BUG_ON(disk_block == 0);
if ((idata->num_blocks > 0 && disk_block >= idata->boundary) ||
sb_region = intersect_with_sb(bytenr, root->sectorsize);
do_barrier = sb_region || disk_block >= idata->boundary;
if ((idata->num_blocks > 0 && do_barrier) ||
(file_block > idata->first_block + idata->num_blocks) ||
(disk_block != idata->disk_block + idata->num_blocks)) {
if (idata->num_blocks > 0) {
@ -468,10 +512,14 @@ static int block_iterate_proc(ext2_filsys ext2_fs,
goto fail;
}
bytenr = disk_block * root->sectorsize;
cache = btrfs_lookup_block_group(root->fs_info, bytenr);
BUG_ON(!cache);
bytenr = cache->key.objectid + cache->key.offset;
if (sb_region) {
bytenr += STRIPE_LEN - 1;
bytenr &= ~((u64)STRIPE_LEN - 1);
} else {
cache = btrfs_lookup_block_group(root->fs_info, bytenr);
BUG_ON(!cache);
bytenr = cache->key.objectid + cache->key.offset;
}
idata->first_block = file_block;
idata->disk_block = disk_block;
@ -925,20 +973,18 @@ static inline dev_t new_decode_dev(u32 dev)
}
static int copy_inode_item(struct btrfs_inode_item *dst,
struct ext2_inode *src)
struct ext2_inode *src, u32 blocksize)
{
btrfs_set_stack_inode_generation(dst, 1);
btrfs_set_stack_inode_size(dst, src->i_size);
btrfs_set_stack_inode_nblocks(dst, src->i_blocks);
btrfs_set_stack_inode_nbytes(dst, (u64)src->i_blocks * blocksize);
btrfs_set_stack_inode_block_group(dst, 0);
btrfs_set_stack_inode_nblocks(dst, 0);
btrfs_set_stack_inode_nlink(dst, src->i_links_count);
btrfs_set_stack_inode_uid(dst, src->i_uid | (src->i_uid_high << 16));
btrfs_set_stack_inode_gid(dst, src->i_gid | (src->i_gid_high << 16));
btrfs_set_stack_inode_mode(dst, src->i_mode);
btrfs_set_stack_inode_rdev(dst, 0);
btrfs_set_stack_inode_flags(dst, 0);
btrfs_set_stack_inode_compat_flags(dst, 0);
btrfs_set_stack_timespec_sec(&dst->atime, src->i_atime);
btrfs_set_stack_timespec_nsec(&dst->atime, 0);
btrfs_set_stack_timespec_sec(&dst->ctime, src->i_ctime);
@ -986,7 +1032,7 @@ static int copy_single_inode(struct btrfs_trans_handle *trans,
if (ext2_inode->i_links_count == 0)
return 0;
copy_inode_item(&btrfs_inode, ext2_inode);
copy_inode_item(&btrfs_inode, ext2_inode, ext2_fs->blocksize);
if (!datacsum && S_ISREG(ext2_inode->i_mode)) {
u32 flags = btrfs_stack_inode_flags(&btrfs_inode) |
BTRFS_INODE_NODATASUM;
@ -1197,7 +1243,7 @@ static int create_ext2_image(struct btrfs_root *root, ext2_filsys ext2_fs,
btrfs_set_stack_inode_generation(&btrfs_inode, 1);
btrfs_set_stack_inode_size(&btrfs_inode, total_bytes);
btrfs_set_stack_inode_nlink(&btrfs_inode, 1);
btrfs_set_stack_inode_nblocks(&btrfs_inode, 0);
btrfs_set_stack_inode_nbytes(&btrfs_inode, 0);
btrfs_set_stack_inode_mode(&btrfs_inode, S_IFREG | 0400);
btrfs_set_stack_inode_flags(&btrfs_inode, BTRFS_INODE_NODATASUM |
BTRFS_INODE_READONLY);
@ -1330,12 +1376,13 @@ next:
btrfs_set_key_type(&location, BTRFS_INODE_ITEM_KEY);
ret = btrfs_insert_dir_item(trans, root, name, strlen(name),
btrfs_root_dirid(&root->root_item),
&location, EXT2_FT_REG_FILE);
&location, EXT2_FT_REG_FILE, objectid);
if (ret)
goto fail;
ret = btrfs_insert_inode_ref(trans, root, name, strlen(name),
objectid,
btrfs_root_dirid(&root->root_item), 0);
btrfs_root_dirid(&root->root_item),
objectid);
if (ret)
goto fail;
location.objectid = btrfs_root_dirid(&root->root_item);
@ -1358,68 +1405,81 @@ fail:
return ret;
}
struct btrfs_root *create_subvol(struct btrfs_root *root, const char *name)
struct btrfs_root *link_subvol(struct btrfs_root *root, const char *base,
u64 root_objectid)
{
int ret;
u64 objectid;
struct btrfs_key location;
struct btrfs_root_item root_item;
struct btrfs_trans_handle *trans;
struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_root *tree_root = fs_info->tree_root;
struct btrfs_root *new_root;
struct extent_buffer *tmp;
struct btrfs_path *path;
struct btrfs_key key;
u64 dirid = btrfs_root_dirid(&root->root_item);
u64 index = 2;
char buf[64];
int i;
int ret;
path = btrfs_alloc_path();
BUG_ON(!path);
key.objectid = dirid;
key.type = BTRFS_DIR_INDEX_KEY;
key.offset = (u64)-1;
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
BUG_ON(ret <= 0);
if (path->slots[0] > 0) {
path->slots[0]--;
btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
if (key.objectid == dirid && key.type == BTRFS_DIR_INDEX_KEY)
index = key.offset + 1;
}
btrfs_free_path(path);
trans = btrfs_start_transaction(root, 1);
BUG_ON(!trans);
objectid = btrfs_super_root_dir(&fs_info->super_copy);
ret = btrfs_find_free_objectid(trans, root, objectid, &objectid);
if (ret)
goto fail;
ret = btrfs_copy_root(trans, root, root->node, &tmp, objectid);
if (ret)
goto fail;
memcpy(&root_item, &root->root_item, sizeof(root_item));
btrfs_set_root_bytenr(&root_item, tmp->start);
btrfs_set_root_level(&root_item, btrfs_header_level(tmp));
free_extent_buffer(tmp);
key.objectid = root_objectid;
key.offset = (u64)-1;
key.type = BTRFS_ROOT_ITEM_KEY;
location.objectid = objectid;
location.offset = 1;
btrfs_set_key_type(&location, BTRFS_ROOT_ITEM_KEY);
ret = btrfs_insert_root(trans, root->fs_info->tree_root,
&location, &root_item);
if (ret)
goto fail;
location.offset = (u64)-1;
ret = btrfs_insert_dir_item(trans, tree_root, name, strlen(name),
btrfs_super_root_dir(&fs_info->super_copy),
&location, BTRFS_FT_DIR);
if (ret)
goto fail;
ret = btrfs_insert_inode_ref(trans, tree_root, name, strlen(name),
objectid,
btrfs_super_root_dir(&fs_info->super_copy),
0);
strcpy(buf, base);
for (i = 0; i < 1024; i++) {
ret = btrfs_insert_dir_item(trans, root, buf, strlen(buf),
dirid, &key, BTRFS_FT_DIR, index);
if (ret != -EEXIST)
break;
sprintf(buf, "%s%d", base, i);
}
if (ret)
goto fail;
/* add the backref first */
ret = btrfs_add_root_ref(trans, tree_root, root_objectid,
BTRFS_ROOT_BACKREF_KEY,
root->root_key.objectid,
dirid, index, buf, strlen(buf));
BUG_ON(ret);
/* now add the forward ref */
ret = btrfs_add_root_ref(trans, tree_root, root->root_key.objectid,
BTRFS_ROOT_REF_KEY, root_objectid,
dirid, index, buf, strlen(buf));
ret = btrfs_commit_transaction(trans, root);
BUG_ON(ret);
new_root = btrfs_read_fs_root(fs_info, &location);
new_root = btrfs_read_fs_root(fs_info, &key);
if (!new_root || IS_ERR(new_root))
goto fail;
trans = btrfs_start_transaction(new_root, 1);
BUG_ON(!trans);
ret = btrfs_make_root_dir(trans, new_root, BTRFS_FIRST_FREE_OBJECTID);
if (ret)
goto fail;
ret = btrfs_commit_transaction(trans, new_root);
BUG_ON(ret);
return new_root;
fail:
return NULL;
}
/*
* Fixup block accounting. The initial block accounting created by
* make_block_groups isn't accuracy in this case.
@ -1572,7 +1632,7 @@ static int create_chunk_mapping(struct btrfs_trans_handle *trans,
btrfs_set_stack_chunk_length(&chunk, cache->key.offset);
btrfs_set_stack_chunk_owner(&chunk,
extent_root->root_key.objectid);
btrfs_set_stack_chunk_stripe_len(&chunk, 64 * 1024);
btrfs_set_stack_chunk_stripe_len(&chunk, STRIPE_LEN);
btrfs_set_stack_chunk_type(&chunk, cache->flags);
btrfs_set_stack_chunk_io_align(&chunk, device->io_align);
btrfs_set_stack_chunk_io_width(&chunk, device->io_width);
@ -1603,6 +1663,42 @@ err:
return ret;
}
static int create_subvol(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 root_objectid)
{
struct extent_buffer *tmp;
struct btrfs_root *new_root;
struct btrfs_key key;
struct btrfs_root_item root_item;
int ret;
ret = btrfs_copy_root(trans, root, root->node, &tmp,
root_objectid);
BUG_ON(ret);
memcpy(&root_item, &root->root_item, sizeof(root_item));
btrfs_set_root_bytenr(&root_item, tmp->start);
btrfs_set_root_level(&root_item, btrfs_header_level(tmp));
btrfs_set_root_generation(&root_item, trans->transid);
free_extent_buffer(tmp);
key.objectid = root_objectid;
key.type = BTRFS_ROOT_ITEM_KEY;
key.offset = trans->transid;
ret = btrfs_insert_root(trans, root->fs_info->tree_root,
&key, &root_item);
key.offset = (u64)-1;
new_root = btrfs_read_fs_root(root->fs_info, &key);
BUG_ON(!new_root || IS_ERR(new_root));
ret = btrfs_make_root_dir(trans, new_root, BTRFS_FIRST_FREE_OBJECTID);
BUG_ON(ret);
btrfs_free_fs_root(root->fs_info, new_root);
return 0;
}
static int init_btrfs(struct btrfs_root *root)
{
int ret;
@ -1629,7 +1725,7 @@ static int init_btrfs(struct btrfs_root *root)
location.offset = (u64)-1;
ret = btrfs_insert_dir_item(trans, fs_info->tree_root, "default", 7,
btrfs_super_root_dir(&fs_info->super_copy),
&location, BTRFS_FT_DIR);
&location, BTRFS_FT_DIR, 0);
if (ret)
goto err;
ret = btrfs_insert_inode_ref(trans, fs_info->tree_root, "default", 7,
@ -1639,6 +1735,14 @@ static int init_btrfs(struct btrfs_root *root)
goto err;
btrfs_set_root_dirid(&fs_info->fs_root->root_item,
BTRFS_FIRST_FREE_OBJECTID);
/* subvol for ext2 image file */
ret = create_subvol(trans, root, EXT2_IMAGE_SUBVOL_OBJECTID);
BUG_ON(ret);
/* subvol for data relocation */
ret = create_subvol(trans, root, BTRFS_DATA_RELOC_TREE_OBJECTID);
BUG_ON(ret);
ret = btrfs_commit_transaction(trans, root);
BUG_ON(ret);
err:
@ -1670,7 +1774,7 @@ static int migrate_super_block(int fd, u64 old_bytenr, u32 sectorsize)
BUG_ON(btrfs_super_bytenr(super) != old_bytenr);
btrfs_set_super_bytenr(super, BTRFS_SUPER_INFO_OFFSET);
csum_tree_block(NULL, buf, 0);
csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
ret = pwrite(fd, buf->data, sectorsize, BTRFS_SUPER_INFO_OFFSET);
if (ret != sectorsize)
goto fail;
@ -1754,7 +1858,7 @@ static int prepare_system_chunk(int fd, u64 sb_bytenr, u32 sectorsize)
if (ret)
goto fail;
csum_tree_block(NULL, buf, 0);
csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
ret = pwrite(fd, buf->data, sectorsize, sb_bytenr);
if (ret != sectorsize)
goto fail;
@ -1770,7 +1874,7 @@ fail:
static int relocate_one_reference(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 extent_start, u64 extent_size,
u64 objectid, u64 offset,
u64 objectid, struct btrfs_key *leaf_key,
struct extent_io_tree *reloc_tree)
{
struct extent_buffer *leaf;
@ -1780,30 +1884,56 @@ static int relocate_one_reference(struct btrfs_trans_handle *trans,
struct btrfs_inode_item inode;
struct blk_iterate_data data;
u64 bytenr;
u64 offset;
u64 num_bytes;
u64 cur_offset;
u64 new_pos;
u64 nblocks;
u64 nbytes;
u64 root_gen;
u64 root_owner;
u64 sector_end;
u32 nritems;
u32 sectorsize = root->sectorsize;
unsigned long ptr;
int found = 0;
int datacsum;
int fd;
int ret;
memcpy(&key, leaf_key, sizeof(key));
if (key.objectid < objectid ||
(key.objectid == objectid &&
key.type < BTRFS_EXTENT_DATA_KEY)) {
key.objectid = objectid;
key.type = BTRFS_EXTENT_DATA_KEY;
key.offset = 0;
}
btrfs_init_path(&path);
ret = btrfs_lookup_file_extent(trans, root, &path,
objectid, offset, -1);
if (ret)
ret = btrfs_search_slot(trans, root, &key, &path, -1, 1);
if (ret < 0)
goto fail;
leaf = path.nodes[0];
fi = btrfs_item_ptr(leaf, path.slots[0],
struct btrfs_file_extent_item);
/* the extent may be referenced by old snapshot */
if (extent_start != btrfs_file_extent_disk_bytenr(leaf, fi) ||
extent_size != btrfs_file_extent_disk_num_bytes(leaf, fi)) {
nritems = btrfs_header_nritems(leaf);
while (1) {
if (path.slots[0] >= nritems)
break;
btrfs_item_key_to_cpu(leaf, &key, path.slots[0]);
if (key.objectid != objectid ||
key.type != BTRFS_EXTENT_DATA_KEY)
break;
fi = btrfs_item_ptr(leaf, path.slots[0],
struct btrfs_file_extent_item);
if (extent_start == btrfs_file_extent_disk_bytenr(leaf, fi) &&
extent_size == btrfs_file_extent_disk_num_bytes(leaf, fi)) {
offset = key.offset;
found = 1;
break;
}
path.slots[0]++;
}
if (!found) {
ret = 1;
goto fail;
}
@ -1817,9 +1947,9 @@ static int relocate_one_reference(struct btrfs_trans_handle *trans,
if (ret)
goto fail;
ret = btrfs_free_extent(trans, root, extent_start, extent_size,
leaf->start, root_owner, root_gen, objectid,
offset, 0);
ret = btrfs_free_extent(trans, root,
extent_start, extent_size, leaf->start,
root_owner, root_gen, objectid, 0);
if (ret)
goto fail;
@ -1838,8 +1968,9 @@ static int relocate_one_reference(struct btrfs_trans_handle *trans,
btrfs_release_path(root, &path);
BUG_ON(num_bytes & (sectorsize - 1));
nblocks = btrfs_stack_inode_nblocks(&inode) - num_bytes / 512;
btrfs_set_stack_inode_nblocks(&inode, nblocks);
nbytes = btrfs_stack_inode_nbytes(&inode) - num_bytes;
btrfs_set_stack_inode_nbytes(&inode, nbytes);
datacsum = !(btrfs_stack_inode_flags(&inode) & BTRFS_INODE_NODATASUM);
data = (struct blk_iterate_data) {
.trans = trans,
@ -1850,7 +1981,7 @@ static int relocate_one_reference(struct btrfs_trans_handle *trans,
.disk_block = 0,
.num_blocks = 0,
.boundary = (u64)-1,
.checksum = 0,
.checksum = datacsum,
.errcode = 0,
};
@ -1926,25 +2057,46 @@ static int relocate_extents_range(struct btrfs_root *fs_root,
{
struct btrfs_fs_info *info = fs_root->fs_info;
struct btrfs_root *extent_root = info->extent_root;
struct btrfs_root *cur_root;
struct btrfs_root *cur_root = NULL;
struct btrfs_trans_handle *trans;
struct btrfs_extent_ref *ref_item;
struct extent_buffer *leaf;
struct btrfs_key key;
struct btrfs_key leaf_key;
struct btrfs_path path;
struct extent_io_tree reloc_tree;
u64 cur_byte;
u64 num_bytes;
u64 ref_root;
u64 ref_owner;
u64 ref_offset;
u64 num_refs;
u64 leaf_start;
int pass = 0;
int ret;
int found;
btrfs_init_path(&path);
extent_io_tree_init(&reloc_tree);
key.objectid = start_byte;
key.offset = 0;
key.type = BTRFS_EXTENT_ITEM_KEY;
ret = btrfs_search_slot(NULL, extent_root, &key, &path, 0, 0);
if (ret < 0)
goto fail;
if (ret > 0) {
ret = btrfs_previous_item(extent_root, &path, 0,
BTRFS_EXTENT_ITEM_KEY);
if (ret < 0)
goto fail;
if (ret == 0) {
leaf = path.nodes[0];
btrfs_item_key_to_cpu(leaf, &key, path.slots[0]);
if (key.objectid + key.offset > start_byte)
start_byte = key.objectid;
}
}
btrfs_release_path(extent_root, &path);
again:
cur_root = (pass % 2 == 0) ? ext2_root : fs_root;
num_refs = 0;
@ -2005,7 +2157,7 @@ next:
struct btrfs_extent_ref);
ref_root = btrfs_ref_root(leaf, ref_item);
ref_owner = btrfs_ref_objectid(leaf, ref_item);
ref_offset = btrfs_ref_offset(leaf, ref_item);
leaf_start = key.offset;
num_refs++;
BUG_ON(ref_owner < BTRFS_FIRST_FREE_OBJECTID);
@ -2018,9 +2170,16 @@ next:
if (!found)
goto next;
leaf = read_tree_block(cur_root, leaf_start,
btrfs_level_size(cur_root, 0), 0);
BUG_ON(!leaf);
BUG_ON(btrfs_header_level(leaf) != 0);
btrfs_item_key_to_cpu(leaf, &leaf_key, 0);
free_extent_buffer(leaf);
ret = relocate_one_reference(trans, cur_root, cur_byte,
num_bytes, ref_owner,
ref_offset, &reloc_tree);
&leaf_key, &reloc_tree);
if (ret < 0)
goto fail;
@ -2056,7 +2215,7 @@ static int cleanup_sys_chunk(struct btrfs_root *fs_root,
struct btrfs_root *ext2_root)
{
struct btrfs_block_group_cache *cache;
int ret = 0;
int i, ret = 0;
u64 offset = 0;
u64 end_byte;
@ -2075,6 +2234,16 @@ static int cleanup_sys_chunk(struct btrfs_root *fs_root,
}
offset = end_byte;
}
for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
offset = btrfs_sb_offset(i);
offset &= ~((u64)STRIPE_LEN - 1);
ret = relocate_extents_range(fs_root, ext2_root,
offset, offset + STRIPE_LEN);
if (ret)
goto fail;
}
ret = 0;
fail:
return ret;
}
@ -2234,7 +2403,7 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr)
}
root->fs_info->extent_ops = &extent_ops;
/* recover block allocation bitmap */
for (i = 0; i < 6; i++) {
for (i = 0; i < 7; i++) {
blocks[i] /= blocksize;
ext2_free_block(ext2_fs, blocks[i]);
}
@ -2243,11 +2412,6 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr)
fprintf(stderr, "unable to setup the root tree\n");
goto fail;
}
ext2_root = create_subvol(root, "ext2_saved");
if (!ext2_root) {
fprintf(stderr, "unable to create subvol\n");
goto fail;
}
printf("creating btrfs metadata.\n");
ret = copy_inodes(root, ext2_fs, datacsum, packing, noxattr);
if (ret) {
@ -2255,6 +2419,11 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr)
goto fail;
}
printf("creating ext2fs image file.\n");
ext2_root = link_subvol(root, "ext2_saved", EXT2_IMAGE_SUBVOL_OBJECTID);
if (!ext2_root) {
fprintf(stderr, "unable to create subvol\n");
goto fail;
}
ret = create_ext2_image(ext2_root, ext2_fs, "image");
if (ret) {
fprintf(stderr, "error during create_ext2_image %d\n", ret);
@ -2401,21 +2570,14 @@ int do_rollback(const char *devname, int force)
}
btrfs_init_path(&path);
name = "ext2_saved";
root_dir = btrfs_super_root_dir(&root->fs_info->super_copy);
dir = btrfs_lookup_dir_item(NULL, root->fs_info->tree_root, &path,
root_dir, name, strlen(name), 0);
if (!dir || IS_ERR(dir)) {
fprintf(stderr, "unable to find subvol %s\n", name);
goto fail;
}
leaf = path.nodes[0];
btrfs_dir_item_key_to_cpu(leaf, dir, &key);
btrfs_release_path(root->fs_info->tree_root, &path);
key.objectid = EXT2_IMAGE_SUBVOL_OBJECTID;
key.type = BTRFS_ROOT_ITEM_KEY;
key.offset = (u64)-1;
ext2_root = btrfs_read_fs_root(root->fs_info, &key);
if (!ext2_root || IS_ERR(ext2_root)) {
fprintf(stderr, "unable to open subvol %s\n", name);
fprintf(stderr, "unable to open subvol %llu\n",
key.objectid);
goto fail;
}
@ -2485,7 +2647,8 @@ int do_rollback(const char *devname, int force)
cache2 = btrfs_lookup_block_group(root->fs_info,
offset + num_bytes - 1);
if (!cache1 || cache1 != cache2 ||
!(cache1->flags & BTRFS_BLOCK_GROUP_SYSTEM))
(!(cache1->flags & BTRFS_BLOCK_GROUP_SYSTEM) &&
!intersect_with_sb(offset, num_bytes)))
break;
set_extent_bits(&io_tree, offset, offset + num_bytes - 1,

125
ctree.c
View File

@ -1114,7 +1114,8 @@ again:
if (ret && slot > 0)
slot -= 1;
p->slots[level] = slot;
if (ins_len > 0 && btrfs_header_nritems(b) >=
if ((p->search_for_split || ins_len > 0) &&
btrfs_header_nritems(b) >=
BTRFS_NODEPTRS_PER_BLOCK(root) - 3) {
int sret = split_node(trans, root, p, level);
BUG_ON(sret > 0);
@ -1949,11 +1950,11 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
int num_doubles = 0;
struct btrfs_disk_key disk_key;
if (extend)
if (extend && data_size)
space_needed = data_size;
/* first try to make some room by pushing left and right */
if (ins_key->type != BTRFS_DIR_ITEM_KEY) {
if (data_size && ins_key->type != BTRFS_DIR_ITEM_KEY) {
wret = push_leaf_right(trans, root, path, data_size, 0);
if (wret < 0) {
return wret;
@ -2031,7 +2032,7 @@ again:
} else {
if (leaf_space_used(l, 0, mid + 1) + space_needed >
BTRFS_LEAF_DATA_SIZE(root)) {
if (!extend && slot == 0) {
if (!extend && data_size && slot == 0) {
btrfs_cpu_key_to_disk(&disk_key, ins_key);
btrfs_set_header_nritems(right, 0);
wret = insert_ptr(trans, root, path,
@ -2050,7 +2051,7 @@ again:
ret = wret;
}
return ret;
} else if (extend && slot == 0) {
} else if ((extend || !data_size) && slot == 0) {
mid = 1;
} else {
mid = slot;
@ -2117,6 +2118,120 @@ again:
return ret;
}
/*
* This function splits a single item into two items,
* giving 'new_key' to the new item and splitting the
* old one at split_offset (from the start of the item).
*
* The path may be released by this operation. After
* the split, the path is pointing to the old item. The
* new item is going to be in the same node as the old one.
*
* Note, the item being split must be smaller enough to live alone on
* a tree block with room for one extra struct btrfs_item
*
* This allows us to split the item in place, keeping a lock on the
* leaf the entire time.
*/
int btrfs_split_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
struct btrfs_key *new_key,
unsigned long split_offset)
{
u32 item_size;
struct extent_buffer *leaf;
struct btrfs_key orig_key;
struct btrfs_item *item;
struct btrfs_item *new_item;
int ret = 0;
int slot;
u32 nritems;
u32 orig_offset;
struct btrfs_disk_key disk_key;
char *buf;
leaf = path->nodes[0];
btrfs_item_key_to_cpu(leaf, &orig_key, path->slots[0]);
if (btrfs_leaf_free_space(root, leaf) >= sizeof(struct btrfs_item))
goto split;
item_size = btrfs_item_size_nr(leaf, path->slots[0]);
btrfs_release_path(root, path);
path->search_for_split = 1;
ret = btrfs_search_slot(trans, root, &orig_key, path, 0, 1);
path->search_for_split = 0;
/* if our item isn't there or got smaller, return now */
if (ret != 0 || item_size != btrfs_item_size_nr(path->nodes[0],
path->slots[0])) {
return -EAGAIN;
}
ret = split_leaf(trans, root, &orig_key, path, 0, 0);
BUG_ON(ret);
BUG_ON(btrfs_leaf_free_space(root, leaf) < sizeof(struct btrfs_item));
leaf = path->nodes[0];
split:
item = btrfs_item_nr(leaf, path->slots[0]);
orig_offset = btrfs_item_offset(leaf, item);
item_size = btrfs_item_size(leaf, item);
buf = kmalloc(item_size, GFP_NOFS);
read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf,
path->slots[0]), item_size);
slot = path->slots[0] + 1;
leaf = path->nodes[0];
nritems = btrfs_header_nritems(leaf);
if (slot != nritems) {
/* shift the items */
memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + 1),
btrfs_item_nr_offset(slot),
(nritems - slot) * sizeof(struct btrfs_item));
}
btrfs_cpu_key_to_disk(&disk_key, new_key);
btrfs_set_item_key(leaf, &disk_key, slot);
new_item = btrfs_item_nr(leaf, slot);
btrfs_set_item_offset(leaf, new_item, orig_offset);
btrfs_set_item_size(leaf, new_item, item_size - split_offset);
btrfs_set_item_offset(leaf, item,
orig_offset + item_size - split_offset);
btrfs_set_item_size(leaf, item, split_offset);
btrfs_set_header_nritems(leaf, nritems + 1);
/* write the data for the start of the original item */
write_extent_buffer(leaf, buf,
btrfs_item_ptr_offset(leaf, path->slots[0]),
split_offset);
/* write the data for the new item */
write_extent_buffer(leaf, buf + split_offset,
btrfs_item_ptr_offset(leaf, slot),
item_size - split_offset);
btrfs_mark_buffer_dirty(leaf);
ret = 0;
if (btrfs_leaf_free_space(root, leaf) < 0) {
btrfs_print_leaf(root, leaf);
BUG();
}
kfree(buf);
return ret;
}
int btrfs_truncate_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,

32
ctree.h
View File

@ -392,6 +392,12 @@ struct btrfs_path {
int slots[BTRFS_MAX_LEVEL];
int reada;
int lowest_level;
/*
* set by btrfs_split_item, tells search_slot to keep all locks
* and to force calls to keep space in the nodes
*/
int search_for_split;
};
/*
@ -642,8 +648,9 @@ struct btrfs_fs_info {
struct btrfs_trans_handle *running_transaction;
struct btrfs_super_block super_copy;
struct extent_buffer *sb_buffer;
struct mutex fs_mutex;
u64 super_bytenr;
u64 total_pinned;
struct btrfs_extent_ops *extent_ops;
@ -1582,6 +1589,11 @@ int btrfs_truncate_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
u32 new_size, int from_end);
int btrfs_split_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
struct btrfs_key *new_key,
unsigned long split_offset);
int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_key *key, struct btrfs_path *p, int
ins_len, int cow);
@ -1629,6 +1641,11 @@ int btrfs_set_item_key_safe(struct btrfs_trans_handle *trans,
struct btrfs_key *new_key);
/* root-item.c */
int btrfs_add_root_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *tree_root,
u64 root_id, u8 type, u64 ref_id,
u64 dirid, u64 sequence,
const char *name, int name_len);
int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct btrfs_key *key);
int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root
@ -1644,7 +1661,7 @@ int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid,
/* dir-item.c */
int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
*root, const char *name, int name_len, u64 dir,
struct btrfs_key *location, u8 type);
struct btrfs_key *location, u8 type, u64 index);
struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path, u64 dir,
@ -1698,6 +1715,8 @@ int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root
struct btrfs_key *location, int mod);
/* file-item.c */
int btrfs_del_csums(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytenr, u64 len);
int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 objectid, u64 pos, u64 offset,
@ -1711,15 +1730,12 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
struct btrfs_path *path, u64 objectid,
u64 bytenr, int mod);
int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_inode_item *inode,
u64 objectid, u64 offset,
char *data, size_t len);
struct btrfs_root *root, u64 alloc_end,
u64 bytenr, char *data, size_t len);
struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
u64 objectid, u64 offset,
int cow);
u64 bytenr, int cow);
int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_path *path,
u64 isize);

View File

@ -107,7 +107,7 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
*root, const char *name, int name_len, u64 dir,
struct btrfs_key *location, u8 type)
struct btrfs_key *location, u8 type, u64 index)
{
int ret = 0;
int ret2 = 0;
@ -128,8 +128,6 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
name, name_len);
if (IS_ERR(dir_item)) {
ret = PTR_ERR(dir_item);
if (ret == -EEXIST)
goto second_insert;
goto out;
}
@ -144,7 +142,6 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
write_extent_buffer(leaf, name, name_ptr, name_len);
btrfs_mark_buffer_dirty(leaf);
second_insert:
/* FIXME, use some real flag for selecting the extra index */
if (root == root->fs_info->tree_root) {
ret = 0;
@ -153,7 +150,7 @@ second_insert:
btrfs_release_path(root, path);
btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
key.offset = location->objectid;
key.offset = index;
dir_item = insert_with_overflow(trans, root, path, &key, data_size,
name, name_len);
if (IS_ERR(dir_item)) {

158
disk-io.c
View File

@ -552,6 +552,7 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
struct btrfs_root *extent_root = malloc(sizeof(struct btrfs_root));
struct btrfs_root *chunk_root = malloc(sizeof(struct btrfs_root));
struct btrfs_root *dev_root = malloc(sizeof(struct btrfs_root));
struct btrfs_root *csum_root = malloc(sizeof(struct btrfs_root));
struct btrfs_fs_info *fs_info = malloc(sizeof(*fs_info));
int ret;
struct btrfs_super_block *disk_super;
@ -580,6 +581,7 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
fs_info->extent_root = extent_root;
fs_info->chunk_root = chunk_root;
fs_info->dev_root = dev_root;
fs_info->csum_root = csum_root;
if (!writes)
fs_info->readonly = 1;
@ -607,27 +609,17 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
ret = btrfs_open_devices(fs_devices, O_RDONLY);
BUG_ON(ret);
fs_info->sb_buffer = btrfs_find_create_tree_block(tree_root, sb_bytenr,
4096);
BUG_ON(!fs_info->sb_buffer);
fs_info->sb_buffer->fd = fs_devices->latest_bdev;
fs_info->sb_buffer->dev_bytenr = sb_bytenr;
ret = read_extent_from_disk(fs_info->sb_buffer);
BUG_ON(ret);
btrfs_set_buffer_uptodate(fs_info->sb_buffer);
read_extent_buffer(fs_info->sb_buffer, &fs_info->super_copy, 0,
sizeof(fs_info->super_copy));
read_extent_buffer(fs_info->sb_buffer, fs_info->fsid,
(unsigned long)btrfs_super_fsid(fs_info->sb_buffer),
BTRFS_FSID_SIZE);
fs_info->super_bytenr = sb_bytenr;
disk_super = &fs_info->super_copy;
if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC,
sizeof(disk_super->magic))) {
ret = btrfs_read_dev_super(fs_devices->latest_bdev,
disk_super, sb_bytenr);
if (ret) {
printk("No valid btrfs found\n");
BUG_ON(1);
}
memcpy(fs_info->fsid, &disk_super->fsid, BTRFS_FSID_SIZE);
nodesize = btrfs_super_nodesize(disk_super);
leafsize = btrfs_super_leafsize(disk_super);
sectorsize = btrfs_super_sectorsize(disk_super);
@ -637,8 +629,6 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
tree_root->sectorsize = sectorsize;
tree_root->stripesize = stripesize;
ret = btrfs_read_super_device(tree_root, fs_info->sb_buffer);
BUG_ON(ret);
ret = btrfs_read_sys_array(tree_root);
BUG_ON(ret);
blocksize = btrfs_level_size(tree_root,
@ -681,6 +671,11 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
BUG_ON(ret);
dev_root->track_dirty = 1;
ret = find_and_setup_root(tree_root, fs_info,
BTRFS_CSUM_TREE_OBJECTID, csum_root);
BUG_ON(ret);
csum_root->track_dirty = 1;
ret = find_and_setup_root(tree_root, fs_info,
BTRFS_FS_TREE_OBJECTID, root);
BUG_ON(ret);
@ -695,27 +690,83 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
return root;
}
int write_dev_supers(struct btrfs_root *root, struct extent_buffer *sb,
int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr)
{
struct btrfs_super_block buf;
int i;
int ret;
u64 transid = 0;
u64 bytenr;
if (sb_bytenr != BTRFS_SUPER_INFO_OFFSET) {
ret = pread64(fd, &buf, sizeof(buf), sb_bytenr);
if (ret < sizeof(buf))
return -1;
if (btrfs_super_bytenr(&buf) != sb_bytenr ||
strncmp((char *)(&buf.magic), BTRFS_MAGIC,
sizeof(buf.magic)))
return -1;
memcpy(sb, &buf, sizeof(*sb));
return 0;
}
for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
bytenr = btrfs_sb_offset(i);
ret = pread64(fd, &buf, sizeof(buf), bytenr);
if (ret < sizeof(buf))
break;
if (btrfs_super_bytenr(&buf) != bytenr ||
strncmp((char *)(&buf.magic), BTRFS_MAGIC,
sizeof(buf.magic)))
continue;
if (btrfs_super_generation(&buf) > transid) {
memcpy(sb, &buf, sizeof(*sb));
transid = btrfs_super_generation(&buf);
}
}
return transid > 0 ? 0 : -1;
}
int write_dev_supers(struct btrfs_root *root, struct btrfs_super_block *sb,
struct btrfs_device *device)
{
u64 bytenr;
u64 flags;
u32 crc;
int i, ret;
sb->fd = device->fd;
if (root->fs_info->super_bytenr != BTRFS_SUPER_INFO_OFFSET) {
btrfs_set_super_bytenr(sb, root->fs_info->super_bytenr);
crc = ~(u32)0;
crc = btrfs_csum_data(NULL, (char *)sb + BTRFS_CSUM_SIZE, crc,
BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE);
btrfs_csum_final(crc, (char *)&sb->csum[0]);
ret = pwrite64(device->fd, sb, BTRFS_SUPER_INFO_SIZE,
root->fs_info->super_bytenr);
BUG_ON(ret != BTRFS_SUPER_INFO_SIZE);
return 0;
}
for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
bytenr = btrfs_sb_offset(i);
if (bytenr + BTRFS_SUPER_INFO_SIZE >= device->total_bytes)
break;
btrfs_set_header_bytenr(sb, bytenr);
flags = btrfs_header_flags(sb);
btrfs_set_header_flags(sb, flags | BTRFS_HEADER_FLAG_WRITTEN);
csum_tree_block(root, sb, 0);
btrfs_set_super_bytenr(sb, bytenr);
sb->dev_bytenr = bytenr;
ret = write_extent_to_disk(sb);
BUG_ON(ret);
crc = ~(u32)0;
crc = btrfs_csum_data(NULL, (char *)sb + BTRFS_CSUM_SIZE, crc,
BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE);
btrfs_csum_final(crc, (char *)&sb->csum[0]);
ret = pwrite64(device->fd, sb, BTRFS_SUPER_INFO_SIZE, bytenr);
BUG_ON(ret != BTRFS_SUPER_INFO_SIZE);
}
return 0;
}
@ -725,32 +776,32 @@ int write_all_supers(struct btrfs_root *root)
struct list_head *cur;
struct list_head *head = &root->fs_info->fs_devices->devices;
struct btrfs_device *dev;
struct extent_buffer *sb;
struct btrfs_super_block *sb;
struct btrfs_dev_item *dev_item;
int ret;
u64 flags;
sb = root->fs_info->sb_buffer;
dev_item = (struct btrfs_dev_item *)offsetof(struct btrfs_super_block,
dev_item);
sb = &root->fs_info->super_copy;
dev_item = &sb->dev_item;
list_for_each(cur, head) {
dev = list_entry(cur, struct btrfs_device, dev_list);
if (!dev->writeable)
continue;
btrfs_set_device_generation(sb, dev_item, 0);
btrfs_set_device_type(sb, dev_item, dev->type);
btrfs_set_device_id(sb, dev_item, dev->devid);
btrfs_set_device_total_bytes(sb, dev_item, dev->total_bytes);
btrfs_set_device_bytes_used(sb, dev_item, dev->bytes_used);
btrfs_set_device_io_align(sb, dev_item, dev->io_align);
btrfs_set_device_io_width(sb, dev_item, dev->io_width);
btrfs_set_device_sector_size(sb, dev_item, dev->sector_size);
write_extent_buffer(sb, dev->uuid,
(unsigned long)btrfs_device_uuid(dev_item),
BTRFS_UUID_SIZE);
write_extent_buffer(sb, dev->fs_devices->fsid,
(unsigned long)btrfs_device_fsid(dev_item),
BTRFS_UUID_SIZE);
btrfs_set_stack_device_generation(dev_item, 0);
btrfs_set_stack_device_type(dev_item, dev->type);
btrfs_set_stack_device_id(dev_item, dev->devid);
btrfs_set_stack_device_total_bytes(dev_item, dev->total_bytes);
btrfs_set_stack_device_bytes_used(dev_item, dev->bytes_used);
btrfs_set_stack_device_io_align(dev_item, dev->io_align);
btrfs_set_stack_device_io_width(dev_item, dev->io_width);
btrfs_set_stack_device_sector_size(dev_item, dev->sector_size);
memcpy(dev_item->uuid, dev->uuid, BTRFS_UUID_SIZE);
memcpy(dev_item->fsid, dev->fs_devices->fsid, BTRFS_UUID_SIZE);
flags = btrfs_super_flags(sb);
btrfs_set_super_flags(sb, flags | BTRFS_HEADER_FLAG_WRITTEN);
ret = write_dev_supers(root, sb, dev);
BUG_ON(ret);
}
@ -779,9 +830,7 @@ int write_ctree_super(struct btrfs_trans_handle *trans,
btrfs_header_level(chunk_root->node));
btrfs_set_super_chunk_root_generation(&root->fs_info->super_copy,
btrfs_header_generation(chunk_root->node));
write_extent_buffer(root->fs_info->sb_buffer,
&root->fs_info->super_copy, 0,
sizeof(root->fs_info->super_copy));
ret = write_all_supers(root);
if (ret)
fprintf(stderr, "failed to write new super block err %d\n", ret);
@ -827,13 +876,13 @@ int close_ctree(struct btrfs_root *root)
if (root->fs_info->tree_root->node)
free_extent_buffer(root->fs_info->tree_root->node);
free_extent_buffer(root->commit_root);
free_extent_buffer(root->fs_info->sb_buffer);
if (root->fs_info->chunk_root->node);
if (root->fs_info->chunk_root->node)
free_extent_buffer(root->fs_info->chunk_root->node);
if (root->fs_info->dev_root->node);
if (root->fs_info->dev_root->node)
free_extent_buffer(root->fs_info->dev_root->node);
if (root->fs_info->csum_root->node)
free_extent_buffer(root->fs_info->csum_root->node);
close_all_devices(root->fs_info);
extent_io_tree_cleanup(&fs_info->extent_cache);
@ -848,6 +897,7 @@ int close_ctree(struct btrfs_root *root)
free(fs_info->fs_root);
free(fs_info->chunk_root);
free(fs_info->dev_root);
free(fs_info->csum_root);
free(fs_info);
return 0;

View File

@ -49,6 +49,7 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
int close_ctree(struct btrfs_root *root);
int write_ctree_super(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr);
int btrfs_map_bh_to_logical(struct btrfs_root *root, struct extent_buffer *bh,
u64 logical);
struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root,

View File

@ -95,10 +95,8 @@ static int cache_block_group(struct btrfs_root *root,
struct extent_buffer *leaf;
struct extent_io_tree *free_space_cache;
int slot;
u64 last = 0;
u64 last;
u64 hole_size;
u64 first_free;
int found = 0;
if (!block_group)
return 0;
@ -114,22 +112,14 @@ static int cache_block_group(struct btrfs_root *root,
return -ENOMEM;
path->reada = 2;
first_free = block_group->key.objectid;
key.objectid = block_group->key.objectid;
last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET);
key.objectid = last;
key.offset = 0;
btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
if (ret < 0)
return ret;
ret = btrfs_previous_item(root, path, 0, BTRFS_EXTENT_ITEM_KEY);
if (ret < 0)
return ret;
if (ret == 0) {
leaf = path->nodes[0];
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
if (key.objectid + key.offset > first_free)
first_free = key.objectid + key.offset;
}
goto err;
while(1) {
leaf = path->nodes[0];
slot = path->slots[0];
@ -153,10 +143,6 @@ static int cache_block_group(struct btrfs_root *root,
}
if (btrfs_key_type(&key) == BTRFS_EXTENT_ITEM_KEY) {
if (!found) {
last = first_free;
found = 1;
}
if (key.objectid > last) {
hole_size = key.objectid - last;
set_extent_dirty(free_space_cache, last,
@ -169,8 +155,6 @@ next:
path->slots[0]++;
}
if (!found)
last = first_free;
if (block_group->key.objectid +
block_group->key.offset > last) {
hole_size = block_group->key.objectid +
@ -1572,12 +1556,7 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
u64 super_used;
u64 root_used;
if (pin) {
ret = pin_down_bytes(trans, root, bytenr, num_bytes, 0);
if (ret > 0)
mark_free = 1;
BUG_ON(ret < 0);
}
/* block accounting for super block */
super_used = btrfs_super_bytes_used(&info->super_copy);
@ -1593,8 +1572,25 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
if (ret)
return ret;
if (ops && ops->free_extent)
ops->free_extent(root, bytenr, num_bytes);
if (ops && ops->free_extent) {
ret = ops->free_extent(root, bytenr, num_bytes);
if (ret > 0) {
pin = 0;
mark_free = 0;
}
}
if (pin) {
ret = pin_down_bytes(trans, root, bytenr, num_bytes, 0);
if (ret > 0)
mark_free = 1;
BUG_ON(ret < 0);
}
if (owner_objectid >= BTRFS_FIRST_FREE_OBJECTID) {
ret = btrfs_del_csums(trans, root, bytenr, num_bytes);
BUG_ON(ret);
}
ret = update_block_group(trans, root, bytenr, num_bytes, 0,
mark_free);
@ -2587,8 +2583,8 @@ int btrfs_make_block_groups(struct btrfs_trans_handle *trans,
group_type = BTRFS_BLOCK_GROUP_SYSTEM;
group_size /= 4;
group_size &= ~(group_align - 1);
group_size = max_t(u64, group_size, 32 * 1024 * 1024);
group_size = min_t(u64, group_size, 128 * 1024 * 1024);
group_size = max_t(u64, group_size, 8 * 1024 * 1024);
group_size = min_t(u64, group_size, 32 * 1024 * 1024);
} else {
group_size &= ~(group_align - 1);
if (total_data >= total_metadata * 2) {

View File

@ -93,94 +93,23 @@ int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans,
key.offset = offset;
btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
if (ret < 0) {
datasize = btrfs_file_extent_calc_inline_size(size);
ret = btrfs_insert_empty_item(trans, root, path, &key, datasize);
if (ret) {
err = ret;
goto fail;
}
if (ret == 1) {
struct btrfs_key found_key;
if (path->slots[0] == 0)
goto insert;
leaf = path->nodes[0];
ei = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_file_extent_item);
btrfs_set_file_extent_generation(leaf, ei, trans->transid);
btrfs_set_file_extent_type(leaf, ei, BTRFS_FILE_EXTENT_INLINE);
btrfs_set_file_extent_ram_bytes(leaf, ei, size);
btrfs_set_file_extent_compression(leaf, ei, 0);
btrfs_set_file_extent_encryption(leaf, ei, 0);
btrfs_set_file_extent_other_encoding(leaf, ei, 0);
path->slots[0]--;
leaf = path->nodes[0];
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
if (found_key.objectid != objectid)
goto insert;
if (found_key.type != BTRFS_EXTENT_DATA_KEY)
goto insert;
ei = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_file_extent_item);
if (btrfs_file_extent_type(leaf, ei) !=
BTRFS_FILE_EXTENT_INLINE) {
goto insert;
}
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
ret = 0;
}
if (ret == 0) {
u32 found_size;
u64 found_end;
leaf = path->nodes[0];
ei = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_file_extent_item);
if (btrfs_file_extent_type(leaf, ei) !=
BTRFS_FILE_EXTENT_INLINE) {
err = ret;
btrfs_print_leaf(root, leaf);
printk("found wasn't inline offset %llu inode %llu\n",
(unsigned long long)offset,
(unsigned long long)objectid);
goto fail;
}
found_size = btrfs_file_extent_inline_len(leaf, ei);
found_end = key.offset + found_size;
if (found_end < offset + size) {
btrfs_release_path(root, path);
ret = btrfs_search_slot(trans, root, &key, path,
offset + size - found_end, 1);
BUG_ON(ret != 0);
ret = btrfs_extend_item(trans, root, path,
offset + size - found_end);
if (ret) {
err = ret;
goto fail;
}
leaf = path->nodes[0];
ei = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_file_extent_item);
}
if (found_end < offset) {
ptr = btrfs_file_extent_inline_start(ei) + found_size;
memset_extent_buffer(leaf, 0, ptr, offset - found_end);
}
} else {
insert:
btrfs_release_path(root, path);
datasize = offset + size - key.offset;
datasize = btrfs_file_extent_calc_inline_size(datasize);
ret = btrfs_insert_empty_item(trans, root, path, &key,
datasize);
if (ret) {
err = ret;
printk("got bad ret %d\n", ret);
goto fail;
}
leaf = path->nodes[0];
ei = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_file_extent_item);
btrfs_set_file_extent_generation(leaf, ei, trans->transid);
btrfs_set_file_extent_type(leaf, ei, BTRFS_FILE_EXTENT_INLINE);
}
ptr = btrfs_file_extent_inline_start(ei) + offset - key.offset;
write_extent_buffer(leaf, buffer, ptr, size);
btrfs_mark_buffer_dirty(leaf);
@ -192,7 +121,7 @@ fail:
struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
u64 objectid, u64 offset, int cow)
u64 bytenr, int cow)
{
int ret;
struct btrfs_key file_key;
@ -200,13 +129,13 @@ struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
struct btrfs_csum_item *item;
struct extent_buffer *leaf;
u64 csum_offset = 0;
int csums_in_item;
u16 csum_size =
btrfs_super_csum_size(&root->fs_info->super_copy);
int csums_in_item;
file_key.objectid = objectid;
file_key.offset = offset;
btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
file_key.offset = bytenr;
btrfs_set_key_type(&file_key, BTRFS_EXTENT_CSUM_KEY);
ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow);
if (ret < 0)
goto fail;
@ -217,11 +146,10 @@ struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
goto fail;
path->slots[0]--;
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY ||
found_key.objectid != objectid) {
if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY)
goto fail;
}
csum_offset = (offset - found_key.offset) >> root->sectorsize;
csum_offset = (bytenr - found_key.offset) / root->sectorsize;
csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]);
csums_in_item /= csum_size;
@ -240,7 +168,6 @@ fail:
return ERR_PTR(ret);
}
int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path, u64 objectid,
@ -259,10 +186,8 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
}
int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_inode_item *inode,
u64 objectid, u64 offset,
char *data, size_t len)
struct btrfs_root *root, u64 alloc_end,
u64 bytenr, char *data, size_t len)
{
int ret;
struct btrfs_key file_key;
@ -282,11 +207,11 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
path = btrfs_alloc_path();
BUG_ON(!path);
file_key.objectid = objectid;
file_key.offset = offset;
btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
file_key.offset = bytenr;
file_key.type = BTRFS_EXTENT_CSUM_KEY;
item = btrfs_lookup_csum(trans, root, path, objectid, offset, 1);
item = btrfs_lookup_csum(trans, root, path, bytenr, 1);
if (!IS_ERR(item)) {
leaf = path->nodes[0];
goto found;
@ -314,8 +239,8 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
slot = 0;
}
btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot);
if (found_key.objectid != objectid ||
found_key.type != BTRFS_CSUM_ITEM_KEY) {
if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
found_key.type != BTRFS_EXTENT_CSUM_KEY) {
found_next = 1;
goto insert;
}
@ -342,9 +267,9 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
path->slots[0]--;
leaf = path->nodes[0];
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
csum_offset = (offset - found_key.offset) / root->sectorsize;
if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY ||
found_key.objectid != objectid ||
csum_offset = (file_key.offset - found_key.offset) / root->sectorsize;
if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
found_key.type != BTRFS_EXTENT_CSUM_KEY ||
csum_offset >= MAX_CSUM_ITEMS(root, csum_size)) {
goto insert;
}
@ -363,8 +288,8 @@ insert:
btrfs_release_path(root, path);
csum_offset = 0;
if (found_next) {
u64 tmp = min(btrfs_stack_inode_size(inode), next_offset);
tmp -= offset & ~((u64)root->sectorsize -1);
u64 tmp = min(alloc_end, next_offset);
tmp -= file_key.offset;
tmp /= root->sectorsize;
tmp = max((u64)1, tmp);
tmp = min(tmp, (u64)MAX_CSUM_ITEMS(root, csum_size));
@ -390,9 +315,8 @@ found:
csum_result = btrfs_csum_data(root, data, csum_result, len);
btrfs_csum_final(csum_result, (char *)&csum_result);
if (csum_result == 0) {
printk("csum result is 0 for inode %llu offset %llu\n",
(unsigned long long)objectid,
(unsigned long long)offset);
printk("csum result is 0 for block %llu\n",
(unsigned long long)bytenr);
}
write_extent_buffer(leaf, &csum_result, (unsigned long)item,
@ -404,28 +328,175 @@ fail:
return ret;
}
int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_path *path,
u64 isize)
/*
* helper function for csum removal, this expects the
* key to describe the csum pointed to by the path, and it expects
* the csum to overlap the range [bytenr, len]
*
* The csum should not be entirely contained in the range and the
* range should not be entirely contained in the csum.
*
* This calls btrfs_truncate_item with the correct args based on the
* overlap, and fixes up the key as required.
*/
static noinline int truncate_one_csum(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
struct btrfs_key *key,
u64 bytenr, u64 len)
{
struct btrfs_key key;
struct extent_buffer *leaf = path->nodes[0];
int slot = path->slots[0];
struct extent_buffer *leaf;
u16 csum_size =
btrfs_super_csum_size(&root->fs_info->super_copy);
u64 csum_end;
u64 end_byte = bytenr + len;
u32 blocksize = root->sectorsize;
int ret;
u32 new_item_size;
u64 new_item_span;
u64 blocks;
btrfs_item_key_to_cpu(leaf, &key, slot);
if (isize <= key.offset)
return 0;
new_item_span = isize - key.offset;
blocks = (new_item_span + root->sectorsize - 1) / root->sectorsize;
new_item_size = blocks *
btrfs_super_csum_size(&root->fs_info->super_copy);
if (new_item_size >= btrfs_item_size_nr(leaf, slot))
return 0;
ret = btrfs_truncate_item(trans, root, path, new_item_size, 1);
BUG_ON(ret);
return ret;
leaf = path->nodes[0];
csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size;
csum_end *= root->sectorsize;
csum_end += key->offset;
if (key->offset < bytenr && csum_end <= end_byte) {
/*
* [ bytenr - len ]
* [ ]
* [csum ]
* A simple truncate off the end of the item
*/
u32 new_size = (bytenr - key->offset) / blocksize;
new_size *= csum_size;
ret = btrfs_truncate_item(trans, root, path, new_size, 1);
BUG_ON(ret);
} else if (key->offset >= bytenr && csum_end > end_byte &&
end_byte > key->offset) {
/*
* [ bytenr - len ]
* [ ]
* [csum ]
* we need to truncate from the beginning of the csum
*/
u32 new_size = (csum_end - end_byte) / blocksize;
new_size *= csum_size;
ret = btrfs_truncate_item(trans, root, path, new_size, 0);
BUG_ON(ret);
key->offset = end_byte;
ret = btrfs_set_item_key_safe(trans, root, path, key);
BUG_ON(ret);
} else {
BUG();
}
return 0;
}
/*
* deletes the csum items from the csum tree for a given
* range of bytes.
*/
int btrfs_del_csums(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytenr, u64 len)
{
struct btrfs_path *path;
struct btrfs_key key;
u64 end_byte = bytenr + len;
u64 csum_end;
struct extent_buffer *leaf;
int ret;
u16 csum_size =
btrfs_super_csum_size(&root->fs_info->super_copy);
int blocksize = root->sectorsize;
root = root->fs_info->csum_root;
path = btrfs_alloc_path();
while (1) {
key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
key.offset = end_byte - 1;
key.type = BTRFS_EXTENT_CSUM_KEY;
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
if (ret > 0) {
if (path->slots[0] == 0)
goto out;
path->slots[0]--;
}
leaf = path->nodes[0];
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
key.type != BTRFS_EXTENT_CSUM_KEY) {
break;
}
if (key.offset >= end_byte)
break;
csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size;
csum_end *= blocksize;
csum_end += key.offset;
/* this csum ends before we start, we're done */
if (csum_end <= bytenr)
break;
/* delete the entire item, it is inside our range */
if (key.offset >= bytenr && csum_end <= end_byte) {
ret = btrfs_del_item(trans, root, path);
BUG_ON(ret);
} else if (key.offset < bytenr && csum_end > end_byte) {
unsigned long offset;
unsigned long shift_len;
unsigned long item_offset;
/*
* [ bytenr - len ]
* [csum ]
*
* Our bytes are in the middle of the csum,
* we need to split this item and insert a new one.
*
* But we can't drop the path because the
* csum could change, get removed, extended etc.
*
* The trick here is the max size of a csum item leaves
* enough room in the tree block for a single
* item header. So, we split the item in place,
* adding a new header pointing to the existing
* bytes. Then we loop around again and we have
* a nicely formed csum item that we can neatly
* truncate.
*/
offset = (bytenr - key.offset) / blocksize;
offset *= csum_size;
shift_len = (len / blocksize) * csum_size;
item_offset = btrfs_item_ptr_offset(leaf,
path->slots[0]);
memset_extent_buffer(leaf, 0, item_offset + offset,
shift_len);
key.offset = bytenr;
/*
* btrfs_split_item returns -EAGAIN when the
* item changed size or key
*/
ret = btrfs_split_item(trans, root, path, &key, offset);
BUG_ON(ret && ret != -EAGAIN);
key.offset = end_byte - 1;
} else {
ret = truncate_one_csum(trans, root, path,
&key, bytenr, len);
BUG_ON(ret);
}
btrfs_release_path(root, path);
}
out:
btrfs_free_path(path);
return 0;
}

2
mkfs.c
View File

@ -125,7 +125,7 @@ static int make_root_dir(struct btrfs_root *root)
ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root,
"default", 7,
btrfs_super_root_dir(&root->fs_info->super_copy),
&location, BTRFS_FT_DIR);
&location, BTRFS_FT_DIR, 0);
if (ret)
goto err;

View File

@ -201,3 +201,53 @@ out:
btrfs_free_path(path);
return ret;
}
/*
* add a btrfs_root_ref item. type is either BTRFS_ROOT_REF_KEY
* or BTRFS_ROOT_BACKREF_KEY.
*
* The dirid, sequence, name and name_len refer to the directory entry
* that is referencing the root.
*
* For a forward ref, the root_id is the id of the tree referencing
* the root and ref_id is the id of the subvol or snapshot.
*
* For a back ref the root_id is the id of the subvol or snapshot and
* ref_id is the id of the tree referencing it.
*/
int btrfs_add_root_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *tree_root,
u64 root_id, u8 type, u64 ref_id,
u64 dirid, u64 sequence,
const char *name, int name_len)
{
struct btrfs_key key;
int ret;
struct btrfs_path *path;
struct btrfs_root_ref *ref;
struct extent_buffer *leaf;
unsigned long ptr;
path = btrfs_alloc_path();
key.objectid = root_id;
key.type = type;
key.offset = ref_id;
ret = btrfs_insert_empty_item(trans, tree_root, path, &key,
sizeof(*ref) + name_len);
BUG_ON(ret);
leaf = path->nodes[0];
ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref);
btrfs_set_root_ref_dirid(leaf, ref, dirid);
btrfs_set_root_ref_sequence(leaf, ref, sequence);
btrfs_set_root_ref_name_len(leaf, ref, name_len);
ptr = (unsigned long)(ref + 1);
write_extent_buffer(leaf, name, ptr, name_len);
btrfs_mark_buffer_dirty(leaf);
btrfs_free_path(path);
return ret;
}

View File

@ -491,6 +491,7 @@ int btrfs_add_to_fsid(struct btrfs_trans_handle *trans,
printf("adding device %s id %llu\n", path,
(unsigned long long)device->devid);
btrfs_set_super_bytenr(disk_super, BTRFS_SUPER_INFO_OFFSET);
btrfs_set_stack_device_id(dev_item, device->devid);
btrfs_set_stack_device_type(dev_item, device->type);
btrfs_set_stack_device_io_align(dev_item, device->io_align);

View File

@ -210,15 +210,10 @@ int btrfs_scan_one_device(int fd, const char *path,
ret = -ENOMEM;
goto error;
}
ret = pread(fd, buf, 4096, super_offset);
if (ret != 4096) {
ret = -EIO;
goto error;
}
disk_super = (struct btrfs_super_block *)buf;
if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC,
sizeof(disk_super->magic))) {
ret = -ENOENT;
ret = btrfs_read_dev_super(fd, disk_super, super_offset);
if (ret < 0) {
ret = -EIO;
goto error_brelse;
}
devid = le64_to_cpu(disk_super->dev_item.devid);
@ -902,10 +897,10 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree,
int i, j, nr = 0;
ce = find_first_cache_extent(&map_tree->cache_tree, chunk_start);
BUG_ON(!ce || ce->start != chunk_start);
BUG_ON(!ce);
map = container_of(ce, struct map_lookup, ce);
length = ce->size;
length = ce->size;
if (map->type & BTRFS_BLOCK_GROUP_RAID10)
length = ce->size / (map->num_stripes / map->sub_stripes);
else if (map->type & BTRFS_BLOCK_GROUP_RAID0)
@ -929,7 +924,7 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree,
} else if (map->type & BTRFS_BLOCK_GROUP_RAID0) {
stripe_nr = stripe_nr * map->num_stripes + i;
}
bytenr = chunk_start + stripe_nr * map->stripe_len;
bytenr = ce->start + stripe_nr * map->stripe_len;
for (j = 0; j < nr; j++) {
if (buf[j] == bytenr)
break;
@ -1328,7 +1323,7 @@ int btrfs_read_super_device(struct btrfs_root *root, struct extent_buffer *buf)
int btrfs_read_sys_array(struct btrfs_root *root)
{
struct btrfs_super_block *super_copy = &root->fs_info->super_copy;
struct extent_buffer *sb = root->fs_info->sb_buffer;
struct extent_buffer *sb;
struct btrfs_disk_key *disk_key;
struct btrfs_chunk *chunk;
struct btrfs_key key;
@ -1340,6 +1335,12 @@ int btrfs_read_sys_array(struct btrfs_root *root)
u32 cur;
int ret;
sb = btrfs_find_create_tree_block(root, BTRFS_SUPER_INFO_OFFSET,
BTRFS_SUPER_INFO_SIZE);
if (!sb)
return -ENOMEM;
btrfs_set_buffer_uptodate(sb);
write_extent_buffer(sb, super_copy, 0, BTRFS_SUPER_INFO_SIZE);
array_size = btrfs_super_sys_array_size(super_copy);
/*
@ -1373,6 +1374,7 @@ int btrfs_read_sys_array(struct btrfs_root *root)
sb_ptr += len;
cur += len;
}
free_extent_buffer(sb);
return 0;
}