An upcoming release of the Linux kernel will support simultaneous use of
multiple huge page sizes.  Each size will be accessed through its own
specially-mounted hugetlbfs filesystem.  The first step in enabling
libhugetlbfs to support multiple simultaneous page sizes is enabling the
support of multiple simultaneous hugetlbfs mount points.

This patch adds basic support for multiple mount points while preserving
backwards-compatibility.  Mount points can be added via the HUGETLB_PATH
environment variable which has been extended in the normal way to allow
multiple paths to be specified (using a colon separator).  Mounts will also be
discovered by reading /proc/mounts or /etc/mtab.  Up to 10 mount points are
allowed to co-exist but only one mount per page size is allowed.  If
HUGETLB_PATH is specified, only mount points listed in that variable will be
added.  Otherwise, paths in /proc/mounts or /etc/mtab will be added in order of
appearance.  The first mount point of a given size is used and subsequent
mounts of that page size are skipped.

For compatibility and ease of use, a default mount point is selected.  When
multiple mount points have been added, /proc/meminfo is read to determine the
system's default huge page size and the mount point having that size is
selected as the default.  If a mount point for the default page size cannot be
found, the first mount point found becomes the default.  The gethugepagesize()
call has been modified to return the default huge page size as determined the
method just described.

Signed-off-by: Adam Litke <[EMAIL PROTECTED]>
---

 hugeutils.c             |  268 ++++++++++++++++++++++++++++++++++-------------
 init.c                  |    1 
 libhugetlbfs_internal.h |    8 +
 3 files changed, 201 insertions(+), 76 deletions(-)


diff --git a/hugeutils.c b/hugeutils.c
index cc5113f..2d53941 100644
--- a/hugeutils.c
+++ b/hugeutils.c
@@ -38,14 +38,21 @@
 #include <sys/types.h>
 #include <sys/mman.h>
 #include <sys/file.h>
+#include <sys/syscall.h>
+#include <linux/types.h>
+#include <linux/dirent.h>
+#include <linux/unistd.h>
 
 #include "libhugetlbfs_internal.h"
 #include "hugetlbfs.h"
 
-static long hpage_size; /* = 0 */
-static char htlb_mount[PATH_MAX+1]; /* = 0 */
 static int hugepagesize_errno; /* = 0 */
 
+#define MAX_HPAGE_SIZES 10
+struct hpage_size hpage_sizes[MAX_HPAGE_SIZES];
+static int nr_hpage_sizes;
+static int hpage_sizes_default_idx = -1;
+
 /********************************************************************/
 /* Internal functions                                               */
 /********************************************************************/
@@ -102,63 +109,113 @@ static long read_meminfo(const char *tag)
        return val;
 }
 
