From: Adam Litke <[EMAIL PROTECTED]> The need to set and get pool counters for multiple huge page sizes is about to extend beyond just the libhugetlbfs tests. Move the counter code into hugeutils.c and make the top-level functions part of the libhugetlbfs pool and mount configuration API. This involves altering some function names and prologues to make them more consistent with the existing libhugetlbfs API.
We create a new libtestutils.c for test case utilities that depend on linkage to libhugetlbfs. NOTE: This patch will cause the shmoverride test to fail compilation. This is fixed up by the next patch. [EMAIL PROTECTED]: consolidate makefile updates in one place] Signed-off-by: Adam Litke <[EMAIL PROTECTED]> Acked-by: Mel Gorman <[EMAIL PROTECTED]> Signed-off-by: Andy Whitcroft <[EMAIL PROTECTED]> --- hugetlbfs.h | 14 ++ hugeutils.c | 173 +++++++++++++++++++++--- tests/Makefile | 4 +- tests/alloc-instantiate-race.c | 5 +- tests/chunk-overcommit.c | 3 +- tests/counters.c | 38 +++--- tests/get_huge_pages.c | 14 +- tests/heap-overflow.c | 2 +- tests/hugetests.h | 20 +--- tests/libtestutils.c | 137 +++++++++++++++++++ tests/misaligned_offset.c | 20 ++-- tests/quota.c | 6 +- tests/shmoverride_unlinked.c | 8 +- tests/testutils.c | 252 +---------------------------------- tests/truncate_reserve_wraparound.c | 21 ++-- tests/truncate_sigbus_versus_oom.c | 3 +- 16 files changed, 365 insertions(+), 355 deletions(-) create mode 100644 tests/libtestutils.c diff --git a/hugetlbfs.h b/hugetlbfs.h index 48a2f68..2103515 100644 --- a/hugetlbfs.h +++ b/hugetlbfs.h @@ -59,4 +59,18 @@ enum { }; int hugetlbfs_test_feature(int feature_code); +/* Hugetlb pool counter operations */ +/* Keys for reading hugetlb pool counters */ +enum { /* The number of pages of a given size that ... */ + HUGEPAGES_TOTAL, /* are allocated to the pool */ + HUGEPAGES_FREE, /* are not in use */ + HUGEPAGES_RSVD, /* are reserved for possible future use */ + HUGEPAGES_SURP, /* are allocated to the pool on demand */ + HUGEPAGES_OC, /* can be allocated on demand - maximum */ + HUGEPAGES_MAX_COUNTERS, +}; +long get_huge_page_counter(long pagesize, unsigned int counter); +int set_nr_hugepages(long pagesize, unsigned long val); +int set_nr_overcommit_hugepages(long pagesize, unsigned long val); +long read_meminfo(const char *tag); #endif /* _HUGETLBFS_H */ diff --git a/hugeutils.c b/hugeutils.c index d4ba088..22ea487 100644 --- a/hugeutils.c +++ b/hugeutils.c @@ -118,7 +118,39 @@ long __lh_parse_page_size(const char *str) return size; } -static long read_meminfo(const char *tag) +struct hugetlb_pool_counter_info_t { + char *meminfo_key; + char *sysfs_file; +}; + +struct hugetlb_pool_counter_info_t hugetlb_counter_info[] = { + [HUGEPAGES_TOTAL] = { + .meminfo_key = "HugePages_Total:", + .sysfs_file = "nr_hugepages", + }, + [HUGEPAGES_FREE] = { + .meminfo_key = "HugePages_Free:", + .sysfs_file = "free_hugepages", + }, + [HUGEPAGES_RSVD] = { + .meminfo_key = "HugePages_Rsvd:", + .sysfs_file = "resv_hugepages", + }, + [HUGEPAGES_SURP] = { + .meminfo_key = "HugePages_Surp:", + .sysfs_file = "surplus_hugepages", + }, + [HUGEPAGES_OC] = { + .meminfo_key = NULL, + .sysfs_file = "nr_overcommit_hugepages" + }, +}; + +/* + * Read numeric data from raw and tagged kernel status files. Used to read + * /proc and /sys data (without a tag) and from /proc/meminfo (with a tag). + */ +long file_read_ulong(char *file, const char *tag) { int fd; char buf[MEMINFO_SIZE]; @@ -126,9 +158,9 @@ static long read_meminfo(const char *tag) char *p, *q; long val; - fd = open("/proc/meminfo", O_RDONLY); + fd = open(file, O_RDONLY); if (fd < 0) { - ERROR("Couldn't open /proc/meminfo (%s)\n", strerror(errno)); + ERROR("Couldn't open %s: %s\n", file, strerror(errno)); return -1; } @@ -136,37 +168,114 @@ static long read_meminfo(const char *tag) readerr = errno; close(fd); if (len < 0) { - ERROR("Error reading /proc/meminfo (%s)\n", strerror(readerr)); + ERROR("Error reading %s: %s\n", file, strerror(errno)); return -1; } if (len == sizeof(buf)) { - ERROR("/proc/meminfo is too large\n"); + ERROR("%s is too large\n", file); return -1; } buf[len] = '\0'; - p = strstr(buf, tag); - if (!p) - return -1; /* looks like the line we want isn't there */ + /* Search for a tag if provided */ + if (tag) { + p = strstr(buf, tag); + if (!p) + return -1; /* looks like the line we want isn't there */ + p += strlen(tag); + } else + p = buf; - p += strlen(tag); - errno = 0; val = strtol(p, &q, 0); - if (errno != 0) { - if (errno == ERANGE && val == LONG_MAX) - ERROR("Value of %s in /proc/meminfo overflows long\n", tag); - else - ERROR("strtol() failed (%s)\n", strerror(errno)); - return -1; - } if (! isspace(*q)) { - ERROR("Couldn't parse /proc/meminfo value\n"); + ERROR("Couldn't parse %s value\n", file); return -1; } return val; } +int file_write_ulong(char *file, unsigned long val) +{ + FILE *f; + int ret; + + f = fopen(file, "w"); + if (!f) { + ERROR("Couldn't open %s: %s\n", file, strerror(errno)); + return -1; + } + + ret = fprintf(f, "%lu", val); + fclose(f); + return ret > 0 ? 0 : -1; +} + +/* + * Pool counters are typically exposed in sysfs in modern kernels, the + * counters for the default page size are exposed in procfs in all kernels + * supporting hugepages. Given a specific counter (e.g. HUGEPAGES_RSVD) + * and a page size return both a filename and an optional tag to locate + * and extract this counter. + */ +int select_pool_counter(unsigned int counter, unsigned long pagesize, + char *filename, char **key) +{ + long default_size; + char *meminfo_key; + char *sysfs_file; + + if (counter >= HUGEPAGES_MAX_COUNTERS) { + ERROR("Invalid counter specified\n"); + return -1; + } + + meminfo_key = hugetlb_counter_info[counter].meminfo_key; + sysfs_file = hugetlb_counter_info[counter].sysfs_file; + if (key) + *key = NULL; + + /* + * Get the meminfo page size. + * This could be made more efficient if utility functions were shared + * between libhugetlbfs and the test suite. For now we will just + * read /proc/meminfo. + */ + default_size = file_read_ulong("/proc/meminfo", "Hugepagesize:"); + default_size *= 1024; /* Convert from kB to B */ + if (default_size < 0) { + ERROR("Cannot determine the default page size\n"); + return -1; + } + + /* Convert a pagesize of 0 to the libhugetlbfs default size */ + if (pagesize == 0) + pagesize = default_size; + + /* If the user is dealing in the default page size, we can use /proc */ + if (pagesize == default_size) { + if (meminfo_key && key) { + strcpy(filename, "/proc/meminfo"); + *key = meminfo_key; + } else + sprintf(filename, "/proc/sys/vm/%s", sysfs_file); + } else /* Use the sysfs interface */ + sprintf(filename, "/sys/kernel/mm/hugepages/hugepages-%lukB/%s", + pagesize / 1024, sysfs_file); + return 0; +} + +int set_pool_counter(unsigned long pagesize, unsigned int counter, + unsigned long val) +{ + char file[PATH_MAX+1]; + + if (select_pool_counter(counter, pagesize, file, NULL)) + return -1; + + return file_write_ulong(file, val); +} + static int hpage_size_to_index(unsigned long size) { int i; @@ -197,7 +306,7 @@ static void probe_default_hpage_size(void) if (env && strlen(env) > 0) size = __lh_parse_page_size(env); else { - size = read_meminfo("Hugepagesize:"); + size = file_read_ulong("/proc/meminfo", "Hugepagesize:"); size *= 1024; /* convert from kB to B */ } @@ -510,6 +619,27 @@ int __lh_hugetlbfs_prefault(int fd, void *addr, size_t length) return 0; } +long get_huge_page_counter(long pagesize, unsigned int counter) +{ + char file[PATH_MAX+1]; + char *key; + + if (select_pool_counter(counter, pagesize, file, &key)) + return -1; + + return file_read_ulong(file, key); +} + +int set_nr_hugepages(long pagesize, unsigned long val) +{ + return set_pool_counter(pagesize, HUGEPAGES_TOTAL, val); +} + +int set_nr_overcommit_hugepages(long pagesize, unsigned long val) +{ + return set_pool_counter(pagesize, HUGEPAGES_OC, val); +} + /********************************************************************/ /* Library user visible DIAGNOSES/DEBUGGING ONLY functions */ /********************************************************************/ @@ -545,3 +675,8 @@ long __lh_dump_proc_pid_maps() fclose(f); return 0; } + +long read_meminfo(const char *tag) +{ + return file_read_ulong("/proc/meminfo", tag); +} diff --git a/tests/Makefile b/tests/Makefile index c8d47a5..beee18e 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -100,11 +100,11 @@ obj64/libheapshrink.so: obj64/heapshrink-helper-pic.o @mkdir -p obj64 $(CC64) -Wl,-soname,$(notdir $@) -shared -o $@ $^ -$(LIB_TESTS:%=obj32/%): %: %.o obj32/testutils.o +$(LIB_TESTS:%=obj32/%): %: %.o obj32/testutils.o obj32/libtestutils.o @$(VECHO) LD32 "(lib test)" $@ $(CC32) $(LDFLAGS) $(LDFLAGS32) -o $@ $^ $(LDLIBS) -lhugetlbfs -$(LIB_TESTS:%=obj64/%) $(LIB_TESTS_64:%=obj64/%): %: %.o obj64/testutils.o +$(LIB_TESTS:%=obj64/%) $(LIB_TESTS_64:%=obj64/%): %: %.o obj64/testutils.o obj64/libtestutils.o @$(VECHO) LD64 "(lib test)" $@ $(CC64) $(LDFLAGS) $(LDFLAGS64) -o $@ $^ $(LDLIBS) -lhugetlbfs diff --git a/tests/alloc-instantiate-race.c b/tests/alloc-instantiate-race.c index 698fa2f..0929924 100644 --- a/tests/alloc-instantiate-race.c +++ b/tests/alloc-instantiate-race.c @@ -233,7 +233,8 @@ int main(int argc, char *argv[]) if (argc != 2) CONFIG("Usage: alloc-instantiate-race <private|shared>"); - totpages = get_pool_counter(HUGEPAGES_FREE, 0); + hpage_size = check_hugepagesize(); + totpages = get_huge_page_counter(hpage_size, HUGEPAGES_FREE); if (strcmp(argv[1], "shared") == 0) { race_type = MAP_SHARED; @@ -243,8 +244,6 @@ int main(int argc, char *argv[]) CONFIG("Usage: alloc-instantiate-race <private|shared>"); } - hpage_size = check_hugepagesize(); - fd = hugetlbfs_unlinked_fd(); if (fd < 0) FAIL("hugetlbfs_unlinked_fd()"); diff --git a/tests/chunk-overcommit.c b/tests/chunk-overcommit.c index 9c6f0a8..e8f20e0 100644 --- a/tests/chunk-overcommit.c +++ b/tests/chunk-overcommit.c @@ -59,9 +59,8 @@ int main(int argc, char *argv[]) test_init(argc, argv); - totpages = get_pool_counter(HUGEPAGES_FREE, 0); - hpage_size = check_hugepagesize(); + totpages = get_huge_page_counter(hpage_size, HUGEPAGES_FREE); fd = hugetlbfs_unlinked_fd(); if (fd < 0) diff --git a/tests/counters.c b/tests/counters.c index f97d68a..522a00d 100644 --- a/tests/counters.c +++ b/tests/counters.c @@ -45,8 +45,8 @@ extern int errno; /* Global test configuration */ #define DYNAMIC_SYSCTL "/proc/sys/vm/nr_overcommit_hugepages" -static long saved_nr_hugepages; -static long saved_oc_hugepages; +static long saved_nr_hugepages = -1; +static long saved_oc_hugepages = -1; static long hpage_size; static int private_resv; @@ -70,17 +70,20 @@ static long prev_surp; /* Restore original nr_hugepages */ void cleanup(void) { - set_pool_counter(HUGEPAGES_TOTAL, saved_nr_hugepages, 0); + if (hpage_size <= 0) + return; + if (saved_nr_hugepages >= 0) + set_nr_hugepages(hpage_size, saved_nr_hugepages); if (saved_oc_hugepages >= 0) - set_pool_counter(HUGEPAGES_OC, saved_oc_hugepages, 0); + set_nr_overcommit_hugepages(hpage_size, saved_oc_hugepages); } void verify_dynamic_pool_support(void) { - saved_oc_hugepages = get_pool_counter(HUGEPAGES_OC, 0); + saved_oc_hugepages = get_huge_page_counter(hpage_size, HUGEPAGES_OC); if (saved_oc_hugepages < 0) FAIL("Kernel appears to lack dynamic hugetlb pool support"); - set_pool_counter(HUGEPAGES_OC, 10, 0); + set_nr_overcommit_hugepages(hpage_size, 10); } void bad_value(int line, const char *name, long expect, long actual) @@ -96,10 +99,10 @@ void verify_counters(int line, long et, long ef, long er, long es) { long t, f, r, s; - t = get_pool_counter(HUGEPAGES_TOTAL, 0); - f = get_pool_counter(HUGEPAGES_FREE, 0); - r = get_pool_counter(HUGEPAGES_RSVD, 0); - s = get_pool_counter(HUGEPAGES_SURP, 0); + t = get_huge_page_counter(hpage_size, HUGEPAGES_TOTAL); + f = get_huge_page_counter(hpage_size, HUGEPAGES_FREE); + r = get_huge_page_counter(hpage_size, HUGEPAGES_RSVD); + s = get_huge_page_counter(hpage_size, HUGEPAGES_SURP); /* Invariant checks */ if (t < 0 || f < 0 || r < 0 || s < 0) @@ -136,7 +139,7 @@ void _set_nr_hugepages(unsigned long count, int line) long min_size; long et, ef, er, es; - if (set_pool_counter(HUGEPAGES_TOTAL, count, 0)) + if (set_nr_hugepages(hpage_size, count)) FAIL("Cannot set nr_hugepages"); /* The code below is based on set_max_huge_pages in mm/hugetlb.c */ @@ -361,19 +364,16 @@ void run_test(char *desc, int base_nr) int main(int argc, char ** argv) { - int fd, base_nr; + int base_nr; test_init(argc, argv); - check_must_be_root(); - saved_nr_hugepages = get_pool_counter(HUGEPAGES_TOTAL, 0); + hpage_size = check_hugepagesize(); + saved_nr_hugepages = get_huge_page_counter(hpage_size, HUGEPAGES_TOTAL); verify_dynamic_pool_support(); + check_must_be_root(); - fd = hugetlbfs_unlinked_fd(); - if ((private_resv = kernel_has_private_reservations(fd)) == -1) + if ((private_resv = kernel_has_private_reservations()) == -1) FAIL("kernel_has_private_reservations() failed\n"); - close(fd); - - hpage_size = check_hugepagesize(); /* * This test case should require a maximum of 3 huge pages. diff --git a/tests/get_huge_pages.c b/tests/get_huge_pages.c index c55be8e..62b27ea 100644 --- a/tests/get_huge_pages.c +++ b/tests/get_huge_pages.c @@ -25,13 +25,14 @@ #include "hugetests.h" +long hpage_size; long oc_hugepages = -1; /* Restore nr_overcommit_hugepages */ void cleanup(void) { if (oc_hugepages != -1) - set_pool_counter(HUGEPAGES_OC, oc_hugepages, 0); + set_nr_overcommit_hugepages(hpage_size, oc_hugepages); } /* Confirm a region really frees, only really important for GHP_FALLBACK */ @@ -45,7 +46,6 @@ void free_and_confirm_region_free(void *p, int line) { void test_get_huge_pages(int num_hugepages) { int err; - long hpage_size = check_hugepagesize(); void *p = get_huge_pages(num_hugepages * hpage_size, GHP_DEFAULT); if (p == NULL) FAIL("get_huge_pages() for %d hugepages", num_hugepages); @@ -65,14 +65,13 @@ void test_get_huge_pages(int num_hugepages) void test_GHP_FALLBACK(void) { int err; - long hpage_size = check_hugepagesize(); - long rsvd_hugepages = get_pool_counter(HUGEPAGES_RSVD, 0); - long num_hugepages = get_pool_counter(HUGEPAGES_TOTAL, 0) + long rsvd_hugepages = get_huge_page_counter(hpage_size, HUGEPAGES_RSVD); + long num_hugepages = get_huge_page_counter(hpage_size, HUGEPAGES_TOTAL) - rsvd_hugepages; /* We must disable overcommitted huge pages to test this */ - oc_hugepages = get_pool_counter(HUGEPAGES_OC, 0); - set_pool_counter(HUGEPAGES_OC, 0, 0); + oc_hugepages = get_huge_page_counter(hpage_size, HUGEPAGES_OC); + set_nr_overcommit_hugepages(hpage_size, 0); /* We should be able to allocate the whole pool */ void *p = get_huge_pages(num_hugepages * hpage_size, GHP_DEFAULT); @@ -118,6 +117,7 @@ void test_GHP_FALLBACK(void) int main(int argc, char *argv[]) { test_init(argc, argv); + hpage_size = gethugepagesize(); check_free_huge_pages(4); test_get_huge_pages(1); test_get_huge_pages(4); diff --git a/tests/heap-overflow.c b/tests/heap-overflow.c index 7d1b9ba..0f1029c 100644 --- a/tests/heap-overflow.c +++ b/tests/heap-overflow.c @@ -41,7 +41,7 @@ int main(int argc, char **argv) hpagesize = check_hugepagesize(); - freepages = get_pool_counter(HUGEPAGES_FREE, 0); + freepages = get_huge_page_counter(hpagesize, HUGEPAGES_FREE); if (freepages < 3) CONFIG("Must have at least 3 free hugepages"); diff --git a/tests/hugetests.h b/tests/hugetests.h index 71a1e21..bb1146e 100644 --- a/tests/hugetests.h +++ b/tests/hugetests.h @@ -127,27 +127,9 @@ static inline long check_hugepagesize() return hpage_size; } -/* Keys for reading hugetlb pool counters */ -enum { - HUGEPAGES_TOTAL, - HUGEPAGES_FREE, - HUGEPAGES_RSVD, - HUGEPAGES_SURP, - HUGEPAGES_OC, - HUGEPAGES_MAX_COUNTERS, -}; -struct hugetlb_pool_counter_info_t { - char *meminfo_key; - char *sysfs_file; -}; -extern struct hugetlb_pool_counter_info_t hugetlb_counter_info[]; -long get_pool_counter(unsigned int counter, unsigned long pagesize); -int set_pool_counter(unsigned int counter, unsigned long val, - unsigned long pagesize); - int using_system_hpage_size(const char *mount); /* WARNING: Racy -- use for test cases only! */ -int kernel_has_private_reservations(int fd); +int kernel_has_private_reservations(void); #endif /* _HUGETESTS_H */ diff --git a/tests/libtestutils.c b/tests/libtestutils.c new file mode 100644 index 0000000..93388a9 --- /dev/null +++ b/tests/libtestutils.c @@ -0,0 +1,137 @@ +/* + * libhugetlbfs - Easy use of Linux hugepages + * Copyright (C) 2008 David Gibson & Adam Litke, IBM Corporation. + * + * 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 _LARGEFILE64_SOURCE +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <unistd.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/vfs.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <fcntl.h> + +#include "hugetlbfs.h" +#include "hugetests.h" + +void check_free_huge_pages(int nr_pages_needed) +{ + long hpage_size = gethugepagesize(); + int freepages = get_huge_page_counter(hpage_size, HUGEPAGES_FREE); + if (freepages < nr_pages_needed) + CONFIG("Must have at least %i free hugepages", nr_pages_needed); +} + +int using_system_hpage_size(const char *mount) +{ + struct statfs64 sb; + int err; + long meminfo_size, mount_size; + + if (!mount) + FAIL("using_system_hpage_size: hugetlbfs is not mounted\n"); + + err = statfs64(mount, &sb); + if (err) + FAIL("statfs64: %s\n", strerror(errno)); + + meminfo_size = read_meminfo("Hugepagesize:"); + if (meminfo_size < 0) + FAIL("using_system_hpage_size: Failed to read /proc/meminfo\n"); + + mount_size = sb.f_bsize / 1024; /* Compare to meminfo in kB */ + if (mount_size == meminfo_size) + return 1; + else + return 0; +} + +/* WARNING: This function relies on the hugetlb pool counters in a way that + * is known to be racy. Due to the expected usage of hugetlbfs test cases, the + * risk of a race is acceptible. This function should NOT be used for real + * applications. + */ +int kernel_has_private_reservations(void) +{ + int fd; + long t, f, r, s; + long nt, nf, nr, ns; + long hpage_size = gethugepagesize(); + void *map; + + /* Read pool counters */ + t = get_huge_page_counter(hpage_size, HUGEPAGES_TOTAL); + f = get_huge_page_counter(hpage_size, HUGEPAGES_FREE); + r = get_huge_page_counter(hpage_size, HUGEPAGES_RSVD); + s = get_huge_page_counter(hpage_size, HUGEPAGES_SURP); + + fd = hugetlbfs_unlinked_fd(); + if (fd < 0) { + ERROR("kernel_has_private_reservations: hugetlbfs_unlinked_fd: " + "%s\n", strerror(errno)); + return -1; + } + map = mmap(NULL, hpage_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + if (map == MAP_FAILED) { + ERROR("kernel_has_private_reservations: mmap: %s\n", + strerror(errno)); + return -1; + } + + /* Recheck the counters */ + nt = get_huge_page_counter(hpage_size, HUGEPAGES_TOTAL); + nf = get_huge_page_counter(hpage_size, HUGEPAGES_FREE); + nr = get_huge_page_counter(hpage_size, HUGEPAGES_RSVD); + ns = get_huge_page_counter(hpage_size, HUGEPAGES_SURP); + + munmap(map, hpage_size); + close(fd); + + /* + * There are only three valid cases: + * 1) If a surplus page was allocated to create a reservation, all + * four pool counters increment + * 2) All counters remain the same except for Hugepages_Rsvd, then + * a reservation was created using an existing pool page. + * 3) All counters remain the same, indicates that no reservation has + * been created + */ + if ((nt == t + 1) && (nf == f + 1) && (ns == s + 1) && (nr == r + 1)) { + return 1; + } else if ((nt == t) && (nf == f) && (ns == s)) { + if (nr == r + 1) + return 1; + else if (nr == r) + return 0; + } else { + ERROR("kernel_has_private_reservations: bad counter state - " + "T:%li F:%li R:%li S:%li -> T:%li F:%li R:%li S:%li\n", + t, f, r, s, nt, nf, nr, ns); + } + return -1; +} diff --git a/tests/misaligned_offset.c b/tests/misaligned_offset.c index 4b1eb8f..e82ffe1 100644 --- a/tests/misaligned_offset.c +++ b/tests/misaligned_offset.c @@ -44,11 +44,6 @@ * 856fc29505556cf263f3dcda2533cf3766c14ab6. */ -static unsigned long read_free(void) -{ - return get_pool_counter(HUGEPAGES_FREE, 0); -} - #define RANDOM_CONSTANT 0x1234ABCD int main(int argc, char *argv[]) @@ -80,7 +75,8 @@ int main(int argc, char *argv[]) * backout path for the bogus mapping is buggy, which it was * in some kernels. */ - verbose_printf("Free hugepages: %lu\n", read_free()); + verbose_printf("Free hugepages: %lu\n", + get_huge_page_counter(hpage_size, HUGEPAGES_FREE)); verbose_printf("Mapping reference map..."); /* First get arena of three hpages size, at file offset 4GB */ @@ -89,7 +85,8 @@ int main(int argc, char *argv[]) FAIL("mmap() offset 4GB: %s", strerror(errno)); verbose_printf("%p-%p\n", p, p+2*hpage_size-1); - verbose_printf("Free hugepages: %lu\n", read_free()); + verbose_printf("Free hugepages: %lu\n", + get_huge_page_counter(hpage_size, HUGEPAGES_FREE)); /* Instantiate the pages */ verbose_printf("Instantiating..."); @@ -98,7 +95,8 @@ int main(int argc, char *argv[]) *pi = RANDOM_CONSTANT; verbose_printf("done.\n"); - verbose_printf("Free hugepages: %lu\n", read_free()); + verbose_printf("Free hugepages: %lu\n", + get_huge_page_counter(hpage_size, HUGEPAGES_FREE)); /* Toggle the permissions on the first page. This forces TLB * entries (including hash page table on powerpc) to be @@ -123,13 +121,15 @@ int main(int argc, char *argv[]) strerror(errno), strerror(EINVAL)); verbose_printf("%s\n", strerror(errno)); - verbose_printf("Free hugepages: %lu\n", read_free()); + verbose_printf("Free hugepages: %lu\n", + get_huge_page_counter(hpage_size, HUGEPAGES_FREE)); if (*pi != RANDOM_CONSTANT) FAIL("Pre-existing mapping clobbered: %x instead of %x", *pi, RANDOM_CONSTANT); - verbose_printf("Free hugepages: %lu\n", read_free()); + verbose_printf("Free hugepages: %lu\n", + get_huge_page_counter(hpage_size, HUGEPAGES_FREE)); /* The real test is whether we got a bad_pud() or similar * during the run. The check above, combined with the earlier diff --git a/tests/quota.c b/tests/quota.c index 3dc9dcd..4961371 100644 --- a/tests/quota.c +++ b/tests/quota.c @@ -207,7 +207,7 @@ void _spawn(int l, int expected_result, unsigned long size, int mmap_flags, int main(int argc, char ** argv) { - int fd, private_resv; + int private_resv; int bad_priv_resv; test_init(argc, argv); @@ -221,9 +221,7 @@ int main(int argc, char ** argv) check_must_be_root(); check_free_huge_pages(1); - fd = hugetlbfs_unlinked_fd(); - private_resv = kernel_has_private_reservations(fd); - close(fd); + private_resv = kernel_has_private_reservations(); if (private_resv == -1) FAIL("kernel_has_private_reservations() failed\n"); bad_priv_resv = private_resv ? BAD_EXIT : BAD_SIG; diff --git a/tests/shmoverride_unlinked.c b/tests/shmoverride_unlinked.c index 2721b92..a8af228 100644 --- a/tests/shmoverride_unlinked.c +++ b/tests/shmoverride_unlinked.c @@ -94,7 +94,7 @@ void _shmunmap(int s, int line) } #define shmunmap(s) _shmunmap(s, __LINE__) -void set_nr_hugepages(unsigned long count) +void setup_hugetlb_pool(unsigned long count) { FILE *fd; unsigned long poolsize; @@ -116,7 +116,7 @@ void run_test(char *desc, int hpages, int bpages, int pool_nr, int expect_diff) { long resv_before, resv_after; verbose_printf("%s...\n", desc); - set_nr_hugepages(pool_nr); + setup_hugetlb_pool(pool_nr); /* untouched, shared mmap */ resv_before = read_meminfo("HugePages_Rsvd:"); @@ -135,7 +135,7 @@ void run_test(char *desc, int hpages, int bpages, int pool_nr, int expect_diff) void cleanup(void) { if (saved_nr_hugepages >= 0) - set_nr_hugepages(saved_nr_hugepages); + setup_hugetlb_pool(saved_nr_hugepages); } int main(int argc, char **argv) @@ -166,7 +166,7 @@ int main(int argc, char **argv) run_test("override-requested-unaligned", 1, 1, POOL_SIZE, 2); /* Run the test with no pool but requested large pages */ - set_nr_hugepages(0); + setup_hugetlb_pool(0); run_test("override-requested-aligned-nopool", 1, 0, 0, 0); PASS(); diff --git a/tests/testutils.c b/tests/testutils.c index 6534e9c..b8a1bf2 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -36,6 +36,7 @@ #include <sys/mman.h> #include <fcntl.h> +#include "hugetlbfs.h" #include "hugetests.h" #define HUGETLBFS_MAGIC 0x958458f6 @@ -45,13 +46,6 @@ int verbose_test = 1; char *test_name; -void check_free_huge_pages(int nr_pages_needed) -{ - int freepages = get_pool_counter(HUGEPAGES_FREE, 0); - if (freepages < nr_pages_needed) - CONFIG("Must have at least %i free hugepages", nr_pages_needed); -} - void check_must_be_root(void) { uid_t uid = getuid(); @@ -205,164 +199,6 @@ int test_addr_huge(void *p) return (sb.f_type == HUGETLBFS_MAGIC); } -struct hugetlb_pool_counter_info_t hugetlb_counter_info[] = { - [HUGEPAGES_TOTAL] = { - .meminfo_key = "HugePages_Total:", - .sysfs_file = "nr_hugepages", - }, - [HUGEPAGES_FREE] = { - .meminfo_key = "HugePages_Free:", - .sysfs_file = "free_hugepages", - }, - [HUGEPAGES_RSVD] = { - .meminfo_key = "HugePages_Rsvd:", - .sysfs_file = "resv_hugepages", - }, - [HUGEPAGES_SURP] = { - .meminfo_key = "HugePages_Surp:", - .sysfs_file = "surplus_hugepages", - }, - [HUGEPAGES_OC] = { - .meminfo_key = NULL, - .sysfs_file = "nr_overcommit_hugepages" - }, -}; - -long file_read_ulong(char *file, const char *tag) -{ - int fd; - char buf[MEMINFO_SZ]; - int len, readerr; - char *p, *q; - long val; - - fd = open(file, O_RDONLY); - if (fd < 0) { - ERROR("Couldn't open %s: %s\n", file, strerror(errno)); - return -1; - } - - len = read(fd, buf, sizeof(buf)); - readerr = errno; - close(fd); - if (len < 0) { - ERROR("Error reading %s: %s\n", file, strerror(errno)); - return -1; - } - if (len == sizeof(buf)) { - ERROR("%s is too large\n", file); - return -1; - } - buf[len] = '\0'; - - /* Search for a tag if provided */ - if (tag) { - p = strstr(buf, tag); - if (!p) - return -1; /* looks like the line we want isn't there */ - p += strlen(tag); - } else - p = buf; - - val = strtol(p, &q, 0); - if (! isspace(*q)) { - ERROR("Couldn't parse %s value\n", file); - return -1; - } - - return val; -} - -int file_write_ulong(char *file, unsigned long val) -{ - FILE *f; - int ret; - - f = fopen(file, "w"); - if (!f) { - ERROR("Couldn't open %s: %s\n", file, strerror(errno)); - return -1; - } - - ret = fprintf(f, "%lu", val); - fclose(f); - return ret > 0 ? 0 : -1; -} - -int select_pool_counter(unsigned int counter, unsigned long pagesize, - char *filename, char **key) -{ - long default_size; - char *meminfo_key; - char *sysfs_file; - - if (counter >= HUGEPAGES_MAX_COUNTERS) { - ERROR("Invalid counter specified\n"); - return -1; - } - - meminfo_key = hugetlb_counter_info[counter].meminfo_key; - sysfs_file = hugetlb_counter_info[counter].sysfs_file; - if (key) - *key = NULL; - - /* - * Get the meminfo page size. - * This could be made more efficient if utility functions were shared - * between libhugetlbfs and the test suite. For now we will just - * read /proc/meminfo. - */ - default_size = file_read_ulong("/proc/meminfo", "Hugepagesize:"); - default_size *= 1024; /* Convert from kB to B */ - if (default_size < 0) { - ERROR("Cannot determine the default page size\n"); - return -1; - } - - /* Convert a pagesize of 0 to the libhugetlbfs default size */ - if (pagesize == 0) - pagesize = default_size; - - /* If the user is dealing in the default page size, we can use /proc */ - if (pagesize == default_size) { - if (meminfo_key && key) { - strcpy(filename, "/proc/meminfo"); - *key = meminfo_key; - } else - sprintf(filename, "/proc/sys/vm/%s", sysfs_file); - } else /* Use the sysfs interface */ - sprintf(filename, "/sys/kernel/mm/hugepages/hugepages-%lukB/%s", - pagesize / 1024, sysfs_file); - return 0; -} - -long get_pool_counter(unsigned int counter, unsigned long pagesize) -{ - char file[PATH_MAX+1]; - char *key; - - if (select_pool_counter(counter, pagesize, file, &key)) - return -1; - - return file_read_ulong(file, key); -} - -int set_pool_counter(unsigned int counter, unsigned long val, - unsigned long pagesize) -{ - char file[PATH_MAX+1]; - - if (select_pool_counter(counter, pagesize, file, NULL)) - return -1; - - return file_write_ulong(file, val); -} - -long read_meminfo(const char *tag) -{ - return file_read_ulong("/proc/meminfo", tag); -} - ino_t get_addr_inode(void *p) { char name[256]; @@ -406,89 +242,3 @@ int remove_shmid(int shmid) } return 0; } - -/* WARNING: This function relies on the hugetlb pool counters in a way that - * is known to be racy. Due to the expected usage of hugetlbfs test cases, the - * risk of a race is acceptible. This function should NOT be used for real - * applications. - */ -int kernel_has_private_reservations(int fd) -{ - long t, f, r, s; - long nt, nf, nr, ns; - void *map; - - /* Read pool counters */ - t = get_pool_counter(HUGEPAGES_TOTAL, 0); - f = get_pool_counter(HUGEPAGES_FREE, 0); - r = get_pool_counter(HUGEPAGES_RSVD, 0); - s = get_pool_counter(HUGEPAGES_SURP, 0); - - - if (fd < 0) { - ERROR("kernel_has_private_reservations: hugetlbfs_unlinked_fd: " - "%s\n", strerror(errno)); - return -1; - } - map = mmap(NULL, gethugepagesize(), PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); - if (map == MAP_FAILED) { - ERROR("kernel_has_private_reservations: mmap: %s\n", - strerror(errno)); - return -1; - } - - /* Recheck the counters */ - nt = get_pool_counter(HUGEPAGES_TOTAL, 0); - nf = get_pool_counter(HUGEPAGES_FREE, 0); - nr = get_pool_counter(HUGEPAGES_RSVD, 0); - ns = get_pool_counter(HUGEPAGES_SURP, 0); - - munmap(map, gethugepagesize()); - - /* - * There are only three valid cases: - * 1) If a surplus page was allocated to create a reservation, all - * four pool counters increment - * 2) All counters remain the same except for Hugepages_Rsvd, then - * a reservation was created using an existing pool page. - * 3) All counters remain the same, indicates that no reservation has - * been created - */ - if ((nt == t + 1) && (nf == f + 1) && (ns == s + 1) && (nr == r + 1)) { - return 1; - } else if ((nt == t) && (nf == f) && (ns == s)) { - if (nr == r + 1) - return 1; - else if (nr == r) - return 0; - } else { - ERROR("kernel_has_private_reservations: bad counter state - " - "T:%li F:%li R:%li S:%li -> T:%li F:%li R:%li S:%li\n", - t, f, r, s, nt, nf, nr, ns); - } - return -1; -} - -int using_system_hpage_size(const char *mount) -{ - struct statfs64 sb; - int err; - long meminfo_size, mount_size; - - if (!mount) - FAIL("using_system_hpage_size: hugetlbfs is not mounted\n"); - - err = statfs64(mount, &sb); - if (err) - FAIL("statfs64: %s\n", strerror(errno)); - - meminfo_size = file_read_ulong("/proc/meminfo", "Hugepagesize:"); - if (meminfo_size < 0) - FAIL("using_system_hpage_size: Failed to read /proc/meminfo\n"); - - mount_size = sb.f_bsize / 1024; /* Compare to meminfo in kB */ - if (mount_size == meminfo_size) - return 1; - else - return 0; -} diff --git a/tests/truncate_reserve_wraparound.c b/tests/truncate_reserve_wraparound.c index f7af96b..0e27787 100644 --- a/tests/truncate_reserve_wraparound.c +++ b/tests/truncate_reserve_wraparound.c @@ -50,11 +50,6 @@ static void sigbus_handler(int signum, siginfo_t *si, void *uc) siglongjmp(sig_escape, 17); } -static unsigned long read_reserved(void) -{ - return get_pool_counter(HUGEPAGES_RSVD, 0); -} - int main(int argc, char *argv[]) { long hpage_size; @@ -77,7 +72,7 @@ int main(int argc, char *argv[]) if (fd < 0) FAIL("hugetlbfs_unlinked_fd()"); - initial_rsvd = read_reserved(); + initial_rsvd = get_huge_page_counter(hpage_size, HUGEPAGES_RSVD); verbose_printf("Reserve count before map: %lu\n", initial_rsvd); p = mmap(NULL, hpage_size, PROT_READ|PROT_WRITE, MAP_SHARED, @@ -86,16 +81,18 @@ int main(int argc, char *argv[]) FAIL("mmap(): %s", strerror(errno)); q = p; - verbose_printf("Reserve count after map: %lu\n", read_reserved()); + verbose_printf("Reserve count after map: %lu\n", + get_huge_page_counter(hpage_size, HUGEPAGES_RSVD)); *q = 0; - verbose_printf("Reserve count after touch: %lu\n", read_reserved()); + verbose_printf("Reserve count after touch: %lu\n", + get_huge_page_counter(hpage_size, HUGEPAGES_RSVD)); err = ftruncate(fd, 0); if (err) FAIL("ftruncate(): %s", strerror(errno)); - rsvd = read_reserved(); + rsvd = get_huge_page_counter(hpage_size, HUGEPAGES_RSVD); verbose_printf("Reserve count after truncate: %lu\n", rsvd); if (rsvd != initial_rsvd) FAIL("Reserved count is not restored after truncate: %lu instead of %lu", @@ -113,7 +110,7 @@ int main(int argc, char *argv[]) if (sigbus_count != 1) FAIL("Didn't SIGBUS after truncate"); - rsvd = read_reserved(); + rsvd = get_huge_page_counter(hpage_size, HUGEPAGES_RSVD); verbose_printf("Reserve count after SIGBUS fault: %lu\n", rsvd); if (rsvd != initial_rsvd) FAIL("Reserved count is altered by SIGBUS fault: %lu instead of %lu", @@ -122,12 +119,12 @@ int main(int argc, char *argv[]) munmap(p, hpage_size); verbose_printf("Reserve count after munmap(): %lu\n", - read_reserved()); + get_huge_page_counter(hpage_size, HUGEPAGES_RSVD)); close(fd); verbose_printf("Reserve count after close(): %lu\n", - read_reserved()); + get_huge_page_counter(hpage_size, HUGEPAGES_RSVD)); PASS(); } diff --git a/tests/truncate_sigbus_versus_oom.c b/tests/truncate_sigbus_versus_oom.c index ab7d90c..7aa2fe5 100644 --- a/tests/truncate_sigbus_versus_oom.c +++ b/tests/truncate_sigbus_versus_oom.c @@ -58,9 +58,8 @@ int main(int argc, char *argv[]) test_init(argc, argv); - totpages = get_pool_counter(HUGEPAGES_FREE, 0); - hpage_size = check_hugepagesize(); + totpages = get_huge_page_counter(hpage_size, HUGEPAGES_TOTAL); fd = hugetlbfs_unlinked_fd(); if (fd < 0) -- 1.6.0.1.451.gc8d31 ------------------------------------------------------------------------- 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