Commit 9d2e1dfe authored by Pavel Emelyanov's avatar Pavel Emelyanov Committed by Andrei Vagin

ipc: Keep shmem segments contents into pagemap/page images

Right now the contents of the sysvipc shmem segment is stored as
raw blob in the ipcns-shm image. This is bad for two reasons.

First is that huge segments with holes are filled with real zeroes
in image. Second is that we prefer not to mix images with pb object
and raw data.

To fix both let's re-use the shmem.c code that keeps anon shared
memory contents in pagemap/pages images.

https://github.com/xemul/criu/issues/287Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: 's avatarAndrei Vagin <avagin@virtuozzo.com>
parent 0ba02b2c
......@@ -13,6 +13,8 @@ extern int collect_sysv_shmem(unsigned long shmid, unsigned long size);
extern int cr_dump_shmem(void);
extern int add_shmem_area(pid_t pid, VmaEntry *vma, u64 *map);
extern int fixup_sysv_shmems(void);
extern int dump_one_sysv_shmem(void *addr, unsigned long size, unsigned long shmid);
extern int restore_sysv_shmem_content(void *addr, unsigned long size, unsigned long shmid);
#define SYSV_SHMEM_SKIP_FD (0x7fffffff)
......
......@@ -338,15 +338,10 @@ static int ipc_sysctl_req(IpcVarEntry *e, int op)
return sysctl_op(req, nr, op, CLONE_NEWIPC);
}
/*
* TODO: Function below should be later improved to locate and dump only dirty
* pages via updated sys_mincore().
*/
static int dump_ipc_shm_pages(struct cr_img *img, const IpcShmEntry *shm)
static int dump_ipc_shm_pages(const IpcShmEntry *shm)
{
int ret;
void *data;
int ifd;
ssize_t size, off;
data = shmat(shm->desc->id, NULL, SHM_RDONLY);
if (data == (void *)-1) {
......@@ -354,32 +349,13 @@ static int dump_ipc_shm_pages(struct cr_img *img, const IpcShmEntry *shm)
return -errno;
}
/*
* FIXME -- this just write the whole memory segment into the
* image. In case the segment is huge this takes time. Need
* to adopt the holes detection code (next_data_segment) from
* shmem.c
*/
ifd = img_raw_fd(img);
size = round_up(shm->size, sizeof(u32));
off = 0;
do {
ssize_t ret;
ret = write(ifd, data + off, size - off);
if (ret <= 0) {
pr_perror("Failed to write IPC shared memory data");
return (int)ret;
}
off += ret;
} while (off < size);
ret = dump_one_sysv_shmem(data, shm->size, shm->desc->id);
if (shmdt(data)) {
pr_perror("Failed to detach IPC shared memory");
return -errno;
}
return 0;
return ret;
}
static int dump_ipc_shm_seg(struct cr_img *img, int id, const struct shmid_ds *ds)
......@@ -390,6 +366,8 @@ static int dump_ipc_shm_seg(struct cr_img *img, int id, const struct shmid_ds *d
shm.desc = &desc;
shm.size = ds->shm_segsz;
shm.has_in_pagemaps = true;
shm.in_pagemaps = true;
fill_ipc_desc(id, shm.desc, &ds->shm_perm);
pr_info_ipc_shm(&shm);
......@@ -398,7 +376,7 @@ static int dump_ipc_shm_seg(struct cr_img *img, int id, const struct shmid_ds *d
pr_err("Failed to write IPC shared memory segment\n");
return ret;
}
return dump_ipc_shm_pages(img, &shm);
return dump_ipc_shm_pages(&shm);
}
static int dump_ipc_shm(struct cr_img *img)
......@@ -811,7 +789,10 @@ static int prepare_ipc_shm_pages(struct cr_img *img, const IpcShmEntry *shm)
return -errno;
}
ret = restore_content(data, img, shm);
if (shm->has_in_pagemaps && shm->in_pagemaps)
ret = restore_sysv_shmem_content(data, shm->size, shm->desc->id);
else
ret = restore_content(data, img, shm);
if (shmdt(data)) {
pr_perror("Failed to detach IPC shared memory");
......
......@@ -492,6 +492,11 @@ static int restore_shmem_content(void *addr, struct shmem_info *si)
return do_restore_shmem_content(addr, si->size, si->shmid);
}
int restore_sysv_shmem_content(void *addr, unsigned long size, unsigned long shmid)
{
return do_restore_shmem_content(addr, round_up(size, PAGE_SIZE), shmid);
}
static int open_shmem(int pid, struct vma_area *vma)
{
VmaEntry *vi = vma->e;
......@@ -689,7 +694,7 @@ static int do_dump_one_shmem(int fd, void *addr, struct shmem_info *si)
next_data_segment(fd, pfn, &next_data_pnf, &next_hole_pfn))
goto err_xfer;
if (is_shmem_tracking_en()) {
if (si->pstate_map && is_shmem_tracking_en()) {
pgstate = get_pstate(si->pstate_map, pfn);
use_mc = pgstate == PST_DONT_DUMP;
}
......@@ -757,6 +762,31 @@ err:
return ret;
}
int dump_one_sysv_shmem(void *addr, unsigned long size, unsigned long shmid)
{
int fd, ret;
struct shmem_info *si, det;
si = shmem_find(shmid);
if (!si) {
pr_info("Detached shmem...\n");
det.pid = SYSVIPC_SHMEM_PID;
det.shmid = shmid;
det.size = round_up(size, PAGE_SIZE);
det.pstate_map = NULL;
si = &det;
}
fd = open_proc(PROC_SELF, "map_files/%lx-%lx",
(unsigned long)addr, (unsigned long)addr + si->size);
if (fd < 0)
return -1;
ret = do_dump_one_shmem(fd, addr, si);
close(fd);
return ret;
}
int cr_dump_shmem(void)
{
int ret = 0, i;
......
......@@ -5,4 +5,5 @@ import "ipc-desc.proto";
message ipc_shm_entry {
required ipc_desc_entry desc = 1;
required uint64 size = 2;
optional bool in_pagemaps = 3;
}
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