2012-01-10 18:03:00 +04:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
2012-01-11 15:45:00 +04:00
|
|
|
#include <errno.h>
|
2012-01-10 18:03:00 +04:00
|
|
|
|
|
|
|
#include <linux/limits.h>
|
2013-02-08 02:54:24 +04:00
|
|
|
#include <linux/major.h>
|
2012-01-10 18:03:00 +04:00
|
|
|
|
2012-01-11 15:45:00 +04:00
|
|
|
#include <sys/types.h>
|
2012-02-07 19:32:11 +04:00
|
|
|
#include <sys/prctl.h>
|
2012-01-11 15:45:00 +04:00
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/un.h>
|
2012-05-29 20:11:00 +04:00
|
|
|
#include <stdlib.h>
|
2012-01-11 15:45:00 +04:00
|
|
|
|
2012-01-10 18:03:00 +04:00
|
|
|
#include "files.h"
|
2013-02-08 02:49:33 +04:00
|
|
|
#include "file-ids.h"
|
2012-06-22 16:24:00 +04:00
|
|
|
#include "files-reg.h"
|
locks: Don't dump locks in per-task manner (v3)
We have a problem with file locks (bug #2512) -- the /proc/locks
file shows the ID of lock creator, not the owner. Thus, if the
creator died, but holder is still alive, criu fails to dump the
lock held by latter task.
The proposal is to find who _might_ hold the lock by checking
for dev:inode pairs on lock vs file descriptors being dumped.
If the creator of the lock is still alive, then he will take
the priority.
One thing to note about flocks -- these belong to file entries,
not to tasks. Thus, when we meet one, we should check whether
the flock is really held by task's FD by trying to set yet
another one. In case of success -- lock really belongs to fd
we dump, in case it doesn't trylock should fail.
At the very end -- walk the list of locks and dump them all at
once, which is possible by merge of per-task file-locks images
into one global one.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-09-02 17:43:06 +04:00
|
|
|
#include "file-lock.h"
|
2012-01-10 18:03:00 +04:00
|
|
|
#include "image.h"
|
|
|
|
#include "list.h"
|
|
|
|
#include "util.h"
|
2013-07-29 12:43:30 +04:00
|
|
|
#include "util-pie.h"
|
2012-01-10 18:03:00 +04:00
|
|
|
#include "lock.h"
|
2012-03-27 12:42:59 +04:00
|
|
|
#include "sockets.h"
|
2012-06-26 14:51:00 +04:00
|
|
|
#include "pstree.h"
|
2012-09-12 20:00:54 +04:00
|
|
|
#include "tty.h"
|
2013-02-08 02:54:24 +04:00
|
|
|
#include "pipes.h"
|
|
|
|
#include "fifo.h"
|
|
|
|
#include "eventfd.h"
|
|
|
|
#include "eventpoll.h"
|
|
|
|
#include "fsnotify.h"
|
|
|
|
#include "signalfd.h"
|
2013-05-18 04:00:05 +04:00
|
|
|
#include "namespaces.h"
|
2013-08-23 19:02:55 +04:00
|
|
|
#include "tun.h"
|
2014-06-30 21:58:05 +04:00
|
|
|
#include "timerfd.h"
|
2014-09-29 12:47:37 +04:00
|
|
|
#include "imgset.h"
|
2014-02-26 13:51:30 +04:00
|
|
|
#include "fs-magic.h"
|
2014-04-09 03:34:53 +04:00
|
|
|
#include "proc_parse.h"
|
Add inherit fd support
There are cases where a process's file descriptor cannot be restored
from the checkpoint images. For example, a pipe file descriptor with
one end in the checkpointed process and the other end in a separate
process (that was not part of the checkpointed process tree) cannot be
restored because after checkpoint the pipe will be broken.
There are also cases where the user wants to use a new file during
restore instead of the original file at checkpoint time. For example,
the user wants to change the log file of a process from /path/to/oldlog
to /path/to/newlog.
In these cases, criu's caller should set up a new file descriptor to be
inherited by the restored process and specify the file descriptor with the
--inherit-fd command line option. The argument of --inherit-fd has the
format fd[%d]:%s, where %d tells criu which of its own file descriptors
to use for restoring the file identified by %s.
As a debugging aid, if the argument has the format debug[%d]:%s, it tells
criu to write out the string after colon to the file descriptor %d. This
can be used, for example, as an easy way to leave a "restore marker"
in the output stream of the process.
It's important to note that inherit fd support breaks applications
that depend on the state of the file descriptor being inherited. So,
consider inherit fd only for specific use cases that you know for sure
won't break the application.
For examples please visit http://criu.org/Category:HOWTO.
v2: Added a check in send_fd_to_self() to avoid closing an inherit fd.
Also, as an extra measure of caution, added checks in the inherit fd
look up functions to make sure that the inherit fd hasn't been reused.
The patch also includes minor cosmetic changes.
Signed-off-by: Saied Kazemi <saied@google.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-12-09 23:20:00 +03:00
|
|
|
#include "cr_options.h"
|
2013-02-08 02:54:24 +04:00
|
|
|
|
|
|
|
#include "parasite.h"
|
|
|
|
#include "parasite-syscall.h"
|
2012-01-10 18:03:00 +04:00
|
|
|
|
2012-07-12 13:06:00 +04:00
|
|
|
#include "protobuf.h"
|
2012-07-17 07:28:38 +04:00
|
|
|
#include "protobuf/fs.pb-c.h"
|
2013-12-20 16:05:17 +04:00
|
|
|
#include "protobuf/ext-file.pb-c.h"
|
|
|
|
|
|
|
|
#include "plugin.h"
|
2012-07-12 13:06:00 +04:00
|
|
|
|
2012-04-06 20:30:48 +04:00
|
|
|
#define FDESC_HASH_SIZE 64
|
2013-08-10 16:41:18 +04:00
|
|
|
static struct hlist_head file_desc_hash[FDESC_HASH_SIZE];
|
2012-04-06 20:30:48 +04:00
|
|
|
|
2012-02-22 18:51:27 +04:00
|
|
|
int prepare_shared_fdinfo(void)
|
|
|
|
{
|
2012-04-06 20:30:48 +04:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < FDESC_HASH_SIZE; i++)
|
2013-08-10 16:41:18 +04:00
|
|
|
INIT_HLIST_HEAD(&file_desc_hash[i]);
|
2012-04-06 20:30:48 +04:00
|
|
|
|
2012-02-22 18:51:27 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-10-16 14:27:23 +04:00
|
|
|
void file_desc_init(struct file_desc *d, u32 id, struct file_desc_ops *ops)
|
2012-04-06 20:03:31 +04:00
|
|
|
{
|
|
|
|
INIT_LIST_HEAD(&d->fd_info_head);
|
2014-10-16 14:27:23 +04:00
|
|
|
INIT_HLIST_NODE(&d->hash);
|
2012-04-06 20:30:48 +04:00
|
|
|
|
2014-10-16 14:27:23 +04:00
|
|
|
d->id = id;
|
|
|
|
d->ops = ops;
|
|
|
|
}
|
2013-08-21 01:06:58 +04:00
|
|
|
|
2014-10-16 14:27:23 +04:00
|
|
|
int file_desc_add(struct file_desc *d, u32 id, struct file_desc_ops *ops)
|
|
|
|
{
|
|
|
|
file_desc_init(d, id, ops);
|
|
|
|
hlist_add_head(&d->hash, &file_desc_hash[id % FDESC_HASH_SIZE]);
|
2013-08-21 01:06:58 +04:00
|
|
|
return 0; /* this is to make tail-calls in collect_one_foo look nice */
|
2012-04-06 20:30:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
struct file_desc *find_file_desc_raw(int type, u32 id)
|
|
|
|
{
|
|
|
|
struct file_desc *d;
|
2013-08-10 16:41:18 +04:00
|
|
|
struct hlist_head *chain;
|
2012-04-06 20:30:48 +04:00
|
|
|
|
2012-06-09 12:17:00 +04:00
|
|
|
chain = &file_desc_hash[id % FDESC_HASH_SIZE];
|
2013-08-10 16:41:18 +04:00
|
|
|
hlist_for_each_entry(d, chain, hash)
|
2012-05-04 15:41:05 +04:00
|
|
|
if (d->ops->type == type && d->id == id)
|
2012-04-06 20:30:48 +04:00
|
|
|
return d;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-07-12 13:06:00 +04:00
|
|
|
static inline struct file_desc *find_file_desc(FdinfoEntry *fe)
|
2012-04-06 20:30:48 +04:00
|
|
|
{
|
|
|
|
return find_file_desc_raw(fe->type, fe->id);
|
2012-04-06 20:03:31 +04:00
|
|
|
}
|
|
|
|
|
2013-09-10 12:13:36 +04:00
|
|
|
/*
|
|
|
|
* A file may be shared between several file descriptors. E.g
|
|
|
|
* when doing a fork() every fd of a forker and respective fds
|
|
|
|
* of the child have such. Another way of getting shared files
|
|
|
|
* is by dup()-ing them or sending them via unix sockets in
|
|
|
|
* SCM_RIGHTS message.
|
|
|
|
*
|
|
|
|
* We restore this type of things in 3 steps (states[] below)
|
|
|
|
*
|
|
|
|
* 1. Prepare step.
|
|
|
|
* Select which task will create the file (open() one, or
|
|
|
|
* call any other syscall for than (socket, pipe, etc.). All
|
|
|
|
* the others, that share one, create unix sockets under the
|
|
|
|
* respective file descriptor (transport socket).
|
|
|
|
* 2. Open step.
|
|
|
|
* The one who creates the file (the 'master') creates one,
|
|
|
|
* then creates one more unix socket (transport) and sends the
|
|
|
|
* created file over this socket to the other recepients.
|
|
|
|
* 3. Receive step.
|
|
|
|
* Those, who wait for the file to appear, receive one via
|
|
|
|
* the transport socket, then close the socket and dup() the
|
|
|
|
* received file descriptor into its place.
|
|
|
|
*
|
|
|
|
* There's the 4th step in the states[] array -- the post_open
|
|
|
|
* one. This one is not about file-sharing resolving, but about
|
|
|
|
* doing something with a file using it's 'desired' fd. The
|
|
|
|
* thing is that while going the 3-step process above, the file
|
|
|
|
* may appear in variuos places in the task's fd table, and if
|
|
|
|
* we want to do something with it's _final_ descriptor value,
|
|
|
|
* we should wait for it to appear there. So the post_open is
|
|
|
|
* called when the file is finally set into its place.
|
|
|
|
*/
|
|
|
|
|
2012-04-06 20:03:31 +04:00
|
|
|
struct fdinfo_list_entry *file_master(struct file_desc *d)
|
|
|
|
{
|
2012-07-28 09:11:12 +04:00
|
|
|
if (list_empty(&d->fd_info_head)) {
|
|
|
|
pr_err("Empty list on file desc id %#x\n", d->id);
|
2012-08-27 23:22:25 +04:00
|
|
|
BUG();
|
2012-07-28 09:11:12 +04:00
|
|
|
}
|
|
|
|
|
2012-04-06 20:03:31 +04:00
|
|
|
return list_first_entry(&d->fd_info_head,
|
2012-04-18 15:46:04 +04:00
|
|
|
struct fdinfo_list_entry, desc_list);
|
2012-04-06 20:03:31 +04:00
|
|
|
}
|
|
|
|
|
2012-04-05 12:48:57 +04:00
|
|
|
void show_saved_files(void)
|
|
|
|
{
|
|
|
|
int i;
|
2012-04-06 20:30:48 +04:00
|
|
|
struct file_desc *fd;
|
2012-04-05 12:48:57 +04:00
|
|
|
|
2012-04-06 20:30:48 +04:00
|
|
|
pr_info("File descs:\n");
|
|
|
|
for (i = 0; i < FDESC_HASH_SIZE; i++)
|
2013-08-10 16:41:18 +04:00
|
|
|
hlist_for_each_entry(fd, &file_desc_hash[i], hash) {
|
2012-04-05 12:48:57 +04:00
|
|
|
struct fdinfo_list_entry *le;
|
|
|
|
|
2012-05-04 15:41:05 +04:00
|
|
|
pr_info(" `- type %d ID %#x\n", fd->ops->type, fd->id);
|
2012-04-18 15:46:04 +04:00
|
|
|
list_for_each_entry(le, &fd->fd_info_head, desc_list)
|
2012-07-07 01:03:00 +04:00
|
|
|
pr_info(" `- FD %d pid %d\n", le->fe->fd, le->pid);
|
2012-04-05 12:48:57 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-10 12:13:36 +04:00
|
|
|
/*
|
|
|
|
* The gen_id thing is used to optimize the comparison of shared files.
|
|
|
|
* If two files have different gen_ids, then they are different for sure.
|
2013-12-11 14:03:11 -08:00
|
|
|
* If it matches, we don't know it and have to call sys_kcmp().
|
2013-09-10 12:13:36 +04:00
|
|
|
*
|
|
|
|
* The kcmp-ids.c engine does this trick, see comments in it for more info.
|
|
|
|
*/
|
|
|
|
|
2013-02-08 02:49:33 +04:00
|
|
|
static u32 make_gen_id(const struct fd_parms *p)
|
|
|
|
{
|
|
|
|
return ((u32)p->stat.st_dev) ^ ((u32)p->stat.st_ino) ^ ((u32)p->pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
int do_dump_gen_file(struct fd_parms *p, int lfd,
|
2014-09-29 12:48:53 +04:00
|
|
|
const struct fdtype_ops *ops, struct cr_img *img)
|
2013-02-08 02:49:33 +04:00
|
|
|
{
|
|
|
|
FdinfoEntry e = FDINFO_ENTRY__INIT;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
e.type = ops->type;
|
|
|
|
e.id = make_gen_id(p);
|
|
|
|
e.fd = p->fd;
|
|
|
|
e.flags = p->fd_flags;
|
|
|
|
|
2014-04-21 18:23:29 +04:00
|
|
|
ret = fd_id_generate(p->pid, &e, p);
|
2013-02-08 02:49:33 +04:00
|
|
|
if (ret == 1) /* new ID generated */
|
|
|
|
ret = ops->dump(lfd, e.id, p);
|
|
|
|
|
|
|
|
if (ret < 0)
|
2013-12-20 16:05:17 +04:00
|
|
|
return ret;
|
2013-02-08 02:49:33 +04:00
|
|
|
|
2013-08-29 14:55:37 +04:00
|
|
|
pr_info("fdinfo: type: 0x%2x flags: %#o/%#o pos: 0x%8"PRIx64" fd: %d\n",
|
2013-02-08 02:49:33 +04:00
|
|
|
ops->type, p->flags, (int)p->fd_flags, p->pos, p->fd);
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
return pb_write_one(img, &e, PB_FDINFO);
|
2013-02-08 02:49:33 +04:00
|
|
|
}
|
|
|
|
|
2013-05-20 13:30:16 +04:00
|
|
|
int fill_fdlink(int lfd, const struct fd_parms *p, struct fd_link *link)
|
|
|
|
{
|
2013-07-08 00:18:37 +04:00
|
|
|
int len;
|
2013-05-20 13:30:16 +04:00
|
|
|
|
|
|
|
link->name[0] = '.';
|
|
|
|
|
|
|
|
len = read_fd_link(lfd, &link->name[1], sizeof(link->name) - 1);
|
|
|
|
if (len < 0) {
|
|
|
|
pr_err("Can't read link for pid %d fd %d\n", p->pid, p->fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
link->len = len + 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-02-08 02:54:24 +04:00
|
|
|
static int fill_fd_params(struct parasite_ctl *ctl, int fd, int lfd,
|
|
|
|
struct fd_opts *opts, struct fd_parms *p)
|
|
|
|
{
|
2013-04-03 21:31:11 +04:00
|
|
|
int ret;
|
2013-12-27 21:14:09 +04:00
|
|
|
struct statfs fsbuf;
|
2014-04-09 03:34:54 +04:00
|
|
|
struct fdinfo_common fdinfo = { .mnt_id = -1 };
|
2013-04-03 21:31:11 +04:00
|
|
|
|
2013-02-08 02:54:24 +04:00
|
|
|
if (fstat(lfd, &p->stat) < 0) {
|
2013-05-02 22:44:24 +04:00
|
|
|
pr_perror("Can't stat fd %d", lfd);
|
2013-02-08 02:54:24 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-12-27 21:14:09 +04:00
|
|
|
if (fstatfs(lfd, &fsbuf) < 0) {
|
|
|
|
pr_perror("Can't statfs fd %d", lfd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-04-09 03:34:53 +04:00
|
|
|
if (parse_fdinfo(lfd, FD_TYPES__UND, NULL, &fdinfo))
|
|
|
|
return -1;
|
|
|
|
|
2013-12-27 21:14:09 +04:00
|
|
|
p->fs_type = fsbuf.f_type;
|
2013-02-08 02:54:24 +04:00
|
|
|
p->ctl = ctl;
|
|
|
|
p->fd = fd;
|
2014-04-09 03:34:53 +04:00
|
|
|
p->pos = fdinfo.pos;
|
|
|
|
p->flags = fdinfo.flags;
|
2014-04-21 18:23:27 +04:00
|
|
|
p->mnt_id = fdinfo.mnt_id;
|
2013-04-08 17:56:48 +04:00
|
|
|
p->pid = ctl->pid.real;
|
2013-02-08 02:54:24 +04:00
|
|
|
p->fd_flags = opts->flags;
|
|
|
|
|
|
|
|
fown_entry__init(&p->fown);
|
|
|
|
|
2013-08-29 14:55:37 +04:00
|
|
|
pr_info("%d fdinfo %d: pos: 0x%16"PRIx64" flags: %16o/%#x\n",
|
2013-04-08 17:56:48 +04:00
|
|
|
ctl->pid.real, fd, p->pos, p->flags, (int)p->fd_flags);
|
2013-02-08 02:54:24 +04:00
|
|
|
|
2013-04-03 21:31:11 +04:00
|
|
|
ret = fcntl(lfd, F_GETSIG, 0);
|
|
|
|
if (ret < 0) {
|
2013-05-02 22:44:24 +04:00
|
|
|
pr_perror("Can't get owner signum on %d", lfd);
|
2013-02-08 02:54:24 +04:00
|
|
|
return -1;
|
|
|
|
}
|
2013-04-03 21:31:11 +04:00
|
|
|
p->fown.signum = ret;
|
2013-02-08 02:54:24 +04:00
|
|
|
|
|
|
|
if (opts->fown.pid == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
p->fown.pid = opts->fown.pid;
|
|
|
|
p->fown.pid_type = opts->fown.pid_type;
|
|
|
|
p->fown.uid = opts->fown.uid;
|
|
|
|
p->fown.euid = opts->fown.euid;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-08-23 19:02:55 +04:00
|
|
|
static const struct fdtype_ops *get_misc_dev_ops(int minor)
|
|
|
|
{
|
|
|
|
switch (minor) {
|
|
|
|
case TUN_MINOR:
|
|
|
|
return &tunfile_dump_ops;
|
|
|
|
};
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
static int dump_chrdev(struct fd_parms *p, int lfd, struct cr_img *img)
|
2013-02-08 02:54:24 +04:00
|
|
|
{
|
|
|
|
int maj = major(p->stat.st_rdev);
|
2013-06-14 00:11:08 +04:00
|
|
|
const struct fdtype_ops *ops;
|
2013-02-08 02:54:24 +04:00
|
|
|
|
|
|
|
switch (maj) {
|
|
|
|
case MEM_MAJOR:
|
2013-06-14 00:11:08 +04:00
|
|
|
ops = ®file_dump_ops;
|
|
|
|
break;
|
2013-08-23 19:02:55 +04:00
|
|
|
case MISC_MAJOR:
|
|
|
|
ops = get_misc_dev_ops(minor(p->stat.st_rdev));
|
|
|
|
if (ops)
|
|
|
|
break;
|
|
|
|
/* fallthrough */
|
2013-11-21 15:28:37 +04:00
|
|
|
default: {
|
|
|
|
char more[32];
|
|
|
|
|
2014-10-16 14:27:20 +04:00
|
|
|
if (is_tty(maj, minor(p->stat.st_rdev))) {
|
2014-10-16 14:27:22 +04:00
|
|
|
struct fd_link link;
|
|
|
|
|
|
|
|
if (fill_fdlink(lfd, p, &link))
|
|
|
|
return -1;
|
|
|
|
p->link = &link;
|
2014-10-16 14:27:20 +04:00
|
|
|
ops = &tty_dump_ops;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-04-01 15:46:00 +04:00
|
|
|
sprintf(more, "%d:%d", maj, minor(p->stat.st_rdev));
|
2014-09-29 12:48:53 +04:00
|
|
|
return dump_unsupp_fd(p, lfd, img, "chr", more);
|
2013-11-21 15:28:37 +04:00
|
|
|
}
|
2013-02-08 02:54:24 +04:00
|
|
|
}
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
return do_dump_gen_file(p, lfd, ops, img);
|
2013-02-08 02:54:24 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int dump_one_file(struct parasite_ctl *ctl, int fd, int lfd, struct fd_opts *opts,
|
2014-09-29 12:48:53 +04:00
|
|
|
struct cr_img *img)
|
2013-02-08 02:54:24 +04:00
|
|
|
{
|
2013-05-07 19:01:23 +04:00
|
|
|
struct fd_parms p = FD_PARMS_INIT;
|
2013-06-14 00:11:08 +04:00
|
|
|
const struct fdtype_ops *ops;
|
2013-02-08 02:54:24 +04:00
|
|
|
|
|
|
|
if (fill_fd_params(ctl, fd, lfd, opts, &p) < 0) {
|
|
|
|
pr_perror("Can't get stat on %d", fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
locks: Don't dump locks in per-task manner (v3)
We have a problem with file locks (bug #2512) -- the /proc/locks
file shows the ID of lock creator, not the owner. Thus, if the
creator died, but holder is still alive, criu fails to dump the
lock held by latter task.
The proposal is to find who _might_ hold the lock by checking
for dev:inode pairs on lock vs file descriptors being dumped.
If the creator of the lock is still alive, then he will take
the priority.
One thing to note about flocks -- these belong to file entries,
not to tasks. Thus, when we meet one, we should check whether
the flock is really held by task's FD by trying to set yet
another one. In case of success -- lock really belongs to fd
we dump, in case it doesn't trylock should fail.
At the very end -- walk the list of locks and dump them all at
once, which is possible by merge of per-task file-locks images
into one global one.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-09-02 17:43:06 +04:00
|
|
|
if (note_file_lock(&ctl->pid, fd, lfd, &p))
|
|
|
|
return -1;
|
|
|
|
|
2013-02-08 02:54:24 +04:00
|
|
|
if (S_ISSOCK(p.stat.st_mode))
|
2014-09-29 12:48:53 +04:00
|
|
|
return dump_socket(&p, lfd, img);
|
2013-02-08 02:54:24 +04:00
|
|
|
|
|
|
|
if (S_ISCHR(p.stat.st_mode))
|
2014-09-29 12:48:53 +04:00
|
|
|
return dump_chrdev(&p, lfd, img);
|
2013-02-08 02:54:24 +04:00
|
|
|
|
2014-01-29 20:09:27 +04:00
|
|
|
if (p.fs_type == ANON_INODE_FS_MAGIC) {
|
2014-02-02 22:14:29 +04:00
|
|
|
char link[32];
|
|
|
|
|
|
|
|
if (read_fd_link(lfd, link, sizeof(link)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (is_eventfd_link(link))
|
2013-06-14 00:11:08 +04:00
|
|
|
ops = &eventfd_dump_ops;
|
2014-02-02 22:14:29 +04:00
|
|
|
else if (is_eventpoll_link(link))
|
2013-06-14 00:11:08 +04:00
|
|
|
ops = &eventpoll_dump_ops;
|
2014-02-02 22:14:29 +04:00
|
|
|
else if (is_inotify_link(link))
|
2013-06-14 00:11:08 +04:00
|
|
|
ops = &inotify_dump_ops;
|
2014-02-02 22:14:29 +04:00
|
|
|
else if (is_fanotify_link(link))
|
2013-06-14 00:11:08 +04:00
|
|
|
ops = &fanotify_dump_ops;
|
2014-02-02 22:14:29 +04:00
|
|
|
else if (is_signalfd_link(link))
|
2013-06-14 00:11:08 +04:00
|
|
|
ops = &signalfd_dump_ops;
|
2014-06-30 21:58:05 +04:00
|
|
|
else if (is_timerfd_link(link))
|
|
|
|
ops = &timerfd_dump_ops;
|
2014-02-02 22:14:29 +04:00
|
|
|
else
|
2014-09-29 12:48:53 +04:00
|
|
|
return dump_unsupp_fd(&p, lfd, img, "anon", link);
|
2013-06-14 00:11:08 +04:00
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
return do_dump_gen_file(&p, lfd, ops, img);
|
2013-02-08 02:54:24 +04:00
|
|
|
}
|
|
|
|
|
2013-05-20 13:30:16 +04:00
|
|
|
if (S_ISREG(p.stat.st_mode) || S_ISDIR(p.stat.st_mode)) {
|
|
|
|
struct fd_link link;
|
|
|
|
|
|
|
|
if (fill_fdlink(lfd, &p, &link))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
p.link = &link;
|
2013-05-18 04:00:05 +04:00
|
|
|
if (link.name[1] == '/')
|
2014-09-29 12:48:53 +04:00
|
|
|
return do_dump_gen_file(&p, lfd, ®file_dump_ops, img);
|
2013-05-18 04:00:05 +04:00
|
|
|
|
|
|
|
if (check_ns_proc(&link))
|
2014-09-29 12:48:53 +04:00
|
|
|
return do_dump_gen_file(&p, lfd, &nsfile_dump_ops, img);
|
2013-05-18 04:00:05 +04:00
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
return dump_unsupp_fd(&p, lfd, img, "reg", link.name + 1);
|
2013-05-20 13:30:16 +04:00
|
|
|
}
|
2013-02-08 02:54:24 +04:00
|
|
|
|
|
|
|
if (S_ISFIFO(p.stat.st_mode)) {
|
2014-01-29 20:09:27 +04:00
|
|
|
if (p.fs_type == PIPEFS_MAGIC)
|
2013-06-14 00:11:08 +04:00
|
|
|
ops = &pipe_dump_ops;
|
2013-02-08 02:54:24 +04:00
|
|
|
else
|
2013-06-14 00:11:08 +04:00
|
|
|
ops = &fifo_dump_ops;
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
return do_dump_gen_file(&p, lfd, ops, img);
|
2013-02-08 02:54:24 +04:00
|
|
|
}
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
return dump_unsupp_fd(&p, lfd, img, "unknown", NULL);
|
2013-02-08 02:54:24 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int dump_task_files_seized(struct parasite_ctl *ctl, struct pstree_item *item,
|
|
|
|
struct parasite_drain_fd *dfds)
|
|
|
|
{
|
2014-09-29 12:48:53 +04:00
|
|
|
int *lfds;
|
|
|
|
struct cr_img *img;
|
2013-02-08 02:54:24 +04:00
|
|
|
struct fd_opts *opts;
|
|
|
|
int i, ret = -1;
|
|
|
|
|
|
|
|
pr_info("\n");
|
2013-04-08 17:56:48 +04:00
|
|
|
pr_info("Dumping opened files (pid: %d)\n", ctl->pid.real);
|
2013-02-08 02:54:24 +04:00
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
|
|
|
|
lfds = xmalloc(dfds->nr_fds * sizeof(int));
|
|
|
|
if (!lfds)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
opts = xmalloc(dfds->nr_fds * sizeof(struct fd_opts));
|
|
|
|
if (!opts)
|
|
|
|
goto err1;
|
|
|
|
|
|
|
|
ret = parasite_drain_fds_seized(ctl, dfds, lfds, opts);
|
|
|
|
if (ret)
|
|
|
|
goto err2;
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
img = open_image(CR_FD_FDINFO, O_DUMP, item->ids->files_id);
|
|
|
|
if (!img)
|
2013-02-08 02:54:24 +04:00
|
|
|
goto err2;
|
|
|
|
|
|
|
|
for (i = 0; i < dfds->nr_fds; i++) {
|
2014-09-29 12:48:53 +04:00
|
|
|
ret = dump_one_file(ctl, dfds->fds[i], lfds[i], opts + i, img);
|
2013-02-08 02:54:24 +04:00
|
|
|
close(lfds[i]);
|
|
|
|
if (ret)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
close_image(img);
|
2013-02-08 02:54:24 +04:00
|
|
|
|
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
err2:
|
|
|
|
xfree(opts);
|
|
|
|
err1:
|
|
|
|
xfree(lfds);
|
|
|
|
err:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-01-30 13:52:55 +04:00
|
|
|
static int predump_one_fd(int pid, int fd)
|
|
|
|
{
|
|
|
|
const struct fdtype_ops *ops;
|
2014-03-31 23:04:00 +04:00
|
|
|
char link[PATH_MAX], t[32];
|
|
|
|
int ret = 0;
|
2014-01-30 13:52:55 +04:00
|
|
|
|
2014-03-31 23:04:00 +04:00
|
|
|
snprintf(t, sizeof(t), "/proc/%d/fd/%d", pid, fd);
|
|
|
|
ret = readlink(t, link, sizeof(link));
|
|
|
|
if (ret < 0) {
|
|
|
|
pr_perror("Can't read link of fd %d", fd);
|
|
|
|
return -1;
|
|
|
|
} else if ((size_t)ret == sizeof(link)) {
|
|
|
|
pr_err("Buffer for read link of fd %d is too small\n", fd);
|
2014-01-30 13:52:55 +04:00
|
|
|
return -1;
|
|
|
|
}
|
2014-03-31 23:04:00 +04:00
|
|
|
link[ret] = 0;
|
2014-01-30 13:52:55 +04:00
|
|
|
|
2014-03-31 23:04:00 +04:00
|
|
|
ret = 0;
|
2014-02-02 22:14:29 +04:00
|
|
|
if (is_inotify_link(link))
|
2014-01-30 13:52:55 +04:00
|
|
|
ops = &inotify_dump_ops;
|
2014-02-02 22:14:29 +04:00
|
|
|
else if (is_fanotify_link(link))
|
2014-01-30 13:52:55 +04:00
|
|
|
ops = &fanotify_dump_ops;
|
|
|
|
else
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
pr_debug("Pre-dumping %d's %d fd\n", pid, fd);
|
|
|
|
ret = ops->pre_dump(pid, fd);
|
|
|
|
out:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int predump_task_files(int pid)
|
|
|
|
{
|
|
|
|
struct dirent *de;
|
|
|
|
DIR *fd_dir;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
pr_info("Pre-dump fds for %d)\n", pid);
|
|
|
|
|
|
|
|
fd_dir = opendir_proc(pid, "fd");
|
|
|
|
if (!fd_dir)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
while ((de = readdir(fd_dir))) {
|
|
|
|
if (dir_dots(de))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (predump_one_fd(pid, atoi(de->d_name)))
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
out:
|
|
|
|
closedir(fd_dir);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-07-19 09:39:00 +04:00
|
|
|
int restore_fown(int fd, FownEntry *fown)
|
2012-04-10 22:54:00 +04:00
|
|
|
{
|
|
|
|
struct f_owner_ex owner;
|
|
|
|
uid_t uids[3];
|
|
|
|
pid_t pid = getpid();
|
|
|
|
|
|
|
|
if (fown->signum) {
|
|
|
|
if (fcntl(fd, F_SETSIG, fown->signum)) {
|
|
|
|
pr_perror("%d: Can't set signal", pid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* May be untouched */
|
|
|
|
if (!fown->pid)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (getresuid(&uids[0], &uids[1], &uids[2])) {
|
|
|
|
pr_perror("%d: Can't get current UIDs", pid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (setresuid(fown->uid, fown->euid, uids[2])) {
|
|
|
|
pr_perror("%d: Can't set UIDs", pid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
owner.type = fown->pid_type;
|
|
|
|
owner.pid = fown->pid;
|
|
|
|
|
|
|
|
if (fcntl(fd, F_SETOWN_EX, &owner)) {
|
|
|
|
pr_perror("%d: Can't setup %d file owner pid",
|
|
|
|
pid, fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (setresuid(uids[0], uids[1], uids[2])) {
|
|
|
|
pr_perror("%d: Can't revert UIDs back", pid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-07-19 09:39:00 +04:00
|
|
|
int rst_file_params(int fd, FownEntry *fown, int flags)
|
2012-04-26 14:03:49 +04:00
|
|
|
{
|
|
|
|
if (set_fd_flags(fd, flags) < 0)
|
|
|
|
return -1;
|
|
|
|
if (restore_fown(fd, fown) < 0)
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-07-12 13:06:00 +04:00
|
|
|
static int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info)
|
2012-01-11 15:45:00 +04:00
|
|
|
{
|
2012-08-27 23:24:06 +04:00
|
|
|
struct fdinfo_list_entry *le, *new_le;
|
2012-04-06 20:03:31 +04:00
|
|
|
struct file_desc *fdesc;
|
2012-01-11 15:45:00 +04:00
|
|
|
|
2013-03-21 00:43:45 +04:00
|
|
|
pr_info("Collect fdinfo pid=%d fd=%d id=%#x\n",
|
2012-04-09 16:18:33 +04:00
|
|
|
pid, e->fd, e->id);
|
2012-01-11 15:45:00 +04:00
|
|
|
|
2012-08-27 23:24:06 +04:00
|
|
|
new_le = shmalloc(sizeof(*new_le));
|
|
|
|
if (!new_le)
|
2012-01-16 23:10:41 +03:00
|
|
|
return -1;
|
|
|
|
|
2012-08-27 23:24:06 +04:00
|
|
|
futex_init(&new_le->real_pid);
|
|
|
|
new_le->pid = pid;
|
|
|
|
new_le->fe = e;
|
2012-01-11 15:45:00 +04:00
|
|
|
|
2012-04-06 20:03:31 +04:00
|
|
|
fdesc = find_file_desc(e);
|
|
|
|
if (fdesc == NULL) {
|
2013-04-05 16:06:09 +04:00
|
|
|
pr_err("No file for fd %d id %#x\n", e->fd, e->id);
|
2012-04-05 16:54:10 +04:00
|
|
|
return -1;
|
|
|
|
}
|
2012-01-11 15:45:00 +04:00
|
|
|
|
2013-08-29 08:07:15 +04:00
|
|
|
list_for_each_entry(le, &fdesc->fd_info_head, desc_list)
|
|
|
|
if (pid_rst_prio(new_le->pid, le->pid))
|
2012-04-05 16:54:10 +04:00
|
|
|
break;
|
|
|
|
|
2014-02-05 15:55:29 +04:00
|
|
|
if (fdesc->ops->collect_fd)
|
|
|
|
fdesc->ops->collect_fd(fdesc, new_le, rst_info);
|
|
|
|
else
|
|
|
|
collect_gen_fd(new_le, rst_info);
|
|
|
|
|
2012-08-27 23:24:06 +04:00
|
|
|
list_add_tail(&new_le->desc_list, &le->desc_list);
|
|
|
|
new_le->desc = fdesc;
|
2012-09-05 20:00:06 +04:00
|
|
|
|
2012-04-05 16:54:10 +04:00
|
|
|
return 0;
|
2012-01-11 15:45:00 +04:00
|
|
|
}
|
|
|
|
|
2012-09-12 20:00:58 +04:00
|
|
|
int prepare_ctl_tty(int pid, struct rst_info *rst_info, u32 ctl_tty_id)
|
|
|
|
{
|
2012-09-12 20:09:05 +04:00
|
|
|
FdinfoEntry *e;
|
|
|
|
|
|
|
|
if (!ctl_tty_id)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
pr_info("Requesting for ctl tty %#x into service fd\n", ctl_tty_id);
|
|
|
|
|
|
|
|
e = xmalloc(sizeof(*e));
|
2012-09-12 20:00:58 +04:00
|
|
|
if (!e)
|
|
|
|
return -1;
|
2012-09-12 20:09:05 +04:00
|
|
|
|
2012-09-12 20:00:58 +04:00
|
|
|
fdinfo_entry__init(e);
|
|
|
|
|
|
|
|
e->id = ctl_tty_id;
|
2013-03-18 23:04:09 +04:00
|
|
|
e->fd = reserve_service_fd(CTL_TTY_OFF);
|
2012-09-12 20:00:58 +04:00
|
|
|
e->type = FD_TYPES__TTY;
|
|
|
|
|
|
|
|
if (collect_fd(pid, e, rst_info)) {
|
|
|
|
xfree(e);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-01-11 18:16:25 +04:00
|
|
|
int prepare_fd_pid(struct pstree_item *item)
|
2012-01-11 15:45:00 +04:00
|
|
|
{
|
2014-09-29 12:48:53 +04:00
|
|
|
int ret = 0;
|
|
|
|
struct cr_img *img;
|
2013-01-11 18:16:25 +04:00
|
|
|
pid_t pid = item->pid.virt;
|
2014-09-29 22:04:39 +04:00
|
|
|
struct rst_info *rst_info = rsti(item);
|
2012-01-11 15:45:00 +04:00
|
|
|
|
2012-04-18 16:24:08 +04:00
|
|
|
INIT_LIST_HEAD(&rst_info->fds);
|
2012-05-04 16:31:00 +04:00
|
|
|
INIT_LIST_HEAD(&rst_info->eventpoll);
|
2012-09-12 20:00:52 +04:00
|
|
|
INIT_LIST_HEAD(&rst_info->tty_slaves);
|
2012-04-18 16:24:08 +04:00
|
|
|
|
2013-01-11 18:16:25 +04:00
|
|
|
if (!fdinfo_per_id) {
|
2014-09-29 12:48:53 +04:00
|
|
|
img = open_image(CR_FD_FDINFO, O_RSTR | O_OPT, pid);
|
|
|
|
if (!img) {
|
2014-09-29 12:47:54 +04:00
|
|
|
if (errno == ENOENT)
|
2013-01-11 18:16:25 +04:00
|
|
|
return 0;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (item->ids == NULL) /* zombie */
|
2012-01-22 20:26:51 +04:00
|
|
|
return 0;
|
2013-01-11 18:16:25 +04:00
|
|
|
|
2014-09-29 22:04:39 +04:00
|
|
|
if (rsti(item)->fdt && rsti(item)->fdt->pid != item->pid.virt)
|
2013-01-11 18:16:25 +04:00
|
|
|
return 0;
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
img = open_image(CR_FD_FDINFO, O_RSTR, item->ids->files_id);
|
|
|
|
if (!img)
|
2012-01-22 20:26:51 +04:00
|
|
|
return -1;
|
2012-01-11 15:45:00 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
2012-07-12 13:06:00 +04:00
|
|
|
FdinfoEntry *e;
|
2012-01-11 15:45:00 +04:00
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
ret = pb_read_one_eof(img, &e, PB_FDINFO);
|
2012-02-07 15:49:04 +04:00
|
|
|
if (ret <= 0)
|
2012-01-11 15:45:00 +04:00
|
|
|
break;
|
2012-02-07 15:49:04 +04:00
|
|
|
|
2012-07-07 01:03:00 +04:00
|
|
|
ret = collect_fd(pid, e, rst_info);
|
2012-07-12 13:06:00 +04:00
|
|
|
if (ret < 0) {
|
|
|
|
fdinfo_entry__free_unpacked(e, NULL);
|
2012-02-07 15:49:04 +04:00
|
|
|
break;
|
2012-07-12 13:06:00 +04:00
|
|
|
}
|
2012-01-11 15:45:00 +04:00
|
|
|
}
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
close_image(img);
|
2012-02-07 15:49:04 +04:00
|
|
|
return ret;
|
2012-01-11 15:45:00 +04:00
|
|
|
}
|
|
|
|
|
2012-05-30 21:06:00 +04:00
|
|
|
#define SETFL_MASK (O_APPEND | O_ASYNC | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME)
|
2012-04-11 13:20:03 +04:00
|
|
|
int set_fd_flags(int fd, int flags)
|
|
|
|
{
|
2012-05-05 19:20:00 +04:00
|
|
|
int ret;
|
2012-04-11 13:20:03 +04:00
|
|
|
|
2012-05-05 19:20:00 +04:00
|
|
|
ret = fcntl(fd, F_GETFL, 0);
|
|
|
|
if (ret < 0)
|
|
|
|
goto err;
|
2012-04-11 13:20:03 +04:00
|
|
|
|
2012-05-05 19:20:00 +04:00
|
|
|
flags = (SETFL_MASK & flags) | (ret & ~SETFL_MASK);
|
2012-04-11 13:20:03 +04:00
|
|
|
|
2012-05-05 19:20:00 +04:00
|
|
|
ret = fcntl(fd, F_SETFL, flags);
|
|
|
|
if (ret < 0)
|
|
|
|
goto err;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err:
|
|
|
|
pr_perror("fcntl call on fd %d (flags %x) failed", fd, flags);
|
|
|
|
return -1;
|
2012-04-11 13:20:03 +04:00
|
|
|
}
|
|
|
|
|
2013-08-23 23:28:44 +04:00
|
|
|
struct fd_open_state {
|
|
|
|
char *name;
|
|
|
|
int (*cb)(int, struct fdinfo_list_entry *);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Two last stages -- receive fds and post-open them -- are
|
|
|
|
* not required always. E.g. if no fd sharing takes place
|
|
|
|
* or task doens't have any files that need to be post-opened.
|
|
|
|
*
|
|
|
|
* Thus, in order not to scan through fdinfo-s lists in vain
|
|
|
|
* and speed things up a little bit, we may want to skeep these.
|
|
|
|
*/
|
|
|
|
bool required;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int open_transport_fd(int pid, struct fdinfo_list_entry *fle);
|
|
|
|
static int open_fd(int pid, struct fdinfo_list_entry *fle);
|
|
|
|
static int receive_fd(int pid, struct fdinfo_list_entry *fle);
|
|
|
|
static int post_open_fd(int pid, struct fdinfo_list_entry *fle);
|
|
|
|
|
|
|
|
static struct fd_open_state states[] = {
|
|
|
|
{ "prepare", open_transport_fd, true,},
|
|
|
|
{ "create", open_fd, true,},
|
|
|
|
{ "receive", receive_fd, false,},
|
|
|
|
{ "post_create", post_open_fd, false,},
|
|
|
|
};
|
|
|
|
|
|
|
|
#define want_recv_stage() do { states[2].required = true; } while (0)
|
|
|
|
#define want_post_open_stage() do { states[3].required = true; } while (0)
|
|
|
|
|
2012-04-06 21:20:28 +04:00
|
|
|
static void transport_name_gen(struct sockaddr_un *addr, int *len,
|
2012-04-09 16:18:33 +04:00
|
|
|
int pid, int fd)
|
2012-03-23 11:02:06 +03:00
|
|
|
{
|
|
|
|
addr->sun_family = AF_UNIX;
|
2012-04-09 16:18:33 +04:00
|
|
|
snprintf(addr->sun_path, UNIX_PATH_MAX, "x/crtools-fd-%d-%d", pid, fd);
|
2012-03-23 11:02:06 +03:00
|
|
|
*len = SUN_LEN(addr);
|
|
|
|
*addr->sun_path = '\0';
|
|
|
|
}
|
|
|
|
|
2012-07-12 13:06:00 +04:00
|
|
|
static int should_open_transport(FdinfoEntry *fe, struct file_desc *fd)
|
2012-04-05 20:02:00 +04:00
|
|
|
{
|
2012-04-06 20:39:48 +04:00
|
|
|
if (fd->ops->want_transport)
|
|
|
|
return fd->ops->want_transport(fe, fd);
|
|
|
|
else
|
|
|
|
return 0;
|
2012-04-05 20:02:00 +04:00
|
|
|
}
|
|
|
|
|
2012-06-03 23:43:35 +04:00
|
|
|
static int open_transport_fd(int pid, struct fdinfo_list_entry *fle)
|
2012-01-11 15:45:00 +04:00
|
|
|
{
|
2012-06-03 23:43:35 +04:00
|
|
|
struct fdinfo_list_entry *flem;
|
2012-01-11 15:45:00 +04:00
|
|
|
struct sockaddr_un saddr;
|
|
|
|
int sock;
|
|
|
|
int ret, sun_len;
|
|
|
|
|
2012-06-03 23:43:35 +04:00
|
|
|
flem = file_master(fle->desc);
|
2012-04-05 20:02:00 +04:00
|
|
|
|
2012-06-03 23:43:35 +04:00
|
|
|
if (flem->pid == pid) {
|
2012-07-07 01:03:00 +04:00
|
|
|
if (flem->fe->fd != fle->fe->fd)
|
2012-06-04 00:23:49 +04:00
|
|
|
/* dup-ed file. Will be opened in the open_fd */
|
2012-04-05 20:02:00 +04:00
|
|
|
return 0;
|
2012-06-04 00:23:49 +04:00
|
|
|
|
2012-07-07 01:03:00 +04:00
|
|
|
if (!should_open_transport(fle->fe, fle->desc))
|
2012-06-04 00:23:49 +04:00
|
|
|
/* pure master file */
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* some master file, that wants a transport, e.g.
|
|
|
|
* a pipe or unix socket pair 'slave' end
|
|
|
|
*/
|
2012-04-05 20:02:00 +04:00
|
|
|
}
|
2012-01-16 19:35:35 +04:00
|
|
|
|
2012-07-07 01:03:00 +04:00
|
|
|
transport_name_gen(&saddr, &sun_len, getpid(), fle->fe->fd);
|
2012-01-11 15:45:00 +04:00
|
|
|
|
2012-05-02 14:42:00 +04:00
|
|
|
pr_info("\t\tCreate transport fd %s\n", saddr.sun_path + 1);
|
2012-01-11 15:45:00 +04:00
|
|
|
|
|
|
|
|
|
|
|
sock = socket(PF_UNIX, SOCK_DGRAM, 0);
|
|
|
|
if (sock < 0) {
|
|
|
|
pr_perror("Can't create socket");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
ret = bind(sock, &saddr, sun_len);
|
|
|
|
if (ret < 0) {
|
2012-01-31 15:13:05 +04:00
|
|
|
pr_perror("Can't bind unix socket %s", saddr.sun_path + 1);
|
2014-10-31 17:50:46 +03:00
|
|
|
goto err;
|
2012-01-11 15:45:00 +04:00
|
|
|
}
|
2012-01-10 18:03:00 +04:00
|
|
|
|
2012-07-07 01:03:00 +04:00
|
|
|
ret = reopen_fd_as(fle->fe->fd, sock);
|
2012-01-11 15:45:00 +04:00
|
|
|
if (ret < 0)
|
2014-10-31 17:50:46 +03:00
|
|
|
goto err;
|
2012-01-10 18:03:00 +04:00
|
|
|
|
2012-07-07 01:03:00 +04:00
|
|
|
pr_info("\t\tWake up fdinfo pid=%d fd=%d\n", fle->pid, fle->fe->fd);
|
2012-03-26 23:11:00 +04:00
|
|
|
futex_set_and_wake(&fle->real_pid, getpid());
|
2013-08-23 23:28:44 +04:00
|
|
|
want_recv_stage();
|
2012-01-11 15:45:00 +04:00
|
|
|
|
|
|
|
return 0;
|
2014-10-31 17:50:46 +03:00
|
|
|
err:
|
|
|
|
close(sock);
|
|
|
|
return -1;
|
2012-01-11 15:45:00 +04:00
|
|
|
}
|
2012-01-10 18:03:00 +04:00
|
|
|
|
2012-08-17 15:43:22 +04:00
|
|
|
int send_fd_to_peer(int fd, struct fdinfo_list_entry *fle, int sock)
|
2012-04-06 21:20:28 +04:00
|
|
|
{
|
|
|
|
struct sockaddr_un saddr;
|
|
|
|
int len;
|
|
|
|
|
2012-07-07 01:03:00 +04:00
|
|
|
pr_info("\t\tWait fdinfo pid=%d fd=%d\n", fle->pid, fle->fe->fd);
|
2012-04-06 21:20:28 +04:00
|
|
|
futex_wait_while(&fle->real_pid, 0);
|
|
|
|
transport_name_gen(&saddr, &len,
|
2012-07-07 01:03:00 +04:00
|
|
|
futex_get(&fle->real_pid), fle->fe->fd);
|
2012-05-02 14:42:00 +04:00
|
|
|
pr_info("\t\tSend fd %d to %s\n", fd, saddr.sun_path + 1);
|
2012-08-17 15:43:22 +04:00
|
|
|
return send_fd(sock, &saddr, len, fd);
|
2012-04-06 21:20:28 +04:00
|
|
|
}
|
|
|
|
|
2012-09-11 22:27:21 +04:00
|
|
|
static int send_fd_to_self(int fd, struct fdinfo_list_entry *fle, int *sock)
|
|
|
|
{
|
|
|
|
int dfd = fle->fe->fd;
|
|
|
|
|
|
|
|
if (fd == dfd)
|
|
|
|
return 0;
|
|
|
|
|
Add inherit fd support
There are cases where a process's file descriptor cannot be restored
from the checkpoint images. For example, a pipe file descriptor with
one end in the checkpointed process and the other end in a separate
process (that was not part of the checkpointed process tree) cannot be
restored because after checkpoint the pipe will be broken.
There are also cases where the user wants to use a new file during
restore instead of the original file at checkpoint time. For example,
the user wants to change the log file of a process from /path/to/oldlog
to /path/to/newlog.
In these cases, criu's caller should set up a new file descriptor to be
inherited by the restored process and specify the file descriptor with the
--inherit-fd command line option. The argument of --inherit-fd has the
format fd[%d]:%s, where %d tells criu which of its own file descriptors
to use for restoring the file identified by %s.
As a debugging aid, if the argument has the format debug[%d]:%s, it tells
criu to write out the string after colon to the file descriptor %d. This
can be used, for example, as an easy way to leave a "restore marker"
in the output stream of the process.
It's important to note that inherit fd support breaks applications
that depend on the state of the file descriptor being inherited. So,
consider inherit fd only for specific use cases that you know for sure
won't break the application.
For examples please visit http://criu.org/Category:HOWTO.
v2: Added a check in send_fd_to_self() to avoid closing an inherit fd.
Also, as an extra measure of caution, added checks in the inherit fd
look up functions to make sure that the inherit fd hasn't been reused.
The patch also includes minor cosmetic changes.
Signed-off-by: Saied Kazemi <saied@google.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-12-09 23:20:00 +03:00
|
|
|
/* make sure we won't clash with an inherit fd */
|
|
|
|
if (inherit_fd_resolve_clash(dfd) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2012-09-11 22:27:21 +04:00
|
|
|
pr_info("\t\t\tGoing to dup %d into %d\n", fd, dfd);
|
|
|
|
if (move_img_fd(sock, dfd))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (dup2(fd, dfd) != dfd) {
|
|
|
|
pr_perror("Can't dup local fd %d -> %d", fd, dfd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-03-18 22:29:22 +04:00
|
|
|
if (fcntl(dfd, F_SETFD, fle->fe->flags) == -1) {
|
|
|
|
pr_perror("Unable to set file descriptor flags");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-09-11 22:27:21 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-09-13 00:17:57 +04:00
|
|
|
static int post_open_fd(int pid, struct fdinfo_list_entry *fle)
|
2012-08-20 17:50:01 +04:00
|
|
|
{
|
2012-09-13 00:17:57 +04:00
|
|
|
struct file_desc *d = fle->desc;
|
2012-08-20 17:50:01 +04:00
|
|
|
|
2012-09-11 22:07:21 +04:00
|
|
|
if (!d->ops->post_open)
|
|
|
|
return 0;
|
|
|
|
|
2012-09-13 00:17:57 +04:00
|
|
|
if (is_service_fd(fle->fe->fd, CTL_TTY_OFF))
|
|
|
|
return d->ops->post_open(d, fle->fe->fd);
|
2012-09-12 20:00:58 +04:00
|
|
|
|
2012-09-13 00:21:14 +04:00
|
|
|
if (fle != file_master(d))
|
2012-08-20 17:50:01 +04:00
|
|
|
return 0;
|
|
|
|
|
2012-09-13 00:21:14 +04:00
|
|
|
return d->ops->post_open(d, fle->fe->fd);
|
2012-08-20 17:50:01 +04:00
|
|
|
}
|
2012-09-11 22:07:21 +04:00
|
|
|
|
2012-09-13 00:08:39 +04:00
|
|
|
|
|
|
|
static int serve_out_fd(int pid, int fd, struct file_desc *d)
|
2012-01-11 15:45:00 +04:00
|
|
|
{
|
2012-09-13 00:08:39 +04:00
|
|
|
int sock, ret;
|
2012-01-11 15:45:00 +04:00
|
|
|
struct fdinfo_list_entry *fle;
|
|
|
|
|
|
|
|
sock = socket(PF_UNIX, SOCK_DGRAM, 0);
|
|
|
|
if (sock < 0) {
|
|
|
|
pr_perror("Can't create socket");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-09-13 00:08:39 +04:00
|
|
|
pr_info("\t\tCreate fd for %d\n", fd);
|
2012-01-11 15:45:00 +04:00
|
|
|
|
2012-04-18 15:46:04 +04:00
|
|
|
list_for_each_entry(fle, &d->fd_info_head, desc_list) {
|
2012-09-11 22:27:21 +04:00
|
|
|
if (pid == fle->pid)
|
2012-09-13 00:08:39 +04:00
|
|
|
ret = send_fd_to_self(fd, fle, &sock);
|
2012-09-11 22:27:21 +04:00
|
|
|
else
|
2012-09-13 00:08:39 +04:00
|
|
|
ret = send_fd_to_peer(fd, fle, sock);
|
2012-01-11 15:45:00 +04:00
|
|
|
|
2012-09-11 22:27:21 +04:00
|
|
|
if (ret) {
|
2012-09-13 00:08:39 +04:00
|
|
|
pr_err("Can't sent fd %d to %d\n", fd, fle->pid);
|
2012-01-11 15:45:00 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
close(sock);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-09-13 00:17:57 +04:00
|
|
|
static int open_fd(int pid, struct fdinfo_list_entry *fle)
|
2012-09-13 00:08:39 +04:00
|
|
|
{
|
2012-09-13 00:17:57 +04:00
|
|
|
struct file_desc *d = fle->desc;
|
2012-09-13 00:08:39 +04:00
|
|
|
int new_fd;
|
|
|
|
|
2013-08-23 23:28:44 +04:00
|
|
|
if (d->ops->post_open)
|
|
|
|
want_post_open_stage();
|
|
|
|
|
2012-09-13 00:21:14 +04:00
|
|
|
if (fle != file_master(d))
|
2012-09-13 00:08:39 +04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
new_fd = d->ops->open(d);
|
|
|
|
if (new_fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
2012-09-13 00:17:57 +04:00
|
|
|
if (reopen_fd_as(fle->fe->fd, new_fd))
|
2012-09-13 00:08:39 +04:00
|
|
|
return -1;
|
|
|
|
|
2013-03-18 22:29:22 +04:00
|
|
|
if (fcntl(fle->fe->fd, F_SETFD, fle->fe->flags) == -1) {
|
|
|
|
pr_perror("Unable to set file descriptor flags");
|
|
|
|
return -1;
|
|
|
|
}
|
2012-09-13 00:08:39 +04:00
|
|
|
|
2012-09-13 00:17:57 +04:00
|
|
|
return serve_out_fd(pid, fle->fe->fd, d);
|
2012-09-13 00:08:39 +04:00
|
|
|
}
|
|
|
|
|
2012-09-13 00:17:57 +04:00
|
|
|
static int receive_fd(int pid, struct fdinfo_list_entry *fle)
|
2012-01-11 15:45:00 +04:00
|
|
|
{
|
2012-01-16 19:18:31 +04:00
|
|
|
int tmp;
|
2012-09-13 00:17:57 +04:00
|
|
|
struct fdinfo_list_entry *flem;
|
2012-01-11 15:45:00 +04:00
|
|
|
|
2012-09-13 00:17:57 +04:00
|
|
|
flem = file_master(fle->desc);
|
|
|
|
if (flem->pid == pid)
|
2012-01-11 15:45:00 +04:00
|
|
|
return 0;
|
|
|
|
|
2012-09-13 00:17:57 +04:00
|
|
|
pr_info("\tReceive fd for %d\n", fle->fe->fd);
|
2012-01-11 15:45:00 +04:00
|
|
|
|
2012-09-13 00:17:57 +04:00
|
|
|
tmp = recv_fd(fle->fe->fd);
|
2012-01-11 15:45:00 +04:00
|
|
|
if (tmp < 0) {
|
2012-02-01 13:00:49 +03:00
|
|
|
pr_err("Can't get fd %d\n", tmp);
|
2012-01-11 15:45:00 +04:00
|
|
|
return -1;
|
|
|
|
}
|
2012-09-13 00:17:57 +04:00
|
|
|
close(fle->fe->fd);
|
2012-01-11 15:45:00 +04:00
|
|
|
|
2012-09-13 00:17:57 +04:00
|
|
|
if (reopen_fd_as(fle->fe->fd, tmp) < 0)
|
2012-04-10 18:36:59 +04:00
|
|
|
return -1;
|
|
|
|
|
2013-03-18 22:29:22 +04:00
|
|
|
if (fcntl(fle->fe->fd, F_SETFD, fle->fe->flags) == -1) {
|
|
|
|
pr_perror("Unable to set file descriptor flags");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-04-10 18:36:59 +04:00
|
|
|
return 0;
|
2012-01-10 18:03:00 +04:00
|
|
|
}
|
|
|
|
|
2012-06-03 22:56:02 +04:00
|
|
|
static int open_fdinfo(int pid, struct fdinfo_list_entry *fle, int state)
|
2012-01-10 18:03:00 +04:00
|
|
|
{
|
2012-06-03 22:56:02 +04:00
|
|
|
pr_info("\tRestoring fd %d (state -> %s)\n",
|
2012-09-13 00:34:37 +04:00
|
|
|
fle->fe->fd, states[state].name);
|
|
|
|
return states[state].cb(pid, fle);
|
2012-01-11 15:45:00 +04:00
|
|
|
}
|
|
|
|
|
2012-09-11 21:47:14 +04:00
|
|
|
static int open_fdinfos(int pid, struct list_head *list, int state)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
struct fdinfo_list_entry *fle;
|
|
|
|
|
|
|
|
list_for_each_entry(fle, list, ps_list) {
|
|
|
|
ret = open_fdinfo(pid, fle, state);
|
|
|
|
if (ret)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-12-30 16:28:39 +03:00
|
|
|
static struct inherit_fd *inherit_fd_lookup_fd(int fd, const char *caller);
|
|
|
|
|
2013-01-11 18:16:24 +04:00
|
|
|
int close_old_fds(struct pstree_item *me)
|
2012-06-27 20:57:42 +04:00
|
|
|
{
|
2012-09-29 11:01:53 +04:00
|
|
|
DIR *dir;
|
|
|
|
struct dirent *de;
|
|
|
|
int fd, ret;
|
|
|
|
|
2015-02-09 14:06:13 +03:00
|
|
|
dir = opendir_proc(PROC_SELF, "fd");
|
2012-09-29 11:01:53 +04:00
|
|
|
if (dir == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
while ((de = readdir(dir))) {
|
2012-11-29 21:12:51 +03:00
|
|
|
if (dir_dots(de))
|
2012-09-29 11:01:53 +04:00
|
|
|
continue;
|
|
|
|
|
|
|
|
ret = sscanf(de->d_name, "%d", &fd);
|
|
|
|
if (ret != 1) {
|
|
|
|
pr_err("Can't parse %s\n", de->d_name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
Add inherit fd support
There are cases where a process's file descriptor cannot be restored
from the checkpoint images. For example, a pipe file descriptor with
one end in the checkpointed process and the other end in a separate
process (that was not part of the checkpointed process tree) cannot be
restored because after checkpoint the pipe will be broken.
There are also cases where the user wants to use a new file during
restore instead of the original file at checkpoint time. For example,
the user wants to change the log file of a process from /path/to/oldlog
to /path/to/newlog.
In these cases, criu's caller should set up a new file descriptor to be
inherited by the restored process and specify the file descriptor with the
--inherit-fd command line option. The argument of --inherit-fd has the
format fd[%d]:%s, where %d tells criu which of its own file descriptors
to use for restoring the file identified by %s.
As a debugging aid, if the argument has the format debug[%d]:%s, it tells
criu to write out the string after colon to the file descriptor %d. This
can be used, for example, as an easy way to leave a "restore marker"
in the output stream of the process.
It's important to note that inherit fd support breaks applications
that depend on the state of the file descriptor being inherited. So,
consider inherit fd only for specific use cases that you know for sure
won't break the application.
For examples please visit http://criu.org/Category:HOWTO.
v2: Added a check in send_fd_to_self() to avoid closing an inherit fd.
Also, as an extra measure of caution, added checks in the inherit fd
look up functions to make sure that the inherit fd hasn't been reused.
The patch also includes minor cosmetic changes.
Signed-off-by: Saied Kazemi <saied@google.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-12-09 23:20:00 +03:00
|
|
|
if ((!is_any_service_fd(fd)) && (dirfd(dir) != fd) &&
|
|
|
|
!inherit_fd_lookup_fd(fd, __FUNCTION__))
|
2012-09-29 11:01:53 +04:00
|
|
|
close_safe(&fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
closedir(dir);
|
|
|
|
close_pid_proc();
|
2012-06-27 20:57:42 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-04-18 16:27:46 +04:00
|
|
|
int prepare_fds(struct pstree_item *me)
|
2012-01-11 15:45:00 +04:00
|
|
|
{
|
2013-01-12 00:44:26 +04:00
|
|
|
u32 ret = 0;
|
2012-01-11 15:45:00 +04:00
|
|
|
int state;
|
|
|
|
|
2012-05-02 14:42:00 +04:00
|
|
|
pr_info("Opening fdinfo-s\n");
|
2012-01-11 15:45:00 +04:00
|
|
|
|
2014-10-07 17:25:26 -05:00
|
|
|
/*
|
|
|
|
* This must be done after forking to allow child
|
|
|
|
* to get the cgroup fd so it can move into the
|
|
|
|
* correct /tasks file if it is in a different cgroup
|
|
|
|
* set than its parent
|
|
|
|
*/
|
|
|
|
close_service_fd(CGROUP_YARD);
|
2014-09-23 20:33:18 +04:00
|
|
|
close_pid_proc(); /* flush any proc cached fds we may have */
|
|
|
|
|
2014-09-29 22:04:39 +04:00
|
|
|
if (rsti(me)->fdt) {
|
|
|
|
struct fdt *fdt = rsti(me)->fdt;
|
2013-01-12 00:44:26 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Wait all tasks, who share a current fd table.
|
|
|
|
* We should be sure, that nobody use any file
|
|
|
|
* descriptor while fdtable is being restored.
|
|
|
|
*/
|
|
|
|
futex_inc_and_wake(&fdt->fdt_lock);
|
|
|
|
futex_wait_while_lt(&fdt->fdt_lock, fdt->nr);
|
|
|
|
|
|
|
|
if (fdt->pid != me->pid.virt) {
|
2013-04-12 13:00:05 -07:00
|
|
|
pr_info("File descriptor table is shared with %d\n", fdt->pid);
|
2013-01-12 00:44:26 +04:00
|
|
|
futex_wait_until(&fdt->fdt_lock, fdt->nr + 1);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-13 00:34:37 +04:00
|
|
|
for (state = 0; state < ARRAY_SIZE(states); state++) {
|
2013-08-23 23:28:44 +04:00
|
|
|
if (!states[state].required) {
|
|
|
|
pr_debug("Skipping %s fd stage\n", states[state].name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-09-29 22:04:39 +04:00
|
|
|
ret = open_fdinfos(me->pid.virt, &rsti(me)->fds, state);
|
2012-09-11 21:47:14 +04:00
|
|
|
if (ret)
|
|
|
|
break;
|
2012-03-23 11:15:58 +03:00
|
|
|
|
2012-09-12 20:00:52 +04:00
|
|
|
/*
|
|
|
|
* Now handle TTYs. Slaves are delayed to be sure masters
|
|
|
|
* are already opened.
|
|
|
|
*/
|
2014-09-29 22:04:39 +04:00
|
|
|
ret = open_fdinfos(me->pid.virt, &rsti(me)->tty_slaves, state);
|
2012-09-12 20:00:52 +04:00
|
|
|
if (ret)
|
|
|
|
break;
|
|
|
|
|
2012-05-04 16:31:00 +04:00
|
|
|
/*
|
|
|
|
* The eventpoll descriptors require all the other ones
|
|
|
|
* to be already restored, thus we store them in a separate
|
|
|
|
* list and restore at the very end.
|
|
|
|
*/
|
2014-09-29 22:04:39 +04:00
|
|
|
ret = open_fdinfos(me->pid.virt, &rsti(me)->eventpoll, state);
|
2012-09-11 21:47:14 +04:00
|
|
|
if (ret)
|
|
|
|
break;
|
2012-05-04 16:31:00 +04:00
|
|
|
}
|
2012-09-11 21:47:14 +04:00
|
|
|
|
2014-09-29 22:04:39 +04:00
|
|
|
if (rsti(me)->fdt)
|
|
|
|
futex_inc_and_wake(&rsti(me)->fdt->fdt_lock);
|
2013-01-12 00:44:26 +04:00
|
|
|
out:
|
2013-09-23 14:33:25 +04:00
|
|
|
close_service_fd(CR_PROC_FD_OFF);
|
2012-10-18 15:51:56 +04:00
|
|
|
tty_fini_fds();
|
2012-04-10 18:47:00 +04:00
|
|
|
return ret;
|
2012-01-10 18:03:00 +04:00
|
|
|
}
|
|
|
|
|
2013-09-25 13:46:01 +04:00
|
|
|
static int fchroot(int fd)
|
|
|
|
{
|
2013-10-15 13:59:59 +04:00
|
|
|
char fd_path[PSFDS];
|
2014-06-05 20:18:41 +04:00
|
|
|
int proc;
|
2013-09-25 13:46:01 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* There's no such thing in syscalls. We can emulate
|
|
|
|
* it using the /proc/self/fd/ :)
|
2014-06-05 20:18:41 +04:00
|
|
|
*
|
|
|
|
* But since there might be no /proc mount in our mount
|
|
|
|
* namespace, we will have to ... workaround it.
|
2013-09-25 13:46:01 +04:00
|
|
|
*/
|
|
|
|
|
2014-06-05 20:18:41 +04:00
|
|
|
proc = get_service_fd(PROC_FD_OFF);
|
|
|
|
if (fchdir(proc) < 0) {
|
|
|
|
pr_perror("Can't chdir to proc");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(fd_path, "./self/fd/%d", fd);
|
2013-09-25 13:46:01 +04:00
|
|
|
pr_debug("Going to chroot into %s\n", fd_path);
|
|
|
|
return chroot(fd_path);
|
|
|
|
}
|
|
|
|
|
2014-07-03 19:07:44 +04:00
|
|
|
int restore_fs(struct pstree_item *me)
|
2012-04-09 13:41:05 +04:00
|
|
|
{
|
2014-07-03 19:07:44 +04:00
|
|
|
int dd_root, dd_cwd, ret, err = -1;
|
2014-09-29 22:04:39 +04:00
|
|
|
struct rst_info *ri = rsti(me);
|
2012-04-09 13:41:05 +04:00
|
|
|
|
2013-09-25 13:46:01 +04:00
|
|
|
/*
|
2014-06-09 16:51:16 +04:00
|
|
|
* First -- open both descriptors. We will not
|
|
|
|
* be able to open the cwd one after we chroot.
|
2013-09-25 13:46:01 +04:00
|
|
|
*/
|
|
|
|
|
2014-07-03 19:08:14 +04:00
|
|
|
dd_root = open_reg_fd(ri->root);
|
2014-06-09 16:51:16 +04:00
|
|
|
if (dd_root < 0) {
|
2014-07-03 19:08:14 +04:00
|
|
|
pr_err("Can't open root\n");
|
2014-07-03 19:07:44 +04:00
|
|
|
goto out;
|
2012-10-24 16:51:50 +04:00
|
|
|
}
|
2012-04-09 13:41:05 +04:00
|
|
|
|
2014-07-03 19:08:14 +04:00
|
|
|
dd_cwd = open_reg_fd(ri->cwd);
|
2014-06-09 16:51:16 +04:00
|
|
|
if (dd_cwd < 0) {
|
2014-07-03 19:08:14 +04:00
|
|
|
pr_err("Can't open cwd\n");
|
2014-07-03 19:07:44 +04:00
|
|
|
goto out;
|
2012-04-09 13:41:05 +04:00
|
|
|
}
|
|
|
|
|
2012-04-09 13:52:42 +04:00
|
|
|
/*
|
2014-06-09 16:51:16 +04:00
|
|
|
* Now do chroot/chdir. Chroot goes first as it
|
|
|
|
* calls chdir into proc service descriptor so
|
|
|
|
* we'd need to fix chdir after it anyway.
|
2012-04-09 13:52:42 +04:00
|
|
|
*/
|
|
|
|
|
2014-06-09 16:51:16 +04:00
|
|
|
ret = fchroot(dd_root);
|
|
|
|
close(dd_root);
|
|
|
|
if (ret < 0) {
|
|
|
|
pr_perror("Can't change root");
|
2014-07-03 19:07:44 +04:00
|
|
|
goto out;
|
2013-09-25 13:46:01 +04:00
|
|
|
}
|
|
|
|
|
2014-06-09 16:51:16 +04:00
|
|
|
ret = fchdir(dd_cwd);
|
|
|
|
close(dd_cwd);
|
2013-09-25 13:46:01 +04:00
|
|
|
if (ret < 0) {
|
2014-06-05 20:18:41 +04:00
|
|
|
pr_perror("Can't change cwd");
|
2014-07-03 19:07:44 +04:00
|
|
|
goto out;
|
2013-09-25 13:46:01 +04:00
|
|
|
}
|
|
|
|
|
2014-07-03 19:07:44 +04:00
|
|
|
if (ri->has_umask) {
|
|
|
|
pr_info("Restoring umask to %o\n", ri->umask);
|
|
|
|
umask(ri->umask);
|
2013-01-10 12:48:31 +03:00
|
|
|
}
|
|
|
|
|
2014-06-09 16:50:05 +04:00
|
|
|
err = 0;
|
2014-07-03 19:07:44 +04:00
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
int prepare_fs_pid(struct pstree_item *item)
|
|
|
|
{
|
|
|
|
pid_t pid = item->pid.virt;
|
2014-09-29 22:04:39 +04:00
|
|
|
struct rst_info *ri = rsti(item);
|
2014-09-29 12:48:53 +04:00
|
|
|
struct cr_img *img;
|
2014-07-03 19:07:44 +04:00
|
|
|
FsEntry *fe;
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
img = open_image(CR_FD_FS, O_RSTR | O_OPT, pid);
|
|
|
|
if (!img) {
|
2014-09-29 12:47:54 +04:00
|
|
|
if (errno == ENOENT)
|
2014-07-04 15:52:29 +04:00
|
|
|
goto ok;
|
|
|
|
else
|
|
|
|
goto out;
|
|
|
|
}
|
2014-07-03 19:07:44 +04:00
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
if (pb_read_one(img, &fe, PB_FS) < 0)
|
2014-07-03 19:07:44 +04:00
|
|
|
goto out_i;
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
close_image(img);
|
2014-07-03 19:07:44 +04:00
|
|
|
|
2014-07-03 19:08:14 +04:00
|
|
|
ri->cwd = collect_special_file(fe->cwd_id);
|
|
|
|
if (!ri->cwd) {
|
|
|
|
pr_err("Can't find task cwd file\n");
|
|
|
|
goto out_f;
|
|
|
|
}
|
|
|
|
|
|
|
|
ri->root = collect_special_file(fe->root_id);
|
|
|
|
if (!ri->root) {
|
|
|
|
pr_err("Can't find task root file\n");
|
|
|
|
goto out_f;
|
|
|
|
}
|
|
|
|
|
2014-07-03 19:07:44 +04:00
|
|
|
ri->has_umask = fe->has_umask;
|
|
|
|
ri->umask = fe->umask;
|
|
|
|
|
2012-07-17 07:28:38 +04:00
|
|
|
fs_entry__free_unpacked(fe, NULL);
|
2014-07-04 15:52:29 +04:00
|
|
|
ok:
|
2014-07-03 19:07:44 +04:00
|
|
|
return 0;
|
|
|
|
|
2014-07-03 19:08:14 +04:00
|
|
|
out_f:
|
|
|
|
fs_entry__free_unpacked(fe, NULL);
|
2014-08-05 12:58:17 +04:00
|
|
|
return -1;
|
|
|
|
|
2013-09-25 13:22:18 +04:00
|
|
|
out_i:
|
2014-09-29 12:48:53 +04:00
|
|
|
close_image(img);
|
2013-09-25 13:22:18 +04:00
|
|
|
out:
|
2014-07-03 19:07:44 +04:00
|
|
|
return -1;
|
2012-04-09 13:41:05 +04:00
|
|
|
}
|
|
|
|
|
2013-01-19 00:30:42 +04:00
|
|
|
int shared_fdt_prepare(struct pstree_item *item)
|
|
|
|
{
|
|
|
|
struct pstree_item *parent = item->parent;
|
|
|
|
struct fdt *fdt;
|
|
|
|
|
2014-09-29 22:04:39 +04:00
|
|
|
if (!rsti(parent)->fdt) {
|
|
|
|
fdt = shmalloc(sizeof(*rsti(item)->fdt));
|
2013-01-19 00:30:42 +04:00
|
|
|
if (fdt == NULL)
|
|
|
|
return -1;
|
|
|
|
|
2014-09-29 22:04:39 +04:00
|
|
|
rsti(parent)->fdt = fdt;
|
2013-01-19 00:30:42 +04:00
|
|
|
|
|
|
|
futex_init(&fdt->fdt_lock);
|
|
|
|
fdt->nr = 1;
|
|
|
|
fdt->pid = parent->pid.virt;
|
|
|
|
} else
|
2014-09-29 22:04:39 +04:00
|
|
|
fdt = rsti(parent)->fdt;
|
2013-01-19 00:30:42 +04:00
|
|
|
|
2014-09-29 22:04:39 +04:00
|
|
|
rsti(item)->fdt = fdt;
|
|
|
|
rsti(item)->service_fd_id = fdt->nr;
|
2013-01-19 00:30:42 +04:00
|
|
|
fdt->nr++;
|
2013-08-29 08:07:15 +04:00
|
|
|
if (pid_rst_prio(item->pid.virt, fdt->pid))
|
2013-01-19 00:30:42 +04:00
|
|
|
fdt->pid = item->pid.virt;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
Add inherit fd support
There are cases where a process's file descriptor cannot be restored
from the checkpoint images. For example, a pipe file descriptor with
one end in the checkpointed process and the other end in a separate
process (that was not part of the checkpointed process tree) cannot be
restored because after checkpoint the pipe will be broken.
There are also cases where the user wants to use a new file during
restore instead of the original file at checkpoint time. For example,
the user wants to change the log file of a process from /path/to/oldlog
to /path/to/newlog.
In these cases, criu's caller should set up a new file descriptor to be
inherited by the restored process and specify the file descriptor with the
--inherit-fd command line option. The argument of --inherit-fd has the
format fd[%d]:%s, where %d tells criu which of its own file descriptors
to use for restoring the file identified by %s.
As a debugging aid, if the argument has the format debug[%d]:%s, it tells
criu to write out the string after colon to the file descriptor %d. This
can be used, for example, as an easy way to leave a "restore marker"
in the output stream of the process.
It's important to note that inherit fd support breaks applications
that depend on the state of the file descriptor being inherited. So,
consider inherit fd only for specific use cases that you know for sure
won't break the application.
For examples please visit http://criu.org/Category:HOWTO.
v2: Added a check in send_fd_to_self() to avoid closing an inherit fd.
Also, as an extra measure of caution, added checks in the inherit fd
look up functions to make sure that the inherit fd hasn't been reused.
The patch also includes minor cosmetic changes.
Signed-off-by: Saied Kazemi <saied@google.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-12-09 23:20:00 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Inherit fd support.
|
|
|
|
*
|
|
|
|
* There are cases where a process's file descriptor cannot be restored
|
|
|
|
* from the checkpointed image. For example, a pipe file descriptor with
|
|
|
|
* one end in the checkpointed process and the other end in a separate
|
|
|
|
* process (that was not part of the checkpointed process tree) cannot be
|
|
|
|
* restored because after checkpoint the pipe would be broken and removed.
|
|
|
|
*
|
|
|
|
* There are also cases where the user wants to use a new file during
|
|
|
|
* restore instead of the original file in the checkpointed image. For
|
|
|
|
* example, the user wants to change the log file of a process from
|
|
|
|
* /path/to/oldlog to /path/to/newlog.
|
|
|
|
*
|
|
|
|
* In these cases, criu's caller should set up a new file descriptor to be
|
|
|
|
* inherited by the restored process and specify it with the --inherit-fd
|
|
|
|
* command line option. The argument of --inherit-fd has the format
|
|
|
|
* fd[%d]:%s, where %d tells criu which of its own file descriptor to use
|
|
|
|
* for restoring file identified by %s.
|
|
|
|
*
|
|
|
|
* As a debugging aid, if the argument has the format debug[%d]:%s, it tells
|
|
|
|
* criu to write out the string after colon to the file descriptor %d. This
|
|
|
|
* can be used to leave a "restore marker" in the output stream of the process.
|
|
|
|
*
|
|
|
|
* It's important to note that inherit fd support breaks applications
|
|
|
|
* that depend on the state of the file descriptor being inherited. So,
|
|
|
|
* consider inherit fd only for specific use cases that you know for sure
|
|
|
|
* won't break the application.
|
|
|
|
*
|
|
|
|
* For examples please visit http://criu.org/Category:HOWTO.
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct inherit_fd {
|
|
|
|
struct list_head inh_list;
|
|
|
|
char *inh_id; /* file identifier */
|
|
|
|
int inh_fd; /* criu's descriptor to inherit */
|
|
|
|
dev_t inh_dev;
|
|
|
|
ino_t inh_ino;
|
|
|
|
mode_t inh_mode;
|
|
|
|
dev_t inh_rdev;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return 1 if inherit fd has been closed or reused, 0 otherwise.
|
2014-12-19 18:50:39 +03:00
|
|
|
*
|
|
|
|
* Some parts of the file restore engine can close an inherit fd
|
|
|
|
* explicitly by close() or implicitly by dup2() to reuse that descriptor.
|
|
|
|
* In some specific functions (for example, send_fd_to_self()), we
|
|
|
|
* check for clashes at the beginning of the function and, therefore,
|
|
|
|
* these specific functions will not reuse an inherit fd. However, to
|
|
|
|
* avoid adding a ton of clash detect and resolve code everywhere we close()
|
|
|
|
* and/or dup2(), we just make sure that when we're dup()ing or close()ing
|
|
|
|
* our inherit fd we're still dealing with the same fd that we inherited.
|
Add inherit fd support
There are cases where a process's file descriptor cannot be restored
from the checkpoint images. For example, a pipe file descriptor with
one end in the checkpointed process and the other end in a separate
process (that was not part of the checkpointed process tree) cannot be
restored because after checkpoint the pipe will be broken.
There are also cases where the user wants to use a new file during
restore instead of the original file at checkpoint time. For example,
the user wants to change the log file of a process from /path/to/oldlog
to /path/to/newlog.
In these cases, criu's caller should set up a new file descriptor to be
inherited by the restored process and specify the file descriptor with the
--inherit-fd command line option. The argument of --inherit-fd has the
format fd[%d]:%s, where %d tells criu which of its own file descriptors
to use for restoring the file identified by %s.
As a debugging aid, if the argument has the format debug[%d]:%s, it tells
criu to write out the string after colon to the file descriptor %d. This
can be used, for example, as an easy way to leave a "restore marker"
in the output stream of the process.
It's important to note that inherit fd support breaks applications
that depend on the state of the file descriptor being inherited. So,
consider inherit fd only for specific use cases that you know for sure
won't break the application.
For examples please visit http://criu.org/Category:HOWTO.
v2: Added a check in send_fd_to_self() to avoid closing an inherit fd.
Also, as an extra measure of caution, added checks in the inherit fd
look up functions to make sure that the inherit fd hasn't been reused.
The patch also includes minor cosmetic changes.
Signed-off-by: Saied Kazemi <saied@google.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-12-09 23:20:00 +03:00
|
|
|
*/
|
|
|
|
static int inherit_fd_reused(struct inherit_fd *inh)
|
|
|
|
{
|
|
|
|
struct stat sbuf;
|
|
|
|
|
|
|
|
if (fstat(inh->inh_fd, &sbuf) == -1) {
|
|
|
|
if (errno == EBADF) {
|
|
|
|
pr_debug("Inherit fd %s -> %d has been closed\n",
|
|
|
|
inh->inh_id, inh->inh_fd);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
pr_perror("Can't fstat inherit fd %d", inh->inh_fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (inh->inh_dev != sbuf.st_dev || inh->inh_ino != sbuf.st_ino ||
|
|
|
|
inh->inh_mode != sbuf.st_mode || inh->inh_rdev != sbuf.st_rdev) {
|
|
|
|
pr_info("Inherit fd %s -> %d has been reused\n",
|
|
|
|
inh->inh_id, inh->inh_fd);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We can't print diagnostics messages in this function because the
|
|
|
|
* log file isn't initialized yet.
|
|
|
|
*/
|
2015-03-30 13:09:25 +03:00
|
|
|
int inherit_fd_parse(char *optarg)
|
Add inherit fd support
There are cases where a process's file descriptor cannot be restored
from the checkpoint images. For example, a pipe file descriptor with
one end in the checkpointed process and the other end in a separate
process (that was not part of the checkpointed process tree) cannot be
restored because after checkpoint the pipe will be broken.
There are also cases where the user wants to use a new file during
restore instead of the original file at checkpoint time. For example,
the user wants to change the log file of a process from /path/to/oldlog
to /path/to/newlog.
In these cases, criu's caller should set up a new file descriptor to be
inherited by the restored process and specify the file descriptor with the
--inherit-fd command line option. The argument of --inherit-fd has the
format fd[%d]:%s, where %d tells criu which of its own file descriptors
to use for restoring the file identified by %s.
As a debugging aid, if the argument has the format debug[%d]:%s, it tells
criu to write out the string after colon to the file descriptor %d. This
can be used, for example, as an easy way to leave a "restore marker"
in the output stream of the process.
It's important to note that inherit fd support breaks applications
that depend on the state of the file descriptor being inherited. So,
consider inherit fd only for specific use cases that you know for sure
won't break the application.
For examples please visit http://criu.org/Category:HOWTO.
v2: Added a check in send_fd_to_self() to avoid closing an inherit fd.
Also, as an extra measure of caution, added checks in the inherit fd
look up functions to make sure that the inherit fd hasn't been reused.
The patch also includes minor cosmetic changes.
Signed-off-by: Saied Kazemi <saied@google.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-12-09 23:20:00 +03:00
|
|
|
{
|
|
|
|
char *cp = NULL;
|
|
|
|
int n = -1;
|
|
|
|
int fd = -1;
|
|
|
|
int dbg = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse the argument.
|
|
|
|
*/
|
|
|
|
if (!strncmp(optarg, "fd", 2))
|
|
|
|
cp = &optarg[2];
|
|
|
|
else if (!strncmp(optarg, "debug", 5)) {
|
|
|
|
cp = &optarg[5];
|
|
|
|
dbg = 1;
|
|
|
|
}
|
|
|
|
if (cp) {
|
|
|
|
n = sscanf(cp, "[%d]:", &fd);
|
|
|
|
cp = strchr(optarg, ':');
|
|
|
|
}
|
|
|
|
if (n != 1 || fd < 0 || !cp || !cp[1]) {
|
|
|
|
pr_err("Invalid inherit fd argument: %s\n", optarg);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the argument is a debug string, write it to fd.
|
|
|
|
* Otherwise, add it to the inherit fd list.
|
|
|
|
*/
|
|
|
|
cp++;
|
|
|
|
if (dbg) {
|
|
|
|
n = strlen(cp);
|
|
|
|
if (write(fd, cp, n) != n) {
|
|
|
|
pr_err("Can't write debug message %s to inherit fd %d\n",
|
|
|
|
cp, fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-03-30 13:09:25 +03:00
|
|
|
return inherit_fd_add(fd, cp);
|
|
|
|
}
|
|
|
|
|
|
|
|
int inherit_fd_add(int fd, char *key)
|
|
|
|
{
|
|
|
|
struct inherit_fd *inh;
|
|
|
|
struct stat sbuf;
|
|
|
|
|
Add inherit fd support
There are cases where a process's file descriptor cannot be restored
from the checkpoint images. For example, a pipe file descriptor with
one end in the checkpointed process and the other end in a separate
process (that was not part of the checkpointed process tree) cannot be
restored because after checkpoint the pipe will be broken.
There are also cases where the user wants to use a new file during
restore instead of the original file at checkpoint time. For example,
the user wants to change the log file of a process from /path/to/oldlog
to /path/to/newlog.
In these cases, criu's caller should set up a new file descriptor to be
inherited by the restored process and specify the file descriptor with the
--inherit-fd command line option. The argument of --inherit-fd has the
format fd[%d]:%s, where %d tells criu which of its own file descriptors
to use for restoring the file identified by %s.
As a debugging aid, if the argument has the format debug[%d]:%s, it tells
criu to write out the string after colon to the file descriptor %d. This
can be used, for example, as an easy way to leave a "restore marker"
in the output stream of the process.
It's important to note that inherit fd support breaks applications
that depend on the state of the file descriptor being inherited. So,
consider inherit fd only for specific use cases that you know for sure
won't break the application.
For examples please visit http://criu.org/Category:HOWTO.
v2: Added a check in send_fd_to_self() to avoid closing an inherit fd.
Also, as an extra measure of caution, added checks in the inherit fd
look up functions to make sure that the inherit fd hasn't been reused.
The patch also includes minor cosmetic changes.
Signed-off-by: Saied Kazemi <saied@google.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-12-09 23:20:00 +03:00
|
|
|
if (fstat(fd, &sbuf) == -1) {
|
|
|
|
pr_perror("Can't fstat inherit fd %d", fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
inh = xmalloc(sizeof *inh);
|
|
|
|
if (inh == NULL)
|
|
|
|
return -1;
|
|
|
|
|
2015-03-30 13:09:25 +03:00
|
|
|
inh->inh_id = key;
|
Add inherit fd support
There are cases where a process's file descriptor cannot be restored
from the checkpoint images. For example, a pipe file descriptor with
one end in the checkpointed process and the other end in a separate
process (that was not part of the checkpointed process tree) cannot be
restored because after checkpoint the pipe will be broken.
There are also cases where the user wants to use a new file during
restore instead of the original file at checkpoint time. For example,
the user wants to change the log file of a process from /path/to/oldlog
to /path/to/newlog.
In these cases, criu's caller should set up a new file descriptor to be
inherited by the restored process and specify the file descriptor with the
--inherit-fd command line option. The argument of --inherit-fd has the
format fd[%d]:%s, where %d tells criu which of its own file descriptors
to use for restoring the file identified by %s.
As a debugging aid, if the argument has the format debug[%d]:%s, it tells
criu to write out the string after colon to the file descriptor %d. This
can be used, for example, as an easy way to leave a "restore marker"
in the output stream of the process.
It's important to note that inherit fd support breaks applications
that depend on the state of the file descriptor being inherited. So,
consider inherit fd only for specific use cases that you know for sure
won't break the application.
For examples please visit http://criu.org/Category:HOWTO.
v2: Added a check in send_fd_to_self() to avoid closing an inherit fd.
Also, as an extra measure of caution, added checks in the inherit fd
look up functions to make sure that the inherit fd hasn't been reused.
The patch also includes minor cosmetic changes.
Signed-off-by: Saied Kazemi <saied@google.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-12-09 23:20:00 +03:00
|
|
|
inh->inh_fd = fd;
|
|
|
|
inh->inh_dev = sbuf.st_dev;
|
|
|
|
inh->inh_ino = sbuf.st_ino;
|
|
|
|
inh->inh_mode = sbuf.st_mode;
|
|
|
|
inh->inh_rdev = sbuf.st_rdev;
|
|
|
|
list_add_tail(&inh->inh_list, &opts.inherit_fds);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Log the inherit fd list. Called for diagnostics purposes
|
|
|
|
* after the log file is initialized.
|
|
|
|
*/
|
|
|
|
void inherit_fd_log(void)
|
|
|
|
{
|
|
|
|
struct inherit_fd *inh;
|
|
|
|
|
|
|
|
list_for_each_entry(inh, &opts.inherit_fds, inh_list) {
|
|
|
|
pr_info("File %s will be restored from inherit fd %d\n",
|
|
|
|
inh->inh_id, inh->inh_fd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Look up the inherit fd list by a file identifier.
|
|
|
|
*/
|
2014-12-30 16:29:06 +03:00
|
|
|
static int inherit_fd_lookup_id(char *id)
|
Add inherit fd support
There are cases where a process's file descriptor cannot be restored
from the checkpoint images. For example, a pipe file descriptor with
one end in the checkpointed process and the other end in a separate
process (that was not part of the checkpointed process tree) cannot be
restored because after checkpoint the pipe will be broken.
There are also cases where the user wants to use a new file during
restore instead of the original file at checkpoint time. For example,
the user wants to change the log file of a process from /path/to/oldlog
to /path/to/newlog.
In these cases, criu's caller should set up a new file descriptor to be
inherited by the restored process and specify the file descriptor with the
--inherit-fd command line option. The argument of --inherit-fd has the
format fd[%d]:%s, where %d tells criu which of its own file descriptors
to use for restoring the file identified by %s.
As a debugging aid, if the argument has the format debug[%d]:%s, it tells
criu to write out the string after colon to the file descriptor %d. This
can be used, for example, as an easy way to leave a "restore marker"
in the output stream of the process.
It's important to note that inherit fd support breaks applications
that depend on the state of the file descriptor being inherited. So,
consider inherit fd only for specific use cases that you know for sure
won't break the application.
For examples please visit http://criu.org/Category:HOWTO.
v2: Added a check in send_fd_to_self() to avoid closing an inherit fd.
Also, as an extra measure of caution, added checks in the inherit fd
look up functions to make sure that the inherit fd hasn't been reused.
The patch also includes minor cosmetic changes.
Signed-off-by: Saied Kazemi <saied@google.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-12-09 23:20:00 +03:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct inherit_fd *inh;
|
|
|
|
|
|
|
|
ret = -1;
|
|
|
|
list_for_each_entry(inh, &opts.inherit_fds, inh_list) {
|
|
|
|
if (!strcmp(inh->inh_id, id)) {
|
|
|
|
if (!inherit_fd_reused(inh)) {
|
|
|
|
ret = inh->inh_fd;
|
|
|
|
pr_debug("Found id %s (fd %d) in inherit fd list\n",
|
|
|
|
id, ret);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-12-30 16:29:06 +03:00
|
|
|
bool inherited_fd(struct file_desc *d, int *fd_p)
|
|
|
|
{
|
|
|
|
char buf[32], *id_str;
|
|
|
|
int i_fd;
|
|
|
|
|
|
|
|
if (!d->ops->name)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
id_str = d->ops->name(d, buf, sizeof(buf));
|
|
|
|
i_fd = inherit_fd_lookup_id(id_str);
|
|
|
|
if (i_fd < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
*fd_p = dup(i_fd);
|
|
|
|
if (*fd_p < 0)
|
|
|
|
pr_perror("Inherit fd DUP failed");
|
|
|
|
else
|
|
|
|
pr_info("File %s will be restored from fd %d duped "
|
|
|
|
"from inherit fd %d\n", id_str, *fd_p, i_fd);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Add inherit fd support
There are cases where a process's file descriptor cannot be restored
from the checkpoint images. For example, a pipe file descriptor with
one end in the checkpointed process and the other end in a separate
process (that was not part of the checkpointed process tree) cannot be
restored because after checkpoint the pipe will be broken.
There are also cases where the user wants to use a new file during
restore instead of the original file at checkpoint time. For example,
the user wants to change the log file of a process from /path/to/oldlog
to /path/to/newlog.
In these cases, criu's caller should set up a new file descriptor to be
inherited by the restored process and specify the file descriptor with the
--inherit-fd command line option. The argument of --inherit-fd has the
format fd[%d]:%s, where %d tells criu which of its own file descriptors
to use for restoring the file identified by %s.
As a debugging aid, if the argument has the format debug[%d]:%s, it tells
criu to write out the string after colon to the file descriptor %d. This
can be used, for example, as an easy way to leave a "restore marker"
in the output stream of the process.
It's important to note that inherit fd support breaks applications
that depend on the state of the file descriptor being inherited. So,
consider inherit fd only for specific use cases that you know for sure
won't break the application.
For examples please visit http://criu.org/Category:HOWTO.
v2: Added a check in send_fd_to_self() to avoid closing an inherit fd.
Also, as an extra measure of caution, added checks in the inherit fd
look up functions to make sure that the inherit fd hasn't been reused.
The patch also includes minor cosmetic changes.
Signed-off-by: Saied Kazemi <saied@google.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-12-09 23:20:00 +03:00
|
|
|
/*
|
|
|
|
* Look up the inherit fd list by a file descriptor.
|
|
|
|
*/
|
2014-12-30 16:28:39 +03:00
|
|
|
static struct inherit_fd *inherit_fd_lookup_fd(int fd, const char *caller)
|
Add inherit fd support
There are cases where a process's file descriptor cannot be restored
from the checkpoint images. For example, a pipe file descriptor with
one end in the checkpointed process and the other end in a separate
process (that was not part of the checkpointed process tree) cannot be
restored because after checkpoint the pipe will be broken.
There are also cases where the user wants to use a new file during
restore instead of the original file at checkpoint time. For example,
the user wants to change the log file of a process from /path/to/oldlog
to /path/to/newlog.
In these cases, criu's caller should set up a new file descriptor to be
inherited by the restored process and specify the file descriptor with the
--inherit-fd command line option. The argument of --inherit-fd has the
format fd[%d]:%s, where %d tells criu which of its own file descriptors
to use for restoring the file identified by %s.
As a debugging aid, if the argument has the format debug[%d]:%s, it tells
criu to write out the string after colon to the file descriptor %d. This
can be used, for example, as an easy way to leave a "restore marker"
in the output stream of the process.
It's important to note that inherit fd support breaks applications
that depend on the state of the file descriptor being inherited. So,
consider inherit fd only for specific use cases that you know for sure
won't break the application.
For examples please visit http://criu.org/Category:HOWTO.
v2: Added a check in send_fd_to_self() to avoid closing an inherit fd.
Also, as an extra measure of caution, added checks in the inherit fd
look up functions to make sure that the inherit fd hasn't been reused.
The patch also includes minor cosmetic changes.
Signed-off-by: Saied Kazemi <saied@google.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-12-09 23:20:00 +03:00
|
|
|
{
|
|
|
|
struct inherit_fd *ret;
|
|
|
|
struct inherit_fd *inh;
|
|
|
|
|
|
|
|
ret = NULL;
|
|
|
|
list_for_each_entry(inh, &opts.inherit_fds, inh_list) {
|
|
|
|
if (inh->inh_fd == fd) {
|
|
|
|
if (!inherit_fd_reused(inh)) {
|
|
|
|
ret = inh;
|
|
|
|
pr_debug("Found fd %d (id %s) in inherit fd list (caller %s)\n",
|
|
|
|
fd, inh->inh_id, caller);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the specified fd clashes with an inherit fd,
|
|
|
|
* move the inherit fd.
|
|
|
|
*/
|
|
|
|
int inherit_fd_resolve_clash(int fd)
|
|
|
|
{
|
|
|
|
int newfd;
|
|
|
|
struct inherit_fd *inh;
|
|
|
|
|
|
|
|
inh = inherit_fd_lookup_fd(fd, __FUNCTION__);
|
|
|
|
if (inh == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
newfd = dup(fd);
|
|
|
|
if (newfd == -1) {
|
|
|
|
pr_perror("Can't dup inherit fd %d", fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (close(fd) == -1) {
|
|
|
|
pr_perror("Can't close inherit fd %d", fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
inh->inh_fd = newfd;
|
|
|
|
pr_debug("Inherit fd %d moved to %d to resolve clash\n", fd, inh->inh_fd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Close all inherit fds.
|
|
|
|
*/
|
|
|
|
int inherit_fd_fini()
|
|
|
|
{
|
|
|
|
int reused;
|
|
|
|
struct inherit_fd *inh;
|
|
|
|
|
|
|
|
list_for_each_entry(inh, &opts.inherit_fds, inh_list) {
|
|
|
|
if (inh->inh_fd < 0) {
|
|
|
|
pr_err("File %s in inherit fd list has invalid fd %d\n",
|
|
|
|
inh->inh_id, inh->inh_fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
reused = inherit_fd_reused(inh);
|
|
|
|
if (reused < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!reused) {
|
|
|
|
pr_debug("Closing inherit fd %d -> %s\n", inh->inh_fd,
|
|
|
|
inh->inh_id);
|
|
|
|
if (close_safe(&inh->inh_fd) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|