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 Libhugetlbfs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/libhugetlbfs-devel