[libvirt] [libvirt-php PATCH] Fixed the libvirt_domain_disk_add and libvirt_domain_disk_remove so that they can handle block devices, and can update a running domain

Martijn Otto martijn.otto at copernica.com
Fri Apr 19 08:31:36 UTC 2013


---
 src/libvirt-php.c |  246 +++++++++++++++++++++++++----------------------------
 1 file changed, 114 insertions(+), 132 deletions(-)

diff --git a/src/libvirt-php.c b/src/libvirt-php.c
index 0b8345a..24e8606 100644
--- a/src/libvirt-php.c
+++ b/src/libvirt-php.c
@@ -4232,11 +4232,12 @@ PHP_FUNCTION(libvirt_domain_change_boot_devices)
 	Since version:	0.4.2
 	Description:	Function is used to add the disk to the virtual machine using set of API functions to make it as simple as possible for the user
 	Arguments:	@res [resource]: libvirt domain resource
-			@img [string]: string for the image file on the host system
+			@path [string]: string for the image file or device node on the system
 			@dev [string]: string for the device to be presented to the guest (e.g. hda)
 			@typ [string]: bus type for the device in the guest, usually 'ide' or 'scsi'
-                        @driver [string]: driver type to be specified, like 'raw' or 'qcow2'
-			@flags [int]: flags for getting the XML description
+			@driver [string]: driver type to be specified, like 'raw' or 'qcow2'
+			@cache [string]: cache mode, can be 'default', 'none', 'writeback' or 'writethrough'
+			@io [string]: io mode, can be 'default', 'native' or 'threads'
 	Returns:	new domain resource
 */
 PHP_FUNCTION(libvirt_domain_disk_add)
@@ -4244,46 +4245,40 @@ PHP_FUNCTION(libvirt_domain_disk_add)
 	php_libvirt_domain *domain=NULL;
 	zval *zdomain;
 	char *tmp1 = NULL;
-	char *tmp2 = NULL;
 	char *xml;
-	char *img = NULL;
-	int img_len;
+	char *path = NULL;
+	int path_len;
 	char *dev = NULL;
 	int dev_len;
 	char *driver = NULL;
 	int driver_len;
 	char *typ = NULL;
 	int typ_len;
-	char *new_xml = NULL;
-	int new_len;
+	char *cache = "default";
+	int cache_len;
+	char *io = "default";
+	int io_len;
 	char new[4096] = { 0 };
-	long xflags = 0;
 	int retval = -1;
-	int pos = -1;
-	php_libvirt_domain *res_domain = NULL;
-	php_libvirt_connection *conn   = NULL;
-	virDomainPtr dom=NULL;
+	int block_device = 0;		// whether the path leads to a block device (1) or to an image (0)
+	char cache_attr[32] = "";	// store the complete cache attribute, or an empty string to denote default
+	char io_attr[32] = "";		// store the complete io attribute, or an empty string to denote default
 
-	GET_DOMAIN_FROM_ARGS("rssss|l",&zdomain,&img,&img_len,&dev,&dev_len,&typ,&typ_len,&driver,&driver_len,&xflags);
+	GET_DOMAIN_FROM_ARGS("rssss|ss",&zdomain,&path,&path_len,&dev,&dev_len,&typ,&typ_len,&driver,&driver_len,&cache,&cache_len,&io,&io_len);
 
-	DPRINTF("%s: Domain %p, device = %s, image = %s, type = %s, driver = %s\n", PHPFUNC,
-		domain->domain, dev, img, typ, driver);
+	DPRINTF("%s: Domain %p, device = %s, path = %s, type = %s, driver = %s, cache = %s, io = %s\n", PHPFUNC,
+		domain->domain, dev, path, typ, driver, cache, io);
 
-	xml=virDomainGetXMLDesc(domain->domain,xflags);
+	// check whether the path leads to a block device
+	if (strncmp(path, "/dev/", 5) == 0)
+		block_device = 1;
+
+	xml=virDomainGetXMLDesc(domain->domain, 0);
 	if (xml==NULL) {
 		set_error_if_unset("Cannot get the XML description" TSRMLS_CC);
 		RETURN_FALSE;
 	}
 
