diff options
author | Jin Qian <jinqian@google.com> | 2016-12-19 10:53:20 -0800 |
---|---|---|
committer | Jin Qian <jinqian@google.com> | 2016-12-19 13:53:07 -0800 |
commit | 6ef6efab23203e967625160e6af4140954e15e91 (patch) | |
tree | 54f4b9dfe9eacc7e367e0050d48f65424f037587 /lib | |
parent | 7fe49140ef755e98607a67199971c01ed6a96930 (diff) | |
download | e2fsprogs-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.c | 47 |
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; } |