[dpdk-dev] [PATCH] mem: get physical address of any pointer

Thomas Monjalon thomas.monjalon at 6wind.com
Wed Jun 12 17:24:52 CEST 2013


From: Damien Millescamps <damien.millescamps at 6wind.com>

Extract rte_mem_virt2phy() from find_physaddr().

rte_mem_virt2phy() permits to obtain the physical address of any
virtual address mapped to the current process calling this function.
Note that this function is very slow and shouldn't be called
after initialization to avoid a performance bottleneck.

The memory must be locked with mlock(). The function rte_mem_lock_page()
is a mlock() helper that lock the whole page.

A better name would be rte_mem_virt2phys but rte_mem_virt2phy is more
consistent with rte_mempool_virt2phy.

Signed-off-by: Damien Millescamps <damien.millescamps at 6wind.com>
Signed-off-by: Thomas Monjalon <thomas.monjalon at 6wind.com>
---
 lib/librte_eal/common/include/rte_memory.h |   22 +++++++
 lib/librte_eal/linuxapp/eal/eal_memory.c   |   89 ++++++++++++++++------------
 2 files changed, 73 insertions(+), 38 deletions(-)

diff --git a/lib/librte_eal/common/include/rte_memory.h b/lib/librte_eal/common/include/rte_memory.h
index bf843dc..d9d368b 100644
--- a/lib/librte_eal/common/include/rte_memory.h
+++ b/lib/librte_eal/common/include/rte_memory.h
@@ -70,6 +70,7 @@ enum rte_page_sizes {
 #ifndef __KERNEL__ /* so we can include this header in kernel modules */
 typedef uint64_t phys_addr_t; /**< Physical address definition. */
 #endif
+#define RTE_BAD_PHYS_ADDR ((phys_addr_t)-1)
 
 /**
  * Physical memory segment descriptor.
@@ -87,6 +88,27 @@ struct rte_memseg {
 	uint32_t nrank;             /**< Number of ranks. */
 } __attribute__((__packed__));
 
+/**
+ * Lock page in physical memory and prevent from swapping.
+ *
+ * @param virt
+ *   The virtual address.
+ * @return
+ *   0 on success, negative on error.
+ */
+int rte_mem_lock_page(const void *virt);
+
+/**
+ * Get physical address of any mapped virtual address in the current process.
+ * It is found by browsing the /proc/self/pagemap special file.
+ * The page must be locked.
+ *
+ * @param virt
+ *   The virtual address.
+ * @return
+ *   The physical address or RTE_BAD_PHYS_ADDR on error.
+ */
+phys_addr_t rte_mem_virt2phy(const void *virt);
 
 /**
  * Get the layout of the available physical memory.
diff --git a/lib/librte_eal/linuxapp/eal/eal_memory.c b/lib/librte_eal/linuxapp/eal/eal_memory.c
index 30a955f..82467f3 100644
--- a/lib/librte_eal/linuxapp/eal/eal_memory.c
+++ b/lib/librte_eal/linuxapp/eal/eal_memory.c
@@ -34,6 +34,7 @@
  *  version: DPDK.L.1.2.3-3
  */
 
+#define _FILE_OFFSET_BITS 64
 #include <errno.h>
 #include <stdarg.h>
 #include <stdlib.h>
@@ -265,54 +266,66 @@ unmap_all_hugepages_orig(struct hugepage *hugepg_tbl, struct hugepage_info *hpi)
 	return 0;
 }
 
+/* Lock page in physical memory and prevent from swapping. */
+int
+rte_mem_lock_page(const void *virt)
+{
+	unsigned long virtual = (unsigned long)virt;
+	int page_size = getpagesize();
+	unsigned long aligned = (virtual & ~ (page_size - 1));
+	return mlock((void*)aligned, page_size);
+}
+
 /*
- * For each hugepage in hugepg_tbl, fill the physaddr value. We find
- * it by browsing the /proc/self/pagemap special file.
+ * Get physical address of any mapped virtual address in the current process.
  */
-static int
-find_physaddr(struct hugepage *hugepg_tbl, struct hugepage_info *hpi)
+phys_addr_t
+rte_mem_virt2phy(const void *virt)
 {
-	int fd;
-	unsigned i;
+	int fdmem;
 	uint64_t page;
-	unsigned long virt_pfn;
-	int page_size;
+	off_t offset;
+	unsigned long virtual = (unsigned long)virt;
+	int page_size = getpagesize();
+
+	fdmem = open("/proc/self/pagemap", O_RDONLY);
+	if (fdmem < 0) {
+		RTE_LOG(ERR, EAL, "%s(): cannot open /proc/self/pagemap: %s\n",
+		                  __func__, strerror(errno));
+		return RTE_BAD_PHYS_ADDR;
+	}
+	offset = (off_t) (virtual / page_size) * sizeof(uint64_t);
+	if (lseek(fdmem, offset, SEEK_SET) == (off_t) -1) {
+		RTE_LOG(ERR, EAL, "%s(): seek error in /proc/self/pagemap: %s\n",
+		                  __func__, strerror(errno));
+		close(fdmem);
+		return RTE_BAD_PHYS_ADDR;
+	}
+	if (read(fdmem, &page, sizeof(uint64_t)) <= 0) {
+		RTE_LOG(ERR, EAL, "%s(): cannot read /proc/self/pagemap: %s\n",
+		                  __func__, strerror(errno));
+		close(fdmem);
+		return RTE_BAD_PHYS_ADDR;
+	}
+	close (fdmem);
 
-	/* standard page size */
-	page_size = getpagesize();
+	/* pfn (page frame number) are bits 0-54 (see pagemap.txt in Linux doc) */
+	return ((page & 0x7fffffffffffffULL) * page_size) + (virtual % page_size);
+}
 
-	fd = open("/proc/self/pagemap", O_RDONLY);
-	if (fd < 0) {
-		RTE_LOG(ERR, EAL, "%s(): cannot open /proc/self/pagemap: %s",
-			__func__, strerror(errno));
-		return -1;
-	}
+/*
+ * For each hugepage in hugepg_tbl, fill the physaddr value.
+ */
+static int
+find_physaddr(struct hugepage *hugepg_tbl, struct hugepage_info *hpi)
+{
+	unsigned i;
 
 	for (i = 0; i < hpi->num_pages; i++) {
-		off_t offset;
-		virt_pfn = (unsigned long)hugepg_tbl[i].orig_va /
-			page_size;
-		offset = sizeof(uint64_t) * virt_pfn;
-		if (lseek(fd, offset, SEEK_SET) == (off_t) -1) {
-			RTE_LOG(ERR, EAL, "%s(): seek error in /proc/self/pagemap: %s",
-					__func__, strerror(errno));
-			close(fd);
-			return -1;
-		}
-		if (read(fd, &page, sizeof(uint64_t)) < 0) {
-			RTE_LOG(ERR, EAL, "%s(): cannot read /proc/self/pagemap: %s",
-					__func__, strerror(errno));
-			close(fd);
+		hugepg_tbl[i].physaddr = rte_mem_virt2phy(hugepg_tbl[i].orig_va);
+		if (hugepg_tbl[i].physaddr == RTE_BAD_PHYS_ADDR)
 			return -1;
-		}
-
-		/*
-		 * the pfn (page frame number) are bits 0-54 (see
-		 * pagemap.txt in linux Documentation)
-		 */
-		hugepg_tbl[i].physaddr = ((page & 0x7fffffffffffffULL) * page_size);
 	}
-	close(fd);
 	return 0;
 }
 
-- 
1.7.10.4



More information about the dev mailing list