[CRIU] [PATCH 10/11] lazy-pages: introduce struct lazy_pages_info
Mike Rapoport
rppt at linux.vnet.ibm.com
Sun Apr 10 23:19:53 PDT 2016
for holding state related to userfaultfd handling
Signed-off-by: Mike Rapoport <rppt at linux.vnet.ibm.com>
---
criu/uffd.c | 133 +++++++++++++++++++++++++++++++++---------------------------
1 file changed, 74 insertions(+), 59 deletions(-)
diff --git a/criu/uffd.c b/criu/uffd.c
index 25b3db0..f37c64d 100644
--- a/criu/uffd.c
+++ b/criu/uffd.c
@@ -34,6 +34,16 @@
#undef LOG_PREFIX
#define LOG_PREFIX "lazy-pages: "
+struct lazy_pages_info {
+ int pid;
+ int uffd;
+
+ struct list_head pages;
+
+ unsigned long total_pages;
+ unsigned long copied_pages;
+};
+
static int send_uffd(int sendfd, int pid)
{
int fd;
@@ -152,16 +162,14 @@ out:
return -1;
}
-static int pid;
-
-static int get_page(unsigned long addr, void *dest)
+static int get_page(struct lazy_pages_info *lpi, unsigned long addr, void *dest)
{
struct iovec iov;
int ret;
unsigned char buf[PAGE_SIZE];
struct page_read pr;
- ret = open_page_read(pid, &pr, PR_TASK | PR_MOD);
+ ret = open_page_read(lpi->pid, &pr, PR_TASK | PR_MOD);
pr_debug("get_page ret %d\n", ret);
ret = pr.get_pagemap(&pr, &iov);
@@ -195,15 +203,13 @@ struct uffd_pages_struct {
int flags;
};
-static unsigned long total_pages;
-static unsigned long uffd_copied_pages;
-
-static int uffd_copy_page(int uffd, __u64 address, void *dest)
+static int uffd_copy_page(struct lazy_pages_info *lpi, __u64 address,
+ void *dest)
{
struct uffdio_copy uffdio_copy;
int rc;
- rc = get_page(address, dest);
+ rc = get_page(lpi, address, dest);
if (rc <= 0)
return rc;
@@ -214,7 +220,7 @@ static int uffd_copy_page(int uffd, __u64 address, void *dest)
uffdio_copy.copy = 0;
pr_debug("uffdio_copy.dst 0x%llx\n", uffdio_copy.dst);
- rc = ioctl(uffd, UFFDIO_COPY, &uffdio_copy);
+ rc = ioctl(lpi->uffd, UFFDIO_COPY, &uffdio_copy);
pr_debug("ioctl UFFDIO_COPY rc 0x%x\n", rc);
pr_debug("uffdio_copy.copy 0x%llx\n", uffdio_copy.copy);
if (rc) {
@@ -228,13 +234,13 @@ static int uffd_copy_page(int uffd, __u64 address, void *dest)
return -1;
}
- uffd_copied_pages++;
+ lpi->copied_pages++;
return uffdio_copy.copy;
}
-static int uffd_zero_page(int uffd, __u64 address)
+static int uffd_zero_page(struct lazy_pages_info *lpi, __u64 address)
{
struct uffdio_zeropage uffdio_zeropage;
unsigned long ps = page_size();
@@ -245,7 +251,7 @@ static int uffd_zero_page(int uffd, __u64 address)
uffdio_zeropage.mode = 0;
pr_debug("uffdio_zeropage.range.start 0x%llx\n", uffdio_zeropage.range.start);
- rc = ioctl(uffd, UFFDIO_ZEROPAGE, &uffdio_zeropage);
+ rc = ioctl(lpi->uffd, UFFDIO_ZEROPAGE, &uffdio_zeropage);
pr_debug("ioctl UFFDIO_ZEROPAGE rc 0x%x\n", rc);
pr_debug("uffdio_zeropage.zeropage 0x%llx\n", uffdio_zeropage.zeropage);
if (rc) {
@@ -256,18 +262,19 @@ static int uffd_zero_page(int uffd, __u64 address)
return ps;
}
-static int uffd_handle_page(int uffd, __u64 address, void *dest)
+static int uffd_handle_page(struct lazy_pages_info *lpi, __u64 address,
+ void *dest)
{
int rc;
- rc = uffd_copy_page(uffd, address, dest);
+ rc = uffd_copy_page(lpi, address, dest);
if (rc == 0)
- rc = uffd_zero_page(uffd, address);
+ rc = uffd_zero_page(lpi, address);
return rc;
}
-static int collect_uffd_pages(struct page_read *pr, struct list_head *uffd_list)
+static int collect_uffd_pages(struct page_read *pr, struct lazy_pages_info *lpi)
{
unsigned long base;
int i;
@@ -277,7 +284,12 @@ static int collect_uffd_pages(struct page_read *pr, struct list_head *uffd_list)
int rc;
struct uffd_pages_struct *uffd_pages;
struct vma_area *vma;
- struct vm_area_list *vmas = &rsti(root_item)->vmas;
+ struct vm_area_list *vmas;
+ struct pstree_item *item = pstree_item_by_virt(lpi->pid);
+
+ BUG_ON(!item);
+
+ vmas = &rsti(item)->vmas;
rc = pr->get_pagemap(pr, &iov);
if (rc <= 0)
@@ -322,24 +334,24 @@ static int collect_uffd_pages(struct page_read *pr, struct list_head *uffd_list)
if (!uffd_pages)
return -1;
uffd_pages->addr = base;
- list_add(&uffd_pages->list, uffd_list);
+ list_add(&uffd_pages->list, &lpi->pages);
}
return 1;
}
-static int handle_remaining_pages(int uffd, struct list_head *uffd_list, void *dest)
+static int handle_remaining_pages(struct lazy_pages_info *lpi, void *dest)
{
struct uffd_pages_struct *uffd_pages;
int rc;
- list_for_each_entry(uffd_pages, uffd_list, list) {
+ list_for_each_entry(uffd_pages, &lpi->pages, list) {
pr_debug("Checking remaining pages 0x%lx (flags 0x%x)\n",
uffd_pages->addr, uffd_pages->flags);
if (uffd_pages->flags & UFFD_FLAG_SENT)
continue;
- rc = uffd_handle_page(uffd, uffd_pages->addr, dest);
+ rc = uffd_handle_page(lpi, uffd_pages->addr, dest);
if (rc < 0) {
pr_err("Error during UFFD copy\n");
return -1;
@@ -352,12 +364,13 @@ static int handle_remaining_pages(int uffd, struct list_head *uffd_list, void *d
}
-static int handle_regular_pages(int uffd, struct list_head *uffd_list, void *dest, __u64 address)
+static int handle_regular_pages(struct lazy_pages_info *lpi, void *dest,
+ __u64 address)
{
int rc;
struct uffd_pages_struct *uffd_pages;
- rc = uffd_handle_page(uffd, address, dest);
+ rc = uffd_handle_page(lpi, address, dest);
if (rc < 0) {
pr_err("Error during UFFD copy\n");
return -1;
@@ -367,7 +380,7 @@ static int handle_regular_pages(int uffd, struct list_head *uffd_list, void *des
* Mark this page as having been already transferred, so
* that it has not to be copied again later.
*/
- list_for_each_entry(uffd_pages, uffd_list, list) {
+ list_for_each_entry(uffd_pages, &lpi->pages, list) {
if (uffd_pages->addr == address)
uffd_pages->flags |= UFFD_FLAG_SENT;
}
@@ -378,7 +391,7 @@ static int handle_regular_pages(int uffd, struct list_head *uffd_list, void *des
/*
* Setting up criu infrastructure and scan for VMAs.
*/
-static int find_vmas(struct list_head *uffd_list)
+static int find_vmas(struct lazy_pages_info *lpi)
{
struct cr_img *img;
int ret;
@@ -387,14 +400,17 @@ static int find_vmas(struct list_head *uffd_list)
struct rst_info *ri;
struct page_read pr;
struct uffd_pages_struct *uffd_pages;
+ struct pstree_item *item = pstree_item_by_virt(lpi->pid);
+
+ BUG_ON(!item);
vm_area_list_init(&vmas);
- ri = rsti(root_item);
+ ri = rsti(item);
if (!ri)
return -1;
- img = open_image(CR_FD_MM, O_RSTR, pid);
+ img = open_image(CR_FD_MM, O_RSTR, lpi->pid);
if (!img)
return -1;
@@ -428,7 +444,7 @@ static int find_vmas(struct list_head *uffd_list)
pr_info("vma 0x%"PRIx64" 0x%"PRIx64"\n", vma->e->start, vma->e->end);
}
- ret = open_page_read(pid, &pr, PR_TASK);
+ ret = open_page_read(lpi->pid, &pr, PR_TASK);
if (ret <= 0) {
ret = -1;
goto out;
@@ -440,7 +456,7 @@ static int find_vmas(struct list_head *uffd_list)
* pushed into the process using userfaultfd.
*/
do {
- ret = collect_uffd_pages(&pr, uffd_list);
+ ret = collect_uffd_pages(&pr, lpi);
if (ret == -1) {
goto out;
}
@@ -450,7 +466,7 @@ static int find_vmas(struct list_head *uffd_list)
pr.close(&pr);
/* Count detected pages */
- list_for_each_entry(uffd_pages, uffd_list, list)
+ list_for_each_entry(uffd_pages, &lpi->pages, list)
ret++;
pr_debug("Found %d pages to be handled by UFFD\n", ret);
@@ -459,7 +475,7 @@ out:
return ret;
}
-static int handle_user_fault(int fd, struct list_head *uffd_list, void *dest)
+static int handle_user_fault(struct lazy_pages_info *lpi, void *dest)
{
struct uffd_msg msg;
__u64 flags;
@@ -467,7 +483,7 @@ static int handle_user_fault(int fd, struct list_head *uffd_list, void *dest)
struct uffd_pages_struct *uffd_pages;
int ret;
- ret = read(fd, &msg, sizeof(msg));
+ ret = read(lpi->uffd, &msg, sizeof(msg));
pr_debug("read() ret: 0x%x\n", ret);
if (!ret)
return 1;
@@ -482,7 +498,7 @@ static int handle_user_fault(int fd, struct list_head *uffd_list, void *dest)
pr_debug("msg.arg.pagefault.address 0x%llx\n", address);
/* Make sure to not transfer a page twice */
- list_for_each_entry(uffd_pages, uffd_list, list)
+ list_for_each_entry(uffd_pages, &lpi->pages, list)
if ((uffd_pages->addr == address) && (uffd_pages->flags & UFFD_FLAG_SENT))
return 0;
@@ -495,7 +511,7 @@ static int handle_user_fault(int fd, struct list_head *uffd_list, void *dest)
return -1;
}
- ret = handle_regular_pages(fd, uffd_list, dest, address);
+ ret = handle_regular_pages(lpi, dest, address);
if (ret < 0) {
pr_err("Error during regular page copy\n");
return -1;
@@ -505,9 +521,8 @@ static int handle_user_fault(int fd, struct list_head *uffd_list, void *dest)
}
static int handle_socket_conn(int listen, struct sockaddr_un *saddr,
- struct list_head *uffd_list)
+ struct lazy_pages_info *lpi)
{
- int uffd;
int uffd_flags;
int client;
int ret;
@@ -525,60 +540,60 @@ static int handle_socket_conn(int listen, struct sockaddr_un *saddr,
/* The "transfer protocol" is first the pid as int and then
* the FD for UFFD */
- ret = recv(client, &pid, sizeof(pid), 0);
- if (ret != sizeof(pid)) {
+ ret = recv(client, &lpi->pid, sizeof(lpi->pid), 0);
+ if (ret != sizeof(lpi->pid)) {
pr_perror("PID recv error:");
ret = -1;
goto out;
}
- pr_debug("received PID: %d\n", pid);
+ pr_debug("received PID: %d\n", lpi->pid);
- uffd = recv_fd(client);
- if (uffd < 0) {
+ lpi->uffd = recv_fd(client);
+ if (lpi->uffd < 0) {
pr_perror("recv_fd error:");
goto out;
}
- pr_debug("uffd is %d\n", uffd);
+ pr_debug("uffd is %d\n", lpi->uffd);
close(client);
- uffd_flags = fcntl(uffd, F_GETFD, NULL);
+ uffd_flags = fcntl(lpi->uffd, F_GETFD, NULL);
pr_debug("uffd_flags are 0x%x\n", uffd_flags);
- if (fcntl(uffd, F_SETFD, uffd_flags | O_NONBLOCK))
+ if (fcntl(lpi->uffd, F_SETFD, uffd_flags | O_NONBLOCK))
return -1;
/*
* Find the memory pages belonging to the restored process so
* that it is trackable when all pages have been transferred.
*/
- if ((total_pages = find_vmas(uffd_list)) == -1)
+ if ((lpi->total_pages = find_vmas(lpi)) == -1)
return -1;
- return uffd;
+ return lpi->uffd;
out:
close(client);
return ret;
}
-static int lazy_pages_summary(void)
+static int lazy_pages_summary(struct lazy_pages_info *lpi)
{
- pr_debug("With UFFD transferred pages: (%ld/%ld)\n", uffd_copied_pages, total_pages);
+ pr_debug("With UFFD transferred pages: (%ld/%ld)\n", lpi->copied_pages, lpi->total_pages);
- if ((uffd_copied_pages != total_pages) && (total_pages > 0)) {
- pr_warn("Only %ld of %ld pages transferred via UFFD\n", uffd_copied_pages,
- total_pages);
+ if ((lpi->copied_pages != lpi->total_pages) && (lpi->total_pages > 0)) {
+ pr_warn("Only %ld of %ld pages transferred via UFFD\n", lpi->copied_pages,
+ lpi->total_pages);
pr_warn("Something probably went wrong.\n");
return 1;
}
return 0;
-
}
#define POLL_TIMEOUT 5000
static int handle_requests(int listen, struct sockaddr_un *saddr)
{
+ struct lazy_pages_info lpi;
struct pollfd *pollfd;
int nr_pollfd = 1;
int max_pollfd;
@@ -588,7 +603,8 @@ static int handle_requests(int listen, struct sockaddr_un *saddr)
void *dest;
int i;
- LIST_HEAD(uffd_list);
+ memset(&lpi, 0, sizeof(lpi));
+ INIT_LIST_HEAD(&lpi.pages);
/* All operations will be done on page size */
ps = page_size();
@@ -628,7 +644,7 @@ static int handle_requests(int listen, struct sockaddr_un *saddr)
}
if (pollfd[0].revents & POLLIN) {
- int fd = handle_socket_conn(listen, saddr, &uffd_list);
+ int fd = handle_socket_conn(listen, saddr, &lpi);
if (fd < 0)
goto out;
pollfd[nr_pollfd].fd = fd;
@@ -647,8 +663,7 @@ static int handle_requests(int listen, struct sockaddr_un *saddr)
for (i = 1; i < nr_pollfd; i++) {
if (pollfd[i].revents & POLLIN) {
- ret = handle_user_fault(pollfd[i].fd,
- &uffd_list, dest);
+ ret = handle_user_fault(&lpi, dest);
if (ret < 0)
goto out;
}
@@ -657,7 +672,7 @@ static int handle_requests(int listen, struct sockaddr_un *saddr)
for (i = 1; i < nr_pollfd; i++) {
pr_debug("Handle remaining pages\n");
- ret = handle_remaining_pages(pollfd[i].fd, &uffd_list, dest);
+ ret = handle_remaining_pages(&lpi, dest);
if (ret < 0) {
pr_err("Error during remaining page copy\n");
ret = 1;
@@ -665,7 +680,7 @@ static int handle_requests(int listen, struct sockaddr_un *saddr)
}
}
- ret = lazy_pages_summary();
+ ret = lazy_pages_summary(&lpi);
out:
for (i = nr_pollfd - 1; i > 0; i--)
--
1.9.1
More information about the CRIU
mailing list