[CRIU] [PATCH 2/2] Make userfaultfd detection a part of kerndat
Mike Rapoport
rppt at linux.vnet.ibm.com
Thu Dec 8 05:10:12 PST 2016
Instead of checking for availability of userfaultfd late during the restore
process, make the detection of supported userfaultfd functionality part of
kerndat. As a bonus, I've extended criu check with ability to verify
presence of userfaultfd.
Signed-off-by: Mike Rapoport <rppt at linux.vnet.ibm.com>
---
criu/cr-check.c | 20 ++++++++++++++++++++
criu/include/kerndat.h | 2 ++
criu/kerndat.c | 41 +++++++++++++++++++++++++++++++++++++++++
criu/uffd.c | 25 +------------------------
4 files changed, 64 insertions(+), 24 deletions(-)
diff --git a/criu/cr-check.c b/criu/cr-check.c
index fa5c2eb..60279e1 100644
--- a/criu/cr-check.c
+++ b/criu/cr-check.c
@@ -47,6 +47,7 @@
#include "cr_options.h"
#include "libnetlink.h"
#include "net.h"
+#include "linux/userfaultfd.h"
static char *feature_name(int (*func)());
@@ -953,6 +954,23 @@ static int check_tcp_window(void)
return 0;
}
+static int check_uffd(void)
+{
+ unsigned long features = UFFD_FEATURE_EVENT_FORK |
+ UFFD_FEATURE_EVENT_REMAP |
+ UFFD_FEATURE_EVENT_MADVDONTNEED;
+
+ if (kerndat_uffd(true))
+ return -1;
+
+ if ((kdat.uffd_features & features) != features) {
+ pr_err("Userfaultfd missing essential features\n");
+ return -1;
+ }
+
+ return 0;
+}
+
static int (*chk_feature)(void);
/*
@@ -1061,6 +1079,7 @@ int cr_check(void)
*/
if (opts.check_experimental_features) {
ret |= check_autofs();
+ ret |= check_uffd();
}
print_on_level(DEFAULT_LOGLEVEL, "%s\n", ret ? CHECK_MAYBE : CHECK_GOOD);
@@ -1134,6 +1153,7 @@ static struct feature_list feature_list[] = {
{ "cgroupns", check_cgroupns },
{ "autofs", check_autofs },
{ "tcp_half_closed", check_tcp_halt_closed },
+ { "lazy_pages", check_uffd },
{ NULL, NULL },
};
diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h
index 7021c18..ab6ef3f 100644
--- a/criu/include/kerndat.h
+++ b/criu/include/kerndat.h
@@ -39,6 +39,7 @@ struct kerndat_s {
enum pagemap_func pmap;
unsigned int has_xtlocks;
bool has_tcp_half_closed;
+ unsigned long uffd_features;
};
extern struct kerndat_s kdat;
@@ -61,5 +62,6 @@ extern int kerndat_fs_virtualized(unsigned int which, u32 kdev);
extern int kerndat_tcp_repair_window();
extern int kerndat_tcp_repair();
+extern int kerndat_uffd(bool need_uffd);
#endif /* __CR_KERNDAT_H__ */
diff --git a/criu/kerndat.c b/criu/kerndat.c
index c30e18e..82599ec 100644
--- a/criu/kerndat.c
+++ b/criu/kerndat.c
@@ -26,6 +26,7 @@
#include "sk-inet.h"
#include <compel/plugins/std/syscall-codes.h>
#include <compel/compel.h>
+#include "linux/userfaultfd.h"
struct kerndat_s kdat = {
};
@@ -532,6 +533,44 @@ static int kerndat_compat_restore(void)
return 0;
}
+int kerndat_uffd(bool need_uffd)
+{
+ struct uffdio_api uffdio_api;
+ int uffd;
+
+ uffd = syscall(SYS_userfaultfd, 0);
+
+ /*
+ * uffd == -1 is probably enough to not use lazy-restore
+ * on this system. Additionally checking for ENOSYS
+ * makes sure it is actually not implemented.
+ */
+ if (uffd == -1 && errno == ENOSYS) {
+ if (!need_uffd)
+ return 0;
+
+ pr_err("Lazy pages are not available\n");
+ return -1;
+ }
+
+ 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;
+
+ close(uffd);
+ return 0;
+}
+
int kerndat_init(void)
{
int ret;
@@ -596,6 +635,8 @@ int kerndat_init_rst(void)
ret = kerndat_compat_restore();
if (!ret)
ret = kerndat_tcp_repair();
+ if (!ret)
+ ret = kerndat_uffd(opts.lazy_pages);
kerndat_lsm();
diff --git a/criu/uffd.c b/criu/uffd.c
index d71a83a..0575d3b 100644
--- a/criu/uffd.c
+++ b/criu/uffd.c
@@ -166,27 +166,6 @@ out:
return ret;
}
-/* Runtime detection if userfaultfd can be used */
-
-static int check_for_uffd()
-{
- int uffd;
-
- uffd = syscall(SYS_userfaultfd, 0);
- /*
- * uffd == -1 is probably enough to not use lazy-restore
- * on this system. Additionally checking for ENOSYS
- * makes sure it is actually not implemented.
- */
- if ((uffd == -1) && (errno == ENOSYS)) {
- pr_err("Runtime detection of userfaultfd failed on this system.\n");
- pr_err("Processes cannot be lazy-restored on this system.\n");
- return -1;
- }
- close(uffd);
- return 0;
-}
-
int lazy_pages_setup_zombie(int pid)
{
if (!opts.lazy_pages)
@@ -208,8 +187,6 @@ int setup_uffd(int pid, struct task_restore_args *task_args)
return 0;
}
- if (check_for_uffd())
- return -1;
/*
* Open userfaulfd FD which is passed to the restorer blob and
* to a second process handling the userfaultfd page faults.
@@ -812,7 +789,7 @@ int cr_lazy_pages(bool daemon)
int lazy_sk;
int ret;
- if (check_for_uffd())
+ if (kerndat_uffd(true))
return -1;
if (prepare_dummy_pstree())
--
1.9.1
More information about the CRIU
mailing list