#include #include #include #include #include #include #include #include #include #include #include #include #include #include "compiler.h" #include "types.h" #include "eventpoll.h" #include "proc_parse.h" #include "crtools.h" #include "image.h" #include "util.h" #include "log.h" #include "protobuf.h" #include "protobuf/eventpoll.pb-c.h" #undef LOG_PREFIX #define LOG_PREFIX "epoll: " struct eventpoll_file_info { EventpollFileEntry *efe; struct file_desc d; }; struct eventpoll_tfd_file_info { EventpollTfdEntry *tdefe; struct list_head list; }; static LIST_HEAD(eventpoll_tfds); /* Checks if file desciptor @lfd is eventfd */ int is_eventpoll_link(int lfd) { return is_anon_link_type(lfd, "[eventpoll]"); } static void pr_info_eventpoll_tfd(char *action, EventpollTfdEntry *e) { pr_info("%seventpoll-tfd: id %#08x tfd %#08x events %#08x data %#016lx\n", action, e->id, e->tfd, e->events, e->data); } static void pr_info_eventpoll(char *action, EventpollFileEntry *e) { pr_info("%seventpoll: id %#08x flags %#04x\n", action, e->id, e->flags); } void show_eventpoll_tfd(int fd, struct cr_options *o) { pb_show_plain(fd, PB_EVENTPOLL_TFD); } void show_eventpoll(int fd, struct cr_options *o) { pb_show_plain(fd, PB_EVENTPOLL); } static int dump_eventpoll_entry(union fdinfo_entries *e, void *arg) { EventpollTfdEntry *efd = &e->epl; efd->id = *(u32 *)arg; pr_info_eventpoll_tfd("Dumping: ", efd); return pb_write_one(fdset_fd(glob_fdset, CR_FD_EVENTPOLL_TFD), efd, PB_EVENTPOLL_TFD); } static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p) { EventpollFileEntry e = EVENTPOLL_FILE_ENTRY__INIT; e.id = id; e.flags = p->flags; e.fown = (FownEntry *)&p->fown; pr_info_eventpoll("Dumping ", &e); if (pb_write_one(fdset_fd(glob_fdset, CR_FD_EVENTPOLL), &e, PB_EVENTPOLL)) return -1; return parse_fdinfo(lfd, FD_TYPES__EVENTPOLL, dump_eventpoll_entry, &id); } static const struct fdtype_ops eventpoll_ops = { .type = FD_TYPES__EVENTPOLL, .dump = dump_one_eventpoll, }; int dump_eventpoll(struct fd_parms *p, int lfd, const struct cr_fdset *set) { return do_dump_gen_file(p, lfd, &eventpoll_ops, set); } static int eventpoll_open(struct file_desc *d) { struct eventpoll_tfd_file_info *td_info; struct eventpoll_file_info *info; int tmp, ret; info = container_of(d, struct eventpoll_file_info, d); tmp = epoll_create(1); if (tmp < 0) { pr_perror("Can't create epoll %#08x", info->efe->id); return -1; } if (rst_file_params(tmp, info->efe->fown, info->efe->flags)) { pr_perror("Can't restore file params on epoll %#08x", info->efe->id); goto err_close; } list_for_each_entry(td_info, &eventpoll_tfds, list) { struct epoll_event event; if (td_info->tdefe->id != info->efe->id) continue; event.events = td_info->tdefe->events; event.data.u64 = td_info->tdefe->data; ret = epoll_ctl(tmp, EPOLL_CTL_ADD, td_info->tdefe->tfd, &event); if (ret) { pr_perror("Can't add event on %#08x", info->efe->id); goto err_close; } } return tmp; err_close: close(tmp); return -1; } static struct file_desc_ops desc_ops = { .type = FD_TYPES__EVENTPOLL, .open = eventpoll_open, }; static int collect_one_epoll_tfd(void *o, ProtobufCMessage *msg) { struct eventpoll_tfd_file_info *info = o; info->tdefe = pb_msg(msg, EventpollTfdEntry); list_add(&info->list, &eventpoll_tfds); pr_info_eventpoll_tfd("Collected ", info->tdefe); return 0; } static int collect_one_epoll(void *o, ProtobufCMessage *msg) { struct eventpoll_file_info *info = o; info->efe = pb_msg(msg, EventpollFileEntry); file_desc_add(&info->d, info->efe->id, &desc_ops); pr_info_eventpoll("Collected ", info->efe); return 0; } int collect_eventpoll(void) { int ret; ret = collect_image(CR_FD_EVENTPOLL_TFD, PB_EVENTPOLL_TFD, sizeof(struct eventpoll_tfd_file_info), collect_one_epoll_tfd); if (!ret) ret = collect_image(CR_FD_EVENTPOLL, PB_EVENTPOLL, sizeof(struct eventpoll_file_info), collect_one_epoll); return ret; }