[CRIU] [PATCH 3/4] remap: add a dead pid /proc remap
Tycho Andersen
tycho.andersen at canonical.com
Fri Sep 12 17:43:30 PDT 2014
If a file like /proc/20/mountinfo is open, but 20 is a zombie (or doesn't exist
any more), we can't read this file at all, so a link remap won't work. Instead,
we add a new remap, called the dead process remap, which forks a TASK_HELPER as
that dead pid so that the restore task can open the new /proc/20/mountinfo
instead.
This commit also adds a new stage CR_STATE_RESTORE_SHARED. Since new
TASK_HELPERS are added when loading the shared resource images, we need to wait
to start forking tasks until after these resources are loaded.
v2: fix a mutex bug
Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
---
cr-restore.c | 7 ++++
files-reg.c | 81 +++++++++++++++++++++++++++++++++++++++++-
include/fs-magic.h | 4 +++
include/restorer.h | 1 +
protobuf/remap-file-path.proto | 1 +
5 files changed, 93 insertions(+), 1 deletion(-)
diff --git a/cr-restore.c b/cr-restore.c
index 7bcdf6e..1d96ef4 100644
--- a/cr-restore.c
+++ b/cr-restore.c
@@ -1416,6 +1416,9 @@ static int restore_task_with_children(void *_arg)
if (root_prepare_shared())
goto err_fini_mnt;
+
+ if (restore_finish_stage(CR_STATE_RESTORE_SHARED) < 0)
+ goto err_fini_mnt;
}
if (prepare_mappings(pid))
@@ -1485,6 +1488,7 @@ static inline int stage_participants(int next_stage)
case CR_STATE_FAIL:
return 0;
case CR_STATE_RESTORE_NS:
+ case CR_STATE_RESTORE_SHARED:
return 1;
case CR_STATE_FORKING:
return task_entries->nr_tasks + task_entries->nr_helpers;
@@ -1697,6 +1701,9 @@ static int restore_root_task(struct pstree_item *init)
goto out;
timing_start(TIME_FORK);
+ ret = restore_switch_stage(CR_STATE_RESTORE_SHARED);
+ if (ret < 0)
+ goto out;
ret = restore_switch_stage(CR_STATE_FORKING);
if (ret < 0)
diff --git a/files-reg.c b/files-reg.c
index 835911a..0b01f31 100644
--- a/files-reg.c
+++ b/files-reg.c
@@ -24,6 +24,7 @@
#include "asm/atomic.h"
#include "namespaces.h"
#include "proc_parse.h"
+#include "pstree.h"
#include "protobuf.h"
#include "protobuf/regfile.pb-c.h"
@@ -226,6 +227,36 @@ static int open_remap_linked(struct reg_file_info *rfi,
return 0;
}
+static int open_remap_dead_process(struct reg_file_info *rfi,
+ RemapFilePathEntry *rfe)
+{
+ struct pstree_item *helper;
+
+ for_each_pstree_item(helper) {
+ /* don't need to add multiple tasks */
+ if (helper->pid.virt == rfe->remap_id) {
+ pr_info("Skipping helper for restoring /proc/%d; pid exists\n", rfe->remap_id);
+ return 0;
+ }
+ }
+
+ helper = alloc_pstree_item_with_rst();
+ if (!helper)
+ return -1;
+
+ helper->sid = root_item->sid;
+ helper->pgid = root_item->pgid;
+ helper->pid.virt = rfe->remap_id;
+ helper->state = TASK_HELPER;
+ helper->parent = root_item;
+ list_add_tail(&helper->sibling, &root_item->children);
+ task_entries->nr_helpers++;
+
+ pr_info("Added a helper for restoring /proc/%d\n", helper->pid.virt);
+
+ return 0;
+}
+
static int collect_one_remap(void *obj, ProtobufCMessage *msg)
{
int ret = -1;
@@ -263,11 +294,13 @@ static int collect_one_remap(void *obj, ProtobufCMessage *msg)
case REMAP_TYPE__GHOST:
ret = open_remap_ghost(rfi, rfe);
break;
+ case REMAP_TYPE__PROCFS:
+ ret = open_remap_dead_process(rfi, rfe);
+ break;
default:
pr_err("unknown remap type %u\n", rfe->remap_type);
goto out;
}
-
out:
return ret;
}
@@ -515,6 +548,20 @@ static int dump_linked_remap(char *path, int len, const struct stat *ost,
&rpe, PB_REMAP_FPATH);
}
+static int dump_dead_process_remap(pid_t pid, char *path, int len, const struct stat *ost,
+ int lfd, u32 id, struct ns_id *nsid)
+{
+ RemapFilePathEntry rpe = REMAP_FILE_PATH_ENTRY__INIT;
+
+ rpe.orig_id = id;
+ rpe.remap_id = pid;
+ rpe.has_remap_type = true;
+ rpe.remap_type = REMAP_TYPE__PROCFS;
+
+ return pb_write_one(fdset_fd(glob_fdset, CR_FD_REMAP_FPATH),
+ &rpe, PB_REMAP_FPATH);
+}
+
static bool is_sillyrename_name(char *name)
{
int i;
@@ -556,6 +603,38 @@ static int check_path_remap(char *rpath, int plen, const struct fd_parms *parms,
struct stat pst;
const struct stat *ost = &parms->stat;
+ if (parms->fs_type == PROC_SUPER_MAGIC) {
+ /* The file points to /proc/pid/<foo> where pid is a dead
+ * process. We remap this file by adding this pid to be
+ * fork()ed into a TASK_HELPER state so that we can point to it
+ * on restore.
+ */
+ pid_t pid;
+ char *start, *end;
+
+ /* skip "./proc/" */
+ start = strstr(rpath, "/") + 1;
+ if (!start)
+ return -1;
+ start = strstr(start, "/") + 1;
+ if (!start)
+ return -1;
+ pid = strtol(start, &end, 10);
+
+ /* if we didn't find another /, this path something
+ * like ./proc/kmsg, which we shouldn't mess with. */
+ if (*end == '/') {
+ *end = 0;
+ ret = access(rpath, F_OK);
+ *end = '/';
+
+ if (ret) {
+ pr_info("Dumping dead process remap of %d\n", pid);
+ return dump_dead_process_remap(pid, rpath + 1, plen - 1, ost, lfd, id, nsid);
+ }
+ }
+ }
+
if (ost->st_nlink == 0)
/*
* Unpleasant, but easy case. File is completely invisible
diff --git a/include/fs-magic.h b/include/fs-magic.h
index 13c4961..777d736 100644
--- a/include/fs-magic.h
+++ b/include/fs-magic.h
@@ -41,4 +41,8 @@
#define AUFS_SUPER_MAGIC 0x61756673
#endif
+#ifndef PROC_SUPER_MAGIC
+#define PROC_SUPER_MAGIC 0x9fa0
+#endif
+
#endif /* __CR_FS_MAGIC_H__ */
diff --git a/include/restorer.h b/include/restorer.h
index dbb7109..16ee645 100644
--- a/include/restorer.h
+++ b/include/restorer.h
@@ -168,6 +168,7 @@ static inline unsigned long restorer_stack(struct thread_restore_args *a)
enum {
CR_STATE_FAIL = -1,
CR_STATE_RESTORE_NS = 0, /* is used for executing "setup-namespace" scripts */
+ CR_STATE_RESTORE_SHARED,
CR_STATE_FORKING,
CR_STATE_RESTORE_FS,
CR_STATE_RESTORE,
diff --git a/protobuf/remap-file-path.proto b/protobuf/remap-file-path.proto
index cb8568f..6af62b1 100644
--- a/protobuf/remap-file-path.proto
+++ b/protobuf/remap-file-path.proto
@@ -1,6 +1,7 @@
enum remap_type {
LINKED = 0;
GHOST = 1;
+ PROCFS = 2;
};
message remap_file_path_entry {
--
1.9.1
More information about the CRIU
mailing list