[libvirt] PATCH 4/5: add virConnectClone operation

Daniel P. Berrange berrange at redhat.com
Tue Dec 9 12:24:08 UTC 2008


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 :|




More information about the libvir-list mailing list