[libvirt] [PATCH v3 0/8] add close callback for drivers with persistent connection

Currently close callback API can only inform us of closing the connection between remote driver and daemon. But what if a driver running in the daemon itself can have another persistent connection? In this case we want to be informed of that connection changes state too. This patch series extends meaning of current close callback API so that now it notifies of closing of any internal persistent connection. The overall approach is to move close callback support to drivers. Changes from v2: Split patches further to make it more comprehensible. Nikolay Shirokovskiy (8): factor out virConnectCloseCallbackDataPtr methods virConnectCloseCallbackData: fix connection object refcount virConnectCloseCallbackData: factor out callback disarming close callback API: remove unnecessary locks virConnectCloseCallbackDataDispose: remove unnecessary locks close callback: move it to driver daemon: add connection close rpc vz: implement connection close notification daemon/libvirtd.h | 1 + daemon/remote.c | 84 ++++++++++++++++++++++++++++++++ po/POTFILES.in | 1 + src/datatypes.c | 113 +++++++++++++++++++++++++++++++++---------- src/datatypes.h | 11 +++++ src/driver-hypervisor.h | 12 +++++ src/libvirt-host.c | 46 ++---------------- src/remote/remote_driver.c | 106 ++++++++++++++++++++++++++++++++-------- src/remote/remote_protocol.x | 24 ++++++++- src/remote_protocol-structs | 6 +++ src/vz/vz_driver.c | 39 +++++++++++++++ src/vz/vz_sdk.c | 4 ++ src/vz/vz_utils.h | 3 ++ 13 files changed, 363 insertions(+), 87 deletions(-) -- 1.8.3.1

Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- po/POTFILES.in | 1 + src/datatypes.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++ src/datatypes.h | 10 +++++++ src/libvirt-host.c | 35 ++-------------------- src/remote/remote_driver.c | 17 ++--------- 5 files changed, 91 insertions(+), 47 deletions(-) diff --git a/po/POTFILES.in b/po/POTFILES.in index 82e8d3e..176b60d 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -43,6 +43,7 @@ src/cpu/cpu_generic.c src/cpu/cpu_map.c src/cpu/cpu_ppc64.c src/cpu/cpu_x86.c +src/datatypes.c src/driver.c src/esx/esx_driver.c src/esx/esx_network_driver.c diff --git a/src/datatypes.c b/src/datatypes.c index c832d80..3750557 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -180,6 +180,81 @@ virConnectCloseCallbackDataDispose(void *obj) virObjectUnlock(cb); } +int virConnectCloseCallbackDataRegister(virConnectCloseCallbackDataPtr close, + virConnectPtr conn, + virConnectCloseFunc cb, + void *opaque, + virFreeCallback freecb) +{ + int ret = -1; + + virObjectLock(close); + + if (close->callback) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("A close callback is already registered")); + goto error; + } + + close->conn = conn; + virObjectRef(close->conn); + close->callback = cb; + close->opaque = opaque; + close->freeCallback = freecb; + + ret = 0; + + error: + virObjectUnlock(close); + return ret; +} + +int virConnectCloseCallbackDataUnregister(virConnectCloseCallbackDataPtr close, + virConnectCloseFunc cb) +{ + int ret = -1; + + virObjectLock(close); + + if (close->callback != cb) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("A different callback was requested")); + goto error; + } + + close->callback = NULL; + if (close->freeCallback) + close->freeCallback(close->opaque); + close->freeCallback = NULL; + virObjectUnref(close->conn); + + ret = 0; + + error: + virObjectUnlock(close); + return ret; +} + +void virConnectCloseCallbackDataCall(virConnectCloseCallbackDataPtr close, + int reason) +{ + virObjectLock(close); + + if (!close->callback) + goto exit; + + VIR_DEBUG("Triggering connection close callback %p reason=%d, opaque=%p", + close->callback, reason, close->opaque); + close->callback(close->conn, reason, close->opaque); + + if (close->freeCallback) + close->freeCallback(close->opaque); + close->callback = NULL; + close->freeCallback = NULL; + + exit: + virObjectUnlock(close); +} /** * virGetDomain: diff --git a/src/datatypes.h b/src/datatypes.h index 1b1777d..096f80f 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -601,4 +601,14 @@ virDomainSnapshotPtr virGetDomainSnapshot(virDomainPtr domain, virAdmConnectPtr virAdmConnectNew(void); +int virConnectCloseCallbackDataRegister(virConnectCloseCallbackDataPtr close, + virConnectPtr conn, + virConnectCloseFunc cb, + void *opaque, + virFreeCallback freecb); +int virConnectCloseCallbackDataUnregister(virConnectCloseCallbackDataPtr close, + virConnectCloseFunc cb); +void virConnectCloseCallbackDataCall(virConnectCloseCallbackDataPtr close, + int reason); + #endif /* __VIR_DATATYPES_H__ */ diff --git a/src/libvirt-host.c b/src/libvirt-host.c index 9c88426..c492bd8 100644 --- a/src/libvirt-host.c +++ b/src/libvirt-host.c @@ -1216,35 +1216,20 @@ virConnectRegisterCloseCallback(virConnectPtr conn, virResetLastError(); virCheckConnectReturn(conn, -1); - - virObjectRef(conn); - virObjectLock(conn); - virObjectLock(conn->closeCallback); virCheckNonNullArgGoto(cb, error); - if (conn->closeCallback->callback) { - virReportError(VIR_ERR_OPERATION_INVALID, "%s", - _("A close callback is already registered")); + if (virConnectCloseCallbackDataRegister(conn->closeCallback, conn, cb, + opaque, freecb) < 0) goto error; - } - - conn->closeCallback->conn = conn; - conn->closeCallback->callback = cb; - conn->closeCallback->opaque = opaque; - conn->closeCallback->freeCallback = freecb; - virObjectUnlock(conn->closeCallback); virObjectUnlock(conn); - return 0; error: - virObjectUnlock(conn->closeCallback); virObjectUnlock(conn); virDispatchError(conn); - virObjectUnref(conn); return -1; } @@ -1271,31 +1256,17 @@ virConnectUnregisterCloseCallback(virConnectPtr conn, virResetLastError(); virCheckConnectReturn(conn, -1); - virObjectLock(conn); - virObjectLock(conn->closeCallback); virCheckNonNullArgGoto(cb, error); - if (conn->closeCallback->callback != cb) { - virReportError(VIR_ERR_OPERATION_INVALID, "%s", - _("A different callback was requested")); + if (virConnectCloseCallbackDataUnregister(conn->closeCallback, cb) < 0) goto error; - } - conn->closeCallback->callback = NULL; - if (conn->closeCallback->freeCallback) - conn->closeCallback->freeCallback(conn->closeCallback->opaque); - conn->closeCallback->freeCallback = NULL; - - virObjectUnlock(conn->closeCallback); virObjectUnlock(conn); - virObjectUnref(conn); - return 0; error: - virObjectUnlock(conn->closeCallback); virObjectUnlock(conn); virDispatchError(conn); return -1; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index a1dd640..f64c678 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -531,21 +531,8 @@ remoteClientCloseFunc(virNetClientPtr client ATTRIBUTE_UNUSED, int reason, void *opaque) { - virConnectCloseCallbackDataPtr cbdata = opaque; - - virObjectLock(cbdata); - - if (cbdata->callback) { - VIR_DEBUG("Triggering connection close callback %p reason=%d, opaque=%p", - cbdata->callback, reason, cbdata->opaque); - cbdata->callback(cbdata->conn, reason, cbdata->opaque); - - if (cbdata->freeCallback) - cbdata->freeCallback(cbdata->opaque); - cbdata->callback = NULL; - cbdata->freeCallback = NULL; - } - virObjectUnlock(cbdata); + virConnectCloseCallbackDataCall((virConnectCloseCallbackDataPtr)opaque, + reason); } /* helper macro to ease extraction of arguments from the URI */ -- 1.8.3.1

We have reference to connection object in virConnectCloseCallbackData object thus we have to refcount it. Obviously we have problems in dispose and call functions. Let's fix it. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/datatypes.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/datatypes.c b/src/datatypes.c index 3750557..73c7e7e 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -176,6 +176,7 @@ virConnectCloseCallbackDataDispose(void *obj) if (cb->freeCallback) cb->freeCallback(cb->opaque); + virObjectUnref(cb->conn); virObjectUnlock(cb); } @@ -227,6 +228,7 @@ int virConnectCloseCallbackDataUnregister(virConnectCloseCallbackDataPtr close, close->freeCallback(close->opaque); close->freeCallback = NULL; virObjectUnref(close->conn); + close->conn = NULL; ret = 0; @@ -251,6 +253,8 @@ void virConnectCloseCallbackDataCall(virConnectCloseCallbackDataPtr close, close->freeCallback(close->opaque); close->callback = NULL; close->freeCallback = NULL; + virObjectUnref(close->conn); + close->conn = NULL; exit: virObjectUnlock(close); -- 1.8.3.1

--- src/datatypes.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/datatypes.c b/src/datatypes.c index 73c7e7e..57162ec 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -161,6 +161,19 @@ virConnectDispose(void *obj) } +static +void virConnectCloseCallbackDataReset(virConnectCloseCallbackDataPtr close) +{ + if (close->freeCallback) + close->freeCallback(close->opaque); + + close->freeCallback = NULL; + close->callback = NULL; + close->opaque = NULL; + virObjectUnref(close->conn); + close->conn = NULL; +} + /** * virConnectCloseCallbackDataDispose: * @obj: the close callback data to release @@ -174,9 +187,7 @@ virConnectCloseCallbackDataDispose(void *obj) virObjectLock(cb); - if (cb->freeCallback) - cb->freeCallback(cb->opaque); - virObjectUnref(cb->conn); + virConnectCloseCallbackDataReset(cb); virObjectUnlock(cb); } @@ -223,12 +234,7 @@ int virConnectCloseCallbackDataUnregister(virConnectCloseCallbackDataPtr close, goto error; } - close->callback = NULL; - if (close->freeCallback) - close->freeCallback(close->opaque); - close->freeCallback = NULL; - virObjectUnref(close->conn); - close->conn = NULL; + virConnectCloseCallbackDataReset(close); ret = 0; @@ -249,12 +255,7 @@ void virConnectCloseCallbackDataCall(virConnectCloseCallbackDataPtr close, close->callback, reason, close->opaque); close->callback(close->conn, reason, close->opaque); - if (close->freeCallback) - close->freeCallback(close->opaque); - close->callback = NULL; - close->freeCallback = NULL; - virObjectUnref(close->conn); - close->conn = NULL; + virConnectCloseCallbackDataReset(close); exit: virObjectUnlock(close); -- 1.8.3.1

closeCallback pointer is immutable (set on connection object creation) and self-locking. --- src/libvirt-host.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/libvirt-host.c b/src/libvirt-host.c index c492bd8..0bab5f2 100644 --- a/src/libvirt-host.c +++ b/src/libvirt-host.c @@ -1214,21 +1214,16 @@ virConnectRegisterCloseCallback(virConnectPtr conn, VIR_DEBUG("conn=%p", conn); virResetLastError(); - virCheckConnectReturn(conn, -1); - virObjectLock(conn); - virCheckNonNullArgGoto(cb, error); if (virConnectCloseCallbackDataRegister(conn->closeCallback, conn, cb, opaque, freecb) < 0) goto error; - virObjectUnlock(conn); return 0; error: - virObjectUnlock(conn); virDispatchError(conn); return -1; } @@ -1254,20 +1249,15 @@ virConnectUnregisterCloseCallback(virConnectPtr conn, VIR_DEBUG("conn=%p", conn); virResetLastError(); - virCheckConnectReturn(conn, -1); - virObjectLock(conn); - virCheckNonNullArgGoto(cb, error); if (virConnectCloseCallbackDataUnregister(conn->closeCallback, cb) < 0) goto error; - virObjectUnlock(conn); return 0; error: - virObjectUnlock(conn); virDispatchError(conn); return -1; } -- 1.8.3.1

We don't need locks in dispose functions as they can only be run in one thread for given object. --- src/datatypes.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/datatypes.c b/src/datatypes.c index 57162ec..29f94e8 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -183,13 +183,7 @@ void virConnectCloseCallbackDataReset(virConnectCloseCallbackDataPtr close) static void virConnectCloseCallbackDataDispose(void *obj) { - virConnectCloseCallbackDataPtr cb = obj; - - virObjectLock(cb); - - virConnectCloseCallbackDataReset(cb); - - virObjectUnlock(cb); + virConnectCloseCallbackDataReset(obj); } int virConnectCloseCallbackDataRegister(virConnectCloseCallbackDataPtr close, -- 1.8.3.1

Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/datatypes.c | 31 ++++++++++-------------------- src/datatypes.h | 1 + src/driver-hypervisor.h | 12 ++++++++++++ src/libvirt-host.c | 7 ++++--- src/remote/remote_driver.c | 47 ++++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 70 insertions(+), 28 deletions(-) diff --git a/src/datatypes.c b/src/datatypes.c index 29f94e8..f7e9f52 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -114,22 +114,10 @@ VIR_ONCE_GLOBAL_INIT(virDataTypes) virConnectPtr virGetConnect(void) { - virConnectPtr ret; - if (virDataTypesInitialize() < 0) return NULL; - if (!(ret = virObjectLockableNew(virConnectClass))) - return NULL; - - if (!(ret->closeCallback = virObjectLockableNew(virConnectCloseCallbackDataClass))) - goto error; - - return ret; - - error: - virObjectUnref(ret); - return NULL; + return virObjectLockableNew(virConnectClass); } /** @@ -150,14 +138,6 @@ virConnectDispose(void *obj) virResetError(&conn->err); virURIFree(conn->uri); - - if (conn->closeCallback) { - virObjectLock(conn->closeCallback); - conn->closeCallback->callback = NULL; - virObjectUnlock(conn->closeCallback); - - virObjectUnref(conn->closeCallback); - } } @@ -186,6 +166,15 @@ virConnectCloseCallbackDataDispose(void *obj) virConnectCloseCallbackDataReset(obj); } +virConnectCloseCallbackDataPtr +virNewConnectCloseCallbackData(void) +{ + if (virDataTypesInitialize() < 0) + return NULL; + + return virObjectLockableNew(virConnectCloseCallbackDataClass); +} + int virConnectCloseCallbackDataRegister(virConnectCloseCallbackDataPtr close, virConnectPtr conn, virConnectCloseFunc cb, diff --git a/src/datatypes.h b/src/datatypes.h index 096f80f..0e99d6a 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -601,6 +601,7 @@ virDomainSnapshotPtr virGetDomainSnapshot(virDomainPtr domain, virAdmConnectPtr virAdmConnectNew(void); +virConnectCloseCallbackDataPtr virNewConnectCloseCallbackData(void); int virConnectCloseCallbackDataRegister(virConnectCloseCallbackDataPtr close, virConnectPtr conn, virConnectCloseFunc cb, diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h index ae2ec4d..2cbd01b 100644 --- a/src/driver-hypervisor.h +++ b/src/driver-hypervisor.h @@ -1212,6 +1212,16 @@ typedef int const char *password, unsigned int flags); +typedef int +(*virDrvConnectRegisterCloseCallback)(virConnectPtr conn, + virConnectCloseFunc cb, + void *opaque, + virFreeCallback freecb); + +typedef int +(*virDrvConnectUnregisterCloseCallback)(virConnectPtr conn, + virConnectCloseFunc cb); + typedef struct _virHypervisorDriver virHypervisorDriver; typedef virHypervisorDriver *virHypervisorDriverPtr; @@ -1443,6 +1453,8 @@ struct _virHypervisorDriver { virDrvDomainGetFSInfo domainGetFSInfo; virDrvDomainInterfaceAddresses domainInterfaceAddresses; virDrvDomainSetUserPassword domainSetUserPassword; + virDrvConnectRegisterCloseCallback connectRegisterCloseCallback; + virDrvConnectUnregisterCloseCallback connectUnregisterCloseCallback; }; diff --git a/src/libvirt-host.c b/src/libvirt-host.c index 0bab5f2..24277b7 100644 --- a/src/libvirt-host.c +++ b/src/libvirt-host.c @@ -1217,8 +1217,8 @@ virConnectRegisterCloseCallback(virConnectPtr conn, virCheckConnectReturn(conn, -1); virCheckNonNullArgGoto(cb, error); - if (virConnectCloseCallbackDataRegister(conn->closeCallback, conn, cb, - opaque, freecb) < 0) + if (conn->driver->connectRegisterCloseCallback && + conn->driver->connectRegisterCloseCallback(conn, cb, opaque, freecb) < 0) goto error; return 0; @@ -1252,7 +1252,8 @@ virConnectUnregisterCloseCallback(virConnectPtr conn, virCheckConnectReturn(conn, -1); virCheckNonNullArgGoto(cb, error); - if (virConnectCloseCallbackDataUnregister(conn->closeCallback, cb) < 0) + if (conn->driver->connectUnregisterCloseCallback && + conn->driver->connectUnregisterCloseCallback(conn, cb) < 0) goto error; return 0; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index f64c678..f35bb28 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -101,6 +101,7 @@ struct private_data { bool serverEventFilter; /* Does server support modern event filtering */ virObjectEventStatePtr eventState; + virConnectCloseCallbackDataPtr closeCallback; }; enum { @@ -959,11 +960,13 @@ doRemoteOpen(virConnectPtr conn, goto failed; } - virObjectRef(conn->closeCallback); - + if (!(priv->closeCallback = virNewConnectCloseCallbackData())) + goto failed; + // ref on behalf of netclient + virObjectRef(priv->closeCallback); virNetClientSetCloseCallback(priv->client, remoteClientCloseFunc, - conn->closeCallback, virObjectFreeCallback); + priv->closeCallback, virObjectFreeCallback); if (!(priv->remoteProgram = virNetClientProgramNew(REMOTE_PROGRAM, REMOTE_PROTOCOL_VERSION, @@ -1093,6 +1096,8 @@ doRemoteOpen(virConnectPtr conn, virNetClientClose(priv->client); virObjectUnref(priv->client); priv->client = NULL; + virObjectUnref(priv->closeCallback); + priv->closeCallback = NULL; #ifdef WITH_GNUTLS virObjectUnref(priv->tls); priv->tls = NULL; @@ -1225,11 +1230,13 @@ doRemoteClose(virConnectPtr conn, struct private_data *priv) virNetClientSetCloseCallback(priv->client, NULL, - conn->closeCallback, virObjectFreeCallback); + priv->closeCallback, virObjectFreeCallback); virNetClientClose(priv->client); virObjectUnref(priv->client); priv->client = NULL; + virObjectUnref(priv->closeCallback); + priv->closeCallback = NULL; virObjectUnref(priv->remoteProgram); virObjectUnref(priv->lxcProgram); virObjectUnref(priv->qemuProgram); @@ -8024,6 +8031,36 @@ remoteDomainInterfaceAddresses(virDomainPtr dom, return rv; } +static int +remoteConnectRegisterCloseCallback(virConnectPtr conn, + virConnectCloseFunc cb, + void *opaque, + virFreeCallback freecb) +{ + struct private_data *priv = conn->privateData; + int ret = -1; + + remoteDriverLock(priv); + ret = virConnectCloseCallbackDataRegister(priv->closeCallback, conn, cb, + opaque, freecb); + remoteDriverUnlock(priv); + + return ret; +} + +static int +remoteConnectUnregisterCloseCallback(virConnectPtr conn, + virConnectCloseFunc cb) +{ + struct private_data *priv = conn->privateData; + int ret = -1; + + remoteDriverLock(priv); + ret = virConnectCloseCallbackDataUnregister(priv->closeCallback, cb); + remoteDriverUnlock(priv); + + return ret; +} static int remoteDomainRename(virDomainPtr dom, const char *new_name, unsigned int flags) @@ -8416,6 +8453,8 @@ static virHypervisorDriver hypervisor_driver = { .domainInterfaceAddresses = remoteDomainInterfaceAddresses, /* 1.2.14 */ .domainSetUserPassword = remoteDomainSetUserPassword, /* 1.2.16 */ .domainRename = remoteDomainRename, /* 1.2.19 */ + .connectRegisterCloseCallback = remoteConnectRegisterCloseCallback, /* 1.3.2 */ + .connectUnregisterCloseCallback = remoteConnectUnregisterCloseCallback, /* 1.3.2 */ }; static virNetworkDriver network_driver = { -- 1.8.3.1

remoteConnectUnregisterCloseCallback is not quite good. if it is given a callback function different from that was registered before then local part will fail silently. On the other hand we can not gracefully handle this fail as the remote part is already unregistered. There are a lot of options to fix it. I think of totally removing the callback argument from unregistering. What's the use of it? --- daemon/libvirtd.h | 1 + daemon/remote.c | 84 ++++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 52 ++++++++++++++++++++++++--- src/remote/remote_protocol.x | 24 ++++++++++++- src/remote_protocol-structs | 6 ++++ 5 files changed, 161 insertions(+), 6 deletions(-) diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h index efd4823..7271b0f 100644 --- a/daemon/libvirtd.h +++ b/daemon/libvirtd.h @@ -60,6 +60,7 @@ struct daemonClientPrivate { size_t nnetworkEventCallbacks; daemonClientEventCallbackPtr *qemuEventCallbacks; size_t nqemuEventCallbacks; + bool closeRegistered; # if WITH_SASL virNetSASLSessionPtr sasl; diff --git a/daemon/remote.c b/daemon/remote.c index 3a3eb09..53fcd29 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -1189,6 +1189,20 @@ remoteRelayDomainQemuMonitorEvent(virConnectPtr conn, VIR_FREE(details_p); } +static +void remoteRelayConnectionClosedEvent(virConnectPtr conn ATTRIBUTE_UNUSED, int reason, void *opaque) +{ + virNetServerClientPtr client = opaque; + + VIR_DEBUG("Relaying connection closed event, reason %d", reason); + + remote_connect_event_connection_closed_msg msg = { reason }; + remoteDispatchObjectEventSend(client, remoteProgram, + REMOTE_PROC_CONNECT_EVENT_CONNECTION_CLOSED, + (xdrproc_t)xdr_remote_connect_event_connection_closed_msg, + &msg); +} + /* * You must hold lock for at least the client * We don't free stuff here, merely disconnect the client's @@ -1251,6 +1265,12 @@ void remoteClientFreeFunc(void *data) } VIR_FREE(priv->qemuEventCallbacks); + if (priv->closeRegistered) { + if (virConnectUnregisterCloseCallback(priv->conn, + remoteRelayConnectionClosedEvent) < 0) + VIR_WARN("unexpected close callback event deregister failure"); + } + virConnectClose(priv->conn); virIdentitySetCurrent(NULL); @@ -3483,6 +3503,70 @@ remoteDispatchNodeDeviceGetParent(virNetServerPtr server ATTRIBUTE_UNUSED, return rv; } +static int +remoteDispatchConnectCloseCallbackRegister(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr) +{ + int rv = -1; + struct daemonClientPrivate *priv = + virNetServerClientGetPrivateData(client); + + virMutexLock(&priv->lock); + + if (!priv->conn) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + // on behalf of close callback + virObjectRef(client); + if (virConnectRegisterCloseCallback(priv->conn, + remoteRelayConnectionClosedEvent, + client, virObjectFreeCallback) < 0) + goto cleanup; + + priv->closeRegistered = true; + rv = 0; + + cleanup: + virMutexUnlock(&priv->lock); + if (rv < 0) + virNetMessageSaveError(rerr); + return rv; +} + +static int +remoteDispatchConnectCloseCallbackUnregister(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr) +{ + int rv = -1; + struct daemonClientPrivate *priv = + virNetServerClientGetPrivateData(client); + + virMutexLock(&priv->lock); + + if (!priv->conn) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + if (virConnectUnregisterCloseCallback(priv->conn, + remoteRelayConnectionClosedEvent) < 0) + goto cleanup; + + priv->closeRegistered = false; + rv = 0; + + cleanup: + virMutexUnlock(&priv->lock); + if (rv < 0) + virNetMessageSaveError(rerr); + return rv; +} /*************************** * Register / deregister events diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index f35bb28..3c8c807 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -347,6 +347,11 @@ remoteNetworkBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, virNetClientPtr client ATTRIBUTE_UNUSED, void *evdata, void *opaque); +static void +remoteConnectNotifyEventConnectionClosed(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, + virNetClientPtr client ATTRIBUTE_UNUSED, + void *evdata, void *opaque); + static virNetClientProgramEvent remoteEvents[] = { { REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE, remoteDomainBuildEventLifecycle, @@ -505,8 +510,23 @@ static virNetClientProgramEvent remoteEvents[] = { remoteDomainBuildEventCallbackDeviceAdded, sizeof(remote_domain_event_callback_device_added_msg), (xdrproc_t)xdr_remote_domain_event_callback_device_added_msg }, + { REMOTE_PROC_CONNECT_EVENT_CONNECTION_CLOSED, + remoteConnectNotifyEventConnectionClosed, + sizeof(remote_connect_event_connection_closed_msg), + (xdrproc_t)xdr_remote_connect_event_connection_closed_msg }, }; +static void +remoteConnectNotifyEventConnectionClosed(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, + virNetClientPtr client ATTRIBUTE_UNUSED, + void *evdata, void *opaque) +{ + virConnectPtr conn = opaque; + struct private_data *priv = conn->privateData; + remote_connect_event_connection_closed_msg *msg = evdata; + + virConnectCloseCallbackDataCall(priv->closeCallback, msg->reason); +} static void remoteDomainBuildQemuMonitorEvent(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, @@ -8041,10 +8061,21 @@ remoteConnectRegisterCloseCallback(virConnectPtr conn, int ret = -1; remoteDriverLock(priv); - ret = virConnectCloseCallbackDataRegister(priv->closeCallback, conn, cb, - opaque, freecb); - remoteDriverUnlock(priv); + if (virConnectCloseCallbackDataRegister(priv->closeCallback, conn, cb, + opaque, freecb) < 0) + goto cleanup; + + if (call(conn, priv, 0, REMOTE_PROC_CONNECT_CLOSE_CALLBACK_REGISTER, + (xdrproc_t) xdr_void, (char *) NULL, + (xdrproc_t) xdr_void, (char *) NULL) == -1) { + virConnectCloseCallbackDataUnregister(priv->closeCallback, cb); + goto cleanup; + } + + ret = 0; + cleanup: + remoteDriverUnlock(priv); return ret; } @@ -8056,9 +8087,20 @@ remoteConnectUnregisterCloseCallback(virConnectPtr conn, int ret = -1; remoteDriverLock(priv); - ret = virConnectCloseCallbackDataUnregister(priv->closeCallback, cb); - remoteDriverUnlock(priv); + if (call(conn, priv, 0, REMOTE_PROC_CONNECT_CLOSE_CALLBACK_UNREGISTER, + (xdrproc_t) xdr_void, (char *) NULL, + (xdrproc_t) xdr_void, (char *) NULL) == -1) { + goto cleanup; + } + + // hopefully nobody will call us with different callback + // or we will fail here + virConnectCloseCallbackDataUnregister(priv->closeCallback, cb); + + ret = 0; + cleanup: + remoteDriverUnlock(priv); return ret; } diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 9f131f8..4d68905 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -3045,6 +3045,10 @@ struct remote_domain_event_callback_device_added_msg { remote_nonnull_string devAlias; }; +struct remote_connect_event_connection_closed_msg { + int reason; +}; + struct remote_connect_get_cpu_model_names_args { remote_nonnull_string arch; int need_results; @@ -5694,5 +5698,23 @@ enum remote_procedure { * @acl: domain:write * @acl: domain:save */ - REMOTE_PROC_DOMAIN_RENAME = 358 + REMOTE_PROC_DOMAIN_RENAME = 358, + + /** + * @generate: none + * @acl: none + */ + REMOTE_PROC_CONNECT_CLOSE_CALLBACK_REGISTER = 359, + + /** + * @generate: none + * @acl: none + */ + REMOTE_PROC_CONNECT_CLOSE_CALLBACK_UNREGISTER = 360, + + /** + * @generate: none + * @acl: none + */ + REMOTE_PROC_CONNECT_EVENT_CONNECTION_CLOSED = 361 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index ff99c00..913f97e 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2502,6 +2502,9 @@ struct remote_domain_event_callback_device_added_msg { remote_nonnull_domain dom; remote_nonnull_string devAlias; }; +struct remote_connect_event_connection_closed_msg { + int reason; +}; struct remote_connect_get_cpu_model_names_args { remote_nonnull_string arch; int need_results; @@ -3051,4 +3054,7 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_DEL_IOTHREAD = 356, REMOTE_PROC_DOMAIN_SET_USER_PASSWORD = 357, REMOTE_PROC_DOMAIN_RENAME = 358, + REMOTE_PROC_CONNECT_CLOSE_CALLBACK_REGISTER = 359, + REMOTE_PROC_CONNECT_CLOSE_CALLBACK_UNREGISTER = 360, + REMOTE_PROC_CONNECT_EVENT_CONNECTION_CLOSED = 361, }; -- 1.8.3.1

Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/vz/vz_driver.c | 39 +++++++++++++++++++++++++++++++++++++++ src/vz/vz_sdk.c | 4 ++++ src/vz/vz_utils.h | 3 +++ 3 files changed, 46 insertions(+) diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index f73f8ef..f48c7c9 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -254,6 +254,9 @@ vzOpenDefault(virConnectPtr conn) if (prlsdkSubscribeToPCSEvents(privconn)) goto error; + if (!(privconn->closeCallback = virNewConnectCloseCallbackData())) + goto error; + conn->privateData = privconn; if (prlsdkLoadDomains(privconn)) @@ -262,6 +265,8 @@ vzOpenDefault(virConnectPtr conn) return VIR_DRV_OPEN_SUCCESS; error: + virObjectUnref(privconn->closeCallback); + privconn->closeCallback = NULL; virObjectUnref(privconn->domains); virObjectUnref(privconn->caps); virObjectEventStateFree(privconn->domainEventState); @@ -329,6 +334,8 @@ vzConnectClose(virConnectPtr conn) virObjectUnref(privconn->caps); virObjectUnref(privconn->xmlopt); virObjectUnref(privconn->domains); + virObjectUnref(privconn->closeCallback); + privconn->closeCallback = NULL; virObjectEventStateFree(privconn->domainEventState); prlsdkDisconnect(privconn); conn->privateData = NULL; @@ -1460,6 +1467,36 @@ vzNodeGetFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED) return freeMem; } +static int +vzConnectRegisterCloseCallback(virConnectPtr conn, + virConnectCloseFunc cb, + void *opaque, + virFreeCallback freecb) +{ + vzConnPtr privconn = conn->privateData; + int ret = -1; + + vzDriverLock(privconn); + ret = virConnectCloseCallbackDataRegister(privconn->closeCallback, conn, cb, + opaque, freecb); + vzDriverUnlock(privconn); + + return ret; +} + +static int +vzConnectUnregisterCloseCallback(virConnectPtr conn, virConnectCloseFunc cb) +{ + vzConnPtr privconn = conn->privateData; + int ret = -1; + + vzDriverLock(privconn); + ret = virConnectCloseCallbackDataUnregister(privconn->closeCallback, cb); + vzDriverUnlock(privconn); + + return ret; +} + static virHypervisorDriver vzDriver = { .name = "vz", .connectOpen = vzConnectOpen, /* 0.10.0 */ @@ -1522,6 +1559,8 @@ static virHypervisorDriver vzDriver = { .domainBlockStatsFlags = vzDomainBlockStatsFlags, /* 1.2.17 */ .domainInterfaceStats = vzDomainInterfaceStats, /* 1.2.17 */ .domainMemoryStats = vzDomainMemoryStats, /* 1.2.17 */ + .connectRegisterCloseCallback = vzConnectRegisterCloseCallback, /* 1.3.2 */ + .connectUnregisterCloseCallback = vzConnectUnregisterCloseCallback, /* 1.3.2 */ }; static virConnectDriver vzConnectDriver = { diff --git a/src/vz/vz_sdk.c b/src/vz/vz_sdk.c index b78c413..c8bded9 100644 --- a/src/vz/vz_sdk.c +++ b/src/vz/vz_sdk.c @@ -1751,6 +1751,10 @@ prlsdkEventsHandler(PRL_HANDLE prlEvent, PRL_VOID_PTR opaque) /* above function takes own of event */ prlEvent = PRL_INVALID_HANDLE; break; + case PET_DSP_EVT_DISP_CONNECTION_CLOSED: + virConnectCloseCallbackDataCall(privconn->closeCallback, + VIR_CONNECT_CLOSE_REASON_EOF); + break; default: VIR_DEBUG("Skipping event of type %d", prlEventType); } diff --git a/src/vz/vz_utils.h b/src/vz/vz_utils.h index b7a4c81..a2468b4 100644 --- a/src/vz/vz_utils.h +++ b/src/vz/vz_utils.h @@ -30,6 +30,7 @@ # include "conf/virdomainobjlist.h" # include "conf/domain_event.h" # include "virthread.h" +# include "datatypes.h" # define vzParseError() \ virReportErrorHelper(VIR_FROM_TEST, VIR_ERR_OPERATION_FAILED, __FILE__, \ @@ -59,6 +60,8 @@ struct _vzConn { virDomainXMLOptionPtr xmlopt; virObjectEventStatePtr domainEventState; const char *drivername; + /* Immutable pointer, self-locking APIs */ + virConnectCloseCallbackDataPtr closeCallback; }; typedef struct _vzConn vzConn; -- 1.8.3.1

22.01.2016 11:59, Nikolay Shirokovskiy пишет:
Currently close callback API can only inform us of closing the connection between remote driver and daemon. But what if a driver running in the daemon itself can have another persistent connection? In this case we want to be informed of that connection changes state too.
This patch series extends meaning of current close callback API so that now it notifies of closing of any internal persistent connection. The overall approach is to move close callback support to drivers.
Changes from v2: Split patches further to make it more comprehensible.
Nikolay Shirokovskiy (8): factor out virConnectCloseCallbackDataPtr methods virConnectCloseCallbackData: fix connection object refcount virConnectCloseCallbackData: factor out callback disarming close callback API: remove unnecessary locks virConnectCloseCallbackDataDispose: remove unnecessary locks close callback: move it to driver daemon: add connection close rpc vz: implement connection close notification
daemon/libvirtd.h | 1 + daemon/remote.c | 84 ++++++++++++++++++++++++++++++++ po/POTFILES.in | 1 + src/datatypes.c | 113 +++++++++++++++++++++++++++++++++---------- src/datatypes.h | 11 +++++ src/driver-hypervisor.h | 12 +++++ src/libvirt-host.c | 46 ++---------------- src/remote/remote_driver.c | 106 ++++++++++++++++++++++++++++++++-------- src/remote/remote_protocol.x | 24 ++++++++- src/remote_protocol-structs | 6 +++ src/vz/vz_driver.c | 39 +++++++++++++++ src/vz/vz_sdk.c | 4 ++ src/vz/vz_utils.h | 3 ++ 13 files changed, 363 insertions(+), 87 deletions(-)
The patch series doesn't apply anymore. Could you please rebase it?
participants (2)
-
Maxim Nestratov
-
Nikolay Shirokovskiy