[CRIU] [PATCH 11/11] lazy-pages: allow handling multiple processes

Mike Rapoport rppt at linux.vnet.ibm.com
Sun Apr 10 23:19:54 PDT 2016


Signed-off-by: Mike Rapoport <rppt at linux.vnet.ibm.com>
---
 criu/uffd.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 81 insertions(+), 25 deletions(-)

diff --git a/criu/uffd.c b/criu/uffd.c
index f37c64d..bd2e0e6 100644
--- a/criu/uffd.c
+++ b/criu/uffd.c
@@ -42,8 +42,39 @@ struct lazy_pages_info {
 
 	unsigned long total_pages;
 	unsigned long copied_pages;
+
+	struct hlist_node hash;
 };
 
+#define LPI_HASH_SIZE	16
+static struct hlist_head lpi_hash[LPI_HASH_SIZE];
+
+static void lpi_hash_init(void)
+{
+	int i;
+
+	for (i = 0; i < LPI_HASH_SIZE; i++)
+		INIT_HLIST_HEAD(&lpi_hash[i]);
+}
+
+struct lazy_pages_info *uffd_to_lpi(int uffd)
+{
+	struct lazy_pages_info *lpi;
+	struct hlist_head *head;
+
+	head = &lpi_hash[uffd % LPI_HASH_SIZE];
+	hlist_for_each_entry(lpi, head, hash)
+		if (lpi->uffd == uffd)
+			return lpi;
+
+	return NULL;
+}
+
+static void lpi_hash_fini(void)
+{
+	/* FIXME: free the hash table memory */
+}
+
 static int send_uffd(int sendfd, int pid)
 {
 	int fd;
@@ -520,9 +551,27 @@ static int handle_user_fault(struct lazy_pages_info *lpi, void *dest)
 	return 0;
 }
 
