erofs-utils: mkfs: fix unexpected errors for chunk-based images
authorGao Xiang <hsiangkao@linux.alibaba.com>
Wed, 16 Oct 2024 07:48:49 +0000 (15:48 +0800)
committerGao Xiang <hsiangkao@linux.alibaba.com>
Wed, 16 Oct 2024 07:54:42 +0000 (15:54 +0800)
mkfs.erofs may fail because copy_file_range() returns the number of
bytes which could be less than the length originally requested.

Fixes: 03cbf7b8f7f7 ("erofs-utils: mkfs: support chunk-based uncompressed files")
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20241016074849.2862282-1-hsiangkao@linux.alibaba.com
lib/blobchunk.c

index 6c2ea0e19e1b9f508bf43cedd9e48db9d9f75811..9e857210fb9741c8531402db2fb7aaadfabbf503 100644 (file)
@@ -480,9 +480,8 @@ int tarerofs_write_chunkes(struct erofs_inode *inode, erofs_off_t data_offset)
 int erofs_mkfs_dump_blobs(struct erofs_sb_info *sbi)
 {
        struct erofs_buffer_head *bh;
-       ssize_t length;
+       ssize_t length, ret;
        u64 pos_in, pos_out;
-       ssize_t ret;
 
        if (blobfile) {
                fflush(blobfile);
@@ -532,9 +531,21 @@ int erofs_mkfs_dump_blobs(struct erofs_sb_info *sbi)
        pos_out += sbi->bdev.offset;
        if (blobfile) {
                pos_in = 0;
-               ret = erofs_copy_file_range(fileno(blobfile), &pos_in,
-                               sbi->bdev.fd, &pos_out, datablob_size);
-               ret = ret < datablob_size ? -EIO : 0;
+               do {
+                       length = min_t(erofs_off_t, datablob_size,  SSIZE_MAX);
+                       ret = erofs_copy_file_range(fileno(blobfile), &pos_in,
+                                       sbi->bdev.fd, &pos_out, length);
+               } while (ret > 0 && (datablob_size -= ret));
+
+               if (ret >= 0) {
+                       if (datablob_size) {
+                               erofs_err("failed to append the remaining %llu-byte chunk data",
+                                         datablob_size);
+                               ret = -EIO;
+                       } else {
+                               ret = 0;
+                       }
+               }
        } else {
                ret = erofs_io_ftruncate(&sbi->bdev, pos_out + datablob_size);
        }