[CRIU] [PATCH 4/9] page-read: New abstraction for restoring pages

Pavel Emelyanov xemul at parallels.com
Thu Apr 11 09:50:26 EDT 2013


Now we have 2 forms of storing pages -- legacy pages.img and
new pagemap + pages image. We'll have one more (ovz) and the
pagemap + pages will be stacked (snapshot restore). Thus it's
handy to have this as an page-reader object.

Signed-off-by: Pavel Emelyanov <xemul at parallels.com>
---
 Makefile.crtools    |   1 +
 cr-restore.c        |  64 +++++++++++-------------------
 include/page-read.h |  16 ++++++++
 page-read.c         | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 148 insertions(+), 42 deletions(-)
 create mode 100644 include/page-read.h
 create mode 100644 page-read.c

diff --git a/Makefile.crtools b/Makefile.crtools
index e7997f5..4d81c36 100644
--- a/Makefile.crtools
+++ b/Makefile.crtools
@@ -44,6 +44,7 @@ obj-y	+= cr-exec.o
 obj-y	+= file-lock.o
 obj-y	+= page-pipe.o
 obj-y	+= page-xfer.o
+obj-y	+= page-read.o
 
 ifneq ($(MAKECMDGOALS),clean)
 incdeps := y
diff --git a/cr-restore.c b/cr-restore.c
index 9f02f34..1d0e1bd 100644
--- a/cr-restore.c
+++ b/cr-restore.c
@@ -55,6 +55,7 @@
 #include "tty.h"
 #include "cpu.h"
 #include "file-lock.h"
+#include "page-read.h"
 
 #include "protobuf.h"
 #include "protobuf/sa.pb-c.h"
