[lxc-devel] [PATCH] cgmanager: avoid stray dbus connections
Serge Hallyn
serge.hallyn at ubuntu.com
Tue Mar 11 02:41:34 UTC 2014
There are two parts to this fix.
First, create a private DBusConnection manually, instead of using
nih_dbus_connect. The latter always creates a shared connection,
which cannot be closed. Note: creating an actual shared connection,
mutexing it among all threads, and creating per-thread proxies would
be an alternative - however we don't want long-lived connections as
they tend not to be reliable (especially if cgmanager restarts).
Second, use pthread_setspecific to create per-thread keys which can
be associated with destructors. Specify a destructor which closes
the dbus connection. If a thread dies while holding cgmanager,
the connection will be closed. Otherwise, we close the connection
and unset the key.
Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
---
src/lxc/cgmanager.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 47 insertions(+), 2 deletions(-)
diff --git a/src/lxc/cgmanager.c b/src/lxc/cgmanager.c
index c80a136..4cf6397 100644
--- a/src/lxc/cgmanager.c
+++ b/src/lxc/cgmanager.c
@@ -70,10 +70,42 @@ struct cgm_data {
static __thread NihDBusProxy *cgroup_manager = NULL;
static __thread DBusConnection *connection = NULL;
static __thread bool cgm_keep_connection = false;
+
+
+struct cgm_key_t {
+ DBusConnection *connection;
+ NihDBusProxy *cgmanager;
+} cgm_key;
+
+void destructor(void *arg) {
+ struct cgm_key_t *cgm_key = arg;
+ nih_free(cgm_key->cgmanager);
+ dbus_connection_flush(cgm_key->connection);
+ dbus_connection_close(cgm_key->connection);
+ dbus_connection_unref(cgm_key->connection);
+}
+static pthread_key_t key;
+static void make_key() {
+ pthread_key_create(&key, destructor);
+}
+
+static void init_cgm_destructor(DBusConnection *c, NihDBusProxy *cgm)
+{
+ static pthread_once_t key_once = PTHREAD_ONCE_INIT;
+ pthread_once(&key_once, make_key);
+ cgm_key.connection = c;
+ cgm_key.cgmanager = cgm;
+ if (!cgm)
+ pthread_setspecific(key, NULL);
+ else if (pthread_getspecific(key) == NULL)
+ pthread_setspecific(key, &cgm_key);
+}
+
#else
static NihDBusProxy *cgroup_manager = NULL;
static DBusConnection *connection = NULL;
static bool cgm_keep_connection = false;
+static inline void init_cgm_destructor(DBusConnection *c, NihDBusProxy *cgm) { }
#endif
static struct cgroup_ops cgmanager_ops;
@@ -87,9 +119,13 @@ static void cgm_dbus_disconnect(void)
if (cgroup_manager)
nih_free(cgroup_manager);
cgroup_manager = NULL;
- if (connection)
+ if (connection) {
+ dbus_connection_flush(connection);
+ dbus_connection_close(connection);
dbus_connection_unref(connection);
+ }
connection = NULL;
+ init_cgm_destructor(NULL, NULL);
}
#define CGMANAGER_DBUS_SOCK "unix:path=/sys/fs/cgroup/cgmanager/sock"
@@ -105,14 +141,22 @@ static bool do_cgm_dbus_connect(void)
dbus_error_init(&dbus_error);
- connection = nih_dbus_connect(CGMANAGER_DBUS_SOCK, NULL);
+ connection = dbus_connection_open_private(CGMANAGER_DBUS_SOCK, &dbus_error);
if (!connection) {
+ ERROR("Failed opening dbus connection: %s: %s",
+ dbus_error.name, dbus_error.message);
+ dbus_error_free(&dbus_error);
+ return false;
+ }
+ if (nih_dbus_setup(connection, NULL) < 0) {
NihError *nerr;
nerr = nih_error_get();
DEBUG("Unable to open cgmanager connection at %s: %s", CGMANAGER_DBUS_SOCK,
nerr->message);
nih_free(nerr);
dbus_error_free(&dbus_error);
+ dbus_connection_unref(connection);
+ connection = NULL;
return false;
}
dbus_connection_set_exit_on_disconnect(connection, FALSE);
@@ -138,6 +182,7 @@ static bool do_cgm_dbus_connect(void)
cgm_dbus_disconnect();
return false;
}
+ init_cgm_destructor(connection, cgroup_manager);
return true;
}
--
1.9.0
More information about the lxc-devel
mailing list