[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