Commit 73cb87f9 authored by Pavel Emelyanov's avatar Pavel Emelyanov

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: 's avatarPavel Emelyanov <xemul@parallels.com>
parent d6d06c9d
...@@ -247,9 +247,23 @@ err: ...@@ -247,9 +247,23 @@ err:
return ret; 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 */ /* 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, 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; int ret;
void *addr, *paddr = NULL; void *addr, *paddr = NULL;
...@@ -257,12 +271,21 @@ static int map_private_vma(struct vma_area *vma, void **tgt_addr, ...@@ -257,12 +271,21 @@ static int map_private_vma(struct vma_area *vma, void **tgt_addr,
struct vma_area *p = *pvma; struct vma_area *p = *pvma;
if (vma_area_is(vma, VMA_FILE_PRIVATE)) { if (vma_area_is(vma, VMA_FILE_PRIVATE)) {
ret = get_filemap_fd(vma); if (fc->d != vma->vmfd) {
if (ret < 0) { if (fc->fd != -1)
pr_err("Can't fixup VMA's fd\n"); close(fc->fd);
return -1;
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; 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, ...@@ -352,9 +375,6 @@ static int map_private_vma(struct vma_area *vma, void **tgt_addr,
vma->premmaped_addr += PAGE_SIZE; vma->premmaped_addr += PAGE_SIZE;
} }
if (vma_area_is(vma, VMA_FILE_PRIVATE))
close(vma->e->fd);
*tgt_addr += size; *tgt_addr += size;
return 0; return 0;
} }
...@@ -366,6 +386,7 @@ static int premap_priv_vmas(struct vm_area_list *vmas, void *at) ...@@ -366,6 +386,7 @@ static int premap_priv_vmas(struct vm_area_list *vmas, void *at)
unsigned long pstart = 0; unsigned long pstart = 0;
int ret = 0; int ret = 0;
LIST_HEAD(empty); LIST_HEAD(empty);
struct vma_fd_cache fc = { .d = NULL, .fd = -1 };
/* /*
* Keep parent vmas at hands to check whether we can "inherit" them. * 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) ...@@ -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)) if (!vma_area_is_private(vma, kdat.task_size))
continue; continue;
ret = map_private_vma(vma, &at, &pvma, parent_vmas); ret = map_private_vma(vma, &at, &pvma, parent_vmas, &fc);
if (ret < 0) if (ret < 0)
break; break;
} }
if (fc.fd != -1)
close(fc.fd);
return ret; return ret;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment