Commit 6728254a authored by Jim Harris's avatar Jim Harris
Browse files

Use DPDK-based vtophys implementation.



The Linux pagemap-based implementation obviously does not
work on FreeBSD.  DPDK has data structures describing the huge
pages it has allocated, so use that instead when we need to
populate new 2MB mappings in our tables.

Signed-off-by: default avatarJim Harris <james.r.harris@intel.com>
Change-Id: I924e104f42891aaa2f931159aabba2779f239e91
parent 004e4f6b
Loading
Loading
Loading
Loading
+22 −70
Original line number Diff line number Diff line
@@ -31,16 +31,15 @@
 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#define _LARGEFILE64_SOURCE
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/user.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>

#include "rte_config.h"
#include "rte_eal.h"
#include "rte_eal_memconfig.h"
#include "spdk/vtophys.h"

/* x86-64 userspace virtual addresses use only the low 47 bits [0..46],
@@ -64,12 +63,6 @@
#define MAP_128TB_IDX(vfn_2mb)	((vfn_2mb) >> (SHIFT_1GB - SHIFT_2MB))
#define MAP_1GB_IDX(vfn_2mb)	((vfn_2mb) & ((1ULL << (SHIFT_1GB - SHIFT_2MB + 1)) - 1))

/* Defines related to Linux pagemap. */
#define PAGEMAP_PFN_MASK	0x007FFFFFFFFFFFFFULL /* bits 54:0 */

/* Defines related to Linux kpageflags. */
#define KPAGEFLAGS_HUGE		17

/* Physical page frame number of a single 2MB page. */
struct map_2mb {
	uint64_t pfn_2mb;
@@ -135,71 +128,30 @@ vtophys_get_map(uint64_t vfn_2mb)
uint64_t
vtophys_get_pfn_2mb(uint64_t vfn_2mb)
{
	off64_t offset;
	uint64_t pfn_4kb, pfn_2mb, pfn_flag_info;
	static __thread int fd = -1;
	static __thread int kpageflag_fd = -1;

	if (fd == -1) {
		fd = open("/proc/self/pagemap", O_RDONLY);
		if (fd == -1) {
			perror("pagemap open failed");
			return VTOPHYS_ERROR;
		}
	}

	/*
	 * pagemap has a separate 8 byte entry for each 4KB
	 * page.  So even though we are only storing a single
	 * PFN for every 2MB VFN, we have to get the 4KB
	 * VFN equivalent to lseek into the pagemap.
	 *
	 * vfn contains the 2MB virtual frame number, but we
	 * we need the 4KB equivalent to lseek into the pagemap.
	 * So do a left shift to convert the 2MB vfn to the
	 * 4KB vfn equivalent.
	 */
	offset = FN_2MB_TO_4KB(vfn_2mb) * sizeof(uint64_t);

	if (lseek64(fd, offset, SEEK_SET) < 0) {
		perror("pagemap llseek failed");
		return VTOPHYS_ERROR;
	}
	uintptr_t vaddr, paddr;
	struct rte_mem_config *mcfg;
	struct rte_memseg *seg;
	uint32_t seg_idx;

	if (read(fd, &pfn_4kb, sizeof(pfn_4kb)) != sizeof(pfn_4kb)) {
		perror("pagemap read failed");
		return VTOPHYS_ERROR;
	}

	pfn_4kb &= PAGEMAP_PFN_MASK;
	vaddr = vfn_2mb << SHIFT_2MB;
	mcfg = rte_eal_get_configuration()->mem_config;

	if (kpageflag_fd == -1) {
		kpageflag_fd = open("/proc/kpageflags", O_RDONLY);
		if (kpageflag_fd == -1) {
			perror("kpageflags open failed");
			return VTOPHYS_ERROR;
		}
	for (seg_idx = 0; seg_idx < RTE_MAX_MEMSEG; seg_idx++) {
		seg = &mcfg->memseg[seg_idx];
		if (seg->addr == NULL) {
			break;
		}

	offset = pfn_4kb * sizeof(uint64_t);
	if (lseek64(kpageflag_fd, offset, SEEK_SET) < 0) {
		perror("kpageflags llseek failed");
		return VTOPHYS_ERROR;
		if (vaddr >= (uintptr_t)seg->addr &&
		    vaddr < ((uintptr_t)seg->addr + seg->len)) {
			paddr = seg->phys_addr;
			paddr += (vaddr - (uintptr_t)seg->addr);
			return paddr >> SHIFT_2MB;
		}

	if (read(kpageflag_fd, &pfn_flag_info, sizeof(pfn_flag_info)) != sizeof(pfn_flag_info)) {
		perror("kpageflags read failed");
		return VTOPHYS_ERROR;
	}

	/* check whether it is a huge page */
	if (!(pfn_flag_info & (1ULL << KPAGEFLAGS_HUGE))) {
		printf("This is not a huge page\n");
		return VTOPHYS_ERROR;
	}

	pfn_2mb = FN_4KB_TO_2MB(pfn_4kb);
	return pfn_2mb;
	fprintf(stderr, "could not find 2MB vfn 0x%jx in DPDK mem config\n", vfn_2mb);
	return -1;
}

uint64_t