From nobody Wed May 15 00:35:40 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) client-ip=170.10.133.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.133.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=1657188485; cv=none; d=zohomail.com; s=zohoarc; b=UYg62+alWf23qiQUK3+iYKJWlM3w5VYDifPNY/d9yPEIBRcZfZ3nwuZ5mKSWoVANIWc4aVJ1HsjAZKd3sTuNvQiVk+P3EV9zIxogqq/VPe7jOR769XB9sKFK/B4Bf13tAFIpDJCfUl+emrK6Rp8UFvJ4oDPX65PnlDF1kGiKoag= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1657188485; 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=Z4lwxCjIAebUadUtQP5+MaR1HuVTrOH3J1EdRVj/uts=; b=ILnsCzx2+Znd6T8/3/wLea6RnW6Ze6GOVCRYz6KDdBu4GD3ZWL9ZrRS8FhmaycTdW6KWQW3UypuZKbH9nAv2fqspXj/FSWYXqRvdsF3thmsQzKjY6r+rtd4WtTZjbOd/7gz1rZjoi2jGKtxkyM6UDB+tGBPIDBhv7Mj7lGX8gxo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.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.133.124]) by mx.zohomail.com with SMTPS id 1657188485700883.7055822225967; Thu, 7 Jul 2022 03:08:05 -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-588-BD4cmebMPri5rnvFXUO51g-1; Thu, 07 Jul 2022 06:07:22 -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 D4FD429324A4; Thu, 7 Jul 2022 10:07:19 +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 539C2C3597A; Thu, 7 Jul 2022 10:07:18 +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 A6EF01947079; Thu, 7 Jul 2022 10:07:13 +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 A78A51947067 for ; Thu, 7 Jul 2022 10:07:11 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id 99A93C2811A; Thu, 7 Jul 2022 10:07:11 +0000 (UTC) Received: from maggie.redhat.com (unknown [10.43.2.39]) by smtp.corp.redhat.com (Postfix) with ESMTP id 42956C28129 for ; Thu, 7 Jul 2022 10:07:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1657188484; 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=Z4lwxCjIAebUadUtQP5+MaR1HuVTrOH3J1EdRVj/uts=; b=WSSmSj+Fh8s7kMnZYA2WAfF1F1mo0hj9Z9TGhfq2Pwm8QJFDR8FXd5Ga/31FdYzUuXSZdG La4Q21+UjV11hUuOzx0dfBb53cROTxl2HjB8p34x0PiJaUOnto1zX9qHYiGu1EAi0obSEF vBmeMdBlrVu6Wa0AW2SH0pvLfF4Qzgs= X-MC-Unique: BD4cmebMPri5rnvFXUO51g-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Michal Privoznik To: libvir-list@redhat.com Subject: [PATCH 1/3] domain_conf: Unexport virDomainDefPostParseDeviceIteratorData Date: Thu, 7 Jul 2022 12:07:07 +0200 Message-Id: <42c61a993286537188f847d0f1037ae5b9d03723.1657188411.git.mprivozn@redhat.com> In-Reply-To: References: MIME-Version: 1.0 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: , Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 2.85 on 10.11.54.8 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-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1657188486202100001 Content-Type: text/plain; charset="utf-8"; x-default="true" The virDomainDefPostParseDeviceIteratorData struct is exported in domain_conf.h because it's used in both domain_conf.c and domain_validate.c. However, the latter usage is not warranted, it's just a shortcut so that we don't have to introduce a similar struct just for domain_validate.c. Well, do the extra step and introduce a separate structure for domain_validate.c. This allows us to move post parse code later on. Signed-off-by: Michal Privoznik Reviewed-by: J=C3=A1n Tomko --- src/conf/domain_conf.c | 7 +++++++ src/conf/domain_conf.h | 6 ------ src/conf/domain_validate.c | 11 +++++++++-- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 2c2f23242e..c67fcd337d 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -6031,6 +6031,13 @@ virDomainDeviceDefPostParseOne(virDomainDeviceDef *d= ev, } =20 =20 +struct virDomainDefPostParseDeviceIteratorData { + virDomainXMLOption *xmlopt; + void *parseOpaque; + unsigned int parseFlags; +}; + + static int virDomainDefPostParseDeviceIterator(virDomainDef *def, virDomainDeviceDef *dev, diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 4c8c42b7eb..543b343be9 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -3302,12 +3302,6 @@ struct _virDomainXMLOption { }; G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainXMLOption, virObjectUnref); =20 -struct virDomainDefPostParseDeviceIteratorData { - virDomainXMLOption *xmlopt; - void *parseOpaque; - unsigned int parseFlags; -}; - bool virDomainSCSIDriveAddressIsUsed(const virDomainDef *def, const virDomainDeviceDriveAddress *addr); diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c index 57d4e63a26..814922cd46 100644 --- a/src/conf/domain_validate.c +++ b/src/conf/domain_validate.c @@ -1889,13 +1889,20 @@ virDomainDefValidateInternal(const virDomainDef *de= f, } =20 =20 +struct virDomainDefValidateDeviceIteratorData { + virDomainXMLOption *xmlopt; + void *parseOpaque; + unsigned int parseFlags; +}; + + static int virDomainDefValidateDeviceIterator(virDomainDef *def, virDomainDeviceDef *dev, virDomainDeviceInfo *info G_GNUC_UNUSED, void *opaque) { - struct virDomainDefPostParseDeviceIteratorData *data =3D opaque; + struct virDomainDefValidateDeviceIteratorData *data =3D opaque; return virDomainDeviceDefValidate(dev, def, data->parseFlags, data->xmlopt, data->parseOpaque); @@ -1924,7 +1931,7 @@ virDomainDefValidate(virDomainDef *def, virDomainXMLOption *xmlopt, void *parseOpaque) { - struct virDomainDefPostParseDeviceIteratorData data =3D { + struct virDomainDefValidateDeviceIteratorData data =3D { .xmlopt =3D xmlopt, .parseFlags =3D parseFlags, .parseOpaque =3D parseOpaque, --=20 2.35.1 From nobody Wed May 15 00:35:40 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) client-ip=170.10.133.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.133.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=1657188452; cv=none; d=zohomail.com; s=zohoarc; b=MZWlFrnoA+X+D78f31e9tidunOP0qHUt5aJzlW9aVvUeeSkOjc/FOtlbXgNrm3QK+5SASFOfoVrOFHQvp7PkfB+p3kRD6nO5FSyvJ0Pnj2zAp2l1we0WA59osU452UpEnp1HHBby7QpEvXSBSCOEhrp/dJT4FkV8LR4k0zoT8tg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1657188452; 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=WBZxQTxZz+1yc8BfZeYyLDJdGkQ3muDiyy5wS8LxGeg=; b=KJ49RrJDL3/QUbNkCZCW+6i8QcL8N3xUG4iYD20Zh2yh1q1MKsFOWiWfukuSBlOEFVt7Tk4pFMRea5IJCko2MoMv3OnG/LGUWyvB4Ogl/TM71Tjb+f5RUKPiyIdj3FiXnaJnAj+jTCGdUZUUxT6xUQ0bPOJAKS0fcxtj4YVKgi4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.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.133.124]) by mx.zohomail.com with SMTPS id 16571884527509.360116269481296; Thu, 7 Jul 2022 03:07:32 -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-640-YJLlF-UeMsiiWWfj4wdZFQ-1; Thu, 07 Jul 2022 06:07:21 -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 0BAFF2932482; Thu, 7 Jul 2022 10:07:20 +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 DF4D7C44AE3; Thu, 7 Jul 2022 10:07:18 +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 EA18A1947B82; Thu, 7 Jul 2022 10:07:13 +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 C04751947076 for ; Thu, 7 Jul 2022 10:07:12 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id A55CFC28129; Thu, 7 Jul 2022 10:07:12 +0000 (UTC) Received: from maggie.redhat.com (unknown [10.43.2.39]) by smtp.corp.redhat.com (Postfix) with ESMTP id D2626C2811A for ; Thu, 7 Jul 2022 10:07:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1657188451; 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=WBZxQTxZz+1yc8BfZeYyLDJdGkQ3muDiyy5wS8LxGeg=; b=dFhVc1zAAMLoCqB5/ZD6j+T9cEN6b8qOmPmrDpZ54ilWrqZUjhOtrG4qe4uYUZCqIEu1v/ UYfCtuKdI1qg1GpwEnU/eZPVfxKhFKRrjqTbVOR53kBd5BiL2s7+D5ErLnF3KHHKBMnqe+ trXZpE2fhaXzpNP2VG6V2zrMUNWwYpM= X-MC-Unique: YJLlF-UeMsiiWWfj4wdZFQ-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Michal Privoznik To: libvir-list@redhat.com Subject: [PATCH 2/3] conf: Separate domain post parse code into domain_postparse.c Date: Thu, 7 Jul 2022 12:07:08 +0200 Message-Id: <72a26953df0ac1b7189864a9bfe14267b94cda54.1657188411.git.mprivozn@redhat.com> In-Reply-To: References: MIME-Version: 1.0 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: , Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 2.85 on 10.11.54.8 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-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1657188453987100005 Content-Type: text/plain; charset="utf-8"; x-default="true" The domain post parse functions currently live in domain_conf.c which thus grows always larger. Mimic what we've done for the validation code and move the post parse code into a separate file: domain_postparse.c. I've started by moving every function with PostParse in its name into the new file and then compile hunting for helper functions only to move them as well. In the end, I've moved virDomainDefPostParse symbol in libvirt_private.syms into a new section. And while virDomainDeviceDefPostParseOne() is made 'public' in domain_postparse.h too, I'm not exporting it because it has no caller outside src/conf/ and it's unlikely it ever will. Signed-off-by: Michal Privoznik Reviewed-by: J=C3=A1n Tomko --- po/POTFILES | 1 + src/conf/domain_conf.c | 1453 +--------------------------------- src/conf/domain_conf.h | 4 - src/conf/domain_postparse.c | 1483 +++++++++++++++++++++++++++++++++++ src/conf/domain_postparse.h | 37 + src/conf/meson.build | 1 + src/libvirt_private.syms | 5 +- src/libxl/xen_xl.c | 1 + src/libxl/xen_xm.c | 1 + src/lxc/lxc_native.c | 1 + src/qemu/qemu_driver.c | 1 + src/qemu/qemu_process.c | 1 + src/vmx/vmx.c | 1 + 13 files changed, 1533 insertions(+), 1457 deletions(-) create mode 100644 src/conf/domain_postparse.c create mode 100644 src/conf/domain_postparse.h diff --git a/po/POTFILES b/po/POTFILES index faaba53c8f..9621efb0d3 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -32,6 +32,7 @@ src/conf/domain_addr.c src/conf/domain_capabilities.c src/conf/domain_conf.c src/conf/domain_event.c +src/conf/domain_postparse.c src/conf/domain_validate.c src/conf/interface_conf.c src/conf/netdev_bandwidth_conf.c diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index c67fcd337d..b639022396 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -33,6 +33,7 @@ #include "datatypes.h" #include "domain_addr.h" #include "domain_conf.h" +#include "domain_postparse.h" #include "domain_validate.h" #include "viralloc.h" #include "virxml.h" @@ -1796,49 +1797,6 @@ virDomainBlkioDeviceParseXML(xmlNodePtr root, } =20 =20 -/** - * virDomainDefCheckUnsupportedMemoryHotplug: - * @def: domain definition - * - * Returns -1 if the domain definition would enable memory hotplug via the - * tunable and reports an error. Otherwise returns 0. - */ -static int -virDomainDefCheckUnsupportedMemoryHotplug(virDomainDef *def) -{ - /* memory hotplug tunables are not supported by this driver */ - if (virDomainDefHasMemoryHotplug(def)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("memory hotplug tunables are not " - "supported by this hypervisor driver")); - return -1; - } - - return 0; -} - - -/** - * virDomainDeviceDefCheckUnsupportedMemoryDevice: - * @dev: device definition - * - * Returns -1 if the device definition describes a memory device and repor= ts an - * error. Otherwise returns 0. - */ -static int -virDomainDeviceDefCheckUnsupportedMemoryDevice(virDomainDeviceDef *dev) -{ - /* This driver doesn't yet know how to handle memory devices */ - if (dev->type =3D=3D VIR_DOMAIN_DEVICE_MEMORY) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("memory devices are not supported by this driver"= )); - return -1; - } - - return 0; -} - - bool virDomainObjTaint(virDomainObj *obj, virDomainTaintFlags taint) { @@ -4733,204 +4691,6 @@ virDomainDefHasDeviceAddress(virDomainDef *def, } =20 =20 -static int -virDomainDefRejectDuplicateControllers(virDomainDef *def) -{ - int max_idx[VIR_DOMAIN_CONTROLLER_TYPE_LAST]; - virBitmap *bitmaps[VIR_DOMAIN_CONTROLLER_TYPE_LAST] =3D { NULL }; - virDomainControllerDef *cont; - size_t nbitmaps =3D 0; - int ret =3D -1; - size_t i; - - memset(max_idx, -1, sizeof(max_idx)); - - for (i =3D 0; i < def->ncontrollers; i++) { - cont =3D def->controllers[i]; - if (cont->idx > max_idx[cont->type]) - max_idx[cont->type] =3D cont->idx; - } - - /* multiple USB controllers with the same index are allowed */ - max_idx[VIR_DOMAIN_CONTROLLER_TYPE_USB] =3D -1; - - for (i =3D 0; i < VIR_DOMAIN_CONTROLLER_TYPE_LAST; i++) { - if (max_idx[i] >=3D 0) - bitmaps[i] =3D virBitmapNew(max_idx[i] + 1); - nbitmaps++; - } - - for (i =3D 0; i < def->ncontrollers; i++) { - cont =3D def->controllers[i]; - - if (max_idx[cont->type] =3D=3D -1) - continue; - - if (virBitmapIsBitSet(bitmaps[cont->type], cont->idx)) { - virReportError(VIR_ERR_XML_ERROR, - _("Multiple '%s' controllers with index '%d'"), - virDomainControllerTypeToString(cont->type), - cont->idx); - goto cleanup; - } - ignore_value(virBitmapSetBit(bitmaps[cont->type], cont->idx)); - } - - ret =3D 0; - cleanup: - for (i =3D 0; i < nbitmaps; i++) - virBitmapFree(bitmaps[i]); - return ret; -} - -static int -virDomainDefRejectDuplicatePanics(virDomainDef *def) -{ - bool exists[VIR_DOMAIN_PANIC_MODEL_LAST]; - size_t i; - - for (i =3D 0; i < VIR_DOMAIN_PANIC_MODEL_LAST; i++) - exists[i] =3D false; - - for (i =3D 0; i < def->npanics; i++) { - virDomainPanicModel model =3D def->panics[i]->model; - if (exists[model]) { - virReportError(VIR_ERR_XML_ERROR, - _("Multiple panic devices with model '%s'"), - virDomainPanicModelTypeToString(model)); - return -1; - } - exists[model] =3D true; - } - - return 0; -} - - -static int -virDomainDefPostParseMemory(virDomainDef *def, - unsigned int parseFlags) -{ - size_t i; - unsigned long long numaMemory =3D 0; - unsigned long long hotplugMemory =3D 0; - - /* Attempt to infer the initial memory size from the sum NUMA memory s= izes - * in case ABI updates are allowed or the element wasn't spec= ified */ - if (def->mem.total_memory =3D=3D 0 || - parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE || - parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE_MIGRATION) - numaMemory =3D virDomainNumaGetMemorySize(def->numa); - - /* calculate the sizes of hotplug memory */ - for (i =3D 0; i < def->nmems; i++) - hotplugMemory +=3D def->mems[i]->size; - - if (numaMemory) { - /* update the sizes in XML if nothing was set in the XML or ABI up= date - * is supported */ - virDomainDefSetMemoryTotal(def, numaMemory + hotplugMemory); - } else { - /* verify that the sum of memory modules doesn't exceed the total - * memory. This is necessary for virDomainDefGetMemoryInitial to w= ork - * properly. */ - if (hotplugMemory > def->mem.total_memory) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("Total size of memory devices exceeds the tot= al " - "memory size")); - return -1; - } - } - - if (virDomainDefGetMemoryInitial(def) =3D=3D 0) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("Memory size must be specified via or in= the " - " configuration")); - return -1; - } - - if (def->mem.cur_balloon > virDomainDefGetMemoryTotal(def) || - def->mem.cur_balloon =3D=3D 0) - def->mem.cur_balloon =3D virDomainDefGetMemoryTotal(def); - - if ((def->mem.max_memory || def->mem.memory_slots) && - !(def->mem.max_memory && def->mem.memory_slots)) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("both maximum memory size and " - "memory slot count must be specified")); - return -1; - } - - if (def->mem.max_memory && - def->mem.max_memory < virDomainDefGetMemoryTotal(def)) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("maximum memory size must be equal or greater tha= n " - "the actual memory size")); - return -1; - } - - return 0; -} - - -static int -virDomainDefPostParseOs(virDomainDef *def) -{ - if (def->os.firmwareFeatures && - def->os.firmwareFeatures[VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_ENROLL= ED_KEYS] =3D=3D VIR_TRISTATE_BOOL_YES) { - - if (def->os.firmwareFeatures[VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_SE= CURE_BOOT] =3D=3D VIR_TRISTATE_BOOL_NO) { - virReportError(VIR_ERR_XML_DETAIL, "%s", - _("firmware feature 'enrolled-keys' cannot be e= nabled when " - "firmware feature 'secure-boot' is disabled")= ); - return -1; - } - - /* For all non-broken firmware builds, enrolled-keys implies - * secure-boot, and having the Secure Boot keys in the NVRAM file - * when the firmware doesn't support the Secure Boot feature doesn= 't - * make sense anyway. Reflect this fact explicitly in the XML */ - def->os.firmwareFeatures[VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_SECURE= _BOOT] =3D VIR_TRISTATE_BOOL_YES; - } - - if (!def->os.loader) - return 0; - - if (def->os.loader->path && - def->os.loader->type =3D=3D VIR_DOMAIN_LOADER_TYPE_NONE) { - /* By default, loader is type of 'rom' */ - def->os.loader->type =3D VIR_DOMAIN_LOADER_TYPE_ROM; - } - - return 0; -} - - -static void -virDomainDefPostParseMemtune(virDomainDef *def) -{ - size_t i; - - if (virDomainNumaGetNodeCount(def->numa) =3D=3D 0) { - /* If guest NUMA is not configured and any hugepage page has nodem= ask - * set to "0" free and clear that nodemas, otherwise we would rise - * an error that there is no guest NUMA node configured. */ - for (i =3D 0; i < def->mem.nhugepages; i++) { - ssize_t nextBit; - - if (!def->mem.hugepages[i].nodemask) - continue; - - nextBit =3D virBitmapNextSetBit(def->mem.hugepages[i].nodemask= , 0); - if (nextBit < 0) { - g_clear_pointer(&def->mem.hugepages[i].nodemask, - virBitmapFree); - } - } - } -} - - static int virDomainDefAddConsoleCompat(virDomainDef *def) { @@ -5046,96 +4806,6 @@ virDomainDefAddConsoleCompat(virDomainDef *def) } =20 =20 -static int -virDomainDefPostParseTimer(virDomainDef *def) -{ - size_t i; - - /* verify settings of guest timers */ - for (i =3D 0; i < def->clock.ntimers; i++) { - virDomainTimerDef *timer =3D def->clock.timers[i]; - - if (timer->name =3D=3D VIR_DOMAIN_TIMER_NAME_KVMCLOCK || - timer->name =3D=3D VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK) { - if (timer->tickpolicy) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("timer %s doesn't support setting of " - "timer tickpolicy"), - virDomainTimerNameTypeToString(timer->name)= ); - return -1; - } - } - - if (timer->tickpolicy !=3D VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP && - (timer->catchup.threshold !=3D 0 || - timer->catchup.limit !=3D 0 || - timer->catchup.slew !=3D 0)) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("setting of timer catchup policies is only " - "supported with tickpolicy=3D'catchup'")); - return -1; - } - - if (timer->name !=3D VIR_DOMAIN_TIMER_NAME_TSC) { - if (timer->frequency !=3D 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("timer %s doesn't support setting of " - "timer frequency"), - virDomainTimerNameTypeToString(timer->name)= ); - return -1; - } - - if (timer->mode) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("timer %s doesn't support setting of " - "timer mode"), - virDomainTimerNameTypeToString(timer->name)= ); - return -1; - } - } - - if (timer->name !=3D VIR_DOMAIN_TIMER_NAME_PLATFORM && - timer->name !=3D VIR_DOMAIN_TIMER_NAME_RTC) { - if (timer->track !=3D VIR_DOMAIN_TIMER_TRACK_NONE) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("timer %s doesn't support setting of " - "timer track"), - virDomainTimerNameTypeToString(timer->name)= ); - return -1; - } - } - } - - return 0; -} - - -static void -virDomainDefPostParseGraphics(virDomainDef *def) -{ - size_t i; - - for (i =3D 0; i < def->ngraphics; i++) { - virDomainGraphicsDef *graphics =3D def->graphics[i]; - - /* If spice graphics is configured without ports and with autoport= =3D'no' - * then we start qemu with Spice to not listen anywhere. Let's co= nvert - * this configuration to the new listen type=3D'none' which does t= he - * same. */ - if (graphics->type =3D=3D VIR_DOMAIN_GRAPHICS_TYPE_SPICE) { - virDomainGraphicsListenDef *glisten =3D &graphics->listens[0]; - - if (glisten->type =3D=3D VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRE= SS && - graphics->data.spice.port =3D=3D 0 && - graphics->data.spice.tlsPort =3D=3D 0 && - !graphics->data.spice.autoport) { - VIR_FREE(glisten->address); - glisten->type =3D VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NONE; - } - } - } -} - =20 /** * virDomainDriveAddressIsUsedByDisk: @@ -5282,1127 +4952,6 @@ virDomainSCSIDriveAddressIsUsed(const virDomainDef= *def, } =20 =20 -/* Find out the next usable "unit" of a specific controller */ -static int -virDomainControllerSCSINextUnit(const virDomainDef *def, - unsigned int controller) -{ - size_t i; - - for (i =3D 0; i < def->scsiBusMaxUnit; i++) { - /* Default to assigning addresses using bus =3D target =3D 0 */ - const virDomainDeviceDriveAddress addr =3D {controller, 0, 0, i, 0= }; - - if (!virDomainSCSIDriveAddressIsUsed(def, &addr)) - return i; - } - - return -1; -} - - -static void -virDomainHostdevAssignAddress(virDomainXMLOption *xmlopt G_GNUC_UNUSED, - const virDomainDef *def, - virDomainHostdevDef *hostdev) -{ - int next_unit =3D 0; - int controller =3D 0; - - /* NB: Do not attempt calling virDomainDefMaybeAddController to - * automagically add a "new" controller. Doing so will result in - * qemuDomainFindOrCreateSCSIDiskController "finding" the controller - * in the domain def list and thus not hotplugging the controller as - * well as the hostdev in the event that there are either no SCSI - * controllers defined or there was no space on an existing one. - * - * Because we cannot add a controller, then we should not walk the - * defined controllers list in order to find empty space. Doing - * so fails to return the valid next unit number for the 2nd - * hostdev being added to the as yet to be created controller. - */ - do { - next_unit =3D virDomainControllerSCSINextUnit(def, controller); - if (next_unit < 0) - controller++; - } while (next_unit < 0); - - - hostdev->info->type =3D VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE; - hostdev->info->addr.drive.controller =3D controller; - hostdev->info->addr.drive.bus =3D 0; - hostdev->info->addr.drive.target =3D 0; - hostdev->info->addr.drive.unit =3D next_unit; -} - - -/** - * virDomainPostParseCheckISCSIPath - * @srcpath: Source path read (a/k/a, IQN) either disk or hostdev - * - * The details of an IQN is defined by RFC 3720 and 3721, but - * we just need to make sure there's a lun provided. If not - * provided, then default to zero. For an ISCSI LUN that is - * is provided by /dev/disk/by-path/... , then that path will - * have the specific lun requested. - */ -static void -virDomainPostParseCheckISCSIPath(char **srcpath) -{ - char *path =3D NULL; - - if (strchr(*srcpath, '/')) - return; - - path =3D g_strdup_printf("%s/0", *srcpath); - g_free(*srcpath); - *srcpath =3D g_steal_pointer(&path); -} - - -static int -virDomainHostdevDefPostParse(virDomainHostdevDef *dev, - const virDomainDef *def, - virDomainXMLOption *xmlopt) -{ - virDomainHostdevSubsysSCSI *scsisrc; - virDomainDeviceDriveAddress *addr =3D NULL; - - if (dev->mode !=3D VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) - return 0; - - switch (dev->source.subsys.type) { - case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: - scsisrc =3D &dev->source.subsys.u.scsi; - if (scsisrc->protocol =3D=3D VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE= _ISCSI) { - virDomainHostdevSubsysSCSIiSCSI *iscsisrc =3D &scsisrc->u.iscs= i; - virDomainPostParseCheckISCSIPath(&iscsisrc->src->path); - } - - if (dev->info->type =3D=3D VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) - virDomainHostdevAssignAddress(xmlopt, def, dev); - - /* Ensure provided address doesn't conflict with existing - * scsi disk drive address - */ - addr =3D &dev->info->addr.drive; - if (virDomainDriveAddressIsUsedByDisk(def, - VIR_DOMAIN_DISK_BUS_SCSI, - addr)) { - virReportError(VIR_ERR_XML_ERROR, - _("SCSI host address controller=3D'%u' " - "bus=3D'%u' target=3D'%u' unit=3D'%u' in " - "use by a SCSI disk"), - addr->controller, addr->bus, - addr->target, addr->unit); - return -1; - } - break; - case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV: { - int model =3D dev->source.subsys.u.mdev.model; - - if (dev->info->type =3D=3D VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) - return 0; - - if ((model =3D=3D VIR_MDEV_MODEL_TYPE_VFIO_PCI && - dev->info->type !=3D VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) || - (model =3D=3D VIR_MDEV_MODEL_TYPE_VFIO_CCW && - dev->info->type !=3D VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)) { - virReportError(VIR_ERR_XML_ERROR, - _("Unsupported address type '%s' with mediated " - "device model '%s'"), - virDomainDeviceAddressTypeToString(dev->info->t= ype), - virMediatedDeviceModelTypeToString(model)); - return -1; - } - } - - case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: - case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: - case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST: - case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: - break; - } - - return 0; -} - - -static int -virDomainChrIsaSerialDefPostParse(virDomainDef *def) -{ - size_t i; - size_t isa_serial_count =3D 0; - bool used_serial_port[VIR_MAX_ISA_SERIAL_PORTS] =3D { false }; - - /* Perform all the required checks. */ - for (i =3D 0; i < def->nserials; i++) { - if (def->serials[i]->targetType !=3D VIR_DOMAIN_CHR_SERIAL_TARGET_= MODEL_ISA_SERIAL) - continue; - - if (isa_serial_count++ >=3D VIR_MAX_ISA_SERIAL_PORTS || - def->serials[i]->target.port >=3D VIR_MAX_ISA_SERIAL_PORTS) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Maximum supported number of ISA serial ports= is '%d'"), - VIR_MAX_ISA_SERIAL_PORTS); - return -1; - } - - if (def->serials[i]->target.port !=3D -1) { - if (used_serial_port[def->serials[i]->target.port]) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("target port '%d' already allocated"), - def->serials[i]->target.port); - return -1; - } - used_serial_port[def->serials[i]->target.port] =3D true; - } - } - - /* Assign the ports to the devices. */ - for (i =3D 0; i < def->nserials; i++) { - size_t j; - - if (def->serials[i]->targetType !=3D VIR_DOMAIN_CHR_SERIAL_TARGET_= MODEL_ISA_SERIAL || - def->serials[i]->target.port !=3D -1) - continue; - - for (j =3D 0; j < VIR_MAX_ISA_SERIAL_PORTS; j++) { - if (!used_serial_port[j]) { - def->serials[i]->target.port =3D j; - used_serial_port[j] =3D true; - break; - } - } - } - - return 0; -} - - -static int -virDomainChrDefPostParse(virDomainChrDef *chr, - const virDomainDef *def) -{ - const virDomainChrDef **arrPtr; - size_t i, cnt; - - virDomainChrGetDomainPtrs(def, chr->deviceType, &arrPtr, &cnt); - - if (chr->deviceType =3D=3D VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE && - chr->targetType =3D=3D VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE) { - chr->targetType =3D VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL; - } - - if (chr->deviceType =3D=3D VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL && - chr->targetType =3D=3D VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA_DEBUG= && - !ARCH_IS_X86(def->os.arch)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("isa-debug serial type only valid on x86 architec= ture")); - return -1; - } - - if (chr->target.port =3D=3D -1 && - (chr->deviceType =3D=3D VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL || - chr->deviceType =3D=3D VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL || - chr->deviceType =3D=3D VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE)) { - int maxport =3D -1; - - for (i =3D 0; i < cnt; i++) { - if (arrPtr[i]->target.port > maxport) - maxport =3D arrPtr[i]->target.port; - } - - chr->target.port =3D maxport + 1; - } - - return 0; -} - - -static void -virDomainRNGDefPostParse(virDomainRNGDef *rng) -{ - /* set default path for virtio-rng "random" backend to /dev/random */ - if (rng->backend =3D=3D VIR_DOMAIN_RNG_BACKEND_RANDOM && - !rng->source.file) { - rng->source.file =3D g_strdup("/dev/random"); - } -} - - -static void -virDomainDiskExpandGroupIoTune(virDomainDiskDef *disk, - const virDomainDef *def) -{ - size_t i; - - if (!disk->blkdeviotune.group_name || - virDomainBlockIoTuneInfoHasAny(&disk->blkdeviotune)) - return; - - for (i =3D 0; i < def->ndisks; i++) { - virDomainDiskDef *d =3D def->disks[i]; - - if (STRNEQ_NULLABLE(disk->blkdeviotune.group_name, d->blkdeviotune= .group_name) || - !virDomainBlockIoTuneInfoHasAny(&d->blkdeviotune)) - continue; - - - VIR_FREE(disk->blkdeviotune.group_name); - virDomainBlockIoTuneInfoCopy(&d->blkdeviotune, &disk->blkdeviotune= ); - - return; - } -} - - -static int -virDomainDiskDefPostParse(virDomainDiskDef *disk, - const virDomainDef *def, - virDomainXMLOption *xmlopt) -{ - if (disk->dst) { - char *newdst; - - /* Work around for compat with Xen driver in previous libvirt rele= ases */ - if ((newdst =3D g_strdup(STRSKIP(disk->dst, "ioemu:")))) { - g_free(disk->dst); - disk->dst =3D newdst; - } - } - - /* Force CDROM to be listed as read only */ - if (disk->device =3D=3D VIR_DOMAIN_DISK_DEVICE_CDROM) - disk->src->readonly =3D true; - - if (disk->bus =3D=3D VIR_DOMAIN_DISK_BUS_NONE) { - disk->bus =3D VIR_DOMAIN_DISK_BUS_IDE; - - if (disk->device =3D=3D VIR_DOMAIN_DISK_DEVICE_FLOPPY) { - disk->bus =3D VIR_DOMAIN_DISK_BUS_FDC; - } else if (disk->dst) { - if (STRPREFIX(disk->dst, "hd")) - disk->bus =3D VIR_DOMAIN_DISK_BUS_IDE; - else if (STRPREFIX(disk->dst, "sd")) - disk->bus =3D VIR_DOMAIN_DISK_BUS_SCSI; - else if (STRPREFIX(disk->dst, "vd")) - disk->bus =3D VIR_DOMAIN_DISK_BUS_VIRTIO; - else if (STRPREFIX(disk->dst, "xvd")) - disk->bus =3D VIR_DOMAIN_DISK_BUS_XEN; - else if (STRPREFIX(disk->dst, "ubd")) - disk->bus =3D VIR_DOMAIN_DISK_BUS_UML; - } - } - - if (disk->snapshot =3D=3D VIR_DOMAIN_SNAPSHOT_LOCATION_DEFAULT && - disk->src->readonly) - disk->snapshot =3D VIR_DOMAIN_SNAPSHOT_LOCATION_NO; - - if (disk->src->type =3D=3D VIR_STORAGE_TYPE_NETWORK && - disk->src->protocol =3D=3D VIR_STORAGE_NET_PROTOCOL_ISCSI) { - virDomainPostParseCheckISCSIPath(&disk->src->path); - } - - if (disk->src->type =3D=3D VIR_STORAGE_TYPE_NVME) { - if (disk->src->nvme->managed =3D=3D VIR_TRISTATE_BOOL_ABSENT) - disk->src->nvme->managed =3D VIR_TRISTATE_BOOL_YES; - } - - /* vhost-user doesn't allow us to snapshot, disable snapshots by defau= lt */ - if (disk->src->type =3D=3D VIR_STORAGE_TYPE_VHOST_USER && - disk->snapshot =3D=3D VIR_DOMAIN_SNAPSHOT_LOCATION_DEFAULT) { - disk->snapshot =3D VIR_DOMAIN_SNAPSHOT_LOCATION_NO; - } - - if (disk->info.type =3D=3D VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE && - disk->dst && - virDomainDiskDefAssignAddress(xmlopt, disk, def) < 0) { - return -1; - } - - virDomainDiskExpandGroupIoTune(disk, def); - - return 0; -} - - -static void -virDomainVideoDefPostParse(virDomainVideoDef *video, - const virDomainDef *def) -{ - /* Fill out (V)RAM if the driver-specific callback did not do so */ - if (video->ram =3D=3D 0 && video->type =3D=3D VIR_DOMAIN_VIDEO_TYPE_QX= L) - video->ram =3D virDomainVideoDefaultRAM(def, video->type); - if (video->vram =3D=3D 0) - video->vram =3D virDomainVideoDefaultRAM(def, video->type); - - video->ram =3D VIR_ROUND_UP_POWER_OF_TWO(video->ram); - video->vram =3D VIR_ROUND_UP_POWER_OF_TWO(video->vram); -} - - -static int -virDomainControllerDefPostParse(virDomainControllerDef *cdev) -{ - if (cdev->iothread && - cdev->model !=3D VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI && - cdev->model !=3D VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_TRANSITIO= NAL && - cdev->model !=3D VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_NON_TRANS= ITIONAL) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("'iothread' attribute only supported for " - "virtio scsi controllers")); - return -1; - } - - return 0; -} - - -static void -virDomainVsockDefPostParse(virDomainVsockDef *vsock) -{ - if (vsock->auto_cid =3D=3D VIR_TRISTATE_BOOL_ABSENT) { - if (vsock->guest_cid !=3D 0) - vsock->auto_cid =3D VIR_TRISTATE_BOOL_NO; - else - vsock->auto_cid =3D VIR_TRISTATE_BOOL_YES; - } -} - - -static int -virDomainMemoryDefPostParse(virDomainMemoryDef *mem, - const virDomainDef *def) -{ - switch (mem->model) { - case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: - /* Virtio-pmem mandates shared access so that guest writes get - * reflected in the underlying file. */ - if (mem->access =3D=3D VIR_DOMAIN_MEMORY_ACCESS_DEFAULT) - mem->access =3D VIR_DOMAIN_MEMORY_ACCESS_SHARED; - break; - - case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: - /* If no NVDIMM UUID was provided in XML, generate one. */ - if (ARCH_IS_PPC64(def->os.arch) && - !mem->uuid) { - - mem->uuid =3D g_new0(unsigned char, VIR_UUID_BUFLEN); - if (virUUIDGenerate(mem->uuid) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Failed to generate UUID")); - return -1; - } - } - break; - - case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: - case VIR_DOMAIN_MEMORY_MODEL_DIMM: - case VIR_DOMAIN_MEMORY_MODEL_NONE: - case VIR_DOMAIN_MEMORY_MODEL_LAST: - break; - } - - return 0; -} - - -static int -virDomainFSDefPostParse(virDomainFSDef *fs) -{ - if (fs->accessmode =3D=3D VIR_DOMAIN_FS_ACCESSMODE_DEFAULT && !fs->soc= k) - fs->accessmode =3D VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH; - - return 0; -} - - -static int -virDomainDeviceDefPostParseCommon(virDomainDeviceDef *dev, - const virDomainDef *def, - unsigned int parseFlags G_GNUC_UNUSED, - virDomainXMLOption *xmlopt) -{ - int ret =3D -1; - - switch ((virDomainDeviceType)dev->type) { - case VIR_DOMAIN_DEVICE_CHR: - ret =3D virDomainChrDefPostParse(dev->data.chr, def); - break; - - case VIR_DOMAIN_DEVICE_RNG: - virDomainRNGDefPostParse(dev->data.rng); - ret =3D 0; - break; - - case VIR_DOMAIN_DEVICE_DISK: - ret =3D virDomainDiskDefPostParse(dev->data.disk, def, xmlopt); - break; - - case VIR_DOMAIN_DEVICE_VIDEO: - virDomainVideoDefPostParse(dev->data.video, def); - ret =3D 0; - break; - - case VIR_DOMAIN_DEVICE_HOSTDEV: - ret =3D virDomainHostdevDefPostParse(dev->data.hostdev, def, xmlop= t); - break; - - case VIR_DOMAIN_DEVICE_CONTROLLER: - ret =3D virDomainControllerDefPostParse(dev->data.controller); - break; - - case VIR_DOMAIN_DEVICE_VSOCK: - virDomainVsockDefPostParse(dev->data.vsock); - ret =3D 0; - break; - - case VIR_DOMAIN_DEVICE_MEMORY: - ret =3D virDomainMemoryDefPostParse(dev->data.memory, def); - break; - - case VIR_DOMAIN_DEVICE_FS: - ret =3D virDomainFSDefPostParse(dev->data.fs); - break; - - case VIR_DOMAIN_DEVICE_LEASE: - case VIR_DOMAIN_DEVICE_NET: - case VIR_DOMAIN_DEVICE_INPUT: - case VIR_DOMAIN_DEVICE_SOUND: - case VIR_DOMAIN_DEVICE_WATCHDOG: - case VIR_DOMAIN_DEVICE_GRAPHICS: - case VIR_DOMAIN_DEVICE_HUB: - case VIR_DOMAIN_DEVICE_REDIRDEV: - case VIR_DOMAIN_DEVICE_SMARTCARD: - case VIR_DOMAIN_DEVICE_MEMBALLOON: - case VIR_DOMAIN_DEVICE_NVRAM: - case VIR_DOMAIN_DEVICE_SHMEM: - case VIR_DOMAIN_DEVICE_TPM: - case VIR_DOMAIN_DEVICE_PANIC: - case VIR_DOMAIN_DEVICE_IOMMU: - case VIR_DOMAIN_DEVICE_AUDIO: - ret =3D 0; - break; - - case VIR_DOMAIN_DEVICE_NONE: - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("unexpected VIR_DOMAIN_DEVICE_NONE")); - break; - - case VIR_DOMAIN_DEVICE_LAST: - default: - virReportEnumRangeError(virDomainDeviceType, dev->type); - break; - } - - return ret; -} - - -/** - * virDomainDefRemoveOfflineVcpuPin: - * @def: domain definition - * - * This function removes vcpu pinning information from offline vcpus. This= is - * designed to be used for drivers which don't support offline vcpupin. - */ -static void -virDomainDefRemoveOfflineVcpuPin(virDomainDef *def) -{ - size_t i; - virDomainVcpuDef *vcpu; - - for (i =3D 0; i < virDomainDefGetVcpusMax(def); i++) { - vcpu =3D virDomainDefGetVcpu(def, i); - - if (vcpu && !vcpu->online && vcpu->cpumask) { - g_clear_pointer(&vcpu->cpumask, virBitmapFree); - - VIR_WARN("Ignoring unsupported vcpupin for offline vcpu '%zu'"= , i); - } - } -} - - -static void -virDomainAssignControllerIndexes(virDomainDef *def) -{ - /* the index attribute of a controller is optional in the XML, but - * is required to be valid at any time after parse. When no index - * is provided for a controller, assign one automatically by - * looking at what indexes are already used for that controller - * type in the domain - the unindexed controller gets the lowest - * unused index. - */ - size_t outer; - - for (outer =3D 0; outer < def->ncontrollers; outer++) { - virDomainControllerDef *cont =3D def->controllers[outer]; - virDomainControllerDef *prev =3D NULL; - size_t inner; - - if (cont->idx !=3D -1) - continue; - - if (outer > 0 && IS_USB2_CONTROLLER(cont)) { - /* USB2 controllers are the only exception to the simple - * "assign the lowest unused index". A group of USB2 - * "companions" should all be at the same index as other - * USB2 controllers in the group, but only do this - * automatically if it appears to be the intent. To prove - * intent: the USB controller on the list just prior to - * this one must also be a USB2 controller, and there must - * not yet be a controller with the exact same model of - * this one and the same index as the previously added - * controller (e.g., if this controller is a UHCI1, then - * the previous controller must be an EHCI1 or a UHCI[23], - * and there must not already be a UHCI1 controller with - * the same index as the previous controller). If all of - * these are satisfied, set this controller to the same - * index as the previous controller. - */ - int prevIdx; - - prevIdx =3D outer - 1; - while (prevIdx >=3D 0 && - def->controllers[prevIdx]->type !=3D VIR_DOMAIN_CONTROL= LER_TYPE_USB) - prevIdx--; - if (prevIdx >=3D 0) - prev =3D def->controllers[prevIdx]; - /* if the last USB controller isn't USB2, that breaks - * the chain, so we need a new index for this new - * controller - */ - if (prev && !IS_USB2_CONTROLLER(prev)) - prev =3D NULL; - - /* if prev !=3D NULL, we've found a potential index to - * use. Make sure this index isn't already used by an - * existing USB2 controller of the same model as the new - * one. - */ - for (inner =3D 0; prev && inner < def->ncontrollers; inner++) { - if (def->controllers[inner]->type =3D=3D VIR_DOMAIN_CONTRO= LLER_TYPE_USB && - def->controllers[inner]->idx =3D=3D prev->idx && - def->controllers[inner]->model =3D=3D cont->model) { - /* we already have a controller of this model with - * the proposed index, so we need to move to a new - * index for this controller - */ - prev =3D NULL; - } - } - if (prev) - cont->idx =3D prev->idx; - } - /* if none of the above applied, prev will be NULL */ - if (!prev) - cont->idx =3D virDomainControllerFindUnusedIndex(def, cont->ty= pe); - } -} - - -#define UNSUPPORTED(FEATURE) (!((FEATURE) & xmlopt->config.features)) -/** - * virDomainDefPostParseCheckFeatures: - * @def: domain definition - * @xmlopt: XML parser option object - * - * This function checks that the domain configuration is supported accordi= ng to - * the supported features for a given hypervisor. See virDomainDefFeatures= and - * virDomainDefParserConfig. - * - * Returns 0 on success and -1 on error with an appropriate libvirt error. - */ -static int -virDomainDefPostParseCheckFeatures(virDomainDef *def, - virDomainXMLOption *xmlopt) -{ - if (UNSUPPORTED(VIR_DOMAIN_DEF_FEATURE_MEMORY_HOTPLUG) && - virDomainDefCheckUnsupportedMemoryHotplug(def) < 0) - return -1; - - if (UNSUPPORTED(VIR_DOMAIN_DEF_FEATURE_OFFLINE_VCPUPIN)) - virDomainDefRemoveOfflineVcpuPin(def); - - if (UNSUPPORTED(VIR_DOMAIN_DEF_FEATURE_NAME_SLASH)) { - if (def->name && strchr(def->name, '/')) { - virReportError(VIR_ERR_XML_ERROR, - _("name %s cannot contain '/'"), def->name); - return -1; - } - } - - if (UNSUPPORTED(VIR_DOMAIN_DEF_FEATURE_INDIVIDUAL_VCPUS) && - def->individualvcpus) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("individual CPU state configuration is not suppor= ted")); - return -1; - } - - return 0; -} - - -/** - * virDomainDeviceDefPostParseCheckFeatures: - * @dev: device definition - * @xmlopt: XML parser option object - * - * This function checks that the device configuration is supported accordi= ng to - * the supported features for a given hypervisor. See virDomainDefFeatures= and - * virDomainDefParserConfig. - * - * Returns 0 on success and -1 on error with an appropriate libvirt error. - */ -static int -virDomainDeviceDefPostParseCheckFeatures(virDomainDeviceDef *dev, - virDomainXMLOption *xmlopt) -{ - if (UNSUPPORTED(VIR_DOMAIN_DEF_FEATURE_MEMORY_HOTPLUG) && - virDomainDeviceDefCheckUnsupportedMemoryDevice(dev) < 0) - return -1; - - if (UNSUPPORTED(VIR_DOMAIN_DEF_FEATURE_NET_MODEL_STRING) && - dev->type =3D=3D VIR_DOMAIN_DEVICE_NET && - dev->data.net->modelstr) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("driver does not support net model '%s'"), - dev->data.net->modelstr); - return -1; - } - - return 0; -} -#undef UNSUPPORTED - - -static int -virDomainDeviceDefPostParse(virDomainDeviceDef *dev, - const virDomainDef *def, - unsigned int flags, - virDomainXMLOption *xmlopt, - void *parseOpaque) -{ - int ret; - - if (xmlopt->config.devicesPostParseCallback) { - ret =3D xmlopt->config.devicesPostParseCallback(dev, def, flags, - xmlopt->config.priv, - parseOpaque); - if (ret < 0) - return ret; - } - - if ((ret =3D virDomainDeviceDefPostParseCommon(dev, def, flags, xmlopt= )) < 0) - return ret; - - if (virDomainDeviceDefPostParseCheckFeatures(dev, xmlopt) < 0) - return -1; - - return 0; -} - -static int -virDomainDeviceDefPostParseOne(virDomainDeviceDef *dev, - const virDomainDef *def, - unsigned int flags, - virDomainXMLOption *xmlopt, - void *parseOpaque) -{ - void *data =3D NULL; - int ret; - - if (!parseOpaque && xmlopt->config.domainPostParseDataAlloc) { - if (xmlopt->config.domainPostParseDataAlloc(def, flags, - xmlopt->config.priv, - &data) < 0) - return -1; - parseOpaque =3D data; - } - - ret =3D virDomainDeviceDefPostParse(dev, def, flags, xmlopt, parseOpaq= ue); - - if (data && xmlopt->config.domainPostParseDataFree) - xmlopt->config.domainPostParseDataFree(data); - - return ret; -} - - -struct virDomainDefPostParseDeviceIteratorData { - virDomainXMLOption *xmlopt; - void *parseOpaque; - unsigned int parseFlags; -}; - - -static int -virDomainDefPostParseDeviceIterator(virDomainDef *def, - virDomainDeviceDef *dev, - virDomainDeviceInfo *info G_GNUC_UNUSE= D, - void *opaque) -{ - struct virDomainDefPostParseDeviceIteratorData *data =3D opaque; - return virDomainDeviceDefPostParse(dev, def, - data->parseFlags, data->xmlopt, - data->parseOpaque); -} - - -static int -virDomainVcpuDefPostParse(virDomainDef *def) -{ - virDomainVcpuDef *vcpu; - size_t maxvcpus =3D virDomainDefGetVcpusMax(def); - size_t i; - - for (i =3D 0; i < maxvcpus; i++) { - vcpu =3D virDomainDefGetVcpu(def, i); - - /* impossible but some compilers don't like it */ - if (!vcpu) - continue; - - switch (vcpu->hotpluggable) { - case VIR_TRISTATE_BOOL_ABSENT: - if (vcpu->online) - vcpu->hotpluggable =3D VIR_TRISTATE_BOOL_NO; - else - vcpu->hotpluggable =3D VIR_TRISTATE_BOOL_YES; - break; - - case VIR_TRISTATE_BOOL_NO: - if (!vcpu->online) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("vcpu '%zu' is both offline and not " - "hotpluggable"), i); - return -1; - } - break; - - case VIR_TRISTATE_BOOL_YES: - case VIR_TRISTATE_BOOL_LAST: - break; - } - } - - return 0; -} - - -static int -virDomainDefPostParseCPU(virDomainDef *def) -{ - if (!def->cpu) - return 0; - - if (def->cpu->mode =3D=3D VIR_CPU_MODE_CUSTOM && - !def->cpu->model && - def->cpu->check !=3D VIR_CPU_CHECK_DEFAULT) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("check attribute specified for CPU with no model"= )); - return -1; - } - - return 0; -} - - -static int -virDomainDefCollectBootOrder(virDomainDef *def G_GNUC_UNUSED, - virDomainDeviceDef *dev G_GNUC_UNUSED, - virDomainDeviceInfo *info, - void *data) -{ - GHashTable *bootHash =3D data; - g_autofree char *order =3D NULL; - - if (info->bootIndex =3D=3D 0) - return 0; - - if (dev->type =3D=3D VIR_DOMAIN_DEVICE_HOSTDEV && - dev->data.hostdev->parentnet) { - /* This hostdev is a child of a higher level device - * (e.g. interface), and thus already being counted on the - * list for the other device type. - */ - return 0; - } - order =3D g_strdup_printf("%u", info->bootIndex); - - if (virHashLookup(bootHash, order)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("boot order '%s' used for more than one device"), - order); - return -1; - } - - if (virHashAddEntry(bootHash, order, (void *) 1) < 0) - return -1; - - return 0; -} - - -static int -virDomainDefBootOrderPostParse(virDomainDef *def) -{ - g_autoptr(GHashTable) bootHash =3D virHashNew(NULL); - - if (virDomainDeviceInfoIterate(def, virDomainDefCollectBootOrder, boot= Hash) < 0) - return -1; - - if (def->os.nBootDevs > 0 && virHashSize(bootHash) > 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("per-device boot elements cannot be used" - " together with os/boot elements")); - return -1; - } - - if (def->os.nBootDevs =3D=3D 0 && virHashSize(bootHash) =3D=3D 0) { - def->os.nBootDevs =3D 1; - def->os.bootDevs[0] =3D VIR_DOMAIN_BOOT_DISK; - } - - return 0; -} - - -static int -virDomainDefPostParseVideo(virDomainDef *def, - void *opaque) -{ - if (def->nvideos =3D=3D 0) - return 0; - - if (def->videos[0]->type =3D=3D VIR_DOMAIN_VIDEO_TYPE_NONE) { - char *alias; - - /* we don't want to format any values we automatically fill in for - * videos into the XML, so clear them, but retain any user-assigned - * alias */ - alias =3D g_steal_pointer(&def->videos[0]->info.alias); - virDomainVideoDefClear(def->videos[0]); - def->videos[0]->type =3D VIR_DOMAIN_VIDEO_TYPE_NONE; - def->videos[0]->info.alias =3D g_steal_pointer(&alias); - } else { - virDomainDeviceDef device =3D { - .type =3D VIR_DOMAIN_DEVICE_VIDEO, - .data.video =3D def->videos[0], - }; - - /* Mark the first video as primary. If the user specified - * primary=3D"yes", the parser already inserted the device at - * def->videos[0] - */ - def->videos[0]->primary =3D true; - - /* videos[0] might have been added in AddImplicitDevices, after we= 've - * done the per-device post-parse */ - if (virDomainDefPostParseDeviceIterator(def, &device, - NULL, opaque) < 0) - return -1; - } - - return 0; -} - - -static int -virDomainDefPostParseCommon(virDomainDef *def, - struct virDomainDefPostParseDeviceIteratorData= *data, - virDomainXMLOption *xmlopt) -{ - size_t i; - - /* verify init path for container based domains */ - if (def->os.type =3D=3D VIR_DOMAIN_OSTYPE_EXE && !def->os.init) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("init binary must be specified")); - return -1; - } - - if (virDomainVcpuDefPostParse(def) < 0) - return -1; - - if (virDomainDefPostParseMemory(def, data->parseFlags) < 0) - return -1; - - if (virDomainDefPostParseOs(def) < 0) - return -1; - - virDomainDefPostParseMemtune(def); - - if (virDomainDefRejectDuplicateControllers(def) < 0) - return -1; - - if (virDomainDefRejectDuplicatePanics(def) < 0) - return -1; - - if (def->os.type =3D=3D VIR_DOMAIN_OSTYPE_HVM && - !(data->xmlopt->config.features & VIR_DOMAIN_DEF_FEATURE_NO_BOOT_O= RDER) && - virDomainDefBootOrderPostParse(def) < 0) - return -1; - - if (virDomainDefPostParseTimer(def) < 0) - return -1; - - if (virDomainDefAddImplicitDevices(def, xmlopt) < 0) - return -1; - - if (virDomainDefPostParseVideo(def, data) < 0) - return -1; - - if (def->nserials !=3D 0) { - virDomainDeviceDef device =3D { - .type =3D VIR_DOMAIN_DEVICE_CHR, - .data.chr =3D def->serials[0], - }; - - /* serials[0] might have been added in AddImplicitDevices, after w= e've - * done the per-device post-parse */ - if (virDomainDefPostParseDeviceIterator(def, &device, NULL, data) = < 0) - return -1; - } - - /* Implicit SCSI controllers without a defined model might have - * been added in AddImplicitDevices, after we've done the per-device - * post-parse. */ - for (i =3D 0; i < def->ncontrollers; i++) { - if (def->controllers[i]->model =3D=3D VIR_DOMAIN_CONTROLLER_MODEL_= SCSI_DEFAULT && - def->controllers[i]->type =3D=3D VIR_DOMAIN_CONTROLLER_TYPE_SC= SI) { - virDomainDeviceDef device =3D { - .type =3D VIR_DOMAIN_DEVICE_CONTROLLER, - .data.controller =3D def->controllers[i], - }; - if (virDomainDefPostParseDeviceIterator(def, &device, NULL, da= ta) < 0) - return -1; - } - } - - /* clean up possibly duplicated metadata entries */ - virXMLNodeSanitizeNamespaces(def->metadata); - - virDomainDefPostParseGraphics(def); - - if (virDomainDefPostParseCPU(def) < 0) - return -1; - - return 0; -} - - -static int -virDomainDefPostParseCheckFailure(virDomainDef *def, - unsigned int parseFlags, - int ret) -{ - if (ret !=3D 0) - def->postParseFailed =3D true; - - if (ret <=3D 0) - return ret; - - if (!(parseFlags & VIR_DOMAIN_DEF_PARSE_ALLOW_POST_PARSE_FAIL)) - return -1; - - virResetLastError(); - return 0; -} - - -int -virDomainDefPostParse(virDomainDef *def, - unsigned int parseFlags, - virDomainXMLOption *xmlopt, - void *parseOpaque) -{ - int ret =3D -1; - bool localParseOpaque =3D false; - struct virDomainDefPostParseDeviceIteratorData data =3D { - .xmlopt =3D xmlopt, - .parseFlags =3D parseFlags, - .parseOpaque =3D parseOpaque, - }; - - def->postParseFailed =3D false; - - /* call the basic post parse callback */ - if (xmlopt->config.domainPostParseBasicCallback) { - ret =3D xmlopt->config.domainPostParseBasicCallback(def, - xmlopt->config.p= riv); - - if (virDomainDefPostParseCheckFailure(def, parseFlags, ret) < 0) - goto cleanup; - } - - if (!data.parseOpaque && - xmlopt->config.domainPostParseDataAlloc) { - ret =3D xmlopt->config.domainPostParseDataAlloc(def, parseFlags, - xmlopt->config.priv, - &data.parseOpaque); - - if (virDomainDefPostParseCheckFailure(def, parseFlags, ret) < 0) - goto cleanup; - localParseOpaque =3D true; - } - - /* this must be done before the hypervisor-specific callback, - * in case presence of a controller at a specific index is checked - */ - virDomainAssignControllerIndexes(def); - - /* call the domain config callback */ - if (xmlopt->config.domainPostParseCallback) { - ret =3D xmlopt->config.domainPostParseCallback(def, parseFlags, - xmlopt->config.priv, - data.parseOpaque); - if (virDomainDefPostParseCheckFailure(def, parseFlags, ret) < 0) - goto cleanup; - } - - if (virDomainChrIsaSerialDefPostParse(def) < 0) - return -1; - - /* iterate the devices */ - ret =3D virDomainDeviceInfoIterateFlags(def, - virDomainDefPostParseDeviceItera= tor, - DOMAIN_DEVICE_ITERATE_ALL_CONSOL= ES | - DOMAIN_DEVICE_ITERATE_MISSING_IN= FO, - &data); - - if (virDomainDefPostParseCheckFailure(def, parseFlags, ret) < 0) - goto cleanup; - - if ((ret =3D virDomainDefPostParseCommon(def, &data, xmlopt)) < 0) - goto cleanup; - - if (xmlopt->config.assignAddressesCallback) { - ret =3D xmlopt->config.assignAddressesCallback(def, parseFlags, - xmlopt->config.priv, - data.parseOpaque); - if (virDomainDefPostParseCheckFailure(def, parseFlags, ret) < 0) - goto cleanup; - } - - if ((ret =3D virDomainDefPostParseCheckFeatures(def, xmlopt)) < 0) - goto cleanup; - - ret =3D 0; - - cleanup: - if (localParseOpaque && xmlopt->config.domainPostParseDataFree) - xmlopt->config.domainPostParseDataFree(data.parseOpaque); - - if (ret =3D=3D 1) - ret =3D -1; - - return ret; -} - - bool virDomainDefHasUSB(const virDomainDef *def) { diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 543b343be9..c56b84683c 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -3306,10 +3306,6 @@ bool virDomainSCSIDriveAddressIsUsed(const virDomainDef *def, const virDomainDeviceDriveAddress *addr); =20 -int virDomainDefPostParse(virDomainDef *def, - unsigned int parseFlags, - virDomainXMLOption *xmlopt, - void *parseOpaque); bool virDomainDefHasUSB(const virDomainDef *def); =20 bool virDomainDeviceAliasIsUserAlias(const char *aliasStr); diff --git a/src/conf/domain_postparse.c b/src/conf/domain_postparse.c new file mode 100644 index 0000000000..18f06dcca8 --- /dev/null +++ b/src/conf/domain_postparse.c @@ -0,0 +1,1483 @@ +/* + * domain_postparse.c: domain post parsing helpers + * + * Copyright (C) 2022 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#include + +#include "domain_postparse.h" +#include "viralloc.h" +#include "virlog.h" + +#define VIR_FROM_THIS VIR_FROM_DOMAIN + +VIR_LOG_INIT("conf.domain_postparse"); + +static int +virDomainDefPostParseMemory(virDomainDef *def, + unsigned int parseFlags) +{ + size_t i; + unsigned long long numaMemory =3D 0; + unsigned long long hotplugMemory =3D 0; + + /* Attempt to infer the initial memory size from the sum NUMA memory s= izes + * in case ABI updates are allowed or the element wasn't spec= ified */ + if (def->mem.total_memory =3D=3D 0 || + parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE || + parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE_MIGRATION) + numaMemory =3D virDomainNumaGetMemorySize(def->numa); + + /* calculate the sizes of hotplug memory */ + for (i =3D 0; i < def->nmems; i++) + hotplugMemory +=3D def->mems[i]->size; + + if (numaMemory) { + /* update the sizes in XML if nothing was set in the XML or ABI up= date + * is supported */ + virDomainDefSetMemoryTotal(def, numaMemory + hotplugMemory); + } else { + /* verify that the sum of memory modules doesn't exceed the total + * memory. This is necessary for virDomainDefGetMemoryInitial to w= ork + * properly. */ + if (hotplugMemory > def->mem.total_memory) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("Total size of memory devices exceeds the tot= al " + "memory size")); + return -1; + } + } + + if (virDomainDefGetMemoryInitial(def) =3D=3D 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("Memory size must be specified via or in= the " + " configuration")); + return -1; + } + + if (def->mem.cur_balloon > virDomainDefGetMemoryTotal(def) || + def->mem.cur_balloon =3D=3D 0) + def->mem.cur_balloon =3D virDomainDefGetMemoryTotal(def); + + if ((def->mem.max_memory || def->mem.memory_slots) && + !(def->mem.max_memory && def->mem.memory_slots)) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("both maximum memory size and " + "memory slot count must be specified")); + return -1; + } + + if (def->mem.max_memory && + def->mem.max_memory < virDomainDefGetMemoryTotal(def)) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("maximum memory size must be equal or greater tha= n " + "the actual memory size")); + return -1; + } + + return 0; +} + + +static int +virDomainDefPostParseOs(virDomainDef *def) +{ + if (def->os.firmwareFeatures && + def->os.firmwareFeatures[VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_ENROLL= ED_KEYS] =3D=3D VIR_TRISTATE_BOOL_YES) { + + if (def->os.firmwareFeatures[VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_SE= CURE_BOOT] =3D=3D VIR_TRISTATE_BOOL_NO) { + virReportError(VIR_ERR_XML_DETAIL, "%s", + _("firmware feature 'enrolled-keys' cannot be e= nabled when " + "firmware feature 'secure-boot' is disabled")= ); + return -1; + } + + /* For all non-broken firmware builds, enrolled-keys implies + * secure-boot, and having the Secure Boot keys in the NVRAM file + * when the firmware doesn't support the Secure Boot feature doesn= 't + * make sense anyway. Reflect this fact explicitly in the XML */ + def->os.firmwareFeatures[VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_SECURE= _BOOT] =3D VIR_TRISTATE_BOOL_YES; + } + + if (!def->os.loader) + return 0; + + if (def->os.loader->path && + def->os.loader->type =3D=3D VIR_DOMAIN_LOADER_TYPE_NONE) { + /* By default, loader is type of 'rom' */ + def->os.loader->type =3D VIR_DOMAIN_LOADER_TYPE_ROM; + } + + return 0; +} + + +static void +virDomainDefPostParseMemtune(virDomainDef *def) +{ + size_t i; + + if (virDomainNumaGetNodeCount(def->numa) =3D=3D 0) { + /* If guest NUMA is not configured and any hugepage page has nodem= ask + * set to "0" free and clear that nodemas, otherwise we would rise + * an error that there is no guest NUMA node configured. */ + for (i =3D 0; i < def->mem.nhugepages; i++) { + ssize_t nextBit; + + if (!def->mem.hugepages[i].nodemask) + continue; + + nextBit =3D virBitmapNextSetBit(def->mem.hugepages[i].nodemask= , 0); + if (nextBit < 0) { + g_clear_pointer(&def->mem.hugepages[i].nodemask, + virBitmapFree); + } + } + } +} + + +static int +virDomainDefPostParseTimer(virDomainDef *def) +{ + size_t i; + + /* verify settings of guest timers */ + for (i =3D 0; i < def->clock.ntimers; i++) { + virDomainTimerDef *timer =3D def->clock.timers[i]; + + if (timer->name =3D=3D VIR_DOMAIN_TIMER_NAME_KVMCLOCK || + timer->name =3D=3D VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK) { + if (timer->tickpolicy) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("timer %s doesn't support setting of " + "timer tickpolicy"), + virDomainTimerNameTypeToString(timer->name)= ); + return -1; + } + } + + if (timer->tickpolicy !=3D VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP && + (timer->catchup.threshold !=3D 0 || + timer->catchup.limit !=3D 0 || + timer->catchup.slew !=3D 0)) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("setting of timer catchup policies is only " + "supported with tickpolicy=3D'catchup'")); + return -1; + } + + if (timer->name !=3D VIR_DOMAIN_TIMER_NAME_TSC) { + if (timer->frequency !=3D 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("timer %s doesn't support setting of " + "timer frequency"), + virDomainTimerNameTypeToString(timer->name)= ); + return -1; + } + + if (timer->mode) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("timer %s doesn't support setting of " + "timer mode"), + virDomainTimerNameTypeToString(timer->name)= ); + return -1; + } + } + + if (timer->name !=3D VIR_DOMAIN_TIMER_NAME_PLATFORM && + timer->name !=3D VIR_DOMAIN_TIMER_NAME_RTC) { + if (timer->track !=3D VIR_DOMAIN_TIMER_TRACK_NONE) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("timer %s doesn't support setting of " + "timer track"), + virDomainTimerNameTypeToString(timer->name)= ); + return -1; + } + } + } + + return 0; +} + + +static void +virDomainDefPostParseGraphics(virDomainDef *def) +{ + size_t i; + + for (i =3D 0; i < def->ngraphics; i++) { + virDomainGraphicsDef *graphics =3D def->graphics[i]; + + /* If spice graphics is configured without ports and with autoport= =3D'no' + * then we start qemu with Spice to not listen anywhere. Let's co= nvert + * this configuration to the new listen type=3D'none' which does t= he + * same. */ + if (graphics->type =3D=3D VIR_DOMAIN_GRAPHICS_TYPE_SPICE) { + virDomainGraphicsListenDef *glisten =3D &graphics->listens[0]; + + if (glisten->type =3D=3D VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRE= SS && + graphics->data.spice.port =3D=3D 0 && + graphics->data.spice.tlsPort =3D=3D 0 && + !graphics->data.spice.autoport) { + VIR_FREE(glisten->address); + glisten->type =3D VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NONE; + } + } + } +} + + +/** + * virDomainPostParseCheckISCSIPath + * @srcpath: Source path read (a/k/a, IQN) either disk or hostdev + * + * The details of an IQN is defined by RFC 3720 and 3721, but + * we just need to make sure there's a lun provided. If not + * provided, then default to zero. For an ISCSI LUN that is + * is provided by /dev/disk/by-path/... , then that path will + * have the specific lun requested. + */ +static void +virDomainPostParseCheckISCSIPath(char **srcpath) +{ + char *path =3D NULL; + + if (strchr(*srcpath, '/')) + return; + + path =3D g_strdup_printf("%s/0", *srcpath); + g_free(*srcpath); + *srcpath =3D g_steal_pointer(&path); +} + + +/* Find out the next usable "unit" of a specific controller */ +static int +virDomainControllerSCSINextUnit(const virDomainDef *def, + unsigned int controller) +{ + size_t i; + + for (i =3D 0; i < def->scsiBusMaxUnit; i++) { + /* Default to assigning addresses using bus =3D target =3D 0 */ + const virDomainDeviceDriveAddress addr =3D {controller, 0, 0, i, 0= }; + + if (!virDomainSCSIDriveAddressIsUsed(def, &addr)) + return i; + } + + return -1; +} + + +static void +virDomainHostdevAssignAddress(virDomainXMLOption *xmlopt G_GNUC_UNUSED, + const virDomainDef *def, + virDomainHostdevDef *hostdev) +{ + int next_unit =3D 0; + int controller =3D 0; + + /* NB: Do not attempt calling virDomainDefMaybeAddController to + * automagically add a "new" controller. Doing so will result in + * qemuDomainFindOrCreateSCSIDiskController "finding" the controller + * in the domain def list and thus not hotplugging the controller as + * well as the hostdev in the event that there are either no SCSI + * controllers defined or there was no space on an existing one. + * + * Because we cannot add a controller, then we should not walk the + * defined controllers list in order to find empty space. Doing + * so fails to return the valid next unit number for the 2nd + * hostdev being added to the as yet to be created controller. + */ + do { + next_unit =3D virDomainControllerSCSINextUnit(def, controller); + if (next_unit < 0) + controller++; + } while (next_unit < 0); + + + hostdev->info->type =3D VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE; + hostdev->info->addr.drive.controller =3D controller; + hostdev->info->addr.drive.bus =3D 0; + hostdev->info->addr.drive.target =3D 0; + hostdev->info->addr.drive.unit =3D next_unit; +} + + +static int +virDomainHostdevDefPostParse(virDomainHostdevDef *dev, + const virDomainDef *def, + virDomainXMLOption *xmlopt) +{ + virDomainHostdevSubsysSCSI *scsisrc; + virDomainDeviceDriveAddress *addr =3D NULL; + + if (dev->mode !=3D VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) + return 0; + + switch (dev->source.subsys.type) { + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: + scsisrc =3D &dev->source.subsys.u.scsi; + if (scsisrc->protocol =3D=3D VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE= _ISCSI) { + virDomainHostdevSubsysSCSIiSCSI *iscsisrc =3D &scsisrc->u.iscs= i; + virDomainPostParseCheckISCSIPath(&iscsisrc->src->path); + } + + if (dev->info->type =3D=3D VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) + virDomainHostdevAssignAddress(xmlopt, def, dev); + + /* Ensure provided address doesn't conflict with existing + * scsi disk drive address + */ + addr =3D &dev->info->addr.drive; + if (virDomainDriveAddressIsUsedByDisk(def, + VIR_DOMAIN_DISK_BUS_SCSI, + addr)) { + virReportError(VIR_ERR_XML_ERROR, + _("SCSI host address controller=3D'%u' " + "bus=3D'%u' target=3D'%u' unit=3D'%u' in " + "use by a SCSI disk"), + addr->controller, addr->bus, + addr->target, addr->unit); + return -1; + } + break; + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV: { + int model =3D dev->source.subsys.u.mdev.model; + + if (dev->info->type =3D=3D VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) + return 0; + + if ((model =3D=3D VIR_MDEV_MODEL_TYPE_VFIO_PCI && + dev->info->type !=3D VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) || + (model =3D=3D VIR_MDEV_MODEL_TYPE_VFIO_CCW && + dev->info->type !=3D VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)) { + virReportError(VIR_ERR_XML_ERROR, + _("Unsupported address type '%s' with mediated " + "device model '%s'"), + virDomainDeviceAddressTypeToString(dev->info->t= ype), + virMediatedDeviceModelTypeToString(model)); + return -1; + } + } + + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST: + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: + break; + } + + return 0; +} + + +static int +virDomainChrIsaSerialDefPostParse(virDomainDef *def) +{ + size_t i; + size_t isa_serial_count =3D 0; + bool used_serial_port[VIR_MAX_ISA_SERIAL_PORTS] =3D { false }; + + /* Perform all the required checks. */ + for (i =3D 0; i < def->nserials; i++) { + if (def->serials[i]->targetType !=3D VIR_DOMAIN_CHR_SERIAL_TARGET_= MODEL_ISA_SERIAL) + continue; + + if (isa_serial_count++ >=3D VIR_MAX_ISA_SERIAL_PORTS || + def->serials[i]->target.port >=3D VIR_MAX_ISA_SERIAL_PORTS) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Maximum supported number of ISA serial ports= is '%d'"), + VIR_MAX_ISA_SERIAL_PORTS); + return -1; + } + + if (def->serials[i]->target.port !=3D -1) { + if (used_serial_port[def->serials[i]->target.port]) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("target port '%d' already allocated"), + def->serials[i]->target.port); + return -1; + } + used_serial_port[def->serials[i]->target.port] =3D true; + } + } + + /* Assign the ports to the devices. */ + for (i =3D 0; i < def->nserials; i++) { + size_t j; + + if (def->serials[i]->targetType !=3D VIR_DOMAIN_CHR_SERIAL_TARGET_= MODEL_ISA_SERIAL || + def->serials[i]->target.port !=3D -1) + continue; + + for (j =3D 0; j < VIR_MAX_ISA_SERIAL_PORTS; j++) { + if (!used_serial_port[j]) { + def->serials[i]->target.port =3D j; + used_serial_port[j] =3D true; + break; + } + } + } + + return 0; +} + + +static int +virDomainChrDefPostParse(virDomainChrDef *chr, + const virDomainDef *def) +{ + const virDomainChrDef **arrPtr; + size_t i, cnt; + + virDomainChrGetDomainPtrs(def, chr->deviceType, &arrPtr, &cnt); + + if (chr->deviceType =3D=3D VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE && + chr->targetType =3D=3D VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE) { + chr->targetType =3D VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL; + } + + if (chr->deviceType =3D=3D VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL && + chr->targetType =3D=3D VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA_DEBUG= && + !ARCH_IS_X86(def->os.arch)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("isa-debug serial type only valid on x86 architec= ture")); + return -1; + } + + if (chr->target.port =3D=3D -1 && + (chr->deviceType =3D=3D VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL || + chr->deviceType =3D=3D VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL || + chr->deviceType =3D=3D VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE)) { + int maxport =3D -1; + + for (i =3D 0; i < cnt; i++) { + if (arrPtr[i]->target.port > maxport) + maxport =3D arrPtr[i]->target.port; + } + + chr->target.port =3D maxport + 1; + } + + return 0; +} + + +static void +virDomainRNGDefPostParse(virDomainRNGDef *rng) +{ + /* set default path for virtio-rng "random" backend to /dev/random */ + if (rng->backend =3D=3D VIR_DOMAIN_RNG_BACKEND_RANDOM && + !rng->source.file) { + rng->source.file =3D g_strdup("/dev/random"); + } +} + + +static void +virDomainDiskExpandGroupIoTune(virDomainDiskDef *disk, + const virDomainDef *def) +{ + size_t i; + + if (!disk->blkdeviotune.group_name || + virDomainBlockIoTuneInfoHasAny(&disk->blkdeviotune)) + return; + + for (i =3D 0; i < def->ndisks; i++) { + virDomainDiskDef *d =3D def->disks[i]; + + if (STRNEQ_NULLABLE(disk->blkdeviotune.group_name, d->blkdeviotune= .group_name) || + !virDomainBlockIoTuneInfoHasAny(&d->blkdeviotune)) + continue; + + + VIR_FREE(disk->blkdeviotune.group_name); + virDomainBlockIoTuneInfoCopy(&d->blkdeviotune, &disk->blkdeviotune= ); + + return; + } +} + + +static int +virDomainDiskDefPostParse(virDomainDiskDef *disk, + const virDomainDef *def, + virDomainXMLOption *xmlopt) +{ + if (disk->dst) { + char *newdst; + + /* Work around for compat with Xen driver in previous libvirt rele= ases */ + if ((newdst =3D g_strdup(STRSKIP(disk->dst, "ioemu:")))) { + g_free(disk->dst); + disk->dst =3D newdst; + } + } + + /* Force CDROM to be listed as read only */ + if (disk->device =3D=3D VIR_DOMAIN_DISK_DEVICE_CDROM) + disk->src->readonly =3D true; + + if (disk->bus =3D=3D VIR_DOMAIN_DISK_BUS_NONE) { + disk->bus =3D VIR_DOMAIN_DISK_BUS_IDE; + + if (disk->device =3D=3D VIR_DOMAIN_DISK_DEVICE_FLOPPY) { + disk->bus =3D VIR_DOMAIN_DISK_BUS_FDC; + } else if (disk->dst) { + if (STRPREFIX(disk->dst, "hd")) + disk->bus =3D VIR_DOMAIN_DISK_BUS_IDE; + else if (STRPREFIX(disk->dst, "sd")) + disk->bus =3D VIR_DOMAIN_DISK_BUS_SCSI; + else if (STRPREFIX(disk->dst, "vd")) + disk->bus =3D VIR_DOMAIN_DISK_BUS_VIRTIO; + else if (STRPREFIX(disk->dst, "xvd")) + disk->bus =3D VIR_DOMAIN_DISK_BUS_XEN; + else if (STRPREFIX(disk->dst, "ubd")) + disk->bus =3D VIR_DOMAIN_DISK_BUS_UML; + } + } + + if (disk->snapshot =3D=3D VIR_DOMAIN_SNAPSHOT_LOCATION_DEFAULT && + disk->src->readonly) + disk->snapshot =3D VIR_DOMAIN_SNAPSHOT_LOCATION_NO; + + if (disk->src->type =3D=3D VIR_STORAGE_TYPE_NETWORK && + disk->src->protocol =3D=3D VIR_STORAGE_NET_PROTOCOL_ISCSI) { + virDomainPostParseCheckISCSIPath(&disk->src->path); + } + + if (disk->src->type =3D=3D VIR_STORAGE_TYPE_NVME) { + if (disk->src->nvme->managed =3D=3D VIR_TRISTATE_BOOL_ABSENT) + disk->src->nvme->managed =3D VIR_TRISTATE_BOOL_YES; + } + + /* vhost-user doesn't allow us to snapshot, disable snapshots by defau= lt */ + if (disk->src->type =3D=3D VIR_STORAGE_TYPE_VHOST_USER && + disk->snapshot =3D=3D VIR_DOMAIN_SNAPSHOT_LOCATION_DEFAULT) { + disk->snapshot =3D VIR_DOMAIN_SNAPSHOT_LOCATION_NO; + } + + if (disk->info.type =3D=3D VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE && + disk->dst && + virDomainDiskDefAssignAddress(xmlopt, disk, def) < 0) { + return -1; + } + + virDomainDiskExpandGroupIoTune(disk, def); + + return 0; +} + + +static void +virDomainVideoDefPostParse(virDomainVideoDef *video, + const virDomainDef *def) +{ + /* Fill out (V)RAM if the driver-specific callback did not do so */ + if (video->ram =3D=3D 0 && video->type =3D=3D VIR_DOMAIN_VIDEO_TYPE_QX= L) + video->ram =3D virDomainVideoDefaultRAM(def, video->type); + if (video->vram =3D=3D 0) + video->vram =3D virDomainVideoDefaultRAM(def, video->type); + + video->ram =3D VIR_ROUND_UP_POWER_OF_TWO(video->ram); + video->vram =3D VIR_ROUND_UP_POWER_OF_TWO(video->vram); +} + + +static int +virDomainControllerDefPostParse(virDomainControllerDef *cdev) +{ + if (cdev->iothread && + cdev->model !=3D VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI && + cdev->model !=3D VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_TRANSITIO= NAL && + cdev->model !=3D VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_NON_TRANS= ITIONAL) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("'iothread' attribute only supported for " + "virtio scsi controllers")); + return -1; + } + + return 0; +} + + +static void +virDomainVsockDefPostParse(virDomainVsockDef *vsock) +{ + if (vsock->auto_cid =3D=3D VIR_TRISTATE_BOOL_ABSENT) { + if (vsock->guest_cid !=3D 0) + vsock->auto_cid =3D VIR_TRISTATE_BOOL_NO; + else + vsock->auto_cid =3D VIR_TRISTATE_BOOL_YES; + } +} + + +static int +virDomainMemoryDefPostParse(virDomainMemoryDef *mem, + const virDomainDef *def) +{ + switch (mem->model) { + case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: + /* Virtio-pmem mandates shared access so that guest writes get + * reflected in the underlying file. */ + if (mem->access =3D=3D VIR_DOMAIN_MEMORY_ACCESS_DEFAULT) + mem->access =3D VIR_DOMAIN_MEMORY_ACCESS_SHARED; + break; + + case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: + /* If no NVDIMM UUID was provided in XML, generate one. */ + if (ARCH_IS_PPC64(def->os.arch) && + !mem->uuid) { + + mem->uuid =3D g_new0(unsigned char, VIR_UUID_BUFLEN); + if (virUUIDGenerate(mem->uuid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Failed to generate UUID")); + return -1; + } + } + break; + + case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: + case VIR_DOMAIN_MEMORY_MODEL_DIMM: + case VIR_DOMAIN_MEMORY_MODEL_NONE: + case VIR_DOMAIN_MEMORY_MODEL_LAST: + break; + } + + return 0; +} + + +static int +virDomainFSDefPostParse(virDomainFSDef *fs) +{ + if (fs->accessmode =3D=3D VIR_DOMAIN_FS_ACCESSMODE_DEFAULT && !fs->soc= k) + fs->accessmode =3D VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH; + + return 0; +} + + +static int +virDomainDeviceDefPostParseCommon(virDomainDeviceDef *dev, + const virDomainDef *def, + unsigned int parseFlags G_GNUC_UNUSED, + virDomainXMLOption *xmlopt) +{ + int ret =3D -1; + + switch ((virDomainDeviceType)dev->type) { + case VIR_DOMAIN_DEVICE_CHR: + ret =3D virDomainChrDefPostParse(dev->data.chr, def); + break; + + case VIR_DOMAIN_DEVICE_RNG: + virDomainRNGDefPostParse(dev->data.rng); + ret =3D 0; + break; + + case VIR_DOMAIN_DEVICE_DISK: + ret =3D virDomainDiskDefPostParse(dev->data.disk, def, xmlopt); + break; + + case VIR_DOMAIN_DEVICE_VIDEO: + virDomainVideoDefPostParse(dev->data.video, def); + ret =3D 0; + break; + + case VIR_DOMAIN_DEVICE_HOSTDEV: + ret =3D virDomainHostdevDefPostParse(dev->data.hostdev, def, xmlop= t); + break; + + case VIR_DOMAIN_DEVICE_CONTROLLER: + ret =3D virDomainControllerDefPostParse(dev->data.controller); + break; + + case VIR_DOMAIN_DEVICE_VSOCK: + virDomainVsockDefPostParse(dev->data.vsock); + ret =3D 0; + break; + + case VIR_DOMAIN_DEVICE_MEMORY: + ret =3D virDomainMemoryDefPostParse(dev->data.memory, def); + break; + + case VIR_DOMAIN_DEVICE_FS: + ret =3D virDomainFSDefPostParse(dev->data.fs); + break; + + case VIR_DOMAIN_DEVICE_LEASE: + case VIR_DOMAIN_DEVICE_NET: + case VIR_DOMAIN_DEVICE_INPUT: + case VIR_DOMAIN_DEVICE_SOUND: + case VIR_DOMAIN_DEVICE_WATCHDOG: + case VIR_DOMAIN_DEVICE_GRAPHICS: + case VIR_DOMAIN_DEVICE_HUB: + case VIR_DOMAIN_DEVICE_REDIRDEV: + case VIR_DOMAIN_DEVICE_SMARTCARD: + case VIR_DOMAIN_DEVICE_MEMBALLOON: + case VIR_DOMAIN_DEVICE_NVRAM: + case VIR_DOMAIN_DEVICE_SHMEM: + case VIR_DOMAIN_DEVICE_TPM: + case VIR_DOMAIN_DEVICE_PANIC: + case VIR_DOMAIN_DEVICE_IOMMU: + case VIR_DOMAIN_DEVICE_AUDIO: + ret =3D 0; + break; + + case VIR_DOMAIN_DEVICE_NONE: + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("unexpected VIR_DOMAIN_DEVICE_NONE")); + break; + + case VIR_DOMAIN_DEVICE_LAST: + default: + virReportEnumRangeError(virDomainDeviceType, dev->type); + break; + } + + return ret; +} + + +/** + * virDomainDefCheckUnsupportedMemoryHotplug: + * @def: domain definition + * + * Returns -1 if the domain definition would enable memory hotplug via the + * tunable and reports an error. Otherwise returns 0. + */ +static int +virDomainDefCheckUnsupportedMemoryHotplug(virDomainDef *def) +{ + /* memory hotplug tunables are not supported by this driver */ + if (virDomainDefHasMemoryHotplug(def)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("memory hotplug tunables are not " + "supported by this hypervisor driver")); + return -1; + } + + return 0; +} + + +/** + * virDomainDeviceDefCheckUnsupportedMemoryDevice: + * @dev: device definition + * + * Returns -1 if the device definition describes a memory device and repor= ts an + * error. Otherwise returns 0. + */ +static int +virDomainDeviceDefCheckUnsupportedMemoryDevice(virDomainDeviceDef *dev) +{ + /* This driver doesn't yet know how to handle memory devices */ + if (dev->type =3D=3D VIR_DOMAIN_DEVICE_MEMORY) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("memory devices are not supported by this driver"= )); + return -1; + } + + return 0; +} + + +/** + * virDomainDefRemoveOfflineVcpuPin: + * @def: domain definition + * + * This function removes vcpu pinning information from offline vcpus. This= is + * designed to be used for drivers which don't support offline vcpupin. + */ +static void +virDomainDefRemoveOfflineVcpuPin(virDomainDef *def) +{ + size_t i; + virDomainVcpuDef *vcpu; + + for (i =3D 0; i < virDomainDefGetVcpusMax(def); i++) { + vcpu =3D virDomainDefGetVcpu(def, i); + + if (vcpu && !vcpu->online && vcpu->cpumask) { + g_clear_pointer(&vcpu->cpumask, virBitmapFree); + + VIR_WARN("Ignoring unsupported vcpupin for offline vcpu '%zu'"= , i); + } + } +} + + +#define UNSUPPORTED(FEATURE) (!((FEATURE) & xmlopt->config.features)) +/** + * virDomainDefPostParseCheckFeatures: + * @def: domain definition + * @xmlopt: XML parser option object + * + * This function checks that the domain configuration is supported accordi= ng to + * the supported features for a given hypervisor. See virDomainDefFeatures= and + * virDomainDefParserConfig. + * + * Returns 0 on success and -1 on error with an appropriate libvirt error. + */ +static int +virDomainDefPostParseCheckFeatures(virDomainDef *def, + virDomainXMLOption *xmlopt) +{ + if (UNSUPPORTED(VIR_DOMAIN_DEF_FEATURE_MEMORY_HOTPLUG) && + virDomainDefCheckUnsupportedMemoryHotplug(def) < 0) + return -1; + + if (UNSUPPORTED(VIR_DOMAIN_DEF_FEATURE_OFFLINE_VCPUPIN)) + virDomainDefRemoveOfflineVcpuPin(def); + + if (UNSUPPORTED(VIR_DOMAIN_DEF_FEATURE_NAME_SLASH)) { + if (def->name && strchr(def->name, '/')) { + virReportError(VIR_ERR_XML_ERROR, + _("name %s cannot contain '/'"), def->name); + return -1; + } + } + + if (UNSUPPORTED(VIR_DOMAIN_DEF_FEATURE_INDIVIDUAL_VCPUS) && + def->individualvcpus) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("individual CPU state configuration is not suppor= ted")); + return -1; + } + + return 0; +} + + +/** + * virDomainDeviceDefPostParseCheckFeatures: + * @dev: device definition + * @xmlopt: XML parser option object + * + * This function checks that the device configuration is supported accordi= ng to + * the supported features for a given hypervisor. See virDomainDefFeatures= and + * virDomainDefParserConfig. + * + * Returns 0 on success and -1 on error with an appropriate libvirt error. + */ +static int +virDomainDeviceDefPostParseCheckFeatures(virDomainDeviceDef *dev, + virDomainXMLOption *xmlopt) +{ + if (UNSUPPORTED(VIR_DOMAIN_DEF_FEATURE_MEMORY_HOTPLUG) && + virDomainDeviceDefCheckUnsupportedMemoryDevice(dev) < 0) + return -1; + + if (UNSUPPORTED(VIR_DOMAIN_DEF_FEATURE_NET_MODEL_STRING) && + dev->type =3D=3D VIR_DOMAIN_DEVICE_NET && + dev->data.net->modelstr) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("driver does not support net model '%s'"), + dev->data.net->modelstr); + return -1; + } + + return 0; +} +#undef UNSUPPORTED + + +static int +virDomainDeviceDefPostParse(virDomainDeviceDef *dev, + const virDomainDef *def, + unsigned int flags, + virDomainXMLOption *xmlopt, + void *parseOpaque) +{ + int ret; + + if (xmlopt->config.devicesPostParseCallback) { + ret =3D xmlopt->config.devicesPostParseCallback(dev, def, flags, + xmlopt->config.priv, + parseOpaque); + if (ret < 0) + return ret; + } + + if ((ret =3D virDomainDeviceDefPostParseCommon(dev, def, flags, xmlopt= )) < 0) + return ret; + + if (virDomainDeviceDefPostParseCheckFeatures(dev, xmlopt) < 0) + return -1; + + return 0; +} + + +int +virDomainDeviceDefPostParseOne(virDomainDeviceDef *dev, + const virDomainDef *def, + unsigned int flags, + virDomainXMLOption *xmlopt, + void *parseOpaque) +{ + void *data =3D NULL; + int ret; + + if (!parseOpaque && xmlopt->config.domainPostParseDataAlloc) { + if (xmlopt->config.domainPostParseDataAlloc(def, flags, + xmlopt->config.priv, + &data) < 0) + return -1; + parseOpaque =3D data; + } + + ret =3D virDomainDeviceDefPostParse(dev, def, flags, xmlopt, parseOpaq= ue); + + if (data && xmlopt->config.domainPostParseDataFree) + xmlopt->config.domainPostParseDataFree(data); + + return ret; +} + + +struct virDomainDefPostParseDeviceIteratorData { + virDomainXMLOption *xmlopt; + void *parseOpaque; + unsigned int parseFlags; +}; + + +static int +virDomainDefPostParseDeviceIterator(virDomainDef *def, + virDomainDeviceDef *dev, + virDomainDeviceInfo *info G_GNUC_UNUSE= D, + void *opaque) +{ + struct virDomainDefPostParseDeviceIteratorData *data =3D opaque; + return virDomainDeviceDefPostParse(dev, def, + data->parseFlags, data->xmlopt, + data->parseOpaque); +} + + +static int +virDomainVcpuDefPostParse(virDomainDef *def) +{ + virDomainVcpuDef *vcpu; + size_t maxvcpus =3D virDomainDefGetVcpusMax(def); + size_t i; + + for (i =3D 0; i < maxvcpus; i++) { + vcpu =3D virDomainDefGetVcpu(def, i); + + /* impossible but some compilers don't like it */ + if (!vcpu) + continue; + + switch (vcpu->hotpluggable) { + case VIR_TRISTATE_BOOL_ABSENT: + if (vcpu->online) + vcpu->hotpluggable =3D VIR_TRISTATE_BOOL_NO; + else + vcpu->hotpluggable =3D VIR_TRISTATE_BOOL_YES; + break; + + case VIR_TRISTATE_BOOL_NO: + if (!vcpu->online) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("vcpu '%zu' is both offline and not " + "hotpluggable"), i); + return -1; + } + break; + + case VIR_TRISTATE_BOOL_YES: + case VIR_TRISTATE_BOOL_LAST: + break; + } + } + + return 0; +} + + +static int +virDomainDefPostParseCPU(virDomainDef *def) +{ + if (!def->cpu) + return 0; + + if (def->cpu->mode =3D=3D VIR_CPU_MODE_CUSTOM && + !def->cpu->model && + def->cpu->check !=3D VIR_CPU_CHECK_DEFAULT) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("check attribute specified for CPU with no model"= )); + return -1; + } + + return 0; +} + + +static int +virDomainDefCollectBootOrder(virDomainDef *def G_GNUC_UNUSED, + virDomainDeviceDef *dev G_GNUC_UNUSED, + virDomainDeviceInfo *info, + void *data) +{ + GHashTable *bootHash =3D data; + g_autofree char *order =3D NULL; + + if (info->bootIndex =3D=3D 0) + return 0; + + if (dev->type =3D=3D VIR_DOMAIN_DEVICE_HOSTDEV && + dev->data.hostdev->parentnet) { + /* This hostdev is a child of a higher level device + * (e.g. interface), and thus already being counted on the + * list for the other device type. + */ + return 0; + } + order =3D g_strdup_printf("%u", info->bootIndex); + + if (virHashLookup(bootHash, order)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("boot order '%s' used for more than one device"), + order); + return -1; + } + + if (virHashAddEntry(bootHash, order, (void *) 1) < 0) + return -1; + + return 0; +} + + +static int +virDomainDefBootOrderPostParse(virDomainDef *def) +{ + g_autoptr(GHashTable) bootHash =3D virHashNew(NULL); + + if (virDomainDeviceInfoIterate(def, virDomainDefCollectBootOrder, boot= Hash) < 0) + return -1; + + if (def->os.nBootDevs > 0 && virHashSize(bootHash) > 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("per-device boot elements cannot be used" + " together with os/boot elements")); + return -1; + } + + if (def->os.nBootDevs =3D=3D 0 && virHashSize(bootHash) =3D=3D 0) { + def->os.nBootDevs =3D 1; + def->os.bootDevs[0] =3D VIR_DOMAIN_BOOT_DISK; + } + + return 0; +} + + +static int +virDomainDefPostParseVideo(virDomainDef *def, + void *opaque) +{ + if (def->nvideos =3D=3D 0) + return 0; + + if (def->videos[0]->type =3D=3D VIR_DOMAIN_VIDEO_TYPE_NONE) { + char *alias; + + /* we don't want to format any values we automatically fill in for + * videos into the XML, so clear them, but retain any user-assigned + * alias */ + alias =3D g_steal_pointer(&def->videos[0]->info.alias); + virDomainVideoDefClear(def->videos[0]); + def->videos[0]->type =3D VIR_DOMAIN_VIDEO_TYPE_NONE; + def->videos[0]->info.alias =3D g_steal_pointer(&alias); + } else { + virDomainDeviceDef device =3D { + .type =3D VIR_DOMAIN_DEVICE_VIDEO, + .data.video =3D def->videos[0], + }; + + /* Mark the first video as primary. If the user specified + * primary=3D"yes", the parser already inserted the device at + * def->videos[0] + */ + def->videos[0]->primary =3D true; + + /* videos[0] might have been added in AddImplicitDevices, after we= 've + * done the per-device post-parse */ + if (virDomainDefPostParseDeviceIterator(def, &device, + NULL, opaque) < 0) + return -1; + } + + return 0; +} + + +static int +virDomainDefRejectDuplicateControllers(virDomainDef *def) +{ + int max_idx[VIR_DOMAIN_CONTROLLER_TYPE_LAST]; + virBitmap *bitmaps[VIR_DOMAIN_CONTROLLER_TYPE_LAST] =3D { NULL }; + virDomainControllerDef *cont; + size_t nbitmaps =3D 0; + int ret =3D -1; + size_t i; + + memset(max_idx, -1, sizeof(max_idx)); + + for (i =3D 0; i < def->ncontrollers; i++) { + cont =3D def->controllers[i]; + if (cont->idx > max_idx[cont->type]) + max_idx[cont->type] =3D cont->idx; + } + + /* multiple USB controllers with the same index are allowed */ + max_idx[VIR_DOMAIN_CONTROLLER_TYPE_USB] =3D -1; + + for (i =3D 0; i < VIR_DOMAIN_CONTROLLER_TYPE_LAST; i++) { + if (max_idx[i] >=3D 0) + bitmaps[i] =3D virBitmapNew(max_idx[i] + 1); + nbitmaps++; + } + + for (i =3D 0; i < def->ncontrollers; i++) { + cont =3D def->controllers[i]; + + if (max_idx[cont->type] =3D=3D -1) + continue; + + if (virBitmapIsBitSet(bitmaps[cont->type], cont->idx)) { + virReportError(VIR_ERR_XML_ERROR, + _("Multiple '%s' controllers with index '%d'"), + virDomainControllerTypeToString(cont->type), + cont->idx); + goto cleanup; + } + ignore_value(virBitmapSetBit(bitmaps[cont->type], cont->idx)); + } + + ret =3D 0; + cleanup: + for (i =3D 0; i < nbitmaps; i++) + virBitmapFree(bitmaps[i]); + return ret; +} + + +static int +virDomainDefRejectDuplicatePanics(virDomainDef *def) +{ + bool exists[VIR_DOMAIN_PANIC_MODEL_LAST]; + size_t i; + + for (i =3D 0; i < VIR_DOMAIN_PANIC_MODEL_LAST; i++) + exists[i] =3D false; + + for (i =3D 0; i < def->npanics; i++) { + virDomainPanicModel model =3D def->panics[i]->model; + if (exists[model]) { + virReportError(VIR_ERR_XML_ERROR, + _("Multiple panic devices with model '%s'"), + virDomainPanicModelTypeToString(model)); + return -1; + } + exists[model] =3D true; + } + + return 0; +} + + +static int +virDomainDefPostParseCommon(virDomainDef *def, + struct virDomainDefPostParseDeviceIteratorData= *data, + virDomainXMLOption *xmlopt) +{ + size_t i; + + /* verify init path for container based domains */ + if (def->os.type =3D=3D VIR_DOMAIN_OSTYPE_EXE && !def->os.init) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("init binary must be specified")); + return -1; + } + + if (virDomainVcpuDefPostParse(def) < 0) + return -1; + + if (virDomainDefPostParseMemory(def, data->parseFlags) < 0) + return -1; + + if (virDomainDefPostParseOs(def) < 0) + return -1; + + virDomainDefPostParseMemtune(def); + + if (virDomainDefRejectDuplicateControllers(def) < 0) + return -1; + + if (virDomainDefRejectDuplicatePanics(def) < 0) + return -1; + + if (def->os.type =3D=3D VIR_DOMAIN_OSTYPE_HVM && + !(data->xmlopt->config.features & VIR_DOMAIN_DEF_FEATURE_NO_BOOT_O= RDER) && + virDomainDefBootOrderPostParse(def) < 0) + return -1; + + if (virDomainDefPostParseTimer(def) < 0) + return -1; + + if (virDomainDefAddImplicitDevices(def, xmlopt) < 0) + return -1; + + if (virDomainDefPostParseVideo(def, data) < 0) + return -1; + + if (def->nserials !=3D 0) { + virDomainDeviceDef device =3D { + .type =3D VIR_DOMAIN_DEVICE_CHR, + .data.chr =3D def->serials[0], + }; + + /* serials[0] might have been added in AddImplicitDevices, after w= e've + * done the per-device post-parse */ + if (virDomainDefPostParseDeviceIterator(def, &device, NULL, data) = < 0) + return -1; + } + + /* Implicit SCSI controllers without a defined model might have + * been added in AddImplicitDevices, after we've done the per-device + * post-parse. */ + for (i =3D 0; i < def->ncontrollers; i++) { + if (def->controllers[i]->model =3D=3D VIR_DOMAIN_CONTROLLER_MODEL_= SCSI_DEFAULT && + def->controllers[i]->type =3D=3D VIR_DOMAIN_CONTROLLER_TYPE_SC= SI) { + virDomainDeviceDef device =3D { + .type =3D VIR_DOMAIN_DEVICE_CONTROLLER, + .data.controller =3D def->controllers[i], + }; + if (virDomainDefPostParseDeviceIterator(def, &device, NULL, da= ta) < 0) + return -1; + } + } + + /* clean up possibly duplicated metadata entries */ + virXMLNodeSanitizeNamespaces(def->metadata); + + virDomainDefPostParseGraphics(def); + + if (virDomainDefPostParseCPU(def) < 0) + return -1; + + return 0; +} + + +static int +virDomainDefPostParseCheckFailure(virDomainDef *def, + unsigned int parseFlags, + int ret) +{ + if (ret !=3D 0) + def->postParseFailed =3D true; + + if (ret <=3D 0) + return ret; + + if (!(parseFlags & VIR_DOMAIN_DEF_PARSE_ALLOW_POST_PARSE_FAIL)) + return -1; + + virResetLastError(); + return 0; +} + + +static void +virDomainAssignControllerIndexes(virDomainDef *def) +{ + /* the index attribute of a controller is optional in the XML, but + * is required to be valid at any time after parse. When no index + * is provided for a controller, assign one automatically by + * looking at what indexes are already used for that controller + * type in the domain - the unindexed controller gets the lowest + * unused index. + */ + size_t outer; + + for (outer =3D 0; outer < def->ncontrollers; outer++) { + virDomainControllerDef *cont =3D def->controllers[outer]; + virDomainControllerDef *prev =3D NULL; + size_t inner; + + if (cont->idx !=3D -1) + continue; + + if (outer > 0 && IS_USB2_CONTROLLER(cont)) { + /* USB2 controllers are the only exception to the simple + * "assign the lowest unused index". A group of USB2 + * "companions" should all be at the same index as other + * USB2 controllers in the group, but only do this + * automatically if it appears to be the intent. To prove + * intent: the USB controller on the list just prior to + * this one must also be a USB2 controller, and there must + * not yet be a controller with the exact same model of + * this one and the same index as the previously added + * controller (e.g., if this controller is a UHCI1, then + * the previous controller must be an EHCI1 or a UHCI[23], + * and there must not already be a UHCI1 controller with + * the same index as the previous controller). If all of + * these are satisfied, set this controller to the same + * index as the previous controller. + */ + int prevIdx; + + prevIdx =3D outer - 1; + while (prevIdx >=3D 0 && + def->controllers[prevIdx]->type !=3D VIR_DOMAIN_CONTROL= LER_TYPE_USB) + prevIdx--; + if (prevIdx >=3D 0) + prev =3D def->controllers[prevIdx]; + /* if the last USB controller isn't USB2, that breaks + * the chain, so we need a new index for this new + * controller + */ + if (prev && !IS_USB2_CONTROLLER(prev)) + prev =3D NULL; + + /* if prev !=3D NULL, we've found a potential index to + * use. Make sure this index isn't already used by an + * existing USB2 controller of the same model as the new + * one. + */ + for (inner =3D 0; prev && inner < def->ncontrollers; inner++) { + if (def->controllers[inner]->type =3D=3D VIR_DOMAIN_CONTRO= LLER_TYPE_USB && + def->controllers[inner]->idx =3D=3D prev->idx && + def->controllers[inner]->model =3D=3D cont->model) { + /* we already have a controller of this model with + * the proposed index, so we need to move to a new + * index for this controller + */ + prev =3D NULL; + } + } + if (prev) + cont->idx =3D prev->idx; + } + /* if none of the above applied, prev will be NULL */ + if (!prev) + cont->idx =3D virDomainControllerFindUnusedIndex(def, cont->ty= pe); + } +} + + +int +virDomainDefPostParse(virDomainDef *def, + unsigned int parseFlags, + virDomainXMLOption *xmlopt, + void *parseOpaque) +{ + int ret =3D -1; + bool localParseOpaque =3D false; + struct virDomainDefPostParseDeviceIteratorData data =3D { + .xmlopt =3D xmlopt, + .parseFlags =3D parseFlags, + .parseOpaque =3D parseOpaque, + }; + + def->postParseFailed =3D false; + + /* call the basic post parse callback */ + if (xmlopt->config.domainPostParseBasicCallback) { + ret =3D xmlopt->config.domainPostParseBasicCallback(def, + xmlopt->config.p= riv); + + if (virDomainDefPostParseCheckFailure(def, parseFlags, ret) < 0) + goto cleanup; + } + + if (!data.parseOpaque && + xmlopt->config.domainPostParseDataAlloc) { + ret =3D xmlopt->config.domainPostParseDataAlloc(def, parseFlags, + xmlopt->config.priv, + &data.parseOpaque); + + if (virDomainDefPostParseCheckFailure(def, parseFlags, ret) < 0) + goto cleanup; + localParseOpaque =3D true; + } + + /* this must be done before the hypervisor-specific callback, + * in case presence of a controller at a specific index is checked + */ + virDomainAssignControllerIndexes(def); + + /* call the domain config callback */ + if (xmlopt->config.domainPostParseCallback) { + ret =3D xmlopt->config.domainPostParseCallback(def, parseFlags, + xmlopt->config.priv, + data.parseOpaque); + if (virDomainDefPostParseCheckFailure(def, parseFlags, ret) < 0) + goto cleanup; + } + + if (virDomainChrIsaSerialDefPostParse(def) < 0) + return -1; + + /* iterate the devices */ + ret =3D virDomainDeviceInfoIterateFlags(def, + virDomainDefPostParseDeviceItera= tor, + DOMAIN_DEVICE_ITERATE_ALL_CONSOL= ES | + DOMAIN_DEVICE_ITERATE_MISSING_IN= FO, + &data); + + if (virDomainDefPostParseCheckFailure(def, parseFlags, ret) < 0) + goto cleanup; + + if ((ret =3D virDomainDefPostParseCommon(def, &data, xmlopt)) < 0) + goto cleanup; + + if (xmlopt->config.assignAddressesCallback) { + ret =3D xmlopt->config.assignAddressesCallback(def, parseFlags, + xmlopt->config.priv, + data.parseOpaque); + if (virDomainDefPostParseCheckFailure(def, parseFlags, ret) < 0) + goto cleanup; + } + + if ((ret =3D virDomainDefPostParseCheckFeatures(def, xmlopt)) < 0) + goto cleanup; + + ret =3D 0; + + cleanup: + if (localParseOpaque && xmlopt->config.domainPostParseDataFree) + xmlopt->config.domainPostParseDataFree(data.parseOpaque); + + if (ret =3D=3D 1) + ret =3D -1; + + return ret; +} diff --git a/src/conf/domain_postparse.h b/src/conf/domain_postparse.h new file mode 100644 index 0000000000..fe5e28ea7c --- /dev/null +++ b/src/conf/domain_postparse.h @@ -0,0 +1,37 @@ +/* + * domain_postparse.h: domain post parsing helpers + * + * Copyright (C) 2022 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#pragma once + +#include "domain_conf.h" +#include "virconftypes.h" + +int +virDomainDeviceDefPostParseOne(virDomainDeviceDef *dev, + const virDomainDef *def, + unsigned int flags, + virDomainXMLOption *xmlopt, + void *parseOpaque); + +int +virDomainDefPostParse(virDomainDef *def, + unsigned int parseFlags, + virDomainXMLOption *xmlopt, + void *parseOpaque); diff --git a/src/conf/meson.build b/src/conf/meson.build index 82d265e975..5ef494c3ba 100644 --- a/src/conf/meson.build +++ b/src/conf/meson.build @@ -14,6 +14,7 @@ domain_conf_sources =3D [ 'domain_capabilities.c', 'domain_conf.c', 'domain_nwfilter.c', + 'domain_postparse.c', 'domain_validate.c', 'moment_conf.c', 'numa_conf.c', diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 76bcc64eb0..1e757389e6 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -343,7 +343,6 @@ virDomainDefNew; virDomainDefParseFile; virDomainDefParseNode; virDomainDefParseString; -virDomainDefPostParse; virDomainDefSave; virDomainDefSetMemoryTotal; virDomainDefSetVcpus; @@ -774,6 +773,10 @@ virDomainConfNWFilterTeardown; virDomainConfVMNWFilterTeardown; =20 =20 +# conf/domain_postparse.h +virDomainDefPostParse; + + # conf/domain_validate.h virDomainActualNetDefValidate; virDomainDefValidate; diff --git a/src/libxl/xen_xl.c b/src/libxl/xen_xl.c index e62f591dcd..4de4e3140f 100644 --- a/src/libxl/xen_xl.c +++ b/src/libxl/xen_xl.c @@ -27,6 +27,7 @@ #include "virerror.h" #include "virlog.h" #include "domain_conf.h" +#include "domain_postparse.h" #include "viralloc.h" #include "virstring.h" #include "storage_source_backingstore.h" diff --git a/src/libxl/xen_xm.c b/src/libxl/xen_xm.c index d6213a852d..081d323c2a 100644 --- a/src/libxl/xen_xm.c +++ b/src/libxl/xen_xm.c @@ -29,6 +29,7 @@ #include "xenxs_private.h" #include "xen_xm.h" #include "domain_conf.h" +#include "domain_postparse.h" #include "xen_common.h" =20 #define VIR_FROM_THIS VIR_FROM_XENXM diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 025c376ad2..3d0060e1b0 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -29,6 +29,7 @@ #include "util/virstring.h" #include "util/virconf.h" #include "conf/domain_conf.h" +#include "conf/domain_postparse.h" #include "virutil.h" =20 #define VIR_FROM_THIS VIR_FROM_LXC diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 97c6ed95af..c4418df1ed 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -67,6 +67,7 @@ #include "domain_audit.h" #include "domain_cgroup.h" #include "domain_driver.h" +#include "domain_postparse.h" #include "domain_validate.h" #include "virpci.h" #include "virpidfile.h" diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 771a623ef7..486be9344a 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -75,6 +75,7 @@ #include "domain_audit.h" #include "domain_cgroup.h" #include "domain_nwfilter.h" +#include "domain_postparse.h" #include "domain_validate.h" #include "locking/domain_lock.h" #include "viruuid.h" diff --git a/src/vmx/vmx.c b/src/vmx/vmx.c index 43ddee5bb6..f7261f5d2d 100644 --- a/src/vmx/vmx.c +++ b/src/vmx/vmx.c @@ -31,6 +31,7 @@ #include "viruri.h" #include "virstring.h" #include "virutil.h" +#include "domain_postparse.h" =20 VIR_LOG_INIT("vmx.vmx"); =20 --=20 2.35.1 From nobody Wed May 15 00:35:40 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) client-ip=170.10.133.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.133.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=1657188451; cv=none; d=zohomail.com; s=zohoarc; b=W4Sjy5MavvAi0vjywxISnfa1o4PCPKYslU/oZQvhI7zuqj+3yf7RF6F+fUWm+5k3wIvS0yZRlC5C5kAPEQs7Y5RJq0px7XkP7tWmmKGBocwFeJ98sWfwREowtmynqsUtzhUUsqYmMryxyKqM3eD0ZTvva4PYfCgCOjiw3UweBTw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1657188451; 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=pkR4dTucfzVsXhJCjA09bYQTWE5ZaPFlLRg3qdwQ20Q=; b=VFdFlbq4FwqMX7AkvUU44bOB1pR6s2KhuNCG3YBfxUSPRCZ0twLATM10v4ipRQALX0O34wCuUao8UK8FeZyUMC0hY1oaabmjMfnvKRVVGjtIIeycBF6SrpJlvvmCWWmZtDRUXX/uG6JksHMlaXk0Zna+0tnCI9oFUv+Q/xOVBMA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.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.133.124]) by mx.zohomail.com with SMTPS id 165718845197751.45182740590144; Thu, 7 Jul 2022 03:07:31 -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-644-9RbZWBADN9e_LyuKb7ApMg-1; Thu, 07 Jul 2022 06:07:24 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 2BB21851784; Thu, 7 Jul 2022 10:07:20 +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 AE3CC2166B2A; Thu, 7 Jul 2022 10:07:19 +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 4E9DB1947B97; Thu, 7 Jul 2022 10:07:16 +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 4F3511947076 for ; Thu, 7 Jul 2022 10:07:13 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id 3F5D7C28129; Thu, 7 Jul 2022 10:07:13 +0000 (UTC) Received: from maggie.redhat.com (unknown [10.43.2.39]) by smtp.corp.redhat.com (Postfix) with ESMTP id DD07EC2811A for ; Thu, 7 Jul 2022 10:07:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1657188448; 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=pkR4dTucfzVsXhJCjA09bYQTWE5ZaPFlLRg3qdwQ20Q=; b=SjqbOGNwa8nK2paERLOaob4v9LH9+h2OMjAS3gTmpMPJwVG+LKDeGsWqsPtttOZ5s/cpGK LEm7RkyFjiL/Udh9JAsVYmEmSVLQHn4IjQDbOiDEijz5Ve+q/BgM1YzX0Y4enzy9jzN/Mw RFXgbHttf3oGNq0z/aYOcQYFgXYvrIc= X-MC-Unique: 9RbZWBADN9e_LyuKb7ApMg-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Michal Privoznik To: libvir-list@redhat.com Subject: [PATCH 3/3] domain_postparse: Move error messages onto single line Date: Thu, 7 Jul 2022 12:07:09 +0200 Message-Id: In-Reply-To: References: MIME-Version: 1.0 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: , Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 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-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1657188453917100002 Content-Type: text/plain; charset="utf-8"; x-default="true" Our coding style suggests 80 chars per line with error messages being exception (for easier git-grep). Apply this exception onto the newly created domain_postparse.c file. Signed-off-by: Michal Privoznik Reviewed-by: J=C3=A1n Tomko --- src/conf/domain_postparse.c | 49 ++++++++++++------------------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/src/conf/domain_postparse.c b/src/conf/domain_postparse.c index 18f06dcca8..df59de2d0d 100644 --- a/src/conf/domain_postparse.c +++ b/src/conf/domain_postparse.c @@ -57,16 +57,14 @@ virDomainDefPostParseMemory(virDomainDef *def, * properly. */ if (hotplugMemory > def->mem.total_memory) { virReportError(VIR_ERR_XML_ERROR, "%s", - _("Total size of memory devices exceeds the tot= al " - "memory size")); + _("Total size of memory devices exceeds the tot= al memory size")); return -1; } } =20 if (virDomainDefGetMemoryInitial(def) =3D=3D 0) { virReportError(VIR_ERR_XML_ERROR, "%s", - _("Memory size must be specified via or in= the " - " configuration")); + _("Memory size must be specified via or in= the configuration")); return -1; } =20 @@ -77,16 +75,14 @@ virDomainDefPostParseMemory(virDomainDef *def, if ((def->mem.max_memory || def->mem.memory_slots) && !(def->mem.max_memory && def->mem.memory_slots)) { virReportError(VIR_ERR_XML_ERROR, "%s", - _("both maximum memory size and " - "memory slot count must be specified")); + _("both maximum memory size and memory slot count m= ust be specified")); return -1; } =20 if (def->mem.max_memory && def->mem.max_memory < virDomainDefGetMemoryTotal(def)) { virReportError(VIR_ERR_XML_ERROR, "%s", - _("maximum memory size must be equal or greater tha= n " - "the actual memory size")); + _("maximum memory size must be equal or greater tha= n the actual memory size")); return -1; } =20 @@ -102,8 +98,7 @@ virDomainDefPostParseOs(virDomainDef *def) =20 if (def->os.firmwareFeatures[VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_SE= CURE_BOOT] =3D=3D VIR_TRISTATE_BOOL_NO) { virReportError(VIR_ERR_XML_DETAIL, "%s", - _("firmware feature 'enrolled-keys' cannot be e= nabled when " - "firmware feature 'secure-boot' is disabled")= ); + _("firmware feature 'enrolled-keys' cannot be e= nabled when firmware feature 'secure-boot' is disabled")); return -1; } =20 @@ -165,8 +160,7 @@ virDomainDefPostParseTimer(virDomainDef *def) timer->name =3D=3D VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK) { if (timer->tickpolicy) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("timer %s doesn't support setting of " - "timer tickpolicy"), + _("timer %s doesn't support setting of time= r tickpolicy"), virDomainTimerNameTypeToString(timer->name)= ); return -1; } @@ -177,24 +171,21 @@ virDomainDefPostParseTimer(virDomainDef *def) timer->catchup.limit !=3D 0 || timer->catchup.slew !=3D 0)) { virReportError(VIR_ERR_XML_ERROR, "%s", - _("setting of timer catchup policies is only " - "supported with tickpolicy=3D'catchup'")); + _("setting of timer catchup policies is only su= pported with tickpolicy=3D'catchup'")); return -1; } =20 if (timer->name !=3D VIR_DOMAIN_TIMER_NAME_TSC) { if (timer->frequency !=3D 0) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("timer %s doesn't support setting of " - "timer frequency"), + _("timer %s doesn't support setting of time= r frequency"), virDomainTimerNameTypeToString(timer->name)= ); return -1; } =20 if (timer->mode) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("timer %s doesn't support setting of " - "timer mode"), + _("timer %s doesn't support setting of time= r mode"), virDomainTimerNameTypeToString(timer->name)= ); return -1; } @@ -204,8 +195,7 @@ virDomainDefPostParseTimer(virDomainDef *def) timer->name !=3D VIR_DOMAIN_TIMER_NAME_RTC) { if (timer->track !=3D VIR_DOMAIN_TIMER_TRACK_NONE) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("timer %s doesn't support setting of " - "timer track"), + _("timer %s doesn't support setting of time= r track"), virDomainTimerNameTypeToString(timer->name)= ); return -1; } @@ -351,9 +341,7 @@ virDomainHostdevDefPostParse(virDomainHostdevDef *dev, VIR_DOMAIN_DISK_BUS_SCSI, addr)) { virReportError(VIR_ERR_XML_ERROR, - _("SCSI host address controller=3D'%u' " - "bus=3D'%u' target=3D'%u' unit=3D'%u' in " - "use by a SCSI disk"), + _("SCSI host address controller=3D'%u' bus=3D'%= u' target=3D'%u' unit=3D'%u' in use by a SCSI disk"), addr->controller, addr->bus, addr->target, addr->unit); return -1; @@ -370,8 +358,7 @@ virDomainHostdevDefPostParse(virDomainHostdevDef *dev, (model =3D=3D VIR_MDEV_MODEL_TYPE_VFIO_CCW && dev->info->type !=3D VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)) { virReportError(VIR_ERR_XML_ERROR, - _("Unsupported address type '%s' with mediated " - "device model '%s'"), + _("Unsupported address type '%s' with mediated = device model '%s'"), virDomainDeviceAddressTypeToString(dev->info->t= ype), virMediatedDeviceModelTypeToString(model)); return -1; @@ -611,8 +598,7 @@ virDomainControllerDefPostParse(virDomainControllerDef = *cdev) cdev->model !=3D VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_TRANSITIO= NAL && cdev->model !=3D VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_NON_TRANS= ITIONAL) { virReportError(VIR_ERR_XML_ERROR, "%s", - _("'iothread' attribute only supported for " - "virtio scsi controllers")); + _("'iothread' attribute only supported for virtio s= csi controllers")); return -1; } =20 @@ -774,8 +760,7 @@ virDomainDefCheckUnsupportedMemoryHotplug(virDomainDef = *def) /* memory hotplug tunables are not supported by this driver */ if (virDomainDefHasMemoryHotplug(def)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("memory hotplug tunables are not " - "supported by this hypervisor driver")); + _("memory hotplug tunables are not supp= orted by this hypervisor driver")); return -1; } =20 @@ -1003,8 +988,7 @@ virDomainVcpuDefPostParse(virDomainDef *def) case VIR_TRISTATE_BOOL_NO: if (!vcpu->online) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("vcpu '%zu' is both offline and not " - "hotpluggable"), i); + _("vcpu '%zu' is both offline and not hotpl= uggable"), i); return -1; } break; @@ -1083,8 +1067,7 @@ virDomainDefBootOrderPostParse(virDomainDef *def) =20 if (def->os.nBootDevs > 0 && virHashSize(bootHash) > 0) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("per-device boot elements cannot be used" - " together with os/boot elements")); + _("per-device boot elements cannot be used together= with os/boot elements")); return -1; } =20 --=20 2.35.1