-/********************************************************************/
-/* Library user visible functions                                   */
-/********************************************************************/
+static long hugetlbfs_test_pagesize(const char *mount)
+{
+       struct statfs64 sb;
+       int err;
 
-/*
- * returns:
- *   on success, size of a huge page in number of bytes
- *   on failure, -1
- *     errno set to ENOSYS if huge pages are not supported
- *     errno set to EOVERFLOW if huge page size would overflow return type
- */
-long gethugepagesize(void)
+       err = statfs64(mount, &sb);
+       if (err)
+               return -1;
+
+       if ((sb.f_bsize <= 0) || (sb.f_bsize > LONG_MAX))
+               return -1;
+
+       return sb.f_bsize / 1024; /* Return in kB */
+}
+
+static int hpage_size_to_index(unsigned long size)
 {
-       long hpage_kb;
-       long max_hpage_kb = LONG_MAX / 1024;
+       int i;
+
+       for (i = 0; i < nr_hpage_sizes; i++)
+               if (hpage_sizes[i].pagesize_kb == size)
+                       return i;
+       return -1;
+}
+
+static void probe_default_hpage_size(void)
+{
+       long size;
+       int index;
 
-       if (hpage_size) {
-               errno = hugepagesize_errno;
-               return hpage_size;
+       if (nr_hpage_sizes == 0) {
+               DEBUG("No configured huge page sizes\n");
+               hpage_sizes_default_idx = -1;
+               return;
        }
-       errno = 0;
 
-       hpage_kb = read_meminfo("Hugepagesize:");
-       if (hpage_kb < 0) {
-               hpage_size = -1;
-               errno = hugepagesize_errno = ENOSYS;
-       } else {
-               if (hpage_kb > max_hpage_kb) {
-                       /* would overflow if converted to bytes */
-                       hpage_size = -1;
-                       errno = hugepagesize_errno = EOVERFLOW;
+       size = read_meminfo("Hugepagesize:");
+       if (size >= 0) {
+               index = hpage_size_to_index(size);
+               if (index >= 0)
+                       hpage_sizes_default_idx = index;
+               else {
+                       DEBUG("No mount point found for default huge page "
+                               "size. Using first available mount point.\n");
+                       hpage_sizes_default_idx = 0;
                }
-               else
-                       /* convert from kb to bytes */
-                       hpage_size = 1024 * hpage_kb;
+       } else {
+               DEBUG("Unable to determine default huge page size\n");
+               hpage_sizes_default_idx = -1;
        }
-
-       return hpage_size;
 }
 
-int hugetlbfs_test_path(const char *mount)
+static void add_hugetlbfs_mount(char *path, int user_mount)
 {
-       struct statfs64 sb;
-       int err;
+       int idx;
+       long size;
 
-       /* Bugs in the 32<->64 translation code in pre-2.6.15 kernels
-        * mean that plain statfs() returns bogus errors on hugetlbfs
-        * filesystems.  Use statfs64() to work around. */
-       err = statfs64(mount, &sb);
-       if (err)
-               return -1;
+       if (strlen(path) > PATH_MAX)
+               return;
 
-       return (sb.f_type == HUGETLBFS_MAGIC);
+       if (!hugetlbfs_test_path(path)) {
+               WARNING("%s is not a hugetlbfs mount point, ignoring\n", path);
+               return;
+       }
+
+       size = hugetlbfs_test_pagesize(path);
+       if (size < 0) {
+               DEBUG("Unable to detect page size for path %s\n", path);
+               return;
+       }
+
+       idx = hpage_size_to_index(size);
+       if (idx < 0) {
+               if (nr_hpage_sizes >= MAX_HPAGE_SIZES) {
+                       WARNING("Maximum number of huge page sizes exceeded, "
+                               "ignoring %lukB page size\n", size);
+                       return;
+               }
+
+               idx = nr_hpage_sizes;
+               hpage_sizes[nr_hpage_sizes++].pagesize_kb = size;
+       }
+
+       if (strlen(hpage_sizes[idx].mount)) {
+               if (user_mount)
+                       WARNING("Mount point already defined for size %li, "
+                               "ignoring %s\n", size, path);
+               return;
+       }
+
+       strcpy(hpage_sizes[idx].mount, path);
+}
+
+static void debug_show_page_sizes(void)
+{
+       int i;
+
+       DEBUG("Detected page sizes:\n");
+       for (i = 0; i < nr_hpage_sizes; i++)
+               DEBUG("   Size: %li kB %s  Mount: %s\n",
+                       hpage_sizes[i].pagesize_kb,
+                       i == hpage_sizes_default_idx ? "(default)" : "",
+                       hpage_sizes[i].mount); 
 }
 
 #define LINE_MAXLEN    2048
-void find_mounts(void)
+static void find_mounts(void)
 {
        int fd;
        char path[PATH_MAX+1];
@@ -195,48 +252,107 @@ void find_mounts(void)
 
                err = sscanf(line, "%*s %" stringify(PATH_MAX) "s hugetlbfs ",
                        path);
-               if ((err == 1) && (hugetlbfs_test_path(path) == 1)) {
-                       strncpy(htlb_mount, path, sizeof(htlb_mount)-1);
-                       break;
-               }
+               if ((err == 1) && (hugetlbfs_test_path(path) == 1))
+                       add_hugetlbfs_mount(path, 0);
        }
        close(fd);
 }
 
-const char *hugetlbfs_find_path(void)
+void __lh_setup_mounts(void)
 {
-       int err;
-       char *tmp;
-
-       /* Have we already located a mount? */
-       if (*htlb_mount)
-               return htlb_mount;
-
-       /* No?  Let's see if we've been told where to look */
-       tmp = getenv("HUGETLB_PATH");
-       if (tmp) {
-               err = hugetlbfs_test_path(tmp);
-               if (err < 0) {
-                       ERROR("Can't statfs() \"%s\" (%s)\n",
-                             tmp, strerror(errno));
-                       return NULL;
-               } else if (err == 0) {
-                       ERROR("\"%s\" is not a hugetlbfs mount\n", tmp);
-                       return NULL;
+       char *env;
+       int do_scan = 1;
+
+       /* If HUGETLB_PATH is set, only add mounts specified there */
+       env = getenv("HUGETLB_PATH");
+       while (env) {
+               char path[PATH_MAX + 1];
+               char *next = strchrnul(env, ':');
+
+               do_scan = 0;
+               if (next - env > PATH_MAX) {
+                       ERROR("Path too long in HUGETLB_PATH -- "
+                               "ignoring environment\n");
+                       break;
                }
-               strncpy(htlb_mount, tmp, sizeof(htlb_mount)-1);
-               return htlb_mount;
+
+               strncpy(path, env, next - env);
+               path[next - env] = '\0';
+               add_hugetlbfs_mount(path, 1);
+
+               /* skip the ':' token */
+               env = *next == '\0' ? NULL : next + 1;
        }
 
-       /* Oh well, let's go searching for a mountpoint */
-       find_mounts();
-       if (*htlb_mount)
-               return htlb_mount;
+       /* Then probe all mounted filesystems */
+       if (do_scan)
+               find_mounts();
+
+       probe_default_hpage_size();
+       if (__hugetlbfs_debug)
+               debug_show_page_sizes();
+}
+
+/********************************************************************/
+/* Library user visible functions                                   */
+/********************************************************************/
 
-       WARNING("Could not find hugetlbfs mount point in /proc/mounts. "
-                       "Is it mounted?\n");
+/*
+ * NOTE: This function uses data that is initialized by
+ * __lh_setup_mounts() which is called during libhugetlbfs initialization.
+ *
+ * returns:
+ *   on success, size of a huge page in number of bytes
+ *   on failure, -1
+ *     errno set to ENOSYS if huge pages are not supported
+ *     errno set to EOVERFLOW if huge page size would overflow return type
+ */
+long gethugepagesize(void)
+{
+       long hpage_kb;
+       long max_hpage_kb = LONG_MAX / 1024;
+
+       /* Are huge pages available and have they been initialized? */
+       if (hpage_sizes_default_idx == -1) {
+               errno = hugepagesize_errno = ENOSYS;
+               return -1;
+       }
+
+       hpage_kb = hpage_sizes[hpage_sizes_default_idx].pagesize_kb;
+       if (hpage_kb > max_hpage_kb) {
+               /* would overflow if converted to bytes */
+               errno = hugepagesize_errno = EOVERFLOW;
+               return -1;
+       } else {
+               errno = 0;
+               /* convert from kb to bytes */
+               return (1024 * hpage_kb);
+       }
+}
+
+int hugetlbfs_test_path(const char *mount)
+{
+       struct statfs64 sb;
+       int err;
+
+       /* Bugs in the 32<->64 translation code in pre-2.6.15 kernels
+        * mean that plain statfs() returns bogus errors on hugetlbfs
+        * filesystems.  Use statfs64() to work around. */
+       err = statfs64(mount, &sb);
+       if (err)
+               return -1;
+
+       return (sb.f_type == HUGETLBFS_MAGIC);
+}
+
+const char *hugetlbfs_find_path(void)
+{
+       char *path = hpage_sizes[hpage_sizes_default_idx].mount;
 
-       return NULL;
+       if (strlen(path))
+               return path;
+       else
+               return NULL;
 }
 
 int hugetlbfs_unlinked_fd(void)
diff --git a/init.c b/init.c
index e1415f5..94fc496 100644
--- a/init.c
+++ b/init.c
@@ -22,6 +22,7 @@
 static void __attribute__ ((constructor)) setup_libhugetlbfs(void)
 {
        __hugetlbfs_setup_debug();
+       __lh_setup_mounts();
 #ifndef NO_ELFLINK
        __hugetlbfs_setup_elflink();
 #endif
diff --git a/libhugetlbfs_internal.h b/libhugetlbfs_internal.h
index 595cc6e..ee1bff0 100644
--- a/libhugetlbfs_internal.h
+++ b/libhugetlbfs_internal.h
@@ -21,6 +21,7 @@
 
 #include <elf.h>
 #include <link.h>
+#include <limits.h>
 
 #ifndef __LIBHUGETLBFS__
 #error This header should not be included by library users.
@@ -46,6 +47,7 @@ extern int __hugetlbfs_prefault;
 extern void __hugetlbfs_setup_elflink();
 extern void __hugetlbfs_setup_morecore();
 extern void __hugetlbfs_setup_debug();
+extern void __lh_setup_mounts();
 extern char __hugetlbfs_hostname[];
 
 #ifndef REPORT
@@ -75,6 +77,12 @@ extern char __hugetlbfs_hostname[];
 #define __LP64__
 #endif
 
+/* Multiple huge page size support */
+struct hpage_size {
+       unsigned long pagesize_kb;
+       char mount[PATH_MAX+1];
+};
+
 /* Arch-specific callbacks */
 extern int direct_syscall(int sysnum, ...);
 extern ElfW(Word) plt_extrasz(ElfW(Dyn) *dyntab);


-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Libhugetlbfs-devel mailing list
Libhugetlbfs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libhugetlbfs-devel

Reply via email to