From nobody Sun Feb 8 17:42:40 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1547480888424832.6033436838735; Mon, 14 Jan 2019 07:48:08 -0800 (PST) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id A373BC0D4721; Mon, 14 Jan 2019 15:48:04 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id D1F8A5DEE1; Mon, 14 Jan 2019 15:48:03 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 6EFCD3F605; Mon, 14 Jan 2019 15:48:03 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id x0EFlv0j012796 for ; Mon, 14 Jan 2019 10:47:57 -0500 Received: by smtp.corp.redhat.com (Postfix) id CD32D17572; Mon, 14 Jan 2019 15:47:57 +0000 (UTC) Received: from antique-work.brq.redhat.com (unknown [10.43.2.63]) by smtp.corp.redhat.com (Postfix) with ESMTP id 51F6D177F1 for ; Mon, 14 Jan 2019 15:47:57 +0000 (UTC) From: Pavel Hrdina To: libvir-list@redhat.com Date: Mon, 14 Jan 2019 16:47:40 +0100 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-loop: libvir-list@redhat.com Subject: [libvirt] [PATCH v2 06/17] vircgroup: introduce virCgroupV2DevicesPrepareProg X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Mon, 14 Jan 2019 15:48:06 +0000 (UTC) Content-Type: text/plain; charset="utf-8" This function will be called for every virCgroup(Allow|Deny)* API in order to prepare BPF program for guest. Since libvirtd can be restarted at any point we will first try to detect existing progam, if there is none we will create a new empty BPF program and lastly if we don't have any space left in the existing BPF map we will create a new copy of the BPF map with more space and attach a new program with that map into the guest cgroup. This solution allows us to start with reasonably small BPF map consuming only small amount of memory and if needed we can easily extend the BPF map if there is a lot of host devices used in guest or if user wants to hot-plug a lot of devices once the guest is running. Since there is no way how to reallocate existing BPF map we need to create a new copy if we run out of space in current BPF map. This overcomes all the limitations in BPF: - map used in program has to be created before the program is loaded into kernel - once map is created you cannot change its size - you cannot replace map in existing program - you cannot use an array of maps because it can store FD to maps of one specific size so we would not be able to use it to overcome the second issue Signed-off-by: Pavel Hrdina --- src/libvirt_private.syms | 1 + src/util/vircgroupv2devices.c | 83 +++++++++++++++++++++++++++++++++++ src/util/vircgroupv2devices.h | 3 ++ 3 files changed, 87 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 8ec188e9cd..1d1f8bf478 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1616,6 +1616,7 @@ virCgroupV2DevicesAttachProg; virCgroupV2DevicesAvailable; virCgroupV2DevicesCreateProg; virCgroupV2DevicesDetectProg; +virCgroupV2DevicesPrepareProg; =20 # util/virclosecallbacks.h virCloseCallbacksGet; diff --git a/src/util/vircgroupv2devices.c b/src/util/vircgroupv2devices.c index cd369ef6ab..e3a415d615 100644 --- a/src/util/vircgroupv2devices.c +++ b/src/util/vircgroupv2devices.c @@ -319,6 +319,52 @@ virCgroupV2DevicesCreateMap(size_t size) } =20 =20 +static int +virCgroupV2DevicesReallocMap(int mapfd, + size_t size) +{ + uint64_t key =3D 0; + uint64_t prevKey =3D 0; + int rc; + int newmapfd =3D virCgroupV2DevicesCreateMap(size); + + VIR_DEBUG("realloc devices map mapfd:%d, size:%lu", mapfd, size); + + if (newmapfd < 0) + return -1; + + while ((rc =3D virBPFGetNextElem(mapfd, &prevKey, &key)) =3D=3D 0) { + uint32_t val =3D 0; + + if (virBPFLookupElem(mapfd, &key, &val) < 0) { + virReportSystemError(errno, "%s", + _("failed to lookup device in old map")); + goto error; + } + + if (virBPFUpdateElem(newmapfd, &key, &val) < 0) { + virReportSystemError(errno, "%s", + _("failed to add device into new map")); + goto error; + } + + prevKey =3D key; + } + + if (rc < 0 && errno !=3D ENOENT) { + virReportSystemError(errno, "%s", + _("failed to copy all device rules")); + goto error; + } + + return newmapfd; + + error: + VIR_FORCE_CLOSE(newmapfd); + return -1; +} + + int virCgroupV2DevicesCreateProg(virCgroupPtr group) { @@ -342,6 +388,33 @@ virCgroupV2DevicesCreateProg(virCgroupPtr group) VIR_FORCE_CLOSE(mapfd); return -1; } + + +int +virCgroupV2DevicesPrepareProg(virCgroupPtr group) +{ + if (virCgroupV2DevicesDetectProg(group) < 0) + return -1; + + if (virCgroupV2DevicesCreateProg(group) < 0) + return -1; + + if (group->unified.devices.count >=3D group->unified.devices.max) { + size_t max =3D group->unified.devices.max * 2; + int newmapfd =3D virCgroupV2DevicesReallocMap(group->unified.devic= es.mapfd, + max); + + if (newmapfd < 0) + return -1; + + if (virCgroupV2DevicesAttachProg(group, newmapfd, max) < 0) { + VIR_FORCE_CLOSE(newmapfd); + return -1; + } + } + + return 0; +} #else /* !HAVE_DECL_BPF_CGROUP_DEVICE */ bool virCgroupV2DevicesAvailable(virCgroupPtr group ATTRIBUTE_UNUSED) @@ -380,4 +453,14 @@ virCgroupV2DevicesCreateProg(virCgroupPtr group ATTRIB= UTE_UNUSED) "with this kernel")); return -1; } + + +int +virCgroupV2DevicesPrepareProg(virCgroupPtr group ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("cgroups v2 BPF devices not supported " + "with this kernel")); + return -1; +} #endif /* !HAVE_DECL_BPF_CGROUP_DEVICE */ diff --git a/src/util/vircgroupv2devices.h b/src/util/vircgroupv2devices.h index bcbd761537..10c80c8ae4 100644 --- a/src/util/vircgroupv2devices.h +++ b/src/util/vircgroupv2devices.h @@ -35,4 +35,7 @@ virCgroupV2DevicesDetectProg(virCgroupPtr group); int virCgroupV2DevicesCreateProg(virCgroupPtr group); =20 +int +virCgroupV2DevicesPrepareProg(virCgroupPtr group); + #endif /* LIBVIRT_VIRCGROUPV2DEVICES_H */ --=20 2.20.1 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list