summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--convert.c391
-rw-r--r--ctree.c125
-rw-r--r--ctree.h32
-rw-r--r--dir-item.c7
-rw-r--r--disk-io.c158
-rw-r--r--disk-io.h1
-rw-r--r--extent-tree.c58
-rw-r--r--file-item.c335
-rw-r--r--mkfs.c2
-rw-r--r--root-tree.c50
-rw-r--r--utils.c1
-rw-r--r--volumes.c26
12 files changed, 824 insertions, 362 deletions
diff --git a/convert.c b/convert.c
index 388c6c44..2cc2a550 100644
--- a/convert.c
+++ b/convert.c
@@ -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)
+ BUG_ON(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 ret;
+
+ 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,
diff --git a/ctree.c b/ctree.c
index 0d9797e5..f4829c8b 100644
--- a/ctree.c
+++ b/ctree.c
@@ -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,
diff --git a/ctree.h b/ctree.h
index 4213b43e..54caa44d 100644
--- a/ctree.h
+++ b/ctree.h
@@ -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);
diff --git a/dir-item.c b/dir-item.c
index aaaad6a6..71373b8b 100644
--- a/dir-item.c
+++ b/dir-item.c
@@ -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)) {
diff --git a/disk-io.c b/disk-io.c
index 46662c5c..c15cf53e 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -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,
@@ -682,6 +672,11 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
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);
root->ref_cows = 1;
@@ -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;
diff --git a/disk-io.h b/disk-io.h
index 8e9fab9d..d9a35afd 100644
--- a/disk-io.h
+++ b/disk-io.h
@@ -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,
diff --git a/extent-tree.c b/extent-tree.c
index b4ae95a9..5dc353a1 100644
--- a/extent-tree.c
+++ b/extent-tree.c
@@ -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) {
diff --git a/file-item.c b/file-item.c
index a7400e24..562857c8 100644
--- a/file-item.c
+++ b/file-item.c
@@ -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;
-
- 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);
+ 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);
- 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 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;
+
+ 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;
- struct extent_buffer *leaf = path->nodes[0];
- int slot = path->slots[0];
+ u64 end_byte = bytenr + len;
+ u64 csum_end;
+ struct extent_buffer *leaf;
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;
+ 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;
}
diff --git a/mkfs.c b/mkfs.c
index f942dc73..89de8ac9 100644
--- a/mkfs.c
+++ b/mkfs.c
@@ -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;
diff --git a/root-tree.c b/root-tree.c
index 189f82d2..782472ca 100644
--- a/root-tree.c
+++ b/root-tree.c
@@ -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;
+}
diff --git a/utils.c b/utils.c
index b6b34ea4..1f99ea32 100644
--- a/utils.c
+++ b/utils.c
@@ -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);
diff --git a/volumes.c b/volumes.c
index b27e66ff..76718550 100644
--- a/volumes.c
+++ b/volumes.c
@@ -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;
}