mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-22 09:58:09 +00:00
IPC: dump namespace itself
Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com> Acked-by: Pavel Emelyanov <xemul@parallels.com> Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
This commit is contained in:
parent
9cdfe71921
commit
c826057a9c
1
Makefile
1
Makefile
@ -40,6 +40,7 @@ OBJS += sockets.o
|
|||||||
OBJS += files.o
|
OBJS += files.o
|
||||||
OBJS += namespaces.o
|
OBJS += namespaces.o
|
||||||
OBJS += uts_ns.o
|
OBJS += uts_ns.o
|
||||||
|
OBJS += ipc_ns.o
|
||||||
|
|
||||||
OBJS-BLOB += parasite.o
|
OBJS-BLOB += parasite.o
|
||||||
SRCS-BLOB += $(patsubst %.o,%.c,$(OBJS-BLOB))
|
SRCS-BLOB += $(patsubst %.o,%.c,$(OBJS-BLOB))
|
||||||
|
@ -110,6 +110,12 @@ struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX] = {
|
|||||||
.fmt = FMT_FNAME_UTSNS,
|
.fmt = FMT_FNAME_UTSNS,
|
||||||
.magic = UTSNS_MAGIC,
|
.magic = UTSNS_MAGIC,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/* IPC namespace */
|
||||||
|
[CR_FD_IPCNS] = {
|
||||||
|
.fmt = FMT_FNAME_IPCNS,
|
||||||
|
.magic = IPCNS_MAGIC,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct cr_fdset *alloc_cr_fdset(void)
|
static struct cr_fdset *alloc_cr_fdset(void)
|
||||||
@ -262,6 +268,8 @@ static int parse_ns_string(const char *ptr, unsigned int *flags)
|
|||||||
goto bad_ns;
|
goto bad_ns;
|
||||||
if (!strncmp(ptr, "uts", 3))
|
if (!strncmp(ptr, "uts", 3))
|
||||||
opts.namespaces_flags |= CLONE_NEWUTS;
|
opts.namespaces_flags |= CLONE_NEWUTS;
|
||||||
|
else if (!strncmp(ptr, "ipc", 3))
|
||||||
|
opts.namespaces_flags |= CLONE_NEWIPC;
|
||||||
else
|
else
|
||||||
goto bad_ns;
|
goto bad_ns;
|
||||||
ptr += 4;
|
ptr += 4;
|
||||||
|
@ -37,6 +37,7 @@ enum {
|
|||||||
|
|
||||||
CR_FD_PSTREE,
|
CR_FD_PSTREE,
|
||||||
CR_FD_UTSNS,
|
CR_FD_UTSNS,
|
||||||
|
CR_FD_IPCNS,
|
||||||
|
|
||||||
CR_FD_MAX
|
CR_FD_MAX
|
||||||
};
|
};
|
||||||
@ -79,6 +80,7 @@ extern struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX];
|
|||||||
#define FMT_FNAME_ITIMERS "itimers-%d.img"
|
#define FMT_FNAME_ITIMERS "itimers-%d.img"
|
||||||
#define FMT_FNAME_CREDS "creds-%d.img"
|
#define FMT_FNAME_CREDS "creds-%d.img"
|
||||||
#define FMT_FNAME_UTSNS "utsns-%d.img"
|
#define FMT_FNAME_UTSNS "utsns-%d.img"
|
||||||
|
#define FMT_FNAME_IPCNS "ipcns-%d.img"
|
||||||
|
|
||||||
extern int get_image_path(char *path, int size, const char *fmt, int pid);
|
extern int get_image_path(char *path, int size, const char *fmt, int pid);
|
||||||
|
|
||||||
@ -109,7 +111,8 @@ struct cr_fdset {
|
|||||||
CR_FD_DESC_USE(CR_FD_ITIMERS) |\
|
CR_FD_DESC_USE(CR_FD_ITIMERS) |\
|
||||||
CR_FD_DESC_USE(CR_FD_CREDS) )
|
CR_FD_DESC_USE(CR_FD_CREDS) )
|
||||||
#define CR_FD_DESC_NS (\
|
#define CR_FD_DESC_NS (\
|
||||||
CR_FD_DESC_USE(CR_FD_UTSNS) )
|
CR_FD_DESC_USE(CR_FD_UTSNS) |\
|
||||||
|
CR_FD_DESC_USE(CR_FD_IPCNS) )
|
||||||
#define CR_FD_DESC_NONE (0)
|
#define CR_FD_DESC_NONE (0)
|
||||||
|
|
||||||
int cr_dump_tasks(pid_t pid, struct cr_options *opts);
|
int cr_dump_tasks(pid_t pid, struct cr_options *opts);
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#define ITIMERS_MAGIC 0x57464056 /* Kostroma */
|
#define ITIMERS_MAGIC 0x57464056 /* Kostroma */
|
||||||
#define UTSNS_MAGIC 0x54473203 /* Smolensk */
|
#define UTSNS_MAGIC 0x54473203 /* Smolensk */
|
||||||
#define CREDS_MAGIC 0x54023547 /* Kozelsk */
|
#define CREDS_MAGIC 0x54023547 /* Kozelsk */
|
||||||
|
#define IPCNS_MAGIC 0x53115007 /* Samara */
|
||||||
|
|
||||||
#define PIPEFS_MAGIC 0x50495045
|
#define PIPEFS_MAGIC 0x50495045
|
||||||
|
|
||||||
@ -104,6 +105,22 @@ struct vma_entry {
|
|||||||
s64 fd;
|
s64 fd;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
struct ipc_ns_entry {
|
||||||
|
u32 sem_ctls[4];
|
||||||
|
u32 msg_ctlmax;
|
||||||
|
u32 msg_ctlmnb;
|
||||||
|
u32 msg_ctlmni;
|
||||||
|
u32 auto_msgmni;
|
||||||
|
u32 shm_ctlmax[2];
|
||||||
|
u64 shm_ctlall[2];
|
||||||
|
u32 shm_ctlmni;
|
||||||
|
u32 shm_rmid_forced;
|
||||||
|
u32 mq_queues_max;
|
||||||
|
u32 mq_msg_max;
|
||||||
|
u32 mq_msgsize_max;
|
||||||
|
u32 in_use[3];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
#define VMA_AREA_NONE (0 << 0)
|
#define VMA_AREA_NONE (0 << 0)
|
||||||
#define VMA_AREA_REGULAR (1 << 0) /* Dumpable area */
|
#define VMA_AREA_REGULAR (1 << 0) /* Dumpable area */
|
||||||
#define VMA_AREA_STACK (1 << 1)
|
#define VMA_AREA_STACK (1 << 1)
|
||||||
|
@ -353,6 +353,10 @@ static long sys_capset(struct cap_header *h, struct cap_data *d)
|
|||||||
#define CLONE_NEWUTS 0x04000000
|
#define CLONE_NEWUTS 0x04000000
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CLONE_NEWIPC
|
||||||
|
#define CLONE_NEWIPC 0x08000000
|
||||||
|
#endif
|
||||||
|
|
||||||
#define setns sys_setns
|
#define setns sys_setns
|
||||||
|
|
||||||
#else /* CONFIG_X86_64 */
|
#else /* CONFIG_X86_64 */
|
||||||
|
276
ipc_ns.c
Normal file
276
ipc_ns.c
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/msg.h>
|
||||||
|
#include <sys/sem.h>
|
||||||
|
#include <sys/shm.h>
|
||||||
|
#include "util.h"
|
||||||
|
#include "crtools.h"
|
||||||
|
#include "syscall.h"
|
||||||
|
#include "namespaces.h"
|
||||||
|
|
||||||
|
struct ipc_ns_data {
|
||||||
|
struct ipc_ns_entry entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IPC_SEM_IDS 0
|
||||||
|
#define IPC_MSG_IDS 1
|
||||||
|
#define IPC_SHM_IDS 2
|
||||||
|
|
||||||
|
static int collect_ipc_msg(void *data)
|
||||||
|
{
|
||||||
|
struct msginfo info;
|
||||||
|
int ret;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
ret = msgctl(0, MSG_INFO, (struct msqid_ds *)&info);
|
||||||
|
if (ret < 0) {
|
||||||
|
pr_err("msgctl failed with %d\n", errno);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
pr_err("IPC messages migration is not supported yet\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int collect_ipc_sem(void *data)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct seminfo info;
|
||||||
|
|
||||||
|
ret = semctl(0, 0, SEM_INFO, &info);
|
||||||
|
if (ret < 0)
|
||||||
|
pr_err("semctl failed with %d\n", errno);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
pr_err("IPC semaphores migration is not supported yet\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int collect_ipc_shm(void *data)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
int ret;
|
||||||
|
struct shmid_ds shmid;
|
||||||
|
|
||||||
|
ret = shmctl(0, IPC_INFO, &shmid);
|
||||||
|
if (ret < 0)
|
||||||
|
pr_err("semctl failed with %d\n", errno);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
pr_err("IPC shared memory migration is not supported yet\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_X86_64
|
||||||
|
static int read_ipc_sysctl_long(char *name, u64 *data, size_t size)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
int ret;
|
||||||
|
char buf[32];
|
||||||
|
|
||||||
|
fd = open(name, O_RDONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
pr_err("Can't open %s\n", name);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
ret = read(fd, buf, 32);
|
||||||
|
if (ret < 0) {
|
||||||
|
pr_err("Can't read %s\n", name);
|
||||||
|
ret = -errno;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
*data = strtoull(buf, NULL, 10);
|
||||||
|
err:
|
||||||
|
close(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int read_ipc_sysctl(char *name, u32 *data, size_t size)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
int ret;
|
||||||
|
char buf[32];
|
||||||
|
|
||||||
|
fd = open(name, O_RDONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
pr_err("Can't open %s\n", name);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
ret = read(fd, buf, 32);
|
||||||
|
if (ret < 0) {
|
||||||
|
pr_err("Can't read %s\n", name);
|
||||||
|
ret = -errno;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
*data = (u32)strtoul(buf, NULL, 10);
|
||||||
|
err:
|
||||||
|
close(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_ipc_sem(u32 sem[])
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
int ret;
|
||||||
|
char buf[128], *ptr = buf;
|
||||||
|
char *name = "/proc/sys/kernel/sem";
|
||||||
|
int i;
|
||||||
|
|
||||||
|
fd = open(name, O_RDONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
pr_err("Can't open %s\n", name);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
ret = read(fd, buf, 128);
|
||||||
|
if (ret < 0) {
|
||||||
|
pr_err("Can't read %s\n", name);
|
||||||
|
ret = -errno;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
sem[0] = (u32)strtoul(ptr, &ptr, 10); ptr++;
|
||||||
|
sem[1] = (u32)strtoul(ptr, &ptr, 10); ptr++;
|
||||||
|
sem[2] = (u32)strtoul(ptr, &ptr, 10); ptr++;
|
||||||
|
sem[3] = (u32)strtoul(ptr, &ptr, 10); ptr++;
|
||||||
|
err:
|
||||||
|
close(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int collect_ipc_tun(struct ipc_ns_entry *entry)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = read_ipc_sem(entry->sem_ctls);
|
||||||
|
if (ret < 0)
|
||||||
|
goto err;
|
||||||
|
ret = read_ipc_sysctl("/proc/sys/kernel/msgmax",
|
||||||
|
&entry->msg_ctlmax, sizeof(entry->msg_ctlmax));
|
||||||
|
if (ret < 0)
|
||||||
|
goto err;
|
||||||
|
ret = read_ipc_sysctl("/proc/sys/kernel/msgmnb",
|
||||||
|
&entry->msg_ctlmnb, sizeof(entry->msg_ctlmnb));
|
||||||
|
if (ret < 0)
|
||||||
|
goto err;
|
||||||
|
ret = read_ipc_sysctl("/proc/sys/kernel/msgmni",
|
||||||
|
&entry->msg_ctlmni, sizeof(entry->msg_ctlmni));
|
||||||
|
if (ret < 0)
|
||||||
|
goto err;
|
||||||
|
ret = read_ipc_sysctl("/proc/sys/kernel/auto_msgmni",
|
||||||
|
&entry->auto_msgmni, sizeof(entry->auto_msgmni));
|
||||||
|
if (ret < 0)
|
||||||
|
goto err;
|
||||||
|
#ifdef CONFIG_X86_64
|
||||||
|
ret = read_ipc_sysctl_long("/proc/sys/kernel/shmmax",
|
||||||
|
(u64 *)entry->shm_ctlmax, sizeof(entry->shm_ctlmax));
|
||||||
|
if (ret < 0)
|
||||||
|
goto err;
|
||||||
|
ret = read_ipc_sysctl_long("/proc/sys/kernel/shmall",
|
||||||
|
(u64 *)entry->shm_ctlall, sizeof(entry->shm_ctlall));
|
||||||
|
#else
|
||||||
|
ret = read_ipc_sysctl("/proc/sys/kernel/shmmax",
|
||||||
|
entry->shm_ctlmax, sizeof(entry->shm_ctlmax));
|
||||||
|
if (ret < 0)
|
||||||
|
goto err;
|
||||||
|
ret = read_ipc_sysctl("/proc/sys/kernel/shmall",
|
||||||
|
entry->shm_ctlall, sizeof(entry->shm_ctlall));
|
||||||
|
#endif
|
||||||
|
if (ret < 0)
|
||||||
|
goto err;
|
||||||
|
ret = read_ipc_sysctl("/proc/sys/kernel/shmmni",
|
||||||
|
&entry->shm_ctlmni, sizeof(entry->shm_ctlmni));
|
||||||
|
if (ret < 0)
|
||||||
|
goto err;
|
||||||
|
ret = read_ipc_sysctl("/proc/sys/kernel/shm_rmid_forced",
|
||||||
|
&entry->shm_rmid_forced, sizeof(entry->shm_rmid_forced));
|
||||||
|
if (ret < 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
|
||||||
|
ret = read_ipc_sysctl("/proc/sys/fs/mqueue/queues_max",
|
||||||
|
&entry->mq_queues_max, sizeof(entry->mq_queues_max));
|
||||||
|
if (ret < 0)
|
||||||
|
goto err;
|
||||||
|
ret = read_ipc_sysctl("/proc/sys/fs/mqueue/msg_max",
|
||||||
|
&entry->mq_msg_max, sizeof(entry->mq_msg_max));
|
||||||
|
if (ret < 0)
|
||||||
|
goto err;
|
||||||
|
ret = read_ipc_sysctl("/proc/sys/fs/mqueue/msgsize_max",
|
||||||
|
&entry->mq_msgsize_max, sizeof(entry->mq_msgsize_max));
|
||||||
|
if (ret < 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
err:
|
||||||
|
pr_err("Failed to dump ipc namespace tunables\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int collect_ipc_data(int ns_pid, struct ipc_ns_data *ipc)
|
||||||
|
{
|
||||||
|
int fd, ret;
|
||||||
|
struct ipc_ns_entry *entry = &ipc->entry;
|
||||||
|
|
||||||
|
ret = switch_ns(ns_pid, CLONE_NEWIPC, "ipc");
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
entry->in_use[IPC_MSG_IDS] = ret = collect_ipc_msg(NULL);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
entry->in_use[IPC_SEM_IDS] = ret = collect_ipc_sem(NULL);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
entry->in_use[IPC_SHM_IDS] = ret = collect_ipc_shm(NULL);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
ret = collect_ipc_tun(entry);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dump_ipc_data(int fd, struct ipc_ns_data *ipc)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = write_img_buf(fd, &ipc->entry, sizeof(ipc->entry));
|
||||||
|
if (err < 0) {
|
||||||
|
pr_err("Failed to write IPC namespace entry\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dump_ipc_ns(int ns_pid, struct cr_fdset *fdset)
|
||||||
|
{
|
||||||
|
int fd, ret;
|
||||||
|
struct ipc_ns_data ipc;
|
||||||
|
|
||||||
|
ret = collect_ipc_data(ns_pid, &ipc);
|
||||||
|
if (ret < 0) {
|
||||||
|
pr_err("Failed to collect IPC namespace data\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = dump_ipc_data(fdset->fds[CR_FD_IPCNS], &ipc);
|
||||||
|
if (ret < 0) {
|
||||||
|
pr_err("Failed to write IPC namespace data\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
12
namespaces.c
12
namespaces.c
@ -4,6 +4,7 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
#include "uts_ns.h"
|
#include "uts_ns.h"
|
||||||
|
#include "ipc_ns.h"
|
||||||
|
|
||||||
int switch_ns(int pid, int type, char *ns)
|
int switch_ns(int pid, int type, char *ns)
|
||||||
{
|
{
|
||||||
@ -35,8 +36,17 @@ static int do_dump_namespaces(int ns_pid, unsigned int ns_flags)
|
|||||||
if (fdset == NULL)
|
if (fdset == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (ns_flags & CLONE_NEWUTS) {
|
||||||
ret = dump_uts_ns(ns_pid, fdset);
|
ret = dump_uts_ns(ns_pid, fdset);
|
||||||
|
if (ret < 0)
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
if (ns_flags & CLONE_NEWIPC) {
|
||||||
|
ret = dump_ipc_ns(ns_pid, fdset);
|
||||||
|
if (ret < 0)
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
err:
|
||||||
close_cr_fdset(&fdset);
|
close_cr_fdset(&fdset);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user