summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Mason <chris.mason@fusionio.com>2013-10-16 10:36:55 -0400
committerChris Mason <chris.mason@fusionio.com>2013-10-16 10:42:53 -0400
commitd1570a06184ed3748536a67693ef5cfd954d4032 (patch)
tree3fe610614ddc64a510006820a518297d14a9dec1
parent005d7d2efb0aaaae056584f3cbd25d3bfce73ea3 (diff)
mkfs: fix mkfs -r to properly allocate space
mkfs -r wasn't creating chunks properly, making it very difficult to allocate space for anything except tiny filesystems. This changes it around to use more of the generic infrastructure, and to do actual logical->physical block number translation. It also allocates space to the files in smaller extents (max 1MB), which keeps the allocator from trying to allocate an extent bigger than a single chunk. It doesn't quite support multi-device mkfs -r yet, but is much closer. Signed-off-by: Chris Mason <chris.mason@fusionio.com>
-rw-r--r--btrfs-convert.c154
-rw-r--r--ctree.h10
-rw-r--r--disk-io.c31
-rw-r--r--disk-io.h2
-rw-r--r--extent-tree.c104
-rw-r--r--mkfs.c231
6 files changed, 235 insertions, 297 deletions
diff --git a/btrfs-convert.c b/btrfs-convert.c
index edef1bd7..26c7b5fd 100644
--- a/btrfs-convert.c
+++ b/btrfs-convert.c
@@ -351,124 +351,33 @@ fail:
ret = -1;
return ret;
}
-/*
- * Record a file extent. Do all the required works, such as inserting
- * file extent item, inserting extent item and backref item into extent
- * tree and updating block accounting.
- */
-static int record_file_extent(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, u64 objectid,
- struct btrfs_inode_item *inode,
- u64 file_pos, u64 disk_bytenr,
- u64 num_bytes, int checksum)
+
+static int csum_disk_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ u64 disk_bytenr, u64 num_bytes)
{
- int ret;
- struct btrfs_fs_info *info = root->fs_info;
- struct btrfs_root *extent_root = info->extent_root;
- struct extent_buffer *leaf;
- struct btrfs_file_extent_item *fi;
- struct btrfs_key ins_key;
- struct btrfs_path path;
- struct btrfs_extent_item *ei;
u32 blocksize = root->sectorsize;
- u64 nbytes;
-
- if (disk_bytenr == 0) {
- ret = btrfs_insert_file_extent(trans, root, objectid,
- file_pos, disk_bytenr,
- num_bytes, num_bytes);
- return ret;
- }
-
- btrfs_init_path(&path);
-
- if (checksum) {
- u64 offset;
- char *buffer;
+ u64 offset;
+ char *buffer;
+ int ret = 0;
- ret = -ENOMEM;
- buffer = malloc(blocksize);
- if (!buffer)
- goto fail;
- for (offset = 0; offset < num_bytes; offset += blocksize) {
- ret = read_disk_extent(root, disk_bytenr + offset,
- blocksize, buffer);
- if (ret)
- break;
- ret = btrfs_csum_file_block(trans,
- root->fs_info->csum_root,
- disk_bytenr + num_bytes,
- disk_bytenr + offset,
- buffer, blocksize);
- if (ret)
- break;
- }
- free(buffer);
+ buffer = malloc(blocksize);
+ if (!buffer)
+ return -ENOMEM;
+ for (offset = 0; offset < num_bytes; offset += blocksize) {
+ ret = read_disk_extent(root, disk_bytenr + offset,
+ blocksize, buffer);
if (ret)
- goto fail;
- }
-
- ins_key.objectid = objectid;
- ins_key.offset = file_pos;
- btrfs_set_key_type(&ins_key, BTRFS_EXTENT_DATA_KEY);
- ret = btrfs_insert_empty_item(trans, root, &path, &ins_key,
- sizeof(*fi));
- if (ret)
- goto fail;
- leaf = path.nodes[0];
- fi = btrfs_item_ptr(leaf, path.slots[0],
- struct btrfs_file_extent_item);
- btrfs_set_file_extent_generation(leaf, fi, trans->transid);
- btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG);
- btrfs_set_file_extent_disk_bytenr(leaf, fi, disk_bytenr);
- 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);
-
- nbytes = btrfs_stack_inode_nbytes(inode) + num_bytes;
- btrfs_set_stack_inode_nbytes(inode, nbytes);
-
- btrfs_release_path(&path);
-
- ins_key.objectid = disk_bytenr;
- ins_key.offset = num_bytes;
- ins_key.type = BTRFS_EXTENT_ITEM_KEY;
-
- ret = btrfs_insert_empty_item(trans, extent_root, &path,
- &ins_key, sizeof(*ei));
- if (ret == 0) {
- leaf = path.nodes[0];
- ei = btrfs_item_ptr(leaf, path.slots[0],
- struct btrfs_extent_item);
-
- btrfs_set_extent_refs(leaf, ei, 0);
- btrfs_set_extent_generation(leaf, ei, 0);
- btrfs_set_extent_flags(leaf, ei, BTRFS_EXTENT_FLAG_DATA);
-
- btrfs_mark_buffer_dirty(leaf);
-
- ret = btrfs_update_block_group(trans, root, disk_bytenr,
- num_bytes, 1, 0);
+ break;
+ ret = btrfs_csum_file_block(trans,
+ root->fs_info->csum_root,
+ disk_bytenr + num_bytes,
+ disk_bytenr + offset,
+ buffer, blocksize);
if (ret)
- goto fail;
- } else if (ret != -EEXIST) {
- goto fail;
+ break;
}
- btrfs_extent_post_op(trans, extent_root);
-
- ret = btrfs_inc_extent_ref(trans, root, disk_bytenr, num_bytes, 0,
- root->root_key.objectid,
- objectid, file_pos);
- if (ret)
- goto fail;
- ret = 0;
-fail:
- btrfs_release_path(&path);
+ free(buffer);
return ret;
}
@@ -478,11 +387,17 @@ static int record_file_blocks(struct btrfs_trans_handle *trans,
u64 file_block, u64 disk_block,
u64 num_blocks, int checksum)
{
+ int ret;
u64 file_pos = file_block * root->sectorsize;
u64 disk_bytenr = disk_block * root->sectorsize;
u64 num_bytes = num_blocks * root->sectorsize;
- return record_file_extent(trans, root, objectid, inode, file_pos,
- disk_bytenr, num_bytes, checksum);
+ ret = btrfs_record_file_extent(trans, root, objectid, inode, file_pos,
+ disk_bytenr, num_bytes);
+
+ if (ret || !checksum)
+ return ret;
+
+ return csum_disk_extent(trans, root, disk_bytenr, num_bytes);
}
struct blk_iterate_data {
@@ -1293,9 +1208,9 @@ static int create_ext2_image(struct btrfs_root *root, ext2_filsys ext2_fs,
sectorsize);
if (ret)
goto fail;
- ret = record_file_extent(trans, root, objectid,
- &btrfs_inode, last_byte,
- key.objectid, sectorsize, 0);
+ ret = btrfs_record_file_extent(trans, root, objectid,
+ &btrfs_inode, last_byte,
+ key.objectid, sectorsize);
if (ret)
goto fail;
}
@@ -1354,8 +1269,9 @@ next:
if (ret)
goto fail;
}
- ret = record_file_extent(trans, root, objectid, &btrfs_inode,
- bytenr, bytenr, num_bytes, 0);
+ ret = btrfs_record_file_extent(trans, root, objectid,
+ &btrfs_inode, bytenr, bytenr,
+ num_bytes);
if (ret)
goto fail;
last_byte = bytenr + num_bytes;
diff --git a/ctree.h b/ctree.h
index 8ca3e76e..2117374b 100644
--- a/ctree.h
+++ b/ctree.h
@@ -2124,6 +2124,11 @@ static inline int btrfs_fs_incompat(struct btrfs_fs_info *fs_info, u64 flag)
btrfs_item_offset_nr(leaf, slot)))
/* extent-tree.c */
+int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ u64 num_bytes, u64 empty_size,
+ u64 hint_byte, u64 search_end,
+ struct btrfs_key *ins, int data);
int btrfs_fix_block_accounting(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
void btrfs_pin_extent(struct btrfs_fs_info *fs_info, u64 bytenr, u64 num_bytes);
@@ -2191,6 +2196,11 @@ int btrfs_make_block_groups(struct btrfs_trans_handle *trans,
int btrfs_update_block_group(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytenr, u64 num,
int alloc, int mark_free);
+int btrfs_record_file_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, u64 objectid,
+ struct btrfs_inode_item *inode,
+ u64 file_pos, u64 disk_bytenr,
+ u64 num_bytes);
/* ctree.c */
int btrfs_del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct btrfs_path *path, int level, int slot);
diff --git a/disk-io.c b/disk-io.c
index b06eb035..ca76c425 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -312,9 +312,9 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
return NULL;
}
-static int write_tree_block(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct extent_buffer *eb)
+int write_and_map_eb(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct extent_buffer *eb)
{
int ret;
int dev_nr;
@@ -322,15 +322,6 @@ static int write_tree_block(struct btrfs_trans_handle *trans,
u64 *raid_map = NULL;
struct btrfs_multi_bio *multi = NULL;
- if (check_tree_block(root, eb))
- BUG();
-
- if (!btrfs_buffer_uptodate(eb, trans->transid))
- BUG();
-
- btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN);
- csum_tree_block(root, eb, 0);
-
dev_nr = 0;
length = eb->len;
ret = btrfs_map_block(&root->fs_info->mapping_tree, WRITE,
@@ -353,6 +344,22 @@ static int write_tree_block(struct btrfs_trans_handle *trans,
return 0;
}
+int write_tree_block(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct extent_buffer *eb)
+{
+ if (check_tree_block(root, eb))
+ BUG();
+
+ if (!btrfs_buffer_uptodate(eb, trans->transid))
+ BUG();
+
+ btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN);
+ csum_tree_block(root, eb, 0);
+
+ return write_and_map_eb(trans, root, eb);
+}
+
int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
u32 stripesize, struct btrfs_root *root,
struct btrfs_fs_info *fs_info, u64 objectid)
diff --git a/disk-io.h b/disk-io.h
index 681ff79b..6f2d4f41 100644
--- a/disk-io.h
+++ b/disk-io.h
@@ -101,6 +101,8 @@ int csum_tree_block_size(struct extent_buffer *buf, u16 csum_sectorsize,
int verify);
int verify_tree_block_csum_silent(struct extent_buffer *buf, u16 csum_size);
int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid);
+int write_and_map_eb(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct extent_buffer *eb);
#endif
/* raid6.c */
diff --git a/extent-tree.c b/extent-tree.c
index 48d06d85..7860d1d9 100644
--- a/extent-tree.c
+++ b/extent-tree.c
@@ -2629,11 +2629,11 @@ error:
return ret;
}
-static int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- u64 num_bytes, u64 empty_size,
- u64 hint_byte, u64 search_end,
- struct btrfs_key *ins, int data)
+int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ u64 num_bytes, u64 empty_size,
+ u64 hint_byte, u64 search_end,
+ struct btrfs_key *ins, int data)
{
int ret;
u64 search_start = 0;
@@ -3488,3 +3488,97 @@ int btrfs_fix_block_accounting(struct btrfs_trans_handle *trans,
btrfs_release_path(&path);
return 0;
}
+
+/*
+ * Record a file extent. Do all the required works, such as inserting
+ * file extent item, inserting extent item and backref item into extent
+ * tree and updating block accounting.
+ */
+int btrfs_record_file_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, u64 objectid,
+ struct btrfs_inode_item *inode,
+ u64 file_pos, u64 disk_bytenr,
+ u64 num_bytes)
+{
+ int ret;
+ struct btrfs_fs_info *info = root->fs_info;
+ struct btrfs_root *extent_root = info->extent_root;
+ struct extent_buffer *leaf;
+ struct btrfs_file_extent_item *fi;
+ struct btrfs_key ins_key;
+ struct btrfs_path path;
+ struct btrfs_extent_item *ei;
+ u64 nbytes;
+
+ if (disk_bytenr == 0) {
+ ret = btrfs_insert_file_extent(trans, root, objectid,
+ file_pos, disk_bytenr,
+ num_bytes, num_bytes);
+ return ret;
+ }
+
+ btrfs_init_path(&path);
+
+ ins_key.objectid = objectid;
+ ins_key.offset = file_pos;
+ btrfs_set_key_type(&ins_key, BTRFS_EXTENT_DATA_KEY);
+ ret = btrfs_insert_empty_item(trans, root, &path, &ins_key,
+ sizeof(*fi));
+ if (ret)
+ goto fail;
+ leaf = path.nodes[0];
+ fi = btrfs_item_ptr(leaf, path.slots[0],
+ struct btrfs_file_extent_item);
+ btrfs_set_file_extent_generation(leaf, fi, trans->transid);
+ btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG);
+ btrfs_set_file_extent_disk_bytenr(leaf, fi, disk_bytenr);
+ 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);
+
+ nbytes = btrfs_stack_inode_nbytes(inode) + num_bytes;
+ btrfs_set_stack_inode_nbytes(inode, nbytes);
+
+ btrfs_release_path(&path);
+
+ ins_key.objectid = disk_bytenr;
+ ins_key.offset = num_bytes;
+ ins_key.type = BTRFS_EXTENT_ITEM_KEY;
+
+ ret = btrfs_insert_empty_item(trans, extent_root, &path,
+ &ins_key, sizeof(*ei));
+ if (ret == 0) {
+ leaf = path.nodes[0];
+ ei = btrfs_item_ptr(leaf, path.slots[0],
+ struct btrfs_extent_item);
+
+ btrfs_set_extent_refs(leaf, ei, 0);
+ btrfs_set_extent_generation(leaf, ei, 0);
+ btrfs_set_extent_flags(leaf, ei, BTRFS_EXTENT_FLAG_DATA);
+
+ btrfs_mark_buffer_dirty(leaf);
+
+ ret = btrfs_update_block_group(trans, root, disk_bytenr,
+ num_bytes, 1, 0);
+ if (ret)
+ goto fail;
+ } else if (ret != -EEXIST) {
+ goto fail;
+ }
+ btrfs_extent_post_op(trans, extent_root);
+
+ ret = btrfs_inc_extent_ref(trans, root, disk_bytenr, num_bytes, 0,
+ root->root_key.objectid,
+ objectid, file_pos);
+ if (ret)
+ goto fail;
+ ret = 0;
+fail:
+ btrfs_release_path(&path);
+ return ret;
+}
diff --git a/mkfs.c b/mkfs.c
index 40da546d..d5767978 100644
--- a/mkfs.c
+++ b/mkfs.c
@@ -567,137 +567,6 @@ static int add_xattr_item(struct btrfs_trans_handle *trans,
return ret;
}
-static int custom_alloc_extent(struct btrfs_root *root, u64 num_bytes,
- u64 hint_byte, struct btrfs_key *ins)
-{
- u64 start;
- u64 end;
- u64 last = hint_byte;
- int ret;
- int wrapped = 0;
- struct btrfs_block_group_cache *cache;
-
- while (1) {
- ret = find_first_extent_bit(&root->fs_info->free_space_cache,
- last, &start, &end, EXTENT_DIRTY);
- if (ret) {
- if (wrapped++ == 0) {
- last = 0;
- continue;
- } else {
- goto fail;
- }
- }
-
- start = max(last, start);
- last = end + 1;
- if (last - start < num_bytes)
- continue;
-
- last = start + num_bytes;
- if (test_range_bit(&root->fs_info->pinned_extents,
- start, last - 1, EXTENT_DIRTY, 0))
- continue;
-
- cache = btrfs_lookup_block_group(root->fs_info, start);
- BUG_ON(!cache);
- if (cache->flags & BTRFS_BLOCK_GROUP_SYSTEM ||
- last > cache->key.objectid + cache->key.offset) {
- last = cache->key.objectid + cache->key.offset;
- continue;
- }
-
- if (cache->flags & (BTRFS_BLOCK_GROUP_SYSTEM |
- BTRFS_BLOCK_GROUP_METADATA)) {
- last = cache->key.objectid + cache->key.offset;
- continue;
- }
-
- clear_extent_dirty(&root->fs_info->free_space_cache,
- start, start + num_bytes - 1, 0);
-
- ins->objectid = start;
- ins->offset = num_bytes;
- ins->type = BTRFS_EXTENT_ITEM_KEY;
- return 0;
- }
-fail:
- fprintf(stderr, "not enough free space\n");
- return -ENOSPC;
-}
-
-static int record_file_extent(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, u64 objectid,
- struct btrfs_inode_item *inode,
- u64 file_pos, u64 disk_bytenr,
- u64 num_bytes)
-{
- int ret;
- struct btrfs_fs_info *info = root->fs_info;
- struct btrfs_root *extent_root = info->extent_root;
- struct extent_buffer *leaf;
- struct btrfs_file_extent_item *fi;
- struct btrfs_key ins_key;
- struct btrfs_path path;
- struct btrfs_extent_item *ei;
-
- btrfs_init_path(&path);
-
- ins_key.objectid = objectid;
- ins_key.offset = 0;
- btrfs_set_key_type(&ins_key, BTRFS_EXTENT_DATA_KEY);
- ret = btrfs_insert_empty_item(trans, root, &path, &ins_key,
- sizeof(*fi));
- if (ret)
- goto fail;
- leaf = path.nodes[0];
- fi = btrfs_item_ptr(leaf, path.slots[0],
- struct btrfs_file_extent_item);
- btrfs_set_file_extent_generation(leaf, fi, trans->transid);
- btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG);
- btrfs_set_file_extent_disk_bytenr(leaf, fi, disk_bytenr);
- 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);
-
- btrfs_release_path(&path);
-
- ins_key.objectid = disk_bytenr;
- ins_key.offset = num_bytes;
- ins_key.type = BTRFS_EXTENT_ITEM_KEY;
-
- ret = btrfs_insert_empty_item(trans, extent_root, &path,
- &ins_key, sizeof(*ei));
- if (ret == 0) {
- leaf = path.nodes[0];
- ei = btrfs_item_ptr(leaf, path.slots[0],
- struct btrfs_extent_item);
-
- btrfs_set_extent_refs(leaf, ei, 0);
- btrfs_set_extent_generation(leaf, ei, trans->transid);
- btrfs_set_extent_flags(leaf, ei, BTRFS_EXTENT_FLAG_DATA);
-
- btrfs_mark_buffer_dirty(leaf);
- ret = btrfs_update_block_group(trans, root, disk_bytenr,
- num_bytes, 1, 0);
- if (ret)
- goto fail;
- } else if (ret != -EEXIST) {
- goto fail;
- }
-
- ret = btrfs_inc_extent_ref(trans, root, disk_bytenr, num_bytes, 0,
- root->root_key.objectid,
- objectid, 0);
-fail:
- btrfs_release_path(&path);
- return ret;
-}
static int add_symbolic_link(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
@@ -735,12 +604,14 @@ static int add_file_items(struct btrfs_trans_handle *trans,
int ret = -1;
ssize_t ret_read;
u64 bytes_read = 0;
- char *buffer = NULL;
struct btrfs_key key;
int blocks;
u32 sectorsize = root->sectorsize;
u64 first_block = 0;
- u64 num_blocks = 0;
+ u64 file_pos = 0;
+ u64 cur_bytes;
+ u64 total_bytes;
+ struct extent_buffer *eb = NULL;
int fd;
fd = open(path_name, O_RDONLY);
@@ -754,7 +625,7 @@ static int add_file_items(struct btrfs_trans_handle *trans,
blocks += 1;
if (st->st_size <= BTRFS_MAX_INLINE_DATA_SIZE(root)) {
- buffer = malloc(st->st_size);
+ char *buffer = malloc(st->st_size);
ret_read = pread64(fd, buffer, st->st_size, bytes_read);
if (ret_read == -1) {
fprintf(stderr, "%s read failed\n", path_name);
@@ -763,57 +634,89 @@ static int add_file_items(struct btrfs_trans_handle *trans,
ret = btrfs_insert_inline_extent(trans, root, objectid, 0,
buffer, st->st_size);
+ free(buffer);
+ goto end;
+ }
+
+ /* round up our st_size to the FS blocksize */
+ total_bytes = (u64)blocks * sectorsize;
+
+ /*
+ * do our IO in extent buffers so it can work
+ * against any raid type
+ */
+ eb = malloc(sizeof(*eb) + sectorsize);
+ if (!eb) {
+ ret = -ENOMEM;
goto end;
}
+ memset(eb, 0, sizeof(*eb) + sectorsize);
+
+again:
- ret = custom_alloc_extent(root, blocks * sectorsize, 0, &key);
+ /*
+ * keep our extent size at 1MB max, this makes it easier to work inside
+ * the tiny block groups created during mkfs
+ */
+ cur_bytes = min(total_bytes, 1024ULL * 1024);
+ ret = btrfs_reserve_extent(trans, root, cur_bytes, 0, 0, (u64)-1,
+ &key, 1);
if (ret)
goto end;
first_block = key.objectid;
bytes_read = 0;
- buffer = malloc(sectorsize);
- do {
- memset(buffer, 0, sectorsize);
- ret_read = pread64(fd, buffer, sectorsize, bytes_read);
+ while (bytes_read < cur_bytes) {
+
+ memset(eb->data, 0, sectorsize);
+
+ ret_read = pread64(fd, eb->data, sectorsize, file_pos + bytes_read);
if (ret_read == -1) {
fprintf(stderr, "%s read failed\n", path_name);
goto end;
}
- ret = pwrite64(out_fd, buffer, sectorsize,
- first_block + bytes_read);
- if (ret != sectorsize) {
- fprintf(stderr, "output file write failed\n");
- goto end;
- }
+ eb->start = first_block + bytes_read;
+ eb->len = sectorsize;
- /* checksum for file data */
+ /*
+ * we're doing the csum before we record the extent, but
+ * that's ok
+ */
ret = btrfs_csum_file_block(trans, root->fs_info->csum_root,
- first_block + (blocks * sectorsize),
- first_block + bytes_read,
- buffer, sectorsize);
+ first_block + bytes_read + sectorsize,
+ first_block + bytes_read,
+ eb->data, sectorsize);
+ if (ret)
+ goto end;
+
+ ret = write_and_map_eb(trans, root, eb);
if (ret) {
- fprintf(stderr, "%s checksum failed\n", path_name);
+ fprintf(stderr, "output file write failed\n");
goto end;
}
- bytes_read += ret_read;
- num_blocks++;
- } while (ret_read == sectorsize);
+ bytes_read += sectorsize;
+ }
- if (num_blocks > 0) {
- ret = record_file_extent(trans, root, objectid, btrfs_inode,
- first_block, first_block,
- blocks * sectorsize);
+ if (bytes_read) {
+ ret = btrfs_record_file_extent(trans, root, objectid, btrfs_inode,
+ file_pos, first_block, cur_bytes);
if (ret)
goto end;
+
}
+ file_pos += cur_bytes;
+ total_bytes -= cur_bytes;
+
+ if (total_bytes)
+ goto again;
+
end:
- if (buffer)
- free(buffer);
+ if (eb)
+ free(eb);
close(fd);
return ret;
}
@@ -1019,6 +922,7 @@ static int create_chunks(struct btrfs_trans_handle *trans,
if (size_of_data < minimum_data_chunk_size)
size_of_data = minimum_data_chunk_size;
+
ret = btrfs_alloc_data_chunk(trans, root->fs_info->extent_root,
&chunk_start, size_of_data, data_type);
BUG_ON(ret);
@@ -1099,6 +1003,7 @@ static u64 size_sourcedir(char *dir_name, u64 sectorsize,
u64 allocated_meta_size = 8 * 1024 * 1024; /* 8MB */
u64 allocated_total_size = 20 * 1024 * 1024; /* 20MB */
u64 num_of_meta_chunks = 0;
+ u64 num_of_data_chunks = 0;
u64 num_of_allocated_meta_chunks =
allocated_meta_size / default_chunk_size;
@@ -1111,6 +1016,9 @@ static u64 size_sourcedir(char *dir_name, u64 sectorsize,
exit(1);
}
+ num_of_data_chunks = (dir_size + default_chunk_size - 1) /
+ default_chunk_size;
+
num_of_meta_chunks = (dir_size / 2) / default_chunk_size;
if (((dir_size / 2) % default_chunk_size) != 0)
num_of_meta_chunks++;
@@ -1119,11 +1027,12 @@ static u64 size_sourcedir(char *dir_name, u64 sectorsize,
else
num_of_meta_chunks -= num_of_allocated_meta_chunks;
- total_size = allocated_total_size + dir_size +
+ total_size = allocated_total_size +
+ (num_of_data_chunks * default_chunk_size) +
(num_of_meta_chunks * default_chunk_size);
*num_of_meta_chunks_ret = num_of_meta_chunks;
-
+ *size_of_data_ret = num_of_data_chunks * default_chunk_size;
return total_size;
}