erofs-utils: fix erofs_io_p{read,write} and erofs_dev_close
authorHongzhen Luo <hongzhen@linux.alibaba.com>
Wed, 19 Jun 2024 02:50:24 +0000 (10:50 +0800)
committerGao Xiang <hsiangkao@linux.alibaba.com>
Wed, 19 Jun 2024 03:11:23 +0000 (11:11 +0800)
erofs_io_p{read,write} should return the number of bytes
successfully {read,write}.

This also fixes `erofs_dev_close` which could close random
fds if `vf->ops` is NULL.

Signed-off-by: Hongzhen Luo <hongzhen@linux.alibaba.com>
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20240619025024.1109782-1-hsiangkao@linux.alibaba.com
include/erofs/internal.h
lib/io.c

index f8a01cee5d8d64b147b2cb01655228d671714025..4917908e76921117bfddbae2ff8fddc46ec086e9 100644 (file)
@@ -460,7 +460,9 @@ 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);
+       if (erofs_io_pwrite(&sbi->bdev, buf, offset, len) != (ssize_t)len)
+               return -EIO;
+       return 0;
 }
 
 static inline int erofs_dev_fillzero(struct erofs_sb_info *sbi, u64 offset,
index c523f006a24dd2725014a3d3ff723f537ee78dab..576d55b5b8a0dc7ab413dcdb71b32e64b0d2d2c0 100644 (file)
--- a/lib/io.c
+++ b/lib/io.c
@@ -29,7 +29,7 @@
 ssize_t erofs_io_pwrite(struct erofs_vfile *vf, const void *buf,
                        u64 pos, size_t len)
 {
-       ssize_t ret;
+       ssize_t ret, written = 0;
 
        if (unlikely(cfg.c_dry_run))
                return 0;
@@ -45,15 +45,20 @@ ssize_t erofs_io_pwrite(struct erofs_vfile *vf, const void *buf,
                ret = pwrite(vf->fd, buf, len, (off_t)pos);
 #endif
                if (ret <= 0) {
-                       erofs_err("failed to write: %s", strerror(errno));
-                       return -errno;
+                       if (!ret)
+                               break;
+                       if (errno != EINTR) {
+                               erofs_err("failed to write: %s", strerror(errno));
+                               return -errno;
+                       }
+                       ret = 0;
                }
-               len -= ret;
                buf += ret;
                pos += ret;
-       } while (len);
+               written += ret;
+       } while (written < len);
 
-       return 0;
+       return written;
 }
 
 int erofs_io_fsync(struct erofs_vfile *vf)
@@ -93,12 +98,12 @@ ssize_t erofs_io_fallocate(struct erofs_vfile *vf, u64 offset,
 #endif
        while (len > EROFS_MAX_BLOCK_SIZE) {
                ret = erofs_io_pwrite(vf, zero, offset, EROFS_MAX_BLOCK_SIZE);
-               if (ret)
+               if (ret < 0)
                        return ret;
-               len -= EROFS_MAX_BLOCK_SIZE;
-               offset += EROFS_MAX_BLOCK_SIZE;
+               len -= ret;
+               offset += ret;
        }
-       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)
@@ -125,7 +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 ret, read = 0;
 
        if (unlikely(cfg.c_dry_run))
                return 0;
@@ -141,11 +146,8 @@ ssize_t erofs_io_pread(struct erofs_vfile *vf, void *buf, u64 pos, size_t len)
                ret = pread(vf->fd, buf, len, (off_t)pos);
 #endif
                if (ret <= 0) {
-                       if (!ret) {
-                               erofs_info("reach EOF of device");
-                               memset(buf, 0, len);
-                               return 0;
-                       }
+                       if (!ret)
+                               break;
                        if (errno != EINTR) {
                                erofs_err("failed to read: %s", strerror(errno));
                                return -errno;
@@ -153,10 +155,11 @@ ssize_t erofs_io_pread(struct erofs_vfile *vf, void *buf, u64 pos, size_t len)
                        ret = 0;
                }
                pos += ret;
-               len -= ret;
                buf += ret;
-       } while (len);
-       return 0;
+               read += ret;
+       } while (read < len);
+
+       return read;
 }
 
 static int erofs_get_bdev_size(int fd, u64 *bytes)
@@ -287,7 +290,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 +324,23 @@ 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 read;
+
+       if (device_id) {
+               read = erofs_io_pread(&((struct erofs_vfile) {
                                .fd = sbi->blobfd[device_id - 1],
                        }), buf, offset, len);
-       return erofs_io_pread(&sbi->bdev, buf, offset, len);
+       } else {
+               read = erofs_io_pread(&sbi->bdev, buf, offset, len);
+       }
+
+       if (read < 0)
+               return read;
+       if (read < len) {
+               erofs_info("reach EOF of device, pading with zeroes");
+               memset(buf + read, 0, len - read);
+       }
+       return 0;
 }
 
 static ssize_t __erofs_copy_file_range(int fd_in, u64 *off_in,