On Sun, Feb 09, 2014 at 06:46:12PM +0400, Roman Bogorodskiy wrote: > +static int > +bhyveBuildDiskArgStr(const virDomainDef *def, virCommandPtr cmd) > +{ > + virDomainDiskDefPtr disk; > + > + if (def->ndisks != 1) { > + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", > + _("domain should have one and only one disk defined")); > + return -1; > + } > + > + disk = def->disks[0]; > + > + virCommandAddArg(cmd, "-s"); > + virCommandAddArgFormat(cmd, "2:0,ahci-hd,%s", disk->src); Before accessing disk->src, you need to check what disk->type is - the 'src' field is only valid for file/block backed disks, not network backed ones. Also based on the fact that your arg contains the string 'ahci' is is correct to say this is exposing a SATA bus disk ? If so, you also want to validate disk->bus == VIR_DOMAIN_DISK_BUS_SATA and disk->device == VIR_DOMAIN_DISK_DEVICE_DISK and report CONFIG_UNSUPPORTED in both cases. > + /* Clarification about -H and -P flags from Peter Grehan: > + * -H and -P flags force the guest to exit when it executes IA32 HLT and PAUSE > + * instructions respectively. > + * > + * For the HLT exit, bhyve uses that to infer that the guest is idling and can > + * be put to sleep until an external event arrives. If this option is not used, > + * the guest will always use 100% of CPU on the host. > + * > + * The PAUSE exit is most useful when there are large numbers of guest VMs running, > + * since it forces the guest to exit when it spins on a lock acquisition. > + */ > + virCommandAddArg(cmd, "-H"); /* vmexit from guest on hlt */ > + virCommandAddArg(cmd, "-P"); /* vmexit from guest on pause */ Ok, agree that both of those make sense to enable unconditionally. > + virCommandAddArg(cmd, "-S"); > + virCommandAddArg(cmd, "31,uart"); Hmm, this is enabling a serial port right ? If so, you only want todo this if you have def->nserials == 1 I reckon. What is the string '31' saying ? > +virCommandPtr > +virBhyveProcessBuildLoadCmd(bhyveConnPtr driver ATTRIBUTE_UNUSED, > + virDomainObjPtr vm) > +{ > + virCommandPtr cmd; > + virDomainDiskDefPtr disk = vm->def->disks[0]; > + > + cmd = virCommandNew(BHYVELOAD); > + > + /* Memory */ > + virCommandAddArg(cmd, "-m"); > + virCommandAddArgFormat(cmd, "%llu", > + VIR_DIV_UP(vm->def->mem.max_balloon, 1024)); > + > + /* Image path */ > + virCommandAddArg(cmd, "-d"); > + virCommandAddArgFormat(cmd, disk->src); Curious, so you have to repeat the disk specification in two commands. Same comment about validating the disk->type before accessing 'src' > diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c > new file mode 100644 > index 0000000..e8e082b > --- /dev/null > +++ b/src/bhyve/bhyve_driver.c > +static virDrvOpenStatus > +bhyveConnectOpen(virConnectPtr conn, > + virConnectAuthPtr auth ATTRIBUTE_UNUSED, > + unsigned int flags) > +{ > + virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); > + > + if (!conn->uri) > + return VIR_DRV_OPEN_DECLINED; This means that you'll never be able to default to "bhyve" when URI == NULL. Generally we have this auto-detected eg if (conn->uri == NULL) { if (bhyve_driver == NULL) { return VIR_DRV_OPEN_DECLINED } ...accept... } else { ...all the logic below.... See qemuConnectOpen for an example of logic to follow > + > + if (!conn->uri->scheme || STRNEQ(conn->uri->scheme, "bhyve")) > + return VIR_DRV_OPEN_DECLINED; > + > + if (conn->uri->server) > + return VIR_DRV_OPEN_DECLINED; > + > + if (!STREQ_NULLABLE(conn->uri->path, "/system")) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Unexpected bhyve URI path '%s', try bhyve:///system"), > + conn->uri->path); > + return VIR_DRV_OPEN_ERROR; > + } > + > + if (bhyve_driver == NULL) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + "%s", _("bhyve state driver is not active")); > + return VIR_DRV_OPEN_ERROR; > + } > + > + conn->privateData = bhyve_driver; > + > + return VIR_DRV_OPEN_SUCCESS; > +} > +static virDomainPtr > +bhyveDomainDefineXML(virConnectPtr conn, const char *xml) > +{ > + bhyveConnPtr privconn = conn->privateData; > + virDomainPtr dom = NULL; > + virDomainDefPtr def = NULL; > + virDomainDefPtr oldDef = NULL; > + virDomainObjPtr vm = NULL; > + > + if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt, > + 1 << VIR_DOMAIN_VIRT_BHYVE, > + VIR_DOMAIN_XML_INACTIVE)) == NULL) { > + virReportError(VIR_ERR_INVALID_ARG, "%s", > + _("Can't parse XML desc")); > + goto cleanup; > + } > + > + if (!(vm = virDomainObjListAdd(privconn->domains, def, > + privconn->xmlopt, > + 0, &oldDef))) > + goto cleanup; > + > + VIR_INFO("Creating domain '%s'", vm->def->name); > + dom = virGetDomain(conn, vm->def->name, vm->def->uuid); > + if (dom) dom->id = vm->def->id; > + > + if (virDomainSaveConfig(BHYVE_CONFIG_DIR, vm->def) < 0) { > + goto cleanup; > + } Nit-pick: we avoid {} for a single-line body > +static int > +bhyveConnectListDefinedDomains(virConnectPtr conn, char **const names, > + int maxnames) > +{ > + bhyveConnPtr privconn = conn->privateData; > + int n; > + > + memset(names, 0, sizeof(*names) * maxnames); > + n = virDomainObjListGetInactiveNames(privconn->domains, names, > + maxnames, NULL, NULL); > + > + return n; > +} > + > +static int > +bhyveConnectNumOfDefinedDomains(virConnectPtr conn) > +{ > + bhyveConnPtr privconn = conn->privateData; > + int count; > + > + count = virDomainObjListNumOfDomains(privconn->domains, false, > + NULL, NULL); > + > + return count; > +} > + > +static int > +bhyveConnectListAllDomains(virConnectPtr conn, > + virDomainPtr **domains, > + unsigned int flags) > +{ > + bhyveConnPtr privconn = conn->privateData; > + int ret = -1; > + > + virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1); > + > + ret = virDomainObjListExport(privconn->domains, conn, domains, > + NULL, flags); > + > + return ret; > +} > +int > +virBhyveProcessStart(virConnectPtr conn, > + bhyveConnPtr driver, > + virDomainObjPtr vm, > + virDomainRunningReason reason) > + VIR_INFO("Loading domain '%s'", vm->def->name); > + if (virCommandRun(cmd, &status) < 0) > + goto cleanup; Now the domain is loaded... > + > + if (status != 0) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Guest failed to load: %d"), status); > + goto cleanup; > + } > + > + virCommandFree(cmd); > + > + VIR_FREE(privconn->pidfile); > + if (!(privconn->pidfile = virPidFileBuildPath(BHYVE_STATE_DIR, > + vm->def->name))) { > + virReportSystemError(errno, > + "%s", _("Failed to build pidfile path.")); > + goto cleanup; > + } > + > + if (unlink(privconn->pidfile) < 0 && > + errno != ENOENT) { > + virReportSystemError(errno, > + _("Cannot remove state PID file %s"), > + privconn->pidfile); > + goto cleanup; > + } > + > + /* Call bhyve to start the VM */ > + if (!(cmd = virBhyveProcessBuildBhyveCmd(driver, > + vm))) > + goto cleanup; I'd suggest this building is done before loading the domain so you don't needlessly load the domain before we detect any possible user configuration errors. Regards, 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 :| -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list