From nobody Tue Feb 10 04:13:14 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; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1693518427; cv=none; d=zohomail.com; s=zohoarc; b=PsSJGEThtxdfPiKA6wUSWLfAVg+xD3Zo+/EXiA5HjL2rOhpdPGIb/g2K/78AKA3DhN+nUFyjOBHKnNGzzp13aLwAwdUXymRxScgJ4dPrxtST+SbmZJ0D7bFedtiiAtT5EY2M/Dx0k+xg0DFipKxqS3mMMmhCIandZOR+2kzVoeU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1693518427; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=kWEmYkdBi2zPSZhhCEmTk3nn8kjz8JNfaLmwG8hWpNQ=; b=QkMh8F+r8sTbJMoVdMex961xQn849eqe/eYTqSQwU/UXcHIs3cWpiZAmXTJAmb+IZhvoj9cc65qIIZ92jpcL83WmgAuAMRzodEXFKYrswE5QtyJqVAEkH7U8yn7LRQ/H+eZMg9BC82VafE3OnyF3GLnFa3pyhU5H+DjBuLnKdHk= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) 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 1693518427056236.17375503032054; Thu, 31 Aug 2023 14:47:07 -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-84-QECNRQQZNuKpTao1LkzpDw-1; Thu, 31 Aug 2023 17:40:49 -0400 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.rdu2.redhat.com [10.11.54.8]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 7E862800303; Thu, 31 Aug 2023 21:40:45 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 68F87C15BAE; Thu, 31 Aug 2023 21:40:45 +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 3DD15194E117; Thu, 31 Aug 2023 21:40:31 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 621DB1946A61 for ; Thu, 31 Aug 2023 21:40:20 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id 46BE6492C18; Thu, 31 Aug 2023 21:40:20 +0000 (UTC) Received: from himantopus.redhat.com (unknown [10.22.17.68]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 1B170492C13; Thu, 31 Aug 2023 21:40:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1693518426; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=kWEmYkdBi2zPSZhhCEmTk3nn8kjz8JNfaLmwG8hWpNQ=; b=JVu22YxGh9FZHYq4rlgk/JjaxlRYRSEl8/bVu3BZWaksd0AKgJenR53M3w9VEVI7GVO12a 0JVr5ViEKFX9IDMMnYBLG56CDfJn1ubk/j7ahrfFvCkKQ2E3xwPyABnqIaNm9fKzG5GjH4 30p7cLagIEnztQ2cdBkz8qyLZOxZ97U= X-MC-Unique: QECNRQQZNuKpTao1LkzpDw-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Jonathon Jongsma To: libvir-list@redhat.com Subject: [libvirt PATCH v8 06/37] qemu: implement persistent file cache for nbdkit caps Date: Thu, 31 Aug 2023 16:39:46 -0500 Message-ID: <20230831214017.1536388-7-jjongsma@redhat.com> In-Reply-To: <20230831214017.1536388-1-jjongsma@redhat.com> References: <20230831214017.1536388-1-jjongsma@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.9 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: Peter Krempa Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 3.1 on 10.11.54.8 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1693518427283100001 Content-Type: text/plain; charset="utf-8"; x-default="true" Implement the loadFile and saveFile virFileCacheHandlers callbacks so that nbdkit capabilities are cached perstistently across daemon restarts. The format and implementation is modeled on the qemu capabilities, but simplified slightly. Signed-off-by: Jonathon Jongsma Reviewed-by: Peter Krempa --- po/POTFILES | 1 + src/qemu/qemu_nbdkit.c | 226 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 225 insertions(+), 2 deletions(-) diff --git a/po/POTFILES b/po/POTFILES index 5d6ec195b4..6167f98ac5 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -181,6 +181,7 @@ src/qemu/qemu_monitor.c src/qemu/qemu_monitor_json.c src/qemu/qemu_monitor_text.c src/qemu/qemu_namespace.c +src/qemu/qemu_nbdkit.c src/qemu/qemu_passt.c src/qemu/qemu_process.c src/qemu/qemu_qapi.c diff --git a/src/qemu/qemu_nbdkit.c b/src/qemu/qemu_nbdkit.c index 9828f562f7..97612b637f 100644 --- a/src/qemu/qemu_nbdkit.c +++ b/src/qemu/qemu_nbdkit.c @@ -312,11 +312,233 @@ virNbdkitCapsNewData(const char *binary, } =20 =20 +static int +qemuNbdkitCapsValidateBinary(qemuNbdkitCaps *nbdkitCaps, + xmlXPathContextPtr ctxt) +{ + g_autofree char *str =3D NULL; + + if (!(str =3D virXPathString("string(./path)", ctxt))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing path in nbdkit capabilities cache")); + return -1; + } + + if (STRNEQ(str, nbdkitCaps->path)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Expected caps for '%1$s' but saw '%2$s'"), + nbdkitCaps->path, str); + return -1; + } + + return 0; +} + + +static int +qemuNbdkitCapsParseFlags(qemuNbdkitCaps *nbdkitCaps, + xmlXPathContextPtr ctxt) +{ + g_autofree xmlNodePtr *nodes =3D NULL; + size_t i; + int n; + + if ((n =3D virXPathNodeSet("./flag", ctxt, &nodes)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse qemu capabilities flags")); + return -1; + } + + VIR_DEBUG("Got flags %d", n); + for (i =3D 0; i < n; i++) { + unsigned int flag; + + if (virXMLPropEnum(nodes[i], "name", qemuNbdkitCapsTypeFromString, + VIR_XML_PROP_REQUIRED, &flag) < 0) + return -1; + + qemuNbdkitCapsSet(nbdkitCaps, flag); + } + + return 0; +} + + +/* + * Parsing a doc that looks like + * + * + * /some/path + * 234235253 + * 234235253 + * 234235253 + * 234235253 + * 1002016 + * + * + * ... + * + * + * Returns 0 on success, 1 if outdated, -1 on error + */ +static int +qemuNbdkitCapsLoadCache(qemuNbdkitCaps *nbdkitCaps, + const char *filename) +{ + g_autoptr(xmlDoc) doc =3D NULL; + g_autoptr(xmlXPathContext) ctxt =3D NULL; + long long int l; + + if (!(doc =3D virXMLParse(filename, NULL, NULL, "nbdkitCaps", &ctxt, N= ULL, false))) + return -1; + + if (virXPathLongLong("string(./selfctime)", ctxt, &l) < 0) { + VIR_DEBUG("missing selfctime in nbdkit capabilities XML"); + return -1; + } + nbdkitCaps->libvirtCtime =3D (time_t)l; + + nbdkitCaps->libvirtVersion =3D 0; + virXPathUInt("string(./selfvers)", ctxt, &nbdkitCaps->libvirtVersion); + + if (nbdkitCaps->libvirtCtime !=3D virGetSelfLastChanged() || + nbdkitCaps->libvirtVersion !=3D LIBVIR_VERSION_NUMBER) { + VIR_DEBUG("Outdated capabilities in %s: libvirt changed (%lld vs %= lld, %lu vs %lu), stopping load", + nbdkitCaps->path, + (long long)nbdkitCaps->libvirtCtime, + (long long)virGetSelfLastChanged(), + (unsigned long)nbdkitCaps->libvirtVersion, + (unsigned long)LIBVIR_VERSION_NUMBER); + return 1; + } + + if (qemuNbdkitCapsValidateBinary(nbdkitCaps, ctxt) < 0) + return -1; + + if (virXPathLongLong("string(./nbdkitctime)", ctxt, &l) < 0) { + VIR_DEBUG("missing nbdkitctime in nbdkit capabilities XML"); + return -1; + } + nbdkitCaps->ctime =3D (time_t)l; + + if (virXPathLongLong("string(./plugindirmtime)", ctxt, &l) < 0) { + VIR_DEBUG("missing plugindirmtime in nbdkit capabilities XML"); + return -1; + } + nbdkitCaps->pluginDirMtime =3D (time_t)l; + + if (virXPathLongLong("string(./filterdirmtime)", ctxt, &l) < 0) { + VIR_DEBUG("missing filterdirmtime in nbdkit capabilities XML"); + return -1; + } + nbdkitCaps->filterDirMtime =3D (time_t)l; + + if (qemuNbdkitCapsParseFlags(nbdkitCaps, ctxt) < 0) + return -1; + + if ((nbdkitCaps->version =3D virXPathString("string(./version)", ctxt)= ) =3D=3D NULL) { + VIR_DEBUG("missing version in nbdkit capabilities cache"); + return -1; + } + + return 0; +} + + +static void* +virNbdkitCapsLoadFile(const char *filename, + const char *binary, + void *privData G_GNUC_UNUSED, + bool *outdated) +{ + g_autoptr(qemuNbdkitCaps) nbdkitCaps =3D qemuNbdkitCapsNew(binary); + int ret; + + if (!nbdkitCaps) + return NULL; + + ret =3D qemuNbdkitCapsLoadCache(nbdkitCaps, filename); + if (ret < 0) + return NULL; + if (ret =3D=3D 1) { + *outdated =3D true; + return NULL; + } + + return g_steal_pointer(&nbdkitCaps); +} + + +static char* +qemuNbdkitCapsFormatCache(qemuNbdkitCaps *nbdkitCaps) +{ + g_auto(virBuffer) buf =3D VIR_BUFFER_INITIALIZER; + size_t i; + + virBufferAddLit(&buf, "\n"); + virBufferAdjustIndent(&buf, 2); + + virBufferEscapeString(&buf, "%s\n", + nbdkitCaps->path); + virBufferAsprintf(&buf, "%lu\n", + nbdkitCaps->ctime); + virBufferAsprintf(&buf, "%lu\n", + nbdkitCaps->pluginDirMtime); + virBufferAsprintf(&buf, "%lu\n", + nbdkitCaps->filterDirMtime); + virBufferAsprintf(&buf, "%lu\n", + nbdkitCaps->libvirtCtime); + virBufferAsprintf(&buf, "%u\n", + nbdkitCaps->libvirtVersion); + + for (i =3D 0; i < QEMU_NBDKIT_CAPS_LAST; i++) { + if (qemuNbdkitCapsGet(nbdkitCaps, i)) { + virBufferAsprintf(&buf, "\n", + qemuNbdkitCapsTypeToString(i)); + } + } + + virBufferAsprintf(&buf, "%s\n", + nbdkitCaps->version); + + virBufferAdjustIndent(&buf, -2); + virBufferAddLit(&buf, "\n"); + + return virBufferContentAndReset(&buf); +} + + +static int +virNbdkitCapsSaveFile(void *data, + const char *filename, + void *privData G_GNUC_UNUSED) +{ + qemuNbdkitCaps *nbdkitCaps =3D data; + g_autofree char *xml =3D NULL; + + xml =3D qemuNbdkitCapsFormatCache(nbdkitCaps); + + if (virFileWriteStr(filename, xml, 0600) < 0) { + virReportSystemError(errno, + _("Failed to save '%1$s' for '%2$s'"), + filename, nbdkitCaps->path); + return -1; + } + + VIR_DEBUG("Saved caps '%s' for '%s' with (%lu, %lu)", + filename, nbdkitCaps->path, + nbdkitCaps->ctime, + nbdkitCaps->libvirtCtime); + + return 0; +} + + virFileCacheHandlers nbdkitCapsCacheHandlers =3D { .isValid =3D virNbdkitCapsIsValid, .newData =3D virNbdkitCapsNewData, - .loadFile =3D NULL, - .saveFile =3D NULL, + .loadFile =3D virNbdkitCapsLoadFile, + .saveFile =3D virNbdkitCapsSaveFile, .privFree =3D NULL, }; =20 --=20 2.41.0