diff --git a/Makefile b/Makefile index 0ac83ead7..7b2cc3b5b 100644 --- a/Makefile +++ b/Makefile @@ -59,6 +59,7 @@ OBJS += eventfd.o OBJS += eventpoll.o OBJS += mount.o OBJS += inotify.o +OBJS += signalfd.o OBJS += pstree.o OBJS += protobuf.o diff --git a/cr-dump.c b/cr-dump.c index 3d9d30d0f..6b445d4a8 100644 --- a/cr-dump.c +++ b/cr-dump.c @@ -44,6 +44,7 @@ #include "eventfd.h" #include "eventpoll.h" #include "inotify.h" +#include "signalfd.h" #include "pstree.h" #include "mount.h" @@ -291,6 +292,8 @@ static int dump_one_file(pid_t pid, int fd, int lfd, char fd_flags, return dump_eventpoll(&p, lfd, cr_fdset); else if (is_inotify_link(lfd)) return dump_inotify(&p, lfd, cr_fdset); + else if (is_signalfd_link(lfd)) + return dump_signalfd(&p, lfd, cr_fdset); else return dump_unsupp_fd(&p); } diff --git a/cr-restore.c b/cr-restore.c index 148eeb6d5..3febf25ca 100644 --- a/cr-restore.c +++ b/cr-restore.c @@ -40,6 +40,7 @@ #include "sk-inet.h" #include "eventfd.h" #include "eventpoll.h" +#include "signalfd.h" #include "proc_parse.h" #include "restorer-blob.h" #include "crtools.h" @@ -107,6 +108,9 @@ static int prepare_shared(void) if (collect_eventpoll()) return -1; + if (collect_signalfd()) + return -1; + if (collect_inotify()) return -1; diff --git a/image.c b/image.c index bcca98c95..725f33409 100644 --- a/image.c +++ b/image.c @@ -3,6 +3,7 @@ #include "crtools.h" #include "image.h" #include "eventpoll.h" +#include "signalfd.h" #include "inotify.h" #include "sockets.h" #include "uts_ns.h" @@ -92,6 +93,7 @@ struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX] = { FD_ENTRY(EVENTFD, "eventfd", show_eventfds), FD_ENTRY(EVENTPOLL, "eventpoll", show_eventpoll), FD_ENTRY(EVENTPOLL_TFD, "eventpoll-tfd", show_eventpoll_tfd), + FD_ENTRY(SIGNALFD, "signalfd", show_signalfd), FD_ENTRY(INOTIFY, "inotify", show_inotify), FD_ENTRY(INOTIFY_WD, "inotify-wd", show_inotify_wd), FD_ENTRY(CORE, "core-%d", show_core), diff --git a/include/crtools.h b/include/crtools.h index 6fda2cdd7..d346a03c1 100644 --- a/include/crtools.h +++ b/include/crtools.h @@ -69,6 +69,7 @@ enum { CR_FD_EVENTFD, CR_FD_EVENTPOLL, CR_FD_EVENTPOLL_TFD, + CR_FD_SIGNALFD, CR_FD_INOTIFY, CR_FD_INOTIFY_WD, _CR_FD_GLOB_TO, diff --git a/include/image.h b/include/image.h index e8a5c6e37..345edc553 100644 --- a/include/image.h +++ b/include/image.h @@ -53,6 +53,7 @@ #define EVENTFD_MAGIC 0x44523722 /* Anapa */ #define EVENTPOLL_MAGIC 0x45023858 /* Krasnodar */ #define EVENTPOLL_TFD_MAGIC 0x44433746 /* Novorossiysk */ +#define SIGNALFD_MAGIC 0x57323820 /* Uglich */ #define INOTIFY_MAGIC 0x48424431 /* Volgograd */ #define INOTIFY_WD_MAGIC 0x54562009 /* Svetlogorsk (Rauschen) */ #define MOUNTPOINTS_MAGIC 0x55563928 /* Petushki */ diff --git a/include/signalfd.h b/include/signalfd.h new file mode 100644 index 000000000..9721a4dbb --- /dev/null +++ b/include/signalfd.h @@ -0,0 +1,10 @@ +#ifndef __CR_SIGNALFD_H__ +#define __CR_SIGNALFD_H__ +struct cr_fdset; +struct fd_parms; +struct cr_options; +extern int is_signalfd_link(int lfd); +extern int dump_signalfd(struct fd_parms *p, int lfd, const struct cr_fdset *set); +extern void show_signalfd(int fd, struct cr_options *o); +extern int collect_signalfd(void); +#endif diff --git a/signalfd.c b/signalfd.c new file mode 100644 index 000000000..1018a4a68 --- /dev/null +++ b/signalfd.c @@ -0,0 +1,147 @@ +#include +#include +#include + +#include "compiler.h" +#include "types.h" +#include "signalfd.h" +#include "proc_parse.h" +#include "crtools.h" +#include "image.h" +#include "util.h" +#include "log.h" +#include "files.h" + +#include "protobuf.h" +#include "protobuf/signalfd.pb-c.h" + +struct signalfd_info { + SignalfdEntry *sfe; + struct file_desc d; +}; + +int is_signalfd_link(int lfd) +{ + return is_anon_link_type(lfd, "[signalfd]"); +} + +struct signalfd_dump_arg { + u32 id; + const struct fd_parms *p; + bool dumped; +}; + +void show_signalfd(int fd, struct cr_options *o) +{ + pb_show_plain(fd, signalfd_entry); +} + +static int dump_signalfd_entry(union fdinfo_entries *e, void *arg) +{ + struct signalfd_dump_arg *da = arg; + + if (da->dumped) { + pr_err("Several counters in a file?\n"); + return -1; + } + + da->dumped = true; + e->sfd.id = da->id; + e->sfd.flags = da->p->flags; + e->sfd.fown = (FownEntry *)&da->p->fown; + + return pb_write(fdset_fd(glob_fdset, CR_FD_SIGNALFD), + &e->sfd, signalfd_entry); +} + +static int dump_one_signalfd(int lfd, u32 id, const struct fd_parms *p) +{ + struct signalfd_dump_arg da = { .id = id, .p = p, }; + return parse_fdinfo(lfd, FD_TYPES__SIGNALFD, dump_signalfd_entry, &da); +} + +static const struct fdtype_ops signalfd_ops = { + .type = FD_TYPES__SIGNALFD, + .make_gen_id = make_gen_id, + .dump = dump_one_signalfd, +}; + +int dump_signalfd(struct fd_parms *p, int lfd, const struct cr_fdset *set) +{ + return do_dump_gen_file(p, lfd, &signalfd_ops, set); +} + +static void sigset_fill(sigset_t *to, unsigned long long from) +{ + int sig; + + pr_info("\tCalculating sigmask for %Lx\n", from); + sigemptyset(to); + for (sig = 1; sig < NSIG; sig++) + if (from & (1ULL << (sig - 1))) { + pr_debug("\t\tAdd %d signal to mask\n", sig); + sigaddset(to, sig); + } +} + +static int signalfd_open(struct file_desc *d) +{ + struct signalfd_info *info; + int tmp; + sigset_t mask; + + info = container_of(d, struct signalfd_info, d); + pr_info("Restoring signalfd %#x\n", info->sfe->id); + + sigset_fill(&mask, info->sfe->sigmask); + tmp = signalfd(-1, &mask, 0); + if (tmp < 0) { + pr_perror("Can't create signalfd %#08x", info->sfe->id); + return -1; + } + + if (rst_file_params(tmp, info->sfe->fown, info->sfe->flags)) { + pr_perror("Can't restore params on signalfd %#08x", + info->sfe->id); + goto err_close; + } + + return tmp; + +err_close: + close(tmp); + return -1; +} + +static struct file_desc_ops signalfd_desc_ops = { + .type = FD_TYPES__SIGNALFD, + .open = signalfd_open, +}; + +int collect_signalfd(void) +{ + struct signalfd_info *info = NULL; + int ret, image_fd; + + image_fd = open_image_ro(CR_FD_SIGNALFD); + if (image_fd < 0) + return -1; + + while (1) { + ret = -1; + info = xmalloc(sizeof(*info)); + if (!info) + break; + + ret = pb_read_eof(image_fd, &info->sfe, signalfd_entry); + if (ret <= 0) + break; + + file_desc_add(&info->d, info->sfe->id, &signalfd_desc_ops); + } + + xfree(info ? info->sfe : NULL); + xfree(info); + close(image_fd); + return ret; +}