[libvirt RFCv11 05/33] virfile: virFileDiskCopy: prepare for O_DIRECT files without wrapper

Claudio Fontana cfontana at suse.de
Tue Jun 7 09:19:08 UTC 2022


we will allow to use already open fds that are not empty
for both read and write, as long as they are properly aligned.

Adapt the truncation to take into account the initial offset.

Signed-off-by: Claudio Fontana <cfontana at suse.de>
---
 src/util/virfile.c | 44 +++++++++++++++++++++++---------------------
 1 file changed, 23 insertions(+), 21 deletions(-)

diff --git a/src/util/virfile.c b/src/util/virfile.c
index 770649108f..201d7f4e64 100644
--- a/src/util/virfile.c
+++ b/src/util/virfile.c
@@ -4811,14 +4811,24 @@ runIOCopy(const struct runIOParams p)
 
         /* handle last write size align in direct case */
         if (got < buflen && p.isDirect && p.isWrite) {
-            if (virFileDirectWrite(p.fdout, buf, got) < 0) {
+            ssize_t nwritten = virFileDirectWrite(p.fdout, buf, got);
+            if (nwritten < 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;
+            if (!p.isBlockDev) {
+                off_t off = lseek(p.fdout, (off_t)0, SEEK_CUR);
+                if (off < 0) {
+                    virReportSystemError(errno, "%s", _("Failed to lseek to get current file offset"));
+                    return -6;
+                }
+                if (nwritten > got) {
+                    off -= nwritten - got;
+                }
+                if (ftruncate(p.fdout, off) < 0) {
+                    virReportSystemError(errno, _("Unable to truncate %s"), p.fdoutname);
+                    return -4;
+                }
             }
 
             break;
@@ -4898,23 +4908,15 @@ virFileDiskCopy(int disk_fd, const char *disk_path, int remote_fd, const char *r
                              (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) {
-            /*
-             * note: for write we do not only check that disk_fd is seekable,
-             * we also want to know that the file is empty, so we need SEEK_END.
-             */
-            if ((off = lseek(disk_fd, 0, SEEK_END)) != 0) {
-                virReportSystemError(off < 0 ? errno : EINVAL, "%s",
-                                     _("O_DIRECT write needs empty seekable file"));
-                goto cleanup;
-            }
-        } else if ((off = lseek(disk_fd, 0, SEEK_CUR)) != 0) {
-            virReportSystemError(off < 0 ? errno : EINVAL, "%s",
-                                 _("O_DIRECT read needs entire seekable file"));
+        off_t off = lseek(disk_fd, 0, SEEK_CUR);
+        if (off < 0) {
+            virReportSystemError(errno, "%s", _("O_DIRECT needs a seekable file"));
+            goto cleanup;
+        }
+        if (virFileDirectAlign(off) != off) {
+            /* we could write some zeroes, but maybe it is safer to just fail */
+            virReportSystemError(EINVAL, "%s", _("O_DIRECT attempted with unaligned file pointer"));
             goto cleanup;
         }
     }
-- 
2.26.2



More information about the libvir-list mailing list