mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-25 19:14:04 +00:00
rst: Re-use opened fd when restoring private mappings
On restore we do a sequence of open+mmap+close steps. On real apps there exists chains of private file mappings for the same file with different pgoffs and/or flags/prots. Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
parent
d6d06c9dfc
commit
73cb87f918
1 changed files with 34 additions and 10 deletions
44
cr-restore.c
44
cr-restore.c
|
|
@ -247,9 +247,23 @@ err:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* When mapping a file in several VMAs we can use one descriptor
|
||||
* for all mappings, no need to re-open it for every mmap. By
|
||||
* doing this we save many open-s since typically applications
|
||||
* have sequences of VMAs for the same file with different pgoffs
|
||||
* and/or prots. This is restore-side analogue of the VMA file
|
||||
* borrowing in proc_parse.c.
|
||||
*/
|
||||
|
||||
struct vma_fd_cache {
|
||||
struct file_desc *d;
|
||||
int fd;
|
||||
};
|
||||
|
||||
/* Map a private vma, if it is not mapped by a parent yet */
|
||||
static int map_private_vma(struct vma_area *vma, void **tgt_addr,
|
||||
struct vma_area **pvma, struct list_head *pvma_list)
|
||||
struct vma_area **pvma, struct list_head *pvma_list, struct vma_fd_cache *fc)
|
||||
{
|
||||
int ret;
|
||||
void *addr, *paddr = NULL;
|
||||
|
|
@ -257,12 +271,21 @@ static int map_private_vma(struct vma_area *vma, void **tgt_addr,
|
|||
struct vma_area *p = *pvma;
|
||||
|
||||
if (vma_area_is(vma, VMA_FILE_PRIVATE)) {
|
||||
ret = get_filemap_fd(vma);
|
||||
if (ret < 0) {
|
||||
pr_err("Can't fixup VMA's fd\n");
|
||||
return -1;
|
||||
if (fc->d != vma->vmfd) {
|
||||
if (fc->fd != -1)
|
||||
close(fc->fd);
|
||||
|
||||
ret = get_filemap_fd(vma);
|
||||
if (ret < 0) {
|
||||
pr_err("Can't fixup VMA's fd\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fc->d = vma->vmfd;
|
||||
fc->fd = ret;
|
||||
}
|
||||
vma->e->fd = ret;
|
||||
|
||||
vma->e->fd = fc->fd;
|
||||
}
|
||||
|
||||
nr_pages = vma_entry_len(vma->e) / PAGE_SIZE;
|
||||
|
|
@ -352,9 +375,6 @@ static int map_private_vma(struct vma_area *vma, void **tgt_addr,
|
|||
vma->premmaped_addr += PAGE_SIZE;
|
||||
}
|
||||
|
||||
if (vma_area_is(vma, VMA_FILE_PRIVATE))
|
||||
close(vma->e->fd);
|
||||
|
||||
*tgt_addr += size;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -366,6 +386,7 @@ static int premap_priv_vmas(struct vm_area_list *vmas, void *at)
|
|||
unsigned long pstart = 0;
|
||||
int ret = 0;
|
||||
LIST_HEAD(empty);
|
||||
struct vma_fd_cache fc = { .d = NULL, .fd = -1 };
|
||||
|
||||
/*
|
||||
* Keep parent vmas at hands to check whether we can "inherit" them.
|
||||
|
|
@ -389,11 +410,14 @@ static int premap_priv_vmas(struct vm_area_list *vmas, void *at)
|
|||
if (!vma_area_is_private(vma, kdat.task_size))
|
||||
continue;
|
||||
|
||||
ret = map_private_vma(vma, &at, &pvma, parent_vmas);
|
||||
ret = map_private_vma(vma, &at, &pvma, parent_vmas, &fc);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (fc.fd != -1)
|
||||
close(fc.fd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue