From nobody Mon Feb 9 20:09:41 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=1666303168; cv=none; d=zohomail.com; s=zohoarc; b=DJtnivQ4wLlgqErSsNW34KZ6BelHWP/MaVqCQrWjT4q/aC2qk54lVImySG/N0oIfrNFqY2pOa+GErViKMZRRjDFs3zdCQly+qyp8G0wX+Q91zBbPZ1L1c0RnKJ7JR0szmXRD+lW6mTw8HZ0MMcEA/Er/i0rIgMSTWIvOu5c0mt8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1666303168; h=Content-Type:Content-Transfer-Encoding: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=fIlylQUwozfgetTl2vG+ssDjDz6JcEUp0yQD6bnvorw=; b=Ijq3FxQoxH8kbq4OecmVCWlyT26kS1Be2xzxhugZhB/DTfMoFJTMfLVn521ZdCx0lGfftRvZof1SwG5eAzF+W8VjkqsTod1cPWU/8FerqhitM7FiJchpFHw3R2jjJP05Z87SbPpg92xd0HzK7JrHOu4d1VzkEbiyQSgL6gLhpMA= 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 1666303168350188.80855509440983; Thu, 20 Oct 2022 14:59:28 -0700 (PDT) Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-557-8y7YDg_JOfqHbcYg3H7iWQ-1; Thu, 20 Oct 2022 17:59:21 -0400 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id C47963817984; Thu, 20 Oct 2022 21:59:16 +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 A8DA31402BD9; Thu, 20 Oct 2022 21:59:16 +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 DC40919465A2; Thu, 20 Oct 2022 21:59:15 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 66AE719465BA for ; Thu, 20 Oct 2022 21:59:14 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id 4922F4047AC; Thu, 20 Oct 2022 21:59:14 +0000 (UTC) Received: from himantopus.redhat.com (unknown [10.22.18.111]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 27CE24047AA for ; Thu, 20 Oct 2022 21:59:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1666303166; h=from:from:sender:sender: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:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=fIlylQUwozfgetTl2vG+ssDjDz6JcEUp0yQD6bnvorw=; b=hlQ216Xh34R2ge8cutDVyP/4rczg1m5Rp7sWh4RfYUWDe3wnOe9cfgarosyyEH6Uw6GF5L oT28YlGf9tEW7en/C6TqHaluclWgVfLt6LB+rbsOGyzZgd+eDB0mYK5hgPUE4rn8j901JO lRXUHCyPIOW4gYGiDsR/bwn4c2jUUWI= X-MC-Unique: 8y7YDg_JOfqHbcYg3H7iWQ-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Jonathon Jongsma To: libvir-list@redhat.com Subject: [libvirt PATCH v3 06/18] qemu: implement persistent file cache for nbdkit caps Date: Thu, 20 Oct 2022 16:58:57 -0500 Message-Id: <20221020215909.1751428-7-jjongsma@redhat.com> In-Reply-To: <20221020215909.1751428-1-jjongsma@redhat.com> References: <20221020215909.1751428-1-jjongsma@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.10 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: , Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 3.1 on 10.11.54.7 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: 1666303170630100002 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 --- src/qemu/qemu_nbdkit.c | 234 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 232 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_nbdkit.c b/src/qemu/qemu_nbdkit.c index 9ab048e9e1..a47e169a0f 100644 --- a/src/qemu/qemu_nbdkit.c +++ b/src/qemu/qemu_nbdkit.c @@ -317,11 +317,241 @@ 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 '%s' but saw '%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; + unsigned long lu; + + if (!(doc =3D virXMLParse(filename, NULL, NULL, "nbdkitCaps", &ctxt, N= ULL, false))) + return -1; + + if (virXPathLongLong("string(./selfctime)", ctxt, &l) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing selfctime in nbdkit capabilities XML")); + return -1; + } + nbdkitCaps->libvirtCtime =3D (time_t)l; + + nbdkitCaps->libvirtVersion =3D 0; + if (virXPathULong("string(./selfvers)", ctxt, &lu) =3D=3D 0) + nbdkitCaps->libvirtVersion =3D lu; + + 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) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing nbdkitctime in nbdkit capabilities XML")= ); + return -1; + } + nbdkitCaps->ctime =3D (time_t)l; + + if (virXPathLongLong("string(./plugindirmtime)", ctxt, &l) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing plugindirmtime in nbdkit capabilities XM= L")); + return -1; + } + nbdkitCaps->pluginDirMtime =3D (time_t)l; + + if (virXPathLongLong("string(./filterdirmtime)", ctxt, &l) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing filterdirmtime in nbdkit capabilities XM= L")); + 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) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("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, "%lld\n", + (long long)nbdkitCaps->ctime); + virBufferAsprintf(&buf, "%lld\n", + (long long)nbdkitCaps->pluginDirMtime); + virBufferAsprintf(&buf, "%lld\n", + (long long)nbdkitCaps->filterDirMtime); + virBufferAsprintf(&buf, "%lld\n", + (long long)nbdkitCaps->libvirtCtime); + virBufferAsprintf(&buf, "%lu\n", + (unsigned long)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 '%s' for '%s'"), + filename, nbdkitCaps->path); + return -1; + } + + VIR_DEBUG("Saved caps '%s' for '%s' with (%lld, %lld)", + filename, nbdkitCaps->path, + (long long)nbdkitCaps->ctime, + (long long)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.37.3