[CRIU] [RFC PATCH v2 21/23] lazy-pages: add handling of UFFD_EVENT_FORK
Mike Rapoport
rppt at linux.vnet.ibm.com
Mon Feb 6 03:44:14 PST 2017
Signed-off-by: Mike Rapoport <rppt at linux.vnet.ibm.com>
---
criu/uffd.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 91 insertions(+)
diff --git a/criu/uffd.c b/criu/uffd.c
index f2a6bfa..b357d08 100644
--- a/criu/uffd.c
+++ b/criu/uffd.c
@@ -74,6 +74,8 @@ struct lazy_pages_info {
struct list_head iovs;
struct list_head reqs;
+ struct lazy_pages_info *parent;
+
struct page_read pr;
unsigned long total_pages;
@@ -88,6 +90,7 @@ struct lazy_pages_info {
static LIST_HEAD(lpis);
static LIST_HEAD(exiting_lpis);
+static LIST_HEAD(pending_lpis);
static int handle_uffd_event(struct epoll_rfd *lpfd);
@@ -366,6 +369,38 @@ static int split_iov(struct lazy_iov *iov, unsigned long addr, bool new_below)
return 0;
}
+static int copy_lazy_iovs(struct lazy_pages_info *src,
+ struct lazy_pages_info *dst)
+{
+ struct lazy_iov *iov, *new, *n;
+ int max_iov_len = 0;
+
+ list_for_each_entry(iov, &src->iovs, l) {
+ new = xzalloc(sizeof(*new));
+ if (!new)
+ return -1;
+
+ new->base = iov->base;
+ new->img_base = iov->img_base;
+ new->len = iov->len;
+
+ list_add_tail(&new->l, &dst->iovs);
+
+ if (new->len > max_iov_len)
+ max_iov_len = new->len;
+ }
+
+ if (posix_memalign(&dst->buf, PAGE_SIZE, max_iov_len))
+ goto free_iovs;
+
+ return 0;
+
+free_iovs:
+ list_for_each_entry_safe(iov, n, &dst->iovs, l)
+ xfree(iov);
+ return -1;
+}
+
/*
* Purge range (addr, addr + len) from lazy_iovs. The range may
* cover several continuous IOVs.
@@ -830,6 +865,58 @@ static int complete_exits(int epollfd)
return 0;
}
+static int handle_fork(struct lazy_pages_info *parent_lpi, struct uffd_msg *msg)
+{
+ struct lazy_pages_info *lpi;
+ int uffd = msg->arg.fork.ufd;
+
+ lp_debug(parent_lpi, "FORK: child with ufd=%d\n", uffd);
+
+ lpi = lpi_init();
+ if (!lpi)
+ return -1;
+
+ if (copy_lazy_iovs(parent_lpi, lpi))
+ goto out;
+
+ lpi->pid = parent_lpi->pid;
+ lpi->lpfd.fd = uffd;
+ lpi->parent = parent_lpi->parent ? parent_lpi->parent : parent_lpi;
+ lpi->copied_pages = lpi->parent->copied_pages;
+ lpi->total_pages = lpi->parent->total_pages;
+ list_add_tail(&lpi->l, &pending_lpis);
+
+ dup_page_read(&lpi->parent->pr, &lpi->pr);
+
+ return 1;
+
+out:
+ lpi_fini(lpi);
+ return -1;
+}
+
+static int complete_forks(int epollfd, struct epoll_event **events, int *nr_fds)
+{
+ struct lazy_pages_info *lpi, *n;
+
+ list_for_each_entry(lpi, &pending_lpis, l)
+ (*nr_fds)++;
+
+ *events = xrealloc(*events, sizeof(struct epoll_event) * (*nr_fds));
+ if (!*events)
+ return -1;
+
+ list_for_each_entry_safe(lpi, n, &pending_lpis, l) {
+ if (epoll_add_rfd(epollfd, &lpi->lpfd))
+ return -1;
+
+ list_del_init(&lpi->l);
+ list_add_tail(&lpi->l, &lpis);
+ }
+
+ return 0;
+}
+
static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg)
{
struct lp_req *req;
@@ -898,6 +985,8 @@ static int handle_uffd_event(struct epoll_rfd *lpfd)
return handle_remap(lpi, &msg);
case UFFD_EVENT_EXIT:
return handle_exit(lpi, &msg);
+ case UFFD_EVENT_FORK:
+ return handle_fork(lpi, &msg);
default:
lp_err(lpi, "unexpected uffd event %u\n", msg.event);
return -1;
@@ -938,6 +1027,8 @@ static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds)
if (ret < 0)
goto out;
if (ret > 0) {
+ if (complete_forks(epollfd, &events, &nr_fds))
+ return -1;
if (complete_exits(epollfd))
return -1;
continue;
--
1.9.1
More information about the CRIU
mailing list