On (15/07/08 15:15), Adam Litke didst pronounce: > The private reservations feature in new kernels changes the semantics of > private huge page mappings in ways that are recognizable by the libhugetlbfs > test suite. So far, counters and quota are effected. Reserved private > mappings now affect the pool counters in the same way as shared mappings. FS > quota is now allocated up-front (mmap time) for private mappings so going over > quota will now cause the mmap to fail rather than a SIGBUS at page > instantiation time. > > To preserve backwards compatibility, the test suite must correctly test > kernels > with and without private reservation support. To achieve this, a function to > check the running kernel's semantics is needed. This patch adds a function > that attempts to check for private reservations. Use of the pool counters in > the manner employed is racy but since this is a test suite and meant to be run > by itself, the counters method should work. The function is clearly commented > to warn against using it for real programs. > > Signed-off-by: Adam Litke <[EMAIL PROTECTED]> > --- > > tests/counters.c | 26 +++++++++++++++------- > tests/hugetests.h | 3 +++ > tests/quota.c | 18 +++++++++++++++ > tests/testutils.c | 62 > +++++++++++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 100 insertions(+), 9 deletions(-) > > > diff --git a/tests/counters.c b/tests/counters.c > index e3a804b..8abfe19 100644 > --- a/tests/counters.c > +++ b/tests/counters.c > @@ -47,6 +47,7 @@ extern int errno; > #define DYNAMIC_SYSCTL "/proc/sys/vm/nr_overcommit_hugepages" > static long saved_nr_hugepages; > static long hpage_size; > +static int private_resv; > > /* State arrays for our mmaps */ > #define NR_SLOTS 2 > @@ -222,8 +223,12 @@ void _map(int s, int hpages, int flags, int line) > * satisfy the reservation, surplus pages are added to the pool. > * NOTE: This code assumes that the whole mapping needs to be > * reserved and hence, will not work with partial reservations. > + * > + * If the kernel supports private reservations, then MAP_PRIVATE > + * mappings behave like MAP_SHARED at mmap time. Otherwise, > + * no counter updates will occur. > */ > - if (flags & MAP_SHARED) { > + if ((flags & MAP_SHARED) || private_resv) { > unsigned long shortfall = 0; > if (hpages + prev_resv > prev_free) > shortfall = hpages - prev_free + prev_resv; > @@ -232,7 +237,6 @@ void _map(int s, int hpages, int flags, int line) > er = prev_resv + hpages; > es = prev_surp + shortfall; > } > - /* MAP_PRIVATE mappings do not alter the counters in any way. */ > > verify_counters(line, et, ef, er, es); > } > @@ -273,7 +277,7 @@ void _unmap(int s, int hpages, int flags, int line) > * reservation. If those pages were not touched, then they will > * not have been freed by the code above. Free them here. > */ > - if (flags & MAP_SHARED) { > + if ((flags & MAP_SHARED) || private_resv) { > int unused_surplus = min(hpages - touched[s], es); > et -= unused_surplus; > ef -= unused_surplus; > @@ -304,15 +308,15 @@ void _touch(int s, int hpages, int flags, int line) > touched[s] = max(touched[s], hpages); > > /* > - * Shared mappings consume resv pages that were previously > - * allocated. Also deduct them from the free count. > + * Shared (and private when supported) mappings and consume resv pages > + * that were previously allocated. Also deduct them from the free count. > * > - * Private mappings may need to allocate surplus pages to > + * Unreserved private mappings may need to allocate surplus pages to > * satisfy the fault. The surplus pages become part of the pool > * which could elevate total, free, and surplus counts. resv is > * unchanged but free must be decreased. > */ > - if (flags & MAP_SHARED) { > + if (flags & MAP_SHARED || private_resv) { > et = prev_total; > ef = prev_free - hpages; > er = prev_resv - hpages; > @@ -375,12 +379,18 @@ void run_test(char *desc, int base_nr) > > int main(int argc, char ** argv) > { > - int base_nr; > + int fd, base_nr; > > test_init(argc, argv); > check_must_be_root(); > saved_nr_hugepages = read_meminfo("HugePages_Total:"); > verify_dynamic_pool_support(); > + > + fd = hugetlbfs_unlinked_fd(); > + if ((private_resv = kernel_has_private_reservations(fd)) == -1) > + FAIL("kernel_has_private_reservations() failed\n"); > + close(fd); > + > hpage_size = check_hugepagesize(); > > /* > diff --git a/tests/hugetests.h b/tests/hugetests.h > index 3b2d81d..61f339b 100644 > --- a/tests/hugetests.h > +++ b/tests/hugetests.h > @@ -127,4 +127,7 @@ static inline long check_hugepagesize() > return hpage_size; > } > > +/* WARNING: Racy -- use for test cases only! */ > +int kernel_has_private_reservations(int fd); > + > #endif /* _HUGETESTS_H */ > diff --git a/tests/quota.c b/tests/quota.c > index 00566bc..832c980 100644 > --- a/tests/quota.c > +++ b/tests/quota.c > @@ -183,13 +183,21 @@ void _spawn(int l, int expected_result, unsigned long > size, int flags, > > int main(int argc, char ** argv) > { > + int fd, private_resv; > + > test_init(argc, argv); > check_must_be_root(); > mountpoint[0] = '\0'; > hpage_size = check_hugepagesize(); > > + check_free_huge_pages(1); > get_quota_fs(hpage_size); > > + fd = hugetlbfs_unlinked_fd(); > + if ((private_resv = kernel_has_private_reservations(fd)) == -1) > + FAIL("kernel_has_private_reservations() failed\n"); > + close(fd); > + > /* > * Check that simple page instantiation works within quota limits > * for private and shared mappings. > @@ -202,7 +210,15 @@ int main(int argc, char ** argv) > * over quota. > */ > spawn(BAD_EXIT, 2 * hpage_size, MAP_SHARED, 0); > - spawn(BAD_SIG, 2 * hpage_size, MAP_PRIVATE, 0); > + > + /* > + * If private mappings are reserved, the quota is checked up front > + * (as is the case for shared mappings). > + */ > + if (private_resv) > + spawn(BAD_EXIT, 2 * hpage_size, MAP_PRIVATE, 0); > + else > + spawn(BAD_SIG, 2 * hpage_size, MAP_PRIVATE, 0); > > /* > * COW should not be allowed if doing so puts the fs over quota. > diff --git a/tests/testutils.c b/tests/testutils.c > index 9d48482..6953314 100644 > --- a/tests/testutils.c > +++ b/tests/testutils.c > @@ -33,6 +33,7 @@ > #include <sys/ipc.h> > #include <sys/shm.h> > #include <sys/stat.h> > +#include <sys/mman.h> > #include <fcntl.h> > > #include "hugetests.h" > @@ -287,3 +288,64 @@ 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 = read_meminfo("HugePages_Total:"); > + f = read_meminfo("HugePages_Free:"); > + r = read_meminfo("HugePages_Rsvd:"); > + s = read_meminfo("HugePages_Surp:"); > + > + 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; > + }
Why is this an error? It implies that the kernel supports private reservations bu the pool is empty. > + > + /* Recheck the counters */ > + nt = read_meminfo("HugePages_Total:"); > + nf = read_meminfo("HugePages_Free:"); > + nr = read_meminfo("HugePages_Rsvd:"); > + ns = read_meminfo("HugePages_Surp:"); > + > + 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; > +} > > > ------------------------------------------------------------------------- > 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 > -- Mel Gorman Part-time Phd Student Linux Technology Center University of Limerick IBM Dublin Software Lab ------------------------------------------------------------------------- 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