conf: add 'multidevs' option

Introduce new 'multidevs' option for filesystem.

  <filesystem type='mount' accessmode='mapped' multidevs='remap'>
    <source dir='/path'/>
    <target dir='mount_tag'>
  </filesystem>

This option prevents misbehaviours on guest if a qemu 9pfs export
contains multiple devices, due to the potential file ID collisions
this otherwise may cause.

Signed-off-by: Christian Schoenebeck <qemu_oss@crudebyte.com>
Signed-off-by: Ján Tomko <jtomko@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
This commit is contained in:
Christian Schoenebeck 2020-03-30 20:05:33 +02:00 committed by Ján Tomko
parent 8fe6e82d1c
commit c3a1856890
7 changed files with 202 additions and 1 deletions

View File

@ -3973,7 +3973,7 @@
&lt;source name='my-vm-template'/&gt;
&lt;target dir='/'/&gt;
&lt;/filesystem&gt;
&lt;filesystem type='mount' accessmode='passthrough'&gt;
&lt;filesystem type='mount' accessmode='passthrough' multidevs='remap'&gt;
&lt;driver type='path' wrpolicy='immediate'/&gt;
&lt;source dir='/export/to/guest'/&gt;
&lt;target dir='/import/from/host'/&gt;
@ -4098,6 +4098,44 @@
for more details.
</p>
<p>
The filesystem element has an optional attribute <code>multidevs</code>
which specifies how to deal with a filesystem export containing more than
one device, in order to avoid file ID collisions on guest when using 9pfs
(<span class="since">since 6.3.0, requires QEMU 4.2</span>).
This attribute is not available for virtiofs. The possible values are:
</p>
<dl>
<dt><code>default</code></dt>
<dd>
Use QEMU's default setting (which currently is <code>warn</code>).
</dd>
<dt><code>remap</code></dt>
<dd>
This setting allows guest to access multiple devices per export without
encountering misbehaviours. Inode numbers from host are automatically
remapped on guest to actively prevent file ID collisions if guest
accesses one export containing multiple devices.
</dd>
<dt><code>forbid</code></dt>
<dd>
Only allow to access one device per export by guest. Attempts to access
additional devices on the same export will cause the individual
filesystem access by guest to fail with an error and being logged (once)
as error on host side.
</dd>
<dt><code>warn</code></dt>
<dd>
This setting resembles the behaviour of 9pfs prior to QEMU 4.2, that is
no action is performed to prevent any potential file ID collisions if an
export contains multiple devices, with the only exception: a warning is
logged (once) on host side now. This setting may lead to misbehaviours
on guest side if more than one device is exported per export, due to the
potential file ID collisions this may cause on guest side in that case.
</dd>
</dl>
</dd>
<p>

View File

@ -2706,6 +2706,16 @@
</choice>
</attribute>
</optional>
<optional>
<attribute name="multidevs">
<choice>
<value>default</value>
<value>remap</value>
<value>forbid</value>
<value>warn</value>
</choice>
</attribute>
</optional>
<optional>
<element name='readonly'>
<empty/>

View File

@ -502,6 +502,14 @@ VIR_ENUM_IMPL(virDomainFSModel,
"virtio-non-transitional",
);
VIR_ENUM_IMPL(virDomainFSMultidevs,
VIR_DOMAIN_FS_MULTIDEVS_LAST,
"default",
"remap",
"forbid",
"warn",
);
VIR_ENUM_IMPL(virDomainFSCacheMode,
VIR_DOMAIN_FS_CACHE_MODE_LAST,
"default",
@ -11389,6 +11397,7 @@ virDomainFSDefParseXML(virDomainXMLOptionPtr xmlopt,
g_autofree char *usage = NULL;
g_autofree char *units = NULL;
g_autofree char *model = NULL;
g_autofree char *multidevs = NULL;
ctxt->node = node;
@ -11427,6 +11436,17 @@ virDomainFSDefParseXML(virDomainXMLOptionPtr xmlopt,
}
}
multidevs = virXMLPropString(node, "multidevs");
if (multidevs) {
if ((def->multidevs = virDomainFSMultidevsTypeFromString(multidevs)) < 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("unknown multidevs '%s'"), multidevs);
goto error;
}
} else {
def->multidevs = VIR_DOMAIN_FS_MULTIDEVS_DEFAULT;
}
if (virDomainParseScaledValue("./space_hard_limit[1]",
NULL, ctxt, &def->space_hard_limit,
1, ULLONG_MAX, false) < 0)
@ -25385,6 +25405,7 @@ virDomainFSDefFormat(virBufferPtr buf,
const char *accessmode = virDomainFSAccessModeTypeToString(def->accessmode);
const char *fsdriver = virDomainFSDriverTypeToString(def->fsdriver);
const char *wrpolicy = virDomainFSWrpolicyTypeToString(def->wrpolicy);
const char *multidevs = virDomainFSMultidevsTypeToString(def->multidevs);
const char *src = def->src->path;
g_auto(virBuffer) driverAttrBuf = VIR_BUFFER_INITIALIZER;
g_auto(virBuffer) driverBuf = VIR_BUFFER_INIT_CHILD(buf);
@ -25403,6 +25424,12 @@ virDomainFSDefFormat(virBufferPtr buf,
return -1;
}
if (!multidevs) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("unexpected multidevs %d"), def->multidevs);
return -1;
}
virBufferAsprintf(buf,
"<filesystem type='%s' accessmode='%s'",
type, accessmode);
@ -25410,6 +25437,8 @@ virDomainFSDefFormat(virBufferPtr buf,
virBufferAsprintf(buf, " model='%s'",
virDomainFSModelTypeToString(def->model));
}
if (def->multidevs)
virBufferAsprintf(buf, " multidevs='%s'", multidevs);
virBufferAddLit(buf, ">\n");
virBufferAdjustIndent(buf, 2);

