It's almost the same as `-Efragments` option, except that will
explicitly pack the whole data into the special inode instead.

Signed-off-by: Gao Xiang <[email protected]>
---
 configure.ac              |  1 +
 include/erofs/config.h    |  1 +
 include/erofs/fragments.h |  1 +
 lib/compress.c            | 32 ++++++++++++++++-------------
 lib/fragments.c           | 43 ++++++++++++++++++++++++++++++++++++++-
 man/mkfs.erofs.1          | 25 ++++++++++++++---------
 mkfs/main.c               |  6 ++++++
 7 files changed, 84 insertions(+), 25 deletions(-)

diff --git a/configure.ac b/configure.ac
index cdbeb33..4dbe86f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -134,6 +134,7 @@ AC_CHECK_HEADERS(m4_flatten([
        stdlib.h
        string.h
        sys/ioctl.h
+       sys/mman.h
        sys/stat.h
        sys/sysmacros.h
        sys/time.h
diff --git a/include/erofs/config.h b/include/erofs/config.h
index 39a6162..648a3e8 100644
--- a/include/erofs/config.h
+++ b/include/erofs/config.h
@@ -48,6 +48,7 @@ struct erofs_configure {
        bool c_noinline_data;
        bool c_ztailpacking;
        bool c_fragments;
+       bool c_all_fragments;
        bool c_dedupe;
        bool c_ignore_mtime;
        bool c_showprogress;
diff --git a/include/erofs/fragments.h b/include/erofs/fragments.h
index 4caaf6b..21753ec 100644
--- a/include/erofs/fragments.h
+++ b/include/erofs/fragments.h
@@ -16,6 +16,7 @@ extern const char *frags_packedname;
 #define EROFS_PACKED_INODE     frags_packedname
 
 int z_erofs_fragments_dedupe(struct erofs_inode *inode, int fd, u32 *tofcrc);
+int z_erofs_pack_file_from_fd(struct erofs_inode *inode, int fd, u32 tofcrc);
 int z_erofs_pack_fragments(struct erofs_inode *inode, void *data,
                           unsigned int len, u32 tofcrc);
 void z_erofs_fragments_commit(struct erofs_inode *inode);
diff --git a/lib/compress.c b/lib/compress.c
index 8169990..65c6f90 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -899,22 +899,26 @@ int erofs_write_compressed_file(struct erofs_inode 
*inode, int fd)
        ctx.remaining = inode->i_size - inode->fragment_size;
        ctx.fix_dedupedfrag = false;
        ctx.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);
+       } else {
+               while (ctx.remaining) {
+                       const u64 rx = min_t(u64, ctx.remaining,
+                                            sizeof(ctx.queue) - ctx.tail);
+
+                       ret = read(fd, ctx.queue + ctx.tail, rx);
+                       if (ret != rx) {
+                               ret = -errno;
+                               goto err_bdrop;
+                       }
+                       ctx.remaining -= rx;
+                       ctx.tail += rx;
 
-       while (ctx.remaining) {
-               const u64 readcount = min_t(u64, ctx.remaining,
-                                           sizeof(ctx.queue) - ctx.tail);
-
-               ret = read(fd, ctx.queue + ctx.tail, readcount);
-               if (ret != readcount) {
-                       ret = -errno;
-                       goto err_bdrop;
+                       ret = vle_compress_one(&ctx);
+                       if (ret)
+                               goto err_free_idata;
                }
-               ctx.remaining -= readcount;
-               ctx.tail += readcount;
-
-               ret = vle_compress_one(&ctx);
-               if (ret)
-                       goto err_free_idata;
        }
        DBG_BUGON(ctx.head != ctx.tail);
 
diff --git a/lib/fragments.c b/lib/fragments.c
index 1e41485..ebff4b5 100644
--- a/lib/fragments.c
+++ b/lib/fragments.c
@@ -17,6 +17,7 @@
 #endif
 #include <stdlib.h>
 #include <unistd.h>
+#include <sys/mman.h>
 #include "erofs/err.h"
 #include "erofs/inode.h"
 #include "erofs/compress.h"
@@ -154,7 +155,11 @@ static int z_erofs_fragments_dedupe_insert(void *data, 
unsigned int len,
 
        if (len <= EROFS_TOF_HASHLEN)
                return 0;
-
+       if (len > EROFS_CONFIG_COMPR_MAX_SZ) {
+               data += len - EROFS_CONFIG_COMPR_MAX_SZ;
+               pos += len - EROFS_CONFIG_COMPR_MAX_SZ;
+               len = EROFS_CONFIG_COMPR_MAX_SZ;
+       }
        di = malloc(sizeof(*di) + len);
        if (!di)
                return -ENOMEM;
@@ -204,6 +209,42 @@ void z_erofs_fragments_commit(struct erofs_inode *inode)
        erofs_sb_set_fragments();
 }
 
+int z_erofs_pack_file_from_fd(struct erofs_inode *inode, int fd,
+                             u32 tofcrc)
+{
+#ifdef HAVE_FTELLO64
+       off64_t offset = ftello64(packedfile);
+#else
+       off_t offset = ftello(packedfile);
+#endif
+       char *memblock;
+       int rc;
+
+       if (offset < 0)
+               return -errno;
+
+       memblock = mmap(NULL, inode->i_size, PROT_READ, MAP_SHARED, fd, 0);
+       if (memblock == MAP_FAILED)
+               return -EFAULT;
+
+       inode->fragmentoff = (erofs_off_t)offset;
+       inode->fragment_size = inode->i_size;
+
+       if (fwrite(memblock, inode->fragment_size, 1, packedfile) != 1) {
+               rc = -EIO;
+               goto out;
+       }
+
+       erofs_dbg("Recording %u fragment data at %lu", inode->fragment_size,
+                 inode->fragmentoff);
+
+       rc = z_erofs_fragments_dedupe_insert(memblock, inode->fragment_size,
+                                            inode->fragmentoff, tofcrc);
+out:
+       munmap(memblock, inode->i_size);
+       return rc;
+}
+
 int z_erofs_pack_fragments(struct erofs_inode *inode, void *data,
                           unsigned int len, u32 tofcrc)
 {
diff --git a/man/mkfs.erofs.1 b/man/mkfs.erofs.1
index ba66a81..61ed24b 100644
--- a/man/mkfs.erofs.1
+++ b/man/mkfs.erofs.1
@@ -42,6 +42,21 @@ and may take an extra argument using the equals ('=') sign.
 The following extended options are supported:
 .RS 1.2i
 .TP
+.BI all-fragments
+Forcely record the whole files into a special inode for better compression and
+it may take an argument as the pcluster size of the packed inode in bytes.
+(Linux v6.1+)
+.TP
+.BI dedupe
+Enable global compressed data deduplication to minimize duplicated data in
+the filesystem. It may be used with \fI-Efragments\fR option together to
+further reduce image sizes. (Linux v6.1+)
+.TP
+.BI fragments
+Pack the tail part (pcluster) of compressed files or the whole files into a
+special inode for smaller image sizes, and it may take an argument as the
+pcluster size of the packed inode in bytes. (Linux v6.1+)
+.TP
 .BI force-inode-compact
 Forcely generate compact inodes (32-byte inodes) to output.
 .TP
@@ -64,16 +79,6 @@ Don't inline regular files to enable FSDAX for these files 
(Linux v5.15+).
 .BI ztailpacking
 Pack the tail part (pcluster) of compressed files into its metadata to save
 more space and the tail part I/O. (Linux v5.17+)
-.TP
-.BI fragments
-Pack the tail part (pcluster) of compressed files or the whole files into a
-special inode for smaller image sizes, and it may take an argument as the
-pcluster size of the packed inode in bytes. (Linux v6.1+)
-.TP
-.BI dedupe
-Enable global compressed data deduplication to minimize duplicated data in
-the filesystem. It may be used with \fI-Efragments\fR option together to
-further reduce image sizes. (Linux v6.1+)
 .RE
 .TP
 .BI "\-L " volume-label
diff --git a/mkfs/main.c b/mkfs/main.c
index d055902..bc973e7 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -208,10 +208,16 @@ static int parse_extended_opts(const char *opts)
                        cfg.c_ztailpacking = true;
                }
 
+               if (MATCH_EXTENTED_OPT("all-fragments", token, keylen)) {
+                       cfg.c_all_fragments = true;
+                       goto handle_fragment;
+               }
+
                if (MATCH_EXTENTED_OPT("fragments", token, keylen)) {
                        char *endptr;
                        u64 i;
 
+handle_fragment:
                        cfg.c_fragments = true;
                        if (vallen) {
                                i = strtoull(value, &endptr, 0);
-- 
2.36.1

Reply via email to