-	snprintf(new, sizeof(new), "//domain/devices/disk/source[@file=\"%s\"]/./@file", img);
-	tmp1 = get_string_from_xpath(xml, new, NULL, &retval);
-	if (tmp1 != NULL) {
-		free(tmp1);
-		snprintf(new, sizeof(new), "Domain already has image <i>%s</i> connected", img);
-		set_error(new TSRMLS_CC);
-		RETURN_FALSE;
-	}
-
 	snprintf(new, sizeof(new), "//domain/devices/disk/target[@dev='%s']/./@dev", dev);
 	tmp1 = get_string_from_xpath(xml, new, NULL, &retval);
 	if (tmp1 != NULL) {
@@ -4293,58 +4288,72 @@ PHP_FUNCTION(libvirt_domain_disk_add)
 		RETURN_FALSE;
 	}
 
-	if (access(img, R_OK) != 0) {
-		snprintf(new, sizeof(new), "Image file <i>%s</i> doesn't exist", img);
-		set_error(new TSRMLS_CC);
-		RETURN_FALSE;
-	}
-
-	snprintf(new, sizeof(new),
-	"    <disk type='file' device='disk'>\n"
-	"      <driver name='qemu' type='%s'/>\n"
-	"      <source file='%s'/>\n"
-	"      <target dev='%s' bus='%s'/>\n"
-	"    </disk>", driver, img, dev, typ);
-	tmp1 = strstr(xml, "</emulator>") + strlen("</emulator>");
-	pos = strlen(xml) - strlen(tmp1);
+	// do we want to use a non-default cache mode?
+	if (strncmp(cache, "default", 7) != 0)
+		snprintf(cache_attr, sizeof(cache_attr), "cache='%s'", cache);
 
-	tmp2 = emalloc( ( pos + 1 )* sizeof(char) );
-	memset(tmp2, 0, pos + 1);
-	memcpy(tmp2, xml, pos);
+	// or a non-default io mode perhaps?
+	if (strncmp(io, "default", 7) != 0)
+		snprintf(io_attr, sizeof(io_attr), "io='%s'", io);
 
-	new_len = strlen(tmp1) + strlen(tmp2) + strlen(new) + 2;
-	new_xml = emalloc( new_len * sizeof(char) );
-	snprintf(new_xml, new_len, "%s\n%s%s", tmp2, new, tmp1);
-
-	conn = domain->conn;
+	// check for valid image file or device node
+	if (block_device == 0) {
+		// check whether the image already appears in the xml
+		snprintf(new, sizeof(new), "//domain/devices/disk/source[@file=\"%s\"]/./@file", path);
+		tmp1 = get_string_from_xpath(xml, new, NULL, &retval);
+		if (tmp1 != NULL) {
+			free(tmp1);
+			snprintf(new, sizeof(new), "Domain already has image <i>%s</i> connected", path);
+			set_error(new TSRMLS_CC);
+			RETURN_FALSE;
+		}
 
-	virDomainUndefine(domain->domain);
-	virDomainFree(domain->domain);
+		if (access(path, R_OK) != 0) {
+			snprintf(new, sizeof(new), "Image file <i>%s</i> doesn't exist", path);
+			set_error(new TSRMLS_CC);
+			RETURN_FALSE;
+		}
 
-	retval = virDomainFree(domain->domain);
-	if (retval != 0) {
-		DPRINTF("%s: Cannot free domain %p, error code = %d (%s)\n", PHPFUNC, domain->domain, retval, LIBVIRT_G(last_error));
-	}
+		// create the xml to add the device
+		snprintf(new, sizeof(new),
+		"    <disk type='file' device='disk'>\n"
+		"      <driver name='qemu' type='%s' %s %s/>\n"
+		"      <source file='%s'/>\n"
+		"      <target dev='%s' bus='%s'/>\n"
+		"    </disk>", driver, cache_attr, io_attr, path, dev, typ);
+        }
 	else {
-		resource_change_counter(INT_RESOURCE_DOMAIN, conn->conn, domain->domain, 0 TSRMLS_CC);
-		DPRINTF("%s: Domain %p freed\n", PHPFUNC, domain->domain);
-	}
-
-	dom=virDomainDefineXML(conn->conn, new_xml);
-	if (dom==NULL) {
-		DPRINTF("%s: Function failed, restoring original XML\n", PHPFUNC);
-		dom=virDomainDefineXML(conn->conn, xml);
-		if (dom == NULL)
+		// check whether the device already appears in the xml
+		snprintf(new, sizeof(new), "//domain/devices/disk/source[@dev=\"%s\"]/./@dev", path);
+		tmp1 = get_string_from_xpath(xml, new, NULL, &retval);
+		if (tmp1 != NULL) {
+			free(tmp1);
+			snprintf(new, sizeof(new), "Domain already has device <i>%s</i> connected", path);
+			set_error(new TSRMLS_CC);
 			RETURN_FALSE;
+		}
+
+		// create the xml to add the device
+		snprintf(new, sizeof(new),
+		"    <disk type='block' device='disk'>\n"
+		"      <driver name='qemu' type='%s' %s %s/>\n"
+		"      <source dev='%s'/>\n"
+		"      <target dev='%s' bus='%s'/>\n"
+		"    </disk>", driver, cache_attr, io_attr, path, dev, typ);
 	}
 
