When `vf->ops` is not null, `vf->ops->pread` returns the
number of bytes successfully read, which is inconsistent
with the semantics of `erofs_io_pread`. Similar situation
occurs in `erofs_io_pwrite`. This fixes this issue.

This also fixes `erofs_dev_close`.

Signed-off-by: Hongzhen Luo <hongz...@linux.alibaba.com>
---
v2: 
https://lore.kernel.org/all/20240618093843.912278-1-hongz...@linux.alibaba.com/
v1: 
https://lore.kernel.org/all/20240617023433.3446706-1-hongz...@linux.alibaba.com/
---
 include/erofs/internal.h |  5 ++++-
 lib/io.c                 | 47 ++++++++++++++++++++++++++++++----------
 2 files changed, 40 insertions(+), 12 deletions(-)

diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index f8a01ce..dfbd958 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -460,7 +460,10 @@ ssize_t erofs_dev_read(struct erofs_sb_info *sbi, int 
device_id,
 static inline int erofs_dev_write(struct erofs_sb_info *sbi, const void *buf,
                                  u64 offset, size_t len)
 {
-       return erofs_io_pwrite(&sbi->bdev, buf, offset, len);
+       ssize_t ret;
+
+       ret = erofs_io_pwrite(&sbi->bdev, buf, offset, len);
+       return (size_t)ret == len ? 0 : -EIO;
 }
 
 static inline int erofs_dev_fillzero(struct erofs_sb_info *sbi, u64 offset,
diff --git a/lib/io.c b/lib/io.c
index c523f00..3417b46 100644
--- a/lib/io.c
+++ b/lib/io.c
@@ -30,6 +30,7 @@ ssize_t erofs_io_pwrite(struct erofs_vfile *vf, const void 
*buf,
                        u64 pos, size_t len)
 {
        ssize_t ret;
+       size_t write = 0;
 
        if (unlikely(cfg.c_dry_run))
                return 0;
@@ -51,9 +52,10 @@ ssize_t erofs_io_pwrite(struct erofs_vfile *vf, const void 
*buf,
                len -= ret;
                buf += ret;
                pos += ret;
+               write += ret;
        } while (len);
 
-       return 0;
+       return write;
 }
 
 int erofs_io_fsync(struct erofs_vfile *vf)
@@ -92,13 +94,15 @@ ssize_t erofs_io_fallocate(struct erofs_vfile *vf, u64 
offset,
                return 0;
 #endif
        while (len > EROFS_MAX_BLOCK_SIZE) {
-               ret = erofs_io_pwrite(vf, zero, offset, EROFS_MAX_BLOCK_SIZE);
+               ret = erofs_io_pwrite(vf, zero, offset,
+                       EROFS_MAX_BLOCK_SIZE) == EROFS_MAX_BLOCK_SIZE ?
+                       0 : -EIO;
                if (ret)
                        return ret;
                len -= EROFS_MAX_BLOCK_SIZE;
                offset += EROFS_MAX_BLOCK_SIZE;
        }
-       return erofs_io_pwrite(vf, zero, offset, len);
+       return erofs_io_pwrite(vf, zero, offset, len) == len ? 0 : -EIO;
 }
 
 int erofs_io_ftruncate(struct erofs_vfile *vf, u64 length)
@@ -126,6 +130,7 @@ int erofs_io_ftruncate(struct erofs_vfile *vf, u64 length)
 ssize_t erofs_io_pread(struct erofs_vfile *vf, void *buf, u64 pos, size_t len)
 {
        ssize_t ret;
+       ssize_t read = 0;
 
        if (unlikely(cfg.c_dry_run))
                return 0;
@@ -142,9 +147,7 @@ ssize_t erofs_io_pread(struct erofs_vfile *vf, void *buf, 
u64 pos, size_t len)
 #endif
                if (ret <= 0) {
                        if (!ret) {
-                               erofs_info("reach EOF of device");
-                               memset(buf, 0, len);
-                               return 0;
+                               return read;
                        }
                        if (errno != EINTR) {
                                erofs_err("failed to read: %s", 
strerror(errno));
@@ -155,8 +158,11 @@ ssize_t erofs_io_pread(struct erofs_vfile *vf, void *buf, 
u64 pos, size_t len)
                pos += ret;
                len -= ret;
                buf += ret;
+               read += ret;
+
        } while (len);
-       return 0;
+
+       return read;
 }
 
 static int erofs_get_bdev_size(int fd, u64 *bytes)
@@ -287,7 +293,8 @@ out:
 
 void erofs_dev_close(struct erofs_sb_info *sbi)
 {
-       close(sbi->bdev.fd);
+       if (!sbi->bdev.ops)
+               close(sbi->bdev.fd);
        free(sbi->devname);
        sbi->devname = NULL;
        sbi->bdev.fd = -1;
@@ -320,11 +327,29 @@ int erofs_blob_open_ro(struct erofs_sb_info *sbi, const 
char *dev)
 ssize_t erofs_dev_read(struct erofs_sb_info *sbi, int device_id,
                       void *buf, u64 offset, size_t len)
 {
-       if (device_id)
-               return erofs_io_pread(&((struct erofs_vfile) {
+       ssize_t ret;
+
+       if (device_id) {
+               ret = erofs_io_pread(&((struct erofs_vfile) {
                                .fd = sbi->blobfd[device_id - 1],
                        }), buf, offset, len);
-       return erofs_io_pread(&sbi->bdev, buf, offset, len);
+               if (ret < 0)
+                       return ret;
+               if (ret < len) {
+                       erofs_info("reach EOF of device");
+                       memset(buf + ret, 0, len - ret);
+               }
+               return 0;
+       }
+
+       ret = erofs_io_pread(&sbi->bdev, buf, offset, len);
+       if (ret < 0)
+               return ret;
+       if (ret < len) {
+               erofs_info("reach EOF of device");
+               memset(buf + ret, 0, len - ret);
+       }
+       return 0;
 }
 
 static ssize_t __erofs_copy_file_range(int fd_in, u64 *off_in,
-- 
2.39.3

Reply via email to