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

Andrew Vagin avagin at virtuozzo.com
Fri Nov 20 05:46:15 PST 2015


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?

> +			closedir(dir);
> +			return -1;
> +		}
> +	}
> +	closedir(dir);
> +
> +	return 0;
> +}
> +
>  static int freeze_processes(void)
>  {
> -	int i, ret, fd, exit_code = -1;
> +	int i, fd, exit_code = -1;
>  	char path[PATH_MAX];
>  	const char *state = thawed;
> -	FILE *f;
>  
>  	snprintf(path, sizeof(path), "%s/freezer.state", opts.freeze_cgroup);
>  	fd = open(path, O_RDWR);
> @@ -117,45 +198,8 @@ static int freeze_processes(void)
>  		struct timespec req = {};
>  		u64 timeout;
>  
> -		/*
> -		 * 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", opts.freeze_cgroup);
> -		f = fopen(path, "r");
> -		if (f == NULL) {
> -			pr_perror("Unable to open %s", path);
> +		if (seize_cgroup_tree(opts.freeze_cgroup, state) < 0)
>  			goto err;
> -		}
> -		while (fgets(path, sizeof(path), f)) {
> -			pid_t pid;
> -
> -			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 */
> -				fclose(f);
> -				goto err;
> -			}
> -		}
> -		fclose(f);
>  
>  		if (state == frozen)
>  			break;
> -- 
> 2.6.2
> 


More information about the CRIU mailing list