aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJin Qian <jinqian@google.com>2016-12-19 10:53:20 -0800
committerJin Qian <jinqian@google.com>2016-12-19 13:53:07 -0800
commit6ef6efab23203e967625160e6af4140954e15e91 (patch)
tree54f4b9dfe9eacc7e367e0050d48f65424f037587 /lib
parent7fe49140ef755e98607a67199971c01ed6a96930 (diff)
downloade2fsprogs-6ef6efab23203e967625160e6af4140954e15e91.tar.gz
libext2fs: merge contiguous data blocks when writing to sparse file
Sparse IO manager allocates one block at a time. This creates many blocks in sparse file even though most of them are contiguous. As a result, fastboot is extremely slow writing that many blocks. Merging contiguous blocks reduces block count and flash time significantly. Change-Id: I211312d24d7423c7f160ee501fe8b62ddf14a847
Diffstat (limited to 'lib')
-rw-r--r--lib/ext2fs/sparse_io.c47
1 files changed, 42 insertions, 5 deletions
diff --git a/lib/ext2fs/sparse_io.c b/lib/ext2fs/sparse_io.c
index 77bc4219..b6168cb7 100644
--- a/lib/ext2fs/sparse_io.c
+++ b/lib/ext2fs/sparse_io.c
@@ -251,6 +251,35 @@ static errcode_t sparsefd_open(const char *name, int flags, io_channel *channel)
return retval;
}
+static errcode_t sparse_merge_blocks(struct sparse_map *sm, uint64_t start,
+ uint64_t num)
+{
+ char *buf;
+ uint64_t i;
+ unsigned int block_size = sm->block_size;
+ errcode_t retval = 0;
+
+ buf = calloc(num, block_size);
+ if (!buf) {
+ fprintf(stderr, "failed to alloc %lu\n", num * block_size);
+ return EXT2_ET_NO_MEMORY;
+ }
+
+ for (i = 0; i < num; i++) {
+ memcpy(buf + i * block_size, sm->blocks[start + i] , block_size);
+ free(sm->blocks[start + i]);
+ sm->blocks[start + i] = NULL;
+ }
+
+ /* free_sparse_blocks will release this buf. */
+ sm->blocks[start] = buf;
+
+ retval = sparse_file_add_data(sm->sparse_file, sm->blocks[start],
+ block_size * num, start);
+
+ return retval;
+}
+
static errcode_t sparse_close_channel(io_channel channel)
{
uint64_t i;
@@ -258,12 +287,20 @@ static errcode_t sparse_close_channel(io_channel channel)
struct sparse_map *sm = channel->private_data;
if (sm->sparse_file) {
+ int64_t chunk_start = (sm->blocks[0] == NULL) ? -1 : 0;
for (i = 0; i < sm->blocks_count; ++i) {
- if (!sm->blocks[i])
- continue;
- retval = sparse_file_add_data(sm->sparse_file,
- sm->blocks[i],
- sm->block_size, i);
+ if (!sm->blocks[i] && chunk_start != -1) {
+ retval = sparse_merge_blocks(sm, chunk_start, i - chunk_start);
+ chunk_start = -1;
+ } else if (sm->blocks[i] && chunk_start == -1) {
+ chunk_start = i;
+ }
+ if (retval)
+ goto ret;
+ }
+ if (chunk_start != -1) {
+ retval = sparse_merge_blocks(sm, chunk_start,
+ sm->blocks_count - chunk_start);
if (retval)
goto ret;
}