@@ -267,55 +268,32 @@ static int map_private_vma(pid_t pid, struct vma_area *vma, void *tgt_addr,
 static int restore_priv_vma_content(pid_t pid)
 {
 	struct vma_area *vma;
-	int fd, fd_pg, ret = 0;
+	int ret = 0;
 
 	unsigned int nr_restored = 0;
 	unsigned int nr_shared = 0;
 	unsigned int nr_droped = 0;
 	unsigned long va;
+	struct page_read pr;
 
 	vma = list_first_entry(&rst_vmas.h, struct vma_area, list);
-
-	fd = open_image(CR_FD_PAGEMAP, O_RSTR, (long)pid);
-	if (fd < 0) {
-		fd_pg = open_image(CR_FD_PAGES_OLD, O_RSTR, pid);
-		if (fd_pg < 0)
-			return -1;
-	} else {
-		fd_pg = open_pages_image(O_RSTR, fd);
-		if (fd_pg < 0) {
-			close(fd);
-			return -1;
-		}
-	}
+	ret = open_page_read(pid, &pr);
+	if (ret)
+		return -1;
 
 	/*
 	 * Read page contents.
 	 */
 	while (1) {
 		unsigned long off, i, nr_pages;;
+		struct iovec iov;
 
-		if (fd >= 0) {
-			PagemapEntry *pe;
-
-			ret = pb_read_one_eof(fd, &pe, PB_PAGEMAP);
-			if (ret <= 0)
-				break;
-
-			va = (unsigned long)decode_pointer(pe->vaddr);
-			nr_pages = pe->nr_pages;
-
-			pagemap_entry__free_unpacked(pe, NULL);
-		} else {
-			__u64 img_va;
+		ret = pr.get_pagemap(&pr, &iov);
+		if (ret <= 0)
+			break;
 
-			ret = read_img_eof(fd_pg, &img_va);
-			if (ret <= 0)
-				break;
-
-			va = (unsigned long)decode_pointer(img_va);
-			nr_pages = 1;
-		}
+		va = (unsigned long)iov.iov_base;
+		nr_pages = iov.iov_len / PAGE_SIZE;
 
 		for (i = 0; i < nr_pages; i++) {
 			unsigned char buf[PAGE_SIZE];
@@ -345,17 +323,16 @@ static int restore_priv_vma_content(pid_t pid)
 			}
 
 			off = (va - vma->vma.start) / PAGE_SIZE;
-			va += PAGE_SIZE;
 
 			set_bit(off, vma->page_bitmap);
 			if (vma->ppage_bitmap)
 				clear_bit(off, vma->ppage_bitmap);
 
-			ret = read(fd_pg, buf, PAGE_SIZE);
-			if (ret != PAGE_SIZE) {
-				pr_err("Can'r read mapping page %d\n", ret);
-				return -1;
-			}
+			ret = pr.read_page(&pr, va, buf);
+			if (ret < 0)
+				break;
+
+			va += PAGE_SIZE;
 
 			p = decode_pointer((off) * PAGE_SIZE +
 					vma_premmaped_start(&vma->vma));
@@ -368,9 +345,12 @@ static int restore_priv_vma_content(pid_t pid)
 			memcpy(p, buf, PAGE_SIZE);
 			nr_restored++;
 		}
+
+		if (pr.put_pagemap)
+			pr.put_pagemap(&pr);
 	}
-	close(fd_pg);
-	close(fd);
+
+	pr.close(&pr);
 	if (ret < 0)
 		return ret;
 
diff --git a/include/page-read.h b/include/page-read.h
new file mode 100644
index 0000000..79b595a
--- /dev/null
+++ b/include/page-read.h
@@ -0,0 +1,16 @@
+#ifndef __CR_PAGE_READ_H__
+#define __CR_PAGE_READ_H__
+#include "protobuf/pagemap.pb-c.h"
+
+struct page_read {
+	int (*get_pagemap)(struct page_read *, struct iovec *iov);
+	int (*read_page)(struct page_read *, unsigned long vaddr, void *);
+	void (*put_pagemap)(struct page_read *);
+	void (*close)(struct page_read *);
+
+	int fd;
+	int fd_pg;
+};
+
+int open_page_read(int pid, struct page_read *);
+#endif
diff --git a/page-read.c b/page-read.c
new file mode 100644
index 0000000..8801892
--- /dev/null
+++ b/page-read.c
@@ -0,0 +1,109 @@
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "crtools.h"
+#include "page-read.h"
+
+#include "protobuf.h"
+#include "protobuf/pagemap.pb-c.h"
+
+static int get_page_vaddr(struct page_read *pr, struct iovec *iov)
+{
+	int ret;
+	__u64 img_va;
+
+	ret = read_img_eof(pr->fd_pg, &img_va);
+	if (ret <= 0)
+		return ret;
+
+	iov->iov_base = (void *)decode_pointer(img_va);
+	iov->iov_len = PAGE_SIZE;
+
+	return 1;
+}
+
+static int read_page(struct page_read *pr, unsigned long vaddr, void *buf)
+{
+	int ret;
+
+	ret = read(pr->fd_pg, buf, PAGE_SIZE);
+	if (ret != PAGE_SIZE) {
+		pr_err("Can'r read mapping page %d\n", ret);
+		return -1;
+	}
+
+	return 1;
+}
+
+static int get_pagemap(struct page_read *pr, struct iovec *iov)
+{
+	int ret;
+	PagemapEntry *pe;
+
+	ret = pb_read_one_eof(pr->fd, &pe, PB_PAGEMAP);
+	if (ret <= 0)
+		return ret;
+
+	iov->iov_base = decode_pointer(pe->vaddr);
+	iov->iov_len = pe->nr_pages * PAGE_SIZE;
+	pagemap_entry__free_unpacked(pe, NULL);
+
+	return 1;
+}
+
+static void put_pagemap(struct page_read *pr)
+{
+}
+
+static int read_pagemap_page(struct page_read *pr, unsigned long vaddr, void *buf)
+{
+	int ret;
+
+	ret = read(pr->fd_pg, buf, PAGE_SIZE);
+	if (ret != PAGE_SIZE) {
+		pr_err("Can'r read mapping page %d\n", ret);
+		return -1;
+	}
+
+	return 1;
+}
+
+static void close_page_read(struct page_read *pr)
+{
+	close(pr->fd_pg);
+	close(pr->fd);
+}
+
+static int open_page_read_at(int dfd, int pid, struct page_read *pr)
+{
+	pr->fd = open_image_at(dfd, CR_FD_PAGEMAP, O_RSTR, (long)pid);
+	if (pr->fd < 0) {
+		pr->fd_pg = open_image_at(dfd, CR_FD_PAGES_OLD, O_RSTR, pid);
+		if (pr->fd_pg < 0)
+			return -1;
+
+		pr->get_pagemap = get_page_vaddr;
+		pr->put_pagemap = NULL;
+		pr->read_page = read_page;
+	} else {
+		pr->fd_pg = open_pages_image_at(dfd, O_RSTR, pr->fd);
+		if (pr->fd_pg < 0) {
+			close_page_read(pr);
+			return -1;
+		}
+
+		pr->get_pagemap = get_pagemap;
+		pr->put_pagemap = put_pagemap;
+		pr->read_page = read_pagemap_page;
+	}
+
+	pr->close = close_page_read;
+
+	return 0;
+}
+
+int open_page_read(int pid, struct page_read *pr)
+{
+	return open_page_read_at(get_service_fd(IMG_FD_OFF), pid, pr);
+}
-- 
1.7.11.7


More information about the CRIU mailing list