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 <cfont...@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

Reply via email to