[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