Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restore a thread to a correct v1 cgroup #2347

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions criu/cgroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -427,10 +427,11 @@ static int dump_cg_props_array(const char *fpath, struct cgroup_dir *ncd, const
}

/*
* Set the is_threaded flag if cgroup.type's value is threaded,
* ignore all other values.
* Set the is_threaded flag if cgroup.type's value is threaded
* or it is a cgroup v1 (it has a 'tasks' property).
StepanPieshkin marked this conversation as resolved.
Show resolved Hide resolved
* Ignore all other values.
*/
if (!strcmp("cgroup.type", prop->name) && !strcmp("threaded", prop->value))
if ((!strcmp("cgroup.type", prop->name) && !strcmp("threaded", prop->value)) || !strcmp("tasks", prop->name))
StepanPieshkin marked this conversation as resolved.
Show resolved Hide resolved
controller->is_threaded = true;

pr_info("Dumping value %s from %s/%s\n", prop->value, fpath, prop->name);
Expand Down Expand Up @@ -1922,7 +1923,7 @@ static int prepare_cgroup_sfd(CgroupEntry *ce)
if (ctrl->cnames[0][0] == 0)
fstype = "cgroup2";

pr_debug("\tMaking controller dir %s (%s)\n", paux, opt);
pr_debug("\tMaking controller dir %s (%s), type %s\n", paux, opt, fstype);
if (mkdir(paux, 0700)) {
pr_perror("\tCan't make controller dir %s", paux);
return -1;
Expand Down Expand Up @@ -1985,6 +1986,7 @@ static int cgroupd(int sk)
CgMemberEntry *ce = cg_set_entry->ctls[i];
char aux[PATH_MAX];
CgControllerEntry *ctrl = NULL;
const char *format;

for (j = 0; j < n_controllers; j++) {
CgControllerEntry *cur = controllers[j];
Expand All @@ -2008,7 +2010,8 @@ static int cgroupd(int sk)
continue;

aux_off = ctrl_dir_and_opt(ctrl, aux, sizeof(aux), NULL, 0);
snprintf(aux + aux_off, sizeof(aux) - aux_off, "/%s/cgroup.threads", ce->path);
format = ctrl->cnames[0][0] ? "/%s/tasks" : "/%s/cgroup.threads";
snprintf(aux + aux_off, sizeof(aux) - aux_off, format, ce->path);

/*
* Cgroupd runs outside of the namespaces so we don't
Expand Down
3 changes: 3 additions & 0 deletions test/zdtm/static/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ TST_DIR = \
cgroup_ignore \
cgroup_stray \
cgroup_yard \
cgroup_threads \
unlink_fstat04 \
unlink_fstat041 \
mntns_remap \
Expand Down Expand Up @@ -684,6 +685,8 @@ s390x_gs_threads: LDFLAGS += -pthread

thread_different_uid_gid: LDLIBS += -pthread -lcap

cgroup_threads: LDFLAGS += -pthread

bpf_hash: LDLIBS += -lbpf
bpf_array: LDLIBS += -lbpf

Expand Down
155 changes: 155 additions & 0 deletions test/zdtm/static/cgroup_threads.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <stdlib.h>
#include <pthread.h>
#include "zdtmtst.h"

const char *test_doc = "Check that cgroup layout of threads is preserved";

Check warning on line 11 in test/zdtm/static/cgroup_threads.c

View workflow job for this annotation

GitHub Actions / build

Copy link
Member

@Snorch Snorch Feb 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: clang-format is complaining about alignment here. s/\t/ / here and below.

const char *test_author = "Michał Cłapiński <[email protected]>";

char *dirname;
TEST_OPTION(dirname, string, "cgroup directory name", 1);
static const char *cgname = "zdtmtst";
#define SUBNAME "subcg_threads"
#define SUBNAME2 SUBNAME "/subsubcg"

static int cg_move(char *name)
{
int cgfd, l;
char paux[256];

sprintf(paux, "%s/%s", dirname, name);
mkdir(paux, 0600);

sprintf(paux, "%s/%s/tasks", dirname, name);

cgfd = open(paux, O_WRONLY);
if (cgfd < 0) {
pr_perror("Can't open tasks");
return -1;
}

l = write(cgfd, "0", 2);
close(cgfd);

if (l < 0) {
pr_perror("Can't move self to subcg");
return -1;
}

return 0;
}

static int cg_check(char *name)
{
int found = 0;
FILE *cgf;
char paux[256], aux[128];

cgf = fopen("/proc/thread-self/cgroup", "r");
if (cgf == NULL)
return -1;

sprintf(aux, "name=%s:/%s", cgname, name);
while (fgets(paux, sizeof(paux), cgf)) {
char *s;

s = strchr(paux, ':') + 1;
s[strlen(s) - 1] = '\0';
test_msg("CMP [%s] vs [%s]\n", s, aux);
if (!strcmp(s, aux)) {
found = 1;
break;
}
}

fclose(cgf);

return found ? 0 : -1;
}

int p1[2], pr[2];

void *child(void *args)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Misleading name for a thread, don't you think?

{
int status = cg_move(SUBNAME2);
write(p1[1], &status, sizeof(status));

if (status == 0) {
read(pr[0], &status, sizeof(status));

status = cg_check(SUBNAME2);
write(p1[1], &status, sizeof(status));
}

pthread_exit(0);
}

int main(int argc, char **argv)
{
char aux[64];
int status;
pthread_t thread;

test_init(argc, argv);

/*
* Pipe to talk to the kid.
* First, it reports that it's ready (int),
* then it reports the restore status (int).
*/

pipe(p1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pls handler errors here and in other places.


/* "Restore happened" pipe */
pipe(pr);

if (mkdir(dirname, 0700) < 0) {
pr_perror("Can't make dir");
goto out;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it has to exit with a non-zero code in this case.

}

sprintf(aux, "none,name=%s", cgname);
if (mount("none", dirname, "cgroup", 0, aux)) {
pr_perror("Can't mount cgroups");
goto out_rd;
}

if (cg_move(SUBNAME))
goto out_rs;

pthread_create(&thread, NULL, child, NULL);

status = -1;
read(p1[0], &status, sizeof(status));
if (status != 0) {
pr_perror("Error moving into cgroups");
close(pr[0]);
goto out_rs;
}

test_daemon();
test_waitsig();

close(pr[1]);

status = -1;
read(p1[0], &status, sizeof(status));
if (status != 0) {
fail("child cg changed");
goto out_rs;
}

pass();

out_rs:
umount(dirname);
out_rd:
rmdir(dirname);
out:
return 0;
}
1 change: 1 addition & 0 deletions test/zdtm/static/cgroup_threads.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{'flavor': 'h', 'flags': 'suid', 'opts': '--manage-cgroups'}
19 changes: 19 additions & 0 deletions test/zdtm/static/cgroup_threads.hook
StepanPieshkin marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/bash

[ "$1" == "--clean" -o "$1" == "--pre-restore" ] || exit 0

set -e

tname=$(mktemp -d cgclean.XXXXXX)
StepanPieshkin marked this conversation as resolved.
Show resolved Hide resolved
trap 'rmdir "${tname}"' EXIT

mount -t cgroup none $tname -o "none,name=zdtmtst"
StepanPieshkin marked this conversation as resolved.
Show resolved Hide resolved
trap 'umount "${tname}"; rmdir "${tname}"' EXIT

echo "Cleaning $tname"

rmdir "$tname/subcg_threads/subsubcg/" || true
rmdir "$tname/subcg_threads/" || true

echo "Left there is:"
ls "$tname"
StepanPieshkin marked this conversation as resolved.
Show resolved Hide resolved
Loading