This patch is a slightly incomplete attempt to add a new virConectClone
operation to the public API. I includes the public API, the internal
driver methods, and implementation for the test & remote drivers. Still
todo is the Xen driver (needs thread-safety for Xen privte data access)
and QEMU/LXC/OpenVZ/UML drivers (trivial, since they're already thread
safe).
The basic scheme of things is
virConnectPtr conn = virConnectOpen(...some URI...)
....now I want to create a background thread...
virConnectPtr copy = virConnectClone(conn);
.... all done with thread..
virConnectClose(copy);
virConnectClose(conn);
ie, you must call virConnectClose as usual for all clones. The internal
data will only be released once all copies are released. There is nothing
special about the first original virConnectPtr - all clones are identical
and indistinguishable.
Daniel
diff --git a/include/libvirt/libvirt.h b/include/libvirt/libvirt.h
--- a/include/libvirt/libvirt.h
+++ b/include/libvirt/libvirt.h
@@ -396,6 +396,7 @@ virConnectPtr virConnectOpenAu
virConnectPtr virConnectOpenAuth (const char *name,
virConnectAuthPtr auth,
int flags);
+virConnectPtr virConnectClone (virConnectPtr conn);
int virConnectClose (virConnectPtr conn);
const char * virConnectGetType (virConnectPtr conn);
int virConnectGetVersion (virConnectPtr conn,
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -396,6 +396,7 @@ virConnectPtr virConnectOpenAu
virConnectPtr virConnectOpenAuth (const char *name,
virConnectAuthPtr auth,
int flags);
+virConnectPtr virConnectClone (virConnectPtr conn);
int virConnectClose (virConnectPtr conn);
const char * virConnectGetType (virConnectPtr conn);
int virConnectGetVersion (virConnectPtr conn,
diff --git a/src/driver.h b/src/driver.h
--- a/src/driver.h
+++ b/src/driver.h
@@ -74,6 +74,9 @@ typedef virDrvOpenStatus
(*virDrvOpen) (virConnectPtr conn,
virConnectAuthPtr auth,
int flags);
+typedef int
+ (*virDrvClone)(virConnectPtr conn,
+ virConnectPtr copied);
typedef int
(*virDrvClose) (virConnectPtr conn);
typedef int
@@ -329,6 +332,7 @@ struct _virDriver {
int no; /* the number virDrvNo */
const char * name; /* the name of the driver */
virDrvOpen open;
+ virDrvClone clone;
virDrvClose close;
virDrvDrvSupportsFeature supports_feature;
virDrvGetType type;
@@ -448,6 +452,7 @@ struct _virNetworkDriver {
struct _virNetworkDriver {
const char * name; /* the name of the driver */
virDrvOpen open;
+ virDrvClone clone;
virDrvClose close;
virDrvNumOfNetworks numOfNetworks;
virDrvListNetworks listNetworks;
@@ -582,6 +587,7 @@ struct _virStorageDriver {
struct _virStorageDriver {
const char * name; /* the name of the driver */
virDrvOpen open;
+ virDrvClone clone;
virDrvClose close;
virDrvConnectNumOfStoragePools numOfPools;
@@ -672,6 +678,7 @@ struct _virDeviceMonitor {
struct _virDeviceMonitor {
const char * name; /* the name of the driver */
virDrvOpen open;
+ virDrvClone clone;
virDrvClose close;
virDevMonNumOfDevices numOfDevices;
virDevMonListDevices listDevices;
diff --git a/src/libvirt.c b/src/libvirt.c
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -1033,6 +1033,79 @@ virConnectOpenAuth(const char *name,
DEBUG("name=%s, auth=%p, flags=%d", name, auth, flags);
return do_open (name, auth, flags);
}
+
+
+virConnectPtr
+virConnectClone(virConnectPtr conn)
+{
+ virConnectPtr ret;
+ DEBUG("conn=%p", conn);
+
+ ret = virGetConnect();
+ if (ret == NULL)
+ return NULL;
+
+ /* We are required to have clone support in
+ * every driver that's active for this to work
+ */
+ if (!conn->driver->clone ||
+ (conn->networkDriver && !conn->networkDriver->clone) ||
+ (conn->storageDriver && !conn->storageDriver->clone) ||
+ (conn->deviceMonitor && !conn->deviceMonitor->clone)) {
+ virLibConnError(NULL, VIR_ERR_NO_SUPPORT,
+ _("clone not supported for this driver"));
+ return NULL;
+ }
+
+ /*
+ * Don't allow changing flags, because that could
+ * allow user to evade read-only restrictions
+ */
+ ret->flags = conn->flags;
+
+ ret->driver = conn->driver;
+ ret->networkDriver = conn->networkDriver;
+ ret->storageDriver = conn->storageDriver;
+ ret->deviceMonitor = conn->deviceMonitor;
+
+ if (ret->driver->clone(conn, ret) < 0)
+ goto error;
+ if (ret->networkDriver &&
+ ret->networkDriver->clone(conn, ret) < 0)
+ goto error;
+ if (ret->storageDriver &&
+ ret->storageDriver->clone(conn, ret) < 0)
+ goto error;
+ if (ret->deviceMonitor &&
+ ret->deviceMonitor->clone(conn, ret) < 0)
+ goto error;
+
+ return ret;
+
+error:
+ if (ret->deviceMonitor &&
+ ret->deviceMonitor->close &&
+ ret->devMonPrivateData)
+ ret->deviceMonitor->close(ret);
+
+ if (ret->storageDriver &&
+ ret->storageDriver->close &&
+ ret->storagePrivateData)
+ ret->storageDriver->close(ret);
+
+ if (ret->networkDriver &&
+ ret->networkDriver->close &&
+ ret->networkPrivateData)
+ ret->networkDriver->close(ret);
+
+ if (ret->privateData &&
+ ret->driver->close)
+ ret->driver->close(ret);
+
+ virUnrefConnect(ret);
+ return NULL;
+}
+
/**
* virConnectClose:
diff --git a/src/libvirt_sym.version.in b/src/libvirt_sym.version.in
--- a/src/libvirt_sym.version.in
+++ b/src/libvirt_sym.version.in
@@ -249,9 +249,12 @@ LIBVIRT_0.5.0 {
} LIBVIRT_0.4.5;
-/* no new entry point in 0.5.1 */
+LIBVIRT_0.5.2 {
+ global:
+ virConnectClone;
+} LIBVIRT_0.5.0;
+
/* .... define new API here using predicted next version number .... */
-
diff --git a/src/lxc_driver.c b/src/lxc_driver.c
--- a/src/lxc_driver.c
+++ b/src/lxc_driver.c
@@ -1391,6 +1391,7 @@ static virDriver lxcDriver = {
VIR_DRV_LXC, /* the number virDrvNo */
"LXC", /* the name of the driver */
lxcOpen, /* open */
+ NULL, /* clone */
lxcClose, /* close */
NULL, /* supports_feature */
NULL, /* type */
diff --git a/src/network_driver.c b/src/network_driver.c
--- a/src/network_driver.c
+++ b/src/network_driver.c
@@ -1275,6 +1275,7 @@ static virNetworkDriver networkDriver =
static virNetworkDriver networkDriver = {
"Network",
networkOpenNetwork, /* open */
+ NULL, /* clone */
networkCloseNetwork, /* close */
networkNumNetworks, /* numOfNetworks */
networkListNetworks, /* listNetworks */
diff --git a/src/openvz_driver.c b/src/openvz_driver.c
--- a/src/openvz_driver.c
+++ b/src/openvz_driver.c
@@ -1247,6 +1247,7 @@ static virDriver openvzDriver = {
VIR_DRV_OPENVZ,
"OPENVZ",
openvzOpen, /* open */
+ NULL, /* clone */
openvzClose, /* close */
NULL, /* supports_feature */
openvzGetType, /* type */
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -4149,6 +4149,7 @@ static virDriver qemuDriver = {
VIR_DRV_QEMU,
"QEMU",
qemudOpen, /* open */
+ NULL, /* clone */
qemudClose, /* close */
qemudSupportsFeature, /* supports_feature */
qemudGetType, /* type */
diff --git a/src/remote_internal.c b/src/remote_internal.c
--- a/src/remote_internal.c
+++ b/src/remote_internal.c
@@ -1202,6 +1202,18 @@ verify_certificate (virConnectPtr conn A
/*----------------------------------------------------------------------*/
+static int
+remoteClone(virConnectPtr conn, virConnectPtr copied)
+{
+ struct private_data *priv = conn->privateData;
+
+ remoteDriverLock(priv);
+ priv->localUses++;
+ copied->privateData = priv;
+ remoteDriverUnlock(priv);
+
+ return 0;
+}
static int
doRemoteClose (virConnectPtr conn, struct private_data *priv)
@@ -3037,6 +3049,19 @@ remoteNetworkOpen (virConnectPtr conn,
}
static int
+remoteNetworkClone(virConnectPtr conn, virConnectPtr copied)
+{
+ struct private_data *priv = conn->networkPrivateData;
+
+ remoteDriverLock(priv);
+ priv->localUses++;
+ copied->networkPrivateData = priv;
+ remoteDriverUnlock(priv);
+
+ return 0;
+}
+
+static int
remoteNetworkClose (virConnectPtr conn)
{
int rv = 0;
@@ -3542,6 +3567,20 @@ remoteStorageOpen (virConnectPtr conn,
return ret;
}
}
+
+static int
+remoteStorageClone(virConnectPtr conn, virConnectPtr copied)
+{
+ struct private_data *priv = conn->storagePrivateData;
+
+ remoteDriverLock(priv);
+ priv->localUses++;
+ copied->storagePrivateData = priv;
+ remoteDriverUnlock(priv);
+
+ return 0;
+}
+
static int
remoteStorageClose (virConnectPtr conn)
@@ -4489,6 +4528,20 @@ remoteDevMonOpen(virConnectPtr conn,
return ret;
}
}
+
+static int
+remoteDevMonClone(virConnectPtr conn, virConnectPtr copied)
+{
+ struct private_data *priv = conn->devMonPrivateData;
+
+ remoteDriverLock(priv);
+ priv->localUses++;
+ copied->devMonPrivateData = priv;
+ remoteDriverUnlock(priv);
+
+ return 0;
+}
+
static int remoteDevMonClose(virConnectPtr conn)
{
@@ -6065,6 +6118,7 @@ static virDriver driver = {
.no = VIR_DRV_REMOTE,
.name = "remote",
.open = remoteOpen,
+ .clone = remoteClone,
.close = remoteClose,
.supports_feature = remoteSupportsFeature,
.type = remoteType,
@@ -6127,6 +6181,7 @@ static virNetworkDriver network_driver =
static virNetworkDriver network_driver = {
.name = "remote",
.open = remoteNetworkOpen,
+ .clone = remoteNetworkClone,
.close = remoteNetworkClose,
.numOfNetworks = remoteNumOfNetworks,
.listNetworks = remoteListNetworks,
@@ -6148,6 +6203,7 @@ static virStorageDriver storage_driver =
static virStorageDriver storage_driver = {
.name = "remote",
.open = remoteStorageOpen,
+ .clone = remoteStorageClone,
.close = remoteStorageClose,
.numOfPools = remoteNumOfStoragePools,
.listPools = remoteListStoragePools,
@@ -6185,6 +6241,7 @@ static virDeviceMonitor dev_monitor = {
static virDeviceMonitor dev_monitor = {
.name = "remote",
.open = remoteDevMonOpen,
+ .clone = remoteDevMonClone,
.close = remoteDevMonClose,
.numOfDevices = remoteNodeNumOfDevices,
.listDevices = remoteNodeListDevices,
diff --git a/src/storage_driver.c b/src/storage_driver.c
--- a/src/storage_driver.c
+++ b/src/storage_driver.c
@@ -1462,6 +1462,7 @@ static virStorageDriver storageDriver =
static virStorageDriver storageDriver = {
.name = "storage",
.open = storageOpen,
+ .clone = NULL,
.close = storageClose,
.numOfPools = storageNumPools,
.listPools = storageListPools,
diff --git a/src/test.c b/src/test.c
--- a/src/test.c
+++ b/src/test.c
@@ -59,6 +59,7 @@ typedef struct _testCell *testCellPtr;
struct _testConn {
PTHREAD_MUTEX_T(lock);
+ int refs;
char path[PATH_MAX];
int nextDomID;
@@ -214,6 +215,7 @@ static int testOpenDefault(virConnectPtr
conn->privateData = privconn;
pthread_mutex_init(&privconn->lock, NULL);
testDriverLock(privconn);
+ privconn->refs = 1;
if (gettimeofday(&tv, NULL) < 0) {
testError(NULL, VIR_ERR_INTERNAL_ERROR, "%s", _("getting time of
day"));
@@ -331,6 +333,7 @@ static int testOpenFromFile(virConnectPt
conn->privateData = privconn;
pthread_mutex_init(&privconn->lock, NULL);
testDriverLock(privconn);
+ privconn->refs = 1;
if (!(privconn->caps = testBuildCapabilities(conn)))
goto error;
@@ -627,18 +630,38 @@ static int testOpen(virConnectPtr conn,
return (ret);
}
-static int testClose(virConnectPtr conn)
+static int testClone(virConnectPtr conn,
+ virConnectPtr copied)
{
testConnPtr privconn = conn->privateData;
testDriverLock(privconn);
+ privconn->refs++;
+ copied->privateData = conn->privateData;
+ testDriverUnlock(privconn);
+ return 0;
+}
+
+static void testRelease(testConnPtr privconn)
+{
virCapabilitiesFree(privconn->caps);
virDomainObjListFree(&privconn->domains);
virNetworkObjListFree(&privconn->networks);
virStoragePoolObjListFree(&privconn->pools);
testDriverUnlock(privconn);
+ VIR_FREE (privconn);
+}
- VIR_FREE (privconn);
- conn->privateData = NULL;
+static int testClose(virConnectPtr conn)
+{
+ testConnPtr privconn = conn->privateData;
+ testDriverLock(privconn);
+ privconn->refs--;
+ if (privconn->refs) {
+ testDriverUnlock(privconn);
+ } else {
+ testRelease(privconn);
+ conn->privateData = NULL;
+ }
return 0;
}
@@ -1751,15 +1774,39 @@ static virDrvOpenStatus testOpenNetwork(
static virDrvOpenStatus testOpenNetwork(virConnectPtr conn,
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
int flags ATTRIBUTE_UNUSED) {
+ testConnPtr privconn = conn->privateData;
if (STRNEQ(conn->driver->name, "Test"))
return VIR_DRV_OPEN_DECLINED;
- conn->networkPrivateData = conn->privateData;
+ testDriverLock(privconn);
+ privconn->refs++;
+ conn->networkPrivateData = privconn;
+ testDriverUnlock(privconn);
+
return VIR_DRV_OPEN_SUCCESS;
}
+static int testCloneNetwork(virConnectPtr conn,
+ virConnectPtr copied)
+{
+ testConnPtr privconn = conn->networkPrivateData;
+ testDriverLock(privconn);
+ privconn->refs++;
+ copied->networkPrivateData = conn->networkPrivateData;
+ testDriverUnlock(privconn);
+ return 0;
+}
+
static int testCloseNetwork(virConnectPtr conn) {
- conn->networkPrivateData = NULL;
+ testConnPtr privconn = conn->networkPrivateData;
+ testDriverLock(privconn);
+ privconn->refs--;
+ if (privconn->refs) {
+ testDriverUnlock(privconn);
+ } else {
+ testRelease(privconn);
+ conn->networkPrivateData = NULL;
+ }
return 0;
}
@@ -2167,17 +2214,42 @@ static virDrvOpenStatus testStorageOpen(
static virDrvOpenStatus testStorageOpen(virConnectPtr conn,
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
int flags ATTRIBUTE_UNUSED) {
+ testConnPtr privconn = conn->privateData;
if (STRNEQ(conn->driver->name, "Test"))
return VIR_DRV_OPEN_DECLINED;
- conn->storagePrivateData = conn->privateData;
+ testDriverLock(privconn);
+ privconn->refs++;
+ conn->storagePrivateData = privconn;
+ testDriverUnlock(privconn);
+
return VIR_DRV_OPEN_SUCCESS;
}
-static int testStorageClose(virConnectPtr conn) {
- conn->storagePrivateData = NULL;
+static int testStorageClone(virConnectPtr conn,
+ virConnectPtr copied)
+{
+ testConnPtr privconn = conn->storagePrivateData;
+ testDriverLock(privconn);
+ privconn->refs++;
+ copied->storagePrivateData = conn->storagePrivateData;
+ testDriverUnlock(privconn);
return 0;
}
+
+static int testStorageClose(virConnectPtr conn) {
+ testConnPtr privconn = conn->storagePrivateData;
+ testDriverLock(privconn);
+ privconn->refs--;
+ if (privconn->refs) {
+ testDriverUnlock(privconn);
+ } else {
+ testRelease(privconn);
+ conn->storagePrivateData = NULL;
+ }
+ return 0;
+}
+
static virStoragePoolPtr
testStoragePoolLookupByUUID(virConnectPtr conn,
@@ -3221,23 +3293,47 @@ static virDrvOpenStatus testDevMonOpen(v
static virDrvOpenStatus testDevMonOpen(virConnectPtr conn,
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
int flags ATTRIBUTE_UNUSED) {
+ testConnPtr privconn = conn->privateData;
if (STRNEQ(conn->driver->name, "Test"))
return VIR_DRV_OPEN_DECLINED;
- conn->devMonPrivateData = conn->privateData;
+ testDriverLock(privconn);
+ privconn->refs++;
+ conn->devMonPrivateData = privconn;
+ testDriverUnlock(privconn);
+
return VIR_DRV_OPEN_SUCCESS;
}
-static int testDevMonClose(virConnectPtr conn) {
- conn->devMonPrivateData = NULL;
+static int testDevMonClone(virConnectPtr conn,
+ virConnectPtr copied)
+{
+ testConnPtr privconn = conn->devMonPrivateData;
+ testDriverLock(privconn);
+ privconn->refs++;
+ copied->devMonPrivateData = conn->devMonPrivateData;
+ testDriverUnlock(privconn);
return 0;
}
+static int testDevMonClose(virConnectPtr conn) {
+ testConnPtr privconn = conn->devMonPrivateData;
+ testDriverLock(privconn);
+ privconn->refs--;
+ if (privconn->refs) {
+ testDriverUnlock(privconn);
+ } else {
+ testRelease(privconn);
+ conn->devMonPrivateData = NULL;
+ }
+ return 0;
+}
static virDriver testDriver = {
VIR_DRV_TEST,
"Test",
testOpen, /* open */
+ testClone, /* clone */
testClose, /* close */
NULL, /* supports_feature */
NULL, /* type */
@@ -3301,6 +3397,7 @@ static virNetworkDriver testNetworkDrive
static virNetworkDriver testNetworkDriver = {
"Test",
testOpenNetwork, /* open */
+ testCloneNetwork, /* clone */
testCloseNetwork, /* close */
testNumNetworks, /* numOfNetworks */
testListNetworks, /* listNetworks */
@@ -3322,6 +3419,7 @@ static virStorageDriver testStorageDrive
static virStorageDriver testStorageDriver = {
.name = "Test",
.open = testStorageOpen,
+ .clone = testStorageClone,
.close = testStorageClose,
.numOfPools = testStorageNumPools,
@@ -3360,6 +3458,7 @@ static virDeviceMonitor testDevMonitor =
static virDeviceMonitor testDevMonitor = {
.name = "Test",
.open = testDevMonOpen,
+ .clone = testDevMonClone,
.close = testDevMonClose,
};
diff --git a/src/uml_driver.c b/src/uml_driver.c
--- a/src/uml_driver.c
+++ b/src/uml_driver.c
@@ -1812,6 +1812,7 @@ static virDriver umlDriver = {
VIR_DRV_UML,
"UML",
umlOpen, /* open */
+ NULL, /* clone */
umlClose, /* close */
NULL, /* supports_feature */
umlGetType, /* type */
diff --git a/src/xen_unified.c b/src/xen_unified.c
--- a/src/xen_unified.c
+++ b/src/xen_unified.c
@@ -1399,6 +1399,7 @@ static virDriver xenUnifiedDriver = {
.no = VIR_DRV_XEN_UNIFIED,
.name = "Xen",
.open = xenUnifiedOpen,
+ .clone = NULL,
.close = xenUnifiedClose,
.supports_feature = xenUnifiedSupportsFeature,
.type = xenUnifiedType,
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org -o-
http://ovirt.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|