map partition paths to cgroups directories, in all mounted controllers.
:since:`Since 1.0.5`
+Fibre Channel VMID
+-------------------
+
+The FC SAN can provide various QoS levels and access control depending on the
+VMID. It can also collect telemetry data at per-VM level which can be used
+to enhance the IO performance of the VM. This can be configured by using
+the ``appid`` attribute of ``fibrechannel`` element. The attribute contains
+single string (max 128 bytes) and it is used by kernel to create VMID.
+
+::
+
+ ...
+ <resource>
+ <fibrechannel appid='userProvidedID'/>
+ </resource>
+ ...
+
+Using this feature requires Fibre Channel capable HW, kernel compiled with
+option ``CONFIG_BLK_CGROUP_FC_APPID`` and ``nvme_fc`` kernel module loaded.
+:since:`Since 7.7.0`
+
:anchor:`<a id="elementsCPU"/>`
CPU model and topology
</element>
</define>
+ <define name="fibrechannel">
+ <element name="fibrechannel">
+ <attribute name="appid">
+ <data type="string">
+ <!-- All printable characters -->
+ <param name="pattern">[ -~]{1,128}</param>
+ </data>
+ </attribute>
+ </element>
+ </define>
+
<!--
The Identifiers can be:
- an optional id attribute with a number on the domain element
<ref name="absFilePath"/>
</element>
</optional>
+ <optional>
+ <ref name="fibrechannel"/>
+ </optional>
</element>
</define>
return;
g_free(resource->partition);
+ g_free(resource->appid);
g_free(resource);
}
VIR_XPATH_NODE_AUTORESTORE(ctxt)
virDomainResourceDef *def = NULL;
char *partition = NULL;
+ char *appid = NULL;
ctxt->node = node;
partition = virXPathString("string(./partition)", ctxt);
+ appid = virXPathString("string(./fibrechannel/@appid)", ctxt);
- if (!partition)
+ if (!partition && !appid)
return NULL;
def = g_new0(virDomainResourceDef, 1);
def->partition = partition;
+ def->appid = appid;
return def;
}
if (def->partition)
virBufferEscapeString(&childBuf, "<partition>%s</partition>\n", def->partition);
+ if (def->appid)
+ virBufferEscapeString(&childBuf, "<fibrechannel appid='%s'/>\n", def->appid);
+
virXMLFormatElement(buf, "resource", NULL, &childBuf);
}
struct _virDomainResourceDef {
char *partition;
+ char *appid;
};
struct _virDomainHugePage {
}
+#define APPID_LEN_MIN 1
+#define APPID_LEN_MAX 128
+
+static int
+virDomainDefResourceValidate(const virDomainDef *def)
+{
+ if (!def->resource)
+ return 0;
+
+ if (def->resource->appid) {
+ int len;
+
+ if (!virStringIsPrintable(def->resource->appid)) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Fibre Channel 'appid' is not a printable string"));
+ return -1;
+ }
+
+ len = strlen(def->resource->appid);
+ if (len < APPID_LEN_MIN || len > APPID_LEN_MAX) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("Fibre Channel 'appid' string length must be between [%d, %d]"),
+ APPID_LEN_MIN, APPID_LEN_MAX);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
static int
virDomainDefVideoValidate(const virDomainDef *def)
{
virDomainDefValidateInternal(const virDomainDef *def,
virDomainXMLOption *xmlopt)
{
+ if (virDomainDefResourceValidate(def) < 0)
+ return -1;
+
if (virDomainDefDuplicateDiskInfoValidate(def) < 0)
return -1;
--- /dev/null
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219100</memory>
+ <currentMemory unit='KiB'>219100</currentMemory>
+ <vcpu placement='static'>4</vcpu>
+ <resource>
+ <fibrechannel appid='someapp:c7a5fdbd-edaf-9455-926a-d65c16db1809'/>
+ </resource>
+ <os>
+ <type arch='x86_64' machine='q35'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu-system-x86_64</emulator>
+ </devices>
+</domain>
DO_TEST_DIFFERENT("cputune");
DO_TEST("device-backenddomain");
+ DO_TEST("fibrechannel-appid");
+
#define DO_TEST_BACKUP_FULL(name, intrnl) \
do { \
const struct testCompareBackupXMLData data = { .testname = name, \