mirror of
https://github.com/checkpoint-restore/criu
synced 2025-09-01 14:55:39 +00:00
criu: lazy-pages: move find_vmas and related code around
Moving the find_vmas and collect_uffd_pages functions before they are actually used. This allows to drop forward declaration of find_vmas and will make subsequent refactoring cleaner. Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com> Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
This commit is contained in:
committed by
Andrei Vagin
parent
6d405370da
commit
c00dd3459f
400
criu/uffd.c
400
criu/uffd.c
@@ -287,85 +287,6 @@ out:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_vmas(struct lazy_pages_info *lpi);
|
|
||||||
|
|
||||||
static int ud_open(int client, struct lazy_pages_info **_lpi)
|
|
||||||
{
|
|
||||||
struct lazy_pages_info *lpi;
|
|
||||||
int ret = -1;
|
|
||||||
int uffd_flags;
|
|
||||||
|
|
||||||
lpi = lpi_init();
|
|
||||||
if (!lpi)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* The "transfer protocol" is first the pid as int and then
|
|
||||||
* the FD for UFFD */
|
|
||||||
ret = recv(client, &lpi->pid, sizeof(lpi->pid), 0);
|
|
||||||
if (ret != sizeof(lpi->pid)) {
|
|
||||||
if (ret < 0)
|
|
||||||
pr_perror("PID recv error");
|
|
||||||
else
|
|
||||||
pr_err("PID recv: short read\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
pr_debug("received PID: %d\n", lpi->pid);
|
|
||||||
|
|
||||||
if (lpi->pid == -1) {
|
|
||||||
lpi_fini(lpi);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
lpi->uffd = recv_fd(client);
|
|
||||||
if (lpi->uffd < 0) {
|
|
||||||
pr_err("recv_fd error\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
pr_debug("lpi->uffd %d\n", lpi->uffd);
|
|
||||||
|
|
||||||
pr_debug("uffd is 0x%d\n", lpi->uffd);
|
|
||||||
uffd_flags = fcntl(lpi->uffd, F_GETFD, NULL);
|
|
||||||
pr_debug("uffd_flags are 0x%x\n", uffd_flags);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Find the memory pages belonging to the restored process
|
|
||||||
* so that it is trackable when all pages have been transferred.
|
|
||||||
*/
|
|
||||||
if ((lpi->total_pages = find_vmas(lpi)) == -1)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
list_add_tail(&lpi->l, &lpis);
|
|
||||||
*_lpi = lpi;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
out:
|
|
||||||
lpi_fini(lpi);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_page(struct lazy_pages_info *lpi, unsigned long addr, void *dest)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
lpi->pr.reset(&lpi->pr);
|
|
||||||
|
|
||||||
ret = lpi->pr.seek_page(&lpi->pr, addr);
|
|
||||||
pr_debug("seek_pagemap_page ret 0x%x\n", ret);
|
|
||||||
if (ret <= 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (pagemap_zero(lpi->pr.pe))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
ret = lpi->pr.read_pages(&lpi->pr, addr, 1, dest, 0);
|
|
||||||
pr_debug("read_pages ret %d\n", ret);
|
|
||||||
if (ret <= 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define UFFD_FLAG_SENT 0x1
|
#define UFFD_FLAG_SENT 0x1
|
||||||
|
|
||||||
struct uffd_pages_struct {
|
struct uffd_pages_struct {
|
||||||
@@ -374,80 +295,6 @@ struct uffd_pages_struct {
|
|||||||
int flags;
|
int flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int uffd_copy_page(struct lazy_pages_info *lpi, __u64 address,
|
|
||||||
void *dest)
|
|
||||||
{
|
|
||||||
struct uffdio_copy uffdio_copy;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (opts.use_page_server)
|
|
||||||
rc = get_remote_pages(lpi->pid, address, 1, dest);
|
|
||||||
else
|
|
||||||
rc = get_page(lpi, address, dest);
|
|
||||||
if (rc <= 0)
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
uffdio_copy.dst = address;
|
|
||||||
uffdio_copy.src = (unsigned long) dest;
|
|
||||||
uffdio_copy.len = page_size();
|
|
||||||
uffdio_copy.mode = 0;
|
|
||||||
uffdio_copy.copy = 0;
|
|
||||||
|
|
||||||
pr_debug("uffdio_copy.dst 0x%llx\n", uffdio_copy.dst);
|
|
||||||
rc = ioctl(lpi->uffd, UFFDIO_COPY, &uffdio_copy);
|
|
||||||
pr_debug("ioctl UFFDIO_COPY rc 0x%x\n", rc);
|
|
||||||
pr_debug("uffdio_copy.copy 0x%llx\n", uffdio_copy.copy);
|
|
||||||
if (rc) {
|
|
||||||
/* real retval in ufdio_copy.copy */
|
|
||||||
if (uffdio_copy.copy != -EEXIST) {
|
|
||||||
pr_err("UFFDIO_COPY error %Ld\n", uffdio_copy.copy);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else if (uffdio_copy.copy != page_size()) {
|
|
||||||
pr_err("UFFDIO_COPY unexpected size %Ld\n", uffdio_copy.copy);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
lpi->copied_pages++;
|
|
||||||
|
|
||||||
return uffdio_copy.copy;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static int uffd_zero_page(struct lazy_pages_info *lpi, __u64 address)
|
|
||||||
{
|
|
||||||
struct uffdio_zeropage uffdio_zeropage;
|
|
||||||
unsigned long ps = page_size();
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
uffdio_zeropage.range.start = address;
|
|
||||||
uffdio_zeropage.range.len = ps;
|
|
||||||
uffdio_zeropage.mode = 0;
|
|
||||||
|
|
||||||
pr_debug("uffdio_zeropage.range.start 0x%llx\n", uffdio_zeropage.range.start);
|
|
||||||
rc = ioctl(lpi->uffd, UFFDIO_ZEROPAGE, &uffdio_zeropage);
|
|
||||||
pr_debug("ioctl UFFDIO_ZEROPAGE rc 0x%x\n", rc);
|
|
||||||
pr_debug("uffdio_zeropage.zeropage 0x%llx\n", uffdio_zeropage.zeropage);
|
|
||||||
if (rc) {
|
|
||||||
pr_err("UFFDIO_ZEROPAGE error %d\n", rc);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ps;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int uffd_handle_page(struct lazy_pages_info *lpi, __u64 address,
|
|
||||||
void *dest)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
rc = uffd_copy_page(lpi, address, dest);
|
|
||||||
if (rc == 0)
|
|
||||||
rc = uffd_zero_page(lpi, address);
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int collect_uffd_pages(struct page_read *pr, struct lazy_pages_info *lpi)
|
static int collect_uffd_pages(struct page_read *pr, struct lazy_pages_info *lpi)
|
||||||
{
|
{
|
||||||
unsigned long base;
|
unsigned long base;
|
||||||
@@ -512,54 +359,6 @@ static int collect_uffd_pages(struct page_read *pr, struct lazy_pages_info *lpi)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int handle_remaining_pages(struct lazy_pages_info *lpi, void *dest)
|
|
||||||
{
|
|
||||||
struct uffd_pages_struct *uffd_pages;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
list_for_each_entry(uffd_pages, &lpi->pages, list) {
|
|
||||||
pr_debug("Checking remaining pages 0x%lx (flags 0x%x)\n",
|
|
||||||
uffd_pages->addr, uffd_pages->flags);
|
|
||||||
if (uffd_pages->flags & UFFD_FLAG_SENT)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
rc = uffd_handle_page(lpi, uffd_pages->addr, dest);
|
|
||||||
if (rc < 0) {
|
|
||||||
pr_err("Error during UFFD copy\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uffd_pages->flags |= UFFD_FLAG_SENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int handle_regular_pages(struct lazy_pages_info *lpi, void *dest,
|
|
||||||
__u64 address)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
struct uffd_pages_struct *uffd_pages;
|
|
||||||
|
|
||||||
rc = uffd_handle_page(lpi, address, dest);
|
|
||||||
if (rc < 0) {
|
|
||||||
pr_err("Error during UFFD copy\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Mark this page as having been already transferred, so
|
|
||||||
* that it has not to be copied again later.
|
|
||||||
*/
|
|
||||||
list_for_each_entry(uffd_pages, &lpi->pages, list) {
|
|
||||||
if (uffd_pages->addr == address)
|
|
||||||
uffd_pages->flags |= UFFD_FLAG_SENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setting up criu infrastructure and scan for VMAs.
|
* Setting up criu infrastructure and scan for VMAs.
|
||||||
*/
|
*/
|
||||||
@@ -643,6 +442,205 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ud_open(int client, struct lazy_pages_info **_lpi)
|
||||||
|
{
|
||||||
|
struct lazy_pages_info *lpi;
|
||||||
|
int ret = -1;
|
||||||
|
int uffd_flags;
|
||||||
|
|
||||||
|
lpi = lpi_init();
|
||||||
|
if (!lpi)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* The "transfer protocol" is first the pid as int and then
|
||||||
|
* the FD for UFFD */
|
||||||
|
ret = recv(client, &lpi->pid, sizeof(lpi->pid), 0);
|
||||||
|
if (ret != sizeof(lpi->pid)) {
|
||||||
|
if (ret < 0)
|
||||||
|
pr_perror("PID recv error");
|
||||||
|
else
|
||||||
|
pr_err("PID recv: short read\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
pr_debug("received PID: %d\n", lpi->pid);
|
||||||
|
|
||||||
|
if (lpi->pid == -1) {
|
||||||
|
lpi_fini(lpi);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lpi->uffd = recv_fd(client);
|
||||||
|
if (lpi->uffd < 0) {
|
||||||
|
pr_err("recv_fd error\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
pr_debug("lpi->uffd %d\n", lpi->uffd);
|
||||||
|
|
||||||
|
pr_debug("uffd is 0x%d\n", lpi->uffd);
|
||||||
|
uffd_flags = fcntl(lpi->uffd, F_GETFD, NULL);
|
||||||
|
pr_debug("uffd_flags are 0x%x\n", uffd_flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find the memory pages belonging to the restored process
|
||||||
|
* so that it is trackable when all pages have been transferred.
|
||||||
|
*/
|
||||||
|
if ((lpi->total_pages = find_vmas(lpi)) == -1)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
list_add_tail(&lpi->l, &lpis);
|
||||||
|
*_lpi = lpi;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
lpi_fini(lpi);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_page(struct lazy_pages_info *lpi, unsigned long addr, void *dest)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
lpi->pr.reset(&lpi->pr);
|
||||||
|
|
||||||
|
ret = lpi->pr.seek_page(&lpi->pr, addr);
|
||||||
|
pr_debug("seek_pagemap_page ret 0x%x\n", ret);
|
||||||
|
if (ret <= 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (pagemap_zero(lpi->pr.pe))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = lpi->pr.read_pages(&lpi->pr, addr, 1, dest, 0);
|
||||||
|
pr_debug("read_pages ret %d\n", ret);
|
||||||
|
if (ret <= 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uffd_copy_page(struct lazy_pages_info *lpi, __u64 address,
|
||||||
|
void *dest)
|
||||||
|
{
|
||||||
|
struct uffdio_copy uffdio_copy;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (opts.use_page_server)
|
||||||
|
rc = get_remote_pages(lpi->pid, address, 1, dest);
|
||||||
|
else
|
||||||
|
rc = get_page(lpi, address, dest);
|
||||||
|
if (rc <= 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
uffdio_copy.dst = address;
|
||||||
|
uffdio_copy.src = (unsigned long) dest;
|
||||||
|
uffdio_copy.len = page_size();
|
||||||
|
uffdio_copy.mode = 0;
|
||||||
|
uffdio_copy.copy = 0;
|
||||||
|
|
||||||
|
pr_debug("uffdio_copy.dst 0x%llx\n", uffdio_copy.dst);
|
||||||
|
rc = ioctl(lpi->uffd, UFFDIO_COPY, &uffdio_copy);
|
||||||
|
pr_debug("ioctl UFFDIO_COPY rc 0x%x\n", rc);
|
||||||
|
pr_debug("uffdio_copy.copy 0x%llx\n", uffdio_copy.copy);
|
||||||
|
if (rc) {
|
||||||
|
/* real retval in ufdio_copy.copy */
|
||||||
|
if (uffdio_copy.copy != -EEXIST) {
|
||||||
|
pr_err("UFFDIO_COPY error %Ld\n", uffdio_copy.copy);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else if (uffdio_copy.copy != page_size()) {
|
||||||
|
pr_err("UFFDIO_COPY unexpected size %Ld\n", uffdio_copy.copy);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
lpi->copied_pages++;
|
||||||
|
|
||||||
|
return uffdio_copy.copy;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uffd_zero_page(struct lazy_pages_info *lpi, __u64 address)
|
||||||
|
{
|
||||||
|
struct uffdio_zeropage uffdio_zeropage;
|
||||||
|
unsigned long ps = page_size();
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
uffdio_zeropage.range.start = address;
|
||||||
|
uffdio_zeropage.range.len = ps;
|
||||||
|
uffdio_zeropage.mode = 0;
|
||||||
|
|
||||||
|
pr_debug("uffdio_zeropage.range.start 0x%llx\n", uffdio_zeropage.range.start);
|
||||||
|
rc = ioctl(lpi->uffd, UFFDIO_ZEROPAGE, &uffdio_zeropage);
|
||||||
|
pr_debug("ioctl UFFDIO_ZEROPAGE rc 0x%x\n", rc);
|
||||||
|
pr_debug("uffdio_zeropage.zeropage 0x%llx\n", uffdio_zeropage.zeropage);
|
||||||
|
if (rc) {
|
||||||
|
pr_err("UFFDIO_ZEROPAGE error %d\n", rc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ps;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uffd_handle_page(struct lazy_pages_info *lpi, __u64 address,
|
||||||
|
void *dest)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = uffd_copy_page(lpi, address, dest);
|
||||||
|
if (rc == 0)
|
||||||
|
rc = uffd_zero_page(lpi, address);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_remaining_pages(struct lazy_pages_info *lpi, void *dest)
|
||||||
|
{
|
||||||
|
struct uffd_pages_struct *uffd_pages;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
list_for_each_entry(uffd_pages, &lpi->pages, list) {
|
||||||
|
pr_debug("Checking remaining pages 0x%lx (flags 0x%x)\n",
|
||||||
|
uffd_pages->addr, uffd_pages->flags);
|
||||||
|
if (uffd_pages->flags & UFFD_FLAG_SENT)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
rc = uffd_handle_page(lpi, uffd_pages->addr, dest);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("Error during UFFD copy\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uffd_pages->flags |= UFFD_FLAG_SENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int handle_regular_pages(struct lazy_pages_info *lpi, void *dest,
|
||||||
|
__u64 address)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct uffd_pages_struct *uffd_pages;
|
||||||
|
|
||||||
|
rc = uffd_handle_page(lpi, address, dest);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("Error during UFFD copy\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mark this page as having been already transferred, so
|
||||||
|
* that it has not to be copied again later.
|
||||||
|
*/
|
||||||
|
list_for_each_entry(uffd_pages, &lpi->pages, list) {
|
||||||
|
if (uffd_pages->addr == address)
|
||||||
|
uffd_pages->flags |= UFFD_FLAG_SENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int handle_user_fault(struct lazy_pages_info *lpi, void *dest)
|
static int handle_user_fault(struct lazy_pages_info *lpi, void *dest)
|
||||||
{
|
{
|
||||||
struct uffd_msg msg;
|
struct uffd_msg msg;
|
||||||
|
Reference in New Issue
Block a user