mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-08-01 22:33:30 +00:00
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: Mike Rapoport <rppt@linux.vnet.ibm.com> Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
This commit is contained in:
parent
1f2cc31fd5
commit
830dd3018f
3 changed files with 53 additions and 37 deletions
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
54
criu/uffd.c
54
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;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue