[API-NEXT,PATCHv4,11/16] linux-gen: _ishm: adding function to map memory from other ODP

Message ID 1477301053-35938-12-git-send-email-christophe.milard@linaro.org
State New
Headers show

Commit Message

Christophe Milard Oct. 24, 2016, 9:24 a.m.
functionality to export and map memory between ODP instance is added:
This includes:
- a bit of simplification in _odp_ishm_reserve() for externaly provided
  file descriptors.
- a new function, _odp_ishm_reserve_exported() to map memory from
  other ODP instances (On same OS)

Signed-off-by: Christophe Milard <christophe.milard@linaro.org>

---
 platform/linux-generic/_ishm.c                  | 119 ++++++++++++++++++------
 platform/linux-generic/include/_ishm_internal.h |   7 ++
 2 files changed, 97 insertions(+), 29 deletions(-)

-- 
2.7.4

Patch

diff --git a/platform/linux-generic/_ishm.c b/platform/linux-generic/_ishm.c
index dabd426..7624eca 100644
--- a/platform/linux-generic/_ishm.c
+++ b/platform/linux-generic/_ishm.c
@@ -141,6 +141,7 @@  typedef struct ishm_fragment {
  * will allocate both a block and a fragment.
  * Blocks contain only global data common to all processes.
  */
+typedef enum {UNKNOWN, HUGE, NORMAL, EXTERNAL} huge_flag_t;
 typedef struct ishm_block {
 	char name[ISHM_NAME_MAXLEN];    /* name for the ishm block (if any) */
 	char filename[ISHM_FILENAME_MAXLEN]; /* name of the .../odp-* file  */
@@ -151,7 +152,7 @@  typedef struct ishm_block {
 	void *start;		 /* only valid if _ODP_ISHM_SINGLE_VA is set*/
 	uint64_t len;		 /* length. multiple of page size. 0 if free*/
 	ishm_fragment_t *fragment; /* used when _ODP_ISHM_SINGLE_VA is used */
-	int   huge;	/* true if this segment is mapped using huge pages  */
+	huge_flag_t huge;	 /* page type: external means unknown here. */
 	uint64_t seq;	/* sequence number, incremented on alloc and free   */
 	uint64_t refcnt;/* number of linux processes mapping this block     */
 } ishm_block_t;
@@ -389,7 +390,8 @@  static void free_fragment(ishm_fragment_t *fragmnt)
  * or /mnt/huge/odp-<pid>-<sequence_or_name> (for huge pages)
  * Return the new file descriptor, or -1 on error.
  */
-static int create_file(int block_index, int huge, uint64_t len, uint32_t flags)
+static int create_file(int block_index, huge_flag_t huge,
+		       uint64_t len, uint32_t flags)
 {
 	char *name;
 	int  fd;
@@ -406,10 +408,11 @@  static int create_file(int block_index, int huge, uint64_t len, uint32_t flags)
 		 ishm_tbl->dev_seq++);
 
 	/* huge dir must be known to create files there!: */
-	if (huge && !odp_global_data.hugepage_info.default_huge_page_dir)
+	if ((huge == HUGE) &&
+	    (!odp_global_data.hugepage_info.default_huge_page_dir))
 		return -1;
 
-	if (huge)
+	if (huge == HUGE)
 		snprintf(filename, ISHM_FILENAME_MAXLEN,
 			 ISHM_FILENAME_FORMAT,
 			 odp_global_data.hugepage_info.default_huge_page_dir,
@@ -465,7 +468,7 @@  static int create_file(int block_index, int huge, uint64_t len, uint32_t flags)
  * Mutex must be assured by the caller.
  */
 static void *do_map(int block_index, uint64_t len, uint32_t align,
-		    uint32_t flags, int huge, int *fd)
+		    uint32_t flags, huge_flag_t huge, int *fd)
 {
 	ishm_block_t *new_block;	  /* entry in the main block table   */
 	void *addr = NULL;
@@ -519,8 +522,6 @@  static void *do_map(int block_index, uint64_t len, uint32_t align,
 		return NULL;
 	}
 
-	new_block->huge = huge;
-
 	return mapped_addr;
 }
 
@@ -723,27 +724,21 @@  int _odp_ishm_reserve(const char *name, uint64_t size, int fd,
 	int new_index;			      /* index in the main block table*/
 	ishm_block_t *new_block;	      /* entry in the main block table*/
 	uint64_t page_sz;		      /* normal page size. usually 4K*/
-	uint64_t alloc_size;		      /* includes extra for alignement*/
 	uint64_t page_hp_size;		      /* huge page size */
-	uint64_t alloc_hp_size;		      /* includes extra for alignement*/
 	uint32_t hp_align;
 	uint64_t len;			      /* mapped length */
 	void *addr = NULL;		      /* mapping address */
 	int new_proc_entry;
-
-	page_sz = odp_sys_page_size();
+	struct stat statbuf;
 
 	odp_spinlock_lock(&ishm_tbl->lock);
 
 	/* update this process view... */
 	procsync();
 
-	/* roundup to page size */
-	alloc_size = (size + (page_sz - 1)) & (-page_sz);
-
+	/* Get system page sizes: page_hp_size is 0 if no huge page available*/
+	page_sz      = odp_sys_page_size();
 	page_hp_size = odp_sys_huge_page_size();
-	/* roundup to page size */
-	alloc_hp_size = (size + (page_hp_size - 1)) & (-page_hp_size);
 
 	/* check if name already exists */
 	if (name && (find_block_by_name(name) >= 0)) {
@@ -776,8 +771,24 @@  int _odp_ishm_reserve(const char *name, uint64_t size, int fd,
 	else
 		new_block->name[0] = 0;
 
-	/* Try first huge pages when possible and needed: */
-	if (page_hp_size && (alloc_size > page_sz)) {
+	/* If a file descriptor is provided, get the real size and map: */
+	if (fd >= 0) {
+		fstat(fd, &statbuf);
+		len = statbuf.st_size;
+		/* note that the huge page flag is meningless here as huge
+		 * page is determined by the provided file descriptor: */
+		addr = do_map(new_index, len, align, flags, EXTERNAL, &fd);
+		if (addr == NULL) {
+			close(fd);
+			odp_spinlock_unlock(&ishm_tbl->lock);
+			ODP_ERR("_ishm_reserve failed.\n");
+			return -1;
+		}
+		new_block->huge = EXTERNAL;
+	}
+
+	/* Otherwise, Try first huge pages when possible and needed: */
+	if ((fd < 0) && page_hp_size && (size > page_sz)) {
 		/* at least, alignment in VA should match page size, but user
 		 * can request more: If the user requirement exceeds the page
 		 * size then we have to make sure the block will be mapped at
@@ -788,18 +799,20 @@  int _odp_ishm_reserve(const char *name, uint64_t size, int fd,
 			hp_align = odp_sys_huge_page_size();
 		else
 			flags |= _ODP_ISHM_SINGLE_VA;
-		len = alloc_hp_size;
-		addr = do_map(new_index, len, hp_align, flags, 1, &fd);
+
+		/* roundup to page size */
+		len = (size + (page_hp_size - 1)) & (-page_hp_size);
+		addr = do_map(new_index, len, hp_align, flags, HUGE, &fd);
 
 		if (addr == NULL)
 			ODP_DBG("No huge pages, fall back to normal pages, "
 				"check: /proc/sys/vm/nr_hugepages.\n");
 		else
-			new_block->huge = 1;
+			new_block->huge = HUGE;
 	}
 
-	/* try normal pages if huge pages failed */
-	if (addr == NULL) {
+	/* Try normal pages if huge pages failed */
+	if (fd < 0) {
 		/* at least, alignment in VA should match page size, but user
 		 * can request more: If the user requirement exceeds the page
 		 * size then we have to make sure the block will be mapped at
@@ -810,13 +823,14 @@  int _odp_ishm_reserve(const char *name, uint64_t size, int fd,
 		else
 			flags |= _ODP_ISHM_SINGLE_VA;
 
-		len = alloc_size;
-		addr = do_map(new_index, len, align, flags, 0, &fd);
-		new_block->huge = 0;
+		/* roundup to page size */
+		len = (size + (page_sz - 1)) & (-page_sz);
+		addr = do_map(new_index, len, align, flags, NORMAL, &fd);
+		new_block->huge = NORMAL;
 	}
 
 	/* if neither huge pages or normal pages works, we cannot proceed: */
-	if ((addr == NULL) || (len == 0)) {
+	if ((fd < 0) || (addr == NULL) || (len == 0)) {
 		if ((new_block->filename[0]) && (fd >= 0))
 			close(fd);
 		odp_spinlock_unlock(&ishm_tbl->lock);
@@ -850,6 +864,41 @@  int _odp_ishm_reserve(const char *name, uint64_t size, int fd,
 }
 
 /*
+ * Try to map an memory block mapped by another ODP instance into the
+ * current ODP instance.
+ * returns 0 on success.
+ */
+int _odp_ishm_reserve_exported(const char *remote_name, pid_t external_odp_pid,
+			       const char *local_name,
+			       uint32_t align,
+			       uint32_t flags, uint32_t user_flags)
+{
+	char linkname[ISHM_FILENAME_MAXLEN];
+	int fd;
+	int ret;
+
+	snprintf(linkname, ISHM_FILENAME_MAXLEN,
+		 ISHM_LINKNAME_FORMAT,
+		 external_odp_pid,
+		 remote_name);
+
+	fd = open(linkname, O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+	if (fd == -1) {
+		ODP_ERR("open failed for %s: %s.\n",
+			linkname, strerror(errno));
+		return -1;
+	}
+
+	ret = _odp_ishm_reserve(local_name, 0, fd, align, flags, user_flags);
+	if (ret < 0) {
+		close(fd);
+		return ret;
+	}
+
+	return ret;
+}
+
+/*
  * Free and unmap internal shared memory:
  * The file descriptor is closed and the .../odp-* file deleted,
  * unless fd was externally provided at reserve() time.
@@ -1160,7 +1209,7 @@  int _odp_ishm_info(int block_index, _odp_ishm_info_t *info)
 	info->name	 = ishm_tbl->block[block_index].name;
 	info->addr	 = ishm_proctable->entry[proc_index].start;
 	info->size	 = ishm_tbl->block[block_index].user_len;
-	info->page_size  = ishm_tbl->block[block_index].huge ?
+	info->page_size  = (ishm_tbl->block[block_index].huge == HUGE) ?
 			   odp_sys_huge_page_size() : odp_sys_page_size();
 	info->flags	 = ishm_tbl->block[block_index].flags;
 	info->user_flags = ishm_tbl->block[block_index].user_flags;
@@ -1454,7 +1503,19 @@  int _odp_ishm_status(const char *title)
 		flags[1] = (ishm_tbl->block[i].flags & _ODP_ISHM_LOCK) ?
 								'L' : '.';
 		flags[2] = 0;
-		huge = (ishm_tbl->block[i].huge) ? 'H' : '.';
+		switch (ishm_tbl->block[i].huge) {
+		case HUGE:
+			huge = 'H';
+			break;
+		case NORMAL:
+			huge = 'N';
+			break;
+		case EXTERNAL:
+			huge = 'E';
+			break;
+		default:
+			huge = '?';
+		}
 		proc_index = procfind_block(i);
 		ODP_DBG("%-3d:  name:%-.24s file:%-.24s"
 			" flags:%s,%c len:0x%-08lx"
diff --git a/platform/linux-generic/include/_ishm_internal.h b/platform/linux-generic/include/_ishm_internal.h
index 4fa6d9c..e49bc12 100644
--- a/platform/linux-generic/include/_ishm_internal.h
+++ b/platform/linux-generic/include/_ishm_internal.h
@@ -11,6 +11,8 @@ 
 extern "C" {
 #endif
 
+#include <sys/types.h>
+
 /* flags available at ishm_reserve: */
 #define _ODP_ISHM_SINGLE_VA		1
 #define _ODP_ISHM_LOCK			2
@@ -36,6 +38,11 @@  int   _odp_ishm_free_by_address(void *addr);
 void *_odp_ishm_lookup_by_index(int block_index);
 int   _odp_ishm_lookup_by_name(const char *name);
 int   _odp_ishm_lookup_by_address(void *addr);
+int   _odp_ishm_reserve_exported(const char *remote_name,
+				 pid_t external_odp_pid,
+				 const char *local_name,
+				 uint32_t align,
+				 uint32_t flags, uint32_t user_flags);
 void *_odp_ishm_address(int block_index);
 int   _odp_ishm_info(int block_index, _odp_ishm_info_t *info);
 int   _odp_ishm_status(const char *title);