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