[1/7] lazy-pages: introduce uffd_open

Submitted by Mike Rapoport on Aug. 15, 2017, 6:23 a.m.

Details

Message ID 1502778234-24415-2-git-send-email-rppt@linux.vnet.ibm.com
State New
Series "lazy-pages: update checks for availability of userfaultfd"
Headers show

Commit Message

Mike Rapoport Aug. 15, 2017, 6:23 a.m.
kdat and lazy-pages use nearly the same sequence to open userfault. This
code can definitely live in a dedicated function.

Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
---
 criu/include/uffd.h |  2 ++
 criu/kerndat.c      | 34 +++++++++++++--------------------
 criu/uffd.c         | 54 +++++++++++++++++++++++++++++++++++++----------------
 3 files changed, 53 insertions(+), 37 deletions(-)

Patch hide | download patch | download mbox

diff --git a/criu/include/uffd.h b/criu/include/uffd.h
index 4d790ce..e2b9be6 100644
--- a/criu/include/uffd.h
+++ b/criu/include/uffd.h
@@ -2,6 +2,8 @@ 
 #define __CR_UFFD_H_
 
 struct task_restore_args;
+
+extern int uffd_open(int flags, unsigned long *features);
 extern int setup_uffd(int pid, struct task_restore_args *task_args);
 extern int lazy_pages_setup_zombie(int pid);
 extern int prepare_lazy_pages_socket(void);
diff --git a/criu/kerndat.c b/criu/kerndat.c
index e107883..d309e04 100644
--- a/criu/kerndat.c
+++ b/criu/kerndat.c
@@ -37,6 +37,7 @@ 
 #include "netfilter.h"
 #include "vdso.h"
 #include "prctl.h"
+#include "uffd.h"
 
 struct kerndat_s kdat = {
 };
@@ -872,18 +873,18 @@  unl:
 
 int kerndat_uffd(void)
 {
-	struct uffdio_api uffdio_api;
 	int uffd;
 
-	uffd = syscall(SYS_userfaultfd, 0);
+	uffd = uffd_open(0, &kdat.uffd_features);
 
 	/*
-	 * uffd == -1 is probably enough to not use lazy-restore
-	 * on this system. Additionally checking for ENOSYS
-	 * makes sure it is actually not implemented.
+	 * uffd == -ENOSYS means userfaultfd is not supported on this
+	 * system and we just happily return with kdat.has_uffd = false.
+	 * Error other than -ENOSYS would mean "Houston, Houston, we
+	 * have a problem!"
 	 */
-	if (uffd == -1) {
-		if (errno == ENOSYS)
+	if (uffd < 0) {
+		if (uffd == -ENOSYS)
 			return 0;
 
 		pr_err("Lazy pages are not available\n");
@@ -892,21 +893,12 @@  int kerndat_uffd(void)
 
 	kdat.has_uffd = true;
 
-	uffdio_api.api = UFFD_API;
-	uffdio_api.features = 0;
-	if (ioctl(uffd, UFFDIO_API, &uffdio_api)) {
-		pr_perror("Failed to get uffd API");
-		return -1;
-	}
-	if (uffdio_api.api != UFFD_API) {
-		pr_err("Incompatible uffd API: expected %Lu, got %Lu\n",
-		       UFFD_API, uffdio_api.api);
-		return -1;
-	}
-
-	kdat.uffd_features = uffdio_api.features;
-
+	/*
+	 * we have to close the uffd and reopen in later in restorer
+	 * to enable non-cooperative features
+	 */
 	close(uffd);
+
 	return 0;
 }
 
diff --git a/criu/uffd.c b/criu/uffd.c
index c5ad785..d3142ae 100644
--- a/criu/uffd.c
+++ b/criu/uffd.c
@@ -211,10 +211,46 @@  int lazy_pages_setup_zombie(int pid)
 	return 0;
 }
 
+int uffd_open(int flags, unsigned long *features)
+{
+	struct uffdio_api uffdio_api = { 0 };
+	int uffd;
+
+	uffd = syscall(SYS_userfaultfd, flags);
+	if (uffd == -1) {
+		pr_perror("Lazy pages are not available");
+		return -errno;
+	}
+
+	uffdio_api.api = UFFD_API;
+	if (features)
+		uffdio_api.features = *features;
+
+	if (ioctl(uffd, UFFDIO_API, &uffdio_api)) {
+		pr_perror("Failed to get uffd API");
+		goto err;
+	}
+
+	if (uffdio_api.api != UFFD_API) {
+		pr_err("Incompatible uffd API: expected %Lu, got %Lu\n",
+		       UFFD_API, uffdio_api.api);
+		goto err;
+	}
+
+	if (features)
+		*features = uffdio_api.features;
+
+	return uffd;
+
+err:
+	close(uffd);
+	return -1;
+}
+
 /* This function is used by 'criu restore --lazy-pages' */
 int setup_uffd(int pid, struct task_restore_args *task_args)
 {
-	struct uffdio_api uffdio_api;
+	unsigned long features = kdat.uffd_features & NEED_UFFD_API_FEATURES;
 
 	if (!opts.lazy_pages) {
 		task_args->uffd = -1;
@@ -225,26 +261,12 @@  int setup_uffd(int pid, struct task_restore_args *task_args)
 	 * Open userfaulfd FD which is passed to the restorer blob and
 	 * to a second process handling the userfaultfd page faults.
 	 */
-	task_args->uffd = syscall(SYS_userfaultfd, O_CLOEXEC | O_NONBLOCK);
+	task_args->uffd = uffd_open(O_CLOEXEC | O_NONBLOCK, &features);
 	if (task_args->uffd < 0) {
 		pr_perror("Unable to open an userfaultfd descriptor");
 		return -1;
 	}
 
-	/*
-	 * Check if the UFFD_API is the one which is expected
-	 */
-	uffdio_api.api = UFFD_API;
-	uffdio_api.features = kdat.uffd_features & NEED_UFFD_API_FEATURES;
-	if (ioctl(task_args->uffd, UFFDIO_API, &uffdio_api)) {
-		pr_err("Checking for UFFDIO_API failed.\n");
-		goto err;
-	}
-	if (uffdio_api.api != UFFD_API) {
-		pr_err("Result of looking up UFFDIO_API does not match: %Lu\n", uffdio_api.api);
-		goto err;
-	}
-
 	if (send_uffd(task_args->uffd, pid) < 0)
 		goto err;