mirror of
https://github.com/checkpoint-restore/criu
synced 2025-09-03 15:55:53 +00:00
proc-parse: Don't open and stat every single map_files link
Quite a lot of VMAs in tasks map the same file with different perms. In that case we may skip opening all these files, but "borrow" one from the previous VMA parsed. There's little sense in seeking more that just previous VMA, as same files are rarely (can be though) mapped in different locations. After this on a basic Centos6 container the number of opens and stats in this function drops from ~1500 to ~500. Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
@@ -116,6 +116,8 @@ static void close_vma_file(struct vma_area *vma)
|
|||||||
return;
|
return;
|
||||||
if (vma->vma.status & VMA_AREA_SOCKET)
|
if (vma->vma.status & VMA_AREA_SOCKET)
|
||||||
return;
|
return;
|
||||||
|
if (vma->file_borrowed)
|
||||||
|
return;
|
||||||
|
|
||||||
close(vma->vm_file_fd);
|
close(vma->vm_file_fd);
|
||||||
}
|
}
|
||||||
|
@@ -25,6 +25,8 @@ struct vma_area {
|
|||||||
unsigned long *ppage_bitmap; /* parent's existent pages */
|
unsigned long *ppage_bitmap; /* parent's existent pages */
|
||||||
|
|
||||||
unsigned long premmaped_addr;
|
unsigned long premmaped_addr;
|
||||||
|
|
||||||
|
bool file_borrowed;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int collect_mappings(pid_t pid, struct vm_area_list *vma_area_list);
|
extern int collect_mappings(pid_t pid, struct vm_area_list *vma_area_list);
|
||||||
|
58
proc_parse.c
58
proc_parse.c
@@ -142,13 +142,41 @@ static inline int is_anon_shmem_map(dev_t dev)
|
|||||||
return kerndat_shmem_dev == dev;
|
return kerndat_shmem_dev == dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vma_get_mapfile(struct vma_area *vma, DIR *mfd)
|
struct vma_file_info {
|
||||||
|
int dev_maj;
|
||||||
|
int dev_min;
|
||||||
|
unsigned long ino;
|
||||||
|
struct vma_area *vma;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline int vfi_equal(struct vma_file_info *a, struct vma_file_info *b)
|
||||||
|
{
|
||||||
|
return ((a->ino ^ b->ino) |
|
||||||
|
(a->dev_maj ^ b->dev_maj) |
|
||||||
|
(a->dev_min ^ b->dev_min)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vma_get_mapfile(struct vma_area *vma, DIR *mfd,
|
||||||
|
struct vma_file_info *vfi, struct vma_file_info *prev_vfi)
|
||||||
{
|
{
|
||||||
char path[32];
|
char path[32];
|
||||||
|
|
||||||
if (!mfd)
|
if (!mfd)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (prev_vfi->vma && vfi_equal(vfi, prev_vfi)) {
|
||||||
|
struct vma_area *prev = prev_vfi->vma;
|
||||||
|
|
||||||
|
pr_debug("vma %lx borrows vfi from previous %lx\n",
|
||||||
|
vma->vma.start, prev->vma.start);
|
||||||
|
vma->vm_file_fd = prev->vm_file_fd;
|
||||||
|
if (prev->vma.status & VMA_AREA_SOCKET)
|
||||||
|
vma->vma.status |= VMA_AREA_SOCKET | VMA_AREA_REGULAR;
|
||||||
|
vma->file_borrowed = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Figure out if it's file mapping */
|
/* Figure out if it's file mapping */
|
||||||
snprintf(path, sizeof(path), "%lx-%lx", vma->vma.start, vma->vma.end);
|
snprintf(path, sizeof(path), "%lx-%lx", vma->vma.start, vma->vma.end);
|
||||||
|
|
||||||
@@ -184,10 +212,10 @@ int parse_smaps(pid_t pid, struct vm_area_list *vma_area_list, bool use_map_file
|
|||||||
struct vma_area *vma_area = NULL;
|
struct vma_area *vma_area = NULL;
|
||||||
unsigned long start, end, pgoff;
|
unsigned long start, end, pgoff;
|
||||||
bool prev_growsdown = false;
|
bool prev_growsdown = false;
|
||||||
unsigned long ino;
|
|
||||||
char r, w, x, s;
|
char r, w, x, s;
|
||||||
int dev_maj, dev_min;
|
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
struct vma_file_info vfi;
|
||||||
|
struct vma_file_info prev_vfi = {};
|
||||||
|
|
||||||
DIR *map_files_dir = NULL;
|
DIR *map_files_dir = NULL;
|
||||||
FILE *smaps = NULL;
|
FILE *smaps = NULL;
|
||||||
@@ -249,6 +277,9 @@ int parse_smaps(pid_t pid, struct vm_area_list *vma_area_list, bool use_map_file
|
|||||||
vma_area_list->priv_size += pages;
|
vma_area_list->priv_size += pages;
|
||||||
vma_area_list->longest = max(vma_area_list->longest, pages);
|
vma_area_list->longest = max(vma_area_list->longest, pages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prev_vfi = vfi;
|
||||||
|
prev_vfi.vma = vma_area;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eof)
|
if (eof)
|
||||||
@@ -260,8 +291,8 @@ int parse_smaps(pid_t pid, struct vm_area_list *vma_area_list, bool use_map_file
|
|||||||
|
|
||||||
memset(file_path, 0, 6);
|
memset(file_path, 0, 6);
|
||||||
num = sscanf(buf, "%lx-%lx %c%c%c%c %lx %x:%x %lu %5s",
|
num = sscanf(buf, "%lx-%lx %c%c%c%c %lx %x:%x %lu %5s",
|
||||||
&start, &end, &r, &w, &x, &s, &pgoff, &dev_maj,
|
&start, &end, &r, &w, &x, &s, &pgoff,
|
||||||
&dev_min, &ino, file_path);
|
&vfi.dev_maj, &vfi.dev_min, &vfi.ino, file_path);
|
||||||
if (num < 10) {
|
if (num < 10) {
|
||||||
pr_err("Can't parse: %s\n", buf);
|
pr_err("Can't parse: %s\n", buf);
|
||||||
goto err;
|
goto err;
|
||||||
@@ -272,7 +303,7 @@ int parse_smaps(pid_t pid, struct vm_area_list *vma_area_list, bool use_map_file
|
|||||||
vma_area->vma.pgoff = pgoff;
|
vma_area->vma.pgoff = pgoff;
|
||||||
vma_area->vma.prot = PROT_NONE;
|
vma_area->vma.prot = PROT_NONE;
|
||||||
|
|
||||||
if (vma_get_mapfile(vma_area, map_files_dir))
|
if (vma_get_mapfile(vma_area, map_files_dir, &vfi, &prev_vfi))
|
||||||
goto err_bogus_mapfile;
|
goto err_bogus_mapfile;
|
||||||
|
|
||||||
if (r == 'r')
|
if (r == 'r')
|
||||||
@@ -309,7 +340,18 @@ int parse_smaps(pid_t pid, struct vm_area_list *vma_area_list, bool use_map_file
|
|||||||
* Some mapping hints for restore, we save this on
|
* Some mapping hints for restore, we save this on
|
||||||
* disk and restore might need to analyze it.
|
* disk and restore might need to analyze it.
|
||||||
*/
|
*/
|
||||||
if (vma_area->vm_file_fd >= 0) {
|
if (vma_area->file_borrowed) {
|
||||||
|
struct vma_area *prev = prev_vfi.vma;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pick-up flags that might be set in the branch below.
|
||||||
|
* Status is copied as-is as it should be zero here,
|
||||||
|
* and have full match with the previous.
|
||||||
|
*/
|
||||||
|
vma_area->vma.flags |= (prev->vma.flags & MAP_ANONYMOUS);
|
||||||
|
vma_area->vma.status = prev->vma.status;
|
||||||
|
vma_area->vma.shmid = prev->vma.shmid;
|
||||||
|
} else if (vma_area->vm_file_fd >= 0) {
|
||||||
struct stat st_buf;
|
struct stat st_buf;
|
||||||
|
|
||||||
if (fstat(vma_area->vm_file_fd, &st_buf) < 0) {
|
if (fstat(vma_area->vm_file_fd, &st_buf) < 0) {
|
||||||
@@ -350,7 +392,7 @@ int parse_smaps(pid_t pid, struct vm_area_list *vma_area_list, bool use_map_file
|
|||||||
*/
|
*/
|
||||||
if (vma_area->vma.flags & MAP_SHARED) {
|
if (vma_area->vma.flags & MAP_SHARED) {
|
||||||
vma_area->vma.status |= VMA_ANON_SHARED;
|
vma_area->vma.status |= VMA_ANON_SHARED;
|
||||||
vma_area->vma.shmid = ino;
|
vma_area->vma.shmid = vfi.ino;
|
||||||
} else {
|
} else {
|
||||||
vma_area->vma.status |= VMA_ANON_PRIVATE;
|
vma_area->vma.status |= VMA_ANON_PRIVATE;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user