[CRIU] [PATCH v3 6/6] log_dirty: count dirty pages for one pid in pagemap

Pavel Tikhomirov ptikhomirov at virtuozzo.com
Fri May 27 03:01:39 PDT 2016


read lines from /proc/<pid>/maps and for each memory region
check PME_SOFT_DIRTY for every page using /proc/<pid>/pagemap
and summup pages and dirty pages.

v3: fix print format for uint64_t
https://travis-ci.org/criupatchwork/criu/builds/133319285

Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
---
 criu/dirty-logger.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 88 insertions(+)

diff --git a/criu/dirty-logger.c b/criu/dirty-logger.c
index 811be23..d50e0d3 100644
--- a/criu/dirty-logger.c
+++ b/criu/dirty-logger.c
@@ -1,9 +1,12 @@
 #include <pthread.h>
 #include <sys/time.h>
+#include <unistd.h>
 
 #include "imgset.h"
 #include "pstree.h"
 #include "protobuf.h"
+#include "util.h"
+#include "mem.h"
 
 #include "images/stats.pb-c.h"
 
@@ -23,13 +26,98 @@ static int sleep_us(long us) {
 	return 0;
 }
 
+void fd_cleanup(void *arg)
+{
+       close(*(int *)arg);
+}
+
+void fp_cleanup(void *arg)
+{
+       fclose((FILE *)arg);
+}
+
 void img_cleanup(void *arg)
 {
        close_image((struct cr_img *)arg);
 }
 
+#define MAPS_PATH "/proc/%d/maps"
+#define MAX_MAPS_PATH 50
+#define BUFF_SIZE 500000
+#define LINELEN 256
+
 static int pid_log_dirty_total(pid_t pid, long *total_pages, long *total_dirty_pages)
 {
+	char maps_path[MAX_MAPS_PATH];
+	FILE * maps;
+	int pagemap_fd;
+
+	u64 pfn[BUFF_SIZE];
+	char line[LINELEN];
+
+	sprintf(maps_path, MAPS_PATH, pid);
+	maps = fopen(maps_path, "r");
+	if (maps == NULL) {
+		pr_perror("Can't open pid %d maps", pid);
+		return -1;
+	}
+	pthread_cleanup_push(fp_cleanup, (void *)maps);
+
+	pagemap_fd = open_proc(pid, "pagemap");
+	if (pagemap_fd < 0) {
+		pr_perror("Can't open pid %d pagemap", pid);
+		return -1;
+	}
+	pthread_cleanup_push(fd_cleanup, (void *)&pagemap_fd);
+
+	/*
+	 * For each line in maps
+	 */
+	while (fgets(line, LINELEN, maps) != NULL) {
+		char * pend;
+		uint64_t start, end;
+		off_t off;
+		long j;
+		int ret;
+
+		start = strtoul(line, &pend, 16);
+		end = strtoul(pend + 1, NULL, 16);
+		if (start >= end)
+			continue;
+
+		off = (start / PAGE_SIZE) * sizeof(u64);
+		pr_debug("Read pagemap from %"PRIx64" to %"PRIx64"\n", start, end);
+		if (lseek (pagemap_fd, off, SEEK_SET) != off) {
+			pr_perror("Failed to seek address %"PRIx64"\n", off);
+			return -1;
+		}
+
+		if ((end - start) / PAGE_SIZE > BUFF_SIZE) {
+			pr_err("Buffer overflow for pid %d\n", pid);
+			return -1;
+		}
+
+		ret = read(pagemap_fd, pfn, ((end - start) / PAGE_SIZE) * sizeof(u64));
+		if (ret != ((end - start) / PAGE_SIZE) * sizeof(u64)) {
+			if (ret == 0) {
+				pr_debug("Can't read because of EOF\n");
+				continue;
+			}
+			pr_perror("Can't read pme for pid %d", pid);
+			return -1;
+		}
+
+		*total_pages += ret/sizeof(u64);
+		for (j = 0; j < ret/sizeof(u64); j++) {
+			if (pfn[j] & PME_SOFT_DIRTY) {
+				(*total_dirty_pages)++;
+			}
+		}
+		pr_debug("Pid %d: %ld pages read, %ld dirty\n", pid, *total_pages, *total_dirty_pages);
+	}
+
+	pthread_cleanup_pop(1);
+	pthread_cleanup_pop(1);
 	return 0;
 }
 
-- 
2.5.5



More information about the CRIU mailing list