[libvirt RFCv4 03/20] iohelper: move runIO function to a separate module

Claudio Fontana cfontana at suse.de
Wed Apr 27 21:13:22 UTC 2022


where it can be reused by other helpers.
No changes other than the move.

Signed-off-by: Claudio Fontana <cfontana at suse.de>
---
 po/POTFILES.in       |   1 +
 src/util/iohelper.c  | 178 +----------------------------------
 src/util/meson.build |   2 +
 src/util/runio.c     | 214 +++++++++++++++++++++++++++++++++++++++++++
 src/util/runio.h     |  23 +++++
 5 files changed, 241 insertions(+), 177 deletions(-)
 create mode 100644 src/util/runio.c
 create mode 100644 src/util/runio.h

diff --git a/po/POTFILES.in b/po/POTFILES.in
index 0d9adb0758..5b4c00d7ac 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -241,6 +241,7 @@
 @SRCDIR at src/storage_file/storage_source_backingstore.c
 @SRCDIR at src/test/test_driver.c
 @SRCDIR at src/util/iohelper.c
+ at SRCDIR@src/util/runio.c
 @SRCDIR at src/util/viralloc.c
 @SRCDIR at src/util/virarptable.c
 @SRCDIR at src/util/viraudit.c
diff --git a/src/util/iohelper.c b/src/util/iohelper.c
index 1584321839..5a0098542e 100644
--- a/src/util/iohelper.c
+++ b/src/util/iohelper.c
@@ -38,183 +38,7 @@
 #include "virrandom.h"
 #include "virstring.h"
 #include "virgettext.h"
-
-#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;
-}
+#include "runio.h"
 
 static const char *program_name;
 
diff --git a/src/util/meson.build b/src/util/meson.build
index 24350a3e67..58001a1699 100644
--- a/src/util/meson.build
+++ b/src/util/meson.build
@@ -175,6 +175,8 @@ keycode_dep = declare_dependency(
 
 io_helper_sources = [
   'iohelper.c',
+  'runio.c',
+  'runio.h',
 ]
 
 virt_util_lib = static_library(
diff --git a/src/util/runio.c b/src/util/runio.c
new file mode 100644
index 0000000000..a7b902af7e
--- /dev/null
+++ b/src/util/runio.c
@@ -0,0 +1,214 @@
+/*
+ * runio.c: I/O copy function
+ *
+ * Copyright (C) 2011-2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "virthread.h"
+#include "virfile.h"
+#include "viralloc.h"
+#include "virerror.h"
+#include "virrandom.h"
+#include "virstring.h"
+#include "virgettext.h"
+#include "runio.h"
+
+#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;
+}
+
+
+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;
+}
diff --git a/src/util/runio.h b/src/util/runio.h
new file mode 100644
index 0000000000..beb58606c9
--- /dev/null
+++ b/src/util/runio.h
@@ -0,0 +1,23 @@
+/*
+ * runio.h: I/O copy function
+ *
+ * Copyright (C) 2011-2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+off_t runIO(const char *path, int fd, int oflags);
-- 
2.34.1



More information about the libvir-list mailing list