[CRIU] [PATCH 1/2] --freeze-cgroup: should also seize tasks in sub-cgroups

Tycho Andersen tycho.andersen at canonical.com
Fri Nov 20 06:35:19 PST 2015


On Fri, Nov 20, 2015 at 04:46:15PM +0300, Andrew Vagin wrote:
> On Thu, Nov 19, 2015 at 09:15:59AM -0700, Tycho Andersen wrote:
> > Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
> > CC: Andrew Vagin <avagin at virtuozzo.com>
> > ---
> >  seize.c | 124 +++++++++++++++++++++++++++++++++++++++++++---------------------
> >  1 file changed, 84 insertions(+), 40 deletions(-)
> > 
> > diff --git a/seize.c b/seize.c
> > index 943f9d1..3281dd0 100644
> > --- a/seize.c
> > +++ b/seize.c
> > @@ -79,12 +79,93 @@ static int freezer_restore_state(void)
> >  	return 0;
> >  }
> >  
> > +static int seize_cgroup_tree(char *root_path, const char *state)
> > +{
> > +	DIR *dir;
> > +	struct dirent *de;
> > +	char path[PATH_MAX];
> > +	FILE *f;
> > +
> > +	/*
> > +	 * New tasks can appear while a freezer state isn't
> > +	 * frozen, so we need to catch all new tasks.
> > +	 */
> > +	snprintf(path, sizeof(path), "%s/tasks", root_path);
> > +	f = fopen(path, "r");
> > +	if (f == NULL) {
> > +		pr_perror("Unable to open %s", path);
> > +		return -1;
> > +	}
> > +	while (fgets(path, sizeof(path), f)) {
> > +		pid_t pid;
> > +		int ret;
> > +
> > +		pid = atoi(path);
> > +
> > +		/*
> > +		 * Here we are going to skip tasks which are already traced.
> > +		 * Ptraced tasks looks like children for us, so if
> > +		 * a task isn't ptraced yet, waitpid() will return a error.
> > +		 */
> > +		ret = wait4(pid, NULL, __WALL | WNOHANG, NULL);
> > +		if (ret == 0)
> > +			continue;
> > +
> > +		if (seize_catch_task(pid) && state == frozen) {
> > +			char buf[] = "/proc/XXXXXXXXXX/exe";
> > +			struct stat st;
> > +
> > +			/* skip kernel threads */
> > +			snprintf(buf, sizeof(buf), "/proc/%d/exe", pid);
> > +			if (stat(buf, &st) == -1 && errno == ENOENT)
> > +				continue;
> > +
> > +			/* fails when meets a zombie */
> > +			pr_err("zombie found while seizing\n");
> > +			fclose(f);
> > +			return -1;
> > +		}
> > +	}
> > +	fclose(f);
> > +
> > +	dir = opendir(root_path);
> > +	if (!dir) {
> > +		pr_perror("Unable to open %s", root_path);
> > +		return -1;
> > +	}
> > +
> > +	while ((de = readdir(dir))) {
> > +		struct stat st;
> > +
> > +		if (dir_dots(de))
> > +			continue;
> > +
> > +		sprintf(path, "%s/%s", root_path, de->d_name);
> > +
> > +		if (fstatat(dirfd(dir), de->d_name, &st, 0) < 0) {
> > +			pr_perror("stat of %s failed", path);
> > +			closedir(dir);
> > +			return -1;
> > +		}
> > +
> > +		if (!S_ISDIR(st.st_mode))
> > +			continue;
> > +
> > +		if (seize_cgroup_tree(path, state) < 0) {
> 
> I don't like this recursion. We don't know how deep it is, so are you
> sure that we will not have a problem with too big stack?

It is limited by PATH_MAX at least, although maybe that is not enough,
I'm not sure. I can resend an iterative version if you like.

Tycho


More information about the CRIU mailing list