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 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 GFP_FORCELARGE and introduce GHP_DEFAULT Signed-off-by: Mel Gorman <[EMAIL PROTECTED]> --- 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 a region 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 that is backed by huge 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 + * + * GFP_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