aboutsummaryrefslogtreecommitdiff
path: root/lib/sqfs/block_processor
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2020-05-23 17:21:24 +0200
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2020-05-23 17:30:29 +0200
commitd9e5895829a2c20e7624326ce391f0e56762b855 (patch)
treec7ba4fa9322d5038da8e53aef200a47d01558604 /lib/sqfs/block_processor
parent4587a56466f0c55d91ece168f0dc872f81a8196c (diff)
block processor: move the block consolidation to the worker thread
Instead of merging fragments into the fragment block inside the process_completed_fragment function, store a linked list of fragments in the fragment block and do the actual merging (several memcpy calls totaling of up to 1M of data in worst case) in the worker thread instead of the locked, serial path. Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib/sqfs/block_processor')
-rw-r--r--lib/sqfs/block_processor/common.c40
-rw-r--r--lib/sqfs/block_processor/internal.h8
-rw-r--r--lib/sqfs/block_processor/serial.c47
3 files changed, 71 insertions, 24 deletions
diff --git a/lib/sqfs/block_processor/common.c b/lib/sqfs/block_processor/common.c
index b8f2760..c3363f9 100644
--- a/lib/sqfs/block_processor/common.c
+++ b/lib/sqfs/block_processor/common.c
@@ -63,6 +63,18 @@ static sqfs_block_t *get_new_block(sqfs_block_processor_t *proc)
static void release_old_block(sqfs_block_processor_t *proc, sqfs_block_t *blk)
{
+ sqfs_block_t *it;
+
+ if (blk->flags & SQFS_BLK_FRAGMENT_BLOCK && blk->frag_list != NULL) {
+ it = blk->frag_list;
+
+ while (it->next != NULL)
+ it = it->next;
+
+ it->next = proc->free_list;
+ proc->free_list = blk->frag_list;
+ }
+
blk->next = proc->free_list;
proc->free_list = blk;
}
@@ -120,11 +132,29 @@ static bool is_zero_block(unsigned char *ptr, size_t size)
int block_processor_do_block(sqfs_block_t *block, sqfs_compressor_t *cmp,
sqfs_u8 *scratch, size_t scratch_size)
{
+ sqfs_block_t *it;
+ size_t offset;
sqfs_s32 ret;
if (block->size == 0)
return 0;
+ if (block->flags & SQFS_BLK_FRAGMENT_BLOCK) {
+ offset = block->size;
+
+ for (it = block->frag_list; it != NULL; it = it->next) {
+ assert(offset >= it->size);
+ offset -= it->size;
+
+ memcpy(block->data + offset, it->data, it->size);
+
+ block->flags |= (it->flags & SQFS_BLK_DONT_COMPRESS);
+
+ sqfs_inode_set_frag_location(*(it->inode),
+ block->index, offset);
+ }
+ }
+
if (is_zero_block(block->data, block->size)) {
block->flags |= SQFS_BLK_IS_SPARSE;
return 0;
@@ -211,17 +241,11 @@ int process_completed_fragment(sqfs_block_processor_t *proc, sqfs_block_t *frag,
if (err)
goto fail;
- sqfs_inode_set_frag_location(*(frag->inode), proc->frag_block->index,
- proc->frag_block->size);
+ frag->next = proc->frag_block->frag_list;
+ proc->frag_block->frag_list = frag;
- memcpy(proc->frag_block->data + proc->frag_block->size,
- frag->data, frag->size);
-
- proc->frag_block->flags |= (frag->flags & SQFS_BLK_DONT_COMPRESS);
proc->frag_block->size += frag->size;
proc->stats.actual_frag_count += 1;
-
- release_old_block(proc, frag);
return 0;
fail:
release_old_block(proc, frag);
diff --git a/lib/sqfs/block_processor/internal.h b/lib/sqfs/block_processor/internal.h
index eff5374..775671c 100644
--- a/lib/sqfs/block_processor/internal.h
+++ b/lib/sqfs/block_processor/internal.h
@@ -22,6 +22,7 @@
#include <string.h>
#include <stdlib.h>
+#include <assert.h>
typedef struct sqfs_block_t {
struct sqfs_block_t *next;
@@ -33,9 +34,14 @@ typedef struct sqfs_block_t {
sqfs_u32 size;
sqfs_u32 checksum;
- /* Data block index within the inode or fragment block index. */
+ /* For data blocks: index within the inode.
+ For fragment fragment blocks: fragment table index. */
sqfs_u32 index;
+ /* For fragment blocks: list of fragments to
+ consolidate in reverse order. */
+ struct sqfs_block_t *frag_list;
+
sqfs_u8 data[];
} sqfs_block_t;
diff --git a/lib/sqfs/block_processor/serial.c b/lib/sqfs/block_processor/serial.c
index a9190b1..54edda1 100644
--- a/lib/sqfs/block_processor/serial.c
+++ b/lib/sqfs/block_processor/serial.c
@@ -13,19 +13,29 @@ typedef struct {
sqfs_u8 scratch[];
} serial_block_processor_t;
-static void block_processor_destroy(sqfs_object_t *obj)
+static void free_block_list(sqfs_block_t *list)
{
- sqfs_block_processor_t *proc = (sqfs_block_processor_t *)obj;
sqfs_block_t *blk;
- while (proc->free_list != NULL) {
- blk = proc->free_list;
- proc->free_list = blk->next;
+ while (list != NULL) {
+ blk = list;
+ list = blk->next;
free(blk);
}
+}
+
+static void block_processor_destroy(sqfs_object_t *obj)
+{
+ sqfs_block_processor_t *proc = (sqfs_block_processor_t *)obj;
+
+ free_block_list(proc->free_list);
+
+ if (proc->frag_block != NULL) {
+ free_block_list(proc->frag_block->frag_list);
+ free(proc->frag_block);
+ }
free(proc->blk_current);
- free(proc->frag_block);
free(proc);
}
@@ -57,16 +67,14 @@ int append_to_work_queue(sqfs_block_processor_t *proc, sqfs_block_t *block)
serial_block_processor_t *sproc = (serial_block_processor_t *)proc;
sqfs_block_t *fragblk = NULL;
- if (sproc->status != 0) {
- free(block);
- return sproc->status;
- }
+ if (sproc->status != 0)
+ goto fail;
sproc->status = block_processor_do_block(block, proc->cmp,
sproc->scratch,
proc->max_block_size);
if (sproc->status != 0)
- return sproc->status;
+ goto fail;
if (block->flags & SQFS_BLK_IS_FRAGMENT) {
sproc->status = process_completed_fragment(proc, block,
@@ -74,15 +82,20 @@ int append_to_work_queue(sqfs_block_processor_t *proc, sqfs_block_t *block)
if (fragblk == NULL)
return sproc->status;
- sproc->status = block_processor_do_block(fragblk, proc->cmp,
+ block = fragblk;
+ sproc->status = block_processor_do_block(block, proc->cmp,
sproc->scratch,
proc->max_block_size);
if (sproc->status != 0)
- return sproc->status;
+ goto fail;
}
sproc->status = process_completed_block(proc, block);
return sproc->status;
+fail:
+ free_block_list(block->frag_list);
+ free(block);
+ return sproc->status;
}
int sqfs_block_processor_sync(sqfs_block_processor_t *proc)
@@ -104,9 +117,13 @@ int sqfs_block_processor_finish(sqfs_block_processor_t *proc)
goto fail;
sproc->status = process_completed_block(proc, proc->frag_block);
+ proc->frag_block = NULL;
return sproc->status;
fail:
- free(proc->frag_block);
- proc->frag_block = NULL;
+ if (proc->frag_block != NULL) {
+ free_block_list(proc->frag_block->frag_list);
+ free(proc->frag_block);
+ proc->frag_block = NULL;
+ }
return sproc->status;
}