From nobody Tue Feb 10 07:40:12 2026 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=1616777354; cv=none; d=zohomail.com; s=zohoarc; b=TxGlJ6av0RqQt51+MPH4pdadnYhQb5vojKApTWEwpUWGHKdZC2OPX90+syYsMB88VGnOLsbEiEvr1TGOzhKH1cnwNlSgRLILmdWTGMXGyl03adArQAJGeRPaMY0NNGq+HUfvaU/qTIBoC45Hklu7f28fzYWwmELK94s+nQFyuIY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1616777354; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=jlK8NSyrEUJdMvEDoCLI2lkLMALIfE12DVeQU05zBWs=; b=TuuaFWPAE/7yHmpRiYm7SSjq1AqriJuTpdB/ZDbKkzl2SGlEa0bVySmjgdhOu0HvPDbroxTDwFhTdbVoWz9O1PwQRvpnOyPOSmAnfHXw2t03YQhu9V+mt58bnGSNo/CBSb0AGCRgNHEyQNe+HLxOhIi/c2+bJiyrKaf94u1O9Ow= 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) header.from= 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 1616777354467704.1402129710261; Fri, 26 Mar 2021 09:49:14 -0700 (PDT) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-68-DlkkhnG1NvKwbnaIpycEug-1; Fri, 26 Mar 2021 12:49:08 -0400 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id A4CDF10866AA; Fri, 26 Mar 2021 16:49:01 +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 7B297100AE43; Fri, 26 Mar 2021 16:49:01 +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 3E1EB4A71A; Fri, 26 Mar 2021 16:49:01 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 12QGmbg0002977 for ; Fri, 26 Mar 2021 12:48:37 -0400 Received: by smtp.corp.redhat.com (Postfix) id 5C3755D755; Fri, 26 Mar 2021 16:48:37 +0000 (UTC) Received: from himantopus.redhat.com (ovpn-113-51.phx2.redhat.com [10.3.113.51]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 228215D6DC; Fri, 26 Mar 2021 16:48:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1616777353; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=jlK8NSyrEUJdMvEDoCLI2lkLMALIfE12DVeQU05zBWs=; b=PsOjGxgRUdJHPsDnb/1a2EwsjnLhtPkWbHpB8ZBQvugLcZes6mA7hBVP3gt5wg835qyFEi 6ivkepfgHaoWKmuCe0MUyN61mGjEn4txZr+LYB2Oqb4sh+tnUyGZmkTsHFgDH2ckKYEXxt 6KJTf7k3KL+3kpGGaIbfGzSbFiSWmj8= X-MC-Unique: DlkkhnG1NvKwbnaIpycEug-1 From: Jonathon Jongsma To: libvir-list@redhat.com Subject: [libvirt PATCH v6 11/30] nodedev: add mdevctl devices to node device list Date: Fri, 26 Mar 2021 11:48:07 -0500 Message-Id: <20210326164826.1720062-12-jjongsma@redhat.com> In-Reply-To: <20210326164826.1720062-1-jjongsma@redhat.com> References: <20210326164826.1720062-1-jjongsma@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-loop: libvir-list@redhat.com Cc: eskultet@redhat.com 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: , Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 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) Content-Type: text/plain; charset="utf-8" At startup, query devices that are defined by 'mdevctl' and add them to the node device list. This adds a complication: we now have two potential sources of information for a node device: - udev for all devices and for activated mediated devices - mdevctl for persistent mediated devices Unfortunately, neither backend returns full information for a mediated device. For example, if a persistent mediated device in the list (with information provided from mdevctl) is 'started', that same device will now be detected by udev. If we simply overwrite the existing device definition with the new one provided by the udev backend, we will lose extra information that was provided by mdevctl (e.g. attributes, etc). To avoid this, make sure to copy the extra information into the new device definition. Signed-off-by: Jonathon Jongsma Reviewed-by: Erik Skultety --- src/node_device/node_device_driver.c | 153 +++++++++++++++++++++++++++ src/node_device/node_device_driver.h | 6 ++ src/node_device/node_device_udev.c | 31 +++++- 3 files changed, 185 insertions(+), 5 deletions(-) diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_de= vice_driver.c index 6911fa36da..efa524f317 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -1164,3 +1164,156 @@ nodeDeviceGenerateName(virNodeDeviceDef *def, *(def->name + i) =3D '_'; } } + + +static int +virMdevctlListDefined(virNodeDeviceDef ***devs) +{ + int status; + g_autofree char *output =3D NULL; + g_autoptr(virCommand) cmd =3D nodeDeviceGetMdevctlListCommand(true, &o= utput); + + if (virCommandRun(cmd, &status) < 0 || status !=3D 0) + return -1; + + if (!output) + return -1; + + return nodeDeviceParseMdevctlJSON(output, devs); +} + + +int +nodeDeviceUpdateMediatedDevices(void) +{ + g_autofree virNodeDeviceDef **defs =3D NULL; + int ndefs; + size_t i; + + if ((ndefs =3D virMdevctlListDefined(&defs)) < 0) { + virReportSystemError(errno, "%s", + _("failed to query mdevs from mdevctl")); + return -1; + } + + for (i =3D 0; i < ndefs; i++) { + virNodeDeviceObj *obj; + virObjectEvent *event; + g_autoptr(virNodeDeviceDef) def =3D defs[i]; + g_autofree char *name =3D g_strdup(def->name); + bool defined =3D false; + + def->driver =3D g_strdup("vfio_mdev"); + + if (!(obj =3D virNodeDeviceObjListFindByName(driver->devs, def->na= me))) { + virNodeDeviceDef *d =3D g_steal_pointer(&def); + if (!(obj =3D virNodeDeviceObjListAssignDef(driver->devs, d)))= { + virNodeDeviceDefFree(d); + return -1; + } + } else { + bool changed; + virNodeDeviceDef *olddef =3D virNodeDeviceObjGetDef(obj); + + defined =3D virNodeDeviceObjIsPersistent(obj); + /* Active devices contain some additional information (e.g. sy= sfs + * path) that is not provided by mdevctl, so re-use the existi= ng + * definition and copy over new mdev data */ + changed =3D nodeDeviceDefCopyFromMdevctl(olddef, def); + + if (defined && !changed) { + /* if this device was already defined and the definition + * hasn't changed, there's nothing to do for this device */ + virNodeDeviceObjEndAPI(&obj); + continue; + } + } + + /* all devices returned by virMdevctlListDefined() are persistent = */ + virNodeDeviceObjSetPersistent(obj, true); + + if (!defined) + event =3D virNodeDeviceEventLifecycleNew(name, + VIR_NODE_DEVICE_EVENT_D= EFINED, + 0); + else + event =3D virNodeDeviceEventUpdateNew(name); + + virNodeDeviceObjEndAPI(&obj); + virObjectEventStateQueue(driver->nodeDeviceEventState, event); + } + + return 0; +} + + +/* returns true if any attributes were copied, else returns false */ +static bool +virMediatedDeviceAttrsCopy(virNodeDevCapMdev *dst, + virNodeDevCapMdev *src) +{ + bool ret =3D false; + size_t i; + + if (src->nattributes !=3D dst->nattributes) { + ret =3D true; + for (i =3D 0; i < dst->nattributes; i++) + virMediatedDeviceAttrFree(dst->attributes[i]); + g_free(dst->attributes); + + dst->nattributes =3D src->nattributes; + dst->attributes =3D g_new0(virMediatedDeviceAttr*, + src->nattributes); + for (i =3D 0; i < dst->nattributes; i++) + dst->attributes[i] =3D virMediatedDeviceAttrNew(); + } + + for (i =3D 0; i < src->nattributes; i++) { + if (STRNEQ_NULLABLE(src->attributes[i]->name, + dst->attributes[i]->name)) { + ret =3D true; + g_free(dst->attributes[i]->name); + dst->attributes[i]->name =3D + g_strdup(src->attributes[i]->name); + } + if (STRNEQ_NULLABLE(src->attributes[i]->value, + dst->attributes[i]->value)) { + ret =3D true; + g_free(dst->attributes[i]->value); + dst->attributes[i]->value =3D + g_strdup(src->attributes[i]->value); + } + } + + return ret; +} + + +/* A mediated device definitions from mdevctl contains additional info tha= t is + * not available from udev. Transfer this data to the new definition. + * Returns true if anything was copied, else returns false */ +bool +nodeDeviceDefCopyFromMdevctl(virNodeDeviceDef *dst, + virNodeDeviceDef *src) +{ + bool ret =3D false; + virNodeDevCapMdev *srcmdev =3D &src->caps->data.mdev; + virNodeDevCapMdev *dstmdev =3D &dst->caps->data.mdev; + + if (STRNEQ_NULLABLE(dstmdev->type, srcmdev->type)) { + ret =3D true; + g_free(dstmdev->type); + dstmdev->type =3D g_strdup(srcmdev->type); + } + + if (STRNEQ_NULLABLE(dstmdev->uuid, srcmdev->uuid)) { + ret =3D true; + g_free(dstmdev->uuid); + dstmdev->uuid =3D g_strdup(srcmdev->uuid); + } + + if (virMediatedDeviceAttrsCopy(dstmdev, srcmdev)) + ret =3D true; + + return ret; +} diff --git a/src/node_device/node_device_driver.h b/src/node_device/node_de= vice_driver.h index 705d83f827..9b54efe4e3 100644 --- a/src/node_device/node_device_driver.h +++ b/src/node_device/node_device_driver.h @@ -128,8 +128,14 @@ int nodeDeviceParseMdevctlJSON(const char *jsonstring, virNodeDeviceDef ***devs); =20 +int +nodeDeviceUpdateMediatedDevices(void); + void nodeDeviceGenerateName(virNodeDeviceDef *def, const char *subsystem, const char *sysname, const char *s); + +bool nodeDeviceDefCopyFromMdevctl(virNodeDeviceDef *dst, + virNodeDeviceDef *src); diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_devi= ce_udev.c index eae301cc95..38ebe7b5c5 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -1421,9 +1421,17 @@ udevRemoveOneDeviceSysPath(const char *path) VIR_NODE_DEVICE_EVENT_DELETED, 0); =20 - VIR_DEBUG("Removing device '%s' with sysfs path '%s'", - def->name, path); - virNodeDeviceObjListRemove(driver->devs, obj); + /* If the device is a mediated device that has been 'stopped', it may = still + * be defined by mdevctl and can therefore be started again. Don't dro= p it + * from the list of node devices */ + if (virNodeDeviceObjIsPersistent(obj)) { + VIR_FREE(def->sysfs_path); + virNodeDeviceObjSetActive(obj, false); + } else { + VIR_DEBUG("Removing device '%s' with sysfs path '%s'", + def->name, path); + virNodeDeviceObjListRemove(driver->devs, obj); + } virNodeDeviceObjEndAPI(&obj); =20 virObjectEventStateQueue(driver->nodeDeviceEventState, event); @@ -1481,7 +1489,6 @@ udevSetParent(struct udev_device *device, return 0; } =20 - static int udevAddOneDevice(struct udev_device *device) { @@ -1491,6 +1498,7 @@ udevAddOneDevice(struct udev_device *device) virObjectEventPtr event =3D NULL; bool new_device =3D true; int ret =3D -1; + bool was_persistent =3D false; =20 def =3D g_new0(virNodeDeviceDef, 1); =20 @@ -1514,14 +1522,23 @@ udevAddOneDevice(struct udev_device *device) goto cleanup; =20 if ((obj =3D virNodeDeviceObjListFindByName(driver->devs, def->name)))= { + objdef =3D virNodeDeviceObjGetDef(obj); + + if (def->caps->data.type =3D=3D VIR_NODE_DEV_CAP_MDEV) + nodeDeviceDefCopyFromMdevctl(def, objdef); + was_persistent =3D virNodeDeviceObjIsPersistent(obj); + /* If the device was defined by mdevctl and was never instantiated= , it + * won't have a sysfs path. We need to emit a CREATED event... */ + new_device =3D (objdef->sysfs_path =3D=3D NULL); + virNodeDeviceObjEndAPI(&obj); - new_device =3D false; } =20 /* If this is a device change, the old definition will be freed * and the current definition will take its place. */ if (!(obj =3D virNodeDeviceObjListAssignDef(driver->devs, def))) goto cleanup; + virNodeDeviceObjSetPersistent(obj, was_persistent); objdef =3D virNodeDeviceObjGetDef(obj); =20 if (new_device) @@ -1941,6 +1958,10 @@ nodeStateInitializeEnumerate(void *opaque) /* Populate with known devices */ if (udevEnumerateDevices(udev) !=3D 0) goto error; + /* Load persistent mdevs (which might not be activated yet) and additi= onal + * information about active mediated devices from mdevctl */ + if (nodeDeviceUpdateMediatedDevices() !=3D 0) + goto error; =20 nodeDeviceLock(); driver->initialized =3D true; --=20 2.26.3