-	res_domain = emalloc(sizeof(php_libvirt_domain));
-	res_domain->domain = dom;
-	res_domain->conn = conn;
+	// attach the disk to the domain
+	retval = virDomainAttachDeviceFlags(domain->domain, new, VIR_DOMAIN_AFFECT_CURRENT);
+	if (retval != 0) {
+		snprintf(new, sizeof(new), "%s: Cannot add device to domain %p, error code = %d (%s)\n", PHPFUNC, domain->domain, retval, LIBVIRT_G(last_error));
+		set_error(new TSRMLS_CC);
+		RETURN_FALSE;
+	}
 
-	DPRINTF("%s: returning %p\n", PHPFUNC, res_domain->domain);
-	resource_change_counter(INT_RESOURCE_DOMAIN, conn->conn, res_domain->domain, 1 TSRMLS_CC);
-	ZEND_REGISTER_RESOURCE(return_value, res_domain, le_libvirt_domain);
+	// the disk was successfully added
+	DPRINTF("%s: returning %p\n", PHPFUNC, domain->domain);
+	zend_list_addref(Z_LVAL_P(zdomain));
+	RETURN_RESOURCE(Z_LVAL_P(zdomain));
 }
 
 /*
@@ -4360,96 +4369,69 @@ PHP_FUNCTION(libvirt_domain_disk_remove)
 {
 	php_libvirt_domain *domain=NULL;
 	zval *zdomain;
-	char *tmp1 = NULL;
-	char *tmp2 = NULL;
+	char *type = NULL;
+	char *path = NULL;
+	char *source = NULL;
 	char *xml;
 	char *dev = NULL;
 	int dev_len;
 	char *new_xml = NULL;
 	int new_len;
 	char new[4096] = { 0 };
-	long xflags = 0;
 	int retval = -1;
-	int pos = -1;
-	int i, idx = 0;
-	php_libvirt_domain *res_domain=NULL;
-	php_libvirt_connection *conn = NULL;
-	virDomainPtr dom = NULL;
 
-	GET_DOMAIN_FROM_ARGS("rs|l",&zdomain,&dev,&dev_len,&xflags);
+	GET_DOMAIN_FROM_ARGS("rs|l",&zdomain,&dev,&dev_len);
 
 	DPRINTF("%s: Trying to remove %s from domain %p\n", PHPFUNC, dev, domain->domain);
 
-	xml=virDomainGetXMLDesc(domain->domain,xflags);
+	xml=virDomainGetXMLDesc(domain->domain, 0);
 	if (xml==NULL) {
 		set_error_if_unset("Cannot get the XML description" TSRMLS_CC);
 		RETURN_FALSE;
 	}
 
-	snprintf(new, sizeof(new), "//domain/devices/disk/target[@dev='%s']/./@dev", dev);
-	tmp1 = get_string_from_xpath(xml, new, NULL, &retval);
-	if (tmp1 == NULL) {
+	// check for the type, if no result is found, the disk does not exist
+	snprintf(new, sizeof(new), "//domain/devices/disk/target[@dev='%s']/../@type", dev);
+	type = get_string_from_xpath(xml, new, NULL, &retval);
+	if (type == NULL) {
 		snprintf(new, sizeof(new), "Device <i>%s</i> is not connected to the guest", dev);
 		set_error(new TSRMLS_CC);
 		RETURN_FALSE;
 	}
 
-	free(tmp1);
-
-	snprintf(new, sizeof(new), "<target dev='%s'", dev);
-	tmp1 = strstr(xml, new) + strlen(new);
-	pos = strlen(xml) - strlen(tmp1);
-
-	tmp2 = emalloc( ( pos + 1 )* sizeof(char) );
-	memset(tmp2, 0, pos + 1);
-	memcpy(tmp2, xml, pos);
-
-	for (i = strlen(tmp2) - 5; i > 0; i--)
-		if ((tmp2[i] == '<') && (tmp2[i+1] == 'd')
-			&& (tmp2[i+2] == 'i') && (tmp2[i+3] == 's')
-			&& (tmp2[i+4] == 'k')) {
-					tmp2[i-5] = 0;
-					break;
-				}
+	// are we dealing with a file or a block device?
+	if (strcmp(type, "file") == 0)
+		source = "file";
+	else
+		source = "dev";
 
-	for (i = 0; i < strlen(tmp1) - 7; i++)
-		if ((tmp1[i] == '<') && (tmp1[i+1] == '/')
-			&& (tmp1[i+2] == 'd') && (tmp1[i+3] == 'i')
-			&& (tmp1[i+4] == 's') && (tmp1[i+5] == 'k')
-			&& (tmp1[i+6] == '>')) {
-					idx = i + 6;
-					break;
-				}
+	// retrieve the device or file
+	snprintf(new, sizeof(new), "//domain/devices/disk/target[@dev='%s']/../source/@%s", dev, source);
+	path = get_string_from_xpath(xml, new, NULL, &retval);
 
-	new_len = strlen(tmp2) + (strlen(tmp1) - idx);
-	new_xml = emalloc( new_len * sizeof(char) );
-	memset(new_xml, 0, new_len);
-	strcpy(new_xml, tmp2);
-	for (i = idx; i < strlen(tmp1) - 1; i++)
-		new_xml[ strlen(tmp2) + i - idx ] = tmp1[i];
+	// define the xml to remove the device
+	snprintf(new, sizeof(new),
+	"   <disk type='%s' device='disk'>"
+	"     <source %s='%s'/>"
+	"     <target dev='%s'/>"
+	"   </disk>", type, source, path, dev);
 
-	conn = domain->conn;
-	virDomainUndefine(domain->domain);
+	// cleanup temporary resources
+	free(type);
+	free(path);
 
-	retval = virDomainFree(domain->domain);
+	// remove the disk from the domain
+	retval = virDomainDetachDeviceFlags(domain->domain, new, VIR_DOMAIN_AFFECT_CURRENT);
 	if (retval != 0) {
-		DPRINTF("%s: Cannot free domain %p, error code = %d (%s)\n", PHPFUNC, domain->domain, retval, LIBVIRT_G(last_error));
-	}
-	else {
-		resource_change_counter(INT_RESOURCE_DOMAIN, conn->conn, domain->domain, 0 TSRMLS_CC);
-		DPRINTF("%s: Domain %p freed\n", PHPFUNC, domain->domain);
+		snprintf(new, sizeof(new), "%s: Cannot remove device from domain %p, error code = %d (%s)\n", PHPFUNC, domain->domain, retval, LIBVIRT_G(last_error));
+		set_error(new TSRMLS_CC);
+		RETURN_FALSE;
 	}
 
-	dom=virDomainDefineXML(conn->conn,new_xml);
-	if (dom==NULL) RETURN_FALSE;
-
-	res_domain = emalloc(sizeof(php_libvirt_domain));
-	res_domain->domain = dom;
-	res_domain->conn = conn;
-
-	DPRINTF("%s: returning %p\n", PHPFUNC, res_domain->domain);
-	resource_change_counter(INT_RESOURCE_DOMAIN, conn->conn, res_domain->domain, 1 TSRMLS_CC);
-	ZEND_REGISTER_RESOURCE(return_value, res_domain, le_libvirt_domain);
+	// the disk was successfully removed
+	DPRINTF("%s: returning %p\n", PHPFUNC, domain->domain);
+	zend_list_addref(Z_LVAL_P(zdomain));
+	RETURN_RESOURCE(Z_LVAL_P(zdomain));
 }
 
 /*
@@ -5172,7 +5154,7 @@ PHP_FUNCTION(libvirt_domain_get_block_info) {
 	GET_DOMAIN_FROM_ARGS("rs",&zdomain,&dev,&dev_len);
 
 	/* Get XML for the domain */
-	xml=virDomainGetXMLDesc(domain->domain, VIR_DOMAIN_XML_INACTIVE);
+	xml=virDomainGetXMLDesc(domain->domain, 0);
 	if (xml==NULL) {
 		set_error("Cannot get domain XML" TSRMLS_CC);
 		RETURN_FALSE;
-- 
1.7.9.5




More information about the libvir-list mailing list