From nobody Wed Feb 11 10:15:07 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.39 as permitted sender) client-ip=209.132.183.39; envelope-from=libvir-list-bounces@redhat.com; helo=mx6-phx2.redhat.com; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.39 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; Return-Path: Received: from mx6-phx2.redhat.com (mx6-phx2.redhat.com [209.132.183.39]) by mx.zohomail.com with SMTPS id 1489596037151436.90290873816764; Wed, 15 Mar 2017 09:40:37 -0700 (PDT) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by mx6-phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v2FGb5AP023647; Wed, 15 Mar 2017 12:37:05 -0400 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id v2FGb1Qm025021 for ; Wed, 15 Mar 2017 12:37:01 -0400 Received: from angien.brq.redhat.com (dhcp129-47.brq.redhat.com [10.34.129.47]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v2FGafIU000870; Wed, 15 Mar 2017 12:37:00 -0400 From: Peter Krempa To: libvir-list@redhat.com Date: Wed, 15 Mar 2017 17:37:28 +0100 Message-Id: In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-loop: libvir-list@redhat.com Cc: Peter Krempa Subject: [libvirt] [PATCH 16/23] qemu: block: Add code to allow detection of auto-allocated node names 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: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" qemu for some time already sets node names automatically for the block nodes. This patch adds code that attempts a best-effort detection of the node names for the backing chain from the output of 'query-named-block-nodes'. The only drawback is that the data provided by qemu needs to be matched by the filename as seen by qemu and thus if two disks share a single backing store file the detection won't work. This will allow us to use qemu commands such as 'block-set-write-threshold' which only accepts node names. In this patch only the detection code is added, it will be used later. --- src/Makefile.am | 1 + src/qemu/qemu_block.c | 280 ++++++++++++++++++++++++++++++++++++++++++++++= ++++ src/qemu/qemu_block.h | 47 +++++++++ 3 files changed, 328 insertions(+) create mode 100644 src/qemu/qemu_block.c create mode 100644 src/qemu/qemu_block.h diff --git a/src/Makefile.am b/src/Makefile.am index f0d8efe50..b4ecd6366 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -823,6 +823,7 @@ VBOX_DRIVER_EXTRA_DIST =3D \ QEMU_DRIVER_SOURCES =3D \ qemu/qemu_agent.c qemu/qemu_agent.h \ qemu/qemu_alias.c qemu/qemu_alias.h \ + qemu/qemu_block.c qemu/qemu_block.h \ qemu/qemu_blockjob.c qemu/qemu_blockjob.h \ qemu/qemu_capabilities.c qemu/qemu_capabilities.h \ qemu/qemu_command.c qemu/qemu_command.h \ diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c new file mode 100644 index 000000000..91c04ab7f --- /dev/null +++ b/src/qemu/qemu_block.c @@ -0,0 +1,280 @@ +/* + * qemu_block.c: helper functions for QEMU block subsystem + * + * 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 "qemu_block.h" +#include "qemu_domain.h" + +#include "viralloc.h" +#include "virstring.h" + +#define VIR_FROM_THIS VIR_FROM_QEMU + + +static void +qemuBlockNodeNameBackingChainDataFree(qemuBlockNodeNameBackingChainDataPtr= data) +{ + size_t i; + + if (!data) + return; + + for (i =3D 0; i < data->nelems; i++) + virJSONValueFree(data->elems[i]); + + VIR_FREE(data->nodeformat); + VIR_FREE(data->nodestorage); + VIR_FREE(data->nodebacking); + + VIR_FREE(data->qemufilename); + VIR_FREE(data->backingstore); + + VIR_FREE(data); +} + + +static void +qemuBlockNodeNameBackingChainDataHashEntryFree(void *opaque, + const void *name ATTRIBUTE_= UNUSED) +{ + qemuBlockNodeNameBackingChainDataFree(opaque); +} + + +struct qemuBlockNodeNameGetBackingChainData { + virHashTablePtr table; + qemuBlockNodeNameBackingChainDataPtr *entries; + size_t nentries; +}; + + +static int +qemuBlockNodeNameDetectProcessByFilename(size_t pos ATTRIBUTE_UNUSED, + virJSONValuePtr item, + void *opaque) +{ + struct qemuBlockNodeNameGetBackingChainData *data =3D opaque; + qemuBlockNodeNameBackingChainDataPtr entry; + const char *file; + + if (!(file =3D virJSONValueObjectGetString(item, "file"))) + return 1; + + if (!(entry =3D virHashLookup(data->table, file))) { + if (VIR_ALLOC(entry) < 0) + return -1; + + if (VIR_APPEND_ELEMENT_COPY(data->entries, data->nentries, entry) = < 0) { + VIR_FREE(entry); + return -1; + } + + if (VIR_STRDUP(entry->qemufilename, file) < 0) + return -1; + + if (virHashAddEntry(data->table, file, entry) < 0) + return -1; + } + + if (VIR_APPEND_ELEMENT(entry->elems, entry->nelems, item) < 0) + return -1; + + return 0; +} + + +static const char *qemuBlockDriversFormat[] =3D { + "qcow2", "raw", "qcow", "luks", "qed", "bochs", "cloop", "dmg", "paral= lels", + "vdi", "vhdx", "vmdk", "vpc", "vvfat", NULL}; +static const char *qemuBlockDriversStorage[] =3D { + "file", "iscsi", "nbd", "host_cdrom", "host_device", "ftp", "ftps", + "gluster", "http", "https", "nfs", "rbd", "sheepdog", "ssh", "tftp", N= ULL}; + + +static bool +qemuBlockDriverMatch(const char *drvname, + const char **drivers) +{ + while (*drivers) { + if (STREQ(drvname, *drivers)) + return true; + + drivers++; + } + + return false; +} + + +static int +qemuBlockNodeNameDetectProcessExtract(qemuBlockNodeNameBackingChainDataPtr= data) +{ + const char *drv; + const char *nodename; + const char *backingstore; + size_t i; + + /* Since the only way to construct the backing chain is to look up the= files + * by file name, if two disks share a backing image we can't know whic= h node + * belongs to which backing chain. Refuse to detect such chains. */ + if (data->nelems > 2) + return 0; + + for (i =3D 0; i < data->nelems; i++) { + drv =3D virJSONValueObjectGetString(data->elems[i], "drv"); + nodename =3D virJSONValueObjectGetString(data->elems[i], "node-nam= e"); + backingstore =3D virJSONValueObjectGetString(data->elems[i], "back= ing_file"); + + if (!drv || !nodename) + continue; + + if (qemuBlockDriverMatch(drv, qemuBlockDriversFormat)) { + if (data->nodeformat) + continue; + + if (VIR_STRDUP(data->nodeformat, nodename) < 0) + return -1; + + /* extract the backing store file name for the protocol layer = */ + if (VIR_STRDUP(data->backingstore, backingstore) < 0) + return -1; + } else if (qemuBlockDriverMatch(drv, qemuBlockDriversStorage)) { + if (data->nodestorage) + continue; + + if (VIR_STRDUP(data->nodestorage, nodename) < 0) + return -1; + } + } + + return 0; +} + + +static int +qemuBlockNodeNameDetectProcessLinkBacking(qemuBlockNodeNameBackingChainDat= aPtr data, + virHashTablePtr table) +{ + qemuBlockNodeNameBackingChainDataPtr backing; + + if (!data->backingstore) + return 0; + + if (!(backing =3D virHashLookup(table, data->backingstore))) + return 0; + + if (VIR_STRDUP(data->nodebacking, backing->nodeformat) < 0) + return -1; + + return 0; +} + + +static void +qemuBlockNodeNameGetBackingChainDataClearLookup(qemuBlockNodeNameBackingCh= ainDataPtr data) +{ + size_t i; + + for (i =3D 0; i < data->nelems; i++) + virJSONValueFree(data->elems[i]); + + VIR_FREE(data->elems); + data->nelems =3D 0; +} + + +/** + * qemuBlockNodeNameGetBackingChain: + * @json: JSON array of data returned from 'query-named-block-nodes' + * + * Tries to reconstruct the backing chain from @json to allow detection of + * node names that were auto-assigned by qemu. This is a best-effort opera= tion + * and may not be successful. The returned hash table contains the entries= as + * qemuBlockNodeNameBackingChainDataPtr accessible by the node name. The f= ields + * then can be used to recover the full backing chain. + * + * Returns a hash table on success and NULL on failure. + */ +virHashTablePtr +qemuBlockNodeNameGetBackingChain(virJSONValuePtr json) +{ + struct qemuBlockNodeNameGetBackingChainData data; + virHashTablePtr nodetable =3D NULL; + virHashTablePtr ret =3D NULL; + size_t i; + + memset(&data, 0, sizeof(data)); + + /* hash table keeps the entries accessible by the 'file' in qemu */ + if (!(data.table =3D virHashCreate(50, NULL))) + goto cleanup; + + /* first group the named entries by the 'file' field */ + if (virJSONValueArrayForeachSteal(json, + qemuBlockNodeNameDetectProcessByFile= name, + &data) < 0) + goto cleanup; + + /* extract the node names for the format and storage layer */ + for (i =3D 0; i < data.nentries; i++) { + if (qemuBlockNodeNameDetectProcessExtract(data.entries[i]) < 0) + goto cleanup; + } + + /* extract the node name for the backing file */ + for (i =3D 0; i < data.nentries; i++) { + if (qemuBlockNodeNameDetectProcessLinkBacking(data.entries[i], + data.table) < 0) + goto cleanup; + } + + /* clear JSON data necessary only for the lookup procedure */ + for (i =3D 0; i < data.nentries; i++) + qemuBlockNodeNameGetBackingChainDataClearLookup(data.entries[i]); + + /* create hash table hashed by the format node name */ + if (!(nodetable =3D virHashCreate(50, + qemuBlockNodeNameBackingChainDataHashE= ntryFree))) + goto cleanup; + + /* fill the entries */ + for (i =3D 0; i < data.nentries; i++) { + if (!data.entries[i]->nodeformat) + continue; + + if (virHashAddEntry(nodetable, data.entries[i]->nodeformat, + data.entries[i]) < 0) + goto cleanup; + + /* hash table steals the entry and then frees it by itself */ + data.entries[i] =3D NULL; + } + + VIR_STEAL_PTR(ret, nodetable); + + cleanup: + virHashFree(data.table); + virHashFree(nodetable); + for (i =3D 0; i < data.nentries; i++) + qemuBlockNodeNameBackingChainDataFree(data.entries[i]); + + VIR_FREE(data.entries); + + return ret; +} diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h new file mode 100644 index 000000000..26f5ae062 --- /dev/null +++ b/src/qemu/qemu_block.h @@ -0,0 +1,47 @@ +/* + * qemu_block.h: helper functions for QEMU block subsystem + * + * 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 + * . + */ + +#ifndef __QEMU_BLOCK_H__ +# define __QEMU_BLOCK_H__ + +# include "internal.h" + +# include "qemu_conf.h" + +# include "virhash.h" +# include "virjson.h" + +typedef struct qemuBlockNodeNameBackingChainData qemuBlockNodeNameBackingC= hainData; +typedef qemuBlockNodeNameBackingChainData *qemuBlockNodeNameBackingChainDa= taPtr; +struct qemuBlockNodeNameBackingChainData { + char *qemufilename; /* name of the image from qemu */ + char *backingstore; + char *nodeformat; /* node name of the format layer */ + char *nodestorage; /* node name of the storage backing the format nod= e */ + + char *nodebacking; /* node name of the backing file format layer */ + + /* data necessary for detection of the node names from qemu */ + virJSONValuePtr *elems; + size_t nelems; +}; + +virHashTablePtr +qemuBlockNodeNameGetBackingChain(virJSONValuePtr data); + +#endif /* __QEMU_BLOCK_H__ */ --=20 2.12.0 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list