[CRIU] [PATCH v3] freeze -- Wait for exiting tasks to complete
Cyrill Gorcunov
gorcunov at openvz.org
Tue Oct 11 13:14:19 PDT 2016
There is a small race between exitings tasks and cgroup freezer:
it can report a pid of exiting process which we will consider
as a zombie and refuse to checkpoint. Lets do a trick instead:
if we meets such task just wait a bit and repeate a freezing.
v3: Use EAGAIN instead of EPERM since EPERM collide
with general -1 error code.
Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
criu/seize.c | 35 ++++++++++++++++++++++++++---------
1 file changed, 26 insertions(+), 9 deletions(-)
diff --git a/criu/seize.c b/criu/seize.c
index e1e805a151db..257227f4d3d9 100644
--- a/criu/seize.c
+++ b/criu/seize.c
@@ -133,11 +133,16 @@ static int seize_cgroup_tree(char *root_path, const char *state)
snprintf(buf, sizeof(buf), "/proc/%d/exe", pid);
if (stat(buf, &st) == -1 && errno == ENOENT)
continue;
-
- /* fails when meets a zombie */
+ /*
+ * fails when meets a zombie, or eixting process:
+ * there is a small race in a kernel -- the process
+ * may start exiting and we are trying to freeze it
+ * before it compete exit procedure. The caller simply
+ * should wait a bit and try freezing again.
+ */
pr_err("zombie found while seizing\n");
fclose(f);
- return -1;
+ return -EAGAIN;
}
}
fclose(f);
@@ -150,6 +155,7 @@ static int seize_cgroup_tree(char *root_path, const char *state)
while ((de = readdir(dir))) {
struct stat st;
+ int ret;
if (dir_dots(de))
continue;
@@ -164,10 +170,10 @@ static int seize_cgroup_tree(char *root_path, const char *state)
if (!S_ISDIR(st.st_mode))
continue;
-
- if (seize_cgroup_tree(path, state) < 0) {
+ ret = seize_cgroup_tree(path, state);
+ if (ret < 0) {
closedir(dir);
- return -1;
+ return ret;
}
}
closedir(dir);
@@ -325,7 +331,7 @@ static int freeze_processes(void)
static const unsigned long step_ms = 100;
unsigned long nr_attempts = (opts.timeout * 1000000) / step_ms;
- unsigned long i;
+ unsigned long i = 0;
const struct timespec req = {
.tv_nsec = step_ms * 1000000,
@@ -371,7 +377,7 @@ static int freeze_processes(void)
* not read @tasks pids while freezer in
* transition stage.
*/
- for (i = 0; i <= nr_attempts; i++) {
+ for (; i <= nr_attempts; i++) {
state = get_freezer_state(fd);
if (!state) {
close(fd);
@@ -395,7 +401,18 @@ static int freeze_processes(void)
pr_debug("freezing processes: %lu attempts done\n", i);
}
- exit_code = seize_cgroup_tree(opts.freeze_cgroup, state);
+ /*
+ * Pay attention on @i variable -- it's continuation.
+ */
+ for (; i <= nr_attempts; i++) {
+ exit_code = seize_cgroup_tree(opts.freeze_cgroup, state);
+ if (exit_code == -EAGAIN) {
+ if (alarm_timeouted())
+ goto err;
+ nanosleep(&req, NULL);
+ } else
+ break;
+ }
err:
if (exit_code == 0 || freezer_thawed) {
--
2.7.4
More information about the CRIU
mailing list