where it can be reused by other helpers.
No changes other than the move.
Note that this makes iohelper now dependent on -lutil and -lacl.
Signed-off-by: Claudio Fontana <cfontana(a)suse.de>
---
src/util/iohelper.c | 175 ----------------------------------------
src/util/meson.build | 5 ++
src/util/virfile.c | 186 +++++++++++++++++++++++++++++++++++++++++++
src/util/virfile.h | 2 +
4 files changed, 193 insertions(+), 175 deletions(-)
diff --git a/src/util/iohelper.c b/src/util/iohelper.c
index 1584321839..b3aaf82b9f 100644
--- a/src/util/iohelper.c
+++ b/src/util/iohelper.c
@@ -41,181 +41,6 @@
#define VIR_FROM_THIS VIR_FROM_STORAGE
-#ifndef O_DIRECT
-# define O_DIRECT 0
-#endif
-
-struct runIOParams {
- bool isBlockDev;
- bool isDirect;
- bool isWrite;
- int fdin;
- const char *fdinname;
- int fdout;
- const char *fdoutname;
-};
-
-/**
- * runIOCopy: execute the IO copy based on the passed parameters
- * @p: the IO parameters
- *
- * Execute the copy based on the passed parameters.
- *
- * Returns: size transfered, or < 0 on error.
- */
-
-static off_t
-runIOCopy(const struct runIOParams p)
-{
- g_autofree void *base = NULL; /* Location to be freed */
- char *buf = NULL; /* Aligned location within base */
- size_t buflen = 1024*1024;
- intptr_t alignMask = 64*1024 - 1;
- off_t total = 0;
-
-#if WITH_POSIX_MEMALIGN
- if (posix_memalign(&base, alignMask + 1, buflen))
- abort();
- buf = base;
-#else
- buf = g_new0(char, buflen + alignMask);
- base = buf;
- buf = (char *) (((intptr_t) base + alignMask) & ~alignMask);
-#endif
-
- while (1) {
- ssize_t got;
-
- /* If we read with O_DIRECT from file we can't use saferead as
- * it can lead to unaligned read after reading last bytes.
- * If we write with O_DIRECT use should use saferead so that
- * writes will be aligned.
- * In other cases using saferead reduces number of syscalls.
- */
- if (!p.isWrite && p.isDirect) {
- if ((got = read(p.fdin, buf, buflen)) < 0 &&
- errno == EINTR)
- continue;
- } else {
- got = saferead(p.fdin, buf, buflen);
- }
-
- if (got < 0) {
- virReportSystemError(errno, _("Unable to read %s"), p.fdinname);
- return -2;
- }
- if (got == 0)
- break;
-
- total += got;
-
- /* handle last write size align in direct case */
- if (got < buflen && p.isDirect && p.isWrite) {
- ssize_t aligned_got = (got + alignMask) & ~alignMask;
-
- memset(buf + got, 0, aligned_got - got);
-
- if (safewrite(p.fdout, buf, aligned_got) < 0) {
- virReportSystemError(errno, _("Unable to write %s"),
p.fdoutname);
- return -3;
- }
-
- if (!p.isBlockDev && ftruncate(p.fdout, total) < 0) {
- virReportSystemError(errno, _("Unable to truncate %s"),
p.fdoutname);
- return -4;
- }
-
- break;
- }
-
- if (safewrite(p.fdout, buf, got) < 0) {
- virReportSystemError(errno, _("Unable to write %s"), p.fdoutname);
- return -3;
- }
- }
- return total;
-}
-
-static int
-runIO(const char *path, int fd, int oflags)
-{
- int ret = -1;
- off_t total = 0;
- struct stat sb;
- struct runIOParams p;
-
- if (fstat(fd, &sb) < 0) {
- virReportSystemError(errno,
- _("Unable to access file descriptor %d path %s"),
- fd, path);
- goto cleanup;
- }
- p.isBlockDev = S_ISBLK(sb.st_mode);
- p.isDirect = O_DIRECT && (oflags & O_DIRECT);
-
- switch (oflags & O_ACCMODE) {
- case O_RDONLY:
- p.isWrite = false;
- p.fdin = fd;
- p.fdinname = path;
- p.fdout = STDOUT_FILENO;
- p.fdoutname = "stdout";
- break;
- case O_WRONLY:
- p.isWrite = true;
- p.fdin = STDIN_FILENO;
- p.fdinname = "stdin";
- p.fdout = fd;
- p.fdoutname = path;
- break;
-
- case O_RDWR:
- default:
- virReportSystemError(EINVAL,
- _("Unable to process file with flags %d"),
- (oflags & O_ACCMODE));
- goto cleanup;
- }
- /* To make the implementation simpler, we give up on any
- * attempt to use O_DIRECT in a non-trivial manner. */
- if (!p.isBlockDev && p.isDirect) {
- off_t off;
- if (p.isWrite) {
- if ((off = lseek(fd, 0, SEEK_END)) != 0) {
- virReportSystemError(off < 0 ? errno : EINVAL, "%s",
- _("O_DIRECT write needs empty seekable
file"));
- goto cleanup;
- }
- } else if ((off = lseek(fd, 0, SEEK_CUR)) != 0) {
- virReportSystemError(off < 0 ? errno : EINVAL, "%s",
- _("O_DIRECT read needs entire seekable
file"));
- goto cleanup;
- }
- }
- total = runIOCopy(p);
- if (total < 0)
- goto cleanup;
-
- /* Ensure all data is written */
- if (virFileDataSync(p.fdout) < 0) {
- if (errno != EINVAL && errno != EROFS) {
- /* fdatasync() may fail on some special FDs, e.g. pipes */
- virReportSystemError(errno, _("unable to fsync %s"), p.fdoutname);
- goto cleanup;
- }
- }
-
- ret = 0;
-
- cleanup:
- if (VIR_CLOSE(fd) < 0 &&
- ret == 0) {
- virReportSystemError(errno, _("Unable to close %s"), path);
- ret = -1;
- }
- return ret;
-}
-
static const char *program_name;
G_GNUC_NORETURN static void
diff --git a/src/util/meson.build b/src/util/meson.build
index 24350a3e67..17755373c8 100644
--- a/src/util/meson.build
+++ b/src/util/meson.build
@@ -175,6 +175,7 @@ keycode_dep = declare_dependency(
io_helper_sources = [
'iohelper.c',
+ 'virfile.c',
]
virt_util_lib = static_library(
@@ -213,6 +214,10 @@ if conf.has('WITH_LIBVIRTD')
files(io_helper_sources),
dtrace_gen_headers,
],
+ 'deps': [
+ acl_dep,
+ libutil_dep,
+ ],
}
endif
diff --git a/src/util/virfile.c b/src/util/virfile.c
index 130b0fbace..0bfdbea81f 100644
--- a/src/util/virfile.c
+++ b/src/util/virfile.c
@@ -4577,3 +4577,189 @@ virFileSetCOW(const char *path,
return 0;
#endif /* ! __linux__ */
}
+
+#ifndef WIN32
+struct runIOParams {
+ bool isBlockDev;
+ bool isDirect;
+ bool isWrite;
+ int fdin;
+ const char *fdinname;
+ int fdout;
+ const char *fdoutname;
+};
+
+/**
+ * runIOCopy: execute the IO copy based on the passed parameters
+ * @p: the IO parameters
+ *
+ * Execute the copy based on the passed parameters.
+ *
+ * Returns: size transfered, or < 0 on error.
+ */
+
+static off_t
+runIOCopy(const struct runIOParams p)
+{
+ g_autofree void *base = NULL; /* Location to be freed */
+ char *buf = NULL; /* Aligned location within base */
+ size_t buflen = 1024*1024;
+ intptr_t alignMask = 64*1024 - 1;
+ off_t total = 0;
+
+#if WITH_POSIX_MEMALIGN
+ if (posix_memalign(&base, alignMask + 1, buflen))
+ abort();
+ buf = base;
+#else
+ buf = g_new0(char, buflen + alignMask);
+ base = buf;
+ buf = (char *) (((intptr_t) base + alignMask) & ~alignMask);
+#endif
+
+ while (1) {
+ ssize_t got;
+
+ /* If we read with O_DIRECT from file we can't use saferead as
+ * it can lead to unaligned read after reading last bytes.
+ * If we write with O_DIRECT use should use saferead so that
+ * writes will be aligned.
+ * In other cases using saferead reduces number of syscalls.
+ */
+ if (!p.isWrite && p.isDirect) {
+ if ((got = read(p.fdin, buf, buflen)) < 0 &&
+ errno == EINTR)
+ continue;
+ } else {
+ got = saferead(p.fdin, buf, buflen);
+ }
+
+ if (got < 0) {
+ virReportSystemError(errno, _("Unable to read %s"), p.fdinname);
+ return -2;
+ }
+ if (got == 0)
+ break;
+
+ total += got;
+
+ /* handle last write size align in direct case */
+ if (got < buflen && p.isDirect && p.isWrite) {
+ ssize_t aligned_got = (got + alignMask) & ~alignMask;
+
+ memset(buf + got, 0, aligned_got - got);
+
+ if (safewrite(p.fdout, buf, aligned_got) < 0) {
+ virReportSystemError(errno, _("Unable to write %s"),
p.fdoutname);
+ return -3;
+ }
+
+ if (!p.isBlockDev && ftruncate(p.fdout, total) < 0) {
+ virReportSystemError(errno, _("Unable to truncate %s"),
p.fdoutname);
+ return -4;
+ }
+
+ break;
+ }
+
+ if (safewrite(p.fdout, buf, got) < 0) {
+ virReportSystemError(errno, _("Unable to write %s"), p.fdoutname);
+ return -3;
+ }
+ }
+ return total;
+}
+
+
+off_t
+runIO(const char *path, int fd, int oflags)
+{
+ int ret = -1;
+ off_t total = 0;
+ struct stat sb;
+ struct runIOParams p;
+
+ if (fstat(fd, &sb) < 0) {
+ virReportSystemError(errno,
+ _("Unable to access file descriptor %d path %s"),
+ fd, path);
+ goto cleanup;
+ }
+ p.isBlockDev = S_ISBLK(sb.st_mode);
+ p.isDirect = O_DIRECT && (oflags & O_DIRECT);
+
+ switch (oflags & O_ACCMODE) {
+ case O_RDONLY:
+ p.isWrite = false;
+ p.fdin = fd;
+ p.fdinname = path;
+ p.fdout = STDOUT_FILENO;
+ p.fdoutname = "stdout";
+ break;
+ case O_WRONLY:
+ p.isWrite = true;
+ p.fdin = STDIN_FILENO;
+ p.fdinname = "stdin";
+ p.fdout = fd;
+ p.fdoutname = path;
+ break;
+
+ case O_RDWR:
+ default:
+ virReportSystemError(EINVAL,
+ _("Unable to process file with flags %d"),
+ (oflags & O_ACCMODE));
+ goto cleanup;
+ }
+ /* To make the implementation simpler, we give up on any
+ * attempt to use O_DIRECT in a non-trivial manner. */
+ if (!p.isBlockDev && p.isDirect) {
+ off_t off;
+ if (p.isWrite) {
+ if ((off = lseek(fd, 0, SEEK_END)) != 0) {
+ virReportSystemError(off < 0 ? errno : EINVAL, "%s",
+ _("O_DIRECT write needs empty seekable
file"));
+ goto cleanup;
+ }
+ } else if ((off = lseek(fd, 0, SEEK_CUR)) != 0) {
+ virReportSystemError(off < 0 ? errno : EINVAL, "%s",
+ _("O_DIRECT read needs entire seekable
file"));
+ goto cleanup;
+ }
+ }
+ total = runIOCopy(p);
+ if (total < 0)
+ goto cleanup;
+
+ /* Ensure all data is written */
+ if (virFileDataSync(p.fdout) < 0) {
+ if (errno != EINVAL && errno != EROFS) {
+ /* fdatasync() may fail on some special FDs, e.g. pipes */
+ virReportSystemError(errno, _("unable to fsync %s"), p.fdoutname);
+ goto cleanup;
+ }
+ }
+
+ ret = 0;
+
+ cleanup:
+ if (VIR_CLOSE(fd) < 0 &&
+ ret == 0) {
+ virReportSystemError(errno, _("Unable to close %s"), path);
+ ret = -1;
+ }
+ return ret;
+}
+
+#else /* WIN32 */
+
+off_t
+runIO(const char *path G_GNUC_UNUSED,
+ int fd G_GNUC_UNUSED,
+ int oflags G_GNUC_UNUSED)
+{
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("runIO unsupported on this platform"));
+ return -1;
+}
+#endif /* WIN32 */
diff --git a/src/util/virfile.h b/src/util/virfile.h
index b04386f6e6..0dc336e339 100644
--- a/src/util/virfile.h
+++ b/src/util/virfile.h
@@ -383,3 +383,5 @@ int virFileDataSync(int fd);
int virFileSetCOW(const char *path,
virTristateBool state);
+
+off_t runIO(const char *path, int fd, int oflags);
--
2.35.3