[CRIU] [PATCH v2 1/4] IPC: dump namespace itself

Kinsbursky Stanislav skinsbursky at openvz.org
Tue Jan 31 06:53:22 EST 2012


From: Stanislav Kinsbursky <skinsbursky at parallels.com>



Signed-off-by: Stanislav Kinsbursky <skinsbursky at parallels.com>

---
 Makefile          |    1 
 crtools.c         |    8 ++
 include/crtools.h |    5 +
 include/image.h   |   17 +++
 include/syscall.h |    4 +
 ipc_ns.c          |  276 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 namespaces.c      |   14 ++-
 7 files changed, 322 insertions(+), 3 deletions(-)
 create mode 100644 ipc_ns.c

diff --git a/Makefile b/Makefile
index 712a7d6..dee0e61 100644
--- a/Makefile
+++ b/Makefile
@@ -40,6 +40,7 @@ OBJS		+= sockets.o
 OBJS		+= files.o
 OBJS		+= namespaces.o
 OBJS		+= uts_ns.o
+OBJS		+= ipc_ns.o
 
 OBJS-BLOB	+= parasite.o
 SRCS-BLOB	+= $(patsubst %.o,%.c,$(OBJS-BLOB))
diff --git a/crtools.c b/crtools.c
index a4b7004..ad71441 100644
--- a/crtools.c
+++ b/crtools.c
@@ -110,6 +110,12 @@ struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX] = {
 		.fmt	= FMT_FNAME_UTSNS,
 		.magic	= UTSNS_MAGIC,
 	},
+
+	/* IPC namespace */
+	[CR_FD_IPCNS] = {
+		.fmt	= FMT_FNAME_IPCNS,
+		.magic	= IPCNS_MAGIC,
+	},
 };
 
 static struct cr_fdset *alloc_cr_fdset(void)
@@ -243,6 +249,8 @@ static int parse_ns_string(const char *ptr, unsigned int *flags)
 			goto bad_ns;
 		if (!strncmp(ptr, "uts", 3))
 			opts.namespaces_flags |= CLONE_NEWUTS;
+		else if (!strncmp(ptr, "ipc", 3))
+			opts.namespaces_flags |= CLONE_NEWIPC;
 		else
 			goto bad_ns;
 		ptr += 4;
diff --git a/include/crtools.h b/include/crtools.h
index 0a9f7ef..3ec7ddd 100644
--- a/include/crtools.h
+++ b/include/crtools.h
@@ -37,6 +37,7 @@ enum {
 
 	CR_FD_PSTREE,
 	CR_FD_UTSNS,
+	CR_FD_IPCNS,
 
 	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_CREDS		"creds-%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);
 
@@ -109,7 +111,8 @@ struct cr_fdset {
 	CR_FD_DESC_USE(CR_FD_ITIMERS)		|\
 	CR_FD_DESC_USE(CR_FD_CREDS)		)
 #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)
 
 int cr_dump_tasks(pid_t pid, struct cr_options *opts);
diff --git a/include/image.h b/include/image.h
index 1b505ad..b63e41f 100644
--- a/include/image.h
+++ b/include/image.h
@@ -21,6 +21,7 @@
 #define ITIMERS_MAGIC	0x57464056 /* Kostroma */
 #define UTSNS_MAGIC	0x54473203 /* Smolensk */
 #define CREDS_MAGIC	0x54023547 /* Kozelsk */
+#define IPCNS_MAGIC	0x53115007 /* Samara */
 
 #define PIPEFS_MAGIC	0x50495045
 
@@ -104,6 +105,22 @@ struct vma_entry {
 	s64	fd;
 } __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_REGULAR	(1 <<  0)	/* Dumpable area */
 #define VMA_AREA_STACK		(1 <<  1)
diff --git a/include/syscall.h b/include/syscall.h
index a1f69c0..9fdb00f 100644
--- a/include/syscall.h
+++ b/include/syscall.h
@@ -353,6 +353,10 @@ static long sys_capset(struct cap_header *h, struct cap_data *d)
 #define CLONE_NEWUTS	0x04000000
 #endif
 
+#ifndef CLONE_NEWIPC
+#define CLONE_NEWIPC	0x08000000
+#endif
+
 #define setns	sys_setns
 
 #else /* CONFIG_X86_64 */
diff --git a/ipc_ns.c b/ipc_ns.c
new file mode 100644
index 0000000..6558d71
--- /dev/null
+++ b/ipc_ns.c
@@ -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 %d\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 %d\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 %d\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;
+}
diff --git a/namespaces.c b/namespaces.c
index ecca8b2..ea0f6d1 100644
--- a/namespaces.c
+++ b/namespaces.c
@@ -4,6 +4,7 @@
 #include "util.h"
 #include "syscall.h"
 #include "uts_ns.h"
+#include "ipc_ns.h"
 
 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)
 		return -1;
 
-	ret = dump_uts_ns(ns_pid, fdset);
-
+	if (ns_flags & CLONE_NEWUTS) {
+		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);
 	return ret;
 



More information about the CRIU mailing list