Commit d9c3b91c authored by Pavel Emelyanov's avatar Pavel Emelyanov

mem: Place mprotect and dump_pages args in one parasite args area

This is required for (soon to be) pre-dump command -- this command
will have to keep parasite args with pagemap (iovecs) some time after
parasite is executed. Since we call mprotect cmd _after_ pages dump
we can thus spoil these iovecs. To address this vmas to mprotect and
iovecs to dump are located in one parasite args area one after another
without intersections.
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent eb41d26d
#ifndef __CR_MEM_H__ #ifndef __CR_MEM_H__
#define __CR_MEM_H__ #define __CR_MEM_H__
struct vm_area_list; struct vm_area_list;
unsigned int vmas_pagemap_size(struct vm_area_list *vmas); unsigned int dump_pages_args_size(struct vm_area_list *vmas);
struct parasite_ctl; struct parasite_ctl;
int parasite_dump_pages_seized(struct parasite_ctl *ctl, int parasite_dump_pages_seized(struct parasite_ctl *ctl,
struct vm_area_list *vma_area_list); struct vm_area_list *vma_area_list);
......
...@@ -60,19 +60,24 @@ struct parasite_vma_entry ...@@ -60,19 +60,24 @@ struct parasite_vma_entry
int prot; int prot;
}; };
struct parasite_mprotect_args
{
unsigned int nr;
struct parasite_vma_entry vmas[0];
};
struct parasite_dump_pages_args { struct parasite_dump_pages_args {
unsigned int nr_vmas;
unsigned int add_prot;
unsigned int off; unsigned int off;
unsigned int nr_segs; unsigned int nr_segs;
unsigned int nr_pages; unsigned int nr_pages;
struct iovec iovs[0];
}; };
static inline struct parasite_vma_entry *pargs_vmas(struct parasite_dump_pages_args *a)
{
return (struct parasite_vma_entry *)(a + 1);
}
static inline struct iovec *pargs_iovs(struct parasite_dump_pages_args *a)
{
return (struct iovec *)(pargs_vmas(a) + a->nr_vmas);
}
struct parasite_dump_sa_args { struct parasite_dump_sa_args {
rt_sigaction_t sas[SIGMAX]; rt_sigaction_t sas[SIGMAX];
}; };
......
...@@ -152,7 +152,7 @@ static void mem_snap_close(struct mem_snap_ctx *ctx) ...@@ -152,7 +152,7 @@ static void mem_snap_close(struct mem_snap_ctx *ctx)
} }
} }
unsigned int vmas_pagemap_size(struct vm_area_list *vmas) unsigned int dump_pages_args_size(struct vm_area_list *vmas)
{ {
/* /*
* In the worst case I need one iovec for half of the * In the worst case I need one iovec for half of the
...@@ -160,6 +160,7 @@ unsigned int vmas_pagemap_size(struct vm_area_list *vmas) ...@@ -160,6 +160,7 @@ unsigned int vmas_pagemap_size(struct vm_area_list *vmas)
*/ */
return sizeof(struct parasite_dump_pages_args) + return sizeof(struct parasite_dump_pages_args) +
vmas->nr * sizeof(struct parasite_vma_entry) +
(vmas->priv_size + 1) * sizeof(struct iovec) / 2; (vmas->priv_size + 1) * sizeof(struct iovec) / 2;
} }
...@@ -257,38 +258,39 @@ static int generate_iovs(struct vma_area *vma, int pagemap, struct page_pipe *pp ...@@ -257,38 +258,39 @@ static int generate_iovs(struct vma_area *vma, int pagemap, struct page_pipe *pp
return 0; return 0;
} }
static int parasite_mprotect_seized(struct parasite_ctl *ctl, struct vm_area_list *vma_area_list, bool unprotect) static struct parasite_dump_pages_args *prep_dump_pages_args(struct parasite_ctl *ctl,
struct vm_area_list *vma_area_list)
{ {
struct parasite_mprotect_args *args; struct parasite_dump_pages_args *args;
struct parasite_vma_entry *p_vma; struct parasite_vma_entry *p_vma;
struct vma_area *vma; struct vma_area *vma;
args = parasite_args_s(ctl, vmas_pagemap_size(vma_area_list)); args = parasite_args_s(ctl, dump_pages_args_size(vma_area_list));
p_vma = args->vmas; p_vma = pargs_vmas(args);
args->nr = 0; args->nr_vmas = 0;
list_for_each_entry(vma, &vma_area_list->h, list) { list_for_each_entry(vma, &vma_area_list->h, list) {
if (!privately_dump_vma(vma)) if (!privately_dump_vma(vma))
continue; continue;
if (vma->vma.prot & PROT_READ) if (vma->vma.prot & PROT_READ)
continue; continue;
p_vma->start = vma->vma.start; p_vma->start = vma->vma.start;
p_vma->len = vma_area_len(vma); p_vma->len = vma_area_len(vma);
p_vma->prot = vma->vma.prot; p_vma->prot = vma->vma.prot;
if (unprotect)
p_vma->prot |= PROT_READ; args->nr_vmas++;
args->nr++;
p_vma++; p_vma++;
} }
return parasite_execute(PARASITE_CMD_MPROTECT_VMAS, ctl); return args;
} }
static int __parasite_dump_pages_seized(struct parasite_ctl *ctl, static int __parasite_dump_pages_seized(struct parasite_ctl *ctl,
struct parasite_dump_pages_args *args,
struct vm_area_list *vma_area_list) struct vm_area_list *vma_area_list)
{ {
struct parasite_dump_pages_args *args;
u64 *map; u64 *map;
int pagemap; int pagemap;
struct page_pipe *pp; struct page_pipe *pp;
...@@ -311,8 +313,6 @@ static int __parasite_dump_pages_seized(struct parasite_ctl *ctl, ...@@ -311,8 +313,6 @@ static int __parasite_dump_pages_seized(struct parasite_ctl *ctl,
if (IS_ERR(snap)) if (IS_ERR(snap))
goto out; goto out;
args = parasite_args_s(ctl, vmas_pagemap_size(vma_area_list));
map = xmalloc(vma_area_list->longest * sizeof(*map)); map = xmalloc(vma_area_list->longest * sizeof(*map));
if (!map) if (!map)
goto out_snap; goto out_snap;
...@@ -328,7 +328,7 @@ static int __parasite_dump_pages_seized(struct parasite_ctl *ctl, ...@@ -328,7 +328,7 @@ static int __parasite_dump_pages_seized(struct parasite_ctl *ctl,
} }
ret = -1; ret = -1;
pp = create_page_pipe(vma_area_list->priv_size / 2, args->iovs); pp = create_page_pipe(vma_area_list->priv_size / 2, pargs_iovs(args));
if (!pp) if (!pp)
goto out_close; goto out_close;
...@@ -388,18 +388,24 @@ int parasite_dump_pages_seized(struct parasite_ctl *ctl, ...@@ -388,18 +388,24 @@ int parasite_dump_pages_seized(struct parasite_ctl *ctl,
struct vm_area_list *vma_area_list) struct vm_area_list *vma_area_list)
{ {
int ret; int ret;
struct parasite_dump_pages_args *pargs;
ret = parasite_mprotect_seized(ctl, vma_area_list, true); pargs = prep_dump_pages_args(ctl, vma_area_list);
pargs->add_prot = PROT_READ;
ret = parasite_execute(PARASITE_CMD_MPROTECT_VMAS, ctl);
if (ret) { if (ret) {
pr_err("Can't dump unprotect vmas with parasite\n"); pr_err("Can't dump unprotect vmas with parasite\n");
return ret; return ret;
} }
ret = __parasite_dump_pages_seized(ctl, vma_area_list); ret = __parasite_dump_pages_seized(ctl, pargs, vma_area_list);
if (ret) if (ret)
pr_err("Can't dump page with parasite\n"); pr_err("Can't dump page with parasite\n");
if (parasite_mprotect_seized(ctl, vma_area_list, false)) { pargs->add_prot = 0;
ret = parasite_execute(PARASITE_CMD_MPROTECT_VMAS, ctl);
if (ret) {
pr_err("Can't rollback unprotected vmas with parasite\n"); pr_err("Can't rollback unprotected vmas with parasite\n");
ret = -1; ret = -1;
} }
......
...@@ -485,12 +485,6 @@ int parasite_dump_creds(struct parasite_ctl *ctl, CredsEntry *ce) ...@@ -485,12 +485,6 @@ int parasite_dump_creds(struct parasite_ctl *ctl, CredsEntry *ce)
return 0; return 0;
} }
static unsigned int vmas_mprotect_size(struct vm_area_list *vmas)
{
return sizeof(struct parasite_mprotect_args) +
(vmas->nr * sizeof(struct parasite_vma_entry));
}
int parasite_drain_fds_seized(struct parasite_ctl *ctl, int parasite_drain_fds_seized(struct parasite_ctl *ctl,
struct parasite_drain_fd *dfds, int *lfds, struct fd_opts *opts) struct parasite_drain_fd *dfds, int *lfds, struct fd_opts *opts)
{ {
...@@ -719,8 +713,7 @@ static unsigned long parasite_args_size(struct vm_area_list *vmas, struct parasi ...@@ -719,8 +713,7 @@ static unsigned long parasite_args_size(struct vm_area_list *vmas, struct parasi
unsigned long size = PARASITE_ARG_SIZE_MIN; unsigned long size = PARASITE_ARG_SIZE_MIN;
size = max(size, (unsigned long)drain_fds_size(dfds)); size = max(size, (unsigned long)drain_fds_size(dfds));
size = max(size, (unsigned long)vmas_pagemap_size(vmas)); size = max(size, (unsigned long)dump_pages_args_size(vmas));
size = max(size, (unsigned long)vmas_mprotect_size(vmas));
return size; return size;
} }
......
...@@ -34,14 +34,15 @@ static unsigned int next_tid_state; ...@@ -34,14 +34,15 @@ static unsigned int next_tid_state;
#define SPLICE_F_GIFT 0x08 #define SPLICE_F_GIFT 0x08
#endif #endif
static int mprotect_vmas(struct parasite_mprotect_args *args) static int mprotect_vmas(struct parasite_dump_pages_args *args)
{ {
struct parasite_vma_entry *vma; struct parasite_vma_entry *vmas, *vma;
int ret = 0, i; int ret = 0, i;
for (i = 0; i < args->nr; i++) { vmas = pargs_vmas(args);
vma = args->vmas + i; for (i = 0; i < args->nr_vmas; i++) {
ret = sys_mprotect((void *)vma->start, vma->len, vma->prot); vma = vmas + i;
ret = sys_mprotect((void *)vma->start, vma->len, vma->prot | args->add_prot);
if (ret) { if (ret) {
pr_err("mprotect(%08lx, %lu) failed with code %d\n", pr_err("mprotect(%08lx, %lu) failed with code %d\n",
vma->start, vma->len, ret); vma->start, vma->len, ret);
...@@ -55,12 +56,14 @@ static int mprotect_vmas(struct parasite_mprotect_args *args) ...@@ -55,12 +56,14 @@ static int mprotect_vmas(struct parasite_mprotect_args *args)
static int dump_pages(struct parasite_dump_pages_args *args) static int dump_pages(struct parasite_dump_pages_args *args)
{ {
int p, ret; int p, ret;
struct iovec *iovs;
p = recv_fd(tsock); p = recv_fd(tsock);
if (p < 0) if (p < 0)
return -1; return -1;
ret = sys_vmsplice(p, &args->iovs[args->off], args->nr_segs, iovs = pargs_iovs(args);
ret = sys_vmsplice(p, &iovs[args->off], args->nr_segs,
SPLICE_F_GIFT | SPLICE_F_NONBLOCK); SPLICE_F_GIFT | SPLICE_F_NONBLOCK);
if (ret != PAGE_SIZE * args->nr_pages) { if (ret != PAGE_SIZE * args->nr_pages) {
sys_close(p); sys_close(p);
......
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