[PATCH v4] erofs-utils: fix erofs_io_p{read,write} and erofs_dev_close
Gao Xiang
hsiangkao at linux.alibaba.com
Wed Jun 19 12:50:24 AEST 2024
From: Hongzhen Luo <hongzhen at linux.alibaba.com>
erofs_io_p{read,write} should return the number of bytes
successfully {read,wrrite}.
This also fixes `erofs_dev_close` which could close random
fds if `vf->ops` is NULL.
Signed-off-by: Hongzhen Luo <hongzhen at linux.alibaba.com>
Signed-off-by: Gao Xiang <hsiangkao at linux.alibaba.com>
---
v3: https://lore.kernel.org/r/20240618114707.1030180-1-hongzhen@linux.alibaba.com
v4:
- minor cleanups for applying.
include/erofs/internal.h | 4 ++-
lib/io.c | 62 +++++++++++++++++++++++++---------------
2 files changed, 42 insertions(+), 24 deletions(-)
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 1d6496a..f61a453 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -465,7 +465,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,
diff --git a/lib/io.c b/lib/io.c
index 83c145c..cd2f034 100644
--- a/lib/io.c
+++ b/lib/io.c
@@ -42,7 +42,7 @@ int erofs_io_fstat(struct erofs_vfile *vf, struct stat *buf)
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;
@@ -58,15 +58,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)
@@ -106,12 +111,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)
@@ -138,7 +143,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;
@@ -154,11 +159,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;
@@ -166,10 +168,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)
@@ -300,7 +303,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;
@@ -333,11 +337,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,
--
2.39.3
More information about the Linux-erofs
mailing list