[CRIU] [PATCH v2 4/7] lazy-pages: introduce struct lazy_pages_info
Mike Rapoport
rppt at linux.vnet.ibm.com
Mon Apr 18 06:34:35 PDT 2016
for holding state related to userfaultfd handling
Signed-off-by: Mike Rapoport <rppt at linux.vnet.ibm.com>
---
criu/uffd.c | 173 ++++++++++++++++++++++++++++++++++++------------------------
1 file changed, 104 insertions(+), 69 deletions(-)
diff --git a/criu/uffd.c b/criu/uffd.c
index 4219a41..f411a3a 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;
@@ -195,14 +205,14 @@ out:
return ret;
}
-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);
@@ -236,15 +246,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;
@@ -255,7 +263,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) {
@@ -269,13 +277,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();
@@ -286,7 +294,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) {
@@ -297,18 +305,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;
@@ -318,7 +327,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)
@@ -363,24 +377,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;
@@ -393,12 +407,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;
@@ -408,7 +423,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;
}
@@ -419,7 +434,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;
@@ -428,14 +443,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;
@@ -469,7 +487,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;
@@ -481,7 +499,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;
}
@@ -491,7 +509,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);
@@ -500,7 +518,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;
@@ -508,7 +526,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;
@@ -523,7 +541,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;
@@ -536,7 +554,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;
@@ -545,13 +563,13 @@ static int handle_user_fault(int fd, struct list_head *uffd_list, void *dest)
return 0;
}
-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;
}
@@ -559,7 +577,7 @@ static int lazy_pages_summary(void)
return 0;
}
-static int handle_requests(int fd)
+static int handle_requests(struct lazy_pages_info *lpi)
{
fd_set set;
int ret = -1;
@@ -567,18 +585,9 @@ static int handle_requests(int fd)
struct timeval timeout;
void *dest;
- LIST_HEAD(uffd_list);
-
- /*
- * 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)
- return -1;
-
/* Initialize FD sets for read() with timeouts (using select()) */
FD_ZERO(&set);
- FD_SET(fd, &set);
+ FD_SET(lpi->uffd, &set);
/* All operations will be done on page size */
ps = page_size();
@@ -596,7 +605,7 @@ static int handle_requests(int fd)
*/
timeout.tv_sec = 5;
timeout.tv_usec = 0;
- ret = select(fd + 1, &set, NULL, NULL, &timeout);
+ ret = select(lpi->uffd + 1, &set, NULL, NULL, &timeout);
pr_debug("select() rc: 0x%x\n", ret);
if (ret == 0) {
pr_debug("read timeout\n");
@@ -604,23 +613,23 @@ static int handle_requests(int fd)
break;
}
- ret = handle_user_fault(fd, &uffd_list, dest);
+ ret = handle_user_fault(lpi, dest);
if (ret < 0)
goto out;
}
pr_debug("Handle remaining pages\n");
- ret = handle_remaining_pages(fd, &uffd_list, dest);
+ ret = handle_remaining_pages(lpi, dest);
if (ret < 0) {
pr_err("Error during remaining page copy\n");
ret = 1;
goto out;
}
- ret = lazy_pages_summary();
+ ret = lazy_pages_summary(lpi);
out:
free(dest);
- close(fd);
+ close(lpi->uffd);
return ret;
}
@@ -646,24 +655,15 @@ static int lazy_pages_prepare_pstree(void)
return 0;
}
-int cr_lazy_pages()
+static int prepare_uffds(struct lazy_pages_info *lpi)
{
int listen;
int uffd;
int uffd_flags;
- int ret;
struct sockaddr_un saddr;
- if (!opts.addr) {
- pr_info("Please specify a file name for the unix domain socket\n");
- pr_info("used to communicate between the lazy-pages server\n");
- pr_info("and the restore process. Use the --address option like\n");
- pr_info("criu --lazy-pages --address /tmp/userfault.socket\n");
- return -1;
- }
-
- if (lazy_pages_prepare_pstree())
- return -1;
+ memset(lpi, 0, sizeof(*lpi));
+ INIT_LIST_HEAD(&lpi->pages);
pr_debug("Waiting for incoming connections on %s\n", opts.addr);
if ((listen = server_listen(&saddr)) < 0) {
@@ -674,17 +674,52 @@ int cr_lazy_pages()
uffd = ud_open(listen, &saddr);
if (uffd < 0) {
pr_perror("uffd open error");
- return -1;
+ goto close_unix_sock;
}
pr_debug("uffd is 0x%d\n", uffd);
uffd_flags = fcntl(uffd, F_GETFD, NULL);
pr_debug("uffd_flags are 0x%x\n", uffd_flags);
- ret = handle_requests(uffd);
+ lpi->uffd = uffd;
+ lpi->pid = pid;
+
+ /*
+ * Find the memory pages belonging to the restored process
+ * so that it is trackable when all pages have been transferred.
+ */
+ if ((lpi->total_pages = find_vmas(lpi)) == -1)
+ goto close_uffd;
+
close(listen);
+ return 0;
- return ret;
+close_uffd:
+ close(uffd);
+close_unix_sock:
+ close(listen);
+ return -1;
+}
+
+int cr_lazy_pages()
+{
+ struct lazy_pages_info lpi;
+
+ if (!opts.addr) {
+ pr_info("Please specify a file name for the unix domain socket\n");
+ pr_info("used to communicate between the lazy-pages server\n");
+ pr_info("and the restore process. Use the --address option like\n");
+ pr_info("criu --lazy-pages --address /tmp/userfault.socket\n");
+ return -1;
+ }
+
+ if (lazy_pages_prepare_pstree())
+ return -1;
+
+ if (prepare_uffds(&lpi))
+ return -1;
+
+ return handle_requests(&lpi);
}
#else /* CONFIG_HAS_UFFD */
--
1.9.1
More information about the CRIU
mailing list