2
0
mirror of https://github.com/checkpoint-restore/criu synced 2025-08-31 06:15:24 +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:
Andrei Vagin
2023-10-25 01:07:27 +00:00
parent 842289c7eb
commit 20628bc8a1
4 changed files with 99 additions and 0 deletions

View File

@@ -1382,6 +1382,14 @@ static int check_ipv6_freebind(void)
return 0;
}
static int check_pagemap_scan(void)
{
if (!kdat.has_pagemap_scan)
return -1;
return 0;
}
static int (*chk_feature)(void);
/*
@@ -1502,6 +1510,7 @@ int cr_check(void)
ret |= check_openat2();
ret |= check_ptrace_get_rseq_conf();
ret |= check_ipv6_freebind();
ret |= check_pagemap_scan();
if (kdat.lsm == LSMTYPE__APPARMOR)
ret |= check_apparmor_stacking();
@@ -1623,6 +1632,7 @@ static struct feature_list feature_list[] = {
{ "openat2", check_openat2 },
{ "get_rseq_conf", check_ptrace_get_rseq_conf },
{ "ipv6_freebind", check_ipv6_freebind },
{ "pagemap_scan", check_pagemap_scan },
{ NULL, NULL },
};

View File

@@ -86,6 +86,7 @@ struct kerndat_s {
struct __ptrace_rseq_configuration libc_rseq_conf;
bool has_ipv6_freebind;
bool has_membarrier_get_registrations;
bool has_pagemap_scan;
};
extern struct kerndat_s kdat;

View 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__ */

View File

@@ -54,6 +54,7 @@
#include "memfd.h"
#include "mount-v2.h"
#include "util-caps.h"
#include "pagemap_scan.h"
struct kerndat_s kdat = {};
volatile int dummy_var;
@@ -74,6 +75,25 @@ static int check_pagemap(void)
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;
while (retry--) {
++dummy_var;