Commit 371947c1 authored by Mike Rapoport's avatar Mike Rapoport Committed by Andrei Vagin

lazy-pages: add handling of UFFD_EVENT_FORK

travis-ci: success for lazy-pages: add non-#PF events handling (rev2)
Signed-off-by: 's avatarMike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
parent d7c0b1f1
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment