[libvirt] 2 patches: dead increment and 4 useless (always-false) disjuncts
by Jim Meyering
>From 74f57af2010f9cbe2315d625c6502a0b259e6802 Mon Sep 17 00:00:00 2001
From: Jim Meyering <meyering(a)redhat.com>
Date: Mon, 7 Sep 2009 10:03:22 +0200
Subject: [PATCH 1/2] xm_internal.c: remove dead increment of "data"
* src/xm_internal.c (xenXMDomainConfigParse): Don't increment it.
---
src/xm_internal.c | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
diff --git a/src/xm_internal.c b/src/xm_internal.c
index f206c8c..18613d4 100644
--- a/src/xm_internal.c
+++ b/src/xm_internal.c
@@ -1314,7 +1314,6 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) {
if (!(data = strchr(key, '=')) || (data[0] == '\0'))
break;
- data++;
if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
if (STRPREFIX(key, "vncunused=")) {
--
1.6.4.2.419.gab238
>From d4db2dfaafbf827d1c8b8626a3dbdaa9f371e479 Mon Sep 17 00:00:00 2001
From: Jim Meyering <meyering(a)redhat.com>
Date: Mon, 7 Sep 2009 10:09:20 +0200
Subject: [PATCH 2/2] xm_internal.c: remove four useless comparisons after strchr
* src/xm_internal.c (xenXMDomainConfigParse): After t=strchr...
don't test *t; it's known. This was *not* detected by clang,
but I spotted it since once instance was in the vicinity of the
dead increment of "data".
---
src/xm_internal.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/xm_internal.c b/src/xm_internal.c
index 18613d4..e7f6a55 100644
--- a/src/xm_internal.c
+++ b/src/xm_internal.c
@@ -862,7 +862,7 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) {
*/
/* Extract the source file path*/
- if (!(offset = strchr(head, ',')) || offset[0] == '\0')
+ if (!(offset = strchr(head, ',')))
goto skipdisk;
if ((offset - head) >= (PATH_MAX-1))
goto skipdisk;
@@ -882,7 +882,7 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) {
head = head + 6;
/* Extract the dest device name */
- if (!(offset = strchr(head, ',')) || offset[0] == '\0')
+ if (!(offset = strchr(head, ',')))
goto skipdisk;
if (VIR_ALLOC_N(disk->dst, (offset - head) + 1) < 0)
goto no_memory;
@@ -1018,7 +1018,7 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) {
char *data;
char *nextkey = strchr(key, ',');
- if (!(data = strchr(key, '=')) || (data[0] == '\0'))
+ if (!(data = strchr(key, '=')))
goto skipnic;
data++;
@@ -1312,7 +1312,7 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) {
nextkey++;
}
- if (!(data = strchr(key, '=')) || (data[0] == '\0'))
+ if (!(data = strchr(key, '=')))
break;
if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
--
1.6.4.2.419.gab238
15 years, 2 months
[libvirt] [PATCH] Fix misc thread locking bugs / bogus warnings
by Daniel P. Berrange
Fix all thread locking bugs reported by object-locking test
case.
NB, some of the driver locking is getting too coarse. Driver
mutexes really need to be turned into RW locks instead to
significantly increase concurrency.
* src/lxc_driver.c: Fix useof driver when unlocked in the methods
lxcDomainGetInfo, lxcSetSchedulerParameters, and
lxcGetSchedulerParameters
* src/opennebula/one_driver.c: Fix missing unlock in oneDomainUndefine.
Fix use of driver when unlocked in oneDomainGetInfo,
oneGetOSType, oneDomainShutdown
* src/qemu_driver.c: Fix use of driver when unlocked in
qemudDomainSavem, qemuGetSchedulerType, qemuSetSchedulerParameters
and qemuGetSchedulerParameters
* src/storage_driver.c: Re-work storagePoolCreate to avoid bogus
lock checking warning. Re-work storageVolumeCreateXMLFrom to
remove a potential NULL de-reference & avoid bogus lock check
warnings
* src/test.c: Remove testDomainAssignDef since it break lock chekc
warnings.
* tests/object-locking.ml: Add oneDriverLock, oneDriverUnlock
and one_driver_t methods/types to allow lock checking on the
OpenNebula drivers
---
src/lxc_driver.c | 6 ++--
src/opennebula/one_driver.c | 35 +++++++++++++++---------
src/qemu_driver.c | 60 +++++++++++++++++++++++-------------------
src/storage_driver.c | 35 ++++++++++++-------------
src/test.c | 55 ++++++++++++++++++++-------------------
tests/object-locking.ml | 7 +++-
6 files changed, 108 insertions(+), 90 deletions(-)
diff --git a/src/lxc_driver.c b/src/lxc_driver.c
index bd0cf0e..0ec1e92 100644
--- a/src/lxc_driver.c
+++ b/src/lxc_driver.c
@@ -439,7 +439,6 @@ static int lxcDomainGetInfo(virDomainPtr dom,
lxcDriverLock(driver);
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
- lxcDriverUnlock(driver);
if (!vm) {
lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN,
@@ -470,6 +469,7 @@ static int lxcDomainGetInfo(virDomainPtr dom,
ret = 0;
cleanup:
+ lxcDriverUnlock(driver);
if (cgroup)
virCgroupFree(&cgroup);
if (vm)
@@ -1667,7 +1667,6 @@ static int lxcSetSchedulerParameters(virDomainPtr domain,
lxcDriverLock(driver);
vm = virDomainFindByUUID(&driver->domains, domain->uuid);
- lxcDriverUnlock(driver);
if (vm == NULL) {
lxcError(NULL, domain, VIR_ERR_INTERNAL_ERROR,
@@ -1698,6 +1697,7 @@ static int lxcSetSchedulerParameters(virDomainPtr domain,
ret = 0;
cleanup:
+ lxcDriverUnlock(driver);
virCgroupFree(&group);
if (vm)
virDomainObjUnlock(vm);
@@ -1725,7 +1725,6 @@ static int lxcGetSchedulerParameters(virDomainPtr domain,
lxcDriverLock(driver);
vm = virDomainFindByUUID(&driver->domains, domain->uuid);
- lxcDriverUnlock(driver);
if (vm == NULL) {
lxcError(NULL, domain, VIR_ERR_INTERNAL_ERROR,
@@ -1745,6 +1744,7 @@ static int lxcGetSchedulerParameters(virDomainPtr domain,
ret = 0;
cleanup:
+ lxcDriverUnlock(driver);
virCgroupFree(&group);
if (vm)
virDomainObjUnlock(vm);
diff --git a/src/opennebula/one_driver.c b/src/opennebula/one_driver.c
index 135397c..9587a2d 100644
--- a/src/opennebula/one_driver.c
+++ b/src/opennebula/one_driver.c
@@ -310,6 +310,8 @@ static int oneDomainUndefine(virDomainPtr dom)
ret=0;
return_point:
+ if (vm)
+ virDomainObjUnlock(vm);
oneDriverUnlock(driver);
return ret;
}
@@ -392,9 +394,9 @@ static int oneDomainGetInfo(virDomainPtr dom,
static char *oneGetOSType(virDomainPtr dom)
{
-
one_driver_t *driver = (one_driver_t *)dom->conn->privateData;
virDomainObjPtr vm = NULL;
+ char *ret = NULL;
oneDriverLock(driver);
vm =virDomainFindByUUID(&driver->domains, dom->uuid);
@@ -402,11 +404,17 @@ static char *oneGetOSType(virDomainPtr dom)
if (!vm) {
oneError(dom->conn,dom, VIR_ERR_INVALID_DOMAIN,
"%s", _("no domain with matching uuid"));
- return NULL;
+ goto cleanup;
}
- virDomainObjUnlock(vm);
- return strdup(vm->def->os.type);
+ ret = strdup(vm->def->os.type);
+ if (!ret)
+ virReportOOMError(dom->conn);
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
}
static int oneDomainStart(virDomainPtr dom)
@@ -499,24 +507,25 @@ static int oneDomainShutdown(virDomainPtr dom)
int ret=-1;
oneDriverLock(driver);
- if((vm=virDomainFindByID(&driver->domains, dom->id))) {
- if(!(c_oneShutdown(vm->pid) ) ) {
- vm->state=VIR_DOMAIN_SHUTDOWN;
- ret= 0;
- goto return_point;
- }
+ if (!(vm=virDomainFindByID(&driver->domains, dom->id))) {
+ oneError(dom->conn,dom, VIR_ERR_INVALID_DOMAIN,
+ _("no domain with id %d"), dom->id);
+ goto return_point;
+ }
+
+ if (c_oneShutdown(vm->pid)) {
oneError(dom->conn, dom, VIR_ERR_OPERATION_INVALID,
_("Wrong state to perform action"));
goto return_point;
}
- oneError(dom->conn,dom, VIR_ERR_INVALID_DOMAIN,
- _("no domain with id %d"), dom->id);
- goto return_point;
+ vm->state=VIR_DOMAIN_SHUTDOWN;
+ ret= 0;
if (!vm->persistent) {
virDomainRemoveInactive(&driver->domains, vm);
vm = NULL;
}
+
return_point:
if(vm)
virDomainObjUnlock(vm);
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index d45d33a..b4cd63d 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -3575,24 +3575,6 @@ static int qemudDomainSave(virDomainPtr dom,
memcpy(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic));
header.version = QEMUD_SAVE_VERSION;
- if (driver->saveImageFormat == NULL)
- header.compressed = QEMUD_SAVE_FORMAT_RAW;
- else if (STREQ(driver->saveImageFormat, "raw"))
- header.compressed = QEMUD_SAVE_FORMAT_RAW;
- else if (STREQ(driver->saveImageFormat, "gzip"))
- header.compressed = QEMUD_SAVE_FORMAT_GZIP;
- else if (STREQ(driver->saveImageFormat, "bzip2"))
- header.compressed = QEMUD_SAVE_FORMAT_BZIP2;
- else if (STREQ(driver->saveImageFormat, "lzma"))
- header.compressed = QEMUD_SAVE_FORMAT_LZMA;
- else if (STREQ(driver->saveImageFormat, "lzop"))
- header.compressed = QEMUD_SAVE_FORMAT_LZOP;
- else {
- qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
- "%s", _("Invalid save image format specified in configuration file"));
- return -1;
- }
-
qemuDriverLock(driver);
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
@@ -3632,6 +3614,24 @@ static int qemudDomainSave(virDomainPtr dom,
}
header.xml_len = strlen(xml) + 1;
+ if (driver->saveImageFormat == NULL)
+ header.compressed = QEMUD_SAVE_FORMAT_RAW;
+ else if (STREQ(driver->saveImageFormat, "raw"))
+ header.compressed = QEMUD_SAVE_FORMAT_RAW;
+ else if (STREQ(driver->saveImageFormat, "gzip"))
+ header.compressed = QEMUD_SAVE_FORMAT_GZIP;
+ else if (STREQ(driver->saveImageFormat, "bzip2"))
+ header.compressed = QEMUD_SAVE_FORMAT_BZIP2;
+ else if (STREQ(driver->saveImageFormat, "lzma"))
+ header.compressed = QEMUD_SAVE_FORMAT_LZMA;
+ else if (STREQ(driver->saveImageFormat, "lzop"))
+ header.compressed = QEMUD_SAVE_FORMAT_LZOP;
+ else {
+ qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
+ "%s", _("Invalid save image format specified in configuration file"));
+ goto cleanup;
+ }
+
/* Write header to file, followed by XML */
if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
@@ -4429,7 +4429,9 @@ static char *qemuDomainXMLFromNative(virConnectPtr conn,
goto cleanup;
}
+ qemuDriverLock(driver);
def = qemuParseCommandLineString(conn, driver->caps, config);
+ qemuDriverUnlock(driver);
if (!def)
goto cleanup;
@@ -6183,12 +6185,13 @@ static char *qemuGetSchedulerType(virDomainPtr dom,
int *nparams)
{
struct qemud_driver *driver = dom->conn->privateData;
- char *ret;
+ char *ret = NULL;
+ qemuDriverLock(driver);
if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
__FUNCTION__);
- return NULL;
+ goto cleanup;
}
if (nparams)
@@ -6197,6 +6200,9 @@ static char *qemuGetSchedulerType(virDomainPtr dom,
ret = strdup("posix");
if (!ret)
virReportOOMError(dom->conn);
+
+cleanup:
+ qemuDriverUnlock(driver);
return ret;
}
@@ -6210,15 +6216,14 @@ static int qemuSetSchedulerParameters(virDomainPtr dom,
virDomainObjPtr vm = NULL;
int ret = -1;
+ qemuDriverLock(driver);
if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
__FUNCTION__);
- return -1;
+ goto cleanup;
}
- qemuDriverLock(driver);
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
- qemuDriverUnlock(driver);
if (vm == NULL) {
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
@@ -6261,6 +6266,7 @@ cleanup:
virCgroupFree(&group);
if (vm)
virDomainObjUnlock(vm);
+ qemuDriverUnlock(driver);
return ret;
}
@@ -6275,21 +6281,20 @@ static int qemuGetSchedulerParameters(virDomainPtr dom,
int ret = -1;
int rc;
+ qemuDriverLock(driver);
if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
__FUNCTION__);
- return -1;
+ goto cleanup;
}
if ((*nparams) != 1) {
qemudReportError(dom->conn, domain, NULL, VIR_ERR_INVALID_ARG,
"%s", _("Invalid parameter count"));
- return -1;
+ goto cleanup;
}
- qemuDriverLock(driver);
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
- qemuDriverUnlock(driver);
if (vm == NULL) {
qemudReportError(dom->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR,
@@ -6319,6 +6324,7 @@ cleanup:
virCgroupFree(&group);
if (vm)
virDomainObjUnlock(vm);
+ qemuDriverUnlock(driver);
return ret;
}
diff --git a/src/storage_driver.c b/src/storage_driver.c
index e9ecb20..14e3bc2 100644
--- a/src/storage_driver.c
+++ b/src/storage_driver.c
@@ -489,24 +489,27 @@ storagePoolCreate(virConnectPtr conn,
def = NULL;
if (backend->startPool &&
- backend->startPool(conn, pool) < 0)
+ backend->startPool(conn, pool) < 0) {
+ virStoragePoolObjRemove(&driver->pools, pool);
+ pool = NULL;
goto cleanup;
+ }
if (backend->refreshPool(conn, pool) < 0) {
if (backend->stopPool)
backend->stopPool(conn, pool);
+ virStoragePoolObjRemove(&driver->pools, pool);
+ pool = NULL;
goto cleanup;
}
pool->active = 1;
ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
- virStoragePoolObjUnlock(pool);
- pool = NULL;
cleanup:
virStoragePoolDefFree(def);
if (pool)
- virStoragePoolObjRemove(&driver->pools, pool);
+ virStoragePoolObjUnlock(pool);
storageDriverUnlock(driver);
return ret;
}
@@ -1321,27 +1324,23 @@ storageVolumeCreateXMLFrom(virStoragePoolPtr obj,
virStorageBackendPtr backend;
virStorageVolDefPtr origvol = NULL, newvol = NULL;
virStorageVolPtr ret = NULL, volobj = NULL;
- int buildret, diffpool;
-
- diffpool = !STREQ(obj->name, vobj->pool);
+ int buildret;
storageDriverLock(driver);
pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
- if (diffpool) {
+ if (pool && STRNEQ(obj->name, vobj->pool)) {
virStoragePoolObjUnlock(pool);
origpool = virStoragePoolObjFindByName(&driver->pools, vobj->pool);
virStoragePoolObjLock(pool);
- } else
- origpool = pool;
+ }
storageDriverUnlock(driver);
-
if (!pool) {
virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
"%s", _("no storage pool with matching uuid"));
goto cleanup;
}
- if (diffpool && !origpool) {
+ if (STRNEQ(obj->name, vobj->pool) && !origpool) {
virStorageReportError(obj->conn, VIR_ERR_NO_STORAGE_POOL,
_("no storage pool with matching name '%s'"),
vobj->pool);
@@ -1354,7 +1353,7 @@ storageVolumeCreateXMLFrom(virStoragePoolPtr obj,
goto cleanup;
}
- if (diffpool && !virStoragePoolObjIsActive(origpool)) {
+ if (origpool && !virStoragePoolObjIsActive(origpool)) {
virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
"%s", _("storage pool is not active"));
goto cleanup;
@@ -1363,7 +1362,7 @@ storageVolumeCreateXMLFrom(virStoragePoolPtr obj,
if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
goto cleanup;
- origvol = virStorageVolDefFindByName(origpool, vobj->name);
+ origvol = virStorageVolDefFindByName(origpool ? origpool : pool, vobj->name);
if (!origvol) {
virStorageReportError(obj->conn, VIR_ERR_NO_STORAGE_VOL,
_("no storage vol with matching name '%s'"),
@@ -1429,7 +1428,7 @@ storageVolumeCreateXMLFrom(virStoragePoolPtr obj,
newvol->building = 1;
virStoragePoolObjUnlock(pool);
- if (diffpool) {
+ if (origpool) {
origpool->asyncjobs++;
virStoragePoolObjUnlock(origpool);
}
@@ -1438,7 +1437,7 @@ storageVolumeCreateXMLFrom(virStoragePoolPtr obj,
storageDriverLock(driver);
virStoragePoolObjLock(pool);
- if (diffpool)
+ if (origpool)
virStoragePoolObjLock(origpool);
storageDriverUnlock(driver);
@@ -1447,7 +1446,7 @@ storageVolumeCreateXMLFrom(virStoragePoolPtr obj,
newvol = NULL;
pool->asyncjobs--;
- if (diffpool) {
+ if (origpool) {
origpool->asyncjobs--;
virStoragePoolObjUnlock(origpool);
origpool = NULL;
@@ -1469,7 +1468,7 @@ cleanup:
virStorageVolDefFree(newvol);
if (pool)
virStoragePoolObjUnlock(pool);
- if (diffpool && origpool)
+ if (origpool)
virStoragePoolObjUnlock(origpool);
return ret;
}
diff --git a/src/test.c b/src/test.c
index 7c8f85b..0e4203e 100644
--- a/src/test.c
+++ b/src/test.c
@@ -261,12 +261,10 @@ testDomainGenerateIfname(virConnectPtr conn,
return NULL;
}
-static virDomainObjPtr
-testDomainAssignDef(virConnectPtr conn,
- virDomainObjList *domlist,
- virDomainDefPtr domdef)
+static int
+testDomainGenerateIfnames(virConnectPtr conn,
+ virDomainDefPtr domdef)
{
- virDomainObjPtr domobj = NULL;
int i = 0;
for (i = 0; i < domdef->nnets; i++) {
@@ -276,18 +274,15 @@ testDomainAssignDef(virConnectPtr conn,
ifname = testDomainGenerateIfname(conn, domdef);
if (!ifname)
- goto error;
+ return -1;
domdef->nets[i]->ifname = ifname;
}
- if (!(domobj = virDomainAssignDef(conn, domlist, domdef)))
- goto error;
-
-error:
- return domobj;
+ return 0;
}
+
static int testOpenDefault(virConnectPtr conn) {
int u;
struct timeval tv;
@@ -342,10 +337,11 @@ static int testOpenDefault(virConnectPtr conn) {
defaultDomainXML,
VIR_DOMAIN_XML_INACTIVE)))
goto error;
- if (!(domobj = testDomainAssignDef(conn, &privconn->domains, domdef))) {
- virDomainDefFree(domdef);
+ if (testDomainGenerateIfnames(conn, domdef) < 0)
goto error;
- }
+ if (!(domobj = virDomainAssignDef(conn, &privconn->domains, domdef)))
+ goto error;
+ domdef = NULL;
domobj->def->id = privconn->nextDomID++;
domobj->state = VIR_DOMAIN_RUNNING;
domobj->persistent = 1;
@@ -399,6 +395,7 @@ error:
testDriverUnlock(privconn);
conn->privateData = NULL;
VIR_FREE(privconn);
+ virDomainDefFree(domdef);
return VIR_DRV_OPEN_ERROR;
}
@@ -668,7 +665,8 @@ static int testOpenFromFile(virConnectPtr conn,
goto error;
}
- if (!(dom = testDomainAssignDef(conn, &privconn->domains, def))) {
+ if (testDomainGenerateIfnames(conn, def) < 0 ||
+ !(dom = virDomainAssignDef(conn, &privconn->domains, def))) {
virDomainDefFree(def);
goto error;
}
@@ -980,11 +978,11 @@ testDomainCreateXML(virConnectPtr conn, const char *xml,
VIR_DOMAIN_XML_INACTIVE)) == NULL)
goto cleanup;
- if ((dom = testDomainAssignDef(conn, &privconn->domains,
- def)) == NULL) {
- virDomainDefFree(def);
+ if (testDomainGenerateIfnames(conn, def) < 0)
goto cleanup;
- }
+ if (!(dom = virDomainAssignDef(conn, &privconn->domains, def)))
+ goto cleanup;
+ def = NULL;
dom->state = VIR_DOMAIN_RUNNING;
dom->def->id = privconn->nextDomID++;
@@ -992,15 +990,17 @@ testDomainCreateXML(virConnectPtr conn, const char *xml,
VIR_DOMAIN_EVENT_STARTED,
VIR_DOMAIN_EVENT_STARTED_BOOTED);
- ret = virGetDomain(conn, def->name, def->uuid);
+ ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
if (ret)
- ret->id = def->id;
+ ret->id = dom->def->id;
cleanup:
if (dom)
virDomainObjUnlock(dom);
if (event)
testDomainEventQueue(privconn, event);
+ if (def)
+ virDomainDefFree(def);
testDriverUnlock(privconn);
return ret;
}
@@ -1531,13 +1531,14 @@ static int testDomainRestore(virConnectPtr conn,
if (!def)
goto cleanup;
- if ((dom = testDomainAssignDef(conn, &privconn->domains,
- def)) == NULL)
+ if (testDomainGenerateIfnames(conn, def) < 0)
goto cleanup;
+ if (!(dom = virDomainAssignDef(conn, &privconn->domains, def)))
+ goto cleanup;
+ def = NULL;
dom->state = VIR_DOMAIN_RUNNING;
dom->def->id = privconn->nextDomID++;
- def = NULL;
event = virDomainEventNewFromObj(dom,
VIR_DOMAIN_EVENT_STARTED,
VIR_DOMAIN_EVENT_STARTED_RESTORED);
@@ -1823,10 +1824,10 @@ static virDomainPtr testDomainDefineXML(virConnectPtr conn,
VIR_DOMAIN_XML_INACTIVE)) == NULL)
goto cleanup;
- if ((dom = testDomainAssignDef(conn, &privconn->domains,
- def)) == NULL) {
+ if (testDomainGenerateIfnames(conn, def) < 0)
+ goto cleanup;
+ if (!(dom = virDomainAssignDef(conn, &privconn->domains, def)))
goto cleanup;
- }
def = NULL;
dom->persistent = 1;
diff --git a/tests/object-locking.ml b/tests/object-locking.ml
index 215a2e5..0c66fc7 100644
--- a/tests/object-locking.ml
+++ b/tests/object-locking.ml
@@ -128,7 +128,8 @@ let driverLockMethods = [
"umlDriverLock";
"nodedevDriverLock";
"networkDriverLock";
- "storageDriverLock"
+ "storageDriverLock";
+ "oneDriverLock"
]
(*
@@ -142,7 +143,8 @@ let driverUnlockMethods = [
"umlDriverUnlock";
"nodedevDriverUnlock";
"networkDriverUnlock";
- "storageDriverUnlock"
+ "storageDriverUnlock";
+ "oneDriverUnlock"
]
(*
@@ -159,6 +161,7 @@ let lockableDrivers = [
"virStorageDriverStatePtr";
"network_driver";
"virDeviceMonitorState";
+ "one_driver_t";
]
--
1.6.2.5
15 years, 2 months
[libvirt] [PATCH] Fix handling of Xen(ner) detection
by Daniel P. Berrange
Latest upstream QEMU can be built with Xen support, which introduces
a -xen-domid argument. This was mistakenly detected as -domid due
to old Xenner support. Adapt to cope with both syntax. Also only
set domid if the virt type is xen, or the guest type is xen
* src/qemu_conf.c, src/qemu_conf.h: Detect new -xen-domid flag in
preference to -domid.
* tests/qemuxml2argvdata/qemuxml2argv-bootloader.args,
tests/qemuxml2argvdata/qemuxml2argv-input-xen.args: Add missing
-domid param
* tests/qemuxml2argvdata/qemuxml2argv-misc-uuid.args: Remove bogus
-boot param.
* tests/qemuxml2argvdata/qemuxml2argv-misc-uuid.xml: Fix domain type
to be xen
* tests/qemuxml2argvtest.c: Add missing QEMUD_CMD_FLAG_DOMID params
---
src/qemu_conf.c | 31 +++++++++++++++----
src/qemu_conf.h | 1 +
.../qemuxml2argvdata/qemuxml2argv-bootloader.args | 2 +-
tests/qemuxml2argvdata/qemuxml2argv-input-xen.args | 2 +-
tests/qemuxml2argvdata/qemuxml2argv-misc-uuid.args | 2 +-
tests/qemuxml2argvdata/qemuxml2argv-misc-uuid.xml | 3 +-
tests/qemuxml2argvtest.c | 4 +-
7 files changed, 31 insertions(+), 14 deletions(-)
diff --git a/src/qemu_conf.c b/src/qemu_conf.c
index 22f5edd..e8414c3 100644
--- a/src/qemu_conf.c
+++ b/src/qemu_conf.c
@@ -769,7 +769,9 @@ static unsigned int qemudComputeCmdFlags(const char *help,
flags |= QEMUD_CMD_FLAG_NAME;
if (strstr(help, "-uuid"))
flags |= QEMUD_CMD_FLAG_UUID;
- if (strstr(help, "-domid"))
+ if (strstr(help, "-xen-domid"))
+ flags |= QEMUD_CMD_FLAG_XEN_DOMID;
+ else if (strstr(help, "-domid"))
flags |= QEMUD_CMD_FLAG_DOMID;
if (strstr(help, "-drive")) {
flags |= QEMUD_CMD_FLAG_DRIVE;
@@ -1594,9 +1596,22 @@ int qemudBuildCommandLine(virConnectPtr conn,
ADD_ARG_LIT("-uuid");
ADD_ARG_LIT(uuid);
}
- if (qemuCmdFlags & QEMUD_CMD_FLAG_DOMID) {
- ADD_ARG_LIT("-domid");
- ADD_ARG_LIT(domid);
+ if (def->virtType == VIR_DOMAIN_VIRT_XEN ||
+ STREQ(def->os.type, "xen") ||
+ STREQ(def->os.type, "linux")) {
+ if (qemuCmdFlags & QEMUD_CMD_FLAG_DOMID) {
+ ADD_ARG_LIT("-domid");
+ ADD_ARG_LIT(domid);
+ } else if (qemuCmdFlags & QEMUD_CMD_FLAG_XEN_DOMID) {
+ ADD_ARG_LIT("-xen-attach");
+ ADD_ARG_LIT("-xen-domid");
+ ADD_ARG_LIT(domid);
+ } else {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("qemu emulator '%s' does not support xen"),
+ def->emulator);
+ goto error;
+ }
}
/*
@@ -1649,9 +1664,11 @@ int qemudBuildCommandLine(virConnectPtr conn,
break;
}
}
- boot[def->os.nBootDevs] = '\0';
- ADD_ARG_LIT("-boot");
- ADD_ARG_LIT(boot);
+ if (def->os.nBootDevs) {
+ boot[def->os.nBootDevs] = '\0';
+ ADD_ARG_LIT("-boot");
+ ADD_ARG_LIT(boot);
+ }
if (def->os.kernel) {
ADD_ARG_LIT("-kernel");
diff --git a/src/qemu_conf.h b/src/qemu_conf.h
index a126dac..99aac81 100644
--- a/src/qemu_conf.h
+++ b/src/qemu_conf.h
@@ -67,6 +67,7 @@ enum qemud_cmd_flags {
QEMUD_CMD_FLAG_HOST_NET_ADD = QEMUD_CMD_FLAG_0_10, /* host_net_add monitor command */
QEMUD_CMD_FLAG_PCIDEVICE = (1 << 17), /* PCI device assignment only supported by qemu-kvm */
+ QEMUD_CMD_FLAG_XEN_DOMID = (1 << 18), /* -xen-domid (new style xen integration) */
};
/* Main driver state */
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-bootloader.args b/tests/qemuxml2argvdata/qemuxml2argv-bootloader.args
index 8a15524..bcae18a 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-bootloader.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-bootloader.args
@@ -1 +1 @@
-LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/xenner -S -M xenner -m 214 -smp 1 -nographic -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -bootloader /usr/bin/pygrub -cdrom /dev/cdrom -net none -serial none -parallel none -usb
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/xenner -S -M xenner -m 214 -smp 1 -domid 6 -nographic -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -bootloader /usr/bin/pygrub -cdrom /dev/cdrom -net none -serial none -parallel none -usb
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-input-xen.args b/tests/qemuxml2argvdata/qemuxml2argv-input-xen.args
index 64c0e1c..65fb073 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-input-xen.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-input-xen.args
@@ -1 +1 @@
-LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/xenner -S -M xenner -m 214 -smp 1 -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -bootloader /foo -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb -vnc 127.0.0.1:3
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/xenner -S -M xenner -m 214 -smp 1 -domid 6 -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -bootloader /foo -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb -vnc 127.0.0.1:3
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-misc-uuid.args b/tests/qemuxml2argvdata/qemuxml2argv-misc-uuid.args
index c735dc7..c4df9ae 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-misc-uuid.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-misc-uuid.args
@@ -1 +1 @@
-LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -name QEMUGuest1 -uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 -domid 6 -nographic -monitor unix:/tmp/test-monitor,server,nowait -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -name QEMUGuest1 -uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 -domid 6 -nographic -monitor unix:/tmp/test-monitor,server,nowait -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-misc-uuid.xml b/tests/qemuxml2argvdata/qemuxml2argv-misc-uuid.xml
index 1b37bdc..7f77e01 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-misc-uuid.xml
+++ b/tests/qemuxml2argvdata/qemuxml2argv-misc-uuid.xml
@@ -5,8 +5,7 @@
<currentMemory>219200</currentMemory>
<vcpu>1</vcpu>
<os>
- <type arch='i686' machine='pc'>hvm</type>
- <boot dev='hd'/>
+ <type arch='x86_64' machine='pc'>xen</type>
</os>
<features>
<acpi/>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 6f25e7d..ad7a690 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -186,7 +186,7 @@ mymain(int argc, char **argv)
DO_TEST("boot-cdrom", 0);
DO_TEST("boot-network", 0);
DO_TEST("boot-floppy", 0);
- DO_TEST("bootloader", 0);
+ DO_TEST("bootloader", QEMUD_CMD_FLAG_DOMID);
DO_TEST("clock-utc", 0);
DO_TEST("clock-localtime", 0);
DO_TEST("disk-cdrom", 0);
@@ -236,7 +236,7 @@ mymain(int argc, char **argv)
DO_TEST("graphics-sdl-fullscreen", 0);
DO_TEST("input-usbmouse", 0);
DO_TEST("input-usbtablet", 0);
- DO_TEST("input-xen", 0);
+ DO_TEST("input-xen", QEMUD_CMD_FLAG_DOMID);
DO_TEST("misc-acpi", 0);
DO_TEST("misc-no-reboot", 0);
DO_TEST("misc-uuid", QEMUD_CMD_FLAG_NAME |
--
1.6.2.5
15 years, 2 months
[libvirt] [PATCH] also allow use of XZ for Qemu image compression
by Jim Meyering
While this patch stays minimal by simply adding XZ/xz to the list,
I think it would be better to remove lzma, since it uses
an inferior format (which lacks an integrity check), and
has been effectively subsumed by xz.
Let me know if you'd like that, and I'll prepare the slightly
more invasive patch.
>From afb7275f14e8062e6d5eebf704e1fd0f582cb407 Mon Sep 17 00:00:00 2001
From: Jim Meyering <meyering(a)redhat.com>
Date: Tue, 8 Sep 2009 20:52:37 +0200
Subject: [PATCH] also allow use of XZ for Qemu image compression
* src/qemu_driver.c (enum qemud_save_formats) [QEMUD_SAVE_FORMAT_XZ]:
New member.
[QEMUD_SAVE_FORMAT_LZMA]: Mark as deprecated.
(qemudDomainSave, qemudDomainRestore): Handle the new member.
* src/qemu.conf: Mention xz, too.
---
src/qemu.conf | 2 +-
src/qemu_driver.c | 10 +++++++++-
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/src/qemu.conf b/src/qemu.conf
index 06babc4..342bb8a 100644
--- a/src/qemu.conf
+++ b/src/qemu.conf
@@ -134,7 +134,7 @@
# memory from the domain is dumped out directly to a file. If you have
# guests with a large amount of memory, however, this can take up quite
# a bit of space. If you would like to compress the images while they
-# are being saved to disk, you can also set "gzip", "bzip2", "lzma"
+# are being saved to disk, you can also set "gzip", "bzip2", "lzma", "xz",
# or "lzop" for save_image_format. Note that this means you slow down
# the process of saving a domain in order to save disk space.
#
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index f64d70b..7b64712 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -3622,7 +3622,8 @@ enum qemud_save_formats {
QEMUD_SAVE_FORMAT_RAW,
QEMUD_SAVE_FORMAT_GZIP,
QEMUD_SAVE_FORMAT_BZIP2,
- QEMUD_SAVE_FORMAT_LZMA,
+ QEMUD_SAVE_FORMAT_LZMA, /* deprecated, in favor of xz */
+ QEMUD_SAVE_FORMAT_XZ,
QEMUD_SAVE_FORMAT_LZOP,
};
@@ -3664,6 +3665,8 @@ static int qemudDomainSave(virDomainPtr dom,
header.compressed = QEMUD_SAVE_FORMAT_BZIP2;
else if (STREQ(driver->saveImageFormat, "lzma"))
header.compressed = QEMUD_SAVE_FORMAT_LZMA;
+ else if (STREQ(driver->saveImageFormat, "xz"))
+ header.compressed = QEMUD_SAVE_FORMAT_XZ;
else if (STREQ(driver->saveImageFormat, "lzop"))
header.compressed = QEMUD_SAVE_FORMAT_LZOP;
else {
@@ -3758,6 +3761,9 @@ static int qemudDomainSave(virDomainPtr dom,
else if (header.compressed == QEMUD_SAVE_FORMAT_LZMA)
internalret = virAsprintf(&command, "migrate \"exec:"
"lzma -c >> '%s' 2>/dev/null\"", safe_path);
+ else if (header.compressed == QEMUD_SAVE_FORMAT_XZ)
+ internalret = virAsprintf(&command, "migrate \"exec:"
+ "xz -c >> '%s' 2>/dev/null\"", safe_path);
else if (header.compressed == QEMUD_SAVE_FORMAT_LZOP)
internalret = virAsprintf(&command, "migrate \"exec:"
"lzop -c >> '%s' 2>/dev/null\"", safe_path);
@@ -4383,6 +4389,8 @@ static int qemudDomainRestore(virConnectPtr conn,
intermediate_argv[0] = "bzip2";
else if (header.compressed == QEMUD_SAVE_FORMAT_LZMA)
intermediate_argv[0] = "lzma";
+ else if (header.compressed == QEMUD_SAVE_FORMAT_XZ)
+ intermediate_argv[0] = "xz";
else if (header.compressed == QEMUD_SAVE_FORMAT_LZOP)
intermediate_argv[0] = "lzop";
else if (header.compressed != QEMUD_SAVE_FORMAT_RAW) {
--
1.6.5.rc0.164.g5f6b0
15 years, 2 months
[libvirt] [PATCH] Automagically check if libssh2 is new enough for Phyp-support to be build
by Maximilian Wilhelm
Hi!
My buildbot spotted a problem with the latest changes to Phyp, as the
function libssh2_session_block_directions() only is available with
libssh2 version 1.0 and later.
At least on Debian Lenny there is an older one which prevents libVirt
from building, so I updated the configure.in script to add another
piece of magic (and thereby fixed the indenation of the Phypchecks).
See attached patch.
Ciao
Max
--
"really soon now": an unspecified period of time, likly to
be greater than any reasonable definition
of "soon".
15 years, 2 months
[libvirt] HVM startup problem"unknown root elementi for storage pool"
by Andreas Sommer
Hi,
I'm having a problem with starting a HVM virtual machine on Xen-3.4 with
python-libvirt. This is the XML:
<?xml version="1.0" encoding="utf-8"?>
<domain type="xen">
<name>b07d6538-60f5-44a9-90e7-761304968e17</name>
<uuid>b07d6538-60f5-44a9-90e7-761304968e17</uuid>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<memory>131072</memory>
<vcpu>1</vcpu>
<os>
<type>hvm</type>
<boot dev="hd" />
</os>
<devices>
<graphics type="vnc" />
<input type="tablet" />
<interface type="bridge">
<source bridge="eth0" />
</interface>
<disk type="file">
<source file="/xen-hvm-test/disk0.img" />
<target dev="sda1" />
</disk>
</devices>
</domain>
Then I call
connection.createXML(libvirtXmlDescription, 0)
which leads to an exception "unknown root elementi for storage pool".
I'm using the Debian package "libvirt0" 0.4.6-10. I guess that's 0.6.4
actually, please tell me if that's a wrong assumption?? The 0.6.4 source
code seems to have corrected "elementi" to "element" that's why I'm
wondering which version I actually have.
Why does this happen? Is there anything missing in my XML description?
Best regards
15 years, 2 months
[libvirt] [PATCH] openvz_conf.c: remove dead store to "p"; use strchrnul
by Jim Meyering
I may separate this into two commits.
Currently we can't use the part that adds the strchrnul use,
since gnulib's module lists its license as LGPL, which
means LGPLv3+, and that conflicts with libvirt's LGPLv2+ requirement.
However, since strchrnul is derived from glibc, it should be easy
to adjust that. I've asked the maintainer of that module on the
bug-gnulib list. We'll see later today when the US wakes up.
>From b76bc73df65c793958ce646fd80763c19a9e4dbd Mon Sep 17 00:00:00 2001
From: Jim Meyering <meyering(a)redhat.com>
Date: Tue, 8 Sep 2009 11:07:32 +0200
Subject: [PATCH] openvz_conf.c: remove dead store to "p"; use strchrnul
* src/openvz_conf.c (openvzReadNetworkConf): Replace open-coded
while loop with equivalent use of strchrnul.
* bootstrap (modules): Add strchrnul.
---
bootstrap | 1 +
src/openvz_conf.c | 5 ++---
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/bootstrap b/bootstrap
index 8b81e0e..5560792 100755
--- a/bootstrap
+++ b/bootstrap
@@ -89,6 +89,7 @@ send
setsockopt
socket
stpcpy
+strchrnul
strndup
strerror
strsep
diff --git a/src/openvz_conf.c b/src/openvz_conf.c
index ce4fc6e..be94b9e 100644
--- a/src/openvz_conf.c
+++ b/src/openvz_conf.c
@@ -239,15 +239,14 @@ openvzReadNetworkConf(virConnectPtr conn,
net->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
- char *p = token, *next = token;
+ char *p = token;
char cpy_temp[32];
int len;
/*parse string*/
do {
- while (*next != '\0' && *next != ',') next++;
+ char *next = strchrnul (token, ',');
if (STRPREFIX(p, "ifname=")) {
- p += 7;
/* skip in libvirt */
} else if (STRPREFIX(p, "host_ifname=")) {
p += 12;
--
1.6.5.rc0.164.g5f6b0
15 years, 2 months
[libvirt] [PATCH] two syntax-check related updates
by Jim Meyering
These changes affect only "make syntax-check".
The first patch is clearing out now-useless or unnecessary exclusions.
The second enables one more test and fixes the few small
violations it spotted.
>From e4719bd092b03ef666d196ebc4b97086a7ecae98 Mon Sep 17 00:00:00 2001
From: Jim Meyering <meyering(a)redhat.com>
Date: Tue, 8 Sep 2009 15:08:07 +0200
Subject: [PATCH 1/2] build: syntax-check: exclude fewer tests
* cfg.mk (local-checks-to-skip): Don't skip tests that pass.
Remove names of renamed or removed tests.
---
cfg.mk | 14 --------------
1 files changed, 0 insertions(+), 14 deletions(-)
diff --git a/cfg.mk b/cfg.mk
index 64bd26e..79dcb81 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -26,31 +26,17 @@ url_dir_list = \
# Tests not to run as part of "make distcheck".
local-checks-to-skip = \
- changelog-check \
- check-AUTHORS \
- makefile-check \
- makefile_path_separator_check \
- patch-check \
sc_GPL_version \
- sc_always_defined_macros \
- sc_cast_of_alloca_return_value \
- sc_dd_max_sym_length \
sc_error_exit_success \
sc_file_system \
sc_immutable_NEWS \
sc_makefile_path_separator_check \
- sc_obsolete_symbols \
- sc_prohibit_S_IS_definition \
sc_prohibit_atoi_atof \
- sc_prohibit_jm_in_m4 \
sc_prohibit_quote_without_use \
sc_prohibit_quotearg_without_use \
sc_prohibit_stat_st_blocks \
- sc_root_tests \
sc_space_tab \
sc_sun_os_names \
- sc_system_h_headers \
- sc_tight_scope \
sc_two_space_separator_in_usage \
sc_error_message_uppercase \
sc_program_name \
--
1.6.5.rc0.164.g5f6b0
>From 7bf84b60be8603f226af6244a3e63335586555d6 Mon Sep 17 00:00:00 2001
From: Jim Meyering <meyering(a)redhat.com>
Date: Tue, 8 Sep 2009 15:24:46 +0200
Subject: [PATCH 2/2] build: no longer skip the makefile PATH separator check
* cfg.mk (local-checks-to-skip): Remove sc_makefile_path_separator_check.
* python/tests/Makefile.am (tests): Use $(PATH_SEPARATOR), not ":"
in shell search PATH definitions.
---
cfg.mk | 1 -
python/tests/Makefile.am | 23 +++++++++++++++--------
2 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/cfg.mk b/cfg.mk
index 79dcb81..7e152f8 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -30,7 +30,6 @@ local-checks-to-skip = \
sc_error_exit_success \
sc_file_system \
sc_immutable_NEWS \
- sc_makefile_path_separator_check \
sc_prohibit_atoi_atof \
sc_prohibit_quote_without_use \
sc_prohibit_quotearg_without_use \
diff --git a/python/tests/Makefile.am b/python/tests/Makefile.am
index 6011fef..11218a8 100644
--- a/python/tests/Makefile.am
+++ b/python/tests/Makefile.am
@@ -12,14 +12,21 @@ EXTRA_DIST = $(PYTESTS)
if WITH_PYTHON
tests: $(PYTESTS)
@echo "## running Python regression tests"
- -@(PYTHONPATH="..:../.libs:../src/.libs:$(srcdir)/../src:$$PYTHONPATH";\
- export PYTHONPATH; \
- LD_LIBRARY_PATH="$(top_builddir)/src/.libs:$$LD_LIBRARY_PATH" ; \
- export LD_LIBRARY_PATH; \
- for test in $(PYTESTS) ; \
- do log=`$(PYTHON) $(srcdir)/$$test` ; \
- if [ "`echo $$log | grep OK`" = "" ] ; then \
- echo "-- $$test" ; echo "$$log" ; fi ; done)
+ -@(p=..; \
+ -@(p="$$p$(PATH_SEPARATOR)../.libs"; \
+ p="$$p$(PATH_SEPARATOR)../src/.libs"; \
+ p="$$p$(PATH_SEPARATOR)$(srcdir)/../src"; \
+ p="$$p$(PATH_SEPARATOR)$$PYTHONPATH"; \
+ PYTHONPATH=$$p; export PYTHONPATH; \
+ p="$(top_builddir)/src/.libs"; \
+ p="$$p$(PATH_SEPARATOR)$$LD_LIBRARY_PATH"; \
+ LD_LIBRARY_PATH=$$p; export LD_LIBRARY_PATH; \
+ for test in $(PYTESTS); do \
+ log=`$(PYTHON) $(srcdir)/$$test`; \
+ if [ "`echo $$log | grep OK`" = "" ]; then \
+ echo "-- $$test"; echo "$$log"; \
+ fi; \
+ done)
else
tests:
endif
--
1.6.5.rc0.164.g5f6b0
15 years, 2 months
[libvirt] rebased multipath patch
by Dave Allan
Here's the multipath patch, rebased against the current head.
Dave
>From 52cb0ff30dd5a52c5a246f3a2022f933cd2a0eab Mon Sep 17 00:00:00 2001
From: David Allan <dallan(a)redhat.com>
Date: Tue, 21 Jul 2009 12:43:01 -0400
Subject: [PATCH] Add a simple pool type for multipath devices
This pool type contains volumes for the multipath devices that are present on the host. It does not (yet) support any sort of multipath configuration, so that aspect of system administration must still be done at host build time.
---
configure.in | 24 +++
po/POTFILES.in | 1 +
src/Makefile.am | 9 +
src/storage_backend.c | 82 ++++++++++
src/storage_backend.h | 5 +-
src/storage_backend_mpath.c | 352 +++++++++++++++++++++++++++++++++++++++++++
src/storage_backend_mpath.h | 31 ++++
src/storage_conf.c | 7 +-
src/storage_conf.h | 1 +
9 files changed, 510 insertions(+), 2 deletions(-)
create mode 100644 src/storage_backend_mpath.c
create mode 100644 src/storage_backend_mpath.h
diff --git a/configure.in b/configure.in
index d28c44a..7c93ab7 100644
--- a/configure.in
+++ b/configure.in
@@ -1046,6 +1046,8 @@ AC_ARG_WITH([storage-iscsi],
[ --with-storage-iscsi with iSCSI backend for the storage driver (on)],[],[with_storage_iscsi=check])
AC_ARG_WITH([storage-scsi],
[ --with-storage-scsi with SCSI backend for the storage driver (on)],[],[with_storage_scsi=check])
+AC_ARG_WITH([storage-mpath],
+[ --with-storage-mpath with mpath backend for the storage driver (on)],[],[with_storage_mpath=check])
AC_ARG_WITH([storage-disk],
[ --with-storage-disk with GPartd Disk backend for the storage driver (on)],[],[with_storage_disk=check])
@@ -1056,6 +1058,7 @@ if test "$with_libvirtd" = "no"; then
with_storage_lvm=no
with_storage_iscsi=no
with_storage_scsi=no
+ with_storage_mpath=no
with_storage_disk=no
fi
if test "$with_storage_dir" = "yes" ; then
@@ -1177,6 +1180,26 @@ if test "$with_storage_scsi" = "check"; then
fi
AM_CONDITIONAL([WITH_STORAGE_SCSI], [test "$with_storage_scsi" = "yes"])
+if test "$with_storage_mpath" = "check"; then
+ with_storage_mpath=yes
+
+ AC_DEFINE_UNQUOTED([WITH_STORAGE_MPATH], 1,
+ [whether mpath backend for storage driver is enabled])
+fi
+AM_CONDITIONAL([WITH_STORAGE_MPATH], [test "$with_storage_mpath" = "yes"])
+
+if test "$with_storage_mpath" = "yes"; then
+ DEVMAPPER_REQUIRED=0.0
+ DEVMAPPER_CFLAGS=
+ DEVMAPPER_LIBS=
+ PKG_CHECK_MODULES(DEVMAPPER, devmapper >= $DEVMAPPER_REQUIRED,
+ [], [
+ AC_MSG_ERROR(
+ [You must install device-mapper-devel >= $DEVMAPPER_REQUIRED to compile libvirt])
+ ])
+fi
+AC_SUBST([DEVMAPPER_CFLAGS])
+AC_SUBST([DEVMAPPER_LIBS])
LIBPARTED_CFLAGS=
LIBPARTED_LIBS=
@@ -1677,6 +1700,7 @@ AC_MSG_NOTICE([ NetFS: $with_storage_fs])
AC_MSG_NOTICE([ LVM: $with_storage_lvm])
AC_MSG_NOTICE([ iSCSI: $with_storage_iscsi])
AC_MSG_NOTICE([ SCSI: $with_storage_scsi])
+AC_MSG_NOTICE([ mpath: $with_storage_mpath])
AC_MSG_NOTICE([ Disk: $with_storage_disk])
AC_MSG_NOTICE([])
AC_MSG_NOTICE([Security Drivers])
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 0a53dab..1586368 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -38,6 +38,7 @@ src/storage_backend_fs.c
src/storage_backend_iscsi.c
src/storage_backend_logical.c
src/storage_backend_scsi.c
+src/storage_backend_mpath.c
src/storage_conf.c
src/storage_driver.c
src/storage_encryption_conf.c
diff --git a/src/Makefile.am b/src/Makefile.am
index bedeb84..cf3420b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -199,6 +199,9 @@ STORAGE_DRIVER_ISCSI_SOURCES = \
STORAGE_DRIVER_SCSI_SOURCES = \
storage_backend_scsi.h storage_backend_scsi.c
+STORAGE_DRIVER_MPATH_SOURCES = \
+ storage_backend_mpath.h storage_backend_mpath.c
+
STORAGE_DRIVER_DISK_SOURCES = \
storage_backend_disk.h storage_backend_disk.c
@@ -478,6 +481,10 @@ if WITH_STORAGE_SCSI
libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_SCSI_SOURCES)
endif
+if WITH_STORAGE_MPATH
+libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_MPATH_SOURCES)
+endif
+
if WITH_STORAGE_DISK
libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_DISK_SOURCES)
endif
@@ -539,6 +546,7 @@ EXTRA_DIST += \
$(STORAGE_DRIVER_LVM_SOURCES) \
$(STORAGE_DRIVER_ISCSI_SOURCES) \
$(STORAGE_DRIVER_SCSI_SOURCES) \
+ $(STORAGE_DRIVER_MPATH_SOURCES) \
$(STORAGE_DRIVER_DISK_SOURCES) \
$(NODE_DEVICE_DRIVER_SOURCES) \
$(NODE_DEVICE_DRIVER_HAL_SOURCES) \
@@ -607,6 +615,7 @@ libvirt_la_LDFLAGS = $(VERSION_SCRIPT_FLAGS)libvirt.syms \
$(COVERAGE_CFLAGS:-f%=-Wc,-f%) \
$(LIBXML_LIBS) $(SELINUX_LIBS) \
$(XEN_LIBS) $(DRIVER_MODULE_LIBS) \
+ $(DEVMAPPER_LIBS) \
@CYGWIN_EXTRA_LDFLAGS@ @MINGW_EXTRA_LDFLAGS@
libvirt_la_CFLAGS = $(COVERAGE_CFLAGS) -DIN_LIBVIRT
libvirt_la_DEPENDENCIES = $(libvirt_la_LIBADD) libvirt.syms
diff --git a/src/storage_backend.c b/src/storage_backend.c
index c818142..4dec06b 100644
--- a/src/storage_backend.c
+++ b/src/storage_backend.c
@@ -59,6 +59,9 @@
#if WITH_STORAGE_SCSI
#include "storage_backend_scsi.h"
#endif
+#if WITH_STORAGE_MPATH
+#include "storage_backend_mpath.h"
+#endif
#if WITH_STORAGE_DISK
#include "storage_backend_disk.h"
#endif
@@ -89,6 +92,9 @@ static virStorageBackendPtr backends[] = {
#if WITH_STORAGE_SCSI
&virStorageBackendSCSI,
#endif
+#if WITH_STORAGE_MPATH
+ &virStorageBackendMpath,
+#endif
#if WITH_STORAGE_DISK
&virStorageBackendDisk,
#endif
@@ -812,6 +818,82 @@ virStorageBackendUpdateVolTargetInfoFD(virConnectPtr conn,
return 0;
}
+
+struct diskType {
+ int part_table_type;
+ unsigned short offset;
+ unsigned short length;
+ unsigned long long magic;
+};
+
+
+static struct diskType const disk_types[] = {
+ { VIR_STORAGE_POOL_DISK_LVM2, 0x218, 8, 0x31303020324D564CULL },
+ { VIR_STORAGE_POOL_DISK_GPT, 0x200, 8, 0x5452415020494645ULL },
+ { VIR_STORAGE_POOL_DISK_DVH, 0x0, 4, 0x41A9E50BULL },
+ { VIR_STORAGE_POOL_DISK_MAC, 0x0, 2, 0x5245ULL },
+ { VIR_STORAGE_POOL_DISK_BSD, 0x40, 4, 0x82564557ULL },
+ { VIR_STORAGE_POOL_DISK_SUN, 0x1fc, 2, 0xBEDAULL },
+ /*
+ * NOTE: pc98 is funky; the actual signature is 0x55AA (just like dos), so
+ * we can't use that. At the moment I'm relying on the "dummy" IPL
+ * bootloader data that comes from parted. Luckily, the chances of running
+ * into a pc98 machine running libvirt are approximately nil.
+ */
+ /*{ 0x1fe, 2, 0xAA55UL },*/
+ { VIR_STORAGE_POOL_DISK_PC98, 0x0, 8, 0x314C5049000000CBULL },
+ /*
+ * NOTE: the order is important here; some other disk types (like GPT and
+ * and PC98) also have 0x55AA at this offset. For that reason, the DOS
+ * one must be the last one.
+ */
+ { VIR_STORAGE_POOL_DISK_DOS, 0x1fe, 2, 0xAA55ULL },
+ { -1, 0x0, 0, 0x0ULL },
+};
+
+
+int
+virStorageBackendUpdateVolTargetFormatFD(virConnectPtr conn,
+ virStorageVolTargetPtr target,
+ int fd)
+{
+ int i;
+ off_t start;
+ unsigned char buffer[1024];
+ ssize_t bytes;
+
+ /* make sure to set the target format "unknown" to begin with */
+ target->format = VIR_STORAGE_POOL_DISK_UNKNOWN;
+
+ start = lseek(fd, 0, SEEK_SET);
+ if (start < 0) {
+ virReportSystemError(conn, errno,
+ _("cannot seek to beginning of file '%s'"),
+ target->path);
+ return -1;
+ }
+ bytes = saferead(fd, buffer, sizeof(buffer));
+ if (bytes < 0) {
+ virReportSystemError(conn, errno,
+ _("cannot read beginning of file '%s'"),
+ target->path);
+ return -1;
+ }
+
+ for (i = 0; disk_types[i].part_table_type != -1; i++) {
+ if (disk_types[i].offset + disk_types[i].length > bytes)
+ continue;
+ if (memcmp(buffer+disk_types[i].offset, &disk_types[i].magic,
+ disk_types[i].length) == 0) {
+ target->format = disk_types[i].part_table_type;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
void virStorageBackendWaitForDevices(virConnectPtr conn)
{
virWaitForDevices(conn);
diff --git a/src/storage_backend.h b/src/storage_backend.h
index e80b05d..eb5bf87 100644
--- a/src/storage_backend.h
+++ b/src/storage_backend.h
@@ -91,7 +91,10 @@ int virStorageBackendUpdateVolTargetInfoFD(virConnectPtr conn,
int fd,
unsigned long long *allocation,
unsigned long long *capacity);
-
+int
+virStorageBackendUpdateVolTargetFormatFD(virConnectPtr conn,
+ virStorageVolTargetPtr target,
+ int fd);
void virStorageBackendWaitForDevices(virConnectPtr conn);
char *virStorageBackendStablePath(virConnectPtr conn,
diff --git a/src/storage_backend_mpath.c b/src/storage_backend_mpath.c
new file mode 100644
index 0000000..41dadf1
--- /dev/null
+++ b/src/storage_backend_mpath.c
@@ -0,0 +1,352 @@
+/*
+ * storage_backend_mpath.c: storage backend for multipath handling
+ *
+ * Copyright (C) 2007-2008 Red Hat, Inc.
+ * Copyright (C) 2007-2008 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange redhat com>
+ */
+
+#include <config.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <fcntl.h>
+
+#include <libdevmapper.h>
+
+#include "virterror_internal.h"
+#include "storage_conf.h"
+#include "storage_backend.h"
+#include "memory.h"
+#include "logging.h"
+
+#define VIR_FROM_THIS VIR_FROM_STORAGE
+
+static int
+virStorageBackendMpathUpdateVolTargetInfo(virConnectPtr conn,
+ virStorageVolTargetPtr target,
+ unsigned long long *allocation,
+ unsigned long long *capacity)
+{
+ int ret = 0;
+ int fd = -1;
+
+ if ((fd = open(target->path, O_RDONLY)) < 0) {
+ virReportSystemError(conn, errno,
+ _("cannot open volume '%s'"),
+ target->path);
+ ret = -1;
+ goto out;
+ }
+
+ if (virStorageBackendUpdateVolTargetInfoFD(conn,
+ target,
+ fd,
+ allocation,
+ capacity) < 0) {
+
+ VIR_ERROR(_("Failed to update volume target info for %s"),
+ target->path);
+
+ ret = -1;
+ goto out;
+ }
+
+ if (virStorageBackendUpdateVolTargetFormatFD(conn,
+ target,
+ fd) < 0) {
+ VIR_ERROR(_("Failed to update volume target format for %s"),
+ target->path);
+
+ ret = -1;
+ goto out;
+ }
+
+out:
+ if (fd != -1) {
+ close(fd);
+ }
+ return ret;
+}
+
+
+static int
+virStorageBackendMpathNewVol(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ const int devnum,
+ const char *dev)
+{
+ virStorageVolDefPtr vol;
+ int retval = 0;
+
+ if (VIR_ALLOC(vol) < 0) {
+ virReportOOMError(conn);
+ retval = -1;
+ goto out;
+ }
+
+ vol->type = VIR_STORAGE_VOL_BLOCK;
+
+ if (virAsprintf(&(vol->name), "dm-%u", devnum) < 0) {
+ virReportOOMError(conn);
+ retval = -1;
+ goto free_vol;
+ }
+
+ if (virAsprintf(&vol->target.path, "/dev/%s", dev) < 0) {
+ virReportOOMError(conn);
+ retval = -1;
+ goto free_vol;
+ }
+
+ if (virStorageBackendMpathUpdateVolTargetInfo(conn,
+ &vol->target,
+ &vol->allocation,
+ &vol->capacity) < 0) {
+
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Failed to update volume for '%s'"),
+ vol->target.path);
+ retval = -1;
+ goto free_vol;
+ }
+
+ /* XXX should use logical unit's UUID instead */
+ vol->key = strdup(vol->target.path);
+ if (vol->key == NULL) {
+ virReportOOMError(conn);
+ retval = -1;
+ goto free_vol;
+ }
+
+ pool->def->capacity += vol->capacity;
+ pool->def->allocation += vol->allocation;
+
+ if (VIR_REALLOC_N(pool->volumes.objs,
+ pool->volumes.count + 1) < 0) {
+ virReportOOMError(conn);
+ retval = -1;
+ goto free_vol;
+ }
+ pool->volumes.objs[pool->volumes.count++] = vol;
+
+ goto out;
+
+free_vol:
+ virStorageVolDefFree(vol);
+out:
+ return retval;
+}
+
+
+static int
+virStorageBackendIsMultipath(const char *devname)
+{
+ int ret = 0;
+ struct dm_task *dmt = NULL;
+ void *next = NULL;
+ uint64_t start, length;
+ char *target_type = NULL;
+ char *params = NULL;
+
+ dmt = dm_task_create(DM_DEVICE_TABLE);
+ if (dmt == NULL) {
+ ret = -1;
+ goto out;
+ }
+
+ if (dm_task_set_name(dmt, devname) == 0) {
+ ret = -1;
+ goto out;
+ }
+
+ dm_task_no_open_count(dmt);
+
+ if (!dm_task_run(dmt)) {
+ ret = -1;
+ goto out;
+ }
+
+ next = dm_get_next_target(dmt, next, &start, &length,
+ &target_type, ¶ms);
+
+ if (target_type == NULL) {
+ ret = -1;
+ goto out;
+ }
+
+ if (!(strcmp(target_type, "multipath"))) {
+ ret = 1;
+ }
+
+out:
+ if (dmt != NULL) {
+ dm_task_destroy(dmt);
+ }
+ return ret;
+}
+
+
+static int
+virStorageBackendGetMinorNumber(const char *devname, uint32_t *minor)
+{
+ int ret = -1;
+ struct dm_task *dmt;
+ struct dm_info info;
+
+ if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
+ goto out;
+ }
+
+ if (!dm_task_set_name(dmt, devname)) {
+ goto out;
+ }
+
+ if (!dm_task_run(dmt)) {
+ goto out;
+ }
+
+ if (!dm_task_get_info(dmt, &info)) {
+ goto out;
+ }
+
+ *minor = info.minor;
+ ret = 0;
+
+out:
+ if (dmt != NULL) {
+ dm_task_destroy(dmt);
+ }
+
+ return ret;
+}
+
+
+static int
+virStorageBackendCreateVols(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ struct dm_names *names)
+{
+ int retval = 0, is_mpath = 0;
+ char *map_device = NULL;
+ uint32_t minor = -1;
+
+ do {
+ is_mpath = virStorageBackendIsMultipath(names->name);
+
+ if (is_mpath < 0) {
+ retval = -1;
+ goto out;
+ }
+
+ if (is_mpath == 1) {
+
+ if (virAsprintf(&map_device, "mapper/%s", names->name) < 0) {
+ virReportOOMError(conn);
+ retval = -1;
+ goto out;
+ }
+
+ if (virStorageBackendGetMinorNumber(names->name, &minor) < 0) {
+ retval = -1;
+ goto out;
+ }
+
+ virStorageBackendMpathNewVol(conn,
+ pool,
+ minor,
+ map_device);
+
+ VIR_FREE(map_device);
+ }
+
+ /* Given the way libdevmapper returns its data, I don't see
+ * any way to avoid this series of casts. */
+ names = (struct dm_names *)(((char *)names) + names->next);
+
+ } while (names->next);
+
+out:
+ return retval;
+}
+
+
+static int
+virStorageBackendGetMaps(virConnectPtr conn,
+ virStoragePoolObjPtr pool)
+{
+ int retval = 0;
+ struct dm_task *dmt = NULL;
+ struct dm_names *names = NULL;
+
+ if (!(dmt = dm_task_create(DM_DEVICE_LIST))) {
+ retval = 1;
+ goto out;
+ }
+
+ dm_task_no_open_count(dmt);
+
+ if (!dm_task_run(dmt)) {
+ retval = 1;
+ goto out;
+ }
+
+ if (!(names = dm_task_get_names(dmt))) {
+ retval = 1;
+ goto out;
+ }
+
+ if (!names->dev) {
+ /* No devices found */
+ goto out;
+ }
+
+ virStorageBackendCreateVols(conn, pool, names);
+
+out:
+ if (dmt != NULL) {
+ dm_task_destroy (dmt);
+ }
+ return retval;
+}
+
+
+static int
+virStorageBackendMpathRefreshPool(virConnectPtr conn,
+ virStoragePoolObjPtr pool)
+{
+ int retval = 0;
+
+ VIR_ERROR(_("in %s"), __func__);
+
+ pool->def->allocation = pool->def->capacity = pool->def->available = 0;
+
+ virStorageBackendWaitForDevices(conn);
+
+ virStorageBackendGetMaps(conn, pool);
+
+ return retval;
+}
+
+
+virStorageBackend virStorageBackendMpath = {
+ .type = VIR_STORAGE_POOL_MPATH,
+
+ .refreshPool = virStorageBackendMpathRefreshPool,
+};
diff --git a/src/storage_backend_mpath.h b/src/storage_backend_mpath.h
new file mode 100644
index 0000000..9de2b79
--- /dev/null
+++ b/src/storage_backend_mpath.h
@@ -0,0 +1,31 @@
+/*
+ * storage_backend_scsi.h: storage backend for SCSI handling
+ *
+ * Copyright (C) 2007-2008 Red Hat, Inc.
+ * Copyright (C) 2007-2008 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange redhat com>
+ */
+
+#ifndef __VIR_STORAGE_BACKEND_MPATH_H__
+#define __VIR_STORAGE_BACKEND_MPATH_H__
+
+#include "storage_backend.h"
+
+extern virStorageBackend virStorageBackendMpath;
+
+#endif /* __VIR_STORAGE_BACKEND_MPATH_H__ */
diff --git a/src/storage_conf.c b/src/storage_conf.c
index c446069..af04080 100644
--- a/src/storage_conf.c
+++ b/src/storage_conf.c
@@ -53,7 +53,7 @@ VIR_ENUM_IMPL(virStoragePool,
VIR_STORAGE_POOL_LAST,
"dir", "fs", "netfs",
"logical", "disk", "iscsi",
- "scsi")
+ "scsi", "mpath")
VIR_ENUM_IMPL(virStoragePoolFormatFileSystem,
VIR_STORAGE_POOL_FS_LAST,
@@ -198,6 +198,11 @@ static virStoragePoolTypeInfo poolTypeInfo[] = {
.formatToString = virStoragePoolFormatDiskTypeToString,
}
},
+ { .poolType = VIR_STORAGE_POOL_MPATH,
+ .volOptions = {
+ .formatToString = virStoragePoolFormatDiskTypeToString,
+ }
+ },
{ .poolType = VIR_STORAGE_POOL_DISK,
.poolOptions = {
.flags = (VIR_STORAGE_POOL_SOURCE_DEVICE),
diff --git a/src/storage_conf.h b/src/storage_conf.h
index bcf9b93..421d305 100644
--- a/src/storage_conf.h
+++ b/src/storage_conf.h
@@ -119,6 +119,7 @@ enum virStoragePoolType {
VIR_STORAGE_POOL_DISK, /* Disk partitions */
VIR_STORAGE_POOL_ISCSI, /* iSCSI targets */
VIR_STORAGE_POOL_SCSI, /* SCSI HBA */
+ VIR_STORAGE_POOL_MPATH, /* Multipath devices */
VIR_STORAGE_POOL_LAST,
};
--
1.6.0.6
15 years, 2 months