Commit f020bef7 authored by Tycho Andersen's avatar Tycho Andersen Committed by Pavel Emelyanov

remap: add a dead pid /proc remap

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: 's avatarTycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent c09ba04c
......@@ -1426,6 +1426,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))
......@@ -1495,6 +1498,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;
......@@ -1706,6 +1710,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)
......
......@@ -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,6 +294,9 @@ 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;
......@@ -516,6 +550,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;
......@@ -557,6 +605,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
......
......@@ -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__ */
......@@ -171,6 +171,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,
CR_STATE_RESTORE_SIGCHLD,
......
enum remap_type {
LINKED = 0;
GHOST = 1;
PROCFS = 2;
};
message remap_file_path_entry {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment