From 4d77b19eb3f8f9ace4a1d67eb28d2986a36a7732 Mon Sep 17 00:00:00 2001 From: Bui Quang Minh Date: Wed, 15 Dec 2021 22:53:09 +0700 Subject: [PATCH] ipc: Add support for checkpoint/restore hugetlb System V shared memory Attach the System V shared memory segments to the address space via shmat() to determine if they are backed by hugetlb and their page size. Use these information for setting the correct flags on restore. Signed-off-by: Bui Quang Minh --- criu/ipc_ns.c | 48 ++++++++++++++++++++++++++++++++++++++++++-- images/ipc-shm.proto | 1 + 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/criu/ipc_ns.c b/criu/ipc_ns.c index a2eb72f28..4fe082fbb 100644 --- a/criu/ipc_ns.c +++ b/criu/ipc_ns.c @@ -15,6 +15,7 @@ #include "sysctl.h" #include "ipc_ns.h" #include "shmem.h" +#include "types.h" #include "protobuf.h" #include "images/ipc-var.pb-c.h" @@ -354,6 +355,42 @@ static int dump_ipc_shm_pages(const IpcShmEntry *shm) return ret; } +static int dump_shm_hugetlb_flag(IpcShmEntry *shm, int id, unsigned long size) +{ + void *addr; + int ret, hugetlb_flag, exit_code = -1; + struct stat st; + char path[64]; + + addr = shmat(id, NULL, SHM_RDONLY); + if (addr == (void *)-1) { + pr_perror("Failed to attach shm"); + return -1; + } + + /* The shm segment size may not be aligned, + * we need to align it up to next page size + */ + size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + snprintf(path, sizeof(path), "/proc/self/map_files/%lx-%lx", (unsigned long)addr, (unsigned long)addr + size); + + ret = stat(path, &st); + if (ret < 0) { + pr_perror("Can't stat map_files"); + goto detach; + } + + if (is_hugetlb_dev(st.st_dev, &hugetlb_flag)) { + shm->has_hugetlb_flag = true; + shm->hugetlb_flag = hugetlb_flag | SHM_HUGETLB; + } + + exit_code = 0; +detach: + shmdt(addr); + return exit_code; +} + static int dump_ipc_shm_seg(struct cr_img *img, int id, const struct shmid_ds *ds) { IpcShmEntry shm = IPC_SHM_ENTRY__INIT; @@ -364,6 +401,10 @@ static int dump_ipc_shm_seg(struct cr_img *img, int id, const struct shmid_ds *d shm.size = ds->shm_segsz; shm.has_in_pagemaps = true; shm.in_pagemaps = true; + + if (dump_shm_hugetlb_flag(&shm, id, ds->shm_segsz)) + return -1; + fill_ipc_desc(id, shm.desc, &ds->shm_perm); pr_info_ipc_shm(&shm); @@ -798,7 +839,7 @@ static int prepare_ipc_shm_pages(struct cr_img *img, const IpcShmEntry *shm) static int prepare_ipc_shm_seg(struct cr_img *img, const IpcShmEntry *shm) { - int ret, id; + int ret, id, hugetlb_flag = 0; struct sysctl_req req[] = { { "kernel/shm_next_id", &shm->desc->id, CTL_U32 }, }; @@ -813,7 +854,10 @@ static int prepare_ipc_shm_seg(struct cr_img *img, const IpcShmEntry *shm) return ret; } - id = shmget(shm->desc->key, shm->size, shm->desc->mode | IPC_CREAT | IPC_EXCL); + if (shm->has_hugetlb_flag) + hugetlb_flag = shm->hugetlb_flag; + + id = shmget(shm->desc->key, shm->size, hugetlb_flag | shm->desc->mode | IPC_CREAT | IPC_EXCL); if (id == -1) { pr_perror("Failed to create shm set"); return -errno; diff --git a/images/ipc-shm.proto b/images/ipc-shm.proto index 7865dad8d..c5feebac0 100644 --- a/images/ipc-shm.proto +++ b/images/ipc-shm.proto @@ -8,4 +8,5 @@ message ipc_shm_entry { required ipc_desc_entry desc = 1; required uint64 size = 2; optional bool in_pagemaps = 3; + optional uint32 hugetlb_flag = 4; }