-static int handle_socket_conn(int listen, struct sockaddr_un *saddr,
-			      struct lazy_pages_info *lpi)
+static struct lazy_pages_info *lpi_init(void)
+{
+	struct lazy_pages_info *lpi = NULL;
+
+	lpi = malloc(sizeof(*lpi));
+	if (!lpi) {
+		pr_err("allocation failed\n");
+		return NULL;
+	}
+
+	memset(lpi, 0, sizeof(*lpi));
+	INIT_LIST_HEAD(&lpi->pages);
+	INIT_HLIST_NODE(&lpi->hash);
+
+	return lpi;
+}
+
+static struct lazy_pages_info *handle_socket_conn(int listen,
+						  struct sockaddr_un *saddr)
 {
+	struct lazy_pages_info *lpi;
 	int uffd_flags;
 	int client;
 	int ret;
@@ -533,17 +582,20 @@ static int handle_socket_conn(int listen, struct sockaddr_un *saddr,
 	if ((client = accept(listen, saddr, &len)) < 0) {
 		pr_perror("server_accept error: %d", client);
 		close(listen);
-		return -1;
+		return NULL;
 	}
 
 	pr_debug("client fd %d\n", client);
 
+	lpi = lpi_init();
+	if (!lpi)
+		goto out;
+
 	/* The "transfer protocol" is first the pid as int and then
 	 * the FD for UFFD */
 	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", lpi->pid);
@@ -556,28 +608,32 @@ static int handle_socket_conn(int listen, struct sockaddr_un *saddr,
 	pr_debug("uffd is %d\n", lpi->uffd);
 	close(client);
 
+	hlist_add_head(&lpi->hash, &lpi_hash[lpi->uffd % LPI_HASH_SIZE]);
+
 	uffd_flags = fcntl(lpi->uffd, F_GETFD, NULL);
 	pr_debug("uffd_flags are 0x%x\n", uffd_flags);
 	if (fcntl(lpi->uffd, F_SETFD, uffd_flags | O_NONBLOCK))
-		return -1;
+		goto out;
 
 	/*
 	 * 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)
-		return -1;
+		goto out;
 
-	return lpi->uffd;
+	return lpi;
 
 out:
 	close(client);
-	return ret;
+	free(lpi);
+	return NULL;
 }
 
 static int lazy_pages_summary(struct lazy_pages_info *lpi)
 {
-	pr_debug("With UFFD transferred pages: (%ld/%ld)\n", lpi->copied_pages, lpi->total_pages);
+	pr_debug("Process %d: with UFFD transferred pages: (%ld/%ld)\n",
+		 lpi->pid, lpi->copied_pages, lpi->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,
@@ -593,7 +649,7 @@ static int lazy_pages_summary(struct lazy_pages_info *lpi)
 
 static int handle_requests(int listen, struct sockaddr_un *saddr)
 {
-	struct lazy_pages_info lpi;
+	struct lazy_pages_info *lpi;
 	struct pollfd *pollfd;
 	int nr_pollfd = 1;
 	int max_pollfd;
@@ -603,9 +659,6 @@ static int handle_requests(int listen, struct sockaddr_un *saddr)
 	void *dest;
 	int i;
 
-	memset(&lpi, 0, sizeof(lpi));
-	INIT_LIST_HEAD(&lpi.pages);
-
 	/* All operations will be done on page size */
 	ps = page_size();
 	dest = malloc(ps);
@@ -644,10 +697,10 @@ static int handle_requests(int listen, struct sockaddr_un *saddr)
 		}
 
 		if (pollfd[0].revents & POLLIN) {
-			int fd = handle_socket_conn(listen, saddr, &lpi);
-			if (fd < 0)
+			lpi = handle_socket_conn(listen, saddr);
+			if (!lpi)
 				goto out;
-			pollfd[nr_pollfd].fd = fd;
+			pollfd[nr_pollfd].fd = lpi->uffd;
 			pollfd[nr_pollfd].events = POLLIN;
 			nr_pollfd++;
 			BUG_ON(nr_pollfd > max_pollfd);
@@ -663,7 +716,8 @@ 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(&lpi, dest);
+				lpi = uffd_to_lpi(pollfd[i].fd);
+				ret = handle_user_fault(lpi, dest);
 				if (ret < 0)
 					goto out;
 			}
@@ -672,7 +726,8 @@ 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(&lpi, dest);
+		lpi = uffd_to_lpi(pollfd[i].fd);
+		ret = handle_remaining_pages(lpi, dest);
 		if (ret < 0) {
 			pr_err("Error during remaining page copy\n");
 			ret = 1;
@@ -680,7 +735,10 @@ static int handle_requests(int listen, struct sockaddr_un *saddr)
 		}
 	}
 
-	ret = lazy_pages_summary(&lpi);
+	for (i = 1; i < nr_pollfd; i++) {
+		lpi = uffd_to_lpi(pollfd[i].fd);
+		ret += lazy_pages_summary(lpi);
+	}
 
 out:
 	for (i = nr_pollfd - 1; i > 0; i--)
@@ -703,12 +761,6 @@ static int lazy_pages_prepare_pstree(void)
 	if (prepare_pstree() == -1)
 		return -1;
 
-	/* bail out early until we know how to handle multiple tasks */
-	if (task_entries->nr_tasks > 1) {
-		pr_msg("lazy-pages cannot restore more than one task, sorry\n");
-		return -1;
-	}
-
 	return 0;
 }
 
@@ -726,6 +778,8 @@ int cr_lazy_pages()
 		return -1;
 	}
 
+	lpi_hash_init();
+
 	if (lazy_pages_prepare_pstree())
 		return -1;
 
@@ -738,6 +792,8 @@ int cr_lazy_pages()
 	ret = handle_requests(listen, &saddr);
 	close(listen);
 
+	lpi_hash_fini();
+
 	return ret;
 }
 
-- 
1.9.1



More information about the CRIU mailing list