Commit 830dd301 authored by Mike Rapoport's avatar Mike Rapoport Committed by Andrei Vagin

lazy-pages: introduce uffd_open

kdat and lazy-pages use nearly the same sequence to open userfault. This
code can definitely live in a dedicated function.
Signed-off-by: 's avatarMike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
parent 1f2cc31f
......@@ -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);
......
......@@ -33,6 +33,7 @@
#include "netfilter.h"
#include "linux/userfaultfd.h"
#include "prctl.h"
#include "uffd.h"
struct kerndat_s kdat = {
};
......@@ -719,18 +720,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");
......@@ -739,21 +740,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;
}
......
......@@ -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;
......
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