[libvirt] [PATCH 00/12] A bunch of extensions to libxl driver

This are some additional features to libxl driver. Some of them require change in domain config structures/syntax. Details described with each patch. The last two patches are bugfix for deadlock during daemon startup. Marek Marczykowski (12): libxl: allow script for any network interface, not only bridge libxl: PCI passthrough support libxl: nodeDevice* support for PCI devices libxl: populate xenstore memory entries at startup conf: add 'script' attribute to disk specification libxl: use disk 'script' attribute conf: support backend domain name in disk and network devices libxl: support backend domain setting for disk and net devices libxl: fill HVM SDL and VNC settings based on <graphics/> entries RFC: libxl: special 'stubdom-dm' emulator to use qemu in stub domain conf: virDomainObjListRemoveLocked function libxl: fix deadlock in libxlReconnectDomain docs/schemas/domaincommon.rng | 14 ++ src/conf/domain_conf.c | 54 ++++++++ src/conf/domain_conf.h | 5 + src/libvirt_private.syms | 1 + src/libxl/libxl_conf.c | 297 +++++++++++++++++++++++++++++++++--------- src/libxl/libxl_conf.h | 6 +- src/libxl/libxl_driver.c | 253 +++++++++++++++++++++++++++++++---- 7 files changed, 545 insertions(+), 85 deletions(-) -- 1.8.1.4

Script to be called to prepare custom device for domain. Done with Xen in mind, it maps to libxl_device_disk.script. XML configuration would be: <disk type='block' device='disk'> <source dev='/dev/mapper/custom-device'/> <script path='/script/to/setup/custom-device'/> <target dev='xvdc'/> </disk> --- src/conf/domain_conf.c | 10 ++++++++++ src/conf/domain_conf.h | 1 + 2 files changed, 11 insertions(+) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index f3fca7f..257a265 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1102,6 +1102,7 @@ void virDomainDiskDefFree(virDomainDiskDefPtr def) VIR_FREE(def->wwn); VIR_FREE(def->vendor); VIR_FREE(def->product); + VIR_FREE(def->script); if (def->auth.secretType == VIR_DOMAIN_DISK_SECRET_TYPE_USAGE) VIR_FREE(def->auth.secret.usage); virStorageEncryptionFree(def->encryption); @@ -3993,6 +3994,7 @@ virDomainDiskDefParseXML(virCapsPtr caps, char *wwn = NULL; char *vendor = NULL; char *product = NULL; + char *script = NULL; int expected_secret_usage = -1; int auth_secret_usage = -1; @@ -4148,6 +4150,9 @@ virDomainDiskDefParseXML(virCapsPtr caps, if (target && STRPREFIX(target, "ioemu:")) memmove(target, target+6, strlen(target)-5); + } else if (!script && + xmlStrEqual(cur->name, BAD_CAST "script")) { + script = virXMLPropString(cur, "path"); } else if (xmlStrEqual(cur->name, BAD_CAST "geometry")) { if (virXPathUInt("string(./geometry/@cyls)", ctxt, &def->geometry.cylinders) < 0) { @@ -4690,6 +4695,8 @@ virDomainDiskDefParseXML(virCapsPtr caps, source = NULL; def->dst = target; target = NULL; + def->script = script; + script = NULL; def->hosts = hosts; hosts = NULL; def->nhosts = nhosts; @@ -4788,6 +4795,7 @@ cleanup: VIR_FREE(wwn); VIR_FREE(vendor); VIR_FREE(product); + VIR_FREE(script); ctxt->node = save_ctxt; return def; @@ -12899,6 +12907,8 @@ virDomainDiskDefFormat(virBufferPtr buf, } } + virBufferEscapeString(buf, " <script path='%s'/>\n", def->script); + virDomainDiskGeometryDefFormat(buf, def); virDomainDiskBlockIoDefFormat(buf, def); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index edddf25..d55d209 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -668,6 +668,7 @@ struct _virDomainDiskDef { bool rawio_specified; int rawio; /* no = 0, yes = 1 */ int sgio; /* enum virDomainDiskSGIO */ + char *script; size_t nseclabels; virSecurityDeviceLabelDefPtr *seclabels; -- 1.8.1.4

On Wed, Apr 10, 2013 at 04:44:43AM +0200, Marek Marczykowski wrote:
Script to be called to prepare custom device for domain. Done with Xen in mind, it maps to libxl_device_disk.script.
XML configuration would be: <disk type='block' device='disk'> <source dev='/dev/mapper/custom-device'/> <script path='/script/to/setup/custom-device'/> <target dev='xvdc'/> </disk>
NACK, all configuration must be explicitly represented in the config, not delegated to arbitrary opaque shell scripts. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 10.04.2013 11:14, Daniel P. Berrange wrote:
On Wed, Apr 10, 2013 at 04:44:43AM +0200, Marek Marczykowski wrote:
Script to be called to prepare custom device for domain. Done with Xen in mind, it maps to libxl_device_disk.script.
XML configuration would be: <disk type='block' device='disk'> <source dev='/dev/mapper/custom-device'/> <script path='/script/to/setup/custom-device'/> <target dev='xvdc'/> </disk>
NACK, all configuration must be explicitly represented in the config, not delegated to arbitrary opaque shell scripts.
Ok, but how to do that if backend is in other domain (not dom0), so you cannot directly execute commands there? -- Best Regards / Pozdrawiam, Marek Marczykowski Invisible Things Lab

While iterating with virDomainObjListForEach it is safe to remove current element. But while iterating, 'doms' lock is already taken, so can't use standard virDomainObjListRemove. So introduce virDomainObjListRemoveLocked for this purpose. --- src/conf/domain_conf.c | 17 +++++++++++++++++ src/conf/domain_conf.h | 2 ++ src/libvirt_private.syms | 1 + 3 files changed, 20 insertions(+) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index bf1fec6..e4f7288 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -2199,6 +2199,23 @@ void virDomainObjListRemove(virDomainObjListPtr doms, virObjectUnlock(doms); } +/* The caller must hold lock on 'doms' in addition to 'virDomainObjListRemove' + * requirements + * + * Can be used to remove current element while iterating with + * virDomainObjListForEach + */ +void virDomainObjListRemoveLocked(virDomainObjListPtr doms, + virDomainObjPtr dom) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN]; + + virUUIDFormat(dom->def->uuid, uuidstr); + virObjectUnlock(dom); + + virHashRemoveEntry(doms->objs, uuidstr); +} + static int virDomainDeviceCCWAddressIsValid(virDomainDeviceCCWAddressPtr addr) { diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index db3002b..e34143b 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2073,6 +2073,8 @@ virDomainObjCopyPersistentDef(virCapsPtr caps, virDomainXMLConfPtr xmlconf, void virDomainObjListRemove(virDomainObjListPtr doms, virDomainObjPtr dom); +void virDomainObjListRemoveLocked(virDomainObjListPtr doms, + virDomainObjPtr dom); virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps, virDomainDefPtr def, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 96eea0a..e6b6b1b 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -270,6 +270,7 @@ virDomainObjListLoadAllConfigs; virDomainObjListNew; virDomainObjListNumOfDomains; virDomainObjListRemove; +virDomainObjListRemoveLocked; virDomainObjNew; virDomainObjSetDefTransient; virDomainObjSetState; -- 1.8.1.4

Marek Marczykowski wrote:
While iterating with virDomainObjListForEach it is safe to remove current element. But while iterating, 'doms' lock is already taken, so can't use standard virDomainObjListRemove. So introduce virDomainObjListRemoveLocked for this purpose.
This seems sane to me, and the code looks good with the exception of my usual indentation nit, but I'd like to get an opinion from someone more familiar with this code. Regards, Jim
--- src/conf/domain_conf.c | 17 +++++++++++++++++ src/conf/domain_conf.h | 2 ++ src/libvirt_private.syms | 1 + 3 files changed, 20 insertions(+)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index bf1fec6..e4f7288 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -2199,6 +2199,23 @@ void virDomainObjListRemove(virDomainObjListPtr doms, virObjectUnlock(doms); }
+/* The caller must hold lock on 'doms' in addition to 'virDomainObjListRemove' + * requirements + * + * Can be used to remove current element while iterating with + * virDomainObjListForEach + */ +void virDomainObjListRemoveLocked(virDomainObjListPtr doms, + virDomainObjPtr dom) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN]; + + virUUIDFormat(dom->def->uuid, uuidstr); + virObjectUnlock(dom); + + virHashRemoveEntry(doms->objs, uuidstr); +} + static int virDomainDeviceCCWAddressIsValid(virDomainDeviceCCWAddressPtr addr) { diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index db3002b..e34143b 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2073,6 +2073,8 @@ virDomainObjCopyPersistentDef(virCapsPtr caps, virDomainXMLConfPtr xmlconf,
void virDomainObjListRemove(virDomainObjListPtr doms, virDomainObjPtr dom); +void virDomainObjListRemoveLocked(virDomainObjListPtr doms, + virDomainObjPtr dom);
virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps, virDomainDefPtr def, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 96eea0a..e6b6b1b 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -270,6 +270,7 @@ virDomainObjListLoadAllConfigs; virDomainObjListNew; virDomainObjListNumOfDomains; virDomainObjListRemove; +virDomainObjListRemoveLocked; virDomainObjNew; virDomainObjSetDefTransient; virDomainObjSetState;

Vfb entries in domain config are used only by PV drivers. Qemu parameters are build based on b_info struct. So fill it with the same data as vfb entries (actually the first one). This will additionally allow graphic-less domain, when no <graphics/> entries are present in domain XML (previously VNC was always enabled). --- src/libxl/libxl_conf.c | 131 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 90 insertions(+), 41 deletions(-) diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index 477e46d..068a97a 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -347,7 +347,64 @@ error: } static int -libxlMakeDomBuildInfo(virDomainDefPtr def, libxl_domain_config *d_config) +libxlMakeVNCInfo(libxlDriverPrivatePtr driver, + virDomainGraphicsDefPtr l_vfb, + libxl_vnc_info *x_vnc) +{ + unsigned short port; + const char *listenAddr; + + libxl_defbool_set(&x_vnc->enable, 1); + /* driver handles selection of free port */ + libxl_defbool_set(&x_vnc->findunused, 0); + if (l_vfb->data.vnc.autoport) { + + if (virPortAllocatorAcquire(driver->reservedVNCPorts, &port) < 0) + return -1; + if (port == 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Unable to find an unused VNC port")); + return -1; + } + l_vfb->data.vnc.port = port; + } + x_vnc->display = l_vfb->data.vnc.port - LIBXL_VNC_PORT_MIN; + + listenAddr = virDomainGraphicsListenGetAddress(l_vfb, 0); + if (listenAddr) { + /* libxl_device_vfb_init() does strdup("127.0.0.1") */ + VIR_FREE(x_vnc->listen); + if ((x_vnc->listen = strdup(listenAddr)) == NULL) { + virReportOOMError(); + return -1; + } + } + return 0; +} + +static int +libxlMakeSDLInfo(virDomainGraphicsDefPtr l_vfb, + libxl_sdl_info *x_sdl) +{ + libxl_defbool_set(&x_sdl->enable, 1); + if (l_vfb->data.sdl.display && + (x_sdl->display = strdup(l_vfb->data.sdl.display)) == NULL) { + virReportOOMError(); + return -1; + } + if (l_vfb->data.sdl.xauth && + (x_sdl->xauthority = + strdup(l_vfb->data.sdl.xauth)) == NULL) { + virReportOOMError(); + return -1; + } + return 0; +} + +static int +libxlMakeDomBuildInfo(libxlDriverPrivatePtr driver, + virDomainDefPtr def, + libxl_domain_config *d_config) { libxl_domain_build_info *b_info = &d_config->b_info; int hvm = STREQ(def->os.type, "hvm"); @@ -421,6 +478,34 @@ libxlMakeDomBuildInfo(virDomainDefPtr def, libxl_domain_config *d_config) goto error; } + /* Disable VNC and SDL until explicitly enabled */ + libxl_defbool_set(&b_info->u.hvm.vnc.enable, 0); + libxl_defbool_set(&b_info->u.hvm.sdl.enable, 0); + + for (i = 0; i < def->ngraphics; i++) { + switch (def->graphics[i]->type) { + case VIR_DOMAIN_GRAPHICS_TYPE_VNC: + if (libxl_defbool_val(b_info->u.hvm.vnc.enable)) + continue; + if (libxlMakeVNCInfo(driver, def->graphics[i], + &b_info->u.hvm.vnc) < 0) + goto error; + if (def->graphics[i]->data.vnc.keymap && + (b_info->u.hvm.keymap = + strdup(def->graphics[i]->data.vnc.keymap)) == NULL) { + virReportOOMError(); + goto error; + } + break; + case VIR_DOMAIN_GRAPHICS_TYPE_SDL: + if (libxl_defbool_val(b_info->u.hvm.sdl.enable)) + continue; + if (libxlMakeSDLInfo(def->graphics[i], &b_info->u.hvm.sdl) < 0) + goto error; + break; + } + } + /* * The following comment and calculation were taken directly from * libxenlight's internal function libxl_get_required_shadow_memory(): @@ -706,50 +791,14 @@ libxlMakeVfb(libxlDriverPrivatePtr driver, virDomainGraphicsDefPtr l_vfb, libxl_device_vfb *x_vfb) { - unsigned short port; - const char *listenAddr; - switch (l_vfb->type) { case VIR_DOMAIN_GRAPHICS_TYPE_SDL: - libxl_defbool_set(&x_vfb->sdl.enable, 1); - if (l_vfb->data.sdl.display && - (x_vfb->sdl.display = strdup(l_vfb->data.sdl.display)) == NULL) { - virReportOOMError(); - return -1; - } - if (l_vfb->data.sdl.xauth && - (x_vfb->sdl.xauthority = - strdup(l_vfb->data.sdl.xauth)) == NULL) { - virReportOOMError(); + if (libxlMakeSDLInfo(l_vfb, &x_vfb->sdl) < 0) return -1; - } break; case VIR_DOMAIN_GRAPHICS_TYPE_VNC: - libxl_defbool_set(&x_vfb->vnc.enable, 1); - /* driver handles selection of free port */ - libxl_defbool_set(&x_vfb->vnc.findunused, 0); - if (l_vfb->data.vnc.autoport) { - - if (virPortAllocatorAcquire(driver->reservedVNCPorts, &port) < 0) - return -1; - if (port == 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Unable to find an unused VNC port")); - return -1; - } - l_vfb->data.vnc.port = port; - } - x_vfb->vnc.display = l_vfb->data.vnc.port - LIBXL_VNC_PORT_MIN; - - listenAddr = virDomainGraphicsListenGetAddress(l_vfb, 0); - if (listenAddr) { - /* libxl_device_vfb_init() does strdup("127.0.0.1") */ - VIR_FREE(x_vfb->vnc.listen); - if ((x_vfb->vnc.listen = strdup(listenAddr)) == NULL) { - virReportOOMError(); - return -1; - } - } + if (libxlMakeVNCInfo(driver, l_vfb, &x_vfb->vnc) < 0) + return -1; if (l_vfb->data.vnc.keymap && (x_vfb->keymap = strdup(l_vfb->data.vnc.keymap)) == NULL) { @@ -920,7 +969,7 @@ libxlBuildDomainConfig(libxlDriverPrivatePtr driver, if (libxlMakeDomCreateInfo(driver, def, &d_config->c_info) < 0) return -1; - if (libxlMakeDomBuildInfo(def, d_config) < 0) { + if (libxlMakeDomBuildInfo(driver, def, d_config) < 0) { goto error; } -- 1.8.1.4

Marek Marczykowski wrote:
Vfb entries in domain config are used only by PV drivers. Qemu parameters are build based on b_info struct. So fill it with the same
s/build/built/
data as vfb entries (actually the first one). This will additionally allow graphic-less domain, when no <graphics/> entries are present in domain XML (previously VNC was always enabled). --- src/libxl/libxl_conf.c | 131 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 90 insertions(+), 41 deletions(-)
diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index 477e46d..068a97a 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -347,7 +347,64 @@ error: }
static int -libxlMakeDomBuildInfo(virDomainDefPtr def, libxl_domain_config *d_config) +libxlMakeVNCInfo(libxlDriverPrivatePtr driver, + virDomainGraphicsDefPtr l_vfb, + libxl_vnc_info *x_vnc)
Indentation.
+{ + unsigned short port; + const char *listenAddr; + + libxl_defbool_set(&x_vnc->enable, 1); + /* driver handles selection of free port */ + libxl_defbool_set(&x_vnc->findunused, 0); + if (l_vfb->data.vnc.autoport) { + + if (virPortAllocatorAcquire(driver->reservedVNCPorts, &port) < 0) + return -1; + if (port == 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Unable to find an unused VNC port")); + return -1; + } + l_vfb->data.vnc.port = port; + } + x_vnc->display = l_vfb->data.vnc.port - LIBXL_VNC_PORT_MIN; + + listenAddr = virDomainGraphicsListenGetAddress(l_vfb, 0); + if (listenAddr) { + /* libxl_device_vfb_init() does strdup("127.0.0.1") */ + VIR_FREE(x_vnc->listen); + if ((x_vnc->listen = strdup(listenAddr)) == NULL) { + virReportOOMError(); + return -1; + }
Thanks to my delay in reviewing this, you'll need to rebase and use VIR_STRDUP :(.
+ } + return 0; +} + +static int +libxlMakeSDLInfo(virDomainGraphicsDefPtr l_vfb, + libxl_sdl_info *x_sdl)
Indentation.
+{ + libxl_defbool_set(&x_sdl->enable, 1); + if (l_vfb->data.sdl.display && + (x_sdl->display = strdup(l_vfb->data.sdl.display)) == NULL) { + virReportOOMError(); + return -1; + } + if (l_vfb->data.sdl.xauth && + (x_sdl->xauthority = + strdup(l_vfb->data.sdl.xauth)) == NULL) { + virReportOOMError(); + return -1; + } + return 0; +} + +static int +libxlMakeDomBuildInfo(libxlDriverPrivatePtr driver, + virDomainDefPtr def, + libxl_domain_config *d_config)
Indentation. Looks good but will need a rebase. Regards, Jim
{ libxl_domain_build_info *b_info = &d_config->b_info; int hvm = STREQ(def->os.type, "hvm"); @@ -421,6 +478,34 @@ libxlMakeDomBuildInfo(virDomainDefPtr def, libxl_domain_config *d_config) goto error; }
+ /* Disable VNC and SDL until explicitly enabled */ + libxl_defbool_set(&b_info->u.hvm.vnc.enable, 0); + libxl_defbool_set(&b_info->u.hvm.sdl.enable, 0); + + for (i = 0; i < def->ngraphics; i++) { + switch (def->graphics[i]->type) { + case VIR_DOMAIN_GRAPHICS_TYPE_VNC: + if (libxl_defbool_val(b_info->u.hvm.vnc.enable)) + continue; + if (libxlMakeVNCInfo(driver, def->graphics[i], + &b_info->u.hvm.vnc) < 0) + goto error; + if (def->graphics[i]->data.vnc.keymap && + (b_info->u.hvm.keymap = + strdup(def->graphics[i]->data.vnc.keymap)) == NULL) { + virReportOOMError(); + goto error; + } + break; + case VIR_DOMAIN_GRAPHICS_TYPE_SDL: + if (libxl_defbool_val(b_info->u.hvm.sdl.enable)) + continue; + if (libxlMakeSDLInfo(def->graphics[i], &b_info->u.hvm.sdl) < 0) + goto error; + break; + } + } + /* * The following comment and calculation were taken directly from * libxenlight's internal function libxl_get_required_shadow_memory(): @@ -706,50 +791,14 @@ libxlMakeVfb(libxlDriverPrivatePtr driver, virDomainGraphicsDefPtr l_vfb, libxl_device_vfb *x_vfb) { - unsigned short port; - const char *listenAddr; - switch (l_vfb->type) { case VIR_DOMAIN_GRAPHICS_TYPE_SDL: - libxl_defbool_set(&x_vfb->sdl.enable, 1); - if (l_vfb->data.sdl.display && - (x_vfb->sdl.display = strdup(l_vfb->data.sdl.display)) == NULL) { - virReportOOMError(); - return -1; - } - if (l_vfb->data.sdl.xauth && - (x_vfb->sdl.xauthority = - strdup(l_vfb->data.sdl.xauth)) == NULL) { - virReportOOMError(); + if (libxlMakeSDLInfo(l_vfb, &x_vfb->sdl) < 0) return -1; - } break; case VIR_DOMAIN_GRAPHICS_TYPE_VNC: - libxl_defbool_set(&x_vfb->vnc.enable, 1); - /* driver handles selection of free port */ - libxl_defbool_set(&x_vfb->vnc.findunused, 0); - if (l_vfb->data.vnc.autoport) { - - if (virPortAllocatorAcquire(driver->reservedVNCPorts, &port) < 0) - return -1; - if (port == 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Unable to find an unused VNC port")); - return -1; - } - l_vfb->data.vnc.port = port; - } - x_vfb->vnc.display = l_vfb->data.vnc.port - LIBXL_VNC_PORT_MIN; - - listenAddr = virDomainGraphicsListenGetAddress(l_vfb, 0); - if (listenAddr) { - /* libxl_device_vfb_init() does strdup("127.0.0.1") */ - VIR_FREE(x_vfb->vnc.listen); - if ((x_vfb->vnc.listen = strdup(listenAddr)) == NULL) { - virReportOOMError(); - return -1; - } - } + if (libxlMakeVNCInfo(driver, l_vfb, &x_vfb->vnc) < 0) + return -1; if (l_vfb->data.vnc.keymap && (x_vfb->keymap = strdup(l_vfb->data.vnc.keymap)) == NULL) { @@ -920,7 +969,7 @@ libxlBuildDomainConfig(libxlDriverPrivatePtr driver, if (libxlMakeDomCreateInfo(driver, def, &d_config->c_info) < 0) return -1;
- if (libxlMakeDomBuildInfo(def, d_config) < 0) { + if (libxlMakeDomBuildInfo(driver, def, d_config) < 0) { goto error; }

Use virDomainObjListRemoveLocked instead of virDomainObjListRemove, as driver->domains is already taken by virDomainObjListForEach. Above deadlock can be triggered when libvirtd is started after some domain have been started by hand (in which case driver will not find libvirt-xml domain config). --- src/libxl/libxl_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index b0f0c6a..687190c 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -1060,7 +1060,7 @@ libxlReconnectDomain(virDomainObjPtr vm, out: libxlVmCleanup(driver, vm, VIR_DOMAIN_SHUTOFF_UNKNOWN); if (!vm->persistent) - virDomainObjListRemove(driver->domains, vm); + virDomainObjListRemoveLocked(driver->domains, vm); else virObjectUnlock(vm); -- 1.8.1.4

Marek Marczykowski wrote:
Use virDomainObjListRemoveLocked instead of virDomainObjListRemove, as driver->domains is already taken by virDomainObjListForEach.
Above deadlock can be triggered when libvirtd is started after some domain have been started by hand (in which case driver will not find libvirt-xml domain config).
Looks good, but let's see what others have to say about the virDomainObjListRemoveLocked() addition. Regards, Jim
--- src/libxl/libxl_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index b0f0c6a..687190c 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -1060,7 +1060,7 @@ libxlReconnectDomain(virDomainObjPtr vm, out: libxlVmCleanup(driver, vm, VIR_DOMAIN_SHUTOFF_UNKNOWN); if (!vm->persistent) - virDomainObjListRemove(driver->domains, vm); + virDomainObjListRemoveLocked(driver->domains, vm); else virObjectUnlock(vm);

Xen have feature of having device model in separate domain (called stub domain). It used to be enabled by special 'stubdom-dm' device model path. Recent xl have separate config option for this feature (device_model_stubdomain_override), but I'm not sure if it worth introducing another xen-specific option in general domain XML syntax. Also use os->cmdline as extra arguments for qemu (for HVM only). This use of os->cmdline is rather dirty hack, but I haven't idea what better attribute use for it. Perhaps worth new attribute (in <emulator/> element?). Anyway os->cmdline was unused for HVM domains. --- src/libxl/libxl_conf.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index 068a97a..181d344 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -478,6 +478,18 @@ libxlMakeDomBuildInfo(libxlDriverPrivatePtr driver, goto error; } + if (def->emulator && strcmp(def->emulator, "stubdom-dm")==0) { + libxl_defbool_set(&b_info->device_model_stubdomain, 1); + } + + if (def->os.cmdline && def->os.cmdline[0]) { + b_info->extra_hvm = virStringSplit(def->os.cmdline, " ", 0); + if (b_info->extra_hvm == NULL) { + virReportOOMError(); + goto error; + } + } + /* Disable VNC and SDL until explicitly enabled */ libxl_defbool_set(&b_info->u.hvm.vnc.enable, 0); libxl_defbool_set(&b_info->u.hvm.sdl.enable, 0); -- 1.8.1.4

Marek Marczykowski wrote:
Xen have feature of having device model in separate domain (called stub domain). It used to be enabled by special 'stubdom-dm' device model path. Recent xl have separate config option for this feature (device_model_stubdomain_override), but I'm not sure if it worth introducing another xen-specific option in general domain XML syntax.
Also use os->cmdline as extra arguments for qemu (for HVM only). This use of os->cmdline is rather dirty hack, but I haven't idea what better attribute use for it. Perhaps worth new attribute (in <emulator/> element?). Anyway os->cmdline was unused for HVM domains. --- src/libxl/libxl_conf.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index 068a97a..181d344 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -478,6 +478,18 @@ libxlMakeDomBuildInfo(libxlDriverPrivatePtr driver, goto error; }
+ if (def->emulator && strcmp(def->emulator, "stubdom-dm")==0) { + libxl_defbool_set(&b_info->device_model_stubdomain, 1); + }
This is another case of libxl exposing some internal implementation detail IMO. Apps know what emulator they want to use, they don't know what special xen bit to set, e.g. stubdom, traditional, new, newer, ...
+ + if (def->os.cmdline && def->os.cmdline[0]) { + b_info->extra_hvm = virStringSplit(def->os.cmdline, " ", 0); + if (b_info->extra_hvm == NULL) { + virReportOOMError(); + goto error; + } + } +
NACK to this change. qemu supports kernel, initrd, and append args for direct kernel boot, which is useful when installing a guest OS. libxl should support this for HVM guests. I'm pretty sure this works in the legacy stack. Regards, Jim
/* Disable VNC and SDL until explicitly enabled */ libxl_defbool_set(&b_info->u.hvm.vnc.enable, 0); libxl_defbool_set(&b_info->u.hvm.sdl.enable, 0);

This can be useful for route or NAT networks, or any other custom network setup. Especially configuration example in documentation uses <script/> tag with type 'ethernet'. --- src/libxl/libxl_conf.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index b208dd8..ffc7bbb 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -608,18 +608,11 @@ libxlMakeNic(virDomainNetDefPtr l_nic, libxl_device_nic *x_nic) virReportOOMError(); return -1; } - if (l_nic->script && - (x_nic->script = strdup(l_nic->script)) == NULL) { - virReportOOMError(); - return -1; - } - } else { - if (l_nic->script) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("scripts are not supported on interfaces of type %s"), - virDomainNetTypeToString(l_nic->type)); - return -1; - } + } + if (l_nic->script && + (x_nic->script = strdup(l_nic->script)) == NULL) { + virReportOOMError(); + return -1; } return 0; -- 1.8.1.4

On Wed, Apr 10, 2013 at 04:44:43AM +0200, Marek Marczykowski wrote:
This can be useful for route or NAT networks, or any other custom network setup. Especially configuration example in documentation uses <script/> tag with type 'ethernet'. --- src/libxl/libxl_conf.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-)
The script should not not have been allowed for type='bridge' in the first place, it is only intended for type='ethernet' usage and nothing else. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 04/10/2013 05:10 AM, Daniel P. Berrange wrote:
This can be useful for route or NAT networks, or any other custom network setup. Especially configuration example in documentation uses <script/> tag with type 'ethernet'. --- src/libxl/libxl_conf.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) The script should not not have been allowed for type='bridge' in
On Wed, Apr 10, 2013 at 04:44:43AM +0200, Marek Marczykowski wrote: the first place, it is only intended for type='ethernet' usage and nothing else.
I thought that it was also allowed/necessary for type='bridge' in xen domains. Is this incorrect? (I agree that it shouldn't be allowed for anything new, though)

Laine Stump wrote:
On 04/10/2013 05:10 AM, Daniel P. Berrange wrote:
On Wed, Apr 10, 2013 at 04:44:43AM +0200, Marek Marczykowski wrote:
This can be useful for route or NAT networks, or any other custom network setup. Especially configuration example in documentation uses <script/> tag with type 'ethernet'. --- src/libxl/libxl_conf.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-)
The script should not not have been allowed for type='bridge' in the first place, it is only intended for type='ethernet' usage and nothing else.
I thought that it was also allowed/necessary for type='bridge' in xen domains. Is this incorrect?
I think it is only necessary if something other than the default (/etc/xen/scripts/vif-bridge) is desired. It has been allowed in both xen drivers for as long as I remember.
(I agree that it shouldn't be allowed for anything new, though)
Agreed, ethernet and bridge only. Regards, Jim

Jim Fehlig wrote:
Laine Stump wrote:
On 04/10/2013 05:10 AM, Daniel P. Berrange wrote:
On Wed, Apr 10, 2013 at 04:44:43AM +0200, Marek Marczykowski wrote:
This can be useful for route or NAT networks, or any other custom network setup. Especially configuration example in documentation uses <script/> tag with type 'ethernet'. --- src/libxl/libxl_conf.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-)
The script should not not have been allowed for type='bridge' in the first place, it is only intended for type='ethernet' usage and nothing else.
I thought that it was also allowed/necessary for type='bridge' in xen domains. Is this incorrect?
I think it is only necessary if something other than the default (/etc/xen/scripts/vif-bridge) is desired. It has been allowed in both xen drivers for as long as I remember.
Any consensus here? I double-checked the legacy xen driver and it does in fact support <script> for <interface type='bridge'>. I'm not sure how many users specify something other than the default, but I'm loath to break them when moving from the old xen toolstack to libxl. Marek, Assuming we continue to allow <script> for type='bridge' interfaces in the libxl driver, you'll have to change your patch to only allow it for type 'bridge' and 'ethernet'. BTW, sorry for the delay in getting to your patches. I have a bit of time to work on libxl stuff and will get to reviewing them. Regards, Jim

Jim Fehlig wrote:
Jim Fehlig wrote:
Laine Stump wrote:
On 04/10/2013 05:10 AM, Daniel P. Berrange wrote:
On Wed, Apr 10, 2013 at 04:44:43AM +0200, Marek Marczykowski wrote:
This can be useful for route or NAT networks, or any other custom network setup. Especially configuration example in documentation uses <script/> tag with type 'ethernet'. --- src/libxl/libxl_conf.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-)
The script should not not have been allowed for type='bridge' in the first place, it is only intended for type='ethernet' usage and nothing else.
I thought that it was also allowed/necessary for type='bridge' in xen domains. Is this incorrect?
I think it is only necessary if something other than the default (/etc/xen/scripts/vif-bridge) is desired. It has been allowed in both xen drivers for as long as I remember.
Any consensus here? I double-checked the legacy xen driver and it does in fact support <script> for <interface type='bridge'>. I'm not sure how many users specify something other than the default, but I'm loath to break them when moving from the old xen toolstack to libxl.
Marek,
Assuming we continue to allow <script> for type='bridge' interfaces in the libxl driver, you'll have to change your patch to only allow it for type 'bridge' and 'ethernet'.
Please send a V2 with this change. Regards, Jim

This implement handling of <domain name=''/> parameter introduced in previous patch. Lookup on domain name (to get domain ID) requires libxlDriverPrivate object, so it must be passed down to libxlMakeDisk and libxlMakeNet from top level callers. --- src/libxl/libxl_conf.c | 62 +++++++++++++++++++++++++++++++++++++++++------- src/libxl/libxl_conf.h | 4 ++-- src/libxl/libxl_driver.c | 50 +++++++++++++++++++++----------------- 3 files changed, 84 insertions(+), 32 deletions(-) diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index 4bd62e9..477e46d 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -472,7 +472,9 @@ error: } int -libxlMakeDisk(virDomainDiskDefPtr l_disk, libxl_device_disk *x_disk) +libxlMakeDisk(libxlDriverPrivatePtr driver, + virDomainDiskDefPtr l_disk, + libxl_device_disk *x_disk) { if (l_disk->src && (x_disk->pdev_path = strdup(l_disk->src)) == NULL) { virReportOOMError(); @@ -549,11 +551,32 @@ libxlMakeDisk(virDomainDiskDefPtr l_disk, libxl_device_disk *x_disk) return -1; } + if (l_disk->domain_name) { + uint32_t domid; + /* Do not use virDomainObjListFindByName as it causes deadlock here - + * we already have lock on this domain object, but + * virDomainObjListFindByName will try to take it again. + */ + switch (libxl_name_to_domid(driver->ctx, l_disk->domain_name, &domid)) { + case ERROR_INVAL: + virReportError(VIR_ERR_XML_DETAIL, + _("Disk backend domain '%s' does not exists"), + l_disk->domain_name); + return -1; + case ERROR_NOMEM: + virReportOOMError(); + return -1; + } + x_disk->backend_domid = domid; + } + return 0; } static int -libxlMakeDiskList(virDomainDefPtr def, libxl_domain_config *d_config) +libxlMakeDiskList(libxlDriverPrivatePtr driver, + virDomainDefPtr def, + libxl_domain_config *d_config) { virDomainDiskDefPtr *l_disks = def->disks; int ndisks = def->ndisks; @@ -566,7 +589,7 @@ libxlMakeDiskList(virDomainDefPtr def, libxl_domain_config *d_config) } for (i = 0; i < ndisks; i++) { - if (libxlMakeDisk(l_disks[i], &x_disks[i]) < 0) + if (libxlMakeDisk(driver, l_disks[i], &x_disks[i]) < 0) goto error; } @@ -583,7 +606,9 @@ error: } int -libxlMakeNic(virDomainNetDefPtr l_nic, libxl_device_nic *x_nic) +libxlMakeNic(libxlDriverPrivatePtr driver, + virDomainNetDefPtr l_nic, + libxl_device_nic *x_nic) { /* TODO: Where is mtu stored? * @@ -620,11 +645,32 @@ libxlMakeNic(virDomainNetDefPtr l_nic, libxl_device_nic *x_nic) return -1; } + if (l_nic->domain_name) { + uint32_t domid; + /* Do not use virDomainObjListFindByName as it causes deadlock here - + * we already have lock on this domain object, but + * virDomainObjListFindByName will try to take it again. + */ + switch (libxl_name_to_domid(driver->ctx, l_nic->domain_name, &domid)) { + case ERROR_INVAL: + virReportError(VIR_ERR_XML_DETAIL, + _("Network backend domain '%s' does not exists"), + l_nic->domain_name); + return -1; + case ERROR_NOMEM: + virReportOOMError(); + return -1; + } + x_nic->backend_domid = domid; + } + return 0; } static int -libxlMakeNicList(virDomainDefPtr def, libxl_domain_config *d_config) +libxlMakeNicList(libxlDriverPrivatePtr driver, + virDomainDefPtr def, + libxl_domain_config *d_config) { virDomainNetDefPtr *l_nics = def->nets; int nnics = def->nnets; @@ -639,7 +685,7 @@ libxlMakeNicList(virDomainDefPtr def, libxl_domain_config *d_config) for (i = 0; i < nnics; i++) { x_nics[i].devid = i; - if (libxlMakeNic(l_nics[i], &x_nics[i])) + if (libxlMakeNic(driver, l_nics[i], &x_nics[i])) goto error; } @@ -878,11 +924,11 @@ libxlBuildDomainConfig(libxlDriverPrivatePtr driver, goto error; } - if (libxlMakeDiskList(def, d_config) < 0) { + if (libxlMakeDiskList(driver, def, d_config) < 0) { goto error; } - if (libxlMakeNicList(def, d_config) < 0) { + if (libxlMakeNicList(driver, def, d_config) < 0) { goto error; } diff --git a/src/libxl/libxl_conf.h b/src/libxl/libxl_conf.h index b3ab3bf..99948b5 100644 --- a/src/libxl/libxl_conf.h +++ b/src/libxl/libxl_conf.h @@ -113,9 +113,9 @@ virCapsPtr libxlMakeCapabilities(libxl_ctx *ctx); int -libxlMakeDisk(virDomainDiskDefPtr l_dev, libxl_device_disk *x_dev); +libxlMakeDisk(libxlDriverPrivatePtr driver, virDomainDiskDefPtr l_dev, libxl_device_disk *x_dev); int -libxlMakeNic(virDomainNetDefPtr l_nic, libxl_device_nic *x_nic); +libxlMakeNic(libxlDriverPrivatePtr driver, virDomainNetDefPtr l_nic, libxl_device_nic *x_nic); int libxlMakeVfb(libxlDriverPrivatePtr driver, virDomainGraphicsDefPtr l_vfb, libxl_device_vfb *x_vfb); diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 89546a5..b0f0c6a 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -3166,8 +3166,9 @@ libxlDomainUndefine(virDomainPtr dom) } static int -libxlDomainChangeEjectableMedia(libxlDomainObjPrivatePtr priv, - virDomainObjPtr vm, virDomainDiskDefPtr disk) +libxlDomainChangeEjectableMedia(libxlDriverPrivatePtr driver, + libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, virDomainDiskDefPtr + disk) { virDomainDiskDefPtr origdisk = NULL; libxl_device_disk x_disk; @@ -3196,7 +3197,7 @@ libxlDomainChangeEjectableMedia(libxlDomainObjPrivatePtr priv, return -1; } - if (libxlMakeDisk(disk, &x_disk) < 0) + if (libxlMakeDisk(driver, disk, &x_disk) < 0) goto cleanup; if ((ret = libxl_cdrom_insert(priv->ctx, vm->def->id, &x_disk, NULL)) < 0) { @@ -3221,8 +3222,9 @@ cleanup: } static int -libxlDomainAttachDeviceDiskLive(libxlDomainObjPrivatePtr priv, - virDomainObjPtr vm, virDomainDeviceDefPtr dev) +libxlDomainAttachDeviceDiskLive(libxlDriverPrivatePtr driver, + libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, + virDomainDeviceDefPtr dev) { virDomainDiskDefPtr l_disk = dev->data.disk; libxl_device_disk x_disk; @@ -3230,7 +3232,7 @@ libxlDomainAttachDeviceDiskLive(libxlDomainObjPrivatePtr priv, switch (l_disk->device) { case VIR_DOMAIN_DISK_DEVICE_CDROM: - ret = libxlDomainChangeEjectableMedia(priv, vm, l_disk); + ret = libxlDomainChangeEjectableMedia(driver, priv, vm, l_disk); break; case VIR_DOMAIN_DISK_DEVICE_DISK: if (l_disk->bus == VIR_DOMAIN_DISK_BUS_XEN) { @@ -3251,7 +3253,7 @@ libxlDomainAttachDeviceDiskLive(libxlDomainObjPrivatePtr priv, goto cleanup; } - if (libxlMakeDisk(l_disk, &x_disk) < 0) + if (libxlMakeDisk(driver, l_disk, &x_disk) < 0) goto cleanup; if ((ret = libxl_device_disk_add(priv->ctx, vm->def->id, @@ -3282,8 +3284,9 @@ cleanup: } static int -libxlDomainDetachDeviceDiskLive(libxlDomainObjPrivatePtr priv, - virDomainObjPtr vm, virDomainDeviceDefPtr dev) +libxlDomainDetachDeviceDiskLive(libxlDriverPrivatePtr driver, + libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, + virDomainDeviceDefPtr dev) { virDomainDiskDefPtr l_disk = NULL; libxl_device_disk x_disk; @@ -3304,7 +3307,7 @@ libxlDomainDetachDeviceDiskLive(libxlDomainObjPrivatePtr priv, l_disk = vm->def->disks[i]; - if (libxlMakeDisk(l_disk, &x_disk) < 0) + if (libxlMakeDisk(driver, l_disk, &x_disk) < 0) goto cleanup; if ((ret = libxl_device_disk_remove(priv->ctx, vm->def->id, @@ -3336,14 +3339,15 @@ cleanup: } static int -libxlDomainAttachDeviceLive(libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, - virDomainDeviceDefPtr dev) +libxlDomainAttachDeviceLive(libxlDriverPrivatePtr driver, + libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, + virDomainDeviceDefPtr dev) { int ret = -1; switch (dev->type) { case VIR_DOMAIN_DEVICE_DISK: - ret = libxlDomainAttachDeviceDiskLive(priv, vm, dev); + ret = libxlDomainAttachDeviceDiskLive(driver, priv, vm, dev); if (!ret) dev->data.disk = NULL; break; @@ -3388,14 +3392,15 @@ libxlDomainAttachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev) } static int -libxlDomainDetachDeviceLive(libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, - virDomainDeviceDefPtr dev) +libxlDomainDetachDeviceLive(libxlDriverPrivatePtr driver, + libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, + virDomainDeviceDefPtr dev) { int ret = -1; switch (dev->type) { case VIR_DOMAIN_DEVICE_DISK: - ret = libxlDomainDetachDeviceDiskLive(priv, vm, dev); + ret = libxlDomainDetachDeviceDiskLive(driver, priv, vm, dev); break; default: @@ -3435,8 +3440,9 @@ libxlDomainDetachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev) } static int -libxlDomainUpdateDeviceLive(libxlDomainObjPrivatePtr priv, - virDomainObjPtr vm, virDomainDeviceDefPtr dev) +libxlDomainUpdateDeviceLive(libxlDriverPrivatePtr driver, + libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, + virDomainDeviceDefPtr dev) { virDomainDiskDefPtr disk; int ret = -1; @@ -3446,7 +3452,7 @@ libxlDomainUpdateDeviceLive(libxlDomainObjPrivatePtr priv, disk = dev->data.disk; switch (disk->device) { case VIR_DOMAIN_DISK_DEVICE_CDROM: - ret = libxlDomainChangeEjectableMedia(priv, vm, disk); + ret = libxlDomainChangeEjectableMedia(driver, priv, vm, disk); if (ret == 0) dev->data.disk = NULL; break; @@ -3601,13 +3607,13 @@ libxlDomainModifyDeviceFlags(virDomainPtr dom, const char *xml, switch (action) { case LIBXL_DEVICE_ATTACH: - ret = libxlDomainAttachDeviceLive(priv, vm, dev); + ret = libxlDomainAttachDeviceLive(driver, priv, vm, dev); break; case LIBXL_DEVICE_DETACH: - ret = libxlDomainDetachDeviceLive(priv, vm, dev); + ret = libxlDomainDetachDeviceLive(driver, priv, vm, dev); break; case LIBXL_DEVICE_UPDATE: - ret = libxlDomainUpdateDeviceLive(priv, vm, dev); + ret = libxlDomainUpdateDeviceLive(driver, priv, vm, dev); break; default: virReportError(VIR_ERR_INTERNAL_ERROR, -- 1.8.1.4

Marek Marczykowski wrote:
This implement handling of <domain name=''/> parameter introduced in previous patch.
Lookup on domain name (to get domain ID) requires libxlDriverPrivate object, so it must be passed down to libxlMakeDisk and libxlMakeNet from top level callers. --- src/libxl/libxl_conf.c | 62 +++++++++++++++++++++++++++++++++++++++++------- src/libxl/libxl_conf.h | 4 ++-- src/libxl/libxl_driver.c | 50 +++++++++++++++++++++----------------- 3 files changed, 84 insertions(+), 32 deletions(-)
diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index 4bd62e9..477e46d 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -472,7 +472,9 @@ error: }
int -libxlMakeDisk(virDomainDiskDefPtr l_disk, libxl_device_disk *x_disk) +libxlMakeDisk(libxlDriverPrivatePtr driver, + virDomainDiskDefPtr l_disk, + libxl_device_disk *x_disk)
Indentation looks off here.
{ if (l_disk->src && (x_disk->pdev_path = strdup(l_disk->src)) == NULL) { virReportOOMError(); @@ -549,11 +551,32 @@ libxlMakeDisk(virDomainDiskDefPtr l_disk, libxl_device_disk *x_disk) return -1; }
+ if (l_disk->domain_name) { + uint32_t domid; + /* Do not use virDomainObjListFindByName as it causes deadlock here - + * we already have lock on this domain object, but + * virDomainObjListFindByName will try to take it again. + */ + switch (libxl_name_to_domid(driver->ctx, l_disk->domain_name, &domid)) { + case ERROR_INVAL: + virReportError(VIR_ERR_XML_DETAIL, + _("Disk backend domain '%s' does not exists"),
I think this error would be better worded with "Backend domain '%s' does not exist for disk '%s'", using l_disk->dst for the disk name.
+ l_disk->domain_name); + return -1; + case ERROR_NOMEM: + virReportOOMError(); + return -1; + } + x_disk->backend_domid = domid;
IMO this could be coded a little more defensively, e.g. only assign backend_domid on "case 0:", and have a default case that will also fail if libxl_name_to_domid() ever returns something besides 0, ERROR_INVAL, or ERROR_NOMEM.
+ } + return 0; }
static int -libxlMakeDiskList(virDomainDefPtr def, libxl_domain_config *d_config) +libxlMakeDiskList(libxlDriverPrivatePtr driver, + virDomainDefPtr def, + libxl_domain_config *d_config)
Indentation.
{ virDomainDiskDefPtr *l_disks = def->disks; int ndisks = def->ndisks; @@ -566,7 +589,7 @@ libxlMakeDiskList(virDomainDefPtr def, libxl_domain_config *d_config) }
for (i = 0; i < ndisks; i++) { - if (libxlMakeDisk(l_disks[i], &x_disks[i]) < 0) + if (libxlMakeDisk(driver, l_disks[i], &x_disks[i]) < 0) goto error; }
@@ -583,7 +606,9 @@ error: }
int -libxlMakeNic(virDomainNetDefPtr l_nic, libxl_device_nic *x_nic) +libxlMakeNic(libxlDriverPrivatePtr driver, + virDomainNetDefPtr l_nic, + libxl_device_nic *x_nic)
Indentation.
{ /* TODO: Where is mtu stored? * @@ -620,11 +645,32 @@ libxlMakeNic(virDomainNetDefPtr l_nic, libxl_device_nic *x_nic) return -1; }
+ if (l_nic->domain_name) { + uint32_t domid; + /* Do not use virDomainObjListFindByName as it causes deadlock here - + * we already have lock on this domain object, but + * virDomainObjListFindByName will try to take it again. + */ + switch (libxl_name_to_domid(driver->ctx, l_nic->domain_name, &domid)) { + case ERROR_INVAL: + virReportError(VIR_ERR_XML_DETAIL, + _("Network backend domain '%s' does not exists"),
Same comment here about the error message.
+ l_nic->domain_name); + return -1; + case ERROR_NOMEM: + virReportOOMError(); + return -1; + } + x_nic->backend_domid = domid;
And same comment here about the switch statement.
+ } + return 0; }
static int -libxlMakeNicList(virDomainDefPtr def, libxl_domain_config *d_config) +libxlMakeNicList(libxlDriverPrivatePtr driver, + virDomainDefPtr def, + libxl_domain_config *d_config)
Indentation.
{ virDomainNetDefPtr *l_nics = def->nets; int nnics = def->nnets; @@ -639,7 +685,7 @@ libxlMakeNicList(virDomainDefPtr def, libxl_domain_config *d_config) for (i = 0; i < nnics; i++) { x_nics[i].devid = i;
- if (libxlMakeNic(l_nics[i], &x_nics[i])) + if (libxlMakeNic(driver, l_nics[i], &x_nics[i])) goto error; }
@@ -878,11 +924,11 @@ libxlBuildDomainConfig(libxlDriverPrivatePtr driver, goto error; }
- if (libxlMakeDiskList(def, d_config) < 0) { + if (libxlMakeDiskList(driver, def, d_config) < 0) { goto error; }
- if (libxlMakeNicList(def, d_config) < 0) { + if (libxlMakeNicList(driver, def, d_config) < 0) { goto error; }
diff --git a/src/libxl/libxl_conf.h b/src/libxl/libxl_conf.h index b3ab3bf..99948b5 100644 --- a/src/libxl/libxl_conf.h +++ b/src/libxl/libxl_conf.h @@ -113,9 +113,9 @@ virCapsPtr libxlMakeCapabilities(libxl_ctx *ctx);
int -libxlMakeDisk(virDomainDiskDefPtr l_dev, libxl_device_disk *x_dev); +libxlMakeDisk(libxlDriverPrivatePtr driver, virDomainDiskDefPtr l_dev, libxl_device_disk *x_dev);
This is more than 80 columns now.
int -libxlMakeNic(virDomainNetDefPtr l_nic, libxl_device_nic *x_nic); +libxlMakeNic(libxlDriverPrivatePtr driver, virDomainNetDefPtr l_nic, libxl_device_nic *x_nic);
Same here.
int libxlMakeVfb(libxlDriverPrivatePtr driver, virDomainGraphicsDefPtr l_vfb, libxl_device_vfb *x_vfb); diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 89546a5..b0f0c6a 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -3166,8 +3166,9 @@ libxlDomainUndefine(virDomainPtr dom) }
static int -libxlDomainChangeEjectableMedia(libxlDomainObjPrivatePtr priv, - virDomainObjPtr vm, virDomainDiskDefPtr disk) +libxlDomainChangeEjectableMedia(libxlDriverPrivatePtr driver, + libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, virDomainDiskDefPtr + disk)
Whitespace issues here. There are no strict guidelines for the whitespace format of function definitions/declarations, but the dominate pattern in libvirt seems to be return type on first line, then name and params on next line. If name and params exceeds 80 columns, params 2..n get their own line. I've tried to move to this pattern in the libxl driver as I touch offending code.
{ virDomainDiskDefPtr origdisk = NULL; libxl_device_disk x_disk; @@ -3196,7 +3197,7 @@ libxlDomainChangeEjectableMedia(libxlDomainObjPrivatePtr priv, return -1; }
- if (libxlMakeDisk(disk, &x_disk) < 0) + if (libxlMakeDisk(driver, disk, &x_disk) < 0) goto cleanup;
if ((ret = libxl_cdrom_insert(priv->ctx, vm->def->id, &x_disk, NULL)) < 0) { @@ -3221,8 +3222,9 @@ cleanup: }
static int -libxlDomainAttachDeviceDiskLive(libxlDomainObjPrivatePtr priv, - virDomainObjPtr vm, virDomainDeviceDefPtr dev) +libxlDomainAttachDeviceDiskLive(libxlDriverPrivatePtr driver, + libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, + virDomainDeviceDefPtr dev)
Indentation.
{ virDomainDiskDefPtr l_disk = dev->data.disk; libxl_device_disk x_disk; @@ -3230,7 +3232,7 @@ libxlDomainAttachDeviceDiskLive(libxlDomainObjPrivatePtr priv,
switch (l_disk->device) { case VIR_DOMAIN_DISK_DEVICE_CDROM: - ret = libxlDomainChangeEjectableMedia(priv, vm, l_disk); + ret = libxlDomainChangeEjectableMedia(driver, priv, vm, l_disk); break; case VIR_DOMAIN_DISK_DEVICE_DISK: if (l_disk->bus == VIR_DOMAIN_DISK_BUS_XEN) { @@ -3251,7 +3253,7 @@ libxlDomainAttachDeviceDiskLive(libxlDomainObjPrivatePtr priv, goto cleanup; }
- if (libxlMakeDisk(l_disk, &x_disk) < 0) + if (libxlMakeDisk(driver, l_disk, &x_disk) < 0) goto cleanup;
if ((ret = libxl_device_disk_add(priv->ctx, vm->def->id, @@ -3282,8 +3284,9 @@ cleanup: }
static int -libxlDomainDetachDeviceDiskLive(libxlDomainObjPrivatePtr priv, - virDomainObjPtr vm, virDomainDeviceDefPtr dev) +libxlDomainDetachDeviceDiskLive(libxlDriverPrivatePtr driver, + libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, + virDomainDeviceDefPtr dev)
Indentation.
{ virDomainDiskDefPtr l_disk = NULL; libxl_device_disk x_disk; @@ -3304,7 +3307,7 @@ libxlDomainDetachDeviceDiskLive(libxlDomainObjPrivatePtr priv,
l_disk = vm->def->disks[i];
- if (libxlMakeDisk(l_disk, &x_disk) < 0) + if (libxlMakeDisk(driver, l_disk, &x_disk) < 0) goto cleanup;
if ((ret = libxl_device_disk_remove(priv->ctx, vm->def->id, @@ -3336,14 +3339,15 @@ cleanup: }
static int -libxlDomainAttachDeviceLive(libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, - virDomainDeviceDefPtr dev) +libxlDomainAttachDeviceLive(libxlDriverPrivatePtr driver, + libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, + virDomainDeviceDefPtr dev)
Indentation.
{ int ret = -1;
switch (dev->type) { case VIR_DOMAIN_DEVICE_DISK: - ret = libxlDomainAttachDeviceDiskLive(priv, vm, dev); + ret = libxlDomainAttachDeviceDiskLive(driver, priv, vm, dev); if (!ret) dev->data.disk = NULL; break; @@ -3388,14 +3392,15 @@ libxlDomainAttachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev) }
static int -libxlDomainDetachDeviceLive(libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, - virDomainDeviceDefPtr dev) +libxlDomainDetachDeviceLive(libxlDriverPrivatePtr driver, + libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, + virDomainDeviceDefPtr dev)
Indentation.
{ int ret = -1;
switch (dev->type) { case VIR_DOMAIN_DEVICE_DISK: - ret = libxlDomainDetachDeviceDiskLive(priv, vm, dev); + ret = libxlDomainDetachDeviceDiskLive(driver, priv, vm, dev); break;
default: @@ -3435,8 +3440,9 @@ libxlDomainDetachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev) }
static int -libxlDomainUpdateDeviceLive(libxlDomainObjPrivatePtr priv, - virDomainObjPtr vm, virDomainDeviceDefPtr dev) +libxlDomainUpdateDeviceLive(libxlDriverPrivatePtr driver, + libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, + virDomainDeviceDefPtr dev)
Indentation. Looks good with the exception of the nits. Depends on patch 7 of course... Regards, Jim
{ virDomainDiskDefPtr disk; int ret = -1; @@ -3446,7 +3452,7 @@ libxlDomainUpdateDeviceLive(libxlDomainObjPrivatePtr priv, disk = dev->data.disk; switch (disk->device) { case VIR_DOMAIN_DISK_DEVICE_CDROM: - ret = libxlDomainChangeEjectableMedia(priv, vm, disk); + ret = libxlDomainChangeEjectableMedia(driver, priv, vm, disk); if (ret == 0) dev->data.disk = NULL; break; @@ -3601,13 +3607,13 @@ libxlDomainModifyDeviceFlags(virDomainPtr dom, const char *xml,
switch (action) { case LIBXL_DEVICE_ATTACH: - ret = libxlDomainAttachDeviceLive(priv, vm, dev); + ret = libxlDomainAttachDeviceLive(driver, priv, vm, dev); break; case LIBXL_DEVICE_DETACH: - ret = libxlDomainDetachDeviceLive(priv, vm, dev); + ret = libxlDomainDetachDeviceLive(driver, priv, vm, dev); break; case LIBXL_DEVICE_UPDATE: - ret = libxlDomainUpdateDeviceLive(priv, vm, dev); + ret = libxlDomainUpdateDeviceLive(driver, priv, vm, dev); break; default: virReportError(VIR_ERR_INTERNAL_ERROR,

libxl uses some xenstore entries for hints in memory management (especially when starting new domain). This includes dom0 memory limit and Xen free memory margin, based on current system state. Entries are created at first usage, so force such usage at daemon startup, which most likely will be before any domain startup. --- src/libxl/libxl_driver.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 011edf8..89546a5 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -1115,6 +1115,7 @@ libxlStartup(bool privileged, char *log_file = NULL; virCommandPtr cmd; int status, ret = 0; + unsigned int free_mem; char ebuf[1024]; /* Disable libxl driver if non-root */ @@ -1240,6 +1241,13 @@ libxlStartup(bool privileged, goto error; } + /* This will fill xenstore info about free and dom0 memory - if missing, + * should be called before starting first domain */ + if (libxl_get_free_memory(libxl_driver->ctx, &free_mem)) { + VIR_ERROR(_("cannot get free memory info")); + goto error; + } + if (!(libxl_driver->xmlconf = virDomainXMLConfNew(&libxlDomainXMLPrivateDataCallbacks, NULL))) goto error; -- 1.8.1.4

Marek Marczykowski wrote:
libxl uses some xenstore entries for hints in memory management (especially when starting new domain). This includes dom0 memory limit and Xen free memory margin, based on current system state. Entries are created at first usage, so force such usage at daemon startup, which most likely will be before any domain startup.
Hmm, I'd like to get the xen developer's opinion on this change. Perhaps Ian C. or Ian J. have some comment...
--- src/libxl/libxl_driver.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 011edf8..89546a5 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -1115,6 +1115,7 @@ libxlStartup(bool privileged, char *log_file = NULL; virCommandPtr cmd; int status, ret = 0; + unsigned int free_mem;
uint32_t to match libxl_get_free_memory() definition?
char ebuf[1024];
/* Disable libxl driver if non-root */ @@ -1240,6 +1241,13 @@ libxlStartup(bool privileged, goto error; }
+ /* This will fill xenstore info about free and dom0 memory - if missing, + * should be called before starting first domain */ + if (libxl_get_free_memory(libxl_driver->ctx, &free_mem)) { + VIR_ERROR(_("cannot get free memory info")); + goto error; + }
Should failure of libxl_get_free_memory() really be fatal and prevent the driver from loading? Regards, Jim
+ if (!(libxl_driver->xmlconf = virDomainXMLConfNew(&libxlDomainXMLPrivateDataCallbacks, NULL))) goto error;

On Thu, 2013-04-11 at 05:09 +0100, Jim Fehlig wrote:
+ /* This will fill xenstore info about free and dom0 memory - if missing, + * should be called before starting first domain */ + if (libxl_get_free_memory(libxl_driver->ctx, &free_mem)) { + VIR_ERROR(_("cannot get free memory info")); + goto error; + }
Should failure of libxl_get_free_memory() really be fatal and prevent the driver from loading?
I'm not sure it is intended to be called like this... I think it is intended to be called as part of starting every domain, to check if there is enough free memory for that domain, rather than calling it once at start of day. In that context if it fails or returns less than the required amount of memory then that would be fatal for starting that domain. In xl we use this as part of the auto balloon of dom0, see xl_cmdimplg.c:freemem. Does libvirt do autoballooning or does it require dom0_mem? Perhaps this is handled at a higher level? Ian.
Regards, Jim
+ if (!(libxl_driver->xmlconf = virDomainXMLConfNew(&libxlDomainXMLPrivateDataCallbacks, NULL))) goto error;
_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel

On 11.04.2013 09:52, Ian Campbell wrote:
On Thu, 2013-04-11 at 05:09 +0100, Jim Fehlig wrote:
+ /* This will fill xenstore info about free and dom0 memory - if missing, + * should be called before starting first domain */ + if (libxl_get_free_memory(libxl_driver->ctx, &free_mem)) { + VIR_ERROR(_("cannot get free memory info")); + goto error; + }
Should failure of libxl_get_free_memory() really be fatal and prevent the driver from loading?
I'm not sure it is intended to be called like this...
I think it is intended to be called as part of starting every domain, to check if there is enough free memory for that domain, rather than calling it once at start of day.
In that context if it fails or returns less than the required amount of memory then that would be fatal for starting that domain.
In xl we use this as part of the auto balloon of dom0, see xl_cmdimplg.c:freemem. Does libvirt do autoballooning or does it require dom0_mem? Perhaps this is handled at a higher level?
The problem is how libxl set initial value for freemem-slack. If, for any reason, dom0 hasn't (almost) all memory assigned before creating first domain, 15% of host memory will no longer be used at all. This "any reason" can be dom0_mem, which is covered by "auto" value for autoballoon in xen-unstable (actually only for xl, not libxl in general). But this can also happen if somebody calls xl set-mem 0 <some value>. The later case doesn't mean the user want to disable autoballoon completely. And to answer you question - libvirt rely on libxl autoballoon. -- Best Regards / Pozdrawiam, Marek Marczykowski Invisible Things Lab

On Thu, 2013-04-11 at 11:53 +0100, Marek Marczykowski wrote:
On 11.04.2013 09:52, Ian Campbell wrote:
On Thu, 2013-04-11 at 05:09 +0100, Jim Fehlig wrote:
+ /* This will fill xenstore info about free and dom0 memory - if missing, + * should be called before starting first domain */ + if (libxl_get_free_memory(libxl_driver->ctx, &free_mem)) { + VIR_ERROR(_("cannot get free memory info")); + goto error; + }
Should failure of libxl_get_free_memory() really be fatal and prevent the driver from loading?
I'm not sure it is intended to be called like this...
I think it is intended to be called as part of starting every domain, to check if there is enough free memory for that domain, rather than calling it once at start of day.
In that context if it fails or returns less than the required amount of memory then that would be fatal for starting that domain.
In xl we use this as part of the auto balloon of dom0, see xl_cmdimplg.c:freemem. Does libvirt do autoballooning or does it require dom0_mem? Perhaps this is handled at a higher level?
The problem is how libxl set initial value for freemem-slack. If, for any reason, dom0 hasn't (almost) all memory assigned before creating first domain, 15% of host memory will no longer be used at all.
This is probably one for Stefano who understands this aspect best, I think. (He's back next week, so this may need to wait). IanJ also knows this stuff better than I, I've added both of them to the CC. Note that whatever problem you are envisaging is also true if /creating first domain/starting libvirtd/ (or whatever the relevant daemon is called).
This "any reason" can be dom0_mem, which is covered by "auto" value for autoballoon in xen-unstable (actually only for xl, not libxl in general). But this can also happen if somebody calls xl set-mem 0 <some value>. The later case doesn't mean the user want to disable autoballoon completely.
And to answer you question - libvirt rely on libxl autoballoon.
AIUI autoballoon and dom0_mem (and I think mem-set at start of day too) are mutually exclusive, which means that as it stands the libvirt backend is incompatible with dom0_mem -- obviously this is something which should be addressed. I don't think this patch is the right way to do that but I'm not sure what is, hopefully Stefano or IanJ have some ideas... Ian.

On Thu, 11 Apr 2013, Marek Marczykowski wrote:
On 11.04.2013 09:52, Ian Campbell wrote:
On Thu, 2013-04-11 at 05:09 +0100, Jim Fehlig wrote:
+ /* This will fill xenstore info about free and dom0 memory - if missing, + * should be called before starting first domain */ + if (libxl_get_free_memory(libxl_driver->ctx, &free_mem)) { + VIR_ERROR(_("cannot get free memory info")); + goto error; + }
Should failure of libxl_get_free_memory() really be fatal and prevent the driver from loading?
I'm not sure it is intended to be called like this...
I think it is intended to be called as part of starting every domain, to check if there is enough free memory for that domain, rather than calling it once at start of day.
In that context if it fails or returns less than the required amount of memory then that would be fatal for starting that domain.
In xl we use this as part of the auto balloon of dom0, see xl_cmdimplg.c:freemem. Does libvirt do autoballooning or does it require dom0_mem? Perhaps this is handled at a higher level?
The problem is how libxl set initial value for freemem-slack. If, for any reason, dom0 hasn't (almost) all memory assigned before creating first domain, 15% of host memory will no longer be used at all. This "any reason" can be dom0_mem, which is covered by "auto" value for autoballoon in xen-unstable (actually only for xl, not libxl in general).
This is the (in)famous incompatibility between autoballoon and dom0_mem.
But this can also happen if somebody calls xl set-mem 0 <some value>. The later case doesn't mean the user want to disable autoballoon completely.
Calling "xl set-mem 0" manually should be compatible with autoballoon. However it wouldn't work with dom0_mem.
And to answer you question - libvirt rely on libxl autoballoon.
Could we introduce something similar to autoballoon=auto to libvirt? Maybe we should push down the autoballoon option to libxl: we should probably rename autoballoon to libxl_memory_management, enable it automatically during initialization (and call libxl__fill_dom0_memory_info) unless dom0_mem has been passed as an option, in which case we would disable it. If we do it at the libxl level we would cover xl as well as libvirt and also fix the "xl set-mem 0" case.

On 19.04.2013 13:10, Stefano Stabellini wrote:
On Thu, 11 Apr 2013, Marek Marczykowski wrote:
On 11.04.2013 09:52, Ian Campbell wrote:
On Thu, 2013-04-11 at 05:09 +0100, Jim Fehlig wrote:
+ /* This will fill xenstore info about free and dom0 memory - if missing, + * should be called before starting first domain */ + if (libxl_get_free_memory(libxl_driver->ctx, &free_mem)) { + VIR_ERROR(_("cannot get free memory info")); + goto error; + }
Should failure of libxl_get_free_memory() really be fatal and prevent the driver from loading?
I'm not sure it is intended to be called like this...
I think it is intended to be called as part of starting every domain, to check if there is enough free memory for that domain, rather than calling it once at start of day.
In that context if it fails or returns less than the required amount of memory then that would be fatal for starting that domain.
In xl we use this as part of the auto balloon of dom0, see xl_cmdimplg.c:freemem. Does libvirt do autoballooning or does it require dom0_mem? Perhaps this is handled at a higher level?
The problem is how libxl set initial value for freemem-slack. If, for any reason, dom0 hasn't (almost) all memory assigned before creating first domain, 15% of host memory will no longer be used at all. This "any reason" can be dom0_mem, which is covered by "auto" value for autoballoon in xen-unstable (actually only for xl, not libxl in general).
This is the (in)famous incompatibility between autoballoon and dom0_mem.
But this can also happen if somebody calls xl set-mem 0 <some value>. The later case doesn't mean the user want to disable autoballoon completely.
Calling "xl set-mem 0" manually should be compatible with autoballoon.
Unless it is called before first domain start (which case is covered by my patch).
However it wouldn't work with dom0_mem.
And to answer you question - libvirt rely on libxl autoballoon.
Could we introduce something similar to autoballoon=auto to libvirt?
Maybe we should push down the autoballoon option to libxl: we should probably rename autoballoon to libxl_memory_management, enable it automatically during initialization (and call libxl__fill_dom0_memory_info) unless dom0_mem has been passed as an option, in which case we would disable it. If we do it at the libxl level we would cover xl as well as libvirt and also fix the "xl set-mem 0" case.
Looks good for me, but IIUC it's too late for such change in 4.3 and it doesn't qualify for later backport, right? If so, some approach still is needed in libvirt for xen 4.2 and 4.3 (like my simple patch). This still doesn't make libvirt compatible with dom0_mem, but at least cover one (independent) case. Perhaps additionally autoballoon=auto code should be copied from xl to libvirt to cover dom0_mem case with xen 4.2 and 4.3? -- Best Regards / Pozdrawiam, Marek Marczykowski Invisible Things Lab

On Fri, 19 Apr 2013, Marek Marczykowski wrote:
And to answer you question - libvirt rely on libxl autoballoon.
Could we introduce something similar to autoballoon=auto to libvirt?
Maybe we should push down the autoballoon option to libxl: we should probably rename autoballoon to libxl_memory_management, enable it automatically during initialization (and call libxl__fill_dom0_memory_info) unless dom0_mem has been passed as an option, in which case we would disable it. If we do it at the libxl level we would cover xl as well as libvirt and also fix the "xl set-mem 0" case.
Looks good for me, but IIUC it's too late for such change in 4.3 and it doesn't qualify for later backport, right? If so, some approach still is needed in libvirt for xen 4.2 and 4.3 (like my simple patch). This still doesn't make libvirt compatible with dom0_mem, but at least cover one (independent) case. Perhaps additionally autoballoon=auto code should be copied from xl to libvirt to cover dom0_mem case with xen 4.2 and 4.3?
Might be a decent solution for the moment.

Marek Marczykowski wrote:
On 19.04.2013 13:10, Stefano Stabellini wrote:
On Thu, 11 Apr 2013, Marek Marczykowski wrote:
On 11.04.2013 09:52, Ian Campbell wrote:
On Thu, 2013-04-11 at 05:09 +0100, Jim Fehlig wrote:
+ /* This will fill xenstore info about free and dom0 memory - if missing, + * should be called before starting first domain */ + if (libxl_get_free_memory(libxl_driver->ctx, &free_mem)) { + VIR_ERROR(_("cannot get free memory info")); + goto error; + }
Should failure of libxl_get_free_memory() really be fatal and prevent the driver from loading?
I'm not sure it is intended to be called like this...
I think it is intended to be called as part of starting every domain, to check if there is enough free memory for that domain, rather than calling it once at start of day.
In that context if it fails or returns less than the required amount of memory then that would be fatal for starting that domain.
In xl we use this as part of the auto balloon of dom0, see xl_cmdimplg.c:freemem. Does libvirt do autoballooning or does it require dom0_mem? Perhaps this is handled at a higher level?
The problem is how libxl set initial value for freemem-slack. If, for any reason, dom0 hasn't (almost) all memory assigned before creating first domain, 15% of host memory will no longer be used at all. This "any reason" can be dom0_mem, which is covered by "auto" value for autoballoon in xen-unstable (actually only for xl, not libxl in general).
This is the (in)famous incompatibility between autoballoon and dom0_mem.
But this can also happen if somebody calls xl set-mem 0 <some value>. The later case doesn't mean the user want to disable autoballoon completely.
Calling "xl set-mem 0" manually should be compatible with autoballoon.
Unless it is called before first domain start (which case is covered by my patch).
However it wouldn't work with dom0_mem.
And to answer you question - libvirt rely on libxl autoballoon.
Could we introduce something similar to autoballoon=auto to libvirt?
Maybe we should push down the autoballoon option to libxl: we should probably rename autoballoon to libxl_memory_management, enable it automatically during initialization (and call libxl__fill_dom0_memory_info) unless dom0_mem has been passed as an option, in which case we would disable it. If we do it at the libxl level we would cover xl as well as libvirt and also fix the "xl set-mem 0" case.
Looks good for me, but IIUC it's too late for such change in 4.3 and it doesn't qualify for later backport, right? If so, some approach still is needed in libvirt for xen 4.2 and 4.3 (like my simple patch). This still doesn't make libvirt compatible with dom0_mem, but at least cover one (independent) case. Perhaps additionally autoballoon=auto code should be copied from xl to libvirt to cover dom0_mem case with xen 4.2 and 4.3?
After reading this thread again, it sounds like the best option is to support the autoballoon option in libvirt, e.g. in /etc/libvirt/libxl.conf. (We currently don't have a config file for the libxl driver, but I think we'll need one anyhow for other knobs, similar to qemu.conf.) As you note, even if autoballoon is pushed down to libxl, libvirt would need to handle it for older libxl. And libvirt needs to handle the dom0_mem case... Regards, Jim

On Wed, 22 May 2013, Jim Fehlig wrote:
Marek Marczykowski wrote:
On 19.04.2013 13:10, Stefano Stabellini wrote:
On Thu, 11 Apr 2013, Marek Marczykowski wrote:
On 11.04.2013 09:52, Ian Campbell wrote:
On Thu, 2013-04-11 at 05:09 +0100, Jim Fehlig wrote:
> + /* This will fill xenstore info about free and dom0 memory - if missing, > + * should be called before starting first domain */ > + if (libxl_get_free_memory(libxl_driver->ctx, &free_mem)) { > + VIR_ERROR(_("cannot get free memory info")); > + goto error; > + } > > Should failure of libxl_get_free_memory() really be fatal and prevent the driver from loading?
I'm not sure it is intended to be called like this...
I think it is intended to be called as part of starting every domain, to check if there is enough free memory for that domain, rather than calling it once at start of day.
In that context if it fails or returns less than the required amount of memory then that would be fatal for starting that domain.
In xl we use this as part of the auto balloon of dom0, see xl_cmdimplg.c:freemem. Does libvirt do autoballooning or does it require dom0_mem? Perhaps this is handled at a higher level?
The problem is how libxl set initial value for freemem-slack. If, for any reason, dom0 hasn't (almost) all memory assigned before creating first domain, 15% of host memory will no longer be used at all. This "any reason" can be dom0_mem, which is covered by "auto" value for autoballoon in xen-unstable (actually only for xl, not libxl in general).
This is the (in)famous incompatibility between autoballoon and dom0_mem.
But this can also happen if somebody calls xl set-mem 0 <some value>. The later case doesn't mean the user want to disable autoballoon completely.
Calling "xl set-mem 0" manually should be compatible with autoballoon.
Unless it is called before first domain start (which case is covered by my patch).
However it wouldn't work with dom0_mem.
And to answer you question - libvirt rely on libxl autoballoon.
Could we introduce something similar to autoballoon=auto to libvirt?
Maybe we should push down the autoballoon option to libxl: we should probably rename autoballoon to libxl_memory_management, enable it automatically during initialization (and call libxl__fill_dom0_memory_info) unless dom0_mem has been passed as an option, in which case we would disable it. If we do it at the libxl level we would cover xl as well as libvirt and also fix the "xl set-mem 0" case.
Looks good for me, but IIUC it's too late for such change in 4.3 and it doesn't qualify for later backport, right? If so, some approach still is needed in libvirt for xen 4.2 and 4.3 (like my simple patch). This still doesn't make libvirt compatible with dom0_mem, but at least cover one (independent) case. Perhaps additionally autoballoon=auto code should be copied from xl to libvirt to cover dom0_mem case with xen 4.2 and 4.3?
After reading this thread again, it sounds like the best option is to support the autoballoon option in libvirt, e.g. in /etc/libvirt/libxl.conf. (We currently don't have a config file for the libxl driver, but I think we'll need one anyhow for other knobs, similar to qemu.conf.) As you note, even if autoballoon is pushed down to libxl, libvirt would need to handle it for older libxl. And libvirt needs to handle the dom0_mem case...
Given all the troubles that we had with the autoballoon option in xl/libxl and how it clashes with dom0_mem, I would strongly advise to consider implementing something like autoballoon=auto from the start.

On 22.05.2013 18:58, Stefano Stabellini wrote:
On Wed, 22 May 2013, Jim Fehlig wrote:
Marek Marczykowski wrote:
On 19.04.2013 13:10, Stefano Stabellini wrote:
On Thu, 11 Apr 2013, Marek Marczykowski wrote:
On 11.04.2013 09:52, Ian Campbell wrote:
On Thu, 2013-04-11 at 05:09 +0100, Jim Fehlig wrote:
>> + /* This will fill xenstore info about free and dom0 memory - if missing, >> + * should be called before starting first domain */ >> + if (libxl_get_free_memory(libxl_driver->ctx, &free_mem)) { >> + VIR_ERROR(_("cannot get free memory info")); >> + goto error; >> + } >> >> > Should failure of libxl_get_free_memory() really be fatal and prevent > the driver from loading? > I'm not sure it is intended to be called like this...
I think it is intended to be called as part of starting every domain, to check if there is enough free memory for that domain, rather than calling it once at start of day.
In that context if it fails or returns less than the required amount of memory then that would be fatal for starting that domain.
In xl we use this as part of the auto balloon of dom0, see xl_cmdimplg.c:freemem. Does libvirt do autoballooning or does it require dom0_mem? Perhaps this is handled at a higher level?
The problem is how libxl set initial value for freemem-slack. If, for any reason, dom0 hasn't (almost) all memory assigned before creating first domain, 15% of host memory will no longer be used at all. This "any reason" can be dom0_mem, which is covered by "auto" value for autoballoon in xen-unstable (actually only for xl, not libxl in general).
This is the (in)famous incompatibility between autoballoon and dom0_mem.
But this can also happen if somebody calls xl set-mem 0 <some value>. The later case doesn't mean the user want to disable autoballoon completely.
Calling "xl set-mem 0" manually should be compatible with autoballoon.
Unless it is called before first domain start (which case is covered by my patch).
However it wouldn't work with dom0_mem.
And to answer you question - libvirt rely on libxl autoballoon.
Could we introduce something similar to autoballoon=auto to libvirt?
Maybe we should push down the autoballoon option to libxl: we should probably rename autoballoon to libxl_memory_management, enable it automatically during initialization (and call libxl__fill_dom0_memory_info) unless dom0_mem has been passed as an option, in which case we would disable it. If we do it at the libxl level we would cover xl as well as libvirt and also fix the "xl set-mem 0" case.
Looks good for me, but IIUC it's too late for such change in 4.3 and it doesn't qualify for later backport, right? If so, some approach still is needed in libvirt for xen 4.2 and 4.3 (like my simple patch). This still doesn't make libvirt compatible with dom0_mem, but at least cover one (independent) case. Perhaps additionally autoballoon=auto code should be copied from xl to libvirt to cover dom0_mem case with xen 4.2 and 4.3?
After reading this thread again, it sounds like the best option is to support the autoballoon option in libvirt, e.g. in /etc/libvirt/libxl.conf. (We currently don't have a config file for the libxl driver, but I think we'll need one anyhow for other knobs, similar to qemu.conf.) As you note, even if autoballoon is pushed down to libxl, libvirt would need to handle it for older libxl. And libvirt needs to handle the dom0_mem case...
Given all the troubles that we had with the autoballoon option in xl/libxl and how it clashes with dom0_mem, I would strongly advise to consider implementing something like autoballoon=auto from the start.
Ok, will send such patch (almost ready). For now it will contain copy&paste auto_autobaloon() from xl.c, so the same logic. Can be easily extended to config option in the future, but probably I will not have time for this. -- Best Regards, Marek Marczykowski Invisible Things Lab

On Thu, 11 Apr 2013, Ian Campbell wrote:
On Thu, 2013-04-11 at 05:09 +0100, Jim Fehlig wrote:
+ /* This will fill xenstore info about free and dom0 memory - if missing, + * should be called before starting first domain */ + if (libxl_get_free_memory(libxl_driver->ctx, &free_mem)) { + VIR_ERROR(_("cannot get free memory info")); + goto error; + }
Should failure of libxl_get_free_memory() really be fatal and prevent the driver from loading?
I'm not sure it is intended to be called like this...
I think it is intended to be called as part of starting every domain, to check if there is enough free memory for that domain, rather than calling it once at start of day.
Actually libxl_get_free_memory is just meant to return to total amount of free memory in the system. Can be called at any time. As a side effect of libxl_get_free_memory, freemem-slack will be written to xenstore if it wasn't before. I think that it is OK to call it as Marek did in this patch, even though might be nicer if we had a proper "libxl_initialize_memory_accounting" function.

At least Xen supports backend drivers in another domain (aka "driver domain"). This patch introduces XML config option for such setting as 'domain' element with 'name' attribute. Verification its content is left for the driver. In the future some option will be needed for USB devices (hostdev objects), but for now libxl doesn't have support for PVUSB. --- docs/schemas/domaincommon.rng | 14 ++++++++++++++ src/conf/domain_conf.c | 27 +++++++++++++++++++++++++++ src/conf/domain_conf.h | 2 ++ 3 files changed, 43 insertions(+) diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 8d7e6db..1423187 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -869,6 +869,13 @@ </optional> <ref name="target"/> <optional> + <element name="domain"> + <attribute name="name"> + <ref name="domainName"/> + </attribute> + </element> + </optional> + <optional> <ref name="deviceBoot"/> </optional> <optional> @@ -1834,6 +1841,13 @@ </element> </optional> <optional> + <element name="domain"> + <attribute name="name"> + <ref name="domainName"/> + </attribute> + </element> + </optional> + <optional> <element name="model"> <attribute name="type"> <data type="string"> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 257a265..bf1fec6 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1103,6 +1103,7 @@ void virDomainDiskDefFree(virDomainDiskDefPtr def) VIR_FREE(def->vendor); VIR_FREE(def->product); VIR_FREE(def->script); + VIR_FREE(def->domain_name); if (def->auth.secretType == VIR_DOMAIN_DISK_SECRET_TYPE_USAGE) VIR_FREE(def->auth.secret.usage); virStorageEncryptionFree(def->encryption); @@ -1228,6 +1229,7 @@ void virDomainNetDefFree(virDomainNetDefPtr def) VIR_FREE(def->virtPortProfile); VIR_FREE(def->script); + VIR_FREE(def->domain_name); VIR_FREE(def->ifname); virDomainDeviceInfoClear(&def->info); @@ -3995,6 +3997,7 @@ virDomainDiskDefParseXML(virCapsPtr caps, char *vendor = NULL; char *product = NULL; char *script = NULL; + char *domain_name = NULL; int expected_secret_usage = -1; int auth_secret_usage = -1; @@ -4153,6 +4156,9 @@ virDomainDiskDefParseXML(virCapsPtr caps, } else if (!script && xmlStrEqual(cur->name, BAD_CAST "script")) { script = virXMLPropString(cur, "path"); + } else if (!domain_name && + xmlStrEqual(cur->name, BAD_CAST "domain")) { + domain_name = virXMLPropString(cur, "name"); } else if (xmlStrEqual(cur->name, BAD_CAST "geometry")) { if (virXPathUInt("string(./geometry/@cyls)", ctxt, &def->geometry.cylinders) < 0) { @@ -4447,6 +4453,11 @@ virDomainDiskDefParseXML(virCapsPtr caps, ctxt->node = saved_node; } + if (domain_name != NULL) { + def->domain_name = domain_name; + domain_name = NULL; + } + if (target == NULL) { virReportError(VIR_ERR_NO_TARGET, source ? "%s" : NULL, source); @@ -4796,6 +4807,7 @@ cleanup: VIR_FREE(vendor); VIR_FREE(product); VIR_FREE(script); + VIR_FREE(domain_name); ctxt->node = save_ctxt; return def; @@ -5353,6 +5365,7 @@ virDomainNetDefParseXML(virCapsPtr caps, char *mode = NULL; char *linkstate = NULL; char *addrtype = NULL; + char *domain_name = NULL; virNWFilterHashTablePtr filterparams = NULL; virDomainActualNetDefPtr actual = NULL; xmlNodePtr oldnode = ctxt->node; @@ -5451,6 +5464,9 @@ virDomainNetDefParseXML(virCapsPtr caps, } else if (!script && xmlStrEqual(cur->name, BAD_CAST "script")) { script = virXMLPropString(cur, "path"); + } else if (!domain_name && + xmlStrEqual(cur->name, BAD_CAST "domain")) { + domain_name = virXMLPropString(cur, "name"); } else if (xmlStrEqual(cur->name, BAD_CAST "model")) { model = virXMLPropString(cur, "type"); } else if (xmlStrEqual(cur->name, BAD_CAST "driver")) { @@ -5682,6 +5698,10 @@ virDomainNetDefParseXML(virCapsPtr caps, def->script = script; script = NULL; } + if (domain_name != NULL) { + def->domain_name = domain_name; + domain_name = NULL; + } if (ifname != NULL) { def->ifname = ifname; ifname = NULL; @@ -5808,6 +5828,7 @@ cleanup: VIR_FREE(mode); VIR_FREE(linkstate); VIR_FREE(addrtype); + VIR_FREE(domain_name); virNWFilterHashTableFree(filterparams); return def; @@ -12909,6 +12930,10 @@ virDomainDiskDefFormat(virBufferPtr buf, virBufferEscapeString(buf, " <script path='%s'/>\n", def->script); + if (def->domain_name) { + virBufferEscapeString(buf, " <domain name='%s'/>\n", def->domain_name); + } + virDomainDiskGeometryDefFormat(buf, def); virDomainDiskBlockIoDefFormat(buf, def); @@ -13456,6 +13481,8 @@ virDomainNetDefFormat(virBufferPtr buf, return -1; virBufferEscapeString(buf, "<script path='%s'/>\n", def->script); + if (def->domain_name) + virBufferEscapeString(buf, "<domain name='%s'/>\n", def->domain_name); if (def->ifname && !((flags & VIR_DOMAIN_XML_INACTIVE) && (STRPREFIX(def->ifname, VIR_NET_GENERATED_PREFIX)))) { diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index d55d209..db3002b 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -669,6 +669,7 @@ struct _virDomainDiskDef { int rawio; /* no = 0, yes = 1 */ int sgio; /* enum virDomainDiskSGIO */ char *script; + char *domain_name; /* backend domain name */ size_t nseclabels; virSecurityDeviceLabelDefPtr *seclabels; @@ -919,6 +920,7 @@ struct _virDomainNetDef { unsigned long sndbuf; } tune; char *script; + char *domain_name; /* backend domain name */ char *ifname; virDomainDeviceInfo info; char *filter; -- 1.8.1.4

Marek Marczykowski wrote:
At least Xen supports backend drivers in another domain (aka "driver domain"). This patch introduces XML config option for such setting as 'domain' element with 'name' attribute. Verification its content is left for the driver.
In the future some option will be needed for USB devices (hostdev objects), but for now libxl doesn't have support for PVUSB. --- docs/schemas/domaincommon.rng | 14 ++++++++++++++ src/conf/domain_conf.c | 27 +++++++++++++++++++++++++++ src/conf/domain_conf.h | 2 ++ 3 files changed, 43 insertions(+)
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 8d7e6db..1423187 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -869,6 +869,13 @@ </optional> <ref name="target"/> <optional> + <element name="domain"> + <attribute name="name"> + <ref name="domainName"/> + </attribute> + </element> + </optional> + <optional> <ref name="deviceBoot"/> </optional> <optional> @@ -1834,6 +1841,13 @@ </element> </optional> <optional> + <element name="domain"> + <attribute name="name"> + <ref name="domainName"/> + </attribute> + </element> + </optional> + <optional>
I'm certainly no expert in RNG, but do these need to include <empty/>? BTW, you'll also need to document this in docs/formatdomain.html.in.
<element name="model"> <attribute name="type"> <data type="string"> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 257a265..bf1fec6 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1103,6 +1103,7 @@ void virDomainDiskDefFree(virDomainDiskDefPtr def) VIR_FREE(def->vendor); VIR_FREE(def->product); VIR_FREE(def->script); + VIR_FREE(def->domain_name); if (def->auth.secretType == VIR_DOMAIN_DISK_SECRET_TYPE_USAGE) VIR_FREE(def->auth.secret.usage); virStorageEncryptionFree(def->encryption); @@ -1228,6 +1229,7 @@ void virDomainNetDefFree(virDomainNetDefPtr def)
VIR_FREE(def->virtPortProfile); VIR_FREE(def->script); + VIR_FREE(def->domain_name); VIR_FREE(def->ifname);
virDomainDeviceInfoClear(&def->info); @@ -3995,6 +3997,7 @@ virDomainDiskDefParseXML(virCapsPtr caps, char *vendor = NULL; char *product = NULL; char *script = NULL; + char *domain_name = NULL; int expected_secret_usage = -1; int auth_secret_usage = -1;
@@ -4153,6 +4156,9 @@ virDomainDiskDefParseXML(virCapsPtr caps, } else if (!script && xmlStrEqual(cur->name, BAD_CAST "script")) { script = virXMLPropString(cur, "path"); + } else if (!domain_name && + xmlStrEqual(cur->name, BAD_CAST "domain")) { + domain_name = virXMLPropString(cur, "name"); } else if (xmlStrEqual(cur->name, BAD_CAST "geometry")) { if (virXPathUInt("string(./geometry/@cyls)", ctxt, &def->geometry.cylinders) < 0) { @@ -4447,6 +4453,11 @@ virDomainDiskDefParseXML(virCapsPtr caps, ctxt->node = saved_node; }
+ if (domain_name != NULL) { + def->domain_name = domain_name; + domain_name = NULL; + } +
Is the 'if' necessary here? It looks like the other fields of def are unconditionally assigned, e.g. def->src = source; source = NULL;
if (target == NULL) { virReportError(VIR_ERR_NO_TARGET, source ? "%s" : NULL, source); @@ -4796,6 +4807,7 @@ cleanup: VIR_FREE(vendor); VIR_FREE(product); VIR_FREE(script); + VIR_FREE(domain_name);
ctxt->node = save_ctxt; return def; @@ -5353,6 +5365,7 @@ virDomainNetDefParseXML(virCapsPtr caps, char *mode = NULL; char *linkstate = NULL; char *addrtype = NULL; + char *domain_name = NULL; virNWFilterHashTablePtr filterparams = NULL; virDomainActualNetDefPtr actual = NULL; xmlNodePtr oldnode = ctxt->node; @@ -5451,6 +5464,9 @@ virDomainNetDefParseXML(virCapsPtr caps, } else if (!script && xmlStrEqual(cur->name, BAD_CAST "script")) { script = virXMLPropString(cur, "path"); + } else if (!domain_name && + xmlStrEqual(cur->name, BAD_CAST "domain")) { + domain_name = virXMLPropString(cur, "name"); } else if (xmlStrEqual(cur->name, BAD_CAST "model")) { model = virXMLPropString(cur, "type"); } else if (xmlStrEqual(cur->name, BAD_CAST "driver")) { @@ -5682,6 +5698,10 @@ virDomainNetDefParseXML(virCapsPtr caps, def->script = script; script = NULL; } + if (domain_name != NULL) { + def->domain_name = domain_name; + domain_name = NULL; + }
The pattern in this function is to conditionally assign def->foo, so I guess my above comment is a nit.
if (ifname != NULL) { def->ifname = ifname; ifname = NULL; @@ -5808,6 +5828,7 @@ cleanup: VIR_FREE(mode); VIR_FREE(linkstate); VIR_FREE(addrtype); + VIR_FREE(domain_name); virNWFilterHashTableFree(filterparams);
return def; @@ -12909,6 +12930,10 @@ virDomainDiskDefFormat(virBufferPtr buf,
virBufferEscapeString(buf, " <script path='%s'/>\n", def->script);
+ if (def->domain_name) { + virBufferEscapeString(buf, " <domain name='%s'/>\n", def->domain_name); + } + virDomainDiskGeometryDefFormat(buf, def); virDomainDiskBlockIoDefFormat(buf, def);
@@ -13456,6 +13481,8 @@ virDomainNetDefFormat(virBufferPtr buf, return -1; virBufferEscapeString(buf, "<script path='%s'/>\n", def->script); + if (def->domain_name) + virBufferEscapeString(buf, "<domain name='%s'/>\n", def->domain_name); if (def->ifname && !((flags & VIR_DOMAIN_XML_INACTIVE) && (STRPREFIX(def->ifname, VIR_NET_GENERATED_PREFIX)))) { diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index d55d209..db3002b 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -669,6 +669,7 @@ struct _virDomainDiskDef { int rawio; /* no = 0, yes = 1 */ int sgio; /* enum virDomainDiskSGIO */ char *script; + char *domain_name; /* backend domain name */
size_t nseclabels; virSecurityDeviceLabelDefPtr *seclabels; @@ -919,6 +920,7 @@ struct _virDomainNetDef { unsigned long sndbuf; } tune; char *script; + char *domain_name; /* backend domain name */ char *ifname; virDomainDeviceInfo info; char *filter;
Also, with danpb's "improving unit test coverage" mail fresh in my head, this needs to include a test? I think changes to domain conf generally require a one anyhow. Looks good, but a V2 is needed with the missing documentation. Regards, Jim

Implement handling of previously introduced <script/> element for disk config. This can be used for custom backend configuration like non-standard device-mapper nodes, or to prepare device in other domain (see the next patch). --- src/libxl/libxl_conf.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index 7668305..4bd62e9 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -484,6 +484,11 @@ libxlMakeDisk(virDomainDiskDefPtr l_disk, libxl_device_disk *x_disk) return -1; } + if (l_disk->script && (x_disk->script = strdup(l_disk->script)) == NULL) { + virReportOOMError(); + return -1; + } + if (l_disk->driverName) { if (STREQ(l_disk->driverName, "tap") || STREQ(l_disk->driverName, "tap2")) { -- 1.8.1.4

--- src/libxl/libxl_conf.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/libxl/libxl_conf.h | 2 ++ 2 files changed, 74 insertions(+) diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index ffc7bbb..7668305 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -759,6 +759,74 @@ error: return -1; } +int +libxlMakePci(virDomainHostdevDefPtr l_hostdev, + libxl_device_pci *x_pci) +{ + if (l_hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("This driver supports only subsystem host device mode (PCI devices only)")); + return -1; + } + if (l_hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("This driver supports only PCI host devices")); + return -1; + } + + x_pci->bus = l_hostdev->source.subsys.u.pci.bus; + x_pci->dev = l_hostdev->source.subsys.u.pci.slot; + x_pci->func = l_hostdev->source.subsys.u.pci.function; + return 0; +} + +static int +libxlMakePciList(virDomainDefPtr def, + libxl_domain_config *d_config) +{ + virDomainHostdevDefPtr *l_hostdevs = def->hostdevs; + int nhostdevs = def->nhostdevs; + int npcidevs = 0; + libxl_device_pci *x_pcidevs; + int i, j; + + if (nhostdevs == 0) + return 0; + + /* count PCI devices, ignore others (USB) */ + for (i = 0; i < nhostdevs; i++) { + if (l_hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && + l_hostdevs[i]->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) + npcidevs++; + } + if (VIR_ALLOC_N(x_pcidevs, npcidevs) < 0) { + virReportOOMError(); + return -1; + } + + for (i = 0, j = 0; i < nhostdevs; i++) { + if (l_hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || + l_hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) + continue; + + libxl_device_pci_init(&x_pcidevs[j]); + + if (libxlMakePci(l_hostdevs[i], &x_pcidevs[j]) < 0) + goto error; + j++; + } + + d_config->pcidevs = x_pcidevs; + d_config->num_pcidevs = npcidevs; + + return 0; + +error: + for (i = 0; i < npcidevs; i++) { + libxl_device_pci_dispose(&x_pcidevs[i]); + } + VIR_FREE(x_pcidevs); + return -1; +} + virCapsPtr libxlMakeCapabilities(libxl_ctx *ctx) { @@ -817,6 +885,10 @@ libxlBuildDomainConfig(libxlDriverPrivatePtr driver, goto error; } + if (libxlMakePciList(def, d_config) < 0) { + goto error; + } + d_config->on_reboot = def->onReboot; d_config->on_poweroff = def->onPoweroff; d_config->on_crash = def->onCrash; diff --git a/src/libxl/libxl_conf.h b/src/libxl/libxl_conf.h index f8602b4..b3ab3bf 100644 --- a/src/libxl/libxl_conf.h +++ b/src/libxl/libxl_conf.h @@ -119,6 +119,8 @@ libxlMakeNic(virDomainNetDefPtr l_nic, libxl_device_nic *x_nic); int libxlMakeVfb(libxlDriverPrivatePtr driver, virDomainGraphicsDefPtr l_vfb, libxl_device_vfb *x_vfb); +int +libxlMakePci(virDomainHostdevDefPtr l_hostdev, libxl_device_pci *x_pci); int libxlBuildDomainConfig(libxlDriverPrivatePtr driver, -- 1.8.1.4

On Wed, Apr 10, 2013 at 04:44:43AM +0200, Marek Marczykowski wrote:
--- src/libxl/libxl_conf.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/libxl/libxl_conf.h | 2 ++ 2 files changed, 74 insertions(+)
This needs todo more than just create the config. You need to use the libvirt PCI APIs to validate that it is safe to assign the devices requested, and track which devices are given to which guest, to avoid concurrent assignemnt to 2 guests. Basically I'd expect this to borrow all the code currently in the QMEU driver related to the 'activePciHostdevs' and 'inactivePciHostdevs' data structures. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Daniel P. Berrange wrote:
On Wed, Apr 10, 2013 at 04:44:43AM +0200, Marek Marczykowski wrote:
--- src/libxl/libxl_conf.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/libxl/libxl_conf.h | 2 ++ 2 files changed, 74 insertions(+)
This needs todo more than just create the config. You need to use the libvirt PCI APIs to validate that it is safe to assign the devices requested, and track which devices are given to which guest, to avoid concurrent assignemnt to 2 guests. Basically I'd expect this to borrow all the code currently in the QMEU driver related to the 'activePciHostdevs' and 'inactivePciHostdevs' data structures.
Right. Chunyan already posted such a patch series [1], but Laine noted that it would be useful to maintain the state of PCI device assignment for coordination among multiple drivers. Chunyan posted a design [2] for a "hostdev passthrough driver", and IIRC she has started coding after receiving feedback from the list. Regards, Jim [1] https://www.redhat.com/archives/libvir-list/2013-January/msg00697.html [2] https://www.redhat.com/archives/libvir-list/2013-March/msg01331.html

On 11.04.2013 05:50, Jim Fehlig wrote:
Right. Chunyan already posted such a patch series [1], but Laine noted that it would be useful to maintain the state of PCI device assignment for coordination among multiple drivers. Chunyan posted a design [2] for a "hostdev passthrough driver", and IIRC she has started coding after receiving feedback from the list.
Regards, Jim
[1] https://www.redhat.com/archives/libvir-list/2013-January/msg00697.html [2] https://www.redhat.com/archives/libvir-list/2013-March/msg01331.html
Chunyan, any progress on this? Perhaps I can help you somehow? -- Best Regards / Pozdrawiam, Marek Marczykowski Invisible Things Lab

In testing, could send out in a couple of days I think. 2013/5/3 Marek Marczykowski <marmarek@invisiblethingslab.com>
On 11.04.2013 05:50, Jim Fehlig wrote:
Right. Chunyan already posted such a patch series [1], but Laine noted that it would be useful to maintain the state of PCI device assignment for coordination among multiple drivers. Chunyan posted a design [2] for a "hostdev passthrough driver", and IIRC she has started coding after receiving feedback from the list.
Regards, Jim
[1] https://www.redhat.com/archives/libvir-list/2013-January/msg00697.html [2] https://www.redhat.com/archives/libvir-list/2013-March/msg01331.html
Chunyan, any progress on this? Perhaps I can help you somehow?
-- Best Regards / Pozdrawiam, Marek Marczykowski Invisible Things Lab

Jim Fehlig wrote:
Daniel P. Berrange wrote:
On Wed, Apr 10, 2013 at 04:44:43AM +0200, Marek Marczykowski wrote:
--- src/libxl/libxl_conf.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/libxl/libxl_conf.h | 2 ++ 2 files changed, 74 insertions(+)
This needs todo more than just create the config. You need to use the libvirt PCI APIs to validate that it is safe to assign the devices requested, and track which devices are given to which guest, to avoid concurrent assignemnt to 2 guests. Basically I'd expect this to borrow all the code currently in the QMEU driver related to the 'activePciHostdevs' and 'inactivePciHostdevs' data structures.
Right. Chunyan already posted such a patch series [1], but Laine noted that it would be useful to maintain the state of PCI device assignment for coordination among multiple drivers. Chunyan posted a design [2] for a "hostdev passthrough driver", and IIRC she has started coding after receiving feedback from the list.
I see that Chunyan has now posted patches for this work https://www.redhat.com/archives/libvir-list/2013-May/msg01162.html Could you can help review and test those? Regards, Jim
Regards, Jim
[1] https://www.redhat.com/archives/libvir-list/2013-January/msg00697.html [2] https://www.redhat.com/archives/libvir-list/2013-March/msg01331.html

On 22.05.2013 16:33, Jim Fehlig wrote:
Jim Fehlig wrote:
Daniel P. Berrange wrote:
On Wed, Apr 10, 2013 at 04:44:43AM +0200, Marek Marczykowski wrote:
--- src/libxl/libxl_conf.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/libxl/libxl_conf.h | 2 ++ 2 files changed, 74 insertions(+)
This needs todo more than just create the config. You need to use the libvirt PCI APIs to validate that it is safe to assign the devices requested, and track which devices are given to which guest, to avoid concurrent assignemnt to 2 guests. Basically I'd expect this to borrow all the code currently in the QMEU driver related to the 'activePciHostdevs' and 'inactivePciHostdevs' data structures.
Right. Chunyan already posted such a patch series [1], but Laine noted that it would be useful to maintain the state of PCI device assignment for coordination among multiple drivers. Chunyan posted a design [2] for a "hostdev passthrough driver", and IIRC she has started coding after receiving feedback from the list.
I see that Chunyan has now posted patches for this work
https://www.redhat.com/archives/libvir-list/2013-May/msg01162.html
Could you can help review and test those?
Sure, will look at it tomorrow. -- Best Regards, Marek Marczykowski Invisible Things Lab

For now only for PCI devices. Mostly copy-paste from old xen driver. --- src/libxl/libxl_driver.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 40a7a6b..011edf8 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -42,6 +42,7 @@ #include "libxl.h" #include "libxl_driver.h" #include "libxl_conf.h" +#include "node_device_conf.h" #include "xen_xm.h" #include "virtypedparam.h" #include "viruri.h" @@ -3666,6 +3667,195 @@ libxlDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml, return libxlDomainModifyDeviceFlags(dom, xml, flags, LIBXL_DEVICE_UPDATE); } +static int +libxlNodeDeviceGetPciInfo(virNodeDevicePtr dev, + unsigned *domain, + unsigned *bus, + unsigned *slot, + unsigned *function) +{ + virNodeDeviceDefPtr def = NULL; + virNodeDevCapsDefPtr cap; + char *xml = NULL; + int ret = -1; + + xml = virNodeDeviceGetXMLDesc(dev, 0); + if (!xml) + goto out; + + def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL); + if (!def) + goto out; + + cap = def->caps; + while (cap) { + if (cap->type == VIR_NODE_DEV_CAP_PCI_DEV) { + *domain = cap->data.pci_dev.domain; + *bus = cap->data.pci_dev.bus; + *slot = cap->data.pci_dev.slot; + *function = cap->data.pci_dev.function; + break; + } + + cap = cap->next; + } + + if (!cap) { + virReportError(VIR_ERR_INVALID_ARG, + _("device %s is not a PCI device"), dev->name); + goto out; + } + + ret = 0; +out: + virNodeDeviceDefFree(def); + VIR_FREE(xml); + return ret; +} + +static int +libxlNodeDeviceDettach(virNodeDevicePtr dev) +{ + virPCIDevicePtr pci; + unsigned domain, bus, slot, function; + int ret = -1; + + if (libxlNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0) + return -1; + + pci = virPCIDeviceNew(domain, bus, slot, function); + if (!pci) + return -1; + + if (virPCIDeviceDetach(pci, NULL, NULL, "pciback") < 0) + goto out; + + ret = 0; +out: + virPCIDeviceFree(pci); + return ret; +} + +static int +libxlNodeDeviceAssignedDomainId(virNodeDevicePtr dev) +{ + int numdomains; + int numpcidevs; + int ret = -1, i, j; + int *ids = NULL; + char *bdf = NULL; + char *xref = NULL; + unsigned int domain, bus, slot, function; + libxl_device_pci *pcidevs = NULL; + virConnectPtr conn = dev->conn; + libxlDriverPrivatePtr driver = conn->privateData; + + /* Get active domains */ + numdomains = libxlNumDomains(conn); + if (numdomains < 0) { + return ret; + } + if (numdomains > 0){ + if (VIR_ALLOC_N(ids, numdomains) < 0) { + virReportOOMError(); + goto out; + } + if ((numdomains = libxlListDomains(conn, &ids[0], numdomains)) < 0) { + goto out; + } + } + + /* Get pci bdf */ + if (libxlNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0) + goto out; + + if (virAsprintf(&bdf, "%04x:%02x:%02x.%0x", + domain, bus, slot, function) < 0) { + virReportOOMError(); + goto out; + } + + libxlDriverLock(driver); + /* Check if bdf is assigned to one of active domains */ + for (i = 0; i < numdomains; i++) { + pcidevs = libxl_device_pci_list(driver->ctx, ids[i], &numpcidevs); + if (pcidevs == NULL) { + continue; + } else { + for (j = 0; j < numpcidevs; j++) { + if (pcidevs[j].bus == bus && pcidevs[j].dev == slot && pcidevs[j].func == function) { + ret = ids[i]; + break; + } + } + VIR_FREE(pcidevs); + } + } + libxlDriverUnlock(driver); + + VIR_FREE(xref); + VIR_FREE(bdf); +out: + VIR_FREE(ids); + + return ret; +} + +static int +libxlNodeDeviceReAttach(virNodeDevicePtr dev) +{ + virPCIDevicePtr pci; + unsigned domain, bus, slot, function; + int ret = -1; + int domid; + + if (libxlNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0) + return -1; + + pci = virPCIDeviceNew(domain, bus, slot, function); + if (!pci) + return -1; + + /* Check if device is assigned to an active guest */ + if ((domid = libxlNodeDeviceAssignedDomainId(dev)) >= 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Device %s has been assigned to guest %d"), + dev->name, domid); + goto out; + } + + if (virPCIDeviceReattach(pci, NULL, NULL, "pciback") < 0) + goto out; + + ret = 0; +out: + virPCIDeviceFree(pci); + return ret; +} + +static int +libxlNodeDeviceReset(virNodeDevicePtr dev) +{ + virPCIDevicePtr pci; + unsigned domain, bus, slot, function; + int ret = -1; + + if (libxlNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0) + return -1; + + pci = virPCIDeviceNew(domain, bus, slot, function); + if (!pci) + return -1; + + if (virPCIDeviceReset(pci, NULL, NULL) < 0) + goto out; + + ret = 0; +out: + virPCIDeviceFree(pci); + return ret; +} + static unsigned long long libxlNodeGetFreeMemory(virConnectPtr conn) { @@ -4233,6 +4423,9 @@ static virDriver libxlDriver = { .nodeGetFreeMemory = libxlNodeGetFreeMemory, /* 0.9.0 */ .domainEventRegister = libxlDomainEventRegister, /* 0.9.0 */ .domainEventDeregister = libxlDomainEventDeregister, /* 0.9.0 */ + .nodeDeviceDettach = libxlNodeDeviceDettach, /* 1.0.4 */ + .nodeDeviceReAttach = libxlNodeDeviceReAttach, /* 1.0.4 */ + .nodeDeviceReset = libxlNodeDeviceReset, /* 1.0.4 */ .domainManagedSave = libxlDomainManagedSave, /* 0.9.2 */ .domainHasManagedSaveImage = libxlDomainHasManagedSaveImage, /* 0.9.2 */ .domainManagedSaveRemove = libxlDomainManagedSaveRemove, /* 0.9.2 */ -- 1.8.1.4

Marek Marczykowski wrote:
For now only for PCI devices. Mostly copy-paste from old xen driver.
This one is (or will be) covered by Chanyan's work as well right? Regards, Jim
--- src/libxl/libxl_driver.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+)
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 40a7a6b..011edf8 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -42,6 +42,7 @@ #include "libxl.h" #include "libxl_driver.h" #include "libxl_conf.h" +#include "node_device_conf.h" #include "xen_xm.h" #include "virtypedparam.h" #include "viruri.h" @@ -3666,6 +3667,195 @@ libxlDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml, return libxlDomainModifyDeviceFlags(dom, xml, flags, LIBXL_DEVICE_UPDATE); }
+static int +libxlNodeDeviceGetPciInfo(virNodeDevicePtr dev, + unsigned *domain, + unsigned *bus, + unsigned *slot, + unsigned *function) +{ + virNodeDeviceDefPtr def = NULL; + virNodeDevCapsDefPtr cap; + char *xml = NULL; + int ret = -1; + + xml = virNodeDeviceGetXMLDesc(dev, 0); + if (!xml) + goto out; + + def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL); + if (!def) + goto out; + + cap = def->caps; + while (cap) { + if (cap->type == VIR_NODE_DEV_CAP_PCI_DEV) { + *domain = cap->data.pci_dev.domain; + *bus = cap->data.pci_dev.bus; + *slot = cap->data.pci_dev.slot; + *function = cap->data.pci_dev.function; + break; + } + + cap = cap->next; + } + + if (!cap) { + virReportError(VIR_ERR_INVALID_ARG, + _("device %s is not a PCI device"), dev->name); + goto out; + } + + ret = 0; +out: + virNodeDeviceDefFree(def); + VIR_FREE(xml); + return ret; +} + +static int +libxlNodeDeviceDettach(virNodeDevicePtr dev) +{ + virPCIDevicePtr pci; + unsigned domain, bus, slot, function; + int ret = -1; + + if (libxlNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0) + return -1; + + pci = virPCIDeviceNew(domain, bus, slot, function); + if (!pci) + return -1; + + if (virPCIDeviceDetach(pci, NULL, NULL, "pciback") < 0) + goto out; + + ret = 0; +out: + virPCIDeviceFree(pci); + return ret; +} + +static int +libxlNodeDeviceAssignedDomainId(virNodeDevicePtr dev) +{ + int numdomains; + int numpcidevs; + int ret = -1, i, j; + int *ids = NULL; + char *bdf = NULL; + char *xref = NULL; + unsigned int domain, bus, slot, function; + libxl_device_pci *pcidevs = NULL; + virConnectPtr conn = dev->conn; + libxlDriverPrivatePtr driver = conn->privateData; + + /* Get active domains */ + numdomains = libxlNumDomains(conn); + if (numdomains < 0) { + return ret; + } + if (numdomains > 0){ + if (VIR_ALLOC_N(ids, numdomains) < 0) { + virReportOOMError(); + goto out; + } + if ((numdomains = libxlListDomains(conn, &ids[0], numdomains)) < 0) { + goto out; + } + } + + /* Get pci bdf */ + if (libxlNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0) + goto out; + + if (virAsprintf(&bdf, "%04x:%02x:%02x.%0x", + domain, bus, slot, function) < 0) { + virReportOOMError(); + goto out; + } + + libxlDriverLock(driver); + /* Check if bdf is assigned to one of active domains */ + for (i = 0; i < numdomains; i++) { + pcidevs = libxl_device_pci_list(driver->ctx, ids[i], &numpcidevs); + if (pcidevs == NULL) { + continue; + } else { + for (j = 0; j < numpcidevs; j++) { + if (pcidevs[j].bus == bus && pcidevs[j].dev == slot && pcidevs[j].func == function) { + ret = ids[i]; + break; + } + } + VIR_FREE(pcidevs); + } + } + libxlDriverUnlock(driver); + + VIR_FREE(xref); + VIR_FREE(bdf); +out: + VIR_FREE(ids); + + return ret; +} + +static int +libxlNodeDeviceReAttach(virNodeDevicePtr dev) +{ + virPCIDevicePtr pci; + unsigned domain, bus, slot, function; + int ret = -1; + int domid; + + if (libxlNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0) + return -1; + + pci = virPCIDeviceNew(domain, bus, slot, function); + if (!pci) + return -1; + + /* Check if device is assigned to an active guest */ + if ((domid = libxlNodeDeviceAssignedDomainId(dev)) >= 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Device %s has been assigned to guest %d"), + dev->name, domid); + goto out; + } + + if (virPCIDeviceReattach(pci, NULL, NULL, "pciback") < 0) + goto out; + + ret = 0; +out: + virPCIDeviceFree(pci); + return ret; +} + +static int +libxlNodeDeviceReset(virNodeDevicePtr dev) +{ + virPCIDevicePtr pci; + unsigned domain, bus, slot, function; + int ret = -1; + + if (libxlNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0) + return -1; + + pci = virPCIDeviceNew(domain, bus, slot, function); + if (!pci) + return -1; + + if (virPCIDeviceReset(pci, NULL, NULL) < 0) + goto out; + + ret = 0; +out: + virPCIDeviceFree(pci); + return ret; +} + static unsigned long long libxlNodeGetFreeMemory(virConnectPtr conn) { @@ -4233,6 +4423,9 @@ static virDriver libxlDriver = { .nodeGetFreeMemory = libxlNodeGetFreeMemory, /* 0.9.0 */ .domainEventRegister = libxlDomainEventRegister, /* 0.9.0 */ .domainEventDeregister = libxlDomainEventDeregister, /* 0.9.0 */ + .nodeDeviceDettach = libxlNodeDeviceDettach, /* 1.0.4 */ + .nodeDeviceReAttach = libxlNodeDeviceReAttach, /* 1.0.4 */ + .nodeDeviceReset = libxlNodeDeviceReset, /* 1.0.4 */ .domainManagedSave = libxlDomainManagedSave, /* 0.9.2 */ .domainHasManagedSaveImage = libxlDomainHasManagedSaveImage, /* 0.9.2 */ .domainManagedSaveRemove = libxlDomainManagedSaveRemove, /* 0.9.2 */

On 22.05.2013 16:36, Jim Fehlig wrote:
Marek Marczykowski wrote:
For now only for PCI devices. Mostly copy-paste from old xen driver.
This one is (or will be) covered by Chanyan's work as well right?
Right.
Regards, Jim
--- src/libxl/libxl_driver.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+)
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 40a7a6b..011edf8 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -42,6 +42,7 @@ #include "libxl.h" #include "libxl_driver.h" #include "libxl_conf.h" +#include "node_device_conf.h" #include "xen_xm.h" #include "virtypedparam.h" #include "viruri.h" @@ -3666,6 +3667,195 @@ libxlDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml, return libxlDomainModifyDeviceFlags(dom, xml, flags, LIBXL_DEVICE_UPDATE); }
+static int +libxlNodeDeviceGetPciInfo(virNodeDevicePtr dev, + unsigned *domain, + unsigned *bus, + unsigned *slot, + unsigned *function) +{ + virNodeDeviceDefPtr def = NULL; + virNodeDevCapsDefPtr cap; + char *xml = NULL; + int ret = -1; + + xml = virNodeDeviceGetXMLDesc(dev, 0); + if (!xml) + goto out; + + def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL); + if (!def) + goto out; + + cap = def->caps; + while (cap) { + if (cap->type == VIR_NODE_DEV_CAP_PCI_DEV) { + *domain = cap->data.pci_dev.domain; + *bus = cap->data.pci_dev.bus; + *slot = cap->data.pci_dev.slot; + *function = cap->data.pci_dev.function; + break; + } + + cap = cap->next; + } + + if (!cap) { + virReportError(VIR_ERR_INVALID_ARG, + _("device %s is not a PCI device"), dev->name); + goto out; + } + + ret = 0; +out: + virNodeDeviceDefFree(def); + VIR_FREE(xml); + return ret; +} + +static int +libxlNodeDeviceDettach(virNodeDevicePtr dev) +{ + virPCIDevicePtr pci; + unsigned domain, bus, slot, function; + int ret = -1; + + if (libxlNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0) + return -1; + + pci = virPCIDeviceNew(domain, bus, slot, function); + if (!pci) + return -1; + + if (virPCIDeviceDetach(pci, NULL, NULL, "pciback") < 0) + goto out; + + ret = 0; +out: + virPCIDeviceFree(pci); + return ret; +} + +static int +libxlNodeDeviceAssignedDomainId(virNodeDevicePtr dev) +{ + int numdomains; + int numpcidevs; + int ret = -1, i, j; + int *ids = NULL; + char *bdf = NULL; + char *xref = NULL; + unsigned int domain, bus, slot, function; + libxl_device_pci *pcidevs = NULL; + virConnectPtr conn = dev->conn; + libxlDriverPrivatePtr driver = conn->privateData; + + /* Get active domains */ + numdomains = libxlNumDomains(conn); + if (numdomains < 0) { + return ret; + } + if (numdomains > 0){ + if (VIR_ALLOC_N(ids, numdomains) < 0) { + virReportOOMError(); + goto out; + } + if ((numdomains = libxlListDomains(conn, &ids[0], numdomains)) < 0) { + goto out; + } + } + + /* Get pci bdf */ + if (libxlNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0) + goto out; + + if (virAsprintf(&bdf, "%04x:%02x:%02x.%0x", + domain, bus, slot, function) < 0) { + virReportOOMError(); + goto out; + } + + libxlDriverLock(driver); + /* Check if bdf is assigned to one of active domains */ + for (i = 0; i < numdomains; i++) { + pcidevs = libxl_device_pci_list(driver->ctx, ids[i], &numpcidevs); + if (pcidevs == NULL) { + continue; + } else { + for (j = 0; j < numpcidevs; j++) { + if (pcidevs[j].bus == bus && pcidevs[j].dev == slot && pcidevs[j].func == function) { + ret = ids[i]; + break; + } + } + VIR_FREE(pcidevs); + } + } + libxlDriverUnlock(driver); + + VIR_FREE(xref); + VIR_FREE(bdf); +out: + VIR_FREE(ids); + + return ret; +} + +static int +libxlNodeDeviceReAttach(virNodeDevicePtr dev) +{ + virPCIDevicePtr pci; + unsigned domain, bus, slot, function; + int ret = -1; + int domid; + + if (libxlNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0) + return -1; + + pci = virPCIDeviceNew(domain, bus, slot, function); + if (!pci) + return -1; + + /* Check if device is assigned to an active guest */ + if ((domid = libxlNodeDeviceAssignedDomainId(dev)) >= 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Device %s has been assigned to guest %d"), + dev->name, domid); + goto out; + } + + if (virPCIDeviceReattach(pci, NULL, NULL, "pciback") < 0) + goto out; + + ret = 0; +out: + virPCIDeviceFree(pci); + return ret; +} + +static int +libxlNodeDeviceReset(virNodeDevicePtr dev) +{ + virPCIDevicePtr pci; + unsigned domain, bus, slot, function; + int ret = -1; + + if (libxlNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0) + return -1; + + pci = virPCIDeviceNew(domain, bus, slot, function); + if (!pci) + return -1; + + if (virPCIDeviceReset(pci, NULL, NULL) < 0) + goto out; + + ret = 0; +out: + virPCIDeviceFree(pci); + return ret; +} + static unsigned long long libxlNodeGetFreeMemory(virConnectPtr conn) { @@ -4233,6 +4423,9 @@ static virDriver libxlDriver = { .nodeGetFreeMemory = libxlNodeGetFreeMemory, /* 0.9.0 */ .domainEventRegister = libxlDomainEventRegister, /* 0.9.0 */ .domainEventDeregister = libxlDomainEventDeregister, /* 0.9.0 */ + .nodeDeviceDettach = libxlNodeDeviceDettach, /* 1.0.4 */ + .nodeDeviceReAttach = libxlNodeDeviceReAttach, /* 1.0.4 */ + .nodeDeviceReset = libxlNodeDeviceReset, /* 1.0.4 */ .domainManagedSave = libxlDomainManagedSave, /* 0.9.2 */ .domainHasManagedSaveImage = libxlDomainHasManagedSaveImage, /* 0.9.2 */ .domainManagedSaveRemove = libxlDomainManagedSaveRemove, /* 0.9.2 */
-- Best Regards, Marek Marczykowski Invisible Things Lab
participants (7)
-
Chunyan Liu
-
Daniel P. Berrange
-
Ian Campbell
-
Jim Fehlig
-
Laine Stump
-
Marek Marczykowski
-
Stefano Stabellini