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 <a...@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

Reply via email to