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

Kir Kolyshkin kir at openvz.org
Tue Jan 31 17:37:33 EST 2012


On 01/31/2012 04:59 PM, Kinsbursky Stanislav wrote:
> 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 587a06c..c5bffef 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];

(1) Did you mean u32 for shm_ctlall?
> +	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..1ed290a
> --- /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)

What is the purpose of size argument here?

> +{
> +	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)

(1) Same question about size argument
(2) Maybe it makes sense to rename it to read_ipc_sysctl_int or similar 
(say read_ipc_sysctl_u32)?
> +{
> +	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));

Do I get it right that the size you pass here is 8 for both x86_64 and 
other case?

> +#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));

Could use write_img here, but it's not important.
> +	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 583bd7a..04d476f 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;
>
>
> _______________________________________________
> CRIU mailing list
> CRIU at openvz.org
> https://openvz.org/mailman/listinfo/criu



More information about the CRIU mailing list