[PATCH 1/3] erofs-utils: determine the [un]compressed data block is inline or not early
Noboru Asai
asai at sijam.com
Thu Apr 18 15:52:29 AEST 2024
Introducing erofs_get_inodesize function and erofs_get_lowest_offset function,
we can determine the [un]compressed data block is inline or not before
executing z_erofs_merge_segment function. It enable the following,
* skip the redundant write for ztailpacking block.
* simplify erofs_prepare_inode_buffer function. (remove handling ENOSPC error)
Signed-off-by: Noboru Asai <asai at sijam.com>
---
include/erofs/inode.h | 2 +
lib/compress.c | 11 +++--
lib/inode.c | 112 ++++++++++++++++++++++++++++++++++++++++--
3 files changed, 116 insertions(+), 9 deletions(-)
diff --git a/include/erofs/inode.h b/include/erofs/inode.h
index d5a732a..fb93b81 100644
--- a/include/erofs/inode.h
+++ b/include/erofs/inode.h
@@ -40,6 +40,8 @@ int __erofs_fill_inode(struct erofs_inode *inode, struct stat *st,
struct erofs_inode *erofs_new_inode(void);
struct erofs_inode *erofs_mkfs_build_tree_from_path(const char *path);
struct erofs_inode *erofs_mkfs_build_special_from_fd(int fd, const char *name);
+unsigned int erofs_get_inodesize(struct erofs_inode *inode);
+unsigned int erofs_get_lowest_offset(struct erofs_inode *inode);
#ifdef __cplusplus
}
diff --git a/lib/compress.c b/lib/compress.c
index 74c5707..dfe59da 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -20,6 +20,7 @@
#include "erofs/block_list.h"
#include "erofs/compress_hints.h"
#include "erofs/fragments.h"
+#include "erofs/inode.h"
#ifdef EROFS_MT_ENABLED
#include "erofs/workqueue.h"
#endif
@@ -530,7 +531,8 @@ static int __z_erofs_compress_one(struct z_erofs_compress_sctx *ctx,
e->length = len;
goto frag_packing;
}
- if (!may_inline && len <= blksz)
+ if ((!may_inline && len <= blksz) ||
+ (may_inline && erofs_get_lowest_offset(inode) + len > blksz))
goto nocompression;
}
@@ -550,7 +552,7 @@ static int __z_erofs_compress_one(struct z_erofs_compress_sctx *ctx,
/* check if there is enough gain to keep the compressed data */
if (ret * h->compress_threshold / 100 >= e->length) {
- if (may_inline && len < blksz) {
+ if (may_inline && (erofs_get_lowest_offset(inode) + len < blksz)) {
ret = z_erofs_fill_inline_data(inode,
ctx->queue + ctx->head, len, true);
} else {
@@ -584,7 +586,8 @@ frag_packing:
e->raw = false;
ictx->fragemitted = true;
/* tailpcluster should be less than 1 block */
- } else if (may_inline && len == e->length && compressedsize < blksz) {
+ } else if (may_inline && len == e->length &&
+ (erofs_get_lowest_offset(inode) + compressedsize < blksz)) {
if (ctx->clusterofs + len <= blksz) {
inode->eof_tailraw = malloc(len);
if (!inode->eof_tailraw)
@@ -621,7 +624,7 @@ frag_packing:
&e->length, dst, &compressedsize);
e->compressedblks = BLK_ROUND_UP(sbi, compressedsize);
- DBG_BUGON(e->compressedblks * blksz >= e->length);
+ DBG_BUGON(!may_inline && e->compressedblks * blksz >= e->length);
padding = 0;
tailused = compressedsize & (blksz - 1);
diff --git a/lib/inode.c b/lib/inode.c
index 7508c74..45d2fbc 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -440,6 +440,11 @@ static int write_uncompressed_file_from_fd(struct erofs_inode *inode, int fd)
inode->datalayout = EROFS_INODE_FLAT_INLINE;
nblocks = inode->i_size / erofs_blksiz(sbi);
+ inode->idata_size = inode->i_size % erofs_blksiz(sbi);
+ if (erofs_get_inodesize(inode) + inode->idata_size > erofs_blksiz(sbi)) {
+ nblocks += 1;
+ inode->idata_size = 0;
+ }
ret = __allocate_inode_bh_data(inode, nblocks, DATA);
if (ret)
@@ -452,7 +457,7 @@ static int write_uncompressed_file_from_fd(struct erofs_inode *inode, int fd)
if (ret != erofs_blksiz(sbi)) {
if (ret < 0)
return -errno;
- return -EAGAIN;
+ memset(buf + ret, 0, erofs_blksiz(sbi) - ret);
}
ret = blk_write(sbi, buf, inode->u.i_blkaddr + i, 1);
@@ -461,7 +466,6 @@ static int write_uncompressed_file_from_fd(struct erofs_inode *inode, int fd)
}
/* read the tail-end data */
- inode->idata_size = inode->i_size % erofs_blksiz(sbi);
if (inode->idata_size) {
inode->idata = malloc(inode->idata_size);
if (!inode->idata)
@@ -667,6 +671,104 @@ static int erofs_prepare_tail_block(struct erofs_inode *inode)
return 0;
}
+static unsigned int erofs_get_compacted_extent_isize(struct erofs_inode *inode)
+{
+ struct erofs_sb_info *sbi = inode->sbi;
+ const unsigned int mpos = roundup(inode->inode_isize +
+ inode->xattr_isize, 8) +
+ sizeof(struct z_erofs_map_header);
+ const unsigned int totalidx = BLK_ROUND_UP(sbi, inode->i_size);
+ /* # of 8-byte units so that it can be aligned with 32 bytes */
+ unsigned int compacted_4b_initial, compacted_4b_end;
+ unsigned int compacted_2b;
+ unsigned int extent_isize = 0;
+
+ if (inode->z_advise & Z_EROFS_ADVISE_COMPACTED_2B) {
+ compacted_4b_initial = (32 - mpos % 32) / 4;
+ if (compacted_4b_initial == 32 / 4)
+ compacted_4b_initial = 0;
+
+ if (compacted_4b_initial > totalidx) {
+ compacted_4b_initial = compacted_2b = 0;
+ compacted_4b_end = totalidx;
+ } else {
+ compacted_2b = rounddown(totalidx -
+ compacted_4b_initial, 16);
+ compacted_4b_end = totalidx - compacted_4b_initial -
+ compacted_2b;
+ }
+ } else {
+ compacted_2b = compacted_4b_initial = 0;
+ compacted_4b_end = totalidx;
+ }
+
+ extent_isize += sizeof(struct z_erofs_map_header);
+
+ /* generate compacted_4b_initial */
+ while (compacted_4b_initial) {
+ extent_isize += 4 * 2;
+ compacted_4b_initial -= 2;
+ }
+ DBG_BUGON(compacted_4b_initial);
+
+ /* generate compacted_2b */
+ while (compacted_2b) {
+ extent_isize += 2 * 16;
+ compacted_2b -= 16;
+ }
+ DBG_BUGON(compacted_2b);
+
+ /* generate compacted_4b_end */
+ while (compacted_4b_end > 1) {
+ extent_isize += 4 * 2;
+ compacted_4b_end -= 2;
+ }
+
+ /* generate final compacted_4b_end if needed */
+ if (compacted_4b_end) {
+ extent_isize += 4 * 2;
+ }
+ return extent_isize;
+}
+
+/* datalayout may change in z_erofs_compress_dedupe function,
+ * so use carefully.
+ */
+unsigned int erofs_get_inodesize(struct erofs_inode *inode)
+{
+ struct erofs_sb_info *sbi = inode->sbi;
+ unsigned int inodesize;
+
+ inodesize = inode->inode_isize + inode->xattr_isize;
+
+ if (inode->extent_isize)
+ return roundup(inodesize, 8) + inode->extent_isize;
+
+ switch (inode->datalayout) {
+ case EROFS_INODE_COMPRESSED_FULL:
+ inodesize = roundup(inodesize, 8);
+ inodesize += BLK_ROUND_UP(sbi, inode->i_size) *
+ sizeof(struct z_erofs_lcluster_index) +
+ Z_EROFS_FULL_INDEX_ALIGN(0); /* Z_EROFS_LEGACY_MAP_HEADER_SIZE */
+ break;
+ case EROFS_INODE_COMPRESSED_COMPACT:
+ inodesize = roundup(inodesize, 8);
+ inodesize += erofs_get_compacted_extent_isize(inode);
+ break;
+ default:
+ }
+
+ return inodesize;
+}
+
+unsigned int erofs_get_lowest_offset(struct erofs_inode *inode)
+{
+ struct erofs_sb_info *sbi = inode->sbi;
+ unsigned int blksz = erofs_blksiz(sbi);
+
+ return erofs_get_inodesize(inode) & (blksz - 1);
+}
+
static int erofs_prepare_inode_buffer(struct erofs_inode *inode)
{
unsigned int inodesize;
@@ -674,9 +776,7 @@ static int erofs_prepare_inode_buffer(struct erofs_inode *inode)
DBG_BUGON(inode->bh || inode->bh_inline);
- inodesize = inode->inode_isize + inode->xattr_isize;
- if (inode->extent_isize)
- inodesize = roundup(inodesize, 8) + inode->extent_isize;
+ inodesize = erofs_get_inodesize(inode);
/* TODO: tailpacking inline of chunk-based format isn't finalized */
if (inode->datalayout == EROFS_INODE_CHUNK_BASED)
@@ -699,6 +799,8 @@ static int erofs_prepare_inode_buffer(struct erofs_inode *inode)
if (bh == ERR_PTR(-ENOSPC)) {
int ret;
+ BUG_ON(1);
+
if (is_inode_layout_compression(inode))
z_erofs_drop_inline_pcluster(inode);
else
--
2.44.0
More information about the Linux-erofs
mailing list