From 2911f505eefcfaea582d457c1fa18df34d151954 Mon Sep 17 00:00:00 2001 From: Jingxian He Date: Wed, 19 May 2021 21:33:22 +0800 Subject: [PATCH 21/72] pid: add pid recover method for criu The default pid recover method cannot recover the task pid at every time. We add a new pid recover method by setting the fork_pid of the parent task struct, add the kernel will alloc pid by the fork_pid. The new pid recover method can also avoid other tasks using the dumping task pids. Signed-off-by: Jingxian He --- criu/config.c | 1 + criu/cr-restore.c | 27 ++++++++++++++++++++++++++- criu/crtools.c | 1 + criu/include/cr_options.h | 1 + criu/include/pin-mem.h | 4 ++++ criu/include/restorer.h | 1 + criu/pie/restorer.c | 25 ++++++++++++++++++++++++- 7 files changed, 58 insertions(+), 2 deletions(-) diff --git a/criu/config.c b/criu/config.c index 53a5cfd..6dfbb01 100644 --- a/criu/config.c +++ b/criu/config.c @@ -699,6 +699,7 @@ int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd, BOOL_OPT("pin-memory", &opts.pin_memory), { "lsm-mount-context", required_argument, 0, 1099 }, { "network-lock", required_argument, 0, 1100 }, + BOOL_OPT("use-fork-pid", &opts.use_fork_pid), {}, }; diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 5514c29..497dd14 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -80,6 +80,7 @@ #include "timens.h" #include "bpfmap.h" #include "apparmor.h" +#include "pin-mem.h" #include "parasite-syscall.h" #include "files-reg.h" @@ -1340,6 +1341,23 @@ static int set_next_pid(void *arg) return 0; } +static int write_fork_pid(int pid) +{ + int fd, ret; + + fd = open(PIN_MEM_FILE, O_RDWR); + if (fd < 0) { + pr_warn("error open file: %s\n", PIN_MEM_FILE); + return -1; + } + ret = ioctl(fd, SET_FORK_PID, &pid); + if (ret < 0) { + pr_warn("write fork pid fail, errno: %s\n", strerror(errno)); + } + close(fd); + return ret; +} + static inline int fork_with_pid(struct pstree_item *item) { struct cr_clone_arg ca; @@ -1424,7 +1442,7 @@ static inline int fork_with_pid(struct pstree_item *item) if (!(ca.clone_flags & CLONE_NEWPID)) { lock_last_pid(); - if (!kdat.has_clone3_set_tid) { + if (!kdat.has_clone3_set_tid && !opts.use_fork_pid) { if (external_pidns) { /* * Restoring into another namespace requires a helper @@ -1434,6 +1452,12 @@ static inline int fork_with_pid(struct pstree_item *item) */ ret = call_in_child_process(set_next_pid, (void *)&pid); } else { + if (opts.use_fork_pid) { + ret = write_fork_pid(pid); + if (ret < 0) + goto err_unlock; + } + ret = set_next_pid((void *)&pid); } if (ret != 0) { @@ -3886,6 +3910,7 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns task_args->thread_args); task_args->pin_memory = opts.pin_memory; + task_args->use_fork_pid = opts.use_fork_pid; /* * An indirect call to task_restore, note it never returns diff --git a/criu/crtools.c b/criu/crtools.c index 1b90481..502acdf 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -448,6 +448,7 @@ usage: " --with-cpu-affinity Allow to restore cpu affinity. Only for hosts with\n" " same cpu quantity.\n" " --pin-memory Use pin memory method for checkpoint and restore.\n" + " --use-fork-pid Allow to restore task pid by setting fork pid of task struct.\n" "\n" "Check options:\n" " Without options, \"criu check\" checks availability of absolutely required\n" diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index 61898fd..923cc5f 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -191,6 +191,7 @@ struct cr_options { /* restore cpu affinity */ int with_cpu_affinity; int pin_memory; + int use_fork_pid; }; extern struct cr_options opts; diff --git a/criu/include/pin-mem.h b/criu/include/pin-mem.h index 7e53b12..2b54996 100644 --- a/criu/include/pin-mem.h +++ b/criu/include/pin-mem.h @@ -6,6 +6,7 @@ #include "vma.pb-c.h" #if __has_include("linux/pin_memory.h") +# define CONFIG_PID_RESERVE # include #else @@ -35,6 +36,9 @@ struct pin_mem_area_set { struct _pin_mem_area mem_area[MAX_PIN_MEM_AREA_NUM]; }; +#define _SET_FORK_PID 8 +#define SET_FORK_PID _IOW(PIN_MEM_MAGIC, _SET_FORK_PID, int) + #endif /* __has_include("linux/pin_memory.h") */ #define PIN_MEM_FILE "/dev/pinmem" diff --git a/criu/include/restorer.h b/criu/include/restorer.h index e0bdc04..93f87f4 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -233,6 +233,7 @@ struct task_restore_args { int child_subreaper; bool has_clone3_set_tid; bool pin_memory; + bool use_fork_pid; } __aligned(64); /* diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index db01ba5..1317582 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1426,6 +1426,22 @@ int remap_vmas(int pid) return ret; } +int write_fork_pid(int pid) +{ + int fd, ret; + + fd = sys_open(PIN_MEM_FILE, O_RDWR, 0); + if (fd < 0) { + pr_warn("error open file: %s\n", PIN_MEM_FILE); + return -1; + } + ret = sys_ioctl(fd, SET_FORK_PID, (unsigned long) &pid); + if (ret < 0) { + pr_warn("write fork pid fail fail: %d\n", pid); + } + sys_close(fd); + return ret; +} /* * The main routine to restore task via sigreturn. @@ -1815,7 +1831,7 @@ long __export_restore_task(struct task_restore_args *args) long parent_tid; int i, fd = -1; - if (!args->has_clone3_set_tid) { + if (!args->has_clone3_set_tid && !args->use_fork_pid) { /* One level pid ns hierarhy */ fd = sys_openat(args->proc_fd, LAST_PID_PATH, O_RDWR, 0); if (fd < 0) { @@ -1847,6 +1863,13 @@ long __export_restore_task(struct task_restore_args *args) pr_debug("Using clone3 to restore the process\n"); RUN_CLONE3_RESTORE_FN(ret, c_args, sizeof(c_args), &thread_args[i], args->clone_restore_fn); + } else if (args->use_fork_pid) { + if (write_fork_pid(thread_args[i].pid) < 0) { + pr_err("Clone fail with fork pid\n"); + mutex_unlock(&task_entries_local->last_pid_mutex); + goto core_restore_end; + } + RUN_CLONE_RESTORE_FN(ret, clone_flags, new_sp, parent_tid, thread_args, args->clone_restore_fn); } else { last_pid_len = std_vprint_num(last_pid_buf, sizeof(last_pid_buf), thread_args[i].pid - 1, &s); -- 2.34.1