提交 8dc88aee 编写于 作者: L Laine Stump

conf: add new <target> subelement with chassisNr attribute to <controller>

There are some configuration options to some types of pci controllers
that are currently automatically derived from other parts of the
controller's configuration. For example, in qemu a pci-bridge
controller has an option that is called "chassis_nr"; up until now
libvirt has always set chassis_nr to the index of the pci-bridge. So
this:

  <controller type='pci' model='pci-bridge' index='2'/>

will always result in:

  -device pci-bridge,chassis_nr=2,...

on the qemu commandline. In the future we may decide there is a better
way to derive that option, but even in that case we will need for
existing domains to retain the same chassis_nr they were using in the
past - that is something that is visible to the guest so it is part of
the guest ABI and changing it would lead to problems for migrating
guests (or just guests with very picky OSes).

The <target> subelement has been added as a place to put the new
"chassisNr" attribute that will be filled in by libvirt when it
auto-generates the chassisNr; it will be saved in the config, then
reused any time the domain is started:

  <controller type='pci' model='pci-bridge' index='2'>
    <model type='pci-bridge'/>
    <target chassisNr='2'/>
  </controller>

The one oddity of all this is that if the controller configuration
is changed (for example to change the index or the pci address
where the controller is plugged in), the items in <target> will
*not* be re-generated, which might lead to conflict. I can't
really see any way around this, but fortunately if there is a
material conflict qemu will let us know and we will pass that on
to the user.
上级 572ebdbc
...@@ -3056,6 +3056,30 @@ ...@@ -3056,6 +3056,30 @@
generated by libvirt. <span class="since">Since 1.2.19 (QEMU generated by libvirt. <span class="since">Since 1.2.19 (QEMU
only).</span> only).</span>
</p> </p>
<p>
PCI controllers also have an optional
subelement <code>&lt;target&gt;</code> with the attributes
listed below. These are configurable items that 1) are visible
to the guest OS so must be preserved for guest ABI
compatibility, and 2) are usually left to default values or
derived automatically by libvirt. In almost all cases, you
should not manually add a <code>&lt;target&gt;</code> subelement
to a controller, nor should you modify the values in the those
that are automatically generated by
libvirt. <span class="since">Since 1.2.19 (QEMU only).</span>
</p>
<dl>
<dt><code>chassisNr</code></dt>
<dd>
PCI controllers that have attribute model="pci-bridge", can
also have a <code>chassisNr</code> attribute in
the <code>&lt;target&gt;</code> subelement, which is used to
control QEMU's "chassis_nr" option for the pci-bridge device
(normally libvirt automatically sets this to the same value as
the index attribute of the pci controller). If set, chassisNr
must be between 0 and 255.
</dd>
</dl>
<p> <p>
For machine types which provide an implicit PCI bus, the pci-root For machine types which provide an implicit PCI bus, the pci-root
controller with index=0 is auto-added and required to use PCI devices. controller with index=0 is auto-added and required to use PCI devices.
......
...@@ -1744,6 +1744,16 @@ ...@@ -1744,6 +1744,16 @@
<empty/> <empty/>
</element> </element>
</optional> </optional>
<optional>
<element name="target">
<optional>
<attribute name='chassisNr'>
<ref name='uint8range'/>
</attribute>
</optional>
<empty/>
</element>
</optional>
<!-- *-root controllers have an optional element "pcihole64"--> <!-- *-root controllers have an optional element "pcihole64"-->
<choice> <choice>
<group> <group>
......
...@@ -1551,6 +1551,8 @@ virDomainControllerDefNew(virDomainControllerType type) ...@@ -1551,6 +1551,8 @@ virDomainControllerDefNew(virDomainControllerType type)
def->opts.vioserial.vectors = -1; def->opts.vioserial.vectors = -1;
break; break;
case VIR_DOMAIN_CONTROLLER_TYPE_PCI: case VIR_DOMAIN_CONTROLLER_TYPE_PCI:
def->opts.pciopts.chassisNr = -1;
break;
case VIR_DOMAIN_CONTROLLER_TYPE_IDE: case VIR_DOMAIN_CONTROLLER_TYPE_IDE:
case VIR_DOMAIN_CONTROLLER_TYPE_FDC: case VIR_DOMAIN_CONTROLLER_TYPE_FDC:
case VIR_DOMAIN_CONTROLLER_TYPE_SCSI: case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
...@@ -7810,6 +7812,8 @@ virDomainControllerDefParseXML(xmlNodePtr node, ...@@ -7810,6 +7812,8 @@ virDomainControllerDefParseXML(xmlNodePtr node,
char *max_sectors = NULL; char *max_sectors = NULL;
bool processedModel = false; bool processedModel = false;
char *modelName = NULL; char *modelName = NULL;
bool processedTarget = false;
char *chassisNr = NULL;
xmlNodePtr saved = ctxt->node; xmlNodePtr saved = ctxt->node;
int rc; int rc;
...@@ -7862,6 +7866,15 @@ virDomainControllerDefParseXML(xmlNodePtr node, ...@@ -7862,6 +7866,15 @@ virDomainControllerDefParseXML(xmlNodePtr node,
} }
modelName = virXMLPropString(cur, "name"); modelName = virXMLPropString(cur, "name");
processedModel = true; processedModel = true;
} else if (xmlStrEqual(cur->name, BAD_CAST "target")) {
if (processedTarget) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Multiple <target> elements in "
"controller definition not allowed"));
goto error;
}
chassisNr = virXMLPropString(cur, "chassisNr");
processedTarget = true;
} }
} }
cur = cur->next; cur = cur->next;
...@@ -7978,6 +7991,23 @@ virDomainControllerDefParseXML(xmlNodePtr node, ...@@ -7978,6 +7991,23 @@ virDomainControllerDefParseXML(xmlNodePtr node,
modelName); modelName);
goto error; goto error;
} }
if (chassisNr) {
if (virStrToLong_i(chassisNr, NULL, 0,
&def->opts.pciopts.chassisNr) < 0) {
virReportError(VIR_ERR_XML_ERROR,
_("Invalid chassisNr '%s' in PCI controller"),
chassisNr);
goto error;
}
if (def->opts.pciopts.chassisNr < 0 ||
def->opts.pciopts.chassisNr > 255) {
virReportError(VIR_ERR_XML_ERROR,
_("PCI controller chassisNr '%s' out of range "
"- must be 0-255"),
chassisNr);
goto error;
}
}
break; break;
default: default:
...@@ -8004,6 +8034,7 @@ virDomainControllerDefParseXML(xmlNodePtr node, ...@@ -8004,6 +8034,7 @@ virDomainControllerDefParseXML(xmlNodePtr node,
VIR_FREE(cmd_per_lun); VIR_FREE(cmd_per_lun);
VIR_FREE(max_sectors); VIR_FREE(max_sectors);
VIR_FREE(modelName); VIR_FREE(modelName);
VIR_FREE(chassisNr);
return def; return def;
...@@ -19016,7 +19047,7 @@ virDomainControllerDefFormat(virBufferPtr buf, ...@@ -19016,7 +19047,7 @@ virDomainControllerDefFormat(virBufferPtr buf,
const char *type = virDomainControllerTypeToString(def->type); const char *type = virDomainControllerTypeToString(def->type);
const char *model = NULL; const char *model = NULL;
const char *modelName = NULL; const char *modelName = NULL;
bool pcihole64 = false, pciModel = false; bool pcihole64 = false, pciModel = false, pciTarget = false;
if (!type) { if (!type) {
virReportError(VIR_ERR_INTERNAL_ERROR, virReportError(VIR_ERR_INTERNAL_ERROR,
...@@ -19058,13 +19089,15 @@ virDomainControllerDefFormat(virBufferPtr buf, ...@@ -19058,13 +19089,15 @@ virDomainControllerDefFormat(virBufferPtr buf,
pcihole64 = true; pcihole64 = true;
if (def->opts.pciopts.modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) if (def->opts.pciopts.modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE)
pciModel = true; pciModel = true;
if (def->opts.pciopts.chassisNr != -1)
pciTarget = true;
break; break;
default: default:
break; break;
} }
if (pciModel || if (pciModel || pciTarget ||
def->queues || def->cmd_per_lun || def->max_sectors || def->queues || def->cmd_per_lun || def->max_sectors ||
virDomainDeviceInfoNeedsFormat(&def->info, flags) || pcihole64) { virDomainDeviceInfoNeedsFormat(&def->info, flags) || pcihole64) {
virBufferAddLit(buf, ">\n"); virBufferAddLit(buf, ">\n");
...@@ -19081,6 +19114,14 @@ virDomainControllerDefFormat(virBufferPtr buf, ...@@ -19081,6 +19114,14 @@ virDomainControllerDefFormat(virBufferPtr buf,
virBufferAsprintf(buf, "<model name='%s'/>\n", modelName); virBufferAsprintf(buf, "<model name='%s'/>\n", modelName);
} }
if (pciTarget) {
virBufferAddLit(buf, "<target");
if (def->opts.pciopts.chassisNr != -1)
virBufferAsprintf(buf, " chassisNr='%d'",
def->opts.pciopts.chassisNr);
virBufferAddLit(buf, "/>\n");
}
if (def->queues || def->cmd_per_lun || def->max_sectors) { if (def->queues || def->cmd_per_lun || def->max_sectors) {
virBufferAddLit(buf, "<driver"); virBufferAddLit(buf, "<driver");
if (def->queues) if (def->queues)
......
...@@ -812,7 +812,15 @@ struct _virDomainPCIControllerOpts { ...@@ -812,7 +812,15 @@ struct _virDomainPCIControllerOpts {
* ... * ...
*/ */
int modelName; /* the exact name of the device in hypervisor */ int modelName; /* the exact name of the device in hypervisor */
};
/* the following items are attributes of the "target" subelement
* of controller type='pci'. They are bits of configuration that
* are specified on the qemu commandline and are visible to the
* guest OS, so they must be preserved to ensure ABI
* compatibility.
*/
int chassisNr; /* used by pci-bridge, -1 == unspecified */
};
/* Stores the virtual disk controller configuration */ /* Stores the virtual disk controller configuration */
struct _virDomainControllerDef { struct _virDomainControllerDef {
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
</controller> </controller>
<controller type='pci' index='2' model='pci-bridge'> <controller type='pci' index='2' model='pci-bridge'>
<model name='pci-bridge'/> <model name='pci-bridge'/>
<target chassisNr='56'/>
</controller> </controller>
<video> <video>
<model type='qxl' ram='65536' vram='32768' vgamem='8192' heads='1'/> <model type='qxl' ram='65536' vram='32768' vgamem='8192' heads='1'/>
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
</controller> </controller>
<controller type='pci' index='2' model='pci-bridge'> <controller type='pci' index='2' model='pci-bridge'>
<model name='pci-bridge'/> <model name='pci-bridge'/>
<target chassisNr='56'/>
</controller> </controller>
<controller type='sata' index='0'/> <controller type='sata' index='0'/>
<video> <video>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册