mirror of
https://github.com/checkpoint-restore/criu
synced 2025-09-01 14:55:39 +00:00
kerndat: check the PAGEMAP_SCAN ioctl
PAGEMAP_SCAN is a new ioctl that allows to get page attributes in a more effeciant way than reading pagemap files. Signed-off-by: Andrei Vagin <avagin@gmail.com>
This commit is contained in:
@@ -1382,6 +1382,14 @@ static int check_ipv6_freebind(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int check_pagemap_scan(void)
|
||||||
|
{
|
||||||
|
if (!kdat.has_pagemap_scan)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int (*chk_feature)(void);
|
static int (*chk_feature)(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1502,6 +1510,7 @@ int cr_check(void)
|
|||||||
ret |= check_openat2();
|
ret |= check_openat2();
|
||||||
ret |= check_ptrace_get_rseq_conf();
|
ret |= check_ptrace_get_rseq_conf();
|
||||||
ret |= check_ipv6_freebind();
|
ret |= check_ipv6_freebind();
|
||||||
|
ret |= check_pagemap_scan();
|
||||||
|
|
||||||
if (kdat.lsm == LSMTYPE__APPARMOR)
|
if (kdat.lsm == LSMTYPE__APPARMOR)
|
||||||
ret |= check_apparmor_stacking();
|
ret |= check_apparmor_stacking();
|
||||||
@@ -1623,6 +1632,7 @@ static struct feature_list feature_list[] = {
|
|||||||
{ "openat2", check_openat2 },
|
{ "openat2", check_openat2 },
|
||||||
{ "get_rseq_conf", check_ptrace_get_rseq_conf },
|
{ "get_rseq_conf", check_ptrace_get_rseq_conf },
|
||||||
{ "ipv6_freebind", check_ipv6_freebind },
|
{ "ipv6_freebind", check_ipv6_freebind },
|
||||||
|
{ "pagemap_scan", check_pagemap_scan },
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -86,6 +86,7 @@ struct kerndat_s {
|
|||||||
struct __ptrace_rseq_configuration libc_rseq_conf;
|
struct __ptrace_rseq_configuration libc_rseq_conf;
|
||||||
bool has_ipv6_freebind;
|
bool has_ipv6_freebind;
|
||||||
bool has_membarrier_get_registrations;
|
bool has_membarrier_get_registrations;
|
||||||
|
bool has_pagemap_scan;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct kerndat_s kdat;
|
extern struct kerndat_s kdat;
|
||||||
|
68
criu/include/pagemap_scan.h
Normal file
68
criu/include/pagemap_scan.h
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#ifndef __CR_PAGEMAP_SCAN_H__
|
||||||
|
#define __CR_PAGEMAP_SCAN_H__
|
||||||
|
|
||||||
|
#ifndef PAGEMAP_SCAN
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include "int.h"
|
||||||
|
|
||||||
|
/* Bitmasks provided in pm_scan_args masks and reported in page_region.categories. */
|
||||||
|
#define PAGE_IS_WPALLOWED (1 << 0)
|
||||||
|
#define PAGE_IS_WRITTEN (1 << 1)
|
||||||
|
#define PAGE_IS_FILE (1 << 2)
|
||||||
|
#define PAGE_IS_PRESENT (1 << 3)
|
||||||
|
#define PAGE_IS_SWAPPED (1 << 4)
|
||||||
|
#define PAGE_IS_PFNZERO (1 << 5)
|
||||||
|
#define PAGE_IS_HUGE (1 << 6)
|
||||||
|
#define PAGE_IS_SOFT_DIRTY (1 << 7)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* struct page_region - Page region with flags
|
||||||
|
* @start: Start of the region
|
||||||
|
* @end: End of the region (exclusive)
|
||||||
|
* @categories: PAGE_IS_* category bitmask for the region
|
||||||
|
*/
|
||||||
|
struct page_region {
|
||||||
|
u64 start;
|
||||||
|
u64 end;
|
||||||
|
u64 categories;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PAGEMAP_SCAN _IOWR('f', 16, struct pm_scan_arg)
|
||||||
|
|
||||||
|
/* Flags for PAGEMAP_SCAN ioctl */
|
||||||
|
#define PM_SCAN_WP_MATCHING (1 << 0) /* Write protect the pages matched. */
|
||||||
|
#define PM_SCAN_CHECK_WPASYNC (1 << 1) /* Abort the scan when a non-WP-enabled page is found. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* struct pm_scan_arg - Pagemap ioctl argument
|
||||||
|
* @size: Size of the structure
|
||||||
|
* @flags: Flags for the IOCTL
|
||||||
|
* @start: Starting address of the region
|
||||||
|
* @end: Ending address of the region
|
||||||
|
* @walk_end Address where the scan stopped (written by kernel).
|
||||||
|
* walk_end == end (address tags cleared) informs that the scan completed on entire range.
|
||||||
|
* @vec: Address of page_region struct array for output
|
||||||
|
* @vec_len: Length of the page_region struct array
|
||||||
|
* @max_pages: Optional limit for number of returned pages (0 = disabled)
|
||||||
|
* @category_inverted: PAGE_IS_* categories which values match if 0 instead of 1
|
||||||
|
* @category_mask: Skip pages for which any category doesn't match
|
||||||
|
* @category_anyof_mask: Skip pages for which no category matches
|
||||||
|
* @return_mask: PAGE_IS_* categories that are to be reported in `page_region`s returned
|
||||||
|
*/
|
||||||
|
struct pm_scan_arg {
|
||||||
|
u64 size;
|
||||||
|
u64 flags;
|
||||||
|
u64 start;
|
||||||
|
u64 end;
|
||||||
|
u64 walk_end;
|
||||||
|
u64 vec;
|
||||||
|
u64 vec_len;
|
||||||
|
u64 max_pages;
|
||||||
|
u64 category_inverted;
|
||||||
|
u64 category_mask;
|
||||||
|
u64 category_anyof_mask;
|
||||||
|
u64 return_mask;
|
||||||
|
};
|
||||||
|
#endif /* PAGEMAP_SCAN */
|
||||||
|
|
||||||
|
#endif /* __CR_PAGEMAP_SCAN_H__ */
|
@@ -54,6 +54,7 @@
|
|||||||
#include "memfd.h"
|
#include "memfd.h"
|
||||||
#include "mount-v2.h"
|
#include "mount-v2.h"
|
||||||
#include "util-caps.h"
|
#include "util-caps.h"
|
||||||
|
#include "pagemap_scan.h"
|
||||||
|
|
||||||
struct kerndat_s kdat = {};
|
struct kerndat_s kdat = {};
|
||||||
volatile int dummy_var;
|
volatile int dummy_var;
|
||||||
@@ -74,6 +75,25 @@ static int check_pagemap(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ioctl(fd, PAGEMAP_SCAN, NULL) == 0) {
|
||||||
|
pr_err("PAGEMAP_SCAN succeeded unexpectedly\n");
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
switch (errno) {
|
||||||
|
case EFAULT:
|
||||||
|
pr_debug("PAGEMAP_SCAN is supported\n");
|
||||||
|
kdat.has_pagemap_scan = true;
|
||||||
|
break;
|
||||||
|
case EINVAL:
|
||||||
|
case ENOTTY:
|
||||||
|
pr_debug("PAGEMAP_SCAN isn't supported\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pr_perror("PAGEMAP_SCAN failed with unexpected errno");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
retry = 3;
|
retry = 3;
|
||||||
while (retry--) {
|
while (retry--) {
|
||||||
++dummy_var;
|
++dummy_var;
|
||||||
|
Reference in New Issue
Block a user