Mel Gorman wrote:
> HUGETLB_MORECORE currently exists to allow glibc to back malloc() with
> large pages instead of small pages. However, not all applications use glibc
> malloc() nor is it always desirable to back malloc() with huge pages. There
> exists a requirement that a hugepage-aware application be able to allocate
> hugepages directly.
>
> Currently, each application is expected to discover the filesystem themselves,
> mmap() the file and other house-keeping tasks. libhugetlbfs already implements
> much of this complex logic internally. This patch exposes a simple API for the
> allocation and freeing of regions backed by hugepages. The implementation is
> a little over-simplistic but can be optimised later if and when applications
> perceive its performance to be a bottleneck. The API itself should not need
> to change as a multi-page aware API would be an additional rather than a
> replacement interface.
>
> Changelog since V2
> o Correct typo of GHP
>
> Changelog since V1
> o Rename hugepages_malloc() to get_huge_pages()
> o Use %zd for size_t arguement
> o Close leaking FD on mmap() failure
> o Drop GHP_FORCELARGE and introduce GHP_DEFAULT
>
> Signed-off-by: Mel Gorman <[EMAIL PROTECTED]>
> Acked-by: David Gibson <[EMAIL PROTECTED]>
>
Tested-by: Jon Tollefson <[EMAIL PROTECTED]>
Tested on ppc64 with 16M huge pages with some tests I wrote and it passes.
# gcc -m64 testgethuge.c -lhugetlbfs -o testgethuge
# LD_LIBARY_PATH=/usr/local/lib64:$LD_LIBRARY_PATH ./testgethuge
testgethuge:
request for size 20 returns NULL
request for size 0x1000000 returns p = 0xe0000000000
request for size 0x5000000 returns q = 0xe0001000000
setting q[0] to 23
q[0] set to 23
freeing q
freeing 0xe0000000000
freeing 0xe0000000000 again
libhugetlbfs [el9-92-101:14195]: ERROR: hugepages_free using invalid or double
free
freeing NULL
libhugetlbfs [el9-92-101:14195]: ERROR: hugepages_free using invalid or double
free
--- /dev/null 2008-04-22 03:00:49.000000000 +0000
+++ testgethuge.c 2008-06-30 20:56:03.000000000 +0000
@@ -0,0 +1,45 @@
+/* Test get_huge_pages and free_huge_pages */
+
+#include <stdio.h>
+#include "/usr/local/include/hugetlbfs.h"
+
+#define ONEHUGEPAGE 16 * 1024 * 1024
+
+int main (int argc, char *argv[])
+{
+ void *p = NULL;
+ int *q = NULL;
+ printf("testgethuge:\n");
+ p = get_huge_pages(20, GHP_DEFAULT);
+ printf(" request for size 20 returns");
+ if(p!=NULL)
+ printf("p=%p\n", p);
+ else
+ printf(" NULL\n");
+ p = get_huge_pages(ONEHUGEPAGE, GHP_DEFAULT);
+ printf(" request for size 0x%X returns", ONEHUGEPAGE);
+ if (p!=NULL)
+ printf(" p = %p\n", p);
+ else
+ printf(" NULL\n");
+
+ q = get_huge_pages(ONEHUGEPAGE * 5, GHP_DEFAULT);
+ printf(" request for size 0x%X returns", ONEHUGEPAGE*5);
+ if (q!=NULL) {
+ printf(" q = %p\n", q);
+ printf(" setting q[0] to 23\n");
+ q[0] = 23;
+ printf(" q[0] set to %d\n", q[0]);
+ printf(" freeing q\n");
+ free_huge_pages(q);
+ }
+ else
+ printf(" NULL\n");
+ printf(" freeing %p\n", p);
+ free_huge_pages(p);
+ printf(" freeing %p again\n", p);
+ free_huge_pages(p);
+ printf(" freeing NULL\n");
+ free_huge_pages(NULL);
+ return 0;
+}
> ---
> Makefile | 5 +
> alloc.c | 152
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> hugetlbfs.h | 11 ++++
> version.lds | 6 ++
> 4 files changed, 173 insertions(+), 1 deletion(-)
>
> diff -rup -X /usr/src/patchset-0.6/bin//dontdiff libhugetlbfs-clean/alloc.c
> libhugetlbfs-userspace-alloc/alloc.c
> --- libhugetlbfs-clean/alloc.c 2008-06-24 11:15:54.000000000 -0700
> +++ libhugetlbfs-userspace-alloc/alloc.c 2008-06-27 10:43:17.000000000
> -0700
> @@ -0,0 +1,132 @@
> +/*
> + * libhugetlbfs - Easy use of Linux hugepages
> + * alloc.c - Simple allocator of regions backed by hugepages
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public License
> + * as published by the Free Software Foundation; either version 2.1 of
> + * the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#define _GNU_SOURCE
> +#include <errno.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <sys/mman.h>
> +#include <sys/types.h>
> +
> +#include "hugetlbfs.h"
> +#include "libhugetlbfs_internal.h"
> +
> +/**
> + * get_huge_pages - Allocate an amount of memory backed by huge pages
> + * len: Size of the region to allocate
> + * flags: Flags specifying the behaviour of the function
> + *
> + * This function allocates a region of memory backed by huge pages and
> + * at least hugepage-aligned. This is not a suitable drop-in for malloc()
> + * and is only suitable in the event the length is expected to be
> + * hugepage-aligned. However, a malloc-like library could use this function
> + * to create additional heap similar in principal to what morecore does for
> + * glibc malloc.
> + */
> +void *get_huge_pages(size_t len, ghp_t flags)
> +{
> + void *buf;
> + int heap_fd;
> +
> + /* Create a file descriptor for the new region */
> + heap_fd = hugetlbfs_unlinked_fd();
> + if (heap_fd < 0) {
> + ERROR("Couldn't open hugetlbfs file for %zd-sized heap\n", len);
> + return NULL;
> + }
> +
> + /* Map the requested region */
> + buf = mmap(NULL, len, PROT_READ|PROT_WRITE,
> + MAP_PRIVATE, heap_fd, len);
> + if (buf == MAP_FAILED) {
> + close(heap_fd);
> + WARNING("New heap segment map failed: %s\n", strerror(errno));
> + return NULL;
> + }
> +
> + /* Close the file so we do not have to track the descriptor */
> + if (close(heap_fd) != 0) {
> + WARNING("Failed to close new heap fd: %s\n", strerror(errno));
> + munmap(buf, len);
> + return NULL;
> + }
> +
> + /* woo, new buffer of shiny */
> + return buf;
> +}
> +
> +#define MAPS_BUF_SZ 4096
> +/**
> + * free_huge_pages - Free a region allocated that was backed by large pages
> + * ptr - The pointer to the buffer returned by get_huge_pages()
> + *
> + * This function finds a region to free based on the contents of
> + * /proc/pid/maps. The assumption is made that the ptr is the start of
> + * a hugepage region allocated with free_huge_pages. No checking is made
> + * that the pointer is to a hugepage backed region.
> + */
> +void free_huge_pages(void *ptr)
> +{
> + FILE *fd;
> + char line[MAPS_BUF_SZ];
> + unsigned long start = 0, end = 0;
> +
> + /*
> + * /proc/self/maps is used to determine the length of the original
> + * allocation. As mappings are based on different files, we can
> + * assume that maps will not merge. If the hugepages were truly
> + * anonymous, this assumption would be broken.
> + */
> + fd = fopen("/proc/self/maps", "r");
> + if (!fd) {
> + ERROR("Failed to open /proc/self/maps\n");
> + return;
> + }
> +
> + /* Parse /proc/maps for address ranges line by line */
> + while (!feof(fd)) {
> + char *bufptr;
> + char *saveptr = NULL;
> +
> + /* Read a line of input */
> + if (fgets(line, MAPS_BUF_SZ, fd) == NULL)
> + break;
> +
> + /* Parse the line to get the start and end of each mapping */
> + bufptr = strtok_r(line, " ", &saveptr);
> + bufptr = strtok_r(bufptr, "-", &saveptr);
> + start = strtoull(bufptr, NULL, 16);
> + bufptr = strtok_r(NULL, "-", &saveptr);
> +
> + /* If the correct mapping is found, remove it */
> + if (start == (unsigned long)ptr) {
> + end = strtoull(bufptr, NULL, 16);
> + munmap(ptr, end - start);
> + break;
> + }
> + }
> +
> + /* Print a warning if the ptr appeared to point nowhere */
> + if (end == 0)
> + ERROR("hugepages_free using invalid or double free\n");
> +
> + fclose(fd);
> +}
> diff -rup -X /usr/src/patchset-0.6/bin//dontdiff
> libhugetlbfs-clean/hugetlbfs.h libhugetlbfs-userspace-alloc/hugetlbfs.h
> --- libhugetlbfs-clean/hugetlbfs.h 2008-05-16 13:43:11.000000000 -0700
> +++ libhugetlbfs-userspace-alloc/hugetlbfs.h 2008-06-27 10:25:02.000000000
> -0700
> @@ -33,4 +33,17 @@ long dump_proc_pid_maps(void);
>
> #define PF_LINUX_HUGETLB 0x100000
>
> +/*
> + * Direct alloc flags and types
> + *
> + * GHP_DEFAULT - Use a combination of flags deemed to be a sensible default
> + * by the current implementation of the library
> + */
> +typedef unsigned long ghp_t;
> +#define GHP_DEFAULT (0)
> +
> +/* Direct alloc functions */
> +void *get_huge_pages(size_t len, ghp_t flags);
> +void free_huge_pages(void *ptr);
> +
> #endif /* _HUGETLBFS_H */
> diff -rup -X /usr/src/patchset-0.6/bin//dontdiff libhugetlbfs-clean/Makefile
> libhugetlbfs-userspace-alloc/Makefile
> --- libhugetlbfs-clean/Makefile 2008-05-16 13:43:11.000000000 -0700
> +++ libhugetlbfs-userspace-alloc/Makefile 2008-06-25 10:33:38.000000000
> -0700
> @@ -1,7 +1,8 @@
> PREFIX = /usr/local
>
> -LIBOBJS = hugeutils.o version.o init.o morecore.o debug.o
> +LIBOBJS = hugeutils.o version.o init.o morecore.o debug.o alloc.o
> INSTALL_OBJ_LIBS = libhugetlbfs.so libhugetlbfs.a
> +INSTALL_HEADERS = hugetlbfs.h
> LDSCRIPT_TYPES = B BDT
> LDSCRIPT_DIST_ELF = elf32ppclinux elf64ppc elf_i386 elf_x86_64
> INSTALL_OBJSCRIPT = ld.hugetlbfs
> @@ -89,6 +90,7 @@ endif
> LIBOBJS32 += $(LIBOBJS:%=obj32/%)
> LIBOBJS64 += $(LIBOBJS:%=obj64/%)
>
> +HEADERDIR = $(PREFIX)/include
> LIBDIR32 = $(PREFIX)/$(LIB32)
> LIBDIR64 = $(PREFIX)/$(LIB64)
> LDSCRIPTDIR = $(PREFIX)/share/libhugetlbfs/ldscripts
> @@ -254,6 +256,7 @@ objscript.%: %
> install: libs $(OBJDIRS:%=%/install) $(INSTALL_OBJSCRIPT:%=objscript.%)
> @$(VECHO) INSTALL
> $(INSTALL) -d $(DESTDIR)$(LDSCRIPTDIR)
> + $(INSTALL) -m 644 $(INSTALL_HEADERS) $(HEADERDIR)
> $(INSTALL) -m 644 $(INSTALL_LDSCRIPTS:%=ldscripts/%)
> $(DESTDIR)$(LDSCRIPTDIR)
> $(INSTALL) -d $(DESTDIR)$(BINDIR)
> for x in $(INSTALL_OBJSCRIPT); do \
> diff -rup -X /usr/src/patchset-0.6/bin//dontdiff
> libhugetlbfs-clean/version.lds libhugetlbfs-userspace-alloc/version.lds
> --- libhugetlbfs-clean/version.lds 2008-05-16 13:43:11.000000000 -0700
> +++ libhugetlbfs-userspace-alloc/version.lds 2008-06-27 10:24:27.000000000
> -0700
> @@ -7,3 +7,9 @@ VERS_1.0 {
> local:
> *;
> };
> +
> +HTLBFS_2.0 {
> + global:
> + get_huge_pages;
> + free_huge_pages;
> +};
>
> ------------------------------------------------------------------------
>
-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://sourceforge.net/services/buy/index.php
_______________________________________________
Libhugetlbfs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/libhugetlbfs-devel