diff --git a/Makefile b/Makefile index aa218c078..006a09cf2 100644 --- a/Makefile +++ b/Makefile @@ -51,6 +51,7 @@ OBJS += uts_ns.o OBJS += ipc_ns.o OBJS += netfilter.o OBJS += shmem.o +OBJS += eventfd.o DEPS := $(patsubst %.o,%.d,$(OBJS)) diff --git a/cr-dump.c b/cr-dump.c index ecb8fcc6c..08c7a9c84 100644 --- a/cr-dump.c +++ b/cr-dump.c @@ -37,6 +37,7 @@ #include "pipes.h" #include "shmem.h" #include "sk-inet.h" +#include "eventfd.h" #ifndef CONFIG_X86_64 # error No x86-32 support yet @@ -321,6 +322,9 @@ static int do_dump_gen_file(const struct fd_parms *p, int lfd, case FDINFO_PIPE: ret = dump_one_pipe(lfd, e.id, p); break; + case FDINFO_EVENTFD: + ret = dump_one_eventfd(lfd, e.id, p); + break; default: ret = dump_one_reg_file(lfd, e.id, p); break; @@ -453,10 +457,18 @@ static int dump_chrdev(struct fd_parms *p, int lfd, const struct cr_fdset *set) return dump_unsupp_fd(p); } +static int dump_eventfd(struct fd_parms *p, int lfd, const struct cr_fdset *set) +{ + p->id = MAKE_FD_GENID(p->stat.st_dev, p->stat.st_ino, p->pos); + p->type = FDINFO_EVENTFD; + return do_dump_gen_file(p, lfd, set); +} + static int dump_one_file(pid_t pid, int fd, int lfd, char fd_flags, const struct cr_fdset *cr_fdset) { struct fd_parms p; + struct statfs statfs; if (fill_fd_params(pid, fd, lfd, fd_flags, &p) < 0) { pr_perror("Can't get stat on %d", fd); @@ -469,6 +481,16 @@ static int dump_one_file(pid_t pid, int fd, int lfd, char fd_flags, if (S_ISCHR(p.stat.st_mode)) return dump_chrdev(&p, lfd, cr_fdset); + if (fstatfs(lfd, &statfs)) { + pr_perror("Can't obtain statfs on fd %d\n", fd); + return -1; + } + + if (is_anon_inode(&statfs)) { + if (is_eventfd_link(lfd)) + return dump_eventfd(&p, lfd, cr_fdset); + } + if (S_ISREG(p.stat.st_mode) || S_ISDIR(p.stat.st_mode) || S_ISFIFO(p.stat.st_mode)) diff --git a/cr-restore.c b/cr-restore.c index fdaf520ff..c5f297498 100644 --- a/cr-restore.c +++ b/cr-restore.c @@ -35,6 +35,7 @@ #include "files.h" #include "pipes.h" #include "sk-inet.h" +#include "eventfd.h" #include "proc_parse.h" #include "restorer-blob.h" #include "crtools.h" @@ -162,6 +163,9 @@ static int prepare_shared(void) if (collect_unix_sockets()) return -1; + if (collect_eventfd()) + return -1; + list_for_each_entry(pi, &tasks, list) { ret = prepare_shmem_pid(pi->pid); if (ret < 0) diff --git a/cr-show.c b/cr-show.c index 6d4e0ec7c..b5ff3e613 100644 --- a/cr-show.c +++ b/cr-show.c @@ -62,6 +62,7 @@ static char *fdtype2s(u8 type) [FDINFO_INETSK] = "isk", [FDINFO_PIPE] = "pipe", [FDINFO_UNIXSK] = "usk", + [FDINFO_EVENTFD] = "efd", }; if (type > FDINFO_UND && type < FD_INFO_MAX) diff --git a/crtools.c b/crtools.c index 1cc1406af..e9469f736 100644 --- a/crtools.c +++ b/crtools.c @@ -24,6 +24,7 @@ #include "ipc_ns.h" #include "files.h" #include "sk-inet.h" +#include "eventfd.h" struct cr_options opts; @@ -63,6 +64,13 @@ struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX] = { .show = show_reg_files, }, + /* eventfd */ + [CR_FD_EVENTFD] = { + .fmt = FMT_FNAME_EVENTFD, + .magic = EVENTFD_MAGIC, + .show = show_eventfds, + }, + /* core data, such as regs and vmas and such */ [CR_FD_CORE] = { .fmt = FMT_FNAME_CORE, diff --git a/eventfd.c b/eventfd.c new file mode 100644 index 000000000..562c9892b --- /dev/null +++ b/eventfd.c @@ -0,0 +1,177 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "compiler.h" +#include "types.h" +#include "eventfd.h" + +#include "crtools.h" +#include "image.h" +#include "util.h" +#include "log.h" + +struct eventfd_file_info { + struct eventfd_file_entry efe; + struct file_desc d; +}; + +/* Checks if file desciptor @lfd is eventfd */ +int is_eventfd_link(int lfd) +{ + char link[PATH_MAX], path[32]; + ssize_t ret; + + snprintf(path, sizeof(path), "/proc/self/fd/%d", lfd); + ret = readlink(path, link, sizeof(link)); + if (ret < 0) { + pr_perror("Can't read link of fd %d\n", lfd); + return 0; + } + link[ret] = 0; + if (!strcmp(link, "anon_inode:[eventfd]")) + return 1; + + return 0; +} + +static void pr_info_eventfd(char *action, struct eventfd_file_entry *efe) +{ + pr_info("%seventfd: id %#08x flags %#04x counter %#016lx\n", + action, efe->id, efe->flags, efe->counter); +} + +void show_eventfds(int fd, struct cr_options *o) +{ + struct eventfd_file_entry efe; + + pr_img_head(CR_FD_EVENTFD); + + while (1) { + int ret; + + ret = read_img_eof(fd, &efe); + if (ret <= 0) + goto out; + pr_msg("id: %#08x flags %#04x counter: %#016lx ", + efe.id, efe.flags, efe.counter); + show_fown_cont(&efe.fown); + pr_msg("\n"); + } + +out: + pr_img_tail(CR_FD_EVENTFD); +} + +int dump_one_eventfd(int lfd, u32 id, const struct fd_parms *p) +{ + int image_fd = fdset_fd(glob_fdset, CR_FD_EVENTFD); + struct eventfd_file_entry efe; + char buf[64]; + char *pos; + int ret, fdinfo; + + efe.id = id; + efe.flags = p->flags; + efe.fown = p->fown; + + snprintf(buf, sizeof(buf), "/proc/self/fdinfo/%d", lfd); + fdinfo = open(buf, O_RDONLY); + if (fdinfo < 0) { + pr_perror("Can't open %d (%d)", p->fd, lfd); + return -1; + } + + ret = read(fdinfo, buf, sizeof(buf)); + close(fdinfo); + + if (ret <= 0) { + pr_perror("Reading eventfd from %d (%d) failed", p->fd, lfd); + return -1; + } + + pos = strstr(buf, "count-raw:"); + if (!pos || !sscanf(pos, "count-raw: %lx", &efe.counter)) { + pr_err("Counter value is not found for %d (%d)\n", p->fd, lfd); + return -1; + } + + pr_info_eventfd("Dumping ", &efe); + if (write_img(image_fd, &efe)) + return -1; + + return 0; +} + +static int eventfd_open(struct file_desc *d) +{ + struct eventfd_file_info *info; + size_t size; + int tmp; + + info = container_of(d, struct eventfd_file_info, d); + + tmp = eventfd(info->efe.counter, 0); + if (tmp < 0) { + pr_perror("Can't create eventfd %#08x", + info->efe.id); + return -1; + } + + if (rst_file_params(tmp, &info->efe.fown, info->efe.flags)) { + pr_perror("Can't restore params on eventfd %#08x", + info->efe.id); + goto err_close; + } + + return tmp; + +err_close: + close(tmp); + return -1; +} + +static struct file_desc_ops eventfd_desc_ops = { + .open = eventfd_open, +}; + +int collect_eventfd(void) +{ + struct eventfd_file_info *info = NULL; + int ret, image_fd; + + image_fd = open_image_ro(CR_FD_EVENTFD); + if (image_fd < 0) + return -1; + + while (1) { + ret = -1; + + info = xmalloc(sizeof(*info)); + if (!info) + break; + + ret = read_img_eof(image_fd, &info->efe); + if (ret < 0) + goto err; + else if (!ret) + break; + pr_info_eventfd("Collected ", &info->efe); + file_desc_add(&info->d, FDINFO_EVENTFD, info->efe.id, &eventfd_desc_ops); + } + +err: + xfree(info); + close(image_fd); + return ret; +} diff --git a/include/crtools.h b/include/crtools.h index 425ba8773..951b26bf4 100644 --- a/include/crtools.h +++ b/include/crtools.h @@ -55,6 +55,7 @@ enum { CR_FD_PIPES, CR_FD_PIPES_DATA, CR_FD_REMAP_FPATH, + CR_FD_EVENTFD, _CR_FD_GLOB_TO, CR_FD_MAX @@ -102,6 +103,7 @@ void show_fs(int fd, struct cr_options *o); void show_remap_files(int fd, struct cr_options *o); void show_ghost_file(int fd, struct cr_options *o); void show_fown_cont(fown_t *fown); +void show_eventfds(int fd, struct cr_options *o); extern void print_data(unsigned long addr, unsigned char *data, size_t size); extern struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX]; @@ -119,6 +121,7 @@ extern struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX]; #define FMT_FNAME_SIGACTS "sigacts-%d.img" #define FMT_FNAME_UNIXSK "unixsk.img" #define FMT_FNAME_INETSK "inetsk.img" +#define FMT_FNAME_EVENTFD "eventfd.img" #define FMT_FNAME_ITIMERS "itimers-%d.img" #define FMT_FNAME_CREDS "creds-%d.img" #define FMT_FNAME_UTSNS "utsns-%d.img" diff --git a/include/eventfd.h b/include/eventfd.h new file mode 100644 index 000000000..7fe8d75bb --- /dev/null +++ b/include/eventfd.h @@ -0,0 +1,17 @@ +#ifndef EVENTFD_H__ +#define EVENTFD_H__ + +#include +#include + +#include "compiler.h" +#include "types.h" +#include "files.h" +#include "crtools.h" + +extern int is_eventfd_link(int lfd); +extern int dump_one_eventfd(int lfd, u32 id, const struct fd_parms *p); +extern int collect_eventfd(void); +extern void show_eventfds(int fd, struct cr_options *o); + +#endif /* EVENTFD_H__ */ diff --git a/include/image.h b/include/image.h index 2886c765a..337fe92d2 100644 --- a/include/image.h +++ b/include/image.h @@ -33,6 +33,7 @@ #define REMAP_FPATH_MAGIC 0x59133954 /* Vologda */ #define GHOST_FILE_MAGIC 0x52583605 /* Oryol */ #define TCP_STREAM_MAGIC 0x51465506 /* Orenburg */ +#define EVENTFD_MAGIC 0x44523722 /* Anapa */ #define PIPEFS_MAGIC 0x50495045 @@ -42,6 +43,7 @@ enum fd_types { FDINFO_PIPE, FDINFO_INETSK, FDINFO_UNIXSK, + FDINFO_EVENTFD, FD_INFO_MAX }; @@ -84,6 +86,13 @@ struct ghost_file_entry { u32 mode; } __packed; +struct eventfd_file_entry { + u32 id; + u16 flags; + fown_t fown; + u64 counter; +} __packed; + struct fdinfo_entry { u32 fd; u8 type;