* [PATCH v2 1/8] erofs-utils: use erofs_atomic_t for inode->i_count
@ 2024-04-22 0:34 Gao Xiang
2024-04-22 0:34 ` [PATCH v2 2/8] erofs-utils: lib: prepare for later deferred work Gao Xiang
` (6 more replies)
0 siblings, 7 replies; 8+ messages in thread
From: Gao Xiang @ 2024-04-22 0:34 UTC (permalink / raw)
To: linux-erofs; +Cc: Gao Xiang
From: Gao Xiang <hsiangkao@linux.alibaba.com>
Since `inode->i_count` can be touched for more than one thread if
multi-threading is enabled.
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
---
patchset v1->v2:
- Fix `--all-fragments` functionality;
- Fix issues pointed out by Yifan.
include/erofs/atomic.h | 10 ++++++++++
include/erofs/inode.h | 2 +-
include/erofs/internal.h | 3 ++-
lib/inode.c | 5 +++--
4 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/include/erofs/atomic.h b/include/erofs/atomic.h
index 214cdb1..f28687e 100644
--- a/include/erofs/atomic.h
+++ b/include/erofs/atomic.h
@@ -25,4 +25,14 @@ __n;})
#define erofs_atomic_test_and_set(ptr) \
__atomic_test_and_set(ptr, __ATOMIC_RELAXED)
+#define erofs_atomic_add_return(ptr, i) \
+ __atomic_add_fetch(ptr, i, __ATOMIC_RELAXED)
+
+#define erofs_atomic_sub_return(ptr, i) \
+ __atomic_sub_fetch(ptr, i, __ATOMIC_RELAXED)
+
+#define erofs_atomic_inc_return(ptr) erofs_atomic_add_return(ptr, 1)
+
+#define erofs_atomic_dec_return(ptr) erofs_atomic_sub_return(ptr, 1)
+
#endif
diff --git a/include/erofs/inode.h b/include/erofs/inode.h
index d5a732a..5d6bc98 100644
--- a/include/erofs/inode.h
+++ b/include/erofs/inode.h
@@ -17,7 +17,7 @@ extern "C"
static inline struct erofs_inode *erofs_igrab(struct erofs_inode *inode)
{
- ++inode->i_count;
+ (void)erofs_atomic_inc_return(&inode->i_count);
return inode;
}
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 4cd2059..f31e548 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -25,6 +25,7 @@ typedef unsigned short umode_t;
#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#endif
+#include "atomic.h"
#ifndef PATH_MAX
#define PATH_MAX 4096 /* # chars in a path name including nul */
@@ -169,7 +170,7 @@ struct erofs_inode {
/* (mkfs.erofs) next pointer for directory dumping */
struct erofs_inode *next_dirwrite;
};
- unsigned int i_count;
+ erofs_atomic_t i_count;
struct erofs_sb_info *sbi;
struct erofs_inode *i_parent;
diff --git a/lib/inode.c b/lib/inode.c
index 7508c74..55969d9 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -129,9 +129,10 @@ struct erofs_inode *erofs_iget_by_nid(erofs_nid_t nid)
unsigned int erofs_iput(struct erofs_inode *inode)
{
struct erofs_dentry *d, *t;
+ unsigned long got = erofs_atomic_dec_return(&inode->i_count);
- if (inode->i_count > 1)
- return --inode->i_count;
+ if (got >= 1)
+ return got;
list_for_each_entry_safe(d, t, &inode->i_subdirs, d_child)
free(d);
--
2.30.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 2/8] erofs-utils: lib: prepare for later deferred work
2024-04-22 0:34 [PATCH v2 1/8] erofs-utils: use erofs_atomic_t for inode->i_count Gao Xiang
@ 2024-04-22 0:34 ` Gao Xiang
2024-04-22 0:34 ` [PATCH v2 3/8] erofs-utils: lib: split out erofs_commit_compressed_file() Gao Xiang
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Gao Xiang @ 2024-04-22 0:34 UTC (permalink / raw)
To: linux-erofs; +Cc: Gao Xiang
From: Gao Xiang <hsiangkao@linux.alibaba.com>
Split out ordered metadata operations and add the following helpers:
- erofs_mkfs_jobfn()
- erofs_mkfs_go()
to handle these mkfs job items for multi-threadding support.
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
---
lib/inode.c | 69 ++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 58 insertions(+), 11 deletions(-)
diff --git a/lib/inode.c b/lib/inode.c
index 55969d9..1ff05e1 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -1133,6 +1133,57 @@ static int erofs_mkfs_handle_nondirectory(struct erofs_inode *inode)
return 0;
}
+enum erofs_mkfs_jobtype { /* ordered job types */
+ EROFS_MKFS_JOB_NDIR,
+ EROFS_MKFS_JOB_DIR,
+ EROFS_MKFS_JOB_DIR_BH,
+};
+
+struct erofs_mkfs_jobitem {
+ enum erofs_mkfs_jobtype type;
+ union {
+ struct erofs_inode *inode;
+ } u;
+};
+
+static int erofs_mkfs_jobfn(struct erofs_mkfs_jobitem *item)
+{
+ struct erofs_inode *inode = item->u.inode;
+ int ret;
+
+ if (item->type == EROFS_MKFS_JOB_NDIR)
+ return erofs_mkfs_handle_nondirectory(inode);
+
+ if (item->type == EROFS_MKFS_JOB_DIR) {
+ ret = erofs_prepare_inode_buffer(inode);
+ if (ret)
+ return ret;
+ inode->bh->op = &erofs_skip_write_bhops;
+ if (IS_ROOT(inode)) /* assign root NID */
+ erofs_fixup_meta_blkaddr(inode);
+ return 0;
+ }
+
+ if (item->type == EROFS_MKFS_JOB_DIR_BH) {
+ erofs_write_dir_file(inode);
+ erofs_write_tail_end(inode);
+ inode->bh->op = &erofs_write_inode_bhops;
+ erofs_iput(inode);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+int erofs_mkfs_go(struct erofs_sb_info *sbi,
+ enum erofs_mkfs_jobtype type, void *elem, int size)
+{
+ struct erofs_mkfs_jobitem item;
+
+ item.type = type;
+ memcpy(&item.u, elem, size);
+ return erofs_mkfs_jobfn(&item);
+}
+
static int erofs_mkfs_handle_directory(struct erofs_inode *dir)
{
DIR *_dir;
@@ -1213,11 +1264,7 @@ static int erofs_mkfs_handle_directory(struct erofs_inode *dir)
else
dir->i_nlink = i_nlink;
- ret = erofs_prepare_inode_buffer(dir);
- if (ret)
- return ret;
- dir->bh->op = &erofs_skip_write_bhops;
- return 0;
+ return erofs_mkfs_go(dir->sbi, EROFS_MKFS_JOB_DIR, &dir, sizeof(dir));
err_closedir:
closedir(_dir);
@@ -1243,7 +1290,8 @@ static int erofs_mkfs_handle_inode(struct erofs_inode *inode)
return ret;
if (!S_ISDIR(inode->i_mode))
- ret = erofs_mkfs_handle_nondirectory(inode);
+ ret = erofs_mkfs_go(inode->sbi, EROFS_MKFS_JOB_NDIR,
+ &inode, sizeof(inode));
else
ret = erofs_mkfs_handle_directory(inode);
erofs_info("file %s dumped (mode %05o)", erofs_fspath(inode->i_srcpath),
@@ -1268,7 +1316,6 @@ struct erofs_inode *erofs_mkfs_build_tree_from_path(const char *path)
err = erofs_mkfs_handle_inode(root);
if (err)
return ERR_PTR(err);
- erofs_fixup_meta_blkaddr(root);
do {
int err;
@@ -1302,10 +1349,10 @@ struct erofs_inode *erofs_mkfs_build_tree_from_path(const char *path)
}
*last = dumpdir; /* fixup the last (or the only) one */
dumpdir = head;
- erofs_write_dir_file(dir);
- erofs_write_tail_end(dir);
- dir->bh->op = &erofs_write_inode_bhops;
- erofs_iput(dir);
+ err = erofs_mkfs_go(dir->sbi, EROFS_MKFS_JOB_DIR_BH,
+ &dir, sizeof(dir));
+ if (err)
+ return ERR_PTR(err);
} while (dumpdir);
return root;
--
2.30.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 3/8] erofs-utils: lib: split out erofs_commit_compressed_file()
2024-04-22 0:34 [PATCH v2 1/8] erofs-utils: use erofs_atomic_t for inode->i_count Gao Xiang
2024-04-22 0:34 ` [PATCH v2 2/8] erofs-utils: lib: prepare for later deferred work Gao Xiang
@ 2024-04-22 0:34 ` Gao Xiang
2024-04-22 0:34 ` [PATCH v2 4/8] erofs-utils: rearrange several fields for multi-threaded mkfs Gao Xiang
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Gao Xiang @ 2024-04-22 0:34 UTC (permalink / raw)
To: linux-erofs; +Cc: Gao Xiang
From: Gao Xiang <hsiangkao@linux.alibaba.com>
Just split out on-disk compressed metadata commit logic.
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
---
lib/compress.c | 191 +++++++++++++++++++++++++++----------------------
1 file changed, 105 insertions(+), 86 deletions(-)
diff --git a/lib/compress.c b/lib/compress.c
index b084446..8ca4033 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -1031,6 +1031,102 @@ int z_erofs_compress_segment(struct z_erofs_compress_sctx *ctx,
return 0;
}
+int erofs_commit_compressed_file(struct z_erofs_compress_ictx *ictx,
+ struct erofs_buffer_head *bh,
+ erofs_blk_t blkaddr,
+ erofs_blk_t compressed_blocks)
+{
+ struct erofs_inode *inode = ictx->inode;
+ struct erofs_sb_info *sbi = inode->sbi;
+ unsigned int legacymetasize;
+ u8 *compressmeta;
+ int ret;
+
+ /* fall back to no compression mode */
+ DBG_BUGON(compressed_blocks < !!inode->idata_size);
+ compressed_blocks -= !!inode->idata_size;
+
+ compressmeta = malloc(BLK_ROUND_UP(sbi, inode->i_size) *
+ sizeof(struct z_erofs_lcluster_index) +
+ Z_EROFS_LEGACY_MAP_HEADER_SIZE);
+ if (!compressmeta) {
+ ret = -ENOMEM;
+ goto err_free_idata;
+ }
+ ictx->metacur = compressmeta + Z_EROFS_LEGACY_MAP_HEADER_SIZE;
+ z_erofs_write_indexes(ictx);
+
+ legacymetasize = ictx->metacur - compressmeta;
+ /* estimate if data compression saves space or not */
+ if (!inode->fragment_size &&
+ compressed_blocks * erofs_blksiz(sbi) + inode->idata_size +
+ legacymetasize >= inode->i_size) {
+ z_erofs_dedupe_commit(true);
+ ret = -ENOSPC;
+ goto err_free_meta;
+ }
+ z_erofs_dedupe_commit(false);
+ z_erofs_write_mapheader(inode, compressmeta);
+
+ if (!ictx->fragemitted)
+ sbi->saved_by_deduplication += inode->fragment_size;
+
+ /* if the entire file is a fragment, a simplified form is used. */
+ if (inode->i_size <= inode->fragment_size) {
+ DBG_BUGON(inode->i_size < inode->fragment_size);
+ DBG_BUGON(inode->fragmentoff >> 63);
+ *(__le64 *)compressmeta =
+ cpu_to_le64(inode->fragmentoff | 1ULL << 63);
+ inode->datalayout = EROFS_INODE_COMPRESSED_FULL;
+ legacymetasize = Z_EROFS_LEGACY_MAP_HEADER_SIZE;
+ }
+
+ if (compressed_blocks) {
+ ret = erofs_bh_balloon(bh, erofs_pos(sbi, compressed_blocks));
+ DBG_BUGON(ret != erofs_blksiz(sbi));
+ } else {
+ if (!cfg.c_fragments && !cfg.c_dedupe)
+ DBG_BUGON(!inode->idata_size);
+ }
+
+ erofs_info("compressed %s (%llu bytes) into %u blocks",
+ inode->i_srcpath, (unsigned long long)inode->i_size,
+ compressed_blocks);
+
+ if (inode->idata_size) {
+ bh->op = &erofs_skip_write_bhops;
+ inode->bh_data = bh;
+ } else {
+ erofs_bdrop(bh, false);
+ }
+
+ inode->u.i_blocks = compressed_blocks;
+
+ if (inode->datalayout == EROFS_INODE_COMPRESSED_FULL) {
+ inode->extent_isize = legacymetasize;
+ } else {
+ ret = z_erofs_convert_to_compacted_format(inode, blkaddr,
+ legacymetasize,
+ compressmeta);
+ DBG_BUGON(ret);
+ }
+ inode->compressmeta = compressmeta;
+ if (!erofs_is_packed_inode(inode))
+ erofs_droid_blocklist_write(inode, blkaddr, compressed_blocks);
+ return 0;
+
+err_free_meta:
+ free(compressmeta);
+ inode->compressmeta = NULL;
+err_free_idata:
+ if (inode->idata) {
+ free(inode->idata);
+ inode->idata = NULL;
+ }
+ erofs_bdrop(bh, true); /* revoke buffer */
+ return ret;
+}
+
#ifdef EROFS_MT_ENABLED
void *z_erofs_mt_wq_tls_alloc(struct erofs_workqueue *wq, void *ptr)
{
@@ -1260,23 +1356,9 @@ int erofs_write_compressed_file(struct erofs_inode *inode, int fd, u64 fpos)
static struct z_erofs_compress_sctx sctx;
struct erofs_compress_cfg *ccfg;
erofs_blk_t blkaddr, compressed_blocks = 0;
- unsigned int legacymetasize;
int ret;
bool ismt = false;
struct erofs_sb_info *sbi = inode->sbi;
- u8 *compressmeta = malloc(BLK_ROUND_UP(sbi, inode->i_size) *
- sizeof(struct z_erofs_lcluster_index) +
- Z_EROFS_LEGACY_MAP_HEADER_SIZE);
-
- if (!compressmeta)
- return -ENOMEM;
-
- /* allocate main data buffer */
- bh = erofs_balloc(DATA, 0, 0, 0);
- if (IS_ERR(bh)) {
- ret = PTR_ERR(bh);
- goto err_free_meta;
- }
/* initialize per-file compression setting */
inode->z_advise = 0;
@@ -1321,20 +1403,24 @@ int erofs_write_compressed_file(struct erofs_inode *inode, int fd, u64 fpos)
if (cfg.c_fragments && !erofs_is_packed_inode(inode)) {
ret = z_erofs_fragments_dedupe(inode, fd, &ctx.tof_chksum);
if (ret < 0)
- goto err_bdrop;
+ return ret;
}
- blkaddr = erofs_mapbh(bh->block); /* start_blkaddr */
ctx.inode = inode;
ctx.fd = fd;
ctx.fpos = fpos;
- ctx.metacur = compressmeta + Z_EROFS_LEGACY_MAP_HEADER_SIZE;
init_list_head(&ctx.extents);
ctx.fix_dedupedfrag = false;
ctx.fragemitted = false;
sctx = (struct z_erofs_compress_sctx) { .ictx = &ctx, };
init_list_head(&sctx.extents);
+ /* allocate main data buffer */
+ bh = erofs_balloc(DATA, 0, 0, 0);
+ if (IS_ERR(bh))
+ return PTR_ERR(bh);
+ blkaddr = erofs_mapbh(bh->block); /* start_blkaddr */
+
if (cfg.c_all_fragments && !erofs_is_packed_inode(inode) &&
!inode->fragment_size) {
ret = z_erofs_pack_file_from_fd(inode, fd, ctx.tof_chksum);
@@ -1363,10 +1449,6 @@ int erofs_write_compressed_file(struct erofs_inode *inode, int fd, u64 fpos)
compressed_blocks = sctx.blkaddr - blkaddr;
}
- /* fall back to no compression mode */
- DBG_BUGON(compressed_blocks < !!inode->idata_size);
- compressed_blocks -= !!inode->idata_size;
-
/* generate an extent for the deduplicated fragment */
if (inode->fragment_size && !ctx.fragemitted) {
struct z_erofs_extent_item *ei;
@@ -1388,80 +1470,17 @@ int erofs_write_compressed_file(struct erofs_inode *inode, int fd, u64 fpos)
z_erofs_commit_extent(&sctx, ei);
}
z_erofs_fragments_commit(inode);
-
if (!ismt)
list_splice_tail(&sctx.extents, &ctx.extents);
- z_erofs_write_indexes(&ctx);
- legacymetasize = ctx.metacur - compressmeta;
- /* estimate if data compression saves space or not */
- if (!inode->fragment_size &&
- compressed_blocks * erofs_blksiz(sbi) + inode->idata_size +
- legacymetasize >= inode->i_size) {
- z_erofs_dedupe_commit(true);
- ret = -ENOSPC;
- goto err_free_idata;
- }
- z_erofs_dedupe_commit(false);
- z_erofs_write_mapheader(inode, compressmeta);
-
- if (!ctx.fragemitted)
- sbi->saved_by_deduplication += inode->fragment_size;
-
- /* if the entire file is a fragment, a simplified form is used. */
- if (inode->i_size <= inode->fragment_size) {
- DBG_BUGON(inode->i_size < inode->fragment_size);
- DBG_BUGON(inode->fragmentoff >> 63);
- *(__le64 *)compressmeta =
- cpu_to_le64(inode->fragmentoff | 1ULL << 63);
- inode->datalayout = EROFS_INODE_COMPRESSED_FULL;
- legacymetasize = Z_EROFS_LEGACY_MAP_HEADER_SIZE;
- }
-
- if (compressed_blocks) {
- ret = erofs_bh_balloon(bh, erofs_pos(sbi, compressed_blocks));
- DBG_BUGON(ret != erofs_blksiz(sbi));
- } else {
- if (!cfg.c_fragments && !cfg.c_dedupe)
- DBG_BUGON(!inode->idata_size);
- }
-
- erofs_info("compressed %s (%llu bytes) into %u blocks",
- inode->i_srcpath, (unsigned long long)inode->i_size,
- compressed_blocks);
-
- if (inode->idata_size) {
- bh->op = &erofs_skip_write_bhops;
- inode->bh_data = bh;
- } else {
- erofs_bdrop(bh, false);
- }
-
- inode->u.i_blocks = compressed_blocks;
-
- if (inode->datalayout == EROFS_INODE_COMPRESSED_FULL) {
- inode->extent_isize = legacymetasize;
- } else {
- ret = z_erofs_convert_to_compacted_format(inode, blkaddr,
- legacymetasize,
- compressmeta);
- DBG_BUGON(ret);
- }
- inode->compressmeta = compressmeta;
- if (!erofs_is_packed_inode(inode))
- erofs_droid_blocklist_write(inode, blkaddr, compressed_blocks);
- return 0;
-
+ return erofs_commit_compressed_file(&ctx, bh, blkaddr,
+ compressed_blocks);
err_free_idata:
if (inode->idata) {
free(inode->idata);
inode->idata = NULL;
}
-err_bdrop:
erofs_bdrop(bh, true); /* revoke buffer */
-err_free_meta:
- free(compressmeta);
- inode->compressmeta = NULL;
return ret;
}
--
2.30.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 4/8] erofs-utils: rearrange several fields for multi-threaded mkfs
2024-04-22 0:34 [PATCH v2 1/8] erofs-utils: use erofs_atomic_t for inode->i_count Gao Xiang
2024-04-22 0:34 ` [PATCH v2 2/8] erofs-utils: lib: prepare for later deferred work Gao Xiang
2024-04-22 0:34 ` [PATCH v2 3/8] erofs-utils: lib: split out erofs_commit_compressed_file() Gao Xiang
@ 2024-04-22 0:34 ` Gao Xiang
2024-04-22 0:34 ` [PATCH v2 5/8] erofs-utils: lib: split up z_erofs_mt_compress() Gao Xiang
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Gao Xiang @ 2024-04-22 0:34 UTC (permalink / raw)
To: linux-erofs; +Cc: Gao Xiang
From: Gao Xiang <hsiangkao@linux.alibaba.com>
They should be located in `struct z_erofs_compress_ictx`.
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
---
lib/compress.c | 57 +++++++++++++++++++++++++++-----------------------
1 file changed, 31 insertions(+), 26 deletions(-)
diff --git a/lib/compress.c b/lib/compress.c
index 8ca4033..0bc5426 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -38,6 +38,7 @@ struct z_erofs_extent_item {
struct z_erofs_compress_ictx { /* inode context */
struct erofs_inode *inode;
+ struct erofs_compress_cfg *ccfg;
int fd;
u64 fpos;
@@ -49,6 +50,14 @@ struct z_erofs_compress_ictx { /* inode context */
u8 *metacur;
struct list_head extents;
u16 clusterofs;
+
+ int seg_num;
+
+#if EROFS_MT_ENABLED
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ int nfini;
+#endif
};
struct z_erofs_compress_sctx { /* segment context */
@@ -68,7 +77,7 @@ struct z_erofs_compress_sctx { /* segment context */
erofs_blk_t blkaddr; /* pointing to the next blkaddr */
u16 clusterofs;
- int seg_num, seg_idx;
+ int seg_idx;
void *membuf;
erofs_off_t memoff;
@@ -98,9 +107,6 @@ struct erofs_compress_work {
static struct {
struct erofs_workqueue wq;
struct erofs_compress_work *idle;
- pthread_mutex_t mutex;
- pthread_cond_t cond;
- int nfini;
} z_erofs_mt_ctrl;
#endif
@@ -513,7 +519,7 @@ static int __z_erofs_compress_one(struct z_erofs_compress_sctx *ctx,
struct erofs_compress *const h = ctx->chandle;
unsigned int len = ctx->tail - ctx->head;
bool is_packed_inode = erofs_is_packed_inode(inode);
- bool tsg = (ctx->seg_idx + 1 >= ctx->seg_num), final = !ctx->remaining;
+ bool tsg = (ctx->seg_idx + 1 >= ictx->seg_num), final = !ctx->remaining;
bool may_packing = (cfg.c_fragments && tsg && final &&
!is_packed_inode && !z_erofs_mt_enabled);
bool may_inline = (cfg.c_ztailpacking && tsg && final && !may_packing);
@@ -1201,7 +1207,8 @@ void z_erofs_mt_workfn(struct erofs_work *work, void *tlsp)
struct erofs_compress_work *cwork = (struct erofs_compress_work *)work;
struct erofs_compress_wq_tls *tls = tlsp;
struct z_erofs_compress_sctx *sctx = &cwork->ctx;
- struct erofs_inode *inode = sctx->ictx->inode;
+ struct z_erofs_compress_ictx *ictx = sctx->ictx;
+ struct erofs_inode *inode = ictx->inode;
struct erofs_sb_info *sbi = inode->sbi;
int ret = 0;
@@ -1228,10 +1235,10 @@ void z_erofs_mt_workfn(struct erofs_work *work, void *tlsp)
out:
cwork->errcode = ret;
- pthread_mutex_lock(&z_erofs_mt_ctrl.mutex);
- ++z_erofs_mt_ctrl.nfini;
- pthread_cond_signal(&z_erofs_mt_ctrl.cond);
- pthread_mutex_unlock(&z_erofs_mt_ctrl.mutex);
+ pthread_mutex_lock(&ictx->mutex);
+ ++ictx->nfini;
+ pthread_cond_signal(&ictx->cond);
+ pthread_mutex_unlock(&ictx->mutex);
}
int z_erofs_merge_segment(struct z_erofs_compress_ictx *ictx,
@@ -1268,16 +1275,19 @@ int z_erofs_merge_segment(struct z_erofs_compress_ictx *ictx,
}
int z_erofs_mt_compress(struct z_erofs_compress_ictx *ictx,
- struct erofs_compress_cfg *ccfg,
erofs_blk_t blkaddr,
erofs_blk_t *compressed_blocks)
{
struct erofs_compress_work *cur, *head = NULL, **last = &head;
+ struct erofs_compress_cfg *ccfg = ictx->ccfg;
struct erofs_inode *inode = ictx->inode;
int nsegs = DIV_ROUND_UP(inode->i_size, cfg.c_segment_size);
int ret, i;
- z_erofs_mt_ctrl.nfini = 0;
+ ictx->seg_num = nsegs;
+ ictx->nfini = 0;
+ pthread_mutex_init(&ictx->mutex, NULL);
+ pthread_cond_init(&ictx->cond, NULL);
for (i = 0; i < nsegs; i++) {
if (z_erofs_mt_ctrl.idle) {
@@ -1294,7 +1304,6 @@ int z_erofs_mt_compress(struct z_erofs_compress_ictx *ictx,
cur->ctx = (struct z_erofs_compress_sctx) {
.ictx = ictx,
- .seg_num = nsegs,
.seg_idx = i,
.pivot = &dummy_pivot,
};
@@ -1316,11 +1325,10 @@ int z_erofs_mt_compress(struct z_erofs_compress_ictx *ictx,
erofs_queue_work(&z_erofs_mt_ctrl.wq, &cur->work);
}
- pthread_mutex_lock(&z_erofs_mt_ctrl.mutex);
- while (z_erofs_mt_ctrl.nfini != nsegs)
- pthread_cond_wait(&z_erofs_mt_ctrl.cond,
- &z_erofs_mt_ctrl.mutex);
- pthread_mutex_unlock(&z_erofs_mt_ctrl.mutex);
+ pthread_mutex_lock(&ictx->mutex);
+ while (ictx->nfini < ictx->seg_num)
+ pthread_cond_wait(&ictx->cond, &ictx->mutex);
+ pthread_mutex_unlock(&ictx->mutex);
ret = 0;
while (head) {
@@ -1354,7 +1362,6 @@ int erofs_write_compressed_file(struct erofs_inode *inode, int fd, u64 fpos)
struct erofs_buffer_head *bh;
static struct z_erofs_compress_ictx ctx;
static struct z_erofs_compress_sctx sctx;
- struct erofs_compress_cfg *ccfg;
erofs_blk_t blkaddr, compressed_blocks = 0;
int ret;
bool ismt = false;
@@ -1389,8 +1396,8 @@ int erofs_write_compressed_file(struct erofs_inode *inode, int fd, u64 fpos)
}
}
#endif
- ccfg = &erofs_ccfg[inode->z_algorithmtype[0]];
- inode->z_algorithmtype[0] = ccfg[0].algorithmtype;
+ ctx.ccfg = &erofs_ccfg[inode->z_algorithmtype[0]];
+ inode->z_algorithmtype[0] = ctx.ccfg->algorithmtype;
inode->z_algorithmtype[1] = 0;
inode->idata_size = 0;
@@ -1429,16 +1436,16 @@ int erofs_write_compressed_file(struct erofs_inode *inode, int fd, u64 fpos)
#ifdef EROFS_MT_ENABLED
} else if (z_erofs_mt_enabled && inode->i_size > cfg.c_segment_size) {
ismt = true;
- ret = z_erofs_mt_compress(&ctx, ccfg, blkaddr, &compressed_blocks);
+ ret = z_erofs_mt_compress(&ctx, blkaddr, &compressed_blocks);
if (ret)
goto err_free_idata;
#endif
} else {
+ ctx.seg_num = 1;
sctx.queue = g_queue;
sctx.destbuf = NULL;
- sctx.chandle = &ccfg->handle;
+ sctx.chandle = &ctx.ccfg->handle;
sctx.remaining = inode->i_size - inode->fragment_size;
- sctx.seg_num = 1;
sctx.seg_idx = 0;
sctx.pivot = &dummy_pivot;
sctx.pclustersize = z_erofs_get_max_pclustersize(inode);
@@ -1628,8 +1635,6 @@ int z_erofs_compress_init(struct erofs_sb_info *sbi, struct erofs_buffer_head *s
z_erofs_mt_enabled = false;
#ifdef EROFS_MT_ENABLED
if (cfg.c_mt_workers > 1) {
- pthread_mutex_init(&z_erofs_mt_ctrl.mutex, NULL);
- pthread_cond_init(&z_erofs_mt_ctrl.cond, NULL);
ret = erofs_alloc_workqueue(&z_erofs_mt_ctrl.wq,
cfg.c_mt_workers,
cfg.c_mt_workers << 2,
--
2.30.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 5/8] erofs-utils: lib: split up z_erofs_mt_compress()
2024-04-22 0:34 [PATCH v2 1/8] erofs-utils: use erofs_atomic_t for inode->i_count Gao Xiang
` (2 preceding siblings ...)
2024-04-22 0:34 ` [PATCH v2 4/8] erofs-utils: rearrange several fields for multi-threaded mkfs Gao Xiang
@ 2024-04-22 0:34 ` Gao Xiang
2024-04-22 0:34 ` [PATCH v2 6/8] erofs-utils: mkfs: prepare inter-file multi-threaded compression Gao Xiang
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Gao Xiang @ 2024-04-22 0:34 UTC (permalink / raw)
To: linux-erofs; +Cc: Gao Xiang
From: Gao Xiang <hsiangkao@linux.alibaba.com>
The on-disk compressed data write will be moved into a new function
erofs_mt_write_compressed_file().
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
---
lib/compress.c | 162 ++++++++++++++++++++++++++++---------------------
1 file changed, 93 insertions(+), 69 deletions(-)
diff --git a/lib/compress.c b/lib/compress.c
index 0bc5426..4ac4760 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -57,6 +57,8 @@ struct z_erofs_compress_ictx { /* inode context */
pthread_mutex_t mutex;
pthread_cond_t cond;
int nfini;
+
+ struct erofs_compress_work *mtworks;
#endif
};
@@ -530,11 +532,11 @@ static int __z_erofs_compress_one(struct z_erofs_compress_sctx *ctx,
if (len <= ctx->pclustersize) {
if (!final || !len)
return 1;
+ if (inode->fragment_size && !ictx->fix_dedupedfrag) {
+ ctx->pclustersize = roundup(len, blksz);
+ goto fix_dedupedfrag;
+ }
if (may_packing) {
- if (inode->fragment_size && !ictx->fix_dedupedfrag) {
- ctx->pclustersize = roundup(len, blksz);
- goto fix_dedupedfrag;
- }
e->length = len;
goto frag_packing;
}
@@ -1034,6 +1036,26 @@ int z_erofs_compress_segment(struct z_erofs_compress_sctx *ctx,
z_erofs_commit_extent(ctx, ctx->pivot);
ctx->pivot = NULL;
}
+
+ /* generate an extra extent for the deduplicated fragment */
+ if (ctx->seg_idx >= ictx->seg_num - 1 &&
+ ictx->inode->fragment_size && !ictx->fragemitted) {
+ struct z_erofs_extent_item *ei;
+
+ ei = malloc(sizeof(*ei));
+ if (!ei)
+ return -ENOMEM;
+
+ ei->e = (struct z_erofs_inmem_extent) {
+ .length = ictx->inode->fragment_size,
+ .compressedblks = 0,
+ .raw = false,
+ .partial = false,
+ .blkaddr = ctx->blkaddr,
+ };
+ init_list_head(&ei->list);
+ z_erofs_commit_extent(ctx, ei);
+ }
return 0;
}
@@ -1048,6 +1070,8 @@ int erofs_commit_compressed_file(struct z_erofs_compress_ictx *ictx,
u8 *compressmeta;
int ret;
+ z_erofs_fragments_commit(inode);
+
/* fall back to no compression mode */
DBG_BUGON(compressed_blocks < !!inode->idata_size);
compressed_blocks -= !!inode->idata_size;
@@ -1125,11 +1149,11 @@ err_free_meta:
free(compressmeta);
inode->compressmeta = NULL;
err_free_idata:
+ erofs_bdrop(bh, true); /* revoke buffer */
if (inode->idata) {
free(inode->idata);
inode->idata = NULL;
}
- erofs_bdrop(bh, true); /* revoke buffer */
return ret;
}
@@ -1260,7 +1284,7 @@ int z_erofs_merge_segment(struct z_erofs_compress_ictx *ictx,
sctx->blkaddr += ei->e.compressedblks;
/* skip write data but leave blkaddr for inline fallback */
- if (ei->e.inlined)
+ if (ei->e.inlined || !ei->e.compressedblks)
continue;
ret2 = blk_write(sbi, sctx->membuf + blkoff * erofs_blksiz(sbi),
ei->e.blkaddr, ei->e.compressedblks);
@@ -1274,15 +1298,13 @@ int z_erofs_merge_segment(struct z_erofs_compress_ictx *ictx,
return ret;
}
-int z_erofs_mt_compress(struct z_erofs_compress_ictx *ictx,
- erofs_blk_t blkaddr,
- erofs_blk_t *compressed_blocks)
+int z_erofs_mt_compress(struct z_erofs_compress_ictx *ictx)
{
struct erofs_compress_work *cur, *head = NULL, **last = &head;
struct erofs_compress_cfg *ccfg = ictx->ccfg;
struct erofs_inode *inode = ictx->inode;
int nsegs = DIV_ROUND_UP(inode->i_size, cfg.c_segment_size);
- int ret, i;
+ int i;
ictx->seg_num = nsegs;
ictx->nfini = 0;
@@ -1290,11 +1312,12 @@ int z_erofs_mt_compress(struct z_erofs_compress_ictx *ictx,
pthread_cond_init(&ictx->cond, NULL);
for (i = 0; i < nsegs; i++) {
- if (z_erofs_mt_ctrl.idle) {
- cur = z_erofs_mt_ctrl.idle;
+ cur = z_erofs_mt_ctrl.idle;
+ if (cur) {
z_erofs_mt_ctrl.idle = cur->next;
cur->next = NULL;
- } else {
+ }
+ if (!cur) {
cur = calloc(1, sizeof(*cur));
if (!cur)
return -ENOMEM;
@@ -1324,14 +1347,31 @@ int z_erofs_mt_compress(struct z_erofs_compress_ictx *ictx,
cur->work.fn = z_erofs_mt_workfn;
erofs_queue_work(&z_erofs_mt_ctrl.wq, &cur->work);
}
+ ictx->mtworks = head;
+ return 0;
+}
+
+int erofs_mt_write_compressed_file(struct z_erofs_compress_ictx *ictx)
+{
+ struct erofs_buffer_head *bh = NULL;
+ struct erofs_compress_work *head = ictx->mtworks, *cur;
+ erofs_blk_t blkaddr, compressed_blocks = 0;
+ int ret;
pthread_mutex_lock(&ictx->mutex);
while (ictx->nfini < ictx->seg_num)
pthread_cond_wait(&ictx->cond, &ictx->mutex);
pthread_mutex_unlock(&ictx->mutex);
+ bh = erofs_balloc(DATA, 0, 0, 0);
+ if (IS_ERR(bh))
+ return PTR_ERR(bh);
+
+ DBG_BUGON(!head);
+ blkaddr = erofs_mapbh(bh->block);
+
ret = 0;
- while (head) {
+ do {
cur = head;
head = cur->next;
@@ -1345,14 +1385,19 @@ int z_erofs_mt_compress(struct z_erofs_compress_ictx *ictx,
if (ret2)
ret = ret2;
- *compressed_blocks += cur->ctx.blkaddr - blkaddr;
+ compressed_blocks += cur->ctx.blkaddr - blkaddr;
blkaddr = cur->ctx.blkaddr;
}
cur->next = z_erofs_mt_ctrl.idle;
z_erofs_mt_ctrl.idle = cur;
- }
- return ret;
+ } while(head);
+
+ if (ret)
+ return ret;
+
+ return erofs_commit_compressed_file(ictx, bh,
+ blkaddr - compressed_blocks, compressed_blocks);
}
#endif
@@ -1362,9 +1407,8 @@ int erofs_write_compressed_file(struct erofs_inode *inode, int fd, u64 fpos)
struct erofs_buffer_head *bh;
static struct z_erofs_compress_ictx ctx;
static struct z_erofs_compress_sctx sctx;
- erofs_blk_t blkaddr, compressed_blocks = 0;
+ erofs_blk_t blkaddr;
int ret;
- bool ismt = false;
struct erofs_sb_info *sbi = inode->sbi;
/* initialize per-file compression setting */
@@ -1419,14 +1463,6 @@ int erofs_write_compressed_file(struct erofs_inode *inode, int fd, u64 fpos)
init_list_head(&ctx.extents);
ctx.fix_dedupedfrag = false;
ctx.fragemitted = false;
- sctx = (struct z_erofs_compress_sctx) { .ictx = &ctx, };
- init_list_head(&sctx.extents);
-
- /* allocate main data buffer */
- bh = erofs_balloc(DATA, 0, 0, 0);
- if (IS_ERR(bh))
- return PTR_ERR(bh);
- blkaddr = erofs_mapbh(bh->block); /* start_blkaddr */
if (cfg.c_all_fragments && !erofs_is_packed_inode(inode) &&
!inode->fragment_size) {
@@ -1434,60 +1470,48 @@ int erofs_write_compressed_file(struct erofs_inode *inode, int fd, u64 fpos)
if (ret)
goto err_free_idata;
#ifdef EROFS_MT_ENABLED
- } else if (z_erofs_mt_enabled && inode->i_size > cfg.c_segment_size) {
- ismt = true;
- ret = z_erofs_mt_compress(&ctx, blkaddr, &compressed_blocks);
+ } else if (z_erofs_mt_enabled) {
+ ret = z_erofs_mt_compress(&ctx);
if (ret)
goto err_free_idata;
+ return erofs_mt_write_compressed_file(&ctx);
#endif
- } else {
- ctx.seg_num = 1;
- sctx.queue = g_queue;
- sctx.destbuf = NULL;
- sctx.chandle = &ctx.ccfg->handle;
- sctx.remaining = inode->i_size - inode->fragment_size;
- sctx.seg_idx = 0;
- sctx.pivot = &dummy_pivot;
- sctx.pclustersize = z_erofs_get_max_pclustersize(inode);
-
- ret = z_erofs_compress_segment(&sctx, -1, blkaddr);
- if (ret)
- goto err_free_idata;
- compressed_blocks = sctx.blkaddr - blkaddr;
}
-
- /* generate an extent for the deduplicated fragment */
- if (inode->fragment_size && !ctx.fragemitted) {
- struct z_erofs_extent_item *ei;
-
- ei = malloc(sizeof(*ei));
- if (!ei) {
- ret = -ENOMEM;
- goto err_free_idata;
- }
-
- ei->e = (struct z_erofs_inmem_extent) {
- .length = inode->fragment_size,
- .compressedblks = 0,
- .raw = false,
- .partial = false,
- .blkaddr = sctx.blkaddr,
- };
- init_list_head(&ei->list);
- z_erofs_commit_extent(&sctx, ei);
+ /* allocate main data buffer */
+ bh = erofs_balloc(DATA, 0, 0, 0);
+ if (IS_ERR(bh)) {
+ ret = PTR_ERR(bh);
+ goto err_free_idata;
}
- z_erofs_fragments_commit(inode);
- if (!ismt)
- list_splice_tail(&sctx.extents, &ctx.extents);
+ blkaddr = erofs_mapbh(bh->block); /* start_blkaddr */
+
+ ctx.seg_num = 1;
+ sctx = (struct z_erofs_compress_sctx) {
+ .ictx = &ctx,
+ .queue = g_queue,
+ .chandle = &ctx.ccfg->handle,
+ .remaining = inode->i_size - inode->fragment_size,
+ .seg_idx = 0,
+ .pivot = &dummy_pivot,
+ .pclustersize = z_erofs_get_max_pclustersize(inode),
+ };
+ init_list_head(&sctx.extents);
+
+ ret = z_erofs_compress_segment(&sctx, -1, blkaddr);
+ if (ret)
+ goto err_bdrop;
+ list_splice_tail(&sctx.extents, &ctx.extents);
return erofs_commit_compressed_file(&ctx, bh, blkaddr,
- compressed_blocks);
+ sctx.blkaddr - blkaddr);
+
+err_bdrop:
+ erofs_bdrop(bh, true); /* revoke buffer */
err_free_idata:
if (inode->idata) {
free(inode->idata);
inode->idata = NULL;
}
- erofs_bdrop(bh, true); /* revoke buffer */
return ret;
}
--
2.30.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 6/8] erofs-utils: mkfs: prepare inter-file multi-threaded compression
2024-04-22 0:34 [PATCH v2 1/8] erofs-utils: use erofs_atomic_t for inode->i_count Gao Xiang
` (3 preceding siblings ...)
2024-04-22 0:34 ` [PATCH v2 5/8] erofs-utils: lib: split up z_erofs_mt_compress() Gao Xiang
@ 2024-04-22 0:34 ` Gao Xiang
2024-04-22 0:34 ` [PATCH v2 7/8] erofs-utils: lib: introduce non-directory jobitem context Gao Xiang
2024-04-22 0:34 ` [PATCH v2 8/8] erofs-utils: mkfs: enable inter-file multi-threaded compression Gao Xiang
6 siblings, 0 replies; 8+ messages in thread
From: Gao Xiang @ 2024-04-22 0:34 UTC (permalink / raw)
To: linux-erofs; +Cc: Gao Xiang, Yifan Zhao, Tong Xin
From: Yifan Zhao <zhaoyifan@sjtu.edu.cn>
This patch separates the compression process into two parts.
Specifically, erofs_begin_compressed_file() will trigger compression.
erofs_write_compressed_file() will wait for the compression finish and
write compressed (meta)data.
Note that it's possible that erofs_begin_compressed_file() and
erofs_write_compressed_file() run with different threads even the
global inode context is used, thus add another synchronization point.
Signed-off-by: Yifan Zhao <zhaoyifan@sjtu.edu.cn>
Co-authored-by: Tong Xin <xin_tong@sjtu.edu.cn>
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
---
include/erofs/compress.h | 5 +-
lib/compress.c | 138 ++++++++++++++++++++++++++++-----------
lib/inode.c | 17 ++++-
3 files changed, 118 insertions(+), 42 deletions(-)
diff --git a/include/erofs/compress.h b/include/erofs/compress.h
index 871db54..c9831a7 100644
--- a/include/erofs/compress.h
+++ b/include/erofs/compress.h
@@ -17,8 +17,11 @@ extern "C"
#define EROFS_CONFIG_COMPR_MAX_SZ (4000 * 1024)
#define Z_EROFS_COMPR_QUEUE_SZ (EROFS_CONFIG_COMPR_MAX_SZ * 2)
+struct z_erofs_compress_ictx;
+
void z_erofs_drop_inline_pcluster(struct erofs_inode *inode);
-int erofs_write_compressed_file(struct erofs_inode *inode, int fd, u64 fpos);
+void *erofs_begin_compressed_file(struct erofs_inode *inode, int fd, u64 fpos);
+int erofs_write_compressed_file(struct z_erofs_compress_ictx *ictx);
int z_erofs_compress_init(struct erofs_sb_info *sbi,
struct erofs_buffer_head *bh);
diff --git a/lib/compress.c b/lib/compress.c
index 4ac4760..7fef698 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -109,6 +109,7 @@ struct erofs_compress_work {
static struct {
struct erofs_workqueue wq;
struct erofs_compress_work *idle;
+ pthread_mutex_t mutex;
} z_erofs_mt_ctrl;
#endif
@@ -1312,11 +1313,13 @@ int z_erofs_mt_compress(struct z_erofs_compress_ictx *ictx)
pthread_cond_init(&ictx->cond, NULL);
for (i = 0; i < nsegs; i++) {
+ pthread_mutex_lock(&z_erofs_mt_ctrl.mutex);
cur = z_erofs_mt_ctrl.idle;
if (cur) {
z_erofs_mt_ctrl.idle = cur->next;
cur->next = NULL;
}
+ pthread_mutex_unlock(&z_erofs_mt_ctrl.mutex);
if (!cur) {
cur = calloc(1, sizeof(*cur));
if (!cur)
@@ -1364,8 +1367,10 @@ int erofs_mt_write_compressed_file(struct z_erofs_compress_ictx *ictx)
pthread_mutex_unlock(&ictx->mutex);
bh = erofs_balloc(DATA, 0, 0, 0);
- if (IS_ERR(bh))
- return PTR_ERR(bh);
+ if (IS_ERR(bh)) {
+ ret = PTR_ERR(bh);
+ goto out;
+ }
DBG_BUGON(!head);
blkaddr = erofs_mapbh(bh->block);
@@ -1389,27 +1394,31 @@ int erofs_mt_write_compressed_file(struct z_erofs_compress_ictx *ictx)
blkaddr = cur->ctx.blkaddr;
}
+ pthread_mutex_lock(&z_erofs_mt_ctrl.mutex);
cur->next = z_erofs_mt_ctrl.idle;
z_erofs_mt_ctrl.idle = cur;
- } while(head);
+ pthread_mutex_unlock(&z_erofs_mt_ctrl.mutex);
+ } while (head);
if (ret)
- return ret;
-
- return erofs_commit_compressed_file(ictx, bh,
+ goto out;
+ ret = erofs_commit_compressed_file(ictx, bh,
blkaddr - compressed_blocks, compressed_blocks);
+
+out:
+ close(ictx->fd);
+ free(ictx);
+ return ret;
}
#endif
-int erofs_write_compressed_file(struct erofs_inode *inode, int fd, u64 fpos)
+static struct z_erofs_compress_ictx g_ictx;
+
+void *erofs_begin_compressed_file(struct erofs_inode *inode, int fd, u64 fpos)
{
- static u8 g_queue[Z_EROFS_COMPR_QUEUE_SZ];
- struct erofs_buffer_head *bh;
- static struct z_erofs_compress_ictx ctx;
- static struct z_erofs_compress_sctx sctx;
- erofs_blk_t blkaddr;
- int ret;
struct erofs_sb_info *sbi = inode->sbi;
+ struct z_erofs_compress_ictx *ictx;
+ int ret;
/* initialize per-file compression setting */
inode->z_advise = 0;
@@ -1440,43 +1449,87 @@ int erofs_write_compressed_file(struct erofs_inode *inode, int fd, u64 fpos)
}
}
#endif
- ctx.ccfg = &erofs_ccfg[inode->z_algorithmtype[0]];
- inode->z_algorithmtype[0] = ctx.ccfg->algorithmtype;
- inode->z_algorithmtype[1] = 0;
-
inode->idata_size = 0;
inode->fragment_size = 0;
+ if (z_erofs_mt_enabled) {
+ ictx = malloc(sizeof(*ictx));
+ if (!ictx)
+ return ERR_PTR(-ENOMEM);
+ ictx->fd = dup(fd);
+ } else {
+#ifdef EROFS_MT_ENABLED
+ pthread_mutex_lock(&g_ictx.mutex);
+ if (g_ictx.seg_num)
+ pthread_cond_wait(&g_ictx.cond, &g_ictx.mutex);
+ g_ictx.seg_num = 1;
+ pthread_mutex_unlock(&g_ictx.mutex);
+#endif
+ ictx = &g_ictx;
+ ictx->fd = fd;
+ }
+
+ ictx->ccfg = &erofs_ccfg[inode->z_algorithmtype[0]];
+ inode->z_algorithmtype[0] = ictx->ccfg->algorithmtype;
+ inode->z_algorithmtype[1] = 0;
+
/*
* Handle tails in advance to avoid writing duplicated
* parts into the packed inode.
*/
if (cfg.c_fragments && !erofs_is_packed_inode(inode)) {
- ret = z_erofs_fragments_dedupe(inode, fd, &ctx.tof_chksum);
+ ret = z_erofs_fragments_dedupe(inode, fd, &ictx->tof_chksum);
if (ret < 0)
- return ret;
+ goto err_free_ictx;
}
- ctx.inode = inode;
- ctx.fd = fd;
- ctx.fpos = fpos;
- init_list_head(&ctx.extents);
- ctx.fix_dedupedfrag = false;
- ctx.fragemitted = false;
+ ictx->inode = inode;
+ ictx->fpos = fpos;
+ init_list_head(&ictx->extents);
+ ictx->fix_dedupedfrag = false;
+ ictx->fragemitted = false;
if (cfg.c_all_fragments && !erofs_is_packed_inode(inode) &&
!inode->fragment_size) {
- ret = z_erofs_pack_file_from_fd(inode, fd, ctx.tof_chksum);
+ ret = z_erofs_pack_file_from_fd(inode, fd, ictx->tof_chksum);
if (ret)
goto err_free_idata;
+ }
#ifdef EROFS_MT_ENABLED
- } else if (z_erofs_mt_enabled) {
- ret = z_erofs_mt_compress(&ctx);
+ if (ictx != &g_ictx) {
+ ret = z_erofs_mt_compress(ictx);
if (ret)
goto err_free_idata;
- return erofs_mt_write_compressed_file(&ctx);
+ }
#endif
+ return ictx;
+
+err_free_idata:
+ if (inode->idata) {
+ free(inode->idata);
+ inode->idata = NULL;
}
+err_free_ictx:
+ if (ictx != &g_ictx)
+ free(ictx);
+ return ERR_PTR(ret);
+}
+
+int erofs_write_compressed_file(struct z_erofs_compress_ictx *ictx)
+{
+ static u8 g_queue[Z_EROFS_COMPR_QUEUE_SZ];
+ struct erofs_buffer_head *bh;
+ static struct z_erofs_compress_sctx sctx;
+ struct erofs_compress_cfg *ccfg = ictx->ccfg;
+ struct erofs_inode *inode = ictx->inode;
+ erofs_blk_t blkaddr;
+ int ret;
+
+#ifdef EROFS_MT_ENABLED
+ if (ictx != &g_ictx)
+ return erofs_mt_write_compressed_file(ictx);
+#endif
+
/* allocate main data buffer */
bh = erofs_balloc(DATA, 0, 0, 0);
if (IS_ERR(bh)) {
@@ -1485,11 +1538,11 @@ int erofs_write_compressed_file(struct erofs_inode *inode, int fd, u64 fpos)
}
blkaddr = erofs_mapbh(bh->block); /* start_blkaddr */
- ctx.seg_num = 1;
+ ictx->seg_num = 1;
sctx = (struct z_erofs_compress_sctx) {
- .ictx = &ctx,
+ .ictx = ictx,
.queue = g_queue,
- .chandle = &ctx.ccfg->handle,
+ .chandle = &ccfg->handle,
.remaining = inode->i_size - inode->fragment_size,
.seg_idx = 0,
.pivot = &dummy_pivot,
@@ -1499,19 +1552,26 @@ int erofs_write_compressed_file(struct erofs_inode *inode, int fd, u64 fpos)
ret = z_erofs_compress_segment(&sctx, -1, blkaddr);
if (ret)
- goto err_bdrop;
- list_splice_tail(&sctx.extents, &ctx.extents);
+ goto err_free_idata;
- return erofs_commit_compressed_file(&ctx, bh, blkaddr,
- sctx.blkaddr - blkaddr);
+ list_splice_tail(&sctx.extents, &ictx->extents);
+ ret = erofs_commit_compressed_file(ictx, bh, blkaddr,
+ sctx.blkaddr - blkaddr);
+ goto out;
-err_bdrop:
- erofs_bdrop(bh, true); /* revoke buffer */
err_free_idata:
+ erofs_bdrop(bh, true); /* revoke buffer */
if (inode->idata) {
free(inode->idata);
inode->idata = NULL;
}
+out:
+#ifdef EROFS_MT_ENABLED
+ pthread_mutex_lock(&ictx->mutex);
+ ictx->seg_num = 0;
+ pthread_cond_signal(&ictx->cond);
+ pthread_mutex_unlock(&ictx->mutex);
+#endif
return ret;
}
@@ -1666,6 +1726,8 @@ int z_erofs_compress_init(struct erofs_sb_info *sbi, struct erofs_buffer_head *s
z_erofs_mt_wq_tls_free);
z_erofs_mt_enabled = !ret;
}
+ pthread_mutex_init(&g_ictx.mutex, NULL);
+ pthread_cond_init(&g_ictx.cond, NULL);
#endif
return 0;
}
diff --git a/lib/inode.c b/lib/inode.c
index 1ff05e1..0d044f4 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -499,10 +499,15 @@ int erofs_write_file(struct erofs_inode *inode, int fd, u64 fpos)
DBG_BUGON(!inode->i_size);
if (cfg.c_compr_opts[0].alg && erofs_file_is_compressible(inode)) {
+ void *ictx;
int ret;
- ret = erofs_write_compressed_file(inode, fd, fpos);
- if (!ret || ret != -ENOSPC)
+ ictx = erofs_begin_compressed_file(inode, fd, fpos);
+ if (IS_ERR(ictx))
+ return PTR_ERR(ictx);
+
+ ret = erofs_write_compressed_file(ictx);
+ if (ret != -ENOSPC)
return ret;
if (lseek(fd, fpos, SEEK_SET) < 0)
@@ -1362,6 +1367,7 @@ struct erofs_inode *erofs_mkfs_build_special_from_fd(int fd, const char *name)
{
struct stat st;
struct erofs_inode *inode;
+ void *ictx;
int ret;
ret = lseek(fd, 0, SEEK_SET);
@@ -1392,7 +1398,12 @@ struct erofs_inode *erofs_mkfs_build_special_from_fd(int fd, const char *name)
inode->nid = inode->sbi->packed_nid;
}
- ret = erofs_write_compressed_file(inode, fd, 0);
+ ictx = erofs_begin_compressed_file(inode, fd, 0);
+ if (IS_ERR(ictx))
+ return ERR_CAST(ictx);
+
+ DBG_BUGON(!ictx);
+ ret = erofs_write_compressed_file(ictx);
if (ret == -ENOSPC) {
ret = lseek(fd, 0, SEEK_SET);
if (ret < 0)
--
2.30.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 7/8] erofs-utils: lib: introduce non-directory jobitem context
2024-04-22 0:34 [PATCH v2 1/8] erofs-utils: use erofs_atomic_t for inode->i_count Gao Xiang
` (4 preceding siblings ...)
2024-04-22 0:34 ` [PATCH v2 6/8] erofs-utils: mkfs: prepare inter-file multi-threaded compression Gao Xiang
@ 2024-04-22 0:34 ` Gao Xiang
2024-04-22 0:34 ` [PATCH v2 8/8] erofs-utils: mkfs: enable inter-file multi-threaded compression Gao Xiang
6 siblings, 0 replies; 8+ messages in thread
From: Gao Xiang @ 2024-04-22 0:34 UTC (permalink / raw)
To: linux-erofs; +Cc: Gao Xiang
From: Gao Xiang <hsiangkao@linux.alibaba.com>
It will describe EROFS_MKFS_JOB_NDIR defer work. Also, start
compression before queueing EROFS_MKFS_JOB_NDIR.
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
---
lib/inode.c | 62 +++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 51 insertions(+), 11 deletions(-)
diff --git a/lib/inode.c b/lib/inode.c
index 0d044f4..6ad66bf 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -1107,8 +1107,36 @@ static void erofs_fixup_meta_blkaddr(struct erofs_inode *rootdir)
rootdir->nid = (off - meta_offset) >> EROFS_ISLOTBITS;
}
-static int erofs_mkfs_handle_nondirectory(struct erofs_inode *inode)
+struct erofs_mkfs_job_ndir_ctx {
+ struct erofs_inode *inode;
+ void *ictx;
+ int fd;
+};
+
+static int erofs_mkfs_job_write_file(struct erofs_mkfs_job_ndir_ctx *ctx)
{
+ struct erofs_inode *inode = ctx->inode;
+ int ret;
+
+ if (ctx->ictx) {
+ ret = erofs_write_compressed_file(ctx->ictx);
+ if (ret != -ENOSPC)
+ goto out;
+ if (lseek(ctx->fd, 0, SEEK_SET) < 0) {
+ ret = -errno;
+ goto out;
+ }
+ }
+ /* fallback to all data uncompressed */
+ ret = erofs_write_unencoded_file(inode, ctx->fd, 0);
+out:
+ close(ctx->fd);
+ return ret;
+}
+
+static int erofs_mkfs_handle_nondirectory(struct erofs_mkfs_job_ndir_ctx *ctx)
+{
+ struct erofs_inode *inode = ctx->inode;
int ret = 0;
if (S_ISLNK(inode->i_mode)) {
@@ -1124,12 +1152,7 @@ static int erofs_mkfs_handle_nondirectory(struct erofs_inode *inode)
ret = erofs_write_file_from_buffer(inode, symlink);
free(symlink);
} else if (inode->i_size) {
- int fd = open(inode->i_srcpath, O_RDONLY | O_BINARY);
-
- if (fd < 0)
- return -errno;
- ret = erofs_write_file(inode, fd, 0);
- close(fd);
+ ret = erofs_mkfs_job_write_file(ctx);
}
if (ret)
return ret;
@@ -1148,6 +1171,7 @@ struct erofs_mkfs_jobitem {
enum erofs_mkfs_jobtype type;
union {
struct erofs_inode *inode;
+ struct erofs_mkfs_job_ndir_ctx ndir;
} u;
};
@@ -1157,7 +1181,7 @@ static int erofs_mkfs_jobfn(struct erofs_mkfs_jobitem *item)
int ret;
if (item->type == EROFS_MKFS_JOB_NDIR)
- return erofs_mkfs_handle_nondirectory(inode);
+ return erofs_mkfs_handle_nondirectory(&item->u.ndir);
if (item->type == EROFS_MKFS_JOB_DIR) {
ret = erofs_prepare_inode_buffer(inode);
@@ -1294,11 +1318,27 @@ static int erofs_mkfs_handle_inode(struct erofs_inode *inode)
if (ret < 0)
return ret;
- if (!S_ISDIR(inode->i_mode))
+ if (!S_ISDIR(inode->i_mode)) {
+ struct erofs_mkfs_job_ndir_ctx ctx = { .inode = inode };
+
+ if (!S_ISLNK(inode->i_mode) && inode->i_size) {
+ ctx.fd = open(inode->i_srcpath, O_RDONLY | O_BINARY);
+ if (ctx.fd < 0)
+ return -errno;
+
+ if (cfg.c_compr_opts[0].alg &&
+ erofs_file_is_compressible(inode)) {
+ ctx.ictx = erofs_begin_compressed_file(inode,
+ ctx.fd, 0);
+ if (IS_ERR(ctx.ictx))
+ return PTR_ERR(ctx.ictx);
+ }
+ }
ret = erofs_mkfs_go(inode->sbi, EROFS_MKFS_JOB_NDIR,
- &inode, sizeof(inode));
- else
+ &ctx, sizeof(ctx));
+ } else {
ret = erofs_mkfs_handle_directory(inode);
+ }
erofs_info("file %s dumped (mode %05o)", erofs_fspath(inode->i_srcpath),
inode->i_mode);
return ret;
--
2.30.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 8/8] erofs-utils: mkfs: enable inter-file multi-threaded compression
2024-04-22 0:34 [PATCH v2 1/8] erofs-utils: use erofs_atomic_t for inode->i_count Gao Xiang
` (5 preceding siblings ...)
2024-04-22 0:34 ` [PATCH v2 7/8] erofs-utils: lib: introduce non-directory jobitem context Gao Xiang
@ 2024-04-22 0:34 ` Gao Xiang
6 siblings, 0 replies; 8+ messages in thread
From: Gao Xiang @ 2024-04-22 0:34 UTC (permalink / raw)
To: linux-erofs; +Cc: Gao Xiang
From: Gao Xiang <hsiangkao@linux.alibaba.com>
Dispatch deferred ops in another per-sb worker thread. Note that
deferred ops are strictly FIFOed.
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
---
include/erofs/internal.h | 6 ++
lib/inode.c | 119 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 123 insertions(+), 2 deletions(-)
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index f31e548..ecbbdf6 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -71,6 +71,7 @@ struct erofs_xattr_prefix_item {
#define EROFS_PACKED_NID_UNALLOCATED -1
+struct erofs_mkfs_dfops;
struct erofs_sb_info {
struct erofs_device_info *devs;
char *devname;
@@ -124,6 +125,11 @@ struct erofs_sb_info {
struct list_head list;
u64 saved_by_deduplication;
+
+#ifdef EROFS_MT_ENABLED
+ pthread_t dfops_worker;
+ struct erofs_mkfs_dfops *mkfs_dfops;
+#endif
};
/* make sure that any user of the erofs headers has atleast 64bit off_t type */
diff --git a/lib/inode.c b/lib/inode.c
index 6ad66bf..cf22bbe 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -1165,6 +1165,7 @@ enum erofs_mkfs_jobtype { /* ordered job types */
EROFS_MKFS_JOB_NDIR,
EROFS_MKFS_JOB_DIR,
EROFS_MKFS_JOB_DIR_BH,
+ EROFS_MKFS_JOB_MAX
};
struct erofs_mkfs_jobitem {
@@ -1203,6 +1204,73 @@ static int erofs_mkfs_jobfn(struct erofs_mkfs_jobitem *item)
return -EINVAL;
}
+#ifdef EROFS_MT_ENABLED
+
+struct erofs_mkfs_dfops {
+ pthread_t worker;
+ pthread_mutex_t lock;
+ pthread_cond_t full, empty;
+ struct erofs_mkfs_jobitem *queue;
+ unsigned int entries, head, tail;
+};
+
+#define EROFS_MT_QUEUE_SIZE 128
+
+void *erofs_mkfs_pop_jobitem(struct erofs_mkfs_dfops *q)
+{
+ struct erofs_mkfs_jobitem *item;
+
+ pthread_mutex_lock(&q->lock);
+ while (q->head == q->tail)
+ pthread_cond_wait(&q->empty, &q->lock);
+
+ item = q->queue + q->head;
+ q->head = (q->head + 1) & (q->entries - 1);
+
+ pthread_cond_signal(&q->full);
+ pthread_mutex_unlock(&q->lock);
+ return item;
+}
+
+void *z_erofs_mt_dfops_worker(void *arg)
+{
+ struct erofs_sb_info *sbi = arg;
+ int ret = 0;
+
+ while (1) {
+ struct erofs_mkfs_jobitem *item;
+
+ item = erofs_mkfs_pop_jobitem(sbi->mkfs_dfops);
+ if (item->type >= EROFS_MKFS_JOB_MAX)
+ break;
+ ret = erofs_mkfs_jobfn(item);
+ if (ret)
+ break;
+ }
+ pthread_exit((void *)(uintptr_t)ret);
+}
+
+int erofs_mkfs_go(struct erofs_sb_info *sbi,
+ enum erofs_mkfs_jobtype type, void *elem, int size)
+{
+ struct erofs_mkfs_jobitem *item;
+ struct erofs_mkfs_dfops *q = sbi->mkfs_dfops;
+
+ pthread_mutex_lock(&q->lock);
+
+ while (((q->tail + 1) & (q->entries - 1)) == q->head)
+ pthread_cond_wait(&q->full, &q->lock);
+
+ item = q->queue + q->tail;
+ item->type = type;
+ memcpy(&item->u, elem, size);
+ q->tail = (q->tail + 1) & (q->entries - 1);
+
+ pthread_cond_signal(&q->empty);
+ pthread_mutex_unlock(&q->lock);
+ return 0;
+}
+#else
int erofs_mkfs_go(struct erofs_sb_info *sbi,
enum erofs_mkfs_jobtype type, void *elem, int size)
{
@@ -1212,6 +1280,7 @@ int erofs_mkfs_go(struct erofs_sb_info *sbi,
memcpy(&item.u, elem, size);
return erofs_mkfs_jobfn(&item);
}
+#endif
static int erofs_mkfs_handle_directory(struct erofs_inode *dir)
{
@@ -1344,7 +1413,11 @@ static int erofs_mkfs_handle_inode(struct erofs_inode *inode)
return ret;
}
-struct erofs_inode *erofs_mkfs_build_tree_from_path(const char *path)
+#ifndef EROFS_MT_ENABLED
+#define __erofs_mkfs_build_tree_from_path erofs_mkfs_build_tree_from_path
+#endif
+
+struct erofs_inode *__erofs_mkfs_build_tree_from_path(const char *path)
{
struct erofs_inode *root, *dumpdir;
int err;
@@ -1399,10 +1472,52 @@ struct erofs_inode *erofs_mkfs_build_tree_from_path(const char *path)
if (err)
return ERR_PTR(err);
} while (dumpdir);
-
return root;
}
+#ifdef EROFS_MT_ENABLED
+struct erofs_inode *erofs_mkfs_build_tree_from_path(const char *path)
+{
+ struct erofs_mkfs_dfops *q;
+ struct erofs_inode *root;
+ int err;
+
+ q = malloc(sizeof(*q));
+ if (!q)
+ return ERR_PTR(-ENOMEM);
+
+ q->entries = EROFS_MT_QUEUE_SIZE;
+ q->queue = malloc(q->entries * sizeof(*q->queue));
+ if (!q->queue) {
+ free(q);
+ return ERR_PTR(-ENOMEM);
+ }
+ pthread_mutex_init(&q->lock, NULL);
+ pthread_cond_init(&q->empty, NULL);
+ pthread_cond_init(&q->full, NULL);
+
+ q->head = 0;
+ q->tail = 0;
+ sbi.mkfs_dfops = q;
+ err = pthread_create(&sbi.dfops_worker, NULL,
+ z_erofs_mt_dfops_worker, &sbi);
+ if (err)
+ goto fail;
+ root = __erofs_mkfs_build_tree_from_path(path);
+
+ erofs_mkfs_go(&sbi, ~0, NULL, 0);
+ err = pthread_join(sbi.dfops_worker, NULL);
+
+fail:
+ pthread_cond_destroy(&q->empty);
+ pthread_cond_destroy(&q->full);
+ pthread_mutex_destroy(&q->lock);
+ free(q->queue);
+ free(q);
+ return err ? ERR_PTR(err) : root;
+}
+#endif
+
struct erofs_inode *erofs_mkfs_build_special_from_fd(int fd, const char *name)
{
struct stat st;
--
2.30.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
end of thread, other threads:[~2024-04-22 0:36 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-04-22 0:34 [PATCH v2 1/8] erofs-utils: use erofs_atomic_t for inode->i_count Gao Xiang
2024-04-22 0:34 ` [PATCH v2 2/8] erofs-utils: lib: prepare for later deferred work Gao Xiang
2024-04-22 0:34 ` [PATCH v2 3/8] erofs-utils: lib: split out erofs_commit_compressed_file() Gao Xiang
2024-04-22 0:34 ` [PATCH v2 4/8] erofs-utils: rearrange several fields for multi-threaded mkfs Gao Xiang
2024-04-22 0:34 ` [PATCH v2 5/8] erofs-utils: lib: split up z_erofs_mt_compress() Gao Xiang
2024-04-22 0:34 ` [PATCH v2 6/8] erofs-utils: mkfs: prepare inter-file multi-threaded compression Gao Xiang
2024-04-22 0:34 ` [PATCH v2 7/8] erofs-utils: lib: introduce non-directory jobitem context Gao Xiang
2024-04-22 0:34 ` [PATCH v2 8/8] erofs-utils: mkfs: enable inter-file multi-threaded compression Gao Xiang
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.