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

Kinsbursky Stanislav skinsbursky at openvz.org
Wed Feb 8 12:27:12 EST 2012



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");
+			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");
+		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");
+		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");
+		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");
+		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");
+		return -errno;
+	}
+	ret = prepare_ipc_shm_pages(fd, shm);
+	if (ret < 0) {
+		pr_err("Failed to update shm pages\n");
+		return -errno;
+	}
+	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;
 }



More information about the CRIU mailing list