From nobody Mon Feb 9 16:00:54 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) client-ip=170.10.129.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=fail(p=none dis=none) header.from=suse.de Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by mx.zohomail.com with SMTPS id 1654593666167343.9430320041952; Tue, 7 Jun 2022 02:21:06 -0700 (PDT) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-515-h3lrXgQEOSuuUNEeP-KaNw-1; Tue, 07 Jun 2022 05:21:00 -0400 Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 60C8580B71A; Tue, 7 Jun 2022 09:20:58 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (unknown [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4667F492C3B; Tue, 7 Jun 2022 09:20:58 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id C436C19451EF; Tue, 7 Jun 2022 09:20:57 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.rdu2.redhat.com [10.11.54.8]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 2917119452D2 for ; Tue, 7 Jun 2022 09:20:56 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id 1B396C23DBF; Tue, 7 Jun 2022 09:20:56 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast06.extmail.prod.ext.rdu2.redhat.com [10.11.55.22]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 174E5C15E72 for ; Tue, 7 Jun 2022 09:20:56 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [205.139.110.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id EFEB5185A7A4 for ; Tue, 7 Jun 2022 09:20:55 +0000 (UTC) Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-588-IzYDd_lWO1CCyoIBLabqgA-1; Tue, 07 Jun 2022 05:20:54 -0400 Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 52C171F8C3; Tue, 7 Jun 2022 09:19:45 +0000 (UTC) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 1CE1413638; Tue, 7 Jun 2022 09:19:45 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id 0L9qBTEYn2IoLwAAMHmgww (envelope-from ); Tue, 07 Jun 2022 09:19:45 +0000 X-MC-Unique: h3lrXgQEOSuuUNEeP-KaNw-1 X-Original-To: libvir-list@listman.corp.redhat.com X-MC-Unique: IzYDd_lWO1CCyoIBLabqgA-1 From: Claudio Fontana To: =?UTF-8?q?Daniel=20P=20=2E=20Berrang=C3=A9?= Subject: [libvirt RFCv11 14/33] virfile: add new API virFileDiskCopyChannel Date: Tue, 7 Jun 2022 11:19:17 +0200 Message-Id: <20220607091936.7948-15-cfontana@suse.de> In-Reply-To: <20220607091936.7948-1-cfontana@suse.de> References: <20220607091936.7948-1-cfontana@suse.de> MIME-Version: 1.0 X-Mimecast-Impersonation-Protect: Policy=CLT - Impersonation Protection Definition; Similar Internal Domain=false; Similar Monitored External Domain=false; Custom External Domain=false; Mimecast External Domain=false; Newly Observed Domain=false; Internal User Name=false; Custom Display Name List=false; Reply-to Address Mismatch=false; Targeted Threat Dictionary=false; Mimecast Threat Dictionary=false; Custom Threat Dictionary=false X-Scanned-By: MIMEDefang 2.85 on 10.11.54.8 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: libvir-list@redhat.com, Claudio Fontana , "Dr . David Alan Gilbert" , Anthony Iliopoulos Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 2.85 on 10.11.54.10 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1654593667855100001 Content-Type: text/plain; charset="utf-8"; x-default="true" allow interleaved parallel write to a single file, using a record size equal to the io buffer size (1MB). Signed-off-by: Claudio Fontana --- src/util/iohelper.c | 3 + src/util/virfile.c | 151 +++++++++++++++++++++++++++++--------------- src/util/virfile.h | 2 + 3 files changed, 106 insertions(+), 50 deletions(-) diff --git a/src/util/iohelper.c b/src/util/iohelper.c index 055540c8c4..dcbdda366f 100644 --- a/src/util/iohelper.c +++ b/src/util/iohelper.c @@ -85,6 +85,9 @@ main(int argc, char **argv) if (fd < 0 || virFileDiskCopy(fd, path, -1, "stdio") < 0) goto error; =20 + if (VIR_CLOSE(fd) < 0) + goto error; + return 0; =20 error: diff --git a/src/util/virfile.c b/src/util/virfile.c index 201d7f4e64..f9ae7d94c4 100644 --- a/src/util/virfile.c +++ b/src/util/virfile.c @@ -4761,6 +4761,9 @@ struct runIOParams { const char *fdinname; int fdout; const char *fdoutname; + int idx; + int nchannels; + off_t total; }; =20 /** @@ -4779,12 +4782,18 @@ runIOCopy(const struct runIOParams p) off_t total =3D 0; size_t buflen =3D 1024*1024; char *buf =3D virFileDirectBufferNew(&base, buflen); + int diskfd =3D p.isWrite ? p.fdout : p.fdin; =20 if (!buf) { virReportSystemError(errno, _("Failed to allocate aligned memory i= n function %s"), __FUNCTION__); return -5; } - + if (p.idx >=3D 0) { + if (lseek(diskfd, p.idx * buflen, SEEK_CUR) < 0) { + virReportSystemError(errno, "%s", _("Failed to lseek to file c= hannel offset")); + return -6; + } + } while (1) { ssize_t got; =20 @@ -4808,7 +4817,12 @@ runIOCopy(const struct runIOParams p) break; =20 total +=3D got; - + if (p.idx >=3D 0 && !p.isWrite && total > p.total) { + /* do not write to socket too much for this channel, according= to CLIA */ + off_t difference =3D total - p.total; + got -=3D difference; + total -=3D difference; + } /* handle last write size align in direct case */ if (got < buflen && p.isDirect && p.isWrite) { ssize_t nwritten =3D virFileDirectWrite(p.fdout, buf, got); @@ -4816,7 +4830,7 @@ runIOCopy(const struct runIOParams p) virReportSystemError(errno, _("Unable to write %s"), p.fdo= utname); return -3; } - if (!p.isBlockDev) { + if (!p.isBlockDev && p.idx < 0) { off_t off =3D lseek(p.fdout, (off_t)0, SEEK_CUR); if (off < 0) { virReportSystemError(errno, "%s", _("Failed to lseek t= o get current file offset")); @@ -4824,6 +4838,7 @@ runIOCopy(const struct runIOParams p) } if (nwritten > got) { off -=3D nwritten - got; + total -=3D nwritten - got; } if (ftruncate(p.fdout, off) < 0) { virReportSystemError(errno, _("Unable to truncate %s")= , p.fdoutname); @@ -4838,51 +4853,61 @@ runIOCopy(const struct runIOParams p) virReportSystemError(errno, _("Unable to write %s"), p.fdoutna= me); return -3; } + if (p.idx >=3D 0) { + if (!p.isWrite && total >=3D p.total) { + /* done for this channel */ + break; + } + /* move channel cursor to the next record */ + if (lseek(diskfd, buflen * (p.nchannels - 1), SEEK_CUR) < 0) { + virReportSystemError(errno, "%s", _("Failed to lseek to ne= xt channel record")); + return -7; + } + } } return total; } =20 /** - * virFileDiskCopy: run IO to copy data between storage and a pipe or sock= et. - * - * @disk_fd: the already open regular file or block device - * @disk_path: the pathname corresponding to disk_fd (for error reportin= g) - * @remote_fd: the pipe or socket - * Use -1 to auto-choose between STDIN or STDOUT. - * @remote_path: the pathname corresponding to remote_fd (for error report= ing) - * - * Note that the direction of the transfer is detected based on the @disk_= fd - * file access mode (man 2 open). Therefore @disk_fd must be opened with - * O_RDONLY or O_WRONLY. O_RDWR is not supported. - * - * virFileDiskCopy always closes the file descriptor disk_fd, - * and any error during close(2) is reported and considered a failure. - * - * Returns: bytes transferred or < 0 on failure. + * virFileDiskCopyChannel: like virFileDiskCopy, channel interleaved read/= write + * ... + * @idx: channel index + * @nchannels: total number of channels */ =20 off_t -virFileDiskCopy(int disk_fd, const char *disk_path, int remote_fd, const c= har *remote_path) +virFileDiskCopyChannel(int disk_fd, const char *disk_path, int remote_fd, = const char *remote_path, + int idx, int nchannels, off_t total) { - int ret =3D -1; - off_t total =3D 0; + off_t new_total =3D -1; struct stat sb; struct runIOParams p; int oflags =3D -1; =20 + if ((nchannels =3D=3D 0) || + (nchannels > 0 && idx >=3D nchannels) || + (nchannels > 0 && idx < 0) || + (nchannels < 0 && idx >=3D 0)) { + virReportSystemError(EINVAL, "%s", _("Invalid channel arguments")); + goto out; + } + p.idx =3D idx; + p.nchannels =3D nchannels; + p.total =3D total; + oflags =3D fcntl(disk_fd, F_GETFL); =20 if (oflags < 0) { virReportSystemError(errno, _("unable to determine access mode of %s"), disk_path); - goto cleanup; + goto out; } if (fstat(disk_fd, &sb) < 0) { virReportSystemError(errno, _("unable to stat file descriptor %d path %s"= ), disk_fd, disk_path); - goto cleanup; + goto out; } p.isBlockDev =3D S_ISBLK(sb.st_mode); p.isDirect =3D O_DIRECT && (oflags & O_DIRECT); @@ -4906,53 +4931,79 @@ virFileDiskCopy(int disk_fd, const char *disk_path,= int remote_fd, const char *r default: virReportSystemError(EINVAL, _("Unable to process file with flags = %d"), (oflags & O_ACCMODE)); - goto cleanup; + goto out; } if (!p.isBlockDev && p.isDirect) { off_t off =3D lseek(disk_fd, 0, SEEK_CUR); if (off < 0) { virReportSystemError(errno, "%s", _("O_DIRECT needs a seekable= file")); - goto cleanup; + goto out; } if (virFileDirectAlign(off) !=3D off) { /* we could write some zeroes, but maybe it is safer to just f= ail */ virReportSystemError(EINVAL, "%s", _("O_DIRECT attempted with = unaligned file pointer")); - goto cleanup; + goto out; } } - total =3D runIOCopy(p); - if (total < 0) - goto cleanup; - - /* Ensure all data is written */ - if (virFileDataSync(p.fdout) < 0) { - if (errno !=3D EINVAL && errno !=3D EROFS) { - /* fdatasync() may fail on some special FDs, e.g. pipes */ - virReportSystemError(errno, _("unable to fsync %s"), p.fdoutna= me); - goto cleanup; + new_total =3D runIOCopy(p); + if (new_total < 0) + goto out; + + if (p.idx < 0 && p.isWrite) { + /* without channels we can run the fdatasync here */ + if (virFileDataSync(disk_fd) < 0) { + if (errno !=3D EINVAL && errno !=3D EROFS) { + virReportSystemError(errno, _("unable to fsyncdata %s"), p= .fdoutname); + new_total =3D -1; + goto out; + } } } =20 - ret =3D 0; - - cleanup: - if (VIR_CLOSE(disk_fd) < 0 && ret =3D=3D 0) { - virReportSystemError(errno, _("Unable to close %s"), disk_path); - ret =3D -1; - } - return ret; + out: + return new_total; } =20 #else /* WIN32 */ =20 off_t -virFileDiskCopy(int disk_fd G_GNUC_UNUSED, - const char *disk_path G_GNUC_UNUSED, - int remote_fd G_GNUC_UNUSED, - const char *remote_path G_GNUC_UNUSED) +virFileDiskCopyChannel(int disk_fd G_GNUC_UNUSED, + const char *disk_path G_GNUC_UNUSED, + int remote_fd G_GNUC_UNUSED, + const char *remote_path G_GNUC_UNUSED, + int idx G_GNUC_UNUSED, + int nchannels G_GNUC_UNUSED, + off_t total G_GNUC_UNUSED) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("virFileDiskCopy unsupported on this platform")); + _("virFileDiskCopyChannel unsupported on this platform"= )); return -1; } #endif /* WIN32 */ + +/** + * virFileDiskCopy: run IO to copy data between storage and a pipe or sock= et. + * + * @disk_fd: the already open regular file or block device + * @disk_path: the pathname corresponding to disk_fd (for error reportin= g) + * @remote_fd: the pipe or socket + * Use -1 to auto-choose between STDIN or STDOUT. + * @remote_path: the pathname corresponding to remote_fd (for error report= ing) + * + * Note that the direction of the transfer is detected based on the @disk_= fd + * file access mode (man 2 open). Therefore @disk_fd must be opened with + * O_RDONLY or O_WRONLY. O_RDWR is not supported. + * + * virFileDiskCopy always closes the file descriptor disk_fd, + * and any error during close(2) is reported and considered a failure. + * + * Returns: bytes transferred or < 0 on failure. + */ + +off_t +virFileDiskCopy(int disk_fd, const char *disk_path, + int remote_fd, const char *remote_path) +{ + return virFileDiskCopyChannel(disk_fd, disk_path, remote_fd, remote_pa= th, + -1, -1, 0); +} diff --git a/src/util/virfile.h b/src/util/virfile.h index 844261e0a4..4d75389c84 100644 --- a/src/util/virfile.h +++ b/src/util/virfile.h @@ -394,3 +394,5 @@ int virFileSetCOW(const char *path, virTristateBool state); =20 off_t virFileDiskCopy(int disk_fd, const char *disk_path, int remote_fd, c= onst char *remote_path); +off_t virFileDiskCopyChannel(int disk_fd, const char *disk_path, int remot= e_fd, const char *remote_path, + int idx, int nchannels, off_t total); --=20 2.26.2