[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