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:
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)) {
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;
}
vma->e->fd = ret;
fc->d = vma->vmfd;
fc->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;
}
......
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