From nobody Tue Mar 3 04:55:56 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass(p=reject dis=none) header.from=lists.libvirt.org ARC-Seal: i=1; a=rsa-sha256; t=1771343909; cv=none; d=zohomail.com; s=zohoarc; b=FhVdY+8hUh7QEPuadA4gGNzEp8SlysU0y0To4tUxXD9+Y5vAPBvzmmVQ4/Vm5jSRIjTZEhLxSLqk9WrjW0r1SpBX5H66ynAtVhLStxcb9gZB90VZL9nicBlIibDtMlqsRMsJfzfJyC8CI/gtw1AiR4nwBIlm6GCUDq18bqhBBs0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1771343909; h=Content-Type:Content-Transfer-Encoding:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Owner:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Subject:Subject:To:To:Message-Id:Cc; bh=hGNdRi3PuJKIgcT90ZFtnEYoRmQfnR7ATVFQWsalZCg=; b=gQEg5wr5VitjeHES8ZJth89dz4UvfGzQwEO2Sn/YjFs5ojxvwCyldarvz00N9Vq9iFSJJRQ5zKzcOfbH71Qv2WpofgvSwxB6azH+LGtyNTOXw2vkkr2Te+8u8gvm2pEhEYyNPGddno72SKdD8+Nt0RIccqvuHhxVveqKsmEbrXo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1771343909710912.8942427965258; Tue, 17 Feb 2026 07:58:29 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 993) id 0ED47418F0; Tue, 17 Feb 2026 10:58:29 -0500 (EST) Received: from [172.19.199.9] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id 565E941AB1; Tue, 17 Feb 2026 10:54:29 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 993) id A0AB54193B; Tue, 17 Feb 2026 10:54:23 -0500 (EST) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id B90AD41911 for ; Tue, 17 Feb 2026 10:53:03 -0500 (EST) Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-442-8h3PfWvUNOWsXzRoaTNvFA-1; Tue, 17 Feb 2026 10:53:02 -0500 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 4CC351956058 for ; Tue, 17 Feb 2026 15:53:01 +0000 (UTC) Received: from speedmetal.lan (unknown [10.45.242.39]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 9A5841800590 for ; Tue, 17 Feb 2026 15:53:00 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-4.7 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HELO_MISC_IP,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED,RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED,SPF_PASS autolearn=unavailable autolearn_force=no version=4.0.1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1771343583; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=hGNdRi3PuJKIgcT90ZFtnEYoRmQfnR7ATVFQWsalZCg=; b=LZLk06vjEVThzeLuTSFSC5PmaUY005e3+Va9GPS+VmKpSdqATDbdiT48kVuGFzfbTUKwc0 nDGEYALOBkXPdl1rOyzIsNimy3CK6paKH/422gSRXRIsNUuC4TkZiLWLb4tk0JvjrWCkdY BLObpQ9ANUAtL0w2nbL9uW3S7TzrJXA= X-MC-Unique: 8h3PfWvUNOWsXzRoaTNvFA-1 X-Mimecast-MFC-AGG-ID: 8h3PfWvUNOWsXzRoaTNvFA_1771343581 To: devel@lists.libvirt.org Subject: [PATCH 6/6] qemu: saveimage: Use 'virFileWrapperFd' when loading non-sparse saveimage Date: Tue, 17 Feb 2026 16:52:51 +0100 Message-ID: <47d236108cc8e0c4b513a09bb550102353b283d8.1771343375.git.pkrempa@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 7vl4Gq_Vz1K4O8vSHY_HQNQVGnmexz8s-99CvZn9b6E_1771343581 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: OQEXFDBHTB6I23FLPVVQ2GMVZTLXQNAF X-Message-ID-Hash: OQEXFDBHTB6I23FLPVVQ2GMVZTLXQNAF X-MailFrom: pkrempa@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Peter Krempa via Devel Reply-To: Peter Krempa X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1771343911017154100 Content-Type: text/plain; charset="utf-8" From: Peter Krempa Always instantiate a 'virFileWrapperFd' (iohelper) to wrap the saveimage file descriptor of a non-'sparse' format saveimage. For 'sparse' images we also need to ensure that the FD returned when opening the save image is an actual file FD (thus not the FD from the helper process used to bypass root-squashed NFS) as qemu requires an actual file in those cases. This patch reworks 'qemuSaveImageOpen' to create the wrapper process based on whether the 'wrapperFd' variable is non-NULL rather than based on a combination of 'sparse' and 'bypass_cache' flags. The caller will then based on the image format and the need for the wrapper use the appropriate settings. As with this patch all non-sparse images will always pass a pipe instead of a file to qemu it also fixes problems with qemu-11.0 where the 'fd' migration protocol rejects FDs which point to a file. Resolves: https://issues.redhat.com/browse/RHEL-76301 Closes: https://gitlab.com/libvirt/libvirt/-/issues/850 Signed-off-by: Peter Krempa --- src/qemu/qemu_driver.c | 32 ++++++++++++++++++++++++++------ src/qemu/qemu_saveimage.c | 24 +++++++++++++----------- src/qemu/qemu_saveimage.h | 4 +++- src/qemu/qemu_snapshot.c | 12 ++++++++++-- 4 files changed, 52 insertions(+), 20 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index c2d810c013..03cdbd9dc3 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -5813,6 +5813,7 @@ qemuDomainRestoreInternal(virConnectPtr conn, bool hook_taint =3D false; bool reset_nvram =3D false; bool sparse =3D false; + bool bypass_cache =3D (flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) !=3D 0; g_autoptr(qemuMigrationParams) restoreParams =3D NULL; virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE | @@ -5844,11 +5845,30 @@ qemuDomainRestoreInternal(virConnectPtr conn, (flags & VIR_DOMAIN_S= AVE_BYPASS_CACHE)))) goto cleanup; - fd =3D qemuSaveImageOpen(driver, path, - (flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) !=3D 0, - sparse, &wrapperFd, false); - if (fd < 0) - goto cleanup; + if (sparse) { + if ((fd =3D qemuSaveImageOpen(driver, path, bypass_cache, NULL, fa= lse)) < 0) + goto cleanup; + + /* In sparse mode the FD needs to be a real file as qemu accesses = it + * directly thus: + * - ensure that we actualy got a file FD + * - there's no need to seek it as qemu does it itself + */ + if (!virFileFDIsRegular(fd)) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("path '%1$s' can't be opened directly (withou= t the use of helper proces) which is incompatible with 'sparse' save image"= ), + path); + goto cleanup; + } + } else { + if ((fd =3D qemuSaveImageOpen(driver, path, bypass_cache, &wrapper= Fd, false)) < 0) + goto cleanup; + + /* When virFileWrapperFD is used 'fd' can't be seeked so to make it + * point to the data read the header */ + if (qemuSaveImageFDSkipHeader(fd) < 0) + goto cleanup; + } if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) { int hookret; @@ -6039,7 +6059,7 @@ qemuDomainSaveImageDefineXML(virConnectPtr conn, cons= t char *path, conn, &def, &data) < 0) goto cleanup; - fd =3D qemuSaveImageOpen(driver, path, false, false, NULL, true); + fd =3D qemuSaveImageOpen(driver, path, false, NULL, true); if (fd < 0) goto cleanup; diff --git a/src/qemu/qemu_saveimage.c b/src/qemu/qemu_saveimage.c index a3519f8538..64fbcd5f51 100644 --- a/src/qemu/qemu_saveimage.c +++ b/src/qemu/qemu_saveimage.c @@ -312,6 +312,13 @@ qemuSaveImageReadHeader(int fd, virQEMUSaveData **ret_= data) } +int +qemuSaveImageFDSkipHeader(int fd) +{ + return qemuSaveImageReadHeader(fd, NULL); +} + + /** * qemuSaveImageDecompressionStart: * @data: data from memory state file @@ -697,7 +704,6 @@ qemuSaveImageGetMetadata(virQEMUDriver *driver, * @driver: qemu driver data * @path: path of the save image * @bypass_cache: bypass cache when opening the file - * @sparse: Image contains mapped-ram save format * @wrapperFd: returns the file wrapper structure * @open_write: open the file for writing (for updates) * @@ -707,7 +713,6 @@ int qemuSaveImageOpen(virQEMUDriver *driver, const char *path, bool bypass_cache, - bool sparse, virFileWrapperFd **wrapperFd, bool open_write) { @@ -729,16 +734,13 @@ qemuSaveImageOpen(virQEMUDriver *driver, if ((fd =3D qemuDomainOpenFile(cfg, NULL, path, oflags, NULL)) < 0) return -1; - /* If sparse, no need for the iohelper or positioning the file pointer= . */ - if (!sparse) { - if (bypass_cache && - !(*wrapperFd =3D virFileWrapperFdNew(&fd, path, - VIR_FILE_WRAPPER_BYPASS_CAC= HE))) - return -1; + if (wrapperFd) { + unsigned int fdflags =3D VIR_FILE_WRAPPER_NON_BLOCKING; + + if (bypass_cache) + fdflags |=3D VIR_FILE_WRAPPER_BYPASS_CACHE; - /* Read the header to position the file pointer for QEMU. Unfortun= ately we - * can't use lseek with virFileWrapperFD. */ - if (qemuSaveImageReadHeader(fd, NULL) < 0) + if (!(*wrapperFd =3D virFileWrapperFdNew(&fd, path, fdflags))) return -1; } diff --git a/src/qemu/qemu_saveimage.h b/src/qemu/qemu_saveimage.h index 887545899f..0d5a383212 100644 --- a/src/qemu/qemu_saveimage.h +++ b/src/qemu/qemu_saveimage.h @@ -92,7 +92,6 @@ int qemuSaveImageOpen(virQEMUDriver *driver, const char *path, bool bypass_cache, - bool sparse, virFileWrapperFd **wrapperFd, bool open_write) ATTRIBUTE_NONNULL(2); @@ -127,6 +126,9 @@ qemuSaveImageCreate(virDomainObj *vm, unsigned int flags, virDomainAsyncJob asyncJob); +int +qemuSaveImageFDSkipHeader(int fd); + int virQEMUSaveDataWrite(virQEMUSaveData *data, int fd, diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c index 70e4c37144..82ae38ca29 100644 --- a/src/qemu/qemu_snapshot.c +++ b/src/qemu/qemu_snapshot.c @@ -2423,6 +2423,7 @@ qemuSnapshotRevertWriteMetadata(virDomainObj *vm, typedef struct _qemuSnapshotRevertMemoryData { int fd; char *path; + virFileWrapperFd *wrapperFd; virQEMUSaveData *data; } qemuSnapshotRevertMemoryData; @@ -2430,6 +2431,8 @@ static void qemuSnapshotClearRevertMemoryData(qemuSnapshotRevertMemoryData *memdata) { VIR_FORCE_CLOSE(memdata->fd); + ignore_value(virFileWrapperFdClose(memdata->wrapperFd)); + virFileWrapperFdFree(memdata->wrapperFd); virQEMUSaveDataFree(memdata->data); } G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(qemuSnapshotRevertMemoryData, qemuSnapsho= tClearRevertMemoryData); @@ -2506,10 +2509,15 @@ qemuSnapshotRevertExternalPrepare(virDomainObj *vm, return -1; memdata->fd =3D qemuSaveImageOpen(driver, memdata->path, - false, false, NULL, false); + false, &memdata->wrapperFd, false); if (memdata->fd < 0) return -1; + /* If 'wrapperFd' is used the FD can't be seeked so we need to make + * it point to the actual data, thus seek across the header */ + if (qemuSaveImageFDSkipHeader(memdata->fd) < 0) + return -1; + if (!virDomainDefCheckABIStability(savedef, domdef, driver->xmlopt= )) return -1; } @@ -2705,7 +2713,7 @@ qemuSnapshotRevertActive(virDomainObj *vm, bool defined =3D false; int rc; g_autoptr(virDomainSnapshotDef) tmpsnapdef =3D NULL; - g_auto(qemuSnapshotRevertMemoryData) memdata =3D { -1, NULL, NULL }; + g_auto(qemuSnapshotRevertMemoryData) memdata =3D { .fd =3D -1 }; bool started =3D false; start_flags |=3D VIR_QEMU_PROCESS_START_PAUSED; --=20 2.53.0