static DBusConnection *connection;
#define CGMANAGER_DBUS_SOCK "unix:path=/sys/fs/cgroup/cgmanager/sock"
-static void cgm_dbus_disconnected(DBusConnection *connection);
static bool cgm_dbus_connect(void)
{
DBusError dbus_error;
dbus_error_init(&dbus_error);
lock_mutex(&thread_mutex);
- connection = nih_dbus_connect(CGMANAGER_DBUS_SOCK, cgm_dbus_disconnected);
+ connection = nih_dbus_connect(CGMANAGER_DBUS_SOCK, NULL);
if (!connection) {
NihError *nerr;
nerr = nih_error_get();
ERROR("Error pinging cgroup manager: %s", nerr->message);
nih_free(nerr);
}
- unlock_mutex(&thread_mutex);
return true;
}
static void cgm_dbus_disconnect(void)
{
- lock_mutex(&thread_mutex);
if (cgroup_manager)
nih_free(cgroup_manager);
cgroup_manager = NULL;
- dbus_connection_unref(connection);
+ if (connection)
+ dbus_connection_unref(connection);
connection = NULL;
unlock_mutex(&thread_mutex);
}
-static void cgm_dbus_disconnected(DBusConnection *connection)
-{
- lock_mutex(&thread_mutex);
- WARN("Cgroup manager connection was terminated");
- cgroup_manager = NULL;
- dbus_connection_unref(connection);
- connection = NULL;
- unlock_mutex(&thread_mutex);
- if (cgm_dbus_connect()) {
- INFO("New cgroup manager connection was opened");
- } else {
- WARN("Cgroup manager unable to re-open connection");
- }
-}
-
static int send_creds(int sock, int rpid, int ruid, int rgid)
{
struct msghdr msg = { 0 };
return 0;
}
+/*
+ * Called during container startup. The cgmanager socket is open
+ */
static bool lxc_cgmanager_create(const char *controller, const char *cgroup_path, int32_t *existed)
{
- lock_mutex(&thread_mutex);
if ( cgmanager_create_sync(NULL, cgroup_manager, controller,
cgroup_path, existed) != 0) {
NihError *nerr;
ERROR("call to cgmanager_create_sync failed: %s", nerr->message);
nih_free(nerr);
ERROR("Failed to create %s:%s", controller, cgroup_path);
- unlock_mutex(&thread_mutex);
return false;
}
- unlock_mutex(&thread_mutex);
return true;
}
{
pid_t me = getpid();
int i;
- lock_mutex(&thread_mutex);
for (i = 0; i < nr_subsystems; i++) {
if (cgmanager_move_pid_abs_sync(NULL, cgroup_manager,
subsystems[i], "/", me) != 0) {
ERROR("call to cgmanager_move_pid_abs_sync(%s) failed: %s",
subsystems[i], nerr->message);
nih_free(nerr);
- unlock_mutex(&thread_mutex);
return false;
}
}
- unlock_mutex(&thread_mutex);
return true;
}
uid_t caller_nsuid = get_ns_uid(origuid);
- lock_mutex(&thread_mutex);
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) < 0) {
SYSERROR("Error creating socketpair");
goto out;
out:
close(sv[0]);
close(sv[1]);
- unlock_mutex(&thread_mutex);
if (ret == 1 && *buf == '1')
return 0;
return -1;
return do_chown_cgroup(arg->controller, arg->cgroup_path, arg->origuid);
}
+/*
+ * Called during container startup. The cgmanager socket is open
+ */
static bool lxc_cgmanager_chmod(const char *controller,
const char *cgroup_path, const char *file, int mode)
{
- lock_mutex(&thread_mutex);
if (cgmanager_chmod_sync(NULL, cgroup_manager, controller,
cgroup_path, file, mode) != 0) {
NihError *nerr;
nerr = nih_error_get();
ERROR("call to cgmanager_chmod_sync failed: %s", nerr->message);
nih_free(nerr);
- unlock_mutex(&thread_mutex);
return false;
}
- unlock_mutex(&thread_mutex);
return true;
}
+/*
+ * Called during container startup. The cgmanager socket is open
+ */
static bool chown_cgroup(const char *controller, const char *cgroup_path,
struct lxc_conf *conf)
{
static void cgm_remove_cgroup(const char *controller, const char *path)
{
int existed;
- lock_mutex(&thread_mutex);
if ( cgmanager_remove_sync(NULL, cgroup_manager, controller,
path, CG_REMOVE_RECURSIVE, &existed) != 0) {
NihError *nerr;
nerr = nih_error_get();
ERROR("call to cgmanager_remove_sync failed: %s", nerr->message);
nih_free(nerr);
- unlock_mutex(&thread_mutex);
ERROR("Error removing %s:%s", controller, path);
}
- unlock_mutex(&thread_mutex);
if (existed == -1)
INFO("cgroup removal attempt: %s:%s did not exist", controller, path);
}
+/*
+ * We are starting up a container. We open the cgmanager socket, and leave it
+ * open (and mutex held) for the rest of container startup.
+ */
static void *cgm_init(const char *name)
{
struct cgm_data *d;
- cgm_dbus_connect();
+ if (!cgm_dbus_connect()) {
+ ERROR("Error connecting to cgroup manager");
+ return NULL;
+ }
d = malloc(sizeof(*d));
if (!d)
return NULL;
return NULL;
}
+/*
+ * Called after a failed container startup. The cgmanager socket was just
+ * closed at end of lxc_spawn. We need to re-open
+ */
static void cgm_destroy(void *hdata)
{
struct cgm_data *d = hdata;
if (!d)
return;
- cgm_dbus_connect();
+ if (!cgm_dbus_connect()) {
+ ERROR("Error connecting to cgroup manager");
+ return;
+ }
for (i = 0; i < nr_subsystems; i++)
cgm_remove_cgroup(subsystems[i], d->cgroup_path);
cgm_remove_cgroup(subsystems[i], path);
}
+/*
+ * Called during container startup. The cgmanager socket is open
+ */
static inline bool cgm_create(void *hdata)
{
struct cgm_data *d = hdata;
static bool lxc_cgmanager_enter(pid_t pid, const char *controller,
const char *cgroup_path)
{
- lock_mutex(&thread_mutex);
if (cgmanager_move_pid_sync(NULL, cgroup_manager, controller,
cgroup_path, pid) != 0) {
NihError *nerr;
nerr = nih_error_get();
ERROR("call to cgmanager_move_pid_sync failed: %s", nerr->message);
nih_free(nerr);
- unlock_mutex(&thread_mutex);
return false;
}
- unlock_mutex(&thread_mutex);
return true;
}
return true;
}
+/*
+ * called during container startup. cgmanager socket is open
+ */
static inline bool cgm_enter(void *hdata, pid_t pid)
{
struct cgm_data *d = hdata;
return d->cgroup_path;
}
+/*
+ * nrtasks is called by the utmp helper by the container monitor.
+ * cgmanager socket was closed after cgroup setup was complete, so we need
+ * to reopen here.
+ */
static int cgm_get_nrtasks(void *hdata)
{
struct cgm_data *d = hdata;
if (!d || !d->cgroup_path)
return false;
- lock_mutex(&thread_mutex);
+ if (!cgm_dbus_connect()) {
+ ERROR("Error connecting to cgroup manager");
+ return false;
+ }
if (cgmanager_get_tasks_sync(NULL, cgroup_manager, subsystems[0],
d->cgroup_path, &pids, &pids_len) != 0) {
NihError *nerr;
nerr = nih_error_get();
ERROR("call to cgmanager_get_tasks_sync failed: %s", nerr->message);
nih_free(nerr);
- unlock_mutex(&thread_mutex);
+ cgm_dbus_disconnect();
return -1;
}
- unlock_mutex(&thread_mutex);
nih_free(pids);
+ cgm_dbus_disconnect();
return pids_len;
}
+/*
+ * cgm_get is called to get container cgroup settings. cgmanager is not
+ * connected.
+ */
static int cgm_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
{
char *result, *controller, *key, *cgroup;
cgroup = lxc_cmd_get_cgroup_path(name, lxcpath, controller);
if (!cgroup)
return -1;
- cgm_dbus_connect();
- lock_mutex(&thread_mutex);
+ if (!cgm_dbus_connect()) {
+ ERROR("Error connecting to cgroup manager");
+ free(cgroup);
+ return -1;
+ }
if (cgmanager_get_value_sync(NULL, cgroup_manager, controller, cgroup, filename, &result) != 0) {
/*
* must consume the nih error
nerr = nih_error_get();
nih_free(nerr);
free(cgroup);
- unlock_mutex(&thread_mutex);
cgm_dbus_disconnect();
return -1;
}
- unlock_mutex(&thread_mutex);
cgm_dbus_disconnect();
free(cgroup);
newlen = strlen(result);
const char *cgroup, const char *value)
{
int ret;
- lock_mutex(&thread_mutex);
ret = cgmanager_set_value_sync(NULL, cgroup_manager, controller,
cgroup, file, value);
if (ret != 0) {
nih_free(nerr);
ERROR("Error setting cgroup %s limit %s", file, cgroup);
}
- unlock_mutex(&thread_mutex);
return ret;
}
+/*
+ * cgm_set is called to change cgroup settings. cgmanager is not connected
+ */
static int cgm_set(const char *filename, const char *value, const char *name, const char *lxcpath)
{
char *controller, *key, *cgroup;
controller, lxcpath, name);
return -1;
}
- cgm_dbus_connect();
+ if (!cgm_dbus_connect()) {
+ ERROR("Error connecting to cgroup manager");
+ free(cgroup);
+ return -1;
+ }
ret = cgm_do_set(controller, filename, cgroup, value);
cgm_dbus_disconnect();
free(cgroup);
return false;
}
+/*
+ * called during cgroup.c:cgroup_ops_init(), at startup. No threads.
+ * We check whether we can talk to cgmanager, escape to root cgroup if
+ * we are root, then close the connection.
+ */
struct cgroup_ops *cgm_ops_init(void)
{
if (!collect_subsytems())
goto err1;
// root; try to escape to root cgroup
- if (geteuid() == 0 && !lxc_cgmanager_escape())
+ if (geteuid() == 0 && !lxc_cgmanager_escape()) {
+ cgm_dbus_disconnect();
goto err2;
+ }
+ cgm_dbus_disconnect();
return &cgmanager_ops;
return NULL;
}
+/*
+ * unfreeze is called by the command api after killing a container.
+ * cgmanager is not connected.
+ */
static bool cgm_unfreeze(void *hdata)
{
struct cgm_data *d = hdata;
if (!d || !d->cgroup_path)
return false;
- lock_mutex(&thread_mutex);
+ if (!cgm_dbus_connect()) {
+ ERROR("Error connecting to cgroup manager");
+ return false;
+ }
if (cgmanager_set_value_sync(NULL, cgroup_manager, "freezer", d->cgroup_path,
"freezer.state", "THAWED") != 0) {
NihError *nerr;
ERROR("call to cgmanager_set_value_sync failed: %s", nerr->message);
nih_free(nerr);
ERROR("Error unfreezing %s", d->cgroup_path);
- unlock_mutex(&thread_mutex);
+ cgm_dbus_disconnect();
return false;
}
- unlock_mutex(&thread_mutex);
+ cgm_dbus_disconnect();
return true;
}
+/*
+ * setup_limits is called during startup. cgmanager is connected, and mutex
+ * is held
+ */
static bool cgm_setup_limits(void *hdata, struct lxc_list *cgroup_settings, bool do_devices)
{
struct cgm_data *d = hdata;
goto out;
}
- cgm_dbus_connect();
+ if (!cgm_dbus_connect()) {
+ ERROR("Error connecting to cgroup manager");
+ goto out;
+ }
if (!(pass = do_cgm_enter(pid, cgroup)))
ERROR("Failed to enter group %s", cgroup);
cgm_dbus_disconnect();