Commit ce5e1916 authored by Mike Rapoport's avatar Mike Rapoport Committed by Andrei Vagin

Make userfaultfd detection a part of kerndat

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: 's avatarMike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
parent 8dcb4e07
......@@ -50,6 +50,7 @@
#include "libnetlink.h"
#include "net.h"
#include "restorer.h"
#include "linux/userfaultfd.h"
static char *feature_name(int (*func)());
......@@ -1045,6 +1046,23 @@ static int check_compat_cr(void)
return -1;
}
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);
/*
......@@ -1156,6 +1174,7 @@ int cr_check(void)
if (opts.check_experimental_features) {
ret |= check_autofs();
ret |= check_compat_cr();
ret |= check_uffd();
}
print_on_level(DEFAULT_LOGLEVEL, "%s\n", ret ? CHECK_MAYBE : CHECK_GOOD);
......@@ -1197,6 +1216,7 @@ static struct feature_list feature_list[] = {
{ "autofs", check_autofs },
{ "tcp_half_closed", check_tcp_halt_closed },
{ "compat_cr", check_compat_cr },
{ "lazy_pages", check_uffd },
{ NULL, NULL },
};
......
......@@ -49,6 +49,7 @@ struct kerndat_s {
bool has_tcp_half_closed;
bool stack_guard_gap_hidden;
int lsm;
unsigned long uffd_features;
};
extern struct kerndat_s kdat;
......@@ -70,5 +71,6 @@ enum {
extern int kerndat_fs_virtualized(unsigned int which, u32 kdev);
extern int kerndat_tcp_repair();
extern int kerndat_uffd(bool need_uffd);
#endif /* __CR_KERNDAT_H__ */
......@@ -30,6 +30,7 @@
#include <compel/plugins/std/syscall-codes.h>
#include <compel/compel.h>
#include "netfilter.h"
#include "linux/userfaultfd.h"
struct kerndat_s kdat = {
};
......@@ -714,6 +715,44 @@ unl:
}
}
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;
......@@ -752,6 +791,8 @@ int kerndat_init(void)
ret = kerndat_has_memfd_create();
if (!ret)
ret = kerndat_detect_stack_guard_gap();
if (!ret)
ret = kerndat_uffd(opts.lazy_pages);
kerndat_lsm();
kerndat_mmap_min_addr();
......
......@@ -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())
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment