[CRIU] [PATCH v3 3/4] IPC: restore shared memory

Kir Kolyshkin kir at openvz.org
Wed Feb 8 13:37:20 EST 2012


On 02/08/2012 09:27 PM, Kinsbursky Stanislav wrote:
>
> Signed-off-by: Stanislav Kinsbursky<skinsbursky at parallels.com>
>
> ---
>   ipc_ns.c |  109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>   1 files changed, 107 insertions(+), 2 deletions(-)
>
> diff --git a/ipc_ns.c b/ipc_ns.c
> index eda3399..5c4d27f 100644
> --- a/ipc_ns.c
> +++ b/ipc_ns.c
> @@ -13,6 +13,14 @@
>   #include "namespaces.h"
>   #include "sysctl.h"
>
> +#ifndef IPC_PRESET
> +#define IPC_PRESET		00040000
> +#endif
> +
> +#ifndef SHM_SET
> +#define SHM_SET			15
> +#endif
> +
>   static void print_ipc_seg(const struct ipc_seg *seg)
>   {
>   	pr_info("id: %-10d key: 0x%08x ", seg->id, seg->key);
> @@ -160,8 +168,12 @@ static int dump_ipc_shm(int fd)
>   		int id, ret;
>
>   		id = shmctl(i, SHM_STAT,&ds);
> -		if (id<  0)
> -			continue;
> +		if (id<  0) {
> +			if (errno == EINVAL)
> +				continue;
> +			pr_perror("Failed to get stats for IPC shared memory\n");

Remove \n

> +			break;
> +		}
>   		ret = dump_ipc_shm_seg(fd, id,&ds);
>   		if (ret<  0)
>   			return ret;
> @@ -277,6 +289,96 @@ void show_ipc_var(int fd)
>   	pr_img_tail(CR_FD_IPCNS);
>   }
>
> +static int prepare_ipc_shm_pages(int fd, const struct ipc_shm_entry *shm)
> +{
> +	int ret;
> +	void *data;
> +
> +	data = shmat(shm->seg.id, NULL, 0);
> +	if (data == (void *)-1) {
> +		pr_err("Failed to attach IPC shared memory\n");

shmat sets errno, so you should use pr_perror() here.

> +		return -errno;
> +	}
> +	ret = read_img_buf(fd, data, round_up(shm->size, sizeof(u32)));
> +	if (ret<  0) {
> +		pr_err("Failed to read IPC shared memory data\n");
> +		return ret;
> +	}
> +	if (shmdt(data)) {
> +		pr_err("Failed to detach IPC shared memory\n");
ditto
> +		return -errno;
> +	}
> +	return 0;
> +}
> +
> +static int prepare_ipc_shm_seg(int fd, const struct ipc_shm_entry *shm)
> +{
> +	int ret, id;
> +	struct shmid_ds ds;
> +
> +	id = shmget(shm->seg.id, shm->size,
> +		     shm->seg.mode | IPC_CREAT | IPC_EXCL | IPC_PRESET);
> +	if (id == -1) {
> 		pr_err("Failed to create shm segment\n");
ditto
> +		return -errno;
> +	}
> +
> +	if (id != shm->seg.id) {
> +		pr_err("Failed to preset id (%d instead of %d)\n",
> +							id, shm->seg.id);
> +		return -EFAULT;
> +	}
> +
> +	ret = shmctl(id, SHM_STAT,&ds);
> +	if (ret<  0) {
> +		pr_err("Failed to stat shm segment\n");
ditto
> +		return -errno;
> +	}
> +
> +	ds.shm_perm.KEY = shm->seg.key;
> +	ret = shmctl(id, SHM_SET,&ds);
> +	if (ret<  0) {
> +		pr_err("Failed to update shm key\n");
ditto
> +		return -errno;
> +	}
> +	ret = prepare_ipc_shm_pages(fd, shm);
> +	if (ret<  0) {
> +		pr_err("Failed to update shm pages\n");
> 		return -errno;
Returning -errno here is wrong, you might end up returning -0. Here's why:

prepare_ipc_shm_pages()
   calls read_img_buf()
     which calls read_img_buf_eof()
       which does this:

        int ret;
         ret = read(fd, ptr, size);
         if (ret == size)
                 return 1;
         if (ret == 0)
                 return 0;

         if (ret < 0)
                 pr_perror("Can't read img file");
         else
                 pr_err("Img trimmed %d/%d\n", ret, size);
         return -1;

See, in case read() will read fewer bytes this function returns -1, but 
errno is unset since read() hasn't failed.


> +	}
> +	return 0;
> +}
> +
> +static int prepare_ipc_shm(int pid)
> +{
> +	int fd;
> +
> +	pr_info("Restoring IPC shared memory\n");
> +	fd = open_image_ro(CR_FD_IPCNS_SHM, pid);
> +	if (fd<  0)
> +		return -1;
> +
> +	while (1) {
> +		int ret, id;
> +		struct ipc_shm_entry shm;
> +
> +		ret = read_img_eof(fd,&shm);
> +		if (ret<  0)
> +			return -EIO;
> +		if (ret == 0)
> +			break;
> +
> +		print_ipc_shm(&shm);
> +
> +		ret = prepare_ipc_shm_seg(fd,&shm);
> +		if (ret<  0) {
> +			pr_err("Failed to prepare shm segment\n");
> +			return ret;
> +		}
> +	}
> +	return 0;
> +}
> +
>   static int prepare_ipc_var(int pid)
>   {
>   	int fd, ret;
> @@ -304,5 +406,8 @@ int prepare_ipc_ns(int pid)
>   	ret = prepare_ipc_var(pid);
>   	if (ret<  0)
>   		return ret;
> +	ret = prepare_ipc_shm(pid);
> +	if (ret<  0)
> +		return ret;
>   	return 0;
>   }
>
> _______________________________________________
> CRIU mailing list
> CRIU at openvz.org
> https://openvz.org/mailman/listinfo/criu



More information about the CRIU mailing list