Utilize copy offloading to speed up copying data from the source filesystem to the target EROFS filesystem.
This method improves build speed by approximately 9% (tested with Linux 5.4.140 source code dataset). Reported-by: Daan De Meyer <daan.j.deme...@gmail.com> Closes: https://lore.kernel.org/r/CAO8sHcmZZORnrJXA=qzmgkynknwn7m+amak_dz19-wl4klu...@mail.gmail.com Signed-off-by: Gao Xiang <hsiang...@linux.alibaba.com> --- changes since v1: - Fix macos build error: https://github.com/erofs/erofsnightly/actions/runs/9607090927 - Fix unexpected lseek related to diskbuf: https://github.com/erofs/erofsnightly/actions/runs/9607047368 configure.ac | 2 ++ include/erofs/io.h | 4 ++++ lib/inode.c | 23 +++++++---------------- lib/io.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 16 deletions(-) diff --git a/configure.ac b/configure.ac index dc5f787..945e254 100644 --- a/configure.ac +++ b/configure.ac @@ -204,6 +204,7 @@ AC_CHECK_HEADERS(m4_flatten([ sys/ioctl.h sys/mman.h sys/random.h + sys/sendfile.h sys/stat.h sys/statfs.h sys/sysmacros.h @@ -267,6 +268,7 @@ AC_CHECK_FUNCS(m4_flatten([ pwrite64 posix_fadvise fstatfs + sendfile strdup strerror strrchr diff --git a/include/erofs/io.h b/include/erofs/io.h index d3a487f..84e4bc6 100644 --- a/include/erofs/io.h +++ b/include/erofs/io.h @@ -33,6 +33,8 @@ struct erofs_vfops { ssize_t (*read)(struct erofs_vfile *vf, void *buf, size_t len); off_t (*lseek)(struct erofs_vfile *vf, u64 offset, int whence); int (*fstat)(struct erofs_vfile *vf, struct stat *buf); + int (*xcopy)(struct erofs_vfile *vout, off_t pos, + struct erofs_vfile *vin, int len); }; struct erofs_vfile { @@ -52,6 +54,8 @@ off_t erofs_io_lseek(struct erofs_vfile *vf, u64 offset, int whence); ssize_t erofs_copy_file_range(int fd_in, u64 *off_in, int fd_out, u64 *off_out, size_t length); +int erofs_io_xcopy(struct erofs_vfile *vout, off_t pos, + struct erofs_vfile *vin, int len); #ifdef __cplusplus } diff --git a/lib/inode.c b/lib/inode.c index 60a076a..866c2ee 100644 --- a/lib/inode.c +++ b/lib/inode.c @@ -514,30 +514,21 @@ static bool erofs_file_is_compressible(struct erofs_inode *inode) static int write_uncompressed_file_from_fd(struct erofs_inode *inode, int fd) { int ret; - unsigned int nblocks, i; + unsigned int nblocks; struct erofs_sb_info *sbi = inode->sbi; inode->datalayout = EROFS_INODE_FLAT_INLINE; - nblocks = inode->i_size / erofs_blksiz(sbi); + nblocks = inode->i_size >> sbi->blkszbits; ret = __allocate_inode_bh_data(inode, nblocks, DATA); if (ret) return ret; - for (i = 0; i < nblocks; ++i) { - char buf[EROFS_MAX_BLOCK_SIZE]; - - ret = read(fd, buf, erofs_blksiz(sbi)); - if (ret != erofs_blksiz(sbi)) { - if (ret < 0) - return -errno; - return -EAGAIN; - } - - ret = erofs_blk_write(sbi, buf, inode->u.i_blkaddr + i, 1); - if (ret) - return ret; - } + ret = erofs_io_xcopy(&sbi->bdev, erofs_pos(sbi, inode->u.i_blkaddr), + &((struct erofs_vfile){ .fd = fd }), + erofs_pos(sbi, nblocks)); + if (ret) + return ret; /* read the tail-end data */ inode->idata_size = inode->i_size % erofs_blksiz(sbi); diff --git a/lib/io.c b/lib/io.c index a2ef344..c2f8fe7 100644 --- a/lib/io.c +++ b/lib/io.c @@ -477,6 +477,10 @@ ssize_t erofs_io_read(struct erofs_vfile *vf, void *buf, size_t bytes) return i; } +#ifdef HAVE_SYS_SENDFILE_H +#include <sys/sendfile.h> +#endif + off_t erofs_io_lseek(struct erofs_vfile *vf, u64 offset, int whence) { if (vf->ops) @@ -484,3 +488,44 @@ off_t erofs_io_lseek(struct erofs_vfile *vf, u64 offset, int whence) return lseek(vf->fd, offset, whence); } + +int erofs_io_xcopy(struct erofs_vfile *vout, off_t pos, + struct erofs_vfile *vin, int len) +{ + if (vout->ops) + return vout->ops->xcopy(vout, pos, vin, len); + +#if defined(HAVE_SYS_SENDFILE_H) && defined(HAVE_SENDFILE) + if (len && !vin->ops) { /* try to use sendfile() */ + off_t ret; + + ret = lseek(vout->fd, pos, SEEK_SET); + if (ret == pos) { + ret = sendfile(vout->fd, vin->fd, NULL, len); + if (ret > 0) { + pos += ret; + len -= ret; + if (!len) + return 0; + } + } + } +#endif + + do { + char buf[32768]; + int ret = min_t(int, len, sizeof(buf)); + + ret = erofs_io_read(vin, buf, ret); + if (ret < 0) + return ret; + if (ret > 0) { + ret = erofs_io_pwrite(vout, buf, pos, ret); + if (ret < 0) + return ret; + pos += ret; + } + len -= ret; + } while (len); + return 0; +} -- 2.39.3