mem: get physical address of any pointer
authorDamien Millescamps <damien.millescamps@6wind.com>
Wed, 12 Jun 2013 05:50:20 +0000 (07:50 +0200)
committerDavid Marchand <david.marchand@6wind.com>
Wed, 26 Feb 2014 10:07:27 +0000 (11:07 +0100)
Extract rte_mem_virt2phy() from get_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@6wind.com>
Signed-off-by: Thomas Monjalon <thomas.monjalon@6wind.com>
Acked-by: Olivier Matz <olivier.matz@6wind.com>
lib/librte_eal/common/include/rte_memory.h
lib/librte_eal/linuxapp/eal/eal_memory.c

index 4ae3bf7..4f04f4a 100644 (file)
@@ -73,6 +73,7 @@ enum rte_page_sizes {
 #define __rte_cache_aligned __attribute__((__aligned__(CACHE_LINE_SIZE)))
 
 typedef uint64_t phys_addr_t; /**< Physical address definition. */
+#define RTE_BAD_PHYS_ADDR ((phys_addr_t)-1)
 
 /**
  * Physical memory segment descriptor.
@@ -97,6 +98,27 @@ struct rte_memseg {
 #endif
 } __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.
index fe31746..b980dba 100644 (file)
@@ -61,6 +61,7 @@
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#define _FILE_OFFSET_BITS 64
 #include <errno.h>
 #include <stdarg.h>
 #include <stdlib.h>
@@ -113,16 +114,30 @@ static uint64_t baseaddr_offset;
 
 #define RANDOMIZE_VA_SPACE_FILE "/proc/sys/kernel/randomize_va_space"
 
-static uint64_t
-get_physaddr(void * virtaddr)
+/* 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);
+}
+
+/*
+ * Get physical address of any mapped virtual address in the current process.
+ */
+phys_addr_t
+rte_mem_virt2phy(const void *virtaddr)
 {
        int fd;
-       uint64_t page, physaddr;
+       uint64_t page, physaddr, virtual;
        unsigned long virt_pfn;
        int page_size;
 
        /* standard page size */
        page_size = getpagesize();
+       virtual = (uint64_t) virtaddr;
 
        fd = open("/proc/self/pagemap", O_RDONLY);
        if (fd < 0) {
@@ -151,7 +166,7 @@ get_physaddr(void * virtaddr)
         * the pfn (page frame number) are bits 0-54 (see
         * pagemap.txt in linux Documentation)
         */
-       physaddr = ((page & 0x7fffffffffffffULL) * page_size);
+       physaddr = ((page & 0x7fffffffffffffULL) * page_size) + (virtual % page_size);
        close(fd);
        return physaddr;
 }
@@ -167,8 +182,8 @@ find_physaddrs(struct hugepage_file *hugepg_tbl, struct hugepage_info *hpi)
        phys_addr_t addr;
 
        for (i = 0; i < hpi->num_pages[0]; i++) {
-               addr = get_physaddr(hugepg_tbl[i].orig_va);
-               if (addr == (phys_addr_t) -1)
+               addr = rte_mem_virt2phy(hugepg_tbl[i].orig_va);
+               if (addr == RTE_BAD_PHYS_ADDR)
                        return -1;
                hugepg_tbl[i].physaddr = addr;
        }
@@ -493,9 +508,9 @@ remap_all_hugepages(struct hugepage_file *hugepg_tbl, struct hugepage_info *hpi)
                rte_snprintf(hugepg_tbl[page_idx].filepath, MAX_HUGEPAGE_PATH, "%s",
                                filepath);
 
-               physaddr = get_physaddr(vma_addr);
+               physaddr = rte_mem_virt2phy(vma_addr);
 
-               if (physaddr == (phys_addr_t) -1)
+               if (physaddr == RTE_BAD_PHYS_ADDR)
                        return -1;
 
                hugepg_tbl[page_idx].final_va = vma_addr;
@@ -516,7 +531,7 @@ remap_all_hugepages(struct hugepage_file *hugepg_tbl, struct hugepage_info *hpi)
 
                        expected_physaddr = hugepg_tbl[page_idx].physaddr + offset;
                        page_addr = RTE_PTR_ADD(vma_addr, offset);
-                       physaddr = get_physaddr(page_addr);
+                       physaddr = rte_mem_virt2phy(page_addr);
 
                        if (physaddr != expected_physaddr) {
                                RTE_LOG(ERR, EAL, "Segment sanity check failed: wrong physaddr "