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 :| -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list