[CRIU] [PATCH 1/7] lazy-pages: introduce uffd_open
Mike Rapoport
rppt at linux.vnet.ibm.com
Tue Aug 15 09:23:48 MSK 2017
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 at linux.vnet.ibm.com>
---
criu/include/uffd.h | 2 ++
criu/kerndat.c | 34 +++++++++++++--------------------
criu/uffd.c | 54 +++++++++++++++++++++++++++++++++++++----------------
3 files changed, 53 insertions(+), 37 deletions(-)
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;
--
2.7.4
More information about the CRIU
mailing list