diff --git a/criu/include/shmem.h b/criu/include/shmem.h index 63e7e9f63..04ab8d076 100644 --- a/criu/include/shmem.h +++ b/criu/include/shmem.h @@ -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) diff --git a/criu/ipc_ns.c b/criu/ipc_ns.c index 0fcee6880..d8590fa39 100644 --- a/criu/ipc_ns.c +++ b/criu/ipc_ns.c @@ -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"); diff --git a/criu/shmem.c b/criu/shmem.c index 0d60d2f6b..69165b64c 100644 --- a/criu/shmem.c +++ b/criu/shmem.c @@ -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; diff --git a/images/ipc-shm.proto b/images/ipc-shm.proto index 4f331d2c2..31e172eb8 100644 --- a/images/ipc-shm.proto +++ b/images/ipc-shm.proto @@ -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; }