View File

@ -796,6 +796,18 @@ typedef enum {
VIR_DOMAIN_FS_WRPOLICY_LAST
} virDomainFSWrpolicy;
/* How to handle exports containing multiple devices. */
typedef enum {
VIR_DOMAIN_FS_MULTIDEVS_DEFAULT = 0, /* Use QEMU's default setting */
VIR_DOMAIN_FS_MULTIDEVS_REMAP, /* Remap inodes from host to guest */
VIR_DOMAIN_FS_MULTIDEVS_FORBID, /* Prohibit more than one device */
VIR_DOMAIN_FS_MULTIDEVS_WARN, /* Just log a warning if multiple devices */
VIR_DOMAIN_FS_MULTIDEVS_LAST
} virDomainFSMultidevs;
VIR_ENUM_DECL(virDomainFSMultidevs);
typedef enum {
VIR_DOMAIN_FS_MODEL_DEFAULT = 0,
VIR_DOMAIN_FS_MODEL_VIRTIO,
@ -820,6 +832,7 @@ struct _virDomainFSDef {
int wrpolicy; /* enum virDomainFSWrpolicy */
int format; /* virStorageFileFormat */
int model; /* virDomainFSModel */
int multidevs; /* virDomainFSMultidevs */
unsigned long long usage; /* in bytes */
virStorageSourcePtr src;
char *dst;

View File

@ -0,0 +1,53 @@
<domain type='qemu'>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219136</memory>
<currentMemory unit='KiB'>219136</currentMemory>
<vcpu placement='static'>1</vcpu>
<os>
<type arch='x86_64' machine='pc'>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>
<controller type='usb' index='0'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
</controller>
<controller type='ide' index='0'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
</controller>
<controller type='pci' index='0' model='pci-root'/>
<filesystem type='mount' accessmode='mapped' multidevs='remap'>
<source dir='/export/fs0'/>
<target dir='fs0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</filesystem>
<filesystem type='mount' accessmode='mapped' multidevs='forbid'>
<source dir='/export/fs1'/>
<target dir='fs1'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</filesystem>
<filesystem type='mount' accessmode='mapped' multidevs='warn'>
<source dir='/export/fs2'/>
<target dir='fs2'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
</filesystem>
<serial type='pty'>
<target type='isa-serial' port='0'>
<model name='isa-serial'/>
</target>
</serial>
<console type='pty'>
<target type='serial' port='0'/>
</console>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<memballoon model='virtio'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x0c' function='0x0'/>
</memballoon>
</devices>
</domain>

View File

@ -0,0 +1,56 @@
<domain type='qemu'>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219136</memory>
<currentMemory unit='KiB'>219136</currentMemory>
<vcpu placement='static'>1</vcpu>
<os>
<type arch='x86_64' machine='pc'>hvm</type>
<boot dev='hd'/>
</os>
<cpu mode='custom' match='exact' check='none'>
<model fallback='forbid'>qemu64</model>
</cpu>
<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>
<controller type='usb' index='0' model='piix3-uhci'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
</controller>
<controller type='ide' index='0'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
</controller>
<controller type='pci' index='0' model='pci-root'/>
<filesystem type='mount' accessmode='mapped' multidevs='remap'>
<source dir='/export/fs0'/>
<target dir='fs0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</filesystem>
<filesystem type='mount' accessmode='mapped' multidevs='forbid'>
<source dir='/export/fs1'/>
<target dir='fs1'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</filesystem>
<filesystem type='mount' accessmode='mapped' multidevs='warn'>
<source dir='/export/fs2'/>
<target dir='fs2'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
</filesystem>
<serial type='pty'>
<target type='isa-serial' port='0'>
<model name='isa-serial'/>
</target>
</serial>
<console type='pty'>
<target type='serial' port='0'/>
</console>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<memballoon model='virtio'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x0c' function='0x0'/>
</memballoon>
</devices>
</domain>

View File

@ -1485,6 +1485,8 @@ mymain(void)
DO_TEST_CAPS_ARCH_LATEST("x86_64-default-cpu-kvm-q35-4.2", "x86_64");
DO_TEST_CAPS_ARCH_LATEST("x86_64-default-cpu-tcg-q35-4.2", "x86_64");
DO_TEST_CAPS_LATEST("virtio-9p-multidevs");
if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL)
virFileDeleteTree(fakerootdir);