From c7f847ed3a00a097cc131a988156db02eb4f3ef8 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 6 May 2021 12:14:01 -0700 Subject: [PATCH] libct/cg/sd: use global dbus connection Using per cgroup manager dbus connection instances means that every cgroup manager instance gets a new connection, and those connections are never closed, ultimately resulting in file descriptors limit being hit. Revert back to using a single global dbus connection for everything, without changing the callers. NOTE that it is assumed a runtime can't use both root and rootless dbus at the same time. If this happens, we panic. Signed-off-by: Kir Kolyshkin --- libcontainer/cgroups/systemd/dbus.go | 48 ++++++++++++++++------------ 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/libcontainer/cgroups/systemd/dbus.go b/libcontainer/cgroups/systemd/dbus.go index deca16b005b..0f7406cd9d6 100644 --- a/libcontainer/cgroups/systemd/dbus.go +++ b/libcontainer/cgroups/systemd/dbus.go @@ -10,37 +10,43 @@ import ( dbus "github.com/godbus/dbus/v5" ) +var ( + dbusC *systemdDbus.Conn + dbusMu sync.RWMutex + dbusInited bool + dbusRootless bool +) + type dbusConnManager struct { - conn *systemdDbus.Conn - rootless bool - sync.RWMutex } // newDbusConnManager initializes systemd dbus connection manager. func newDbusConnManager(rootless bool) *dbusConnManager { - return &dbusConnManager{ - rootless: rootless, + if dbusInited && rootless != dbusRootless { + panic("can't have both root and rootless dbus") } + dbusRootless = rootless + return &dbusConnManager{} } // getConnection lazily initializes and returns systemd dbus connection. func (d *dbusConnManager) getConnection() (*systemdDbus.Conn, error) { - // In the case where d.conn != nil + // In the case where dbusC != nil // Use the read lock the first time to ensure // that Conn can be acquired at the same time. - d.RLock() - if conn := d.conn; conn != nil { - d.RUnlock() + dbusMu.RLock() + if conn := dbusC; conn != nil { + dbusMu.RUnlock() return conn, nil } - d.RUnlock() + dbusMu.RUnlock() - // In the case where d.conn == nil + // In the case where dbusC == nil // Use write lock to ensure that only one // will be created - d.Lock() - defer d.Unlock() - if conn := d.conn; conn != nil { + dbusMu.Lock() + defer dbusMu.Unlock() + if conn := dbusC; conn != nil { return conn, nil } @@ -48,12 +54,12 @@ func (d *dbusConnManager) getConnection() (*systemdDbus.Conn, error) { if err != nil { return nil, err } - d.conn = conn + dbusC = conn return conn, nil } func (d *dbusConnManager) newConnection() (*systemdDbus.Conn, error) { - if d.rootless { + if dbusRootless { return newUserSystemdDbus() } return systemdDbus.NewWithContext(context.TODO()) @@ -62,11 +68,11 @@ func (d *dbusConnManager) newConnection() (*systemdDbus.Conn, error) { // resetConnection resets the connection to its initial state // (so it can be reconnected if necessary). func (d *dbusConnManager) resetConnection(conn *systemdDbus.Conn) { - d.Lock() - defer d.Unlock() - if d.conn != nil && d.conn == conn { - d.conn.Close() - d.conn = nil + dbusMu.Lock() + defer dbusMu.Unlock() + if dbusC != nil && dbusC == conn { + dbusC.Close() + dbusC = nil } }